diff --git a/docshell/base/nsIContentViewer.idl b/docshell/base/nsIContentViewer.idl index e8a399051f..dcf0087e59 100644 --- a/docshell/base/nsIContentViewer.idl +++ b/docshell/base/nsIContentViewer.idl @@ -31,7 +31,7 @@ class nsDOMNavigationTiming; [ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming); [ref] native nsIContentViewerTArray(nsTArray >); -[scriptable, builtinclass, uuid(702e0a92-7d63-490e-b5ee-d247e6bd4588)] +[scriptable, builtinclass, uuid(2da17016-7851-4a45-a7a8-00b360e01595)] interface nsIContentViewer : nsISupports { @@ -245,6 +245,18 @@ interface nsIContentViewer : nsISupports */ [noscript] void appendSubtree(in nsIContentViewerTArray array); + /** + * Instruct the refresh driver to discontinue painting until further + * notice. + */ + void pausePainting(); + + /** + * Instruct the refresh driver to resume painting after a previous call to + * pausePainting(). + */ + void resumePainting(); + /* * Render the document as if being viewed on a device with the specified * media type. This will cause a reflow. diff --git a/dom/animation/CSSPseudoElement.cpp b/dom/animation/CSSPseudoElement.cpp index 791990f0ee..e27f3d646a 100644 --- a/dom/animation/CSSPseudoElement.cpp +++ b/dom/animation/CSSPseudoElement.cpp @@ -36,6 +36,12 @@ CSSPseudoElement::~CSSPseudoElement() } } +ParentObject +CSSPseudoElement::GetParentObject() const +{ + return mParentElement->GetParentObject(); +} + JSObject* CSSPseudoElement::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { diff --git a/dom/animation/CSSPseudoElement.h b/dom/animation/CSSPseudoElement.h index f5c2a05145..4082a07aa7 100644 --- a/dom/animation/CSSPseudoElement.h +++ b/dom/animation/CSSPseudoElement.h @@ -11,6 +11,7 @@ #include "mozilla/Attributes.h" #include "mozilla/ErrorResult.h" #include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/Element.h" #include "mozilla/RefPtr.h" #include "nsCSSPseudoElements.h" #include "nsWrapperCache.h" @@ -32,10 +33,7 @@ protected: virtual ~CSSPseudoElement(); public: - ParentObject GetParentObject() const - { - return mParentElement->GetParentObject(); - } + ParentObject GetParentObject() const; virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; @@ -46,7 +44,12 @@ public: MOZ_ASSERT(nsCSSPseudoElements::GetPseudoAtom(mPseudoType), "All pseudo-types allowed by this class should have a" " corresponding atom"); - nsCSSPseudoElements::GetPseudoAtom(mPseudoType)->ToString(aRetVal); + // Our atoms use one colon and we would like to return two colons syntax + // for the returned pseudo type string, so serialize this to the + // non-deprecated two colon syntax. + aRetVal.Assign(char16_t(':')); + aRetVal.Append( + nsDependentAtomString(nsCSSPseudoElements::GetPseudoAtom(mPseudoType))); } already_AddRefed ParentElement() const { diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 233827cdb2..74bec69b6d 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -3700,8 +3700,10 @@ nsDOMWindowUtils::GetContentAPZTestData(JSContext* aContext, if (nsIWidget* widget = GetWidget()) { RefPtr lm = widget->GetLayerManager(); - if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { - ClientLayerManager* clm = static_cast(lm.get()); + if (!lm) { + return NS_OK; + } + if (ClientLayerManager* clm = lm->AsClientLayerManager()) { if (!clm->GetAPZTestData().ToJS(aOutContentTestData, aContext)) { return NS_ERROR_FAILURE; } @@ -3719,8 +3721,10 @@ nsDOMWindowUtils::GetCompositorAPZTestData(JSContext* aContext, if (nsIWidget* widget = GetWidget()) { RefPtr lm = widget->GetLayerManager(); - if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { - ClientLayerManager* clm = static_cast(lm.get()); + if (!lm) { + return NS_OK; + } + if (ClientLayerManager* clm = lm->AsClientLayerManager()) { APZTestData compositorSideData; clm->GetCompositorSideAPZTestData(&compositorSideData); if (!compositorSideData.ToJS(aOutCompositorTestData, aContext)) { @@ -3955,9 +3959,8 @@ nsDOMWindowUtils::SetNextPaintSyncId(int32_t aSyncId) MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome()); if (nsIWidget* widget = GetWidget()) { RefPtr lm = widget->GetLayerManager(); - if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { - ClientLayerManager* clm = static_cast(lm.get()); - clm->SetNextPaintSyncId(aSyncId); + if (lm && lm->AsClientLayerManager()) { + lm->AsClientLayerManager()->SetNextPaintSyncId(aSyncId); return NS_OK; } } diff --git a/dom/bindings/Exceptions.cpp b/dom/bindings/Exceptions.cpp index 80ac49e204..582f9355a2 100644 --- a/dom/bindings/Exceptions.cpp +++ b/dom/bindings/Exceptions.cpp @@ -159,6 +159,7 @@ CreateException(JSContext* aCx, nsresult aRv, const nsACString& aMessage) case NS_ERROR_MODULE_DOM_FILEHANDLE: case NS_ERROR_MODULE_DOM_BLUETOOTH: case NS_ERROR_MODULE_DOM_ANIM: + case NS_ERROR_MODULE_DOM_PUSH: if (aMessage.IsEmpty()) { return DOMException::Create(aRv); } diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index c57fb3aca8..6779408ea2 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -2793,7 +2793,7 @@ TabChild::DidComposite(uint64_t aTransactionId, MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT); - RefPtr manager = + ClientLayerManager *manager = static_cast(mPuppetWidget->GetLayerManager()); manager->DidComposite(aTransactionId, aCompositeStart, aCompositeEnd); @@ -2827,8 +2827,7 @@ TabChild::ClearCachedResources() MOZ_ASSERT(mPuppetWidget->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT); - ClientLayerManager *manager = - static_cast(mPuppetWidget->GetLayerManager()); + ClientLayerManager *manager = mPuppetWidget->GetLayerManager()->AsClientLayerManager(); manager->ClearCachedResources(); } diff --git a/dom/permission/PermissionSettings.js b/dom/permission/PermissionSettings.js index 6e8d3adb4d..6393eda1d0 100644 --- a/dom/permission/PermissionSettings.js +++ b/dom/permission/PermissionSettings.js @@ -78,7 +78,7 @@ PermissionSettings.prototype = { set: function set(aPermName, aPermValue, aManifestURL, aOrigin, aBrowserFlag) { debug("Set called with: " + aPermName + ", " + aManifestURL + ", " + - aOrigin + ", " + aPermValue + ", " + aBrowserFlag); + aOrigin + ", " + aPermValue + ", " + aBrowserFlag); let currentPermValue = this.get(aPermName, aManifestURL, aOrigin, aBrowserFlag); let action; diff --git a/dom/permission/Permissions.cpp b/dom/permission/Permissions.cpp index d114ecea3a..a185f8e56b 100644 --- a/dom/permission/Permissions.cpp +++ b/dom/permission/Permissions.cpp @@ -122,8 +122,8 @@ CheckPermission(JSContext* aCx, case PermissionName::Push: return CheckPushPermission(aCx, aPermission, aWindow, aResult); - case PermissionName::Midi: default: + MOZ_ASSERT_UNREACHABLE("Unhandled type"); return NS_ERROR_NOT_IMPLEMENTED; } } diff --git a/dom/plugins/ipc/PluginMessageUtils.h b/dom/plugins/ipc/PluginMessageUtils.h index 1e5f1a5f28..97a1247259 100644 --- a/dom/plugins/ipc/PluginMessageUtils.h +++ b/dom/plugins/ipc/PluginMessageUtils.h @@ -23,6 +23,9 @@ #include "nsTArray.h" #include "mozilla/Logging.h" #include "nsHashKeys.h" +#ifdef MOZ_CRASHREPORTER +# include "nsExceptionHandler.h" +#endif #ifdef XP_MACOSX #include "PluginInterposeOSX.h" #else @@ -100,7 +103,7 @@ struct NPRemoteWindow typedef HWND NativeWindowHandle; #elif defined(MOZ_X11) typedef XID NativeWindowHandle; -#elif defined(XP_MACOSX) || defined(ANDROID) || defined(MOZ_WIDGET_QT) +#elif defined(XP_DARWIN) || defined(ANDROID) || defined(MOZ_WIDGET_QT) typedef intptr_t NativeWindowHandle; // never actually used, will always be 0 #else #error Need NativeWindowHandle for this platform @@ -195,7 +198,7 @@ inline bool IsPluginThread() inline void AssertPluginThread() { - NS_ASSERTION(IsPluginThread(), "Should be on the plugin's main thread!"); + MOZ_RELEASE_ASSERT(IsPluginThread(), "Should be on the plugin's main thread!"); } #define ENSURE_PLUGIN_THREAD(retval) \ @@ -405,44 +408,6 @@ struct ParamTraits } }; -template <> -struct ParamTraits -{ - typedef NPString paramType; - - static void Write(Message* aMsg, const paramType& aParam) - { - WriteParam(aMsg, aParam.UTF8Length); - aMsg->WriteBytes(aParam.UTF8Characters, - aParam.UTF8Length * sizeof(NPUTF8)); - } - - static bool Read(const Message* aMsg, void** aIter, paramType* aResult) - { - if (ReadParam(aMsg, aIter, &aResult->UTF8Length)) { - int byteCount = aResult->UTF8Length * sizeof(NPUTF8); - if (!byteCount) { - aResult->UTF8Characters = "\0"; - return true; - } - - const char* messageBuffer = nullptr; - mozilla::UniquePtr newBuffer(new char[byteCount]); - if (newBuffer && aMsg->ReadBytes(aIter, &messageBuffer, byteCount )) { - memcpy((void*)messageBuffer, newBuffer.get(), byteCount); - aResult->UTF8Characters = newBuffer.release(); - return true; - } - } - return false; - } - - static void Log(const paramType& aParam, std::wstring* aLog) - { - aLog->append(StringPrintf(L"%s", aParam.UTF8Characters)); - } -}; - #ifdef XP_MACOSX template <> struct ParamTraits @@ -608,142 +573,6 @@ struct ParamTraits }; #endif // #ifdef XP_MACOSX -template <> -struct ParamTraits -{ - typedef NPVariant paramType; - - static void Write(Message* aMsg, const paramType& aParam) - { - if (NPVARIANT_IS_VOID(aParam)) { - aMsg->WriteInt(0); - return; - } - - if (NPVARIANT_IS_NULL(aParam)) { - aMsg->WriteInt(1); - return; - } - - if (NPVARIANT_IS_BOOLEAN(aParam)) { - aMsg->WriteInt(2); - WriteParam(aMsg, NPVARIANT_TO_BOOLEAN(aParam)); - return; - } - - if (NPVARIANT_IS_INT32(aParam)) { - aMsg->WriteInt(3); - WriteParam(aMsg, NPVARIANT_TO_INT32(aParam)); - return; - } - - if (NPVARIANT_IS_DOUBLE(aParam)) { - aMsg->WriteInt(4); - WriteParam(aMsg, NPVARIANT_TO_DOUBLE(aParam)); - return; - } - - if (NPVARIANT_IS_STRING(aParam)) { - aMsg->WriteInt(5); - WriteParam(aMsg, NPVARIANT_TO_STRING(aParam)); - return; - } - - NS_ERROR("Unsupported type!"); - } - - static bool Read(const Message* aMsg, void** aIter, paramType* aResult) - { - int type; - if (!aMsg->ReadInt(aIter, &type)) { - return false; - } - - switch (type) { - case 0: - VOID_TO_NPVARIANT(*aResult); - return true; - - case 1: - NULL_TO_NPVARIANT(*aResult); - return true; - - case 2: { - bool value; - if (ReadParam(aMsg, aIter, &value)) { - BOOLEAN_TO_NPVARIANT(value, *aResult); - return true; - } - } break; - - case 3: { - int32_t value; - if (ReadParam(aMsg, aIter, &value)) { - INT32_TO_NPVARIANT(value, *aResult); - return true; - } - } break; - - case 4: { - double value; - if (ReadParam(aMsg, aIter, &value)) { - DOUBLE_TO_NPVARIANT(value, *aResult); - return true; - } - } break; - - case 5: { - NPString value; - if (ReadParam(aMsg, aIter, &value)) { - STRINGN_TO_NPVARIANT(value.UTF8Characters, value.UTF8Length, - *aResult); - return true; - } - } break; - - default: - NS_ERROR("Unsupported type!"); - } - - return false; - } - - static void Log(const paramType& aParam, std::wstring* aLog) - { - if (NPVARIANT_IS_VOID(aParam)) { - aLog->append(L"[void]"); - return; - } - - if (NPVARIANT_IS_NULL(aParam)) { - aLog->append(L"[null]"); - return; - } - - if (NPVARIANT_IS_BOOLEAN(aParam)) { - LogParam(NPVARIANT_TO_BOOLEAN(aParam), aLog); - return; - } - - if (NPVARIANT_IS_INT32(aParam)) { - LogParam(NPVARIANT_TO_INT32(aParam), aLog); - return; - } - - if (NPVARIANT_IS_DOUBLE(aParam)) { - LogParam(NPVARIANT_TO_DOUBLE(aParam), aLog); - return; - } - - if (NPVARIANT_IS_STRING(aParam)) { - LogParam(NPVARIANT_TO_STRING(aParam), aLog); - return; - } - - NS_ERROR("Unsupported type!"); - } -}; - template <> struct ParamTraits { diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 93ac6cc2bb..405234f270 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -33,6 +33,7 @@ #include "nsCRT.h" #include "nsIFile.h" #include "nsIObserverService.h" +#include "nsIXULRuntime.h" #include "nsNPAPIPlugin.h" #include "nsPrintfCString.h" #include "prsystem.h" @@ -133,16 +134,6 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId, return true; } *rv = PPluginModule::Bridge(aContentParent, chromeParent); - if (NS_FAILED(*rv)) { -#if defined(MOZ_CRASHREPORTER) - // We are going to abort due to the failure, lets note the cause - // in the report for diagnosing. - nsAutoCString error; - error.AppendPrintf("%X %d", *rv, chromeParent->GetIPCChannel()->GetChannelState__TotallyRacy()); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BridgePluginError"), error); -#endif - return false; - } return true; } @@ -673,7 +664,8 @@ PluginModuleParent::PluginModuleParent(bool aIsChrome, bool aAllowAsyncInit) { #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) mIsStartingAsync = aAllowAsyncInit && - Preferences::GetBool(kAsyncInitPref, false); + Preferences::GetBool(kAsyncInitPref, false) && + !BrowserTabsRemoteAutostart(); #if defined(MOZ_CRASHREPORTER) CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AsyncPluginInit"), mIsStartingAsync ? diff --git a/dom/plugins/ipc/PluginProcessChild.cpp b/dom/plugins/ipc/PluginProcessChild.cpp index 98ea1b48f0..85a6bb500f 100644 --- a/dom/plugins/ipc/PluginProcessChild.cpp +++ b/dom/plugins/ipc/PluginProcessChild.cpp @@ -35,16 +35,6 @@ using mozilla::ipc::IOThreadChild; #ifdef OS_WIN #include "nsSetDllDirectory.h" #include - -namespace { - -std::size_t caseInsensitiveFind(std::string aHaystack, std::string aNeedle) { - std::transform(aHaystack.begin(), aHaystack.end(), aHaystack.begin(), ::tolower); - std::transform(aNeedle.begin(), aNeedle.end(), aNeedle.begin(), ::tolower); - return aHaystack.find(aNeedle); -} - -} #endif namespace mozilla { diff --git a/dom/power/WakeLock.h b/dom/power/WakeLock.h index 29553334a8..3c6873e675 100644 --- a/dom/power/WakeLock.h +++ b/dom/power/WakeLock.h @@ -15,7 +15,7 @@ #include "nsWrapperCache.h" #include "mozilla/ErrorResult.h" -class nsIDOMWindow; +class nsPIDOMWindowInner; namespace mozilla { namespace dom { diff --git a/dom/push/PushManager.cpp b/dom/push/PushManager.cpp index 7a659df5e4..54f8c9aba2 100644 --- a/dom/push/PushManager.cpp +++ b/dom/push/PushManager.cpp @@ -105,7 +105,7 @@ public: if (NS_SUCCEEDED(aStatus)) { mPromise->MaybeResolve(aSuccess); } else { - mPromise->MaybeReject(NS_ERROR_DOM_NETWORK_ERR); + mPromise->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE); } return NS_OK; @@ -403,7 +403,7 @@ public: if (NS_SUCCEEDED(mStatus)) { promise->MaybeResolve(mSuccess); } else { - promise->MaybeReject(NS_ERROR_DOM_NETWORK_ERR); + promise->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE); } mProxy->CleanUp(aCx); @@ -477,10 +477,16 @@ public: Run() override { AssertIsOnMainThread(); - MutexAutoLock lock(mProxy->Lock()); - if (mProxy->CleanedUp()) { - return NS_OK; + + nsCOMPtr principal; + { + MutexAutoLock lock(mProxy->Lock()); + if (mProxy->CleanedUp()) { + return NS_OK; + } + principal = mProxy->GetWorkerPrivate()->GetPrincipal(); } + MOZ_ASSERT(principal); RefPtr callback = new WorkerUnsubscribeResultCallback(mProxy); @@ -492,7 +498,6 @@ public: return NS_OK; } - nsCOMPtr principal = mProxy->GetWorkerPrivate()->GetPrincipal(); if (NS_WARN_IF(NS_FAILED(service->Unsubscribe(mScope, principal, callback)))) { callback->OnUnsubscribe(NS_ERROR_FAILURE, false); return NS_OK; @@ -523,7 +528,7 @@ WorkerPushSubscription::Unsubscribe(ErrorResult &aRv) RefPtr proxy = PromiseWorkerProxy::Create(worker, p); if (!proxy) { - p->MaybeReject(NS_ERROR_DOM_NETWORK_ERR); + p->MaybeReject(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE); return p.forget(); } @@ -593,6 +598,8 @@ public: mRawP256dhKey, mAuthSecret); promise->MaybeResolve(sub); } + } else if (NS_ERROR_GET_MODULE(mStatus) == NS_ERROR_MODULE_DOM_PUSH ) { + promise->MaybeReject(mStatus); } else { promise->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR); } @@ -742,15 +749,23 @@ public: Run() override { AssertIsOnMainThread(); - MutexAutoLock lock(mProxy->Lock()); - if (mProxy->CleanedUp()) { - return NS_OK; + + nsCOMPtr principal; + { + // Bug 1228723: If permission is revoked or an error occurs, the + // subscription callback will be called synchronously. This causes + // `GetSubscriptionCallback::OnPushSubscription` to deadlock when + // it tries to acquire the lock. + MutexAutoLock lock(mProxy->Lock()); + if (mProxy->CleanedUp()) { + return NS_OK; + } + principal = mProxy->GetWorkerPrivate()->GetPrincipal(); } + MOZ_ASSERT(principal); RefPtr callback = new GetSubscriptionCallback(mProxy, mScope); - nsCOMPtr principal = mProxy->GetWorkerPrivate()->GetPrincipal(); - PushPermissionState state; nsresult rv = GetPermissionState(principal, state); if (NS_FAILED(rv)) { @@ -763,7 +778,7 @@ public: callback->OnPushSubscriptionError(NS_OK); return NS_OK; } - callback->OnPushSubscriptionError(NS_ERROR_FAILURE); + callback->OnPushSubscriptionError(NS_ERROR_DOM_PUSH_DENIED_ERR); return NS_OK; } diff --git a/dom/push/test/frame.html b/dom/push/test/frame.html index 6ab58b76b8..50036db15e 100644 --- a/dom/push/test/frame.html +++ b/dom/push/test/frame.html @@ -4,20 +4,18 @@ diff --git a/dom/push/test/mochitest.ini b/dom/push/test/mochitest.ini index 9b08ae3524..7d176125d9 100644 --- a/dom/push/test/mochitest.ini +++ b/dom/push/test/mochitest.ini @@ -6,6 +6,7 @@ support-files = frame.html webpush.js lifetime_worker.js + test_utils.js [test_has_permissions.html] skip-if = os == "android" || toolkit == "gonk" @@ -21,6 +22,8 @@ skip-if = os == "android" || toolkit == "gonk" skip-if = os == "android" || toolkit == "gonk" [test_multiple_register_different_scope.html] skip-if = os == "android" || toolkit == "gonk" +[test_subscription_change.html] +skip-if = os == "android" || toolkit == "gonk" [test_data.html] skip-if = os == "android" || toolkit == "gonk" # Disabled for too many intermittent failures (bug 1164432) diff --git a/dom/push/test/test_data.html b/dom/push/test/test_data.html index 119f9586b6..d1ed78bf5e 100644 --- a/dom/push/test/test_data.html +++ b/dom/push/test/test_data.html @@ -11,6 +11,7 @@ http://creativecommons.org/licenses/publicdomain/ Test for Bug 1185544 + @@ -25,25 +26,10 @@ http://creativecommons.org/licenses/publicdomain/ + + @@ -27,111 +29,63 @@ http://creativecommons.org/licenses/publicdomain/ // console.log(str + "\n"); } - var controlledFrame; - function createControlledIFrame(swr) { - var p = new Promise(function(res, rej) { - var iframe = document.createElement('iframe'); - iframe.id = "controlledFrame"; - iframe.src = "http://mochi.test:8888/tests/dom/push/test/frame.html"; - - iframe.onload = function() { - res(swr) - } - controlledFrame = iframe; - document.body.appendChild(iframe); - }); - return p; - } - - function checkPermissionState(swr) { - return swr.pushManager.permissionState().then(function(state) { - ok(state === "granted", "permissionState() should resolve to granted."); - return swr; - }).catch(function(e) { - ok(false, "permissionState() should resolve to granted."); - return swr; - }); - } - - function sendPushToPushServer(pushEndpoint) { - // Work around CORS for now. - var xhr = new XMLHttpRequest(); - xhr.open('GET', "http://mochi.test:8888/tests/dom/push/test/push-server.sjs", true); - xhr.setRequestHeader("X-Push-Server", pushEndpoint); - xhr.onload = function(e) { - debug("xhr : " + this.status); - } - xhr.onerror = function(e) { - debug("xhr error: " + e); - } - xhr.send("version=24601"); - } - var registration; + add_task(function* start() { + yield setupPrefs(); + yield setPushPermission(true); - function start() { - return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."}) - .then((swr) => registration = swr); - } + var url = "worker.js" + "?" + (Math.random()); + registration = yield navigator.serviceWorker.register(url, {scope: "."}); + }); - function unregister() { - return registration.unregister().then(function(result) { - ok(result, "Unregister should return true."); - }, function(e) { - dump("Unregistering the SW failed with " + e + "\n"); + var controlledFrame; + add_task(function* createControlledIFrame() { + controlledFrame = yield injectControlledFrame(); + }); + + add_task(function* checkPermissionState() { + var state = yield registration.pushManager.permissionState(); + is(state, "granted", "permissionState() should resolve to granted."); + }); + + var pushSubscription; + add_task(function* subscribe() { + pushSubscription = yield registration.pushManager.subscribe(); + }); + + add_task(function* resubscribe() { + var data = yield sendRequestToWorker({ + type: "resubscribe", + endpoint: pushSubscription.endpoint, }); - } + pushSubscription = yield registration.pushManager.getSubscription(); + is(data.endpoint, pushSubscription.endpoint, + "Subscription endpoints should match after resubscribing in worker"); + }); - function setupPushNotification(swr) { - var p = new Promise(function(res, rej) { - swr.pushManager.subscribe().then( - function(pushSubscription) { - ok(true, "successful registered for push notification"); - res(pushSubscription); - }, function(error) { - ok(false, "could not register for push notification"); - res(null); - } - ); - }); - return p; - } + add_task(function* waitForPushNotification() { + yield Promise.all([ + controlledFrame.waitOnWorkerMessage("finished"), + fetch("http://mochi.test:8888/tests/dom/push/test/push-server.sjs", { + method: "PUT", + headers: { + "X-Push-Method": "POST", + "X-Push-Server": pushSubscription.endpoint, + }, + }), + ]); + }); - function unregisterPushNotification(pushSubscription) { - controlledFrame.parentNode.removeChild(controlledFrame); - controlledFrame = null; - return pushSubscription.unsubscribe(); - } + add_task(function* unsubscribe() { + controlledFrame.remove(); + yield pushSubscription.unsubscribe(); + }); - function waitForPushNotification(pushSubscription) { - var p = controlledFrame.contentWindow.waitOnPushMessage(); - sendPushToPushServer(pushSubscription.endpoint); - return p.then(function() { - return pushSubscription; - }); - } + add_task(function* unregister() { + var result = yield registration.unregister(); + ok(result, "Unregister should return true."); + }); - function runTest() { - start() - .then(createControlledIFrame) - .then(checkPermissionState) - .then(setupPushNotification) - .then(waitForPushNotification) - .then(unregisterPushNotification) - .then(unregister) - .catch(function(e) { - ok(false, "Some test failed with error " + e); - }).then(SimpleTest.finish); - } - - SpecialPowers.pushPrefEnv({"set": [ - ["dom.push.enabled", true], - ["dom.serviceWorkers.exemptFromPerDomainMax", true], - ["dom.serviceWorkers.enabled", true], - ["dom.serviceWorkers.testing.enabled", true] - ]}, runTest); - SpecialPowers.addPermission('push', true, document); - SimpleTest.waitForExplicitFinish(); diff --git a/dom/push/test/test_subscription_change.html b/dom/push/test/test_subscription_change.html new file mode 100644 index 0000000000..7b8ef0a214 --- /dev/null +++ b/dom/push/test/test_subscription_change.html @@ -0,0 +1,68 @@ + + + + + Test for Bug 1205109 + + + + + + +Mozilla Bug 1205109 +

+ +
+
+ + + + diff --git a/dom/push/test/test_utils.js b/dom/push/test/test_utils.js new file mode 100644 index 0000000000..f18363bab0 --- /dev/null +++ b/dom/push/test/test_utils.js @@ -0,0 +1,60 @@ +// Remove permissions and prefs when the test finishes. +SimpleTest.registerCleanupFunction(() => + new Promise(resolve => { + SpecialPowers.flushPermissions(_ => { + SpecialPowers.flushPrefEnv(resolve); + }); + }) +); + +function setPushPermission(allow) { + return new Promise(resolve => { + SpecialPowers.pushPermissions([ + { type: "desktop-notification", allow, context: document }, + ], resolve); + }); +} + +function setupPrefs() { + return new Promise(resolve => { + SpecialPowers.pushPrefEnv({"set": [ + ["dom.push.enabled", true], + ["dom.serviceWorkers.exemptFromPerDomainMax", true], + ["dom.serviceWorkers.enabled", true], + ["dom.serviceWorkers.testing.enabled", true] + ]}, resolve); + }); +} + +function injectControlledFrame(target = document.body) { + return new Promise(function(res, rej) { + var iframe = document.createElement("iframe"); + iframe.src = "/tests/dom/push/test/frame.html"; + + var controlledFrame = { + remove() { + target.removeChild(iframe); + iframe = null; + }, + waitOnWorkerMessage(type) { + return iframe ? iframe.contentWindow.waitOnWorkerMessage(type) : + Promise.reject(new Error("Frame removed from document")); + }, + }; + + iframe.onload = () => res(controlledFrame); + target.appendChild(iframe); + }); +} + +function sendRequestToWorker(request) { + return navigator.serviceWorker.ready.then(registration => { + return new Promise((resolve, reject) => { + var channel = new MessageChannel(); + channel.port1.onmessage = e => { + (e.data.error ? reject : resolve)(e.data); + }; + registration.active.postMessage(request, [channel.port2]); + }); + }); +} diff --git a/dom/push/test/worker.js b/dom/push/test/worker.js index 23ff23941f..53e6b2118b 100644 --- a/dom/push/test/worker.js +++ b/dom/push/test/worker.js @@ -1,8 +1,16 @@ // Any copyright is dedicated to the Public Domain. // http://creativecommons.org/licenses/publicdomain/ +// This worker is used for two types of tests. `handlePush` sends messages to +// `frame.html`, which verifies that the worker can receive push messages. + +// `handleMessage` receives messages from `test_push_manager_worker.html` +// and `test_data.html`, and verifies that `PushManager` can be used from +// the worker. + this.onpush = handlePush; this.onmessage = handleMessage; +this.onpushsubscriptionchange = handlePushSubscriptionChange; function getJSON(data) { var result = { @@ -17,48 +25,105 @@ function getJSON(data) { return result; } -function handlePush(event) { +function assert(value, message) { + if (!value) { + throw new Error(message); + } +} - event.waitUntil(self.clients.matchAll().then(function(result) { - if (event instanceof PushEvent) { - if (!('data' in event)) { - result[0].postMessage({type: "finished", okay: "yes"}); - return; - } - var message = { - type: "finished", - okay: "yes", - }; - if (event.data) { - message.data = { - text: event.data.text(), - arrayBuffer: event.data.arrayBuffer(), - json: getJSON(event.data), - blob: event.data.blob(), - }; - } - result[0].postMessage(message); +function broadcast(event, promise) { + event.waitUntil(Promise.resolve(promise).then(message => { + return self.clients.matchAll().then(clients => { + clients.forEach(client => client.postMessage(message)); + }); + })); +} + +function reply(event, promise) { + event.waitUntil(Promise.resolve(promise).then(result => { + event.ports[0].postMessage(result); + }).catch(error => { + event.ports[0].postMessage({ + error: String(error), + }); + })); +} + +function handlePush(event) { + if (event instanceof PushEvent) { + if (!('data' in event)) { + broadcast(event, {type: "finished", okay: "yes"}); return; } - result[0].postMessage({type: "finished", okay: "no"}); - })); + var message = { + type: "finished", + okay: "yes", + }; + if (event.data) { + message.data = { + text: event.data.text(), + arrayBuffer: event.data.arrayBuffer(), + json: getJSON(event.data), + blob: event.data.blob(), + }; + } + broadcast(event, message); + return; + } + broadcast(event, {type: "finished", okay: "no"}); } function handleMessage(event) { if (event.data.type == "publicKey") { - event.waitUntil(self.registration.pushManager.getSubscription().then(subscription => { - event.ports[0].postMessage({ + reply(event, self.registration.pushManager.getSubscription().then( + subscription => ({ p256dh: subscription.getKey("p256dh"), auth: subscription.getKey("auth"), - }); - }).catch(error => { - event.ports[0].postMessage({ - error: String(error), - }); + }) + )); + return; + } + if (event.data.type == "resubscribe") { + reply(event, self.registration.pushManager.getSubscription().then( + subscription => { + assert(subscription.endpoint == event.data.endpoint, + "Wrong push endpoint in worker"); + return subscription.unsubscribe(); + } + ).then(result => { + assert(result, "Error unsubscribing in worker"); + return self.registration.pushManager.getSubscription(); + }).then(subscription => { + assert(!subscription, "Subscription not removed in worker"); + return self.registration.pushManager.subscribe(); + }).then(subscription => { + return { + endpoint: subscription.endpoint, + }; })); return; } - event.ports[0].postMessage({ - error: "Invalid message type: " + event.data.type, - }); + if (event.data.type == "denySubscribe") { + reply(event, self.registration.pushManager.getSubscription().then( + subscription => { + assert(!subscription, + "Should not return worker subscription with revoked permission"); + return self.registration.pushManager.subscribe().then(_ => { + assert(false, "Expected error subscribing with revoked permission"); + }, error => { + return { + isDOMException: error instanceof DOMException, + name: error.name, + }; + }); + } + )); + return; + } + reply(event, Promise.reject( + "Invalid message type: " + event.data.type)); +} + +function handlePushSubscriptionChange(event) { + broadcast(event, {type: "changed", okay: "yes"}); } diff --git a/dom/webidl/Permissions.webidl b/dom/webidl/Permissions.webidl index 0c7f8f30d0..17574c75e5 100644 --- a/dom/webidl/Permissions.webidl +++ b/dom/webidl/Permissions.webidl @@ -10,8 +10,8 @@ enum PermissionName { "geolocation", "notifications", - "push", - "midi" + "push" + // Unsupported: "midi" }; dictionary PermissionDescriptor { diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp index 3b5027d667..e12b688a04 100644 --- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -92,6 +92,7 @@ #include "nsJSUtils.h" #include "mozilla/dom/URL.h" #include "nsIContentPolicy.h" +#include "mozAutoDocUpdate.h" using namespace mozilla; using namespace mozilla::dom; @@ -2967,10 +2968,14 @@ XULDocument::DoneWalking() // XXXldb This is where we should really be setting the chromehidden // attribute. - uint32_t count = mOverlaySheets.Length(); - for (uint32_t i = 0; i < count; ++i) { - AddStyleSheet(mOverlaySheets[i]); + { + mozAutoDocUpdate updateBatch(this, UPDATE_STYLE, true); + uint32_t count = mOverlaySheets.Length(); + for (uint32_t i = 0; i < count; ++i) { + AddStyleSheet(mOverlaySheets[i]); + } } + mOverlaySheets.Clear(); if (!mDocumentLoaded) { diff --git a/editor/libeditor/nsTableEditor.cpp b/editor/libeditor/nsTableEditor.cpp index 664db9ecaf..277a165b05 100644 --- a/editor/libeditor/nsTableEditor.cpp +++ b/editor/libeditor/nsTableEditor.cpp @@ -599,6 +599,7 @@ nsHTMLEditor::InsertTableRow(int32_t aNumber, bool aAfter) // We are adding a new row after all others // If it weren't for colspan=0 effect, // we could simply use colCount for number of new cells... + // XXX colspan=0 support has now been removed in table layout so maybe this can be cleaned up now? (bug 1243183) cellsInRow = colCount; // ...but we must compensate for all cells with rowSpan = 0 in the last row diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 002fa13ae3..5ef82fcb4c 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -885,9 +885,11 @@ AsyncPanZoomController::GetSharedFrameMetricsCompositor() APZThreadUtils::AssertOnCompositorThread(); if (mSharingFrameMetricsAcrossProcesses) { - const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(mLayersId); // |state| may be null here if the CrossProcessCompositorParent has already been destroyed. - return state ? state->mCrossProcessParent : nullptr; + if (const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(mLayersId)) { + return state->CrossProcessPCompositor(); + } + return nullptr; } return mCompositorParent.get(); } diff --git a/gfx/layers/ipc/CompositorParent.cpp b/gfx/layers/ipc/CompositorParent.cpp index 087b70d402..af3cca858a 100644 --- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -1977,6 +1977,12 @@ private: bool mNotifyAfterRemotePaint; }; +PCompositorParent* +CompositorParent::LayerTreeState::CrossProcessPCompositor() const +{ + return mCrossProcessParent; +} + void CompositorParent::DidComposite(TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd) diff --git a/gfx/layers/ipc/CompositorParent.h b/gfx/layers/ipc/CompositorParent.h index 470c5b5149..e21f29577c 100644 --- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -56,6 +56,7 @@ class CompositorParent; class LayerManagerComposite; class LayerTransactionParent; class PAPZParent; +class CrossProcessCompositorParent; struct ScopedLayerTreeRegistration { @@ -389,7 +390,7 @@ public: // Pointer to the CrossProcessCompositorParent. Used by APZCs to share // their FrameMetrics with the corresponding child process that holds // the PCompositorChild - PCompositorParent* mCrossProcessParent; + CrossProcessCompositorParent* mCrossProcessParent; TargetConfig mTargetConfig; APZTestData mApzTestData; LayerTransactionParent* mLayerTree; @@ -397,6 +398,8 @@ public: bool mUpdatedPluginDataAvailable; RefPtr mLayerTreeReadyObserver; RefPtr mLayerTreeClearedObserver; + + PCompositorParent* CrossProcessPCompositor() const; }; /** diff --git a/gfx/thebes/gfxPlatformMac.cpp b/gfx/thebes/gfxPlatformMac.cpp index f9ab0c6336..77e5d6f923 100644 --- a/gfx/thebes/gfxPlatformMac.cpp +++ b/gfx/thebes/gfxPlatformMac.cpp @@ -99,12 +99,14 @@ gfxPlatformMac::gfxPlatformMac() MacIOSurfaceLib::LoadLibrary(); } -#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) gfxPlatformMac::~gfxPlatformMac() { +#if defined(MAC_OS_X_VERSION_10_6) && (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) gfxCoreTextShaper::Shutdown(); +#endif } +#if defined(MAC_OS_X_VERSION_10_5) && (MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5) ByteCount gfxPlatformMac::GetCachedDirSizeForFont(nsString name) { diff --git a/gfx/thebes/gfxScriptItemizer.cpp b/gfx/thebes/gfxScriptItemizer.cpp index b6091a0c3f..24e823de76 100644 --- a/gfx/thebes/gfxScriptItemizer.cpp +++ b/gfx/thebes/gfxScriptItemizer.cpp @@ -175,7 +175,7 @@ gfxScriptItemizer::Next(uint32_t& aRunStart, uint32_t& aRunLimit, * We only do this if the script is COMMON; for chars with * specific script assignments, we just use them as-is. */ - GetGeneralCategory(ch); + gc = GetGeneralCategory(ch); if (gc == HB_UNICODE_GENERAL_CATEGORY_OPEN_PUNCTUATION) { uint32_t endPairChar = mozilla::unicode::GetMirroredChar(ch); if (endPairChar != ch) { diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h index de4f1757dc..6152b527fa 100644 --- a/layout/base/RestyleManager.h +++ b/layout/base/RestyleManager.h @@ -442,6 +442,10 @@ public: void PostRebuildAllStyleDataEvent(nsChangeHint aExtraHint, nsRestyleHint aRestyleHint); +#ifdef DEBUG + bool InRebuildAllStyleData() const { return mInRebuildAllStyleData; } +#endif + #ifdef RESTYLE_LOGGING /** * Returns whether a restyle event currently being processed by this diff --git a/layout/base/RestyleTracker.cpp b/layout/base/RestyleTracker.cpp index c0ff65e78e..1d2935f8f0 100644 --- a/layout/base/RestyleTracker.cpp +++ b/layout/base/RestyleTracker.cpp @@ -413,8 +413,19 @@ RestyleTracker::GetRestyleData(Element* aElement, nsAutoPtr& aData) // element. Leave it around for now, but remove the other restyle // hints and the change hint for it. Also unset its root bit, // since it's no longer a root with the new restyle data. - NS_ASSERTION(aData->mDescendants.IsEmpty(), + + // During a normal restyle, we should have already processed the + // mDescendants array the last time we processed the restyle + // for this element. But in RebuildAllStyleData, we don't initially + // expand out eRestyle_LaterSiblings, so we can get in here the + // first time we need to process a restyle for this element. In that + // case, it's fine for us to have a non-empty mDescendants, since + // we know that RebuildAllStyleData adds eRestyle_ForceDescendants + // and we're guaranteed we'll restyle the entire tree. + NS_ASSERTION(mRestyleManager->InRebuildAllStyleData() || + aData->mDescendants.IsEmpty(), "expected descendants to be handled by now"); + RestyleData* newData = new RestyleData; newData->mChangeHint = nsChangeHint(0); newData->mRestyleHint = eRestyle_LaterSiblings; diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 5595c78e94..425a365fe6 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -3998,7 +3998,7 @@ GetDashInfo(nscoord aBorderLength, } void -nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, +nsCSSRendering::DrawTableBorderSegment(DrawTarget& aDrawTarget, uint8_t aBorderStyle, nscolor aBorderColor, const nsStyleBackground* aBGColor, @@ -4021,14 +4021,6 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, aEndBevelOffset = 0; } - gfxContext *ctx = aContext.ThebesContext(); - AntialiasMode oldMode = ctx->CurrentAntialiasMode(); - ctx->SetAntialiasMode(AntialiasMode::NONE); - - ctx->SetColor(Color::FromABGR(aBorderColor)); - - DrawTarget& drawTarget = *aContext.GetDrawTarget(); - switch (aBorderStyle) { case NS_STYLE_BORDER_STYLE_NONE: case NS_STYLE_BORDER_STYLE_HIDDEN: @@ -4051,36 +4043,36 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, GetDashInfo(aBorder.width, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength); nsRect rect(aBorder.x, aBorder.y, startDashLength, aBorder.height); - DrawSolidBorderSegment(drawTarget, rect, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel); rect.x += startDashLength + dashLength; rect.width = aBorder.width - (startDashLength + endDashLength + dashLength); - DrawDashedSegment(drawTarget, rect, dashLength, aBorderColor, + DrawDashedSegment(aDrawTarget, rect, dashLength, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, horizontal); rect.x += rect.width; rect.width = endDashLength; - DrawSolidBorderSegment(drawTarget, rect, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel); } else { GetDashInfo(aBorder.height, dashLength, twipsPerPixel, numDashSpaces, startDashLength, endDashLength); nsRect rect(aBorder.x, aBorder.y, aBorder.width, startDashLength); - DrawSolidBorderSegment(drawTarget, rect, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel); rect.y += rect.height + dashLength; rect.height = aBorder.height - (startDashLength + endDashLength + dashLength); - DrawDashedSegment(drawTarget, rect, dashLength, aBorderColor, + DrawDashedSegment(aDrawTarget, rect, dashLength, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, horizontal); rect.y += rect.height; rect.height = endDashLength; - DrawSolidBorderSegment(drawTarget, rect, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, rect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel); } } @@ -4092,7 +4084,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if ((horizontal && (twipsPerPixel >= aBorder.height)) || (!horizontal && (twipsPerPixel >= aBorder.width))) { // a one pixel border - DrawSolidBorderSegment(drawTarget, aBorder, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, aBorder, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, aStartBevelOffset, aEndBevelSide, aEndBevelOffset); @@ -4108,8 +4100,6 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, nscolor bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor); - // XXXbz is this SetColor call still needed? - ctx->SetColor(Color::FromABGR(bevelColor)); nsRect rect(aBorder); nscoord half; if (horizontal) { // top, bottom @@ -4122,7 +4112,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_TOP == aEndBevelSide) { rect.width -= endBevel; } - DrawSolidBorderSegment(drawTarget, rect, bevelColor, + DrawSolidBorderSegment(aDrawTarget, rect, bevelColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, startBevel, aEndBevelSide, endBevel); @@ -4137,7 +4127,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_LEFT == aEndBevelSide) { rect.height -= endBevel; } - DrawSolidBorderSegment(drawTarget, rect, bevelColor, + DrawSolidBorderSegment(aDrawTarget, rect, bevelColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, startBevel, aEndBevelSide, endBevel); @@ -4149,8 +4139,6 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, // background color, but I don't care. bevelColor = MakeBevelColor(ridgeGrooveSide, ridgeGroove, aBGColor->mBackgroundColor, aBorderColor); - // XXXbz is this SetColor call still needed? - ctx->SetColor(Color::FromABGR(bevelColor)); if (horizontal) { rect.y = rect.y + half; rect.height = aBorder.height - half; @@ -4161,7 +4149,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_BOTTOM == aEndBevelSide) { rect.width -= endBevel; } - DrawSolidBorderSegment(drawTarget, rect, bevelColor, + DrawSolidBorderSegment(aDrawTarget, rect, bevelColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, startBevel, aEndBevelSide, endBevel); @@ -4176,7 +4164,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_RIGHT == aEndBevelSide) { rect.height -= endBevel; } - DrawSolidBorderSegment(drawTarget, rect, bevelColor, + DrawSolidBorderSegment(aDrawTarget, rect, bevelColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, startBevel, aEndBevelSide, endBevel); @@ -4205,7 +4193,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_TOP == aEndBevelSide) { topRect.width -= aEndBevelOffset - endBevel; } - DrawSolidBorderSegment(drawTarget, topRect, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, topRect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, startBevel, aEndBevelSide, endBevel); @@ -4220,7 +4208,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_BOTTOM == aEndBevelSide) { bottomRect.width -= aEndBevelOffset - endBevel; } - DrawSolidBorderSegment(drawTarget, bottomRect, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, bottomRect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, startBevel, aEndBevelSide, endBevel); @@ -4236,7 +4224,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_LEFT == aEndBevelSide) { leftRect.height -= aEndBevelOffset - endBevel; } - DrawSolidBorderSegment(drawTarget, leftRect, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, leftRect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, startBevel, aEndBevelSide, endBevel); @@ -4250,7 +4238,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, if (NS_SIDE_RIGHT == aEndBevelSide) { rightRect.height -= aEndBevelOffset - endBevel; } - DrawSolidBorderSegment(drawTarget, rightRect, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, rightRect, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, startBevel, aEndBevelSide, endBevel); @@ -4260,7 +4248,7 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, // else fall through to solid MOZ_FALLTHROUGH; case NS_STYLE_BORDER_STYLE_SOLID: - DrawSolidBorderSegment(drawTarget, aBorder, aBorderColor, + DrawSolidBorderSegment(aDrawTarget, aBorder, aBorderColor, aAppUnitsPerDevPixel, twipsPerPixel, aStartBevelSide, aStartBevelOffset, aEndBevelSide, aEndBevelOffset); break; @@ -4272,8 +4260,6 @@ nsCSSRendering::DrawTableBorderSegment(nsRenderingContext& aContext, NS_ASSERTION(false, "Unexpected 'auto' table border"); break; } - - ctx->SetAntialiasMode(oldMode); } // End table border-collapsing section diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h index 83ecfa2c9f..b546768930 100644 --- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -656,8 +656,8 @@ struct nsCSSRendering { // Draw a border segment in the table collapsing border model without // beveling corners - static void DrawTableBorderSegment(nsRenderingContext& aContext, - uint8_t aBorderStyle, + static void DrawTableBorderSegment(DrawTarget& aDrawTarget, + uint8_t aBorderStyle, nscolor aBorderColor, const nsStyleBackground* aBGColor, const nsRect& aBorderRect, diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 7637fa9050..d891d61f7f 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -2888,6 +2888,17 @@ nsDocumentViewer::CallChildren(CallChildFunc aFunc, void* aClosure) } } +static void +ChangeChildPaintingEnabled(nsIContentViewer* aChild, void* aClosure) +{ + bool* enablePainting = (bool*) aClosure; + if (*enablePainting) { + aChild->ResumePainting(); + } else { + aChild->PausePainting(); + } +} + struct ZoomInfo { float mZoom; @@ -3317,6 +3328,34 @@ NS_IMETHODIMP nsDocumentViewer::AppendSubtree(nsTArrayPausePainting(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocumentViewer::ResumePainting() +{ + bool enablePaint = true; + CallChildren(ChangeChildPaintingEnabled, &enablePaint); + + nsIPresShell* presShell = GetPresShell(); + if (presShell) { + presShell->ResumePainting(); + } + + return NS_OK; +} + NS_IMETHODIMP nsDocumentViewer::GetContentSize(int32_t* aWidth, int32_t* aHeight) { diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index f4774ceb81..bd0274478a 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -137,10 +137,10 @@ typedef struct CapturingContentInfo { mozilla::StaticRefPtr mContent; } CapturingContentInfo; -// 6654f67f-c5aa-4934-b611-6d8d01e6193f +// f17842ee-f1f0-4193-814f-70d706b67060 #define NS_IPRESSHELL_IID \ -{ 0x6654f67f, 0xc5aa, 0x4934, \ - { 0xb6, 0x11, 0x6d, 0x8d, 0x01, 0xe6, 0x19, 0x3f } } +{ 0xf17842ee, 0xf1f0, 0x4193, \ + { 0x81, 0x4f, 0x70, 0xd7, 0x06, 0xb6, 0x70, 0x60 } } // debug VerifyReflow flags #define VERIFY_REFLOW_ON 0x01 @@ -908,6 +908,20 @@ public: */ bool IsPaintingSuppressed() const { return mPaintingSuppressed; } + /** + * Pause painting by freezing the refresh driver of this and all parent + * presentations. This may not have the desired effect if this pres shell + * has its own refresh driver. + */ + virtual void PausePainting() = 0; + + /** + * Resume painting by thawing the refresh driver of this and all parent + * presentations. This may not have the desired effect if this pres shell + * has its own refresh driver. + */ + virtual void ResumePainting() = 0; + /** * Unsuppress painting. */ @@ -1773,6 +1787,7 @@ protected: bool mFontSizeInflationForceEnabled; bool mFontSizeInflationDisabledInMasterProcess; bool mFontSizeInflationEnabled; + bool mPaintingIsFrozen; // Dirty bit indicating that mFontSizeInflationEnabled needs to be recomputed. bool mFontSizeInflationEnabledIsDirty; diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 89133f2e30..83f7b4ba79 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -29,6 +29,7 @@ #include "mozilla/ToString.h" #include "nsHTMLReflowMetrics.h" #include "ImageContainer.h" +#include "gfx2DGlue.h" #include #include diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 040a6d3ca1..ca240e8371 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -747,6 +747,7 @@ PresShell::PresShell() mSelectionFlags = nsISelectionDisplay::DISPLAY_TEXT | nsISelectionDisplay::DISPLAY_IMAGES; mIsThemeSupportDisabled = false; mIsActive = true; + mIsHidden = false; // FIXME/bug 735029: find a better solution to this problem #if defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_ANDROID_APZ) // The java pan/zoom code uses this to mean approximately "request a @@ -778,6 +779,7 @@ PresShell::PresShell() addedPointerEventEnabled = true; } + mPaintingIsFrozen = false; mHasCSSBackgroundColor = true; mIsLastChromeOnlyEscapeKeyConsumed = false; mHasReceivedPaintMessage = false; @@ -801,6 +803,13 @@ PresShell::~PresShell() mLastCallbackEventRequest == nullptr, "post-reflow queues not empty. This means we're leaking"); + // Verify that if painting was frozen, but we're being removed from the tree, + // that we now re-enable painting on our refresh driver, since it may need to + // be re-used by another presentation. + if (mPaintingIsFrozen) { + mPresContext->RefreshDriver()->Thaw(); + } + #ifdef DEBUG MOZ_ASSERT(mPresArenaAllocCount == 0, "Some pres arena objects were not freed"); @@ -10451,6 +10460,10 @@ void PresShell::QueryIsActive() if (docshell) { bool isActive; nsresult rv = docshell->GetIsActive(&isActive); + // Even though in theory the docshell here could be "Inactive and + // Foreground", thus implying aIsHidden=false for SetIsActive(), + // this is a newly created PresShell so we'd like to invalidate anyway + // upon being made active to ensure that the contents get painted. if (NS_SUCCEEDED(rv)) SetIsActive(isActive); } @@ -10488,6 +10501,11 @@ PresShell::SetIsActive(bool aIsActive, bool aIsHidden) NS_PRECONDITION(mDocument, "should only be called with a document"); mIsActive = aIsActive; + + // Keep track of whether we've called TabChild::MakeHidden() or not. + // This can still be true even if aIsHidden is false. + mIsHidden |= aIsHidden; + nsPresContext* presContext = GetPresContext(); if (presContext && presContext->RefreshDriver()->PresContext() == presContext) { @@ -10527,10 +10545,14 @@ PresShell::SetIsActive(bool aIsActive, bool aIsHidden) // and (ii) has easy access to the TabChild. So we use this // notification to signal the TabChild to drop its layer tree and // stop trying to repaint. - if (aIsHidden) { + if (mIsHidden) { if (TabChild* tab = TabChild::GetFrom(this)) { if (aIsActive) { tab->MakeVisible(); + // The only time we should set this to false is when + // TabChild::MakeVisible() is called. + mIsHidden = false; + if (!mIsZombie) { if (nsIFrame* root = mFrameConstructor->GetRootFrame()) { FrameLayerBuilder::InvalidateAllLayersForFrame( @@ -10750,6 +10772,26 @@ nsIPresShell::FontSizeInflationEnabled() return mFontSizeInflationEnabled; } +void +PresShell::PausePainting() +{ + if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext()) + return; + + mPaintingIsFrozen = true; + GetPresContext()->RefreshDriver()->Freeze(); +} + +void +PresShell::ResumePainting() +{ + if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext()) + return; + + mPaintingIsFrozen = false; + GetPresContext()->RefreshDriver()->Thaw(); +} + void nsIPresShell::SyncWindowProperties(nsView* aView) { diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index fba251a8f6..5eaf39b323 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -494,6 +494,8 @@ protected: friend class nsPresShellEventCB; bool mCaretEnabled; + + bool mIsHidden; #ifdef DEBUG nsStyleSet* CloneStyleSet(nsStyleSet* aSet); bool VerifyIncrementalReflow(); @@ -720,6 +722,10 @@ protected: #ifdef ANDROID virtual nsIDocument* GetTouchEventTargetDocument(); #endif + + virtual void PausePainting() override; + virtual void ResumePainting() override; + void UpdateImageVisibility(); void UpdateActivePointerState(mozilla::WidgetGUIEvent* aEvent); diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index abfb15121e..a90837d168 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -1175,7 +1175,7 @@ nsRefreshDriver::EnsureTimerStarted(EnsureTimerStartedFlags aFlags) return; // will it already fire, and no other changes needed? - if (mActiveTimer && !(aFlags & eAdjustingTimer)) + if (mActiveTimer && !(aFlags & eForceAdjustTimer)) return; if (IsFrozen() || !mPresContext) { @@ -1207,6 +1207,15 @@ nsRefreshDriver::EnsureTimerStarted(EnsureTimerStartedFlags aFlags) mActiveTimer->AddRefreshDriver(this); } + // When switching from an inactive timer to an active timer, the root + // refresh driver is skipped due to being set to the content refresh + // driver's timestamp. In case of EnsureTimerStarted is called from + // ScheduleViewManagerFlush, we should avoid this behavior to flush + // a paint in the same tick on the root refresh driver. + if (aFlags & eNeverAdjustTimer) { + return; + } + // Since the different timers are sampled at different rates, when switching // timers, the most recent refresh of the new timer may be *before* the // most recent refresh of the old timer. However, the refresh driver time @@ -2068,7 +2077,7 @@ nsRefreshDriver::SetThrottled(bool aThrottled) if (mActiveTimer) { // We want to switch our timer type here, so just stop and // restart the timer. - EnsureTimerStarted(eAdjustingTimer); + EnsureTimerStarted(eForceAdjustTimer); } } } @@ -2115,7 +2124,7 @@ nsRefreshDriver::ScheduleViewManagerFlush() NS_ASSERTION(mPresContext->IsRoot(), "Should only schedule view manager flush on root prescontexts"); mViewManagerFlushIsPending = true; - EnsureTimerStarted(); + EnsureTimerStarted(eNeverAdjustTimer); } void diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h index c1fc4c8051..1d782dd95c 100644 --- a/layout/base/nsRefreshDriver.h +++ b/layout/base/nsRefreshDriver.h @@ -331,8 +331,9 @@ private: enum EnsureTimerStartedFlags { eNone = 0, - eAdjustingTimer = 1 << 0, - eAllowTimeToGoBackwards = 1 << 1 + eForceAdjustTimer = 1 << 0, + eAllowTimeToGoBackwards = 1 << 1, + eNeverAdjustTimer = 1 << 2, }; void EnsureTimerStarted(EnsureTimerStartedFlags aFlags = eNone); void StopTimer(); diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index 7e11716588..2839c20e6a 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -106,9 +106,8 @@ RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader, mAsyncPanZoomEnabled = lm && lm->AsyncPanZoomEnabled(); // Perhaps the document containing this frame currently has no presentation? - if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { - *aTextureFactoryIdentifier = - static_cast(lm.get())->GetTextureFactoryIdentifier(); + if (lm && lm->AsClientLayerManager()) { + *aTextureFactoryIdentifier = lm->AsClientLayerManager()->GetTextureFactoryIdentifier(); } else { *aTextureFactoryIdentifier = TextureFactoryIdentifier(); } @@ -119,10 +118,8 @@ RenderFrameParent::RenderFrameParent(nsFrameLoader* aFrameLoader, // and we'll keep an indirect reference to that tree. browser->Manager()->AsContentParent()->AllocateLayerTreeId(browser, aId); mLayersId = *aId; - if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { - ClientLayerManager *clientManager = - static_cast(lm.get()); - clientManager->GetRemoteRenderer()->SendNotifyChildCreated(mLayersId); + if (lm && lm->AsClientLayerManager()) { + lm->AsClientLayerManager()->GetRemoteRenderer()->SendNotifyChildCreated(mLayersId); } } else if (XRE_IsContentProcess()) { ContentChild::GetSingleton()->SendAllocateLayerTreeId(browser->Manager()->ChildID(), browser->GetTabId(), aId); @@ -208,10 +205,8 @@ RenderFrameParent::OwnerContentChanged(nsIContent* aContent) RefPtr lm = mFrameLoader ? GetFrom(mFrameLoader) : nullptr; // Perhaps the document containing this frame currently has no presentation? - if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { - ClientLayerManager *clientManager = - static_cast(lm.get()); - clientManager->GetRemoteRenderer()->SendAdoptChild(mLayersId); + if (lm && lm->AsClientLayerManager()) { + lm->AsClientLayerManager()->GetRemoteRenderer()->SendAdoptChild(mLayersId); } } @@ -294,9 +289,8 @@ RenderFrameParent::GetTextureFactoryIdentifier(TextureFactoryIdentifier* aTextur { RefPtr lm = mFrameLoader ? GetFrom(mFrameLoader) : nullptr; // Perhaps the document containing this frame currently has no presentation? - if (lm && lm->GetBackendType() == LayersBackend::LAYERS_CLIENT) { - *aTextureFactoryIdentifier = - static_cast(lm.get())->GetTextureFactoryIdentifier(); + if (lm && lm->AsClientLayerManager()) { + *aTextureFactoryIdentifier = lm->AsClientLayerManager()->GetTextureFactoryIdentifier(); } else { *aTextureFactoryIdentifier = TextureFactoryIdentifier(); } diff --git a/layout/reftests/font-matching/reftest.list b/layout/reftests/font-matching/reftest.list index 16ee8809a9..408c3bb915 100644 --- a/layout/reftests/font-matching/reftest.list +++ b/layout/reftests/font-matching/reftest.list @@ -63,7 +63,7 @@ HTTP(..) == weightmapping-45.html weightmapping-45-ref.html HTTP(..) == weightmapping-458.html weightmapping-458-ref.html HTTP(..) == weightmapping-478.html weightmapping-478-ref.html HTTP(..) == weightmapping-7.html weightmapping-7-ref.html -HTTP(..) == weightmapping-12579.html weightmapping-12579-ref.html +fuzzy-if(OSX==1010,1,30) HTTP(..) == weightmapping-12579.html weightmapping-12579-ref.html skip-if(B2G||Mulet) HTTP(..) == stretchmapping-all.html stretchmapping-all-ref.html # bug 773482 # Initial mulet triage: parity with B2G/B2G Desktop skip-if(B2G||Mulet) HTTP(..) == stretchmapping-reverse.html stretchmapping-reverse-ref.html # Initial mulet triage: parity with B2G/B2G Desktop diff --git a/layout/tables/celldata.h b/layout/tables/celldata.h index c369eaf8aa..b744b51752 100644 --- a/layout/tables/celldata.h +++ b/layout/tables/celldata.h @@ -80,19 +80,6 @@ public: */ bool IsColSpan() const; - /** is the entry spanned by a zero colspan - * zero colspans span all cells starting from the originating cell towards - * the end of the colgroup or a cell originating in the same row - * or a rowspanned entry - * @return is true if the entry is spanned by a zero colspan - */ - bool IsZeroColSpan() const; - - /** mark the current entry as spanned by a zero colspan - * @param aIsZero if true mark the entry as covered by a zero colspan - */ - void SetZeroColSpan(bool aIsZero); - /** get the distance from the current entry to the corresponding origin of the colspan * @return containing the distance in the row to the originating cell */ @@ -250,7 +237,9 @@ public: // The layout of a celldata is as follows. The top 10 bits are the colspan // offset (which is enough to represent our allowed values 1-1000 for colspan). -// Then there are three bits of flags. Then 16 bits of rowspan offset (which +// Then there are two bits of flags. +// XXXmats Then one unused bit that we should decide how to use in bug 862624. +// Then 16 bits of rowspan offset (which // lets us represent numbers up to 65535. Then another 3 bits of flags. // num bits to shift right to get right aligned col span @@ -267,8 +256,7 @@ public: #define SPAN 0x00000001 // there a row or col span #define ROW_SPAN 0x00000002 // there is a row span #define ROW_SPAN_0 0x00000004 // the row span is 0 -#define COL_SPAN (1 << (COL_SPAN_SHIFT - 3)) // there is a col span -#define COL_SPAN_0 (1 << (COL_SPAN_SHIFT - 2)) // the col span is 0 +#define COL_SPAN (1 << (COL_SPAN_SHIFT - 2)) // there is a col span #define OVERLAP (1 << (COL_SPAN_SHIFT - 1)) // there is a row span and // col span but not by // same cell @@ -348,25 +336,6 @@ inline bool CellData::IsColSpan() const (COL_SPAN == (COL_SPAN & mBits)); } -inline bool CellData::IsZeroColSpan() const -{ - return (SPAN == (SPAN & mBits)) && - (COL_SPAN == (COL_SPAN & mBits)) && - (COL_SPAN_0 == (COL_SPAN_0 & mBits)); -} - -inline void CellData::SetZeroColSpan(bool aIsZeroSpan) -{ - if (SPAN == (SPAN & mBits)) { - if (aIsZeroSpan) { - mBits |= COL_SPAN_0; - } - else { - mBits &= ~COL_SPAN_0; - } - } -} - inline uint32_t CellData::GetColSpanOffset() const { if ((SPAN == (SPAN & mBits)) && ((COL_SPAN == (COL_SPAN & mBits)))) { diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp index 77942d1f21..7e1d0a9902 100644 --- a/layout/tables/nsCellMap.cpp +++ b/layout/tables/nsCellMap.cpp @@ -353,8 +353,7 @@ nsTableCellMap::GetEffectiveColSpan(int32_t aRowIndex, nsCellMap* map = mFirstMap; while (map) { if (map->GetRowCount() > rowIndex) { - bool zeroColSpan; - return map->GetEffectiveColSpan(*this, rowIndex, aColIndex, zeroColSpan); + return map->GetEffectiveColSpan(*this, rowIndex, aColIndex); } rowIndex -= map->GetRowCount(); map = map->GetNextSibling(); @@ -899,18 +898,6 @@ bool nsTableCellMap::RowHasSpanningCells(int32_t aRowIndex, return false; } -void nsTableCellMap::ExpandZeroColSpans() -{ - mTableFrame.SetNeedColSpanExpansion(false); // mark the work done - mTableFrame.SetHasZeroColSpans(false); // reset the bit, if there is a - // zerospan it will be set again. - nsCellMap* cellMap = mFirstMap; - while (cellMap) { - cellMap->ExpandZeroColSpans(*this); - cellMap = cellMap->GetNextSibling(); - } -} - void nsTableCellMap::ResetBStartStart(LogicalSide aSide, nsCellMap& aCellMap, @@ -1454,15 +1441,6 @@ nsCellMap::AppendCell(nsTableCellMap& aMap, origData = data; break; } - if (data->IsZeroColSpan() ) { - // appending a cell collapses zerospans. - CollapseZeroColSpan(aMap, data, aRowIndex, startColIndex); - // ask again for the data as it should be modified - origData = GetDataAt(aRowIndex, startColIndex); - NS_ASSERTION(origData->IsDead(), - "The cellposition should have been cleared"); - break; - } } // We found the place to append the cell, when the next cell is appended // the next search does not need to duplicate the search but can start @@ -1470,13 +1448,7 @@ nsCellMap::AppendCell(nsTableCellMap& aMap, if (aColToBeginSearch) *aColToBeginSearch = startColIndex + 1; - bool zeroColSpan = false; - int32_t colSpan = (aCellFrame) ? - GetColSpanForNewCell(*aCellFrame, zeroColSpan) : 1; - if (zeroColSpan) { - aMap.mTableFrame.SetHasZeroColSpans(true); - aMap.mTableFrame.SetNeedColSpanExpansion(true); - } + int32_t colSpan = aCellFrame ? aCellFrame->GetColSpan() : 1; // if the new cell could potentially span into other rows and collide with // originating cells there, we will play it safe and just rebuild the map @@ -1563,10 +1535,6 @@ nsCellMap::AppendCell(nsTableCellMap& aMap, cellData->SetOverlap(true); } cellData->SetColSpanOffset(colX - startColIndex); - if (zeroColSpan) { - cellData->SetZeroColSpan(true); - } - nsColInfo* colInfo = aMap.GetColInfoAt(colX); colInfo->mNumCellsSpan++; } @@ -1583,9 +1551,6 @@ nsCellMap::AppendCell(nsTableCellMap& aMap, } if (colX > startColIndex) { cellData->SetColSpanOffset(colX - startColIndex); - if (zeroColSpan) { - cellData->SetZeroColSpan(true); - } } SetDataAt(aMap, *cellData, rowX, colX); } @@ -1599,50 +1564,6 @@ nsCellMap::AppendCell(nsTableCellMap& aMap, return origData; } -void nsCellMap::CollapseZeroColSpan(nsTableCellMap& aMap, - CellData* aOrigData, - int32_t aRowIndex, - int32_t aColIndex) -{ - // if after a colspan = 0 cell another cell is appended in a row the html 4 - // spec is already violated. In principle one should then append the cell - // after the last column but then the zero spanning cell would also have - // to grow. The only plausible way to break this cycle is ignore the zero - // colspan and reset the cell to colspan = 1. - - NS_ASSERTION(aOrigData && aOrigData->IsZeroColSpan(), - "zero colspan should have been passed"); - // find the originating cellframe - nsTableCellFrame* cell = GetCellFrame(aRowIndex, aColIndex, *aOrigData, true); - NS_ASSERTION(cell, "originating cell not found"); - - // find the clearing region - int32_t startRowIndex = aRowIndex - aOrigData->GetRowSpanOffset(); - bool zeroSpan; - int32_t rowSpan = GetRowSpanForNewCell(cell, startRowIndex, zeroSpan); - int32_t endRowIndex = startRowIndex + rowSpan; - - int32_t origColIndex = aColIndex - aOrigData->GetColSpanOffset(); - int32_t endColIndex = origColIndex + - GetEffectiveColSpan(aMap, startRowIndex, - origColIndex, zeroSpan); - for (int32_t colX = origColIndex +1; colX < endColIndex; colX++) { - // Start the collapse just after the originating cell, since - // we're basically making the originating cell act as if it - // has colspan="1". - nsColInfo* colInfo = aMap.GetColInfoAt(colX); - colInfo->mNumCellsSpan -= rowSpan; - - for (int32_t rowX = startRowIndex; rowX < endRowIndex; rowX++) - { - CellData* data = mRows[rowX][colX]; - NS_ASSERTION(data->IsZeroColSpan(), - "Overwriting previous data - memory leak"); - data->Init(nullptr); // mark the cell as a dead cell. - } - } -} - bool nsCellMap::CellsSpanOut(nsTArray& aRows) const { int32_t numNewRows = aRows.Length(); @@ -1749,11 +1670,6 @@ void nsCellMap::InsertCells(nsTableCellMap& aMap, // // Not a span. Stop. break; } - if (data->IsZeroColSpan()) { - // Zero colspans collapse. Stop in this case too. - CollapseZeroColSpan(aMap, data, aRowIndex, startColIndex); - break; - } } // record whether inserted cells are going to cause complications due @@ -1863,12 +1779,7 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap, if (!origData) return; // set the starting and ending col index for the new cell - bool zeroColSpan = false; - int32_t colSpan = GetColSpanForNewCell(*cellFrame, zeroColSpan); - if (zeroColSpan) { - aMap.mTableFrame.SetHasZeroColSpans(true); - aMap.mTableFrame.SetNeedColSpanExpansion(true); - } + int32_t colSpan = cellFrame->GetColSpan(); totalColSpan += colSpan; if (cellX == 0) { endColIndex = aColIndex + colSpan - 1; @@ -1911,9 +1822,6 @@ void nsCellMap::ExpandWithCells(nsTableCellMap& aMap, } if (colX > startColIndex) { data->SetColSpanOffset(colX - startColIndex); - if (zeroColSpan) { - data->SetZeroColSpan(true); - } } } SetDataAt(aMap, *data, rowX, colX); @@ -2011,25 +1919,11 @@ void nsCellMap::ShrinkWithoutRows(nsTableCellMap& aMap, aMap.GetRowCount() - firstDamagedRow, aDamageArea); } -int32_t nsCellMap::GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd, - bool& aIsZeroColSpan) const -{ - aIsZeroColSpan = false; - int32_t colSpan = aCellFrameToAdd.GetColSpan(); - if (0 == colSpan) { - colSpan = 1; // set the min colspan it will be expanded later - aIsZeroColSpan = true; - } - return colSpan; -} - int32_t nsCellMap::GetEffectiveColSpan(const nsTableCellMap& aMap, int32_t aRowIndex, - int32_t aColIndex, - bool& aZeroColSpan) const + int32_t aColIndex) const { int32_t numColsInTable = aMap.GetColCount(); - aZeroColSpan = false; int32_t colSpan = 1; if (uint32_t(aRowIndex) >= mRows.Length()) { return colSpan; @@ -2060,9 +1954,6 @@ int32_t nsCellMap::GetEffectiveColSpan(const nsTableCellMap& aMap, } if (data->IsColSpan()) { colSpan++; - if (data->IsZeroColSpan()) { - aZeroColSpan = true; - } } else { break; @@ -2153,17 +2044,12 @@ void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap, uint32_t colX, rowX; // get the rowspan and colspan from the cell map since the content may have changed - bool zeroColSpan; uint32_t numCols = aMap.GetColCount(); int32_t rowSpan = GetRowSpan(aRowIndex, aColIndex, true); - uint32_t colSpan = GetEffectiveColSpan(aMap, aRowIndex, aColIndex, zeroColSpan); + uint32_t colSpan = GetEffectiveColSpan(aMap, aRowIndex, aColIndex); uint32_t endRowIndex = aRowIndex + rowSpan - 1; uint32_t endColIndex = aColIndex + colSpan - 1; - if (aMap.mTableFrame.HasZeroColSpans()) { - aMap.mTableFrame.SetNeedColSpanExpansion(true); - } - // adjust the col counts due to the deleted cell before removing it for (colX = aColIndex; colX <= endColIndex; colX++) { nsColInfo* colInfo = aMap.GetColInfoAt(colX); @@ -2455,80 +2341,6 @@ void nsCellMap::RemoveCell(nsTableCellMap& aMap, } } -void nsCellMap::ExpandZeroColSpans(nsTableCellMap& aMap) -{ - NS_ASSERTION(!!aMap.mBCInfo == mIsBC, "BC state mismatch"); - uint32_t numRows = mRows.Length(); - uint32_t numCols = aMap.GetColCount(); - uint32_t rowIndex, colIndex; - - for (rowIndex = 0; rowIndex < numRows; rowIndex++) { - for (colIndex = 0; colIndex < numCols; colIndex++) { - CellData* data = mRows[rowIndex].SafeElementAt(colIndex); - if (!data || !data->IsOrig()) - continue; - nsTableCellFrame* cell = data->GetCellFrame(); - NS_ASSERTION(cell, "There has to be a cell"); - int32_t cellRowSpan = cell->GetRowSpan(); - int32_t cellColSpan = cell->GetColSpan(); - bool rowZeroSpan = (0 == cell->GetRowSpan()); - bool colZeroSpan = (0 == cell->GetColSpan()); - if (colZeroSpan) { - aMap.mTableFrame.SetHasZeroColSpans(true); - // do the expansion - NS_ASSERTION(numRows > 0, "Bogus numRows"); - NS_ASSERTION(numCols > 0, "Bogus numCols"); - uint32_t endRowIndex = rowZeroSpan ? numRows - 1 : - rowIndex + cellRowSpan - 1; - uint32_t endColIndex = colZeroSpan ? numCols - 1 : - colIndex + cellColSpan - 1; - uint32_t colX, rowX; - colX = colIndex + 1; - while (colX <= endColIndex) { - // look at columns from here to our colspan. For each one, check - // the rows from here to our rowspan to make sure there is no - // obstacle to marking that column as a zerospanned column; if there - // isn't, mark it so - for (rowX = rowIndex; rowX <= endRowIndex; rowX++) { - CellData* oldData = GetDataAt(rowX, colX); - if (oldData) { - if (oldData->IsOrig()) { - break; // something is in the way - } - if (oldData->IsRowSpan()) { - if ((rowX - rowIndex) != oldData->GetRowSpanOffset()) { - break; - } - } - if (oldData->IsColSpan()) { - if ((colX - colIndex) != oldData->GetColSpanOffset()) { - break; - } - } - } - } - if (endRowIndex >= rowX) - break;// we hit something - for (rowX = rowIndex; rowX <= endRowIndex; rowX++) { - CellData* newData = AllocCellData(nullptr); - if (!newData) return; - - newData->SetColSpanOffset(colX - colIndex); - newData->SetZeroColSpan(true); - - if (rowX > rowIndex) { - newData->SetRowSpanOffset(rowX - rowIndex); - if (rowZeroSpan) - newData->SetZeroRowSpan(true); - } - SetDataAt(aMap, *newData, rowX, colX); - } - colX++; - } // while (colX <= endColIndex) - } // if zerocolspan - } - } -} #ifdef DEBUG void nsCellMap::Dump(bool aIsBorderCollapse) const { @@ -2643,7 +2455,8 @@ nsCellMap::GetDataAt(int32_t aMapRowIndex, } // only called if the cell at aMapRowIndex, aColIndex is null or dead -// (the latter from ExpandZeroColSpans). +// (the latter from ExpandZeroColSpans (XXXmats which has now been removed - +// are there other ways cells may be dead?)). void nsCellMap::SetDataAt(nsTableCellMap& aMap, CellData& aNewCell, int32_t aMapRowIndex, @@ -2709,8 +2522,7 @@ nsCellMap::GetCellInfoAt(const nsTableCellMap& aMap, if (cellFrame && aColSpan) { int32_t initialColIndex; cellFrame->GetColIndex(initialColIndex); - bool zeroSpan; - *aColSpan = GetEffectiveColSpan(aMap, aRowX, initialColIndex, zeroSpan); + *aColSpan = GetEffectiveColSpan(aMap, aRowX, initialColIndex); } } return cellFrame; @@ -2887,9 +2699,7 @@ nsCellMapColumnIterator::GetNextFrame(int32_t* aRow, int32_t* aColSpan) NS_ASSERTION(cellFrame, "Orig data without cellframe?"); *aRow = mCurMapStart + mCurMapRow; - bool ignoredZeroSpan; - *aColSpan = mCurMap->GetEffectiveColSpan(*mMap, mCurMapRow, mCol, - ignoredZeroSpan); + *aColSpan = mCurMap->GetEffectiveColSpan(*mMap, mCurMapRow, mCol); IncrementRow(cellFrame->GetRowSpan()); diff --git a/layout/tables/nsCellMap.h b/layout/tables/nsCellMap.h index c0bc94a766..fbb3206399 100644 --- a/layout/tables/nsCellMap.h +++ b/layout/tables/nsCellMap.h @@ -198,8 +198,6 @@ protected: TableArea& aDamageArea); public: - void ExpandZeroColSpans(); - void ResetBStartStart(mozilla::LogicalSide aSide, nsCellMap& aCellMap, uint32_t aYPos, @@ -355,22 +353,6 @@ public: TableArea& aDamageArea, int32_t* aBeginSearchAtCol = nullptr); - /** Function to be called when a cell is added at a location which is spanned - * to by a zero colspan. We handle this situation by collapsing the zero - * colspan, since there is really no good way to deal with it (trying to - * increase the number of columns to hold the new cell would just mean the - * zero colspan needs to expand). - - * @param aMap - reference to the table cell map - * @param aOrigData - zero colspanned cell that will be collapsed - * @param aRowIndex - row where the first collision appears - * @param aColIndex - column where the first collision appears - **/ - void CollapseZeroColSpan(nsTableCellMap& aMap, - CellData* aOrigData, - int32_t aRowIndex, - int32_t aColIndex); - void InsertCells(nsTableCellMap& aMap, nsTArray& aCellFrames, int32_t aRowIndex, @@ -416,8 +398,6 @@ public: bool RowHasSpanningCells(int32_t aRowIndex, int32_t aNumEffCols) const; - void ExpandZeroColSpans(nsTableCellMap& aMap); - /** indicate whether the row has more than one cell that either originates * or is spanned from the rows above */ @@ -435,8 +415,7 @@ public: int32_t GetEffectiveColSpan(const nsTableCellMap& aMap, int32_t aRowIndex, - int32_t aColIndex, - bool& aIsZeroColSpan) const; + int32_t aColIndex) const; typedef nsTArray CellDataArray; @@ -540,9 +519,6 @@ protected: int32_t aStartColIndex, int32_t aEndColIndex) const; - void ExpandForZeroSpan(nsTableCellFrame* aCellFrame, - int32_t aNumColsInTable); - bool CreateEmptyRow(int32_t aRowIndex, int32_t aNumCols); @@ -550,9 +526,6 @@ protected: int32_t aRowIndex, bool& aIsZeroRowSpan) const; - int32_t GetColSpanForNewCell(nsTableCellFrame& aCellFrameToAdd, - bool& aIsZeroColSpan) const; - // Destroy a CellData struct. This will handle the case of aData // actually being a BCCellData properly. void DestroyCellData(CellData* aData); diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index 4e28d7b0c9..33bf362e91 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -477,10 +477,9 @@ nsTableFrame::GetEffectiveColSpan(const nsTableCellFrame& aCell, int32_t colIndex, rowIndex; aCell.GetColIndex(colIndex); aCell.GetRowIndex(rowIndex); - bool ignore; if (aCellMap) - return aCellMap->GetEffectiveColSpan(*tableCellMap, rowIndex, colIndex, ignore); + return aCellMap->GetEffectiveColSpan(*tableCellMap, rowIndex, colIndex); else return tableCellMap->GetEffectiveColSpan(rowIndex, colIndex); } @@ -780,21 +779,6 @@ nsTableFrame::MatchCellMapToColCache(nsTableCellMap* aCellMap) aCellMap->AddColsAtEnd(numColsNotRemoved); } } - if (numColsToAdd && HasZeroColSpans()) { - SetNeedColSpanExpansion(true); - } - if (NeedColSpanExpansion()) { - // This flag can be set in two ways -- either by changing - // the number of columns (that happens in the block above), - // or by adding a cell with colspan="0" to the cellmap. To - // handle the latter case we need to explicitly check the - // flag here -- it may be set even if the number of columns - // did not change. - // - // @see nsCellMap::AppendCell - - aCellMap->ExpandZeroColSpans(); - } } void @@ -1404,9 +1388,8 @@ nsTableFrame::PaintTableBorderBackground(nsDisplayListBuilder* aBuilder, nsCSSRendering::PaintBorder(presContext, aRenderingContext, this, aDirtyRect, rect, mStyleContext, borderFlags, skipSides); - } - else { - gfxContext* ctx = aRenderingContext.ThebesContext(); + } else { + DrawTarget* drawTarget = aRenderingContext.GetDrawTarget(); gfxPoint devPixelOffset = nsLayoutUtils::PointToGfxPoint(aPt, @@ -1414,10 +1397,11 @@ nsTableFrame::PaintTableBorderBackground(nsDisplayListBuilder* aBuilder, // XXX we should probably get rid of this translation at some stage // But that would mean modifying PaintBCBorders, ugh - gfxContextMatrixAutoSaveRestore autoSR(ctx); - ctx->SetMatrix(ctx->CurrentMatrix().Translate(devPixelOffset)); + AutoRestoreTransform autoRestoreTransform(drawTarget); + drawTarget->SetTransform( + drawTarget->GetTransform().PreTranslate(ToPoint(devPixelOffset))); - PaintBCBorders(aRenderingContext, aDirtyRect - aPt); + PaintBCBorders(*drawTarget, aDirtyRect - aPt); } } @@ -6222,7 +6206,7 @@ struct BCBlockDirSeg void Paint(BCPaintBorderIterator& aIter, - nsRenderingContext& aRenderingContext, + DrawTarget& aDrawTarget, BCPixelSize aInlineSegBSize); void AdvanceOffsetB(); void IncludeCurrentBorder(BCPaintBorderIterator& aIter); @@ -6272,8 +6256,7 @@ struct BCInlineDirSeg BCPixelSize aIStartSegISize); void AdvanceOffsetI(); void IncludeCurrentBorder(BCPaintBorderIterator& aIter); - void Paint(BCPaintBorderIterator& aIter, - nsRenderingContext& aRenderingContext); + void Paint(BCPaintBorderIterator& aIter, DrawTarget& aDrawTarget); nscoord mOffsetI; // i-offset with respect to the table edge nscoord mOffsetB; // b-offset with respect to the table edge @@ -6317,8 +6300,8 @@ public: bool SetDamageArea(const nsRect& aDamageRect); void First(); void Next(); - void AccumulateOrPaintInlineDirSegment(nsRenderingContext& aRenderingContext); - void AccumulateOrPaintBlockDirSegment(nsRenderingContext& aRenderingContext); + void AccumulateOrPaintInlineDirSegment(DrawTarget& aDrawTarget); + void AccumulateOrPaintBlockDirSegment(DrawTarget& aDrawTarget); void ResetVerInfo(); void StoreColumnWidth(int32_t aIndex); bool BlockDirSegmentOwnsCorner(); @@ -6948,14 +6931,14 @@ BCBlockDirSeg::GetBEndCorner(BCPaintBorderIterator& aIter, /** * Paint the block-dir segment - * @param aIter - iterator containing the structural information - * @param aRenderingContext - the rendering context - * @param aInlineSegBSize - the width of the inline-dir segment joining the corner - * at the start + * @param aIter - iterator containing the structural information + * @param aDrawTarget - the draw target + * @param aInlineSegBSize - the width of the inline-dir segment joining the + * corner at the start */ void BCBlockDirSeg::Paint(BCPaintBorderIterator& aIter, - nsRenderingContext& aRenderingContext, + DrawTarget& aDrawTarget, BCPixelSize aInlineSegBSize) { // get the border style, color and paint the segment @@ -7060,8 +7043,8 @@ BCBlockDirSeg::Paint(BCPaintBorderIterator& aIter, Swap(startBevelSide, endBevelSide); Swap(startBevelOffset, endBevelOffset); } - nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color, - aIter.mTableBgColor, physicalRect, + nsCSSRendering::DrawTableBorderSegment(aDrawTarget, style, color, + aIter.mTableBgColor, physicalRect, appUnitsPerDevPixel, aIter.mTable->PresContext()->AppUnitsPerDevPixel(), startBevelSide, startBevelOffset, @@ -7163,12 +7146,11 @@ BCInlineDirSeg::GetIEndCorner(BCPaintBorderIterator& aIter, /** * Paint the inline-dir segment - * @param aIter - iterator containing the structural information - * @param aRenderingContext - the rendering context + * @param aIter - iterator containing the structural information + * @param aDrawTarget - the draw target */ void -BCInlineDirSeg::Paint(BCPaintBorderIterator& aIter, - nsRenderingContext& aRenderingContext) +BCInlineDirSeg::Paint(BCPaintBorderIterator& aIter, DrawTarget& aDrawTarget) { // get the border style, color and paint the segment LogicalSide side = @@ -7266,7 +7248,7 @@ BCInlineDirSeg::Paint(BCPaintBorderIterator& aIter, Swap(startBevelSide, endBevelSide); Swap(startBevelOffset, endBevelOffset); } - nsCSSRendering::DrawTableBorderSegment(aRenderingContext, style, color, + nsCSSRendering::DrawTableBorderSegment(aDrawTarget, style, color, aIter.mTableBgColor, physicalRect, appUnitsPerDevPixel, aIter.mTable->PresContext()->AppUnitsPerDevPixel(), @@ -7325,10 +7307,10 @@ BCPaintBorderIterator::BlockDirSegmentOwnsCorner() /** * Paint if necessary an inline-dir segment, otherwise accumulate it - * @param aRenderingContext - the rendering context + * @param aDrawTarget - the draw target */ void -BCPaintBorderIterator::AccumulateOrPaintInlineDirSegment(nsRenderingContext& aRenderingContext) +BCPaintBorderIterator::AccumulateOrPaintInlineDirSegment(DrawTarget& aDrawTarget) { int32_t relColIndex = GetRelativeColIndex(); @@ -7361,7 +7343,7 @@ BCPaintBorderIterator::AccumulateOrPaintInlineDirSegment(nsRenderingContext& aRe if (mInlineSeg.mLength > 0) { mInlineSeg.GetIEndCorner(*this, iStartSegISize); if (mInlineSeg.mWidth > 0) { - mInlineSeg.Paint(*this, aRenderingContext); + mInlineSeg.Paint(*this, aDrawTarget); } mInlineSeg.AdvanceOffsetI(); } @@ -7373,10 +7355,10 @@ BCPaintBorderIterator::AccumulateOrPaintInlineDirSegment(nsRenderingContext& aRe } /** * Paint if necessary a block-dir segment, otherwise accumulate it - * @param aRenderingContext - the rendering context + * @param aDrawTarget - the draw target */ void -BCPaintBorderIterator::AccumulateOrPaintBlockDirSegment(nsRenderingContext& aRenderingContext) +BCPaintBorderIterator::AccumulateOrPaintBlockDirSegment(DrawTarget& aDrawTarget) { BCBorderOwner borderOwner = eCellOwner; BCBorderOwner ignoreBorderOwner; @@ -7403,7 +7385,7 @@ BCPaintBorderIterator::AccumulateOrPaintBlockDirSegment(nsRenderingContext& aRen if (blockDirSeg.mLength > 0) { blockDirSeg.GetBEndCorner(*this, inlineSegBSize); if (blockDirSeg.mWidth > 0) { - blockDirSeg.Paint(*this, aRenderingContext, inlineSegBSize); + blockDirSeg.Paint(*this, aDrawTarget, inlineSegBSize); } blockDirSeg.AdvanceOffsetB(); } @@ -7431,12 +7413,11 @@ BCPaintBorderIterator::ResetVerInfo() /** * Method to paint BCBorders, this does not use currently display lists although * it will do this in future - * @param aRenderingContext - the rendering context - * @param aDirtyRect - inside this rectangle the BC Borders will redrawn + * @param aDrawTarget - the rendering context + * @param aDirtyRect - inside this rectangle the BC Borders will redrawn */ void -nsTableFrame::PaintBCBorders(nsRenderingContext& aRenderingContext, - const nsRect& aDirtyRect) +nsTableFrame::PaintBCBorders(DrawTarget& aDrawTarget, const nsRect& aDirtyRect) { // We first transfer the aDirtyRect into cellmap coordinates to compute which // cell borders need to be painted @@ -7455,7 +7436,7 @@ nsTableFrame::PaintBCBorders(nsRenderingContext& aRenderingContext, // this we the now active segment with the current border. These // segments are stored in mBlockDirInfo to be used on the next row for (iter.First(); !iter.mAtEnd; iter.Next()) { - iter.AccumulateOrPaintBlockDirSegment(aRenderingContext); + iter.AccumulateOrPaintBlockDirSegment(aDrawTarget); } // Next, paint all of the inline-dir border segments from bStart to bEnd reuse @@ -7463,7 +7444,7 @@ nsTableFrame::PaintBCBorders(nsRenderingContext& aRenderingContext, // corner calculations iter.Reset(); for (iter.First(); !iter.mAtEnd; iter.Next()) { - iter.AccumulateOrPaintInlineDirSegment(aRenderingContext); + iter.AccumulateOrPaintInlineDirSegment(aDrawTarget); } } diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index bbe97b5136..711b316bdf 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -312,8 +312,7 @@ public: void AddBCDamageArea(const mozilla::TableArea& aValue); bool BCRecalcNeeded(nsStyleContext* aOldStyleContext, nsStyleContext* aNewStyleContext); - void PaintBCBorders(nsRenderingContext& aRenderingContext, - const nsRect& aDirtyRect); + void PaintBCBorders(DrawTarget& aDrawTarget, const nsRect& aDirtyRect); virtual void MarkIntrinsicISizesDirty() override; // For border-collapse tables, the caller must not add padding and @@ -763,12 +762,6 @@ public: bool NeedToCollapse() const; void SetNeedToCollapse(bool aValue); - bool HasZeroColSpans() const; - void SetHasZeroColSpans(bool aValue); - - bool NeedColSpanExpansion() const; - void SetNeedColSpanExpansion(bool aValue); - /** The GeometryDirty bit is similar to the NS_FRAME_IS_DIRTY frame * state bit, which implies that all descendants are dirty. The * GeometryDirty still implies that all the parts of the table are @@ -875,9 +868,7 @@ protected: uint32_t mNeedToCalcBCBorders:1; uint32_t mGeometryDirty:1; uint32_t mIStartContBCBorder:8; - uint32_t mNeedToCollapse:1; // rows, cols that have visibility:collapse need to be collapsed - uint32_t mHasZeroColSpans:1; - uint32_t mNeedColSpanExpansion:1; + uint32_t mNeedToCollapse:1; // rows, cols that have visibility:collapse need to be collapsed uint32_t mResizedColumns:1; // have we resized columns since last reflow? } mBits; @@ -944,27 +935,6 @@ inline bool nsTableFrame::NeedToCollapse() const return (bool) static_cast(FirstInFlow())->mBits.mNeedToCollapse; } -inline void nsTableFrame::SetHasZeroColSpans(bool aValue) -{ - mBits.mHasZeroColSpans = (unsigned)aValue; -} - -inline bool nsTableFrame::HasZeroColSpans() const -{ - return (bool)mBits.mHasZeroColSpans; -} - -inline void nsTableFrame::SetNeedColSpanExpansion(bool aValue) -{ - mBits.mNeedColSpanExpansion = (unsigned)aValue; -} - -inline bool nsTableFrame::NeedColSpanExpansion() const -{ - return (bool)mBits.mNeedColSpanExpansion; -} - - inline nsFrameList& nsTableFrame::GetColGroups() { return static_cast(FirstInFlow())->mColGroups; diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index a9059c41ac..fa38f40fff 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -190,6 +190,7 @@ #include "mozilla/layers/APZCTreeManager.h" #include "mozilla/layers/InputAPZContext.h" +#include "ClientLayerManager.h" #include "InputData.h" #include "mozilla/Telemetry.h" @@ -1402,6 +1403,17 @@ nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints) c.mMinSize.width = std::max(int32_t(::GetSystemMetrics(SM_CXMINTRACK)), c.mMinSize.width); c.mMinSize.height = std::max(int32_t(::GetSystemMetrics(SM_CYMINTRACK)), c.mMinSize.height); } + ClientLayerManager *clientLayerManager = GetLayerManager()->AsClientLayerManager(); + + if (clientLayerManager) { + int32_t maxSize = clientLayerManager->GetMaxTextureSize(); + // We can't make ThebesLayers bigger than this anyway.. no point it letting + // a window grow bigger as we won't be able to draw content there in + // general. + c.mMaxSize.width = std::min(c.mMaxSize.width, maxSize); + c.mMaxSize.height = std::min(c.mMaxSize.height, maxSize); + } + mSizeConstraintsScale = GetDefaultScale().scale; nsBaseWidget::SetSizeConstraints(c); diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index 2399dff919..ed622e5e3e 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -218,10 +218,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) return true; } - ClientLayerManager *clientLayerManager = - (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) - ? static_cast(GetLayerManager()) - : nullptr; + ClientLayerManager *clientLayerManager = GetLayerManager()->AsClientLayerManager(); if (clientLayerManager && mCompositorParent && !mBounds.IsEqualEdges(mLastPaintBounds))