From c53ac18e413609af823278cf322d9d351c9528ed Mon Sep 17 00:00:00 2001 From: Javi Rueda Date: Thu, 20 Oct 2011 09:51:44 +0200 Subject: [PATCH 01/42] Bug 448717 - Firefox improperly names html file type "Firefox Document". r=rstrong --- browser/installer/windows/nsis/shared.nsh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser/installer/windows/nsis/shared.nsh b/browser/installer/windows/nsis/shared.nsh index a0aadd113a1..5208d8fc582 100755 --- a/browser/installer/windows/nsis/shared.nsh +++ b/browser/installer/windows/nsis/shared.nsh @@ -289,7 +289,7 @@ ; An empty string is used for the 5th param because FirefoxHTML is not a ; protocol handler - ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} Document" "" \ + ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} HTML Document" "" \ "${DDEApplication}" "$3" "WWW_OpenURL" ${AddDDEHandlerValues} "FirefoxURL" "$2" "$8,1" "${AppRegName} URL" "true" \ @@ -509,7 +509,7 @@ ${If} "$R9" == "true" ; An empty string is used for the 5th param because FirefoxHTML is not a ; protocol handler. - ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} Document" "" \ + ${AddDDEHandlerValues} "FirefoxHTML" "$2" "$8,1" "${AppRegName} HTML Document" "" \ "${DDEApplication}" "$3" "WWW_OpenURL" ${EndIf} From f0c25c3b32ec0dbea59e5d5c23b2fa41706c8d3e Mon Sep 17 00:00:00 2001 From: "jhorak@redhat.com" Date: Thu, 20 Oct 2011 09:55:18 +0200 Subject: [PATCH 02/42] Bug 694261 - link xpcshell against jemalloc on ia64. r=bz --- js/xpconnect/shell/Makefile.in | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/xpconnect/shell/Makefile.in b/js/xpconnect/shell/Makefile.in index f5c3fdd3c71..37c58fdde77 100644 --- a/js/xpconnect/shell/Makefile.in +++ b/js/xpconnect/shell/Makefile.in @@ -74,6 +74,9 @@ WIN32_EXE_LDFLAGS += -STACK:2097152 endif endif +ifeq ($(OS_TEST),ia64) +LIBS += $(JEMALLOC_LIBS) +endif include $(topsrcdir)/config/config.mk include $(topsrcdir)/ipc/chromium/chromium-config.mk include $(topsrcdir)/config/rules.mk From c5e0ed5349e4e342add4d9e1b94accb703ccad3e Mon Sep 17 00:00:00 2001 From: Matheus Kerschbaum Date: Thu, 20 Oct 2011 09:57:36 +0200 Subject: [PATCH 03/42] Bug 694722 - Remove support code for obsolete platforms from js/src/Makefile.in r=ted --- js/src/Makefile.in | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/js/src/Makefile.in b/js/src/Makefile.in index ca60f5fa4f2..b641d17fb27 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -820,9 +820,6 @@ endif ifeq ($(OS_ARCH),Linux) EXTRA_LIBS += -ldl endif -ifeq ($(OS_ARCH),OSF1) -EXTRA_LIBS += -lc_r -endif # Silence warnings on AIX/HP-UX from non-GNU compilers ifndef GNU_CC ifeq ($(OS_ARCH),AIX) @@ -908,19 +905,8 @@ ifdef CROSS_COMPILE JSCPUCFG_DEFINES = $(ACDEFINES) endif -ifeq ($(OS_ARCH),QNX) -ifneq ($(OS_TARGET),NTO) -# QNX's compiler apparently can't build a binary directly from a source file. -jscpucfg.o: jscpucfg.cpp Makefile.in - $(HOST_CXX) $(HOST_CXXFLAGS) -c $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) -o $@ $< - -jscpucfg: jscpucfg.o - $(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) -o $@ $< -endif -else jscpucfg$(HOST_BIN_SUFFIX): jscpucfg.cpp Makefile.in $(HOST_CXX) $(HOST_CXXFLAGS) $(JSCPUCFG_DEFINES) $(DEFINES) $(NSPR_CFLAGS) $(HOST_OUTOPTION)$@ $< -endif # Compute the linker flags that programs linking against SpiderMonkey should # pass to get SpiderMonkey and its dependencies, beyond just the -L and -l From d36e6f2d7b9183aa9d0bafb4803383f69d15994a Mon Sep 17 00:00:00 2001 From: Geoff Lankow Date: Wed, 19 Oct 2011 10:59:27 +1300 Subject: [PATCH 04/42] Bug 675371 - load/unload chrome.manifest files for bootstrapped addons automatically; r=dtownsend --- toolkit/mozapps/extensions/XPIProvider.jsm | 51 ++++++----- .../addons/test_bug675371/chrome.manifest | 1 + .../test/addons/test_bug675371/install.rdf | 24 +++++ .../test/addons/test_bug675371/test.js | 1 + .../test/xpcshell/test_bug675371.js | 91 +++++++++++++++++++ .../extensions/test/xpcshell/xpcshell.ini | 1 + 6 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf create mode 100644 toolkit/mozapps/extensions/test/addons/test_bug675371/test.js create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm index 33aa184825a..04dd2846e2e 100644 --- a/toolkit/mozapps/extensions/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/XPIProvider.jsm @@ -3552,30 +3552,39 @@ var XPIProvider = { if (Services.appinfo.inSafeMode) return; - // Load the scope if it hasn't already been loaded - if (!(aId in this.bootstrapScopes)) - this.loadBootstrapScope(aId, aFile, aVersion, aType); + if (aMethod == "startup") + Components.manager.addBootstrappedManifestLocation(aFile); - if (!(aMethod in this.bootstrapScopes[aId])) { - WARN("Add-on " + aId + " is missing bootstrap method " + aMethod); - return; - } - - let params = { - id: aId, - version: aVersion, - installPath: aFile.clone(), - resourceURI: getURIForResourceInFile(aFile, "") - }; - - LOG("Calling bootstrap method " + aMethod + " on " + aId + " version " + - aVersion); try { - this.bootstrapScopes[aId][aMethod](params, aReason); + // Load the scope if it hasn't already been loaded + if (!(aId in this.bootstrapScopes)) + this.loadBootstrapScope(aId, aFile, aVersion, aType); + + if (!(aMethod in this.bootstrapScopes[aId])) { + WARN("Add-on " + aId + " is missing bootstrap method " + aMethod); + return; + } + + let params = { + id: aId, + version: aVersion, + installPath: aFile.clone(), + resourceURI: getURIForResourceInFile(aFile, "") + }; + + LOG("Calling bootstrap method " + aMethod + " on " + aId + " version " + + aVersion); + try { + this.bootstrapScopes[aId][aMethod](params, aReason); + } + catch (e) { + WARN("Exception running bootstrap method " + aMethod + " on " + + aId, e); + } } - catch (e) { - WARN("Exception running bootstrap method " + aMethod + " on " + - aId, e); + finally { + if (aMethod == "shutdown") + Components.manager.removeBootstrappedManifestLocation(aFile); } }, diff --git a/toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest b/toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest new file mode 100644 index 00000000000..17d5c99ec45 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_bug675371/chrome.manifest @@ -0,0 +1 @@ +content bug675371 . diff --git a/toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf b/toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf new file mode 100644 index 00000000000..ca2881e5ac1 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_bug675371/install.rdf @@ -0,0 +1,24 @@ + + + + + + bug675371@tests.mozilla.org + 1.0 + true + + + Bug 675371 Test + Test Description + + + + xpcshell@tests.mozilla.org + 1 + 1 + + + + + diff --git a/toolkit/mozapps/extensions/test/addons/test_bug675371/test.js b/toolkit/mozapps/extensions/test/addons/test_bug675371/test.js new file mode 100644 index 00000000000..ae74c174d80 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_bug675371/test.js @@ -0,0 +1 @@ +active = true; diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js b/toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js new file mode 100644 index 00000000000..270825f58c9 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_bug675371.js @@ -0,0 +1,91 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +function run_test() { + do_test_pending(); + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + startupManager(); + + prepare_test({ }, [ + "onNewInstall" + ]); + + AddonManager.getInstallForFile(do_get_addon("test_bug675371"), function(install) { + ensure_test_completed(); + + do_check_neq(install, null); + + prepare_test({ + "bug675371@tests.mozilla.org": [ + ["onInstalling", false], + "onInstalled" + ] + }, [ + "onInstallStarted", + "onInstallEnded", + ], check_test); + install.install(); + }); +} + +function check_test() { + AddonManager.getAddonByID("bug675371@tests.mozilla.org", function(addon) { + do_check_neq(addon, null); + do_check_true(addon.isActive); + + // Tests that chrome.manifest is registered when the addon is installed. + var target = { active: false }; + Services.scriptloader.loadSubScript("chrome://bug675371/content/test.js", target); + do_check_true(target.active); + + prepare_test({ + "bug675371@tests.mozilla.org": [ + ["onDisabling", false], + "onDisabled" + ] + }); + + // Tests that chrome.manifest is unregistered when the addon is disabled. + addon.userDisabled = true; + target.active = false; + try { + Services.scriptloader.loadSubScript("chrome://bug675371/content/test.js", target); + do_throw("Chrome file should not have been found"); + } catch (e) { + do_check_false(target.active); + } + + prepare_test({ + "bug675371@tests.mozilla.org": [ + ["onEnabling", false], + "onEnabled" + ] + }); + + // Tests that chrome.manifest is registered when the addon is enabled. + addon.userDisabled = false; + target.active = false; + Services.scriptloader.loadSubScript("chrome://bug675371/content/test.js", target); + do_check_true(target.active); + + prepare_test({ + "bug675371@tests.mozilla.org": [ + ["onUninstalling", false], + "onUninstalled" + ] + }); + + // Tests that chrome.manifest is unregistered when the addon is uninstalled. + addon.uninstall(); + target.active = false; + try { + Services.scriptloader.loadSubScript("chrome://bug675371/content/test.js", target); + do_throw("Chrome file should not have been found"); + } catch (e) { + do_check_false(target.active); + } + + do_test_finished(); + }); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini index c3b57d04644..5d5db49342b 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini @@ -117,6 +117,7 @@ fail-if = os == "android" [test_bug620837.js] [test_bug655254.js] [test_bug659772.js] +[test_bug675371.js] [test_cacheflush.js] [test_checkcompatibility.js] [test_corrupt.js] From e86f414e30558cdeb864ee8ec2b36f36e18db789 Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Thu, 20 Oct 2011 10:08:59 +0200 Subject: [PATCH 05/42] Bug 695102 - fix a comment typo. r=cpearce --- content/media/nsBuiltinDecoderReader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/media/nsBuiltinDecoderReader.h b/content/media/nsBuiltinDecoderReader.h index 00a002ee026..f846cec9518 100644 --- a/content/media/nsBuiltinDecoderReader.h +++ b/content/media/nsBuiltinDecoderReader.h @@ -385,7 +385,7 @@ private: }; // Encapsulates the decoding and reading of media data. Reading can only be -// done on the decode thread thread. Never hold the decoder monitor when +// done on the decode thread. Never hold the decoder monitor when // calling into this class. Unless otherwise specified, methods and fields of // this class can only be accessed on the decode thread. class nsBuiltinDecoderReader : public nsRunnable { From 5d17969b844f50b9497b7afe0065aef0d51d5a1c Mon Sep 17 00:00:00 2001 From: "Kang-Hao (Kenny) Lu" Date: Thu, 20 Oct 2011 10:09:33 +0200 Subject: [PATCH 06/42] Bug695538 - Make sure that trailing spaces don't get dropped by nsCSSFrameConstructor::CreateNeededTablePseudos in certain cases. r=bz --- layout/base/nsCSSFrameConstructor.cpp | 12 ++++++++--- .../table-anonymous-boxes/695538-1-ref.html | 21 +++++++++++++++++++ .../table-anonymous-boxes/695538-1.html | 17 +++++++++++++++ .../table-anonymous-boxes/reftest.list | 1 + 4 files changed, 48 insertions(+), 3 deletions(-) create mode 100644 layout/reftests/table-anonymous-boxes/695538-1-ref.html create mode 100644 layout/reftests/table-anonymous-boxes/695538-1.html diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index fe9afda75a3..3769c8cd408 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -9288,9 +9288,15 @@ nsCSSFrameConstructor::CreateNeededTablePseudos(nsFrameConstructorState& aState, spaceEndIter.item().IsWhitespace(aState)) { bool trailingSpaces = spaceEndIter.SkipWhitespace(aState); - // See whether we can drop the whitespace - if (trailingSpaces || - spaceEndIter.item().DesiredParentType() != eTypeBlock) { + // We drop the whitespace if these are not trailing spaces and the next item + // does not want a block parent (see case 2 above) + // if these are trailing spaces and aParentFrame is a tabular container + // according to rule 1.3 of CSS 2.1 Sec 17.2.1. (Being a tabular container + // pretty much means ourParentType != eTypeBlock besides the eTypeColGroup case, + // which won't reach here.) + if ((trailingSpaces && ourParentType != eTypeBlock) || + (!trailingSpaces && spaceEndIter.item().DesiredParentType() != + eTypeBlock)) { bool updateStart = (iter == endIter); endIter.DeleteItemsTo(spaceEndIter); NS_ASSERTION(trailingSpaces == endIter.IsDone(), "These should match"); diff --git a/layout/reftests/table-anonymous-boxes/695538-1-ref.html b/layout/reftests/table-anonymous-boxes/695538-1-ref.html new file mode 100644 index 00000000000..ead17e75620 --- /dev/null +++ b/layout/reftests/table-anonymous-boxes/695538-1-ref.html @@ -0,0 +1,21 @@ + + + A +B + diff --git a/layout/reftests/table-anonymous-boxes/695538-1.html b/layout/reftests/table-anonymous-boxes/695538-1.html new file mode 100644 index 00000000000..7a5a686725d --- /dev/null +++ b/layout/reftests/table-anonymous-boxes/695538-1.html @@ -0,0 +1,17 @@ + + + A B + diff --git a/layout/reftests/table-anonymous-boxes/reftest.list b/layout/reftests/table-anonymous-boxes/reftest.list index 8c01d1dd1a3..fdbb7e60c2c 100644 --- a/layout/reftests/table-anonymous-boxes/reftest.list +++ b/layout/reftests/table-anonymous-boxes/reftest.list @@ -35,6 +35,7 @@ random-if(d2d) == 394402-1a.html 394402-1-ref.html # bug 586833 == 443616-1b.html 443616-1-ref.html == 448111-1.html 448111-1-ref.html == 490174-1.html 490174-1-ref.html +== 695538-1.html 695538-1-ref.html == infer-first-row.html 3x3-ref.html == infer-first-row-and-table.html 3x3-ref.html == infer-second-row.html 3x3-ref.html From b0c073bb36e9a130755723220f0dde2f6133a4c5 Mon Sep 17 00:00:00 2001 From: Wellington Fernando de Macedo Date: Thu, 20 Oct 2011 01:27:13 -0700 Subject: [PATCH 07/42] Bug 664894. Eliminate nsWebSocketEstablishedConnection and fold code into nsWebSocket. r=jduell --- content/base/src/nsWebSocket.cpp | 628 +++++++----------- content/base/src/nsWebSocket.h | 45 +- content/base/test/test_websocket.html | 6 + .../protocol/websocket/WebSocketChannel.cpp | 82 +-- netwerk/protocol/websocket/WebSocketChannel.h | 8 + 5 files changed, 308 insertions(+), 461 deletions(-) diff --git a/content/base/src/nsWebSocket.cpp b/content/base/src/nsWebSocket.cpp index 5699b4e6348..8a1c9eb9313 100644 --- a/content/base/src/nsWebSocket.cpp +++ b/content/base/src/nsWebSocket.cpp @@ -55,7 +55,6 @@ #include "jsapi.h" #include "nsIURL.h" #include "nsIPrivateDOMEvent.h" -#include "nsIInterfaceRequestor.h" #include "nsICharsetConverterManager.h" #include "nsIUnicodeEncoder.h" #include "nsThreadUtils.h" @@ -73,20 +72,13 @@ #include "nsJSUtils.h" #include "nsIScriptError.h" #include "nsNetUtil.h" -#include "nsIWebSocketChannel.h" -#include "nsIWebSocketListener.h" #include "nsILoadGroup.h" -#include "nsIRequest.h" #include "mozilla/Preferences.h" #include "nsDOMLists.h" #include "xpcpublic.h" using namespace mozilla; -//////////////////////////////////////////////////////////////////////////////// -// nsWebSocketEstablishedConnection -//////////////////////////////////////////////////////////////////////////////// - #define UTF_8_REPLACEMENT_CHAR static_cast(0xFFFD) #define ENSURE_TRUE_AND_FAIL_IF_FAILED(x, ret) \ @@ -108,223 +100,13 @@ using namespace mozilla; } \ PR_END_MACRO -// nsIInterfaceRequestor will be the unambiguous class for this class -class nsWebSocketEstablishedConnection: public nsIInterfaceRequestor, - public nsIWebSocketListener, - public nsIRequest -{ -public: - nsWebSocketEstablishedConnection(); - virtual ~nsWebSocketEstablishedConnection(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSIWEBSOCKETLISTENER - NS_DECL_NSIREQUEST - - nsresult Init(nsWebSocket *aOwner); - nsresult Disconnect(); - - // these method when called can release both the WebSocket object - // (i.e. mOwner) and its connection (i.e. *this*). - nsresult Close(); - nsresult FailConnection(); - nsresult ConsoleError(); - - bool HasOutgoingMessages() - { return mOutgoingBufferedAmount != 0; } - - bool ClosedCleanly() { return mClosedCleanly; } - - nsresult PostMessage(const nsString& aMessage); - PRUint32 GetOutgoingBufferedAmount() { return mOutgoingBufferedAmount; } - -private: - - nsresult PrintErrorOnConsole(const char *aBundleURI, - const PRUnichar *aError, - const PRUnichar **aFormatStrings, - PRUint32 aFormatStringsLen); - nsresult UpdateMustKeepAlive(); - - // Frames that have been sent to websockethandler but not placed on wire - PRUint32 mOutgoingBufferedAmount; - - nsWebSocket* mOwner; // weak reference - nsCOMPtr mWebSocketChannel; - - bool mClosedCleanly; - - enum ConnectionStatus { - CONN_NOT_CONNECTED, - CONN_CONNECTED_AND_READY, - CONN_CLOSED - }; - - ConnectionStatus mStatus; -}; - -//----------------------------------------------------------------------------- -// nsWebSocketEstablishedConnection::nsISupports -//----------------------------------------------------------------------------- - -NS_IMPL_THREADSAFE_ISUPPORTS3(nsWebSocketEstablishedConnection, - nsIInterfaceRequestor, - nsIWebSocketListener, - nsIRequest) - -//----------------------------------------------------------------------------- -// nsWebSocketEstablishedConnection methods: -//----------------------------------------------------------------------------- - -nsWebSocketEstablishedConnection::nsWebSocketEstablishedConnection() : - mOutgoingBufferedAmount(0), - mOwner(nsnull), - mClosedCleanly(false), - mStatus(CONN_NOT_CONNECTED) -{ - NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - nsLayoutStatics::AddRef(); -} - -nsWebSocketEstablishedConnection::~nsWebSocketEstablishedConnection() -{ - NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - NS_ABORT_IF_FALSE(!mOwner, "Disconnect wasn't called!"); - NS_ABORT_IF_FALSE(!mWebSocketChannel, "Disconnect wasn't called!"); -} - nsresult -nsWebSocketEstablishedConnection::PostMessage(const nsString& aMessage) +nsWebSocket::PrintErrorOnConsole(const char *aBundleURI, + const PRUnichar *aError, + const PRUnichar **aFormatStrings, + PRUint32 aFormatStringsLen) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - - if (!mOwner) { - return NS_OK; - } - - // only send messages when connected - NS_ENSURE_STATE(mStatus >= CONN_CONNECTED_AND_READY); - - nsresult rv; - - nsCOMPtr ccm = - do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); - ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); - - nsCOMPtr converter; - rv = ccm->GetUnicodeEncoder("UTF-8", getter_AddRefs(converter)); - ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); - - rv = converter->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, - nsnull, UTF_8_REPLACEMENT_CHAR); - ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); - - PRInt32 inLen = aMessage.Length(); - PRInt32 maxLen; - rv = converter->GetMaxLength(aMessage.BeginReading(), inLen, &maxLen); - ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); - - nsCString buf; - buf.SetLength(maxLen); - ENSURE_TRUE_AND_FAIL_IF_FAILED(buf.Length() == static_cast(maxLen), - NS_ERROR_OUT_OF_MEMORY); - - char* start = buf.BeginWriting(); - - PRInt32 outLen = maxLen; - rv = converter->Convert(aMessage.BeginReading(), &inLen, start, &outLen); - if (NS_SUCCEEDED(rv)) { - PRInt32 outLen2 = maxLen - outLen; - rv = converter->Finish(start + outLen, &outLen2); - outLen += outLen2; - } - if (NS_FAILED(rv) || rv == NS_ERROR_UENC_NOMAPPING) { - // Yes, NS_ERROR_UENC_NOMAPPING is a success code - return NS_ERROR_DOM_SYNTAX_ERR; - } - - buf.SetLength(outLen); - ENSURE_TRUE_AND_FAIL_IF_FAILED(buf.Length() == static_cast(outLen), - NS_ERROR_UNEXPECTED); - - if (mStatus == CONN_CLOSED) { - NS_ABORT_IF_FALSE(mOwner, "Posting data after disconnecting the websocket"); - // the tcp connection has been closed, but the main thread hasn't received - // the event for disconnecting the object yet. - rv = NS_BASE_STREAM_CLOSED; - } else { - mOutgoingBufferedAmount += buf.Length(); - mWebSocketChannel->SendMsg(buf); - rv = NS_OK; - } - - UpdateMustKeepAlive(); - ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); - - return NS_OK; -} - -nsresult -nsWebSocketEstablishedConnection::Init(nsWebSocket *aOwner) -{ - NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - NS_ABORT_IF_FALSE(!mOwner, "WebSocket's connection is already initialized"); - - nsresult rv; - mOwner = aOwner; - - if (mOwner->mSecure) { - mWebSocketChannel = - do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv); - } - else { - mWebSocketChannel = - do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv); - } - NS_ENSURE_SUCCESS(rv, rv); - - rv = mWebSocketChannel->SetNotificationCallbacks(this); - NS_ENSURE_SUCCESS(rv, rv); - - // add ourselves to the document's load group and - // provide the http stack the loadgroup info too - nsCOMPtr loadGroup; - rv = GetLoadGroup(getter_AddRefs(loadGroup)); - if (loadGroup) { - rv = mWebSocketChannel->SetLoadGroup(loadGroup); - NS_ENSURE_SUCCESS(rv, rv); - rv = loadGroup->AddRequest(this, nsnull); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (!mOwner->mRequestedProtocolList.IsEmpty()) { - rv = mWebSocketChannel->SetProtocol(mOwner->mRequestedProtocolList); - NS_ENSURE_SUCCESS(rv, rv); - } - - nsCString asciiOrigin; - rv = nsContentUtils::GetASCIIOrigin(mOwner->mPrincipal, asciiOrigin); - NS_ENSURE_SUCCESS(rv, rv); - - ToLowerCase(asciiOrigin); - - rv = mWebSocketChannel->AsyncOpen(mOwner->mURI, - asciiOrigin, this, nsnull); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -nsresult -nsWebSocketEstablishedConnection::PrintErrorOnConsole(const char *aBundleURI, - const PRUnichar *aError, - const PRUnichar **aFormatStrings, - PRUint32 aFormatStringsLen) -{ - NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - NS_ABORT_IF_FALSE(mOwner, "No owner"); - nsresult rv; nsCOMPtr bundleService = @@ -354,14 +136,12 @@ nsWebSocketEstablishedConnection::PrintErrorOnConsole(const char *aBundleURI, } NS_ENSURE_SUCCESS(rv, rv); - errorObject->InitWithWindowID - (message.get(), - NS_ConvertUTF8toUTF16(mOwner->GetScriptFile()).get(), - nsnull, - mOwner->GetScriptLine(), 0, nsIScriptError::errorFlag, - "Web Socket", mOwner->InnerWindowID() - ); - + errorObject->InitWithWindowID(message.get(), + NS_ConvertUTF8toUTF16(mScriptFile).get(), + nsnull, mScriptLine, 0, + nsIScriptError::errorFlag, "Web Socket", + mInnerWindowID); + // print the error message directly to the JS console nsCOMPtr logError(do_QueryInterface(errorObject)); rv = console->LogMessage(logError); @@ -372,52 +152,49 @@ nsWebSocketEstablishedConnection::PrintErrorOnConsole(const char *aBundleURI, // when this is called the browser side wants no more part of it nsresult -nsWebSocketEstablishedConnection::Close() +nsWebSocket::CloseConnection() { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (!mOwner) + if (mDisconnected) return NS_OK; // Disconnect() can release this object, so we keep a // reference until the end of the method - nsRefPtr kungfuDeathGrip = this; + nsRefPtr kungfuDeathGrip = this; - if (mOwner->mReadyState == nsIMozWebSocket::CONNECTING) { - mOwner->SetReadyState(nsIMozWebSocket::CLOSED); - mWebSocketChannel->Close(mOwner->mClientReasonCode, - mOwner->mClientReason); + if (mReadyState == nsIMozWebSocket::CONNECTING) { + SetReadyState(nsIMozWebSocket::CLOSED); + mWebSocketChannel->Close(mClientReasonCode, mClientReason); Disconnect(); return NS_OK; } - mOwner->SetReadyState(nsIMozWebSocket::CLOSING); + SetReadyState(nsIMozWebSocket::CLOSING); - if (mStatus == CONN_CLOSED) { - mOwner->SetReadyState(nsIMozWebSocket::CLOSED); + if (mDisconnected) { + SetReadyState(nsIMozWebSocket::CLOSED); Disconnect(); return NS_OK; } - return mWebSocketChannel->Close(mOwner->mClientReasonCode, - mOwner->mClientReason); + return mWebSocketChannel->Close(mClientReasonCode, mClientReason); } nsresult -nsWebSocketEstablishedConnection::ConsoleError() +nsWebSocket::ConsoleError() { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); nsresult rv; - if (!mOwner) return NS_OK; - + nsCAutoString targetSpec; - rv = mOwner->mURI->GetSpec(targetSpec); + rv = mURI->GetSpec(targetSpec); if (NS_FAILED(rv)) { NS_WARNING("Failed to get targetSpec"); } else { NS_ConvertUTF8toUTF16 specUTF16(targetSpec); const PRUnichar *formatStrings[] = { specUTF16.get() }; - - if (mStatus < CONN_CONNECTED_AND_READY) { + + if (mReadyState < nsIMozWebSocket::OPEN) { PrintErrorOnConsole("chrome://global/locale/appstrings.properties", NS_LITERAL_STRING("connectionFailure").get(), formatStrings, ArrayLength(formatStrings)); @@ -433,65 +210,58 @@ nsWebSocketEstablishedConnection::ConsoleError() nsresult -nsWebSocketEstablishedConnection::FailConnection() +nsWebSocket::FailConnection() { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - nsresult rv = ConsoleError(); - Close(); - return rv; + ConsoleError(); + + nsresult rv = CloseConnection(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error")); + if (NS_FAILED(rv)) + NS_WARNING("Failed to dispatch the error event"); + + return NS_OK; } nsresult -nsWebSocketEstablishedConnection::Disconnect() +nsWebSocket::Disconnect() { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (!mOwner) { + if (mDisconnected) return NS_OK; - } - + nsCOMPtr loadGroup; GetLoadGroup(getter_AddRefs(loadGroup)); if (loadGroup) loadGroup->RemoveRequest(this, nsnull, NS_OK); - // If mOwner is deleted when calling mOwner->DontKeepAliveAnyMore() - // then this method can be called again, and we will get a deadlock. - nsRefPtr kungfuDeathGrip = mOwner; - - mOwner->DontKeepAliveAnyMore(); - mStatus = CONN_CLOSED; - mOwner = nsnull; + // DontKeepAliveAnyMore() can release the object. So hold a reference to this + // until the end of the method. + nsRefPtr kungfuDeathGrip = this; + + DontKeepAliveAnyMore(); mWebSocketChannel = nsnull; + mDisconnected = true; - nsLayoutStatics::Release(); - return NS_OK; -} - -nsresult -nsWebSocketEstablishedConnection::UpdateMustKeepAlive() -{ - NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - NS_ABORT_IF_FALSE(mOwner, "No owner"); - - mOwner->UpdateMustKeepAlive(); return NS_OK; } //----------------------------------------------------------------------------- -// nsWebSocketEstablishedConnection::nsIWebSocketListener methods: +// nsWebSocket::nsIWebSocketListener methods: //----------------------------------------------------------------------------- NS_IMETHODIMP -nsWebSocketEstablishedConnection::OnMessageAvailable(nsISupports *aContext, - const nsACString & aMsg) +nsWebSocket::OnMessageAvailable(nsISupports *aContext, const nsACString & aMsg) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (!mOwner) - return NS_ERROR_NOT_AVAILABLE; - + + NS_ABORT_IF_FALSE(!mDisconnected, "Received message after disconnecting"); + // Dispatch New Message - nsresult rv = mOwner->CreateAndDispatchMessageEvent(aMsg); + nsresult rv = CreateAndDispatchMessageEvent(aMsg); if (NS_FAILED(rv)) { NS_WARNING("Failed to dispatch the message event"); } @@ -499,104 +269,91 @@ nsWebSocketEstablishedConnection::OnMessageAvailable(nsISupports *aContext, } NS_IMETHODIMP -nsWebSocketEstablishedConnection::OnBinaryMessageAvailable( - nsISupports *aContext, - const nsACString & aMsg) +nsWebSocket::OnBinaryMessageAvailable(nsISupports *aContext, + const nsACString & aMsg) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::OnStart(nsISupports *aContext) +nsWebSocket::OnStart(nsISupports *aContext) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (!mOwner) + if (mDisconnected) return NS_OK; - if (!mOwner->mRequestedProtocolList.IsEmpty()) - mWebSocketChannel->GetProtocol(mOwner->mEstablishedProtocol); + if (!mRequestedProtocolList.IsEmpty()) + mWebSocketChannel->GetProtocol(mEstablishedProtocol); - mWebSocketChannel->GetExtensions(mOwner->mEstablishedExtensions); + mWebSocketChannel->GetExtensions(mEstablishedExtensions); - mStatus = CONN_CONNECTED_AND_READY; - mOwner->SetReadyState(nsIMozWebSocket::OPEN); + SetReadyState(nsIMozWebSocket::OPEN); return NS_OK; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::OnStop(nsISupports *aContext, - nsresult aStatusCode) +nsWebSocket::OnStop(nsISupports *aContext, nsresult aStatusCode) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (!mOwner) + if (mDisconnected) return NS_OK; mClosedCleanly = NS_SUCCEEDED(aStatusCode); - if (aStatusCode == NS_BASE_STREAM_CLOSED && - mOwner->mReadyState >= nsIMozWebSocket::CLOSING) { + if (aStatusCode == NS_BASE_STREAM_CLOSED && + mReadyState >= nsIMozWebSocket::CLOSING) { // don't generate an error event just because of an unclean close aStatusCode = NS_OK; } if (NS_FAILED(aStatusCode)) { ConsoleError(); - if (mOwner) { - nsresult rv = - mOwner->CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error")); - if (NS_FAILED(rv)) - NS_WARNING("Failed to dispatch the error event"); - } + nsresult rv = CreateAndDispatchSimpleEvent(NS_LITERAL_STRING("error")); + if (NS_FAILED(rv)) + NS_WARNING("Failed to dispatch the error event"); } - mStatus = CONN_CLOSED; - if (mOwner) { - mOwner->SetReadyState(nsIMozWebSocket::CLOSED); - Disconnect(); - } + SetReadyState(nsIMozWebSocket::CLOSED); + Disconnect(); + return NS_OK; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::OnAcknowledge(nsISupports *aContext, - PRUint32 aSize) +nsWebSocket::OnAcknowledge(nsISupports *aContext, PRUint32 aSize) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); if (aSize > mOutgoingBufferedAmount) return NS_ERROR_UNEXPECTED; - + mOutgoingBufferedAmount -= aSize; return NS_OK; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::OnServerClose(nsISupports *aContext, - PRUint16 aCode, - const nsACString &aReason) +nsWebSocket::OnServerClose(nsISupports *aContext, PRUint16 aCode, + const nsACString &aReason) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (mOwner) { - mOwner->mServerReasonCode = aCode; - CopyUTF8toUTF16(aReason, mOwner->mServerReason); - } + mServerReasonCode = aCode; + CopyUTF8toUTF16(aReason, mServerReason); - Close(); /* reciprocate! */ + CloseConnection(); /* reciprocate! */ return NS_OK; } //----------------------------------------------------------------------------- -// nsWebSocketEstablishedConnection::nsIInterfaceRequestor +// nsWebSocket::nsIInterfaceRequestor //----------------------------------------------------------------------------- NS_IMETHODIMP -nsWebSocketEstablishedConnection::GetInterface(const nsIID &aIID, - void **aResult) +nsWebSocket::GetInterface(const nsIID &aIID, void **aResult) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (!mOwner) + if (mDisconnected) return NS_ERROR_FAILURE; if (aIID.Equals(NS_GET_IID(nsIAuthPrompt)) || @@ -604,11 +361,9 @@ nsWebSocketEstablishedConnection::GetInterface(const nsIID &aIID, nsresult rv; nsCOMPtr doc = - nsContentUtils::GetDocumentFromScriptContext(mOwner->mScriptContext); - - if (!doc) { + nsContentUtils::GetDocumentFromScriptContext(mScriptContext); + if (!doc) return NS_ERROR_NOT_AVAILABLE; - } nsCOMPtr wwatch = do_GetService(NS_WINDOWWATCHER_CONTRACTID, &rv); @@ -628,6 +383,8 @@ nsWebSocketEstablishedConnection::GetInterface(const nsIID &aIID, nsWebSocket::nsWebSocket() : mKeepingAlive(false), mCheckMustKeepAlive(true), mTriggeredCloseEvent(false), + mClosedCleanly(false), + mDisconnected(false), mClientReasonCode(0), mServerReasonCode(nsIWebSocketChannel::CLOSE_ABNORMAL), mReadyState(nsIMozWebSocket::CONNECTING), @@ -636,19 +393,18 @@ nsWebSocket::nsWebSocket() : mKeepingAlive(false), mInnerWindowID(0) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); + nsLayoutStatics::AddRef(); } nsWebSocket::~nsWebSocket() { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (mConnection) { - mConnection->Disconnect(); - mConnection = nsnull; - } if (mListenerManager) { mListenerManager->Disconnect(); mListenerManager = nsnull; } + Disconnect(); + nsLayoutStatics::Release(); } NS_IMPL_CYCLE_COLLECTION_CLASS(nsWebSocket) @@ -661,22 +417,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsWebSocket, NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnErrorListener) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mPrincipal) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mURI) - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mConnection"); - cb.NoteXPCOMChild(static_cast(tmp->mConnection)); + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mWebSocketChannel) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsWebSocket, nsDOMEventTargetWrapperCache) - if (tmp->mConnection) { - tmp->mConnection->Disconnect(); - tmp->mConnection = nsnull; - } + tmp->Disconnect(); NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnOpenListener) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnMessageListener) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnCloseListener) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnErrorListener) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mPrincipal) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mURI) + NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mWebSocketChannel) NS_IMPL_CYCLE_COLLECTION_UNLINK_END DOMCI_DATA(MozWebSocket, nsWebSocket) @@ -684,6 +437,9 @@ DOMCI_DATA(MozWebSocket, nsWebSocket) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsWebSocket) NS_INTERFACE_MAP_ENTRY(nsIMozWebSocket) NS_INTERFACE_MAP_ENTRY(nsIJSNativeInitializer) + NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) + NS_INTERFACE_MAP_ENTRY(nsIWebSocketListener) + NS_INTERFACE_MAP_ENTRY(nsIRequest) NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(MozWebSocket) NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetWrapperCache) @@ -811,24 +567,72 @@ nsWebSocket::Initialize(nsISupports* aOwner, // nsWebSocket methods: //----------------------------------------------------------------------------- +class nsAutoCloseWS +{ +public: + nsAutoCloseWS(nsWebSocket *aWebSocket) + : mWebSocket(aWebSocket) + {} + + ~nsAutoCloseWS() + { + if (!mWebSocket->mWebSocketChannel) { + mWebSocket->CloseConnection(); + } + } +private: + nsRefPtr mWebSocket; +}; + nsresult nsWebSocket::EstablishConnection() { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - NS_ABORT_IF_FALSE(!mConnection, "mConnection should be null"); + NS_ABORT_IF_FALSE(!mWebSocketChannel, "mWebSocketChannel should be null"); nsresult rv; - nsRefPtr conn = - new nsWebSocketEstablishedConnection(); + nsCOMPtr wsChannel; + nsAutoCloseWS autoClose(this); - rv = conn->Init(this); - mConnection = conn; - if (NS_FAILED(rv)) { - Close(0, EmptyString(), 0); - mConnection = nsnull; - return rv; + if (mSecure) { + wsChannel = + do_CreateInstance("@mozilla.org/network/protocol;1?name=wss", &rv); + } else { + wsChannel = + do_CreateInstance("@mozilla.org/network/protocol;1?name=ws", &rv); } + NS_ENSURE_SUCCESS(rv, rv); + + rv = wsChannel->SetNotificationCallbacks(this); + NS_ENSURE_SUCCESS(rv, rv); + + // add ourselves to the document's load group and + // provide the http stack the loadgroup info too + nsCOMPtr loadGroup; + rv = GetLoadGroup(getter_AddRefs(loadGroup)); + if (loadGroup) { + rv = wsChannel->SetLoadGroup(loadGroup); + NS_ENSURE_SUCCESS(rv, rv); + rv = loadGroup->AddRequest(this, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (!mRequestedProtocolList.IsEmpty()) { + rv = wsChannel->SetProtocol(mRequestedProtocolList); + NS_ENSURE_SUCCESS(rv, rv); + } + + nsCString asciiOrigin; + rv = nsContentUtils::GetASCIIOrigin(mPrincipal, asciiOrigin); + NS_ENSURE_SUCCESS(rv, rv); + + ToLowerCase(asciiOrigin); + + rv = wsChannel->AsyncOpen(mURI, asciiOrigin, this, nsnull); + NS_ENSURE_SUCCESS(rv, rv); + + mWebSocketChannel = wsChannel; return NS_OK; } @@ -890,7 +694,7 @@ nsWebSocket::CreateAndDispatchMessageEvent(const nsACString& aData) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); nsresult rv; - + rv = CheckInnerWindowCorrectness(); if (NS_FAILED(rv)) { return NS_OK; @@ -1023,22 +827,15 @@ nsWebSocket::SetReadyState(PRUint16 aNewReadyState) if (aNewReadyState == nsIMozWebSocket::CLOSED) { mReadyState = aNewReadyState; - if (mConnection) { - // The close event must be dispatched asynchronously. - nsCOMPtr event = - new nsWSCloseEvent(this, - mConnection->ClosedCleanly(), - mServerReasonCode, - mServerReason); - mOutgoingBufferedAmount += mConnection->GetOutgoingBufferedAmount(); - mConnection = nsnull; // this is no longer necessary - - rv = NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to dispatch the close event"); - mTriggeredCloseEvent = true; - UpdateMustKeepAlive(); - } + // The close event must be dispatched asynchronously. + rv = NS_DispatchToMainThread(new nsWSCloseEvent(this, mClosedCleanly, + mServerReasonCode, + mServerReason), + NS_DISPATCH_NORMAL); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to dispatch the close event"); + mTriggeredCloseEvent = true; + UpdateMustKeepAlive(); } } } @@ -1148,6 +945,7 @@ nsWebSocket::UpdateMustKeepAlive() { if (mListenerManager->HasListenersFor(NS_LITERAL_STRING("open")) || mListenerManager->HasListenersFor(NS_LITERAL_STRING("message")) || + mListenerManager->HasListenersFor(NS_LITERAL_STRING("error")) || mListenerManager->HasListenersFor(NS_LITERAL_STRING("close"))) { shouldKeepAlive = true; } @@ -1158,8 +956,9 @@ nsWebSocket::UpdateMustKeepAlive() case nsIMozWebSocket::CLOSING: { if (mListenerManager->HasListenersFor(NS_LITERAL_STRING("message")) || + mListenerManager->HasListenersFor(NS_LITERAL_STRING("error")) || mListenerManager->HasListenersFor(NS_LITERAL_STRING("close")) || - mConnection->HasOutgoingMessages()) { + mOutgoingBufferedAmount != 0) { shouldKeepAlive = true; } } @@ -1263,11 +1062,7 @@ nsWebSocket::GetReadyState(PRUint16 *aReadyState) NS_IMETHODIMP nsWebSocket::GetBufferedAmount(PRUint32 *aBufferedAmount) { - if (!mConnection) { - *aBufferedAmount = mOutgoingBufferedAmount; - } else { - *aBufferedAmount = mConnection->GetOutgoingBufferedAmount(); - } + *aBufferedAmount = mOutgoingBufferedAmount; return NS_OK; } @@ -1328,7 +1123,53 @@ nsWebSocket::Send(const nsAString& aData) return NS_OK; } - mConnection->PostMessage(PromiseFlatString(aData)); + nsString message = PromiseFlatString(aData); + nsresult rv; + + nsCOMPtr ccm = + do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv); + ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); + + nsCOMPtr converter; + rv = ccm->GetUnicodeEncoder("UTF-8", getter_AddRefs(converter)); + ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); + + rv = converter->SetOutputErrorBehavior(nsIUnicodeEncoder::kOnError_Replace, + nsnull, UTF_8_REPLACEMENT_CHAR); + ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); + + PRInt32 inLen = message.Length(); + PRInt32 maxLen; + rv = converter->GetMaxLength(message.BeginReading(), inLen, &maxLen); + ENSURE_SUCCESS_AND_FAIL_IF_FAILED(rv, rv); + + nsCString buf; + buf.SetLength(maxLen); + ENSURE_TRUE_AND_FAIL_IF_FAILED(buf.Length() == static_cast(maxLen), + NS_ERROR_OUT_OF_MEMORY); + + char* start = buf.BeginWriting(); + + PRInt32 outLen = maxLen; + rv = converter->Convert(message.BeginReading(), &inLen, start, &outLen); + if (NS_SUCCEEDED(rv)) { + PRInt32 outLen2 = maxLen - outLen; + rv = converter->Finish(start + outLen, &outLen2); + outLen += outLen2; + } + if (NS_FAILED(rv) || rv == NS_ERROR_UENC_NOMAPPING) { + // Yes, NS_ERROR_UENC_NOMAPPING is a success code + return NS_ERROR_DOM_SYNTAX_ERR; + } + + buf.SetLength(outLen); + ENSURE_TRUE_AND_FAIL_IF_FAILED(buf.Length() == static_cast(outLen), + NS_ERROR_UNEXPECTED); + + mOutgoingBufferedAmount += buf.Length(); + mWebSocketChannel->SendMsg(buf); + + UpdateMustKeepAlive(); return NS_OK; } @@ -1372,14 +1213,12 @@ nsWebSocket::Close(PRUint16 code, const nsAString & reason, PRUint8 argc) // before calling it nsRefPtr kungfuDeathGrip = this; - if (mConnection) { - mConnection->FailConnection(); - } + FailConnection(); return NS_OK; } // mReadyState == nsIMozWebSocket::OPEN - mConnection->Close(); + CloseConnection(); return NS_OK; } @@ -1408,8 +1247,7 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal, if (aOwnerWindow) { mOwner = aOwnerWindow->IsOuterWindow() ? aOwnerWindow->GetCurrentInnerWindow() : aOwnerWindow; - } - else { + } else { mOwner = nsnull; } @@ -1438,7 +1276,7 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal, NS_ENSURE_SUCCESS(rv, rv); // Don't allow https:// to open ws:// - if (!mSecure && + if (!mSecure && !Preferences::GetBool("network.websocket.allowInsecureFromHTTPS", false)) { // Confirmed we are opening plain ws:// and want to prevent this from a @@ -1471,28 +1309,25 @@ nsWebSocket::Init(nsIPrincipal* aPrincipal, } //----------------------------------------------------------------------------- -// nsWebSocketEstablishedConnection::nsIRequest +// nsWebSocket::nsIRequest //----------------------------------------------------------------------------- NS_IMETHODIMP -nsWebSocketEstablishedConnection::GetName(nsACString &aName) +nsWebSocket::GetName(nsACString &aName) { - if (!mOwner) - return NS_ERROR_UNEXPECTED; - - CopyUTF16toUTF8(mOwner->mOriginalURL, aName); + CopyUTF16toUTF8(mOriginalURL, aName); return NS_OK; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::IsPending(bool *aValue) +nsWebSocket::IsPending(bool *aValue) { - *aValue = !!(mOwner); + *aValue = !mDisconnected; return NS_OK; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::GetStatus(nsresult *aStatus) +nsWebSocket::GetStatus(nsresult *aStatus) { *aStatus = NS_OK; return NS_OK; @@ -1500,39 +1335,36 @@ nsWebSocketEstablishedConnection::GetStatus(nsresult *aStatus) // Window closed, stop/reload button pressed, user navigated away from page, etc. NS_IMETHODIMP -nsWebSocketEstablishedConnection::Cancel(nsresult aStatus) +nsWebSocket::Cancel(nsresult aStatus) { NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); - if (!mOwner) { + if (mDisconnected) return NS_OK; - } ConsoleError(); - return Close(); + return CloseConnection(); } NS_IMETHODIMP -nsWebSocketEstablishedConnection::Suspend() +nsWebSocket::Suspend() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::Resume() +nsWebSocket::Resume() { return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::GetLoadGroup(nsILoadGroup **aLoadGroup) +nsWebSocket::GetLoadGroup(nsILoadGroup **aLoadGroup) { *aLoadGroup = nsnull; - if (!mOwner) - return NS_OK; nsCOMPtr doc = - nsContentUtils::GetDocumentFromScriptContext(mOwner->mScriptContext); + nsContentUtils::GetDocumentFromScriptContext(mScriptContext); if (doc) { *aLoadGroup = doc->GetDocumentLoadGroup().get(); // already_AddRefed @@ -1542,20 +1374,20 @@ nsWebSocketEstablishedConnection::GetLoadGroup(nsILoadGroup **aLoadGroup) } NS_IMETHODIMP -nsWebSocketEstablishedConnection::SetLoadGroup(nsILoadGroup *aLoadGroup) +nsWebSocket::SetLoadGroup(nsILoadGroup *aLoadGroup) { return NS_ERROR_UNEXPECTED; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::GetLoadFlags(nsLoadFlags *aLoadFlags) +nsWebSocket::GetLoadFlags(nsLoadFlags *aLoadFlags) { *aLoadFlags = nsIRequest::LOAD_BACKGROUND; return NS_OK; } NS_IMETHODIMP -nsWebSocketEstablishedConnection::SetLoadFlags(nsLoadFlags aLoadFlags) +nsWebSocket::SetLoadFlags(nsLoadFlags aLoadFlags) { // we won't change the load flags at all. return NS_OK; diff --git a/content/base/src/nsWebSocket.h b/content/base/src/nsWebSocket.h index 3ae5a42008d..a2b6d289dc4 100644 --- a/content/base/src/nsWebSocket.h +++ b/content/base/src/nsWebSocket.h @@ -51,6 +51,10 @@ #include "nsDOMEventTargetWrapperCache.h" #include "nsAutoPtr.h" #include "nsIDOMDOMStringList.h" +#include "nsIInterfaceRequestor.h" +#include "nsIWebSocketChannel.h" +#include "nsIWebSocketListener.h" +#include "nsIRequest.h" #define DEFAULT_WS_SCHEME_PORT 80 #define DEFAULT_WSS_SCHEME_PORT 443 @@ -62,17 +66,18 @@ #define NS_WEBSOCKET_CONTRACTID "@mozilla.org/websocket;1" -class nsWSNetAddressComparator; -class nsWebSocketEstablishedConnection; class nsWSCloseEvent; +class nsAutoCloseWS; class nsWebSocket: public nsDOMEventTargetWrapperCache, public nsIMozWebSocket, - public nsIJSNativeInitializer + public nsIJSNativeInitializer, + public nsIInterfaceRequestor, + public nsIWebSocketListener, + public nsIRequest { -friend class nsWSNetAddressComparator; -friend class nsWebSocketEstablishedConnection; friend class nsWSCloseEvent; +friend class nsAutoCloseWS; public: nsWebSocket(); @@ -81,6 +86,9 @@ public: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsWebSocket, nsDOMEventTargetWrapperCache) NS_DECL_NSIMOZWEBSOCKET + NS_DECL_NSIINTERFACEREQUESTOR + NS_DECL_NSIWEBSOCKETLISTENER + NS_DECL_NSIREQUEST // nsIJSNativeInitializer NS_IMETHOD Initialize(nsISupports* aOwner, JSContext* aContext, @@ -99,20 +107,26 @@ public: // Determine if preferences allow WebSocket static bool PrefEnabled(); - const PRUint64 InnerWindowID() const { return mInnerWindowID; } - const nsCString& GetScriptFile() const { return mScriptFile; } - const PRUint32 GetScriptLine() const { return mScriptLine; } - protected: nsresult ParseURL(const nsString& aURL); nsresult EstablishConnection(); + // these three methods when called can release the WebSocket object + nsresult FailConnection(); + nsresult CloseConnection(); + nsresult Disconnect(); + + nsresult ConsoleError(); + nsresult PrintErrorOnConsole(const char *aBundleURI, + const PRUnichar *aError, + const PRUnichar **aFormatStrings, + PRUint32 aFormatStringsLen); + nsresult CreateAndDispatchSimpleEvent(const nsString& aName); nsresult CreateAndDispatchMessageEvent(const nsACString& aData); nsresult CreateAndDispatchCloseEvent(bool aWasClean, PRUint16 aCode, const nsString &aReason); - // called from mConnection accordingly to the situation void SetReadyState(PRUint16 aNewReadyState); // if there are "strong event listeners" (see comment in nsWebSocket.cpp) or @@ -123,6 +137,8 @@ protected: // (and possibly collected). void DontKeepAliveAnyMore(); + nsCOMPtr mWebSocketChannel; + nsRefPtr mOnOpenListener; nsRefPtr mOnErrorListener; nsRefPtr mOnMessageListener; @@ -136,6 +152,8 @@ protected: bool mKeepingAlive; bool mCheckMustKeepAlive; bool mTriggeredCloseEvent; + bool mClosedCleanly; + bool mDisconnected; nsCString mClientReason; PRUint16 mClientReasonCode; @@ -146,7 +164,7 @@ protected: PRUint32 mPort; nsCString mResource; // [filepath[?query]] nsString mUTF16Origin; - + nsCOMPtr mURI; nsCString mRequestedProtocolList; nsCString mEstablishedProtocol; @@ -156,10 +174,7 @@ protected: nsCOMPtr mPrincipal; - nsRefPtr mConnection; - PRUint32 mOutgoingBufferedAmount; // actually, we get this value from - // mConnection when we are connected, - // but we need this one after disconnecting. + PRUint32 mOutgoingBufferedAmount; // Web Socket owner information: // - the script file name, UTF8 encoded. diff --git a/content/base/test/test_websocket.html b/content/base/test/test_websocket.html index d6bc5783d49..3dedc4d7317 100644 --- a/content/base/test/test_websocket.html +++ b/content/base/test/test_websocket.html @@ -370,9 +370,15 @@ function test9() waitTest9 = true; var ws = CreateTestWS("ws://test2.example.org/tests/content/base/test/file_websocket", "test-9"); + ws._receivedErrorEvent = false; ws.onopen = shouldNotOpen; + ws.onerror = function(e) + { + ws._receivedErrorEvent = true; + }; ws.onclose = function(e) { + ok(ws._receivedErrorEvent, "Didn't received the error event in test 9."); shouldCloseNotCleanly(e); waitTest9 = false; maybeFinished(); diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index 344634bf406..a97f795ff7d 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -118,29 +118,26 @@ class CallOnMessageAvailable : public nsIRunnable public: NS_DECL_ISUPPORTS - CallOnMessageAvailable(nsIWebSocketListener *aListener, - nsISupports *aContext, - nsCString &aData, - PRInt32 aLen) - : mListener(aListener), - mContext(aContext), + CallOnMessageAvailable(WebSocketChannel *aChannel, + nsCString &aData, + PRInt32 aLen) + : mChannel(aChannel), mData(aData), mLen(aLen) {} NS_SCRIPTABLE NS_IMETHOD Run() { if (mLen < 0) - mListener->OnMessageAvailable(mContext, mData); + mChannel->mListener->OnMessageAvailable(mChannel->mContext, mData); else - mListener->OnBinaryMessageAvailable(mContext, mData); + mChannel->mListener->OnBinaryMessageAvailable(mChannel->mContext, mData); return NS_OK; } private: ~CallOnMessageAvailable() {} - nsCOMPtr mListener; - nsCOMPtr mContext; + nsRefPtr mChannel; nsCString mData; PRInt32 mLen; }; @@ -151,24 +148,21 @@ class CallOnStop : public nsIRunnable public: NS_DECL_ISUPPORTS - CallOnStop(nsIWebSocketListener *aListener, - nsISupports *aContext, - nsresult aData) - : mListener(aListener), - mContext(aContext), + CallOnStop(WebSocketChannel *aChannel, + nsresult aData) + : mChannel(aChannel), mData(aData) {} NS_SCRIPTABLE NS_IMETHOD Run() { - mListener->OnStop(mContext, mData); + mChannel->mListener->OnStop(mChannel->mContext, mData); return NS_OK; } private: ~CallOnStop() {} - nsCOMPtr mListener; - nsCOMPtr mContext; + nsRefPtr mChannel; nsresult mData; }; NS_IMPL_THREADSAFE_ISUPPORTS1(CallOnStop, nsIRunnable) @@ -178,26 +172,23 @@ class CallOnServerClose : public nsIRunnable public: NS_DECL_ISUPPORTS - CallOnServerClose(nsIWebSocketListener *aListener, - nsISupports *aContext, - PRUint16 aCode, - nsCString &aReason) - : mListener(aListener), - mContext(aContext), + CallOnServerClose(WebSocketChannel *aChannel, + PRUint16 aCode, + nsCString &aReason) + : mChannel(aChannel), mCode(aCode), mReason(aReason) {} NS_SCRIPTABLE NS_IMETHOD Run() { - mListener->OnServerClose(mContext, mCode, mReason); + mChannel->mListener->OnServerClose(mChannel->mContext, mCode, mReason); return NS_OK; } private: ~CallOnServerClose() {} - nsCOMPtr mListener; - nsCOMPtr mContext; + nsRefPtr mChannel; PRUint16 mCode; nsCString mReason; }; @@ -208,25 +199,22 @@ class CallAcknowledge : public nsIRunnable public: NS_DECL_ISUPPORTS - CallAcknowledge(nsIWebSocketListener *aListener, - nsISupports *aContext, - PRUint32 aSize) - : mListener(aListener), - mContext(aContext), + CallAcknowledge(WebSocketChannel *aChannel, + PRUint32 aSize) + : mChannel(aChannel), mSize(aSize) {} NS_SCRIPTABLE NS_IMETHOD Run() { LOG(("WebSocketChannel::CallAcknowledge: Size %u\n", mSize)); - mListener->OnAcknowledge(mContext, mSize); + mChannel->mListener->OnAcknowledge(mChannel->mContext, mSize); return NS_OK; } private: ~CallAcknowledge() {} - nsCOMPtr mListener; - nsCOMPtr mContext; + nsRefPtr mChannel; PRUint32 mSize; }; NS_IMPL_THREADSAFE_ISUPPORTS1(CallAcknowledge, nsIRunnable) @@ -236,10 +224,10 @@ class nsPostMessage : public nsIRunnable public: NS_DECL_ISUPPORTS - nsPostMessage(WebSocketChannel *channel, + nsPostMessage(WebSocketChannel *aChannel, nsCString *aData, PRInt32 aDataLen) - : mChannel(channel), + : mChannel(aChannel), mData(aData), mDataLen(aDataLen) {} @@ -935,8 +923,7 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count) return NS_ERROR_ILLEGAL_VALUE; } - NS_DispatchToMainThread(new CallOnMessageAvailable(mListener, mContext, - utf8Data, -1)); + NS_DispatchToMainThread(new CallOnMessageAvailable(this, utf8Data, -1)); } } else if (opcode & kControlFrameMask) { // control frames @@ -981,10 +968,10 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count) mCloseTimer->Cancel(); mCloseTimer = nsnull; } - if (mListener) - NS_DispatchToMainThread( - new CallOnServerClose(mListener, mContext, - mServerCloseCode, mServerCloseReason)); + if (mListener) { + NS_DispatchToMainThread(new CallOnServerClose(this, mServerCloseCode, + mServerCloseReason)); + } if (mClientClosed) ReleaseSession(); @@ -1019,8 +1006,7 @@ WebSocketChannel::ProcessInput(PRUint8 *buffer, PRUint32 count) LOG(("WebSocketChannel:: binary frame received\n")); if (mListener) { nsCString binaryData((const char *)payload, payloadLength); - NS_DispatchToMainThread(new CallOnMessageAvailable(mListener, mContext, - binaryData, + NS_DispatchToMainThread(new CallOnMessageAvailable(this, binaryData, payloadLength)); } } else if (opcode != kContinuation) { @@ -1489,7 +1475,7 @@ WebSocketChannel::StopSession(nsresult reason) if (!mCalledOnStop) { mCalledOnStop = 1; if (mListener) - NS_DispatchToMainThread(new CallOnStop(mListener, mContext, reason)); + NS_DispatchToMainThread(new CallOnStop(this, reason)); } return; @@ -2202,7 +2188,7 @@ WebSocketChannel::OnTransportAvailable(nsISocketTransport *aTransport, nsresult rv; rv = mTransport->SetEventSink(nsnull, nsnull); if (NS_FAILED(rv)) return rv; - rv = mTransport->SetSecurityCallbacks(mCallbacks); + rv = mTransport->SetSecurityCallbacks(this); if (NS_FAILED(rv)) return rv; mRecvdHttpUpgradeTransport = 1; @@ -2520,7 +2506,7 @@ WebSocketChannel::OnOutputStreamReady(nsIAsyncOutputStream *aStream) } else { if (amtSent == toSend) { if (!mStopped) { - NS_DispatchToMainThread(new CallAcknowledge(mListener, mContext, + NS_DispatchToMainThread(new CallAcknowledge(this, mCurrentOut->Length())); } delete mCurrentOut; diff --git a/netwerk/protocol/websocket/WebSocketChannel.h b/netwerk/protocol/websocket/WebSocketChannel.h index 23474e860d6..c00ebef9d99 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.h +++ b/netwerk/protocol/websocket/WebSocketChannel.h @@ -70,6 +70,10 @@ namespace mozilla { namespace net { class nsPostMessage; class nsWSAdmissionManager; class nsWSCompression; +class CallOnMessageAvailable; +class CallOnStop; +class CallOnServerClose; +class CallAcknowledge; class WebSocketChannel : public BaseWebSocketChannel, public nsIHttpUpgradeListener, @@ -129,6 +133,10 @@ protected: private: friend class nsPostMessage; friend class nsWSAdmissionManager; + friend class CallOnMessageAvailable; + friend class CallOnStop; + friend class CallOnServerClose; + friend class CallAcknowledge; void SendMsgInternal(nsCString *aMsg, PRInt32 datalen); void PrimeNewOutgoingMessage(); From 1425bd36ff93900da11c0ff2d61d5f0b8fc0df5d Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Thu, 20 Oct 2011 10:43:27 +0200 Subject: [PATCH 08/42] Bug 695121 - Auto scroll does not work on https://beta.mozillalabs.com/en-US/; r=neil@parkwaycc.co.uk --HG-- extra : rebase_source : edd22718766bb7659a002f6e98eb435b6eac4bad --- toolkit/content/widgets/browser.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index 27b1e8d57b5..37cab6e258f 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -921,11 +921,12 @@ // area and can therefore be scrolled for (this._scrollable = event.originalTarget; this._scrollable; this._scrollable = this._scrollable.parentNode) { - // do not use overflow based autoscroll for Elements - // or non-html elements such as svg or Document nodes + // do not use overflow based autoscroll for and + // Elements or non-html elements such as svg or Document nodes // also make sure to skip select elements that are not multiline if (!(this._scrollable instanceof HTMLElement) || (this._scrollable instanceof HTMLHtmlElement) || + (this._scrollable instanceof HTMLBodyElement) || ((this._scrollable instanceof HTMLSelectElement) && !this._scrollable.multiple)) { continue; } From 944164c15350c97e7e348089967299d2cbb67799 Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Tue, 30 Aug 2011 16:22:01 +0200 Subject: [PATCH 09/42] Fix for bug 669096 (Injecting function from chrome extends the lifetime of navigated-away inner window). r=mrbkap. --HG-- extra : rebase_source : 3375132c3e507e09dd79e63d277769090040f6bf --- dom/base/nsGlobalWindow.cpp | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 15e1fcaace1..f1bb6318cd1 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1817,6 +1817,34 @@ WindowStateHolder::~WindowStateHolder() NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder) + +struct ReparentWaiverClosure +{ + JSContext *mCx; + JSObject *mNewInner; +}; + +static JSDHashOperator +ReparentWaiverWrappers(JSDHashTable *table, JSDHashEntryHdr *hdr, + uint32 number, void *arg) +{ + ReparentWaiverClosure *closure = static_cast(arg); + JSObject *value = static_cast(hdr)->value; + + // We reparent wrappers that have as their parent an inner window whose + // outer has the new inner window as its current inner. + JSObject *parent = JS_GetParent(closure->mCx, value); + JSObject *outer = JS_ObjectToOuterObject(closure->mCx, parent); + if (outer) { + JSObject *inner = JS_ObjectToInnerObject(closure->mCx, outer); + if (inner == closure->mNewInner && inner != parent) + JS_SetParent(closure->mCx, value, closure->mNewInner); + } else { + JS_ClearPendingException(closure->mCx); + } + return JS_DHASH_NEXT; +} + nsresult nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, nsISupports* aState, @@ -2163,6 +2191,19 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject); mContext->SetOuterObject(mJSObject); + + JSCompartment *compartment = js::GetObjectCompartment(mJSObject); + xpc::CompartmentPrivate *priv = + static_cast(JS_GetCompartmentPrivate(cx, compartment)); + if (priv && priv->waiverWrapperMap) { + NS_ASSERTION(!JS_IsExceptionPending(cx), + "We might overwrite a pending exception!"); + ReparentWaiverClosure closure = { + cx, + newInnerWindow->mJSObject + }; + priv->waiverWrapperMap->Enumerate(ReparentWaiverWrappers, &closure); + } } } From 34fc1ec4a51f50417c9cfd6f5a0615d15c3e4c7f Mon Sep 17 00:00:00 2001 From: Peter Van der Beken Date: Thu, 13 Oct 2011 15:36:09 +0200 Subject: [PATCH 10/42] Fix for bug 693258 (Fixes for test failures when turning off new list DOM bindings). r=bz/Waldo. --HG-- extra : rebase_source : f0b6f8443cc29098ce75c114ff5a343597d9f38c --- dom/base/nsDOMClassInfo.cpp | 25 ++++++++++++++++++++ dom/base/nsDOMClassInfo.h | 3 +++ dom/base/nsWrapperCache.h | 10 +++++++- dom/tests/mochitest/bugs/test_bug633133.html | 2 +- js/src/jsarray.cpp | 2 +- js/src/jsarray.h | 4 ---- js/src/jsfriendapi.h | 3 +++ js/xpconnect/src/dombindings.cpp | 5 ++++ js/xpconnect/tests/chrome/test_nodelists.xul | 5 +++- 9 files changed, 51 insertions(+), 8 deletions(-) diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index df67fd02165..4ddaf1ce869 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -7980,6 +7980,31 @@ nsNamedNodeMapSH::GetNamedItem(nsISupports *aNative, const nsAString& aName, // HTMLCollection helper +nsresult +nsHTMLCollectionSH::PreCreate(nsISupports *nativeObj, JSContext *cx, + JSObject *globalObj, JSObject **parentObj) +{ + nsIHTMLCollection* list = static_cast(nativeObj); +#ifdef DEBUG + { + nsCOMPtr list_qi = do_QueryInterface(nativeObj); + + // If this assertion fires the QI implementation for the object in + // question doesn't use the nsIHTMLCollection pointer as the nsISupports + // pointer. That must be fixed, or we'll crash... + NS_ASSERTION(list_qi == list, "Uh, fix QI!"); + } +#endif + + nsINode* native_parent = list->GetParentObject(); + + nsresult rv = + WrapNativeParent(cx, globalObj, native_parent, native_parent, parentObj); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_SUCCESS_ALLOW_SLIM_WRAPPERS; +} + nsresult nsHTMLCollectionSH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JSObject *obj, PRUint32 *length) diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index 15974b5e5be..43ecee501d4 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -732,6 +732,9 @@ protected: nsresult *aResult); public: + NS_IMETHOD PreCreate(nsISupports *nativeObj, JSContext *cx, + JSObject *globalObj, JSObject **parentObj); + static nsIClassInfo *doCreate(nsDOMClassInfoData* aData) { return new nsHTMLCollectionSH(aData); diff --git a/dom/base/nsWrapperCache.h b/dom/base/nsWrapperCache.h index d97e70a54d6..e330f2fe3b4 100644 --- a/dom/base/nsWrapperCache.h +++ b/dom/base/nsWrapperCache.h @@ -158,7 +158,15 @@ public: void SetIsProxy() { - mWrapperPtrBits |= WRAPPER_IS_PROXY; + NS_ASSERTION(!mWrapperPtrBits, + "This flag should be set before creating any wrappers."); + mWrapperPtrBits = WRAPPER_IS_PROXY; + } + void ClearIsProxy() + { + NS_ASSERTION(!mWrapperPtrBits || mWrapperPtrBits == WRAPPER_IS_PROXY, + "This flag should be cleared before creating any wrappers."); + mWrapperPtrBits = 0; } bool IsProxy() const diff --git a/dom/tests/mochitest/bugs/test_bug633133.html b/dom/tests/mochitest/bugs/test_bug633133.html index 66efc5ecee2..2d5f1166146 100644 --- a/dom/tests/mochitest/bugs/test_bug633133.html +++ b/dom/tests/mochitest/bugs/test_bug633133.html @@ -28,7 +28,7 @@ var divCollection = document.getElementsByTagName('div'); ok("foo" in divCollection, "'foo' should be in the div collection"); ok("bar" in divCollection, "'bar' should be in the div collection"); -ok("" in divCollection, "empty string should be in the div collection"); +ok(!("" in divCollection), "empty string shouldn't be in the div collection"); ok(!("foobar" in divCollection), "'foobar' shouldn't be in the div collection"); var select = $('select'); diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index fb0b7558a76..64b734cef54 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -197,7 +197,7 @@ namespace js { * "08" or "4.0" as array indices, which they are not. * */ -bool +JS_FRIEND_API(bool) StringIsArrayIndex(JSLinearString *str, jsuint *indexp) { const jschar *s = str->chars(); diff --git a/js/src/jsarray.h b/js/src/jsarray.h index 596529952ce..b775cfe2ee5 100644 --- a/js/src/jsarray.h +++ b/js/src/jsarray.h @@ -68,10 +68,6 @@ JSObject::isPackedDenseArray() namespace js { /* 2^32-2, inclusive */ const uint32 MAX_ARRAY_INDEX = 4294967294u; - -extern bool -StringIsArrayIndex(JSLinearString *str, jsuint *indexp); - } inline JSBool diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 0a0338ad1e0..e7daf111e3c 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -334,6 +334,9 @@ CastAsJSStrictPropertyOp(JSObject *object) JS_FRIEND_API(bool) GetPropertyNames(JSContext *cx, JSObject *obj, uintN flags, js::AutoIdVector *props); +JS_FRIEND_API(bool) +StringIsArrayIndex(JSLinearString *str, jsuint *indexp); + /* * NB: these flag bits are encoded into the bytecode stream in the immediate * operand of JSOP_ITER, so don't change them without advancing jsxdrapi.h's diff --git a/js/xpconnect/src/dombindings.cpp b/js/xpconnect/src/dombindings.cpp index 9ee0706e45c..55101acdc9a 100644 --- a/js/xpconnect/src/dombindings.cpp +++ b/js/xpconnect/src/dombindings.cpp @@ -487,6 +487,8 @@ ListBase::create(JSContext *cx, XPCWrappedNativeScope *scope, ListType *aLis } JSObject *proto = getPrototype(cx, scope, triedToWrap); + if (!proto && !*triedToWrap) + aWrapperCache->ClearIsProxy(); if (!proto) return NULL; JSObject *obj = NewProxyObject(cx, &ListBase::instance, @@ -539,6 +541,9 @@ GetArrayIndexFromId(JSContext *cx, jsid id) jschar s = *atom->chars(); if (NS_LIKELY((unsigned)s >= 'a' && (unsigned)s <= 'z')) return -1; + + jsuint i; + return js::StringIsArrayIndex(JSID_TO_ATOM(id), &i) ? i : -1; } return IdToInt32(cx, id); } diff --git a/js/xpconnect/tests/chrome/test_nodelists.xul b/js/xpconnect/tests/chrome/test_nodelists.xul index 7c4d5f44ce6..92ba3192a86 100644 --- a/js/xpconnect/tests/chrome/test_nodelists.xul +++ b/js/xpconnect/tests/chrome/test_nodelists.xul @@ -30,7 +30,10 @@ ok("2" in list, "in operator works"); is(win.document.body.removeChild(win.document.body.lastChild), list2, "remove last paragraph element"); - ok(!("2" in list), "in operator doesn't see phantom element"); + if (SpecialPowers.getBoolPref("dom.new_bindings")) + ok(!("2" in list), "in operator doesn't see phantom element"); + else + todo(!("2" in list), "in operator doesn't see phantom element"); is(list[2], undefined, "no node there!"); SimpleTest.finish(); } From a0899ca0c295d061e3a6d39bd99d64498f904534 Mon Sep 17 00:00:00 2001 From: Marco Zehe Date: Thu, 20 Oct 2011 10:27:13 -0400 Subject: [PATCH 11/42] Bug 694266 - Change about window to be an accessible dialog and put all relevant static info into its acc description. r=gavin --- browser/base/content/aboutDialog.xul | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/browser/base/content/aboutDialog.xul b/browser/base/content/aboutDialog.xul index de182166782..f43559927fe 100644 --- a/browser/base/content/aboutDialog.xul +++ b/browser/base/content/aboutDialog.xul @@ -67,7 +67,8 @@ #else title="&aboutDialog.title;" #endif - aria-describedby="version distribution distributionId" + role="dialog" + aria-describedby="version distribution distributionId communityDesc contributeDesc trademark" > + + + + + +Mozilla Bug 612128 +

+
+ +
+
+
+
+
+ + diff --git a/editor/libeditor/html/tests/test_bug676401.html b/editor/libeditor/html/tests/test_bug676401.html index ba60753f757..e1915c7b9b8 100644 --- a/editor/libeditor/html/tests/test_bug676401.html +++ b/editor/libeditor/html/tests/test_bug676401.html @@ -35,10 +35,17 @@ var gBlock1, gBlock2; function IsCommandEnabled(command) { var enabled; + var resultInNonEditableRegion = false; + if (command == "selectAll") { + // The select all command is sort of exceptional, as it needs to be enabled + // everywhere. + resultInNonEditableRegion = true; + } + // non-editable div: should return false window.getSelection().selectAllChildren(gBlock1); enabled = document.queryCommandEnabled(command); - is(enabled, false, "'" + command + "' should not be enabled on a non-editable block."); + is(enabled, resultInNonEditableRegion, "'" + command + "' should not be enabled on a non-editable block."); // editable div: should return true window.getSelection().selectAllChildren(gBlock2); diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 3769c8cd408..c685c6b6264 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -3882,6 +3882,31 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsFrameConstructorState& aState, return NS_OK; } +static void +SetFlagsOnSubtree(nsIContent *aNode, PtrBits aFlagsToSet) +{ +#ifdef DEBUG + // Make sure that the node passed to us doesn't have any XBL children + { + nsIDocument *doc = aNode->OwnerDoc(); + NS_ASSERTION(doc, "The node must be in a document"); + NS_ASSERTION(!doc->BindingManager()->GetXBLChildNodesFor(aNode), + "The node should not have any XBL children"); + } +#endif + + // Set the flag on the node itself + aNode->SetFlags(aFlagsToSet); + + // Set the flag on all of its children recursively + PRUint32 count; + nsIContent * const *children = aNode->GetChildArray(&count); + + for (PRUint32 index = 0; index < count; ++index) { + SetFlagsOnSubtree(children[index], aFlagsToSet); + } +} + nsresult nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent, nsIFrame* aParentFrame, @@ -3909,7 +3934,17 @@ nsCSSFrameConstructor::GetAnonymousContent(nsIContent* aParent, content->SetNativeAnonymous(); } + bool anonContentIsEditable = content->HasFlag(NODE_IS_EDITABLE); rv = content->BindToTree(mDocument, aParent, aParent, true); + // If the anonymous content creator requested that the content should be + // editable, honor its request. + // We need to set the flag on the whole subtree, because existing + // children's flags have already been set as part of the BindToTree operation. + if (anonContentIsEditable) { + NS_ASSERTION(aParentFrame->GetType() == nsGkAtoms::textInputFrame, + "We only expect this for anonymous content under a text control frame"); + SetFlagsOnSubtree(content, NODE_IS_EDITABLE); + } if (NS_FAILED(rv)) { content->UnbindFromTree(); return rv; @@ -6132,25 +6167,6 @@ nsCSSFrameConstructor::ReframeTextIfNeeded(nsIContent* aParentContent, ContentInserted(aParentContent, aContent, nsnull, false); } -// We want to disable lazy frame construction for nodes that are under an -// editor. We use nsINode::IsEditable, but that includes inputs with type text -// and password and textareas, which are common and aren't really editable (the -// native anonymous content under them is what is actually editable) so we want -// to construct frames for those lazily. -// The logic for this check is based on -// nsGenericHTMLFormElement::UpdateEditableFormControlState and so must be kept -// in sync with that. MayHaveContentEditableAttr() being true only indicates -// a contenteditable attribute, it doesn't indicate whether it is true or false, -// so we force eager construction in some cases when the node is not editable, -// but that should be rare. -static inline bool -IsActuallyEditable(nsIContent* aContainer, nsIContent* aChild) -{ - return (aChild->IsEditable() && - (aContainer->IsEditable() || - aChild->MayHaveContentEditableAttr())); -} - // For inserts aChild should be valid, for appends it should be null. // Returns true if this operation can be lazy, false if not. bool @@ -6165,7 +6181,7 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation, if (aOperation == CONTENTINSERT) { if (aChild->IsRootOfAnonymousSubtree() || - aChild->IsXUL() || IsActuallyEditable(aContainer, aChild)) { + aChild->IsEditable() || aChild->IsXUL()) { return false; } } else { // CONTENTAPPEND @@ -6174,7 +6190,7 @@ nsCSSFrameConstructor::MaybeConstructLazily(Operation aOperation, for (nsIContent* child = aChild; child; child = child->GetNextSibling()) { NS_ASSERTION(!child->IsRootOfAnonymousSubtree(), "Should be coming through the CONTENTAPPEND case"); - if (child->IsXUL() || IsActuallyEditable(aContainer, child)) { + if (child->IsXUL() || child->IsEditable()) { return false; } } diff --git a/layout/generic/nsIAnonymousContentCreator.h b/layout/generic/nsIAnonymousContentCreator.h index b1e84dc5305..4c351a99b69 100644 --- a/layout/generic/nsIAnonymousContentCreator.h +++ b/layout/generic/nsIAnonymousContentCreator.h @@ -79,6 +79,10 @@ public: * Creates "native" anonymous content and adds the created content to * the aElements array. None of the returned elements can be nsnull. * + * If the anonymous content creator sets the editable flag on some + * of the elements that it creates, the flag will be applied to the node + * upon being bound to the document. + * * @note The returned elements are owned by this object. This object is * responsible for calling UnbindFromTree on the elements it returned * from CreateAnonymousContent when appropriate (i.e. before releasing diff --git a/layout/reftests/editor/readonly-editable-ref.html b/layout/reftests/editor/readonly-editable-ref.html new file mode 100644 index 00000000000..99f1e510173 --- /dev/null +++ b/layout/reftests/editor/readonly-editable-ref.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/layout/reftests/editor/readonly-editable.html b/layout/reftests/editor/readonly-editable.html new file mode 100644 index 00000000000..49210e58147 --- /dev/null +++ b/layout/reftests/editor/readonly-editable.html @@ -0,0 +1,24 @@ + + + + + + + hide me + hide me + hide me + hide me + hide me + hide me + hide me + hide me + + diff --git a/layout/reftests/editor/readonly-non-editable-ref.html b/layout/reftests/editor/readonly-non-editable-ref.html new file mode 100644 index 00000000000..a91071e42c3 --- /dev/null +++ b/layout/reftests/editor/readonly-non-editable-ref.html @@ -0,0 +1,21 @@ + + + + + + + hide me + + hide me + + hide me + + hide me + + + diff --git a/layout/reftests/editor/readonly-non-editable.html b/layout/reftests/editor/readonly-non-editable.html new file mode 100644 index 00000000000..9766045ed73 --- /dev/null +++ b/layout/reftests/editor/readonly-non-editable.html @@ -0,0 +1,24 @@ + + + + + + + hide me + hide me + hide me + hide me + hide me + hide me + hide me + hide me + + diff --git a/layout/reftests/editor/readwrite-editable-ref.html b/layout/reftests/editor/readwrite-editable-ref.html new file mode 100644 index 00000000000..99f1e510173 --- /dev/null +++ b/layout/reftests/editor/readwrite-editable-ref.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/layout/reftests/editor/readwrite-editable.html b/layout/reftests/editor/readwrite-editable.html new file mode 100644 index 00000000000..49210e58147 --- /dev/null +++ b/layout/reftests/editor/readwrite-editable.html @@ -0,0 +1,24 @@ + + + + + + + hide me + hide me + hide me + hide me + hide me + hide me + hide me + hide me + + diff --git a/layout/reftests/editor/readwrite-non-editable-ref.html b/layout/reftests/editor/readwrite-non-editable-ref.html new file mode 100644 index 00000000000..12e1c46c0ae --- /dev/null +++ b/layout/reftests/editor/readwrite-non-editable-ref.html @@ -0,0 +1,21 @@ + + + + + + + + hide me + + hide me + + hide me + + hide me + + diff --git a/layout/reftests/editor/readwrite-non-editable.html b/layout/reftests/editor/readwrite-non-editable.html new file mode 100644 index 00000000000..535f21f1aa0 --- /dev/null +++ b/layout/reftests/editor/readwrite-non-editable.html @@ -0,0 +1,24 @@ + + + + + + + hide me + hide me + hide me + hide me + hide me + hide me + hide me + hide me + + diff --git a/layout/reftests/editor/reftest.list b/layout/reftests/editor/reftest.list index 39e08999262..f72d06fdc08 100644 --- a/layout/reftests/editor/reftest.list +++ b/layout/reftests/editor/reftest.list @@ -83,4 +83,8 @@ skip-if(Android) == 674212-spellcheck.html 674212-spellcheck-ref.html skip-if(Android) == 338427-2.html 338427-2-ref.html skip-if(Android) needs-focus == 338427-3.html 338427-3-ref.html skip-if(Android) == 462758-grabbers-resizers.html 462758-grabbers-resizers-ref.html +== readwrite-non-editable.html readwrite-non-editable-ref.html +== readwrite-editable.html readwrite-editable-ref.html +== readonly-non-editable.html readonly-non-editable-ref.html +== readonly-editable.html readonly-editable-ref.html == dynamic-overflow-change.html dynamic-overflow-change-ref.html From 92c83507d3e45c4d8200a9af7b949b03bff86b08 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Sun, 16 Oct 2011 16:15:40 -0400 Subject: [PATCH 22/42] Bug 688438 - Fix the IME code to handle text controls correctly when checking for IME status; r=bzbarsky --HG-- extra : rebase_source : 4c532f5ece3e88e907aabfef2197bced1223d9f2 --- content/base/src/nsGenericElement.cpp | 7 ++++++- content/events/src/nsIMEStateManager.cpp | 13 ++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index b878891938b..5582f3576bb 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -1348,7 +1348,12 @@ PRUint32 nsIContent::GetDesiredIMEState() { if (!IsEditableInternal()) { - return IME_STATUS_DISABLE; + // Check for the special case where we're dealing with elements which don't + // have the editable flag set, but are readwrite (such as text controls). + if (!IsElement() || + !AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) { + return IME_STATUS_DISABLE; + } } // NOTE: The content for independent editors (e.g., input[type=text], // textarea) must override this method, so, we don't need to worry about diff --git a/content/events/src/nsIMEStateManager.cpp b/content/events/src/nsIMEStateManager.cpp index 7ba8fac471e..ee20286f372 100644 --- a/content/events/src/nsIMEStateManager.cpp +++ b/content/events/src/nsIMEStateManager.cpp @@ -646,13 +646,24 @@ nsTextStateManager::ContentRemoved(nsIDocument* aDocument, new TextChangeEvent(mWidget, offset, offset + childOffset, offset)); } +static bool IsEditable(nsINode* node) { + if (node->IsEditable()) { + return true; + } + // |node| might be readwrite (for example, a text control) + if (node->IsElement() && node->AsElement()->State().HasState(NS_EVENT_STATE_MOZ_READWRITE)) { + return true; + } + return false; +} + static nsINode* GetRootEditableNode(nsPresContext* aPresContext, nsIContent* aContent) { if (aContent) { nsINode* root = nsnull; nsINode* node = aContent; - while (node && node->IsEditable()) { + while (node && IsEditable(node)) { root = node; node = node->GetNodeParent(); } From f3be36275719143ddfead921bc19428ac9483aa7 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 20 Oct 2011 12:27:48 -0400 Subject: [PATCH 23/42] Bug 694880 - The editable state is not updated correctly when designMode is turned off; r=bz,peterv --- content/html/document/src/nsHTMLDocument.cpp | 12 ++++++------ layout/reftests/editor/694880-1.html | 10 ++++++++++ layout/reftests/editor/694880-2.html | 11 +++++++++++ layout/reftests/editor/694880-3.html | 10 ++++++++++ layout/reftests/editor/694880-ref.html | 9 +++++++++ layout/reftests/editor/reftest.list | 3 +++ 6 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 layout/reftests/editor/694880-1.html create mode 100644 layout/reftests/editor/694880-2.html create mode 100644 layout/reftests/editor/694880-3.html create mode 100644 layout/reftests/editor/694880-ref.html diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 365a037ac98..88345f848bb 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -2699,17 +2699,15 @@ nsHTMLDocument::GetDocumentAllResult(const nsAString& aID, } static void -NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument, - bool aEditable) +NotifyEditableStateChange(nsINode *aNode, nsIDocument *aDocument) { for (nsIContent* child = aNode->GetFirstChild(); child; child = child->GetNextSibling()) { - if (child->HasFlag(NODE_IS_EDITABLE) != aEditable && - child->IsElement()) { + if (child->IsElement()) { child->AsElement()->UpdateState(true); } - NotifyEditableStateChange(child, aDocument, aEditable); + NotifyEditableStateChange(child, aDocument); } } @@ -2802,6 +2800,8 @@ nsHTMLDocument::EditingStateChanged() if (newState == eOff) { // Editing is being turned off. + nsAutoScriptBlocker scriptBlocker; + NotifyEditableStateChange(this, this); return TurnEditingOff(); } @@ -2958,7 +2958,7 @@ nsHTMLDocument::EditingStateChanged() if (updateState) { nsAutoScriptBlocker scriptBlocker; - NotifyEditableStateChange(this, this, designMode); + NotifyEditableStateChange(this, this); } // Resync the editor's spellcheck state. diff --git a/layout/reftests/editor/694880-1.html b/layout/reftests/editor/694880-1.html new file mode 100644 index 00000000000..373c3070a90 --- /dev/null +++ b/layout/reftests/editor/694880-1.html @@ -0,0 +1,10 @@ + + + + +
test
+ + diff --git a/layout/reftests/editor/694880-2.html b/layout/reftests/editor/694880-2.html new file mode 100644 index 00000000000..9f2617883af --- /dev/null +++ b/layout/reftests/editor/694880-2.html @@ -0,0 +1,11 @@ + + + + +
test
+
+ + diff --git a/layout/reftests/editor/694880-3.html b/layout/reftests/editor/694880-3.html new file mode 100644 index 00000000000..c6d7837f743 --- /dev/null +++ b/layout/reftests/editor/694880-3.html @@ -0,0 +1,10 @@ + + + + +
test
+ + diff --git a/layout/reftests/editor/694880-ref.html b/layout/reftests/editor/694880-ref.html new file mode 100644 index 00000000000..d5c40547ee4 --- /dev/null +++ b/layout/reftests/editor/694880-ref.html @@ -0,0 +1,9 @@ + + + + +
test
+ + diff --git a/layout/reftests/editor/reftest.list b/layout/reftests/editor/reftest.list index f72d06fdc08..55229b805ac 100644 --- a/layout/reftests/editor/reftest.list +++ b/layout/reftests/editor/reftest.list @@ -88,3 +88,6 @@ skip-if(Android) == 462758-grabbers-resizers.html 462758-grabbers-resizers-ref.h == readonly-non-editable.html readonly-non-editable-ref.html == readonly-editable.html readonly-editable-ref.html == dynamic-overflow-change.html dynamic-overflow-change-ref.html +== 694880-1.html 694880-ref.html +== 694880-2.html 694880-ref.html +== 694880-3.html 694880-ref.html From 495c00a54f74a10ce24fcb3a8da591f4cc5c66b1 Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Thu, 20 Oct 2011 09:55:16 -0700 Subject: [PATCH 24/42] Bug 693698: 3rd Party add-ons from the application folder are not disabled on upgrade. r=Unfocused --- .../extensions/content/selectAddons.js | 8 +--- .../extensions/content/selectAddons.xml | 17 +++------ .../test/browser/browser_select_selection.js | 37 ++++++++++--------- 3 files changed, 26 insertions(+), 36 deletions(-) diff --git a/toolkit/mozapps/extensions/content/selectAddons.js b/toolkit/mozapps/extensions/content/selectAddons.js index c4e4fffb72c..508e0e08022 100644 --- a/toolkit/mozapps/extensions/content/selectAddons.js +++ b/toolkit/mozapps/extensions/content/selectAddons.js @@ -80,13 +80,7 @@ function isAddonDistroInstalled(aID) { } function orderForScope(aScope) { - switch (aScope) { - case AddonManager.SCOPE_PROFILE: - case AddonManager.SCOPE_APPLICATION: - return 1; - default: - return 0; - } + return aScope == AddonManager.SCOPE_PROFILE ? 1 : 0; } var gAddons = {}; diff --git a/toolkit/mozapps/extensions/content/selectAddons.xml b/toolkit/mozapps/extensions/content/selectAddons.xml index 2b93a7ec27a..f08eb273d46 100644 --- a/toolkit/mozapps/extensions/content/selectAddons.xml +++ b/toolkit/mozapps/extensions/content/selectAddons.xml @@ -119,20 +119,15 @@ this.setAttribute("name", aAddon.name); this.setAttribute("type", aAddon.type); - // User and application installed add-ons default to staying enabled, + // User and bundled add-ons default to staying enabled, // others default to disabled. - let scope = aAddon.scope; - if (aDistroInstalled) - scope = AddonManager.SCOPE_APPLICATION; - - switch (scope) { + switch (aAddon.scope) { case AddonManager.SCOPE_PROFILE: this._keep.checked = !aAddon.userDisabled; - this.setAttribute("source", this._strings.getString("source.profile")); - break; - case AddonManager.SCOPE_APPLICATION: - this._keep.checked = !aAddon.userDisabled; - this.setAttribute("source", this._strings.getString("source.bundled")); + if (aDistroInstalled) + this.setAttribute("source", this._strings.getString("source.bundled")); + else + this.setAttribute("source", this._strings.getString("source.profile")); break; default: this._keep.checked = false; diff --git a/toolkit/mozapps/extensions/test/browser/browser_select_selection.js b/toolkit/mozapps/extensions/test/browser/browser_select_selection.js index 92943113b13..7c277bdc70b 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_select_selection.js +++ b/toolkit/mozapps/extensions/test/browser/browser_select_selection.js @@ -11,15 +11,16 @@ const PROFILE = AddonManager.SCOPE_PROFILE; const USER = AddonManager.SCOPE_USER; const APP = AddonManager.SCOPE_APPLICATION; const SYSTEM = AddonManager.SCOPE_SYSTEM; +const DIST = -1; // The matrix of testcases for the selection part of the UI // Note that the isActive flag has the value it had when the previous version // of the application ran with this add-on. var ADDONS = [ //userDisabled wasAppDisabled isAppDisabled isActive hasUpdate autoUpdate scope defaultKeep position keepString disableString - [false, true, false, false, false, true, PROFILE, true, 38, "enabled", ""], // 0 - [false, true, false, false, true, true, PROFILE, true, 39, "enabled", ""], // 1 - [false, true, false, false, true, false, PROFILE, true, 48, "unneededupdate", ""], // 2 + [false, true, false, false, false, true, PROFILE, true, 42, "enabled", ""], // 0 + [false, true, false, false, true, true, PROFILE, true, 43, "enabled", ""], // 1 + [false, true, false, false, true, false, PROFILE, true, 52, "unneededupdate", ""], // 2 [false, false, false, true, false, true, PROFILE, true, 53, "", "disabled"], // 3 [false, false, false, true, true, true, PROFILE, true, 54, "", "disabled"], // 4 [false, false, false, true, true, false, PROFILE, true, 55, "unneededupdate", "disabled"], // 5 @@ -27,17 +28,17 @@ var ADDONS = [ [false, true, true, false, true, true, PROFILE, true, 57, "autoupdate", ""], // 7 [false, true, true, false, true, false, PROFILE, true, 58, "neededupdate", ""], // 8 [false, false, true, true, false, true, PROFILE, true, 59, "incompatible", "disabled"], // 9 - [false, true, true, true, true, true, PROFILE, true, 40, "autoupdate", "disabled"], // 10 - [false, true, true, true, true, false, PROFILE, true, 41, "neededupdate", "disabled"], // 11 - [true, false, false, false, false, true, PROFILE, false, 42, "enabled", ""], // 12 - [true, false, false, false, true, true, PROFILE, false, 43, "enabled", ""], // 13 - [true, false, false, false, true, false, PROFILE, false, 44, "unneededupdate", ""], // 14 + [false, true, true, true, true, true, PROFILE, true, 44, "autoupdate", "disabled"], // 10 + [false, true, true, true, true, false, PROFILE, true, 45, "neededupdate", "disabled"], // 11 + [true, false, false, false, false, true, PROFILE, false, 46, "enabled", ""], // 12 + [true, false, false, false, true, true, PROFILE, false, 47, "enabled", ""], // 13 + [true, false, false, false, true, false, PROFILE, false, 48, "unneededupdate", ""], // 14 // userDisabled and isActive cannot be true on startup - [true, true, true, false, false, true, PROFILE, false, 45, "incompatible", ""], // 15 - [true, true, true, false, true, true, PROFILE, false, 46, "autoupdate", ""], // 16 - [true, true, true, false, true, false, PROFILE, false, 47, "neededupdate", ""], // 17 + [true, true, true, false, false, true, PROFILE, false, 49, "incompatible", ""], // 15 + [true, true, true, false, true, true, PROFILE, false, 50, "autoupdate", ""], // 16 + [true, true, true, false, true, false, PROFILE, false, 51, "neededupdate", ""], // 17 // userDisabled and isActive cannot be true on startup @@ -50,10 +51,10 @@ var ADDONS = [ [true, true, false, false, true, false, SYSTEM, false, 5, "enabled", ""], // 23 [false, true, true, true, true, false, SYSTEM, false, 6, "incompatible", "disabled"], // 24 [true, true, true, false, true, false, SYSTEM, false, 7, "incompatible", ""], // 25 - [false, false, false, true, true, false, APP, true, 49, "", "disabled"], // 26 - [true, true, false, false, true, false, APP, false, 50, "enabled", ""], // 27 - [false, true, true, true, true, false, APP, true, 51, "incompatible", "disabled"], // 28 - [true, true, true, false, true, false, APP, false, 52, "incompatible", ""], // 29 + [false, false, false, true, true, false, APP, false, 8, "", "disabled"], // 26 + [true, true, false, false, true, false, APP, false, 9, "enabled", ""], // 27 + [false, true, true, true, true, false, APP, false, 10, "incompatible", "disabled"], // 28 + [true, true, true, false, true, false, APP, false, 11, "incompatible", ""], // 29 ]; function waitForView(aView, aCallback) { @@ -78,10 +79,10 @@ function getSourceString(aSource) { var strings = Services.strings.createBundle("chrome://mozapps/locale/extensions/selectAddons.properties"); switch (aSource) { - case APP: - return strings.GetStringFromName("source.bundled"); case PROFILE: return strings.GetStringFromName("source.profile"); + case DIST: + return strings.GetStringFromName("source.bundled"); default: return strings.GetStringFromName("source.other"); } @@ -232,7 +233,7 @@ add_test(function selection_test() { if (id == 3 || id == 12 || id == 15) { // Distro Installed To Profile - is(source.textContent, getSourceString(APP), "Source message should have the right text for Distributed Addons"); + is(source.textContent, getSourceString(DIST), "Source message should have the right text for Distributed Addons"); } else { is(source.textContent, getSourceString(addon[6]), "Source message should have the right text"); } From 24bfeefc852939d8b665643015b2f6b886bb8428 Mon Sep 17 00:00:00 2001 From: Dave Townsend Date: Thu, 20 Oct 2011 09:55:57 -0700 Subject: [PATCH 25/42] Bug 694595: Some settings for add-ons aren't being migrated when we change database schemas. r=Unfocused --- toolkit/mozapps/extensions/XPIProvider.jsm | 24 +- .../test/addons/test_migrate4_6/install.rdf | 23 ++ .../test/xpcshell/data/test_migrate4.rdf | 46 ++++ .../extensions/test/xpcshell/test_migrate1.js | 2 +- .../extensions/test/xpcshell/test_migrate2.js | 1 - .../extensions/test/xpcshell/test_migrate3.js | 2 +- .../extensions/test/xpcshell/test_migrate4.js | 223 ++++++++++++++++++ .../extensions/test/xpcshell/xpcshell.ini | 1 + 8 files changed, 315 insertions(+), 7 deletions(-) create mode 100644 toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf create mode 100644 toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm index 04dd2846e2e..e75d3ba0617 100644 --- a/toolkit/mozapps/extensions/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/XPIProvider.jsm @@ -2599,14 +2599,20 @@ var XPIProvider = { newAddon.installDate = aMigrateData.installDate; if ("softDisabled" in aMigrateData) newAddon.softDisabled = aMigrateData.softDisabled; + if ("applyBackgroundUpdates" in aMigrateData) + newAddon.applyBackgroundUpdates = aMigrateData.applyBackgroundUpdates; + if ("sourceURI" in aMigrateData) + newAddon.sourceURI = aMigrateData.sourceURI; + if ("releaseNotesURI" in aMigrateData) + newAddon.releaseNotesURI = aMigrateData.releaseNotesURI; // Some properties should only be migrated if the add-on hasn't changed. // The version property isn't a perfect check for this but covers the // vast majority of cases. - if (aMigrateData.version == newAddon.version) { + if (aMigrateData.version == newAddon.version && + "targetApplications" in aMigrateData) { LOG("Migrating compatibility info"); - if ("targetApplications" in aMigrateData) - newAddon.applyCompatibilityUpdate(aMigrateData, true); + newAddon.applyCompatibilityUpdate(aMigrateData, true); } // Since the DB schema has changed make sure softDisabled is correct @@ -4366,7 +4372,11 @@ var XPIDatabase = { // and future versions of the schema var sql = []; sql.push("SELECT internal_id, id, location, userDisabled, " + - "softDisabled, installDate, version FROM addon"); + "softDisabled, installDate, version, applyBackgroundUpdates, " + + "sourceURI, releaseNotesURI FROM addon"); + sql.push("SELECT internal_id, id, location, userDisabled, " + + "installDate, version, applyBackgroundUpdates, " + + "sourceURI, releaseNotesURI FROM addon"); sql.push("SELECT internal_id, id, location, userDisabled, installDate, " + "version FROM addon"); @@ -4397,6 +4407,12 @@ var XPIDatabase = { if ("softDisabled" in row) migrateData[row.location][row.id].softDisabled = row.softDisabled == 1; + if ("applyBackgroundUpdates" in row) + migrateData[row.location][row.id].applyBackgroundUpdates = row.applyBackgroundUpdates == 1; + if ("sourceURI" in row) + migrateData[row.location][row.id].sourceURI = row.sourceURI; + if ("releaseNotesURI" in row) + migrateData[row.location][row.id].releaseNotesURI = row.releaseNotesURI; } var taStmt = this.connection.createStatement("SELECT id, minVersion, " + diff --git a/toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf b/toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf new file mode 100644 index 00000000000..5924982f72c --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/test_migrate4_6/install.rdf @@ -0,0 +1,23 @@ + + + + + + addon6@tests.mozilla.org + 2.0 + + + Test 6 + Test Description + + + + xpcshell@tests.mozilla.org + 1 + 2 + + + + + diff --git a/toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf b/toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf new file mode 100644 index 00000000000..88e42267f39 --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/data/test_migrate4.rdf @@ -0,0 +1,46 @@ + + + + + + + +
  • + + 2.0 + + + xpcshell@tests.mozilla.org + 0 + 2 + + + +
  • +
    +
    +
    + + + + +
  • + + 2.0 + + + xpcshell@tests.mozilla.org + 0 + 2 + http://localhost:4444/addons/test_migrate4_6.xpi + http://example.com/updateInfo.xhtml + + + +
  • +
    +
    +
    + +
    diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js index 2769fb03e79..50c91c8059e 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate1.js @@ -2,7 +2,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Checks that we migrate data from previous versions of the database +// Checks that we migrate data from the old rdf style database var addon1 = { id: "addon1@tests.mozilla.org", diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js index efeac14f375..9f15f167299 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate2.js @@ -177,7 +177,6 @@ function run_test() { do_check_false(a5.userDisabled); do_check_false(a5.appDisabled); do_check_true(a5.isActive); - do_test_finished(); // addon6 was disabled and compatible but a new version has been installed // since, it should still be disabled but should be incompatible do_check_neq(a6, null); diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js index 25aae35aafd..095026da8bd 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate3.js @@ -2,7 +2,7 @@ * http://creativecommons.org/publicdomain/zero/1.0/ */ -// Checks that we migrate data from previous versions of the database. This +// Checks that we migrate data from the old extensions.rdf database. This // matches test_migrate1.js however it runs with a lightweight theme selected // so the themes should appear disabled. diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js b/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js new file mode 100644 index 00000000000..f79f4f6190f --- /dev/null +++ b/toolkit/mozapps/extensions/test/xpcshell/test_migrate4.js @@ -0,0 +1,223 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +// Checks that we migrate data from a previous version of the sqlite database + +// The test extension uses an insecure update url. +Services.prefs.setBoolPref("extensions.checkUpdateSecurity", false); + +var addon1 = { + id: "addon1@tests.mozilla.org", + version: "1.0", + name: "Test 1", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "2" + }] +}; + +var addon2 = { + id: "addon2@tests.mozilla.org", + version: "2.0", + name: "Test 2", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "2" + }] +}; + +var addon3 = { + id: "addon3@tests.mozilla.org", + version: "2.0", + name: "Test 3", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "2" + }] +}; + +var addon4 = { + id: "addon4@tests.mozilla.org", + version: "2.0", + name: "Test 4", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "1", + maxVersion: "2" + }] +}; + +var addon5 = { + id: "addon5@tests.mozilla.org", + version: "2.0", + name: "Test 5", + updateURL: "http://localhost:4444/data/test_migrate4.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "0", + maxVersion: "1" + }] +}; + +var addon6 = { + id: "addon6@tests.mozilla.org", + version: "1.0", + name: "Test 6", + updateURL: "http://localhost:4444/data/test_migrate4.rdf", + targetApplications: [{ + id: "xpcshell@tests.mozilla.org", + minVersion: "0", + maxVersion: "1" + }] +}; + +const profileDir = gProfD.clone(); +profileDir.append("extensions"); + +do_load_httpd_js(); +var testserver; + +function prepare_profile() { + createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2"); + + // Create and configure the HTTP server. + testserver = new nsHttpServer(); + testserver.registerDirectory("/data/", do_get_file("data")); + testserver.registerDirectory("/addons/", do_get_file("addons")); + testserver.start(4444); + + writeInstallRDFForExtension(addon1, profileDir); + writeInstallRDFForExtension(addon2, profileDir); + writeInstallRDFForExtension(addon3, profileDir); + writeInstallRDFForExtension(addon4, profileDir); + writeInstallRDFForExtension(addon5, profileDir); + writeInstallRDFForExtension(addon6, profileDir); + + startupManager(); + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org", + "addon6@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6]) { + a2.userDisabled = true; + a2.applyBackgroundUpdates = false; + a4.userDisabled = true; + a6.userDisabled = true; + + a6.findUpdates({ + onUpdateAvailable: function(aAddon, aInstall) { + completeAllInstalls([aInstall], function() { + restartManager(); + + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org", + "addon6@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6]) { + a3.userDisabled = true; + a4.userDisabled = false; + + a5.findUpdates({ + onUpdateFinished: function() { + shutdownManager(); + + perform_migration(); + } + }, AddonManager.UPDATE_WHEN_USER_REQUESTED); + }); + }); + } + }, AddonManager.UPDATE_WHEN_USER_REQUESTED); + }); +} + +function perform_migration() { + let dbfile = gProfD.clone(); + dbfile.append("extensions.sqlite"); + let db = AM_Cc["@mozilla.org/storage/service;1"]. + getService(AM_Ci.mozIStorageService). + openDatabase(dbfile); + db.schemaVersion = 1; + Services.prefs.setIntPref("extensions.databaseSchema", 1); + db.close(); + + gAppInfo.version = "2" + startupManager(true); + test_results(); +} + +function test_results() { + check_startup_changes("installed", []); + check_startup_changes("updated", []); + check_startup_changes("uninstalled", []); + check_startup_changes("disabled", []); + check_startup_changes("enabled", []); + + AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org", + "addon2@tests.mozilla.org", + "addon3@tests.mozilla.org", + "addon4@tests.mozilla.org", + "addon5@tests.mozilla.org", + "addon6@tests.mozilla.org"], + function([a1, a2, a3, a4, a5, a6]) { + // addon1 was enabled + do_check_neq(a1, null); + do_check_false(a1.userDisabled); + do_check_false(a1.appDisabled); + do_check_true(a1.isActive); + do_check_true(a1.applyBackgroundUpdates); + + // addon2 was disabled + do_check_neq(a2, null); + do_check_true(a2.userDisabled); + do_check_false(a2.appDisabled); + do_check_false(a2.isActive); + do_check_false(a2.applyBackgroundUpdates); + + // addon3 was pending-disable in the database + do_check_neq(a3, null); + do_check_true(a3.userDisabled); + do_check_false(a3.appDisabled); + do_check_false(a3.isActive); + do_check_true(a3.applyBackgroundUpdates); + + // addon4 was pending-enable in the database + do_check_neq(a4, null); + do_check_false(a4.userDisabled); + do_check_false(a4.appDisabled); + do_check_true(a4.isActive); + do_check_true(a4.applyBackgroundUpdates); + + // addon5 was enabled in the database but needed a compatibiltiy update + do_check_neq(a5, null); + do_check_false(a5.userDisabled); + do_check_false(a5.appDisabled); + do_check_true(a5.isActive); + do_check_true(a5.applyBackgroundUpdates); + + // addon6 was disabled and compatible but a new version has been installed + do_check_neq(a6, null); + do_check_eq(a6.version, "2.0"); + do_check_true(a6.userDisabled); + do_check_false(a6.appDisabled); + do_check_false(a6.isActive); + do_check_true(a6.applyBackgroundUpdates); + do_check_eq(a6.sourceURI.spec, "http://localhost:4444/addons/test_migrate4_6.xpi"); + do_check_eq(a6.releaseNotesURI.spec, "http://example.com/updateInfo.xhtml"); + testserver.stop(do_test_finished); + }); +} + +function run_test() { + do_test_pending(); + + prepare_profile(); +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini index 5d5db49342b..9266062b5d7 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini +++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini @@ -159,6 +159,7 @@ skip-if = os == "android" [test_migrate1.js] [test_migrate2.js] [test_migrate3.js] +[test_migrate4.js] [test_migrateAddonRepository.js] [test_permissions.js] [test_plugins.js] From 332c11b9c97ecc7dd4eafb1f171c5eb43f6c1f27 Mon Sep 17 00:00:00 2001 From: Timothy Nikkel Date: Thu, 20 Oct 2011 12:44:28 -0500 Subject: [PATCH 26/42] Bug 694213. Make various display items return bounds in the correct coordinate space. r=roc --- layout/forms/nsButtonFrameRenderer.cpp | 2 +- layout/forms/nsSelectsAreaFrame.cpp | 2 +- layout/generic/nsBulletFrame.cpp | 2 +- layout/generic/nsTextFrameThebes.cpp | 2 +- layout/xul/base/src/nsTextBoxFrame.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp index 563ba2e73cf..916438376fc 100644 --- a/layout/forms/nsButtonFrameRenderer.cpp +++ b/layout/forms/nsButtonFrameRenderer.cpp @@ -114,7 +114,7 @@ private: nsRect nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } void diff --git a/layout/forms/nsSelectsAreaFrame.cpp b/layout/forms/nsSelectsAreaFrame.cpp index 9c4fc4b518f..10506d92ce7 100644 --- a/layout/forms/nsSelectsAreaFrame.cpp +++ b/layout/forms/nsSelectsAreaFrame.cpp @@ -153,7 +153,7 @@ public: // override bounds because the list item focus ring may extend outside // the nsSelectsAreaFrame nsListControlFrame* listFrame = GetEnclosingListFrame(GetUnderlyingFrame()); - return listFrame->GetVisualOverflowRect() + + return listFrame->GetVisualOverflowRectRelativeToSelf() + aBuilder->ToReferenceFrame(listFrame); } virtual void Paint(nsDisplayListBuilder* aBuilder, diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index a49e1237512..eb3cc0137b0 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -226,7 +226,7 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) { diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 9a491fb01c4..f7868013594 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -4137,7 +4137,7 @@ public: #endif virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) { diff --git a/layout/xul/base/src/nsTextBoxFrame.cpp b/layout/xul/base/src/nsTextBoxFrame.cpp index 974d0a7fa91..0c1fde0da95 100644 --- a/layout/xul/base/src/nsTextBoxFrame.cpp +++ b/layout/xul/base/src/nsTextBoxFrame.cpp @@ -379,7 +379,7 @@ nsDisplayXULTextBox::PaintTextToContext(nsRenderingContext* aCtx, nsRect nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } nsRect From 50052a640f38c999051b05ad700e17c2ff641e45 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Thu, 20 Oct 2011 14:01:12 -0400 Subject: [PATCH 27/42] Bug 612128 followup - Adjust the assertion count because bug bug 695364 should be fixed now --- editor/libeditor/base/crashtests/crashtests.list | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editor/libeditor/base/crashtests/crashtests.list b/editor/libeditor/base/crashtests/crashtests.list index 054f51183cf..5e59732aa20 100644 --- a/editor/libeditor/base/crashtests/crashtests.list +++ b/editor/libeditor/base/crashtests/crashtests.list @@ -6,5 +6,5 @@ load 407256-1.html load 430624-1.html load 459613.html load 475132-1.xhtml -asserts-if(!Android,1) load 633709.xhtml # Bug 695364 +load 633709.xhtml asserts-if(!Android,6) load 636074-1.html # Bug 439258, charged to the wrong test due to bug 635550 From 9784f12f4d591ca2839d9c420b2778180c687c9d Mon Sep 17 00:00:00 2001 From: Benoit Girard Date: Thu, 13 Oct 2011 10:36:59 -0400 Subject: [PATCH 28/42] Bug 688844 - Stop using PBuffers for plugins on OS X. r=jrmuizel --- gfx/thebes/nsCoreAnimationSupport.h | 16 ++--- gfx/thebes/nsCoreAnimationSupport.mm | 97 ++++++++++++++-------------- 2 files changed, 56 insertions(+), 57 deletions(-) diff --git a/gfx/thebes/nsCoreAnimationSupport.h b/gfx/thebes/nsCoreAnimationSupport.h index a87ee5d2c87..c5f2badffae 100644 --- a/gfx/thebes/nsCoreAnimationSupport.h +++ b/gfx/thebes/nsCoreAnimationSupport.h @@ -60,9 +60,9 @@ typedef uint32_t IOSurfaceID; class THEBES_API nsCARenderer { NS_INLINE_DECL_REFCOUNTING(nsCARenderer) public: - nsCARenderer() : mCARenderer(nsnull), mPixelBuffer(nsnull), mOpenGLContext(nsnull), + nsCARenderer() : mCARenderer(nsnull), mFBOTexture(nsnull), mOpenGLContext(nsnull), mCGImage(nsnull), mCGData(nsnull), mIOSurface(nsnull), mFBO(nsnull), - mIOTexture(nsnull), + mIOTexture(nsnull), mUnsupportedWidth(UINT32_MAX), mUnsupportedHeight(UINT32_MAX) {} ~nsCARenderer(); nsresult SetupRenderer(void* aCALayer, int aWidth, int aHeight); @@ -72,15 +72,15 @@ public: * Render the CALayer to an IOSurface. If no IOSurface * is attached then an internal pixel buffer will be * used. - */ + */ void AttachIOSurface(nsRefPtr aSurface); IOSurfaceID GetIOSurfaceID(); - static nsresult DrawSurfaceToCGContext(CGContextRef aContext, - nsIOSurface *surf, - CGColorSpaceRef aColorSpace, + static nsresult DrawSurfaceToCGContext(CGContextRef aContext, + nsIOSurface *surf, + CGColorSpaceRef aColorSpace, int aX, int aY, size_t aWidth, size_t aHeight); - + // Remove & Add the layer without destroying // the renderer for fast back buffer swapping. void DettachCALayer(); @@ -92,7 +92,7 @@ private: void Destroy(); void *mCARenderer; - _CGLPBufferObject *mPixelBuffer; + GLuint mFBOTexture; _CGLContextObject *mOpenGLContext; CGImageRef mCGImage; void *mCGData; diff --git a/gfx/thebes/nsCoreAnimationSupport.mm b/gfx/thebes/nsCoreAnimationSupport.mm index 3f85894719b..964fc9346e0 100644 --- a/gfx/thebes/nsCoreAnimationSupport.mm +++ b/gfx/thebes/nsCoreAnimationSupport.mm @@ -402,15 +402,15 @@ void nsCARenderer::Destroy() { caRenderer.layer = nsnull; [caRenderer release]; } - if (mPixelBuffer) { - ::CGLDestroyPBuffer((CGLPBufferObj)mPixelBuffer); - } if (mOpenGLContext) { - if (mFBO || mIOTexture) { + if (mFBO || mIOTexture || mFBOTexture) { // Release these resources with the context that allocated them CGLContextObj oldContext = ::CGLGetCurrentContext(); ::CGLSetCurrentContext(mOpenGLContext); + if (mFBOTexture) { + ::glDeleteTextures(1, &mFBOTexture); + } if (mIOTexture) { ::glDeleteTextures(1, &mIOTexture); } @@ -430,7 +430,7 @@ void nsCARenderer::Destroy() { // mCGData is deallocated by cgdata_release_callback mCARenderer = nil; - mPixelBuffer = nsnull; + mFBOTexture = 0; mOpenGLContext = nsnull; mCGImage = nsnull; mIOSurface = nsnull; @@ -442,7 +442,7 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { if (aWidth == 0 || aHeight == 0) return NS_ERROR_FAILURE; - if (aWidth == mUnsupportedWidth && + if (aWidth == mUnsupportedWidth && aHeight == mUnsupportedHeight) { return NS_ERROR_FAILURE; } @@ -457,17 +457,6 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { (CGLPixelFormatAttribute)0 }; - if (!mIOSurface) { - CGLError result = ::CGLCreatePBuffer(aWidth, aHeight, - GL_TEXTURE_2D, GL_RGBA, 0, &mPixelBuffer); - if (result != kCGLNoError) { - mUnsupportedWidth = aWidth; - mUnsupportedHeight = aHeight; - Destroy(); - return NS_ERROR_FAILURE; - } - } - GLint screen; CGLPixelFormatObj format; if (::CGLChoosePixelFormat(attributes, &format, &screen) != kCGLNoError) { @@ -516,7 +505,7 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { caRenderer.bounds = CGRectMake(0, 0, aWidth, aHeight); [CATransaction commit]; - // We either target rendering to a CGImage or IOSurface. + // We target rendering to a CGImage if no shared IOSurface are given. if (!mIOSurface) { mCGData = malloc(aWidth*aHeight*4); if (!mCGData) { @@ -528,7 +517,7 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { CGDataProviderRef dataProvider = nsnull; dataProvider = ::CGDataProviderCreateWithData(mCGData, - mCGData, aHeight*aWidth*4, + mCGData, aHeight*aWidth*4, cgdata_release_callback); if (!dataProvider) { cgdata_release_callback(mCGData, mCGData, aHeight*aWidth*4); @@ -540,7 +529,7 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { CGColorSpaceRef colorSpace = CreateSystemColorSpace(); - mCGImage = ::CGImageCreate(aWidth, aHeight, 8, 32, aWidth * 4, colorSpace, + mCGImage = ::CGImageCreate(aWidth, aHeight, 8, 32, aWidth * 4, colorSpace, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host, dataProvider, NULL, true, kCGRenderingIntentDefault); @@ -554,10 +543,12 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { Destroy(); return NS_ERROR_FAILURE; } - } else { - CGLContextObj oldContext = ::CGLGetCurrentContext(); - ::CGLSetCurrentContext(mOpenGLContext); + } + CGLContextObj oldContext = ::CGLGetCurrentContext(); + ::CGLSetCurrentContext(mOpenGLContext); + + if (mIOSurface) { // Create the IOSurface mapped texture. ::glGenTextures(1, &mIOTexture); ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mIOTexture); @@ -565,35 +556,41 @@ nsresult nsCARenderer::SetupRenderer(void *aCALayer, int aWidth, int aHeight) { ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); nsIOSurfaceLib::CGLTexImageIOSurface2D(mOpenGLContext, GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, aWidth, aHeight, - GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, mIOSurface->mIOSurfacePtr, 0); ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - - // Create the fbo - ::glGenFramebuffersEXT(1, &mFBO); - ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); - ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - GL_TEXTURE_RECTANGLE_ARB, mIOTexture, 0); - - // Make sure that the Framebuffer configuration is supported on the client machine - GLenum fboStatus; - fboStatus = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); - if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT) { - NS_ERROR("FBO not supported"); - if (oldContext) - ::CGLSetCurrentContext(oldContext); - mUnsupportedWidth = aWidth; - mUnsupportedHeight = aHeight; - Destroy(); - return NS_ERROR_FAILURE; - } - - if (oldContext) - ::CGLSetCurrentContext(oldContext); + } else { + ::glGenTextures(1, &mFBOTexture); + ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, mFBOTexture); + ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + ::glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + ::glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); } - CGLContextObj oldContext = ::CGLGetCurrentContext(); - ::CGLSetCurrentContext(mOpenGLContext); + // Create the fbo + ::glGenFramebuffersEXT(1, &mFBO); + ::glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFBO); + if (mIOSurface) { + ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, mIOTexture, 0); + } else { + ::glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, mFBOTexture, 0); + } + + + // Make sure that the Framebuffer configuration is supported on the client machine + GLenum fboStatus; + fboStatus = ::glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); + if (fboStatus != GL_FRAMEBUFFER_COMPLETE_EXT) { + NS_ERROR("FBO not supported"); + if (oldContext) + ::CGLSetCurrentContext(oldContext); + mUnsupportedWidth = aWidth; + mUnsupportedHeight = aHeight; + Destroy(); + return NS_ERROR_FAILURE; + } ::glViewport(0.0, 0.0, aWidth, aHeight); ::glMatrixMode(GL_PROJECTION); @@ -682,7 +679,9 @@ nsresult nsCARenderer::Render(int aWidth, int aHeight, CGLContextObj oldContext = ::CGLGetCurrentContext(); ::CGLSetCurrentContext(mOpenGLContext); if (!mIOSurface) { - ::CGLSetPBuffer(mOpenGLContext, mPixelBuffer, 0, 0, 0); + // If no shared IOSurface is given render to our own + // texture for readback. + ::glGenTextures(1, &mFBOTexture); } GLenum result = ::glGetError(); From 40f53182bf0356f6c2597d188af682432d544a01 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 20 Oct 2011 14:41:27 -0400 Subject: [PATCH 29/42] Bug 695538 followup. Fix typo in reference and format the test to look more like the reference. --- layout/reftests/table-anonymous-boxes/695538-1-ref.html | 2 +- layout/reftests/table-anonymous-boxes/695538-1.html | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/layout/reftests/table-anonymous-boxes/695538-1-ref.html b/layout/reftests/table-anonymous-boxes/695538-1-ref.html index ead17e75620..080b6c928e2 100644 --- a/layout/reftests/table-anonymous-boxes/695538-1-ref.html +++ b/layout/reftests/table-anonymous-boxes/695538-1-ref.html @@ -16,6 +16,6 @@ display: table; } - A + A B diff --git a/layout/reftests/table-anonymous-boxes/695538-1.html b/layout/reftests/table-anonymous-boxes/695538-1.html index 7a5a686725d..16568885c8f 100644 --- a/layout/reftests/table-anonymous-boxes/695538-1.html +++ b/layout/reftests/table-anonymous-boxes/695538-1.html @@ -13,5 +13,6 @@ border: solid blue; } - A B + A +B From 92509fcd34f56c0a4a4b16f2f0020a9252191a20 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Thu, 20 Oct 2011 16:25:31 -0400 Subject: [PATCH 30/42] Bug 695538 another test followup. Make sure that the test actually _could_ pass. --- layout/reftests/table-anonymous-boxes/695538-1-ref.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/reftests/table-anonymous-boxes/695538-1-ref.html b/layout/reftests/table-anonymous-boxes/695538-1-ref.html index 080b6c928e2..00155267c68 100644 --- a/layout/reftests/table-anonymous-boxes/695538-1-ref.html +++ b/layout/reftests/table-anonymous-boxes/695538-1-ref.html @@ -13,7 +13,7 @@ border: solid blue; } .table { - display: table; + display: inline-table; } A From 9c96d8c248d9ff45827580f5baf2961821a30ec8 Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Thu, 20 Oct 2011 22:51:13 +0200 Subject: [PATCH 31/42] Bug 696158 - Adapt expiration aggressivity to the distance from the history limit. r=dietrich --- toolkit/components/places/nsPlacesExpiration.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/toolkit/components/places/nsPlacesExpiration.js b/toolkit/components/places/nsPlacesExpiration.js index 0bc8c02ed45..ce1d56afc7d 100644 --- a/toolkit/components/places/nsPlacesExpiration.js +++ b/toolkit/components/places/nsPlacesExpiration.js @@ -155,6 +155,10 @@ const SHUTDOWN_WITH_RECENT_CLEARHISTORY_TIMEOUT_SECONDS = 10; // should be analyzed again. const ANALYZE_PAGES_THRESHOLD = 100; +// If the number of pages over history limit is greater than this threshold, +// expiration will be more aggressive, to bring back history to a saner size. +const OVERLIMIT_PAGES_THRESHOLD = 1000; + const USECS_PER_DAY = 86400000000; const ANNOS_EXPIRE_POLICIES = [ { bind: "expire_days", @@ -631,16 +635,21 @@ nsPlacesExpiration.prototype = { { // Check if we are over history capacity, if so visits must be expired. this._getPagesStats((function onPagesCount(aPagesCount, aStatsCount) { - this._overLimit = aPagesCount > this._urisLimit; - let action = this._overLimit ? ACTION.TIMED_OVERLIMIT : ACTION.TIMED; + let overLimitPages = aPagesCount - this._urisLimit; + this._overLimit = overLimitPages > 0; + let action = this._overLimit ? ACTION.TIMED_OVERLIMIT : ACTION.TIMED; // If the number of pages changed significantly from the last ANALYZE // update SQLite statistics. if (Math.abs(aPagesCount - aStatsCount) >= ANALYZE_PAGES_THRESHOLD) { action = action | ACTION.TIMED_ANALYZE; } - this._expireWithActionAndLimit(action, LIMIT.SMALL); + // Adapt expiration aggressivity to the number of pages over the limit. + let limit = overLimitPages > OVERLIMIT_PAGES_THRESHOLD ? LIMIT.LARGE + : LIMIT.SMALL; + + this._expireWithActionAndLimit(action, limit); }).bind(this)); }, From 1a8ce6c37c277fdab6ea02e44796af5f17ba5942 Mon Sep 17 00:00:00 2001 From: Justin Lebar Date: Thu, 20 Oct 2011 17:38:39 -0400 Subject: [PATCH 32/42] No bug - Fix vim modelines in hal. rs=biesi DONTBUILD --- hal/HalImpl.h | 2 +- hal/HalSandbox.h | 2 +- hal/fallback/FallbackHal.cpp | 2 +- hal/sandbox/PHal.ipdl | 2 +- hal/sandbox/SandboxHal.cpp | 2 +- hal/sandbox/SandboxHal.h | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/hal/HalImpl.h b/hal/HalImpl.h index 03a56aebf0b..61b3147cfb6 100644 --- a/hal/HalImpl.h +++ b/hal/HalImpl.h @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/HalSandbox.h b/hal/HalSandbox.h index 7ee1082dee8..10ab8ffeacd 100644 --- a/hal/HalSandbox.h +++ b/hal/HalSandbox.h @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/fallback/FallbackHal.cpp b/hal/fallback/FallbackHal.cpp index 80d0a9756c8..da6b0656a52 100644 --- a/hal/fallback/FallbackHal.cpp +++ b/hal/fallback/FallbackHal.cpp @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/sandbox/PHal.ipdl b/hal/sandbox/PHal.ipdl index ff685e9ba9d..d32ac911ee6 100644 --- a/hal/sandbox/PHal.ipdl +++ b/hal/sandbox/PHal.ipdl @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/sandbox/SandboxHal.cpp b/hal/sandbox/SandboxHal.cpp index a451a7f9971..5f2d204b7b8 100644 --- a/hal/sandbox/SandboxHal.cpp +++ b/hal/sandbox/SandboxHal.cpp @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * diff --git a/hal/sandbox/SandboxHal.h b/hal/sandbox/SandboxHal.h index b9033ab162c..808544efa10 100644 --- a/hal/sandbox/SandboxHal.h +++ b/hal/sandbox/SandboxHal.h @@ -1,5 +1,5 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: sw=2 ts=8 et ft=cpp : */ +/* vim: set sw=2 ts=8 et ft=cpp : */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * From 0c4c3e74cb815240900db4e2815e32ce3f551847 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 20 Oct 2011 15:47:39 -0700 Subject: [PATCH 33/42] Back out 56ec5e954858 (from bug 685783) due to a Dromaeo regression. --- js/public/Vector.h | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/js/public/Vector.h b/js/public/Vector.h index eac50701a14..d5022d5471a 100644 --- a/js/public/Vector.h +++ b/js/public/Vector.h @@ -560,7 +560,6 @@ Vector::calculateNewCapacity(size_t curLength, size_t lengthInc, size_t &newCap) { size_t newMinCap = curLength + lengthInc; - size_t newMinSize = newMinCap * sizeof(T); /* * Check for overflow in the above addition, below CEILING_LOG2, and later @@ -572,14 +571,8 @@ Vector::calculateNewCapacity(size_t curLength, size_t lengthInc, return false; } - /* - * It's best to request 2^N sized chunks because they are unlikely to be - * rounded up by the allocator. (Asking for a 2^N number of elements isn't - * as good, because if sizeof(T) is not a power-of-two that would result in - * a non-2^N request size, which can cause waste.) - */ - size_t newSize = RoundUpPow2(newMinSize); - newCap = newSize / sizeof(T); + /* Round up to next power of 2. */ + newCap = RoundUpPow2(newMinCap); /* * Do not allow a buffer large enough that the expression ((char *)end() - From 023ca05eed566209cd04ac2ef626dec6b9220f36 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Thu, 20 Oct 2011 17:42:39 -0700 Subject: [PATCH 34/42] Bug 696211 - Align ChunkInfo by inserting padding in Chunk; r=billm We get a 2% speedup on EarlyBoyer if ChunkInfo (hot all over the GC allocator paths) is not split across a cache line. An easy and guaranteed effective way to do this is to just pad Chunk out to the full 1MiB allocation. This makes ChunkInfo abut the end of the 1MiB allocation, rather than whereever the Arenas and ChunkBitmap happen to end. Since GC Chunks are aligned at 1MiB address boundaries, this ensures that ChunkInfo is inside of a cache line. --- js/src/jsgc.h | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 45d637b9935..697ad7576ca 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -615,12 +615,22 @@ struct ChunkBitmap { JS_STATIC_ASSERT(ArenaBitmapBytes * ArenasPerChunk == sizeof(ChunkBitmap)); +const size_t ChunkPadSize = GC_CHUNK_SIZE + - (sizeof(Arena) * ArenasPerChunk) + - sizeof(ChunkBitmap) + - sizeof(ChunkInfo); +JS_STATIC_ASSERT(ChunkPadSize < BytesPerArena); + /* * Chunks contain arenas and associated data structures (mark bitmap, delayed * marking state). */ struct Chunk { Arena arenas[ArenasPerChunk]; + + /* Pad to full size to ensure cache alignment of ChunkInfo. */ + uint8 padding[ChunkPadSize]; + ChunkBitmap bitmap; ChunkInfo info; @@ -667,8 +677,7 @@ struct Chunk { inline void init(); }; -JS_STATIC_ASSERT(sizeof(Chunk) <= GC_CHUNK_SIZE); -JS_STATIC_ASSERT(sizeof(Chunk) + BytesPerArena > GC_CHUNK_SIZE); +JS_STATIC_ASSERT(sizeof(Chunk) == GC_CHUNK_SIZE); class ChunkPool { Chunk *emptyChunkListHead; From 4a97eecc777a078975ff8bae963dbfa3459dacf8 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Fri, 21 Oct 2011 14:21:40 +1300 Subject: [PATCH 35/42] Bug 695275 - Add nsIDOMWindowUtils::CheckAndClearPaintedState to test painting. r=roc --- dom/base/nsDOMWindowUtils.cpp | 17 +++++++++++++++++ dom/interfaces/base/nsIDOMWindowUtils.idl | 9 ++++++++- layout/base/FrameLayerBuilder.cpp | 4 ++++ layout/generic/nsFrame.cpp | 19 +++++++++++++++++++ layout/generic/nsIFrame.h | 7 +++++++ 5 files changed, 55 insertions(+), 1 deletion(-) diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 2d95dd6c660..65e0b8113a3 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -1941,3 +1941,20 @@ nsDOMWindowUtils::GetMayHaveTouchEventListeners(bool* aResult) return NS_OK; } +NS_IMETHODIMP +nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResult) +{ + if (!aElement) { + return NS_ERROR_INVALID_ARG; + } + + nsresult rv; + nsCOMPtr content = do_QueryInterface(aElement, &rv); + NS_ENSURE_SUCCESS(rv, rv); + + nsIFrame* frame = content->GetPrimaryFrame(); + + *aResult = frame->CheckAndClearPaintedState(); + return NS_OK; +} + diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 23e2e0d452d..9e55574e815 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -68,7 +68,7 @@ interface nsIDOMWindow; interface nsIDOMFile; interface nsIFile; -[scriptable, uuid(bc6c156a-c41f-43dd-ace3-e3bca9894ed1)] +[scriptable, uuid(910484d7-219c-4c72-b999-7a7e9c954646)] interface nsIDOMWindowUtils : nsISupports { /** @@ -919,4 +919,11 @@ interface nsIDOMWindowUtils : nsISupports { * true if the (current inner) window may have event listeners for touch events. */ readonly attribute boolean mayHaveTouchEventListeners; + + /** + * Check if any ThebesLayer painting has been done for this element, + * clears the painted flags if they have. + */ + boolean checkAndClearPaintedState(in nsIDOMElement aElement); + }; diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 30470c706dc..57c529d3584 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -2106,6 +2106,10 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, if (cdi->mInactiveLayer) { PaintInactiveLayer(builder, cdi->mItem, aContext); } else { + nsIFrame* frame = cdi->mItem->GetUnderlyingFrame(); + if (frame) { + frame->AddStateBits(NS_FRAME_PAINTED_THEBES); + } cdi->mItem->Paint(builder, rc); } diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 69e6bec0552..2a7be0aefe5 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -282,6 +282,25 @@ nsIFrame::MarkAsAbsoluteContainingBlock() { Properties().Set(AbsoluteContainingBlockProperty(), new nsAbsoluteContainingBlock(GetAbsoluteListID())); } +bool +nsIFrame::CheckAndClearPaintedState() +{ + bool result = (GetStateBits() & NS_FRAME_PAINTED_THEBES); + RemoveStateBits(NS_FRAME_PAINTED_THEBES); + + nsIFrame::ChildListIterator lists(this); + for (; !lists.IsDone(); lists.Next()) { + nsFrameList::Enumerator childFrames(lists.CurrentList()); + for (; !childFrames.AtEnd(); childFrames.Next()) { + nsIFrame* child = childFrames.get(); + if (child->CheckAndClearPaintedState()) { + result = true; + } + } + } + return result; +} + static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder, const nsIFrame* aFrame, const nsStyleDisplay* aDisp, diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index b0124063f2c..f454083fd20 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -290,6 +290,9 @@ typedef PRUint64 nsFrameState; // Frame can accept absolutely positioned children. #define NS_FRAME_HAS_ABSPOS_CHILDREN NS_FRAME_STATE_BIT(37) +// A display item for this frame has been painted as part of a ThebesLayer. +#define NS_FRAME_PAINTED_THEBES NS_FRAME_STATE_BIT(38) + // The lower 20 bits and upper 32 bits of the frame state are reserved // by this API. #define NS_FRAME_RESERVED ~NS_FRAME_IMPL_RESERVED @@ -2753,6 +2756,10 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::EmbeddingLevelProperty())) // Child frame types override this function to select their own child list name virtual mozilla::layout::FrameChildListID GetAbsoluteListID() const { return kAbsoluteList; } + // Checks if we (or any of our descendents) have NS_FRAME_PAINTED_THEBES set, and + // clears this bit if so. + bool CheckAndClearPaintedState(); + protected: // Members nsRect mRect; From 36cd8755bfe28d81f6a47bbc9d36e500dc1d9efb Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Fri, 21 Oct 2011 14:22:19 +1300 Subject: [PATCH 36/42] Bug 695275 - Fix conversion of ThebesLayers to ImageLayers. r=roc --- layout/base/FrameLayerBuilder.cpp | 27 +++++++++++++++++---------- layout/generic/nsImageFrame.cpp | 7 ++++++- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 57c529d3584..7cf4e3d5f25 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -970,6 +970,12 @@ ContainerState::PopThebesLayerData() nsRefPtr imageLayer = CreateOrRecycleImageLayer(); imageLayer->SetContainer(imageContainer); data->mImage->ConfigureLayer(imageLayer); + if (mParameters.mInActiveTransformedSubtree) { + // The layer's current transform is applied first, then the result is scaled. + gfx3DMatrix transform = imageLayer->GetTransform()* + gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f); + imageLayer->SetTransform(transform); + } NS_ASSERTION(data->mImageClip.mRoundedClipRects.IsEmpty(), "How did we get rounded clip rects here?"); if (data->mImageClip.mHaveClipRect) { @@ -1124,6 +1130,17 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState, { nscolor uniformColor; bool isUniform = aItem->IsUniform(aState->mBuilder, &uniformColor); + + /* Mark as available for conversion to image layer if this is a nsDisplayImage and + * we are the first visible item in the ThebesLayerData object. + */ + if (aItem->GetType() == nsDisplayItem::TYPE_IMAGE && mVisibleRegion.IsEmpty()) { + mImage = static_cast(aItem); + mImageClip = aClip; + } else { + mImage = nsnull; + } + // Some display items have to exist (so they can set forceTransparentSurface // below) but don't draw anything. They'll return true for isUniform but // a color with opacity 0. @@ -1152,16 +1169,6 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState, mDrawRegion.Or(mDrawRegion, aDrawRect); mDrawRegion.SimplifyOutward(4); } - - /* Mark as available for conversion to image layer if this is a nsDisplayImage and - * we are the first visible item in the ThebesLayerData object. - */ - if (aItem->GetType() == nsDisplayItem::TYPE_IMAGE && mVisibleRegion.IsEmpty()) { - mImage = static_cast(aItem); - mImageClip = aClip; - } else { - mImage = nsnull; - } bool forceTransparentSurface = false; nsRegion opaque = aItem->GetOpaqueRegion(aState->mBuilder, &forceTransparentSurface); diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 451c41fe169..45275cffd24 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -544,6 +544,7 @@ nsImageFrame::OnStartContainer(imgIRequest *aRequest, imgIContainer *aImage) */ nsPresContext *presContext = PresContext(); aImage->SetAnimationMode(presContext->ImageAnimationMode()); + mImageContainer = nsnull; if (IsPendingLoad(aRequest)) { // We don't care @@ -621,6 +622,7 @@ nsImageFrame::OnStopDecode(imgIRequest *aRequest, nsPresContext *presContext = PresContext(); nsIPresShell *presShell = presContext->GetPresShell(); NS_ASSERTION(presShell, "No PresShell."); + mImageContainer = nsnull; // Check what request type we're dealing with nsCOMPtr imageLoader = do_QueryInterface(mContent); @@ -1237,7 +1239,10 @@ nsDisplayImage::ConfigureLayer(ImageLayer* aLayer) nsRefPtr nsImageFrame::GetContainer(LayerManager* aManager, imgIContainer* aImage) { - if (mImageContainer && mImageContainer->Manager() == aManager) { + if (mImageContainer && + (mImageContainer->Manager() == aManager || + (!mImageContainer->Manager() && + (mImageContainer->GetBackendType() == aManager->GetBackendType())))) { return mImageContainer; } From 2b175a9ca10416a745666f21645e4487a55dea78 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Fri, 21 Oct 2011 14:23:05 +1300 Subject: [PATCH 37/42] Bug 695275 - Add test for ThebesLayer -> ImageLayer conversion. r=roc --- layout/base/tests/Makefile.in | 3 ++ layout/base/tests/image_rgrg-256x256.png | Bin 0 -> 131 bytes layout/base/tests/image_rrgg-256x256.png | Bin 0 -> 120 bytes layout/base/tests/test_image_layers.html | 46 +++++++++++++++++++++++ 4 files changed, 49 insertions(+) create mode 100644 layout/base/tests/image_rgrg-256x256.png create mode 100644 layout/base/tests/image_rrgg-256x256.png create mode 100644 layout/base/tests/test_image_layers.html diff --git a/layout/base/tests/Makefile.in b/layout/base/tests/Makefile.in index d241d692af3..16464fe0d0b 100644 --- a/layout/base/tests/Makefile.in +++ b/layout/base/tests/Makefile.in @@ -65,6 +65,9 @@ _TEST_FILES = \ border_radius_hit_testing_iframe.html \ test_preserve3d_sorting_hit_testing.html \ preserve3d_sorting_hit_testing_iframe.html \ + test_image_layers.html \ + image_rgrg-256x256.png \ + image_rrgg-256x256.png \ bug369950-subframe.xml \ decoration_line_rendering.js \ test_after_paint_pref.html \ diff --git a/layout/base/tests/image_rgrg-256x256.png b/layout/base/tests/image_rgrg-256x256.png new file mode 100644 index 0000000000000000000000000000000000000000..e6fba3daa5dfc788eaeedb73636e82abfedc8ae5 GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K585o&?RN5XZRUpL{;1lA?@E-^nF3$E^2NbdJ zba4#HxcBygq7VZE$Kefs|6hKPZW*&`@vN1XK>A@orcocp1kyImtX-KO9z9rOVgwTP MboFyt=akR{0Mu9^N&o-= literal 0 HcmV?d00001 diff --git a/layout/base/tests/image_rrgg-256x256.png b/layout/base/tests/image_rrgg-256x256.png new file mode 100644 index 0000000000000000000000000000000000000000..7f6351565473f4b8db1fa69530700491f7c88a54 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K585o&?RN5XZRUpL{;1lA?@E-^nF3$E^2Ncou zba4#HxcBzdMqUO64(0{_{%@Ig;oy#gKFc~3IGSMSkRebhgH5!(>W4@ApRc=tc%H6) JF6*2UngH?+BB1~P literal 0 HcmV?d00001 diff --git a/layout/base/tests/test_image_layers.html b/layout/base/tests/test_image_layers.html new file mode 100644 index 00000000000..cba1522a394 --- /dev/null +++ b/layout/base/tests/test_image_layers.html @@ -0,0 +1,46 @@ + + + + Test that images that are the only item in ThebesLayers get put into ImageLayers + + + + +
    + +
    +
    +
    +
    + + From dadc414f5ecafe891eefb0bd189c9940486eea5c Mon Sep 17 00:00:00 2001 From: "Oleg Romashin ext:(%2C%20Matt%20Woodrow%20%3Cmwoodrow%40mozilla.com%3E)" Date: Fri, 21 Oct 2011 14:29:09 +1300 Subject: [PATCH 38/42] Bug 695406 - Reset IPC double buffers if the ContentType has changed. r=cjones --- gfx/layers/basic/BasicLayers.cpp | 40 ++++++++++++++++++++++------ gfx/layers/opengl/CanvasLayerOGL.cpp | 3 ++- gfx/layers/opengl/ImageLayerOGL.cpp | 3 ++- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/gfx/layers/basic/BasicLayers.cpp b/gfx/layers/basic/BasicLayers.cpp index 9e9b852cb2c..2c3ea16a3ab 100644 --- a/gfx/layers/basic/BasicLayers.cpp +++ b/gfx/layers/basic/BasicLayers.cpp @@ -2389,7 +2389,8 @@ class BasicShadowableImageLayer : public BasicImageLayer, { public: BasicShadowableImageLayer(BasicShadowLayerManager* aManager) : - BasicImageLayer(aManager) + BasicImageLayer(aManager), + mBufferIsOpaque(false) { MOZ_COUNT_CTOR(BasicShadowableImageLayer); } @@ -2451,6 +2452,7 @@ private: // For YUV Images these are the 3 planes (Y, Cb and Cr), // for RGB images only mBackSurface is used. SurfaceDescriptor mBackBuffer; + bool mBufferIsOpaque; nsRefPtr mBackBufferY; nsRefPtr mBackBufferU; nsRefPtr mBackBufferV; @@ -2518,12 +2520,16 @@ BasicShadowableImageLayer::Paint(gfxContext* aContext) if (!pat || !HasShadow()) return; - if (oldSize != mSize || !IsSurfaceDescriptorValid(mBackBuffer)) { + bool isOpaque = (GetContentFlags() & CONTENT_OPAQUE); + if (oldSize != mSize || + !IsSurfaceDescriptorValid(mBackBuffer) || + isOpaque != mBufferIsOpaque) { DestroyBackBuffer(); + mBufferIsOpaque = isOpaque; if (!BasicManager()->AllocBuffer( mSize, - (GetContentFlags() & CONTENT_OPAQUE) ? + isOpaque ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA, &mBackBuffer)) NS_RUNTIMEABORT("creating ImageLayer 'front buffer' failed!"); @@ -2575,7 +2581,8 @@ class BasicShadowableCanvasLayer : public BasicCanvasLayer, { public: BasicShadowableCanvasLayer(BasicShadowLayerManager* aManager) : - BasicCanvasLayer(aManager) + BasicCanvasLayer(aManager), + mBufferIsOpaque(false) { MOZ_COUNT_CTOR(BasicShadowableCanvasLayer); } @@ -2622,6 +2629,7 @@ private: } SurfaceDescriptor mBackBuffer; + bool mBufferIsOpaque; }; void @@ -2651,10 +2659,14 @@ BasicShadowableCanvasLayer::Paint(gfxContext* aContext) return; } - if (!IsSurfaceDescriptorValid(mBackBuffer)) { + bool isOpaque = (GetContentFlags() & CONTENT_OPAQUE); + if (!IsSurfaceDescriptorValid(mBackBuffer) || + isOpaque != mBufferIsOpaque) { + DestroyBackBuffer(); + mBufferIsOpaque = isOpaque; if (!BasicManager()->AllocBuffer( gfxIntSize(mBounds.width, mBounds.height), - (GetContentFlags() & CONTENT_OPAQUE) ? + isOpaque ? gfxASurface::CONTENT_COLOR : gfxASurface::CONTENT_COLOR_ALPHA, &mBackBuffer)) NS_RUNTIMEABORT("creating CanvasLayer back buffer failed!"); @@ -2943,7 +2955,13 @@ BasicShadowImageLayer::Swap(const SharedImage& aNewFront, nsRefPtr surface = BasicManager()->OpenDescriptor(aNewFront); // Destroy mFrontBuffer if size different - if (surface->GetSize() != mSize) { + bool needDrop = false; + if (IsSurfaceDescriptorValid(mFrontBuffer)) { + nsRefPtr front = BasicManager()->OpenDescriptor(mFrontBuffer); + needDrop = surface->GetSize() != mSize || + surface->GetContentType() != front->GetContentType(); + } + if (needDrop) { DestroyFrontBuffer(); mSize = surface->GetSize(); } @@ -3059,7 +3077,13 @@ BasicShadowCanvasLayer::Swap(const CanvasSurface& aNewFront, bool needYFlip, BasicManager()->OpenDescriptor(aNewFront); // Destroy mFrontBuffer if size different gfxIntSize sz = surface->GetSize(); - if (sz != gfxIntSize(mBounds.width, mBounds.height)) { + bool needDrop = false; + if (IsSurfaceDescriptorValid(mFrontSurface)) { + nsRefPtr front = BasicManager()->OpenDescriptor(mFrontSurface); + needDrop = sz != gfxIntSize(mBounds.width, mBounds.height) || + surface->GetContentType() != front->GetContentType(); + } + if (needDrop) { DestroyFrontBuffer(); mBounds.SetRect(0, 0, sz.width, sz.height); } diff --git a/gfx/layers/opengl/CanvasLayerOGL.cpp b/gfx/layers/opengl/CanvasLayerOGL.cpp index c1338e0945f..77cad933cb9 100644 --- a/gfx/layers/opengl/CanvasLayerOGL.cpp +++ b/gfx/layers/opengl/CanvasLayerOGL.cpp @@ -324,7 +324,8 @@ ShadowCanvasLayerOGL::Swap(const CanvasSurface& aNewFront, if (!mDestroyed) { nsRefPtr surf = ShadowLayerForwarder::OpenDescriptor(aNewFront); gfxIntSize sz = surf->GetSize(); - if (!mTexImage || mTexImage->GetSize() != sz) { + if (!mTexImage || mTexImage->GetSize() != sz || + mTexImage->GetContentType() != surf->GetContentType()) { Init(aNewFront, needYFlip); } nsIntRegion updateRegion(nsIntRect(0, 0, sz.width, sz.height)); diff --git a/gfx/layers/opengl/ImageLayerOGL.cpp b/gfx/layers/opengl/ImageLayerOGL.cpp index 0bfe44eb506..8681ac13fcc 100644 --- a/gfx/layers/opengl/ImageLayerOGL.cpp +++ b/gfx/layers/opengl/ImageLayerOGL.cpp @@ -885,7 +885,8 @@ ShadowImageLayerOGL::Swap(const SharedImage& aNewFront, nsRefPtr surf = ShadowLayerForwarder::OpenDescriptor(aNewFront.get_SurfaceDescriptor()); gfxIntSize size = surf->GetSize(); - if (mSize != size || !mTexImage) { + if (mSize != size || !mTexImage || + mTexImage->GetContentType() != surf->GetContentType()) { Init(aNewFront); } // XXX this is always just ridiculously slow From 93fde9b68ecc85a6e87f822c1b5ff0eb6c6abba2 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Fri, 21 Oct 2011 14:33:00 +1300 Subject: [PATCH 39/42] Bug 695275 - Follow-up to fix review comments that I missed. --- dom/base/nsDOMWindowUtils.cpp | 4 ++++ layout/base/FrameLayerBuilder.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 65e0b8113a3..8d754648d72 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -1953,6 +1953,10 @@ nsDOMWindowUtils::CheckAndClearPaintedState(nsIDOMElement* aElement, bool* aResu NS_ENSURE_SUCCESS(rv, rv); nsIFrame* frame = content->GetPrimaryFrame(); + if (!frame) { + *aResult = false; + return NS_OK; + } *aResult = frame->CheckAndClearPaintedState(); return NS_OK; diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 7cf4e3d5f25..1a18cf5069c 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -973,7 +973,7 @@ ContainerState::PopThebesLayerData() if (mParameters.mInActiveTransformedSubtree) { // The layer's current transform is applied first, then the result is scaled. gfx3DMatrix transform = imageLayer->GetTransform()* - gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f); + gfx3DMatrix::ScalingMatrix(mParameters.mXScale, mParameters.mYScale, 1.0f); imageLayer->SetTransform(transform); } NS_ASSERTION(data->mImageClip.mRoundedClipRects.IsEmpty(), From ac9ee510543a35ea14601254cf563c023293e653 Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 21 Oct 2011 14:41:36 +1300 Subject: [PATCH 40/42] Bug 681867. text-overflow only needs to affect the scrolling behavior of the block container with text-overflow. r=mats --- layout/generic/TextOverflow.cpp | 20 +++----------------- layout/generic/TextOverflow.h | 7 ------- layout/generic/nsBlockFrame.cpp | 5 ----- layout/generic/nsGfxScrollFrame.cpp | 4 ++++ layout/generic/nsGfxScrollFrame.h | 6 ++++++ 5 files changed, 13 insertions(+), 29 deletions(-) diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp index c5a74997768..29ba6a226b9 100644 --- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -51,6 +51,7 @@ #include "nsRect.h" #include "nsRenderingContext.h" #include "nsTextFrame.h" +#include "nsGfxScrollFrame.h" namespace mozilla { namespace css { @@ -278,6 +279,8 @@ TextOverflow::WillProcessLines(nsDisplayListBuilder* aBuilder, textOverflow->mCanHaveHorizontalScrollbar = scroll->GetScrollbarStyles().mHorizontal != NS_STYLE_OVERFLOW_HIDDEN; textOverflow->mContentArea.MoveBy(scroll->GetScrollPosition()); + nsIFrame* scrollFrame = do_QueryFrame(scroll); + scrollFrame->AddStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL); } PRUint8 direction = aBlockFrame->GetStyleVisibility()->mDirection; textOverflow->mBlockIsRTL = direction == NS_STYLE_DIRECTION_RTL; @@ -290,23 +293,6 @@ TextOverflow::WillProcessLines(nsDisplayListBuilder* aBuilder, return textOverflow.forget(); } -void -TextOverflow::DidProcessLines() -{ - nsIScrollableFrame* scroll = nsLayoutUtils::GetScrollableFrameFor(mBlock); - if (scroll) { - // Create a dummy item covering the entire area, it doesn't paint - // but reports true for IsVaryingRelativeToMovingFrame(). - nsIFrame* scrollFrame = do_QueryFrame(scroll); - nsDisplayItem* marker = new (mBuilder) - nsDisplayForcePaintOnScroll(mBuilder, scrollFrame); - if (marker) { - mMarkerList->AppendNewToBottom(marker); - mBlock->PresContext()->SetHasFixedBackgroundFrame(); - } - } -} - void TextOverflow::ExamineFrameSubtree(nsIFrame* aFrame, const nsRect& aContentArea, diff --git a/layout/generic/TextOverflow.h b/layout/generic/TextOverflow.h index 0f8eaa2a2b4..abba2b3eb4c 100644 --- a/layout/generic/TextOverflow.h +++ b/layout/generic/TextOverflow.h @@ -52,7 +52,6 @@ namespace css { * Usage: * 1. allocate an object using WillProcessLines * 2. then call ProcessLine for each line you are building display lists for - * 3. finally call DidProcessLines */ class TextOverflow { public: @@ -70,12 +69,6 @@ class TextOverflow { */ void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine); - /** - * Do final processing, currently just adds a dummy item for scroll frames - * to make IsVaryingRelativeToMovingFrame() true for the entire area. - */ - void DidProcessLines(); - /** * @return true if aBlockFrame needs analysis for text overflow. */ diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 161b6913a71..bf7b9de51ee 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -6247,11 +6247,6 @@ nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, } } - // Finalize text-overflow processing. - if (textOverflow) { - textOverflow->DidProcessLines(); - } - if (NS_SUCCEEDED(rv) && (nsnull != mBullet) && HaveOutsideBullet()) { // Display outside bullets manually rv = BuildDisplayListForChild(aBuilder, mBullet, aDirtyRect, aLists); diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 69ee18c5ea3..065ec8e70d1 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1619,6 +1619,9 @@ static void AdjustViews(nsIFrame* aFrame) static bool CanScrollWithBlitting(nsIFrame* aFrame) { + if (aFrame->GetStateBits() & NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL) + return false; + for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) { if (nsSVGIntegrationUtils::UsingEffectsForFrame(f) || @@ -1732,6 +1735,7 @@ void nsGfxScrollFrameInner::ScrollVisual() // to be consistent with the frame hierarchy. PRUint32 flags = nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT; bool canScrollWithBlitting = CanScrollWithBlitting(mOuter); + mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL); if (IsScrollingActive()) { if (!canScrollWithBlitting) { MarkInactive(); diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index 43e24107724..77fd7a0d42c 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -64,6 +64,12 @@ class nsIScrollFrameInternal; class nsPresState; struct ScrollReflowState; +// When set, the next scroll operation on the scrollframe will invalidate its +// entire contents. Useful for text-overflow. +// This bit is cleared after each time the scrollframe is scrolled. Whoever +// needs to set it should set it again on each paint. +#define NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL NS_FRAME_STATE_BIT(20) + class nsGfxScrollFrameInner : public nsIReflowCallback { public: class AsyncScroll; From 88740ba6da7f038f5eff21121560ca450ce4adfa Mon Sep 17 00:00:00 2001 From: Robert O'Callahan Date: Fri, 21 Oct 2011 14:41:36 +1300 Subject: [PATCH 41/42] Bug 681867. Part 2: remove nsDisplayForcePaintOnScroll. r=mats --- layout/base/nsDisplayList.cpp | 17 ----------------- layout/base/nsDisplayList.h | 18 ------------------ 2 files changed, 35 deletions(-) diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index bef625719a2..ba2ce9f3954 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2977,20 +2977,3 @@ bool nsDisplaySVGEffects::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem other->mBounds + other->mEffectsFrame->GetOffsetTo(mEffectsFrame)); return true; } - -nsDisplayForcePaintOnScroll::nsDisplayForcePaintOnScroll( - nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) - : nsDisplayItem(aBuilder, aFrame) { - MOZ_COUNT_CTOR(nsDisplayForcePaintOnScroll); -} - -#ifdef NS_BUILD_REFCNT_LOGGING -nsDisplayForcePaintOnScroll::~nsDisplayForcePaintOnScroll() { - MOZ_COUNT_DTOR(nsDisplayForcePaintOnScroll); -} -#endif - -bool nsDisplayForcePaintOnScroll::IsVaryingRelativeToMovingFrame( - nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) { - return true; -} diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index f805e8a7f27..59a3a18d918 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -2261,22 +2261,4 @@ public: nscoord mRightEdge; // length from the right side }; - -/** - * This is a dummy item that reports true for IsVaryingRelativeToMovingFrame. - * It forces the bounds of its frame to be repainted every time it is scrolled. - * It is transparent to events and does not paint anything. - */ -class nsDisplayForcePaintOnScroll : public nsDisplayItem -{ -public: - nsDisplayForcePaintOnScroll(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame); -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayForcePaintOnScroll(); -#endif - NS_DISPLAY_DECL_NAME("ForcePaintOnScroll", TYPE_FORCEPAINTONSCROLL) - virtual bool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder, - nsIFrame* aFrame); -}; - #endif /*NSDISPLAYLIST_H_*/ From 79abab2e7b088b5dde369253f9304b0e595c94d4 Mon Sep 17 00:00:00 2001 From: Timothy Nikkel Date: Thu, 20 Oct 2011 20:59:47 -0500 Subject: [PATCH 42/42] Backout 18f70ede04b0 (bug 694213). --- layout/forms/nsButtonFrameRenderer.cpp | 2 +- layout/forms/nsSelectsAreaFrame.cpp | 2 +- layout/generic/nsBulletFrame.cpp | 2 +- layout/generic/nsTextFrameThebes.cpp | 2 +- layout/xul/base/src/nsTextBoxFrame.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp index 916438376fc..563ba2e73cf 100644 --- a/layout/forms/nsButtonFrameRenderer.cpp +++ b/layout/forms/nsButtonFrameRenderer.cpp @@ -114,7 +114,7 @@ private: nsRect nsDisplayButtonBoxShadowOuter::GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); } void diff --git a/layout/forms/nsSelectsAreaFrame.cpp b/layout/forms/nsSelectsAreaFrame.cpp index 10506d92ce7..9c4fc4b518f 100644 --- a/layout/forms/nsSelectsAreaFrame.cpp +++ b/layout/forms/nsSelectsAreaFrame.cpp @@ -153,7 +153,7 @@ public: // override bounds because the list item focus ring may extend outside // the nsSelectsAreaFrame nsListControlFrame* listFrame = GetEnclosingListFrame(GetUnderlyingFrame()); - return listFrame->GetVisualOverflowRectRelativeToSelf() + + return listFrame->GetVisualOverflowRect() + aBuilder->ToReferenceFrame(listFrame); } virtual void Paint(nsDisplayListBuilder* aBuilder, diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index eb3cc0137b0..a49e1237512 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -226,7 +226,7 @@ public: virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); } virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) { diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index f7868013594..9a491fb01c4 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -4137,7 +4137,7 @@ public: #endif virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); } virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) { diff --git a/layout/xul/base/src/nsTextBoxFrame.cpp b/layout/xul/base/src/nsTextBoxFrame.cpp index 0c1fde0da95..974d0a7fa91 100644 --- a/layout/xul/base/src/nsTextBoxFrame.cpp +++ b/layout/xul/base/src/nsTextBoxFrame.cpp @@ -379,7 +379,7 @@ nsDisplayXULTextBox::PaintTextToContext(nsRenderingContext* aCtx, nsRect nsDisplayXULTextBox::GetBounds(nsDisplayListBuilder* aBuilder) { - return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); + return mFrame->GetVisualOverflowRect() + ToReferenceFrame(); } nsRect