Merge from mc

This commit is contained in:
Doug Turner 2010-06-29 14:39:57 -07:00
commit c92986c46a
62 changed files with 2642 additions and 617 deletions

View File

@ -438,6 +438,11 @@ HandlerInfoWrapper.prototype = {
this._prefSvc.setCharPref(PREF_DISABLED_PLUGIN_TYPES,
disabledPluginTypes.join(","));
// Update the category manager so existing browser windows update.
this._categoryMgr.deleteCategoryEntry("Gecko-Content-Viewers",
this.type,
false);
},
enablePluginType: function() {
@ -448,6 +453,14 @@ HandlerInfoWrapper.prototype = {
this._prefSvc.setCharPref(PREF_DISABLED_PLUGIN_TYPES,
disabledPluginTypes.join(","));
// Update the category manager so existing browser windows update.
this._categoryMgr.
addCategoryEntry("Gecko-Content-Viewers",
this.type,
"@mozilla.org/content/plugin/document-loader-factory;1",
false,
true);
},

View File

@ -365,7 +365,122 @@
@BINPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/icon.png
@BINPATH@/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}/preview.png
#if MOZ_UPDATE_CHANNEL == beta
@BINPATH@/extensions/testpilot@labs.mozilla.com/*
@BINPATH@/extensions/testpilot@labs.mozilla.com/chrome.manifest
@BINPATH@/extensions/testpilot@labs.mozilla.com/components/TestPilot.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/all-studies-window.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/all-studies-window.xul
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/browser.css
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/browser.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/debug.html
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/experiment-page.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/feedback-browser.xul
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.colorhelpers.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.colorhelpers.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.crosshair.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.crosshair.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.image.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.image.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.navigate.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.navigate.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.selection.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.selection.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.stack.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.stack.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.threshold.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.flot.threshold.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/flot/jquery.min.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/raw-data-dialog.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/raw-data-dialog.xul
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/screen.css
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/status-quit.html
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/status.html
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/survey-generator.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/take-survey.html
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/tp-browser.xul
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/welcome-page.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/welcome.html
@BINPATH@/extensions/testpilot@labs.mozilla.com/content/window-utils.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/defaults/preferences/preferences.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/install.rdf
@BINPATH@/extensions/testpilot@labs.mozilla.com/instrument/chrome.manifest
@BINPATH@/extensions/testpilot@labs.mozilla.com/instrument/install.rdf
@BINPATH@/extensions/testpilot@labs.mozilla.com/instrument/instrument.jsm
@BINPATH@/extensions/testpilot@labs.mozilla.com/instrument/instrument.xul
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/dbutils.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/experiment_data_store.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/extension-update.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/feedback.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/jar-code-store.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/cuddlefish.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/memory.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/observer-service.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/plain-text-console.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/preferences-service.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/securable-module.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/timer.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/traceback.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/unit-test.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/unload.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/lib/url.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/log4moz.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/metadata.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/Observers.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/remote-experiment-loader.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/setup.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/string_sanitizer.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/modules/tasks.js
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/badge-default.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/bg.jpg
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/css/screen-standalone.css
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/dino_32x32.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/bg-status.jpg
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/callout.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/callout_continue.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/data1.jpg
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/data2.jpg
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/home_comments.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/home_computer.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/home_continue.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/home_quit.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/home_results.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/home_twitter.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/images/home_upcoming.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/logo.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/mozilla-logo.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/status-completed.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/status-ejected.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/status-missed.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/testpilot_16x16.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/testPilot_200x200.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/testpilot_32x32.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/tp-completedstudies-32x32.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/tp-currentstudies-32x32.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/tp-generic-32x32.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/tp-learned-32x32.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/tp-results-48x48.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/tp-settings-32x32.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/tp-study-48x48.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/all/tp-submit-48x48.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/linux/close_button.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/linux/feedback-frown-16x16.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/linux/feedback-smile-16x16.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/linux/feedback.css
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/mac/close_button.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/mac/feedback-frown-16x16.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/mac/feedback-smile-16x16.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/mac/feedback.css
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/mac/notification-tail-down.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/mac/notification-tail-up.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/win/close_button.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/win/feedback-frown-16x16.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/win/feedback-smile-16x16.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/win/feedback.css
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/win/notification-tail-down.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/skin/win/notification-tail-up.png
@BINPATH@/extensions/testpilot@labs.mozilla.com/tests/test_data_store.js
#endif
@BINPATH@/chrome/toolkit.jar
@BINPATH@/chrome/toolkit.manifest

View File

@ -1778,30 +1778,10 @@ nsScriptSecurityManager::CanExecuteScripts(JSContext* cx,
docshell = window->GetDocShell();
}
nsCOMPtr<nsIDocShellTreeItem> globalObjTreeItem =
do_QueryInterface(docshell);
if (globalObjTreeItem)
{
nsCOMPtr<nsIDocShellTreeItem> treeItem(globalObjTreeItem);
nsCOMPtr<nsIDocShellTreeItem> parentItem;
// Walk up the docshell tree to see if any containing docshell disallows scripts
do
{
rv = docshell->GetAllowJavascript(result);
if (NS_FAILED(rv)) return rv;
if (!*result)
return NS_OK; // Do not run scripts
treeItem->GetParent(getter_AddRefs(parentItem));
treeItem.swap(parentItem);
docshell = do_QueryInterface(treeItem);
#ifdef DEBUG
if (treeItem && !docshell) {
NS_ERROR("cannot get a docshell from a treeItem!");
}
#endif // DEBUG
} while (treeItem && docshell);
if (docshell) {
rv = docshell->GetCanExecuteScripts(result);
if (NS_FAILED(rv)) return rv;
if (!*result) return NS_OK;
}
// OK, the docshell doesn't have script execution explicitly disabled.

View File

@ -6183,41 +6183,22 @@ nsIContentUtils::FindInternalContentViewer(const char* aType,
if (!catMan)
return NULL;
FullPagePluginEnabledType pluginEnabled = NOT_ENABLED;
nsCOMPtr<nsIPluginHost> pluginHost =
do_GetService(MOZ_PLUGIN_HOST_CONTRACTID);
if (pluginHost) {
pluginHost->IsFullPagePluginEnabledForType(aType, &pluginEnabled);
}
nsCOMPtr<nsIDocumentLoaderFactory> docFactory;
if (OVERRIDE_BUILTIN == pluginEnabled) {
docFactory = do_GetService(PLUGIN_DLF_CONTRACTID);
if (docFactory && aLoaderType) {
*aLoaderType = TYPE_PLUGIN;
}
return docFactory.forget();
}
nsXPIDLCString contractID;
nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", aType, getter_Copies(contractID));
if (NS_SUCCEEDED(rv)) {
docFactory = do_GetService(contractID);
if (docFactory && aLoaderType) {
*aLoaderType = contractID.EqualsLiteral(CONTENT_DLF_CONTRACTID) ? TYPE_CONTENT : TYPE_UNKNOWN;
if (contractID.EqualsLiteral(CONTENT_DLF_CONTRACTID))
*aLoaderType = TYPE_CONTENT;
else if (contractID.EqualsLiteral(PLUGIN_DLF_CONTRACTID))
*aLoaderType = TYPE_PLUGIN;
else
*aLoaderType = TYPE_UNKNOWN;
}
return docFactory.forget();
}
if (AVAILABLE == pluginEnabled) {
docFactory = do_GetService(PLUGIN_DLF_CONTRACTID);
if (docFactory && aLoaderType) {
*aLoaderType = TYPE_PLUGIN;
}
return docFactory.forget();
}
return NULL;
}

View File

@ -65,7 +65,6 @@ _TEST_FILES = test_bug1682.html \
test_bug369370.html \
bug369370-popup.png \
test_bug380383.html \
test_bug386495.html \
test_bug391777.html \
test_bug402680.html \
test_bug403868.html \

View File

@ -1,42 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=386495
-->
<head>
<title>Test for Bug 386495</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=386495">Mozilla Bug 386495</a>
<p id="display"></p>
<div id="content">
<iframe id="testIframe"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 386495 **/
function finishTest() {
is(document.getElementById("testIframe").contentWindow.timeoutFired, false, "Timeout shouldn't fire.");
SimpleTest.finish();
}
function testContentEditable() {
document.getElementById('testIframe').style.display = 'block';
document.getElementById('testIframe').contentWindow.timeoutFired = false;
document.getElementById('testIframe').contentWindow.setTimeout("window.timeoutFired = true", 50);
document.getElementById('testIframe').contentDocument.designMode = 'on';
setTimeout(finishTest, 100);
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(testContentEditable);
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,28 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" onload="boom();" class="reftest-wait">
<script type="text/javascript">
// <![CDATA[
function boom()
{
var t = document.getBoxObjectFor(document.documentElement).lastChild;
document.documentElement.style.counterIncrement = "c";
setTimeout(boom2, 0, t);
}
function boom2(t)
{
try {
document.documentElement.appendChild(t);
} catch(e) {
// appendChild is expected to throw
document.documentElement.removeAttribute("class");
}
}
// ]]>
</script>
</window>

View File

@ -21,3 +21,4 @@ load 429085-1.xhtml
load 431906-1.html
load 451311-1.xul
load 461917-1.xhtml
load 467869-1.xul

View File

@ -43,6 +43,7 @@
#include "nsISupports.h"
class nsIURI;
class nsString;
namespace mozilla {
@ -51,7 +52,7 @@ namespace mozilla {
}
#define IHISTORY_IID \
{0xaf27265d, 0x5672, 0x4d23, {0xa0, 0x75, 0x34, 0x8e, 0xb9, 0x73, 0x5a, 0x9a}}
{0x6f736049, 0x6370, 0x4376, {0xb7, 0x17, 0xfa, 0xfc, 0x0b, 0x4f, 0xd0, 0xf1}}
class IHistory : public nsISupports
{
@ -96,6 +97,50 @@ public:
*/
NS_IMETHOD UnregisterVisitedCallback(nsIURI *aURI, dom::Link *aLink) = 0;
enum VisitFlags {
/**
* Indicates whether the URI was loaded in a top-level window.
*/
TOP_LEVEL = 1 << 0,
/**
* Indicates whether the URI was loaded as part of a permanent redirect.
*/
REDIRECT_PERMANENT = 1 << 1,
/**
* Indicates whether the URI was loaded as part of a temporary redirect.
*/
REDIRECT_TEMPORARY = 1 << 2
};
/**
* Adds a history visit for the URI.
*
* @pre aURI must not be null.
*
* @param aURI
* The URI of the page being visited.
* @param aLastVisitedURI
* The URI of the last visit in the chain.
* @param aFlags
* The VisitFlags describing this visit.
*/
NS_IMETHOD VisitURI(
nsIURI *aURI,
nsIURI *aLastVisitedURI,
PRUint32 aFlags
) = 0;
/**
* Set the title of the URI.
*
* @pre aURI must not be null.
*
* @param aURI
* The URI to set the title for.
* @param aTitle
* The title string.
*/
NS_IMETHOD SetURITitle(nsIURI* aURI, const nsAString& aTitle) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(IHistory, IHISTORY_IID)
@ -104,7 +149,11 @@ NS_DEFINE_STATIC_IID_ACCESSOR(IHistory, IHISTORY_IID)
NS_IMETHOD RegisterVisitedCallback(nsIURI *aURI, \
mozilla::dom::Link *aContent); \
NS_IMETHOD UnregisterVisitedCallback(nsIURI *aURI, \
mozilla::dom::Link *aContent);
mozilla::dom::Link *aContent); \
NS_IMETHOD VisitURI(nsIURI *aURI, \
nsIURI *aLastVisitedURI, \
PRUint32 aFlags); \
NS_IMETHOD SetURITitle(nsIURI* aURI, const nsAString& aTitle);
} // namespace mozilla

View File

@ -112,6 +112,8 @@
#include "nsIOfflineCacheUpdate.h"
#include "nsCPrefetchService.h"
#include "nsJSON.h"
#include "IHistory.h"
#include "mozilla/Services.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@ -4702,11 +4704,16 @@ nsDocShell::SetTitle(const PRUnichar * aTitle)
treeOwnerAsWin->SetTitle(aTitle);
}
if (mGlobalHistory && mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
nsCOMPtr<IHistory> history = services::GetHistoryService();
if (history) {
history->SetURITitle(mCurrentURI, mTitle);
}
else if (mGlobalHistory) {
mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
}
}
// Update SessionHistory with the document's title.
if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
mLoadType != LOAD_ERROR_PAGE) {
@ -5672,32 +5679,53 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
if (!(aStateFlags & STATE_IS_DOCUMENT))
return; // not a toplevel document
nsCOMPtr<nsIGlobalHistory3> history3(do_QueryInterface(mGlobalHistory));
nsresult result = NS_ERROR_NOT_IMPLEMENTED;
if (history3) {
// notify global history of this redirect
result = history3->AddDocumentRedirect(aOldChannel, aNewChannel,
aRedirectFlags, !IsFrame());
nsCOMPtr<nsIURI> oldURI, newURI;
aOldChannel->GetURI(getter_AddRefs(oldURI));
aNewChannel->GetURI(getter_AddRefs(newURI));
if (!oldURI || !newURI) {
return;
}
if (result == NS_ERROR_NOT_IMPLEMENTED) {
// when there is no GlobalHistory3, or it doesn't implement
// AddToplevelRedirect, we fall back to GlobalHistory2. Just notify
// that the redirecting page was a rePdirect so it will be link colored
// but not visible.
nsCOMPtr<nsIURI> oldURI;
aOldChannel->GetURI(getter_AddRefs(oldURI));
if (! oldURI)
return; // nothing to tell anybody about
AddToGlobalHistory(oldURI, PR_TRUE, aOldChannel);
// Below a URI visit is saved (see AddURIVisit method doc).
// The visit chain looks something like:
// ...
// Site N - 1
// => Site N
// (redirect to =>) Site N + 1 (we are here!)
// Get N - 1 and transition type
nsCOMPtr<nsIURI> previousURI;
PRUint32 previousFlags = 0;
ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
ChannelIsPost(aOldChannel)) {
// 1. Internal redirects are ignored because they are specific to the
// channel implementation.
// 2. POSTs are not saved by global history.
//
// Regardless, we need to propagate the previous visit to the new
// channel.
SaveLastVisit(aNewChannel, previousURI, previousFlags);
}
else {
nsCOMPtr<nsIURI> referrer;
// Treat referrer as null if there is an error getting it.
(void)NS_GetReferrerFromChannel(aOldChannel,
getter_AddRefs(referrer));
// Add visit N -1 => N
AddURIVisit(oldURI, referrer, previousURI, previousFlags);
// Since N + 1 could be the final destination, we will not save N => N + 1
// here. OnNewURI will do that, so we will cache it.
SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
}
// check if the new load should go through the application cache.
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
do_QueryInterface(aNewChannel);
if (appCacheChannel) {
nsCOMPtr<nsIURI> newURI;
aNewChannel->GetURI(getter_AddRefs(newURI));
appCacheChannel->SetChooseApplicationCache(ShouldCheckAppCache(newURI));
}
@ -8937,7 +8965,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
nsCOMPtr<nsIInputStream> inputStream;
if (aChannel) {
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
// Check if the HTTPChannel is hiding under a multiPartChannel
if (!httpChannel) {
GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
@ -9027,8 +9055,8 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
nsCOMPtr<nsISupports> cacheKey;
// Get the Cache Key and store it in SH.
if (cacheChannel)
// Get the Cache Key and store it in SH.
if (cacheChannel)
cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
// If we already have a loading history entry, store the new cache key
// in it. Otherwise, since we're doing a reload and won't be updating
@ -9050,10 +9078,22 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
getter_AddRefs(mLSHE));
}
// Update Global history
if (aAddToGlobalHistory) {
// Get the referrer uri from the channel
AddToGlobalHistory(aURI, PR_FALSE, aChannel);
// If this is a POST request, we do not want to include this in global
// history.
if (!ChannelIsPost(aChannel)) {
nsCOMPtr<nsIURI> previousURI;
PRUint32 previousFlags = 0;
ExtractLastVisit(aChannel, getter_AddRefs(previousURI),
&previousFlags);
nsCOMPtr<nsIURI> referrer;
// Treat referrer as null if there is an error getting it.
(void)NS_GetReferrerFromChannel(aChannel,
getter_AddRefs(referrer));
AddURIVisit(aURI, referrer, previousURI, previousFlags);
}
}
}
@ -9372,7 +9412,7 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
SetCurrentURI(newURI, nsnull, PR_TRUE);
document->SetDocumentURI(newURI);
AddToGlobalHistory(newURI, PR_FALSE, oldURI);
AddURIVisit(newURI, oldURI, oldURI, 0);
}
else {
FireOnLocationChange(this, nsnull, mCurrentURI);
@ -10068,53 +10108,109 @@ NS_IMETHODIMP nsDocShell::MakeEditable(PRBool inWaitForUriLoad)
return mEditorData->MakeEditable(inWaitForUriLoad);
}
nsresult
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIChannel * aChannel)
bool
nsDocShell::ChannelIsPost(nsIChannel* aChannel)
{
// If this is a POST request, we do not want to include this in global
// history, so return early.
nsCOMPtr<nsIHttpChannel> hchan(do_QueryInterface(aChannel));
if (hchan) {
nsCAutoString type;
nsresult rv = hchan->GetRequestMethod(type);
if (NS_SUCCEEDED(rv) && type.EqualsLiteral("POST"))
return NS_OK;
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
if (!httpChannel) {
return false;
}
nsCOMPtr<nsIURI> referrer;
if (aChannel)
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
return AddToGlobalHistory(aURI, aRedirect, referrer);
nsCAutoString method;
httpChannel->GetRequestMethod(method);
return method.Equals("POST");
}
nsresult
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIURI * aReferrer)
void
nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
nsIURI** aURI,
PRUint32* aChannelRedirectFlags)
{
if (mItemType != typeContent || !mGlobalHistory)
return NS_OK;
PRBool visited;
nsresult rv = mGlobalHistory->IsVisited(aURI, &visited);
if (NS_FAILED(rv))
return rv;
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), aReferrer);
if (NS_FAILED(rv))
return rv;
if (!visited) {
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nsnull);
}
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
if (!props) {
return;
}
return NS_OK;
nsresult rv = props->GetPropertyAsInterface(
NS_LITERAL_STRING("docshell.previousURI"),
NS_GET_IID(nsIURI),
reinterpret_cast<void**>(aURI)
);
if (NS_FAILED(rv)) {
// There is no last visit for this channel, so this must be the first
// link. Link the visit to the referrer of this request, if any.
// Treat referrer as null if there is an error getting it.
(void)NS_GetReferrerFromChannel(aChannel, aURI);
}
else {
rv = props->GetPropertyAsUint32(
NS_LITERAL_STRING("docshell.previousFlags"),
aChannelRedirectFlags
);
NS_WARN_IF_FALSE(
NS_FAILED(rv),
"Could not fetch previous flags, URI will be treated like referrer"
);
}
}
void
nsDocShell::SaveLastVisit(nsIChannel* aChannel,
nsIURI* aURI,
PRUint32 aChannelRedirectFlags)
{
nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
if (!props || !aURI) {
return;
}
props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
aURI);
props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
aChannelRedirectFlags);
}
void
nsDocShell::AddURIVisit(nsIURI* aURI,
nsIURI* aReferrerURI,
nsIURI* aPreviousURI,
PRUint32 aChannelRedirectFlags)
{
NS_ASSERTION(aURI, "Visited URI is null!");
// Only content-type docshells save URI visits.
if (mItemType != typeContent) {
return;
}
nsCOMPtr<IHistory> history = services::GetHistoryService();
if (history) {
PRUint32 visitURIFlags = 0;
if (!IsFrame()) {
visitURIFlags |= IHistory::TOP_LEVEL;
}
if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
}
else if (aChannelRedirectFlags &
nsIChannelEventSink::REDIRECT_PERMANENT) {
visitURIFlags |= IHistory::REDIRECT_PERMANENT;
}
(void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
}
else if (mGlobalHistory) {
// Falls back to sync global history interface.
(void)mGlobalHistory->AddURI(aURI,
!!aChannelRedirectFlags,
!IsFrame(),
aReferrerURI);
}
}
//*****************************************************************************
@ -11171,3 +11267,97 @@ nsDocShell::GetPrintPreview(nsIWebBrowserPrint** aPrintPreview)
#ifdef DEBUG
unsigned long nsDocShell::gNumberOfDocShells = 0;
#endif
NS_IMETHODIMP
nsDocShell::GetCanExecuteScripts(PRBool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = PR_FALSE; // disallow by default
nsCOMPtr<nsIDocShell> docshell = this;
nsCOMPtr<nsIDocShellTreeItem> globalObjTreeItem =
do_QueryInterface(docshell);
if (globalObjTreeItem)
{
nsCOMPtr<nsIDocShellTreeItem> treeItem(globalObjTreeItem);
nsCOMPtr<nsIDocShellTreeItem> parentItem;
PRBool firstPass = PR_TRUE;
PRBool lookForParents = PR_FALSE;
// Walk up the docshell tree to see if any containing docshell disallows scripts
do
{
nsresult rv = docshell->GetAllowJavascript(aResult);
if (NS_FAILED(rv)) return rv;
if (!*aResult) {
nsDocShell* realDocshell = static_cast<nsDocShell*>(docshell.get());
if (realDocshell->mContentViewer) {
nsIDocument* doc = realDocshell->mContentViewer->GetDocument();
if (doc && doc->HasFlag(NODE_IS_EDITABLE) &&
realDocshell->mEditorData) {
nsCOMPtr<nsIEditingSession> editSession;
realDocshell->mEditorData->GetEditingSession(getter_AddRefs(editSession));
PRBool jsDisabled = PR_FALSE;
if (editSession &&
NS_SUCCEEDED(rv = editSession->GetJsAndPluginsDisabled(&jsDisabled))) {
if (firstPass) {
if (jsDisabled) {
// We have a docshell which has been explicitly set
// to design mode, so we disallow scripts.
return NS_OK;
}
// The docshell was not explicitly set to design mode,
// so it must be so because a parent was explicitly
// set to design mode. We don't need to look at higher
// docshells.
*aResult = PR_TRUE;
break;
} else if (lookForParents && jsDisabled) {
// If a parent was explicitly set to design mode,
// we should allow script execution on the child.
*aResult = PR_TRUE;
break;
}
// If the child docshell allows scripting, and the
// parent is inside design mode, we don't need to look
// further.
*aResult = PR_TRUE;
return NS_OK;
}
NS_WARNING("The editing session does not work?");
return NS_FAILED(rv) ? rv : NS_ERROR_FAILURE;
}
if (firstPass) {
// Don't be too hard on docshells on the first pass.
// There may be a parent docshell which has been set
// to design mode, so look for it.
lookForParents = PR_TRUE;
} else {
// We have a docshell which disallows scripts
// and is not editable, so we shouldn't allow
// scripts at all.
return NS_OK;
}
}
} else if (lookForParents) {
// The parent docshell was not explicitly set to design
// mode, so js on the child docshell was disabled for
// another reason. Therefore, we need to disable js.
return NS_OK;
}
firstPass = PR_FALSE;
treeItem->GetParent(getter_AddRefs(parentItem));
treeItem.swap(parentItem);
docshell = do_QueryInterface(treeItem);
#ifdef DEBUG
if (treeItem && !docshell) {
NS_ERROR("cannot get a docshell from a treeItem!");
}
#endif // DEBUG
} while (treeItem && docshell);
}
return NS_OK;
}

View File

@ -433,12 +433,77 @@ protected:
PRUint32 aRedirectFlags,
PRUint32 aStateFlags);
// Global History
/**
* Helper function that determines if channel is an HTTP POST.
*
* @param aChannel
* The channel to test
*
* @return True iff channel is an HTTP post.
*/
bool ChannelIsPost(nsIChannel* aChannel);
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIChannel * aChannel);
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIURI * aReferrer);
/**
* Helper function that finds the last URI and its transition flags for a
* channel.
*
* This method first checks the channel's property bag to see if previous
* info has been saved. If not, it gives back the referrer of the channel.
*
* @param aChannel
* The channel we are transitioning to
* @param aURI
* Output parameter with the previous URI, not addref'd
* @param aChannelRedirectFlags
* If a redirect, output parameter with the previous redirect flags
* from nsIChannelEventSink
*/
void ExtractLastVisit(nsIChannel* aChannel,
nsIURI** aURI,
PRUint32* aChannelRedirectFlags);
/**
* Helper function that caches a URI and a transition for saving later.
*
* @param aChannel
* Channel that will have these properties saved
* @param aURI
* The URI to save for later
* @param aChannelRedirectFlags
* The nsIChannelEventSink redirect flags to save for later
*/
void SaveLastVisit(nsIChannel* aChannel,
nsIURI* aURI,
PRUint32 aChannelRedirectFlags);
/**
* Helper function for adding a URI visit using IHistory. If IHistory is
* not available, the method tries nsIGlobalHistory2.
*
* The IHistory API maintains chains of visits, tracking both HTTP referrers
* and redirects for a user session. VisitURI requires the current URI and
* the previous URI in the chain.
*
* Visits can be saved either during a redirect or when the request has
* reached its final destination. The previous URI in the visit may be
* from another redirect or it may be the referrer.
*
* @pre aURI is not null.
*
* @param aURI
* The URI that was just visited
* @param aReferrerURI
* The referrer URI of this request
* @param aPreviousURI
* The previous URI of this visit (may be the same as aReferrerURI)
* @param aChannelRedirectFlags
* For redirects, the redirect flags from nsIChannelEventSink
* (0 otherwise)
*/
void AddURIVisit(nsIURI* aURI,
nsIURI* aReferrerURI,
nsIURI* aPreviousURI,
PRUint32 aChannelRedirectFlags);
// Helper Routines
nsresult ConfirmRepost(PRBool * aRepost);
@ -700,6 +765,9 @@ protected:
PRInt32 mMarginWidth;
PRInt32 mMarginHeight;
// This can either be a content docshell or a chrome docshell. After
// Create() is called, the type is not expected to change.
PRInt32 mItemType;
// Index into the SHTransaction list, indicating the previous and current

View File

@ -71,7 +71,7 @@ interface nsIPrincipal;
interface nsIWebBrowserPrint;
interface nsIVariant;
[scriptable, uuid(3adde256-05a9-43a7-a190-f8fe75eecfd6)]
[scriptable, uuid(8ac6b880-776a-44d4-b271-a7e64ae3debd)]
interface nsIDocShell : nsISupports
{
/**
@ -511,4 +511,14 @@ interface nsIDocShell : nsISupports
* is loaded.
*/
readonly attribute nsIWebBrowserPrint printPreview;
/**
* Whether this docshell can execute scripts based on its hierarchy.
* The rule of thumb here is that we disable js if this docshell or any
* of its parents disallow scripting, unless the only reason for js being
* disabled in this docshell is a parent docshell having a document that
* is in design mode. In that case, we explicitly allow scripting on the
* current docshell.
*/
readonly attribute boolean canExecuteScripts;
};

View File

@ -61,4 +61,5 @@ EmptyGetElementByIdParam=Empty string passed to getElementById().
LowMemoryTitle=Warning: Low memory
LowMemoryMessage=A script on this page has been stopped due to a low memory condition.
WrongEventPropertyAccessWarning=The '%S' property of a %S event should not be used. The value is meaningless.
SpeculationFailed=An unbalanced tree was written using document.write() causing data from the network to be reparsed. For more information https://developer.mozilla.org/en/Optimizing_Your_Pages_for_Speculative_Parsing

View File

@ -43,7 +43,7 @@
interface nsIEditor;
[scriptable, uuid(274cd32e-3675-47e1-9d8a-fc6504ded9ce)]
[scriptable, uuid(24f3f4da-18a4-448d-876d-7360fefac029)]
interface nsIEditingSession : nsISupports
{
@ -128,5 +128,10 @@ interface nsIEditingSession : nsISupports
* to the window.
*/
void reattachToWindow(in nsIDOMWindow aWindow);
/**
* Whether this session has disabled JS and plugins.
*/
readonly attribute boolean jsAndPluginsDisabled;
};

View File

@ -261,6 +261,14 @@ nsEditingSession::RestoreJSAndPlugins(nsIDOMWindow *aWindow)
return docShell->SetAllowPlugins(mPluginsEnabled);
}
NS_IMETHODIMP
nsEditingSession::GetJsAndPluginsDisabled(PRBool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = mDisabledJSAndPlugins;
return NS_OK;
}
/*---------------------------------------------------------------------------
WindowIsEditable

View File

@ -48,6 +48,7 @@ _TEST_FILES = \
test_bug348497.html \
test_bug384147.html \
test_bug389350.html \
test_bug519928.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,96 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=519928
-->
<head>
<title>Test for Bug 519928</title>
<script type="text/javascript" src="/MochiKit/packed.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=519928">Mozilla Bug 519928</a>
<p id="display"></p>
<div id="content">
<iframe id="load-frame"></iframe>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
var iframe = document.getElementById("load-frame");
function enableJS() allowJS(true);
function disableJS() allowJS(false);
function allowJS(allow) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
iframe.contentWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShell)
.allowJavascript = allow;
}
function expectJSAllowed(allowed, testCondition, callback) {
window.ICanRunMyJS = false;
var self_ = window;
testCondition();
var doc = iframe.contentDocument;
doc.body.innerHTML = "<iframe></iframe>";
var innerFrame = doc.querySelector("iframe");
innerFrame.addEventListener("load", function() {
innerFrame.removeEventListener("load", arguments.callee, false);
var msg = "The inner iframe should" + (allowed ? "" : " not") + " be able to run Javascript";
is(self_.ICanRunMyJS, allowed, msg);
callback();
}, false);
var iframeSrc = "data:text/html,<script>parent.parent.ICanRunMyJS = true;</scr" + "ipt>";
innerFrame.src = iframeSrc;
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
var enterDesignMode = function() document.designMode = "on";
var leaveDesignMode = function() document.designMode = "off";
expectJSAllowed(false, disableJS, function() {
expectJSAllowed(true, enableJS, function() {
expectJSAllowed(true, enterDesignMode, function() {
expectJSAllowed(true, leaveDesignMode, function() {
expectJSAllowed(false, disableJS, function() {
expectJSAllowed(false, enterDesignMode, function() {
expectJSAllowed(false, leaveDesignMode, function() {
expectJSAllowed(true, enableJS, function() {
enterDesignMode = function() iframe.contentDocument.designMode = "on";
leaveDesignMode = function() iframe.contentDocument.designMode = "off";
expectJSAllowed(false, disableJS, function() {
expectJSAllowed(true, enableJS, function() {
expectJSAllowed(true, enterDesignMode, function() {
expectJSAllowed(true, leaveDesignMode, function() {
expectJSAllowed(false, disableJS, function() {
expectJSAllowed(true, enterDesignMode, function() {
expectJSAllowed(false, leaveDesignMode, function() {
expectJSAllowed(true, enableJS, function() {
SimpleTest.finish();
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
});
</script>
</pre>
</body>
</html>

View File

@ -249,7 +249,9 @@ nsRangeUpdater::SelAdjCreateNode(nsIDOMNode *aParent, PRInt32 aPosition)
if (mLock) return NS_OK; // lock set by Will/DidReplaceParent, etc...
NS_ENSURE_TRUE(aParent, NS_ERROR_NULL_POINTER);
PRUint32 i, count = mArray.Length();
NS_ENSURE_TRUE(count, NS_OK);
if (!count) {
return NS_OK;
}
nsRangeStore *item;

View File

@ -60,8 +60,6 @@ abstract public class GeckoApp
public static GeckoSurfaceView surfaceView;
public static GeckoApp mAppContext;
public static boolean useSoftwareDrawing;
void launch()
{
// unpack files in the components directory
@ -121,8 +119,6 @@ abstract public class GeckoApp
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
useSoftwareDrawing = true; //isInEmulator() == 1;
if (!GeckoAppShell.sGeckoRunning) {
// Load our JNI libs; we need to do this before launch() because
// setInitialSize will be called even before Gecko is actually up

View File

@ -100,6 +100,13 @@ class GeckoSurfaceView
Log.w("GeckoAppJava", "surfaceChanged while mInDrawing is true!");
}
if (width == 0 || height == 0)
mSoftwareBuffer = null;
else if (mSoftwareBuffer == null ||
mSoftwareBuffer.capacity() < (width * height * 2) ||
mWidth != width || mHeight != height)
mSoftwareBuffer = ByteBuffer.allocateDirect(width * height * 2);
mFormat = format;
mWidth = width;
mHeight = height;
@ -122,8 +129,6 @@ class GeckoSurfaceView
}
mSurfaceChanged = true;
//Log.i("GeckoAppJava", "<< surfaceChanged");
} finally {
mSurfaceLock.unlock();
}
@ -137,14 +142,10 @@ class GeckoSurfaceView
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("GeckoAppJava", "surface destroyed");
mSurfaceValid = false;
mSoftwareBuffer = null;
}
public ByteBuffer getSoftwareDrawBuffer() {
//#ifdef DEBUG
if (!mSurfaceLock.isHeldByCurrentThread())
Log.e("GeckoAppJava", "getSoftwareDrawBuffer called outside of mSurfaceLock!");
//#endif
return mSoftwareBuffer;
}
@ -154,42 +155,8 @@ class GeckoSurfaceView
public static final int DRAW_ERROR = 0;
public static final int DRAW_GLES_2 = 1;
public static final int DRAW_SOFTWARE = 2;
int innerBeginDrawing() {
/*
* Software (non-GL) rendering
*/
if (GeckoApp.useSoftwareDrawing) {
if (mWidth != mBufferWidth ||
mHeight != mBufferHeight ||
mSurfaceChanged)
{
if (mWidth*mHeight != mBufferWidth*mBufferHeight)
mSoftwareBuffer = ByteBuffer.allocateDirect(mWidth*mHeight*4);
mSoftwareBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
mBufferWidth = mWidth;
mBufferHeight = mHeight;
mSurfaceChanged = false;
}
mSoftwareCanvas = getHolder().lockCanvas(null);
if (mSoftwareCanvas == null) {
Log.e("GeckoAppJava", "lockCanvas failed! << beginDrawing");
return DRAW_ERROR;
}
return DRAW_SOFTWARE;
}
return DRAW_GLES_2;
}
public int beginDrawing() {
//Log.i("GeckoAppJava", ">> beginDrawing");
if (mInDrawing) {
Log.e("GeckoAppJava", "Recursive beginDrawing call!");
return DRAW_ERROR;
@ -214,21 +181,11 @@ class GeckoSurfaceView
return DRAW_ERROR;
}
// call the inner function to do the work, so we can sanely unlock on error
int result = innerBeginDrawing();
if (result == DRAW_ERROR) {
mSurfaceLock.unlock();
return DRAW_ERROR;
}
mInDrawing = true;
return result;
return DRAW_GLES_2;
}
public void endDrawing() {
//Log.w("GeckoAppJava", ">> endDrawing");
if (!mInDrawing) {
Log.e("GeckoAppJava", "endDrawing without beginDrawing!");
return;
@ -239,30 +196,36 @@ class GeckoSurfaceView
Log.e("GeckoAppJava", "endDrawing with false mSurfaceValid");
return;
}
if (GeckoApp.useSoftwareDrawing) {
if (!mSurfaceChanged) {
mSoftwareBitmap.copyPixelsFromBuffer(mSoftwareBuffer);
mSoftwareCanvas.drawBitmap(mSoftwareBitmap, 0, 0, null);
getHolder().unlockCanvasAndPost(mSoftwareCanvas);
mSoftwareCanvas = null;
}
}
} catch (java.lang.IllegalArgumentException ex) {
mSurfaceChanged = true;
} finally {
mInDrawing = false;
//#ifdef DEBUG
if (!mSurfaceLock.isHeldByCurrentThread())
Log.e("GeckoAppJava", "endDrawing while mSurfaceLock not held by current thread!");
//#endif
mSurfaceLock.unlock();
}
}
public void draw2D(ByteBuffer buffer) {
Canvas c = getHolder().lockCanvas();
if (c == null)
return;
if (buffer != mSoftwareBuffer) {
getHolder().unlockCanvasAndPost(c);
return;
}
if (mSoftwareBitmap == null ||
mSoftwareBitmap.getHeight() != mHeight ||
mSoftwareBitmap.getWidth() != mWidth) {
mSoftwareBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.RGB_565);
}
mSoftwareBitmap.copyPixelsFromBuffer(mSoftwareBuffer);
c.drawBitmap(mSoftwareBitmap, 0, 0, null);
getHolder().unlockCanvasAndPost(c);
}
@Override
public boolean onCheckIsTextEditor () {
return false;
@ -347,7 +310,6 @@ class GeckoSurfaceView
// Software rendering
ByteBuffer mSoftwareBuffer;
Bitmap mSoftwareBitmap;
Canvas mSoftwareCanvas;
}
class GeckoInputConnection

View File

@ -87,8 +87,11 @@ already_AddRefed<gfxASurface>
gfxAndroidPlatform::CreateOffscreenSurface(const gfxIntSize& size,
gfxASurface::gfxImageFormat imageFormat)
{
nsRefPtr<gfxASurface> newSurface =
new gfxImageSurface (size, imageFormat);
nsRefPtr<gfxASurface> newSurface;
if (imageFormat == gfxImageSurface::ImageFormatRGB24)
newSurface = new gfxImageSurface (size, gfxASurface::ImageFormatRGB16_565);
else
newSurface = new gfxImageSurface (size, imageFormat);
return newSurface.forget();
}

View File

@ -0,0 +1,53 @@
<!DOCTYPE HTML>
<html class="reftest-print">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Testcase for bug 570160</title>
<!-- distilled from href="http://www.musicalcriticism.com/concerts/usherhall-rsno-clein-0510.shtml" -->
<style type="text/css">
.manuscript {
position: absolute;
left: 770px;
top: 134px;
width: 233px;
height: 133px;
}
#maintext {
padding: 0px px 15px 15px;
position: absolute;
left: 16px;
top: 299px;
width: 752px;
height: 636px;
}
#maintext img {
padding: 10px 10px 10px 25px;
float: right;
}
</style></head>
<body>
<div class="manuscript"></div>
<div id="maintext">
<div style="height:98%"></div>
<p><img src="yyyyyyy" alt="line" width="750" height="50" /></p>
<p><strong><img src="xxxxx" alt="maxwell davies" width="100" height="100" />Related articles:</strong></p>
<p>The RSNO and Denève in Mahler 6<br />
</div>
</body>
</html>

View File

@ -324,4 +324,5 @@ load 547843-1.xhtml
load 551635-1.html
load 564368-1.xhtml
load 564968.xhtml
load 570160.html
load 571618-1.svg

View File

@ -718,90 +718,88 @@ nsInlineFrame::ReflowInlineFrame(nsPresContext* aPresContext,
if (NS_FAILED(rv)) {
return rv;
}
if (NS_INLINE_IS_BREAK(aStatus)) {
if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) {
if (aFrame != mFrames.FirstChild()) {
// Change break-before status into break-after since we have
// already placed at least one child frame. This preserves the
// break-type so that it can be propagated upward.
aStatus = NS_FRAME_NOT_COMPLETE |
NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
(aStatus & NS_INLINE_BREAK_TYPE_MASK);
PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs);
}
else {
// Preserve reflow status when breaking-before our first child
// and propagate it upward without modification.
// Note: if we're lazily setting the frame pointer for our child
// frames, then we need to set it now. Don't return and leave the
// remaining child frames in our child list with the wrong parent
// frame pointer...
if (irs.mSetParentPointer) {
if (irs.mLineContainer && irs.mLineContainer->GetPrevContinuation()) {
ReparentFloatsForInlineChild(irs.mLineContainer, aFrame->GetNextSibling(),
PR_TRUE);
}
for (nsIFrame* f = aFrame->GetNextSibling(); f; f = f->GetNextSibling()) {
f->SetParent(this);
if (lineLayout->GetInFirstLine()) {
aPresContext->FrameManager()->ReparentStyleContext(f);
}
}
}
}
if (NS_INLINE_IS_BREAK_BEFORE(aStatus)) {
if (aFrame != mFrames.FirstChild()) {
// Change break-before status into break-after since we have
// already placed at least one child frame. This preserves the
// break-type so that it can be propagated upward.
aStatus = NS_FRAME_NOT_COMPLETE |
NS_INLINE_BREAK | NS_INLINE_BREAK_AFTER |
(aStatus & NS_INLINE_BREAK_TYPE_MASK);
PushFrames(aPresContext, aFrame, irs.mPrevFrame, irs);
}
else {
// Break-after
if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) {
nsIFrame* newFrame;
rv = CreateNextInFlow(aPresContext, aFrame, newFrame);
if (NS_FAILED(rv)) {
return rv;
// Preserve reflow status when breaking-before our first child
// and propagate it upward without modification.
// Note: if we're lazily setting the frame pointer for our child
// frames, then we need to set it now. Don't return and leave the
// remaining child frames in our child list with the wrong parent
// frame pointer...
if (irs.mSetParentPointer) {
if (irs.mLineContainer && irs.mLineContainer->GetPrevContinuation()) {
ReparentFloatsForInlineChild(irs.mLineContainer, aFrame->GetNextSibling(),
PR_TRUE);
}
}
nsIFrame* nextFrame = aFrame->GetNextSibling();
if (nextFrame) {
NS_FRAME_SET_INCOMPLETE(aStatus);
PushFrames(aPresContext, nextFrame, aFrame, irs);
}
else if (nsnull != GetNextInFlow()) {
// We must return an incomplete status if there are more child
// frames remaining in a next-in-flow that follows this frame.
nsInlineFrame* nextInFlow = (nsInlineFrame*) GetNextInFlow();
while (nsnull != nextInFlow) {
if (nextInFlow->mFrames.NotEmpty()) {
NS_FRAME_SET_INCOMPLETE(aStatus);
break;
for (nsIFrame* f = aFrame->GetNextSibling(); f; f = f->GetNextSibling()) {
f->SetParent(this);
if (lineLayout->GetInFirstLine()) {
aPresContext->FrameManager()->ReparentStyleContext(f);
}
nextInFlow = (nsInlineFrame*) nextInFlow->GetNextInFlow();
}
}
}
return NS_OK;
}
else if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
// Create a next-in-flow if needed.
if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
if (nsGkAtoms::placeholderFrame == aFrame->GetType()) {
nsBlockReflowState* blockRS = lineLayout->mBlockRS;
nsPlaceholderFrame* placeholder = static_cast<nsPlaceholderFrame*>(aFrame);
rv = blockRS->mBlock->SplitFloat(*blockRS, placeholder->GetOutOfFlowFrame(),
nsPlaceholderFrame* placeholder =
static_cast<nsPlaceholderFrame*>(aFrame);
rv = blockRS->mBlock->SplitFloat(*blockRS,
placeholder->GetOutOfFlowFrame(),
aStatus);
// Allow the parent to continue reflowing
// Allow the parent to continue reflowing.
aStatus = NS_FRAME_COMPLETE;
return rv;
}
else {
nsIFrame* newFrame;
rv = CreateNextInFlow(aPresContext, aFrame, newFrame);
if (NS_FAILED(rv)) {
return rv;
}
if (!reflowingFirstLetter) {
nsIFrame* nextFrame = aFrame->GetNextSibling();
if (nextFrame) {
PushFrames(aPresContext, nextFrame, aFrame, irs);
}
}
nsIFrame* newFrame;
rv = CreateNextInFlow(aPresContext, aFrame, newFrame);
if (NS_FAILED(rv)) {
return rv;
}
}
return rv;
if (NS_INLINE_IS_BREAK_AFTER(aStatus)) {
nsIFrame* nextFrame = aFrame->GetNextSibling();
if (nextFrame) {
NS_FRAME_SET_INCOMPLETE(aStatus);
PushFrames(aPresContext, nextFrame, aFrame, irs);
}
else {
// We must return an incomplete status if there are more child
// frames remaining in a next-in-flow that follows this frame.
nsInlineFrame* nextInFlow = static_cast<nsInlineFrame*>(GetNextInFlow());
while (nextInFlow) {
if (nextInFlow->mFrames.NotEmpty()) {
NS_FRAME_SET_INCOMPLETE(aStatus);
break;
}
nextInFlow = static_cast<nsInlineFrame*>(nextInFlow->GetNextInFlow());
}
}
return NS_OK;
}
if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus) && !reflowingFirstLetter) {
nsIFrame* nextFrame = aFrame->GetNextSibling();
if (nextFrame) {
PushFrames(aPresContext, nextFrame, aFrame, irs);
}
}
return NS_OK;
}
nsIFrame*

View File

@ -1,6 +1,6 @@
== dynamic-1-remove-to-none-grouped.xul dynamic-1-ref.xul
== dynamic-1-add-to-one-grouped.xul dynamic-1-ref.xul
== dynamic-1-remove-to-one-grouped-1.xul dynamic-1-ref.xul
fails == dynamic-1-remove-to-one-grouped-2.xul dynamic-1-ref.xul
fails == dynamic-1-remove-to-one-grouped-2.xul dynamic-1-ref.xul # bug 575500
== dynamic-1-add-to-two-grouped-1.xul dynamic-1-ref.xul
== dynamic-1-add-to-two-grouped-2.xul dynamic-1-ref.xul

View File

@ -64,23 +64,6 @@ interface nsIPluginStreamListener;
[ptr] native PRLibraryPtr(PRLibrary);
[ref] native nsIStreamListenerRef(nsIStreamListener *);
[ptr] native nsPluginNativeWindowPtr(nsPluginNativeWindow);
native FullPagePluginEnabledType(FullPagePluginEnabledType);
%{C++
enum FullPagePluginEnabledType
{
// No plugin was found for this MIME type.
NOT_ENABLED,
// A plugin is available and should take precedence over builtin
// content viewers.
OVERRIDE_BUILTIN,
// A plugin is available, but a builtin content viewers should be used if
// present.
AVAILABLE
};
%}
[scriptable, uuid(D419142E-0571-416B-B797-2A8E6624491D)]
interface nsIPluginHost : nsISupports
@ -123,8 +106,6 @@ interface nsIPluginHost : nsISupports
// NS_ERROR_FAILURE if there is no plugin for this type.
[noscript] void isPluginEnabledForType(in string aMimeType);
[noscript] FullPagePluginEnabledType isFullPagePluginEnabledForType(in string aMimeType);
// The return code is NS_OK if the plugin is enabled and NS_ERROR_FAILURE if
// the plugin is explicitly disabled or there is no plugin.
[noscript] void isPluginEnabledForExtension(in string aExtension, in constCharStarRef aMimeType);

View File

@ -2606,42 +2606,6 @@ nsPluginHost::IsPluginEnabledForType(const char* aMimeType)
return NS_OK;
}
NS_IMETHODIMP
nsPluginHost::IsFullPagePluginEnabledForType(const char* aMimeType,
FullPagePluginEnabledType* aResult)
{
*aResult = NOT_ENABLED;
nsCOMPtr<nsIPrefBranch> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!psvc)
return NS_OK;
// A preference controls whether or not the full page plugin is disabled for
// a particular type. The string must be in the form:
// type1,type2,type3,type4
// Note: need an actual interface to control this and subsequent disabling
// (and other plugin host settings) so applications can reliably disable
// plugins - without relying on implementation details such as prefs/category
// manager entries.
nsXPIDLCString overrideTypes;
psvc->GetCharPref("plugin.disable_full_page_plugin_for_types", getter_Copies(overrideTypes));
overrideTypes.Insert(',', 0);
overrideTypes.Append(',');
nsCAutoString commaSeparated(',');
commaSeparated.Append(aMimeType);
commaSeparated.Append(',');
if (overrideTypes.Find(commaSeparated) != kNotFound)
return NS_OK;
nsPluginTag* plugin = FindPluginForType(aMimeType, PR_TRUE);
if (!plugin || !plugin->IsEnabled())
return NS_OK;
*aResult = mOverrideInternalTypes ? OVERRIDE_BUILTIN : AVAILABLE;
return NS_OK;
}
// check comma delimitered extensions
static int CompareExtensions(const char *aExtensionList, const char *aExtension)
{
@ -3386,6 +3350,9 @@ nsresult nsPluginHost::ScanPluginsDirectory(nsIFile * pluginsDir,
pluginTag->SetHost(this);
pluginTag->mNext = mPlugins;
mPlugins = pluginTag;
if (pluginTag->IsEnabled())
pluginTag->RegisterWithCategoryManager(mOverrideInternalTypes);
}
}

View File

@ -412,16 +412,104 @@ nsPluginTag::SetBlocklisted(PRBool aBlocklisted)
return NS_OK;
}
void
nsPluginTag::RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
nsPluginTag::nsRegisterType aType)
{
if (!mMimeTypeArray)
return;
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
("nsPluginTag::RegisterWithCategoryManager plugin=%s, removing = %s\n",
mFileName.get(), aType == ePluginUnregister ? "yes" : "no"));
nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
if (!catMan)
return;
const char *contractId = "@mozilla.org/content/plugin/document-loader-factory;1";
nsCOMPtr<nsIPrefBranch> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
if (!psvc)
return; // NS_ERROR_OUT_OF_MEMORY
// A preference controls whether or not the full page plugin is disabled for
// a particular type. The string must be in the form:
// type1,type2,type3,type4
// Note: need an actual interface to control this and subsequent disabling
// (and other plugin host settings) so applications can reliably disable
// plugins - without relying on implementation details such as prefs/category
// manager entries.
nsXPIDLCString overrideTypes;
psvc->GetCharPref("plugin.disable_full_page_plugin_for_types", getter_Copies(overrideTypes));
nsCAutoString overrideTypesFormatted;
overrideTypesFormatted.Assign(',');
overrideTypesFormatted += overrideTypes;
overrideTypesFormatted.Append(',');
nsACString::const_iterator start, end;
for (int i = 0; i < mVariants; i++) {
if (aType == ePluginUnregister) {
nsXPIDLCString value;
if (NS_SUCCEEDED(catMan->GetCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
getter_Copies(value)))) {
// Only delete the entry if a plugin registered for it
if (strcmp(value, contractId) == 0) {
catMan->DeleteCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
PR_TRUE);
}
}
} else {
overrideTypesFormatted.BeginReading(start);
overrideTypesFormatted.EndReading(end);
nsDependentCString mimeType(mMimeTypeArray[i]);
nsCAutoString commaSeparated;
commaSeparated.Assign(',');
commaSeparated += mimeType;
commaSeparated.Append(',');
if (!FindInReadable(commaSeparated, start, end)) {
catMan->AddCategoryEntry("Gecko-Content-Viewers",
mMimeTypeArray[i],
contractId,
PR_FALSE, /* persist: broken by bug 193031 */
aOverrideInternalTypes, /* replace if we're told to */
nsnull);
}
}
PLUGIN_LOG(PLUGIN_LOG_NOISY,
("nsPluginTag::RegisterWithCategoryManager mime=%s, plugin=%s\n",
mMimeTypeArray[i], mFileName.get()));
}
}
void nsPluginTag::Mark(PRUint32 mask)
{
PRBool wasEnabled = IsEnabled();
mFlags |= mask;
// Update entries in the category manager if necessary.
if (mPluginHost && wasEnabled != IsEnabled()) {
if (wasEnabled)
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
else
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
}
}
void nsPluginTag::UnMark(PRUint32 mask)
{
PRBool wasEnabled = IsEnabled();
mFlags &= ~mask;
// Update entries in the category manager if necessary.
if (mPluginHost && wasEnabled != IsEnabled()) {
if (wasEnabled)
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
else
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
}
}
PRBool nsPluginTag::HasFlag(PRUint32 flag)
@ -475,6 +563,12 @@ void nsPluginTag::TryUnloadPlugin()
// again so the calling code should not be fooled and reload
// the library fresh
mLibrary = nsnull;
// Remove mime types added to the category manager
// only if we were made 'active' by setting the host
if (mPluginHost) {
RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
}
}
/* nsPluginInstanceTag */

View File

@ -66,6 +66,11 @@ struct nsPluginInfo;
class nsPluginTag : public nsIPluginTag
{
public:
enum nsRegisterType {
ePluginRegister,
ePluginUnregister
};
NS_DECL_ISUPPORTS
NS_DECL_NSIPLUGINTAG
@ -93,6 +98,8 @@ public:
PRUint32 Flags();
PRBool Equals(nsPluginTag* aPluginTag);
PRBool IsEnabled();
void RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
nsRegisterType aType = ePluginRegister);
nsRefPtr<nsPluginTag> mNext;
nsPluginHost *mPluginHost;

View File

@ -211,8 +211,8 @@ public final class ElementName
// return "ISINDEX";
// case TreeBuilder.LI:
// return "LI";
// case TreeBuilder.LINK:
// return "LINK";
// case TreeBuilder.LINK_OR_BASEFONT_OR_BGSOUND:
// return "LINK_OR_BASEFONT_OR_BGSOUND";
// case TreeBuilder.MATH:
// return "MATH";
// case TreeBuilder.META:
@ -283,8 +283,8 @@ public final class ElementName
// return "NOEMBED";
// case TreeBuilder.EMBED_OR_IMG:
// return "EMBED_OR_IMG";
// case TreeBuilder.AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR:
// return "AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR";
// case TreeBuilder.AREA_OR_SPACER_OR_WBR:
// return "AREA_OR_SPACER_OR_WBR";
// case TreeBuilder.DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU:
// return "DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU";
// case TreeBuilder.FIELDSET:
@ -433,10 +433,10 @@ public final class ElementName
public static final ElementName TAN = new ElementName("tan", "tan", TreeBuilder.OTHER, false, false, false);
public static final ElementName USE = new ElementName("use", "use", TreeBuilder.OTHER, false, false, false);
public static final ElementName VAR = new ElementName("var", "var", TreeBuilder.RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR, false, false, false);
public static final ElementName WBR = new ElementName("wbr", "wbr", TreeBuilder.AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, true, false, false);
public static final ElementName WBR = new ElementName("wbr", "wbr", TreeBuilder.AREA_OR_SPACER_OR_WBR, true, false, false);
public static final ElementName XMP = new ElementName("xmp", "xmp", TreeBuilder.XMP, false, false, false);
public static final ElementName XOR = new ElementName("xor", "xor", TreeBuilder.OTHER, false, false, false);
public static final ElementName AREA = new ElementName("area", "area", TreeBuilder.AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, true, false, false);
public static final ElementName AREA = new ElementName("area", "area", TreeBuilder.AREA_OR_SPACER_OR_WBR, true, false, false);
public static final ElementName ABBR = new ElementName("abbr", "abbr", TreeBuilder.OTHER, false, false, false);
public static final ElementName BASE = new ElementName("base", "base", TreeBuilder.BASE, true, false, false);
public static final ElementName BVAR = new ElementName("bvar", "bvar", TreeBuilder.OTHER, false, false, false);
@ -457,7 +457,7 @@ public final class ElementName
public static final ElementName HEAD = new ElementName("head", "head", TreeBuilder.HEAD, true, false, false);
public static final ElementName HTML = new ElementName("html", "html", TreeBuilder.HTML, false, true, false);
public static final ElementName LINE = new ElementName("line", "line", TreeBuilder.OTHER, false, false, false);
public static final ElementName LINK = new ElementName("link", "link", TreeBuilder.LINK, true, false, false);
public static final ElementName LINK = new ElementName("link", "link", TreeBuilder.LINK_OR_BASEFONT_OR_BGSOUND, true, false, false);
public static final ElementName LIST = new ElementName("list", "list", TreeBuilder.OTHER, false, false, false);
public static final ElementName META = new ElementName("meta", "meta", TreeBuilder.META, true, false, false);
public static final ElementName MSUB = new ElementName("msub", "msub", TreeBuilder.OTHER, false, false, false);
@ -578,7 +578,7 @@ public final class ElementName
public static final ElementName STRONG = new ElementName("strong", "strong", TreeBuilder.B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U, false, false, false);
public static final ElementName SWITCH = new ElementName("switch", "switch", TreeBuilder.OTHER, false, false, false);
public static final ElementName SYMBOL = new ElementName("symbol", "symbol", TreeBuilder.OTHER, false, false, false);
public static final ElementName SPACER = new ElementName("spacer", "spacer", TreeBuilder.AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, true, false, false);
public static final ElementName SPACER = new ElementName("spacer", "spacer", TreeBuilder.AREA_OR_SPACER_OR_WBR, true, false, false);
public static final ElementName SELECT = new ElementName("select", "select", TreeBuilder.SELECT, true, false, false);
public static final ElementName SUBSET = new ElementName("subset", "subset", TreeBuilder.OTHER, false, false, false);
public static final ElementName SCRIPT = new ElementName("script", "script", TreeBuilder.SCRIPT, true, false, false);
@ -594,7 +594,7 @@ public final class ElementName
public static final ElementName ARCCOTH = new ElementName("arccoth", "arccoth", TreeBuilder.OTHER, false, false, false);
public static final ElementName ACRONYM = new ElementName("acronym", "acronym", TreeBuilder.OTHER, false, false, false);
public static final ElementName ADDRESS = new ElementName("address", "address", TreeBuilder.ADDRESS_OR_DIR_OR_ARTICLE_OR_ASIDE_OR_DATAGRID_OR_DETAILS_OR_HGROUP_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_NAV_OR_SECTION, true, false, false);
public static final ElementName BGSOUND = new ElementName("bgsound", "bgsound", TreeBuilder.AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, true, false, false);
public static final ElementName BGSOUND = new ElementName("bgsound", "bgsound", TreeBuilder.LINK_OR_BASEFONT_OR_BGSOUND, true, false, false);
public static final ElementName COMMAND = new ElementName("command", "command", TreeBuilder.COMMAND, true, false, false);
public static final ElementName COMPOSE = new ElementName("compose", "compose", TreeBuilder.OTHER, false, false, false);
public static final ElementName CEILING = new ElementName("ceiling", "ceiling", TreeBuilder.OTHER, false, false, false);
@ -632,7 +632,7 @@ public final class ElementName
public static final ElementName TENDSTO = new ElementName("tendsto", "tendsto", TreeBuilder.OTHER, false, false, false);
public static final ElementName UPLIMIT = new ElementName("uplimit", "uplimit", TreeBuilder.OTHER, false, false, false);
public static final ElementName ALTGLYPH = new ElementName("altglyph", "altGlyph", TreeBuilder.OTHER, false, false, false);
public static final ElementName BASEFONT = new ElementName("basefont", "basefont", TreeBuilder.AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, true, false, false);
public static final ElementName BASEFONT = new ElementName("basefont", "basefont", TreeBuilder.LINK_OR_BASEFONT_OR_BGSOUND, true, false, false);
public static final ElementName CLIPPATH = new ElementName("clippath", "clipPath", TreeBuilder.OTHER, false, false, false);
public static final ElementName CODOMAIN = new ElementName("codomain", "codomain", TreeBuilder.OTHER, false, false, false);
public static final ElementName COLGROUP = new ElementName("colgroup", "colgroup", TreeBuilder.COLGROUP, true, false, false);

View File

@ -5860,7 +5860,7 @@ public class Tokenizer implements Locator {
private void emitReplacementCharacter(@NoLength char[] buf, int pos)
throws SAXException {
flushChars(buf, pos);
tokenHandler.characters(Tokenizer.REPLACEMENT_CHARACTER, 0, 1);
tokenHandler.zeroOriginatingReplacementCharacter();
cstart = pos + 1;
}

View File

@ -60,6 +60,11 @@ import org.xml.sax.SAXParseException;
public abstract class TreeBuilder<T> implements TokenHandler,
TreeBuilderState<T> {
/**
* Array version of U+FFFD.
*/
private static final @NoLength char[] REPLACEMENT_CHARACTER = { '\uFFFD' };
// Start dispatch groups
final static int OTHER = 0;
@ -94,7 +99,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
final static int LI = 15;
final static int LINK = 16;
final static int LINK_OR_BASEFONT_OR_BGSOUND = 16;
final static int MATH = 17;
@ -158,7 +163,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
final static int EMBED_OR_IMG = 48;
final static int AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR = 49;
final static int AREA_OR_SPACER_OR_WBR = 49;
final static int DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU = 50;
@ -839,8 +844,11 @@ public abstract class TreeBuilder<T> implements TokenHandler,
needToDropLF = false;
}
if (inForeign) {
accumulateCharacters(buf, start, length);
return;
}
// optimize the most common case
// XXX should there be an IN FOREIGN check here?
switch (mode) {
case IN_BODY:
case IN_CELL:
@ -1206,6 +1214,16 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
}
/**
* @see nu.validator.htmlparser.common.TokenHandler#zeroOriginatingReplacementCharacter()
*/
@Override public void zeroOriginatingReplacementCharacter()
throws SAXException {
if (inForeign || mode == TEXT) {
characters(REPLACEMENT_CHARACTER, 0, 1);
}
}
public final void eof() throws SAXException {
flushCharacters();
if (inForeign) {
@ -1768,7 +1786,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
case MARQUEE_OR_APPLET:
case OBJECT:
case TABLE:
case AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR:
case AREA_OR_SPACER_OR_WBR:
case BR:
case EMBED_OR_IMG:
case INPUT:
@ -1797,7 +1815,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
}
break starttagloop;
case BASE:
case LINK:
case LINK_OR_BASEFONT_OR_BGSOUND:
case META:
case STYLE:
case SCRIPT:
@ -1989,7 +2007,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
break starttagloop;
case BR:
case EMBED_OR_IMG:
case AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR:
case AREA_OR_SPACER_OR_WBR:
reconstructTheActiveFormattingElements();
// FALL THROUGH to PARAM_OR_SOURCE
case PARAM_OR_SOURCE:
@ -2313,7 +2331,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
attributes = null; // CPP
break starttagloop;
case META:
case LINK:
case LINK_OR_BASEFONT_OR_BGSOUND:
// Fall through to IN_HEAD_NOSCRIPT
break inheadloop;
case TITLE:
@ -2390,7 +2408,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
attributes = null; // CPP
}
break starttagloop;
case LINK:
case LINK_OR_BASEFONT_OR_BGSOUND:
appendVoidElementToCurrentMayFoster(
"http://www.w3.org/1999/xhtml",
elementName, attributes);
@ -2766,7 +2784,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
pop(); // head
attributes = null; // CPP
break starttagloop;
case LINK:
case LINK_OR_BASEFONT_OR_BGSOUND:
err("\u201Clink\u201D element outside \u201Chead\u201D.");
pushHeadPointerOntoStack();
appendVoidElementToCurrentMayFoster(
@ -3576,7 +3594,7 @@ public abstract class TreeBuilder<T> implements TokenHandler,
elementName,
HtmlAttributes.EMPTY_ATTRIBUTES);
break endtagloop;
case AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR:
case AREA_OR_SPACER_OR_WBR:
case PARAM_OR_SOURCE:
case EMBED_OR_IMG:
case IMAGE:

View File

@ -224,10 +224,10 @@ nsHtml5ElementName::initializeStatics()
ELT_TAN = new nsHtml5ElementName(nsHtml5Atoms::tan, nsHtml5Atoms::tan, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_USE = new nsHtml5ElementName(nsHtml5Atoms::use, nsHtml5Atoms::use, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_VAR = new nsHtml5ElementName(nsHtml5Atoms::var, nsHtml5Atoms::var, NS_HTML5TREE_BUILDER_RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_WBR = new nsHtml5ElementName(nsHtml5Atoms::wbr, nsHtml5Atoms::wbr, NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_WBR = new nsHtml5ElementName(nsHtml5Atoms::wbr, nsHtml5Atoms::wbr, NS_HTML5TREE_BUILDER_AREA_OR_SPACER_OR_WBR, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_XMP = new nsHtml5ElementName(nsHtml5Atoms::xmp, nsHtml5Atoms::xmp, NS_HTML5TREE_BUILDER_XMP, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_XOR = new nsHtml5ElementName(nsHtml5Atoms::xor_, nsHtml5Atoms::xor_, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_AREA = new nsHtml5ElementName(nsHtml5Atoms::area, nsHtml5Atoms::area, NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_AREA = new nsHtml5ElementName(nsHtml5Atoms::area, nsHtml5Atoms::area, NS_HTML5TREE_BUILDER_AREA_OR_SPACER_OR_WBR, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_ABBR = new nsHtml5ElementName(nsHtml5Atoms::abbr, nsHtml5Atoms::abbr, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_BASE = new nsHtml5ElementName(nsHtml5Atoms::base, nsHtml5Atoms::base, NS_HTML5TREE_BUILDER_BASE, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_BVAR = new nsHtml5ElementName(nsHtml5Atoms::bvar, nsHtml5Atoms::bvar, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
@ -248,7 +248,7 @@ nsHtml5ElementName::initializeStatics()
ELT_HEAD = new nsHtml5ElementName(nsHtml5Atoms::head, nsHtml5Atoms::head, NS_HTML5TREE_BUILDER_HEAD, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_HTML = new nsHtml5ElementName(nsHtml5Atoms::html, nsHtml5Atoms::html, NS_HTML5TREE_BUILDER_HTML, PR_FALSE, PR_TRUE, PR_FALSE);
ELT_LINE = new nsHtml5ElementName(nsHtml5Atoms::line, nsHtml5Atoms::line, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_LINK = new nsHtml5ElementName(nsHtml5Atoms::link, nsHtml5Atoms::link, NS_HTML5TREE_BUILDER_LINK, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_LINK = new nsHtml5ElementName(nsHtml5Atoms::link, nsHtml5Atoms::link, NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_LIST = new nsHtml5ElementName(nsHtml5Atoms::list, nsHtml5Atoms::list, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_META = new nsHtml5ElementName(nsHtml5Atoms::meta, nsHtml5Atoms::meta, NS_HTML5TREE_BUILDER_META, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_MSUB = new nsHtml5ElementName(nsHtml5Atoms::msub, nsHtml5Atoms::msub, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
@ -369,7 +369,7 @@ nsHtml5ElementName::initializeStatics()
ELT_STRONG = new nsHtml5ElementName(nsHtml5Atoms::strong, nsHtml5Atoms::strong, NS_HTML5TREE_BUILDER_B_OR_BIG_OR_CODE_OR_EM_OR_I_OR_S_OR_SMALL_OR_STRIKE_OR_STRONG_OR_TT_OR_U, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_SWITCH = new nsHtml5ElementName(nsHtml5Atoms::switch_, nsHtml5Atoms::switch_, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_SYMBOL = new nsHtml5ElementName(nsHtml5Atoms::symbol, nsHtml5Atoms::symbol, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_SPACER = new nsHtml5ElementName(nsHtml5Atoms::spacer, nsHtml5Atoms::spacer, NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_SPACER = new nsHtml5ElementName(nsHtml5Atoms::spacer, nsHtml5Atoms::spacer, NS_HTML5TREE_BUILDER_AREA_OR_SPACER_OR_WBR, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_SELECT = new nsHtml5ElementName(nsHtml5Atoms::select, nsHtml5Atoms::select, NS_HTML5TREE_BUILDER_SELECT, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_SUBSET = new nsHtml5ElementName(nsHtml5Atoms::subset, nsHtml5Atoms::subset, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_SCRIPT = new nsHtml5ElementName(nsHtml5Atoms::script, nsHtml5Atoms::script, NS_HTML5TREE_BUILDER_SCRIPT, PR_TRUE, PR_FALSE, PR_FALSE);
@ -385,7 +385,7 @@ nsHtml5ElementName::initializeStatics()
ELT_ARCCOTH = new nsHtml5ElementName(nsHtml5Atoms::arccoth, nsHtml5Atoms::arccoth, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_ACRONYM = new nsHtml5ElementName(nsHtml5Atoms::acronym, nsHtml5Atoms::acronym, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_ADDRESS = new nsHtml5ElementName(nsHtml5Atoms::address, nsHtml5Atoms::address, NS_HTML5TREE_BUILDER_ADDRESS_OR_DIR_OR_ARTICLE_OR_ASIDE_OR_DATAGRID_OR_DETAILS_OR_HGROUP_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_NAV_OR_SECTION, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_BGSOUND = new nsHtml5ElementName(nsHtml5Atoms::bgsound, nsHtml5Atoms::bgsound, NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_BGSOUND = new nsHtml5ElementName(nsHtml5Atoms::bgsound, nsHtml5Atoms::bgsound, NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_COMMAND = new nsHtml5ElementName(nsHtml5Atoms::command, nsHtml5Atoms::command, NS_HTML5TREE_BUILDER_COMMAND, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_COMPOSE = new nsHtml5ElementName(nsHtml5Atoms::compose, nsHtml5Atoms::compose, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_CEILING = new nsHtml5ElementName(nsHtml5Atoms::ceiling, nsHtml5Atoms::ceiling, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
@ -423,7 +423,7 @@ nsHtml5ElementName::initializeStatics()
ELT_TENDSTO = new nsHtml5ElementName(nsHtml5Atoms::tendsto, nsHtml5Atoms::tendsto, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_UPLIMIT = new nsHtml5ElementName(nsHtml5Atoms::uplimit, nsHtml5Atoms::uplimit, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_ALTGLYPH = new nsHtml5ElementName(nsHtml5Atoms::altglyph, nsHtml5Atoms::altGlyph, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_BASEFONT = new nsHtml5ElementName(nsHtml5Atoms::basefont, nsHtml5Atoms::basefont, NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_BASEFONT = new nsHtml5ElementName(nsHtml5Atoms::basefont, nsHtml5Atoms::basefont, NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND, PR_TRUE, PR_FALSE, PR_FALSE);
ELT_CLIPPATH = new nsHtml5ElementName(nsHtml5Atoms::clippath, nsHtml5Atoms::clipPath, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_CODOMAIN = new nsHtml5ElementName(nsHtml5Atoms::codomain, nsHtml5Atoms::codomain, NS_HTML5TREE_BUILDER_OTHER, PR_FALSE, PR_FALSE, PR_FALSE);
ELT_COLGROUP = new nsHtml5ElementName(nsHtml5Atoms::colgroup, nsHtml5Atoms::colgroup, NS_HTML5TREE_BUILDER_COLGROUP, PR_TRUE, PR_FALSE, PR_FALSE);

View File

@ -51,6 +51,7 @@
#include "nsHtml5AtomTable.h"
#include "nsHtml5Module.h"
#include "nsHtml5RefPtr.h"
#include "nsIScriptError.h"
static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID);
@ -959,6 +960,17 @@ nsHtml5StreamParser::ContinueAfterScripts(nsHtml5Tokenizer* aTokenizer,
mFirstBuffer = speculation->GetBuffer();
mFirstBuffer->setStart(speculation->GetStart());
mTokenizer->setLineNumber(speculation->GetStartLineNumber());
nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
"SpeculationFailed",
nsnull, 0,
mExecutor->GetDocument()->GetDocumentURI(),
EmptyString(),
speculation->GetStartLineNumber(),
0,
nsIScriptError::warningFlag,
"DOM Events");
nsHtml5UTF16Buffer* buffer = mFirstBuffer->next;
while (buffer) {
buffer->setStart(0);
@ -992,6 +1004,13 @@ nsHtml5StreamParser::ContinueAfterScripts(nsHtml5Tokenizer* aTokenizer,
mSpeculations.RemoveElementAt(0);
if (mSpeculations.IsEmpty()) {
// yes, it was still the only speculation. Now stop speculating
if (mTreeBuilder->IsDiscretionaryFlushSafe()) {
// However, before telling the executor to read from stage, flush
// any pending ops straight to the executor, because otherwise
// they remain unflushed until we get more data from the network.
mTreeBuilder->SetOpSink(mExecutor);
mTreeBuilder->Flush();
}
mTreeBuilder->SetOpSink(mExecutor->GetStage());
mExecutor->StartReadingFromStage();
mSpeculating = PR_FALSE;

View File

@ -3339,7 +3339,7 @@ void
nsHtml5Tokenizer::emitReplacementCharacter(PRUnichar* buf, PRInt32 pos)
{
flushChars(buf, pos);
tokenHandler->characters(nsHtml5Tokenizer::REPLACEMENT_CHARACTER, 0, 1);
tokenHandler->zeroOriginatingReplacementCharacter();
cstart = pos + 1;
}

View File

@ -190,6 +190,10 @@ nsHtml5TreeBuilder::characters(const PRUnichar* buf, PRInt32 start, PRInt32 leng
}
needToDropLF = PR_FALSE;
}
if (inForeign) {
accumulateCharacters(buf, start, length);
return;
}
switch(mode) {
case NS_HTML5TREE_BUILDER_IN_BODY:
case NS_HTML5TREE_BUILDER_IN_CELL:
@ -413,6 +417,14 @@ nsHtml5TreeBuilder::characters(const PRUnichar* buf, PRInt32 start, PRInt32 leng
}
}
void
nsHtml5TreeBuilder::zeroOriginatingReplacementCharacter()
{
if (inForeign || mode == NS_HTML5TREE_BUILDER_TEXT) {
characters(REPLACEMENT_CHARACTER, 0, 1);
}
}
void
nsHtml5TreeBuilder::eof()
{
@ -864,7 +876,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
case NS_HTML5TREE_BUILDER_MARQUEE_OR_APPLET:
case NS_HTML5TREE_BUILDER_OBJECT:
case NS_HTML5TREE_BUILDER_TABLE:
case NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR:
case NS_HTML5TREE_BUILDER_AREA_OR_SPACER_OR_WBR:
case NS_HTML5TREE_BUILDER_BR:
case NS_HTML5TREE_BUILDER_EMBED_OR_IMG:
case NS_HTML5TREE_BUILDER_INPUT:
@ -895,7 +907,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
NS_HTML5_BREAK(starttagloop);
}
case NS_HTML5TREE_BUILDER_BASE:
case NS_HTML5TREE_BUILDER_LINK:
case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND:
case NS_HTML5TREE_BUILDER_META:
case NS_HTML5TREE_BUILDER_STYLE:
case NS_HTML5TREE_BUILDER_SCRIPT:
@ -1060,7 +1072,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
}
case NS_HTML5TREE_BUILDER_BR:
case NS_HTML5TREE_BUILDER_EMBED_OR_IMG:
case NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR: {
case NS_HTML5TREE_BUILDER_AREA_OR_SPACER_OR_WBR: {
reconstructTheActiveFormattingElements();
}
case NS_HTML5TREE_BUILDER_PARAM_OR_SOURCE: {
@ -1304,7 +1316,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
NS_HTML5_BREAK(starttagloop);
}
case NS_HTML5TREE_BUILDER_META:
case NS_HTML5TREE_BUILDER_LINK: {
case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: {
NS_HTML5_BREAK(inheadloop);
}
case NS_HTML5TREE_BUILDER_TITLE: {
@ -1368,7 +1380,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
}
NS_HTML5_BREAK(starttagloop);
}
case NS_HTML5TREE_BUILDER_LINK: {
case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: {
appendVoidElementToCurrentMayFoster(kNameSpaceID_XHTML, elementName, attributes);
selfClosing = PR_FALSE;
attributes = nsnull;
@ -1671,7 +1683,7 @@ nsHtml5TreeBuilder::startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttribu
attributes = nsnull;
NS_HTML5_BREAK(starttagloop);
}
case NS_HTML5TREE_BUILDER_LINK: {
case NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND: {
pushHeadPointerOntoStack();
appendVoidElementToCurrentMayFoster(kNameSpaceID_XHTML, elementName, attributes);
@ -2386,7 +2398,7 @@ nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName)
appendVoidElementToCurrentMayFoster(kNameSpaceID_XHTML, elementName, nsHtml5HtmlAttributes::EMPTY_ATTRIBUTES);
NS_HTML5_BREAK(endtagloop);
}
case NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR:
case NS_HTML5TREE_BUILDER_AREA_OR_SPACER_OR_WBR:
case NS_HTML5TREE_BUILDER_PARAM_OR_SOURCE:
case NS_HTML5TREE_BUILDER_EMBED_OR_IMG:
case NS_HTML5TREE_BUILDER_IMAGE:

View File

@ -70,6 +70,7 @@ class nsHtml5Portability;
class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState
{
private:
static PRUnichar REPLACEMENT_CHARACTER[];
static jArray<const char*,PRInt32> QUIRKY_PUBLIC_IDS;
PRInt32 mode;
PRInt32 originalMode;
@ -100,6 +101,7 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState
void doctype(nsIAtom* name, nsString* publicIdentifier, nsString* systemIdentifier, PRBool forceQuirks);
void comment(PRUnichar* buf, PRInt32 start, PRInt32 length);
void characters(const PRUnichar* buf, PRInt32 start, PRInt32 length);
void zeroOriginatingReplacementCharacter();
void eof();
void endTokenization();
void startTag(nsHtml5ElementName* elementName, nsHtml5HtmlAttributes* attributes, PRBool selfClosing);
@ -239,6 +241,7 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState
};
#ifdef nsHtml5TreeBuilder_cpp__
PRUnichar nsHtml5TreeBuilder::REPLACEMENT_CHARACTER[] = { 0xfffd };
jArray<const char*,PRInt32> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = nsnull;
#endif
@ -258,7 +261,7 @@ jArray<const char*,PRInt32> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = nsnull;
#define NS_HTML5TREE_BUILDER_INPUT 13
#define NS_HTML5TREE_BUILDER_ISINDEX 14
#define NS_HTML5TREE_BUILDER_LI 15
#define NS_HTML5TREE_BUILDER_LINK 16
#define NS_HTML5TREE_BUILDER_LINK_OR_BASEFONT_OR_BGSOUND 16
#define NS_HTML5TREE_BUILDER_MATH 17
#define NS_HTML5TREE_BUILDER_META 18
#define NS_HTML5TREE_BUILDER_SVG 19
@ -290,7 +293,7 @@ jArray<const char*,PRInt32> nsHtml5TreeBuilder::QUIRKY_PUBLIC_IDS = nsnull;
#define NS_HTML5TREE_BUILDER_UL_OR_OL_OR_DL 46
#define NS_HTML5TREE_BUILDER_IFRAME 47
#define NS_HTML5TREE_BUILDER_EMBED_OR_IMG 48
#define NS_HTML5TREE_BUILDER_AREA_OR_BASEFONT_OR_BGSOUND_OR_SPACER_OR_WBR 49
#define NS_HTML5TREE_BUILDER_AREA_OR_SPACER_OR_WBR 49
#define NS_HTML5TREE_BUILDER_DIV_OR_BLOCKQUOTE_OR_CENTER_OR_MENU 50
#define NS_HTML5TREE_BUILDER_ADDRESS_OR_DIR_OR_ARTICLE_OR_ASIDE_OR_DATAGRID_OR_DETAILS_OR_HGROUP_OR_FIGURE_OR_FOOTER_OR_HEADER_OR_NAV_OR_SECTION 51
#define NS_HTML5TREE_BUILDER_RUBY_OR_SPAN_OR_SUB_OR_SUP_OR_VAR 52

View File

@ -64,5 +64,10 @@ _TEST_FILES = parser_datreader.js \
invalidchar.xml \
$(NULL)
# Disabled test due to orange on Linux
# test_bug568470.html \
# file_bug568470.sjs \
# file_bug568470-script.sjs \
libs:: $(_TEST_FILES)
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)

View File

@ -0,0 +1,14 @@
function handleRequest(request, response)
{
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/javascript", false);
response.write("var i = 0;");
response.bodyOutputStream.flush();
response.processAsync();
var timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(function() {
response.finish();
}, 500, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}

View File

@ -0,0 +1,19 @@
function handleRequest(request, response)
{
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "text/html", false);
response.write("<script src='file_bug568470-script.sjs'></script>");
response.write("<div id='flushable'>");
for (var i = 0; i < 2000; i++) {
response.write("Lorem ipsum dolor sit amet. ");
}
response.write("</div>");
response.bodyOutputStream.flush();
response.processAsync();
var timer = Components.classes["@mozilla.org/timer;1"]
.createInstance(Components.interfaces.nsITimer);
timer.initWithCallback(function() {
response.finish();
}, 1200, Components.interfaces.nsITimer.TYPE_ONE_SHOT);
}

View File

@ -0,0 +1,51 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=568470
-->
<head>
<title>Test for Bug 568470</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=568470">Mozilla Bug 568470</a>
<p id="display"></p>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 568470 **/
SimpleTest.waitForExplicitFinish();
// assuming the test runs in less than a year...
var time = new Date().getTime() + 1000*60*60*24*365;
var interval = setInterval(function() {
var iframe = document.getElementsByTagName("iframe")[0];
if (iframe) {
var doc = iframe.contentDocument;
if (doc) {
if (doc.getElementById("flushable")) {
time = new Date();
clearInterval(interval);
}
}
}
}, 25);
function finish() {
clearInterval(interval);
var elapsed = new Date().getTime() - time;
ok(elapsed > 350,
"Content flush time and parse end time not enough apart.");
SimpleTest.finish();
}
</script>
</pre>
<div id="content" style="display: none">
<iframe onload="finish();" src="file_bug568470.sjs"></iframe>
</div>
</body>
</html>

View File

@ -1,2 +1,2 @@
<body>&#xFFFD;hello world
<body>hello world

View File

@ -60,7 +60,7 @@ AsyncStatementCallback::HandleError(mozIStorageError *aError)
nsCAutoString warnMsg;
warnMsg.Append("An error occurred while executing an async statement: ");
warnMsg.Append(result);
warnMsg.AppendInt(result);
warnMsg.Append(" ");
warnMsg.Append(message);
NS_WARNING(warnMsg.get());
@ -180,6 +180,33 @@ URIBinder::Bind(mozIStorageBindingParams* aParams,
#undef URI_TO_URLCSTRING
nsresult
GetReversedHostname(nsIURI* aURI, nsString& aRevHost)
{
nsCAutoString forward8;
nsresult rv = aURI->GetHost(forward8);
NS_ENSURE_SUCCESS(rv, rv);
// can't do reversing in UTF8, better use 16-bit chars
GetReversedHostname(NS_ConvertUTF8toUTF16(forward8), aRevHost);
return NS_OK;
}
void
GetReversedHostname(const nsString& aForward, nsString& aRevHost)
{
ReverseString(aForward, aRevHost);
aRevHost.Append(PRUnichar('.'));
}
void
ReverseString(const nsString& aInput, nsString& aReversed)
{
aReversed.Truncate(0);
for (PRInt32 i = aInput.Length() - 1; i >= 0; i--) {
aReversed.Append(aInput[i]);
}
}
} // namespace places
} // namespace mozilla

View File

@ -136,6 +136,44 @@ public:
const nsACString& aURLString);
};
/**
* This extracts the hostname from the URI and reverses it in the
* form that we use (always ending with a "."). So
* "http://microsoft.com/" becomes "moc.tfosorcim."
*
* The idea behind this is that we can create an index over the items in
* the reversed host name column, and then query for as much or as little
* of the host name as we feel like.
*
* For example, the query "host >= 'gro.allizom.' AND host < 'gro.allizom/'
* Matches all host names ending in '.mozilla.org', including
* 'developer.mozilla.org' and just 'mozilla.org' (since we define all
* reversed host names to end in a period, even 'mozilla.org' matches).
* The important thing is that this operation uses the index. Any substring
* calls in a select statement (even if it's for the beginning of a string)
* will bypass any indices and will be slow).
*
* @param aURI
* URI that contains spec to reverse
* @param aRevHost
* Out parameter
*/
nsresult GetReversedHostname(nsIURI* aURI, nsString& aRevHost);
/**
* Similar method to GetReversedHostName but for strings
*/
void GetReversedHostname(const nsString& aForward, nsString& aRevHost);
/**
* Reverses a string.
*
* @param aInput
* The string to be reversed
* @param aReversed
* Ouput parameter will contain the reversed string
*/
void ReverseString(const nsString& aInput, nsString& aReversed);
} // namespace places
} // namespace mozilla

View File

@ -39,6 +39,7 @@
#include "History.h"
#include "nsNavHistory.h"
#include "nsNavBookmarks.h"
#include "Helpers.h"
#include "mozilla/storage.h"
@ -58,6 +59,87 @@ namespace places {
#define URI_VISITED "visited"
#define URI_NOT_VISITED "not visited"
#define URI_VISITED_RESOLUTION_TOPIC "visited-status-resolution"
// Observer event fired after a visit has been registered in the DB.
#define URI_VISIT_SAVED "uri-visit-saved"
////////////////////////////////////////////////////////////////////////////////
//// Step
class Step : public AsyncStatementCallback
{
public:
/**
* Executes statement asynchronously using this as a callback.
*
* @param aStmt
* Statement to execute asynchronously
*/
NS_IMETHOD ExecuteAsync(mozIStorageStatement* aStmt);
/**
* Called once after query is completed. If your query has more than one
* result set to process, you will want to override HandleResult to process
* each one.
*
* @param aResultSet
* Results from ExecuteAsync
* Unlike HandleResult, this *can be NULL* if there were no results.
*/
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet);
/**
* By default, stores the last result set received in mResultSet.
* For queries with only one result set, you don't need to override.
*
* @param aResultSet
* Results from ExecuteAsync
*/
NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet);
/**
* By default, this calls Callback with any saved results from HandleResult.
* For queries with only one result set, you don't need to override.
*
* @param aReason
* SQL status code
*/
NS_IMETHOD HandleCompletion(PRUint16 aReason);
private:
// Used by HandleResult to cache results until HandleCompletion is called.
nsCOMPtr<mozIStorageResultSet> mResultSet;
};
NS_IMETHODIMP
Step::ExecuteAsync(mozIStorageStatement* aStmt)
{
nsCOMPtr<mozIStoragePendingStatement> handle;
nsresult rv = aStmt->ExecuteAsync(this, getter_AddRefs(handle));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
Step::Callback(mozIStorageResultSet* aResultSet)
{
return NS_OK;
}
NS_IMETHODIMP
Step::HandleResult(mozIStorageResultSet* aResultSet)
{
mResultSet = aResultSet;
return NS_OK;
}
NS_IMETHODIMP
Step::HandleCompletion(PRUint16 aReason)
{
nsCOMPtr<mozIStorageResultSet> resultSet = mResultSet;
mResultSet = NULL;
Callback(resultSet);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// Anonymous Helpers
@ -71,7 +153,7 @@ public:
static nsresult Start(nsIURI* aURI)
{
NS_ASSERTION(aURI, "Don't pass a null URI!");
NS_PRECONDITION(aURI, "Null URI");
nsNavHistory* navHist = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(navHist, NS_ERROR_FAILURE);
@ -144,6 +226,626 @@ NS_IMPL_ISUPPORTS1(
mozIStorageStatementCallback
)
/**
* Fail-safe mechanism for ensuring that your task completes, no matter what.
* Pass this around as an nsAutoPtr in your steps to guarantee that when all
* your steps are finished, your task is finished.
*/
class FailSafeFinishTask
{
public:
~FailSafeFinishTask() {
History::GetService()->CurrentTaskFinished();
}
};
////////////////////////////////////////////////////////////////////////////////
//// Steps for VisitURI
struct VisitURIData : public FailSafeFinishTask
{
PRInt64 placeId;
PRInt32 hidden;
PRInt32 typed;
nsCOMPtr<nsIURI> uri;
// Url of last added visit in chain.
nsCString lastSpec;
PRInt64 lastVisitId;
PRInt32 transitionType;
PRInt64 sessionId;
PRTime dateTime;
};
/**
* Step 6: Update frecency of URI and notify observers.
*/
class UpdateFrecencyAndNotifyStep : public Step
{
public:
NS_DECL_ISUPPORTS
UpdateFrecencyAndNotifyStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
// Result set contains new visit created in earlier step
NS_ENSURE_STATE(aResultSet);
nsCOMPtr<mozIStorageRow> row;
nsresult rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 visitId;
rv = row->GetInt64(0, &visitId);
NS_ENSURE_SUCCESS(rv, rv);
// TODO need to figure out story for not synchronous frecency updating
// (bug 556631)
// Swallow errors here, since if we've gotten this far, it's more
// important to notify the observers below.
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_WARN_IF_FALSE(history, "Could not get history service");
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_WARN_IF_FALSE(bookmarks, "Could not get bookmarks service");
if (history && bookmarks) {
// Update frecency *after* the visit info is in the db
nsresult rv = history->UpdateFrecency(
mData->placeId,
bookmarks->IsRealBookmark(mData->placeId)
);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not update frecency");
// Notify nsNavHistory observers of visit, but only for certain types of
// visits to maintain consistency with nsNavHistory::GetQueryResults.
if (!mData->hidden &&
mData->transitionType != nsINavHistoryService::TRANSITION_EMBED &&
mData->transitionType != nsINavHistoryService::TRANSITION_FRAMED_LINK) {
history->NotifyOnVisit(mData->uri, visitId, mData->dateTime,
mData->sessionId, mData->lastVisitId,
mData->transitionType);
}
}
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService) {
nsresult rv = obsService->NotifyObservers(mData->uri, URI_VISIT_SAVED, nsnull);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not notify observers");
}
History::GetService()->NotifyVisited(mData->uri);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
UpdateFrecencyAndNotifyStep
, mozIStorageStatementCallback
)
/**
* Step 5: Get newly created visit ID from moz_history_visits table.
*/
class GetVisitIDStep : public Step
{
public:
NS_DECL_ISUPPORTS
GetVisitIDStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
// Find visit ID, needed for notifying observers in next step.
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_RECENT_VISIT_OF_URL);
NS_ENSURE_STATE(stmt);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new UpdateFrecencyAndNotifyStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
GetVisitIDStep
, mozIStorageStatementCallback
)
/**
* Step 4: Add visit to moz_history_visits table.
*/
class AddVisitStep : public Step
{
public:
NS_DECL_ISUPPORTS
AddVisitStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsresult rv;
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
// TODO need to figure out story for new session IDs that isn't synchronous
// (bug 561450)
if (aResultSet) {
// Result set contains last visit information for this session
nsCOMPtr<mozIStorageRow> row;
rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 possibleSessionId;
PRTime lastVisitOfSession;
rv = row->GetInt64(0, &mData->lastVisitId);
NS_ENSURE_SUCCESS(rv, rv);
rv = row->GetInt64(1, &possibleSessionId);
NS_ENSURE_SUCCESS(rv, rv);
rv = row->GetInt64(2, &lastVisitOfSession);
NS_ENSURE_SUCCESS(rv, rv);
if (mData->dateTime - lastVisitOfSession <= RECENT_EVENT_THRESHOLD) {
mData->sessionId = possibleSessionId;
}
else {
// Session is too old. Start a new one.
mData->sessionId = history->GetNewSessionID();
mData->lastVisitId = 0;
}
}
else {
// No previous saved visit entry could be found, so start a new session.
mData->sessionId = history->GetNewSessionID();
mData->lastVisitId = 0;
}
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_INSERT_VISIT);
NS_ENSURE_STATE(stmt);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("from_visit"),
mData->lastVisitId);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"),
mData->placeId);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("visit_date"),
mData->dateTime);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("visit_type"),
mData->transitionType);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("session"),
mData->sessionId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new GetVisitIDStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
AddVisitStep
, mozIStorageStatementCallback
)
/**
* Step 3: Callback for inserting or updating a moz_places entry.
* This step checks database for the last visit in session.
*/
class CheckLastVisitStep : public Step
{
public:
NS_DECL_ISUPPORTS
CheckLastVisitStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsresult rv;
if (aResultSet) {
// Last step inserted a new URL. This query contains the id.
nsCOMPtr<mozIStorageRow> row;
rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
rv = row->GetInt64(0, &mData->placeId);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!mData->lastSpec.IsEmpty()) {
// Find last visit ID and session ID using lastSpec so we can add them
// to a browsing session if the visit was recent.
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_RECENT_VISIT_OF_URL);
NS_ENSURE_STATE(stmt);
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->lastSpec);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new AddVisitStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
// Empty lastSpec.
// Not part of a session. Just run next step's callback with no results.
nsCOMPtr<Step> step = new AddVisitStep(mData);
rv = step->Callback(NULL);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
CheckLastVisitStep
, mozIStorageStatementCallback
)
/**
* Step 2a: Called only when a new entry is put into moz_places.
* Finds the ID of a recently inserted place.
*/
class FindNewIdStep : public Step
{
public:
NS_DECL_ISUPPORTS
FindNewIdStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_GET_PAGE_VISIT_STATS);
NS_ENSURE_STATE(stmt);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new CheckLastVisitStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
FindNewIdStep
, mozIStorageStatementCallback
)
/**
* Step 2: Callback for checking for an existing URI in moz_places.
* This step inserts or updates the URI accordingly.
*/
class CheckExistingStep : public Step
{
public:
NS_DECL_ISUPPORTS
CheckExistingStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsresult rv;
nsCOMPtr<mozIStorageStatement> stmt;
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
if (aResultSet) {
nsCOMPtr<mozIStorageRow> row;
rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
rv = row->GetInt64(0, &mData->placeId);
NS_ENSURE_SUCCESS(rv, rv);
if (!mData->typed) {
// If this transition wasn't typed, others might have been. If database
// has location as typed, reflect that in our data structure.
rv = row->GetInt32(2, &mData->typed);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mData->hidden) {
// If this transition was hidden, it is possible that others were not.
// Any one visible transition makes this location visible. If database
// has location as visible, reflect that in our data structure.
rv = row->GetInt32(3, &mData->hidden);
NS_ENSURE_SUCCESS(rv, rv);
}
// Note: trigger will update visit_count.
stmt = history->GetStatementById(DB_UPDATE_PAGE_VISIT_STATS);
NS_ENSURE_STATE(stmt);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("typed"), mData->typed);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("hidden"), mData->hidden);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), mData->placeId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new CheckLastVisitStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
// No entry exists, so create one.
stmt = history->GetStatementById(DB_ADD_NEW_PAGE);
NS_ENSURE_STATE(stmt);
nsAutoString revHost;
rv = GetReversedHostname(mData->uri, revHost);
NS_ENSURE_SUCCESS(rv, rv);
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("rev_host"), revHost);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("typed"), mData->typed);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("hidden"), mData->hidden);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("frecency"), -1);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new FindNewIdStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
CheckExistingStep
, mozIStorageStatementCallback
)
/**
* Step 1: See if there is an existing URI.
*/
class StartVisitURIStep : public Step
{
public:
NS_DECL_ISUPPORTS
StartVisitURIStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
// Find existing entry in moz_places table, if any.
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_GET_PAGE_VISIT_STATS);
NS_ENSURE_STATE(stmt);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new CheckExistingStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
StartVisitURIStep
, Step
)
////////////////////////////////////////////////////////////////////////////////
//// Steps for SetURITitle
struct SetTitleData : public FailSafeFinishTask
{
nsCOMPtr<nsIURI> uri;
nsString title;
};
/**
* Step 3: Notify that title has been updated.
*/
class TitleNotifyStep: public Step
{
public:
NS_DECL_ISUPPORTS
TitleNotifyStep(nsAutoPtr<SetTitleData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
history->NotifyTitleChange(mData->uri, mData->title);
return NS_OK;
}
protected:
nsAutoPtr<SetTitleData> mData;
};
NS_IMPL_ISUPPORTS1(
TitleNotifyStep
, mozIStorageStatementCallback
)
/**
* Step 2: Set title.
*/
class SetTitleStep : public Step
{
public:
NS_DECL_ISUPPORTS
SetTitleStep(nsAutoPtr<SetTitleData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
if (!aResultSet) {
// URI record was not found.
return NS_OK;
}
nsCOMPtr<mozIStorageRow> row;
nsresult rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString title;
rv = row->GetString(2, title);
NS_ENSURE_SUCCESS(rv, rv);
// It is actually common to set the title to be the same thing it used to
// be. For example, going to any web page will always cause a title to be set,
// even though it will often be unchanged since the last visit. In these
// cases, we can avoid DB writing and observer overhead.
if (mData->title.Equals(title) || (mData->title.IsVoid() && title.IsVoid()))
return NS_OK;
nsNavHistory* history = nsNavHistory::GetHistoryService();
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_SET_PLACE_TITLE);
NS_ENSURE_STATE(stmt);
if (mData->title.IsVoid()) {
rv = stmt->BindNullByName(NS_LITERAL_CSTRING("page_title"));
}
else {
rv = stmt->BindStringByName(
NS_LITERAL_CSTRING("page_title"),
StringHead(mData->title, TITLE_LENGTH_MAX)
);
}
NS_ENSURE_SUCCESS(rv, rv);
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new TitleNotifyStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<SetTitleData> mData;
};
NS_IMPL_ISUPPORTS1(
SetTitleStep
, mozIStorageStatementCallback
)
/**
* Step 1: See if there is an existing URI.
*/
class StartSetURITitleStep : public Step
{
public:
NS_DECL_ISUPPORTS
StartSetURITitleStep(nsAutoPtr<SetTitleData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
// Find existing entry in moz_places table, if any.
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_GET_URL_PAGE_INFO);
NS_ENSURE_STATE(stmt);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new SetTitleStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<SetTitleData> mData;
};
NS_IMPL_ISUPPORTS1(
StartSetURITitleStep
, Step
)
} // anonymous namespace
////////////////////////////////////////////////////////////////////////////////
@ -160,6 +862,7 @@ History::History()
History::~History()
{
gService = NULL;
#ifdef DEBUG
if (mObservers.IsInitialized()) {
NS_ASSERTION(mObservers.Count() == 0,
@ -168,6 +871,28 @@ History::~History()
#endif
}
void
History::AppendTask(Step* aTask)
{
NS_PRECONDITION(aTask, "Got NULL task.");
NS_ADDREF(aTask);
mPendingVisits.Push(aTask);
if (mPendingVisits.GetSize() == 1) {
// There are no other pending tasks.
StartNextTask();
}
}
void
History::CurrentTaskFinished()
{
nsCOMPtr<Step> deadTaskWalking =
dont_AddRef(static_cast<Step*>(mPendingVisits.PopFront()));
StartNextTask();
}
void
History::NotifyVisited(nsIURI* aURI)
{
@ -228,9 +953,107 @@ History::GetSingleton()
return gService;
}
void
History::StartNextTask()
{
nsCOMPtr<Step> nextTask =
static_cast<Step*>(mPendingVisits.PeekFront());
if (!nextTask) {
// No more pending visits left to process.
return;
}
nsresult rv = nextTask->Callback(NULL);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Beginning a task failed.");
}
////////////////////////////////////////////////////////////////////////////////
//// IHistory
NS_IMETHODIMP
History::VisitURI(nsIURI* aURI,
nsIURI* aLastVisitedURI,
PRUint32 aFlags)
{
NS_PRECONDITION(aURI, "URI should not be NULL.");
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
// Silently return if URI is something we shouldn't add to DB.
PRBool canAdd;
nsresult rv = history->CanAddURI(aURI, &canAdd);
NS_ENSURE_SUCCESS(rv, rv);
if (!canAdd) {
return NS_OK;
}
// Populate data structure that will be used in our async SQL steps.
nsAutoPtr<VisitURIData> data(new VisitURIData());
nsCAutoString spec;
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
if (aLastVisitedURI) {
rv = aLastVisitedURI->GetSpec(data->lastSpec);
NS_ENSURE_SUCCESS(rv, rv);
}
if (spec.Equals(data->lastSpec)) {
// Do not save refresh-page visits.
return NS_OK;
}
// Assigns a type to the edge in the visit linked list. Each type will be
// considered differently when weighting the frecency of a location.
PRUint32 recentFlags = history->GetRecentFlags(aURI);
bool redirected = false;
if (aFlags & IHistory::REDIRECT_TEMPORARY) {
data->transitionType = nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY;
redirected = true;
}
else if (aFlags & IHistory::REDIRECT_PERMANENT) {
data->transitionType = nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT;
redirected = true;
}
else if (recentFlags & nsNavHistory::RECENT_TYPED) {
data->transitionType = nsINavHistoryService::TRANSITION_TYPED;
}
else if (recentFlags & nsNavHistory::RECENT_BOOKMARKED) {
data->transitionType = nsINavHistoryService::TRANSITION_BOOKMARK;
}
else if (aFlags & IHistory::TOP_LEVEL) {
// User was redirected or link was clicked in the main window.
data->transitionType = nsINavHistoryService::TRANSITION_LINK;
}
else if (recentFlags & nsNavHistory::RECENT_ACTIVATED) {
// User activated a link in a frame.
data->transitionType = nsINavHistoryService::TRANSITION_FRAMED_LINK;
}
else {
// A frame redirected to a new site without user interaction.
data->transitionType = nsINavHistoryService::TRANSITION_EMBED;
}
data->typed = (data->transitionType == nsINavHistoryService::TRANSITION_TYPED) ? 1 : 0;
data->hidden =
(data->transitionType == nsINavHistoryService::TRANSITION_FRAMED_LINK ||
data->transitionType == nsINavHistoryService::TRANSITION_EMBED ||
redirected) ? 1 : 0;
data->dateTime = PR_Now();
data->uri = aURI;
nsCOMPtr<Step> task(new StartVisitURIStep(data));
AppendTask(task);
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nsnull);
}
return NS_OK;
}
NS_IMETHODIMP
History::RegisterVisitedCallback(nsIURI* aURI,
Link* aLink)
@ -308,12 +1131,42 @@ History::UnregisterVisitedCallback(nsIURI* aURI,
return NS_OK;
}
NS_IMETHODIMP
History::SetURITitle(nsIURI* aURI, const nsAString& aTitle)
{
NS_PRECONDITION(aURI, "Must pass a non-null URI!");
nsNavHistory* history = nsNavHistory::GetHistoryService();
PRBool canAdd;
nsresult rv = history->CanAddURI(aURI, &canAdd);
NS_ENSURE_SUCCESS(rv, rv);
if (!canAdd) {
return NS_OK;
}
nsAutoPtr<SetTitleData> data(new SetTitleData());
data->uri = aURI;
if (aTitle.IsEmpty()) {
data->title.SetIsVoid(PR_TRUE);
}
else {
data->title.Assign(aTitle);
}
nsCOMPtr<Step> task(new StartSetURITitleStep(data));
AppendTask(task);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// nsISupports
NS_IMPL_ISUPPORTS1(
History,
IHistory
History
, IHistory
)
} // namespace places

View File

@ -46,12 +46,13 @@
#include "nsString.h"
#include "nsURIHashKey.h"
#include "nsTArray.h"
#include "nsDeque.h"
namespace mozilla {
namespace places {
#define NS_HISTORYSERVICE_CID \
{0x9fc91e65, 0x1475, 0x4353, {0x9b, 0x9a, 0x93, 0xd7, 0x6f, 0x5b, 0xd9, 0xb7}}
{0x0937a705, 0x91a6, 0x417a, {0x82, 0x92, 0xb2, 0x2e, 0xb1, 0x0d, 0xa8, 0x6c}}
class History : public IHistory
{
@ -69,6 +70,26 @@ public:
*/
void NotifyVisited(nsIURI *aURI);
/**
* Append a task to the queue for SQL queries that need to happen
* atomically.
*
* @pre aTask is not null
*
* @param aTask
* Task that needs to be completed atomically
*/
void AppendTask(class Step* aTask);
/**
* Call when all steps of the current running task are finished. Each task
* should be responsible for calling this when it is finished (even if there
* are errors).
*
* Do not call this twice for the same visit.
*/
void CurrentTaskFinished();
/**
* Obtains a pointer to this service.
*/
@ -83,6 +104,26 @@ public:
private:
~History();
/**
* Since visits rapidly fire at once, it's very likely to have race
* conditions for SQL queries. We often need to see if a row exists
* or peek at values, and by the time we have retrieved them they could
* be different.
*
* We guarantee an ordering of our SQL statements so that a set of
* callbacks for one visit are guaranteed to be atomic. Each visit consists
* of a data structure that sits in this queue.
*
* The front of the queue always has the current visit we are processing.
*/
nsDeque mPendingVisits;
/**
* Begins next task at the front of the queue. The task remains in the queue
* until it is done and calls CurrentTaskFinished.
*/
void StartNextTask();
static History *gService;
typedef nsTArray<mozilla::dom::Link *> ObserverArray;

View File

@ -88,11 +88,6 @@
using namespace mozilla::places;
// Microsecond timeout for "recent" events such as typed and bookmark following.
// If you typed it more than this time ago, it's not recent.
// This is 15 minutes m s/m us/s
#define RECENT_EVENT_THRESHOLD PRTime((PRInt64)15 * 60 * PR_USEC_PER_SEC)
// The maximum number of things that we will store in the recent events list
// before calling ExpireNonrecentEvents. This number should be big enough so it
// is very difficult to get that many unconsumed events (for example, typed but
@ -237,21 +232,12 @@ NS_IMPL_CI_INTERFACE_GETTER5(
namespace {
static nsresult GetReversedHostname(nsIURI* aURI, nsAString& host);
static void GetReversedHostname(const nsString& aForward, nsAString& aReversed);
static PRInt64 GetSimpleBookmarksQueryFolder(
const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions);
static void ParseSearchTermsFromQueries(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsTArray<nsTArray<nsString>*>* aTerms);
inline void ReverseString(const nsString& aInput, nsAString& aReversed)
{
aReversed.Truncate(0);
for (PRInt32 i = aInput.Length() - 1; i >= 0; i --)
aReversed.Append(aInput[i]);
}
} // anonymous namespace
namespace mozilla {
@ -909,6 +895,27 @@ nsNavHistory::UpdateSchemaVersion()
}
PRUint32
nsNavHistory::GetRecentFlags(nsIURI *aURI)
{
PRUint32 result = 0;
nsCAutoString spec;
nsresult rv = aURI->GetSpec(spec);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to get aURI's spec");
if (NS_SUCCEEDED(rv)) {
if (CheckIsRecentEvent(&mRecentTyped, spec))
result |= RECENT_TYPED;
if (CheckIsRecentEvent(&mRecentLink, spec))
result |= RECENT_ACTIVATED;
if (CheckIsRecentEvent(&mRecentBookmark, spec))
result |= RECENT_BOOKMARKED;
}
return result;
}
/**
* Called after InitDB, this creates our own functions
*/
@ -1865,6 +1872,9 @@ nsNavHistory::GetUrlIdFor(nsIURI* aURI, PRInt64* aEntryID,
// THIS SHOULD BE THE ONLY PLACE NEW moz_places ROWS ARE
// CREATED. This allows us to maintain better consistency.
//
// XXX this functionality is being moved to History.cpp, so
// in fact there *are* two places where new pages are added.
//
// If non-null, the new page ID will be placed into aPageID.
nsresult
@ -2162,6 +2172,29 @@ nsNavHistory::GetNewSessionID()
}
void
nsNavHistory::NotifyOnVisit(nsIURI* aURI,
PRInt64 aVisitID,
PRTime aTime,
PRInt64 aSessionID,
PRInt64 referringVisitID,
PRInt32 aTransitionType)
{
PRUint32 added = 0;
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver,
OnVisit(aURI, aVisitID, aTime, aSessionID,
referringVisitID, aTransitionType, &added));
}
void
nsNavHistory::NotifyTitleChange(nsIURI* aURI, const nsString& aTitle)
{
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnTitleChanged(aURI, aTitle));
}
PRInt32
nsNavHistory::GetDaysOfHistory() {
PRInt32 daysOfHistory = 0;
@ -2866,12 +2899,9 @@ nsNavHistory::AddVisit(nsIURI* aURI, PRTime aTime, nsIURI* aReferringURI,
// Notify observers: The hidden detection code must match that in
// GetQueryResults to maintain consistency.
// FIXME bug 325241: make a way to observe hidden URLs
PRUint32 added = 0;
if (!hidden) {
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver,
OnVisit(aURI, *aVisitID, aTime, aSessionID,
referringVisitID, aTransitionType, &added));
NotifyOnVisit(aURI, *aVisitID, aTime, aSessionID, referringVisitID,
aTransitionType);
}
// Normally docshell sends the link visited observer notification for us (this
@ -7335,7 +7365,6 @@ nsNavHistory::SetPageTitleInternal(nsIURI* aURI, const nsAString& aTitle)
rv = mDBSetPlaceTitle->Execute();
NS_ENSURE_SUCCESS(rv, rv);
// observers (have to check first if it's bookmarked)
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnTitleChanged(aURI, aTitle));
@ -7547,52 +7576,6 @@ nsNavHistory::RemoveDuplicateURIs()
namespace {
// GetReversedHostname
//
// This extracts the hostname from the URI and reverses it in the
// form that we use (always ending with a "."). So
// "http://microsoft.com/" becomes "moc.tfosorcim."
//
// The idea behind this is that we can create an index over the items in
// the reversed host name column, and then query for as much or as little
// of the host name as we feel like.
//
// For example, the query "host >= 'gro.allizom.' AND host < 'gro.allizom/'
// Matches all host names ending in '.mozilla.org', including
// 'developer.mozilla.org' and just 'mozilla.org' (since we define all
// reversed host names to end in a period, even 'mozilla.org' matches).
// The important thing is that this operation uses the index. Any substring
// calls in a select statement (even if it's for the beginning of a string)
// will bypass any indices and will be slow).
nsresult
GetReversedHostname(nsIURI* aURI, nsAString& aRevHost)
{
nsCString forward8;
nsresult rv = aURI->GetHost(forward8);
if (NS_FAILED(rv)) {
return rv;
}
// can't do reversing in UTF8, better use 16-bit chars
NS_ConvertUTF8toUTF16 forward(forward8);
GetReversedHostname(forward, aRevHost);
return NS_OK;
}
// GetReversedHostname
//
// Same as previous but for strings
void
GetReversedHostname(const nsString& aForward, nsAString& aRevHost)
{
ReverseString(aForward, aRevHost);
aRevHost.Append(PRUnichar('.'));
}
// GetSimpleBookmarksQueryFolder
//
// Determines if this set of queries is a simple bookmarks query for a

View File

@ -88,6 +88,10 @@
#define URI_LENGTH_MAX 65536
#define TITLE_LENGTH_MAX 4096
// Microsecond timeout for "recent" events such as typed and bookmark following.
// If you typed it more than this time ago, it's not recent.
#define RECENT_EVENT_THRESHOLD PRTime((PRInt64)15 * 60 * PR_USEC_PER_SEC)
#ifdef MOZ_XUL
// Fired after autocomplete feedback has been updated.
#define TOPIC_AUTOCOMPLETE_FEEDBACK_UPDATED "places-autocomplete-feedback-updated"
@ -112,6 +116,13 @@ namespace places {
DB_GET_PAGE_INFO_BY_URL = 0
, DB_GET_TAGS = 1
, DB_IS_PAGE_VISITED = 2
, DB_INSERT_VISIT = 3
, DB_RECENT_VISIT_OF_URL = 4
, DB_GET_PAGE_VISIT_STATS = 5
, DB_UPDATE_PAGE_VISIT_STATS = 6
, DB_ADD_NEW_PAGE = 7
, DB_GET_URL_PAGE_INFO = 8
, DB_SET_PLACE_TITLE = 9
};
} // namespace places
@ -394,6 +405,19 @@ public:
*/
bool canNotify() { return mCanNotify; }
enum RecentEventFlags {
RECENT_TYPED = 1 << 0, // User typed in URL recently
RECENT_ACTIVATED = 1 << 1, // User tapped URL link recently
RECENT_BOOKMARKED = 1 << 2 // User bookmarked URL recently
};
/**
* Returns any recent activity done with a URL.
* @return Any recent events associated with this URI. Each bit is set
* according to RecentEventFlags enum values.
*/
PRUint32 GetRecentFlags(nsIURI *aURI);
mozIStorageStatement* GetStatementById(
enum mozilla::places::HistoryStatementId aStatementId
)
@ -406,10 +430,41 @@ public:
return mDBGetTags;
case DB_IS_PAGE_VISITED:
return mDBIsPageVisited;
case DB_INSERT_VISIT:
return mDBInsertVisit;
case DB_RECENT_VISIT_OF_URL:
return mDBRecentVisitOfURL;
case DB_GET_PAGE_VISIT_STATS:
return mDBGetPageVisitStats;
case DB_UPDATE_PAGE_VISIT_STATS:
return mDBUpdatePageVisitStats;
case DB_ADD_NEW_PAGE:
return mDBAddNewPage;
case DB_GET_URL_PAGE_INFO:
return mDBGetURLPageInfo;
case DB_SET_PLACE_TITLE:
return mDBSetPlaceTitle;
}
return nsnull;
}
PRInt64 GetNewSessionID();
/**
* Fires onVisit event to nsINavHistoryService observers
*/
void NotifyOnVisit(nsIURI* aURI,
PRInt64 aVisitID,
PRTime aTime,
PRInt64 aSessionID,
PRInt64 referringVisitID,
PRInt32 aTransitionType);
/**
* Fires onTitleChanged event to nsINavHistoryService observers
*/
void NotifyTitleChange(nsIURI* aURI, const nsString& title);
private:
~nsNavHistory();
@ -687,7 +742,6 @@ protected:
// Sessions tracking.
PRInt64 mLastSessionID;
PRInt64 GetNewSessionID();
#ifdef MOZ_XUL
// AutoComplete stuff

View File

@ -47,6 +47,8 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_bug399606.js \
browser_visituri.js \
browser_settitle.js \
$(NULL)
# These are files that need to be loaded via the HTTP proxy server
@ -58,6 +60,12 @@ _HTTP_FILES = \
bug_399606/399606-window.location.href.html \
bug_399606/399606-window.location.html \
bug_399606/399606-history.go-0.html \
visituri/begin.html \
visituri/redirect_twice.sjs \
visituri/redirect_once.sjs \
visituri/final.html \
settitle/title1.html \
settitle/title2.html \
$(NULL)
libs:: $(_BROWSER_FILES)

View File

@ -47,6 +47,9 @@
#include "nsINavHistoryService.h"
#include "nsIObserverService.h"
#include "mozilla/IHistory.h"
#include "mozIStorageConnection.h"
#include "mozIStorageStatement.h"
#include "nsPIPlacesDatabase.h"
using namespace mozilla;
@ -117,6 +120,21 @@ addURI(nsIURI* aURI)
do_check_success(rv);
}
struct PlaceRecord
{
PRInt64 id;
PRInt32 hidden;
PRInt32 typed;
PRInt32 visitCount;
};
struct VisitRecord
{
PRInt64 id;
PRInt64 lastVisitId;
PRInt32 transitionType;
};
already_AddRefed<IHistory>
do_get_IHistory()
{
@ -124,3 +142,107 @@ do_get_IHistory()
do_check_true(history);
return history.forget();
}
already_AddRefed<nsINavHistoryService>
do_get_NavHistory()
{
nsCOMPtr<nsINavHistoryService> serv =
do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID);
do_check_true(serv);
return serv.forget();
}
already_AddRefed<mozIStorageConnection>
do_get_db()
{
nsCOMPtr<nsINavHistoryService> history = do_get_NavHistory();
nsCOMPtr<nsPIPlacesDatabase> database = do_QueryInterface(history);
do_check_true(database);
mozIStorageConnection* dbConn;
nsresult rv = database->GetDBConnection(&dbConn);
do_check_success(rv);
return dbConn;
}
/**
* Get the place record from the database.
*
* @param aURI The unique URI of the place we are looking up
* @param result Out parameter where the result is stored
*/
void
do_get_place(nsIURI* aURI, PlaceRecord& result)
{
nsCOMPtr<mozIStorageConnection> dbConn = do_get_db();
nsCOMPtr<mozIStorageStatement> stmt;
nsCString spec;
nsresult rv = aURI->GetSpec(spec);
do_check_success(rv);
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, hidden, typed, visit_count FROM moz_places_temp "
"WHERE url=?1 "
"UNION ALL "
"SELECT id, hidden, typed, visit_count FROM moz_places "
"WHERE url=?1 "
"LIMIT 1"
), getter_AddRefs(stmt));
do_check_success(rv);
rv = stmt->BindUTF8StringParameter(0, spec);
do_check_success(rv);
PRBool hasResults;
rv = stmt->ExecuteStep(&hasResults);
do_check_true(hasResults);
do_check_success(rv);
rv = stmt->GetInt64(0, &result.id);
do_check_success(rv);
rv = stmt->GetInt32(1, &result.hidden);
do_check_success(rv);
rv = stmt->GetInt32(2, &result.typed);
do_check_success(rv);
rv = stmt->GetInt32(3, &result.visitCount);
do_check_success(rv);
}
/**
* Gets the most recent visit to a place.
*
* @param placeID ID from the moz_places table
* @param result Out parameter where visit is stored
*/
void
do_get_lastVisit(PRInt64 placeId, VisitRecord& result)
{
nsCOMPtr<mozIStorageConnection> dbConn = do_get_db();
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, from_visit, visit_type FROM moz_historyvisits_temp "
"WHERE place_id=?1 "
"UNION ALL "
"SELECT id, from_visit, visit_type FROM moz_historyvisits "
"WHERE place_id=?1 "
"LIMIT 1"
), getter_AddRefs(stmt));
do_check_success(rv);
rv = stmt->BindInt64Parameter(0, placeId);
do_check_success(rv);
PRBool hasResults;
rv = stmt->ExecuteStep(&hasResults);
do_check_true(hasResults);
do_check_success(rv);
rv = stmt->GetInt64(0, &result.id);
do_check_success(rv);
rv = stmt->GetInt64(1, &result.lastVisitId);
do_check_success(rv);
rv = stmt->GetInt32(2, &result.transitionType);
do_check_success(rv);
}

View File

@ -38,6 +38,7 @@
* ***** END LICENSE BLOCK ***** */
#include "places_test_harness.h"
#include "nsIBrowserHistory.h"
#include "mock_Link.h"
using namespace mozilla::dom;
@ -76,6 +77,53 @@ new_test_uri()
return testURI.forget();
}
class VisitURIObserver : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
VisitURIObserver(int aExpectedVisits = 1) :
mVisits(0),
mExpectedVisits(aExpectedVisits)
{
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
do_check_true(observerService);
(void)observerService->AddObserver(this,
"uri-visit-saved",
PR_FALSE);
}
void WaitForNotification()
{
while (mVisits < mExpectedVisits) {
(void)NS_ProcessNextEvent();
}
}
NS_IMETHOD Observe(nsISupports* aSubject,
const char* aTopic,
const PRUnichar* aData)
{
mVisits++;
if (mVisits == mExpectedVisits) {
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
(void)observerService->RemoveObserver(this, "uri-visit-saved");
}
return NS_OK;
}
private:
int mVisits;
int mExpectedVisits;
};
NS_IMPL_ISUPPORTS1(
VisitURIObserver,
nsIObserver
)
////////////////////////////////////////////////////////////////////////////////
//// Test Functions
@ -363,6 +411,145 @@ test_observer_topic_dispatched()
run_next_test();
}
void
test_visituri_inserts()
{
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
do_get_place(visitedURI, place);
do_check_true(place.id > 0);
do_check_false(place.hidden);
do_check_false(place.typed);
do_check_true(place.visitCount == 1);
run_next_test();
}
void
test_visituri_updates()
{
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
nsCOMPtr<VisitURIObserver> finisher;
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
finisher = new VisitURIObserver();
finisher->WaitForNotification();
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
do_get_place(visitedURI, place);
do_check_true(place.visitCount == 2);
run_next_test();
}
void
test_visituri_preserves_shown_and_typed()
{
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
// this simulates the uri visit happening in a frame. Normally frame
// transitions would be hidden unless it was previously loaded top-level
history->VisitURI(visitedURI, lastURI, 0);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver(2);
finisher->WaitForNotification();
PlaceRecord place;
do_get_place(visitedURI, place);
do_check_false(place.hidden);
run_next_test();
}
void
test_visituri_creates_visit()
{
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
VisitRecord visit;
do_get_place(visitedURI, place);
do_get_lastVisit(place.id, visit);
do_check_true(visit.id > 0);
do_check_true(visit.lastVisitId == 0);
do_check_true(visit.transitionType == nsINavHistoryService::TRANSITION_LINK);
run_next_test();
}
void
test_visituri_transition_typed()
{
nsCOMPtr<nsINavHistoryService> navHistory = do_get_NavHistory();
nsCOMPtr<nsIBrowserHistory> browserHistory = do_QueryInterface(navHistory);
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
browserHistory->MarkPageAsTyped(visitedURI);
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
VisitRecord visit;
do_get_place(visitedURI, place);
do_get_lastVisit(place.id, visit);
do_check_true(visit.transitionType == nsINavHistoryService::TRANSITION_TYPED);
run_next_test();
}
void
test_visituri_transition_embed()
{
nsCOMPtr<nsINavHistoryService> navHistory = do_get_NavHistory();
nsCOMPtr<nsIBrowserHistory> browserHistory = do_QueryInterface(navHistory);
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
history->VisitURI(visitedURI, lastURI, 0);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
VisitRecord visit;
do_get_place(visitedURI, place);
do_get_lastVisit(place.id, visit);
do_check_true(visit.transitionType == nsINavHistoryService::TRANSITION_EMBED);
run_next_test();
}
////////////////////////////////////////////////////////////////////////////////
//// Test Harness
@ -378,6 +565,12 @@ Test gTests[] = {
TEST(test_new_visit_notifies_waiting_Link),
TEST(test_RegisterVisitedCallback_returns_before_notifying),
TEST(test_observer_topic_dispatched),
TEST(test_visituri_inserts),
TEST(test_visituri_updates),
TEST(test_visituri_preserves_shown_and_typed),
TEST(test_visituri_creates_visit),
TEST(test_visituri_transition_typed),
TEST(test_visituri_transition_embed),
};
const char* file = __FILE__;

View File

@ -53,10 +53,10 @@ WindowDraggingElement.prototype = {
"radiogroup", "deck", "scrollbox", "arrowscrollbox", "tabs"],
shouldDrag: function(aEvent) {
if (aEvent.button != 0 ||
this._window.fullScreen ||
!this.mouseDownCheck.call(this._elem, aEvent) ||
aEvent.getPreventDefault())
return false;
this._window.fullScreen ||
!this.mouseDownCheck.call(this._elem, aEvent) ||
aEvent.getPreventDefault())
return false;
// Maybe we have been removed from the document
if (!this._elem._alive)
@ -80,9 +80,8 @@ WindowDraggingElement.prototype = {
},
handleEvent: function(aEvent) {
#ifdef XP_WIN
if (this.shouldDrag(aEvent)) {
aEvent.preventDefault();
}
if (this.shouldDrag(aEvent))
aEvent.preventDefault();
#else
switch (aEvent.type) {
case "mousedown":

View File

@ -165,8 +165,9 @@
if (!this._draggableStarted) {
this._draggableStarted = true;
try {
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm");
new WindowDraggingElement(this, window);
let tmp = {};
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
new tmp.WindowDraggingElement(this, window);
} catch (e) {}
}
</constructor>
@ -270,8 +271,9 @@
if (!this._draggableStarted) {
this._draggableStarted = true;
try {
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm");
new WindowDraggingElement(this, window);
let tmp = {};
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
new tmp.WindowDraggingElement(this, window);
} catch (e) {}
}
</constructor>

View File

@ -445,8 +445,9 @@
if (!this._draggableStarted) {
this._draggableStarted = true;
try {
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm");
let draggableThis = new WindowDraggingElement(this, window);
let tmp = {};
Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp);
let draggableThis = new tmp.WindowDraggingElement(this, window);
draggableThis.mouseDownCheck = function(e) {
// Don't move while customizing.
return !this.parentNode.customizing;

View File

@ -1,58 +1,68 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Tests the Preferences button for addons in list view
*/
function test() {
waitForExplicitFinish();
var addonPrefsURI = TESTROOT + "addon_prefs.xul";
var gProvider = new MockProvider();
gProvider.createAddons([{
id: "test1@tests.mozilla.org",
name: "Test add-on 1",
description: "foo"
},
{
id: "test2@tests.mozilla.org",
name: "Test add-on 2",
description: "bar",
optionsURL: addonPrefsURI
}]);
open_manager(null, function(aWindow) {
var addonList = aWindow.document.getElementById("addon-list");
var addonItem = addonList.childNodes[0];
var prefsBtn = aWindow.document.getAnonymousElementByAttribute(addonItem,
"anonid",
"preferences-btn");
is(prefsBtn.hidden, true, "Prefs button should be hidden for addon with no optionsURL set")
addonItem = addonList.childNodes[1];
prefsBtn = aWindow.document.getAnonymousElementByAttribute(addonItem,
"anonid",
"preferences-btn");
is(prefsBtn.hidden, false, "Prefs button should be shown for addon with a optionsURL set")
Services.ww.registerNotification(function(aSubject, aTopic, aData) {
if (aTopic == "domwindowclosed") {
Services.ww.unregisterNotification(arguments.callee);
} else if (aTopic == "domwindowopened") {
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.documentURI, addonPrefsURI, "The correct addon pref window should open"
waitForFocus(function() {
win.close();
aWindow.close();
finish();
}, win);
}
});
EventUtils.synthesizeMouse(prefsBtn, 2, 2, { }, aWindow);
});
}
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Tests the Preferences button for addons in list view
*/
function test() {
waitForExplicitFinish();
var addonPrefsURI = TESTROOT + "addon_prefs.xul";
var gProvider = new MockProvider();
gProvider.createAddons([{
id: "test1@tests.mozilla.org",
name: "Test add-on 1",
description: "foo"
},
{
id: "test2@tests.mozilla.org",
name: "Test add-on 2",
description: "bar",
optionsURL: addonPrefsURI
}]);
open_manager(null, function(aWindow) {
var addonList = aWindow.document.getElementById("addon-list");
for (var i = 0; i < addonList.childNodes.length; i++) {
var addonItem = addonList.childNodes[i];
if (addonItem.hasAttribute("name") &&
addonItem.getAttribute("name") == "Test add-on 1")
break;
}
var prefsBtn = aWindow.document.getAnonymousElementByAttribute(addonItem,
"anonid",
"preferences-btn");
is(prefsBtn.hidden, true, "Prefs button should be hidden for addon with no optionsURL set")
for (i = 0; i < addonList.childNodes.length; i++) {
addonItem = addonList.childNodes[i];
if (addonItem.hasAttribute("name") &&
addonItem.getAttribute("name") == "Test add-on 2")
break;
}
prefsBtn = aWindow.document.getAnonymousElementByAttribute(addonItem,
"anonid",
"preferences-btn");
is(prefsBtn.hidden, false, "Prefs button should be shown for addon with a optionsURL set")
Services.ww.registerNotification(function(aSubject, aTopic, aData) {
if (aTopic == "domwindowclosed") {
Services.ww.unregisterNotification(arguments.callee);
} else if (aTopic == "domwindowopened") {
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.documentURI, addonPrefsURI, "The correct addon pref window should open"
waitForFocus(function() {
win.close();
aWindow.close();
finish();
}, win);
}
});
EventUtils.synthesizeMouse(prefsBtn, 2, 2, { }, aWindow);
});
}

View File

@ -83,6 +83,7 @@ jmethodID AndroidLocation::jGetTimeMethod = 0;
jclass AndroidGeckoSurfaceView::jGeckoSurfaceViewClass = 0;
jmethodID AndroidGeckoSurfaceView::jBeginDrawingMethod = 0;
jmethodID AndroidGeckoSurfaceView::jEndDrawingMethod = 0;
jmethodID AndroidGeckoSurfaceView::jDraw2DMethod = 0;
jmethodID AndroidGeckoSurfaceView::jGetSoftwareDrawBufferMethod = 0;
jmethodID AndroidGeckoSurfaceView::jGetHolderMethod = 0;
@ -147,6 +148,7 @@ AndroidGeckoSurfaceView::InitGeckoSurfaceViewClass(JNIEnv *jEnv)
jBeginDrawingMethod = getMethod("beginDrawing", "()I");
jGetSoftwareDrawBufferMethod = getMethod("getSoftwareDrawBuffer", "()Ljava/nio/ByteBuffer;");
jEndDrawingMethod = getMethod("endDrawing", "()V");
jDraw2DMethod = getMethod("draw2D", "(Ljava/nio/ByteBuffer;)V");
jGetHolderMethod = getMethod("getHolder", "()Landroid/view/SurfaceHolder;");
}
@ -361,23 +363,16 @@ AndroidGeckoSurfaceView::EndDrawing()
JNI()->CallVoidMethod(wrapped_obj, jEndDrawingMethod);
}
unsigned char *
AndroidGeckoSurfaceView::GetSoftwareDrawBuffer(int *cap)
void
AndroidGeckoSurfaceView::Draw2D(jobject buffer)
{
jobject buf = JNI()->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod);
if (!buf)
return nsnull;
JNI()->CallVoidMethod(wrapped_obj, jDraw2DMethod, buffer);
}
void *bp = JNI()->GetDirectBufferAddress(buf);
jlong blen = JNI()->GetDirectBufferCapacity(buf);
if (!bp || blen == -1)
return nsnull;
if (cap)
*cap = blen;
return (unsigned char*) bp;
jobject
AndroidGeckoSurfaceView::GetSoftwareDrawBuffer()
{
return JNI()->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod);
}
jobject

View File

@ -163,13 +163,13 @@ public:
enum {
DRAW_ERROR = 0,
DRAW_GLES_2 = 1,
DRAW_SOFTWARE = 2
DRAW_GLES_2 = 1
};
int BeginDrawing();
unsigned char *GetSoftwareDrawBuffer(int *cap);
jobject GetSoftwareDrawBuffer();
void EndDrawing();
void Draw2D(jobject buffer);
// must have a JNI local frame when calling this,
// and you'd better know what you're doing
@ -179,6 +179,7 @@ protected:
static jclass jGeckoSurfaceViewClass;
static jmethodID jBeginDrawingMethod;
static jmethodID jEndDrawingMethod;
static jmethodID jDraw2DMethod;
static jmethodID jGetSoftwareDrawBufferMethod;
static jmethodID jGetHolderMethod;
};

View File

@ -584,8 +584,7 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
int nh = ae->P0().y;
if (nw == gAndroidBounds.width &&
nh == gAndroidBounds.height)
{
nh == gAndroidBounds.height) {
return;
}
@ -687,12 +686,12 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
if (coveringChildIndex == -1) {
ALOG("nsWindow[%p]::DrawTo no covering child, drawing this", (void*) this);
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.region = boundsRect;
switch (GetLayerManager()->GetBackendType()) {
case LayerManager::LAYERS_BASIC: {
nsRefPtr<gfxContext> ctx = new gfxContext(targetSurface);
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.region = boundsRect;
{
AutoLayerManagerSetup setupLayerManager(this, ctx);
status = DispatchEvent(&event);
@ -707,19 +706,16 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
// XXX if we got an ignore for the parent, do we still want to draw the children?
// We don't really have a good way not to...
}
break;
}
case LayerManager::LAYERS_OPENGL: {
static_cast<mozilla::layers::LayerManagerOGL*>(GetLayerManager())->
SetClippingRegion(nsIntRegion(boundsRect));
nsPaintEvent event(PR_TRUE, NS_PAINT, this);
event.region = boundsRect;
status = DispatchEvent(&event);
}
break;
}
default:
NS_ERROR("Invalid layer manager");
@ -737,8 +733,7 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
for (PRUint32 i = coveringChildIndex; i < mChildren.Length(); ++i) {
if (mChildren[i]->mBounds.IsEmpty() ||
!mChildren[i]->mBounds.Intersects(boundsRect))
{
!mChildren[i]->mBounds.Intersects(boundsRect)) {
continue;
}
@ -759,20 +754,6 @@ nsWindow::DrawTo(gfxASurface *targetSurface)
return PR_TRUE;
}
static int
next_power_of_two(int v)
{
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
void
nsWindow::OnDraw(AndroidGeckoEvent *ae)
{
@ -798,43 +779,36 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
return;
}
int drawType = sview.BeginDrawing();
if (drawType == AndroidGeckoSurfaceView::DRAW_ERROR) {
ALOG("##### BeginDrawing failed!");
return;
}
if (GetLayerManager()->GetBackendType() == LayerManager::LAYERS_BASIC) {
drawType = AndroidGeckoSurfaceView::DRAW_SOFTWARE;
} else {
drawType = AndroidGeckoSurfaceView::DRAW_GLES_2;
}
jobject bytebuf = sview.GetSoftwareDrawBuffer();
if (!bytebuf) {
ALOG("no buffer to draw into - skipping draw");
return;
}
if (drawType == AndroidGeckoSurfaceView::DRAW_SOFTWARE) {
int bufCap;
unsigned char *buf = sview.GetSoftwareDrawBuffer(&bufCap);
if (!buf || bufCap != mBounds.width * mBounds.height * 4) {
ALOG("### Software drawing, but too small a buffer %d expected %d (or no buffer %p)!", bufCap, mBounds.width * mBounds.height * 4, (void*)buf);
sview.EndDrawing();
void *buf = AndroidBridge::JNI()->GetDirectBufferAddress(bytebuf);
int cap = AndroidBridge::JNI()->GetDirectBufferCapacity(bytebuf);
if (!buf || cap < (mBounds.width * mBounds.height * 2)) {
ALOG("### Software drawing, but too small a buffer %d expected %d (or no buffer %p)!", cap, mBounds.width * mBounds.height * 2, buf);
return;
}
nsRefPtr<gfxImageSurface> targetSurface =
new gfxImageSurface(buf,
new gfxImageSurface((unsigned char *)buf,
gfxIntSize(mBounds.width, mBounds.height),
mBounds.width * 4,
gfxASurface::ImageFormatARGB32);
mBounds.width * 2,
gfxASurface::ImageFormatRGB16_565);
DrawTo(targetSurface);
sview.Draw2D(bytebuf);
} else {
int drawType = sview.BeginDrawing();
// need to swap B and R channels, to get ABGR instead of ARGB
unsigned int *ibuf = (unsigned int*) buf;
unsigned int *ibufMax = ibuf + mBounds.width * mBounds.height;
while (ibuf < ibufMax) {
*ibuf++ = (*ibuf & 0xff00ff00) | ((*ibuf & 0x00ff0000) >> 16) | ((*ibuf & 0x000000ff) << 16);
if (drawType == AndroidGeckoSurfaceView::DRAW_ERROR) {
ALOG("##### BeginDrawing failed!");
return;
}
} else if (drawType == AndroidGeckoSurfaceView::DRAW_GLES_2) {
NS_ASSERTION(sGLContext, "Drawing with GLES without a GL context?");
sGLContext->fClear(LOCAL_GL_COLOR_BUFFER_BIT | LOCAL_GL_DEPTH_BUFFER_BIT);
@ -843,9 +817,8 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
if (sGLContext)
sGLContext->SwapBuffers();
sview.EndDrawing();
}
sview.EndDrawing();
}
void

View File

@ -113,6 +113,7 @@ LOCAL_INCLUDES = \
-I$(srcdir)/../threads/_xpidlgen \
-I$(srcdir)/../proxy/src \
-I$(srcdir)/../reflect/xptinfo/src \
-I$(srcdir)/../../docshell/base \
$(NULL)
EXPORTS_NAMESPACES = mozilla

View File

@ -5,3 +5,14 @@ MOZ_SERVICE(XULOverlayProviderService, nsIXULOverlayProvider, "@mozilla.org/chro
MOZ_SERVICE(IOService, nsIIOService, "@mozilla.org/network/io-service;1")
MOZ_SERVICE(ObserverService, nsIObserverService, "@mozilla.org/observer-service;1")
MOZ_SERVICE(StringBundleService, nsIStringBundleService, "@mozilla.org/intl/stringbundle;1")
#ifdef MOZ_USE_NAMESPACE
namespace mozilla
{
#endif
MOZ_SERVICE(HistoryService, IHistory, "@mozilla.org/browser/history;1")
#ifdef MOZ_USE_NAMESPACE
}
#endif

View File

@ -48,7 +48,9 @@
#include "nsIStringBundle.h"
#include "nsIToolkitChromeRegistry.h"
#include "nsIXULOverlayProvider.h"
#include "IHistory.h"
using namespace mozilla;
using namespace mozilla::services;
/*

View File

@ -42,9 +42,12 @@
#include "nscore.h"
#include "nsCOMPtr.h"
#define MOZ_USE_NAMESPACE
#define MOZ_SERVICE(NAME, TYPE, SERVICE_CID) class TYPE;
#include "ServiceList.h"
#undef MOZ_SERVICE
#undef MOZ_USE_NAMESPACE
namespace mozilla {
namespace services {