From 2e9d874b1142b5fc670700a7923f873af5eb274d Mon Sep 17 00:00:00 2001 From: Ed Morley Date: Thu, 27 Sep 2012 16:34:46 +0100 Subject: [PATCH] Revert mozilla-inbound to e4dd1fa6d222 for crashes and test failures on a CLOSED TREE --- browser/base/content/tabbrowser.xml | 3 +- browser/components/tabview/content.js | 4 +- content/base/src/nsFrameLoader.cpp | 22 +- content/base/src/nsObjectLoadingContent.cpp | 2 +- content/events/src/nsDOMNotifyPaintEvent.cpp | 28 +- content/events/src/nsPaintRequest.cpp | 12 +- content/events/test/Makefile.in | 2 - content/events/test/bug426082.html | 161 -- content/events/test/bug656379-1.html | 181 -- content/events/test/test_bug426082.html | 144 +- content/events/test/test_bug656379-1.html | 166 +- .../html/content/src/nsHTMLCanvasElement.cpp | 21 +- content/media/VideoFrameContainer.cpp | 5 +- dom/base/nsDOMWindowUtils.cpp | 13 +- dom/plugins/base/nsPluginInstanceOwner.cpp | 18 +- dom/plugins/test/mochitest/test_painting.html | 3 +- dom/tests/mochitest/chrome/selectAtPoint.html | 18 +- .../libeditor/html/crashtests/crashtests.list | 2 +- editor/reftests/reftest.list | 2 +- ...ellcheck-textarea-focused-notreadonly.html | 2 +- editor/reftests/spellcheck-textarea-ref2.html | 11 - gfx/layers/ImageLayers.h | 2 - gfx/layers/LayerTreeInvalidation.cpp | 341 ---- gfx/layers/LayerTreeInvalidation.h | 70 - gfx/layers/Layers.h | 43 +- gfx/layers/Makefile.in | 2 - gfx/layers/basic/BasicThebesLayer.h | 4 +- gfx/layers/basic/BasicTiledThebesLayer.h | 1 - gfx/layers/d3d10/ThebesLayerD3D10.cpp | 4 +- gfx/layers/d3d9/ThebesLayerD3D9.cpp | 4 +- gfx/layers/opengl/ThebesLayerOGL.cpp | 4 +- gfx/thebes/gfx3DMatrix.cpp | 7 - gfx/thebes/gfx3DMatrix.h | 1 - image/src/RasterImage.cpp | 71 +- image/src/RasterImage.h | 9 - image/test/mochitest/test_animSVGImage.html | 2 - layout/base/FrameLayerBuilder.cpp | 1518 +++++++---------- layout/base/FrameLayerBuilder.h | 292 +--- layout/base/Makefile.in | 2 - layout/base/nsCSSFrameConstructor.cpp | 32 +- layout/base/nsCaret.cpp | 41 +- layout/base/nsCaret.h | 6 + layout/base/nsDisplayList.cpp | 145 +- layout/base/nsDisplayList.h | 174 +- layout/base/nsDisplayListInvalidation.cpp | 70 - layout/base/nsDisplayListInvalidation.h | 96 -- layout/base/nsDocumentViewer.cpp | 3 +- layout/base/nsFrameManager.cpp | 7 +- layout/base/nsFrameManager.h | 3 +- layout/base/nsIPresShell.h | 10 - layout/base/nsLayoutUtils.cpp | 7 +- layout/base/nsPresContext.cpp | 148 +- layout/base/nsPresContext.h | 39 +- layout/base/nsPresShell.cpp | 84 +- layout/base/nsPresShell.h | 3 - layout/base/nsRefreshDriver.cpp | 10 - layout/base/nsRefreshDriver.h | 14 - layout/base/tests/Makefile.in | 3 +- layout/base/tests/bug450930.xhtml | 183 -- layout/base/tests/chrome/Makefile.in | 3 - ...t_leaf_layers_partition_browser_window.xul | 2 +- .../test_transformed_scrolling_repaints.html | 2 +- ...test_transformed_scrolling_repaints_2.html | 8 +- layout/base/tests/test_after_paint_pref.html | 1 - layout/base/tests/test_bug450930.xhtml | 192 ++- layout/forms/nsButtonFrameRenderer.cpp | 7 - layout/forms/nsComboboxControlFrame.cpp | 2 +- layout/forms/nsFieldSetFrame.cpp | 2 +- layout/forms/nsListControlFrame.cpp | 24 +- layout/forms/nsListControlFrame.h | 4 + layout/forms/nsMeterFrame.cpp | 2 +- layout/forms/nsProgressFrame.cpp | 2 +- layout/forms/nsTextControlFrame.cpp | 3 + layout/generic/crashtests/crashtests.list | 8 +- layout/generic/nsAbsoluteContainingBlock.cpp | 17 + layout/generic/nsBlockFrame.cpp | 146 +- layout/generic/nsBlockFrame.h | 3 + layout/generic/nsBlockReflowState.cpp | 1 + layout/generic/nsBulletFrame.cpp | 4 +- layout/generic/nsCanvasFrame.cpp | 18 +- layout/generic/nsCanvasFrame.h | 54 - layout/generic/nsColumnSetFrame.cpp | 8 + layout/generic/nsContainerFrame.cpp | 30 + layout/generic/nsFrame.cpp | 605 ++++--- layout/generic/nsFrame.h | 10 + layout/generic/nsGfxScrollFrame.cpp | 253 ++- layout/generic/nsGfxScrollFrame.h | 8 + layout/generic/nsHTMLCanvasFrame.cpp | 6 +- layout/generic/nsIFrame.h | 252 +-- layout/generic/nsImageFrame.cpp | 102 +- layout/generic/nsImageFrame.h | 10 +- layout/generic/nsImageMap.cpp | 4 +- layout/generic/nsObjectFrame.cpp | 4 +- layout/generic/nsPageFrame.cpp | 22 +- layout/generic/nsPlaceholderFrame.cpp | 3 +- layout/generic/nsSimplePageSequence.cpp | 13 + layout/generic/nsSimplePageSequence.h | 4 + layout/generic/nsSubDocumentFrame.cpp | 21 +- layout/generic/nsTextFrame.h | 19 - layout/generic/nsTextFrameThebes.cpp | 58 +- layout/generic/nsVideoFrame.cpp | 6 +- layout/generic/nsViewportFrame.cpp | 48 +- layout/generic/nsViewportFrame.h | 4 + layout/inspector/src/inFlasher.cpp | 2 +- layout/ipc/RenderFrameParent.cpp | 14 +- layout/mathml/nsMathMLChar.cpp | 9 +- layout/reftests/bidi/reftest.list | 6 +- layout/reftests/bugs/482659-1a.html | 3 +- layout/reftests/bugs/482659-1b.html | 3 +- layout/reftests/bugs/482659-1c.html | 3 +- layout/reftests/bugs/482659-1d.html | 3 +- layout/reftests/bugs/reftest.list | 4 +- .../css-invalid/input/input-customerror.html | 11 +- .../css-invalid/input/input-type-invalid.html | 5 +- .../reftests/css-invalid/input/reftest.list | 4 +- .../css-invalid/textarea/reftest.list | 10 +- .../textarea/textarea-customerror.html | 11 +- .../textarea/textarea-dyn-disabled.html | 5 +- .../textarea/textarea-dyn-not-disabled.html | 5 +- .../textarea/textarea-dyn-not-readonly.html | 11 +- .../textarea/textarea-dyn-readonly.html | 11 +- .../input/input-customerror.html | 11 +- .../input/input-type-invalid.html | 5 +- .../css-ui-invalid/input/reftest.list | 4 +- .../css-ui-invalid/textarea/reftest.list | 14 +- .../textarea/textarea-customerror.html | 11 +- .../textarea/textarea-dyn-disabled.html | 5 +- .../textarea/textarea-dyn-not-disabled.html | 5 +- .../textarea-dyn-not-readonly-changed.html | 14 +- ...textarea-dyn-not-readonly-not-changed.html | 11 +- .../textarea/textarea-dyn-readonly.html | 11 +- .../textarea-required-invalid-changed.html | 12 +- .../css-ui-valid/input/input-customerror.html | 11 +- .../input/input-type-invalid.html | 5 +- .../reftests/css-ui-valid/input/reftest.list | 4 +- .../reftests/css-ui-valid/select/reftest.list | 2 +- ...elect-required-multiple-valid-changed.html | 18 +- .../css-ui-valid/textarea/reftest.list | 16 +- .../textarea/textarea-customerror.html | 11 +- .../textarea/textarea-dyn-disabled.html | 11 +- .../textarea-dyn-not-disabled-changed.html | 14 +- .../textarea/textarea-dyn-not-disabled.html | 12 +- .../textarea-dyn-not-readonly-changed.html | 14 +- .../textarea/textarea-dyn-not-readonly.html | 12 +- .../textarea/textarea-dyn-readonly.html | 11 +- .../textarea-maxlength-valid-changed.html | 12 +- .../css-valid/input/input-customerror.html | 11 +- .../css-valid/input/input-type-invalid.html | 5 +- layout/reftests/css-valid/input/reftest.list | 4 +- .../reftests/css-valid/textarea/reftest.list | 10 +- .../textarea/textarea-customerror.html | 11 +- .../textarea/textarea-dyn-disabled.html | 11 +- .../textarea/textarea-dyn-not-disabled.html | 11 +- .../textarea/textarea-dyn-not-readonly.html | 11 +- .../textarea/textarea-dyn-readonly.html | 11 +- layout/reftests/font-inflation/reftest.list | 4 +- .../reftests/forms/placeholder/reftest.list | 2 +- layout/reftests/layers/reftest.list | 2 +- .../reftests/reftest-sanity/invalidation.html | 2 +- layout/reftests/scrolling/fixed-text-1.html | 2 +- layout/reftests/svg/reftest.list | 8 +- layout/reftests/svg/smil/sort/reftest.list | 2 +- .../reftests/svg/smil/transform/reftest.list | 6 +- layout/reftests/text-overflow/reftest.list | 2 +- layout/reftests/text/reftest.list | 2 +- layout/style/ImageLoader.cpp | 19 +- layout/svg/nsSVGEffects.cpp | 80 +- layout/svg/nsSVGEffects.h | 19 +- layout/svg/nsSVGForeignObjectFrame.cpp | 90 +- layout/svg/nsSVGForeignObjectFrame.h | 16 +- layout/svg/nsSVGIntegrationUtils.cpp | 14 +- layout/svg/nsSVGIntegrationUtils.h | 4 +- layout/svg/nsSVGOuterSVGFrame.cpp | 39 - layout/svg/nsSVGOuterSVGFrame.h | 24 +- layout/svg/nsSVGUtils.cpp | 11 +- layout/tables/nsTableCellFrame.cpp | 25 +- layout/tables/nsTableCellFrame.h | 4 - layout/tables/nsTableColFrame.cpp | 18 - layout/tables/nsTableColFrame.h | 4 - layout/tables/nsTableColGroupFrame.cpp | 19 - layout/tables/nsTableColGroupFrame.h | 5 - layout/tables/nsTableFrame.cpp | 61 +- layout/tables/nsTableFrame.h | 15 +- layout/tables/nsTableOuterFrame.cpp | 10 +- layout/tables/nsTableRowFrame.cpp | 50 +- layout/tables/nsTableRowFrame.h | 4 - layout/tables/nsTableRowGroupFrame.cpp | 56 +- layout/tables/nsTableRowGroupFrame.h | 4 - layout/tools/reftest/reftest-content.js | 2 - layout/tools/reftest/reftest.js | 4 - layout/xul/base/src/nsBox.cpp | 12 +- layout/xul/base/src/nsDeckFrame.cpp | 2 +- layout/xul/base/src/nsImageBoxFrame.cpp | 109 +- layout/xul/base/src/nsImageBoxFrame.h | 27 - layout/xul/base/src/nsListBoxLayout.cpp | 4 +- layout/xul/base/src/nsMenuPopupFrame.cpp | 10 +- layout/xul/base/src/nsMenuPopupFrame.h | 4 + layout/xul/base/src/nsSliderFrame.cpp | 2 +- layout/xul/base/src/nsStackLayout.cpp | 9 +- .../xul/base/src/tree/src/nsTreeBodyFrame.cpp | 12 +- mobile/android/base/gfx/ScreenshotLayer.java | 6 +- toolkit/content/tests/chrome/window_panel.xul | 10 +- view/src/nsViewManager.cpp | 27 +- view/src/nsViewManager.h | 1 + widget/android/nsLookAndFeel.cpp | 2 +- widget/android/nsWindow.cpp | 20 - widget/android/nsWindow.h | 2 +- widget/gtk2/nsNativeThemeGTK.cpp | 6 - widget/xpwidgets/nsNativeTheme.cpp | 2 +- 209 files changed, 3080 insertions(+), 4547 deletions(-) delete mode 100644 content/events/test/bug426082.html delete mode 100644 content/events/test/bug656379-1.html delete mode 100644 editor/reftests/spellcheck-textarea-ref2.html delete mode 100644 gfx/layers/LayerTreeInvalidation.cpp delete mode 100644 gfx/layers/LayerTreeInvalidation.h delete mode 100644 layout/base/nsDisplayListInvalidation.cpp delete mode 100644 layout/base/nsDisplayListInvalidation.h delete mode 100644 layout/base/tests/bug450930.xhtml diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index 27195217380a2..86d783c7e368f 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -3958,8 +3958,7 @@ class="tab-content" align="center"> + role="presentation"/> diff --git a/browser/components/tabview/content.js b/browser/components/tabview/content.js index 4e871f987bd59..89d9318544cce 100644 --- a/browser/components/tabview/content.js +++ b/browser/components/tabview/content.js @@ -41,9 +41,7 @@ let WindowEventHandler = { // Sends an asynchronous message when the "onMozAfterPaint" event // is fired. onMozAfterPaint: function WEH_onMozAfterPaint(event) { - if (event.clientRects.length > 0) { - sendAsyncMessage("Panorama:MozAfterPaint"); - } + sendAsyncMessage("Panorama:MozAfterPaint"); } }; diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp index 781da57574ebe..d950ba2fb5ea2 100644 --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -120,6 +120,14 @@ class nsAsyncDocShellDestroyer : public nsRunnable nsRefPtr mDocShell; }; +static void InvalidateFrame(nsIFrame* aFrame, uint32_t aFlags) +{ + if (!aFrame) + return; + nsRect rect = nsRect(nsPoint(0, 0), aFrame->GetRect().Size()); + aFrame->InvalidateWithFlags(rect, aFlags); +} + NS_IMPL_ISUPPORTS1(nsContentView, nsIContentView) bool @@ -154,6 +162,13 @@ nsContentView::Update(const ViewConfig& aConfig) rfp->ContentViewScaleChanged(this); } + // XXX could be clever here and compute a smaller invalidation + // rect + // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view + // semantics the same for both in-process and out-of-process + // . This is just a transform of the layer subtree in + // both. + InvalidateFrame(mFrameLoader->GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS); return NS_OK; } @@ -1816,6 +1831,11 @@ nsFrameLoader::SetRenderMode(uint32_t aRenderMode) } mRenderMode = aRenderMode; + // NB: we pass INVALIDATE_NO_THEBES_LAYERS here to keep view + // semantics the same for both in-process and out-of-process + // . This is just a transform of the layer subtree in + // both. + InvalidateFrame(GetPrimaryFrameOfOwningContent(), nsIFrame::INVALIDATE_NO_THEBES_LAYERS); return NS_OK; } @@ -1846,7 +1866,7 @@ nsFrameLoader::SetClipSubdocument(bool aClip) mClipSubdocument = aClip; nsIFrame* frame = GetPrimaryFrameOfOwningContent(); if (frame) { - frame->InvalidateFrame(); + InvalidateFrame(frame, 0); frame->PresContext()->PresShell()-> FrameNeedsReflow(frame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); nsSubDocumentFrame* subdocFrame = do_QueryFrame(frame); diff --git a/content/base/src/nsObjectLoadingContent.cpp b/content/base/src/nsObjectLoadingContent.cpp index 449c88363f4e0..19f7e108f70d0 100644 --- a/content/base/src/nsObjectLoadingContent.cpp +++ b/content/base/src/nsObjectLoadingContent.cpp @@ -951,7 +951,7 @@ nsObjectLoadingContent::HasNewFrame(nsIObjectFrame* aFrame) // Set up new frame to draw. objFrame->FixupWindow(objFrame->GetContentRectRelativeToSelf().Size()); - objFrame->InvalidateFrame(); + objFrame->Invalidate(objFrame->GetContentRectRelativeToSelf()); } return NS_OK; } diff --git a/content/events/src/nsDOMNotifyPaintEvent.cpp b/content/events/src/nsDOMNotifyPaintEvent.cpp index 9fd3014c3a0d8..fe428fb03b954 100644 --- a/content/events/src/nsDOMNotifyPaintEvent.cpp +++ b/content/events/src/nsDOMNotifyPaintEvent.cpp @@ -40,10 +40,12 @@ nsRegion nsDOMNotifyPaintEvent::GetRegion() { nsRegion r; - if (!nsContentUtils::IsCallerTrustedForRead()) { - return r; - } + bool isTrusted = nsContentUtils::IsCallerTrustedForRead(); for (uint32_t i = 0; i < mInvalidateRequests.Length(); ++i) { + if (!isTrusted && + (mInvalidateRequests[i].mFlags & nsIFrame::INVALIDATE_CROSS_DOC)) + continue; + r.Or(r, mInvalidateRequests[i].mRect); r.SimplifyOutward(10); } @@ -97,15 +99,17 @@ nsDOMNotifyPaintEvent::GetPaintRequests(nsIDOMPaintRequestList** aResult) if (!requests) return NS_ERROR_OUT_OF_MEMORY; - if (nsContentUtils::IsCallerTrustedForRead()) { - for (uint32_t i = 0; i < mInvalidateRequests.Length(); ++i) { - nsRefPtr r = new nsPaintRequest(); - if (!r) - return NS_ERROR_OUT_OF_MEMORY; - - r->SetRequest(mInvalidateRequests[i]); - requests->Append(r); - } + bool isTrusted = nsContentUtils::IsCallerTrustedForRead(); + for (uint32_t i = 0; i < mInvalidateRequests.Length(); ++i) { + if (!isTrusted && + (mInvalidateRequests[i].mFlags & nsIFrame::INVALIDATE_CROSS_DOC)) + continue; + + nsRefPtr r = new nsPaintRequest(); + if (!r) + return NS_ERROR_OUT_OF_MEMORY; + r->SetRequest(mInvalidateRequests[i]); + requests->Append(r); } requests.forget(aResult); diff --git a/content/events/src/nsPaintRequest.cpp b/content/events/src/nsPaintRequest.cpp index db6c1a7840b8e..fee912cfc6264 100644 --- a/content/events/src/nsPaintRequest.cpp +++ b/content/events/src/nsPaintRequest.cpp @@ -35,7 +35,17 @@ nsPaintRequest::GetClientRect(nsIDOMClientRect** aResult) NS_IMETHODIMP nsPaintRequest::GetReason(nsAString& aResult) { - aResult.AssignLiteral("repaint"); + switch (mRequest.mFlags & nsIFrame::INVALIDATE_REASON_MASK) { + case nsIFrame::INVALIDATE_REASON_SCROLL_BLIT: + aResult.AssignLiteral("scroll copy"); + break; + case nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT: + aResult.AssignLiteral("scroll repaint"); + break; + default: + aResult.Truncate(); + break; + } return NS_OK; } diff --git a/content/events/test/Makefile.in b/content/events/test/Makefile.in index c7229d90b5eb8..433c1c9c4a120 100644 --- a/content/events/test/Makefile.in +++ b/content/events/test/Makefile.in @@ -36,7 +36,6 @@ MOCHITEST_FILES = \ test_bug412567.html \ test_bug422132.html \ test_bug426082.html \ - bug426082.html \ test_bug427537.html \ test_bug432698.html \ test_bug443985.html \ @@ -72,7 +71,6 @@ MOCHITEST_FILES = \ test_bug648573.html \ test_bug615597.html \ test_bug656379-1.html \ - bug656379-1.html \ test_bug656379-2.html \ test_bug656954.html \ test_bug659071.html \ diff --git a/content/events/test/bug426082.html b/content/events/test/bug426082.html deleted file mode 100644 index 4a7b178e190ad..0000000000000 --- a/content/events/test/bug426082.html +++ /dev/null @@ -1,161 +0,0 @@ - - - - - Test for Bug 426082 - - - - - - - -Mozilla Bug 426082 -

- -

-

-

Something under the label

-
-
-
- - diff --git a/content/events/test/bug656379-1.html b/content/events/test/bug656379-1.html deleted file mode 100644 index bf40853573629..0000000000000 --- a/content/events/test/bug656379-1.html +++ /dev/null @@ -1,181 +0,0 @@ - - - - - Test for Bug 656379 - - - - - - - -Mozilla Bug 656379 -

- -
-
-
-

-

-

Something under the label

- - - diff --git a/content/events/test/test_bug426082.html b/content/events/test/test_bug426082.html index d07559413911e..83ba01577a258 100644 --- a/content/events/test/test_bug426082.html +++ b/content/events/test/test_bug426082.html @@ -9,22 +9,156 @@ + - - + +Mozilla Bug 426082 +

+
 
 
+

+

+

Something under the label

diff --git a/content/events/test/test_bug656379-1.html b/content/events/test/test_bug656379-1.html index bc92189e241ee..faf03a1b3e62c 100644 --- a/content/events/test/test_bug656379-1.html +++ b/content/events/test/test_bug656379-1.html @@ -9,22 +9,176 @@ - - + + + +Mozilla Bug 426082 +

+
 
 
+

+

+

Something under the label

diff --git a/content/html/content/src/nsHTMLCanvasElement.cpp b/content/html/content/src/nsHTMLCanvasElement.cpp index bd5d90fe11370..cb2cf58bdea3f 100644 --- a/content/html/content/src/nsHTMLCanvasElement.cpp +++ b/content/html/content/src/nsHTMLCanvasElement.cpp @@ -836,23 +836,32 @@ nsHTMLCanvasElement::InvalidateCanvasContent(const gfxRect* damageRect) frame->MarkLayersActive(nsChangeHint(0)); - Layer* layer; + nsRect invalRect; + nsRect contentArea = frame->GetContentRect(); if (damageRect) { nsIntSize size = GetWidthHeight(); if (size.width != 0 && size.height != 0) { + // damageRect and size are in CSS pixels; contentArea is in appunits + // We want a rect in appunits; so avoid doing pixels-to-appunits and + // vice versa conversion here. gfxRect realRect(*damageRect); + realRect.Scale(contentArea.width / gfxFloat(size.width), + contentArea.height / gfxFloat(size.height)); realRect.RoundOut(); // then make it a nsRect - nsIntRect invalRect(realRect.X(), realRect.Y(), - realRect.Width(), realRect.Height()); + invalRect = nsRect(realRect.X(), realRect.Y(), + realRect.Width(), realRect.Height()); - layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS, &invalRect); + invalRect = invalRect.Intersect(nsRect(nsPoint(0,0), contentArea.Size())); } } else { - layer = frame->InvalidateLayer(nsDisplayItem::TYPE_CANVAS); + invalRect = nsRect(nsPoint(0, 0), contentArea.Size()); } + invalRect.MoveBy(contentArea.TopLeft() - frame->GetPosition()); + + Layer* layer = frame->InvalidateLayer(invalRect, nsDisplayItem::TYPE_CANVAS); if (layer) { static_cast(layer)->Updated(); } @@ -880,7 +889,7 @@ nsHTMLCanvasElement::InvalidateCanvas() if (!frame) return; - frame->InvalidateFrame(); + frame->Invalidate(frame->GetContentRect() - frame->GetPosition()); } int32_t diff --git a/content/media/VideoFrameContainer.cpp b/content/media/VideoFrameContainer.cpp index 0ed671beb20b7..1dda5b658d8a6 100644 --- a/content/media/VideoFrameContainer.cpp +++ b/content/media/VideoFrameContainer.cpp @@ -131,10 +131,11 @@ void VideoFrameContainer::Invalidate() } if (frame) { + nsRect contentRect = frame->GetContentRect() - frame->GetPosition(); if (invalidateFrame) { - frame->InvalidateFrame(); + frame->Invalidate(contentRect); } else { - frame->InvalidateLayer(nsDisplayItem::TYPE_VIDEO); + frame->InvalidateLayer(contentRect, nsDisplayItem::TYPE_VIDEO); } } diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 71c5d55847cde..b0dcbf99967d9 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -220,10 +220,12 @@ nsDOMWindowUtils::Redraw(uint32_t aCount, uint32_t *aDurationOut) nsIFrame *rootFrame = presShell->GetRootFrame(); if (rootFrame) { + nsRect r(nsPoint(0, 0), rootFrame->GetSize()); + PRIntervalTime iStart = PR_IntervalNow(); for (uint32_t i = 0; i < aCount; i++) - rootFrame->InvalidateFrame(); + rootFrame->InvalidateWithFlags(r, nsIFrame::INVALIDATE_IMMEDIATE); #if defined(MOZ_X11) && defined(MOZ_WIDGET_GTK) XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), False); @@ -387,7 +389,14 @@ nsDOMWindowUtils::SetDisplayPortForElement(float aXPx, float aYPx, nsIFrame* rootFrame = presShell->FrameManager()->GetRootFrame(); if (rootFrame) { - rootFrame->InvalidateFrame(); + nsIContent* rootContent = + rootScrollFrame ? rootScrollFrame->GetContent() : nullptr; + nsRect rootDisplayport; + bool usingDisplayport = rootContent && + nsLayoutUtils::GetDisplayPort(rootContent, &rootDisplayport); + rootFrame->InvalidateWithFlags( + usingDisplayport ? rootDisplayport : rootFrame->GetVisualOverflowRect(), + nsIFrame::INVALIDATE_NO_THEBES_LAYERS); // If we are hiding something that is a display root then send empty paint // transaction in order to release retained layers because it won't get diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 0dd1b47ce1e04..d4779ac790980 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -660,11 +660,15 @@ NS_IMETHODIMP nsPluginInstanceOwner::InvalidateRect(NPRect *invalidRect) return NS_OK; } #endif - nsIntRect rect(invalidRect->left, - invalidRect->top, - invalidRect->right - invalidRect->left, - invalidRect->bottom - invalidRect->top); - mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN, &rect); + + nsPresContext* presContext = mObjectFrame->PresContext(); + nsRect rect(presContext->DevPixelsToAppUnits(invalidRect->left), + presContext->DevPixelsToAppUnits(invalidRect->top), + presContext->DevPixelsToAppUnits(invalidRect->right - invalidRect->left), + presContext->DevPixelsToAppUnits(invalidRect->bottom - invalidRect->top)); + + rect.MoveBy(mObjectFrame->GetContentRectRelativeToSelf().TopLeft()); + mObjectFrame->InvalidateLayer(rect, nsDisplayItem::TYPE_PLUGIN); return NS_OK; } @@ -677,7 +681,7 @@ NS_IMETHODIMP nsPluginInstanceOwner::RedrawPlugin() { if (mObjectFrame) { - mObjectFrame->InvalidateLayer(nsDisplayItem::TYPE_PLUGIN); + mObjectFrame->InvalidateLayer(mObjectFrame->GetContentRectRelativeToSelf(), nsDisplayItem::TYPE_PLUGIN); } return NS_OK; } @@ -3743,7 +3747,7 @@ void nsPluginInstanceOwner::SetFrame(nsObjectFrame *aFrame) mObjectFrame->PrepForDrawing(mWidget); } mObjectFrame->FixupWindow(mObjectFrame->GetContentRectRelativeToSelf().Size()); - mObjectFrame->InvalidateFrame(); + mObjectFrame->Invalidate(mObjectFrame->GetContentRectRelativeToSelf()); // Scroll position listening is only required for Carbon event model plugins on Mac OS X. #if defined(XP_MACOSX) && !defined(NP_NO_CARBON) diff --git a/dom/plugins/test/mochitest/test_painting.html b/dom/plugins/test/mochitest/test_painting.html index a8a6e973f15b7..a2d524946216f 100644 --- a/dom/plugins/test/mochitest/test_painting.html +++ b/dom/plugins/test/mochitest/test_painting.html @@ -94,9 +94,8 @@ function waitForPaint(func) { paint_waiter.last_paint_count = paint_waiter.getPaintCount(); - // Ensure the waiter has had a style change, so that this will + // Ensure the waiter has been reflowed with zero height, so that this will // change its size and cause a paint. - paint_waiter.style.backgroundColor = paint_waiter.style.backgroundColor == "blue" ? "yellow" : "blue"; var flush = paint_waiter.offsetHeight; paint_waiter.style.height = "1px"; waitForPaintHelper(func); diff --git a/dom/tests/mochitest/chrome/selectAtPoint.html b/dom/tests/mochitest/chrome/selectAtPoint.html index 798aff4386e27..45abb599cb187 100644 --- a/dom/tests/mochitest/chrome/selectAtPoint.html +++ b/dom/tests/mochitest/chrome/selectAtPoint.html @@ -197,23 +197,13 @@ } function onFrameLoad() { - // Exit the onload handler before trying the test, because we need - // to ensure that paint unsupression has happened. - setTimeout(function() { - frameLoad = true; - testReady(); - }, 0); + frameLoad = true; + testReady(); } function onPageLoad() { - // Exit the onload handler before trying the test, because we need - // to ensure that paint unsupression has happened - // XXXroc why do we need to separately test for the loading of the frame - // and a paint? That should not be necessary for this test. - setTimeout(function() { - pageLoad = true; - testReady(); - }, 0); + pageLoad = true; + testReady(); } function onPaint() { diff --git a/editor/libeditor/html/crashtests/crashtests.list b/editor/libeditor/html/crashtests/crashtests.list index 8cf65364169f5..dd8fde519ba53 100644 --- a/editor/libeditor/html/crashtests/crashtests.list +++ b/editor/libeditor/html/crashtests/crashtests.list @@ -25,7 +25,7 @@ load 615450-1.html load 639736-1.xhtml load 643786-1.html load 682650-1.html -asserts(0-1) load 716456-1.html +load 716456-1.html load 759748.html load 761861.html load 769008-1.html diff --git a/editor/reftests/reftest.list b/editor/reftests/reftest.list index 6c61cbf2dfe89..15555821efc0e 100644 --- a/editor/reftests/reftest.list +++ b/editor/reftests/reftest.list @@ -45,7 +45,7 @@ fails-if(Android) != spellcheck-input-property-dynamic-override-inherit.html spe random-if(Android) != spellcheck-textarea-attr.html spellcheck-textarea-ref.html needs-focus == spellcheck-textarea-focused.html spellcheck-textarea-ref.html needs-focus == spellcheck-textarea-focused-reframe.html spellcheck-textarea-ref.html -needs-focus == spellcheck-textarea-focused-notreadonly.html spellcheck-textarea-ref2.html +needs-focus == spellcheck-textarea-focused-notreadonly.html spellcheck-textarea-ref.html random-if(Android) != spellcheck-textarea-nofocus.html spellcheck-textarea-ref.html random-if(Android) != spellcheck-textarea-disabled.html spellcheck-textarea-ref.html random-if(Android) != spellcheck-textarea-attr-inherit.html spellcheck-textarea-ref.html diff --git a/editor/reftests/spellcheck-textarea-focused-notreadonly.html b/editor/reftests/spellcheck-textarea-focused-notreadonly.html index 475ae60020da6..79b1c38d301e2 100644 --- a/editor/reftests/spellcheck-textarea-focused-notreadonly.html +++ b/editor/reftests/spellcheck-textarea-focused-notreadonly.html @@ -2,7 +2,7 @@ - + - - diff --git a/gfx/layers/ImageLayers.h b/gfx/layers/ImageLayers.h index 1f42108db2f15..39f99a4ba9a7b 100644 --- a/gfx/layers/ImageLayers.h +++ b/gfx/layers/ImageLayers.h @@ -54,8 +54,6 @@ class THEBES_API ImageLayer : public Layer { ImageContainer* GetContainer() { return mContainer; } gfxPattern::GraphicsFilter GetFilter() { return mFilter; } - const gfxIntSize& GetScaleToSize() { return mScaleToSize; } - ScaleMode GetScaleMode() { return mScaleMode; } MOZ_LAYER_DECL_NAME("ImageLayer", TYPE_IMAGE) diff --git a/gfx/layers/LayerTreeInvalidation.cpp b/gfx/layers/LayerTreeInvalidation.cpp deleted file mode 100644 index 3df94cdd70f4f..0000000000000 --- a/gfx/layers/LayerTreeInvalidation.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "LayerTreeInvalidation.h" -#include "Layers.h" -#include "ImageLayers.h" -#include "gfxUtils.h" - -namespace mozilla { -namespace layers { - -struct LayerPropertiesBase; -LayerPropertiesBase* CloneLayerTreePropertiesInternal(Layer* aRoot); - -static nsIntRect -TransformRect(const nsIntRect& aRect, const gfx3DMatrix& aTransform) -{ - if (aRect.IsEmpty()) { - return nsIntRect(); - } - - gfxRect rect(aRect.x, aRect.y, aRect.width, aRect.height); - rect = aTransform.TransformBounds(rect); - rect.RoundOut(); - - nsIntRect intRect; - if (!gfxUtils::GfxRectToIntRect(rect, &intRect)) { - return nsIntRect(); - } - - return intRect; -} - -/** - * Walks over this layer, and all descendant layers. - * If any of these are a ContainerLayer that reports invalidations to a PresShell, - * then report that the entire bounds have changed. - */ -static void -NotifySubdocumentInvalidationRecursive(Layer* aLayer, NotifySubDocInvalidationFunc aCallback) -{ - aLayer->ClearInvalidRect(); - ContainerLayer* container = aLayer->AsContainerLayer(); - - if (aLayer->GetMaskLayer()) { - NotifySubdocumentInvalidationRecursive(aLayer->GetMaskLayer(), aCallback); - } - - if (!container) { - return; - } - - for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { - NotifySubdocumentInvalidationRecursive(child, aCallback); - } - - aCallback(container, container->GetVisibleRegion()); -} - -struct LayerPropertiesBase : public LayerProperties -{ - LayerPropertiesBase(Layer* aLayer) - : mLayer(aLayer) - , mMaskLayer(nullptr) - , mVisibleBounds(aLayer->GetVisibleRegion().GetBounds()) - , mTransform(aLayer->GetTransform()) - , mOpacity(aLayer->GetOpacity()) - , mUseClipRect(!!aLayer->GetClipRect()) - { - MOZ_COUNT_CTOR(LayerPropertiesBase); - if (aLayer->GetMaskLayer()) { - mMaskLayer = CloneLayerTreePropertiesInternal(aLayer->GetMaskLayer()); - } - if (mUseClipRect) { - mClipRect = *aLayer->GetClipRect(); - } - } - LayerPropertiesBase() - : mLayer(nullptr) - , mMaskLayer(nullptr) - { - MOZ_COUNT_CTOR(LayerPropertiesBase); - } - ~LayerPropertiesBase() - { - MOZ_COUNT_DTOR(LayerPropertiesBase); - } - - virtual nsIntRect ComputeDifferences(Layer* aRoot, - NotifySubDocInvalidationFunc aCallback); - - virtual void MoveBy(const nsIntPoint& aOffset); - - nsIntRect ComputeChange(NotifySubDocInvalidationFunc aCallback) - { - bool transformChanged = mTransform != mLayer->GetTransform(); - Layer* otherMask = mLayer->GetMaskLayer(); - const nsIntRect* otherClip = mLayer->GetClipRect(); - nsIntRect result; - if ((mMaskLayer ? mMaskLayer->mLayer : nullptr) != otherMask || - (mUseClipRect != !!otherClip) || - mLayer->GetOpacity() != mOpacity || - transformChanged) - { - result = OldTransformedBounds(); - if (transformChanged) { - result = result.Union(NewTransformedBounds()); - } - - // If we don't have to generate invalidations separately for child - // layers then we can just stop here since we've already invalidated the entire - // old and new bounds. - if (!aCallback) { - ClearInvalidations(mLayer); - return result; - } - } - - result = result.Union(ComputeChangeInternal(aCallback)); - result = result.Union(TransformRect(mLayer->GetInvalidRegion().GetBounds(), mTransform)); - - if (mMaskLayer && otherMask) { - nsIntRect maskDiff = mMaskLayer->ComputeChange(aCallback); - result = result.Union(TransformRect(maskDiff, mTransform)); - } - - if (mUseClipRect && otherClip) { - if (!mClipRect.IsEqualInterior(*otherClip)) { - nsIntRegion tmp; - tmp.Xor(mClipRect, *otherClip); - result = result.Union(tmp.GetBounds()); - } - } - - mLayer->ClearInvalidRect(); - return result; - } - - nsIntRect NewTransformedBounds() - { - return TransformRect(mLayer->GetVisibleRegion().GetBounds(), mLayer->GetTransform()); - } - - nsIntRect OldTransformedBounds() - { - return TransformRect(mVisibleBounds, mTransform); - } - - virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) { return nsIntRect(); } - - nsRefPtr mLayer; - nsAutoPtr mMaskLayer; - nsIntRect mVisibleBounds; - gfx3DMatrix mTransform; - float mOpacity; - nsIntRect mClipRect; - bool mUseClipRect; -}; - -struct ContainerLayerProperties : public LayerPropertiesBase -{ - ContainerLayerProperties(ContainerLayer* aLayer) - : LayerPropertiesBase(aLayer) - { - for (Layer* child = aLayer->GetFirstChild(); child; child = child->GetNextSibling()) { - mChildren.AppendElement(CloneLayerTreePropertiesInternal(child)); - } - } - - virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) - { - ContainerLayer* container = mLayer->AsContainerLayer(); - nsIntRegion result; - - uint32_t i = 0; - for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { - if (i >= mChildren.Length() || child != mChildren[i]->mLayer) { - // Child change. Invalidate the full areas. - // TODO: We could be smarter here if non-overlapping children - // swap order. - result.Or(result, TransformRect(child->GetVisibleRegion().GetBounds(), child->GetTransform())); - if (i < mChildren.Length()) { - result.Or(result, mChildren[i]->OldTransformedBounds()); - } - if (aCallback) { - NotifySubdocumentInvalidationRecursive(child, aCallback); - } else { - ClearInvalidations(child); - } - } else { - // Same child, check for differences within the child - result.Or(result, mChildren[i]->ComputeChange(aCallback)); - } - - i++; - } - - // Process remaining removed children. - while (i < mChildren.Length()) { - result.Or(result, mChildren[i]->OldTransformedBounds()); - i++; - } - - if (aCallback) { - aCallback(container, result); - } - - return TransformRect(result.GetBounds(), mLayer->GetTransform()); - } - - nsAutoTArray,1> mChildren; -}; - -struct ColorLayerProperties : public LayerPropertiesBase -{ - ColorLayerProperties(ColorLayer *aLayer) - : LayerPropertiesBase(aLayer) - , mColor(aLayer->GetColor()) - { } - - virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) - { - ColorLayer* color = static_cast(mLayer.get()); - - if (mColor != color->GetColor()) { - return NewTransformedBounds(); - } - - return nsIntRect(); - } - - gfxRGBA mColor; -}; - -struct ImageLayerProperties : public LayerPropertiesBase -{ - ImageLayerProperties(ImageLayer* aImage) - : LayerPropertiesBase(aImage) - , mVisibleRegion(aImage->GetVisibleRegion()) - , mContainer(aImage->GetContainer()) - , mFilter(aImage->GetFilter()) - , mScaleToSize(aImage->GetScaleToSize()) - , mScaleMode(aImage->GetScaleMode()) - { } - - virtual nsIntRect ComputeChangeInternal(NotifySubDocInvalidationFunc aCallback) - { - ImageLayer* image = static_cast(mLayer.get()); - - if (!image->GetVisibleRegion().IsEqual(mVisibleRegion)) { - nsIntRect result = NewTransformedBounds(); - result = result.Union(OldTransformedBounds()); - return result; - } - - if (mContainer != image->GetContainer() || - mFilter != image->GetFilter() || - mScaleToSize != image->GetScaleToSize() || - mScaleMode != image->GetScaleMode()) { - return NewTransformedBounds(); - } - - return nsIntRect(); - } - - nsIntRegion mVisibleRegion; - nsRefPtr mContainer; - gfxPattern::GraphicsFilter mFilter; - gfxIntSize mScaleToSize; - ImageLayer::ScaleMode mScaleMode; -}; - -LayerPropertiesBase* -CloneLayerTreePropertiesInternal(Layer* aRoot) -{ - if (!aRoot) { - return new LayerPropertiesBase(); - } - - switch (aRoot->GetType()) { - case Layer::TYPE_CONTAINER: return new ContainerLayerProperties(aRoot->AsContainerLayer()); - case Layer::TYPE_COLOR: return new ColorLayerProperties(static_cast(aRoot)); - case Layer::TYPE_IMAGE: return new ImageLayerProperties(static_cast(aRoot)); - default: return new LayerPropertiesBase(aRoot); - } - - return nullptr; -} - -/* static */ LayerProperties* -LayerProperties::CloneFrom(Layer* aRoot) -{ - return CloneLayerTreePropertiesInternal(aRoot); -} - -/* static */ void -LayerProperties::ClearInvalidations(Layer *aLayer) -{ - aLayer->ClearInvalidRect(); - if (aLayer->GetMaskLayer()) { - ClearInvalidations(aLayer->GetMaskLayer()); - } - - ContainerLayer* container = aLayer->AsContainerLayer(); - if (!container) { - return; - } - - for (Layer* child = container->GetFirstChild(); child; child = child->GetNextSibling()) { - ClearInvalidations(child); - } -} - -nsIntRect -LayerPropertiesBase::ComputeDifferences(Layer* aRoot, NotifySubDocInvalidationFunc aCallback) -{ - NS_ASSERTION(aRoot, "Must have a layer tree to compare against!"); - if (mLayer != aRoot) { - if (aCallback) { - NotifySubdocumentInvalidationRecursive(aRoot, aCallback); - } else { - ClearInvalidations(aRoot); - } - nsIntRect result = TransformRect(aRoot->GetVisibleRegion().GetBounds(), aRoot->GetTransform()); - result = result.Union(OldTransformedBounds()); - return result; - } else { - return ComputeChange(aCallback); - } -} - -void -LayerPropertiesBase::MoveBy(const nsIntPoint& aOffset) -{ - mTransform.TranslatePost(gfxPoint3D(aOffset.x, aOffset.y, 0)); -} - -} // namespace layers -} // namespace mozilla diff --git a/gfx/layers/LayerTreeInvalidation.h b/gfx/layers/LayerTreeInvalidation.h deleted file mode 100644 index 0e3dc2535c37c..0000000000000 --- a/gfx/layers/LayerTreeInvalidation.h +++ /dev/null @@ -1,70 +0,0 @@ -/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GFX_LAYER_TREE_INVALIDATION_H -#define GFX_LAYER_TREE_INVALIDATION_H - -#include "nsRegion.h" - -class nsPresContext; - -namespace mozilla { -namespace layers { - -class Layer; -class ContainerLayer; - -/** - * Callback for ContainerLayer invalidations. - * - * @param aContainer ContainerLayer being invalidated. - * @param aRegion Invalidated region in the ContainerLayer's coordinate - * space. - */ -typedef void (*NotifySubDocInvalidationFunc)(ContainerLayer* aLayer, - const nsIntRegion& aRegion); - -/** - * A set of cached layer properties (including those of child layers), - * used for comparing differences in layer trees. - */ -struct LayerProperties -{ - virtual ~LayerProperties() {} - - /** - * Copies the current layer tree properties into - * a new LayerProperties object. - * - * @param Layer tree to copy, or nullptr if we have no - * initial layer tree. - */ - static LayerProperties* CloneFrom(Layer* aRoot); - - /** - * Clear all invalidation status from this layer tree. - */ - static void ClearInvalidations(Layer* aRoot); - - /** - * Compares a set of existing layer tree properties to the current layer - * tree and generates the changed rectangle. - * - * @param aRoot Root layer of the layer tree to compare against. - * @param aCallback If specified, callback to call when ContainerLayers - * are invalidated. - * @return Painted area changed by the layer tree changes. - */ - virtual nsIntRect ComputeDifferences(Layer* aRoot, - NotifySubDocInvalidationFunc aCallback) = 0; - - - virtual void MoveBy(const nsIntPoint& aOffset) = 0; -}; - -} // namespace layers -} // namespace mozilla - -#endif /* GFX_LAYER_TREE_INVALIDATON_H */ diff --git a/gfx/layers/Layers.h b/gfx/layers/Layers.h index d187d7d7a18cb..8448665279a5c 100644 --- a/gfx/layers/Layers.h +++ b/gfx/layers/Layers.h @@ -87,6 +87,20 @@ class THEBES_API LayerUserData { virtual ~LayerUserData() {} }; +class LayerManagerLayerBuilder : public LayerUserData { +public: + LayerManagerLayerBuilder(FrameLayerBuilder* aBuilder, bool aDelete = true) + : mLayerBuilder(aBuilder) + , mDelete(aDelete) + { + MOZ_COUNT_CTOR(LayerManagerLayerBuilder); + } + ~LayerManagerLayerBuilder(); + + FrameLayerBuilder* mLayerBuilder; + bool mDelete; +}; + /* * Motivation: For truly smooth animation and video playback, we need to * be able to compose frames and render them on a dedicated thread (i.e. @@ -199,7 +213,8 @@ class THEBES_API LayerManager { }; FrameLayerBuilder* GetLayerBuilder() { - return reinterpret_cast(GetUserData(&gLayerManagerLayerBuilder)); + LayerManagerLayerBuilder *data = static_cast(GetUserData(&gLayerManagerLayerBuilder)); + return data ? data->mLayerBuilder : nullptr; } /** @@ -957,29 +972,6 @@ class THEBES_API Layer { static bool IsLogEnabled() { return LayerManager::IsLogEnabled(); } - /** - * Returns the current area of the layer (in layer-space coordinates) - * marked as needed to be recomposited. - */ - const nsIntRegion& GetInvalidRegion() { return mInvalidRegion; } - - /** - * Mark the entirety of the layer's visible region as being invalid. - */ - void SetInvalidRectToVisibleRegion() { mInvalidRegion = GetVisibleRegion(); } - - /** - * Adds to the current invalid rect. - */ - void AddInvalidRect(const nsIntRect& aRect) { mInvalidRegion.Or(mInvalidRegion, aRect); } - - /** - * Clear the invalid rect, marking the layer as being identical to what is currently - * composited. - */ - void ClearInvalidRect() { mInvalidRegion.SetEmpty(); } - - #ifdef DEBUG void SetDebugColorIndex(uint32_t aIndex) { mDebugColorIndex = aIndex; } uint32_t GetDebugColorIndex() { return mDebugColorIndex; } @@ -1041,7 +1033,6 @@ class THEBES_API Layer { float mOpacity; nsIntRect mClipRect; nsIntRect mTileSourceRect; - nsIntRegion mInvalidRegion; uint32_t mContentFlags; bool mUseClipRect; bool mUseTileSourceRect; @@ -1387,7 +1378,7 @@ class THEBES_API CanvasLayer : public Layer { * Notify this CanvasLayer that the canvas surface contents have * changed (or will change) before the next transaction. */ - void Updated() { mDirty = true; SetInvalidRectToVisibleRegion(); } + void Updated() { mDirty = true; } /** * Register a callback to be called at the end of each transaction. diff --git a/gfx/layers/Makefile.in b/gfx/layers/Makefile.in index 186385fb9ef9b..e59a9350412ec 100644 --- a/gfx/layers/Makefile.in +++ b/gfx/layers/Makefile.in @@ -44,7 +44,6 @@ EXPORTS = \ LayerManagerOGL.h \ LayerManagerOGLProgram.h \ LayerSorter.h \ - LayerTreeInvalidation.h \ ReadbackLayer.h \ ShadowLayersManager.h \ SharedTextureImage.h \ @@ -77,7 +76,6 @@ CPPSRCS = \ ReusableTileStoreOGL.cpp \ LayerManagerOGLProgram.cpp \ LayerSorter.cpp \ - LayerTreeInvalidation.cpp \ ImageLayers.cpp \ TexturePoolOGL.cpp \ $(NULL) diff --git a/gfx/layers/basic/BasicThebesLayer.h b/gfx/layers/basic/BasicThebesLayer.h index a9cc7aca2b2b5..317f9cd8eb2fc 100644 --- a/gfx/layers/basic/BasicThebesLayer.h +++ b/gfx/layers/basic/BasicThebesLayer.h @@ -37,9 +37,7 @@ class BasicThebesLayer : public ThebesLayer, public BasicImplData { { NS_ASSERTION(BasicManager()->InConstruction(), "Can only set properties in construction phase"); - mInvalidRegion.Or(mInvalidRegion, aRegion); - mInvalidRegion.SimplifyOutward(10); - mValidRegion.Sub(mValidRegion, mInvalidRegion); + mValidRegion.Sub(mValidRegion, aRegion); } virtual void PaintThebes(gfxContext* aContext, diff --git a/gfx/layers/basic/BasicTiledThebesLayer.h b/gfx/layers/basic/BasicTiledThebesLayer.h index 69f6453c5e9b9..0ee6150eb1a88 100644 --- a/gfx/layers/basic/BasicTiledThebesLayer.h +++ b/gfx/layers/basic/BasicTiledThebesLayer.h @@ -175,7 +175,6 @@ class BasicTiledThebesLayer : public ThebesLayer, // Thebes Layer virtual Layer* AsLayer() { return this; } virtual void InvalidateRegion(const nsIntRegion& aRegion) { - mInvalidRegion.Or(mInvalidRegion, aRegion); mValidRegion.Sub(mValidRegion, aRegion); } diff --git a/gfx/layers/d3d10/ThebesLayerD3D10.cpp b/gfx/layers/d3d10/ThebesLayerD3D10.cpp index f438a3f2333b5..28372d33cf7c7 100644 --- a/gfx/layers/d3d10/ThebesLayerD3D10.cpp +++ b/gfx/layers/d3d10/ThebesLayerD3D10.cpp @@ -45,9 +45,7 @@ ThebesLayerD3D10::~ThebesLayerD3D10() void ThebesLayerD3D10::InvalidateRegion(const nsIntRegion &aRegion) { - mInvalidRegion.Or(mInvalidRegion, aRegion); - mInvalidRegion.SimplifyOutward(10); - mValidRegion.Sub(mValidRegion, mInvalidRegion); + mValidRegion.Sub(mValidRegion, aRegion); } void ThebesLayerD3D10::CopyRegion(ID3D10Texture2D* aSrc, const nsIntPoint &aSrcOffset, diff --git a/gfx/layers/d3d9/ThebesLayerD3D9.cpp b/gfx/layers/d3d9/ThebesLayerD3D9.cpp index 8216c51cca430..1cfd77eeea289 100644 --- a/gfx/layers/d3d9/ThebesLayerD3D9.cpp +++ b/gfx/layers/d3d9/ThebesLayerD3D9.cpp @@ -49,9 +49,7 @@ ThebesLayerD3D9::~ThebesLayerD3D9() void ThebesLayerD3D9::InvalidateRegion(const nsIntRegion &aRegion) { - mInvalidRegion.Or(mInvalidRegion, aRegion); - mInvalidRegion.SimplifyOutward(10); - mValidRegion.Sub(mValidRegion, mInvalidRegion); + mValidRegion.Sub(mValidRegion, aRegion); } void diff --git a/gfx/layers/opengl/ThebesLayerOGL.cpp b/gfx/layers/opengl/ThebesLayerOGL.cpp index 99ea98f5036d0..9fd4393342b1e 100644 --- a/gfx/layers/opengl/ThebesLayerOGL.cpp +++ b/gfx/layers/opengl/ThebesLayerOGL.cpp @@ -789,9 +789,7 @@ ThebesLayerOGL::SetVisibleRegion(const nsIntRegion &aRegion) void ThebesLayerOGL::InvalidateRegion(const nsIntRegion &aRegion) { - mInvalidRegion.Or(mInvalidRegion, aRegion); - mInvalidRegion.SimplifyOutward(10); - mValidRegion.Sub(mValidRegion, mInvalidRegion); + mValidRegion.Sub(mValidRegion, aRegion); } void diff --git a/gfx/thebes/gfx3DMatrix.cpp b/gfx/thebes/gfx3DMatrix.cpp index 68605fc6f79b4..cc720674df500 100644 --- a/gfx/thebes/gfx3DMatrix.cpp +++ b/gfx/thebes/gfx3DMatrix.cpp @@ -115,13 +115,6 @@ gfx3DMatrix::operator==(const gfx3DMatrix& o) const _41 == o._41 && _42 == o._42 && _43 == o._43 && _44 == o._44; } -bool -gfx3DMatrix::operator!=(const gfx3DMatrix& o) const -{ - return !((*this) == o); -} - - gfx3DMatrix& gfx3DMatrix::operator/=(const gfxFloat scalar) { diff --git a/gfx/thebes/gfx3DMatrix.h b/gfx/thebes/gfx3DMatrix.h index 02ba92fef5e93..62c4e30f67f7f 100644 --- a/gfx/thebes/gfx3DMatrix.h +++ b/gfx/thebes/gfx3DMatrix.h @@ -56,7 +56,6 @@ class THEBES_API gfx3DMatrix * Return true if this matrix and |aMatrix| are the same matrix. */ bool operator==(const gfx3DMatrix& aMatrix) const; - bool operator!=(const gfx3DMatrix& aMatrix) const; /** * Divide all values in the matrix by a scalar value diff --git a/image/src/RasterImage.cpp b/image/src/RasterImage.cpp index 1a050aeeff5d7..a23ee56dca172 100644 --- a/image/src/RasterImage.cpp +++ b/image/src/RasterImage.cpp @@ -171,8 +171,7 @@ RasterImage::RasterImage(imgStatusTracker* aStatusTracker) : mHasBeenDecoded(false), mInDecoder(false), mAnimationFinished(false), - mFinishing(false), - mInUpdateImageContainer(false) + mFinishing(false) { // Set up the discard tracker node. mDiscardTrackerNode.img = this; @@ -293,6 +292,7 @@ RasterImage::AdvanceFrame(TimeStamp aTime, nsIntRect* aDirtyRect) uint32_t currentFrameIndex = mAnim->currentAnimationFrameIndex; uint32_t nextFrameIndex = mAnim->currentAnimationFrameIndex + 1; uint32_t timeout = 0; + mImageContainer = nullptr; // Figure out if we have the next full frame. This is more complicated than // just checking for mFrames.Length() because decoders append their frames @@ -439,7 +439,6 @@ RasterImage::RequestRefresh(const mozilla::TimeStamp& aTime) mFramesNotified++; #endif - UpdateImageContainer(); observer->FrameChanged(nullptr, this, &dirtyRect); } } @@ -863,44 +862,34 @@ RasterImage::GetFrame(uint32_t aWhichFrame, return rv; } -already_AddRefed -RasterImage::GetCurrentImage() + +NS_IMETHODIMP +RasterImage::GetImageContainer(ImageContainer **_retval) { + if (mImageContainer) { + *_retval = mImageContainer; + NS_ADDREF(*_retval); + return NS_OK; + } + + CairoImage::Data cairoData; nsRefPtr imageSurface; nsresult rv = GetFrame(FRAME_CURRENT, FLAG_SYNC_DECODE, getter_AddRefs(imageSurface)); - NS_ENSURE_SUCCESS(rv, nullptr); + NS_ENSURE_SUCCESS(rv, rv); - CairoImage::Data cairoData; cairoData.mSurface = imageSurface; GetWidth(&cairoData.mSize.width); GetHeight(&cairoData.mSize.height); + mImageContainer = LayerManager::CreateImageContainer(); + + // Now create a CairoImage to display the surface. ImageFormat cairoFormat = CAIRO_SURFACE; nsRefPtr image = mImageContainer->CreateImage(&cairoFormat, 1); NS_ASSERTION(image, "Failed to create Image"); - + NS_ASSERTION(image->GetFormat() == cairoFormat, "Wrong format"); static_cast(image.get())->SetData(cairoData); - - return image.forget(); -} - - -NS_IMETHODIMP -RasterImage::GetImageContainer(ImageContainer **_retval) -{ - if (mImageContainer) { - *_retval = mImageContainer; - NS_ADDREF(*_retval); - return NS_OK; - } - - mImageContainer = LayerManager::CreateImageContainer(); - - nsRefPtr image = GetCurrentImage(); - if (!image) { - return NS_ERROR_FAILURE; - } mImageContainer->SetCurrentImageInTransaction(image); *_retval = mImageContainer; @@ -908,23 +897,6 @@ RasterImage::GetImageContainer(ImageContainer **_retval) return NS_OK; } -void -RasterImage::UpdateImageContainer() -{ - if (!mImageContainer || IsInUpdateImageContainer()) { - return; - } - - SetInUpdateImageContainer(true); - - nsRefPtr image = GetCurrentImage(); - if (!image) { - return; - } - mImageContainer->SetCurrentImage(image); - SetInUpdateImageContainer(false); -} - size_t RasterImage::HeapSizeOfSourceWithComputedFallback(nsMallocSizeOfFun aMallocSizeOf) const { @@ -1213,11 +1185,8 @@ RasterImage::FrameUpdated(uint32_t aFrameNum, nsIntRect &aUpdatedRect) NS_ABORT_IF_FALSE(frame, "Calling FrameUpdated on frame that doesn't exist!"); frame->ImageUpdated(aUpdatedRect); - - if (aFrameNum == GetCurrentImgFrameIndex()) { - // The image has changed, so we need to invalidate our cached ImageContainer. - UpdateImageContainer(); - } + // The image has changed, so we need to invalidate our cached ImageContainer. + mImageContainer = NULL; } nsresult @@ -1411,7 +1380,7 @@ RasterImage::ResetAnimation() mAnim->lastCompositedFrameIndex = -1; mAnim->currentAnimationFrameIndex = 0; - UpdateImageContainer(); + mImageContainer = nullptr; // Note - We probably want to kick off a redecode somewhere around here when // we fix bug 500402. diff --git a/image/src/RasterImage.h b/image/src/RasterImage.h index cb17e081d17f9..9218a6c6b476e 100644 --- a/image/src/RasterImage.h +++ b/image/src/RasterImage.h @@ -127,7 +127,6 @@ namespace mozilla { namespace layers { class LayerManager; class ImageContainer; -class Image; } namespace image { @@ -575,12 +574,6 @@ class RasterImage : public Image bool ApplyDecodeFlags(uint32_t aNewFlags); - already_AddRefed GetCurrentImage(); - void UpdateImageContainer(); - - void SetInUpdateImageContainer(bool aInUpdate) { mInUpdateImageContainer = aInUpdate; } - bool IsInUpdateImageContainer() { return mInUpdateImageContainer; } - private: // data nsIntSize mSize; @@ -661,8 +654,6 @@ class RasterImage : public Image // Whether we're calling Decoder::Finish() from ShutdownDecoder. bool mFinishing:1; - bool mInUpdateImageContainer:1; - // Decoding nsresult WantDecodedFrames(); nsresult SyncDecode(); diff --git a/image/test/mochitest/test_animSVGImage.html b/image/test/mochitest/test_animSVGImage.html index e19416891743f..a59867f9dd2bf 100644 --- a/image/test/mochitest/test_animSVGImage.html +++ b/image/test/mochitest/test_animSVGImage.html @@ -55,7 +55,6 @@ function myOnStopFrame(aRequest, aFrame) { gOnStopFrameCounter++; - ok(true, "myOnStopFrame called"); let currentSnapshot = snapshotWindow(window, false); if (compareSnapshots(currentSnapshot, gReferenceSnapshot, true)[0]) { // SUCCESS! @@ -63,7 +62,6 @@ "at call #" + gOnStopFrameCounter + " to onStopFrame"); cleanUpAndFinish(); } - setTimeout(function() { myOnStopFrame(0, 0); }, 1000); } function failTest() { diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 0c5acd8c9cfef..0127964c85c27 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -14,12 +14,10 @@ #include "nsCSSRendering.h" #include "nsCSSFrameConstructor.h" #include "gfxUtils.h" +#include "nsImageFrame.h" #include "nsRenderingContext.h" #include "MaskLayerImageCache.h" #include "nsIScrollableFrame.h" -#include "nsPrintfCString.h" -#include "LayerTreeInvalidation.h" -#include "nsSVGIntegrationUtils.h" #include "mozilla/Preferences.h" #include "sampler.h" @@ -29,7 +27,6 @@ #ifdef DEBUG #include -//#define DEBUG_INVALIDATIONS #endif using namespace mozilla::layers; @@ -41,62 +38,29 @@ FrameLayerBuilder::DisplayItemData::DisplayItemData(Layer* aLayer, uint32_t aKey , mDisplayItemKey(aKey) , mContainerLayerGeneration(aGeneration) , mLayerState(aLayerState) - , mUsed(false) {} -FrameLayerBuilder::DisplayItemData::DisplayItemData(DisplayItemData &toCopy) -{ - // This isn't actually a copy-constructor; notice that it steals toCopy's - // mGeometry pointer. Be careful. - mLayer = toCopy.mLayer; - mInactiveManager = toCopy.mInactiveManager; - mFrameList = toCopy.mFrameList; - mGeometry = toCopy.mGeometry; - mDisplayItemKey = toCopy.mDisplayItemKey; - mContainerLayerGeneration = toCopy.mContainerLayerGeneration; - mLayerState = toCopy.mLayerState; - mUsed = toCopy.mUsed; -} - FrameLayerBuilder::DisplayItemData::~DisplayItemData() {} -bool -FrameLayerBuilder::DisplayItemData::FrameListMatches(nsDisplayItem* aOther) -{ - nsAutoTArray copy = mFrameList; - if (!copy.RemoveElement(aOther->GetUnderlyingFrame())) { - return false; - } - - nsAutoTArray mergedFrames; - aOther->GetMergedFrames(&mergedFrames); - for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { - if (!copy.RemoveElement(mergedFrames[i])) { - return false; - } - } - - return copy.IsEmpty(); -} - /** * This is the userdata we associate with a layer manager. */ class LayerManagerData : public LayerUserData { public: - LayerManagerData() : - mInvalidateAllLayers(false) + LayerManagerData(LayerManager *aManager) : + mInvalidateAllLayers(false), + mLayerManager(aManager) { MOZ_COUNT_CTOR(LayerManagerData); mFramesWithLayers.Init(); } ~LayerManagerData() { - MOZ_COUNT_DTOR(LayerManagerData); // Remove display item data properties now, since we won't be able // to find these frames again without mFramesWithLayers. mFramesWithLayers.EnumerateEntries( - FrameLayerBuilder::RemoveDisplayItemDataForFrame, this); + FrameLayerBuilder::RemoveDisplayItemDataForFrame, nullptr); + MOZ_COUNT_DTOR(LayerManagerData); } /** @@ -104,14 +68,16 @@ class LayerManagerData : public LayerUserData { */ nsTHashtable mFramesWithLayers; bool mInvalidateAllLayers; + /** Layer manager we belong to, we hold a reference to this object. */ + nsRefPtr mLayerManager; }; -/* static */ void -FrameLayerBuilder::DestroyDisplayItemDataFor(nsIFrame* aFrame) +LayerManagerLayerBuilder::~LayerManagerLayerBuilder() { - FrameProperties props = aFrame->Properties(); - props.Delete(LayerManagerDataProperty()); - props.Delete(LayerManagerSecondaryDataProperty()); + MOZ_COUNT_DTOR(LayerManagerLayerBuilder); + if (mDelete) { + delete mLayerBuilder; + } } namespace { @@ -128,6 +94,43 @@ static inline MaskLayerImageCache* GetMaskLayerImageCache() return gMaskLayerImageCache; } +static void DestroyRefCountedRegion(void* aPropertyValue) +{ + static_cast(aPropertyValue)->Release(); +} + +/** + * This property represents a region that should be invalidated in every + * ThebesLayer child whose parent ContainerLayer is associated with the + * frame. This is an nsRegion*; the coordinates of the region are + * relative to the top-left of the border-box of the frame the property + * is attached to (which is the frame for the ContainerLayer). + * + * We add to this region in InvalidateThebesLayerContents. The region + * is propagated to ContainerState in BuildContainerLayerFor, and then + * the region(s) are actually invalidated in CreateOrRecycleThebesLayer. + * + * When the property value is null, the region is infinite --- i.e. all + * areas of the ThebesLayers should be invalidated. + */ +NS_DECLARE_FRAME_PROPERTY(ThebesLayerInvalidRegionProperty, DestroyRefCountedRegion) + +static void DestroyPoint(void* aPropertyValue) +{ + delete static_cast(aPropertyValue); +} + +/** + * The valid content in our child ThebesLayers is defined relative to + * the offset from this frame to its active scroll root, mapped back + * by the ThebesLayer's inverse transform. Since we accumulate the + * region invalidated between last-paint and next-paint, and because + * the offset of this frame to its active root may change during that + * period, we save the offset at last-paint in this property and use + * it to invalidate at next-paint. + */ +NS_DECLARE_FRAME_PROPERTY(ThebesLayerLastPaintOffsetProperty, DestroyPoint) + /** * This is a helper object used to build up the layer children for * a ContainerLayer. @@ -138,20 +141,16 @@ class ContainerState { LayerManager* aManager, FrameLayerBuilder* aLayerBuilder, nsIFrame* aContainerFrame, - nsDisplayItem* aContainerItem, ContainerLayer* aContainerLayer, const FrameLayerBuilder::ContainerParameters& aParameters) : mBuilder(aBuilder), mManager(aManager), mLayerBuilder(aLayerBuilder), - mContainerFrame(aContainerFrame), - mContainerLayer(aContainerLayer), + mContainerFrame(aContainerFrame), mContainerLayer(aContainerLayer), mParameters(aParameters), - mNextFreeRecycledThebesLayer(0) + mNextFreeRecycledThebesLayer(0), mInvalidateAllThebesContent(false) { nsPresContext* presContext = aContainerFrame->PresContext(); mAppUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); - mContainerReferenceFrame = aContainerItem ? aContainerItem->ReferenceFrame() : - mBuilder->FindReferenceFrameFor(mContainerFrame); // When AllowResidualTranslation is false, display items will be drawn // scaled with a translation by integer pixels, so we know how the snapping // will work. @@ -165,6 +164,14 @@ class ContainerState { NO_COMPONENT_ALPHA = 0x01, }; + void AddInvalidThebesContent(const nsIntRegion& aRegion) + { + mInvalidThebesContent.Or(mInvalidThebesContent, aRegion); + } + void SetInvalidateAllThebesContent() + { + mInvalidateAllThebesContent = true; + } /** * This is the method that actually walks a display list and builds * the child layers. We invoke it recursively to process clipped sublists. @@ -182,7 +189,7 @@ class ContainerState { * @param aTextContentFlags if any child layer has CONTENT_COMPONENT_ALPHA, * set *aTextContentFlags to CONTENT_COMPONENT_ALPHA */ - void Finish(uint32_t *aTextContentFlags, LayerManagerData* aData); + void Finish(uint32_t *aTextContentFlags); nsRect GetChildrenBounds() { return mBounds; } @@ -224,6 +231,8 @@ class ContainerState { mAppUnitsPerDevPixel); } + const FrameLayerBuilder::ContainerParameters& ScaleParameters() { return mParameters; }; + protected: /** * We keep a stack of these to represent the ThebesLayers that are @@ -310,7 +319,7 @@ class ContainerState { * be non-null; all content in a ThebesLayer must have the same * active scrolled root. */ - const nsIFrame* mActiveScrolledRoot; + const nsIFrame* mActiveScrolledRoot; ThebesLayer* mLayer; /** * If mIsSolidColorInVisibleRegion is true, this is the color of the visible @@ -338,7 +347,7 @@ class ContainerState { * Stores the pointer to the nsDisplayImage if we want to * convert this to an ImageLayer. */ - nsDisplayImageContainer* mImage; + nsDisplayImage* mImage; /** * Stores the clip that we need to apply to the image or, if there is no * image, a clip for SOME item in the layer. There is no guarantee which @@ -371,9 +380,7 @@ class ContainerState { * a recycled ThebesLayer, and sets up the transform on the ThebesLayer * to account for scrolling. */ - already_AddRefed CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, - const nsIFrame *aReferenceFrame, - const nsPoint& aTopLeft); + already_AddRefed CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, const nsIFrame *aReferenceFrame); /** * Grab the next recyclable ColorLayer, or create one if there are no * more recyclable ColorLayers. @@ -400,10 +407,7 @@ class ContainerState { * aItem in that layer. If aNewLayer is a ThebesLayer, invalidates the area of * aItem in that layer. */ - void InvalidateForLayerChange(nsDisplayItem* aItem, - Layer* aNewLayer, - const FrameLayerBuilder::Clip& aClip, - const nsPoint& aTopLeft); + void InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer); /** * Try to determine whether the ThebesLayer at aThebesLayerIndex * has a single opaque color behind it, over the entire bounds of its visible @@ -438,8 +442,7 @@ class ContainerState { const nsIntRect& aVisibleRect, const nsIntRect& aDrawRect, const FrameLayerBuilder::Clip& aClip, - const nsIFrame* aActiveScrolledRoot, - const nsPoint& aTopLeft); + const nsIFrame* aActiveScrolledRoot); ThebesLayerData* GetTopThebesLayerData() { return mThebesLayerDataStack.IsEmpty() ? nullptr @@ -462,7 +465,6 @@ class ContainerState { LayerManager* mManager; FrameLayerBuilder* mLayerBuilder; nsIFrame* mContainerFrame; - const nsIFrame* mContainerReferenceFrame; ContainerLayer* mContainerLayer; FrameLayerBuilder::ContainerParameters mParameters; /** @@ -484,6 +486,7 @@ class ContainerState { mRecycledMaskImageLayers; uint32_t mNextFreeRecycledThebesLayer; nscoord mAppUnitsPerDevPixel; + bool mInvalidateAllThebesContent; bool mSnappingEnabled; }; @@ -494,7 +497,6 @@ class ThebesDisplayItemLayerUserData : public LayerUserData mMaskClipCount(0), mForcedBackgroundColor(NS_RGBA(0,0,0,0)), mXScale(1.f), mYScale(1.f), - mAppUnitsPerDevPixel(0), mTranslation(0, 0), mActiveScrolledRootPosition(0, 0) {} @@ -516,11 +518,6 @@ class ThebesDisplayItemLayerUserData : public LayerUserData */ float mXScale, mYScale; - /** - * The appunits per dev pixel for the items in this layer. - */ - nscoord mAppUnitsPerDevPixel; - /** * The offset from the ThebesLayer's 0,0 to the * reference frame. This isn't necessarily the same as the transform @@ -541,14 +538,6 @@ class ThebesDisplayItemLayerUserData : public LayerUserData */ gfxPoint mActiveScrolledRootPosition; - nsIntRegion mRegionToInvalidate; - - // The offset between the active scrolled root of this layer - // and the root of the container for the previous and current - // paints respectively. - nsPoint mLastActiveScrolledRootOrigin; - nsPoint mActiveScrolledRootOrigin; - nsRefPtr mColorLayer; nsRefPtr mImageLayer; }; @@ -644,61 +633,6 @@ ThebesDisplayItemLayerUserData* GetThebesDisplayItemLayerUserData(Layer* aLayer) } // anonymous namespace -uint8_t gLayerManagerSecondary; - -bool FrameLayerBuilder::sWidgetManagerSecondary = nullptr; - -/* static */ const FramePropertyDescriptor* -FrameLayerBuilder::GetDescriptorForManager(LayerManager* aManager) -{ - bool secondary = sWidgetManagerSecondary; - if (aManager) { - secondary = !!static_cast(aManager->GetUserData(&gLayerManagerSecondary)); - } - - return secondary ? LayerManagerSecondaryDataProperty() : LayerManagerDataProperty(); -} - -LayerManagerData* -FrameLayerBuilder::GetManagerData(nsIFrame* aFrame, LayerManager* aManager) -{ - FrameProperties props = aFrame->Properties(); - return static_cast(props.Get(GetDescriptorForManager(aManager))); -} - -void -FrameLayerBuilder::SetManagerData(nsIFrame* aFrame, LayerManagerData* aData) -{ - FrameProperties props = aFrame->Properties(); - const FramePropertyDescriptor* desc = GetDescriptorForManager(nullptr); - - props.Remove(desc); - if (aData) { - props.Set(desc, aData); - } -} - -void -FrameLayerBuilder::ClearManagerData(nsIFrame* aFrame) -{ - SetManagerData(aFrame, nullptr); -} - -void -FrameLayerBuilder::ClearManagerData(nsIFrame* aFrame, LayerManagerData* aData) -{ - NS_ABORT_IF_FALSE(aData, "Must have a widget manager to check for manager data!"); - - FrameProperties props = aFrame->Properties(); - if (aData == static_cast(props.Get(LayerManagerDataProperty()))) { - props.Remove(LayerManagerDataProperty()); - return; - } - if (aData == static_cast(props.Get(LayerManagerSecondaryDataProperty()))) { - props.Remove(LayerManagerSecondaryDataProperty()); - return; - } -} /* static */ void FrameLayerBuilder::Shutdown() { @@ -711,20 +645,21 @@ FrameLayerBuilder::Shutdown() void FrameLayerBuilder::Init(nsDisplayListBuilder* aBuilder, LayerManager* aManager) { - mDisplayListBuilder = aBuilder; mRootPresContext = aBuilder->RootReferenceFrame()->PresContext()->GetRootPresContext(); if (mRootPresContext) { mInitialDOMGeneration = mRootPresContext->GetDOMGeneration(); } - aManager->SetUserData(&gLayerManagerLayerBuilder, this); + aManager->SetUserData(&gLayerManagerLayerBuilder, new LayerManagerLayerBuilder(this)); } bool FrameLayerBuilder::DisplayItemDataEntry::HasNonEmptyContainerLayer() { + if (mIsSharingContainerLayer) + return true; for (uint32_t i = 0; i < mData.Length(); ++i) { - if (mData[i]->mLayer->GetType() == Layer::TYPE_CONTAINER && - mData[i]->mLayerState != LAYER_ACTIVE_EMPTY) + if (mData[i].mLayer->GetType() == Layer::TYPE_CONTAINER && + mData[i].mLayerState != LAYER_ACTIVE_EMPTY) return true; } return false; @@ -751,123 +686,32 @@ FrameLayerBuilder::FlashPaint(gfxContext *aContext) } } -nsTArray >* +/* static */ nsTArray* FrameLayerBuilder::GetDisplayItemDataArrayForFrame(nsIFrame* aFrame) { - LayerManagerData* data = static_cast - (mRetainingManager->GetUserData(&gLayerManagerUserData)); - if (!data) { + FrameProperties props = aFrame->Properties(); + LayerManagerData *data = + reinterpret_cast(props.Get(LayerManagerDataProperty())); + if (!data) return nullptr; - } DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame); + NS_ASSERTION(entry, "out of sync?"); if (!entry) return nullptr; return &entry->mData; } -nsACString& -AppendToString(nsACString& s, const nsIntRect& r, - const char* pfx="", const char* sfx="") -{ - s += pfx; - s += nsPrintfCString( - "(x=%d, y=%d, w=%d, h=%d)", - r.x, r.y, r.width, r.height); - return s += sfx; -} - -nsACString& -AppendToString(nsACString& s, const nsIntRegion& r, - const char* pfx="", const char* sfx="") -{ - s += pfx; - - nsIntRegionRectIterator it(r); - s += "< "; - while (const nsIntRect* sr = it.Next()) { - AppendToString(s, *sr) += "; "; - } - s += ">"; - - return s += sfx; -} - -/** - * Invalidate aRegion in aLayer. aLayer is in the coordinate system - * *after* aTranslation has been applied, so we need to - * apply the inverse of that transform before calling InvalidateRegion. - */ -static void -InvalidatePostTransformRegion(ThebesLayer* aLayer, const nsIntRegion& aRegion, - const nsIntPoint& aTranslation) -{ - // Convert the region from the coordinates of the container layer - // (relative to the snapped top-left of the display list reference frame) - // to the ThebesLayer's own coordinates - nsIntRegion rgn = aRegion; - rgn.MoveBy(-aTranslation); - aLayer->InvalidateRegion(rgn); -#ifdef DEBUG_INVALIDATIONS - nsAutoCString str; - AppendToString(str, rgn); - printf("Invalidating layer %p: %s\n", aLayer, str.get()); -#endif -} - -static nsIntPoint -GetTranslationForThebesLayer(ThebesLayer* aLayer) -{ - ThebesDisplayItemLayerUserData* data = - static_cast - (aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); - NS_ASSERTION(data, "Must be a tracked thebes layer!"); - - return data->mTranslation; -} - -/** - * Some frames can have multiple, nested, retaining layer managers - * associated with them (normal manager, inactive managers, SVG effects). - * In these cases we store the 'outermost' LayerManager data property - * on the frame since we can walk down the chain from there. - * - * If one of these frames has just been destroyed, we will free the inner - * layer manager when removing the entry from mFramesWithLayers. Destroying - * the layer manager destroys the LayerManagerData and calls into - * RemoveDisplayItemDataForFrame. If the inner layer manager had any - * items with the same frame, then we attempt to retrieve properties - * from the deleted frame. - * - * Cache the destroyed frame pointer here so we can avoid crashing in this case. - */ -static nsIFrame* sDestroyedFrame = NULL; - /* static */ void FrameLayerBuilder::RemoveFrameFromLayerManager(nsIFrame* aFrame, void* aPropertyValue) { LayerManagerData *data = reinterpret_cast(aPropertyValue); - - DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(aFrame); - for (uint32_t i = 0; i < entry->mData.Length(); ++i) { - ThebesLayer* t = entry->mData[i]->mLayer->AsThebesLayer(); - if (t) { - ThebesDisplayItemLayerUserData* data = - static_cast(t->GetUserData(&gThebesDisplayItemLayerUserData)); - if (data) { - nsRegion old = entry->mData[i]->mGeometry->ComputeInvalidationRegion(); - nsIntRegion rgn = old.ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel); - rgn.MoveBy(-GetTranslationForThebesLayer(t)); - data->mRegionToInvalidate.Or(data->mRegionToInvalidate, rgn); - } - } - } - - sDestroyedFrame = aFrame; data->mFramesWithLayers.RemoveEntry(aFrame); - sDestroyedFrame = NULL; + if (data->mFramesWithLayers.Count() == 0) { + data->mLayerManager->RemoveUserData(&gLayerManagerUserData); + } } void @@ -878,93 +722,127 @@ FrameLayerBuilder::DidBeginRetainedLayerTransaction(LayerManager* aManager) (aManager->GetUserData(&gLayerManagerUserData)); if (data) { mInvalidateAllLayers = data->mInvalidateAllLayers; - } else { - data = new LayerManagerData(); - aManager->SetUserData(&gLayerManagerUserData, data); } } +/** + * A helper function to remove the mThebesLayerItems entries and + * layer ownership user-data for every layer in aLayer's subtree. + */ void -FrameLayerBuilder::StoreOptimizedLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, Layer* aImage) +FrameLayerBuilder::RemoveThebesItemsAndOwnerDataForLayerSubtree(Layer* aLayer, + bool aRemoveThebesItems, + bool aRemoveOwnerData) { - DisplayItemDataEntry *entry = mNewDisplayItemData.GetEntry(aFrame); - if (!entry) - return; + if (aRemoveOwnerData) { + // Remove the layer owner flag so that this layer can be recovered by other + // frames in future layer tree constructions. + aLayer->RemoveUserData(&gLayerOwnerUserData); + } - nsTArray > *array = &entry->mData; - if (!array) + ThebesLayer* thebes = aLayer->AsThebesLayer(); + if (thebes) { + if (aRemoveThebesItems) { + mThebesLayerItems.RemoveEntry(thebes); + } return; + } - for (uint32_t i = 0; i < array->Length(); ++i) { - if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) { - array->ElementAt(i)->mOptLayer = aImage; - return; - } + for (Layer* child = aLayer->GetFirstChild(); child; + child = child->GetNextSibling()) { + RemoveThebesItemsAndOwnerDataForLayerSubtree(child, aRemoveThebesItems, + aRemoveOwnerData); } } void -FrameLayerBuilder::DidEndTransaction() +FrameLayerBuilder::DidEndTransaction(LayerManager* aManager) { + Layer* root = aManager->GetRoot(); + if (root) { + RemoveThebesItemsAndOwnerDataForLayerSubtree(root, aManager != mRetainingManager, true); + } + GetMaskLayerImageCache()->Sweep(); } void -FrameLayerBuilder::WillEndTransaction() +FrameLayerBuilder::WillEndTransaction(LayerManager* aManager) { - if (!mRetainingManager) { + if (aManager != mRetainingManager) return; - } - // We need to save the data we'll need to support retaining. + // We need to save the data we'll need to support retaining. We do this + // before we paint so that invalidation triggered by painting will + // be able to update the ThebesLayerInvalidRegionProperty values + // correctly and the NS_FRAME_HAS_CONTAINER_LAYER bits will be set + // correctly. LayerManagerData* data = static_cast (mRetainingManager->GetUserData(&gLayerManagerUserData)); - NS_ASSERTION(data, "Must have data!"); - // Update all the frames that used to have layers. - data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this); - + if (data) { + // Update all the frames that used to have layers. + data->mFramesWithLayers.EnumerateEntries(UpdateDisplayItemDataForFrame, this); + } else { + data = new LayerManagerData(mRetainingManager); + mRetainingManager->SetUserData(&gLayerManagerUserData, data); + } // Now go through all the frames that didn't have any retained // display items before, and record those retained display items. // This also empties mNewDisplayItemData. mNewDisplayItemData.EnumerateEntries(StoreNewDisplayItemData, data); data->mInvalidateAllLayers = false; + + NS_ASSERTION(data->mFramesWithLayers.Count() > 0, + "Some frame must have a layer!"); +} + +/** + * If *aThebesLayerInvalidRegion is non-null, use it as this frame's + * region property. Otherwise set it to the frame's region property. + */ +static void +SetHasContainerLayer(nsIFrame* aFrame, nsPoint aOffsetToRoot) +{ + aFrame->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER); + for (nsIFrame* f = aFrame; + f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT); + f = nsLayoutUtils::GetCrossDocParentFrame(f)) { + f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT); + } + + FrameProperties props = aFrame->Properties(); + nsPoint* lastPaintOffset = static_cast + (props.Get(ThebesLayerLastPaintOffsetProperty())); + if (lastPaintOffset) { + *lastPaintOffset = aOffsetToRoot; + } else { + props.Set(ThebesLayerLastPaintOffsetProperty(), new nsPoint(aOffsetToRoot)); + } } -struct ProcessRemovedDisplayItemsData +static void +SetNoContainerLayer(nsIFrame* aFrame) { - ProcessRemovedDisplayItemsData(Layer* aLayer, FrameLayerBuilder* aLayerBuilder) - : mLayer(aLayer) - , mLayerBuilder(aLayerBuilder) - {} + FrameProperties props = aFrame->Properties(); + props.Delete(ThebesLayerInvalidRegionProperty()); + props.Delete(ThebesLayerLastPaintOffsetProperty()); + aFrame->RemoveStateBits(NS_FRAME_HAS_CONTAINER_LAYER); +} - Layer *mLayer; - FrameLayerBuilder *mLayerBuilder; -}; +/* static */ void +FrameLayerBuilder::SetAndClearInvalidRegion(DisplayItemDataEntry* aEntry) +{ + if (aEntry->mInvalidRegion) { + nsIFrame* f = aEntry->GetKey(); + FrameProperties props = f->Properties(); -/* static */ PLDHashOperator -FrameLayerBuilder::ProcessRemovedDisplayItems(DisplayItemDataEntry* aEntry, - void* aUserArg) -{ - ProcessRemovedDisplayItemsData *userData = - static_cast(aUserArg); - Layer* layer = userData->mLayer; - FrameLayerBuilder* layerBuilder = userData->mLayerBuilder; - for (uint32_t i = 0; i < aEntry->mData.Length(); ++i) { - DisplayItemData* item = aEntry->mData[i]; - ThebesLayer* t = item->mLayer->AsThebesLayer(); - if (!item->mUsed && t && item->mLayer == layer) { -#ifdef DEBUG_INVALIDATIONS - printf("Invalidating unused display item (%i) belonging to frame %p from layer %p\n", item->mDisplayItemKey, aEntry->GetKey(), t); -#endif - ThebesDisplayItemLayerUserData* data = - static_cast(t->GetUserData(&gThebesDisplayItemLayerUserData)); - InvalidatePostTransformRegion(t, - item->mGeometry->ComputeInvalidationRegion(). - ScaleToOutsidePixels(data->mXScale, data->mYScale, data->mAppUnitsPerDevPixel), - layerBuilder->GetLastPaintOffset(t)); - } + RefCountedRegion* invalidRegion; + aEntry->mInvalidRegion.forget(&invalidRegion); + + invalidRegion->mRegion.SetEmpty(); + invalidRegion->mIsInfinite = false; + props.Set(ThebesLayerInvalidRegionProperty(), invalidRegion); } - return PL_DHASH_NEXT; } /* static */ PLDHashOperator @@ -973,45 +851,36 @@ FrameLayerBuilder::UpdateDisplayItemDataForFrame(DisplayItemDataEntry* aEntry, { FrameLayerBuilder* builder = static_cast(aUserArg); nsIFrame* f = aEntry->GetKey(); + FrameProperties props = f->Properties(); DisplayItemDataEntry* newDisplayItems = builder ? builder->mNewDisplayItemData.GetEntry(f) : nullptr; - - LayerManagerData* managerData = static_cast - (builder->GetRetainingLayerManager()->GetUserData(&gLayerManagerUserData)); - LayerManagerData* data = GetManagerData(f); - if (!newDisplayItems || newDisplayItems->mData.IsEmpty()) { + if (!newDisplayItems || (newDisplayItems->mData.IsEmpty() && + !newDisplayItems->mIsSharingContainerLayer)) { // This frame was visible, but isn't anymore. if (newDisplayItems) { builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems); } - if (data == managerData) { - ClearManagerData(f); - } + bool found; + props.Remove(LayerManagerDataProperty(), &found); + NS_ASSERTION(found, "How can the frame property be missing?"); + SetNoContainerLayer(f); return PL_DHASH_REMOVE; } - SetManagerData(f, managerData); + if (!newDisplayItems->HasNonEmptyContainerLayer()) { + SetNoContainerLayer(f); + } // Steal the list of display item layers and invalid region aEntry->mData.SwapElements(newDisplayItems->mData); + aEntry->mInvalidRegion.swap(newDisplayItems->mInvalidRegion); + // Clear and reset the invalid region now so we can start collecting new + // dirty areas. + SetAndClearInvalidRegion(aEntry); // Don't need to process this frame again builder->mNewDisplayItemData.RawRemoveEntry(newDisplayItems); return PL_DHASH_NEXT; } - -/* static */ PLDHashOperator -FrameLayerBuilder::RemoveDisplayItemDataForFrame(DisplayItemDataEntry* aEntry, - void* aClosure) -{ - LayerManagerData* managerData = static_cast(aClosure); - nsIFrame* f = aEntry->GetKey(); - // If this was called from a frame destructor then the prop is definitely already gone, - // and we could crash trying to check. See the definition of sDestroyedFrame. - if (f != sDestroyedFrame) { - ClearManagerData(f, managerData); - } - return PL_DHASH_REMOVE; -} /* static */ PLDHashOperator FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry, @@ -1019,142 +888,44 @@ FrameLayerBuilder::StoreNewDisplayItemData(DisplayItemDataEntry* aEntry, { LayerManagerData* data = static_cast(aUserArg); nsIFrame* f = aEntry->GetKey(); + FrameProperties props = f->Properties(); + + // Clear and reset the invalid region now so we can start collecting new + // dirty areas. + SetAndClearInvalidRegion(aEntry); // Remember that this frame has display items in retained layers NS_ASSERTION(!data->mFramesWithLayers.GetEntry(f), "We shouldn't get here if we're already in mFramesWithLayers"); DisplayItemDataEntry *newEntry = data->mFramesWithLayers.PutEntry(f); + NS_ASSERTION(!props.Get(LayerManagerDataProperty()), + "mFramesWithLayers out of sync"); newEntry->mData.SwapElements(aEntry->mData); - // Remove any old layer manager data for this frame. We don't destroy it - // because we don't want it to call the frame destroyed function. - // When a frame has multiple layer managers (main, inactive, svg), we - // only need to store the outermost one since that will be enough to - // invalidate the entire region covered by all the children. - SetManagerData(f, data); + props.Set(LayerManagerDataProperty(), data); return PL_DHASH_REMOVE; } -/** - * Attempts to find the LayerManagerData for the widget manager - * for the given frame, nullptr otherwise. - */ -static LayerManagerData* -GetDefaultLayerManagerDataForFrame(nsIFrame* aFrame) -{ - FrameProperties props = aFrame->Properties(); - return static_cast(props.Get(FrameLayerBuilder::LayerManagerDataProperty())); -} - -static LayerManagerData* -GetSecondaryLayerManagerDataForFrame(nsIFrame* aFrame) -{ - FrameProperties props = aFrame->Properties(); - return static_cast(props.Get(FrameLayerBuilder::LayerManagerSecondaryDataProperty())); -} - -/* static */ FrameLayerBuilder::DisplayItemData* -FrameLayerBuilder::GetDisplayItemDataForManager(nsIFrame* aFrame, - uint32_t aDisplayItemKey, - LayerManagerData* aData) -{ - DisplayItemDataEntry *entry = aData->mFramesWithLayers.GetEntry(aFrame); - if (!entry) { - return nullptr; - } - - for (uint32_t i = 0; i < entry->mData.Length(); ++i) { - if (entry->mData[i]->mDisplayItemKey == aDisplayItemKey) { - return entry->mData[i]; - } - } - - return nullptr; -} - -/* static */ FrameLayerBuilder::DisplayItemData* -FrameLayerBuilder::GetDisplayItemDataForManager(nsIFrame* aFrame, - uint32_t aDisplayItemKey, - LayerManager* aManager) -{ - LayerManagerData *data = - static_cast(aManager->GetUserData(&gLayerManagerUserData)); - - if (!data) { - return nullptr; - } - - return GetDisplayItemDataForManager(aFrame, aDisplayItemKey, data); -} - -/* static */ FrameLayerBuilder::DisplayItemData* -FrameLayerBuilder::GetDisplayItemDataForManager(nsDisplayItem* aItem, - LayerManager* aManager) -{ - DisplayItemData* data = - GetDisplayItemDataForManager(aItem->GetUnderlyingFrame(), - aItem->GetPerFrameKey(), - aManager); - if (data) { - return data->FrameListMatches(aItem) ? data : nullptr; - } - - nsAutoTArray mergedFrames; - aItem->GetMergedFrames(&mergedFrames); - for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { - data = - GetDisplayItemDataForManager(mergedFrames[i], - aItem->GetPerFrameKey(), - aManager); - if (data) { - return data->FrameListMatches(aItem) ? data : nullptr; - } - } - return nullptr; -} - -/* static */ FrameLayerBuilder::DisplayItemData* -FrameLayerBuilder::GetDisplayItemDataForManager(nsIFrame* aFrame, - uint32_t aDisplayItemKey) -{ - LayerManagerData *data = GetDefaultLayerManagerDataForFrame(aFrame); - - if (!data) { - return nullptr; - } - - return GetDisplayItemDataForManager(aFrame, aDisplayItemKey, data); -} - bool -FrameLayerBuilder::HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey, LayerManager* aManager) +FrameLayerBuilder::HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { - DisplayItemData* data = GetDisplayItemDataForManager(aFrame, aDisplayItemKey, aManager); - if (data) { - Layer* layer = data->mLayer; - if (layer->Manager()->GetUserData(&gLayerManagerUserData)) { - // All layer managers with our user data are retained layer managers - return true; - } - } - return false; -} + nsTArray *array = GetDisplayItemDataArrayForFrame(aFrame); + if (!array) + return false; -bool -FrameLayerBuilder::HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) -{ - LayerManagerData* data = GetDefaultLayerManagerDataForFrame(aFrame); - if (data && GetDisplayItemDataForManager(aFrame, aDisplayItemKey, data)) { - return true; - } - data = GetSecondaryLayerManagerDataForFrame(aFrame); - if (data && GetDisplayItemDataForManager(aFrame, aDisplayItemKey, data)) { - return true; + for (uint32_t i = 0; i < array->Length(); ++i) { + if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) { + Layer* layer = array->ElementAt(i).mLayer; + if (layer->Manager()->GetUserData(&gLayerManagerUserData)) { + // All layer managers with our user data are retained layer managers + return true; + } + } } return false; } -FrameLayerBuilder::DisplayItemData* +Layer* FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey) { // If we need to build a new layer tree, then just refuse to recycle @@ -1162,15 +933,19 @@ FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKe if (!mRetainingManager || mInvalidateAllLayers) return nullptr; - nsTArray > *array = GetDisplayItemDataArrayForFrame(aFrame); + nsTArray *array = GetDisplayItemDataArrayForFrame(aFrame); if (!array) return nullptr; for (uint32_t i = 0; i < array->Length(); ++i) { - if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) { - Layer* layer = array->ElementAt(i)->mLayer; + if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) { + Layer* layer = array->ElementAt(i).mLayer; if (layer->Manager() == mRetainingManager) { - return array->ElementAt(i); + LayerOwnerUserData* layerOwner = static_cast + (layer->GetUserData(&gLayerOwnerUserData)); + if (!layerOwner || layerOwner->mOwnerFrame == aFrame) { + return layer; + } } } } @@ -1178,46 +953,35 @@ FrameLayerBuilder::GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKe } Layer* -FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem, nsDisplayItemGeometry** aOldGeometry, Clip** aOldClip) +FrameLayerBuilder::GetOldLayerFor(nsDisplayItem* aItem) { uint32_t key = aItem->GetPerFrameKey(); nsIFrame* frame = aItem->GetUnderlyingFrame(); if (frame) { - DisplayItemData* oldData = GetOldLayerForFrame(frame, key); - if (oldData) { - if (aOldGeometry) { - *aOldGeometry = oldData->mGeometry.get(); - } - if (aOldClip) { - *aOldClip = &oldData->mClip; - } - return oldData->mLayer; + Layer* oldLayer = GetOldLayerForFrame(frame, key); + if (oldLayer) { + return oldLayer; } } nsAutoTArray mergedFrames; aItem->GetMergedFrames(&mergedFrames); for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { - DisplayItemData* oldData = GetOldLayerForFrame(mergedFrames[i], key); - if (oldData) { - if (aOldGeometry) { - *aOldGeometry = oldData->mGeometry.get(); - } - if (aOldClip) { - *aOldClip = &oldData->mClip; - } - return oldData->mLayer; + Layer* oldLayer = GetOldLayerForFrame(mergedFrames[i], key); + if (oldLayer) { + return oldLayer; } } return nullptr; -} +} /* static */ Layer* FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey) { - LayerManagerData* data = GetManagerData(aFrame); + FrameProperties props = aFrame->Properties(); + LayerManagerData* data = static_cast(props.Get(LayerManagerDataProperty())); if (!data) { return nullptr; } @@ -1225,34 +989,33 @@ FrameLayerBuilder::GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKe if (!entry) return nullptr; - nsTArray > *array = &entry->mData; + nsTArray *array = &entry->mData; if (!array) return nullptr; for (uint32_t i = 0; i < array->Length(); ++i) { - if (array->ElementAt(i)->mDisplayItemKey == aDisplayItemKey) { - return array->ElementAt(i)->mLayer; + if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) { + return array->ElementAt(i).mLayer; } } return nullptr; } -LayerManager* -FrameLayerBuilder::GetInactiveLayerManagerFor(nsDisplayItem* aItem) +/** + * Invalidate aRegion in aLayer. aLayer is in the coordinate system + * *after* aTranslation has been applied, so we need to + * apply the inverse of that transform before calling InvalidateRegion. + */ +static void +InvalidatePostTransformRegion(ThebesLayer* aLayer, const nsIntRegion& aRegion, + const nsIntPoint& aTranslation) { - nsTArray > *array = GetDisplayItemDataArrayForFrame(aItem->GetUnderlyingFrame()); - NS_ASSERTION(array, "We need an array here!. Really, we do."); - - nsRefPtr tempManager; - for (uint32_t i = 0; i < array->Length(); ++i) { - if (array->ElementAt(i)->mDisplayItemKey == aItem->GetPerFrameKey()) { - NS_ASSERTION(array->ElementAt(i)->mInactiveManager, "Must already have one of these"); - return array->ElementAt(i)->mInactiveManager; - - } - } - NS_ERROR("Failed to find data for display item"); - return NULL; + // Convert the region from the coordinates of the container layer + // (relative to the snapped top-left of the display list reference frame) + // to the ThebesLayer's own coordinates + nsIntRegion rgn = aRegion; + rgn.MoveBy(-aTranslation); + aLayer->InvalidateRegion(rgn); } already_AddRefed @@ -1322,6 +1085,17 @@ ContainerState::CreateOrRecycleMaskImageLayerFor(Layer* aLayer) return result.forget(); } +static nsIntPoint +GetTranslationForThebesLayer(ThebesLayer* aLayer) +{ + ThebesDisplayItemLayerUserData* data = + static_cast + (aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); + NS_ASSERTION(data, "Must be a tracked thebes layer!"); + + return data->mTranslation; +} + static const double SUBPIXEL_OFFSET_EPSILON = 0.02; /** @@ -1362,18 +1136,13 @@ ResetScrollPositionForLayerPixelAlignment(const nsIFrame* aActiveScrolledRoot) static void InvalidateEntireThebesLayer(ThebesLayer* aLayer, const nsIFrame* aActiveScrolledRoot) { -#ifdef DEBUG_INVALIDATIONS - printf("Invalidating entire layer %p\n", aLayer); -#endif nsIntRect invalidate = aLayer->GetValidRegion().GetBounds(); aLayer->InvalidateRegion(invalidate); ResetScrollPositionForLayerPixelAlignment(aActiveScrolledRoot); } already_AddRefed -ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, - const nsIFrame* aReferenceFrame, - const nsPoint& aTopLeft) +ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, const nsIFrame* aReferenceFrame) { // We need a new thebes layer nsRefPtr layer; @@ -1400,24 +1169,18 @@ ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, // transform. See nsGfxScrollFrame::InvalidateInternal, where // we ensure that mInvalidThebesContent is updated according to the // scroll position as of the most recent paint. - if (data->mXScale != mParameters.mXScale || + if (mInvalidateAllThebesContent || + data->mXScale != mParameters.mXScale || data->mYScale != mParameters.mYScale) { InvalidateEntireThebesLayer(layer, aActiveScrolledRoot); didResetScrollPositionForLayerPixelAlignment = true; + } else { + nsIntRect bounds = mInvalidThebesContent.GetBounds(); + if (!bounds.IsEmpty()) { + InvalidatePostTransformRegion(layer, mInvalidThebesContent, + GetTranslationForThebesLayer(layer)); + } } - if (!data->mRegionToInvalidate.IsEmpty()) { -#ifdef DEBUG_INVALIDATIONS - printf("Invalidating deleted frame content from layer %p\n", layer.get()); -#endif - layer->InvalidateRegion(data->mRegionToInvalidate); -#ifdef DEBUG_INVALIDATIONS - nsAutoCString str; - AppendToString(str, data->mRegionToInvalidate); - printf("Invalidating layer %p: %s\n", layer.get(), str.get()); -#endif - data->mRegionToInvalidate.SetEmpty(); - } - // We do not need to Invalidate these areas in the widget because we // assume the caller of InvalidateThebesLayerContents has ensured // the area is invalidated in the widget. @@ -1434,9 +1197,6 @@ ContainerState::CreateOrRecycleThebesLayer(const nsIFrame* aActiveScrolledRoot, } data->mXScale = mParameters.mXScale; data->mYScale = mParameters.mYScale; - data->mLastActiveScrolledRootOrigin = data->mActiveScrolledRootOrigin; - data->mActiveScrolledRootOrigin = aTopLeft; - data->mAppUnitsPerDevPixel = mAppUnitsPerDevPixel; layer->SetAllowResidualTranslation(mParameters.AllowResidualTranslation()); mLayerBuilder->SaveLastPaintOffset(layer); @@ -1617,9 +1377,6 @@ ContainerState::PopThebesLayerData() imageLayer->IntersectClipRect(clip); } layer = imageLayer; - mLayerBuilder->StoreOptimizedLayerForFrame(data->mImage->GetUnderlyingFrame(), - data->mImage->GetPerFrameKey(), - imageLayer); } else { nsRefPtr colorLayer = CreateOrRecycleColorLayer(data->mLayer); colorLayer->SetIsFixedPosition(data->mLayer->GetIsFixedPosition()); @@ -1791,10 +1548,8 @@ ContainerState::ThebesLayerData::Accumulate(ContainerState* aState, /* 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 (mVisibleRegion.IsEmpty() && - (aItem->GetType() == nsDisplayItem::TYPE_IMAGE || - aItem->GetType() == nsDisplayItem::TYPE_XUL_IMAGE)) { - mImage = static_cast(aItem); + if (mVisibleRegion.IsEmpty() && aItem->GetType() == nsDisplayItem::TYPE_IMAGE) { + mImage = static_cast(aItem); } else { mImage = nullptr; } @@ -1905,8 +1660,7 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem, const nsIntRect& aVisibleRect, const nsIntRect& aDrawRect, const FrameLayerBuilder::Clip& aClip, - const nsIFrame* aActiveScrolledRoot, - const nsPoint& aTopLeft) + const nsIFrame* aActiveScrolledRoot) { int32_t i; int32_t lowestUsableLayerWithScrolledRoot = -1; @@ -1946,7 +1700,7 @@ ContainerState::FindThebesLayerFor(nsDisplayItem* aItem, nsRefPtr layer; ThebesLayerData* thebesLayerData = nullptr; if (lowestUsableLayerWithScrolledRoot < 0) { - layer = CreateOrRecycleThebesLayer(aActiveScrolledRoot, aItem->ReferenceFrame(), aTopLeft); + layer = CreateOrRecycleThebesLayer(aActiveScrolledRoot, aItem->ReferenceFrame()); NS_ASSERTION(!mNewChildLayers.Contains(layer), "Layer already in list???"); mNewChildLayers.AppendElement(layer); @@ -1984,20 +1738,19 @@ DumpPaintedImage(nsDisplayItem* aItem, gfxASurface* aSurf) static void PaintInactiveLayer(nsDisplayListBuilder* aBuilder, - LayerManager* aManager, nsDisplayItem* aItem, gfxContext* aContext, - nsRenderingContext* aCtx) + nsRenderingContext* aCtx, + FrameLayerBuilder *aLayerBuilder) { // This item has an inactive layer. Render it to a ThebesLayer // using a temporary BasicLayerManager. - BasicLayerManager* basic = static_cast(aManager); - nsRefPtr context = aContext; -#ifdef MOZ_DUMP_PAINTING int32_t appUnitsPerDevPixel = AppUnitsPerDevPixel(aItem); nsIntRect itemVisibleRect = aItem->GetVisibleRect().ToOutsidePixels(appUnitsPerDevPixel); + nsRefPtr context = aContext; +#ifdef MOZ_DUMP_PAINTING nsRefPtr surf; if (gfxUtils::sDumpPainting) { surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(itemVisibleRect.Size(), @@ -2006,22 +1759,30 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder, context = new gfxContext(surf); } #endif - basic->SetTarget(context); + nsRefPtr tempManager = new BasicLayerManager(); + tempManager->SetUserData(&gLayerManagerLayerBuilder, new LayerManagerLayerBuilder(aLayerBuilder, false)); + tempManager->BeginTransactionWithTarget(context); + nsRefPtr layer = + aItem->BuildLayer(aBuilder, tempManager, FrameLayerBuilder::ContainerParameters()); + if (!layer) { + tempManager->EndTransaction(nullptr, nullptr); + return; + } + RestrictVisibleRegionForLayer(layer, itemVisibleRect); + + tempManager->SetRoot(layer); + aLayerBuilder->WillEndTransaction(tempManager); if (aItem->GetType() == nsDisplayItem::TYPE_SVG_EFFECTS) { - static_cast(aItem)->PaintAsLayer(aBuilder, aCtx, basic); - if (basic->InTransaction()) { - basic->AbortTransaction(); + static_cast(aItem)->PaintAsLayer(aBuilder, aCtx, tempManager); + if (tempManager->InTransaction()) { + tempManager->AbortTransaction(); } } else { - basic->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder); - } - FrameLayerBuilder *builder = static_cast(basic->GetUserData(&gLayerManagerLayerBuilder)); - if (builder) { - builder->DidEndTransaction(); + tempManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder); } + aLayerBuilder->DidEndTransaction(tempManager); - basic->SetUserData(&gLayerManagerLayerBuilder, NULL); #ifdef MOZ_DUMP_PAINTING if (gfxUtils::sDumpPainting) { DumpPaintedImage(aItem, surf); @@ -2085,19 +1846,16 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, bool isFixed; bool forceInactive; const nsIFrame* activeScrolledRoot; - nsPoint topLeft; if (aFlags & NO_COMPONENT_ALPHA) { // When NO_COMPONENT_ALPHA is set, items will be flattened onto the // reference frame. In this case, force the active scrolled root to // that frame. forceInactive = true; - activeScrolledRoot = mContainerReferenceFrame; - topLeft = nsPoint(0, 0); + activeScrolledRoot = mBuilder->FindReferenceFrameFor(mContainerFrame); isFixed = mBuilder->IsFixedItem(item, nullptr, activeScrolledRoot); } else { forceInactive = false; isFixed = mBuilder->IsFixedItem(item, &activeScrolledRoot); - topLeft = activeScrolledRoot->GetOffsetToCrossDoc(mContainerReferenceFrame); } // Assign the item to a layer @@ -2117,22 +1875,17 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, // way, since their ThebesLayer may decide it wants to draw them // into its buffer even if they're currently covered. if (itemVisibleRect.IsEmpty() && layerState != LAYER_ACTIVE_EMPTY) { - InvalidateForLayerChange(item, nullptr, aClip, topLeft); + InvalidateForLayerChange(item, nullptr); continue; } // Just use its layer. nsRefPtr ownLayer = item->BuildLayer(mBuilder, mManager, mParameters); if (!ownLayer) { - InvalidateForLayerChange(item, ownLayer, aClip, topLeft); + InvalidateForLayerChange(item, ownLayer); continue; } - nsRect invalid; - if (item->IsInvalid(invalid)) { - ownLayer->SetInvalidRectToVisibleRegion(); - } - // If it's not a ContainerLayer, we need to apply the scale transform // ourselves. if (!ownLayer->AsContainerLayer()) { @@ -2182,24 +1935,22 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, NS_ASSERTION(!mNewChildLayers.Contains(ownLayer), "Layer already in list???"); - InvalidateForLayerChange(item, ownLayer, aClip, topLeft); + InvalidateForLayerChange(item, ownLayer); mNewChildLayers.AppendElement(ownLayer); - mLayerBuilder->AddLayerDisplayItem(ownLayer, item, - aClip, layerState, - topLeft, nullptr); + mLayerBuilder->AddLayerDisplayItem(ownLayer, item, layerState); } else { ThebesLayerData* data = FindThebesLayerFor(item, itemVisibleRect, itemDrawRect, aClip, - activeScrolledRoot, topLeft); + activeScrolledRoot); data->mLayer->SetIsFixedPosition(isFixed); - InvalidateForLayerChange(item, data->mLayer, aClip, topLeft); + InvalidateForLayerChange(item, data->mLayer); mLayerBuilder->AddThebesDisplayItem(data->mLayer, item, aClip, mContainerFrame, - layerState, topLeft); + layerState); // check to see if the new item has rounded rect clips in common with // other items in the layer @@ -2209,101 +1960,50 @@ ContainerState::ProcessDisplayItems(const nsDisplayList& aList, } void -ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, - Layer* aNewLayer, - const FrameLayerBuilder::Clip& aClip, - const nsPoint& aTopLeft) +ContainerState::InvalidateForLayerChange(nsDisplayItem* aItem, Layer* aNewLayer) { - nsIFrame* f = aItem->GetUnderlyingFrame(); - NS_ASSERTION(f, "Display items that render using Thebes must have a frame"); - uint32_t key = aItem->GetPerFrameKey(); - NS_ASSERTION(key, "Display items that render using Thebes must have a key"); - nsDisplayItemGeometry *oldGeometry = NULL; - FrameLayerBuilder::Clip* oldClip = NULL; - nsAutoPtr geometry(aItem->AllocateGeometry(mBuilder)); - Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem, &oldGeometry, &oldClip); - if (aNewLayer != oldLayer && oldLayer) { + NS_ASSERTION(aItem->GetUnderlyingFrame(), "Display items that render using Thebes must have a frame"); + NS_ASSERTION(aItem->GetPerFrameKey(), "Display items that render using Thebes must have a key"); + Layer* oldLayer = mLayerBuilder->GetOldLayerFor(aItem); + if (!oldLayer) { + // Nothing to do here, this item didn't have a layer before + return; + } + if (aNewLayer != oldLayer) { // The item has changed layers. - // Invalidate the old bounds in the old layer and new bounds in the new layer. + // Invalidate the bounds in the old layer and new layer. + // The bounds might have changed, but we assume that any difference + // in the bounds will have been invalidated for all Thebes layers + // in the container via regular frame invalidation. + bool snap; + nsRect bounds = aItem->GetBounds(mBuilder, &snap); + ThebesLayer* t = oldLayer->AsThebesLayer(); if (t) { + ThebesDisplayItemLayerUserData* data = + static_cast(t->GetUserData(&gThebesDisplayItemLayerUserData)); // Note that whenever the layer's scale changes, we invalidate the whole thing, // so it doesn't matter whether we are using the old scale at last paint // or a new scale here -#ifdef DEBUG_INVALIDATIONS - printf("Display item type %s(%p) changed layers %p to %p!\n", aItem->Name(), f, t, aNewLayer); -#endif - ThebesDisplayItemLayerUserData* data = - static_cast(t->GetUserData(&gThebesDisplayItemLayerUserData)); InvalidatePostTransformRegion(t, - oldGeometry->ComputeInvalidationRegion(). - ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), + bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), mLayerBuilder->GetLastPaintOffset(t)); } if (aNewLayer) { - ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer(); - if (newThebesLayer) { + ThebesLayer* newLayer = aNewLayer->AsThebesLayer(); + if (newLayer) { ThebesDisplayItemLayerUserData* data = - static_cast(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData)); - InvalidatePostTransformRegion(newThebesLayer, - geometry->ComputeInvalidationRegion(). - ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), - GetTranslationForThebesLayer(newThebesLayer)); + static_cast(newLayer->GetUserData(&gThebesDisplayItemLayerUserData)); + InvalidatePostTransformRegion(newLayer, + bounds.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), + GetTranslationForThebesLayer(newLayer)); } } - return; - } - if (!aNewLayer) { - return; - } - - ThebesLayer* newThebesLayer = aNewLayer->AsThebesLayer(); - if (!newThebesLayer) { - return; - } - ThebesDisplayItemLayerUserData* data = - static_cast(newThebesLayer->GetUserData(&gThebesDisplayItemLayerUserData)); - // If the frame is marked as invalidated, and didn't specify a rect to invalidate then we want to - // invalidate both the old and new bounds, otherwise we only want to invalidate the changed areas. - // If we do get an invalid rect, then we want to add this on top of the change areas. - nsRect invalid; - nsRegion combined; - if (!oldLayer) { - // This item is being added for the first time, invalidate its entire area. - //TODO: We call GetGeometry again in AddThebesDisplayItem, we should reuse this. - combined = geometry->ComputeInvalidationRegion(); -#ifdef DEBUG_INVALIDATIONS - printf("Display item type %s(%p) added to layer %p!\n", aItem->Name(), f, aNewLayer); -#endif - } else if (aItem->IsInvalid(invalid) && invalid.IsEmpty()) { - // Either layout marked item as needing repainting, invalidate the entire old and new areas. - combined.Or(geometry->ComputeInvalidationRegion(), oldGeometry->ComputeInvalidationRegion()); -#ifdef DEBUG_INVALIDATIONS - printf("Display item type %s(%p) (in layer %p) belongs to an invalidated frame!\n", aItem->Name(), f, aNewLayer); -#endif - } else { - // Let the display item check for geometry changes and decide what needs to be - // repainted. - nsPoint shift = aTopLeft - data->mLastActiveScrolledRootOrigin; - oldGeometry->MoveBy(shift); - aItem->ComputeInvalidationRegion(mBuilder, oldGeometry, &combined); - oldClip->AddOffsetAndComputeDifference(shift, oldGeometry->ComputeInvalidationRegion(), - aClip, geometry->ComputeInvalidationRegion(), - &combined); - - // Add in any rect that the frame specified - combined = combined.Or(combined, invalid); -#ifdef DEBUG_INVALIDATIONS - if (!combined.IsEmpty()) { - printf("Display item type %s(%p) (in layer %p) changed geometry!\n", aItem->Name(), f, aNewLayer); - } -#endif - } - if (!combined.IsEmpty()) { - InvalidatePostTransformRegion(newThebesLayer, - combined.ScaleToOutsidePixels(data->mXScale, data->mYScale, mAppUnitsPerDevPixel), - GetTranslationForThebesLayer(newThebesLayer)); + mContainerFrame->InvalidateWithFlags( + bounds - mBuilder->ToReferenceFrame(mContainerFrame), + nsIFrame::INVALIDATE_NO_THEBES_LAYERS | + nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT); } } @@ -2311,24 +2011,8 @@ bool FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem) { - if (!aItem->ShouldFixToViewport(aBuilder)) { - return true; - } - - nsRefPtr layerManager; - nsIFrame* referenceFrame = aBuilder->RootReferenceFrame(); - NS_ASSERTION(referenceFrame == nsLayoutUtils::GetDisplayRootFrame(referenceFrame), - "Reference frame must be a display root for us to use the layer manager"); - nsIWidget* window = referenceFrame->GetNearestWidget(); - if (window) { - layerManager = window->GetLayerManager(); - } - - if (layerManager) { - return !HasRetainedLayerFor(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey(), layerManager); - } - - return true; + return !aItem->ShouldFixToViewport(aBuilder) || + !HasRetainedLayerFor(aItem->GetUnderlyingFrame(), aItem->GetPerFrameKey()); } void @@ -2336,21 +2020,9 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer, nsDisplayItem* aItem, const Clip& aClip, nsIFrame* aContainerLayerFrame, - LayerState aLayerState, - const nsPoint& aTopLeft) + LayerState aLayerState) { - nsRefPtr tempManager; - if (aLayerState != LAYER_NONE) { - DisplayItemData *data = GetDisplayItemDataForManager(aItem, aLayer->Manager()); - if (data) { - tempManager = data->mInactiveManager; - } - if (!tempManager) { - tempManager = new BasicLayerManager(); - } - } - - AddLayerDisplayItem(aLayer, aItem, aClip, aLayerState, aTopLeft, tempManager); + AddLayerDisplayItem(aLayer, aItem, aLayerState); ThebesLayerItemsEntry* entry = mThebesLayerItems.PutEntry(aLayer); if (entry) { @@ -2359,130 +2031,42 @@ FrameLayerBuilder::AddThebesDisplayItem(ThebesLayer* aLayer, entry->mContainerLayerGeneration = mContainerLayerGeneration; } NS_ASSERTION(aItem->GetUnderlyingFrame(), "Must have frame"); - if (tempManager) { - FrameLayerBuilder* layerBuilder = new FrameLayerBuilder(); - layerBuilder->Init(mDisplayListBuilder, tempManager); - - tempManager->BeginTransaction(); - if (mRetainingManager) { - layerBuilder->DidBeginRetainedLayerTransaction(tempManager); - } - - nsAutoPtr props(LayerProperties::CloneFrom(tempManager->GetRoot())); - nsRefPtr layer = - aItem->BuildLayer(mDisplayListBuilder, tempManager, FrameLayerBuilder::ContainerParameters()); - // We have no easy way of detecting if this transaction will ever actually get finished. - // For now, I've just silenced the warning with nested transactions in BasicLayers.cpp - if (!layer) { - tempManager->EndTransaction(nullptr, nullptr); - tempManager->SetUserData(&gLayerManagerLayerBuilder, nullptr); - return; - } - - // If BuildLayer didn't call BuildContainerLayerFor, then our new layer won't have been - // stored in layerBuilder. Manually add it now. - nsRefPtr data = - new DisplayItemData(layer, aItem->GetPerFrameKey(), - LAYER_ACTIVE, mContainerLayerGeneration); - layerBuilder->StoreDataForFrame(aItem->GetUnderlyingFrame(), data); - - tempManager->SetRoot(layer); - layerBuilder->WillEndTransaction(); - - nsIntPoint offset = GetLastPaintOffset(aLayer) - GetTranslationForThebesLayer(aLayer); - props->MoveBy(-offset); - nsIntRect invalid = props->ComputeDifferences(layer, nullptr); - if (aLayerState == LAYER_SVG_EFFECTS) { - invalid = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(aItem->GetUnderlyingFrame(), invalid); - } - if (!invalid.IsEmpty()) { -#ifdef DEBUG_INVALIDATIONS - printf("Inactive LayerManager(%p) for display item %s(%p) has an invalid region - invalidating layer %p\n", tempManager.get(), aItem->Name(), aItem->GetUnderlyingFrame(), aLayer); -#endif - ThebesDisplayItemLayerUserData* data = - static_cast(aLayer->GetUserData(&gThebesDisplayItemLayerUserData)); - invalid.ScaleRoundOut(data->mXScale, data->mYScale); - InvalidatePostTransformRegion(aLayer, invalid, - GetTranslationForThebesLayer(aLayer)); - } - } ClippedDisplayItem* cdi = entry->mItems.AppendElement(ClippedDisplayItem(aItem, aClip, mContainerLayerGeneration)); - cdi->mInactiveLayer = tempManager; + cdi->mInactiveLayer = aLayerState != LAYER_NONE; } } void -FrameLayerBuilder::StoreDataForFrame(nsIFrame* aFrame, DisplayItemData* aData) +FrameLayerBuilder::AddLayerDisplayItemForFrame(Layer* aLayer, + nsIFrame* aFrame, + uint32_t aDisplayItemKey, + LayerState aLayerState) { - DisplayItemDataEntry *entry = mNewDisplayItemData.GetEntry(aFrame); - if (entry) { - return; - } - entry = mNewDisplayItemData.PutEntry(aFrame); + DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aFrame); if (entry) { - entry->mData.AppendElement(aData); - } -} - -FrameLayerBuilder::ClippedDisplayItem::~ClippedDisplayItem() -{ - if (mInactiveLayer) { - // We always start a transaction during layer construction for all inactive - // layers, but we don't necessarily call EndTransaction during painting. - // If the transaaction is still open, end it to avoid assertions. - BasicLayerManager* basic = static_cast(mInactiveLayer.get()); - if (basic->InTransaction()) { - basic->EndTransaction(nullptr, nullptr); - } - basic->SetUserData(&gLayerManagerLayerBuilder, nullptr); + entry->mContainerLayerGeneration = mContainerLayerGeneration; + entry->mData.AppendElement(DisplayItemData(aLayer, aDisplayItemKey, aLayerState, mContainerLayerGeneration)); } } void FrameLayerBuilder::AddLayerDisplayItem(Layer* aLayer, nsDisplayItem* aItem, - const Clip& aClip, - LayerState aLayerState, - const nsPoint& aTopLeft, - LayerManager* aManager) + LayerState aLayerState) { if (aLayer->Manager() != mRetainingManager) return; - - nsRefPtr data = - new DisplayItemData(aLayer, aItem->GetPerFrameKey(), aLayerState, mContainerLayerGeneration); - - ThebesLayer *t = aLayer->AsThebesLayer(); - if (t) { - data->mGeometry = aItem->AllocateGeometry(mDisplayListBuilder); - data->mClip = aClip; - } - data->mInactiveManager = aManager; - DisplayItemDataEntry* entry = - mNewDisplayItemData.PutEntry(aItem->GetUnderlyingFrame()); - if (entry) { - entry->mContainerLayerGeneration = mContainerLayerGeneration; - entry->mData.AppendElement(data); - data->AddFrame(aItem->GetUnderlyingFrame()); - } + nsIFrame* f = aItem->GetUnderlyingFrame(); + uint32_t key = aItem->GetPerFrameKey(); + AddLayerDisplayItemForFrame(aLayer, f, key, aLayerState); nsAutoTArray mergedFrames; aItem->GetMergedFrames(&mergedFrames); for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { - entry = mNewDisplayItemData.PutEntry(mergedFrames[i]); - if (entry) { - entry->mContainerLayerGeneration = mContainerLayerGeneration; - entry->mData.AppendElement(data); - data->AddFrame(mergedFrames[i]); - } - } - - DisplayItemData* oldData = GetDisplayItemDataForManager(aItem, mRetainingManager); - if (oldData && oldData->FrameListMatches(aItem)) { - oldData->mUsed = true; + AddLayerDisplayItemForFrame(aLayer, mergedFrames[i], key, aLayerState); } } @@ -2556,7 +2140,7 @@ ContainerState::CollectOldLayers() } void -ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData) +ContainerState::Finish(uint32_t* aTextContentFlags) { while (!mThebesLayerDataStack.IsEmpty()) { PopThebesLayerData(); @@ -2570,11 +2154,6 @@ ContainerState::Finish(uint32_t* aTextContentFlags, LayerManagerData* aData) for (uint32_t i = 0; i < mNewChildLayers.Length(); ++i) { Layer* prevChild = i == 0 ? nullptr : mNewChildLayers[i - 1].get(); layer = mNewChildLayers[i]; - - if (aData) { - ProcessRemovedDisplayItemsData data(layer, mLayerBuilder); - aData->mFramesWithLayers.EnumerateEntries(FrameLayerBuilder::ProcessRemovedDisplayItems, &data); - } if (!layer->GetVisibleRegion().IsEmpty()) { textContentFlags |= layer->GetContentFlags() & Layer::CONTENT_COMPONENT_ALPHA; @@ -2704,6 +2283,58 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder, return result; } +static void +ApplyThebesLayerInvalidation(nsDisplayListBuilder* aBuilder, + nsIFrame* aContainerFrame, + nsDisplayItem* aContainerItem, + ContainerState& aState, + nsPoint* aCurrentOffset, + nsDisplayTransform* aTransform) +{ + *aCurrentOffset = aContainerItem ? aContainerItem->ToReferenceFrame() + : aBuilder->ToReferenceFrame(aContainerFrame); + + FrameProperties props = aContainerFrame->Properties(); + RefCountedRegion* invalidThebesContent = static_cast + (props.Get(ThebesLayerInvalidRegionProperty())); + const FrameLayerBuilder::ContainerParameters& scaleParameters = aState.ScaleParameters(); + + nsRegion invalidRegion; + if (invalidThebesContent) { + if (invalidThebesContent->mIsInfinite) { + // The region was marked as infinite to indicate that everything should be + // invalidated. + aState.SetInvalidateAllThebesContent(); + return; + } + + invalidRegion = invalidThebesContent->mRegion; + } else { + // The region doesn't exist, so this is a newly visible frame. Invalidate + // the frame area. + invalidRegion = + aContainerFrame->GetVisualOverflowRectRelativeToSelf() + *aCurrentOffset; + } + + if (aTransform) { + // XXX We're simplifying the transform by only using the bounds of the + // region. This may have performance implications. + invalidRegion = aTransform-> + TransformRectOut(invalidRegion.GetBounds(), + aTransform->GetUnderlyingFrame(), -(*aCurrentOffset)); + } + + aState.AddInvalidThebesContent(invalidRegion. + ScaleToOutsidePixels(scaleParameters.mXScale, scaleParameters.mYScale, + aState.GetAppUnitsPerDevPixel())); + + // We have to preserve the current contents of invalidThebesContent + // because there might be multiple container layers for the same + // frame and we need to invalidate the ThebesLayer children of all + // of them. Also, multiple calls to ApplyThebesLayerInvalidation for the + // same layer can share the same region. +} + /* static */ PLDHashOperator FrameLayerBuilder::RestoreDisplayItemData(DisplayItemDataEntry* aEntry, void* aUserArg) { @@ -2714,7 +2345,7 @@ FrameLayerBuilder::RestoreDisplayItemData(DisplayItemDataEntry* aEntry, void* aU } for (uint32_t i = 0; i < aEntry->mData.Length(); i++) { - if (aEntry->mData[i]->mContainerLayerGeneration >= *generation) { + if (aEntry->mData[i].mContainerLayerGeneration >= *generation) { aEntry->mData.TruncateLength(i); return PL_DHASH_NEXT; } @@ -2742,6 +2373,36 @@ FrameLayerBuilder::RestoreThebesLayerItemEntries(ThebesLayerItemsEntry* aEntry, return PL_DHASH_NEXT; } +static nsDisplayTransform* FindTransformForContainerFrame(nsIFrame* aContainerFrame, + nsDisplayItem* aContainerItem) +{ + if (!aContainerFrame->IsTransformed() || + aContainerItem->GetType() == nsDisplayItem::TYPE_TRANSFORM) + return nullptr; + + nsTArray queue; + queue.AppendElement(aContainerItem); + while (queue.Length()) { + nsDisplayItem* item = queue[queue.Length() - 1]; + queue.RemoveElementAt(queue.Length() - 1); + + if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM) { + return static_cast(item); + } + + if (item->GetList()) { + for (nsDisplayItem* child = item->GetList()->GetBottom(); child; + child = child->GetAbove()) { + if (child->GetUnderlyingFrame() == aContainerFrame) { + queue.AppendElement(child); + } + } + } + } + + return nullptr; +} + already_AddRefed FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, LayerManager* aManager, @@ -2764,15 +2425,9 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, // frame. The underlying frame can change when a page scrolls, so this // avoids layer recreation in the situation that a new underlying frame is // picked for a layer. - Layer* oldLayer = nullptr; - if (aContainerItem) { - oldLayer = GetOldLayerFor(aContainerItem); - } else { - DisplayItemData *data = GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey); - if (data) { - oldLayer = data->mLayer; - } - } + Layer* oldLayer = aContainerItem ? + GetOldLayerFor(aContainerItem) : + GetOldLayerForFrame(aContainerFrame, containerDisplayItemKey); if (oldLayer) { NS_ASSERTION(oldLayer->Manager() == aManager, "Wrong manager"); @@ -2822,30 +2477,20 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, mContainerLayerGeneration = ++mMaxContainerLayerGeneration; nsRefPtr thebesLayerInvalidRegion = nullptr; - if (mRetainingManager) { - nsRefPtr data = - new DisplayItemData(containerLayer, containerDisplayItemKey, - LAYER_ACTIVE, mContainerLayerGeneration); - + if (aManager == mRetainingManager) { + FrameProperties props = aContainerFrame->Properties(); DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(aContainerFrame); if (entry) { - entry->mData.AppendElement(data); - data->AddFrame(aContainerFrame); - entry->mContainerLayerGeneration = mContainerLayerGeneration; - } - - nsAutoTArray mergedFrames; - if (aContainerItem) { - aContainerItem->GetMergedFrames(&mergedFrames); - } - for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { - nsIFrame* mergedFrame = mergedFrames[i]; - entry = mNewDisplayItemData.PutEntry(mergedFrame); - if (entry) { - entry->mContainerLayerGeneration = mContainerLayerGeneration; - entry->mData.AppendElement(data); - data->AddFrame(mergedFrame); + entry->mData.AppendElement( + DisplayItemData(containerLayer, containerDisplayItemKey, + LAYER_ACTIVE, mContainerLayerGeneration)); + thebesLayerInvalidRegion = static_cast + (props.Get(ThebesLayerInvalidRegionProperty())); + if (!thebesLayerInvalidRegion) { + thebesLayerInvalidRegion = new RefCountedRegion(); } + entry->mInvalidRegion = thebesLayerInvalidRegion; + entry->mContainerLayerGeneration = mContainerLayerGeneration; } } @@ -2856,21 +2501,63 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, (aContainerFrame->GetStateBits() & NS_FRAME_NO_COMPONENT_ALPHA) ? ContainerState::NO_COMPONENT_ALPHA : 0; uint32_t flags; - - LayerManagerData* data = static_cast - (aManager->GetUserData(&gLayerManagerUserData)); + bool flattenedLayers = false; while (true) { ContainerState state(aBuilder, aManager, aManager->GetLayerBuilder(), - aContainerFrame, aContainerItem, - containerLayer, scaleParameters); - + aContainerFrame, containerLayer, scaleParameters); + if (flattenedLayers) { + state.SetInvalidateAllThebesContent(); + } + + if (aManager == mRetainingManager) { + // If the container frame has a transform and it's contained in the + // container item's sub-tree, we need to transform the invalid region + // before applying it. + nsDisplayTransform* transformItem = + FindTransformForContainerFrame(aContainerFrame, aContainerItem); + + nsPoint currentOffset; + ApplyThebesLayerInvalidation(aBuilder, aContainerFrame, aContainerItem, state, + ¤tOffset, transformItem); + SetHasContainerLayer(aContainerFrame, currentOffset); + + nsAutoTArray mergedFrames; + if (aContainerItem) { + aContainerItem->GetMergedFrames(&mergedFrames); + } + for (uint32_t i = 0; i < mergedFrames.Length(); ++i) { + nsIFrame* mergedFrame = mergedFrames[i]; + DisplayItemDataEntry* entry = mNewDisplayItemData.PutEntry(mergedFrame); + if (entry) { + // Append the container layer so we don't regenerate layers when + // the underlying frame of an item changes to one of the existing + // merged frames. + entry->mData.AppendElement( + DisplayItemData(containerLayer, containerDisplayItemKey, + LAYER_ACTIVE, mContainerLayerGeneration)); + + // Ensure that UpdateDisplayItemDataForFrame recognizes that we + // still have a container layer associated with this frame. + entry->mIsSharingContainerLayer = true; + + // Store the invalid region property in case this frame is represented + // by multiple container layers. This is cleared and set when iterating + // over the DisplayItemDataEntry's in WillEndTransaction. + entry->mInvalidRegion = thebesLayerInvalidRegion; + } + ApplyThebesLayerInvalidation(aBuilder, mergedFrame, nullptr, state, + ¤tOffset, transformItem); + SetHasContainerLayer(mergedFrame, currentOffset); + } + } + Clip clip; state.ProcessDisplayItems(aChildren, clip, stateFlags); // Set CONTENT_COMPONENT_ALPHA if any of our children have it. // This is suboptimal ... a child could have text that's over transparent // pixels in its own layer, but over opaque parts of previous siblings. - state.Finish(&flags, data); + state.Finish(&flags); bounds = state.GetChildrenBounds(); pixBounds = state.ScaleToOutsidePixels(bounds, false); appUnitsPerDevPixel = state.GetAppUnitsPerDevPixel(); @@ -2889,6 +2576,7 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, mThebesLayerItems.EnumerateEntries(RestoreThebesLayerItemEntries, &mContainerLayerGeneration); aContainerFrame->AddStateBits(NS_FRAME_NO_COMPONENT_ALPHA); + flattenedLayers = true; continue; } break; @@ -2909,18 +2597,20 @@ FrameLayerBuilder::BuildContainerLayerFor(nsDisplayListBuilder* aBuilder, containerLayer->SetContentFlags(flags); mContainerLayerGeneration = oldGeneration; - containerLayer->SetUserData(&gNotifySubDocInvalidationData, nullptr); - return containerLayer.forget(); } Layer* FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, nsDisplayItem* aItem) { + if (aManager != mRetainingManager) + return nullptr; + nsIFrame* f = aItem->GetUnderlyingFrame(); NS_ASSERTION(f, "Can only call GetLeafLayerFor on items that have a frame"); - Layer* layer = GetOldLayerFor(aItem); + Layer* layer = GetOldLayerForFrame(f, aItem->GetPerFrameKey()); if (!layer) return nullptr; if (layer->HasUserData(&gThebesDisplayItemLayerUserData)) { @@ -2936,23 +2626,105 @@ FrameLayerBuilder::GetLeafLayerFor(nsDisplayListBuilder* aBuilder, } /* static */ void -FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager) +FrameLayerBuilder::InvalidateThebesLayerContents(nsIFrame* aFrame, + const nsRect& aRect) { - LayerManagerData* data = static_cast - (aManager->GetUserData(&gLayerManagerUserData)); - if (data) { - data->mInvalidateAllLayers = true; + FrameProperties props = aFrame->Properties(); + RefCountedRegion* invalidThebesContent = static_cast + (props.Get(ThebesLayerInvalidRegionProperty())); + if (!invalidThebesContent) + return; + + nsPoint* offsetAtLastPaint = static_cast + (props.Get(ThebesLayerLastPaintOffsetProperty())); + NS_ASSERTION(offsetAtLastPaint, + "This must have been set up along with ThebesLayerInvalidRegionProperty"); + invalidThebesContent->mRegion.Or(invalidThebesContent->mRegion, + aRect + *offsetAtLastPaint); + invalidThebesContent->mRegion.SimplifyOutward(20); +} + +/** + * Returns true if we find a descendant with a container layer + */ +static bool +InternalInvalidateThebesLayersInSubtree(nsIFrame* aFrame, bool aTrustFrameGeometry) +{ + if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT)) + return false; + + bool foundContainerLayer = false; + if (aFrame->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) { + if (aTrustFrameGeometry) { + // Just invalidate the area covered by the frame. This helps if a single + // region is being shared by multiple container layers. + FrameLayerBuilder::InvalidateThebesLayerContents(aFrame, + aFrame->GetVisualOverflowRectRelativeToSelf()); + } else { + // Mark the invalid region as infinite to indicate that all Thebes + // contents need to be invalidated + FrameProperties props = aFrame->Properties(); + RefCountedRegion* invalidRegion = static_cast + (props.Get(ThebesLayerInvalidRegionProperty())); + if (!invalidRegion) { + invalidRegion = new RefCountedRegion(); + invalidRegion->AddRef(); + props.Set(ThebesLayerInvalidRegionProperty(), invalidRegion); + } + invalidRegion->mIsInfinite = true; + } + foundContainerLayer = true; + } + + nsAutoTArray childListArray; + if (!aFrame->GetFirstPrincipalChild()) { + nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(aFrame); + if (subdocumentFrame) { + // Descend into the subdocument + nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame(); + if (root) { + childListArray.AppendElement(nsIFrame::ChildList( + nsFrameList(root, nsLayoutUtils::GetLastSibling(root)), + nsIFrame::kPrincipalList)); + } + } + } + + aFrame->GetChildLists(&childListArray); + nsIFrame::ChildListArrayIterator lists(childListArray); + for (; !lists.IsDone(); lists.Next()) { + nsFrameList::Enumerator childFrames(lists.CurrentList()); + for (; !childFrames.AtEnd(); childFrames.Next()) { + if (InternalInvalidateThebesLayersInSubtree(childFrames.get(), + aTrustFrameGeometry)) { + foundContainerLayer = true; + } + } + } + + if (!foundContainerLayer) { + aFrame->RemoveStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT); } + return foundContainerLayer; } /* static */ void -FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame) +FrameLayerBuilder::InvalidateThebesLayersInSubtree(nsIFrame* aFrame) { - LayerManagerData* data = GetDefaultLayerManagerDataForFrame(aFrame); - if (data) { - data->mInvalidateAllLayers = true; - } - data = GetSecondaryLayerManagerDataForFrame(aFrame); + InternalInvalidateThebesLayersInSubtree(aFrame, true); +} + +/* static */ void +FrameLayerBuilder::InvalidateThebesLayersInSubtreeWithUntrustedFrameGeometry(nsIFrame* aFrame) +{ + InternalInvalidateThebesLayersInSubtree(aFrame, false); +} + +/* static */ void +FrameLayerBuilder::InvalidateAllLayers(LayerManager* aManager) +{ + LayerManagerData* data = static_cast + (aManager->GetUserData(&gLayerManagerUserData)); if (data) { data->mInvalidateAllLayers = true; } @@ -2962,24 +2734,18 @@ FrameLayerBuilder::InvalidateAllLayersForFrame(nsIFrame *aFrame) Layer* FrameLayerBuilder::GetDedicatedLayer(nsIFrame* aFrame, uint32_t aDisplayItemKey) { - //TODO: This isn't completely correct, since a frame could exist as a layer - // in the normal widget manager, and as a different layer (or no layer) - // in the secondary manager - - DisplayItemData *data = GetDisplayItemDataForManager(aFrame, aDisplayItemKey); - if (!data) { + nsTArray* array = GetDisplayItemDataArrayForFrame(aFrame); + if (!array) return nullptr; - } - - if (data->mOptLayer) { - return data->mOptLayer; - } - Layer* layer = data->mLayer; - if (!layer->HasUserData(&gColorLayerUserData) && - !layer->HasUserData(&gImageLayerUserData) && - !layer->HasUserData(&gThebesDisplayItemLayerUserData)) { - return layer; + for (uint32_t i = 0; i < array->Length(); ++i) { + if (array->ElementAt(i).mDisplayItemKey == aDisplayItemKey) { + Layer* layer = array->ElementAt(i).mLayer; + if (!layer->HasUserData(&gColorLayerUserData) && + !layer->HasUserData(&gImageLayerUserData) && + !layer->HasUserData(&gThebesDisplayItemLayerUserData)) + return layer; + } } return nullptr; } @@ -3005,27 +2771,25 @@ FrameLayerBuilder::GetThebesLayerScaleForFrame(nsIFrame* aFrame) nsIFrame* last; for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetCrossDocParentFrame(f)) { last = f; - LayerManagerData *data = GetDefaultLayerManagerDataForFrame(f); - if (!data) - continue; - DisplayItemDataEntry *entry = data->mFramesWithLayers.GetEntry(f); - // Some frames with NS_FRAME_HAS_CONTAINER_LAYER may not have display items. - // In particular the root frame probably doesn't! - if (!entry) - continue; - nsTArray >* array = &entry->mData; - for (uint32_t i = 0; i < array->Length(); ++i) { - Layer* layer = array->ElementAt(i)->mLayer; - ContainerLayer* container = layer->AsContainerLayer(); - if (!container) { - continue; - } - for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) { - ThebesDisplayItemLayerUserData* data = - static_cast - (l->GetUserData(&gThebesDisplayItemLayerUserData)); - if (data) { - return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale)); + if (f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) { + nsTArray* array = GetDisplayItemDataArrayForFrame(f); + // Some frames with NS_FRAME_HAS_CONTAINER_LAYER may not have display items. + // In particular the root frame probably doesn't! + if (!array) + continue; + for (uint32_t i = 0; i < array->Length(); ++i) { + Layer* layer = array->ElementAt(i).mLayer; + ContainerLayer* container = layer->AsContainerLayer(); + if (!container) { + continue; + } + for (Layer* l = container->GetFirstChild(); l; l = l->GetNextSibling()) { + ThebesDisplayItemLayerUserData* data = + static_cast + (l->GetUserData(&gThebesDisplayItemLayerUserData)); + if (data) { + return PredictScaleForContent(aFrame, f, gfxSize(data->mXScale, data->mYScale)); + } } } } @@ -3149,6 +2913,14 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, nsPresContext* presContext = containerLayerFrame->PresContext(); int32_t appUnitsPerDevPixel = presContext->AppUnitsPerDevPixel(); + if (!aRegionToInvalidate.IsEmpty()) { + nsRect r = (aRegionToInvalidate.GetBounds() + offset). + ToAppUnits(appUnitsPerDevPixel); + r.ScaleInverseRoundOut(userData->mXScale, userData->mYScale); + containerLayerFrame->InvalidateWithFlags(r, + nsIFrame::INVALIDATE_NO_THEBES_LAYERS | + nsIFrame::INVALIDATE_EXCLUDE_CURRENT_PAINT); + } uint32_t i; // Update visible regions. We need perform visibility analysis again @@ -3231,7 +3003,7 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, } if (cdi->mInactiveLayer) { - PaintInactiveLayer(builder, cdi->mInactiveLayer, cdi->mItem, aContext, rc); + PaintInactiveLayer(builder, cdi->mItem, aContext, rc, layerBuilder); } else { nsIFrame* frame = cdi->mItem->GetUnderlyingFrame(); if (frame) { @@ -3264,9 +3036,6 @@ FrameLayerBuilder::DrawThebesLayer(ThebesLayer* aLayer, } FlashPaint(aContext); - if (!aRegionToInvalidate.IsEmpty()) { - aLayer->AddInvalidRect(aRegionToInvalidate.GetBounds()); - } } bool @@ -3498,43 +3267,6 @@ FrameLayerBuilder::Clip::RemoveRoundedCorners() mRoundedClipRects.Clear(); } -static void -AccumulateRectDifference(const nsRect& aR1, const nsRect& aR2, nsRegion* aOut) -{ - if (aR1.IsEqualInterior(aR2)) - return; - nsRegion r; - r.Xor(aR1, aR2); - aOut->Or(*aOut, r); -} - -void -FrameLayerBuilder::Clip::AddOffsetAndComputeDifference(const nsPoint& aOffset, - const nsRect& aBounds, - const Clip& aOther, - const nsRect& aOtherBounds, - nsRegion* aDifference) -{ - if (mHaveClipRect != aOther.mHaveClipRect || - mRoundedClipRects.Length() != aOther.mRoundedClipRects.Length()) { - aDifference->Or(*aDifference, aBounds); - aDifference->Or(*aDifference, aOtherBounds); - return; - } - if (mHaveClipRect) { - AccumulateRectDifference((mClipRect + aOffset).Intersect(aBounds), - aOther.mClipRect.Intersect(aOtherBounds), - aDifference); - } - for (uint32_t i = 0; i < mRoundedClipRects.Length(); ++i) { - if (mRoundedClipRects[i] + aOffset != aOther.mRoundedClipRects[i]) { - // The corners make it tricky so we'll just add both rects here. - aDifference->Or(*aDifference, mRoundedClipRects[i].mRect.Intersect(aBounds)); - aDifference->Or(*aDifference, aOther.mRoundedClipRects[i].mRect.Intersect(aOtherBounds)); - } - } -} - gfxRect CalculateBounds(const nsTArray& aRects, int32_t A2D) { diff --git a/layout/base/FrameLayerBuilder.h b/layout/base/FrameLayerBuilder.h index a1204b9e961ad..53cdda1ca1ca3 100644 --- a/layout/base/FrameLayerBuilder.h +++ b/layout/base/FrameLayerBuilder.h @@ -11,9 +11,6 @@ #include "nsTArray.h" #include "nsRegion.h" #include "nsIFrame.h" -#include "nsDisplayListInvalidation.h" -#include "LayerTreeInvalidation.h" -#include "ImageLayers.h" class nsDisplayListBuilder; class nsDisplayList; @@ -29,7 +26,6 @@ class ThebesLayer; } class FrameLayerBuilder; -class LayerManagerData; enum LayerState { LAYER_NONE, @@ -44,11 +40,6 @@ enum LayerState { LAYER_SVG_EFFECTS }; -extern uint8_t gLayerManagerSecondary; - -class LayerManagerSecondary : public layers::LayerUserData { -}; - class RefCountedRegion : public RefCounted { public: RefCountedRegion() : mIsInfinite(false) {} @@ -57,14 +48,15 @@ class RefCountedRegion : public RefCounted { }; /** - * The FrameLayerBuilder is responsible for converting display lists - * into layer trees. Every LayerManager needs a unique FrameLayerBuilder - * to build layers. + * The FrameLayerBuilder belongs to an nsDisplayListBuilder and is + * responsible for converting display lists into layer trees. * * The most important API in this class is BuildContainerLayerFor. This * method takes a display list as input and constructs a ContainerLayer * with child layers that render the contents of the display list. It - * records the relationship between frames and layers. + * also updates userdata for the retained layer manager, and + * DisplayItemDataProperty data for frames, to record the relationship + * between frames and layers. * * That data enables us to retain layer trees. When constructing a * ContainerLayer, we first check to see if there's an existing @@ -83,7 +75,7 @@ class RefCountedRegion : public RefCounted { * FrameLayerBuilder sets up ThebesLayers so that 0,0 in the Thebes layer * corresponds to the (pixel-snapped) top-left of the aActiveScrolledRoot. * It sets up ContainerLayers so that 0,0 in the container layer - * corresponds to the snapped top-left of the display item reference frame. + * corresponds to the snapped top-left of the display list reference frame. * * When we construct a container layer, we know the transform that will be * applied to the layer. If the transform scales the content, we can get @@ -94,12 +86,11 @@ class RefCountedRegion : public RefCounted { * integer types (nsIntPoint/nsIntSize/nsIntRect/nsIntRegion) are all in layer * coordinates, post-scaling, whereas appunit types are all pre-scaling. */ -class FrameLayerBuilder : public layers::LayerUserData { +class FrameLayerBuilder { public: typedef layers::ContainerLayer ContainerLayer; typedef layers::Layer Layer; typedef layers::ThebesLayer ThebesLayer; - typedef layers::ImageLayer ImageLayer; typedef layers::LayerManager LayerManager; FrameLayerBuilder() : @@ -129,14 +120,18 @@ class FrameLayerBuilder : public layers::LayerUserData { void DidBeginRetainedLayerTransaction(LayerManager* aManager); /** - * Call this just before we end a transaction. + * Call this just before we end a transaction on aManager. If aManager + * is not the retained layer manager then it must be a temporary layer + * manager that will not be used again. */ - void WillEndTransaction(); + void WillEndTransaction(LayerManager* aManager); /** - * Call this after we end a transaction. + * Call this after we end a transaction on aManager. If aManager + * is not the retained layer manager then it must be a temporary layer + * manager that will not be used again. */ - void DidEndTransaction(); + void DidEndTransaction(LayerManager* aManager); struct ContainerParameters { ContainerParameters() : @@ -217,14 +212,38 @@ class FrameLayerBuilder : public layers::LayerUserData { * region. */ Layer* GetLeafLayerFor(nsDisplayListBuilder* aBuilder, + LayerManager* aManager, nsDisplayItem* aItem); + /** + * Call this during invalidation if aFrame has + * the NS_FRAME_HAS_CONTAINER_LAYER state bit. Only the nearest + * ancestor frame of the damaged frame that has + * NS_FRAME_HAS_CONTAINER_LAYER needs to be invalidated this way. + * It is assumed that aRect does NOT have the frame's transforms applied. + */ + static void InvalidateThebesLayerContents(nsIFrame* aFrame, + const nsRect& aRect); + + /** + * For any descendant frame of aFrame (including across documents) that + * has an associated container layer, invalidate all the contents of + * all ThebesLayer children of the container. Useful when aFrame is + * being moved and we need to invalidate everything in aFrame's subtree. + */ + static void InvalidateThebesLayersInSubtree(nsIFrame* aFrame); + + /** + * As InvalidateThebesLayersInSubtree, but don't trust frame geometry + * (e.g. because appunits-per-dev-pixel changed). + */ + static void InvalidateThebesLayersInSubtreeWithUntrustedFrameGeometry(nsIFrame* aFrame); + /** * Call this to force all retained layers to be discarded and recreated at * the next paint. */ static void InvalidateAllLayers(LayerManager* aManager); - static void InvalidateAllLayersForFrame(nsIFrame *aFrame); /** * Call this to determine if a frame has a dedicated (non-Thebes) layer @@ -260,93 +279,49 @@ class FrameLayerBuilder : public layers::LayerUserData { /** * Record aItem as a display item that is rendered by aLayer. - * - * @param aLayer Layer that the display item will be rendered into - * @param aItem Display item to be drawn. - * @param aLayerState What LayerState the item is using. - * @param aTopLeft offset from active scrolled root to reference frame - * @param aManager If the layer is in the LAYER_INACTIVE state, - * then this is the temporary layer manager to draw with. */ - struct Clip; void AddLayerDisplayItem(Layer* aLayer, nsDisplayItem* aItem, - const Clip& aClip, - LayerState aLayerState, - const nsPoint& aTopLeft, - LayerManager* aManager = nullptr); + LayerState aLayerState); + + /** + * Record aFrame as a frame that is rendered by an item on aLayer. + */ + void AddLayerDisplayItemForFrame(Layer* aLayer, + nsIFrame* aFrame, + uint32_t aDisplayItemKey, + LayerState aLayerState); /** * Record aItem as a display item that is rendered by the ThebesLayer * aLayer, with aClipRect, where aContainerLayerFrame is the frame * for the container layer this ThebesItem belongs to. * aItem must have an underlying frame. - * @param aTopLeft offset from active scrolled root to reference frame */ + struct Clip; void AddThebesDisplayItem(ThebesLayer* aLayer, nsDisplayItem* aItem, const Clip& aClip, nsIFrame* aContainerLayerFrame, - LayerState aLayerState, - const nsPoint& aTopLeft); - - /** - * Set the current top-level LayerManager for the widget being - * painted. - */ - static void SetWidgetLayerManager(LayerManager* aManager) - { - LayerManagerSecondary* secondary = - static_cast(aManager->GetUserData(&gLayerManagerSecondary)); - sWidgetManagerSecondary = !!secondary; - } - - /** - * Gets the frame property descriptor for the given manager, or for the current - * widget layer manager if nullptr is passed. - */ - static const FramePropertyDescriptor* GetDescriptorForManager(LayerManager* aManager); + LayerState aLayerState); /** - * Get the LayerManagerData for a given frame and layer manager. If no layer manager - * is passed, then the current widget layer manager is used. - */ - static LayerManagerData* GetManagerData(nsIFrame* aFrame, LayerManager* aManager = nullptr); - - /** - * Set the LayerManagerData for a given frame and current widget layer manager. - * This replaces any existing data for the same frame/layer manager pair. - */ - static void SetManagerData(nsIFrame* aFrame, LayerManagerData* aData); - - /** - * Clears the current LayerManagerData for the given frame and current widget - * layer manager. - */ - static void ClearManagerData(nsIFrame* aFrame); - - /** - * Clears any references to the given LayerManagerData for the given frame - * and belonging to any layer manager. + * Given a frame and a display item key that uniquely identifies a + * display item for the frame, find the layer that was last used to + * render that display item. Returns null if there is no such layer. + * This could be a dedicated layer for the display item, or a ThebesLayer + * that renders many display items. */ - static void ClearManagerData(nsIFrame* aFrame, LayerManagerData* aData); + Layer* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey); /** * Calls GetOldLayerForFrame on the underlying frame of the display item, * and each subsequent merged frame if no layer is found for the underlying * frame. */ - Layer* GetOldLayerFor(nsDisplayItem* aItem, nsDisplayItemGeometry** aOldGeometry = nullptr, Clip** aOldClip = nullptr); + Layer* GetOldLayerFor(nsDisplayItem* aItem); static Layer* GetDebugOldLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey); - - /** - * If the display item was previously drawn as an inactive layer, - * then return the layer manager used for the inactive transaction. - * Returns nullptr if no manager could be found. - */ - LayerManager* GetInactiveLayerManagerFor(nsDisplayItem* aItem); - /** * Try to determine whether the ThebesLayer aLayer paints an opaque * single color everywhere it's visible in aRect. @@ -359,7 +334,10 @@ class FrameLayerBuilder : public layers::LayerUserData { * Destroy any stored LayerManagerDataProperty and the associated data for * aFrame. */ - static void DestroyDisplayItemDataFor(nsIFrame* aFrame); + static void DestroyDisplayItemDataFor(nsIFrame* aFrame) + { + aFrame->Properties().Delete(LayerManagerDataProperty()); + } LayerManager* GetRetainingLayerManager() { return mRetainingManager; } @@ -378,21 +356,11 @@ class FrameLayerBuilder : public layers::LayerUserData { * into a retained layer. * Returns false if it was rendered into a temporary layer manager and then * into a retained layer. - * - * Since display items can belong to multiple retained LayerManagers, we need to - * specify which LayerManager to check. */ - static bool HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey, LayerManager* aManager); + static bool HasRetainedLayerFor(nsIFrame* aFrame, uint32_t aDisplayItemKey); /** - * Returns true if the given display item was rendered during the previous - * paint. Returns false otherwise. - */ - static bool HasRetainedDataFor(nsIFrame* aFrame, uint32_t aDisplayItemKey); - - /** - * Save transform that was in aLayer when we last painted, and the position - * of the active scrolled root frame. It must be an integer + * Save transform that was in aLayer when we last painted. It must be an integer * translation. */ void SaveLastPaintOffset(ThebesLayer* aLayer); @@ -412,14 +380,6 @@ class FrameLayerBuilder : public layers::LayerUserData { */ static gfxSize GetThebesLayerScaleForFrame(nsIFrame* aFrame); - /** - * Stores a Layer as the dedicated layer in the DisplayItemData for a given frame/key pair. - * - * Used when we optimize a ThebesLayer into an ImageLayer and want to retroactively update the - * DisplayItemData so we can retrieve the layer from within layout. - */ - void StoreOptimizedLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey, Layer* aImage); - /** * Clip represents the intersection of an optional rectangle with a * list of rounded rectangles. @@ -430,11 +390,6 @@ class FrameLayerBuilder : public layers::LayerUserData { // Indices into mRadii are the NS_CORNER_* constants in nsStyleConsts.h nscoord mRadii[8]; - RoundedRect operator+(const nsPoint& aOffset) const { - RoundedRect r = *this; - r.mRect += aOffset; - return r; - } bool operator==(const RoundedRect& aOther) const { if (!mRect.IsEqualInterior(aOther.mRect)) { return false; @@ -497,12 +452,6 @@ class FrameLayerBuilder : public layers::LayerUserData { // Gets rid of any rounded corners in this clip. void RemoveRoundedCorners(); - // Adds the difference between Intersect(*this + aPoint, aBounds) and - // Intersect(aOther, aOtherBounds) to aDifference. - void AddOffsetAndComputeDifference(const nsPoint& aPoint, const nsRect& aBounds, - const Clip& aOther, const nsRect& aOtherBounds, - nsRegion* aDifference); - bool operator==(const Clip& aOther) const { return mHaveClipRect == aOther.mHaveClipRect && (!mHaveClipRect || mClipRect.IsEqualInterior(aOther.mClipRect)) && @@ -512,12 +461,6 @@ class FrameLayerBuilder : public layers::LayerUserData { return !(*this == aOther); } }; - - NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty, - RemoveFrameFromLayerManager) - - NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerSecondaryDataProperty, - RemoveFrameFromLayerManager) protected: /** @@ -528,78 +471,47 @@ class FrameLayerBuilder : public layers::LayerUserData { class DisplayItemData { public: DisplayItemData(Layer* aLayer, uint32_t aKey, LayerState aLayerState, uint32_t aGeneration); - DisplayItemData() - : mUsed(false) - {} - DisplayItemData(DisplayItemData &toCopy); ~DisplayItemData(); - NS_INLINE_DECL_REFCOUNTING(DisplayItemData) - - void AddFrame(nsIFrame* aFrame) - { - mFrameList.AppendElement(aFrame); - } - - bool FrameListMatches(nsDisplayItem* aOther); - nsRefPtr mLayer; - nsRefPtr mOptLayer; - nsRefPtr mInactiveManager; - nsAutoTArray mFrameList; - nsAutoPtr mGeometry; - Clip mClip; uint32_t mDisplayItemKey; uint32_t mContainerLayerGeneration; LayerState mLayerState; - - /** - * Used to track if data currently stored in mFramesWithLayers (from an existing - * paint) is also used in the current paint and has an equivalent data object - * in mNewDisplayItemData. - */ - bool mUsed; }; static void RemoveFrameFromLayerManager(nsIFrame* aFrame, void* aPropertyValue); - /** - * Given a frame and a display item key that uniquely identifies a - * display item for the frame, find the layer that was last used to - * render that display item. Returns null if there is no such layer. - * This could be a dedicated layer for the display item, or a ThebesLayer - * that renders many display items. - */ - DisplayItemData* GetOldLayerForFrame(nsIFrame* aFrame, uint32_t aDisplayItemKey); + NS_DECLARE_FRAME_PROPERTY_WITH_FRAME_IN_DTOR(LayerManagerDataProperty, + RemoveFrameFromLayerManager) /** * We accumulate DisplayItemData elements in a hashtable during - * the paint process, one per visible display item. - * There is one hashtable per layer manager, and one entry - * per frame. This is the hashentry for that hashtable. + * the paint process, and store them in the frame property only when + * paint is complete. This is the hashentry for that hashtable. */ class DisplayItemDataEntry : public nsPtrHashKey { public: DisplayItemDataEntry(const nsIFrame *key) : nsPtrHashKey(key) - { - MOZ_COUNT_CTOR(DisplayItemDataEntry); - } + , mIsSharingContainerLayer(false) + {} DisplayItemDataEntry(DisplayItemDataEntry &toCopy) : nsPtrHashKey(toCopy.mKey) + , mIsSharingContainerLayer(toCopy.mIsSharingContainerLayer) { - MOZ_COUNT_CTOR(DisplayItemDataEntry); // This isn't actually a copy-constructor; notice that it steals toCopy's // array and invalid region. Be careful. mData.SwapElements(toCopy.mData); + mInvalidRegion.swap(toCopy.mInvalidRegion); mContainerLayerGeneration = toCopy.mContainerLayerGeneration; } - ~DisplayItemDataEntry() { MOZ_COUNT_DTOR(DisplayItemDataEntry); } bool HasNonEmptyContainerLayer(); - nsAutoTArray, 1> mData; + nsAutoTArray mData; + nsRefPtr mInvalidRegion; uint32_t mContainerLayerGeneration; + bool mIsSharingContainerLayer; enum { ALLOW_MEMMOVE = false }; }; @@ -607,12 +519,6 @@ class FrameLayerBuilder : public layers::LayerUserData { // LayerManagerData needs to see DisplayItemDataEntry. friend class LayerManagerData; - /** - * Stores DisplayItemData associated with aFrame, stores the data in - * mNewDisplayItemData. - */ - void StoreDataForFrame(nsIFrame* aFrame, DisplayItemData* data); - // Flash the area within the context clip if paint flashing is enabled. static void FlashPaint(gfxContext *aContext); @@ -623,29 +529,19 @@ class FrameLayerBuilder : public layers::LayerUserData { * Note that the pointer returned here is only valid so long as you don't * poke the LayerManagerData's mFramesWithLayers hashtable. */ - nsTArray >* GetDisplayItemDataArrayForFrame(nsIFrame *aFrame); - - /* - * Get the DisplayItemData associated with this frame / display item pair, - * using the LayerManager instead of FrameLayerBuilder. - */ - static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame, - uint32_t aDisplayItemKey, - LayerManager* aManager); - static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame, - uint32_t aDisplayItemKey); - static DisplayItemData* GetDisplayItemDataForManager(nsDisplayItem* aItem, LayerManager* aManager); - static DisplayItemData* GetDisplayItemDataForManager(nsIFrame* aFrame, - uint32_t aDisplayItemKey, - LayerManagerData* aData); + static nsTArray* GetDisplayItemDataArrayForFrame(nsIFrame *aFrame); /** * A useful hashtable iteration function that removes the - * DisplayItemData property for the frame and returns PL_DHASH_REMOVE. + * DisplayItemData property for the frame, clears its + * NS_FRAME_HAS_CONTAINER_LAYER bit and returns PL_DHASH_REMOVE. * aClosure is ignored. */ static PLDHashOperator RemoveDisplayItemDataForFrame(DisplayItemDataEntry* aEntry, - void* aClosure); + void* aClosure) + { + return UpdateDisplayItemDataForFrame(aEntry, nullptr); + } /** * We store one of these for each display item associated with a @@ -663,19 +559,10 @@ class FrameLayerBuilder : public layers::LayerUserData { { } - ~ClippedDisplayItem(); - nsDisplayItem* mItem; - - /** - * If the display item is being rendered as an inactive - * layer, then this stores the layer manager being - * used for the inactive transaction. - */ - nsRefPtr mInactiveLayer; - Clip mClip; uint32_t mContainerLayerGeneration; + bool mInactiveLayer; }; /** @@ -720,8 +607,6 @@ class FrameLayerBuilder : public layers::LayerUserData { return mThebesLayerItems.GetEntry(aLayer); } - static PLDHashOperator ProcessRemovedDisplayItems(DisplayItemDataEntry* aEntry, - void* aUserArg); protected: void RemoveThebesItemsAndOwnerDataForLayerSubtree(Layer* aLayer, bool aRemoveThebesItems, @@ -754,11 +639,6 @@ class FrameLayerBuilder : public layers::LayerUserData { * The root prescontext for the display list builder reference frame */ nsRootPresContext* mRootPresContext; - - /** - * The display list builder being used. - */ - nsDisplayListBuilder* mDisplayListBuilder; /** * A map from frames to a list of (display item key, layer) pairs that * describes what layers various parts of the frame are assigned to. @@ -786,12 +666,6 @@ class FrameLayerBuilder : public layers::LayerUserData { uint32_t mContainerLayerGeneration; uint32_t mMaxContainerLayerGeneration; - - /** - * True if the current top-level LayerManager for the widget being - * painted is marked as being a 'secondary' LayerManager. - */ - static bool sWidgetManagerSecondary; }; } diff --git a/layout/base/Makefile.in b/layout/base/Makefile.in index ae9234bb97845..7a0882f9a6740 100644 --- a/layout/base/Makefile.in +++ b/layout/base/Makefile.in @@ -38,7 +38,6 @@ EXPORTS = \ nsCompatibility.h \ nsDisplayItemTypes.h \ nsDisplayList.h \ - nsDisplayListInvalidation.h \ nsFrameManager.h \ nsFrameManagerBase.h \ nsFrameIterator.h \ @@ -74,7 +73,6 @@ CPPSRCS = \ nsChildIterator.cpp \ nsCounterManager.cpp \ nsDisplayList.cpp \ - nsDisplayListInvalidation.cpp \ nsDocumentViewer.cpp \ nsFrameManager.cpp \ nsFrameIterator.cpp \ diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index d5100d81de162..4f4b8d2e7bfa7 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -7704,6 +7704,11 @@ UpdateViewsForTree(nsIFrame* aFrame, DoApplyRenderingChangeToTree(child, aFrameManager, aChange); } else { // regular frame + if ((child->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER) && + (aChange & nsChangeHint_RepaintFrame)) { + FrameLayerBuilder::InvalidateThebesLayerContents(child, + child->GetVisualOverflowRectRelativeToSelf()); + } UpdateViewsForTree(child, aFrameManager, aChange); } } @@ -7745,15 +7750,20 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame, nsSVGUtils::InvalidateBounds(aFrame); } } else { - aFrame->InvalidateFrameSubtree(); + aFrame->InvalidateOverflowRect(); } } if (aChange & nsChangeHint_UpdateOpacityLayer) { aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer); + aFrame->InvalidateLayer(aFrame->GetVisualOverflowRectRelativeToSelf(), + nsDisplayItem::TYPE_OPACITY); } if (aChange & nsChangeHint_UpdateTransformLayer) { aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer); + // Invalidate the old transformed area. The new transformed area + // will be invalidated by nsFrame::FinishAndStoreOverflowArea. + aFrame->InvalidateTransformLayer(); } if (aChange & nsChangeHint_ChildrenOnlyTransform) { // The long comment in ProcessRestyledFrames that precedes the @@ -7765,9 +7775,11 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame, nsIFrame* childFrame = f->GetFirstPrincipalChild(); for ( ; childFrame; childFrame = childFrame->GetNextSibling()) { childFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer); + // Invalidate the old transformed area. The new transformed area + // will be invalidated by nsFrame::FinishAndStoreOverflowArea. + childFrame->InvalidateTransformLayer(); } } - aFrame->SchedulePaint(); } } @@ -12421,8 +12433,6 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame) return true; } - aFrame->SchedulePaint(); - // For relative positioning, we can simply update the frame rect if (display->mPosition == NS_STYLE_POSITION_RELATIVE) { nsIFrame* cb = aFrame->GetContainingBlock(); @@ -12430,6 +12440,9 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame) const nsPoint oldOffsets = aFrame->GetRelativeOffset(); nsMargin newOffsets; + // Invalidate the old rect + aFrame->InvalidateOverflowRect(); + // Move the frame nsHTMLReflowState::ComputeRelativeOffsets( cb->GetStyleVisibility()->mDirection, @@ -12440,6 +12453,9 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame) aFrame->SetPosition(aFrame->GetPosition() - oldOffsets + nsPoint(newOffsets.left, newOffsets.top)); + // Invalidate the new rect + aFrame->InvalidateFrameSubtree(); + return true; } @@ -12510,7 +12526,10 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame) size.height - reflowState.mComputedMargin.top; } - + + // Invalidate the old rect + aFrame->InvalidateFrameSubtree(); + // Move the frame nsPoint pos(parentBorder.left + reflowState.mComputedOffsets.left + reflowState.mComputedMargin.left, @@ -12518,6 +12537,9 @@ nsCSSFrameConstructor::RecomputePosition(nsIFrame* aFrame) reflowState.mComputedMargin.top); aFrame->SetPosition(pos); + // Invalidate the new rect + aFrame->InvalidateFrameSubtree(); + return true; } diff --git a/layout/base/nsCaret.cpp b/layout/base/nsCaret.cpp index 6156d8630d9ce..7af708e042e67 100644 --- a/layout/base/nsCaret.cpp +++ b/layout/base/nsCaret.cpp @@ -483,9 +483,8 @@ void nsCaret::InvalidateOutsideCaret() nsIFrame *frame = GetCaretFrame(); // Only invalidate if we are not fully contained by our frame's rect. - if (frame && !frame->GetVisualOverflowRect().Contains(GetCaretRect())) { - frame->SchedulePaint(); - } + if (frame && !frame->GetVisualOverflowRect().Contains(GetCaretRect())) + InvalidateRects(mCaretRect, GetHookRect(), frame); } void nsCaret::UpdateCaretPosition() @@ -614,9 +613,31 @@ nsresult nsCaret::PrimeTimer() return NS_OK; } +void nsCaret::InvalidateTextOverflowBlock() +{ + // If the nearest block has a potential 'text-overflow' marker then + // invalidate it. + if (mLastContent) { + nsIFrame* caretFrame = mLastContent->GetPrimaryFrame(); + if (caretFrame) { + nsIFrame* block = nsLayoutUtils::GetAsBlock(caretFrame) ? caretFrame : + nsLayoutUtils::FindNearestBlockAncestor(caretFrame); + if (block) { + const nsStyleTextReset* style = block->GetStyleTextReset(); + if (style->mTextOverflow.mLeft.mType != NS_STYLE_TEXT_OVERFLOW_CLIP || + style->mTextOverflow.mRight.mType != NS_STYLE_TEXT_OVERFLOW_CLIP) { + block->InvalidateOverflowRect(); + } + } + } + } +} + //----------------------------------------------------------------------------- void nsCaret::StartBlinking() { + InvalidateTextOverflowBlock(); + if (mReadOnly) { // Make sure the one draw command we use for a readonly caret isn't // done until the selection is set @@ -640,6 +661,8 @@ void nsCaret::StartBlinking() //----------------------------------------------------------------------------- void nsCaret::StopBlinking() { + InvalidateTextOverflowBlock(); + if (mDrawn) // erase the caret if necessary DrawCaret(true); @@ -698,7 +721,7 @@ nsCaret::DrawAtPositionWithHint(nsIDOMNode* aNode, } if (aInvalidate) - theFrame->SchedulePaint(); + InvalidateRects(mCaretRect, mHookRect, theFrame); return true; } @@ -1114,6 +1137,16 @@ nsCaret::UpdateCaretRects(nsIFrame* aFrame, int32_t aFrameOffset) return true; } +// static +void nsCaret::InvalidateRects(const nsRect &aRect, const nsRect &aHook, + nsIFrame *aFrame) +{ + NS_ASSERTION(aFrame, "Must have a frame to invalidate"); + nsRect rect; + rect.UnionRect(aRect, aHook); + aFrame->Invalidate(rect); +} + //----------------------------------------------------------------------------- /* static */ void nsCaret::CaretBlinkCallback(nsITimer *aTimer, void *aClosure) diff --git a/layout/base/nsCaret.h b/layout/base/nsCaret.h index c84eef9a5285a..b38974781b4e0 100644 --- a/layout/base/nsCaret.h +++ b/layout/base/nsCaret.h @@ -173,6 +173,10 @@ class nsCaret : public nsISelectionListener void StartBlinking(); void StopBlinking(); + // If the nearest block has a potential 'text-overflow' marker then + // invalidate it. + void InvalidateTextOverflowBlock(); + bool DrawAtPositionWithHint(nsIDOMNode* aNode, int32_t aOffset, nsFrameSelection::HINT aFrameHint, @@ -199,6 +203,8 @@ class nsCaret : public nsISelectionListener void DrawCaret(bool aInvalidate); void DrawCaretAfterBriefDelay(); bool UpdateCaretRects(nsIFrame* aFrame, int32_t aFrameOffset); + static void InvalidateRects(const nsRect &aRect, const nsRect &aHook, + nsIFrame *aFrame); nsRect GetHookRect() { #ifdef IBMBIDI diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 487d3e7d63b04..5df3cf10dc009 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -28,7 +28,6 @@ #include "nsLayoutUtils.h" #include "nsIScrollableFrame.h" #include "nsThemeConstants.h" -#include "LayerTreeInvalidation.h" #include "imgIContainer.h" #include "nsIInterfaceRequestorUtils.h" @@ -970,13 +969,10 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, "Must call ComputeVisibility before calling Paint"); nsRefPtr layerManager; - bool widgetTransaction = false; bool allowRetaining = false; bool doBeginTransaction = true; - nsIView *view = nullptr; if (aFlags & PAINT_USE_WIDGET_LAYERS) { nsIFrame* rootReferenceFrame = aBuilder->RootReferenceFrame(); - view = rootReferenceFrame->GetView(); NS_ASSERTION(rootReferenceFrame == nsLayoutUtils::GetDisplayRootFrame(rootReferenceFrame), "Reference frame must be a display root for us to use the layer manager"); nsIWidget* window = rootReferenceFrame->GetNearestWidget(); @@ -984,8 +980,6 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, layerManager = window->GetLayerManager(&allowRetaining); if (layerManager) { doBeginTransaction = !(aFlags & PAINT_EXISTING_TRANSACTION); - FrameLayerBuilder::SetWidgetLayerManager(layerManager); - widgetTransaction = true; } } } @@ -1018,25 +1012,11 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, nsPresContext* presContext = aForFrame->PresContext(); nsIPresShell* presShell = presContext->GetPresShell(); - NotifySubDocInvalidationFunc computeInvalidFunc = - presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0; - bool computeInvalidRect = (computeInvalidFunc || - (layerManager->GetBackendType() == LAYERS_BASIC)) && - widgetTransaction; - - nsAutoPtr props(computeInvalidRect ? - LayerProperties::CloneFrom(layerManager->GetRoot()) : - nullptr); - nsDisplayItem::ContainerParameters containerParameters (presShell->GetXResolution(), presShell->GetYResolution()); nsRefPtr root = layerBuilder-> BuildContainerLayerFor(aBuilder, layerManager, aForFrame, nullptr, *this, containerParameters, nullptr); - - if (widgetTransaction) { - aForFrame->ClearInvalidationStateBits(); - } if (!root) { layerManager->RemoveUserData(&gLayerManagerLayerBuilder); @@ -1082,34 +1062,12 @@ void nsDisplayList::PaintForFrame(nsDisplayListBuilder* aBuilder, } layerManager->SetRoot(root); - layerBuilder->WillEndTransaction(); + layerBuilder->WillEndTransaction(layerManager); bool temp = aBuilder->SetIsCompositingCheap(layerManager->IsCompositingCheap()); layerManager->EndTransaction(FrameLayerBuilder::DrawThebesLayer, aBuilder, (aFlags & PAINT_NO_COMPOSITE) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT); aBuilder->SetIsCompositingCheap(temp); - layerBuilder->DidEndTransaction(); - - nsIntRect invalid; - if (props) { - invalid = props->ComputeDifferences(root, computeInvalidFunc); - } else if (widgetTransaction) { - LayerProperties::ClearInvalidations(root); - } - - if (view) { - if (props) { - if (!invalid.IsEmpty()) { - nsRect rect(presContext->DevPixelsToAppUnits(invalid.x), - presContext->DevPixelsToAppUnits(invalid.y), - presContext->DevPixelsToAppUnits(invalid.width), - presContext->DevPixelsToAppUnits(invalid.height)); - view->GetViewManager()->InvalidateViewNoSuppression(view, rect); - presContext->NotifyInvalidation(invalid, 0); - } - } else { - view->GetViewManager()->InvalidateView(view); - } - } + layerBuilder->DidEndTransaction(layerManager); if (aFlags & PAINT_FLUSH_LAYERS) { FrameLayerBuilder::InvalidateAllLayers(layerManager); @@ -1904,7 +1862,7 @@ nsDisplayBackground::GetOpaqueRegion(nsDisplayListBuilder* aBuilder, // theme background overrides any other background if (mIsThemed) { if (mThemeTransparency == nsITheme::eOpaque) { - result = nsRect(ToReferenceFrame(), mFrame->GetSize()); + result = GetBounds(aBuilder, aSnap); } return result; } @@ -2003,36 +1961,6 @@ nsDisplayBackground::IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuild nsLayoutUtils::IsProperAncestorFrame(aFrame, mFrame)); } -bool -nsDisplayBackground::RenderingMightDependOnFrameSize() -{ - // theme background overrides any other background and we don't know what to do here - if (mIsThemed) - return true; - - // We could be smarter with rounded corners and only invalidate the new area + the piece that was previously - // clipped out. - nscoord radii[8]; - if (mFrame->GetBorderRadii(radii)) - return true; - - nsPresContext* presContext = mFrame->PresContext(); - nsStyleContext *bgSC; - bool hasBG = - nsCSSRendering::FindBackground(presContext, mFrame, &bgSC); - if (!hasBG) - return false; - const nsStyleBackground* bg = bgSC->GetStyleBackground(); - - NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) { - const nsStyleBackground::Layer &layer = bg->mLayers[i]; - if (layer.RenderingMightDependOnFrameSize()) { - return true; - } - } - return false; -} - bool nsDisplayBackground::ShouldFixToViewport(nsDisplayListBuilder* aBuilder) { @@ -2056,28 +1984,6 @@ nsDisplayBackground::Paint(nsDisplayListBuilder* aBuilder, flags, nullptr, mLayer); } -void nsDisplayBackground::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) -{ - const nsDisplayBackgroundGeometry* geometry = static_cast(aGeometry); - if (ShouldFixToViewport(aBuilder)) { - // This is incorrect, We definitely need to check more things here. - return; - } - - bool snap; - if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || - !geometry->mPaddingRect.IsEqualInterior(GetPaddingRect()) || - !geometry->mContentRect.IsEqualInterior(GetContentRect())) { - if (!RenderingMightDependOnFrameSize() && geometry->mBounds.TopLeft() == GetBounds(aBuilder, &snap).TopLeft()) { - aInvalidRegion->Xor(GetBounds(aBuilder, &snap), geometry->mBounds); - } else { - aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds); - } - } -} - nsRect nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { nsRect r(nsPoint(0,0), mFrame->GetSize()); @@ -2087,10 +1993,6 @@ nsDisplayBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { presContext->GetTheme()-> GetWidgetOverflow(presContext->DeviceContext(), mFrame, mFrame->GetStyleDisplay()->mAppearance, &r); -#ifdef XP_MACOSX - // Bug 748219 - r.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel()); -#endif } *aSnap = true; @@ -2192,29 +2094,7 @@ nsDisplayBorder::ComputeVisibility(nsDisplayListBuilder* aBuilder, return true; } - -nsDisplayItemGeometry* -nsDisplayBorder::AllocateGeometry(nsDisplayListBuilder* aBuilder) -{ - return new nsDisplayBorderGeometry(this, aBuilder); -} -void -nsDisplayBorder::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) -{ - const nsDisplayBorderGeometry* geometry = static_cast(aGeometry); - bool snap; - if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || - !geometry->mContentRect.IsEqualInterior(GetContentRect())) { - // We can probably get away with only invalidating the difference - // between the border and padding rects, but the XUL ui at least - // is apparently painting a background with this? - aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds); - } -} - void nsDisplayBorder::Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { @@ -2638,10 +2518,8 @@ bool nsDisplayOpacity::TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* a } nsDisplayOwnLayer::nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, - nsIFrame* aFrame, nsDisplayList* aList, - uint32_t aFlags) - : nsDisplayWrapList(aBuilder, aFrame, aList) - , mFlags(aFlags) { + nsIFrame* aFrame, nsDisplayList* aList) + : nsDisplayWrapList(aBuilder, aFrame, aList) { MOZ_COUNT_CTOR(nsDisplayOwnLayer); } @@ -2659,12 +2537,6 @@ nsDisplayOwnLayer::BuildLayer(nsDisplayListBuilder* aBuilder, nsRefPtr layer = aManager->GetLayerBuilder()-> BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList, aContainerParameters, nullptr); - - if (mFlags & GENERATE_SUBDOC_INVALIDATIONS) { - ContainerLayerPresContext* pres = new ContainerLayerPresContext; - pres->mPresContext = mFrame->PresContext(); - layer->SetUserData(&gNotifySubDocInvalidationData, pres); - } return layer.forget(); } @@ -3127,10 +2999,9 @@ bool nsDisplayClipRoundedRect::TryMerge(nsDisplayListBuilder* aBuilder, nsDispla nsDisplayZoom::nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, - int32_t aAPD, int32_t aParentAPD, - uint32_t aFlags) - : nsDisplayOwnLayer(aBuilder, aFrame, aList, aFlags) - , mAPD(aAPD), mParentAPD(aParentAPD) { + int32_t aAPD, int32_t aParentAPD) + : nsDisplayOwnLayer(aBuilder, aFrame, aList), mAPD(aAPD), + mParentAPD(aParentAPD) { MOZ_COUNT_CTOR(nsDisplayZoom); } diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index 13ea4b78df282..6261ab91d7f7f 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -25,7 +25,6 @@ #include "FrameLayerBuilder.h" #include "nsThemeConstants.h" #include "nsLayoutUtils.h" -#include "nsDisplayListInvalidation.h" #include "mozilla/StandardInteger.h" @@ -760,72 +759,6 @@ class nsDisplayItem : public nsDisplayItemLink { *aSnap = false; return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize()); } - nsRect GetBorderRect() { - return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize()); - } - nsRect GetPaddingRect() { - return GetUnderlyingFrame()->GetPaddingRectRelativeToSelf() + ToReferenceFrame(); - } - nsRect GetContentRect() { - return GetUnderlyingFrame()->GetContentRectRelativeToSelf() + ToReferenceFrame(); - } - - /** - * Checks if the frame(s) owning this display item have been marked as invalid, - * and needing repainting. - */ - virtual bool IsInvalid(nsRect& aRect) { - bool result = mFrame ? mFrame->IsInvalid(aRect) : false; - aRect += ToReferenceFrame(); - return result; - } - - /** - * Creates and initializes an nsDisplayItemGeometry object that retains the current - * areas covered by this display item. These need to retain enough information - * such that they can be compared against a future nsDisplayItem of the same type, - * and determine if repainting needs to happen. - * - * Subclasses wishing to store more information need to override both this - * and ComputeInvalidationRegion, as well as implementing an nsDisplayItemGeometry - * subclass. - * - * The default implementation tracks both the display item bounds, and the frame's - * border rect. - */ - virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) - { - return new nsDisplayItemGenericGeometry(this, aBuilder); - } - - /** - * Compares an nsDisplayItemGeometry object from a previous paint against the - * current item. Computes if the geometry of the item has changed, and the - * invalidation area required for correct repainting. - * - * The existing geometry will have been created from a display item with a - * matching GetPerFrameKey()/mFrame pair to the current item. - * - * The default implementation compares the display item bounds, and the frame's - * border rect, and invalidates the entire bounds if either rect changes. - * - * @param aGeometry The geometry of the matching display item from the - * previous paint. - * @param aInvalidRegion Output param, the region to invalidate, or - * unchanged if none. - */ - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) - { - const nsDisplayItemGenericGeometry* geometry = static_cast(aGeometry); - bool snap; - if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || - !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) { - aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds); - } - } - /** * @param aSnap set to true if the edges of the rectangles of the opaque * region would be snapped to device pixels when drawing @@ -1674,12 +1607,6 @@ class nsDisplayBorder : public nsDisplayItem { nsRegion* aVisibleRegion, const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; NS_DISPLAY_DECL_NAME("Border", TYPE_BORDER) - - virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder); - - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion); }; /** @@ -1782,22 +1709,6 @@ class nsDisplayBackground : public nsDisplayItem { // Returns the value of GetUnderlyingFrame()->IsThemed(), but cached bool IsThemed() { return mIsThemed; } - /** - * Returns true if existing rendered pixels of this display item may need - * to be redrawn if the frame size changes. - * If false, only the changed area needs to be redrawn. - */ - bool RenderingMightDependOnFrameSize(); - - virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) - { - return new nsDisplayBackgroundGeometry(this, aBuilder); - } - - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion); - protected: typedef class mozilla::layers::ImageContainer ImageContainer; typedef class mozilla::layers::ImageLayer ImageLayer; @@ -1845,21 +1756,6 @@ class nsDisplayBoxShadowOuter : public nsDisplayItem { nsRegion* aVisibleRegion, const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; NS_DISPLAY_DECL_NAME("BoxShadowOuter", TYPE_BOX_SHADOW_OUTER) - - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) - { - const nsDisplayItemGenericGeometry* geometry = static_cast(aGeometry); - bool snap; - if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || - !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) { - nsRegion oldShadow, newShadow; - oldShadow = oldShadow.Sub(geometry->mBounds, geometry->mBorderRect); - newShadow = newShadow.Sub(GetBounds(aBuilder, &snap), GetBorderRect()); - aInvalidRegion->Or(oldShadow, newShadow); - } - } private: nsRegion mVisibleRegion; @@ -1885,24 +1781,6 @@ class nsDisplayBoxShadowInner : public nsDisplayItem { nsRegion* aVisibleRegion, const nsRect& aAllowVisibleRegionExpansion) MOZ_OVERRIDE; NS_DISPLAY_DECL_NAME("BoxShadowInner", TYPE_BOX_SHADOW_INNER) - - virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) - { - return new nsDisplayBoxShadowInnerGeometry(this, aBuilder); - } - - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) - { - const nsDisplayBoxShadowInnerGeometry* geometry = static_cast(aGeometry); - if (!geometry->mPaddingRect.IsEqualInterior(GetPaddingRect())) { - // nsDisplayBoxShadowInner is based around the padding rect, but it can - // touch pixels outside of this. We should invalidate the entire bounds. - bool snap; - aInvalidRegion->Or(geometry->mBounds, GetBounds(aBuilder, &snap)); - } - } private: nsRegion mVisibleRegion; @@ -2009,22 +1887,6 @@ class nsDisplayWrapList : public nsDisplayItem { { aFrames->AppendElements(mMergedFrames); } - virtual bool IsInvalid(nsRect& aRect) - { - if (mFrame->IsInvalid(aRect) && aRect.IsEmpty()) { - return true; - } - nsRect temp; - for (uint32_t i = 0; i < mMergedFrames.Length(); i++) { - if (mMergedFrames[i]->IsInvalid(temp) && temp.IsEmpty()) { - aRect.SetEmpty(); - return true; - } - aRect = aRect.Union(temp); - } - aRect += ToReferenceFrame(); - return !aRect.IsEmpty(); - } NS_DISPLAY_DECL_NAME("WrapList", TYPE_WRAP_LIST) virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder); @@ -2137,21 +1999,8 @@ class nsDisplayOpacity : public nsDisplayWrapList { */ class nsDisplayOwnLayer : public nsDisplayWrapList { public: - - /** - * nsDisplayOwnLayer constructor flags - */ - enum { - GENERATE_SUBDOC_INVALIDATIONS = 0x01 - }; - - /** - * @param aFlags GENERATE_SUBDOC_INVALIDATIONS : - * Add UserData to the created ContainerLayer, so that invalidations - * for this layer are send to our nsPresContext. - */ nsDisplayOwnLayer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, - nsDisplayList* aList, uint32_t aFlags = 0); + nsDisplayList* aList); #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayOwnLayer(); #endif @@ -2171,8 +2020,6 @@ class nsDisplayOwnLayer : public nsDisplayWrapList { return false; } NS_DISPLAY_DECL_NAME("OwnLayer", TYPE_OWN_LAYER) -private: - uint32_t mFlags; }; /** @@ -2406,14 +2253,10 @@ class nsDisplayZoom : public nsDisplayOwnLayer { * @param aAPD is the app units per dev pixel ratio of the subdocument. * @param aParentAPD is the app units per dev pixel ratio of the parent * document. - * @param aFlags GENERATE_SUBDOC_INVALIDATIONS : - * Add UserData to the created ContainerLayer, so that invalidations - * for this layer are send to our nsPresContext. */ nsDisplayZoom(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsDisplayList* aList, - int32_t aAPD, int32_t aParentAPD, - uint32_t aFlags = 0); + int32_t aAPD, int32_t aParentAPD); #ifdef NS_BUILD_REFCNT_LOGGING virtual ~nsDisplayZoom(); #endif @@ -2733,17 +2576,4 @@ class nsCharClipDisplayItem : public nsDisplayItem { nscoord mRightEdge; // length from the right side }; -class nsDisplayImageContainer : public nsDisplayItem { -public: - typedef mozilla::layers::ImageContainer ImageContainer; - typedef mozilla::layers::ImageLayer ImageLayer; - - nsDisplayImageContainer(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) - : nsDisplayItem(aBuilder, aFrame) - {} - - virtual already_AddRefed GetContainer() = 0; - virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) = 0; -}; - #endif /*NSDISPLAYLIST_H_*/ diff --git a/layout/base/nsDisplayListInvalidation.cpp b/layout/base/nsDisplayListInvalidation.cpp deleted file mode 100644 index d6a89976a28ad..0000000000000 --- a/layout/base/nsDisplayListInvalidation.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsDisplayListInvalidation.h" -#include "nsDisplayList.h" - -nsDisplayItemGeometry::nsDisplayItemGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) -{ - MOZ_COUNT_CTOR(nsDisplayItemGeometry); - bool snap; - mBounds = aItem->GetBounds(aBuilder, &snap); -} - -nsDisplayItemGeometry::~nsDisplayItemGeometry() -{ - MOZ_COUNT_DTOR(nsDisplayItemGeometry); -} - -nsDisplayItemGenericGeometry::nsDisplayItemGenericGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) - : nsDisplayItemGeometry(aItem, aBuilder) - , mBorderRect(aItem->GetBorderRect()) -{} - -void -nsDisplayItemGenericGeometry::MoveBy(const nsPoint& aOffset) -{ - mBounds.MoveBy(aOffset); - mBorderRect.MoveBy(aOffset); -} - -nsDisplayBorderGeometry::nsDisplayBorderGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) - : nsDisplayItemGeometry(aItem, aBuilder) - , mContentRect(aItem->GetContentRect()) -{} - -void -nsDisplayBorderGeometry::MoveBy(const nsPoint& aOffset) -{ - mBounds.MoveBy(aOffset); - mContentRect.MoveBy(aOffset); -} - -nsDisplayBackgroundGeometry::nsDisplayBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) - : nsDisplayItemGeometry(aItem, aBuilder) - , mPaddingRect(aItem->GetPaddingRect()) - , mContentRect(aItem->GetContentRect()) -{} - -void -nsDisplayBackgroundGeometry::MoveBy(const nsPoint& aOffset) -{ - mBounds.MoveBy(aOffset); - mPaddingRect.MoveBy(aOffset); - mContentRect.MoveBy(aOffset); -} - -nsDisplayBoxShadowInnerGeometry::nsDisplayBoxShadowInnerGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) - : nsDisplayItemGeometry(aItem, aBuilder) - , mPaddingRect(aItem->GetPaddingRect()) -{} - -void -nsDisplayBoxShadowInnerGeometry::MoveBy(const nsPoint& aOffset) -{ - mBounds.MoveBy(aOffset); - mPaddingRect.MoveBy(aOffset); -} - diff --git a/layout/base/nsDisplayListInvalidation.h b/layout/base/nsDisplayListInvalidation.h deleted file mode 100644 index f9275c400ccdb..0000000000000 --- a/layout/base/nsDisplayListInvalidation.h +++ /dev/null @@ -1,96 +0,0 @@ -/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef NSDISPLAYLISTINVALIDATION_H_ -#define NSDISPLAYLISTINVALIDATION_H_ - -#include "nsRect.h" - -class nsDisplayItem; -class nsDisplayListBuilder; - -/** - * This stores the geometry of an nsDisplayItem, and the area - * that will be affected when painting the item. - * - * It is used to retain information about display items so they - * can be compared against new display items in the next paint. - */ -class nsDisplayItemGeometry -{ -public: - nsDisplayItemGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); - virtual ~nsDisplayItemGeometry(); - - /** - * Compute the area required to be invalidated if this - * display item is removed. - */ - const nsRect& ComputeInvalidationRegion() { return mBounds; } - - /** - * Shifts all retained areas of the nsDisplayItemGeometry by the given offset. - * - * This is used to compensate for scrolling, since the destination buffer - * can scroll without requiring a full repaint. - * - * @param aOffset Offset to shift by. - */ - virtual void MoveBy(const nsPoint& aOffset) = 0; - - /** - * Bounds of the display item - */ - nsRect mBounds; -}; - -/** - * A default geometry implementation, used by nsDisplayItem. Retains - * and compares the bounds, and border rect. - * - * This should be sufficient for the majority of display items. - */ -class nsDisplayItemGenericGeometry : public nsDisplayItemGeometry -{ -public: - nsDisplayItemGenericGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); - - virtual void MoveBy(const nsPoint& aOffset); - - nsRect mBorderRect; -}; - -class nsDisplayBorderGeometry : public nsDisplayItemGeometry -{ -public: - nsDisplayBorderGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); - - virtual void MoveBy(const nsPoint& aOffset); - - nsRect mContentRect; -}; - -class nsDisplayBackgroundGeometry : public nsDisplayItemGeometry -{ -public: - nsDisplayBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); - - virtual void MoveBy(const nsPoint& aOffset); - - nsRect mPaddingRect; - nsRect mContentRect; -}; - -class nsDisplayBoxShadowInnerGeometry : public nsDisplayItemGeometry -{ -public: - nsDisplayBoxShadowInnerGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); - - virtual void MoveBy(const nsPoint& aOffset); - - nsRect mPaddingRect; -}; - -#endif /*NSDISPLAYLISTINVALIDATION_H_*/ diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 6f97561791c82..c2d670d7a6cc0 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -2906,7 +2906,8 @@ DocumentViewerImpl::SetFullZoom(float aFullZoom) nsIFrame* rootFrame = shell->GetRootFrame(); if (rootFrame) { - rootFrame->InvalidateFrame(); + nsRect rect(nsPoint(0, 0), rootFrame->GetSize()); + rootFrame->Invalidate(rect); } return NS_OK; } diff --git a/layout/base/nsFrameManager.cpp b/layout/base/nsFrameManager.cpp index 9aaa58b2a0935..5f0234b4e3089 100644 --- a/layout/base/nsFrameManager.cpp +++ b/layout/base/nsFrameManager.cpp @@ -467,7 +467,8 @@ nsFrameManager::InsertFrames(nsIFrame* aParentFrame, nsresult nsFrameManager::RemoveFrame(ChildListID aListID, - nsIFrame* aOldFrame) + nsIFrame* aOldFrame, + bool aInvalidate /* = true */) { bool wasDestroyingFrames = mIsDestroyingFrames; mIsDestroyingFrames = true; @@ -478,7 +479,9 @@ nsFrameManager::RemoveFrame(ChildListID aListID, // that doesn't change the size of the parent.) // This has to sure to invalidate the entire overflow rect; this // is important in the presence of absolute positioning - aOldFrame->InvalidateFrameForRemoval(); + if (aInvalidate) { + aOldFrame->InvalidateFrameSubtree(); + } NS_ASSERTION(!aOldFrame->GetPrevContinuation() || // exception for nsCSSFrameConstructor::RemoveFloatingFirstLetterFrames diff --git a/layout/base/nsFrameManager.h b/layout/base/nsFrameManager.h index 8e46b54571701..a23083e89cd54 100644 --- a/layout/base/nsFrameManager.h +++ b/layout/base/nsFrameManager.h @@ -95,7 +95,8 @@ class nsFrameManager : public nsFrameManagerBase nsFrameList& aFrameList); NS_HIDDEN_(nsresult) RemoveFrame(ChildListID aListID, - nsIFrame* aOldFrame); + nsIFrame* aOldFrame, + bool aInvalidate = true); /* * Notification that a frame is about to be destroyed. This allows any diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 065c2ecd00a02..4559c42d5f1b4 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -1239,11 +1239,6 @@ class nsIPresShell : public nsIPresShell_base * root pres shell. */ virtual void DidPaint() = 0; - - /** - * Ensures that the refresh driver is running, and schedules a view - * manager flush on the next tick. - */ virtual void ScheduleViewManagerFlush() = 0; virtual void ClearMouseCaptureOnView(nsIView* aView) = 0; virtual bool IsVisible() = 0; @@ -1271,10 +1266,6 @@ class nsIPresShell : public nsIPresShell_base return mFontSizeInflationLineThreshold; } - virtual void AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver) = 0; - - void InvalidatePresShellIfHidden(); - /** * Refresh observer management. */ @@ -1355,7 +1346,6 @@ class nsIPresShell : public nsIPresShell_base // GetRootFrame() can be inlined: nsFrameManagerBase* mFrameManager; nsWeakPtr mForwardingContainer; - nsRefreshDriver* mHiddenInvalidationObserverRefreshDriver; #ifdef ACCESSIBILITY DocAccessible* mAccDocument; #endif diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 714e5f33b6e5c..1c52f9e610975 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -4001,15 +4001,10 @@ nsLayoutUtils::IsPopup(nsIFrame* aFrame) /* static */ nsIFrame* nsLayoutUtils::GetDisplayRootFrame(nsIFrame* aFrame) { - // We could use GetRootPresContext() here if the - // NS_FRAME_IN_POPUP frame bit is set. nsIFrame* f = aFrame; for (;;) { - if (!f->HasAnyStateBits(NS_FRAME_IN_POPUP)) { - f = f->PresContext()->FrameManager()->GetRootFrame(); - } else if (IsPopup(f)) { + if (IsPopup(f)) return f; - } nsIFrame* parent = GetCrossDocParentFrame(f); if (!parent) return f; diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 034f0b5507a31..769469e43f09c 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -88,8 +88,6 @@ using namespace mozilla; using namespace mozilla::dom; -uint8_t gNotifySubDocInvalidationData; - namespace { class CharSetChangingRunnable : public nsRunnable @@ -131,22 +129,6 @@ nsPresContext::MakeColorPref(const nsString& aColor) : NS_RGB(0, 0, 0); } -bool -nsPresContext::IsDOMPaintEventPending() -{ - if (!mInvalidateRequests.mRequests.IsEmpty()) { - return true; - } - if (GetDisplayRootPresContext()->GetRootPresContext()->mRefreshDriver->ViewManagerFlushIsPending()) { - // Since we're promising that there will be a MozAfterPaint event - // fired, we record an empty invalidation in case display list - // invalidation doesn't invalidate anything further. - NotifyInvalidation(nsRect(0, 0, 0, 0), 0); - return true; - } - return false; -} - int nsPresContext::PrefChangedCallback(const char* aPrefName, void* instance_data) { @@ -194,8 +176,7 @@ nsPresContext::nsPresContext(nsIDocument* aDocument, nsPresContextType aType) mTextZoom(1.0), mFullZoom(1.0), mLastFontInflationScreenWidth(-1.0), mPageSize(-1, -1), mPPScale(1.0f), mViewportStyleOverflow(NS_STYLE_OVERFLOW_AUTO, NS_STYLE_OVERFLOW_AUTO), - mImageAnimationModePref(imgIContainer::kNormalAnimMode), - mAllInvalidated(false) + mImageAnimationModePref(imgIContainer::kNormalAnimMode) { // NOTE! nsPresContext::operator new() zeroes out all members, so don't // bother initializing members to 0. @@ -795,7 +776,7 @@ nsPresContext::InvalidateThebesLayers() // FrameLayerBuilder caches invalidation-related values that depend on the // appunits-per-dev-pixel ratio, so ensure that all ThebesLayer drawing // is completely flushed. - rootFrame->InvalidateFrameSubtree(); + FrameLayerBuilder::InvalidateThebesLayersInSubtreeWithUntrustedFrameGeometry(rootFrame); } } @@ -1987,14 +1968,29 @@ nsPresContext::FireDOMPaintEvent() nsCOMPtr dispatchTarget = do_QueryInterface(ourWindow); nsCOMPtr eventTarget = dispatchTarget; - if (!IsChrome() && !mSendAfterPaintToContent) { - // Don't tell the window about this event, it should not know that - // something happened in a subdocument. Tell only the chrome event handler. - // (Events sent to the window get propagated to the chrome event handler - // automatically.) - dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget()); - if (!dispatchTarget) { - return; + if (!IsChrome()) { + bool notifyContent = mSendAfterPaintToContent; + + if (notifyContent) { + // If the pref is set, we still don't post events when they're + // entirely cross-doc. + notifyContent = false; + for (uint32_t i = 0; i < mInvalidateRequests.mRequests.Length(); ++i) { + if (!(mInvalidateRequests.mRequests[i].mFlags & + nsIFrame::INVALIDATE_CROSS_DOC)) { + notifyContent = true; + } + } + } + if (!notifyContent) { + // Don't tell the window about this event, it should not know that + // something happened in a subdocument. Tell only the chrome event handler. + // (Events sent to the window get propagated to the chrome event handler + // automatically.) + dispatchTarget = do_QueryInterface(ourWindow->GetParentTarget()); + if (!dispatchTarget) { + return; + } } } // Events sent to the window get propagated to the chrome event handler @@ -2006,7 +2002,6 @@ nsPresContext::FireDOMPaintEvent() NS_NewDOMNotifyPaintEvent(getter_AddRefs(event), this, nullptr, NS_AFTERPAINT, &mInvalidateRequests); - mAllInvalidated = false; if (!event) { return; } @@ -2019,24 +2014,6 @@ nsPresContext::FireDOMPaintEvent() nsEventDispatcher::DispatchDOMEvent(dispatchTarget, nullptr, event, this, nullptr); } -static bool -MayHavePaintEventListenerSubdocumentCallback(nsIDocument* aDocument, void* aData) -{ - bool *result = static_cast(aData); - nsIPresShell* shell = aDocument->GetShell(); - if (shell) { - nsPresContext* pc = shell->GetPresContext(); - if (pc) { - *result = pc->MayHavePaintEventListenerInSubDocument(); - - // If we found a paint event listener, then we can stop enumerating - // sub documents. - return !*result; - } - } - return true; -} - static bool MayHavePaintEventListener(nsPIDOMWindow* aInnerWindow) { @@ -2088,36 +2065,6 @@ nsPresContext::MayHavePaintEventListener() return ::MayHavePaintEventListener(mDocument->GetInnerWindow()); } -bool -nsPresContext::MayHavePaintEventListenerInSubDocument() -{ - if (MayHavePaintEventListener()) { - return true; - } - - bool result = false; - mDocument->EnumerateSubDocuments(MayHavePaintEventListenerSubdocumentCallback, &result); - return result; -} - -void -nsPresContext::NotifyInvalidation(uint32_t aFlags) -{ - nsIFrame* rootFrame = PresShell()->FrameManager()->GetRootFrame(); - NotifyInvalidation(rootFrame->GetVisualOverflowRect(), aFlags); - mAllInvalidated = true; -} - -void -nsPresContext::NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags) -{ - nsRect rect(DevPixelsToAppUnits(aRect.x), - DevPixelsToAppUnits(aRect.y), - DevPixelsToAppUnits(aRect.width), - DevPixelsToAppUnits(aRect.height)); - NotifyInvalidation(rect, aFlags); -} - void nsPresContext::NotifyInvalidation(const nsRect& aRect, uint32_t aFlags) { @@ -2126,10 +2073,8 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, uint32_t aFlags) // MayHavePaintEventListener is pretty cheap and we could make it // even cheaper by providing a more efficient // nsPIDOMWindow::GetListenerManager. - - if (mAllInvalidated) { + if (aRect.IsEmpty() || !MayHavePaintEventListener()) return; - } nsPresContext* pc; for (pc = this; pc; pc = pc->GetParentPresContext()) { @@ -2153,30 +2098,6 @@ nsPresContext::NotifyInvalidation(const nsRect& aRect, uint32_t aFlags) request->mFlags = aFlags; } -/* static */ void -nsPresContext::NotifySubDocInvalidation(ContainerLayer* aContainer, - const nsIntRegion& aRegion) -{ - ContainerLayerPresContext *data = - static_cast( - aContainer->GetUserData(&gNotifySubDocInvalidationData)); - if (!data) { - return; - } - - nsIntPoint topLeft = aContainer->GetVisibleRegion().GetBounds().TopLeft(); - - nsIntRegionRectIterator iter(aRegion); - while (const nsIntRect* r = iter.Next()) { - nsIntRect rect = *r; - //PresContext coordinate space is relative to the start of our visible - // region. Is this really true? This feels like the wrong way to get the right - // answer. - rect.MoveBy(-topLeft); - data->mPresContext->NotifyInvalidation(rect, 0); - } -} - static bool NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData) { @@ -2193,18 +2114,19 @@ NotifyDidPaintSubdocumentCallback(nsIDocument* aDocument, void* aData) void nsPresContext::NotifyDidPaintForSubtree() { - if (IsRoot()) { - if (!mFireAfterPaintEvents) - return; + if (!mFireAfterPaintEvents) + return; + mFireAfterPaintEvents = false; + if (IsRoot()) { static_cast(this)->CancelDidPaintTimer(); } - mFireAfterPaintEvents = false; - - nsCOMPtr ev = - NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent); - nsContentUtils::AddScriptRunner(ev); + if (!mInvalidateRequests.mRequests.IsEmpty()) { + nsCOMPtr ev = + NS_NewRunnableMethod(this, &nsPresContext::FireDOMPaintEvent); + nsContentUtils::AddScriptRunner(ev); + } mDocument->EnumerateSubDocuments(NotifyDidPaintSubdocumentCallback, nullptr); } diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index f9e9623602989..b57ce35592b3b 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -32,7 +32,6 @@ #include "nsIWidget.h" #include "mozilla/TimeStamp.h" #include "prclist.h" -#include "Layers.h" #ifdef IBMBIDI class nsBidiPresUtils; @@ -113,17 +112,6 @@ class nsInvalidateRequestList { nsTArray mRequests; }; -/** - * Layer UserData for ContainerLayers that want to be notified - * of local invalidations of them and their descendant layers. - * Pass a callback to ComputeDifferences to have these called. - */ -class ContainerLayerPresContext : public mozilla::layers::LayerUserData { -public: - nsPresContext* mPresContext; -}; -extern uint8_t gNotifySubDocInvalidationData; - /* Used by nsPresContext::HasAuthorSpecifiedRules */ #define NS_AUTHOR_SPECIFIED_BACKGROUND (1 << 0) #define NS_AUTHOR_SPECIFIED_BORDER (1 << 1) @@ -805,21 +793,15 @@ class nsPresContext : public nsIObserver { // Returns true on success and false on failure (not safe). bool EnsureSafeToHandOutCSSRules(); - void NotifyInvalidation(uint32_t aFlags); void NotifyInvalidation(const nsRect& aRect, uint32_t aFlags); - // aRect is in device pixels - void NotifyInvalidation(const nsIntRect& aRect, uint32_t aFlags); void NotifyDidPaintForSubtree(); void FireDOMPaintEvent(); - // Callback for catching invalidations in ContainerLayers - // Passed to LayerProperties::ComputeDifference - static void NotifySubDocInvalidation(mozilla::layers::ContainerLayer* aContainer, - const nsIntRegion& aRegion); - bool IsDOMPaintEventPending(); + bool IsDOMPaintEventPending() { + return !mInvalidateRequests.mRequests.IsEmpty(); + } void ClearMozAfterPaintEvents() { mInvalidateRequests.mRequests.Clear(); - mAllInvalidated = false; } bool IsProcessingRestyles() const { @@ -1021,22 +1003,12 @@ class nsPresContext : public nsIObserver { public: void DoChangeCharSet(const nsCString& aCharSet); - /** - * Checks for MozAfterPaint listeners on the document - */ - bool MayHavePaintEventListener(); - - /** - * Checks for MozAfterPaint listeners on the document and - * any subdocuments, except for subdocuments that are non-top-level - * content documents. - */ - bool MayHavePaintEventListenerInSubDocument(); - protected: void InvalidateThebesLayers(); void AppUnitsPerDevPixelChanged(); + bool MayHavePaintEventListener(); + void HandleRebuildUserFontSet() { mPostedFlushUserFontSet = false; FlushUserFontSet(); @@ -1168,7 +1140,6 @@ class nsPresContext : public nsIObserver { unsigned mPendingMediaFeatureValuesChanged : 1; unsigned mPrefChangePendingNeedsReflow : 1; unsigned mMayHaveFixedBackgroundFrames : 1; - unsigned mAllInvalidated : 1; // Are we currently drawing an SVG glyph? unsigned mIsGlyph : 1; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 7dc007ee61875..c6a1efbd5f97d 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -119,8 +119,6 @@ #endif #include "nsSMILAnimationController.h" #include "SVGContentUtils.h" -#include "nsSVGUtils.h" -#include "nsSVGEffects.h" #include "SVGFragmentIdentifier.h" #include "nsRefreshDriver.h" @@ -177,7 +175,6 @@ #include "mozilla/css/ImageLoader.h" #include "Layers.h" -#include "LayerTreeInvalidation.h" #include "nsAsyncDOMEvent.h" #define ANCHOR_SCROLL_FLAGS (SCROLL_OVERFLOW_HIDDEN | SCROLL_NO_PARENT_FRAMES) @@ -609,24 +606,6 @@ nsIPresShell::GetVerifyReflowEnable() #endif return gVerifyReflowEnabled; } - -void -PresShell::AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver) -{ - if (!mHiddenInvalidationObserverRefreshDriver && !mIsDestroying && !mHaveShutDown) { - aDriver->AddPresShellToInvalidateIfHidden(this); - mHiddenInvalidationObserverRefreshDriver = aDriver; - } -} - -void -nsIPresShell::InvalidatePresShellIfHidden() -{ - if (!IsVisible() && mPresContext) { - mPresContext->NotifyInvalidation(0); - } - mHiddenInvalidationObserverRefreshDriver = nullptr; -} void nsIPresShell::SetVerifyReflowEnable(bool aEnabled) @@ -1051,10 +1030,6 @@ PresShell::Destroy() // before we destroy the frame manager, since apparently frame destruction // sometimes spins the event queue when plug-ins are involved(!). rd->RemoveLayoutFlushObserver(this); - if (mHiddenInvalidationObserverRefreshDriver) { - mHiddenInvalidationObserverRefreshDriver->RemovePresShellToInvalidateIfHidden(this); - } - rd->RevokeViewManagerFlush(); mResizeEvent.Revoke(); @@ -3570,7 +3545,8 @@ PresShell::UnsuppressAndInvalidate() nsIFrame* rootFrame = mFrameConstructor->GetRootFrame(); if (rootFrame) { // let's assume that outline on a root frame is not supported - rootFrame->InvalidateFrame(); + nsRect rect(nsPoint(0, 0), rootFrame->GetSize()); + rootFrame->Invalidate(rect); if (mCaretEnabled && mCaret) { mCaret->CheckCaretDrawingState(); @@ -3972,7 +3948,7 @@ PresShell::DocumentStatesChanged(nsIDocument* aDocument, if (aStateMask.HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) { nsIFrame* root = mFrameConstructor->GetRootFrame(); if (root) { - FrameLayerBuilder::InvalidateAllLayersForFrame(root); + root->InvalidateFrameSubtree(); if (root->HasView()) { root->GetView()->SetForcedRepaint(true); } @@ -5259,45 +5235,17 @@ PresShell::Paint(nsIView* aViewToPaint, return; } NS_WARNING("Must complete empty transaction when compositing!"); - } else { + } else if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) { layerManager->BeginTransaction(); - } - - if (!(frame->GetStateBits() & NS_FRAME_UPDATE_LAYER_TREE)) { - NotifySubDocInvalidationFunc computeInvalidFunc = - presContext->MayHavePaintEventListenerInSubDocument() ? nsPresContext::NotifySubDocInvalidation : 0; - bool computeInvalidRect = computeInvalidFunc || - (layerManager->GetBackendType() == LAYERS_BASIC); - - nsAutoPtr props(computeInvalidRect ? - LayerProperties::CloneFrom(layerManager->GetRoot()) : - nullptr); - if (layerManager->EndEmptyTransaction((aType == PaintType_NoComposite) ? LayerManager::END_NO_COMPOSITE : LayerManager::END_DEFAULT)) { - nsIntRect invalid; - if (props) { - invalid = props->ComputeDifferences(layerManager->GetRoot(), computeInvalidFunc); - } else { - LayerProperties::ClearInvalidations(layerManager->GetRoot()); - } - if (!invalid.IsEmpty()) { - if (props) { - nsRect rect(presContext->DevPixelsToAppUnits(invalid.x), - presContext->DevPixelsToAppUnits(invalid.y), - presContext->DevPixelsToAppUnits(invalid.width), - presContext->DevPixelsToAppUnits(invalid.height)); - aViewToPaint->GetViewManager()->InvalidateViewNoSuppression(aViewToPaint, rect); - presContext->NotifyInvalidation(invalid, 0); - } else { - aViewToPaint->GetViewManager()->InvalidateView(aViewToPaint); - } - } - frame->UpdatePaintCountForPaintedPresShells(); presContext->NotifyDidPaintForSubtree(); return; } + } else { + layerManager->BeginTransaction(); } + frame->RemoveStateBits(NS_FRAME_UPDATE_LAYER_TREE); } else { layerManager->BeginTransaction(); @@ -6153,11 +6101,13 @@ PresShell::ShowEventTargetDebug() if (nsFrame::GetShowEventTargetFrameBorder() && GetCurrentEventFrame()) { if (mDrawEventTargetFrame) { - mDrawEventTargetFrame->InvalidateFrame(); + mDrawEventTargetFrame->Invalidate( + nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize())); } mDrawEventTargetFrame = mCurrentEventFrame; - mDrawEventTargetFrame->InvalidateFrame(); + mDrawEventTargetFrame->Invalidate( + nsRect(nsPoint(0, 0), mDrawEventTargetFrame->GetSize())); } } #endif @@ -7335,13 +7285,6 @@ PresShell::ScheduleReflowOffTimer() bool PresShell::DoReflow(nsIFrame* target, bool aInterruptible) { - target->SchedulePaint(); - nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(target); - while (parent) { - nsSVGEffects::InvalidateDirectRenderingObservers(parent); - parent = nsLayoutUtils::GetCrossDocParentFrame(parent); - } - nsAutoCString docURL("N/A"); nsIURI *uri = mDocument->GetDocumentURI(); if (uri) @@ -7373,6 +7316,11 @@ PresShell::DoReflow(nsIFrame* target, bool aInterruptible) nsSize size; if (target == rootFrame) { size = mPresContext->GetVisibleArea().Size(); + + // target->GetRect() has the old size of the frame, + // mPresContext->GetVisibleArea() has the new size. + target->InvalidateRectDifference(mPresContext->GetVisibleArea(), + target->GetRect()); } else { size = target->GetSize(); } diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index d44a3d9ea2a26..8217a243d6162 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -321,9 +321,6 @@ class PresShell : public nsIPresShell, size_t *aPresContextSize); size_t SizeOfTextRuns(nsMallocSizeOfFun aMallocSizeOf) const; - virtual void AddInvalidateHiddenPresShellObserver(nsRefreshDriver *aDriver); - - // This data is stored as a content property (nsGkAtoms::scrolling) on // mContentToScrollTo when we have a pending ScrollIntoView. struct ScrollIntoViewData { diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index d0fae4a595721..db68a11448301 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -100,11 +100,6 @@ nsRefreshDriver::~nsRefreshDriver() NS_ABORT_IF_FALSE(ObserverCount() == 0, "observers should have unregistered"); NS_ABORT_IF_FALSE(!mTimer, "timer should be gone"); - - for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) { - mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden(); - } - mPresShellsToInvalidateIfHidden.Clear(); } // Method for testing. See nsIDOMWindowUtils.advanceTimeAndRefresh @@ -417,11 +412,6 @@ nsRefreshDriver::Notify(nsITimer *aTimer) mRequests.EnumerateEntries(nsRefreshDriver::ImageRequestEnumerator, &parms); EnsureTimerStarted(false); } - - for (uint32_t i = 0; i < mPresShellsToInvalidateIfHidden.Length(); i++) { - mPresShellsToInvalidateIfHidden[i]->InvalidatePresShellIfHidden(); - } - mPresShellsToInvalidateIfHidden.Clear(); if (mViewManagerFlushIsPending) { #ifdef DEBUG_INVALIDATIONS diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h index 0347253bd869d..c750659d0c133 100644 --- a/layout/base/nsRefreshDriver.h +++ b/layout/base/nsRefreshDriver.h @@ -144,16 +144,6 @@ class nsRefreshDriver MOZ_FINAL : public nsITimerCallback { bool IsLayoutFlushObserver(nsIPresShell* aShell) { return mLayoutFlushObservers.Contains(aShell); } - bool AddPresShellToInvalidateIfHidden(nsIPresShell* aShell) { - NS_ASSERTION(!mPresShellsToInvalidateIfHidden.Contains(aShell), - "Double-adding style flush observer"); - bool appended = mPresShellsToInvalidateIfHidden.AppendElement(aShell) != nullptr; - EnsureTimerStarted(false); - return appended; - } - void RemovePresShellToInvalidateIfHidden(nsIPresShell* aShell) { - mPresShellsToInvalidateIfHidden.RemoveElement(aShell); - } /** * Remember whether our presshell's view manager needs a flush @@ -162,9 +152,6 @@ class nsRefreshDriver MOZ_FINAL : public nsITimerCallback { void RevokeViewManagerFlush() { mViewManagerFlushIsPending = false; } - bool ViewManagerFlushIsPending() { - return mViewManagerFlushIsPending; - } /** * Add a document for which we have nsIFrameRequestCallbacks @@ -268,7 +255,6 @@ class nsRefreshDriver MOZ_FINAL : public nsITimerCallback { nsAutoTArray mStyleFlushObservers; nsAutoTArray mLayoutFlushObservers; - nsAutoTArray mPresShellsToInvalidateIfHidden; // nsTArray on purpose, because we want to be able to swap. nsTArray mFrameRequestCallbackDocs; diff --git a/layout/base/tests/Makefile.in b/layout/base/tests/Makefile.in index 66f06d21ac573..5d2161b931adb 100644 --- a/layout/base/tests/Makefile.in +++ b/layout/base/tests/Makefile.in @@ -48,7 +48,6 @@ MOCHITEST_FILES = \ test_bug423523.html \ test_bug449781.html \ test_bug450930.xhtml \ - bug450930.xhtml \ test_bug458898.html \ test_bug465448.xul \ test_bug469170.html \ @@ -346,7 +345,7 @@ endif ifeq (,$(filter cocoa,$(MOZ_WIDGET_TOOLKIT))) # THESE TESTS (BELOW) DO NOT RUN ON MAC MOCHITEST_FILES += \ - $(warning test_flush_on_paint.html disabled due to random orange; see bug 539356) \ + test_flush_on_paint.html \ $(NULL) # THESE TESTS (ABOVE) DO NOT RUN ON MAC endif diff --git a/layout/base/tests/bug450930.xhtml b/layout/base/tests/bug450930.xhtml deleted file mode 100644 index 57a7e1f03f83d..0000000000000 --- a/layout/base/tests/bug450930.xhtml +++ /dev/null @@ -1,183 +0,0 @@ - - - - - Test for Bug 450930 (MozAfterPaint) - - - - -Mozilla Bug 450930 -
-
- - - - - - -
- - - -
-
-
- - - diff --git a/layout/base/tests/chrome/Makefile.in b/layout/base/tests/chrome/Makefile.in index 23f98a789349a..46b9ce6a45f4f 100644 --- a/layout/base/tests/chrome/Makefile.in +++ b/layout/base/tests/chrome/Makefile.in @@ -50,12 +50,9 @@ MOCHITEST_CHROME_FILES = \ $(NULL) ifdef MOZ_DEBUG -# Disabled on Mac because of Bug 748219 -ifneq (cocoa,$(MOZ_WIDGET_TOOLKIT)) MOCHITEST_CHROME_FILES += \ test_leaf_layers_partition_browser_window.xul \ $(NULL) endif -endif include $(topsrcdir)/config/rules.mk diff --git a/layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul b/layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul index 5828426f5ea4d..6ffcfa3eeb2b2 100644 --- a/layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul +++ b/layout/base/tests/chrome/test_leaf_layers_partition_browser_window.xul @@ -43,7 +43,7 @@ var initialCount = win.mozPaintCount; function nextStep() { - if (win.mozPaintCount == initialCount || win.isMozAfterPaintPending) { + if (win.mozPaintCount == initialCount) { SimpleTest.info("Waiting for mozPaintCount (= " + initialCount + ") to increase" + testInfo()); // Do not use SimpleTest.executeSoon() here: give a little more time. setTimeout(nextStep, 100); diff --git a/layout/base/tests/chrome/test_transformed_scrolling_repaints.html b/layout/base/tests/chrome/test_transformed_scrolling_repaints.html index ff0c3c48d5843..6db02c2c53fb9 100644 --- a/layout/base/tests/chrome/test_transformed_scrolling_repaints.html +++ b/layout/base/tests/chrome/test_transformed_scrolling_repaints.html @@ -33,7 +33,7 @@ waitForAllPaintsFlushed(function () { // Clear paint state now and scroll again. utils.checkAndClearPaintedState(e); - t.scrollTop = 15; + t.scrollTop = 33; waitForAllPaintsFlushed(function () { var painted = utils.checkAndClearPaintedState(e); if (isLinux && !is64) { diff --git a/layout/base/tests/chrome/test_transformed_scrolling_repaints_2.html b/layout/base/tests/chrome/test_transformed_scrolling_repaints_2.html index 9268cc5c05494..45eaac49c28ba 100644 --- a/layout/base/tests/chrome/test_transformed_scrolling_repaints_2.html +++ b/layout/base/tests/chrome/test_transformed_scrolling_repaints_2.html @@ -9,9 +9,9 @@
-
-
-
+
Hello
+
Kitty
+
Kitty
 
 
 
+Mozilla Bug 450930
+
+
+ + + + + + +
+
 
 
diff --git a/layout/forms/nsButtonFrameRenderer.cpp b/layout/forms/nsButtonFrameRenderer.cpp index 7bea461c81103..1c736cbb00f30 100644 --- a/layout/forms/nsButtonFrameRenderer.cpp +++ b/layout/forms/nsButtonFrameRenderer.cpp @@ -117,18 +117,11 @@ class nsDisplayButtonBorderBackground : public nsDisplayItem { } virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx); - virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap); NS_DISPLAY_DECL_NAME("ButtonBorderBackground", TYPE_BUTTON_BORDER_BACKGROUND) private: nsButtonFrameRenderer* mBFR; }; -nsRect -nsDisplayButtonBorderBackground::GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { - *aSnap = false; - return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); -} - class nsDisplayButtonForeground : public nsDisplayItem { public: nsDisplayButtonForeground(nsDisplayListBuilder* aBuilder, diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp index 232261fd90e55..7218747c85795 100644 --- a/layout/forms/nsComboboxControlFrame.cpp +++ b/layout/forms/nsComboboxControlFrame.cpp @@ -356,7 +356,7 @@ nsComboboxControlFrame::SetFocus(bool aOn, bool aRepaint) // This is needed on a temporary basis. It causes the focus // rect to be drawn. This is much faster than ReResolvingStyle // Bug 32920 - InvalidateFrame(); + Invalidate(nsRect(0,0,mRect.width,mRect.height)); } void diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp index cb8009981fc57..f968132731e97 100644 --- a/layout/forms/nsFieldSetFrame.cpp +++ b/layout/forms/nsFieldSetFrame.cpp @@ -584,7 +584,7 @@ nsFieldSetFrame::Reflow(nsPresContext* aPresContext, ConsiderChildOverflow(aDesiredSize.mOverflowAreas, mContentFrame); FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); - InvalidateFrame(); + Invalidate(aDesiredSize.VisualOverflow()); NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); return NS_OK; diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp index 799f736c5449d..2749435206fc2 100644 --- a/layout/forms/nsListControlFrame.cpp +++ b/layout/forms/nsListControlFrame.cpp @@ -256,7 +256,15 @@ nsListControlFrame::InvalidateFocus() nsIFrame* containerFrame = GetOptionsContainer(); if (containerFrame) { - containerFrame->InvalidateFrame(); + // Invalidating from the containerFrame because that's where our focus + // is drawn. + // The origin of the scrollport is the origin of containerFrame. + float inflation = nsLayoutUtils::FontSizeInflationFor(this); + nsRect invalidateArea = containerFrame->GetVisualOverflowRect(); + nsRect emptyFallbackArea(0, 0, GetScrollPortRect().width, + CalcFallbackRowHeight(inflation)); + invalidateArea.UnionRect(invalidateArea, emptyFallbackArea); + containerFrame->Invalidate(invalidateArea); } } @@ -992,8 +1000,6 @@ nsListControlFrame::Init(nsIContent* aContent, mLastDropdownBackstopColor = PresContext()->DefaultBackgroundColor(); - AddStateBits(NS_FRAME_IN_POPUP); - return result; } @@ -1673,6 +1679,18 @@ nsListControlFrame::GetType() const return nsGkAtoms::listControlFrame; } +void +nsListControlFrame::InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags) +{ + if (!IsInDropDownMode()) { + nsHTMLScrollFrame::InvalidateInternal(aDamageRect, aX, aY, this, aFlags); + return; + } + InvalidateRoot(aDamageRect + nsPoint(aX, aY), aFlags); +} + #ifdef DEBUG NS_IMETHODIMP nsListControlFrame::GetFrameName(nsAString& aResult) const diff --git a/layout/forms/nsListControlFrame.h b/layout/forms/nsListControlFrame.h index 9f17ec950950d..a74726b646396 100644 --- a/layout/forms/nsListControlFrame.h +++ b/layout/forms/nsListControlFrame.h @@ -92,6 +92,10 @@ class nsListControlFrame : public nsHTMLScrollFrame, ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); } + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags) MOZ_OVERRIDE; + #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; #endif diff --git a/layout/forms/nsMeterFrame.cpp b/layout/forms/nsMeterFrame.cpp index 204cb5f661250..212e3efd607cd 100644 --- a/layout/forms/nsMeterFrame.cpp +++ b/layout/forms/nsMeterFrame.cpp @@ -209,7 +209,7 @@ nsMeterFrame::AttributeChanged(int32_t aNameSpaceID, PresContext()->PresShell()->FrameNeedsReflow(barFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); - InvalidateFrame(); + Invalidate(GetVisualOverflowRectRelativeToSelf()); } return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, diff --git a/layout/forms/nsProgressFrame.cpp b/layout/forms/nsProgressFrame.cpp index 9ce76489d365e..4568f9665888f 100644 --- a/layout/forms/nsProgressFrame.cpp +++ b/layout/forms/nsProgressFrame.cpp @@ -224,7 +224,7 @@ nsProgressFrame::AttributeChanged(int32_t aNameSpaceID, NS_ASSERTION(barFrame, "The progress frame should have a child with a frame!"); PresContext()->PresShell()->FrameNeedsReflow(barFrame, nsIPresShell::eResize, NS_FRAME_IS_DIRTY); - InvalidateFrame(); + Invalidate(GetVisualOverflowRectRelativeToSelf()); } return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp index 984a5a15d1384..b0abcded04d61 100644 --- a/layout/forms/nsTextControlFrame.cpp +++ b/layout/forms/nsTextControlFrame.cpp @@ -541,6 +541,9 @@ nsTextControlFrame::Reflow(nsPresContext* aPresContext, kid = kid->GetNextSibling(); } + // If we're resizing, we might need to invalidate our border areas and such + CheckInvalidateSizeChange(aDesiredSize); + // take into account css properties that affect overflow handling FinishAndStoreOverflow(&aDesiredSize); diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list index a33c8af9e8095..8a121ac0b120f 100644 --- a/layout/generic/crashtests/crashtests.list +++ b/layout/generic/crashtests/crashtests.list @@ -14,7 +14,7 @@ load 310556-1.xhtml load 322780-1.xul load 323381-1.html load 323381-2.html -asserts-if(gtk2Widget,13-14) load 323386-1.html # Bug 575011 +asserts-if(gtk2Widget,12-13) load 323386-1.html # Bug 575011 load 323389-1.html load 323389-2.html load 323493-1.html @@ -259,8 +259,8 @@ load 465651-1.html load 467137-1.html load 467213-1.html load 467487-1.html -asserts(6-9) load 467493-1.html -asserts(4-8) load 467493-2.html +asserts(5-7) load 467493-1.html +asserts(4-6) load 467493-2.html load 467875-1.xhtml load 467914-1.html load 468207-1.html @@ -323,7 +323,7 @@ load 536692-1.xhtml load 541277-1.html load 541277-2.html asserts(3) load 541714-1.html -asserts(3-8) load 541714-2.html +asserts(3-7) load 541714-2.html load 542136-1.html load 545571-1.html load 547338.xul diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp index da83579ef33d8..cee3fe20747c4 100644 --- a/layout/generic/nsAbsoluteContainingBlock.cpp +++ b/layout/generic/nsAbsoluteContainingBlock.cpp @@ -456,6 +456,23 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat nsContainerFrame::PositionChildViews(aKidFrame); } + if (oldRect.TopLeft() != rect.TopLeft() || + (aDelegatingFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + // The frame moved + aKidFrame->GetParent()->Invalidate(oldOverflowRect); + aKidFrame->InvalidateFrameSubtree(); + } else if (oldRect.Size() != rect.Size()) { + // Invalidate the area where the frame changed size. + nscoord innerWidth = NS_MIN(oldRect.width, rect.width); + nscoord innerHeight = NS_MIN(oldRect.height, rect.height); + nscoord outerWidth = NS_MAX(oldRect.width, rect.width); + nscoord outerHeight = NS_MAX(oldRect.height, rect.height); + aKidFrame->GetParent()->Invalidate( + nsRect(rect.x + innerWidth, rect.y, outerWidth - innerWidth, outerHeight)); + // Invalidate the horizontal strip + aKidFrame->GetParent()->Invalidate( + nsRect(rect.x, rect.y + innerHeight, outerWidth, outerHeight - innerHeight)); + } aKidFrame->DidReflow(aPresContext, &kidReflowState, NS_FRAME_REFLOW_FINISHED); #ifdef DEBUG diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp index 5d559727f1a32..203cfdd41fa4d 100644 --- a/layout/generic/nsBlockFrame.cpp +++ b/layout/generic/nsBlockFrame.cpp @@ -487,6 +487,32 @@ nsBlockFrame::GetType() const return nsGkAtoms::blockFrame; } +void +nsBlockFrame::InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags) +{ + // Optimize by suppressing invalidation of areas that are clipped out + // with CSS 'clip'. Don't suppress invalidation of *this* frame directly, + // because when 'clip' shrinks we need to invalidate this frame and + // be able to invalidate areas outside the 'clip'. + if (aForChild) { + const nsStyleDisplay* disp = GetStyleDisplay(); + nsRect clipRect; + if (GetClipPropClipRect(disp, &clipRect, GetSize())) { + // Restrict the invalidated area to abs-pos clip rect + // abs-pos clipping clips everything in the frame + nsRect r; + if (r.IntersectRect(aDamageRect, clipRect - nsPoint(aX, aY))) { + nsBlockFrameSuper::InvalidateInternal(r, aX, aY, this, aFlags); + } + return; + } + } + + nsBlockFrameSuper::InvalidateInternal(aDamageRect, aX, aY, this, aFlags); +} + nscoord nsBlockFrame::GetBaseline() const { @@ -1188,6 +1214,9 @@ nsBlockFrame::Reflow(nsPresContext* aPresContext, } } + // Determine if we need to repaint our border, background or outline + CheckInvalidateSizeChange(aMetrics); + FinishAndStoreOverflow(&aMetrics); // Clear the float manager pointer in the block reflow state so we @@ -2447,6 +2476,18 @@ nsBlockFrame::DeleteLine(nsBlockReflowState& aState, } } +static void +InvalidateThebesLayersInLineBox(nsIFrame* aBlock, nsLineBox* aLine) +{ + if (aBlock->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) { + int32_t childCount = aLine->GetChildCount(); + for (nsIFrame* f = aLine->mFirstChild; childCount; + --childCount, f = f->GetNextSibling()) { + FrameLayerBuilder::InvalidateThebesLayersInSubtree(f); + } + } +} + /** * Reflow a line. The line will either contain a single block frame * or contain 1 or more inline frames. aKeepReflowGoing indicates @@ -2469,10 +2510,78 @@ nsBlockFrame::ReflowLine(nsBlockReflowState& aState, // Now that we know what kind of line we have, reflow it if (aLine->IsBlock()) { + nsRect oldBounds = aLine->mFirstChild->GetRect(); + nsRect oldVisOverflow(aLine->GetVisualOverflowArea()); rv = ReflowBlockFrame(aState, aLine, aKeepReflowGoing); - } else { + nsRect newBounds = aLine->mFirstChild->GetRect(); + + // We expect blocks to damage any area inside their bounds that is + // dirty; however, if the frame changes size or position then we + // need to do some repainting. + // XXX roc --- the above statement is ambiguous about whether 'bounds' + // means the frame's bounds or overflowArea, and in fact this is a source + // of much confusion and bugs. Thus the following hack considers *both* + // overflowArea and bounds. This should be considered a temporary hack + // until we decide how it's really supposed to work. + // Note that we have a similar hack in nsTableFrame::InvalidateFrame. + nsRect visOverflow(aLine->GetVisualOverflowArea()); + if (oldVisOverflow.TopLeft() != visOverflow.TopLeft() || + oldBounds.TopLeft() != newBounds.TopLeft()) { + // The block has moved, and so to be safe we need to repaint + // XXX We need to improve on this... + nsRect dirtyRect; + dirtyRect.UnionRect(oldVisOverflow, visOverflow); +#ifdef NOISY_BLOCK_INVALIDATE + printf("%p invalidate 6 (%d, %d, %d, %d)\n", + this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); +#endif + Invalidate(dirtyRect); + FrameLayerBuilder::InvalidateThebesLayersInSubtree(aLine->mFirstChild); + } else { + nsRect combinedAreaHStrip, combinedAreaVStrip; + nsRect boundsHStrip, boundsVStrip; + nsLayoutUtils::GetRectDifferenceStrips(oldBounds, newBounds, + &boundsHStrip, &boundsVStrip); + nsLayoutUtils::GetRectDifferenceStrips(oldVisOverflow, visOverflow, + &combinedAreaHStrip, + &combinedAreaVStrip); + +#ifdef NOISY_BLOCK_INVALIDATE + printf("%p invalidate boundsVStrip (%d, %d, %d, %d)\n", + this, boundsVStrip.x, boundsVStrip.y, boundsVStrip.width, boundsVStrip.height); + printf("%p invalidate boundsHStrip (%d, %d, %d, %d)\n", + this, boundsHStrip.x, boundsHStrip.y, boundsHStrip.width, boundsHStrip.height); + printf("%p invalidate combinedAreaVStrip (%d, %d, %d, %d)\n", + this, combinedAreaVStrip.x, combinedAreaVStrip.y, combinedAreaVStrip.width, combinedAreaVStrip.height); + printf("%p invalidate combinedAreaHStrip (%d, %d, %d, %d)\n", + this, combinedAreaHStrip.x, combinedAreaHStrip.y, combinedAreaHStrip.width, combinedAreaHStrip.height); +#endif + // The first thing Invalidate does is check if the rect is empty, so + // don't bother doing that here. + Invalidate(boundsVStrip); + Invalidate(boundsHStrip); + Invalidate(combinedAreaVStrip); + Invalidate(combinedAreaHStrip); + } + } + else { + nsRect oldVisOverflow(aLine->GetVisualOverflowArea()); aLine->SetLineWrapped(false); + rv = ReflowInlineFrames(aState, aLine, aKeepReflowGoing); + + // We don't really know what changed in the line, so use the union + // of the old and new combined areas + nsRect dirtyRect; + dirtyRect.UnionRect(oldVisOverflow, aLine->GetVisualOverflowArea()); +#ifdef NOISY_BLOCK_INVALIDATE + printf("%p invalidate (%d, %d, %d, %d)\n", + this, dirtyRect.x, dirtyRect.y, dirtyRect.width, dirtyRect.height); + if (aLine->IsForceInvalidate()) + printf(" dirty line is %p\n", static_cast(aLine.get())); +#endif + Invalidate(dirtyRect); + InvalidateThebesLayersInLineBox(this, aLine); } return rv; @@ -2576,6 +2685,9 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState, } else { // Free up the fromLine now that it's empty // Its bounds might need to be redrawn, though. + // XXX WHY do we invalidate the bounds AND the combined area? doesn't + // the combined area always enclose the bounds? + Invalidate(fromLine->mBounds); FrameLines* overflowLines = aFromOverflowLine ? aFromContainer->RemoveOverflowLines() : nullptr; nsLineList* fromLineList = @@ -2583,6 +2695,7 @@ nsBlockFrame::PullFrameFrom(nsBlockReflowState& aState, if (aFromLine.next() != fromLineList->end()) aFromLine.next()->MarkPreviousMarginDirty(); + Invalidate(fromLine->GetVisualOverflowArea()); fromLineList->erase(aFromLine); // aFromLine is now invalid aFromContainer->FreeLineBox(fromLine); @@ -2622,8 +2735,11 @@ nsBlockFrame::SlideLine(nsBlockReflowState& aState, { NS_PRECONDITION(aDY != 0, "why slide a line nowhere?"); + Invalidate(aLine->GetVisualOverflowArea()); // Adjust line state aLine->SlideBy(aDY); + Invalidate(aLine->GetVisualOverflowArea()); + InvalidateThebesLayersInLineBox(this, aLine); // Adjust the frames in the line nsIFrame* kid = aLine->mFirstChild; @@ -2922,6 +3038,9 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, // its view as needed. nsPoint originalPosition = frame->GetPosition(); while (true) { + // Save the frame's current position. We might need it later. + nscoord passOriginalY = frame->GetRect().y; + clearance = 0; nscoord topMargin = 0; bool mayNeedRetry = false; @@ -3088,6 +3207,14 @@ nsBlockFrame::ReflowBlockFrame(nsBlockReflowState& aState, clearance, aState.IsAdjacentWithTop(), aLine.get(), blockHtmlRS, frameReflowStatus, aState); + // If this was a second-pass reflow and the block's vertical position + // changed, invalidates from the first pass might have happened in the + // wrong places. Invalidate the entire overflow rect at the new position. + if (!mayNeedRetry && clearanceFrame && + frame->GetRect().y != passOriginalY) { + Invalidate(frame->GetVisualOverflowRect() + frame->GetPosition()); + } + NS_ENSURE_SUCCESS(rv, rv); if (mayNeedRetry && clearanceFrame) { @@ -5413,6 +5540,7 @@ nsBlockFrame::DoRemoveFrame(nsIFrame* aDeletedFrame, uint32_t aFlags) this, visOverflow.x, visOverflow.y, visOverflow.width, visOverflow.height); #endif + Invalidate(visOverflow); } else { // XXX update searchingOverflowList directly, remove only when empty FrameLines* overflowLines = RemoveOverflowLines(); @@ -5871,8 +5999,24 @@ nsBlockFrame::ReflowPushedFloats(nsBlockReflowState& aState, } if (NS_SUBTREE_DIRTY(f) || aState.mReflowState.ShouldReflowAllKids()) { + // Cache old bounds + nsRect oldRect = f->GetRect(); + nsRect oldOverflow = f->GetVisualOverflowRect(); + // Reflow aState.FlowAndPlaceFloat(f); + + // Invalidate if there was a position or size change + nsRect rect = f->GetRect(); + if (!rect.IsEqualInterior(oldRect)) { + nsRect dirtyRect = oldOverflow; + dirtyRect.MoveBy(oldRect.x, oldRect.y); + Invalidate(dirtyRect); + + dirtyRect = f->GetVisualOverflowRect(); + dirtyRect.MoveBy(rect.x, rect.y); + Invalidate(dirtyRect); + } } else { // Just reload the float region into the space manager diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h index b5d79253c637e..1c7b58df080dd 100644 --- a/layout/generic/nsBlockFrame.h +++ b/layout/generic/nsBlockFrame.h @@ -158,6 +158,9 @@ class nsBlockFrame : public nsBlockFrameSuper NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, const nsDisplayListSet& aLists); + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags); virtual nsIAtom* GetType() const; virtual bool IsFrameOfType(uint32_t aFlags) const { diff --git a/layout/generic/nsBlockReflowState.cpp b/layout/generic/nsBlockReflowState.cpp index 21715d50cec76..679ca95906f99 100644 --- a/layout/generic/nsBlockReflowState.cpp +++ b/layout/generic/nsBlockReflowState.cpp @@ -790,6 +790,7 @@ nsBlockReflowState::FlowAndPlaceFloat(nsIFrame* aFloat) aFloat->SetPosition(origin); nsContainerFrame::PositionFrameView(aFloat); nsContainerFrame::PositionChildViews(aFloat); + FrameLayerBuilder::InvalidateThebesLayersInSubtree(aFloat); } // Update the float combined area state diff --git a/layout/generic/nsBulletFrame.cpp b/layout/generic/nsBulletFrame.cpp index 6d4fd9ef2f120..ddc390e757bb5 100644 --- a/layout/generic/nsBulletFrame.cpp +++ b/layout/generic/nsBulletFrame.cpp @@ -1481,7 +1481,7 @@ NS_IMETHODIMP nsBulletFrame::OnDataAvailable(imgIRequest *aRequest, // The image has changed. // Invalidate the entire content area. Maybe it's not optimal but it's simple and // always correct, and I'll be a stunned mullet if it ever matters for performance - InvalidateFrame(); + Invalidate(nsRect(0, 0, mRect.width, mRect.height)); return NS_OK; } @@ -1523,7 +1523,7 @@ NS_IMETHODIMP nsBulletFrame::FrameChanged(imgIRequest *aRequest, { // Invalidate the entire content area. Maybe it's not optimal but it's simple and // always correct. - InvalidateFrame(); + Invalidate(nsRect(0, 0, mRect.width, mRect.height)); return NS_OK; } diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp index 74c7d881977d8..8d05d463773a6 100644 --- a/layout/generic/nsCanvasFrame.cpp +++ b/layout/generic/nsCanvasFrame.cpp @@ -156,6 +156,12 @@ nsCanvasFrame::RemoveFrame(ChildListID aListID, if (aOldFrame != mFrames.FirstChild()) return NS_ERROR_FAILURE; + // It's our one and only child frame + // Damage the area occupied by the deleted frame + // The child of the canvas probably can't have an outline, but why bother + // thinking about that? + Invalidate(aOldFrame->GetVisualOverflowRect() + aOldFrame->GetPosition()); + // Remove the frame and destroy it mFrames.DestroyFrame(aOldFrame); @@ -501,7 +507,15 @@ nsCanvasFrame::Reflow(nsPresContext* aPresContext, // could also include overflow to our top and left (out of the viewport) // which doesn't need to be painted. nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame(); - viewport->InvalidateFrame(); + viewport->Invalidate(nsRect(nsPoint(0, 0), viewport->GetSize())); + } else { + nsRect newKidRect = kidFrame->GetRect(); + if (newKidRect.TopLeft() == oldKidRect.TopLeft()) { + InvalidateRectDifference(oldKidRect, kidFrame->GetRect()); + } else { + Invalidate(oldKidRect); + Invalidate(newKidRect); + } } // Return our desired size. Normally it's what we're told, but @@ -545,7 +559,7 @@ nsCanvasFrame::Reflow(nsPresContext* aPresContext, const nsStyleBackground::Layer& layer = bg->mLayers[i]; if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED && layer.RenderingMightDependOnFrameSize()) { - InvalidateFrame(); + Invalidate(nsRect(nsPoint(0, 0), GetSize())); break; } } diff --git a/layout/generic/nsCanvasFrame.h b/layout/generic/nsCanvasFrame.h index 1dd5d18b3d69d..f39550d9446e6 100644 --- a/layout/generic/nsCanvasFrame.h +++ b/layout/generic/nsCanvasFrame.h @@ -116,28 +116,6 @@ class nsCanvasFrame : public nsContainerFrame, bool mAddedScrollPositionListener; }; -class nsDisplayCanvasBackgroundGeometry : public nsDisplayItemGeometry -{ -public: - nsDisplayCanvasBackgroundGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder, const nsRect& aChildBorder) - : nsDisplayItemGeometry(aItem, aBuilder) - , mChildBorder(aChildBorder) - , mPaddingRect(aItem->GetPaddingRect()) - , mContentRect(aItem->GetContentRect()) - {} - - virtual void MoveBy(const nsPoint& aOffset) - { - mBounds.MoveBy(aOffset); - mPaddingRect.MoveBy(aOffset); - mContentRect.MoveBy(aOffset); - } - - nsRect mChildBorder; - nsRect mPaddingRect; - nsRect mContentRect; -}; - /** * Override nsDisplayBackground methods so that we pass aBGClipRect to * PaintBackground, covering the whole overflow area. @@ -191,39 +169,7 @@ class nsDisplayCanvasBackground : public nsDisplayBackground { // We need to override so we don't consider border-radius. aOutFrames->AppendElement(mFrame); } - - virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) - { - nsIFrame *child = mFrame->GetFirstPrincipalChild(); - return new nsDisplayCanvasBackgroundGeometry(this, aBuilder, - child ? child->GetRect() : nsRect());; - } - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) - { - const nsDisplayCanvasBackgroundGeometry* geometry = static_cast(aGeometry); - if (ShouldFixToViewport(aBuilder)) { - // This is incorrect, We definitely need to check more things here. - return; - } - - nsIFrame *child = mFrame->GetFirstPrincipalChild(); - - bool snap; - if (!geometry->mBounds.IsEqualInterior(GetBounds(aBuilder, &snap)) || - (child && !geometry->mChildBorder.IsEqualInterior(child->GetRect())) || - !geometry->mPaddingRect.IsEqualInterior(GetPaddingRect()) || - !geometry->mContentRect.IsEqualInterior(GetContentRect())) { - if (!RenderingMightDependOnFrameSize() && geometry->mBounds.TopLeft() == GetBounds(aBuilder, &snap).TopLeft()) { - aInvalidRegion->Xor(GetBounds(aBuilder, &snap), geometry->mBounds); - } else { - aInvalidRegion->Or(GetBounds(aBuilder, &snap), geometry->mBounds); - } - } - } - virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) MOZ_OVERRIDE; diff --git a/layout/generic/nsColumnSetFrame.cpp b/layout/generic/nsColumnSetFrame.cpp index 97d4ba21b2ceb..a7bc1e221037b 100644 --- a/layout/generic/nsColumnSetFrame.cpp +++ b/layout/generic/nsColumnSetFrame.cpp @@ -441,7 +441,13 @@ static void MoveChildTo(nsIFrame* aParent, nsIFrame* aChild, nsPoint aOrigin) { return; } + nsRect r = aChild->GetVisualOverflowRect(); + r += aChild->GetPosition(); + aParent->Invalidate(r); + r -= aChild->GetPosition(); aChild->SetPosition(aOrigin); + r += aOrigin; + aParent->Invalidate(r); PlaceFrameView(aChild); } @@ -1079,6 +1085,8 @@ nsColumnSetFrame::Reflow(nsPresContext* aPresContext, aStatus = NS_FRAME_COMPLETE; } + CheckInvalidateSizeChange(aDesiredSize); + // XXXjwir3: This call should be replaced with FinishWithAbsoluteFrames // when bug 724978 is fixed and nsColumnSetFrame is a full absolute // container. diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp index d83c6ae0f9021..9108fdb96aaa9 100644 --- a/layout/generic/nsContainerFrame.cpp +++ b/layout/generic/nsContainerFrame.cpp @@ -930,6 +930,11 @@ nsContainerFrame::ReflowChild(nsIFrame* aKidFrame, aKidFrame->WillReflow(aPresContext); if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) { + if ((aFlags & NS_FRAME_INVALIDATE_ON_MOVE) && + !(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) && + aKidFrame->GetPosition() != nsPoint(aX, aY)) { + aKidFrame->InvalidateFrameSubtree(); + } aKidFrame->SetPosition(nsPoint(aX, aY)); } @@ -1038,6 +1043,13 @@ nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame, // correctly positioned PositionChildViews(aKidFrame); } + + // We also need to redraw everything associated with the frame + // because if the frame's Reflow issued any invalidates, then they + // will be at the wrong offset ... note that this includes + // invalidates issued against the frame's children, so we need to + // invalidate the overflow area too. + aKidFrame->Invalidate(aDesiredSize.VisualOverflow()); } return aKidFrame->DidReflow(aPresContext, aReflowState, NS_FRAME_REFLOW_FINISHED); @@ -1117,6 +1129,10 @@ nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPres frame, availSpace); nsReflowStatus frameStatus = NS_FRAME_COMPLETE; + // Cache old bounds + nsRect oldRect = frame->GetRect(); + nsRect oldOverflow = frame->GetVisualOverflowRect(); + // Reflow rv = ReflowChild(frame, aPresContext, desiredSize, frameState, prevRect.x, 0, aFlags, frameStatus, &tracker); @@ -1127,6 +1143,18 @@ nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPres prevRect.x, 0, aFlags); NS_ENSURE_SUCCESS(rv, rv); + // Invalidate if there was a position or size change + nsRect rect = frame->GetRect(); + if (!rect.IsEqualInterior(oldRect)) { + nsRect dirtyRect = oldOverflow; + dirtyRect.MoveBy(oldRect.x, oldRect.y); + Invalidate(dirtyRect); + + dirtyRect = frame->GetVisualOverflowRect(); + dirtyRect.MoveBy(rect.x, rect.y); + Invalidate(dirtyRect); + } + // Handle continuations if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) { if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) { @@ -1341,6 +1369,8 @@ nsContainerFrame::DeleteNextInFlowChild(nsPresContext* aPresContext, } } + aNextInFlow->InvalidateFrameSubtree(); + // Take the next-in-flow out of the parent's child list #ifdef DEBUG nsresult rv = diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 811a630d3fe3e..deda2ec2def4b 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -85,7 +85,6 @@ #include "nsChangeHint.h" #include "nsDeckFrame.h" #include "nsTableFrame.h" -#include "nsSubDocumentFrame.h" #include "gfxContext.h" #include "nsRenderingContext.h" @@ -505,8 +504,7 @@ nsFrame::Init(nsIContent* aContent, // Make bits that are currently off (see constructor) the same: mState |= state & (NS_FRAME_INDEPENDENT_SELECTION | NS_FRAME_GENERATED_CONTENT | - NS_FRAME_IS_SVG_TEXT | - NS_FRAME_IN_POPUP); + NS_FRAME_IS_SVG_TEXT); } const nsStyleDisplay *disp = GetStyleDisplay(); if (disp->HasTransform()) { @@ -1270,23 +1268,6 @@ nsFrame::GetChildLists(nsTArray* aLists) const } } -void -nsIFrame::GetCrossDocChildLists(nsTArray* aLists) -{ - nsSubDocumentFrame* subdocumentFrame = do_QueryFrame(this); - if (subdocumentFrame) { - // Descend into the subdocument - nsIFrame* root = subdocumentFrame->GetSubdocumentRootFrame(); - if (root) { - aLists->AppendElement(nsIFrame::ChildList( - nsFrameList(root, nsLayoutUtils::GetLastSibling(root)), - nsIFrame::kPrincipalList)); - } - } - - GetChildLists(aLists); -} - static nsIFrame* GetActiveSelectionFrame(nsPresContext* aPresContext, nsIFrame* aFrame) { @@ -4153,8 +4134,6 @@ nsFrame::DidReflow(nsPresContext* aPresContext, NS_FRAME_TRACE_MSG(NS_FRAME_TRACE_CALLS, ("nsFrame::DidReflow: aStatus=%d", aStatus)); - nsSVGEffects::InvalidateDirectRenderingObservers(this, nsSVGEffects::INVALIDATE_REFLOW); - if (NS_FRAME_REFLOW_FINISHED == aStatus) { mState &= ~(NS_FRAME_IN_REFLOW | NS_FRAME_FIRST_REFLOW | NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN); @@ -4589,6 +4568,46 @@ nsIFrame::IsLeaf() const return true; } +Layer* +nsIFrame::InvalidateLayer(const nsRect& aDamageRect, uint32_t aDisplayItemKey) +{ + NS_ASSERTION(aDisplayItemKey > 0, "Need a key"); + + Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey); + if (!layer) { + Invalidate(aDamageRect); + return nullptr; + } + + uint32_t flags = INVALIDATE_NO_THEBES_LAYERS; + if (aDisplayItemKey == nsDisplayItem::TYPE_VIDEO || + aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN || + aDisplayItemKey == nsDisplayItem::TYPE_CANVAS) { + flags |= INVALIDATE_NO_UPDATE_LAYER_TREE; + } + + InvalidateWithFlags(aDamageRect, flags); + return layer; +} + +void +nsIFrame::InvalidateTransformLayer() +{ + NS_ASSERTION(mParent, "How can a viewport frame have a transform?"); + + bool hasLayer = + FrameLayerBuilder::GetDedicatedLayer(this, nsDisplayItem::TYPE_TRANSFORM) != nullptr; + // Invalidate post-transform area in the parent. We have to invalidate + // in the parent because our transform style may have changed from what was + // used to paint this frame. + // It's OK to bypass the SVG effects processing and other processing + // performed if we called this->InvalidateWithFlags, because those effects + // are performed before applying transforms. + mParent->InvalidateInternal(GetVisualOverflowRect() + GetPosition(), + 0, 0, this, + hasLayer ? INVALIDATE_NO_THEBES_LAYERS : 0); +} + class LayerActivity { public: LayerActivity(nsIFrame* aFrame) : mFrame(aFrame), mChangeHint(nsChangeHint(0)) {} @@ -4642,18 +4661,7 @@ LayerActivityTracker::NotifyExpired(LayerActivity* aObject) nsIFrame* f = aObject->mFrame; aObject->mFrame = nullptr; f->Properties().Delete(LayerActivityProperty()); - - // if there are hints other than transform/opacity, invalidate, since we don't know what else to do. - if (aObject->mChangeHint & ~(nsChangeHint_UpdateOpacityLayer|nsChangeHint_UpdateTransformLayer)) { - f->InvalidateFrameSubtree(); - } else { - if (aObject->mChangeHint & nsChangeHint_UpdateOpacityLayer) { - f->InvalidateFrameSubtree(nsDisplayItem::TYPE_OPACITY); - } - if (aObject->mChangeHint & nsChangeHint_UpdateTransformLayer) { - f->InvalidateFrameSubtree(nsDisplayItem::TYPE_TRANSFORM); - } - } + f->InvalidateFrameSubtree(); } void @@ -4696,6 +4704,131 @@ nsFrame::ShutdownLayerActivityTimer() gLayerActivityTracker = nullptr; } +void +nsIFrame::InvalidateWithFlags(const nsRect& aDamageRect, uint32_t aFlags) +{ + if (aDamageRect.IsEmpty()) { + return; + } + + // Don't allow invalidates to do anything when + // painting is suppressed. + nsIPresShell *shell = PresContext()->GetPresShell(); + if (shell) { + if (shell->IsPaintingSuppressed()) + return; + } + + InvalidateInternal(aDamageRect, 0, 0, nullptr, aFlags); +} + +/** + * Helper function that funnels an InvalidateInternal request up to the + * parent. This function is used so that if MOZ_SVG is not defined, we still + * have unified control paths in the InvalidateInternal chain. + * + * @param aDamageRect The rect to invalidate. + * @param aX The x offset from the origin of this frame to the rectangle. + * @param aY The y offset from the origin of this frame to the rectangle. + * @param aImmediate Whether to redraw immediately. + * @return None, though this funnels the request up to the parent frame. + */ +void +nsIFrame::InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX, + nscoord aY, uint32_t aFlags) +{ + if (aDamageRect.IsEmpty()) { + return; + } + + /* If we're a transformed frame, then we need to apply our transform to the + * damage rectangle so that the redraw correctly redraws the transformed + * region. We're moved over aX and aY from our origin, but since this aX + * and aY is contained within our border, we need to scoot back by -aX and + * -aY to get back to the origin of the transform. + * + * There's one more problem, though, and that's that we don't know what + * coordinate space this rectangle is in. Sometimes it's in the local + * coordinate space for the frame, and sometimes its in the transformed + * coordinate space. If we get it wrong, we'll display incorrectly. Until I + * find a better fix for this problem, we'll invalidate the union of the two + * rectangles (original rectangle and transformed rectangle). At least one of + * these will be correct. + * + * When we are preserving-3d, we can have arbitrary hierarchies of preserved 3d + * children. The computed transform on these children is relative to the root + * transform object in the hierarchy, not necessarily their direct ancestor. + * In this case we transform by the child's transform, and mark the rectangle + * as being transformed until it is passed up to the root of the hierarchy. + * + * See bug #452496 for more details. + */ + + // Check the transformed flags and remove it + bool rectIsTransformed = (aFlags & INVALIDATE_ALREADY_TRANSFORMED); + if (!Preserves3D()) { + // We only want to remove the flag if we aren't preserving 3d. Otherwise + // the rect will already have been transformed into the root preserve-3d + // frame coordinate space, and we should continue passing it up without + // further transforms. + aFlags &= ~INVALIDATE_ALREADY_TRANSFORMED; + } + + if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) && + !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) { + // XXX need to set INVALIDATE_NO_THEBES_LAYERS for certain kinds of + // invalidation, e.g. video update, 'opacity' change + FrameLayerBuilder::InvalidateThebesLayerContents(this, + aDamageRect + nsPoint(aX, aY)); + // Don't need to invalidate any more Thebes layers + aFlags |= INVALIDATE_NO_THEBES_LAYERS; + if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) { + return; + } + } + if (IsTransformed() && !rectIsTransformed) { + nsRect newDamageRect = nsDisplayTransform::TransformRectOut + (aDamageRect, this, nsPoint(-aX, -aY)); + if (!(GetStateBits() & NS_FRAME_SVG_LAYOUT)) { + newDamageRect.UnionRect(newDamageRect, aDamageRect); + } + + // If we are preserving 3d, then our computed transform includes that of any + // ancestor frames that also preserve 3d. Mark the rectangle as already being + // transformed into the parent's coordinate space. + if (Preserves3D()) { + aFlags |= INVALIDATE_ALREADY_TRANSFORMED; + } + + GetParent()-> + InvalidateInternal(newDamageRect, aX + mRect.x, aY + mRect.y, this, + aFlags); + } + else + GetParent()-> + InvalidateInternal(aDamageRect, aX + mRect.x, aY + mRect.y, this, aFlags); +} + +void +nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY, + nsIFrame* aForChild, uint32_t aFlags) +{ + ClearDisplayItemCache(); + nsSVGEffects::InvalidateDirectRenderingObservers(this); + if (nsSVGIntegrationUtils::UsingEffectsForFrame(this)) { + nsRect r = nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(this, + aDamageRect + nsPoint(aX, aY)); + /* Rectangle is now in our own local space, so aX and aY are effectively + * zero. Thus we'll pretend that the entire time this was in our own + * local coordinate space and do any remaining processing. + */ + InvalidateInternalAfterResize(r, 0, 0, aFlags); + return; + } + + InvalidateInternalAfterResize(aDamageRect, aX, aY, aFlags); +} + gfx3DMatrix nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor, nsIFrame** aOutAncestor) @@ -4763,188 +4896,64 @@ nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor, 0.0f); } -static void InvalidateFrameInternal(nsIFrame *aFrame, bool aHasDisplayItem = true) -{ - if (aHasDisplayItem) { - aFrame->AddStateBits(NS_FRAME_NEEDS_PAINT); - } - nsSVGEffects::InvalidateDirectRenderingObservers(aFrame); - nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame); - while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) { - if (aHasDisplayItem) { - parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); - } - nsSVGEffects::InvalidateDirectRenderingObservers(parent); - parent = nsLayoutUtils::GetCrossDocParentFrame(parent); - } - if (!aHasDisplayItem) { - return; - } - if (!parent) { - aFrame->SchedulePaint(); - } - if (aFrame->HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { - aFrame->Properties().Delete(nsIFrame::InvalidationRect()); - aFrame->RemoveStateBits(NS_FRAME_HAS_INVALID_RECT); - } -} - void -nsIFrame::InvalidateFrameSubtree(uint32_t aDisplayItemKey) +nsIFrame::InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2) { - bool hasDisplayItem = - !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); - InvalidateFrameInternal(this, hasDisplayItem); - - if (HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT) || !hasDisplayItem) { - return; - } - - AddStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT); - - nsAutoTArray childListArray; - GetCrossDocChildLists(&childListArray); - - nsIFrame::ChildListArrayIterator lists(childListArray); - for (; !lists.IsDone(); lists.Next()) { - nsFrameList::Enumerator childFrames(lists.CurrentList()); - for (; !childFrames.AtEnd(); childFrames.Next()) { - childFrames.get()->InvalidateFrameSubtree(); - } - } + nsRect sizeHStrip, sizeVStrip; + nsLayoutUtils::GetRectDifferenceStrips(aR1, aR2, &sizeHStrip, &sizeVStrip); + Invalidate(sizeVStrip); + Invalidate(sizeHStrip); } void -nsIFrame::ClearInvalidationStateBits() +nsIFrame::InvalidateFrameSubtree() { - if (HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) { - nsAutoTArray childListArray; - GetCrossDocChildLists(&childListArray); - - nsIFrame::ChildListArrayIterator lists(childListArray); - for (; !lists.IsDone(); lists.Next()) { - nsFrameList::Enumerator childFrames(lists.CurrentList()); - for (; !childFrames.AtEnd(); childFrames.Next()) { - childFrames.get()->ClearInvalidationStateBits(); - } - } - } - - RemoveStateBits(NS_FRAME_NEEDS_PAINT | - NS_FRAME_DESCENDANT_NEEDS_PAINT | - NS_FRAME_ALL_DESCENDANTS_NEED_PAINT); + Invalidate(GetVisualOverflowRectRelativeToSelf()); + FrameLayerBuilder::InvalidateThebesLayersInSubtree(this); } void -nsIFrame::InvalidateFrame(uint32_t aDisplayItemKey) +nsIFrame::InvalidateOverflowRect() { - bool hasDisplayItem = - !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); - InvalidateFrameInternal(this, hasDisplayItem); + Invalidate(GetVisualOverflowRectRelativeToSelf()); } +NS_DECLARE_FRAME_PROPERTY(DeferInvalidatesProperty, nsIFrame::DestroyRegion) + void -nsIFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) +nsIFrame::InvalidateRoot(const nsRect& aDamageRect, uint32_t aFlags) { - bool hasDisplayItem = - !aDisplayItemKey || FrameLayerBuilder::HasRetainedDataFor(this, aDisplayItemKey); - bool alreadyInvalid = false; - if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) { - InvalidateFrameInternal(this, hasDisplayItem); - } else { - alreadyInvalid = true; - } - - if (!hasDisplayItem) { - return; - } + NS_ASSERTION(nsLayoutUtils::GetDisplayRootFrame(this) == this, + "Can only call this on display roots"); - nsRect *rect = static_cast(Properties().Get(InvalidationRect())); - if (!rect) { - if (alreadyInvalid) { + if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) && + !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) { + FrameLayerBuilder::InvalidateThebesLayerContents(this, aDamageRect); + if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) { return; } - rect = new nsRect(); - Properties().Set(InvalidationRect(), rect); - AddStateBits(NS_FRAME_HAS_INVALID_RECT); - } - - *rect = rect->Union(aRect); -} - -bool -nsIFrame::IsInvalid(nsRect& aRect) -{ - if (!HasAnyStateBits(NS_FRAME_NEEDS_PAINT)) { - return false; - } - - if (HasAnyStateBits(NS_FRAME_HAS_INVALID_RECT)) { - nsRect *rect = static_cast(Properties().Get(InvalidationRect())); - NS_ASSERTION(rect, "Must have an invalid rect if NS_FRAME_HAS_INVALID_RECT is set!"); - aRect = *rect; - } else { - aRect.SetEmpty(); - } - return true; -} - -void -nsIFrame::SchedulePaint(uint32_t aFlags) -{ - nsIFrame *displayRoot = nsLayoutUtils::GetDisplayRootFrame(this); - nsPresContext *pres = displayRoot->PresContext()->GetRootPresContext(); - - // No need to schedule a paint for an external document since they aren't - // painted directly. - if (!pres || (pres->Document() && pres->Document()->GetDisplayDocument())) { - return; - } - - pres->PresShell()->ScheduleViewManagerFlush(); - if (!(aFlags & PAINT_COMPOSITE_ONLY)) { - displayRoot->AddStateBits(NS_FRAME_UPDATE_LAYER_TREE); - } - nsIPresShell* shell = PresContext()->PresShell(); - if (shell) { - shell->AddInvalidateHiddenPresShellObserver(pres->RefreshDriver()); - } -} - -Layer* -nsIFrame::InvalidateLayer(uint32_t aDisplayItemKey, const nsIntRect* aDamageRect) -{ - NS_ASSERTION(aDisplayItemKey > 0, "Need a key"); - - Layer* layer = FrameLayerBuilder::GetDedicatedLayer(this, aDisplayItemKey); - if (aDamageRect && aDamageRect->IsEmpty()) { - return layer; } - if (!layer) { - // Plugins can transition from not rendering anything to rendering, - // and still only call this. So always invalidate, with specifying - // the display item type just in case. - if (aDisplayItemKey == nsDisplayItem::TYPE_PLUGIN) { - InvalidateFrame(); - } else { - InvalidateFrame(aDisplayItemKey); - } - return nullptr; + nsRect rect = aDamageRect; + nsRegion* excludeRegion = static_cast + (Properties().Get(DeferInvalidatesProperty())); + if (excludeRegion && (aFlags & INVALIDATE_EXCLUDE_CURRENT_PAINT)) { + nsRegion r; + r.Sub(rect, *excludeRegion); + if (r.IsEmpty()) + return; + rect = r.GetBounds(); } - if (aDamageRect) { - layer->AddInvalidRect(*aDamageRect); - } else { - layer->SetInvalidRectToVisibleRegion(); + if (!(aFlags & INVALIDATE_NO_UPDATE_LAYER_TREE)) { + AddStateBits(NS_FRAME_UPDATE_LAYER_TREE); } - SchedulePaint(PAINT_COMPOSITE_ONLY); - return layer; + nsIView* view = GetView(); + NS_ASSERTION(view, "This can only be called on frames with views"); + view->GetViewManager()->InvalidateViewNoSuppression(view, rect); } -NS_DECLARE_FRAME_PROPERTY(DeferInvalidatesProperty, nsIFrame::DestroyRegion) - void nsIFrame::BeginDeferringInvalidatesForDisplayRoot(const nsRegion& aExcludeRegion) { @@ -5196,6 +5205,107 @@ nsFrame::UpdateOverflow() return false; } +void +nsFrame::CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize) +{ + nsIFrame::CheckInvalidateSizeChange(mRect, GetVisualOverflowRect(), + nsSize(aNewDesiredSize.width, aNewDesiredSize.height)); +} + +static void +InvalidateRectForFrameSizeChange(nsIFrame* aFrame, const nsRect& aRect) +{ + nsStyleContext *bgSC; + if (!nsCSSRendering::FindBackground(aFrame->PresContext(), aFrame, &bgSC)) { + nsIFrame* rootFrame = + aFrame->PresContext()->PresShell()->FrameManager()->GetRootFrame(); + rootFrame->Invalidate(nsRect(nsPoint(0, 0), rootFrame->GetSize())); + } + + aFrame->Invalidate(aRect); +} + +void +nsIFrame::CheckInvalidateSizeChange(const nsRect& aOldRect, + const nsRect& aOldVisualOverflowRect, + const nsSize& aNewDesiredSize) +{ + if (aNewDesiredSize == aOldRect.Size()) + return; + + // Below, we invalidate the old frame area (or, in the case of + // outline, combined area) if the outline, border or background + // settings indicate that something other than the difference + // between the old and new areas needs to be painted. We are + // assuming that the difference between the old and new areas will + // be invalidated by some other means. That also means invalidating + // the old frame area is the same as invalidating the new frame area + // (since in either case the UNION of old and new areas will be + // invalidated) + + // We use InvalidateRectForFrameSizeChange throughout this method, even + // though root-invalidation is technically only needed in the case where + // layer.RenderingMightDependOnFrameSize(). This allows us to simplify the + // code somewhat and return immediately after invalidation in the earlier + // cases. + + // Invalidate the entire old frame+outline if the frame has an outline + bool anyOutlineOrEffects; + nsRect r = ComputeOutlineAndEffectsRect(this, &anyOutlineOrEffects, + aOldVisualOverflowRect, + aNewDesiredSize, + false); + if (anyOutlineOrEffects) { + r.UnionRect(aOldVisualOverflowRect, r); + InvalidateRectForFrameSizeChange(this, r); + return; + } + + // Invalidate the old frame border box if the frame has borders. Those + // borders may be moving. + const nsStyleBorder* border = GetStyleBorder(); + NS_FOR_CSS_SIDES(side) { + if (border->GetComputedBorderWidth(side) != 0) { + if ((side == NS_SIDE_LEFT || side == NS_SIDE_TOP) && + !nsLayoutUtils::HasNonZeroCornerOnSide(border->mBorderRadius, side) && + !border->GetBorderImage() && + border->GetBorderStyle(side) == NS_STYLE_BORDER_STYLE_SOLID) { + // We also need to be sure that the bottom-left or top-right + // corner is simple. For example, if the bottom or right border + // has a different color, we would need to invalidate the corner + // area. But that's OK because if there is a right or bottom border, + // we'll invalidate the entire border-box here anyway. + continue; + } + InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height)); + return; + } + } + + const nsStyleBackground *bg = GetStyleBackground(); + if (!bg->IsTransparent()) { + // Invalidate the old frame background if the frame has a background + // whose position depends on the size of the frame + NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, bg) { + const nsStyleBackground::Layer &layer = bg->mLayers[i]; + if (layer.RenderingMightDependOnFrameSize()) { + InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height)); + return; + } + } + + // Invalidate the old frame background if the frame has a background + // that is being clipped by border-radius, since the old or new area + // clipped off by the radius is not necessarily in the area that has + // already been invalidated (even if only the top-left corner has a + // border radius). + if (nsLayoutUtils::HasNonZeroCorner(border->mBorderRadius)) { + InvalidateRectForFrameSizeChange(this, nsRect(0, 0, aOldRect.width, aOldRect.height)); + return; + } + } +} + // Define the MAX_FRAME_DEPTH to be the ContentSink's MAX_REFLOW_DEPTH plus // 4 for the frames above the document's frames: // the Viewport, GFXScroll, ScrollPort, and Canvas @@ -6931,7 +7041,7 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, // If there is no outline or other effects now, then we don't have // to do anything here since removing those styles can't require // repainting of areas that weren't in the old overflow area. - InvalidateFrame(); + Invalidate(aOverflowAreas.VisualOverflow()); } else if (hasClipPropClip || didHaveClipPropClip) { // If we are (or were) clipped by the 'clip' property, and our // overflow area changes, it might be because the clipping changed. @@ -6939,13 +7049,32 @@ nsIFrame::FinishAndStoreOverflow(nsOverflowAreas& aOverflowAreas, // repaint the old overflow area, so if the overflow area has // changed (in particular, if it grows), we have to repaint the // new area here. - InvalidateFrame(); + Invalidate(aOverflowAreas.VisualOverflow()); } } - - if (anyOverflowChanged) { - nsSVGEffects::InvalidateDirectRenderingObservers(this); + // XXXSDL For SVG the invalidation happens in ReflowSVG for now, so we + // don't currently invalidate SVG here: + if (anyOverflowChanged && hasTransform && + !(GetStateBits() & NS_FRAME_SVG_LAYOUT)) { + // When there's a transform, changes to that style might require + // repainting of the old and new overflow areas in the widget. + // Repainting of the frame itself will not be required if there's + // a retained layer, so we can call InvalidateLayer here + // which will avoid repainting ThebesLayers if possible. + // nsCSSFrameConstructor::DoApplyRenderingChangeToTree repaints + // the old overflow area in the widget in response to + // nsChangeHint_UpdateTransformLayer. But since the new overflow + // area is not known at that time, we have to handle it here. + // If the overflow area hasn't changed, then it doesn't matter that + // we didn't reach here since repainting the old overflow area was enough. + // If there is no transform now, then the container layer for + // the transform will go away and the frame contents will change + // ThebesLayers, forcing it to be invalidated, so it doesn't matter + // that we didn't reach here. + InvalidateLayer(aOverflowAreas.VisualOverflow(), + nsDisplayItem::TYPE_TRANSFORM); } + return anyOverflowChanged; } @@ -7467,8 +7596,11 @@ nsFrame::RefreshSizeCache(nsBoxLayoutState& aState) if (!DoesNeedRecalc(metrics->mBlockPrefSize)) return NS_OK; + // get the old rect. + nsRect oldRect = GetRect(); + // the rect we plan to size to. - nsRect rect = GetRect(); + nsRect rect(oldRect); nsMargin bp(0,0,0,0); GetBorderAndPadding(bp); @@ -7490,6 +7622,15 @@ nsFrame::RefreshSizeCache(nsBoxLayoutState& aState) rect.x, rect.y, metrics->mBlockPrefSize.width, NS_UNCONSTRAINEDSIZE); + nsRect newRect = GetRect(); + + // make sure we draw any size change + if (oldRect.width != newRect.width || oldRect.height != newRect.height) { + newRect.x = 0; + newRect.y = 0; + Redraw(aState, &newRect); + } + metrics->mBlockMinSize.height = 0; // ok we need the max ascent of the items on the line. So to do this // ask the block for its line iterator. Get the max ascent. @@ -8006,55 +8147,6 @@ nsFrame::BoxMetrics() const return metrics; } -/** - * Adds the NS_FRAME_IN_POPUP state bit to the current frame, - * and all descendant frames (including cross-doc ones). - */ -static void -AddInPopupStateBitToDescendants(nsIFrame* aFrame) -{ - aFrame->AddStateBits(NS_FRAME_IN_POPUP); - - nsAutoTArray childListArray; - aFrame->GetCrossDocChildLists(&childListArray); - - nsIFrame::ChildListArrayIterator lists(childListArray); - for (; !lists.IsDone(); lists.Next()) { - nsFrameList::Enumerator childFrames(lists.CurrentList()); - for (; !childFrames.AtEnd(); childFrames.Next()) { - AddInPopupStateBitToDescendants(childFrames.get()); - } - } -} - -/** - * Removes the NS_FRAME_IN_POPUP state bit from the current - * frames and all descendant frames (including cross-doc ones), - * unless the frame is a popup itself. - */ -static void -RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame) -{ - if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) || - aFrame->GetType() == nsGkAtoms::listControlFrame || - aFrame->GetType() == nsGkAtoms::menuPopupFrame) { - return; - } - - aFrame->RemoveStateBits(NS_FRAME_IN_POPUP); - - nsAutoTArray childListArray; - aFrame->GetCrossDocChildLists(&childListArray); - - nsIFrame::ChildListArrayIterator lists(childListArray); - for (; !lists.IsDone(); lists.Next()) { - nsFrameList::Enumerator childFrames(lists.CurrentList()); - for (; !childFrames.AtEnd(); childFrames.Next()) { - RemoveInPopupStateBitFromDescendants(childFrames.get()); - } - } -} - void nsFrame::SetParent(nsIFrame* aParent) { @@ -8073,27 +8165,14 @@ nsFrame::SetParent(nsIFrame* aParent) f->AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW); } } - - if (HasInvalidFrameInSubtree()) { + + if (GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT) { for (nsIFrame* f = aParent; - f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); + f && !(f->GetStateBits() & NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT); f = nsLayoutUtils::GetCrossDocParentFrame(f)) { - f->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); + f->AddStateBits(NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT); } } - - if (aParent->HasAnyStateBits(NS_FRAME_IN_POPUP)) { - AddInPopupStateBitToDescendants(this); - } else { - RemoveInPopupStateBitFromDescendants(this); - } - - // If our new parent only has invalid children, then we just invalidate - // ourselves too. This is probably faster than clearing the flag all - // the way up the frame tree. - if (aParent->HasAnyStateBits(NS_FRAME_ALL_DESCENDANTS_NEED_PAINT)) { - InvalidateFrame(); - } } void diff --git a/layout/generic/nsFrame.h b/layout/generic/nsFrame.h index f849a7185b349..1babc667d047a 100644 --- a/layout/generic/nsFrame.h +++ b/layout/generic/nsFrame.h @@ -391,6 +391,16 @@ class nsFrame : public nsBox //-------------------------------------------------- // Additional methods + /** + * Helper method to invalidate portions of a standard container frame if the + * desired size indicates that the size has changed (specifically border, + * background and outline). + * We assume that the difference between the old frame area and the new + * frame area is invalidated by some other means. + * @param aDesiredSize the new size of the frame + */ + void CheckInvalidateSizeChange(nsHTMLReflowMetrics& aNewDesiredSize); + // Helper function that tests if the frame tree is too deep; if it is // it marks the frame as "unflowable", zeroes out the metrics, sets // the reflow status, and returns true. Otherwise, the frame is diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 4754f539ff93e..c414975c3b166 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -160,6 +160,94 @@ nsHTMLScrollFrame::GetType() const return nsGkAtoms::scrollFrame; } +void +nsHTMLScrollFrame::InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags) +{ + if (aForChild) { + if (aForChild == mInner.mScrolledFrame) { + nsRect damage = aDamageRect + nsPoint(aX, aY); + // This is the damage rect that we're going to pass up to our parent. + nsRect parentDamage; + if (mInner.IsIgnoringViewportClipping()) { + parentDamage = damage; + } else { + // If we're using a displayport, we might be displaying an area + // different than our scroll port and the damage needs to be + // clipped to that instead. + nsRect displayport; + bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(), + &displayport); + if (usingDisplayport) { + parentDamage.IntersectRect(damage, displayport); + } else { + parentDamage.IntersectRect(damage, mInner.mScrollPort); + } + } + + if (IsScrollingActive()) { + // This is the damage rect that we're going to pass up and + // only request invalidation of ThebesLayers for. + // damage is now in our coordinate system, which means it was + // translated using the current scroll position. Adjust it to + // reflect the scroll position at last paint, since that's what + // the ThebesLayers are currently set up for. + // This should not be clipped to the scrollport since ThebesLayers + // can contain content outside the scrollport that may need to be + // invalidated. + nsRect thebesLayerDamage = damage + GetScrollPosition() - mInner.mScrollPosAtLastPaint; + if (parentDamage.IsEqualInterior(thebesLayerDamage)) { + // This single call will take care of both rects + nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags); + } else { + // Invalidate rects separately + if (!(aFlags & INVALIDATE_NO_THEBES_LAYERS)) { + nsContainerFrame::InvalidateInternal(thebesLayerDamage, 0, 0, aForChild, + aFlags | INVALIDATE_ONLY_THEBES_LAYERS); + } + if (!(aFlags & INVALIDATE_ONLY_THEBES_LAYERS) && !parentDamage.IsEmpty()) { + nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, + aFlags | INVALIDATE_NO_THEBES_LAYERS); + } + } + } else { + if (!parentDamage.IsEmpty()) { + nsContainerFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags); + } + } + + if (mInner.mIsRoot && !parentDamage.IsEqualInterior(damage)) { + // Make sure we notify our prescontext about invalidations outside + // viewport clipping. + // This is important for things that are snapshotting the viewport, + // possibly outside the scrolled bounds. + // We don't need to propagate this any further up, though. Anyone who + // cares about scrolled-out-of-view invalidates had better be listening + // to our window directly. + PresContext()->NotifyInvalidation(damage, aFlags); + } + return; + } else if (aForChild == mInner.mHScrollbarBox) { + if (!mInner.mHasHorizontalScrollbar) { + // Our scrollbars may send up invalidations even when they're collapsed, + // because we just size a collapsed scrollbar to empty and some + // descendants may be non-empty. Suppress that invalidation here. + return; + } + } else if (aForChild == mInner.mVScrollbarBox) { + if (!mInner.mHasVerticalScrollbar) { + // Our scrollbars may send up invalidations even when they're collapsed, + // because we just size a collapsed scrollbar to empty and some + // descendants may be non-empty. Suppress that invalidation here. + return; + } + } + } + + nsContainerFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags); +} + /** HTML scrolling implementation @@ -828,6 +916,8 @@ nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext, state.mContentsOverflowAreas + mInner.mScrolledFrame->GetPosition()); } + CheckInvalidateSizeChange(aDesiredSize); + FinishReflowWithAbsoluteFrames(aPresContext, aDesiredSize, aReflowState, aStatus); if (!InInitialReflow() && !mInner.mHadNonInitialReflow) { @@ -1010,6 +1100,63 @@ nsXULScrollFrame::GetType() const return nsGkAtoms::scrollFrame; } +void +nsXULScrollFrame::InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags) +{ + if (aForChild == mInner.mScrolledFrame) { + nsRect damage = aDamageRect + nsPoint(aX, aY); + // This is the damage rect that we're going to pass up to our parent. + nsRect parentDamage; + // If we're using a displayport, we might be displaying an area + // different than our scroll port and the damage needs to be + // clipped to that instead. + nsRect displayport; + bool usingDisplayport = nsLayoutUtils::GetDisplayPort(GetContent(), + &displayport); + if (usingDisplayport) { + parentDamage.IntersectRect(damage, displayport); + } else { + parentDamage.IntersectRect(damage, mInner.mScrollPort); + } + + if (IsScrollingActive()) { + // This is the damage rect that we're going to pass up and + // only request invalidation of ThebesLayers for. + // damage is now in our coordinate system, which means it was + // translated using the current scroll position. Adjust it to + // reflect the scroll position at last paint, since that's what + // the ThebesLayers are currently set up for. + // This should not be clipped to the scrollport since ThebesLayers + // can contain content outside the scrollport that may need to be + // invalidated. + nsRect thebesLayerDamage = damage + GetScrollPosition() - mInner.mScrollPosAtLastPaint; + if (parentDamage.IsEqualInterior(thebesLayerDamage)) { + // This single call will take care of both rects + nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags); + } else { + // Invalidate rects separately + if (!(aFlags & INVALIDATE_NO_THEBES_LAYERS)) { + nsBoxFrame::InvalidateInternal(thebesLayerDamage, 0, 0, aForChild, + aFlags | INVALIDATE_ONLY_THEBES_LAYERS); + } + if (!(aFlags & INVALIDATE_ONLY_THEBES_LAYERS) && !parentDamage.IsEmpty()) { + nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, + aFlags | INVALIDATE_NO_THEBES_LAYERS); + } + } + } else { + if (!parentDamage.IsEmpty()) { + nsBoxFrame::InvalidateInternal(parentDamage, 0, 0, aForChild, aFlags); + } + } + return; + } + + nsBoxFrame::InvalidateInternal(aDamageRect, aX, aY, aForChild, aFlags); +} + nscoord nsXULScrollFrame::GetBoxAscent(nsBoxLayoutState& aState) { @@ -1695,7 +1842,7 @@ InvalidateFixedBackgroundFramesFromList(nsDisplayListBuilder* aBuilder, item->IsVaryingRelativeToMovingFrame(aBuilder, aMovingFrame)) { if (FrameLayerBuilder::NeedToInvalidateFixedDisplayItem(aBuilder, item)) { // FrameLayerBuilder does not take care of scrolling this one - f->InvalidateFrame(); + f->Invalidate(item->GetVisibleRect() - item->ToReferenceFrame()); } } } @@ -1793,23 +1940,34 @@ void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos) AdjustViews(mScrolledFrame); // We need to call this after fixing up the view positions // to be consistent with the frame hierarchy. - bool invalidate = false; + uint32_t flags = nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT; bool canScrollWithBlitting = CanScrollWithBlitting(mOuter); mOuter->RemoveStateBits(NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL); if (IsScrollingActive()) { if (!canScrollWithBlitting) { MarkInactive(); } else { - invalidate = true; + flags |= nsIFrame::INVALIDATE_NO_THEBES_LAYERS; } } if (canScrollWithBlitting) { MarkActive(); } - mOuter->SchedulePaint(); + nsRect invalidateRect, displayPort; + bool hasDisplayPort = + nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort); + if (IsIgnoringViewportClipping()) { + nsRect visualOverflow = mScrolledFrame->GetVisualOverflowRect(); + invalidateRect.UnionRect(visualOverflow + mScrolledFrame->GetPosition(), + visualOverflow + aOldScrolledFramePos); + } else { + invalidateRect = hasDisplayPort ? displayPort : mScrollPort; + } + + mOuter->InvalidateWithFlags(invalidateRect, flags); - if (invalidate) { + if (flags & nsIFrame::INVALIDATE_NO_THEBES_LAYERS) { nsIFrame* displayRoot = nsLayoutUtils::GetDisplayRootFrame(mOuter); nsRect update = GetScrollPortRect() + mOuter->GetOffsetToCrossDoc(displayRoot); @@ -1817,6 +1975,25 @@ void nsGfxScrollFrameInner::ScrollVisual(nsPoint aOldScrolledFramePos) mOuter->PresContext()->AppUnitsPerDevPixel(), displayRoot->PresContext()->AppUnitsPerDevPixel()); InvalidateFixedBackgroundFrames(displayRoot, mScrolledFrame, displayRootUpdate); + + // Invalidate content that has scrolled into view. Normally, this will + // already be invalid, because it shouldn't have been drawn in any layer, + // but there can be stray rows/columns of pixels that partially overlapped + // the layer's visible region and hence were drawn and added to the layer's + // visible region, but these pixels ended up outside the cliprect after + // snapping so their contents need to be updated now that new content has + // scrolled into the cliprect. + nsPoint scrollDelta = mScrolledFrame->GetPosition() - aOldScrolledFramePos; + if (!hasDisplayPort) { + displayPort = GetScrollPortRect(); + } + nsRect preservedContents = displayPort + scrollDelta; + nsRegion invalidate; + invalidate.Sub(displayPort, preservedContents); + nsRegionRectIterator iter(invalidate); + while (const nsRect* r = iter.Next()) { + mOuter->InvalidateWithFlags(*r, nsIFrame::INVALIDATE_REASON_SCROLL_REPAINT); + } } } @@ -3083,6 +3260,28 @@ nsXULScrollFrame::LayoutScrollArea(nsBoxLayoutState& aState, ClampAndSetBounds(aState, childRect, aScrollPosition, true); } + nsRect finalRect = mInner.mScrolledFrame->GetRect(); + nsRect finalVisOverflow = mInner.mScrolledFrame->GetVisualOverflowRect(); + // The position of the scrolled frame shouldn't change, but if it does or + // the position of the overflow rect changes just invalidate both the old + // and new overflow rect. + if (originalRect.TopLeft() != finalRect.TopLeft() || + originalVisOverflow.TopLeft() != finalVisOverflow.TopLeft()) + { + // The old overflow rect needs to be adjusted if the frame's position + // changed. + mInner.mScrolledFrame->Invalidate( + originalVisOverflow + originalRect.TopLeft() - finalRect.TopLeft()); + mInner.mScrolledFrame->Invalidate(finalVisOverflow); + } else if (!originalVisOverflow.IsEqualInterior(finalVisOverflow)) { + // If the overflow rect changed then invalidate the difference between the + // old and new overflow rects. + mInner.mScrolledFrame->CheckInvalidateSizeChange( + originalRect, originalVisOverflow, finalRect.Size()); + mInner.mScrolledFrame->InvalidateRectDifference( + originalVisOverflow, finalVisOverflow); + } + aState.SetLayoutFlags(oldflags); } @@ -3496,6 +3695,40 @@ nsGfxScrollFrameInner::ReflowCallbackCanceled() mPostedReflowCallback = false; } +static void LayoutAndInvalidate(nsBoxLayoutState& aState, + nsIFrame* aBox, const nsRect& aRect, + bool aScrollbarIsBeingHidden) +{ + // When a child box changes shape of position, the parent + // is responsible for invalidation; the overflow rect must be invalidated + // to make sure to catch any overflow. + // We invalidate the parent (i.e. the scrollframe) directly, because + // invalidates coming from scrollbars are suppressed by nsHTMLScrollFrame when + // mHasVScrollbar/mHasHScrollbar is false, and this is called after those + // flags have been set ... if a scrollbar is being hidden, we still need + // to invalidate the scrollbar area here. + // But we also need to invalidate the scrollbar itself in case it has + // its own layer; we need to ensure that layer is updated. + bool rectChanged = !aBox->GetRect().IsEqualInterior(aRect); + if (rectChanged) { + if (aScrollbarIsBeingHidden) { + aBox->GetParent()->Invalidate(aBox->GetVisualOverflowRect() + + aBox->GetPosition()); + } else { + aBox->InvalidateFrameSubtree(); + } + } + nsBoxFrame::LayoutChildAt(aState, aBox, aRect); + if (rectChanged) { + if (aScrollbarIsBeingHidden) { + aBox->GetParent()->Invalidate(aBox->GetVisualOverflowRect() + + aBox->GetPosition()); + } else { + aBox->InvalidateFrameSubtree(); + } + } +} + bool nsGfxScrollFrameInner::UpdateOverflow() { @@ -3590,7 +3823,7 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState, } if (mScrollCornerBox) { - nsBoxFrame::LayoutChildAt(aState, mScrollCornerBox, r); + LayoutAndInvalidate(aState, mScrollCornerBox, r, false); } if (hasResizer) { @@ -3613,11 +3846,11 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState, r.y = aContentArea.YMost() - r.height; } - nsBoxFrame::LayoutChildAt(aState, mResizerBox, r); + LayoutAndInvalidate(aState, mResizerBox, r, false); } else if (mResizerBox) { // otherwise lay out the resizer with an empty rectangle - nsBoxFrame::LayoutChildAt(aState, mResizerBox, nsRect()); + LayoutAndInvalidate(aState, mResizerBox, nsRect(), false); } } @@ -3633,7 +3866,7 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState, vRect.Deflate(margin); } AdjustScrollbarRectForResizer(mOuter, presContext, vRect, hasResizer, true); - nsBoxFrame::LayoutChildAt(aState, mVScrollbarBox, vRect); + LayoutAndInvalidate(aState, mVScrollbarBox, vRect, !mHasVerticalScrollbar); } if (mHScrollbarBox) { @@ -3647,7 +3880,7 @@ nsGfxScrollFrameInner::LayoutScrollbars(nsBoxLayoutState& aState, hRect.Deflate(margin); } AdjustScrollbarRectForResizer(mOuter, presContext, hRect, hasResizer, false); - nsBoxFrame::LayoutChildAt(aState, mHScrollbarBox, hRect); + LayoutAndInvalidate(aState, mHScrollbarBox, hRect, !mHasHorizontalScrollbar); } // may need to update fixed position children of the viewport, diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h index d83d39a2115c9..a490535a1d95a 100644 --- a/layout/generic/nsGfxScrollFrame.h +++ b/layout/generic/nsGfxScrollFrame.h @@ -423,6 +423,10 @@ class nsHTMLScrollFrame : public nsContainerFrame, return mInner.GetScrolledFrame()->GetContentInsertionFrame(); } + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags); + virtual bool DoesClipChildren() { return true; } virtual nsSplittableType GetSplittableType() const; @@ -634,6 +638,10 @@ class nsXULScrollFrame : public nsBoxFrame, return mInner.GetScrolledFrame()->GetContentInsertionFrame(); } + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags); + virtual bool DoesClipChildren() { return true; } virtual nsSplittableType GetSplittableType() const; diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp index 3ec97f8114a69..d86a012c3b6d2 100644 --- a/layout/generic/nsHTMLCanvasFrame.cpp +++ b/layout/generic/nsHTMLCanvasFrame.cpp @@ -213,6 +213,10 @@ nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext, aMetrics.SetOverflowAreasToDesiredBounds(); FinishAndStoreOverflow(&aMetrics); + if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) { + Invalidate(nsRect(0, 0, mRect.width, mRect.height)); + } + // Reflow the single anon block child. nsReflowStatus childStatus; nsSize availSize(aReflowState.ComputedWidth(), NS_UNCONSTRAINEDSIZE); @@ -264,7 +268,7 @@ nsHTMLCanvasFrame::BuildLayer(nsDisplayListBuilder* aBuilder, return nullptr; CanvasLayer* oldLayer = static_cast - (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); + (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem)); nsRefPtr layer = element->GetCanvasLayer(aBuilder, oldLayer, aManager); if (!layer) return nullptr; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 583a7fca662ac..4e577dd285ea0 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -138,6 +138,10 @@ typedef uint64_t nsFrameState; // continuation, e.g. a bidi continuation. #define NS_FRAME_IS_FLUID_CONTINUATION NS_FRAME_STATE_BIT(2) +// This bit is set whenever the frame has one or more associated +// container layers. +#define NS_FRAME_HAS_CONTAINER_LAYER NS_FRAME_STATE_BIT(3) + // If this bit is set, then a reference to the frame is being held // elsewhere. The frame may want to send a notification when it is // destroyed to allow these references to be cleared. @@ -249,6 +253,10 @@ typedef uint64_t nsFrameState; // This bit acts as a loop flag for recursive paint server drawing. #define NS_FRAME_DRAWING_AS_PAINTSERVER NS_FRAME_STATE_BIT(33) +// Frame or one of its (cross-doc) descendants may have the +// NS_FRAME_HAS_CONTAINER_LAYER bit. +#define NS_FRAME_HAS_CONTAINER_LAYER_DESCENDANT NS_FRAME_STATE_BIT(34) + // Frame's overflow area was clipped by the 'clip' property. #define NS_FRAME_HAS_CLIP NS_FRAME_STATE_BIT(35) @@ -303,26 +311,6 @@ typedef uint64_t nsFrameState; // text layout. #define NS_FRAME_IS_SVG_TEXT NS_FRAME_STATE_BIT(47) -// Frame is marked as needing painting -#define NS_FRAME_NEEDS_PAINT NS_FRAME_STATE_BIT(48) - -// Frame has a descendant frame that needs painting - This includes -// cross-doc children. -#define NS_FRAME_DESCENDANT_NEEDS_PAINT NS_FRAME_STATE_BIT(49) - -// Frame is a descendant of a popup -#define NS_FRAME_IN_POPUP NS_FRAME_STATE_BIT(50) - -// Frame has only descendant frames that needs painting - This includes -// cross-doc children. This guarantees that all descendents have -// NS_FRAME_NEEDS_PAINT and NS_FRAME_ALL_DESCENDANTS_NEED_PAINT, or they -// have no display items. -#define NS_FRAME_ALL_DESCENDANTS_NEED_PAINT NS_FRAME_STATE_BIT(51) - -// Frame is marked as NS_FRAME_NEEDS_PAINT and also has an explicit -// rect stored to invalidate. -#define NS_FRAME_HAS_INVALID_RECT NS_FRAME_STATE_BIT(52) - // Box layout bits #define NS_STATE_IS_HORIZONTAL NS_FRAME_STATE_BIT(22) #define NS_STATE_IS_DIRECTION_NORMAL NS_FRAME_STATE_BIT(31) @@ -959,8 +947,6 @@ class nsIFrame : public nsQueryFrame NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImage, DestroySurface) - NS_DECLARE_FRAME_PROPERTY(InvalidationRect, DestroyRect) - /** * Return the distance between the border edge of the frame and the * margin edge of the frame. Like GetRect(), returns the dimensions @@ -1090,13 +1076,6 @@ class nsIFrame : public nsQueryFrame virtual const nsFrameList& GetChildList(ChildListID aListID) const = 0; const nsFrameList& PrincipalChildList() { return GetChildList(kPrincipalList); } virtual void GetChildLists(nsTArray* aLists) const = 0; - - /** - * Gets the child lists for this frame, including - * ones belong to a child document. - */ - void GetCrossDocChildLists(nsTArray* aLists); - // XXXbz this method should go away nsIFrame* GetFirstChild(ChildListID aListID) const { return GetChildList(aListID).FirstChild(); @@ -1420,16 +1399,6 @@ class nsIFrame : public nsQueryFrame void AddStateBits(nsFrameState aBits) { mState |= aBits; } void RemoveStateBits(nsFrameState aBits) { mState &= ~aBits; } - /** - * Checks if the current frame-state includes all of the listed bits - */ - bool HasAllStateBits(nsFrameState aBits) { return (mState & aBits) == aBits; } - - /** - * Checks if the current frame-state includes any of the listed bits - */ - bool HasAnyStateBits(nsFrameState aBits) { return mState & aBits; } - /** * This call is invoked on the primary frame for a character data content * node, when it is changed in the content tree. @@ -2178,105 +2147,141 @@ class nsIFrame : public nsQueryFrame bool AreLayersMarkedActive(nsChangeHint aChangeHint); /** - * Marks all display items created by this frame as needing a repaint, - * and calls SchedulePaint() if requested and one is not already pending. - * - * This includes all display items created by this frame, including - * container types. - * - * @param aDisplayItemKey If specified, only issues an invalidate - * if this frame painted a display item of that type during the - * previous paint. SVG rendering observers are always notified. + * @param aFlags see InvalidateInternal below */ - virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0); + void InvalidateWithFlags(const nsRect& aDamageRect, uint32_t aFlags); /** - * Same as InvalidateFrame(), but only mark a fixed rect as needing - * repainting. + * Invalidate part of the frame by asking the view manager to repaint. + * aDamageRect is allowed to extend outside the frame's bounds. We'll do the right + * thing. + * We deliberately don't have an Invalidate() method that defaults to the frame's bounds. + * We want all callers to *think* about what has changed in the frame and what area might + * need to be repainted. * - * @param aRect The rect to invalidate, relative to the TopLeft of the - * frame's border box. - * @param aDisplayItemKey If specified, only issues an invalidate - * if this frame painted a display item of that type during the - * previous paint. SVG rendering observers are always notified. + * @param aDamageRect is in the frame's local coordinate space */ - virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0); - + void Invalidate(const nsRect& aDamageRect) + { return InvalidateWithFlags(aDamageRect, 0); } + /** - * Calls InvalidateFrame() on all frames descendant frames (including - * this one). - * - * This function doesn't walk through placeholder frames to invalidate - * the out-of-flow frames. - * - * @param aDisplayItemKey If specified, only issues an invalidate - * if this frame painted a display item of that type during the - * previous paint. SVG rendering observers are always notified. + * As Invalidate above, except that this should be called when the + * rendering that has changed is performed using layers so we can avoid + * updating the contents of ThebesLayers. + * If the frame has a dedicated layer rendering this display item, we + * return that layer. + * @param aDisplayItemKey must not be zero; indicates the kind of display + * item that is being invalidated. */ - void InvalidateFrameSubtree(uint32_t aDisplayItemKey = 0); + Layer* InvalidateLayer(const nsRect& aDamageRect, uint32_t aDisplayItemKey); /** - * Called when a frame is about to be removed and needs to be invalidated. - * Normally does nothing since DLBI handles removed frames. - * + * Invalidate the area of the parent that's covered by the transformed + * visual overflow rect of this frame. Don't depend on the transform style + * for this frame, in case that's changed since this frame was painted. */ - virtual void InvalidateFrameForRemoval() {} - + void InvalidateTransformLayer(); + /** - * Checks if a frame has had InvalidateFrame() called on it since the - * last paint. + * Helper function that can be overridden by frame classes. The rectangle + * (plus aOffsetX/aOffsetY) is relative to this frame. + * + * The offset is given as two coords rather than as an nsPoint because + * gcc optimizes it better that way, in particular in the default + * implementation that passes the area to the parent frame becomes a tail + * call. * - * If true, then the invalid rect is returned in aRect, with an - * empty rect meaning all pixels drawn by this frame should be - * invalidated. - * If false, aRect is left unchanged. + * The default implementation will crash if the frame has no parent so + * frames without parents MUST* override. + * + * @param aForChild if the invalidation is coming from a child frame, this + * is the frame; otherwise, this is null. + * @param aFlags INVALIDATE_IMMEDIATE: repaint now if true, repaint later if false. + * In case it's true, pending notifications will be flushed which + * could cause frames to be deleted (including |this|). + * @param aFlags INVALIDATE_CROSS_DOC: true if the invalidation + * originated in a subdocument + * @param aFlags INVALIDATE_REASON_SCROLL_BLIT: set if the invalidation + * was really just the scroll machinery copying pixels from one + * part of the window to another + * @param aFlags INVALIDATE_REASON_SCROLL_REPAINT: set if the invalidation + * was triggered by scrolling + * @param aFlags INVALIDATE_NO_THEBES_LAYERS: don't invalidate the + * ThebesLayers of any container layer owned by an ancestor. Set this + * only if ThebesLayers definitely don't need to be updated. + * @param aFlags INVALIDATE_ONLY_THEBES_LAYERS: invalidate only in the + * ThebesLayers of the nearest container layer. + * @param aFlags INVALIDATE_EXCLUDE_CURRENT_PAINT: if the invalidation + * occurs while we're painting (to be precise, while + * BeginDeferringInvalidatesForDisplayRoot is active on the display root), + * then invalidation in the current paint region is simply discarded. + * Use this flag if areas that are being painted do not need + * to be invalidated. By default, when this flag is not specified, + * areas that are invalidated while currently being painted will be repainted + * again. + * This flag is useful when, during painting, FrameLayerBuilder discovers that + * a region of the window needs to be drawn differently, and that region + * may or may not be contained in the currently painted region. + * @param aFlags INVALIDATE_NO_UPDATE_LAYER_TREE: display lists and the + * layer tree do not need to be updated. This can be used when the layer + * tree has already been updated outside a transaction, e.g. via + * ImageContainer::SetCurrentImage. */ - bool IsInvalid(nsRect& aRect); - + enum { + INVALIDATE_IMMEDIATE = 0x01, + INVALIDATE_CROSS_DOC = 0x02, + INVALIDATE_REASON_SCROLL_BLIT = 0x04, + INVALIDATE_REASON_SCROLL_REPAINT = 0x08, + INVALIDATE_REASON_MASK = INVALIDATE_REASON_SCROLL_BLIT | + INVALIDATE_REASON_SCROLL_REPAINT, + INVALIDATE_NO_THEBES_LAYERS = 0x10, + INVALIDATE_ONLY_THEBES_LAYERS = 0x20, + INVALIDATE_EXCLUDE_CURRENT_PAINT = 0x40, + INVALIDATE_NO_UPDATE_LAYER_TREE = 0x80, + INVALIDATE_ALREADY_TRANSFORMED = 0x100 + }; + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aOffsetX, nscoord aOffsetY, + nsIFrame* aForChild, uint32_t aFlags); + /** - * Check if any frame within the frame subtree (including this frame) - * returns true for IsInvalid(). + * Helper function that funnels an InvalidateInternal request up to the + * parent. This function is used so that if MOZ_SVG is not defined, we still + * have unified control paths in the InvalidateInternal chain. + * + * @param aDamageRect The rect to invalidate. + * @param aX The x offset from the origin of this frame to the rectangle. + * @param aY The y offset from the origin of this frame to the rectangle. + * @param aImmediate Whether to redraw immediately. + * @return None, though this funnels the request up to the parent frame. */ - bool HasInvalidFrameInSubtree() - { - return HasAnyStateBits(NS_FRAME_NEEDS_PAINT | NS_FRAME_DESCENDANT_NEEDS_PAINT); - } + void InvalidateInternalAfterResize(const nsRect& aDamageRect, nscoord aX, + nscoord aY, uint32_t aFlags); /** - * Removes the invalid state from the current frame and all - * descendant frames. + * Take two rectangles in the coordinate system of this frame which + * have the same origin and invalidate the difference between them. + * This is a helper method to be used when a frame is being resized. + * + * @param aR1 the first rectangle + * @param aR2 the second rectangle */ - void ClearInvalidationStateBits(); + void InvalidateRectDifference(const nsRect& aR1, const nsRect& aR2); /** - * Ensures that the refresh driver is running, and schedules a view - * manager flush on the next tick. - * - * The view manager flush will update the layer tree, repaint any - * invalid areas in the layer tree and schedule a layer tree - * composite operation to display the layer tree. - * - * @param aFlags PAINT_COMPOSITE_ONLY : No changes have been made - * that require a layer tree update, so only schedule a layer - * tree composite. + * Invalidate the entire frame subtree for this frame. Invalidates this + * frame's overflow rect, and also ensures that all ThebesLayer children + * of ContainerLayers associated with frames in this subtree are + * completely invalidated. */ - enum { - PAINT_COMPOSITE_ONLY - }; - void SchedulePaint(uint32_t aFlags = 0); + void InvalidateFrameSubtree(); /** - * Checks if the layer tree includes a dedicated layer for this - * frame/display item key pair, and invalidates at least aDamageRect - * area within that layer. - * - * If no layer is found, calls InvalidateFrame() instead. - * - * @param aDamageRect Area of the layer to invalidate. - * @param aDisplayItemKey Display item type. - * @return Layer, if found, nullptr otherwise. + * Invalidates this frame's visual overflow rect. Does not necessarily + * cause ThebesLayers for descendant frames to be repainted; only this + * frame can be relied on to be repainted. */ - Layer* InvalidateLayer(uint32_t aDisplayItemKey, const nsIntRect* aDamageRect = nullptr); + void InvalidateOverflowRect(); /** * Returns a rect that encompasses everything that might be painted by @@ -2738,7 +2743,7 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::ParagraphDepthProperty())) bool IsHorizontal() const { return (mState & NS_STATE_IS_HORIZONTAL) != 0; } bool IsNormalDirection() const { return (mState & NS_STATE_IS_DIRECTION_NORMAL) != 0; } - NS_HIDDEN_(nsresult) Redraw(nsBoxLayoutState& aState); + NS_HIDDEN_(nsresult) Redraw(nsBoxLayoutState& aState, const nsRect* aRect = nullptr); NS_IMETHOD RelayoutChildAtOrdinal(nsBoxLayoutState& aState, nsIFrame* aChild)=0; // XXX take this out after we've branched virtual bool GetMouseThrough() const { return false; } @@ -2787,6 +2792,17 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::ParagraphDepthProperty())) */ CaretPosition GetExtremeCaretPosition(bool aStart); + /** + * Same thing as nsFrame::CheckInvalidateSizeChange, but more flexible. The + * implementation of this method must not depend on the mRect or + * GetVisualOverflowRect() of the frame! Note that it's safe to + * assume in this method that the frame origin didn't change. If it + * did, whoever moved the frame will invalidate as needed anyway. + */ + void CheckInvalidateSizeChange(const nsRect& aOldRect, + const nsRect& aOldVisualOverflowRect, + const nsSize& aNewDesiredSize); + /** * Get a line iterator for this frame, if supported. * @@ -2949,6 +2965,12 @@ NS_PTR_TO_INT32(frame->Properties().Get(nsIFrame::ParagraphDepthProperty())) } mOverflow; // Helpers + /** + * For frames that have top-level windows (top-level viewports, + * comboboxes, menupoups) this function will invalidate the window. + */ + void InvalidateRoot(const nsRect& aDamageRect, uint32_t aFlags); + /** * Can we stop inside this frame when we're skipping non-rendered whitespace? * @param aForward [in] Are we moving forward (or backward) in content order. diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 890783c2e2d10..550fb571f402d 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -587,20 +587,20 @@ nsImageFrame::OnDataAvailable(imgIRequest *aRequest, // from if (!aCurrentFrame) return NS_OK; - + + // XXX We really need to round this out, now that we're doing better + // image scaling! + nsRect r = aRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect()) ? + GetInnerArea() : + SourceRectToDest(*aRect); + #ifdef DEBUG_decode - printf("Source rect (%d,%d,%d,%d)\n", - aRect->x, aRect->y, aRect->width, aRect->height); + printf("Source rect (%d,%d,%d,%d) -> invalidate dest rect (%d,%d,%d,%d)\n", + aRect->x, aRect->y, aRect->width, aRect->height, + r.x, r.y, r.width, r.height); #endif - if (aRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect())) { - InvalidateFrame(nsDisplayItem::TYPE_IMAGE); - InvalidateFrame(nsDisplayItem::TYPE_ALT_FEEDBACK); - } else { - nsRect invalid = SourceRectToDest(*aRect); - InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_IMAGE); - InvalidateFrameWithRect(invalid, nsDisplayItem::TYPE_ALT_FEEDBACK); - } + Invalidate(r); return NS_OK; } @@ -659,8 +659,10 @@ nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest, NS_FRAME_IS_DIRTY); } } else { + nsSize s = GetSize(); + nsRect r(0, 0, s.width, s.height); // Update border+content to account for image change - InvalidateFrame(); + Invalidate(r); } } } @@ -679,7 +681,12 @@ nsImageFrame::FrameChanged(imgIRequest *aRequest, return NS_OK; } - InvalidateLayer(nsDisplayItem::TYPE_IMAGE); + nsRect r = aDirtyRect->IsEqualInterior(nsIntRect::GetMaxSizedIntRect()) ? + GetInnerArea() : + SourceRectToDest(*aDirtyRect); + + // Update border+content to account for image change + Invalidate(r); return NS_OK; } @@ -872,22 +879,16 @@ nsImageFrame::Reflow(nsPresContext* aPresContext, } aMetrics.SetOverflowAreasToDesiredBounds(); - nsEventStates contentState = mContent->AsElement()->State(); - bool imageOK = IMAGE_OK(contentState, true); - - // Determine if the size is available - bool haveSize = false; - if (loadStatus & imgIRequest::STATUS_SIZE_AVAILABLE) { - haveSize = true; - } + FinishAndStoreOverflow(&aMetrics); - if (!imageOK || !haveSize) { - nsRect altFeedbackSize(0, 0, - 2*(nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+ICON_PADDING+ALT_BORDER_WIDTH)), - 2*(nsPresContext::CSSPixelsToAppUnits(ICON_SIZE+ICON_PADDING+ALT_BORDER_WIDTH))); - aMetrics.mOverflowAreas.UnionAllWith(altFeedbackSize); + // Now that that's all done, check whether we're resizing... if we are, + // invalidate our rect. + // XXXbz we really only want to do this when reflow is completely done, but + // we have no way to detect when mRect changes (since SetRect is non-virtual, + // so this is the best we can do). + if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) { + Invalidate(nsRect(0, 0, mRect.width, mRect.height)); } - FinishAndStoreOverflow(&aMetrics); NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsImageFrame::Reflow: size=%d,%d", @@ -1044,33 +1045,6 @@ struct nsRecessedBorder : public nsStyleBorder { } }; -class nsDisplayAltFeedback : public nsDisplayItem { -public: - nsDisplayAltFeedback(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) - : nsDisplayItem(aBuilder, aFrame) {} - - virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) - { - *aSnap = false; - return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); - } - - virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) - { - nsImageFrame* f = static_cast(mFrame); - nsEventStates state = f->GetContent()->AsElement()->State(); - f->DisplayAltFeedback(*aCtx, - mVisibleRect, - IMAGE_OK(state, true) - ? nsImageFrame::gIconLoad->mLoadingImage - : nsImageFrame::gIconLoad->mBrokenImage, - ToReferenceFrame()); - - } - - NS_DISPLAY_DECL_NAME("AltFeedback", TYPE_ALT_FEEDBACK) -}; - void nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext, const nsRect& aDirtyRect, @@ -1185,6 +1159,19 @@ nsImageFrame::DisplayAltFeedback(nsRenderingContext& aRenderingContext, aRenderingContext.PopState(); } +static void PaintAltFeedback(nsIFrame* aFrame, nsRenderingContext* aCtx, + const nsRect& aDirtyRect, nsPoint aPt) +{ + nsImageFrame* f = static_cast(aFrame); + nsEventStates state = f->GetContent()->AsElement()->State(); + f->DisplayAltFeedback(*aCtx, + aDirtyRect, + IMAGE_OK(state, true) + ? nsImageFrame::gIconLoad->mLoadingImage + : nsImageFrame::gIconLoad->mBrokenImage, + aPt); +} + #ifdef DEBUG static void PaintDebugImageMap(nsIFrame* aFrame, nsRenderingContext* aCtx, const nsRect& aDirtyRect, nsPoint aPt) { @@ -1386,7 +1373,8 @@ nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, // No image yet, or image load failed. Draw the alt-text and an icon // indicating the status rv = replacedContent.AppendNewToTop(new (aBuilder) - nsDisplayAltFeedback(aBuilder, this)); + nsDisplayGeneric(aBuilder, this, PaintAltFeedback, "AltFeedback", + nsDisplayItem::TYPE_ALT_FEEDBACK)); NS_ENSURE_SUCCESS(rv, rv); } else { @@ -2023,7 +2011,7 @@ nsImageFrame::IconLoad::OnStopRequest(imgIRequest *aRequest, nsImageFrame *frame; while (iter.HasMore()) { frame = iter.GetNext(); - frame->InvalidateFrame(); + frame->Invalidate(frame->GetRect()); } return NS_OK; @@ -2044,7 +2032,7 @@ nsImageFrame::IconLoad::FrameChanged(imgIRequest *aRequest, nsImageFrame *frame; while (iter.HasMore()) { frame = iter.GetNext(); - frame->InvalidateFrame(); + frame->Invalidate(frame->GetRect()); } return NS_OK; diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index dbb68ae5b3e62..3cd892f697a46 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -362,13 +362,15 @@ class nsImageFrame : public ImageFrameSuper { * image itself, and hence receive events just as if the image itself * received events. */ -class nsDisplayImage : public nsDisplayImageContainer { +class nsDisplayImage : public nsDisplayItem { public: + typedef mozilla::layers::ImageContainer ImageContainer; + typedef mozilla::layers::ImageLayer ImageLayer; typedef mozilla::layers::LayerManager LayerManager; nsDisplayImage(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame, imgIContainer* aImage) - : nsDisplayImageContainer(aBuilder, aFrame), mImage(aImage) { + : nsDisplayItem(aBuilder, aFrame), mImage(aImage) { MOZ_COUNT_CTOR(nsDisplayImage); } virtual ~nsDisplayImage() { @@ -381,7 +383,7 @@ class nsDisplayImage : public nsDisplayImageContainer { * Returns an ImageContainer for this image if the image type * supports it (TYPE_RASTER only). */ - virtual already_AddRefed GetContainer() MOZ_OVERRIDE; + already_AddRefed GetContainer(); gfxRect GetDestRect(); @@ -397,7 +399,7 @@ class nsDisplayImage : public nsDisplayImageContainer { * Configure an ImageLayer for this display item. * Set the required filter and scaling transform. */ - virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE; + void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset); NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE) private: diff --git a/layout/generic/nsImageMap.cpp b/layout/generic/nsImageMap.cpp index a55fe437c748a..b5f3d96fb7e76 100644 --- a/layout/generic/nsImageMap.cpp +++ b/layout/generic/nsImageMap.cpp @@ -981,7 +981,9 @@ nsImageMap::HandleEvent(nsIDOMEvent* aEvent) area->HasFocus(focus); //Now invalidate the rect if (mImageFrame) { - mImageFrame->InvalidateFrame(); + nsRect dmgRect; + area->GetRect(mImageFrame, dmgRect); + mImageFrame->Invalidate(dmgRect); } break; } diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index cd2b2679f9946..5be34f9004735 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -427,7 +427,7 @@ nsObjectFrame::PrepForDrawing(nsIWidget *aWidget) // plugins are painted through Thebes and we need to ensure // the Thebes layer containing the plugin is updated. if (parentWidget == GetNearestWidget()) { - InvalidateFrame(); + Invalidate(GetContentRectRelativeToSelf()); } #endif @@ -1638,7 +1638,7 @@ nsObjectFrame::BuildLayer(nsDisplayListBuilder* aBuilder, // to provide crisper and faster drawing. r.Round(); nsRefPtr layer = - (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); + (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem)); if (aItem->GetType() == nsDisplayItem::TYPE_PLUGIN) { if (!layer) { diff --git a/layout/generic/nsPageFrame.cpp b/layout/generic/nsPageFrame.cpp index 29b61fe8de4c2..2f81e5a74cd95 100644 --- a/layout/generic/nsPageFrame.cpp +++ b/layout/generic/nsPageFrame.cpp @@ -363,7 +363,6 @@ nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext, * Remove all leaf display items that are not for descendants of * aBuilder->GetReferenceFrame() from aList, and move all nsDisplayClip * wrappers to their correct locations. - * @param aPage the page we're constructing the display list for * @param aExtraPage the page we constructed aList for * @param aY the Y-coordinate where aPage would be positioned relative * to the main page (aBuilder->GetReferenceFrame()), considering only @@ -372,10 +371,11 @@ nsPageFrame::DrawHeaderFooter(nsRenderingContext& aRenderingContext, */ static void PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, - nsPageFrame* aPage, nsIFrame* aExtraPage, - nscoord aY, nsDisplayList* aList) + nsIFrame* aExtraPage, nscoord aY, nsDisplayList* aList) { nsDisplayList newList; + // The page which we're really constructing a display list for + nsIFrame* mainPage = aBuilder->RootReferenceFrame(); while (true) { nsDisplayItem* i = aList->RemoveBottom(); @@ -383,7 +383,7 @@ PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, break; nsDisplayList* subList = i->GetList(); if (subList) { - PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, aY, subList); + PruneDisplayListForExtraPage(aBuilder, aExtraPage, aY, subList); nsDisplayItem::Type type = i->GetType(); if (type == nsDisplayItem::TYPE_CLIP || type == nsDisplayItem::TYPE_CLIP_ROUNDED_RECT) { @@ -400,12 +400,12 @@ PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, // (bug 426909). nsDisplayClip* clip = static_cast(i); clip->SetClipRect(clip->GetClipRect() + nsPoint(0, aY) - - aExtraPage->GetOffsetTo(aBuilder->FindReferenceFrameFor(aPage))); + aExtraPage->GetOffsetTo(mainPage)); } newList.AppendToTop(i); } else { nsIFrame* f = i->GetUnderlyingFrame(); - if (f && nsLayoutUtils::IsProperAncestorFrameCrossDoc(aPage, f)) { + if (f && nsLayoutUtils::IsProperAncestorFrameCrossDoc(mainPage, f)) { // This one is in the page we care about, keep it newList.AppendToTop(i); } else { @@ -421,8 +421,7 @@ PruneDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, static nsresult BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, - nsPageFrame* aPage, nsIFrame* aExtraPage, - nscoord aY, nsDisplayList* aList) + nsIFrame* aPage, nscoord aY, nsDisplayList* aList) { nsDisplayList list; // Pass an empty dirty rect since we're only interested in finding @@ -431,11 +430,10 @@ BuildDisplayListForExtraPage(nsDisplayListBuilder* aBuilder, // have already been marked as NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO. // Note that we should still do a prune step since we don't want to // rely on dirty-rect checking for correctness. - nsresult rv = - aExtraPage->BuildDisplayListForStackingContext(aBuilder, nsRect(), &list); + nsresult rv = aPage->BuildDisplayListForStackingContext(aBuilder, nsRect(), &list); if (NS_FAILED(rv)) return rv; - PruneDisplayListForExtraPage(aBuilder, aPage, aExtraPage, aY, &list); + PruneDisplayListForExtraPage(aBuilder, aPage, aY, &list); aList->AppendToTop(&list); return NS_OK; } @@ -500,7 +498,7 @@ nsPageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsIFrame* page = child; nscoord y = child->GetSize().height; while ((page = GetNextPage(page)) != nullptr) { - rv = BuildDisplayListForExtraPage(aBuilder, this, page, y, &content); + rv = BuildDisplayListForExtraPage(aBuilder, page, y, &content); if (NS_FAILED(rv)) break; y += page->GetSize().height; diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp index 919eec3c332a5..c3880dbdb5a4a 100644 --- a/layout/generic/nsPlaceholderFrame.cpp +++ b/layout/generic/nsPlaceholderFrame.cpp @@ -135,6 +135,7 @@ nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot) nsIPresShell* shell = PresContext()->GetPresShell(); nsIFrame* oof = mOutOfFlowFrame; if (oof) { + oof->InvalidateFrameSubtree(); // Unregister out-of-flow frame shell->FrameManager()->UnregisterPlaceholderFrame(this); mOutOfFlowFrame = nullptr; @@ -145,7 +146,7 @@ nsPlaceholderFrame::DestroyFrom(nsIFrame* aDestructRoot) ((GetStateBits() & PLACEHOLDER_FOR_POPUP) || !nsLayoutUtils::IsProperAncestorFrame(aDestructRoot, oof))) { ChildListID listId = nsLayoutUtils::GetChildListNameFor(oof); - shell->FrameManager()->RemoveFrame(listId, oof); + shell->FrameManager()->RemoveFrame(listId, oof, false); } // else oof will be destroyed by its parent } diff --git a/layout/generic/nsSimplePageSequence.cpp b/layout/generic/nsSimplePageSequence.cpp index 9a72efd7557d2..05490b9284643 100644 --- a/layout/generic/nsSimplePageSequence.cpp +++ b/layout/generic/nsSimplePageSequence.cpp @@ -674,6 +674,19 @@ nsSimplePageSequenceFrame::PrePrintNextPage(nsITimerCallback* aCallback, bool* a return NS_OK; } +void +nsSimplePageSequenceFrame::InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, + nsIFrame* aForChild, + uint32_t aFlags) +{ + // xxx Invalidate the entire frame as otherwise invalidate of printCanvas + // don't work properly. This is hopefully no longer necessary once 539356 + // lands. + nsContainerFrame::InvalidateInternal( + nsRect(nsPoint(0,0), GetSize()), 0, 0, aForChild, aFlags); +} + NS_IMETHODIMP nsSimplePageSequenceFrame::ResetPrintCanvasList() { diff --git a/layout/generic/nsSimplePageSequence.h b/layout/generic/nsSimplePageSequence.h index c5895eab81c47..c4474b981351c 100644 --- a/layout/generic/nsSimplePageSequence.h +++ b/layout/generic/nsSimplePageSequence.h @@ -98,6 +98,10 @@ class nsSimplePageSequenceFrame : public nsContainerFrame, */ virtual nsIAtom* GetType() const; + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, + nsIFrame* aForChild, + uint32_t aFlags); #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const; #endif diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 47815a6531656..92a70479a52e5 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -53,7 +53,6 @@ #include "nsObjectFrame.h" #include "nsIServiceManager.h" #include "nsContentUtils.h" -#include "LayerTreeInvalidation.h" // For Accessibility #ifdef ACCESSIBILITY @@ -384,16 +383,14 @@ nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, nsDisplayZoom* zoomItem = new (aBuilder) nsDisplayZoom(aBuilder, subdocRootFrame, &childItems, - subdocAPD, parentAPD, - nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS); + subdocAPD, parentAPD); childItems.AppendToTop(zoomItem); } if (!addedLayer && presContext->IsRootContentDocument()) { // We always want top level content documents to be in their own layer. nsDisplayOwnLayer* layerItem = new (aBuilder) nsDisplayOwnLayer( - aBuilder, subdocRootFrame ? subdocRootFrame : this, - &childItems, nsDisplayOwnLayer::GENERATE_SUBDOC_INVALIDATIONS); + aBuilder, subdocRootFrame ? subdocRootFrame : this, &childItems); childItems.AppendToTop(layerItem); } @@ -659,6 +656,9 @@ nsSubDocumentFrame::Reflow(nsPresContext* aPresContext, } } + // Determine if we need to repaint our border, background or outline + CheckInvalidateSizeChange(aDesiredSize); + FinishAndStoreOverflow(&aDesiredSize); if (!aPresContext->IsPaginated() && !mPostedReflowCallback) { @@ -954,9 +954,6 @@ nsSubDocumentFrame::BeginSwapDocShells(nsIFrame* aOther) return NS_ERROR_NOT_IMPLEMENTED; } - NS_ASSERTION(HasAnyStateBits(NS_FRAME_IN_POPUP) == other->HasAnyStateBits(NS_FRAME_IN_POPUP), - "Can't swap doc shells when only one is within a popup!"); - if (mInnerView && other->mInnerView) { nsIView* ourSubdocViews = mInnerView->GetFirstChild(); nsIView* ourRemovedViews = ::BeginSwapDocShellsForViews(ourSubdocViews); @@ -1011,14 +1008,6 @@ EndSwapDocShellsForViews(nsIView* aSibling) if (doc) { ::EndSwapDocShellsForDocument(doc, nullptr); } - nsIFrame *frame = aSibling->GetFrame(); - if (frame && frame->HasInvalidFrameInSubtree()) { - nsIFrame *parent = nsLayoutUtils::GetCrossDocParentFrame(frame); - while (parent && !parent->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) { - parent->AddStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT); - parent = nsLayoutUtils::GetCrossDocParentFrame(parent); - } - } } } diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h index b28c3bd02e191..3dc2c396cf548 100644 --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -29,17 +29,12 @@ class PropertyProvider; typedef nsFrame nsTextFrameBase; -class nsDisplayTextGeometry; -class nsDisplayText; - class nsTextFrame : public nsTextFrameBase { public: NS_DECL_QUERYFRAME_TARGET(nsTextFrame) NS_DECL_FRAMEARENA_HELPERS friend class nsContinuingTextFrame; - friend class nsDisplayTextGeometry; - friend class nsDisplayText; nsTextFrame(nsStyleContext* aContext) : nsTextFrameBase(aContext) @@ -587,10 +582,6 @@ class nsTextFrame : public nsTextFrameBase { mColor == aOther.mColor && mBaselineOffset == aOther.mBaselineOffset; } - - bool operator!=(const LineDecoration& aOther) const { - return !(*this == aOther); - } }; struct TextDecorations { nsAutoTArray mOverlines, mUnderlines, mStrikes; @@ -609,16 +600,6 @@ class nsTextFrame : public nsTextFrameBase { bool HasStrikeout() const { return !mStrikes.IsEmpty(); } - bool operator==(const TextDecorations& aOther) const { - return mOverlines == aOther.mOverlines && - mUnderlines == aOther.mUnderlines && - mStrikes == aOther.mStrikes; - } - - bool operator!=(const TextDecorations& aOther) const { - return !(*this == aOther); - } - }; enum TextDecorationColorResolution { eResolvedColors, diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp index 7d2136c8d51f8..c5be4845a84c3 100644 --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -3383,7 +3383,8 @@ NS_IMETHODIMP nsBlinkTimer::Notify(nsITimer *timer) // Determine damaged area and tell view manager to redraw it // blink doesn't blink outline ... I hope - frameData.mFrame->InvalidateFrame(); + nsRect bounds(nsPoint(0, 0), frameData.mFrame->GetSize()); + frameData.mFrame->Invalidate(bounds); } return NS_OK; } @@ -4430,7 +4431,6 @@ nsTextFrame::CharacterDataChanged(CharacterDataChangeInfo* aInfo) // will do that when it gets called during reflow. textFrame->AddStateBits(NS_FRAME_IS_DIRTY); } - textFrame->InvalidateFrame(); // Below, frames that start after the deleted text will be adjusted so that // their offsets move with the trailing unchanged text. If this change @@ -4471,25 +4471,7 @@ nsTextFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { nsFrame::DidSetStyleContext(aOldStyleContext); ClearTextRuns(); -} - -class nsDisplayTextGeometry : public nsDisplayItemGenericGeometry -{ -public: - nsDisplayTextGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) - : nsDisplayItemGenericGeometry(aItem, aBuilder) - { - nsTextFrame* f = static_cast(aItem->GetUnderlyingFrame()); - f->GetTextDecorations(f->PresContext(), nsTextFrame::eResolvedColors, mDecorations); - } - - /** - * We store the computed text decorations here since they are - * computed using style data from parent frames. Any changes to these - * styles will only invalidate the parent frame and not this frame. - */ - nsTextFrame::TextDecorations mDecorations; -}; +} class nsDisplayText : public nsCharClipDisplayItem { public: @@ -4506,10 +4488,7 @@ class nsDisplayText : public nsCharClipDisplayItem { virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder, bool* aSnap) { *aSnap = false; - nsRect temp = mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); - // Bug 748228 - temp.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel()); - return temp; + return mFrame->GetVisualOverflowRectRelativeToSelf() + ToReferenceFrame(); } virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect, HitTestState* aState, nsTArray *aOutFrames) { @@ -4527,31 +4506,6 @@ class nsDisplayText : public nsCharClipDisplayItem { return GetBounds(aBuilder, &snap); } - virtual nsDisplayItemGeometry* AllocateGeometry(nsDisplayListBuilder* aBuilder) - { - return new nsDisplayTextGeometry(this, aBuilder); - } - - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion *aInvalidRegion) - { - const nsDisplayTextGeometry* geometry = static_cast(aGeometry); - nsTextFrame* f = static_cast(mFrame); - - nsTextFrame::TextDecorations decorations; - f->GetTextDecorations(f->PresContext(), nsTextFrame::eResolvedColors, decorations); - - bool snap; - nsRect newRect = geometry->mBounds; - nsRect oldRect = GetBounds(aBuilder, &snap); - if (decorations != geometry->mDecorations || - !oldRect.IsEqualInterior(newRect) || - !geometry->mBorderRect.IsEqualInterior(GetBorderRect())) { - aInvalidRegion->Or(oldRect, newRect); - } - } - virtual void DisableComponentAlpha() { mDisableSubpixelAA = true; } bool mDisableSubpixelAA; @@ -6328,7 +6282,7 @@ nsTextFrame::SetSelectedRange(uint32_t aStart, uint32_t aEnd, bool aSelected, } } // Selection might change anything. Invalidate the overflow area. - f->InvalidateFrame(); + f->InvalidateOverflowRect(); f = static_cast(f->GetNextContinuation()); } @@ -8101,7 +8055,7 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth, SetLength(contentLength, &aLineLayout, ALLOW_FRAME_CREATION_AND_DESTRUCTION); - InvalidateFrame(); + Invalidate(aMetrics.VisualOverflow()); #ifdef NOISY_REFLOW ListTag(stdout); diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index 4af756a90b399..6982dcd213b43 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -196,7 +196,7 @@ nsVideoFrame::BuildLayer(nsDisplayListBuilder* aBuilder, container->SetScaleHint(scaleHint); nsRefPtr layer = static_cast - (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); + (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem)); if (!layer) { layer = aManager->CreateImageLayer(); if (!layer) @@ -301,6 +301,10 @@ nsVideoFrame::Reflow(nsPresContext* aPresContext, FinishAndStoreOverflow(&aMetrics); + if (mRect.width != aMetrics.width || mRect.height != aMetrics.height) { + Invalidate(nsRect(0, 0, mRect.width, mRect.height)); + } + NS_FRAME_TRACE(NS_FRAME_TRACE_CALLS, ("exit nsVideoFrame::Reflow: size=%d,%d", aMetrics.width, aMetrics.height)); diff --git a/layout/generic/nsViewportFrame.cpp b/layout/generic/nsViewportFrame.cpp index 524d1ce448889..333f0bf945ca9 100644 --- a/layout/generic/nsViewportFrame.cpp +++ b/layout/generic/nsViewportFrame.cpp @@ -34,16 +34,7 @@ ViewportFrame::Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow) { - nsresult rv = Super::Init(aContent, aParent, aPrevInFlow); - - nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this); - if (parent) { - nsFrameState state = parent->GetStateBits(); - - mState |= state & (NS_FRAME_IN_POPUP); - } - - return rv; + return Super::Init(aContent, aParent, aPrevInFlow); } void @@ -263,7 +254,8 @@ ViewportFrame::Reflow(nsPresContext* aPresContext, // If we were dirty then do a repaint if (GetStateBits() & NS_FRAME_IS_DIRTY) { - InvalidateFrame(); + nsRect damageRect(0, 0, aDesiredSize.width, aDesiredSize.height); + Invalidate(damageRect); } // Clipping is handled by the document container (e.g., nsSubDocumentFrame), @@ -291,6 +283,40 @@ ViewportFrame::GetType() const return nsGkAtoms::viewportFrame; } +void +ViewportFrame::InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags) +{ + nsRect r = aDamageRect + nsPoint(aX, aY); + nsPresContext* presContext = PresContext(); + presContext->NotifyInvalidation(r, aFlags); + + if ((mState & NS_FRAME_HAS_CONTAINER_LAYER) && + !(aFlags & INVALIDATE_NO_THEBES_LAYERS)) { + FrameLayerBuilder::InvalidateThebesLayerContents(this, r); + // Don't need to invalidate any more Thebes layers + aFlags |= INVALIDATE_NO_THEBES_LAYERS; + if (aFlags & INVALIDATE_ONLY_THEBES_LAYERS) { + return; + } + } + + nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this); + if (parent) { + if (!presContext->PresShell()->IsActive()) + return; + nsPoint pt = -parent->GetOffsetToCrossDoc(this); + int32_t ourAPD = presContext->AppUnitsPerDevPixel(); + int32_t parentAPD = parent->PresContext()->AppUnitsPerDevPixel(); + r = r.ConvertAppUnitsRoundOut(ourAPD, parentAPD); + parent->InvalidateInternal(r, pt.x, pt.y, this, + aFlags | INVALIDATE_CROSS_DOC); + return; + } + InvalidateRoot(r, aFlags); +} + #ifdef DEBUG NS_IMETHODIMP ViewportFrame::GetFrameName(nsAString& aResult) const diff --git a/layout/generic/nsViewportFrame.h b/layout/generic/nsViewportFrame.h index 01693b12b61ca..51da058510940 100644 --- a/layout/generic/nsViewportFrame.h +++ b/layout/generic/nsViewportFrame.h @@ -70,6 +70,10 @@ class ViewportFrame : public nsContainerFrame { */ virtual nsIAtom* GetType() const MOZ_OVERRIDE; + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags); + #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const MOZ_OVERRIDE; #endif diff --git a/layout/inspector/src/inFlasher.cpp b/layout/inspector/src/inFlasher.cpp index 51b52dfbc186a..81d61259b86e4 100644 --- a/layout/inspector/src/inFlasher.cpp +++ b/layout/inspector/src/inFlasher.cpp @@ -103,7 +103,7 @@ inFlasher::RepaintElement(nsIDOMElement* aElement) nsIFrame* frame = inLayoutUtils::GetFrameFor(aElement); if (!frame) return NS_OK; - frame->InvalidateFrame(); + frame->Invalidate(frame->GetRect()); return NS_OK; } diff --git a/layout/ipc/RenderFrameParent.cpp b/layout/ipc/RenderFrameParent.cpp index 28fd8829dde67..6afc31ecf5319 100644 --- a/layout/ipc/RenderFrameParent.cpp +++ b/layout/ipc/RenderFrameParent.cpp @@ -646,7 +646,7 @@ RenderFrameParent::BuildLayer(nsDisplayListBuilder* aBuilder, MOZ_ASSERT(!GetRootLayer()); nsRefPtr layer = - (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aItem)); + (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, aManager, aItem)); if (!layer) { layer = aManager->CreateRefLayer(); } @@ -838,7 +838,17 @@ RenderFrameParent::TriggerRepaint() return; } - docFrame->SchedulePaint(); + // FIXME/cjones: we should collect the rects/regions updated for + // Painted*Layer() calls and pass that region to here, then only + // invalidate that rect + // + // We pass INVALIDATE_NO_THEBES_LAYERS here because we're + // invalidating the on behalf of its counterpart in the + // content process. Not only do we not need to invalidate the + // shadow layers, things would just break if we did --- we have no + // way to repaint shadow layers from this process. + nsRect rect = nsRect(nsPoint(0, 0), docFrame->GetRect().Size()); + docFrame->InvalidateWithFlags(rect, nsIFrame::INVALIDATE_NO_THEBES_LAYERS); } ShadowLayersParent* diff --git a/layout/mathml/nsMathMLChar.cpp b/layout/mathml/nsMathMLChar.cpp index 0faa1920e8e59..4b37db0bcdf7d 100644 --- a/layout/mathml/nsMathMLChar.cpp +++ b/layout/mathml/nsMathMLChar.cpp @@ -1683,13 +1683,10 @@ class nsDisplayMathMLCharForeground : public nsDisplayItem { nsPoint offset = ToReferenceFrame() + rect.TopLeft(); nsBoundingMetrics bm; mChar->GetBoundingMetrics(bm); - nsRect temp(offset.x + bm.leftBearing, offset.y, - bm.rightBearing - bm.leftBearing, bm.ascent + bm.descent); - // Bug 748220 - temp.Inflate(mFrame->PresContext()->AppUnitsPerDevPixel()); - return temp; + return nsRect(offset.x + bm.leftBearing, offset.y, + bm.rightBearing - bm.leftBearing, bm.ascent + bm.descent); } - + virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx) { diff --git a/layout/reftests/bidi/reftest.list b/layout/reftests/bidi/reftest.list index a2c1d60f2818c..f2f2a24652adb 100644 --- a/layout/reftests/bidi/reftest.list +++ b/layout/reftests/bidi/reftest.list @@ -16,8 +16,8 @@ random-if(cocoaWidget) == bidi-006-j.html bidi-006-ref.html # bug 734313 == bidiSVG-04.svg bidiSVG-04-ref.svg == bidiSVG-05.svg bidiSVG-05-ref.svg == bidiMirroring.svg bidiMirroring-ref.svg -fuzzy-if(Android,9,134) random-if(layersGPUAccelerated) == visualmarquee.html marquee-ref.html -fuzzy-if(Android,9,134) random-if(layersGPUAccelerated) == logicalmarquee.html marquee-ref.html +random-if(layersGPUAccelerated) == visualmarquee.html marquee-ref.html +random-if(layersGPUAccelerated) == logicalmarquee.html marquee-ref.html == visualmarquee.html logicalmarquee.html # test for glyph mirroring in right-to-left text == mirroring-01.html mirroring-01-ref.html @@ -100,7 +100,7 @@ random-if(winWidget) == 305643-1.html 305643-1-ref.html # depends on windows ver == 613149-1a.html 613149-1-ref.html == 613149-1b.html 613149-1-ref.html fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia) == 613149-2a.html 613149-2-ref.html # bug 696672 -fuzzy-if(Android,24,1) fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia) == 613149-2b.html 613149-2-ref.html # bug 696672 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia) == 613149-2b.html 613149-2-ref.html # bug 696672 == 613157-1.html 613157-1-ref.html fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated&&!azureSkia) == 613157-2.html 613157-2-ref.html # bug 696673 == 662288-1.html 662288-1-ref.html diff --git a/layout/reftests/bugs/482659-1a.html b/layout/reftests/bugs/482659-1a.html index 26439e4e94fd3..c183b4af3e584 100644 --- a/layout/reftests/bugs/482659-1a.html +++ b/layout/reftests/bugs/482659-1a.html @@ -2,12 +2,11 @@ diff --git a/layout/reftests/bugs/482659-1b.html b/layout/reftests/bugs/482659-1b.html index 281ba38205757..a47a36e92b9ee 100644 --- a/layout/reftests/bugs/482659-1b.html +++ b/layout/reftests/bugs/482659-1b.html @@ -2,12 +2,11 @@ diff --git a/layout/reftests/bugs/482659-1c.html b/layout/reftests/bugs/482659-1c.html index ce753a3d9aa8b..2bdc54c3aaa10 100644 --- a/layout/reftests/bugs/482659-1c.html +++ b/layout/reftests/bugs/482659-1c.html @@ -2,7 +2,7 @@ diff --git a/layout/reftests/bugs/482659-1d.html b/layout/reftests/bugs/482659-1d.html index d4ad92e4008fd..e77aea6ad7fd1 100644 --- a/layout/reftests/bugs/482659-1d.html +++ b/layout/reftests/bugs/482659-1d.html @@ -2,7 +2,7 @@ diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 95950bf5fff9f..671f59f065796 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1316,7 +1316,7 @@ fails-if(Android) random-if(winWidget) fails-if(gtk2Widget) == 481948-3.html 481 == 482398-1.html 482398-1-ref.html random-if(d2d) == 482592-1a.xhtml 482592-1-ref.html # bug 586771 random-if(d2d) == 482592-1b.xhtml 482592-1-ref.html # bug 586771 -random-if(winWidget) == 482659-1a.html 482659-1-ref.html +== 482659-1a.html 482659-1-ref.html == 482659-1b.html 482659-1-ref.html == 482659-1c.html 482659-1-ref.html == 482659-1d.html 482659-1-ref.html @@ -1568,7 +1568,7 @@ fails-if(Android) random-if(layersGPUAccelerated) fails-if(/^Windows\x20NT\x205\ == 582037-1b.html 582037-1-ref.html == 582037-2a.html 582037-2-ref.html == 582037-2b.html 582037-2-ref.html -asserts(0-12) == 582146-1.html about:blank +asserts(0-11) == 582146-1.html about:blank == 582476-1.svg 582476-1-ref.svg == 584400-dash-length.svg 584400-dash-length-ref.svg == 584699-1.html 584699-1-ref.html diff --git a/layout/reftests/css-invalid/input/input-customerror.html b/layout/reftests/css-invalid/input/input-customerror.html index b954d67c786f5..2fdfcc4ceb602 100644 --- a/layout/reftests/css-invalid/input/input-customerror.html +++ b/layout/reftests/css-invalid/input/input-customerror.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-invalid/input/input-type-invalid.html b/layout/reftests/css-invalid/input/input-type-invalid.html index e37173edec6c8..23fbec2db61fe 100644 --- a/layout/reftests/css-invalid/input/input-type-invalid.html +++ b/layout/reftests/css-invalid/input/input-type-invalid.html @@ -5,16 +5,15 @@ it should not be affected by :valid pseudo-class. --> - + diff --git a/layout/reftests/css-invalid/input/reftest.list b/layout/reftests/css-invalid/input/reftest.list index 3bf1df13a2e02..76d5ffd607de3 100644 --- a/layout/reftests/css-invalid/input/reftest.list +++ b/layout/reftests/css-invalid/input/reftest.list @@ -1,5 +1,5 @@ == input-valid.html input-ref.html -fuzzy(11,4) == input-customerror.html input-ref.html +== input-customerror.html input-ref.html fails-if(Android) == input-disabled.html input-ref.html fails-if(Android) == input-dyn-disabled.html input-ref.html == input-dyn-not-disabled.html input-ref.html @@ -19,7 +19,7 @@ fails-if(Android) == input-dyn-disabled.html input-ref.html == input-pattern-valid.html input-withtext-ref.html == input-pattern-invalid.html input-withtext-ref.html == input-type-barred.html input-button-ref.html -fuzzy(11,4) == input-type-invalid.html input-ref.html +== input-type-invalid.html input-ref.html == input-disabled-fieldset-1.html input-fieldset-ref.html == input-disabled-fieldset-2.html input-fieldset-ref.html == input-fieldset-legend.html input-fieldset-legend-ref.html diff --git a/layout/reftests/css-invalid/textarea/reftest.list b/layout/reftests/css-invalid/textarea/reftest.list index e30706452b7ab..855a9ad47f5f7 100644 --- a/layout/reftests/css-invalid/textarea/reftest.list +++ b/layout/reftests/css-invalid/textarea/reftest.list @@ -1,11 +1,11 @@ == textarea-valid.html textarea-ref.html -fuzzy(11,4) == textarea-customerror.html textarea-ref.html +== textarea-customerror.html textarea-ref.html fails-if(Android) == textarea-disabled.html textarea-ref.html -fuzzy(11,4) fails-if(Android) == textarea-dyn-disabled.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-not-disabled.html textarea-ref.html +fails-if(Android) == textarea-dyn-disabled.html textarea-ref.html +== textarea-dyn-not-disabled.html textarea-ref.html == textarea-readonly.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-readonly.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-not-readonly.html textarea-ref.html +== textarea-dyn-readonly.html textarea-ref.html +== textarea-dyn-not-readonly.html textarea-ref.html == textarea-maxlength-valid.html textarea-ref.html == textarea-maxlength-invalid.html textarea-withtext-ref.html == textarea-required-valid.html textarea-withtext-ref.html diff --git a/layout/reftests/css-invalid/textarea/textarea-customerror.html b/layout/reftests/css-invalid/textarea/textarea-customerror.html index c7eb33123bc38..a164d8bf097c5 100644 --- a/layout/reftests/css-invalid/textarea/textarea-customerror.html +++ b/layout/reftests/css-invalid/textarea/textarea-customerror.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-invalid/textarea/textarea-dyn-disabled.html b/layout/reftests/css-invalid/textarea/textarea-dyn-disabled.html index ca707f6c40331..8f70a4020b571 100644 --- a/layout/reftests/css-invalid/textarea/textarea-dyn-disabled.html +++ b/layout/reftests/css-invalid/textarea/textarea-dyn-disabled.html @@ -4,16 +4,15 @@ validation and should not be affected by :invalid pseudo-class. --> - + diff --git a/layout/reftests/css-invalid/textarea/textarea-dyn-not-disabled.html b/layout/reftests/css-invalid/textarea/textarea-dyn-not-disabled.html index 3a075a9fdbdb6..e939872aec329 100644 --- a/layout/reftests/css-invalid/textarea/textarea-dyn-not-disabled.html +++ b/layout/reftests/css-invalid/textarea/textarea-dyn-not-disabled.html @@ -5,16 +5,15 @@ by :invalid pseudo-class. --> - + diff --git a/layout/reftests/css-invalid/textarea/textarea-dyn-not-readonly.html b/layout/reftests/css-invalid/textarea/textarea-dyn-not-readonly.html index 1cf07c03c6421..e5ded5fe2b524 100644 --- a/layout/reftests/css-invalid/textarea/textarea-dyn-not-readonly.html +++ b/layout/reftests/css-invalid/textarea/textarea-dyn-not-readonly.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-invalid/textarea/textarea-dyn-readonly.html b/layout/reftests/css-invalid/textarea/textarea-dyn-readonly.html index 102e35b6684fe..0a4d61606c80e 100644 --- a/layout/reftests/css-invalid/textarea/textarea-dyn-readonly.html +++ b/layout/reftests/css-invalid/textarea/textarea-dyn-readonly.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-ui-invalid/input/input-customerror.html b/layout/reftests/css-ui-invalid/input/input-customerror.html index 676b4bd48a918..7d646eee5aa6f 100644 --- a/layout/reftests/css-ui-invalid/input/input-customerror.html +++ b/layout/reftests/css-ui-invalid/input/input-customerror.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-ui-invalid/input/input-type-invalid.html b/layout/reftests/css-ui-invalid/input/input-type-invalid.html index e37173edec6c8..23fbec2db61fe 100644 --- a/layout/reftests/css-ui-invalid/input/input-type-invalid.html +++ b/layout/reftests/css-ui-invalid/input/input-type-invalid.html @@ -5,16 +5,15 @@ it should not be affected by :valid pseudo-class. --> - + diff --git a/layout/reftests/css-ui-invalid/input/reftest.list b/layout/reftests/css-ui-invalid/input/reftest.list index 34ac0afbc9027..265cd774f12e6 100644 --- a/layout/reftests/css-ui-invalid/input/reftest.list +++ b/layout/reftests/css-ui-invalid/input/reftest.list @@ -1,5 +1,5 @@ == input-valid.html input-ref.html -fuzzy(64,4) == input-customerror.html input-ref.html +== input-customerror.html input-ref.html fails-if(Android) == input-disabled.html input-ref.html fails-if(Android) == input-dyn-disabled.html input-ref.html == input-dyn-not-disabled.html input-ref.html @@ -25,7 +25,7 @@ fails-if(Android) == input-dyn-disabled.html input-ref.html == input-pattern-invalid-default.html input-withtext-ref.html == input-pattern-invalid-changed.html input-withtext-ref.html == input-type-barred.html input-button-ref.html -fuzzy(64,4) == input-type-invalid.html input-ref.html +== input-type-invalid.html input-ref.html == input-disabled-fieldset-1.html input-fieldset-ref.html == input-disabled-fieldset-2.html input-fieldset-ref.html == input-fieldset-legend.html input-fieldset-legend-ref.html diff --git a/layout/reftests/css-ui-invalid/textarea/reftest.list b/layout/reftests/css-ui-invalid/textarea/reftest.list index 05d0e0e24f7cb..3843b2e8f7e2b 100644 --- a/layout/reftests/css-ui-invalid/textarea/reftest.list +++ b/layout/reftests/css-ui-invalid/textarea/reftest.list @@ -1,18 +1,18 @@ == textarea-valid.html textarea-ref.html -fuzzy(11,4) == textarea-customerror.html textarea-ref.html +== textarea-customerror.html textarea-ref.html fails-if(Android) == textarea-disabled.html textarea-ref.html -fuzzy(11,4) fails-if(Android) == textarea-dyn-disabled.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-not-disabled.html textarea-ref.html +fails-if(Android) == textarea-dyn-disabled.html textarea-ref.html +== textarea-dyn-not-disabled.html textarea-ref.html == textarea-readonly.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-readonly.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-not-readonly-not-changed.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-not-readonly-changed.html textarea-ref.html +== textarea-dyn-readonly.html textarea-ref.html +== textarea-dyn-not-readonly-not-changed.html textarea-ref.html +== textarea-dyn-not-readonly-changed.html textarea-ref.html == textarea-maxlength-valid.html textarea-ref.html == textarea-maxlength-invalid.html textarea-withtext-ref.html == textarea-maxlength-default-value-invalid.html textarea-withtext-ref.html == textarea-required-valid.html textarea-withtext-ref.html == textarea-required-invalid.html textarea-ref.html -fuzzy(11,4) == textarea-required-invalid-changed.html textarea-ref.html +== textarea-required-invalid-changed.html textarea-ref.html == textarea-disabled-fieldset-1.html textarea-fieldset-ref.html == textarea-disabled-fieldset-2.html textarea-fieldset-ref.html == textarea-novalidate.html textarea-ref.html diff --git a/layout/reftests/css-ui-invalid/textarea/textarea-customerror.html b/layout/reftests/css-ui-invalid/textarea/textarea-customerror.html index ebe0fd968b95b..0ccbca27d4600 100644 --- a/layout/reftests/css-ui-invalid/textarea/textarea-customerror.html +++ b/layout/reftests/css-ui-invalid/textarea/textarea-customerror.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-disabled.html b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-disabled.html index 6a3fa36aa7a33..7ababb7e7e2c6 100644 --- a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-disabled.html +++ b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-disabled.html @@ -4,16 +4,15 @@ validation and should not be affected by :-moz-ui-invalid pseudo-class. --> - + diff --git a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-disabled.html b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-disabled.html index 954cfa5a4c142..983fe7e3c4643 100644 --- a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-disabled.html +++ b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-disabled.html @@ -5,16 +5,15 @@ by :-moz-ui-invalid pseudo-class. --> - + diff --git a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-changed.html b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-changed.html index 2e47cfc13f942..70459fb87c7ba 100644 --- a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-changed.html +++ b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-changed.html @@ -1,19 +1,11 @@ - - - - + diff --git a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-not-changed.html b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-not-changed.html index 3f93d55e34903..185540838802d 100644 --- a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-not-changed.html +++ b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-not-readonly-not-changed.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-readonly.html b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-readonly.html index fb54a2b144094..6acccf51e60a8 100644 --- a/layout/reftests/css-ui-invalid/textarea/textarea-dyn-readonly.html +++ b/layout/reftests/css-ui-invalid/textarea/textarea-dyn-readonly.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-ui-invalid/textarea/textarea-required-invalid-changed.html b/layout/reftests/css-ui-invalid/textarea/textarea-required-invalid-changed.html index 6fa004393780f..67215c162ec0d 100644 --- a/layout/reftests/css-ui-invalid/textarea/textarea-required-invalid-changed.html +++ b/layout/reftests/css-ui-invalid/textarea/textarea-required-invalid-changed.html @@ -1,18 +1,10 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/input/input-customerror.html b/layout/reftests/css-ui-valid/input/input-customerror.html index 3e787580916cc..9aa3efb307895 100644 --- a/layout/reftests/css-ui-valid/input/input-customerror.html +++ b/layout/reftests/css-ui-valid/input/input-customerror.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/input/input-type-invalid.html b/layout/reftests/css-ui-valid/input/input-type-invalid.html index 3fa4a555689c6..6926e003583cb 100644 --- a/layout/reftests/css-ui-valid/input/input-type-invalid.html +++ b/layout/reftests/css-ui-valid/input/input-type-invalid.html @@ -5,16 +5,15 @@ it should not be affected by :-moz-ui-valid pseudo-class. --> - + diff --git a/layout/reftests/css-ui-valid/input/reftest.list b/layout/reftests/css-ui-valid/input/reftest.list index b87a73067f698..37b18d01fb3e4 100644 --- a/layout/reftests/css-ui-valid/input/reftest.list +++ b/layout/reftests/css-ui-valid/input/reftest.list @@ -1,5 +1,5 @@ == input-valid.html input-ref.html -fuzzy(11,4) == input-customerror.html input-ref.html +== input-customerror.html input-ref.html fails-if(Android) == input-disabled.html input-ref.html fails-if(Android) == input-dyn-disabled.html input-ref.html == input-dyn-not-disabled.html input-ref.html @@ -26,7 +26,7 @@ fails-if(Android) == input-dyn-disabled.html input-ref.html == input-pattern-valid-changed.html input-withtext-ref.html == input-pattern-invalid.html input-withtext-ref.html == input-type-barred.html input-button-ref.html -fuzzy(64,4) == input-type-invalid.html input-ref.html +== input-type-invalid.html input-ref.html == input-disabled-fieldset-1.html input-fieldset-ref.html == input-disabled-fieldset-2.html input-fieldset-ref.html == input-fieldset-legend.html input-fieldset-legend-ref.html diff --git a/layout/reftests/css-ui-valid/select/reftest.list b/layout/reftests/css-ui-valid/select/reftest.list index 094b161fc09ab..87c7bf6804905 100644 --- a/layout/reftests/css-ui-valid/select/reftest.list +++ b/layout/reftests/css-ui-valid/select/reftest.list @@ -11,7 +11,7 @@ needs-focus == select-required-valid-changed-1.html select-required-ref.html needs-focus == select-required-valid-changed-2.html select-required-ref.html needs-focus == select-required-multiple-invalid.html select-required-multiple-ref.html needs-focus == select-required-multiple-valid.html select-required-multiple-ref.html -fuzzy(64,4) needs-focus == select-required-multiple-valid-changed.html select-required-multiple-ref.html +needs-focus == select-required-multiple-valid-changed.html select-required-multiple-ref.html fails-if(Android) needs-focus == select-disabled-fieldset-1.html select-fieldset-ref.html fails-if(Android) needs-focus == select-disabled-fieldset-2.html select-fieldset-ref.html needs-focus == select-fieldset-legend.html select-fieldset-legend-ref.html diff --git a/layout/reftests/css-ui-valid/select/select-required-multiple-valid-changed.html b/layout/reftests/css-ui-valid/select/select-required-multiple-valid-changed.html index 704a6e80a6713..45231bf08d678 100644 --- a/layout/reftests/css-ui-valid/select/select-required-multiple-valid-changed.html +++ b/layout/reftests/css-ui-valid/select/select-required-multiple-valid-changed.html @@ -1,21 +1,13 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/textarea/textarea-dyn-disabled.html b/layout/reftests/css-ui-valid/textarea/textarea-dyn-disabled.html index 2a07363ce0387..09326c7108866 100644 --- a/layout/reftests/css-ui-valid/textarea/textarea-dyn-disabled.html +++ b/layout/reftests/css-ui-valid/textarea/textarea-dyn-disabled.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled-changed.html b/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled-changed.html index 24faa3ecce6ae..3595f9d301b55 100644 --- a/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled-changed.html +++ b/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled-changed.html @@ -1,19 +1,11 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled.html b/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled.html index 73e0876e9675d..ff14517d64c45 100644 --- a/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled.html +++ b/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-disabled.html @@ -1,18 +1,10 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly-changed.html b/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly-changed.html index bf44240e13c86..81215b2f545e1 100644 --- a/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly-changed.html +++ b/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly-changed.html @@ -1,19 +1,11 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly.html b/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly.html index 514b40eb87835..b1606e39d16ec 100644 --- a/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly.html +++ b/layout/reftests/css-ui-valid/textarea/textarea-dyn-not-readonly.html @@ -1,18 +1,10 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/textarea/textarea-dyn-readonly.html b/layout/reftests/css-ui-valid/textarea/textarea-dyn-readonly.html index 4fc894ca54518..69a38d302d643 100644 --- a/layout/reftests/css-ui-valid/textarea/textarea-dyn-readonly.html +++ b/layout/reftests/css-ui-valid/textarea/textarea-dyn-readonly.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-ui-valid/textarea/textarea-maxlength-valid-changed.html b/layout/reftests/css-ui-valid/textarea/textarea-maxlength-valid-changed.html index 228ababcf5298..e69c516d67307 100644 --- a/layout/reftests/css-ui-valid/textarea/textarea-maxlength-valid-changed.html +++ b/layout/reftests/css-ui-valid/textarea/textarea-maxlength-valid-changed.html @@ -1,18 +1,10 @@ - - - - + diff --git a/layout/reftests/css-valid/input/input-customerror.html b/layout/reftests/css-valid/input/input-customerror.html index 6cca5c66eeb44..369d0e663a273 100644 --- a/layout/reftests/css-valid/input/input-customerror.html +++ b/layout/reftests/css-valid/input/input-customerror.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-valid/input/input-type-invalid.html b/layout/reftests/css-valid/input/input-type-invalid.html index 631fc499a1e07..6861385d7e85c 100644 --- a/layout/reftests/css-valid/input/input-type-invalid.html +++ b/layout/reftests/css-valid/input/input-type-invalid.html @@ -5,16 +5,15 @@ it should not be affected by :valid pseudo-class. --> - + diff --git a/layout/reftests/css-valid/input/reftest.list b/layout/reftests/css-valid/input/reftest.list index 704f5ad76cb61..e12b5372c7de0 100644 --- a/layout/reftests/css-valid/input/reftest.list +++ b/layout/reftests/css-valid/input/reftest.list @@ -1,5 +1,5 @@ == input-valid.html input-ref.html -fuzzy(64,4) == input-customerror.html input-ref.html +== input-customerror.html input-ref.html fails-if(Android) == input-disabled.html input-ref.html fails-if(Android) == input-dyn-disabled.html input-ref.html == input-dyn-not-disabled.html input-ref.html @@ -19,7 +19,7 @@ fails-if(Android) == input-dyn-disabled.html input-ref.html == input-pattern-valid.html input-withtext-ref.html == input-pattern-invalid.html input-withtext-ref.html == input-type-barred.html input-button-ref.html -fuzzy(64,4) == input-type-invalid.html input-ref.html +== input-type-invalid.html input-ref.html == input-disabled-fieldset-1.html input-fieldset-ref.html == input-disabled-fieldset-2.html input-fieldset-ref.html == input-fieldset-legend.html input-fieldset-legend-ref.html diff --git a/layout/reftests/css-valid/textarea/reftest.list b/layout/reftests/css-valid/textarea/reftest.list index e30706452b7ab..855a9ad47f5f7 100644 --- a/layout/reftests/css-valid/textarea/reftest.list +++ b/layout/reftests/css-valid/textarea/reftest.list @@ -1,11 +1,11 @@ == textarea-valid.html textarea-ref.html -fuzzy(11,4) == textarea-customerror.html textarea-ref.html +== textarea-customerror.html textarea-ref.html fails-if(Android) == textarea-disabled.html textarea-ref.html -fuzzy(11,4) fails-if(Android) == textarea-dyn-disabled.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-not-disabled.html textarea-ref.html +fails-if(Android) == textarea-dyn-disabled.html textarea-ref.html +== textarea-dyn-not-disabled.html textarea-ref.html == textarea-readonly.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-readonly.html textarea-ref.html -fuzzy(11,4) == textarea-dyn-not-readonly.html textarea-ref.html +== textarea-dyn-readonly.html textarea-ref.html +== textarea-dyn-not-readonly.html textarea-ref.html == textarea-maxlength-valid.html textarea-ref.html == textarea-maxlength-invalid.html textarea-withtext-ref.html == textarea-required-valid.html textarea-withtext-ref.html diff --git a/layout/reftests/css-valid/textarea/textarea-customerror.html b/layout/reftests/css-valid/textarea/textarea-customerror.html index c9c2c91f9096b..4a312fcd3b9ae 100644 --- a/layout/reftests/css-valid/textarea/textarea-customerror.html +++ b/layout/reftests/css-valid/textarea/textarea-customerror.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-valid/textarea/textarea-dyn-disabled.html b/layout/reftests/css-valid/textarea/textarea-dyn-disabled.html index 88b278da5d0e1..42c24a1fb9bfa 100644 --- a/layout/reftests/css-valid/textarea/textarea-dyn-disabled.html +++ b/layout/reftests/css-valid/textarea/textarea-dyn-disabled.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-valid/textarea/textarea-dyn-not-disabled.html b/layout/reftests/css-valid/textarea/textarea-dyn-not-disabled.html index 5570260b046e6..d5acd2e77a9fe 100644 --- a/layout/reftests/css-valid/textarea/textarea-dyn-not-disabled.html +++ b/layout/reftests/css-valid/textarea/textarea-dyn-not-disabled.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-valid/textarea/textarea-dyn-not-readonly.html b/layout/reftests/css-valid/textarea/textarea-dyn-not-readonly.html index fc3c6ae45edc5..0d3c34fe54e9b 100644 --- a/layout/reftests/css-valid/textarea/textarea-dyn-not-readonly.html +++ b/layout/reftests/css-valid/textarea/textarea-dyn-not-readonly.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/css-valid/textarea/textarea-dyn-readonly.html b/layout/reftests/css-valid/textarea/textarea-dyn-readonly.html index 94fc88e9d868d..00600ad5dc3b1 100644 --- a/layout/reftests/css-valid/textarea/textarea-dyn-readonly.html +++ b/layout/reftests/css-valid/textarea/textarea-dyn-readonly.html @@ -1,18 +1,9 @@ - - - - + diff --git a/layout/reftests/font-inflation/reftest.list b/layout/reftests/font-inflation/reftest.list index 112a95e3f64b6..c7b0f3d461a78 100644 --- a/layout/reftests/font-inflation/reftest.list +++ b/layout/reftests/font-inflation/reftest.list @@ -49,8 +49,8 @@ test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineTh test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-2.html select-combobox-2-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) != select-combobox-2.html select-combobox-2.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) == select-combobox-3.html select-combobox-3-ref.html -asserts-if(gtk2Widget,0-4) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) != input-checkbox.html input-checkbox.html -asserts-if(gtk2Widget,0-4) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) != input-radio.html input-radio.html +asserts-if(gtk2Widget,0-2) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) != input-checkbox.html input-checkbox.html +asserts-if(gtk2Widget,0-2) test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) != input-radio.html input-radio.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) == disable-fontinfl-on-mobile.html disable-fontinfl-on-mobile-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) == disable-fontinfl-on-mobile-2.html disable-fontinfl-on-mobile-ref.html test-pref(font.size.inflation.emPerLine,15) test-pref(font.size.inflation.lineThreshold,0) == disable-fontinfl-on-mobile-3.html disable-fontinfl-on-mobile-ref.html diff --git a/layout/reftests/forms/placeholder/reftest.list b/layout/reftests/forms/placeholder/reftest.list index b1780b905b960..ac39eebeb7df1 100644 --- a/layout/reftests/forms/placeholder/reftest.list +++ b/layout/reftests/forms/placeholder/reftest.list @@ -17,7 +17,7 @@ needs-focus == placeholder-10.html placeholder-visible-ref.html == placeholder-13.html placeholder-visible-ref.html == placeholder-14.html placeholder-visible-ref.html == placeholder-18.html placeholder-overridden-ref.html -random-if(winWidget) == placeholder-19.xul placeholder-overridden-ref.xul +== placeholder-19.xul placeholder-overridden-ref.xul needs-focus == placeholder-20.html placeholder-focus-ref.html needs-focus == placeholder-21.html placeholder-blank-ref.html needs-focus == placeholder-22.html placeholder-blank-ref.html diff --git a/layout/reftests/layers/reftest.list b/layout/reftests/layers/reftest.list index 8897ae38591b2..7d8a5c8e11d61 100644 --- a/layout/reftests/layers/reftest.list +++ b/layout/reftests/layers/reftest.list @@ -1,2 +1,2 @@ == move-to-background-1.html move-to-background-1-ref.html -fuzzy-if(cocoaWidget,2,6) random-if(Android&&!browserIsRemote) == component-alpha-exit-1.html component-alpha-exit-1-ref.html # bug 760275 +random-if(Android&&!browserIsRemote) == component-alpha-exit-1.html component-alpha-exit-1-ref.html # bug 760275 diff --git a/layout/reftests/reftest-sanity/invalidation.html b/layout/reftests/reftest-sanity/invalidation.html index 144587b9c20a9..28990102995bf 100644 --- a/layout/reftests/reftest-sanity/invalidation.html +++ b/layout/reftests/reftest-sanity/invalidation.html @@ -2,7 +2,7 @@ -

Hello Kitty

+

Hello Kitty diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list index 5d5345e01c393..5bb38d42a9b79 100644 --- a/layout/reftests/svg/reftest.list +++ b/layout/reftests/svg/reftest.list @@ -156,10 +156,10 @@ fails-if(Android) == filter-extref-differentOrigin-01.svg pass.svg # Bug 695385 == foreignObject-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html == foreignObject-dynamic-fixedpos-01.html foreignObject-dynamic-abspos-01-ref.html == getElementById-a-element-01.svg pass.svg -== gradient-live-01a.svg gradient-live-01-ref.svg -== gradient-live-01b.svg gradient-live-01-ref.svg -== gradient-live-01c.svg gradient-live-01-ref.svg -== gradient-live-01d.svg gradient-live-01-ref.svg +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01a.svg gradient-live-01-ref.svg # bug 696674 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01b.svg gradient-live-01-ref.svg # bug 696674 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01c.svg gradient-live-01-ref.svg # bug 696674 +fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)&&!layersGPUAccelerated) == gradient-live-01d.svg gradient-live-01-ref.svg # bug 696674 fails == inline-in-xul-basic-01.xul pass.svg == invalid-text-01.svg pass.svg == lang-attribute-01.svg pass.svg diff --git a/layout/reftests/svg/smil/sort/reftest.list b/layout/reftests/svg/smil/sort/reftest.list index 93037547734b4..28631268763f2 100644 --- a/layout/reftests/svg/smil/sort/reftest.list +++ b/layout/reftests/svg/smil/sort/reftest.list @@ -9,4 +9,4 @@ == sort-startSame-1b.svg sort-startSame-1-ref.svg == sort-startSame-2a.svg sort-startSame-2-ref.svg == sort-startSame-2b.svg sort-startSame-2-ref.svg -random == sort-additive-1.svg sort-additive-1-ref.svg # bug 547801 +random-if(Android) == sort-additive-1.svg sort-additive-1-ref.svg # bug 547801 diff --git a/layout/reftests/svg/smil/transform/reftest.list b/layout/reftests/svg/smil/transform/reftest.list index ef6cc2597aa5b..6eda8fc0bf26a 100644 --- a/layout/reftests/svg/smil/transform/reftest.list +++ b/layout/reftests/svg/smil/transform/reftest.list @@ -2,14 +2,14 @@ # element. == additive-1.svg additive-1-ref.svg -fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,18) == paced-1.svg paced-1-ref.svg +== paced-1.svg paced-1-ref.svg == rotate-angle-1.svg rotate-angle-ref.svg == rotate-angle-2.svg rotate-angle-ref.svg == rotate-angle-3.svg rotate-angle-ref.svg -fuzzy-if(Android,16,2) == rotate-angle-4.svg rotate-angle-ref.svg +== rotate-angle-4.svg rotate-angle-ref.svg == rotate-angle-5.svg rotate-angle-ref.svg == scale-1.svg scale-1-ref.svg -fuzzy-if(cocoaWidget&&layersGPUAccelerated,1,45) == skew-1.svg skew-1-ref.svg +== skew-1.svg skew-1-ref.svg random-if(Android&&!browserIsRemote) == translate-clipPath-1.svg lime.svg # bug 760266 fails-if(OSX==10.6) == translate-gradient-1.svg lime.svg == translate-pattern-1.svg lime.svg diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list index 5e99fc018cdad..eb13649d2a504 100644 --- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -4,7 +4,7 @@ HTTP(..) == marker-string.html marker-string-ref.html skip-if(Android) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing skip-if(!gtk2Widget) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing fuzzy-if(Android,9,2125) HTTP(..) == scroll-rounding.html scroll-rounding-ref.html # bug 760264 -fuzzy-if(OSX==10.8,1,1) HTTP(..) == anonymous-block.html anonymous-block-ref.html +HTTP(..) == anonymous-block.html anonymous-block-ref.html HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html HTTP(..) == visibility-hidden.html visibility-hidden-ref.html HTTP(..) == block-padding.html block-padding-ref.html diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list index 6042f325fa599..e48f9efdc7b34 100644 --- a/layout/reftests/text/reftest.list +++ b/layout/reftests/text/reftest.list @@ -50,7 +50,7 @@ skip-if(!(d2d||cocoaWidget)) random-if(d2d) != subpixel-glyphs-x-2a.html subpixe HTTP(..) == subpixel-glyphs-x-3a.html subpixel-glyphs-x-3b.html # No platforms do subpixel positioning vertically == subpixel-glyphs-y-1a.html subpixel-glyphs-y-1b.html -fuzzy-if(Android,9,61) == subpixel-lineheight-1a.html subpixel-lineheight-1b.html +== subpixel-lineheight-1a.html subpixel-lineheight-1b.html == swash-1.html swash-1-ref.html HTTP(..) != synthetic-bold-metrics-01.html synthetic-bold-metrics-01-notref.html == synthetic-bold-papyrus-01.html synthetic-bold-papyrus-01-ref.html diff --git a/layout/style/ImageLoader.cpp b/layout/style/ImageLoader.cpp index 2adf0a0a0169f..63adbd7b5fc72 100644 --- a/layout/style/ImageLoader.cpp +++ b/layout/style/ImageLoader.cpp @@ -324,8 +324,25 @@ ImageLoader::DoRedraw(FrameSet* aFrameSet) for (FrameSet::size_type i = 0; i < length; i++) { nsIFrame* frame = aFrameSet->ElementAt(i); + // NOTE: It is not sufficient to invalidate only the size of the image: + // the image may be tiled! + // The best option is to call into the frame, however lacking this + // we have to at least invalidate the frame's bounds, hence + // as long as we have a frame we'll use its size. + // + + // Invalidate the entire frame + // XXX We really only need to invalidate the client area of the frame... + + nsRect bounds(nsPoint(0, 0), frame->GetSize()); + + if (frame->GetType() == nsGkAtoms::canvasFrame) { + // The canvas's background covers the whole viewport. + bounds = frame->GetVisualOverflowRect(); + } + if (frame->GetStyleVisibility()->IsVisible()) { - frame->InvalidateFrame(); + frame->Invalidate(bounds); } } } diff --git a/layout/svg/nsSVGEffects.cpp b/layout/svg/nsSVGEffects.cpp index fb1aa88ad2cc9..68006caf862ce 100644 --- a/layout/svg/nsSVGEffects.cpp +++ b/layout/svg/nsSVGEffects.cpp @@ -14,7 +14,6 @@ #include "nsSVGFilterFrame.h" #include "nsSVGMaskFrame.h" #include "nsSVGTextPathFrame.h" -#include "nsIReflowCallback.h" using namespace mozilla; using namespace mozilla::dom; @@ -239,7 +238,7 @@ InvalidateAllContinuations(nsIFrame* aFrame) { for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetNextContinuationOrSpecialSibling(f)) { - f->InvalidateFrame(); + f->InvalidateOverflowRect(); } } @@ -285,32 +284,6 @@ nsSVGMarkerProperty::DoUpdate() mFrame->GetContent()->AsElement(), nsRestyleHint(0), changeHint); } -class nsAsyncNotifyGlyphMetricsChange MOZ_FINAL : public nsIReflowCallback -{ -public: - nsAsyncNotifyGlyphMetricsChange(nsIFrame* aFrame) : mWeakFrame(aFrame) - { - } - - virtual bool ReflowFinished() - { - nsSVGTextPathFrame* frame = - static_cast(mWeakFrame.GetFrame()); - if (frame) { - frame->NotifyGlyphMetricsChange(); - } - delete this; - return true; - } - - virtual void ReflowCallbackCanceled() - { - delete this; - } - - nsWeakFrame mWeakFrame; -}; - void nsSVGTextPathProperty::DoUpdate() { @@ -321,13 +294,8 @@ nsSVGTextPathProperty::DoUpdate() NS_ASSERTION(mFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected"); if (mFrame->GetType() == nsGkAtoms::svgTextPathFrame) { - if (mFrame->PresContext()->PresShell()->IsReflowLocked()) { - nsIReflowCallback* cb = new nsAsyncNotifyGlyphMetricsChange(mFrame); - mFrame->PresContext()->PresShell()->PostReflowCallback(cb); - } else { - nsSVGTextPathFrame* textPathFrame = static_cast(mFrame); - textPathFrame->NotifyGlyphMetricsChange(); - } + nsSVGTextPathFrame* textPathFrame = static_cast(mFrame); + textPathFrame->NotifyGlyphMetricsChange(); } } @@ -561,20 +529,6 @@ GatherEnumerator(nsPtrHashKey* aEntry, void* aArg) return PL_DHASH_REMOVE; } -static PLDHashOperator -GatherEnumeratorForReflow(nsPtrHashKey* aEntry, void* aArg) -{ - if (!aEntry->GetKey()->ObservesReflow()) { - return PL_DHASH_NEXT; - } - - nsTArray* array = - static_cast*>(aArg); - array->AppendElement(aEntry->GetKey()); - - return PL_DHASH_REMOVE; -} - void nsSVGRenderingObserverList::InvalidateAll() { @@ -591,22 +545,6 @@ nsSVGRenderingObserverList::InvalidateAll() } } -void -nsSVGRenderingObserverList::InvalidateAllForReflow() -{ - if (mObservers.Count() == 0) - return; - - nsAutoTArray observers; - - // The PL_DHASH_REMOVE in GatherEnumerator drops all our observers here: - mObservers.EnumerateEntries(GatherEnumeratorForReflow, &observers); - - for (uint32_t i = 0; i < observers.Length(); ++i) { - observers[i]->InvalidateViaReferencedElement(); - } -} - void nsSVGRenderingObserverList::RemoveAll() { @@ -697,24 +635,20 @@ nsSVGEffects::InvalidateRenderingObservers(nsIFrame *aFrame) } void -nsSVGEffects::InvalidateDirectRenderingObservers(Element *aElement, uint32_t aFlags /* = 0 */) +nsSVGEffects::InvalidateDirectRenderingObservers(Element *aElement) { if (aElement->HasRenderingObservers()) { nsSVGRenderingObserverList *observerList = GetObserverList(aElement); if (observerList) { - if (aFlags & INVALIDATE_REFLOW) { - observerList->InvalidateAllForReflow(); - } else { - observerList->InvalidateAll(); - } + observerList->InvalidateAll(); } } } void -nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame, uint32_t aFlags /* = 0 */) +nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame *aFrame) { if (aFrame->GetContent() && aFrame->GetContent()->IsElement()) { - InvalidateDirectRenderingObservers(aFrame->GetContent()->AsElement(), aFlags); + InvalidateDirectRenderingObservers(aFrame->GetContent()->AsElement()); } } diff --git a/layout/svg/nsSVGEffects.h b/layout/svg/nsSVGEffects.h index 544afd94dd9d9..3c4ab9d3838b8 100644 --- a/layout/svg/nsSVGEffects.h +++ b/layout/svg/nsSVGEffects.h @@ -78,8 +78,6 @@ class nsSVGRenderingObserver : public nsStubMutationObserver { Element* GetReferencedElement(); - virtual bool ObservesReflow() { return true; } - protected: // Non-virtual protected methods void StartListening(); @@ -187,8 +185,6 @@ class nsSVGTextPathProperty : public nsSVGIDRenderingObserver { nsSVGTextPathProperty(nsIURI *aURI, nsIFrame *aFrame, bool aReferenceImage) : nsSVGIDRenderingObserver(aURI, aFrame, aReferenceImage) {} - virtual bool ObservesReflow() MOZ_OVERRIDE { return false; } - protected: virtual void DoUpdate() MOZ_OVERRIDE; }; @@ -247,12 +243,6 @@ class nsSVGRenderingObserverList { */ void InvalidateAll(); - /** - * Drop all observers that observe reflow, and notify them that we have changed and dropped - * our reference to them. - */ - void InvalidateAllForReflow(); - /** * Drop all our observers, and notify them that we have dropped our reference * to them. @@ -382,17 +372,12 @@ class nsSVGEffects { * to make invalidation relatively lightweight when an SVG effect changes. */ static void InvalidateRenderingObservers(nsIFrame *aFrame); - - enum { - INVALIDATE_REFLOW = 1 - }; - /** * This can be called on any element or frame. Only direct observers of this * (frame's) element, if any, are invalidated. */ - static void InvalidateDirectRenderingObservers(Element *aElement, uint32_t aFlags = 0); - static void InvalidateDirectRenderingObservers(nsIFrame *aFrame, uint32_t aFlags = 0); + static void InvalidateDirectRenderingObservers(Element *aElement); + static void InvalidateDirectRenderingObservers(nsIFrame *aFrame); /** * Get an nsSVGMarkerProperty for the frame, creating a fresh one if necessary diff --git a/layout/svg/nsSVGForeignObjectFrame.cpp b/layout/svg/nsSVGForeignObjectFrame.cpp index 3b1bfe0afe85b..b911bcbf61f02 100644 --- a/layout/svg/nsSVGForeignObjectFrame.cpp +++ b/layout/svg/nsSVGForeignObjectFrame.cpp @@ -178,6 +178,37 @@ nsSVGForeignObjectFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists); } +void +nsSVGForeignObjectFrame::InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, + nsIFrame* aForChild, + uint32_t aFlags) +{ + // This is called by our descendants when they change. + + if (GetStateBits() & NS_FRAME_IS_DIRTY) { + // Our entire area has been (or will be) invalidated, so no point + // keeping track of sub-areas that our descendants dirty. + return; + } + + if (GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) { + nsSVGEffects::InvalidateRenderingObservers(this); + return; + } + + if (!mInReflow) { + // We can't collect dirty areas, since we don't have a place to reliably + // call FlushDirtyRegion before we paint, so we have to invalidate now. + InvalidateDirtyRect(aDamageRect + nsPoint(aX, aY), aFlags, false); + return; + } + + nsRegion* region = (aFlags & INVALIDATE_CROSS_DOC) + ? &mSubDocDirtyRegion : &mSameDocDirtyRegion; + region->Or(*region, aDamageRect + nsPoint(aX, aY)); +} + bool nsSVGForeignObjectFrame::IsSVGTransformed(gfxMatrix *aOwnTransform, gfxMatrix *aFromParentTransform) const @@ -391,6 +422,12 @@ nsSVGForeignObjectFrame::ReflowSVG() gfxRect(x, y, w, h), PresContext()->AppUnitsPerCSSPixel()); + // Since we'll invalidate our entire area at the end of this method, we + // empty our cached dirty regions to prevent FlushDirtyRegion under DoReflow + // from wasting time invalidating: + mSameDocDirtyRegion.SetEmpty(); + mSubDocDirtyRegion.SetEmpty(); + // Fully mark our kid dirty so that it gets resized if necessary // (NS_FRAME_HAS_DIRTY_CHILDREN isn't enough in that case): nsIFrame* kid = GetFirstPrincipalChild(); @@ -611,20 +648,51 @@ nsSVGForeignObjectFrame::DoReflow() NS_FRAME_NO_MOVE_FRAME); mInReflow = false; + + if (!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)) { + // Since we're a reflow root and can be reflowed independently of our + // outer-, we can't just blindly pass 'true' here. + FlushDirtyRegion(0, nsSVGUtils::OuterSVGIsCallingReflowSVG(this)); + } } -nsRect -nsSVGForeignObjectFrame::GetInvalidRegion() +void +nsSVGForeignObjectFrame::InvalidateDirtyRect(const nsRect& aRect, + uint32_t aFlags, + bool aDuringReflowSVG) { - nsIFrame* kid = GetFirstPrincipalChild(); - if (kid->HasInvalidFrameInSubtree()) { - gfxRect r(mRect.x, mRect.y, mRect.width, mRect.height); - r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel()); - nsRect rect = ToCanvasBounds(r, GetCanvasTM(FOR_PAINTING), PresContext()); - rect = nsSVGUtils::GetPostFilterVisualOverflowRect(this, rect); - return rect; - } - return nsRect(); + if (aRect.IsEmpty()) + return; + + // Don't invalidate areas outside our bounds: + nsRect rect = aRect.Intersect(nsRect(nsPoint(0,0), mRect.Size())); + if (rect.IsEmpty()) + return; + + nsSVGUtils::InvalidateBounds(this, aDuringReflowSVG, &rect, aFlags); } +void +nsSVGForeignObjectFrame::FlushDirtyRegion(uint32_t aFlags, + bool aDuringReflowSVG) +{ + NS_ABORT_IF_FALSE(!(GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD), + "Should not have been called"); + + NS_ASSERTION(!mInReflow, + "We shouldn't be flushing while we have a pending flush"); + + if (mSameDocDirtyRegion.IsEmpty() && mSubDocDirtyRegion.IsEmpty()) { + return; + } + InvalidateDirtyRect(mSameDocDirtyRegion.GetBounds(), + aFlags, + aDuringReflowSVG); + InvalidateDirtyRect(mSubDocDirtyRegion.GetBounds(), + aFlags | INVALIDATE_CROSS_DOC, + aDuringReflowSVG); + + mSameDocDirtyRegion.SetEmpty(); + mSubDocDirtyRegion.SetEmpty(); +} diff --git a/layout/svg/nsSVGForeignObjectFrame.h b/layout/svg/nsSVGForeignObjectFrame.h index d9cd2903f88a0..78806107e2e4c 100644 --- a/layout/svg/nsSVGForeignObjectFrame.h +++ b/layout/svg/nsSVGForeignObjectFrame.h @@ -67,6 +67,10 @@ class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase, ~(nsIFrame::eSVG | nsIFrame::eSVGForeignObject)); } + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags); + virtual bool IsSVGTransformed(gfxMatrix *aOwnTransform, gfxMatrix *aFromParentTransform) const; @@ -90,18 +94,26 @@ class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase, gfxMatrix GetCanvasTM(uint32_t aFor); - nsRect GetInvalidRegion(); - protected: // implementation helpers: void DoReflow(); void RequestReflow(nsIPresShell::IntrinsicDirty aType); + void InvalidateDirtyRect(const nsRect& aRect, uint32_t aFlags, + bool aDuringReflowSVG); + void FlushDirtyRegion(uint32_t aFlags, bool aDuringReflowSVG); + // If width or height is less than or equal to zero we must disable rendering bool IsDisabled() const { return mRect.width <= 0 || mRect.height <= 0; } nsAutoPtr mCanvasTM; + // Areas dirtied by changes to decendents that are in our document + nsRegion mSameDocDirtyRegion; + + // Areas dirtied by changes to sub-documents embedded by our decendents + nsRegion mSubDocDirtyRegion; + bool mInReflow; }; diff --git a/layout/svg/nsSVGIntegrationUtils.cpp b/layout/svg/nsSVGIntegrationUtils.cpp index 9cad61533d5f6..d69f7517f1b7e 100644 --- a/layout/svg/nsSVGIntegrationUtils.cpp +++ b/layout/svg/nsSVGIntegrationUtils.cpp @@ -280,9 +280,9 @@ nsRect return overflowRect - (aFrame->GetOffsetTo(firstFrame) + firstFrameToUserSpace); } -nsIntRect +nsRect nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, - const nsIntRect& aInvalidRect) + const nsRect& aInvalidRect) { // Don't bother calling GetEffectProperties; the filter property should // already have been set up during reflow/ComputeFrameEffectsRect @@ -298,26 +298,22 @@ nsSVGIntegrationUtils::AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, return aInvalidRect; } - int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel(); - nsSVGFilterFrame* filterFrame = prop->GetFilterFrame(); if (!filterFrame) { // The frame is either not there or not currently available, // perhaps because we're in the middle of tearing stuff down. // Be conservative. - nsRect overflow = aFrame->GetVisualOverflowRect(); - return overflow.ToOutsidePixels(appUnitsPerDevPixel); + return aFrame->GetVisualOverflowRect(); } // Convert aInvalidRect into "user space" in app units: nsPoint toUserSpace = aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame); - nsRect preEffectsRect = aInvalidRect.ToAppUnits(appUnitsPerDevPixel) + toUserSpace; + nsRect preEffectsRect = aInvalidRect + toUserSpace; // Return ther result, relative to aFrame, not in user space: - nsRect result = filterFrame->GetPostFilterDirtyArea(firstFrame, preEffectsRect) - + return filterFrame->GetPostFilterDirtyArea(firstFrame, preEffectsRect) - toUserSpace; - return result.ToOutsidePixels(appUnitsPerDevPixel); } nsRect diff --git a/layout/svg/nsSVGIntegrationUtils.h b/layout/svg/nsSVGIntegrationUtils.h index 16d157e5cb190..4e883a6055599 100644 --- a/layout/svg/nsSVGIntegrationUtils.h +++ b/layout/svg/nsSVGIntegrationUtils.h @@ -116,8 +116,8 @@ class nsSVGIntegrationUtils MOZ_FINAL * Used to adjust the area of a frame that needs to be invalidated to take * account of SVG effects. */ - static nsIntRect - AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, const nsIntRect& aInvalidRect); + static nsRect + AdjustInvalidAreaForSVGEffects(nsIFrame* aFrame, const nsRect& aInvalidRect); /** * Figure out which area of the source is needed given an area to diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp index a6821f3dfe627..9280cb5807baa 100644 --- a/layout/svg/nsSVGOuterSVGFrame.cpp +++ b/layout/svg/nsSVGOuterSVGFrame.cpp @@ -22,7 +22,6 @@ #include "nsSVGSVGElement.h" #include "nsSVGTextFrame.h" #include "nsSVGViewElement.h" -#include "nsSubDocumentFrame.h" namespace dom = mozilla::dom; @@ -506,11 +505,6 @@ class nsDisplayOuterSVG : public nsDisplayItem { HitTestState* aState, nsTArray *aOutFrames); virtual void Paint(nsDisplayListBuilder* aBuilder, nsRenderingContext* aCtx); - - virtual void ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion); - NS_DISPLAY_DECL_NAME("SVGOuterSVG", TYPE_SVG_OUTER_SVG) }; @@ -576,39 +570,6 @@ nsDisplayOuterSVG::Paint(nsDisplayListBuilder* aBuilder, #endif } -static PLDHashOperator CheckForeignObjectInvalidatedArea(nsPtrHashKey* aEntry, void* aData) -{ - nsRegion* region = static_cast(aData); - region->Or(*region, aEntry->GetKey()->GetInvalidRegion()); - return PL_DHASH_NEXT; -} - -nsRegion -nsSVGOuterSVGFrame::FindInvalidatedForeignObjectFrameChildren(nsIFrame* aFrame) -{ - nsRegion result; - if (mForeignObjectHash.Count()) { - mForeignObjectHash.EnumerateEntries(CheckForeignObjectInvalidatedArea, &result); - } - return result; -} - -void -nsDisplayOuterSVG::ComputeInvalidationRegion(nsDisplayListBuilder* aBuilder, - const nsDisplayItemGeometry* aGeometry, - nsRegion* aInvalidRegion) -{ - nsSVGOuterSVGFrame *frame = static_cast(mFrame); - frame->InvalidateSVG(frame->FindInvalidatedForeignObjectFrameChildren(frame)); - - nsRegion result = frame->GetInvalidRegion(); - result.MoveBy(ToReferenceFrame()); - frame->ClearInvalidRegion(); - - nsDisplayItem::ComputeInvalidationRegion(aBuilder, aGeometry, aInvalidRegion); - aInvalidRegion->Or(*aInvalidRegion, result); -} - // helper static inline bool DependsOnIntrinsicSize(const nsIFrame* aEmbeddingFrame) diff --git a/layout/svg/nsSVGOuterSVGFrame.h b/layout/svg/nsSVGOuterSVGFrame.h index 5f61a34b343b1..82d19194361b7 100644 --- a/layout/svg/nsSVGOuterSVGFrame.h +++ b/layout/svg/nsSVGOuterSVGFrame.h @@ -144,26 +144,6 @@ class nsSVGOuterSVGFrame : public nsSVGOuterSVGFrameBase, return mCallingReflowSVG; } - void InvalidateSVG(const nsRegion& aRegion) - { - if (!aRegion.IsEmpty()) { - mInvalidRegion.Or(mInvalidRegion, aRegion); - InvalidateFrame(); - } - } - - void ClearInvalidRegion() { mInvalidRegion.SetEmpty(); } - - const nsRegion& GetInvalidRegion() { - nsRect rect; - if (!IsInvalid(rect)) { - mInvalidRegion.SetEmpty(); - } - return mInvalidRegion; - } - - nsRegion FindInvalidatedForeignObjectFrameChildren(nsIFrame* aFrame); - protected: bool mCallingReflowSVG; @@ -184,12 +164,10 @@ class nsSVGOuterSVGFrame : public nsSVGOuterSVGFrameBase, // A hash-set containing our nsSVGForeignObjectFrame descendants. Note we use // a hash-set to avoid the O(N^2) behavior we'd get tearing down an SVG frame // subtree if we were to use a list (see bug 381285 comment 20). - nsTHashtable > mForeignObjectHash; + nsTHashtable mForeignObjectHash; nsAutoPtr mCanvasTM; - nsRegion mInvalidRegion; - float mFullZoom; bool mViewportInitialized; diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 6af829de6b27e..b6b3af90a9fba 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -415,14 +415,6 @@ nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate, return; } - aFrame->InvalidateFrameSubtree(); - - if ((aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame || - aFrame->GetType() == nsGkAtoms::svgGlyphFrame) && - NS_SVGDisplayListPaintingEnabled()) { - return; - } - // Okay, so now we pass the area that needs to be invalidated up our parent // chain, accounting for filter effects and transforms as we go, until we // reach our nsSVGOuterSVGFrame where we can invalidate: @@ -487,7 +479,8 @@ nsSVGUtils::InvalidateBounds(nsIFrame *aFrame, bool aDuringUpdate, NS_ASSERTION(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG, "SVG frames must always have an nsSVGOuterSVGFrame ancestor!"); - static_cast(aFrame)->InvalidateSVG(invalidArea); + static_cast(aFrame)->InvalidateWithFlags(invalidArea, + aFlags); } void diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp index fc9f6ffac07ca..dbbbec4b37778 100644 --- a/layout/tables/nsTableCellFrame.cpp +++ b/layout/tables/nsTableCellFrame.cpp @@ -28,7 +28,6 @@ #include "nsDisplayList.h" #include "nsLayoutUtils.h" #include "nsTextFrame.h" -#include "FrameLayerBuilder.h" //TABLECELL SELECTION #include "nsFrameSelection.h" @@ -397,21 +396,6 @@ nsDisplayTableCellBackground::GetBounds(nsDisplayListBuilder* aBuilder, return nsDisplayItem::GetBounds(aBuilder, aSnap); } -void nsTableCellFrame::InvalidateFrame(uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrame(aDisplayItemKey); - GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey); -} - -void nsTableCellFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey); - // If we have filters applied that would affects our bounds, then - // we get an inactive layer created and this is computed - // within FrameLayerBuilder - GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey); -} - static void PaintTableCellSelection(nsIFrame* aFrame, nsRenderingContext* aCtx, const nsRect& aRect, nsPoint aPt) @@ -926,8 +910,8 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext, FinishReflowChild(firstKid, aPresContext, &kidReflowState, kidSize, kidOrigin.x, kidOrigin.y, 0); - nsTableFrame::InvalidateTableFrame(firstKid, origRect, origVisualOverflow, - firstReflow); + nsTableFrame::InvalidateFrame(firstKid, origRect, origVisualOverflow, + firstReflow); // first, compute the height which can be set w/o being restricted by aMaxSize.height nscoord cellHeight = kidSize.height; @@ -963,9 +947,8 @@ NS_METHOD nsTableCellFrame::Reflow(nsPresContext* aPresContext, // If our parent is in initial reflow, it'll handle invalidating our // entire overflow rect. - if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && - nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) { - InvalidateFrame(); + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + CheckInvalidateSizeChange(aDesiredSize); } // remember the desired size for this reflow diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h index b87cf6a36c2da..da7d3fed0d196 100644 --- a/layout/tables/nsTableCellFrame.h +++ b/layout/tables/nsTableCellFrame.h @@ -210,10 +210,6 @@ class nsTableCellFrame : public nsContainerFrame, nsPoint aPt); virtual bool UpdateOverflow(); - - virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); } protected: /** implement abstract method on nsContainerFrame */ diff --git a/layout/tables/nsTableColFrame.cpp b/layout/tables/nsTableColFrame.cpp index a63fc1a97b7b3..50d3af1e14ea0 100644 --- a/layout/tables/nsTableColFrame.cpp +++ b/layout/tables/nsTableColFrame.cpp @@ -190,21 +190,3 @@ nsTableColFrame::GetSplittableType() const return NS_FRAME_NOT_SPLITTABLE; } -void -nsTableColFrame::InvalidateFrame(uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrame(aDisplayItemKey); - GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey); -} - -void -nsTableColFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey); - - // If we have filters applied that would affects our bounds, then - // we get an inactive layer created and this is computed - // within FrameLayerBuilder - GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey); -} - diff --git a/layout/tables/nsTableColFrame.h b/layout/tables/nsTableColFrame.h index 233e3f0e61936..5acfd5953962d 100644 --- a/layout/tables/nsTableColFrame.h +++ b/layout/tables/nsTableColFrame.h @@ -263,10 +263,6 @@ class nsTableColFrame : public nsSplittableFrame { nscoord GetFinalWidth() { return mFinalWidth; } - - virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); } protected: diff --git a/layout/tables/nsTableColGroupFrame.cpp b/layout/tables/nsTableColGroupFrame.cpp index ecba179bdcf8b..54e6c1281904a 100644 --- a/layout/tables/nsTableColGroupFrame.cpp +++ b/layout/tables/nsTableColGroupFrame.cpp @@ -72,8 +72,6 @@ nsTableColGroupFrame::AddColsToTable(int32_t aFirstColIndex, { nsTableFrame* tableFrame = nsTableFrame::GetTableFrame(this); - tableFrame->InvalidateFrameSubtree(); - // set the col indices of the col frames and and add col info to the table int32_t colIndex = aFirstColIndex; nsFrameList::Enumerator e(aCols); @@ -463,23 +461,6 @@ nsTableColGroupFrame::GetType() const { return nsGkAtoms::tableColGroupFrame; } - -void -nsTableColGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrame(aDisplayItemKey); - GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey); -} - -void -nsTableColGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey); - // If we have filters applied that would affects our bounds, then - // we get an inactive layer created and this is computed - // within FrameLayerBuilder - GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey); -} #ifdef DEBUG NS_IMETHODIMP diff --git a/layout/tables/nsTableColGroupFrame.h b/layout/tables/nsTableColGroupFrame.h index 0c7b2e28d0be4..724a364417e4f 100644 --- a/layout/tables/nsTableColGroupFrame.h +++ b/layout/tables/nsTableColGroupFrame.h @@ -196,11 +196,6 @@ class nsTableColGroupFrame : public nsContainerFrame */ void SetContinuousBCBorderWidth(uint8_t aForSide, BCPixelSize aPixelValue); - - virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); } - protected: nsTableColGroupFrame(nsStyleContext* aContext); diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp index e8d35eaee744e..106a66aec6e63 100644 --- a/layout/tables/nsTableFrame.cpp +++ b/layout/tables/nsTableFrame.cpp @@ -1211,7 +1211,10 @@ AnyTablePartHasBorderOrBackground(nsIFrame* aStart, nsIFrame* aEnd) for (nsIFrame* f = aStart; f != aEnd; f = f->GetNextSibling()) { NS_ASSERTION(IsFrameAllowedInTable(f->GetType()), "unexpected frame type"); - if (FrameHasBorderOrBackground(f)) + if (f->GetStyleVisibility()->IsVisible() && + (!f->GetStyleBackground()->IsTransparent() || + f->GetStyleDisplay()->mAppearance || + f->GetStyleBorder()->HasBorder())) return true; nsTableCellFrame *cellFrame = do_QueryFrame(f); @@ -1391,7 +1394,10 @@ nsTableFrame::ProcessRowInserted(nscoord aNewHeight) if (rowFrame->IsFirstInserted()) { rowFrame->SetFirstInserted(false); // damage the table from the 1st row inserted to the end of the table - nsIFrame::InvalidateFrame(); + nscoord damageY = rgFrame->GetPosition().y + rowFrame->GetPosition().y; + nsRect damageRect(0, damageY, GetSize().width, aNewHeight - damageY); + + Invalidate(damageRect); // XXXbz didn't we do this up front? Why do we need to do it again? SetRowInserted(false); return; // found it, so leave @@ -1806,9 +1812,11 @@ NS_METHOD nsTableFrame::Reflow(nsPresContext* aPresContext, } aDesiredSize.mOverflowAreas.UnionAllWith(tableRect); - if ((GetStateBits() & NS_FRAME_FIRST_REFLOW) || - nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) { - nsIFrame::InvalidateFrame(); + if (GetStateBits() & NS_FRAME_FIRST_REFLOW) { + // Fulfill the promise InvalidateFrame makes. + Invalidate(aDesiredSize.VisualOverflow()); + } else { + CheckInvalidateSizeChange(aDesiredSize); } FinishAndStoreOverflow(&aDesiredSize); @@ -2503,8 +2511,8 @@ void nsTableFrame::PlaceChild(nsTableReflowState& aReflowState, FinishReflowChild(aKidFrame, PresContext(), nullptr, aKidDesiredSize, aReflowState.x, aReflowState.y, 0); - InvalidateTableFrame(aKidFrame, aOriginalKidRect, aOriginalKidVisualOverflow, - isFirstReflow); + InvalidateFrame(aKidFrame, aOriginalKidRect, aOriginalKidVisualOverflow, + isFirstReflow); // Adjust the running y-offset aReflowState.y += aKidDesiredSize.height; @@ -3121,8 +3129,7 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, //rowFrame->DidResize(); nsTableFrame::RePositionViews(rowFrame); - rgFrame->InvalidateFrameWithRect(oldRowRect); - rgFrame->InvalidateFrame(); + rgFrame->InvalidateRectDifference(oldRowRect, rowRect); } } else { @@ -3151,8 +3158,8 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, rgFrame->SetRect(rgRect); - nsTableFrame::InvalidateTableFrame(rgFrame, origRgRect, - origRgVisualOverflow, false); + nsTableFrame::InvalidateFrame(rgFrame, origRgRect, + origRgVisualOverflow, false); } } else if (amountUsed > 0 && yOriginRG != rgRect.y) { @@ -3286,8 +3293,8 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, //rowFrame->DidResize(); nsTableFrame::RePositionViews(rowFrame); - nsTableFrame::InvalidateTableFrame(rowFrame, rowRect, rowVisualOverflow, - false); + nsTableFrame::InvalidateFrame(rowFrame, rowRect, rowVisualOverflow, + false); } else { if (amountUsed > 0 && yOriginRow != rowRect.y) { @@ -3309,8 +3316,8 @@ nsTableFrame::DistributeHeightToRows(const nsHTMLReflowState& aReflowState, rgFrame->SetRect(nsRect(rgRect.x, yOriginRG, rgRect.width, rgRect.height + amountUsedByRG)); - nsTableFrame::InvalidateTableFrame(rgFrame, rgRect, rgVisualOverflow, - false); + nsTableFrame::InvalidateFrame(rgFrame, rgRect, rgVisualOverflow, + false); } // Make sure child views are properly positioned } @@ -7234,10 +7241,10 @@ bool nsTableFrame::RowIsSpannedInto(int32_t aRowIndex, int32_t aNumEffCols) /* static */ void -nsTableFrame::InvalidateTableFrame(nsIFrame* aFrame, - const nsRect& aOrigRect, - const nsRect& aOrigVisualOverflow, - bool aIsFirstReflow) +nsTableFrame::InvalidateFrame(nsIFrame* aFrame, + const nsRect& aOrigRect, + const nsRect& aOrigVisualOverflow, + bool aIsFirstReflow) { nsIFrame* parent = aFrame->GetParent(); NS_ASSERTION(parent, "What happened here?"); @@ -7251,9 +7258,6 @@ nsTableFrame::InvalidateTableFrame(nsIFrame* aFrame, // The part that looks at both the rect and the overflow rect is a // bit of a hack. See nsBlockFrame::ReflowLine for an eloquent // description of its hackishness. - // - // This doesn't really make sense now that we have DLBI. - // This code can probably be simplified a fair bit. nsRect visualOverflow = aFrame->GetVisualOverflowRect(); if (aIsFirstReflow || aOrigRect.TopLeft() != aFrame->GetPosition() || @@ -7264,12 +7268,13 @@ nsTableFrame::InvalidateTableFrame(nsIFrame* aFrame, // aFrame's parent, and reposition that overflow rect to the right // place. // XXXbz this doesn't handle outlines, does it? - aFrame->InvalidateFrame(); - parent->InvalidateFrameWithRect(aOrigVisualOverflow + aOrigRect.TopLeft()); + aFrame->Invalidate(visualOverflow); + parent->Invalidate(aOrigVisualOverflow + aOrigRect.TopLeft()); } else { - aFrame->InvalidateFrameWithRect(aOrigVisualOverflow);; - aFrame->InvalidateFrame(); - parent->InvalidateFrameWithRect(aOrigRect);; - parent->InvalidateFrame(); + nsRect rect = aFrame->GetRect(); + aFrame->CheckInvalidateSizeChange(aOrigRect, aOrigVisualOverflow, + rect.Size()); + aFrame->InvalidateRectDifference(aOrigVisualOverflow, visualOverflow); + parent->InvalidateRectDifference(aOrigRect, rect); } } diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 54845fa23643b..ed71bf000c8fe 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -33,13 +33,6 @@ static inline bool IS_TABLE_CELL(nsIAtom* frameType) { nsGkAtoms::bcTableCellFrame == frameType; } -static inline bool FrameHasBorderOrBackground(nsIFrame* f) { - return (f->GetStyleVisibility()->IsVisible() && - (!f->GetStyleBackground()->IsTransparent() || - f->GetStyleDisplay()->mAppearance || - f->GetStyleBorder()->HasBorder())); -} - class nsDisplayTableItem : public nsDisplayItem { public: @@ -476,10 +469,10 @@ class nsTableFrame : public nsContainerFrame, public nsITableLayout * @param aIsFirstReflow True if the size/position change is due to the * first reflow of aFrame. */ - static void InvalidateTableFrame(nsIFrame* aFrame, - const nsRect& aOrigRect, - const nsRect& aOrigVisualOverflow, - bool aIsFirstReflow); + static void InvalidateFrame(nsIFrame* aFrame, + const nsRect& aOrigRect, + const nsRect& aOrigVisualOverflow, + bool aIsFirstReflow); virtual bool UpdateOverflow(); diff --git a/layout/tables/nsTableOuterFrame.cpp b/layout/tables/nsTableOuterFrame.cpp index 08df255da3f9d..bdb115232c4bb 100644 --- a/layout/tables/nsTableOuterFrame.cpp +++ b/layout/tables/nsTableOuterFrame.cpp @@ -1052,12 +1052,12 @@ NS_METHOD nsTableOuterFrame::Reflow(nsPresContext* aPresContext, innerOrigin.x, innerOrigin.y, 0); innerRS->~nsHTMLReflowState(); - nsTableFrame::InvalidateTableFrame(InnerTableFrame(), origInnerRect, - origInnerVisualOverflow, innerFirstReflow); + nsTableFrame::InvalidateFrame(InnerTableFrame(), origInnerRect, + origInnerVisualOverflow, innerFirstReflow); if (mCaptionFrames.NotEmpty()) { - nsTableFrame::InvalidateTableFrame(mCaptionFrames.FirstChild(), origCaptionRect, - origCaptionVisualOverflow, - captionFirstReflow); + nsTableFrame::InvalidateFrame(mCaptionFrames.FirstChild(), origCaptionRect, + origCaptionVisualOverflow, + captionFirstReflow); } UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, captionMargin); diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp index e34bad7ba527e..a4aa1594676d3 100644 --- a/layout/tables/nsTableRowFrame.cpp +++ b/layout/tables/nsTableRowFrame.cpp @@ -339,9 +339,9 @@ nsTableRowFrame::DidResize() if (cellRect.height != cellHeight) { cellFrame->SetSize(nsSize(cellRect.width, cellHeight)); - nsTableFrame::InvalidateTableFrame(cellFrame, cellRect, - cellVisualOverflow, - false); + nsTableFrame::InvalidateFrame(cellFrame, cellRect, + cellVisualOverflow, + false); } // realign cell content based on the new height. We might be able to @@ -930,8 +930,8 @@ nsTableRowFrame::ReflowChildren(nsPresContext* aPresContext, FinishReflowChild(kidFrame, aPresContext, nullptr, desiredSize, x, 0, 0); - nsTableFrame::InvalidateTableFrame(kidFrame, kidRect, kidVisualOverflow, - firstReflow); + nsTableFrame::InvalidateFrame(kidFrame, kidRect, kidVisualOverflow, + firstReflow); x += desiredSize.width; } @@ -1028,9 +1028,8 @@ nsTableRowFrame::Reflow(nsPresContext* aPresContext, // If our parent is in initial reflow, it'll handle invalidating our // entire overflow rect. - if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && - nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) { - InvalidateFrame(); + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + CheckInvalidateSizeChange(aDesiredSize); } NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize); @@ -1079,10 +1078,10 @@ nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext, aCellFrame->VerticallyAlignChild(mMaxCellAscent); } - nsTableFrame::InvalidateTableFrame(aCellFrame, cellRect, - cellVisualOverflow, - (aCellFrame->GetStateBits() & - NS_FRAME_FIRST_REFLOW) != 0); + nsTableFrame::InvalidateFrame(aCellFrame, cellRect, + cellVisualOverflow, + (aCellFrame->GetStateBits() & + NS_FRAME_FIRST_REFLOW) != 0); aCellFrame->DidReflow(aPresContext, nullptr, NS_FRAME_REFLOW_FINISHED); @@ -1130,7 +1129,7 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, // need to invalidate if our row is not moving, because the cell might // span out of this row, so invalidating our row rect won't do enough. if (aRowOffset == 0) { - InvalidateFrame(); + Invalidate(cRect); } cRect.height = 0; cellFrame->SetRect(cRect); @@ -1241,9 +1240,9 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, ConsiderChildOverflow(overflow, cellFrame); if (aRowOffset == 0) { - nsTableFrame::InvalidateTableFrame(cellFrame, oldCellRect, - oldCellVisualOverflow, - false); + nsTableFrame::InvalidateFrame(cellFrame, oldCellRect, + oldCellVisualOverflow, + false); } } kidFrame = iter.Next(); // Get the next child @@ -1255,7 +1254,7 @@ nsTableRowFrame::CollapseRowIfNecessary(nscoord aRowOffset, FinishAndStoreOverflow(overflow, nsSize(rowRect.width, rowRect.height)); nsTableFrame::RePositionViews(this); - nsTableFrame::InvalidateTableFrame(this, oldRect, oldVisualOverflow, false); + nsTableFrame::InvalidateFrame(this, oldRect, oldVisualOverflow, false); return shift; } @@ -1381,23 +1380,6 @@ void nsTableRowFrame::InitHasCellWithStyleHeight(nsTableFrame* aTableFrame) } RemoveStateBits(NS_ROW_HAS_CELL_WITH_STYLE_HEIGHT); } - -void -nsTableRowFrame::InvalidateFrame(uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrame(aDisplayItemKey); - GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey); -} - -void -nsTableRowFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey); - // If we have filters applied that would affects our bounds, then - // we get an inactive layer created and this is computed - // within FrameLayerBuilder - GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey); -} /* ----- global methods ----- */ diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h index 09a9e8441bd52..a14959f79cfac 100644 --- a/layout/tables/nsTableRowFrame.h +++ b/layout/tables/nsTableRowFrame.h @@ -224,10 +224,6 @@ class nsTableRowFrame : public nsContainerFrame void SetContinuousBCBorderWidth(uint8_t aForSide, BCPixelSize aPixelValue); - virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); } - #ifdef ACCESSIBILITY virtual already_AddRefed CreateAccessible() MOZ_OVERRIDE; #endif diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp index 3c73166c36553..0109a9f796491 100644 --- a/layout/tables/nsTableRowGroupFrame.cpp +++ b/layout/tables/nsTableRowGroupFrame.cpp @@ -261,8 +261,8 @@ nsTableRowGroupFrame::PlaceChild(nsPresContext* aPresContext, FinishReflowChild(aKidFrame, aPresContext, nullptr, aDesiredSize, 0, aReflowState.y, 0); - nsTableFrame::InvalidateTableFrame(aKidFrame, aOriginalKidRect, - aOriginalKidVisualOverflow, isFirstReflow); + nsTableFrame::InvalidateFrame(aKidFrame, aOriginalKidRect, + aOriginalKidVisualOverflow, isFirstReflow); // Adjust the running y-offset aReflowState.y += aDesiredSize.height; @@ -396,7 +396,15 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, // differently, repaint the entire row nsRect kidRect(0, aReflowState.y, desiredSize.width, desiredSize.height); - InvalidateFrame(); + Invalidate(kidRect); + + // Invalidate the area we're offseting. Note that we only + // repaint within our existing frame bounds. + if (kidRect.YMost() < mRect.height) { + nsRect dirtyRect(0, kidRect.YMost(), + mRect.width, mRect.height - kidRect.YMost()); + Invalidate(dirtyRect); + } } else if (oldKidRect.height != desiredSize.height) needToCalcRowHeights = true; @@ -441,7 +449,11 @@ nsTableRowGroupFrame::ReflowChildren(nsPresContext* aPresContext, else if (needToCalcRowHeights) { CalculateRowHeights(aPresContext, aDesiredSize, aReflowState.reflowState); if (!reflowAllKids) { - InvalidateFrame(); + // Because we don't know what changed repaint everything. + // XXX We should change CalculateRowHeights() to return the bounding + // rect of what changed. Or whether anything moved or changed size... + nsRect dirtyRect(0, 0, mRect.width, mRect.height); + Invalidate(dirtyRect); } } @@ -763,8 +775,8 @@ nsTableRowGroupFrame::CalculateRowHeights(nsPresContext* aPresContext, rowFrame->SetRect(nsRect(rowBounds.x, yOrigin, rowBounds.width, rowHeight)); - nsTableFrame::InvalidateTableFrame(rowFrame, rowBounds, rowVisualOverflow, - false); + nsTableFrame::InvalidateFrame(rowFrame, rowBounds, rowVisualOverflow, + false); } if (movedFrame) { nsTableFrame::RePositionViews(rowFrame); @@ -828,8 +840,8 @@ nsTableRowGroupFrame::CollapseRowGroupIfNecessary(nscoord aYTotalOffset, overflow.UnionAllWith(nsRect(0, 0, groupRect.width, groupRect.height)); FinishAndStoreOverflow(overflow, nsSize(groupRect.width, groupRect.height)); nsTableFrame::RePositionViews(this); - nsTableFrame::InvalidateTableFrame(this, oldGroupRect, oldGroupVisualOverflow, - false); + nsTableFrame::InvalidateFrame(this, oldGroupRect, oldGroupVisualOverflow, + false); return yGroupOffset; } @@ -1080,9 +1092,9 @@ nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext, rowFrame->DidReflow(aPresContext, nullptr, NS_FRAME_REFLOW_FINISHED); rowFrame->DidResize(); - nsTableFrame::InvalidateTableFrame(rowFrame, oldRowRect, - oldRowVisualOverflow, - false); + nsTableFrame::InvalidateFrame(rowFrame, oldRowRect, + oldRowVisualOverflow, + false); if (NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // The row frame is incomplete and all of the rowspan 1 cells' block frames split @@ -1313,9 +1325,8 @@ nsTableRowGroupFrame::Reflow(nsPresContext* aPresContext, // If our parent is in initial reflow, it'll handle invalidating our // entire overflow rect. - if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW) && - nsSize(aDesiredSize.width, aDesiredSize.height) != mRect.Size()) { - InvalidateFrame(); + if (!(GetParent()->GetStateBits() & NS_FRAME_FIRST_REFLOW)) { + CheckInvalidateSizeChange(aDesiredSize); } FinishAndStoreOverflow(&aDesiredSize); @@ -1871,20 +1882,3 @@ nsTableRowGroupFrame::FrameCursorData::AppendFrame(nsIFrame* aFrame) mOverflowBelow = NS_MAX(mOverflowBelow, overflowBelow); return mFrames.AppendElement(aFrame) != nullptr; } - -void -nsTableRowGroupFrame::InvalidateFrame(uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrame(aDisplayItemKey); - GetParent()->InvalidateFrameWithRect(GetVisualOverflowRect() + GetPosition(), aDisplayItemKey); -} - -void -nsTableRowGroupFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey) -{ - nsIFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey); - // If we have filters applied that would affects our bounds, then - // we get an inactive layer created and this is computed - // within FrameLayerBuilder - GetParent()->InvalidateFrameWithRect(aRect + GetPosition(), aDisplayItemKey); -} diff --git a/layout/tables/nsTableRowGroupFrame.h b/layout/tables/nsTableRowGroupFrame.h index 2846120bb0439..f011fd9763f12 100644 --- a/layout/tables/nsTableRowGroupFrame.h +++ b/layout/tables/nsTableRowGroupFrame.h @@ -325,10 +325,6 @@ class nsTableRowGroupFrame virtual nsILineIterator* GetLineIterator() { return this; } - virtual void InvalidateFrame(uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayItemKey = 0) MOZ_OVERRIDE; - virtual void InvalidateFrameForRemoval() MOZ_OVERRIDE { InvalidateFrameSubtree(); } - protected: nsTableRowGroupFrame(nsStyleContext* aContext); diff --git a/layout/tools/reftest/reftest-content.js b/layout/tools/reftest/reftest-content.js index cc41b4c009634..222c467b12d87 100644 --- a/layout/tools/reftest/reftest-content.js +++ b/layout/tools/reftest/reftest-content.js @@ -790,7 +790,6 @@ function SendUpdateCanvasForEvent(event) var rects = [ ]; var rectList = event.clientRects; - LogInfo("SendUpdateCanvasForEvent with " + rectList.length + " rects"); for (var i = 0; i < rectList.length; ++i) { var r = rectList[i]; // Set left/top/right/bottom to "device pixel" boundaries @@ -798,7 +797,6 @@ function SendUpdateCanvasForEvent(event) var top = Math.floor(roundTo(r.top*scale, 0.001)); var right = Math.ceil(roundTo(r.right*scale, 0.001)); var bottom = Math.ceil(roundTo(r.bottom*scale, 0.001)); - LogInfo("Rect: " + left + " " + top + " " + right + " " + bottom); rects.push({ left: left, top: top, right: right, bottom: bottom }); } diff --git a/layout/tools/reftest/reftest.js b/layout/tools/reftest/reftest.js index 42f76d385bd45..0afa0ec578ad4 100644 --- a/layout/tools/reftest/reftest.js +++ b/layout/tools/reftest/reftest.js @@ -278,10 +278,6 @@ function InitAndStartRefTests() gDumpLog("REFTEST TEST-UNEXPECTED-FAIL | | EXCEPTION: " + e + "\n"); } - try { - prefs.setBoolPref("android.widget_paints_background", false); - } catch (e) {} - /* set the gLoadTimeout */ try { gLoadTimeout = prefs.getIntPref("reftest.timeout"); diff --git a/layout/xul/base/src/nsBox.cpp b/layout/xul/base/src/nsBox.cpp index d02157a3fbf8b..502a2cd1a2a76 100644 --- a/layout/xul/base/src/nsBox.cpp +++ b/layout/xul/base/src/nsBox.cpp @@ -583,14 +583,22 @@ nsBox::SyncLayout(nsBoxLayoutState& aState) } nsresult -nsIFrame::Redraw(nsBoxLayoutState& aState) +nsIFrame::Redraw(nsBoxLayoutState& aState, + const nsRect* aDamageRect) { if (aState.PaintingDisabled()) return NS_OK; + nsRect damageRect(0,0,0,0); + if (aDamageRect) + damageRect = *aDamageRect; + else + damageRect = GetVisualOverflowRect(); + + Invalidate(damageRect); // nsStackLayout, at least, expects us to repaint descendants even // if a damage rect is provided - InvalidateFrameSubtree(); + FrameLayerBuilder::InvalidateThebesLayersInSubtree(this); return NS_OK; } diff --git a/layout/xul/base/src/nsDeckFrame.cpp b/layout/xul/base/src/nsDeckFrame.cpp index 27ae0896a68c0..106434aaca992 100644 --- a/layout/xul/base/src/nsDeckFrame.cpp +++ b/layout/xul/base/src/nsDeckFrame.cpp @@ -97,7 +97,7 @@ nsDeckFrame::IndexChanged() return; // redraw - InvalidateFrame(); + InvalidateOverflowRect(); // hide the currently showing box nsIFrame* currentBox = GetSelectedBox(); diff --git a/layout/xul/base/src/nsImageBoxFrame.cpp b/layout/xul/base/src/nsImageBoxFrame.cpp index e4f1ae79a6ccc..0e2bfff6e3ca6 100644 --- a/layout/xul/base/src/nsImageBoxFrame.cpp +++ b/layout/xul/base/src/nsImageBoxFrame.cpp @@ -44,15 +44,11 @@ #include "nsGUIEvent.h" #include "nsEventDispatcher.h" #include "nsDisplayList.h" -#include "ImageLayers.h" -#include "ImageContainer.h" #include "nsContentUtils.h" #define ONLOAD_CALLED_TOO_EARLY 1 -using namespace mozilla::layers; - class nsImageBoxFrameEvent : public nsRunnable { public: @@ -286,6 +282,36 @@ nsImageBoxFrame::UpdateLoadFlags() } } +class nsDisplayXULImage : public nsDisplayItem { +public: + nsDisplayXULImage(nsDisplayListBuilder* aBuilder, + nsImageBoxFrame* aFrame) : + nsDisplayItem(aBuilder, aFrame) { + MOZ_COUNT_CTOR(nsDisplayXULImage); + } +#ifdef NS_BUILD_REFCNT_LOGGING + virtual ~nsDisplayXULImage() { + MOZ_COUNT_DTOR(nsDisplayXULImage); + } +#endif + + // Doesn't handle HitTest because nsLeafBoxFrame already creates an + // event receiver for us + virtual void Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx); + NS_DISPLAY_DECL_NAME("XULImage", TYPE_XUL_IMAGE) +}; + +void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder, + nsRenderingContext* aCtx) +{ + static_cast(mFrame)-> + PaintImage(*aCtx, mVisibleRect, ToReferenceFrame(), + aBuilder->ShouldSyncDecodeImages() + ? (uint32_t) imgIContainer::FLAG_SYNC_DECODE + : (uint32_t) imgIContainer::FLAG_NONE); +} + NS_IMETHODIMP nsImageBoxFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, const nsRect& aDirtyRect, @@ -337,74 +363,6 @@ nsImageBoxFrame::PaintImage(nsRenderingContext& aRenderingContext, } } -void nsDisplayXULImage::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) -{ - static_cast(mFrame)-> - PaintImage(*aCtx, mVisibleRect, ToReferenceFrame(), - aBuilder->ShouldSyncDecodeImages() - ? (uint32_t) imgIContainer::FLAG_SYNC_DECODE - : (uint32_t) imgIContainer::FLAG_NONE); -} - -void -nsDisplayXULImage::ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) -{ - aLayer->SetFilter(nsLayoutUtils::GetGraphicsFilterForFrame(mFrame)); - - int32_t factor = mFrame->PresContext()->AppUnitsPerDevPixel(); - nsImageBoxFrame* imageFrame = static_cast(mFrame); - - nsRect dest; - imageFrame->GetClientRect(dest); - dest += ToReferenceFrame(); - gfxRect destRect(dest.x, dest.y, dest.width, dest.height); - destRect.ScaleInverse(factor); - - nsCOMPtr imgCon; - imageFrame->mImageRequest->GetImage(getter_AddRefs(imgCon)); - int32_t imageWidth; - int32_t imageHeight; - imgCon->GetWidth(&imageWidth); - imgCon->GetHeight(&imageHeight); - - NS_ASSERTION(imageWidth != 0 && imageHeight != 0, "Invalid image size!"); - - gfxMatrix transform; - transform.Translate(destRect.TopLeft() + aOffset); - transform.Scale(destRect.Width()/imageWidth, - destRect.Height()/imageHeight); - aLayer->SetBaseTransform(gfx3DMatrix::From2D(transform)); - - aLayer->SetVisibleRegion(nsIntRect(0, 0, imageWidth, imageHeight)); -} - -already_AddRefed -nsDisplayXULImage::GetContainer() -{ - return static_cast(mFrame)->GetContainer(); -} - -already_AddRefed -nsImageBoxFrame::GetContainer() -{ - bool hasSubRect = !mUseSrcAttr && (mSubRect.width > 0 || mSubRect.height > 0); - if (hasSubRect || !mImageRequest) { - return nullptr; - } - - nsCOMPtr imgCon; - mImageRequest->GetImage(getter_AddRefs(imgCon)); - if (!imgCon) { - return nullptr; - } - - nsRefPtr container; - nsresult rv = imgCon->GetImageContainer(getter_AddRefs(container)); - NS_ENSURE_SUCCESS(rv, nullptr); - return container.forget(); -} - // // DidSetStyleContext @@ -635,11 +593,8 @@ NS_IMETHODIMP nsImageBoxFrame::FrameChanged(imgIRequest *aRequest, imgIContainer *aContainer, const nsIntRect *aDirtyRect) { - if ((0 == mRect.width) || (0 == mRect.height)) { - return NS_OK; - } - - InvalidateLayer(nsDisplayItem::TYPE_XUL_IMAGE); + nsBoxLayoutState state(PresContext()); + this->Redraw(state); return NS_OK; } diff --git a/layout/xul/base/src/nsImageBoxFrame.h b/layout/xul/base/src/nsImageBoxFrame.h index a06f41fbb6191..b8c6b90f88fcd 100644 --- a/layout/xul/base/src/nsImageBoxFrame.h +++ b/layout/xul/base/src/nsImageBoxFrame.h @@ -15,8 +15,6 @@ class nsImageBoxFrame; -class nsDisplayXULImage; - class nsImageBoxListener : public nsStubImageDecoderObserver { public: @@ -45,7 +43,6 @@ class nsImageBoxListener : public nsStubImageDecoderObserver class nsImageBoxFrame : public nsLeafBoxFrame { public: - friend class nsDisplayXULImage; NS_DECL_FRAMEARENA_HELPERS virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState); @@ -106,7 +103,6 @@ class nsImageBoxFrame : public nsLeafBoxFrame const nsRect& aDirtyRect, nsPoint aPt, uint32_t aFlags); - already_AddRefed GetContainer(); protected: nsImageBoxFrame(nsIPresShell* aShell, nsStyleContext* aContext); @@ -131,27 +127,4 @@ class nsImageBoxFrame : public nsLeafBoxFrame bool mSuppressStyleCheck; }; // class nsImageBoxFrame -class nsDisplayXULImage : public nsDisplayImageContainer { -public: - nsDisplayXULImage(nsDisplayListBuilder* aBuilder, - nsImageBoxFrame* aFrame) : - nsDisplayImageContainer(aBuilder, aFrame) { - MOZ_COUNT_CTOR(nsDisplayXULImage); - } -#ifdef NS_BUILD_REFCNT_LOGGING - virtual ~nsDisplayXULImage() { - MOZ_COUNT_DTOR(nsDisplayXULImage); - } -#endif - - virtual already_AddRefed GetContainer() MOZ_OVERRIDE; - virtual void ConfigureLayer(ImageLayer* aLayer, const nsIntPoint& aOffset) MOZ_OVERRIDE; - - // Doesn't handle HitTest because nsLeafBoxFrame already creates an - // event receiver for us - virtual void Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx); - NS_DISPLAY_DECL_NAME("XULImage", TYPE_XUL_IMAGE) -}; - #endif /* nsImageBoxFrame_h___ */ diff --git a/layout/xul/base/src/nsListBoxLayout.cpp b/layout/xul/base/src/nsListBoxLayout.cpp index 7da88cbdd4552..095eb07579c36 100644 --- a/layout/xul/base/src/nsListBoxLayout.cpp +++ b/layout/xul/base/src/nsListBoxLayout.cpp @@ -197,7 +197,9 @@ nsListBoxLayout::LayoutInternal(nsIFrame* aBox, nsBoxLayoutState& aState) // before them then redraw everything under the inserted rows. The inserted // rows will automatically be redrawn because the were marked dirty on insertion. if (redrawStart > -1) { - aBox->Redraw(aState); + nsRect bounds(aBox->GetRect()); + nsRect tempRect(0,redrawStart,bounds.width, bounds.height - redrawStart); + aBox->Redraw(aState, &tempRect); } return NS_OK; diff --git a/layout/xul/base/src/nsMenuPopupFrame.cpp b/layout/xul/base/src/nsMenuPopupFrame.cpp index 220b7b68caba2..9f60549e7b9bf 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -170,8 +170,6 @@ nsMenuPopupFrame::Init(nsIContent* aContent, } } - AddStateBits(NS_FRAME_IN_POPUP); - return rv; } @@ -814,6 +812,14 @@ nsMenuPopupFrame::HidePopup(bool aDeselectMenu, nsPopupState aNewState) } } +void +nsMenuPopupFrame::InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags) +{ + InvalidateRoot(aDamageRect + nsPoint(aX, aY), aFlags); +} + void nsMenuPopupFrame::GetLayoutFlags(uint32_t& aFlags) { diff --git a/layout/xul/base/src/nsMenuPopupFrame.h b/layout/xul/base/src/nsMenuPopupFrame.h index 8859f963151d3..cbc2e130d3fe7 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.h +++ b/layout/xul/base/src/nsMenuPopupFrame.h @@ -160,6 +160,10 @@ class nsMenuPopupFrame : public nsBoxFrame, public nsMenuParent virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE; + virtual void InvalidateInternal(const nsRect& aDamageRect, + nscoord aX, nscoord aY, nsIFrame* aForChild, + uint32_t aFlags); + // returns true if the popup is a panel with the noautohide attribute set to // true. These panels do not roll up automatically. bool IsNoAutoHide() const; diff --git a/layout/xul/base/src/nsSliderFrame.cpp b/layout/xul/base/src/nsSliderFrame.cpp index f93a1cf9818d6..0bb74e1c95503 100644 --- a/layout/xul/base/src/nsSliderFrame.cpp +++ b/layout/xul/base/src/nsSliderFrame.cpp @@ -696,7 +696,7 @@ nsSliderFrame::CurrentPositionChanged(nsPresContext* aPresContext, thumbFrame->SetRect(newThumbRect); // Redraw the scrollbar - //InvalidateFrame(); + InvalidateWithFlags(clientRect, aImmediateRedraw ? INVALIDATE_IMMEDIATE : 0); mCurPos = curPos; diff --git a/layout/xul/base/src/nsStackLayout.cpp b/layout/xul/base/src/nsStackLayout.cpp index 4ba62ce7a1057..ad731c8581f60 100644 --- a/layout/xul/base/src/nsStackLayout.cpp +++ b/layout/xul/base/src/nsStackLayout.cpp @@ -364,7 +364,14 @@ nsStackLayout::Layout(nsIFrame* aBox, nsBoxLayoutState& aState) // if the new and old rect intersect meaning we just moved a little // then just redraw the union. If they don't intersect (meaning // we moved a good distance) redraw both separately. - aBox->Redraw(aState); + if (childRectNoMargin.Intersects(oldRect)) { + nsRect u; + u.UnionRect(oldRect, childRectNoMargin); + aBox->Redraw(aState, &u); + } else { + aBox->Redraw(aState, &oldRect); + aBox->Redraw(aState, &childRectNoMargin); + } } } diff --git a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp index ec278bc20db9a..74156a6bd3a49 100644 --- a/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp +++ b/layout/xul/base/src/tree/src/nsTreeBodyFrame.cpp @@ -644,7 +644,7 @@ nsTreeBodyFrame::Invalidate() if (mUpdateBatchNest) return NS_OK; - InvalidateFrame(); + InvalidateOverflowRect(); return NS_OK; } @@ -670,7 +670,7 @@ nsTreeBodyFrame::InvalidateColumn(nsITreeColumn* aCol) // When false then column is out of view if (OffsetForHorzScroll(columnRect, true)) - InvalidateFrameWithRect(columnRect); + nsIFrame::Invalidate(columnRect); return NS_OK; } @@ -691,7 +691,7 @@ nsTreeBodyFrame::InvalidateRow(int32_t aIndex) return NS_OK; nsRect rowRect(mInnerBox.x, mInnerBox.y+mRowHeight*aIndex, mInnerBox.width, mRowHeight); - InvalidateFrameWithRect(rowRect); + nsLeafBoxFrame::Invalidate(rowRect); return NS_OK; } @@ -721,7 +721,7 @@ nsTreeBodyFrame::InvalidateCell(int32_t aIndex, nsITreeColumn* aCol) NS_ENSURE_SUCCESS(rv, rv); if (OffsetForHorzScroll(cellRect, true)) - InvalidateFrameWithRect(cellRect); + nsIFrame::Invalidate(cellRect); return NS_OK; } @@ -754,7 +754,7 @@ nsTreeBodyFrame::InvalidateRange(int32_t aStart, int32_t aEnd) #endif nsRect rangeRect(mInnerBox.x, mInnerBox.y+mRowHeight*(aStart-mTopRowIndex), mInnerBox.width, mRowHeight*(aEnd-aStart+1)); - InvalidateFrameWithRect(rangeRect); + nsIFrame::Invalidate(rangeRect); return NS_OK; } @@ -797,7 +797,7 @@ nsTreeBodyFrame::InvalidateColumnRange(int32_t aStart, int32_t aEnd, nsITreeColu &rangeRect); NS_ENSURE_SUCCESS(rv, rv); - InvalidateFrameWithRect(rangeRect); + nsIFrame::Invalidate(rangeRect); return NS_OK; } diff --git a/mobile/android/base/gfx/ScreenshotLayer.java b/mobile/android/base/gfx/ScreenshotLayer.java index b43ffd2a373bd..9b71d9bd21cf5 100644 --- a/mobile/android/base/gfx/ScreenshotLayer.java +++ b/mobile/android/base/gfx/ScreenshotLayer.java @@ -123,11 +123,7 @@ void copyBuffer(ByteBuffer src, ByteBuffer dst, Rect rect, int stride) { end = Math.max(start, Math.min(dst.limit(), Math.min(src.capacity(), end))); dst.position(start); src.position(start).limit(end); - // This allocates a lot of memory and can fail sometimes. Handling the - // exception is better than crashing. - try { - dst.put(src); - } catch (java.lang.OutOfMemoryError e) {} + dst.put(src); } synchronized void setBitmap(ByteBuffer data, int width, int height, int format, Rect rect) { diff --git a/toolkit/content/tests/chrome/window_panel.xul b/toolkit/content/tests/chrome/window_panel.xul index 1bfd525fa39a5..10243f7088db7 100644 --- a/toolkit/content/tests/chrome/window_panel.xul +++ b/toolkit/content/tests/chrome/window_panel.xul @@ -193,18 +193,14 @@ var tests = [ result: function(testname, panel) { var panelrect = panel.getBoundingClientRect(); ok(panelrect.left >= 200 - mozInnerScreenX, testname + "left"); - if (navigator.platform.indexOf("Linux") < 0) { - ok(panelrect.top >= 210 - mozInnerScreenY + 10, testname + "top greater"); - } + ok(panelrect.top >= 210 - mozInnerScreenY + 10, testname + "top greater"); ok(panelrect.top <= 210 - mozInnerScreenY + 30, testname + "top less"); is(panelrect.width, 120, testname + "width"); is(panelrect.height, 40, testname + "height"); var screenRect = panel.getOuterScreenRect(); - if (navigator.platform.indexOf("Linux") < 0) { - is(screenRect.left, 200, testname + " screen left"); - is(screenRect.top, 210, testname + " screen top"); - } + is(screenRect.left, 200, testname + " screen left"); + is(screenRect.top, 210, testname + " screen top"); ok(screenRect.width >= 120 && screenRect.width <= 140, testname + " screen width"); ok(screenRect.height >= 40 && screenRect.height <= 80, testname + " screen height"); diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 59e7987f39a15..230d563001bfe 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -84,6 +84,7 @@ nsViewManager::nsViewManager() // NOTE: we use a zeroing operator new, so all data members are // assumed to be cleared here. + mHasPendingUpdates = false; mHasPendingWidgetGeometryChanges = false; mRecursiveRefreshPending = false; } @@ -407,7 +408,8 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView, // Push out updates after we've processed the children; ensures that // damage is applied based on the final widget geometry - if (aFlushDirtyRegion) { + if (aFlushDirtyRegion && aView->HasNonEmptyDirtyRegion()) { + FlushDirtyRegionToWidget(aView); if (IsRefreshDriverPaintingEnabled()) { nsIWidget *widget = aView->GetWidget(); if (widget && widget->NeedsPaint()) { @@ -441,7 +443,6 @@ void nsViewManager::ProcessPendingUpdatesForView(nsView* aView, SetPainting(false); } } - FlushDirtyRegionToWidget(aView); } } @@ -484,6 +485,7 @@ void nsViewManager::PostPendingUpdate() { nsViewManager* rootVM = RootViewManager(); + rootVM->mHasPendingUpdates = true; rootVM->mHasPendingWidgetGeometryChanges = true; if (rootVM->mPresShell) { rootVM->mPresShell->ScheduleViewManagerFlush(); @@ -625,6 +627,9 @@ NS_IMETHODIMP nsViewManager::InvalidateViewNoSuppression(nsIView *aView, // process it later. AddDirtyRegion(displayRoot, nsRegion(damagedRect)); + // Schedule an invalidation flush with the refresh driver. + PostPendingUpdate(); + return NS_OK; } @@ -1201,16 +1206,20 @@ nsViewManager::ProcessPendingUpdates() if (IsRefreshDriverPaintingEnabled()) { mPresShell->GetPresContext()->RefreshDriver()->RevokeViewManagerFlush(); + if (mHasPendingUpdates) { + mHasPendingUpdates = false; - // Flush things like reflows and plugin widget geometry updates by - // calling WillPaint on observer presShells. - if (mPresShell) { - CallWillPaintOnObservers(true); + // Flush things like reflows and plugin widget geometry updates by + // calling WillPaint on observer presShells. + if (mPresShell) { + CallWillPaintOnObservers(true); + } + ProcessPendingUpdatesForView(mRootView, true); + CallDidPaintOnObserver(); } + } else if (mHasPendingUpdates) { ProcessPendingUpdatesForView(mRootView, true); - CallDidPaintOnObserver(); - } else { - ProcessPendingUpdatesForView(mRootView, true); + mHasPendingUpdates = false; } } diff --git a/view/src/nsViewManager.h b/view/src/nsViewManager.h index 925bec03a5070..69f25006d8efe 100644 --- a/view/src/nsViewManager.h +++ b/view/src/nsViewManager.h @@ -203,6 +203,7 @@ class nsViewManager : public nsIViewManager { // Use IsPainting() and SetPainting() to access mPainting. bool mPainting; bool mRecursiveRefreshPending; + bool mHasPendingUpdates; bool mHasPendingWidgetGeometryChanges; bool mInScroll; diff --git a/widget/android/nsLookAndFeel.cpp b/widget/android/nsLookAndFeel.cpp index e2c57fc999f96..950eec35d411a 100644 --- a/widget/android/nsLookAndFeel.cpp +++ b/widget/android/nsLookAndFeel.cpp @@ -100,7 +100,7 @@ nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) // (except here at least TextSelectBackground and TextSelectForeground) // The CSS2 colors below are used. case eColorID_WindowBackground: - aColor = NS_RGB(0xFF, 0xFF, 0xFF); + aColor = mSystemColors.colorBackground; break; case eColorID_WindowForeground: aColor = mSystemColors.textColorPrimary; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index f25bb7f1146ea..1523c7d0d9148 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -2243,10 +2243,6 @@ nsWindow::DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) AndroidGeckoLayerClient& client = AndroidBridge::Bridge()->GetLayerClient(); if (!client.CreateFrame(&jniFrame, mLayerRendererFrame)) return; - - if (!WidgetPaintsBackground()) - return; - if (!client.ActivateProgram(&jniFrame)) return; if (!mLayerRendererFrame.BeginDrawing(&jniFrame)) return; if (!mLayerRendererFrame.DrawBackground(&jniFrame)) return; @@ -2313,22 +2309,6 @@ nsWindow::ScheduleResumeComposition(int width, int height) } } -bool -nsWindow::WidgetPaintsBackground() -{ - static bool sWidgetPaintsBackground = true; - static bool sWidgetPaintsBackgroundPrefCached = false; - - if (!sWidgetPaintsBackgroundPrefCached) { - sWidgetPaintsBackgroundPrefCached = true; - mozilla::Preferences::AddBoolVarCache(&sWidgetPaintsBackground, - "android.widget_paints_background", - true); - } - - return sWidgetPaintsBackground; -} - bool nsWindow::NeedsPaint() { diff --git a/widget/android/nsWindow.h b/widget/android/nsWindow.h index 8dc229fbf4103..340c19bf1d436 100644 --- a/widget/android/nsWindow.h +++ b/widget/android/nsWindow.h @@ -157,7 +157,7 @@ class nsWindow : static void SchedulePauseComposition(); static void ScheduleResumeComposition(int width, int height); - virtual bool WidgetPaintsBackground(); + virtual bool WidgetPaintsBackground() { return true; } #endif protected: diff --git a/widget/gtk2/nsNativeThemeGTK.cpp b/widget/gtk2/nsNativeThemeGTK.cpp index b07f4c97cbdaa..59132735dada8 100644 --- a/widget/gtk2/nsNativeThemeGTK.cpp +++ b/widget/gtk2/nsNativeThemeGTK.cpp @@ -719,12 +719,6 @@ nsNativeThemeGTK::GetExtraSizeForWidget(nsIFrame* aFrame, uint8_t aWidgetType, aExtra->bottom = extra; } } - case NS_THEME_TEXTFIELD: - { - aExtra->top = aExtra->bottom = 1; - aExtra->left = aExtra->right = 1; - return true; - } default: return false; } diff --git a/widget/xpwidgets/nsNativeTheme.cpp b/widget/xpwidgets/nsNativeTheme.cpp index f8ee3f08334f8..6cb42c68e78c8 100644 --- a/widget/xpwidgets/nsNativeTheme.cpp +++ b/widget/xpwidgets/nsNativeTheme.cpp @@ -566,7 +566,7 @@ nsNativeTheme::Notify(nsITimer* aTimer) for (uint32_t index = 0; index < count; index++) { nsIFrame* frame = mAnimatedContentList[index]->GetPrimaryFrame(); if (frame) { - frame->InvalidateFrame(); + frame->InvalidateOverflowRect(); } }