From 28eae10bc76d3ab0cb970096e2eefb1415ae3dbe Mon Sep 17 00:00:00 2001 From: roytam1 Date: Thu, 13 Jun 2024 11:26:16 +0800 Subject: [PATCH] import changes from `dev' branch of rmottola/Arctic-Fox: - Bug 1251797 - Don't fault struct out of rule tree if all of the potential physical property destinations already have a winning value in the cascade. r=heycam (b64f25ae75) - Bug 1257688 part 0: Add an "IsLegacyBox" accessor to nsFlexContainerFrame, to enable special handling of display:-webkit-box & display:-webkit-inline-box. r=mats (f728070412) - Bug 1257688 part 1: Change "-webkit-box-pack" & "-webkit-box-align" to alias their -moz equivalents, & change nsFlexContainerFrame to respect them in a -webkit-box. r=mats (fda7e641bb) - Bug 1174248 - Apply RTL resizer failure only to GTK2. r=karlt (5f264b52bc) - Bug 1234941 part 1: Add reftests for "-webkit-box" rendering, with -webkit-box-orient unset. r=heycam (bbdb2737a0) - Bug 1234941 part 2: Add reftests for "-webkit-box" rendering, with -webkit-box-orient:horizontal. r=heycam (815f24f010) - Bug 1234941 part 3: Add reftests for "-webkit-box" rendering, with -webkit-box-orient:vertical. r=heycam (a4f71266b9) - Bug 1257688 part 2: Enable "-webkit-box-pack: justify" sections of -webkit-box reftests, & fix reference cases to use 'space-between' (the modern equivalent). (no review) (7641615ec0) - Bug 1257688 part 3: Change "-webkit-box-ordinal-group" to alias its -moz equivalent, & change nsFlexContainerFrame to respect it in a -webkit-box. r=mats (90797264fe) - Bug 1257688 part 4: Add reftests for -webkit-box-ordinal-group inside of display:-webkit-box. r=mats (7623b7a5dd) - Bug 1257688 part 5: Change "-webkit-box-flex" to alias its -moz equivalent, & change nsFlexContainerFrame to use it instead of flex-shrink & flex-grow in a -webkit-box. r=mats (dabf0415f3) - Bug 1257688 part 6: Add reftest for -webkit-box-flex inside of display:-webkit-box. r=mats (06d1384d0b) - Bug 1257688 followup: Fix typo in s in webkit-box-ordinal-group reftests. (no review, test-metadata only) (b8753af073) - Bug 1262049 part 1: Back out bug 1208344 in its entirety, and mark -webkit-box-orient:vertical reftests as failing (for now). (no review) (fd3890a164) - Bug 1262049 part 2: Add -webkit-box-orient & -webkit-box-direction as aliases for -moz versions, in the style system (but not yet honored by flexbox layout). r=mats (33e137427f) - Bug 1262049 part 3: Refactor FlexboxAxisTracker constructor to take pointer to nsFlexContainerFrame. r=mats (0e9a26b85d) - Bug 1262049 part 4: Refactor some of FlexboxAxisTracker constructor's logic into a helper method. r=mats (c298827ed2) - Bug 1264837 Part 1 - Remove nsTextBoxFrameSuper. r=dholbert (dc64371da6) - Bug 1264837 Part 2 - Remove nsColorControlFrameSuper. r=dholbert (166c5c13c3) - Bug 1264837 Part 3 - Remove nsFormControlFrameSuper. r=dholbert (70c4c13c79) - Bug 1264837 Part 4 - Remove nsImageControlFrameSuper. r=dholbert (68af4648e6) - Bug 1264837 Part 5 - Remove nsFlexContainerFrameSuper. r=dholbert (ef7b1a912e) - Bug 1261553 - Don't return from OnVisibilityChanged implementations without calling the superclass implementation. r=mstange (033d4cdf72) - Bug 1264837 Part 6 - Remove ImageFrameSuper. r=dholbert (cbf002ba56) - Bug 1264837 Part 7 - Remove nsInlineFrameBase r=dholbert (42e277593f) - Bug 1262049 part 5: Honor -webkit-box-orient & -webkit-box-direction when determining axes for a -webkit-box flexbox. r=mats (a4f03722ed) - Bug 1262049 part 6: Add reftest for -webkit-box-direction. (no review) (d41936d107) - Bug 1266248 part 1: Rename MapSinglePropertyInto() args, to make src-vs-target distinctions clearer. r=heycam (2d46c21c34) - Bug 1266248 part 2: Add assertion to verify that MapSinglePropertyInto() isn't called with a logical target-property. r=heycam (c51b780a2b) - Bug 1264837 Part 8 - Remove nsPluginFrameSuper. r=dholbert (615738f0f0) - Bug 1264837 Part 9 - Remove nsRubyBaseFrameSuper. r=dholbert (0fb30cf0a3) - Bug 1264837 Part 10 - Remove nsRubyContentFrameSuper. r=dholbert (df02f9983c) - Bug 1264837 Part 11 - Remove nsRubyFrameSuper. r=dholbert (684a20009b) - Bug 1264837 Part 12 - Remove nsRubyTextContainerFrameSuper. r=dholbert (4961565c4b) - Bug 1264837 Part 13 - Remove nsRubyTextFrameSuper. r=dholbert (aa9e863378) - bits of 1261230 (cffbacd922) - Bug 1264837 Part 14 - Remove nsSubDocumentFrameSuper. r=dholbert (2ddc0b2028) - Bug 1264837 Part 15 - Remove nsVideoFrameBase r=dholbert (c1246fd0bc) - Bug 1264837 Part 16 - Remove ViewportFrame::Super. r=dholbert (dff457b117) - Bug 1264837 Part 17 - Remove nsSVGAFrameBase. r=dholbert (0df66e92c5) - Bug 1253590, part 1 - Generalize AutoReferenceLoopDetector to allow it to be used to limit reference chain lengths. r=longsonr (e1673d2e9e) - Bug 1253590, part 2 - Use the new AutoReferenceLimiter helper to limit clip path reference chain lengths. r=longsonr (4e03ec9001) - Bug 1253590, part 3 - Crashtest for long clipPath reference chains. r=longsonr (c4da0e1dc4) - Bug 1253590, part 4 - Follow-up to return the correct type. r=bustage (61c7fd965a) - Bug 1264837 Part 18 - Remove nsSVGClipPathFrameBase. r=dholbert (ec78340590) - Bug 1264837 Part 19 - Remove nsSVGContainerFrameBase. r=dholbert (57c5c44826) - Bug 1264837 Part 20 - Remove nsSVGFilterFrameBase. r=dholbert (5f41a15a86) - Bug 1264837 Part 21 - Remove nsSVGForeignObjectFrameBase. r=dholbert (c9aeb556ce) - Bug 1264837 Part 22 - Remove nsSVGGenericContainerFrameBase. r=dholbert (bd4e21975d) - Bug 1264837 Part 23 - Remove nsSVGGFrameBase. r=dholbert (bed40424fd) - Bug 1264837 Part 24 - Remove nsSVGGradientFrameBase. r=dholbert (a9a7d3e0d4) - Bug 1264837 Part 25 - Remove nsSVGLinearGradientFrameBase. r=dholbert (a48ed6b6b2) - Bug 1264837 Part 26 - Remove nsSVGRadialGradientFrameBase. r=dholbert (76181ad3b2) - Bug 1264837 Part 27 - Remove nsSVGImageFrameBase. r=dholbert (5aaa32517d) - Bug 1242256 - ensure images in patterns and masks animate properly. r=jwatt,seth (cc40ee9520) - Bug 1264837 Part 28 - Remove nsSVGInnerSVGFrameBase. r=dholbert (04b9d9b5fb) - Bug 1264837 Part 29 - Remove nsSVGMarkerFrameBase. r=dholbert (bc28eca472) - Bug 1264837 Part 30 - Remove nsSVGMarkerAnonChildFrameBase. r=dholbert (6898a93a31) - Bug 1264837 Part 31 - Remove nsSVGMaskFrameBase. r=dholbert (26d0e7a5e1) - Bug 1264837 Part 32 - Remove nsSVGOuterSVGFrameBase. r=dholbert (a473ae8be3) - Bug 1264837 Part 33 - Remove nsSVGOuterSVGAnonChildFrameBase. r=dholbert (8c6cca5e9b) - Bug 1264837 Part 34 - Remove nsSVGPaintServerFrameBase. r=dholbert (eab458bfab) - Bug 1264837 Part 35 - Remove nsSVGPathGeometryFrameBase. r=dholbert (e5245d2be0) - Bug 1264837 Part 36 - Remove nsSVGPatternFrameBase. r=dholbert (2df37d4056) - Bug 1264837 Part 37 - Remove nsSVGStopFrameBase. r=dholbert (e367dba151) - Bug 1264837 Part 38 - Remove nsSVGSwitchFrameBase. r=dholbert (7ffe7a731a) - Bug 1264837 Part 39 - Remove nsSVGUseFrameBase. r=dholbert (b4445728e3) - Bug 1264837 Part 40 - Remove SVGFEContainerFrameBase. r=dholbert (ee08ef9caf) - Bug 1264837 Part 41 - Remove SVGFEImageFrameBase. r=dholbert (010f79b418) - Bug 1264837 Part 42 - Remove SVGFELeafFrameBase. r=dholbert (949aeba02d) - Bug 1264837 Part 44 - Remove SVGTextFrameBase. r=dholbert (bfd0603d44) - Bug 1264837 Part 45 - Remove SVGViewFrameBase. r=dholbert (151f3c95b2) - Bug 1265591 patch 1 - Remove Internal/External versions of ReconstructStyleData. r=heycam (a91f96e3b3) - Bug 1265591 patch 2 - Rename nsIPresShell::ReconstructStyleData to RestyleForCSSRuleChanges. r=heycam (8ad2bc3021) - Bug 1265591 patch 3 - Make the comment describing RestyleForCSSRuleChanges match reality. r=heycam (2ef053622d) - Bug 1251150. Add crash annotations if image visibility is re-entering. r=mats (975a3e98d7) - Bug 1261554 (Part 1) - Prepare for implementing in-displayport visibility tracking. r=mstange (b139489249) - Bug 1261554 (Part 2) - Mark frames which are added to the display list when painting to the window as having Visibility::IN_DISPLAYPORT. r=mstange (4c8185bf0e) - Bug 1259529 - Clean up the APZ minimap rendering code a bit. No functional changes. r=BenWa (9b99c27777) - Bug 1256532 - Show the critical displayport in the APZ minimap as well. r=BenWa (9b131616a0) - Bug 1251886 - Correct inputFrameID selection when using e10s r=daoshengmu (9e042f6af3) - Bug 1261554 (Part 3) - Visualize Visibility::IN_DISPLAYPORT regions in the APZ minimap visibility debugger. r=botond (f9b72319e1) - Bug 1261554 (Followup) - Fix memory reporting for PresShell::mVisibleRegions. r=me (6fc953c1de) - Bug 1259529 - Ensure that the APZ minimap for subframes remains scaled to the visible portion of the composition bounds. r=BenWa (9f156773cf) - Bug 1251150. Back out crash annotations used to try to diagnose crash. (db6ba80214) - missing bits of Bug 1258476 - Optimize CreateRangePaintInfo by generating display lists for the minimum amount of range subtrees rather than for the range common ancestor. r=tn (2ded969082) - Bug 1237821. Use displayport getter for image visibility in the (unused) display list builder based image visibility code. r=botond (a634182065) - Bug 1253995 - Display stale image in nsImageFrame if we have a new src but haven't decoded it yet - r=seth (6add357448) - Bug 1261703. When moving flex frame, position its view as well as any child views. r=dholbert (abd586f55f) - bug 1246772 - work around x87 floating point truncation issues in gecko r=dholbert (de38865a9f) - missing bits of 1202908 (4a254234f7) - Bug 1249134: Remove support for -webkit-appearance as an alias for -moz-appearance, since the two prefixed properties behave differently in practice. r=heycam (7fd6826fb0) - Bug 1249937 - Rename LayerComposite::SetShadowTransform to SetShadowBaseTransform. r=botond (c91f175b8d) - Bug 1260335 - On perspective ContainerLayers, the clip deferred from their child layer needs to be affected by the perspective layer's async transforms. r=botond (ee1a19e113) - Bug 1260335 - Add a comment that explains why the perspective child can't have more than one frame metrics. r=mattwoodrow (639d9ede24) - Bug 1148978 - Remove plugin window update composition deferment. r=mattwoodrow (01e7da3570) - Bug 1263515 - Destroy the compositor earlier in RecvWillStop when it still has a valid widget. r=jnicol (c14135bf7c) - Bug 1258440 - Don't attempt to hide plugin windows when switching trees if the previous remote layer tree didn't contain plugin windows. Fixes a tpaint regression. r=mconley (929db2fdf2) - Bug 1260976 - Make nsTransitionManager use Keyframe objects to set up transitions; r=heycam (3b8ef91fe9) - Bug 1265611 - Make TransitionProperty() and ToValue() safe when mProperties is not set; r=heycam (37d234aad4) - Bug 1259675 - Clean up InternalTransitionEvent r=masayuki (f6526d4dfa) - Bug 1260976 - Remove some references to properties within nsTransitionManager; r=heycam (6c0f84fb17) - Bug 1182856 - Part 4: Refactor code in nsTransitionManager::StyleContextChanged(). r=heycam (ee0f4d76fd) - Bug 1182856 - Part 5: Avoid unnecessary transition update if display:none. r=heycam (5e01fff5cc) - Bug 1182856 - Part 6: Revise tests for display:none in test_transitions.html. r=heycam (ac2dfe8e47) - Bug 1182856 - Part 7: Test. r=cam (2aed7d5ae6) - Bug 1265611 - Don't trigger transitions for properties that are disabled; r=heycam (dabf201421) - Bug 1247533 - Annotate intentional switch fallthrough to suppress -Wimplicit-fallthrough warning in layout/style/. r=dbaron (a0b748bea2) - Bug 1264830 - Part 1: Add an nsStyleAutoArray array type, similar to AutoTArray<...,1> but memmovable. r=bholley (ad4eb0692c) - Bug 1264830 - Part 2: Change nsStyleImageLayers::mLayers to use nsStyleAutoArray. r=bholley (963a9e4033) - Bug 1264830 - Part 3: Change nsStyleDisplay::{mTransitions,mAnimations} to use nsStyleAutoArray. r=bholley (396812da9d) - Bug 1264830 - Part 4: Change nsStyleDisplay::mWillChange to use nsTArray. r=bholley (7dead8570f) - Bug 1264830 - Part 5: Require all style structs be memmovable. r=bholley (8fdd844d1c) - Bug 1244628: compare nsStyleImageLayers::mAttachmentCount in nsStyleImageLayers::CalcDifference. r=dbaron. (11e2bb1665) - Bug 1252739 - nsStyleImageLayers::HasLayerWithImage should return true when we have mask-image:<element-reference> | <gradient>; r=dbaron (904b65a0e5) - cleanup empty line (8263e0793e) - Bug 1261392 - Define gettid for all Linux builds. r=bgirard (781ae95acc) --- browser/app/macbuild/Contents/MacOS-files.in | 1 - dom/base/nsImageLoadingContent.cpp | 18 +- dom/events/TransitionEvent.cpp | 12 +- dom/html/nsHTMLDocument.cpp | 4 +- dom/svg/crashtests/crashtests.list | 2 + .../long-clipPath-reference-chain.svg | 53 +++ editor/libeditor/nsHTMLEditor.cpp | 4 +- .../composite/AsyncCompositionManager.cpp | 20 +- .../composite/ContainerLayerComposite.cpp | 141 +++--- gfx/layers/composite/LayerManagerComposite.h | 46 +- gfx/layers/ipc/CompositorBridgeChild.cpp | 15 +- gfx/layers/ipc/CompositorBridgeChild.h | 7 +- gfx/layers/ipc/CompositorBridgeParent.cpp | 99 ++-- gfx/layers/ipc/CompositorBridgeParent.h | 19 +- gfx/layers/ipc/PCompositorBridge.ipdl | 16 +- gfx/vr/gfxVROculus.cpp | 8 + gfx/vr/gfxVROculus050.cpp | 1 + layout/base/nsIPresShell.h | 37 +- layout/base/nsPresShell.cpp | 428 +++++++++--------- layout/base/nsPresShell.h | 48 +- layout/forms/nsColorControlFrame.cpp | 10 +- layout/forms/nsColorControlFrame.h | 4 +- layout/forms/nsFormControlFrame.cpp | 10 +- layout/forms/nsFormControlFrame.h | 14 +- layout/forms/nsImageControlFrame.cpp | 28 +- layout/generic/Visibility.h | 40 +- layout/generic/VisibilityIPC.h | 45 ++ layout/generic/moz.build | 1 + layout/generic/nsFlexContainerFrame.cpp | 300 ++++++++++-- layout/generic/nsFlexContainerFrame.h | 28 +- layout/generic/nsFrame.cpp | 115 +++-- layout/generic/nsIFrame.h | 46 +- layout/generic/nsImageFrame.cpp | 56 ++- layout/generic/nsImageFrame.h | 17 +- layout/generic/nsInlineFrame.cpp | 6 +- layout/generic/nsInlineFrame.h | 4 +- layout/generic/nsPluginFrame.cpp | 22 +- layout/generic/nsPluginFrame.h | 10 +- layout/generic/nsRubyBaseFrame.cpp | 2 +- layout/generic/nsRubyBaseFrame.h | 6 +- layout/generic/nsRubyContentFrame.cpp | 2 +- layout/generic/nsRubyContentFrame.h | 6 +- layout/generic/nsRubyFrame.cpp | 4 +- layout/generic/nsRubyFrame.h | 6 +- layout/generic/nsRubyTextContainerFrame.cpp | 10 +- layout/generic/nsRubyTextContainerFrame.h | 6 +- layout/generic/nsRubyTextFrame.cpp | 7 +- layout/generic/nsRubyTextFrame.h | 6 +- layout/generic/nsSubDocumentFrame.cpp | 30 +- layout/generic/nsSubDocumentFrame.h | 6 +- layout/generic/nsVideoFrame.cpp | 11 +- layout/generic/nsVideoFrame.h | 5 +- layout/generic/nsViewportFrame.cpp | 2 +- layout/generic/nsViewportFrame.h | 2 - .../perspective-scrolling-4-ref.html | 44 ++ .../perspective-scrolling-4.html | 49 ++ layout/reftests/async-scrolling/reftest.list | 1 + layout/reftests/forms/textarea/reftest.list | 14 +- layout/reftests/forms/textbox/reftest.list | 17 +- layout/reftests/reftest.list | 21 +- layout/reftests/webkit-box/reftest.list | 16 + .../webkit-box-align-horiz-1-ref.html | 172 +++++++ .../webkit-box/webkit-box-align-horiz-1a.html | 173 +++++++ .../webkit-box/webkit-box-align-horiz-1b.html | 174 +++++++ .../webkit-box-align-vert-1-ref.html | 173 +++++++ .../webkit-box/webkit-box-align-vert-1.html | 174 +++++++ .../webkit-box-direction-1-ref.html | 82 ++++ .../webkit-box/webkit-box-direction-1.html | 87 ++++ .../webkit-box/webkit-box-flex-1-ref.html | 101 +++++ .../webkit-box/webkit-box-flex-1.html | 94 ++++ .../webkit-box-ordinal-group-1-ref.html | 84 ++++ .../webkit-box-ordinal-group-1.html | 88 ++++ .../webkit-box-ordinal-group-2-ref.html | 29 ++ .../webkit-box-ordinal-group-2.html | 36 ++ .../webkit-box-ordinal-group-3-ref.html | 83 ++++ .../webkit-box-ordinal-group-3.html | 103 +++++ .../webkit-box-pack-horiz-1-ref.html | 150 ++++++ .../webkit-box/webkit-box-pack-horiz-1a.html | 151 ++++++ .../webkit-box/webkit-box-pack-horiz-1b.html | 152 +++++++ .../webkit-box-pack-vert-1-ref.html | 151 ++++++ .../webkit-box/webkit-box-pack-vert-1.html | 152 +++++++ layout/style/nsCSSDataBlock.cpp | 145 ++---- layout/style/nsCSSPropAliasList.h | 26 +- layout/style/nsCSSPropList.h | 16 - layout/style/nsCSSPropLogicalGroupList.h | 12 - layout/style/nsCSSProperty.h | 3 - layout/style/nsCSSProps.cpp | 28 +- layout/style/nsCSSProps.h | 28 +- layout/style/nsCSSRuleProcessor.cpp | 2 +- layout/style/nsRuleNode.cpp | 20 +- layout/style/nsStyleStruct.cpp | 21 +- layout/style/nsStyleStruct.h | 115 +++-- layout/style/nsStyleTransformMatrix.cpp | 1 + layout/style/nsTransitionManager.cpp | 378 +++++++++------- layout/style/nsTransitionManager.h | 49 +- layout/style/test/mochitest.ini | 3 +- layout/style/test/property_database.js | 78 +--- layout/style/test/test_transitions.html | 15 +- ..._transitions_with_disabled_properties.html | 56 +++ .../test_transitions_with_displaynone.html | 71 +++ layout/style/test/test_webkit_box_orient.html | 54 --- layout/svg/AutoReferenceLimiter.h | 127 ++++++ layout/svg/SVGFEContainerFrame.cpp | 13 +- layout/svg/SVGFEImageFrame.cpp | 28 +- layout/svg/SVGFELeafFrame.cpp | 13 +- layout/svg/SVGTextFrame.cpp | 6 +- layout/svg/SVGTextFrame.h | 12 +- layout/svg/SVGViewFrame.cpp | 13 +- layout/svg/nsSVGAFrame.cpp | 12 +- layout/svg/nsSVGClipPathFrame.cpp | 66 ++- layout/svg/nsSVGClipPathFrame.h | 70 +-- layout/svg/nsSVGContainerFrame.cpp | 4 +- layout/svg/nsSVGContainerFrame.h | 8 +- layout/svg/nsSVGFilterFrame.cpp | 6 +- layout/svg/nsSVGFilterFrame.h | 10 +- layout/svg/nsSVGForeignObjectFrame.cpp | 10 +- layout/svg/nsSVGForeignObjectFrame.h | 8 +- layout/svg/nsSVGGFrame.cpp | 8 +- layout/svg/nsSVGGFrame.h | 8 +- layout/svg/nsSVGGenericContainerFrame.h | 10 +- layout/svg/nsSVGGradientFrame.cpp | 22 +- layout/svg/nsSVGGradientFrame.h | 20 +- layout/svg/nsSVGImageFrame.cpp | 27 +- layout/svg/nsSVGInnerSVGFrame.cpp | 12 +- layout/svg/nsSVGInnerSVGFrame.h | 12 +- layout/svg/nsSVGMarkerFrame.cpp | 8 +- layout/svg/nsSVGMarkerFrame.h | 15 +- layout/svg/nsSVGMaskFrame.cpp | 6 +- layout/svg/nsSVGMaskFrame.h | 6 +- layout/svg/nsSVGOuterSVGFrame.cpp | 15 +- layout/svg/nsSVGOuterSVGFrame.h | 13 +- layout/svg/nsSVGPaintServerFrame.h | 8 +- layout/svg/nsSVGPathGeometryFrame.cpp | 6 +- layout/svg/nsSVGPathGeometryFrame.h | 10 +- layout/svg/nsSVGPatternFrame.cpp | 12 +- layout/svg/nsSVGPatternFrame.h | 4 +- layout/svg/nsSVGStopFrame.cpp | 13 +- layout/svg/nsSVGSwitchFrame.cpp | 10 +- layout/svg/nsSVGUseFrame.cpp | 26 +- layout/xul/nsTextBoxFrame.cpp | 8 +- layout/xul/nsTextBoxFrame.h | 3 +- layout/xul/test/mochitest.ini | 2 +- tools/profiler/core/platform.h | 8 +- widget/ContentEvents.h | 14 +- 144 files changed, 4705 insertions(+), 1545 deletions(-) create mode 100644 dom/svg/crashtests/long-clipPath-reference-chain.svg create mode 100644 layout/generic/VisibilityIPC.h create mode 100644 layout/reftests/async-scrolling/perspective-scrolling-4-ref.html create mode 100644 layout/reftests/async-scrolling/perspective-scrolling-4.html create mode 100644 layout/reftests/webkit-box/webkit-box-align-horiz-1-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-align-horiz-1a.html create mode 100644 layout/reftests/webkit-box/webkit-box-align-horiz-1b.html create mode 100644 layout/reftests/webkit-box/webkit-box-align-vert-1-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-align-vert-1.html create mode 100644 layout/reftests/webkit-box/webkit-box-direction-1-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-direction-1.html create mode 100644 layout/reftests/webkit-box/webkit-box-flex-1-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-flex-1.html create mode 100644 layout/reftests/webkit-box/webkit-box-ordinal-group-1-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-ordinal-group-1.html create mode 100644 layout/reftests/webkit-box/webkit-box-ordinal-group-2-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-ordinal-group-2.html create mode 100644 layout/reftests/webkit-box/webkit-box-ordinal-group-3-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-ordinal-group-3.html create mode 100644 layout/reftests/webkit-box/webkit-box-pack-horiz-1-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-pack-horiz-1a.html create mode 100644 layout/reftests/webkit-box/webkit-box-pack-horiz-1b.html create mode 100644 layout/reftests/webkit-box/webkit-box-pack-vert-1-ref.html create mode 100644 layout/reftests/webkit-box/webkit-box-pack-vert-1.html create mode 100644 layout/style/test/test_transitions_with_disabled_properties.html create mode 100644 layout/style/test/test_transitions_with_displaynone.html delete mode 100644 layout/style/test/test_webkit_box_orient.html create mode 100644 layout/svg/AutoReferenceLimiter.h diff --git a/browser/app/macbuild/Contents/MacOS-files.in b/browser/app/macbuild/Contents/MacOS-files.in index 561366def2..849336bc9b 100644 --- a/browser/app/macbuild/Contents/MacOS-files.in +++ b/browser/app/macbuild/Contents/MacOS-files.in @@ -7,4 +7,3 @@ /ssltunnel /xpcshell /XUL - diff --git a/dom/base/nsImageLoadingContent.cpp b/dom/base/nsImageLoadingContent.cpp index 6adb56b214..31105116e1 100644 --- a/dom/base/nsImageLoadingContent.cpp +++ b/dom/base/nsImageLoadingContent.cpp @@ -285,9 +285,8 @@ nsImageLoadingContent::OnUnlockedDraw() return; } - if (frame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE) { - // This frame is already marked visible; there's nothing to do. - return; + if (frame->IsVisibleOrMayBecomeVisibleSoon()) { + return; // Nothing to do. } nsPresContext* presContext = frame->PresContext(); @@ -300,7 +299,7 @@ nsImageLoadingContent::OnUnlockedDraw() return; } - presShell->EnsureFrameInApproximatelyVisibleList(frame); + presShell->MarkFrameVisibleInDisplayPort(frame); } nsresult @@ -527,7 +526,7 @@ nsImageLoadingContent::FrameDestroyed(nsIFrame* aFrame) nsIPresShell* presShell = presContext ? presContext->GetPresShell() : nullptr; if (presShell) { - presShell->RemoveFrameFromApproximatelyVisibleList(aFrame); + presShell->MarkFrameNonvisible(aFrame); } } @@ -1423,12 +1422,13 @@ nsImageLoadingContent::OnVisibilityChange(Visibility aNewVisibility, const Maybe<OnNonvisible>& aNonvisibleAction) { switch (aNewVisibility) { - case Visibility::APPROXIMATELY_VISIBLE: + case Visibility::MAY_BECOME_VISIBLE: + case Visibility::IN_DISPLAYPORT: TrackImage(mCurrentRequest); TrackImage(mPendingRequest); break; - case Visibility::APPROXIMATELY_NONVISIBLE: + case Visibility::NONVISIBLE: UntrackImage(mCurrentRequest, aNonvisibleAction); UntrackImage(mPendingRequest, aNonvisibleAction); break; @@ -1454,11 +1454,11 @@ nsImageLoadingContent::TrackImage(imgIRequest* aImage) } // We only want to track this request if we're visible. Ordinarily we check - // the visible count, but that requires a frame; in cases where + // whether our frame considers itself visible, but in cases where // GetOurPrimaryFrame() cannot obtain a frame (e.g. <feImage>), we assume // we're visible if FrameCreated() was called. nsIFrame* frame = GetOurPrimaryFrame(); - if ((frame && frame->GetVisibility() == Visibility::APPROXIMATELY_NONVISIBLE) || + if ((frame && !frame->IsVisibleOrMayBecomeVisibleSoon()) || (!frame && !mFrameCreateCalled)) { return; } diff --git a/dom/events/TransitionEvent.cpp b/dom/events/TransitionEvent.cpp index 8bcc048640..ecea482935 100644 --- a/dom/events/TransitionEvent.cpp +++ b/dom/events/TransitionEvent.cpp @@ -47,9 +47,9 @@ TransitionEvent::Constructor(const GlobalObject& aGlobal, e->InitEvent(aType, aParam.mBubbles, aParam.mCancelable); InternalTransitionEvent* internalEvent = e->mEvent->AsTransitionEvent(); - internalEvent->propertyName = aParam.mPropertyName; - internalEvent->elapsedTime = aParam.mElapsedTime; - internalEvent->pseudoElement = aParam.mPseudoElement; + internalEvent->mPropertyName = aParam.mPropertyName; + internalEvent->mElapsedTime = aParam.mElapsedTime; + internalEvent->mPseudoElement = aParam.mPseudoElement; e->SetTrusted(trusted); return e.forget(); @@ -58,7 +58,7 @@ TransitionEvent::Constructor(const GlobalObject& aGlobal, NS_IMETHODIMP TransitionEvent::GetPropertyName(nsAString& aPropertyName) { - aPropertyName = mEvent->AsTransitionEvent()->propertyName; + aPropertyName = mEvent->AsTransitionEvent()->mPropertyName; return NS_OK; } @@ -72,13 +72,13 @@ TransitionEvent::GetElapsedTime(float* aElapsedTime) float TransitionEvent::ElapsedTime() { - return mEvent->AsTransitionEvent()->elapsedTime; + return mEvent->AsTransitionEvent()->mElapsedTime; } NS_IMETHODIMP TransitionEvent::GetPseudoElement(nsAString& aPseudoElement) { - aPseudoElement = mEvent->AsTransitionEvent()->pseudoElement; + aPseudoElement = mEvent->AsTransitionEvent()->mPseudoElement; return NS_OK; } diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index dd6e3c4911..4b3d299767 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -2657,7 +2657,7 @@ nsHTMLDocument::TearingDownEditor(nsIEditor *aEditor) presShell->SetAgentStyleSheets(agentSheets); - presShell->ReconstructStyleData(); + presShell->RestyleForCSSRuleChanges(); } } @@ -2821,7 +2821,7 @@ nsHTMLDocument::EditingStateChanged() rv = presShell->SetAgentStyleSheets(agentSheets); NS_ENSURE_SUCCESS(rv, rv); - presShell->ReconstructStyleData(); + presShell->RestyleForCSSRuleChanges(); // Adjust focused element with new style but blur event shouldn't be fired // until mEditingState is modified with newState. diff --git a/dom/svg/crashtests/crashtests.list b/dom/svg/crashtests/crashtests.list index 5a8f8cb0ee..08d378e556 100644 --- a/dom/svg/crashtests/crashtests.list +++ b/dom/svg/crashtests/crashtests.list @@ -72,3 +72,5 @@ load 880544-3.svg load 880544-4.svg load 880544-5.svg load 898915-1.svg +# Disabled for now due to it taking a very long time to run - bug 1259356 +#load long-clipPath-reference-chain.svg diff --git a/dom/svg/crashtests/long-clipPath-reference-chain.svg b/dom/svg/crashtests/long-clipPath-reference-chain.svg new file mode 100644 index 0000000000..31a587c740 --- /dev/null +++ b/dom/svg/crashtests/long-clipPath-reference-chain.svg @@ -0,0 +1,53 @@ +<svg xmlns="http://www.w3.org/2000/svg"> + <title>Test very long clipPath chain - MAY CRASH + + + + + diff --git a/editor/libeditor/nsHTMLEditor.cpp b/editor/libeditor/nsHTMLEditor.cpp index 0bae586997..6c909bd5c7 100644 --- a/editor/libeditor/nsHTMLEditor.cpp +++ b/editor/libeditor/nsHTMLEditor.cpp @@ -2879,7 +2879,7 @@ nsHTMLEditor::AddOverrideStyleSheet(const nsAString& aURL) // (This checks if already exists) ps->AddOverrideStyleSheet(sheet); - ps->ReconstructStyleData(); + ps->RestyleForCSSRuleChanges(); // Save as the last-loaded sheet mLastOverrideStyleSheetURL = aURL; @@ -2924,7 +2924,7 @@ nsHTMLEditor::RemoveOverrideStyleSheet(const nsAString &aURL) NS_ENSURE_TRUE(ps, NS_ERROR_NOT_INITIALIZED); ps->RemoveOverrideStyleSheet(sheet); - ps->ReconstructStyleData(); + ps->RestyleForCSSRuleChanges(); // Remove it from our internal list return rv; diff --git a/gfx/layers/composite/AsyncCompositionManager.cpp b/gfx/layers/composite/AsyncCompositionManager.cpp index 4ef207241a..f05a19bae2 100644 --- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -234,7 +234,7 @@ SetShadowTransform(Layer* aLayer, LayerToParentLayerMatrix4x4 aTransform) aTransform.PostScale(1.0f / aLayer->GetPostXScale(), 1.0f / aLayer->GetPostYScale(), 1); - aLayer->AsLayerComposite()->SetShadowTransform(aTransform.ToUnknownMatrix()); + aLayer->AsLayerComposite()->SetShadowBaseTransform(aTransform.ToUnknownMatrix()); } static void @@ -642,7 +642,7 @@ SampleAnimations(Layer* aLayer, TimeStamp aPoint) if (ContainerLayer* c = aLayer->AsContainerLayer()) { matrix.PostScale(c->GetInheritedXScale(), c->GetInheritedYScale(), 1); } - layerComposite->SetShadowTransform(matrix); + layerComposite->SetShadowBaseTransform(matrix); layerComposite->SetShadowTransformSetByAnimation(true); break; } @@ -811,6 +811,11 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, // The final clip for the layer is the intersection of these clips. Maybe asyncClip = aLayer->GetClipRect(); + // If we are a perspective transform ContainerLayer, apply the clip deferred + // from our child (if there is any) before we iterate over our frame metrics, + // because this clip is subject to all async transforms of this layer. + asyncClip = IntersectMaybeRects(asyncClip, clipDeferredFromChildren); + // The transform of a mask layer is relative to the masked layer's parent // layer. So whenever we apply an async transform to a layer, we need to // apply that same transform to the layer's own mask layer. @@ -934,6 +939,12 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, // our scroll clip to it instead of to this layer (see bug 1168263). // A layer with a perspective transform shouldn't have multiple // children with FrameMetrics, nor a child with multiple FrameMetrics. + // (A child with multiple FrameMetrics would mean that there's *another* + // scrollable element between the one with the CSS perspective and the + // transformed element. But you'd have to use preserve-3d on the inner + // scrollable element in order to have the perspective apply to the + // transformed child, and preserve-3d is not supported on scrollable + // elements, so this case can't occur.) MOZ_ASSERT(!aClipDeferredToParent); aClipDeferredToParent = Some(clip); } else { @@ -958,8 +969,7 @@ AsyncCompositionManager::ApplyAsyncContentTransformToTree(Layer *aLayer, } if (hasAsyncTransform || clipDeferredFromChildren) { - aLayer->AsLayerComposite()->SetShadowClipRect( - IntersectMaybeRects(asyncClip, clipDeferredFromChildren)); + aLayer->AsLayerComposite()->SetShadowClipRect(asyncClip); } if (hasAsyncTransform) { @@ -1426,7 +1436,7 @@ AsyncCompositionManager::TransformShadowTree(TimeStamp aCurrentFrame, gfx::Matrix4x4 trans = rootComposite->GetShadowBaseTransform(); trans *= gfx::Matrix4x4::From2D(mWorldTransform); - rootComposite->SetShadowTransform(trans); + rootComposite->SetShadowBaseTransform(trans); if (gfxPrefs::CollectScrollTransforms()) { RecordShadowTransforms(root); diff --git a/gfx/layers/composite/ContainerLayerComposite.cpp b/gfx/layers/composite/ContainerLayerComposite.cpp index 19a601d134..f86fff188f 100755 --- a/gfx/layers/composite/ContainerLayerComposite.cpp +++ b/gfx/layers/composite/ContainerLayerComposite.cpp @@ -141,8 +141,7 @@ template void ContainerRenderVR(ContainerT* aContainer, LayerManagerComposite* aManager, const gfx::IntRect& aClipRect, - RefPtr aHMD, - int32_t aInputFrameID) + RefPtr aHMD) { int32_t inputFrameID = -1; @@ -273,11 +272,29 @@ ContainerRenderVR(ContainerT* aContainer, surfaceRect.width, surfaceRect.height)); layerToRender->RenderLayer(surfaceRect); - CompositableHost *ch = layerToRender->GetCompositableHost(); - if (ch) { - int32_t compositableInputFrameID = ch->GetLastInputFrameID(); - if (compositableInputFrameID != -1) { - inputFrameID = compositableInputFrameID; + // Search all children recursively until we find the canvas with + // an inputFrameID + std::stack searchLayers; + searchLayers.push(layerToRender); + while (!searchLayers.empty() && inputFrameID == -1) { + LayerComposite* searchLayer = searchLayers.top(); + searchLayers.pop(); + if (searchLayer) { + searchLayers.push(searchLayer->GetFirstChildComposite()); + Layer* sibling = searchLayer->GetLayer(); + if (sibling) { + sibling = sibling->GetNextSibling(); + } + if (sibling) { + searchLayers.push(sibling->AsLayerComposite()); + } + CompositableHost *ch = searchLayer->GetCompositableHost(); + if (ch) { + int32_t compositableInputFrameID = ch->GetLastInputFrameID(); + if (compositableInputFrameID != -1) { + inputFrameID = compositableInputFrameID; + } + } } } @@ -457,6 +474,22 @@ ContainerPrepare(ContainerT* aContainer, } } +template void +DrawRegion(CSSIntRegion* aRegion, + gfx::Color aColor, + const RectPainter& aRectPainter) +{ + MOZ_ASSERT(aRegion); + + // Iterate through and draw the rects in the region using the provided lambda. + for (CSSIntRegion::RectIterator iterator = aRegion->RectIter(); + !iterator.Done(); + iterator.Next()) + { + aRectPainter(iterator.Get(), aColor); + } +} + template void RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager, const RenderTargetIntRect& aClipRect, Layer* aLayer) @@ -481,9 +514,11 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager, gfx::Color tileActiveColor(1, 1, 1, 0.4f); gfx::Color tileBorderColor(0, 0, 0, 0.1f); gfx::Color pageBorderColor(0, 0, 0); + gfx::Color criticalDisplayPortColor(1.f, 1.f, 0); gfx::Color displayPortColor(0, 1.f, 0); gfx::Color viewPortColor(0, 0, 1.f, 0.3f); - gfx::Color visibilityColor(1.f, 0, 0); + gfx::Color approxVisibilityColor(1.f, 0, 0); + gfx::Color inDisplayPortVisibilityColor(1.f, 1.f, 0); // Rects const FrameMetrics& fm = aLayer->GetFrameMetrics(0); @@ -491,6 +526,10 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager, LayerRect scrollRect = fm.GetScrollableRect() * fm.LayersPixelsPerCSSPixel(); LayerRect viewRect = ParentLayerRect(scrollOffset, compositionBounds.Size()) / LayerToParentLayerScale(1); LayerRect dp = (fm.GetDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel(); + Maybe cdp; + if (!fm.GetCriticalDisplayPort().IsEmpty()) { + cdp = Some((fm.GetCriticalDisplayPort() + fm.GetScrollOffset()) * fm.LayersPixelsPerCSSPixel()); + } // Don't render trivial minimap. They can show up from textboxes and other tiny frames. if (viewRect.width < 64 && viewRect.height < 64) { @@ -502,41 +541,32 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager, float scaleFactor; float scaleFactorX; float scaleFactorY; - scaleFactorX = 100.f / scrollRect.width; - scaleFactorY = ((viewRect.height) - 2 * verticalPadding) / scrollRect.height; + Rect dest = Rect(aClipRect.ToUnknownRect()); + if (aLayer->GetEffectiveClipRect()) { + dest = Rect(aLayer->GetEffectiveClipRect().value().ToUnknownRect()); + } else { + dest = aContainer->GetEffectiveTransform().Inverse().TransformBounds(dest); + } + dest = dest.Intersect(compositionBounds.ToUnknownRect()); + scaleFactorX = std::min(100.f, dest.width - (2 * horizontalPadding)) / scrollRect.width; + scaleFactorY = (dest.height - (2 * verticalPadding)) / scrollRect.height; scaleFactor = std::min(scaleFactorX, scaleFactorY); + if (scaleFactor <= 0) { + return; + } Matrix4x4 transform = Matrix4x4::Scaling(scaleFactor, scaleFactor, 1); - transform.PostTranslate(horizontalPadding + compositionBounds.x, verticalPadding + compositionBounds.y, 0); + transform.PostTranslate(horizontalPadding + dest.x, verticalPadding + dest.y, 0); - Rect clipRect = aContainer->GetEffectiveTransform().TransformBounds( - transform.TransformBounds(scrollRect.ToUnknownRect())); + Rect transformedScrollRect = transform.TransformBounds(scrollRect.ToUnknownRect()); + + Rect clipRect = aContainer->GetEffectiveTransform().TransformBounds(transformedScrollRect); clipRect.width++; clipRect.height++; - Rect r; - r = transform.TransformBounds(scrollRect.ToUnknownRect()); - compositor->FillRect(r, backgroundColor, clipRect, aContainer->GetEffectiveTransform()); - - /* Disabled because on long pages SlowDrawRect becomes a bottleneck. - int tileW = gfxPrefs::LayersTileWidth(); - int tileH = gfxPrefs::LayersTileHeight(); - - for (int x = scrollRect.x; x < scrollRect.XMost(); x += tileW) { - for (int y = scrollRect.y; y < scrollRect.YMost(); y += tileH) { - LayerRect tileRect = LayerRect(x - x % tileW, y - y % tileH, tileW, tileH); - r = transform.TransformBounds(tileRect.ToUnknownRect()); - if (tileRect.Intersects(dp)) { - compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform()); - } - compositor->SlowDrawRect(r, tileBorderColor, clipRect, aContainer->GetEffectiveTransform()); - } - } - */ - // Render the scrollable area. - r = transform.TransformBounds(scrollRect.ToUnknownRect()); - compositor->SlowDrawRect(r, pageBorderColor, clipRect, aContainer->GetEffectiveTransform()); + compositor->FillRect(transformedScrollRect, backgroundColor, clipRect, aContainer->GetEffectiveTransform()); + compositor->SlowDrawRect(transformedScrollRect, pageBorderColor, clipRect, aContainer->GetEffectiveTransform()); // If enabled, render information about visibility. if (gfxPrefs::APZMinimapVisibilityEnabled()) { @@ -547,31 +577,34 @@ RenderMinimap(ContainerT* aContainer, LayerManagerComposite* aManager, ScrollableLayerGuid guid = controller->GetGuid(); - // Get the approximately visible region. - static CSSIntRegion emptyRegion; - CSSIntRegion* visibleRegion = aManager->GetApproximatelyVisibleRegion(guid); - if (!visibleRegion) { - visibleRegion = &emptyRegion; - } - - // Iterate through and draw the rects in the region. - for (CSSIntRegion::RectIterator iterator = visibleRegion->RectIter(); - !iterator.Done(); - iterator.Next()) - { - CSSIntRect rect = iterator.Get(); - LayerRect scaledRect = rect * fm.LayersPixelsPerCSSPixel(); + auto rectPainter = [&](const CSSIntRect& aRect, const gfx::Color& aColor) { + LayerRect scaledRect = aRect * fm.LayersPixelsPerCSSPixel(); Rect r = transform.TransformBounds(scaledRect.ToUnknownRect()); - compositor->FillRect(r, visibilityColor, clipRect, aContainer->GetEffectiveTransform()); - } + compositor->FillRect(r, aColor, clipRect, aContainer->GetEffectiveTransform()); + }; + + // Draw the approximately visible region. + CSSIntRegion* approxVisibleRegion = + aManager->GetVisibleRegion(VisibilityCounter::MAY_BECOME_VISIBLE, guid); + DrawRegion(approxVisibleRegion, approxVisibilityColor, rectPainter); + + // Draw the in-displayport visible region. + CSSIntRegion* inDisplayPortVisibleRegion = + aManager->GetVisibleRegion(VisibilityCounter::IN_DISPLAYPORT, guid); + DrawRegion(inDisplayPortVisibleRegion, inDisplayPortVisibilityColor, rectPainter); } // Render the displayport. - r = transform.TransformBounds(dp.ToUnknownRect()); + Rect r = transform.TransformBounds(dp.ToUnknownRect()); compositor->FillRect(r, tileActiveColor, clipRect, aContainer->GetEffectiveTransform()); - r = transform.TransformBounds(dp.ToUnknownRect()); compositor->SlowDrawRect(r, displayPortColor, clipRect, aContainer->GetEffectiveTransform()); + // Render the critical displayport if there is one + if (cdp) { + r = transform.TransformBounds(cdp->ToUnknownRect()); + compositor->SlowDrawRect(r, criticalDisplayPortColor, clipRect, aContainer->GetEffectiveTransform()); + } + // Render the viewport. r = transform.TransformBounds(viewRect.ToUnknownRect()); compositor->SlowDrawRect(r, viewPortColor, clipRect, aContainer->GetEffectiveTransform(), 2); @@ -750,7 +783,7 @@ ContainerRender(ContainerT* aContainer, RefPtr hmdInfo = gfx::VRManager::Get()->GetDevice(aContainer->GetVRDeviceID()); if (hmdInfo && hmdInfo->GetConfiguration().IsValid()) { - ContainerRenderVR(aContainer, aManager, aClipRect, hmdInfo, aContainer->GetInputFrameID()); + ContainerRenderVR(aContainer, aManager, aClipRect, hmdInfo); aContainer->mPrepared = nullptr; return; } diff --git a/gfx/layers/composite/LayerManagerComposite.h b/gfx/layers/composite/LayerManagerComposite.h index c8d9ddecfa..c3a4961a6c 100644 --- a/gfx/layers/composite/LayerManagerComposite.h +++ b/gfx/layers/composite/LayerManagerComposite.h @@ -33,6 +33,7 @@ #include "nsRegion.h" // for nsIntRegion #include "nscore.h" // for nsAString, etc #include "LayerTreeInvalidation.h" +#include "Visibility.h" class gfxContext; @@ -219,10 +220,17 @@ public: mInvalidRegion.Or(mInvalidRegion, aRegion); } - void ClearApproximatelyVisibleRegions(uint64_t aLayersId, - const Maybe& aPresShellId) + void ClearVisibleRegions(uint64_t aLayersId, + const Maybe& aPresShellId) { - for (auto iter = mVisibleRegions.Iter(); !iter.Done(); iter.Next()) { + for (auto iter = mApproximatelyVisibleRegions.Iter(); !iter.Done(); iter.Next()) { + if (iter.Key().mLayersId == aLayersId && + (!aPresShellId || iter.Key().mPresShellId == *aPresShellId)) { + iter.Remove(); + } + } + + for (auto iter = mInDisplayPortVisibleRegions.Iter(); !iter.Done(); iter.Next()) { if (iter.Key().mLayersId == aLayersId && (!aPresShellId || iter.Key().mPresShellId == *aPresShellId)) { iter.Remove(); @@ -230,18 +238,35 @@ public: } } - void UpdateApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, - const CSSIntRegion& aRegion) + void UpdateVisibleRegion(VisibilityCounter aCounter, + const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion) { - CSSIntRegion* regionForScrollFrame = mVisibleRegions.LookupOrAdd(aGuid); + VisibleRegions& regions = aCounter == VisibilityCounter::MAY_BECOME_VISIBLE + ? mApproximatelyVisibleRegions + : mInDisplayPortVisibleRegions; + + CSSIntRegion* regionForScrollFrame = regions.LookupOrAdd(aGuid); MOZ_ASSERT(regionForScrollFrame); *regionForScrollFrame = aRegion; } - CSSIntRegion* GetApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid) + CSSIntRegion* GetVisibleRegion(VisibilityCounter aCounter, + const ScrollableLayerGuid& aGuid) { - return mVisibleRegions.Get(aGuid); + static CSSIntRegion emptyRegion; + + VisibleRegions& regions = aCounter == VisibilityCounter::MAY_BECOME_VISIBLE + ? mApproximatelyVisibleRegions + : mInDisplayPortVisibleRegions; + + CSSIntRegion* region = regions.Get(aGuid); + if (!region) { + region = &emptyRegion; + } + + return region; } Compositor* GetCompositor() const @@ -382,7 +407,8 @@ private: typedef nsClassHashtable, CSSIntRegion> VisibleRegions; - VisibleRegions mVisibleRegions; + VisibleRegions mApproximatelyVisibleRegions; + VisibleRegions mInDisplayPortVisibleRegions; UniquePtr mFPS; @@ -491,7 +517,7 @@ public: mShadowClipRect = aRect; } - void SetShadowTransform(const gfx::Matrix4x4& aMatrix) + void SetShadowBaseTransform(const gfx::Matrix4x4& aMatrix) { mShadowTransform = aMatrix; } diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp index abc93eed65..8e0826d46e 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -727,29 +727,28 @@ CompositorBridgeChild::SendRequestNotifyAfterRemotePaint() } bool -CompositorBridgeChild::SendClearApproximatelyVisibleRegions(uint64_t aLayersId, - uint32_t aPresShellId) +CompositorBridgeChild::SendClearVisibleRegions(uint64_t aLayersId, + uint32_t aPresShellId) { MOZ_ASSERT(mCanSend); if (!mCanSend) { return true; } - return PCompositorBridgeChild::SendClearApproximatelyVisibleRegions(aLayersId, - aPresShellId); + return PCompositorBridgeChild::SendClearVisibleRegions(aLayersId, aPresShellId); } bool -CompositorBridgeChild::SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, - const CSSIntRegion& aRegion) +CompositorBridgeChild::SendUpdateVisibleRegion(VisibilityCounter aCounter, + const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion) { MOZ_ASSERT(mCanSend); if (!mCanSend) { return true; } - return PCompositorBridgeChild::SendNotifyApproximatelyVisibleRegion(aGuid, aRegion); + return PCompositorBridgeChild::SendUpdateVisibleRegion(aCounter, aGuid, aRegion); } - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ipc/CompositorBridgeChild.h b/gfx/layers/ipc/CompositorBridgeChild.h index 0ec6fb8815..0087aca420 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.h +++ b/gfx/layers/ipc/CompositorBridgeChild.h @@ -126,9 +126,10 @@ public: bool SendStopFrameTimeRecording(const uint32_t& startIndex, nsTArray* intervals); bool SendNotifyRegionInvalidated(const nsIntRegion& region); bool SendRequestNotifyAfterRemotePaint(); - bool SendClearApproximatelyVisibleRegions(uint64_t aLayersId, uint32_t aPresShellId); - bool SendNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, - const mozilla::CSSIntRegion& aRegion); + bool SendClearVisibleRegions(uint64_t aLayersId, uint32_t aPresShellId); + bool SendUpdateVisibleRegion(VisibilityCounter aCounter, + const ScrollableLayerGuid& aGuid, + const mozilla::CSSIntRegion& aRegion); bool IsSameProcess() const; static void ShutDown(); diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 13784670a2..82db271424 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -701,7 +701,6 @@ CompositorBridgeParent::CompositorBridgeParent(nsIWidget* aWidget, , mCompositorScheduler(nullptr) #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) , mLastPluginUpdateLayerTreeId(0) - , mPluginUpdateResponsePending(false) , mDeferPluginWindows(false) , mPluginWindowsHidden(false) #endif @@ -785,6 +784,8 @@ CompositorBridgeParent::RecvWillClose() if (mCompositor) { mCompositor->DetachWidget(); + mCompositor->Destroy(); + mCompositor = nullptr; } return true; @@ -897,19 +898,19 @@ CompositorBridgeParent::RecvStopFrameTimeRecording(const uint32_t& aStartIndex, } bool -CompositorBridgeParent::RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId, - const uint32_t& aPresShellId) +CompositorBridgeParent::RecvClearVisibleRegions(const uint64_t& aLayersId, + const uint32_t& aPresShellId) { - ClearApproximatelyVisibleRegions(aLayersId, Some(aPresShellId)); + ClearVisibleRegions(aLayersId, Some(aPresShellId)); return true; } void -CompositorBridgeParent::ClearApproximatelyVisibleRegions(const uint64_t& aLayersId, - const Maybe& aPresShellId) +CompositorBridgeParent::ClearVisibleRegions(const uint64_t& aLayersId, + const Maybe& aPresShellId) { if (mLayerManager) { - mLayerManager->ClearApproximatelyVisibleRegions(aLayersId, aPresShellId); + mLayerManager->ClearVisibleRegions(aLayersId, aPresShellId); // We need to recomposite to update the minimap. ScheduleComposition(); @@ -917,16 +918,25 @@ CompositorBridgeParent::ClearApproximatelyVisibleRegions(const uint64_t& aLayers } bool -CompositorBridgeParent::RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, - const CSSIntRegion& aRegion) +CompositorBridgeParent::RecvUpdateVisibleRegion(const VisibilityCounter& aCounter, + const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion) +{ + UpdateVisibleRegion(aCounter, aGuid, aRegion); + return true; +} + +void +CompositorBridgeParent::UpdateVisibleRegion(const VisibilityCounter& aCounter, + const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion) { if (mLayerManager) { - mLayerManager->UpdateApproximatelyVisibleRegion(aGuid, aRegion); + mLayerManager->UpdateVisibleRegion(aCounter, aGuid, aRegion); // We need to recomposite to update the minimap. ScheduleComposition(); } - return true; } void @@ -1175,7 +1185,7 @@ CompositorBridgeParent::SetShadowProperties(Layer* aLayer) // FIXME: Bug 717688 -- Do these updates in LayerTransactionParent::RecvUpdate. LayerComposite* layerComposite = aLayer->AsLayerComposite(); // Set the layerComposite's base transform to the layer's base transform. - layerComposite->SetShadowTransform(aLayer->GetBaseTransform()); + layerComposite->SetShadowBaseTransform(aLayer->GetBaseTransform()); layerComposite->SetShadowTransformSetByAnimation(false); layerComposite->SetShadowVisibleRegion(aLayer->GetVisibleRegion()); layerComposite->SetShadowClipRect(aLayer->GetClipRect()); @@ -1213,20 +1223,6 @@ CompositorBridgeParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRec return; } -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) - // Still waiting on plugin update confirmation - if (mPluginUpdateResponsePending) { - return; - } -#endif - - bool hasRemoteContent = false; - bool pluginsUpdatedFlag = true; - AutoResolveRefLayers resolve(mCompositionManager, this, - &hasRemoteContent, - &pluginsUpdatedFlag); - -#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) /* * AutoResolveRefLayers handles two tasks related to Windows and Linux * plugin window management: @@ -1239,27 +1235,20 @@ CompositorBridgeParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRec * since plugin clipping can depend on chrome (for example, due to tab modal * prompts). Updates in step 2 are applied via an async ipc message sent * to the main thread. - * Windows specific: The compositor will wait for confirmation that plugin - * updates have been applied before painting. Deferment of painting is - * indicated by the mPluginUpdateResponsePending flag. The main thread - * messages back using the RemotePluginsReady async ipc message. - * This is neccessary since plugin windows can leave remnants of window - * content if moved after the underlying window paints. */ - if (pluginsUpdatedFlag) { - mPluginUpdateResponsePending = true; - return; - } + bool hasRemoteContent = false; + bool updatePluginsFlag = true; + AutoResolveRefLayers resolve(mCompositionManager, this, + &hasRemoteContent, + &updatePluginsFlag); +#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) // We do not support plugins in local content. When switching tabs // to local pages, hide every plugin associated with the window. if (!hasRemoteContent && BrowserTabsRemoteAutostart() && mCachedPluginData.Length()) { Unused << SendHideAllPlugins((uintptr_t)GetWidget()); mCachedPluginData.Clear(); - // Wait for confirmation the hide operation is complete. - mPluginUpdateResponsePending = true; - return; } #endif @@ -1343,7 +1332,6 @@ bool CompositorBridgeParent::RecvRemotePluginsReady() { #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) - mPluginUpdateResponsePending = false; ScheduleComposition(); return true; #else @@ -1770,7 +1758,7 @@ EraseLayerState(uint64_t aId) if (iter != sIndirectLayerTrees.end()) { CompositorBridgeParent* parent = iter->second.mParent; if (parent) { - parent->ClearApproximatelyVisibleRegions(aId, Nothing()); + parent->ClearVisibleRegions(aId, Nothing()); } sIndirectLayerTrees.erase(iter); @@ -1953,31 +1941,38 @@ public: virtual bool RecvStartFrameTimeRecording(const int32_t& aBufferSize, uint32_t* aOutStartIndex) override { return true; } virtual bool RecvStopFrameTimeRecording(const uint32_t& aStartIndex, InfallibleTArray* intervals) override { return true; } - virtual bool RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId, - const uint32_t& aPresShellId) override + virtual bool RecvClearVisibleRegions(const uint64_t& aLayersId, + const uint32_t& aPresShellId) override { CompositorBridgeParent* parent; { // scope lock MonitorAutoLock lock(*sIndirectLayerTreesLock); parent = sIndirectLayerTrees[aLayersId].mParent; } - if (parent) { - parent->ClearApproximatelyVisibleRegions(aLayersId, Some(aPresShellId)); + + if (!parent) { + return false; } + + parent->ClearVisibleRegions(aLayersId, Some(aPresShellId)); return true; } - virtual bool RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, - const CSSIntRegion& aRegion) override + virtual bool RecvUpdateVisibleRegion(const VisibilityCounter& aCounter, + const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion) override { CompositorBridgeParent* parent; { // scope lock MonitorAutoLock lock(*sIndirectLayerTreesLock); parent = sIndirectLayerTrees[aGuid.mLayersId].mParent; } - if (parent) { - return parent->RecvNotifyApproximatelyVisibleRegion(aGuid, aRegion); + + if (!parent) { + return false; } + + parent->UpdateVisibleRegion(aCounter, aGuid, aRegion); return true; } @@ -2474,6 +2469,11 @@ CompositorBridgeParent::UpdatePluginWindowState(uint64_t aId) } if (!lts.mPluginData.Length()) { + // Don't hide plugins if the previous remote layer tree didn't contain any. + if (!mCachedPluginData.Length()) { + PLUGINS_LOG("[%" PRIu64 "] nothing to hide", aId); + return false; + } // We will pass through here in cases where the previous shadow layer // tree contained visible plugins and the new tree does not. All we need // to do here is hide the plugins for the old tree, so don't waste time @@ -2562,7 +2562,6 @@ CompositorBridgeParent::HideAllPluginWindows() return; } mDeferPluginWindows = true; - mPluginUpdateResponsePending = true; mPluginWindowsHidden = true; Unused << SendHideAllPlugins((uintptr_t)GetWidget()); ScheduleComposition(); diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index 8abad4a90e..aa8a898b36 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -258,12 +258,16 @@ public: // @see CrossProcessCompositorBridgeParent::RecvRequestNotifyAfterRemotePaint virtual bool RecvRequestNotifyAfterRemotePaint() override { return true; }; - virtual bool RecvClearApproximatelyVisibleRegions(const uint64_t& aLayersId, - const uint32_t& aPresShellId) override; - void ClearApproximatelyVisibleRegions(const uint64_t& aLayersId, - const Maybe& aPresShellId); - virtual bool RecvNotifyApproximatelyVisibleRegion(const ScrollableLayerGuid& aGuid, - const CSSIntRegion& aRegion) override; + virtual bool RecvClearVisibleRegions(const uint64_t& aLayersId, + const uint32_t& aPresShellId) override; + void ClearVisibleRegions(const uint64_t& aLayersId, + const Maybe& aPresShellId); + virtual bool RecvUpdateVisibleRegion(const VisibilityCounter& aCounter, + const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion) override; + void UpdateVisibleRegion(const VisibilityCounter& aCounter, + const ScrollableLayerGuid& aGuid, + const CSSIntRegion& aRegion); virtual void ActorDestroy(ActorDestroyReason why) override; @@ -599,9 +603,6 @@ protected: nsIntPoint mPluginsLayerOffset; nsIntRegion mPluginsLayerVisibleRegion; nsTArray mCachedPluginData; - // indicates if we are currently waiting on a plugin update confirmation. - // When this is true, composition is currently on hold. - bool mPluginUpdateResponsePending; // indicates if plugin window visibility and metric updates are currently // being defered due to a scroll operation. bool mDeferPluginWindows; diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl index 42f937b3a5..ee18ea64a1 100644 --- a/gfx/layers/ipc/PCompositorBridge.ipdl +++ b/gfx/layers/ipc/PCompositorBridge.ipdl @@ -25,6 +25,7 @@ using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasi using mozilla::CSSIntRegion from "Units.h"; using mozilla::LayoutDeviceIntPoint from "Units.h"; using mozilla::LayoutDeviceIntRegion from "Units.h"; +using mozilla::VisibilityCounter from "VisibilityIPC.h"; using class mozilla::TimeStamp from "mozilla/TimeStamp.h"; using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h"; @@ -173,15 +174,18 @@ parent: */ async RequestNotifyAfterRemotePaint(); - // The child clears the 'approximately visible' regions associated with the - // provided layers ID and pres shell ID (i.e., the regions for all view IDs - // associated with those IDs). - async ClearApproximatelyVisibleRegions(uint64_t layersId, uint32_t presShellId); + // The child sends a request to clear the visible regions (approximate, + // in-displayport, etc.) associated with the provided layers ID and pres shell + // ID (i.e., the regions for all view IDs associated with those IDs). + async ClearVisibleRegions(uint64_t layersId, uint32_t presShellId); // The child sends a region containing rects associated with the provided - // scrollable layer GUID that the child considers 'approximately visible'. + // scrollable layer GUID that the child considers visible in the sense + // specified by |counter|. // We visualize this information in the APZ minimap. - async NotifyApproximatelyVisibleRegion(ScrollableLayerGuid guid, CSSIntRegion region); + async UpdateVisibleRegion(VisibilityCounter counter, + ScrollableLayerGuid guid, + CSSIntRegion region); child: // Send back Compositor Frame Metrics from APZCs so tiled layers can diff --git a/gfx/vr/gfxVROculus.cpp b/gfx/vr/gfxVROculus.cpp index ef76f70c7a..bc031e54ef 100644 --- a/gfx/vr/gfxVROculus.cpp +++ b/gfx/vr/gfxVROculus.cpp @@ -526,6 +526,12 @@ HMDInfoOculus::SubmitFrame(RenderTargetSet *aRTSet, int32_t aInputFrameID) RenderTargetSetOculus *rts = static_cast(aRTSet); MOZ_ASSERT(rts->hmd != nullptr); MOZ_ASSERT(rts->textureSet != nullptr); + MOZ_ASSERT(aInputFrameID >= 0); + if (aInputFrameID < 0) { + // Sanity check to prevent invalid memory access on builds with assertions + // disabled. + aInputFrameID = 0; + } VRHMDSensorState sensorState = mLastSensorState[aInputFrameID % kMaxLatencyFrames]; // It is possible to get a cache miss on mLastSensorState if latency is @@ -535,6 +541,7 @@ HMDInfoOculus::SubmitFrame(RenderTargetSet *aRTSet, int32_t aInputFrameID) // un-viewable and a more accurate pose prediction is not likely to // compensate. ovrLayerEyeFov layer; + memset(&layer, 0, sizeof(layer)); layer.Header.Type = ovrLayerType_EyeFov; layer.Header.Flags = 0; layer.ColorTexture[0] = rts->textureSet; @@ -607,6 +614,7 @@ VRHMDManagerOculus::Init() mOculusThread = already_AddRefed(thread); ovrInitParams params; + memset(¶ms, 0, sizeof(params)); params.Flags = ovrInit_RequestVersion; params.RequestedMinorVersion = OVR_MINOR_VERSION; params.LogCallback = nullptr; diff --git a/gfx/vr/gfxVROculus050.cpp b/gfx/vr/gfxVROculus050.cpp index dd526d3a48..34968c4c10 100644 --- a/gfx/vr/gfxVROculus050.cpp +++ b/gfx/vr/gfxVROculus050.cpp @@ -543,6 +543,7 @@ VRHMDManagerOculus050::Init() mOculusThread = already_AddRefed(thread); ovrInitParams params; + memset(¶ms, 0, sizeof(params)); params.Flags = ovrInit_RequestVersion; params.RequestedMinorVersion = LIBOVR_MINOR_VERSION; params.LogCallback = nullptr; diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 6b12a9bd7d..f517f17c30 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -45,7 +45,6 @@ #include "nsRefPtrHashtable.h" #include "nsClassHashtable.h" #include "nsPresArena.h" -#include "nsIImageLoadingContent.h" #include "nsMargin.h" #include "nsFrameState.h" @@ -358,22 +357,25 @@ public: bool GetAuthorStyleDisabled() const; /* - * Called when stylesheets are added/removed/enabled/disabled to rebuild - * all style data for a given pres shell without necessarily reconstructing - * all of the frames. This will not reconstruct style synchronously; if - * you need to do that, call FlushPendingNotifications to flush out style - * reresolves. + * Called when stylesheets are added/removed/enabled/disabled to + * recompute style and clear other cached data as needed. This will + * not reconstruct style synchronously; if you need to do that, call + * FlushPendingNotifications to flush out style reresolves. + * + * This handles the the addition and removal of the various types of + * style rules that can be in CSS style sheets, such as @font-face + * rules and @counter-style rules. + * + * It requires that StyleSheetAdded, StyleSheetRemoved, + * StyleSheetApplicableStateChanged, StyleRuleAdded, StyleRuleRemoved, + * or StyleRuleChanged has been called on the style sheets that have + * changed. + * * // XXXbz why do we have this on the interface anyway? The only consumer * is calling AddOverrideStyleSheet/RemoveOverrideStyleSheet, and I think * those should just handle reconstructing style data... */ - virtual void ReconstructStyleDataExternal(); - void ReconstructStyleDataInternal(); -#ifdef MOZILLA_INTERNAL_API - void ReconstructStyleData() { ReconstructStyleDataInternal(); } -#else - void ReconstructStyleData() { ReconstructStyleDataExternal(); } -#endif + void RestyleForCSSRuleChanges(); /** * Update the style set somehow to take into account changed prefs which @@ -1588,11 +1590,12 @@ public: virtual void RebuildApproximateFrameVisibility(nsRect* aRect = nullptr, bool aRemoveOnly = false) = 0; - /// Ensures @aFrame is in the list of approximately visible frames. - virtual void EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame) = 0; + /// Adds @aFrame to the list of frames which were visible within the + /// displayport during the last paint. + virtual void MarkFrameVisibleInDisplayPort(nsIFrame* aFrame) = 0; - /// Removes @aFrame from the list of approximately visible frames if present. - virtual void RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) = 0; + /// Marks @aFrame nonvisible and removes it from all lists of visible frames. + virtual void MarkFrameNonvisible(nsIFrame* aFrame) = 0; /// Whether we should assume all frames are visible. virtual bool AssumeAllFramesVisible() = 0; diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 306b938ecb..1f3f3da05d 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1184,8 +1184,9 @@ PresShell::Destroy() mSynthMouseMoveEvent.Revoke(); mUpdateApproximateFrameVisibilityEvent.Revoke(); + mNotifyCompositorOfVisibleRegionsChangeEvent.Revoke(); - ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES)); + ClearVisibleFramesSets(Some(OnNonvisible::DISCARD_IMAGES)); if (mCaret) { mCaret->Terminate(); @@ -1343,7 +1344,7 @@ nsIPresShell::SetAuthorStyleDisabled(bool aStyleDisabled) { if (aStyleDisabled != mStyleSet->GetAuthorStyleDisabled()) { mStyleSet->SetAuthorStyleDisabled(aStyleDisabled); - ReconstructStyleData(); + RestyleForCSSRuleChanges(); nsCOMPtr observerService = mozilla::services::GetObserverService(); @@ -1452,7 +1453,7 @@ PresShell::AddUserSheet(nsISupports* aSheet) mStyleSet->EndUpdate(); - ReconstructStyleData(); + RestyleForCSSRuleChanges(); } void @@ -1468,7 +1469,7 @@ PresShell::AddAgentSheet(nsISupports* aSheet) } mStyleSet->AppendStyleSheet(SheetType::Agent, sheet); - ReconstructStyleData(); + RestyleForCSSRuleChanges(); } void @@ -1491,7 +1492,7 @@ PresShell::AddAuthorSheet(nsISupports* aSheet) mStyleSet->AppendStyleSheet(SheetType::Doc, sheet); } - ReconstructStyleData(); + RestyleForCSSRuleChanges(); } void @@ -1504,7 +1505,7 @@ PresShell::RemoveSheet(SheetType aType, nsISupports* aSheet) } mStyleSet->RemoveStyleSheet(aType, sheet); - ReconstructStyleData(); + RestyleForCSSRuleChanges(); } NS_IMETHODIMP @@ -2407,7 +2408,7 @@ PresShell::EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType) if (aUpdateType & UPDATE_STYLE) { mStyleSet->EndUpdate(); if (mStylesHaveChanged || !mChangedScopeStyleRoots.IsEmpty()) - ReconstructStyleData(); + RestyleForCSSRuleChanges(); } mFrameConstructor->EndUpdate(); @@ -4440,7 +4441,7 @@ PresShell::ReconstructFrames(void) } void -nsIPresShell::ReconstructStyleDataInternal() +nsIPresShell::RestyleForCSSRuleChanges() { AutoTArray,1> scopeRoots; mChangedScopeStyleRoots.SwapElements(scopeRoots); @@ -4490,12 +4491,6 @@ nsIPresShell::ReconstructStyleDataInternal() } } -void -nsIPresShell::ReconstructStyleDataExternal() -{ - ReconstructStyleDataInternal(); -} - void PresShell::RecordStyleSheetChange(StyleSheetHandle aStyleSheet) { @@ -4575,6 +4570,71 @@ PresShell::GetPlaceholderFrameFor(nsIFrame* aFrame) const return mFrameConstructor->GetPlaceholderFrameFor(aFrame); } +void +PresShell::NotifyCompositorOfVisibleRegionsChange() +{ + mNotifyCompositorOfVisibleRegionsChangeEvent.Revoke(); + + if (!mVisibleRegions) { + return; + } + + // Retrieve the layers ID and pres shell ID. + TabChild* tabChild = TabChild::GetFrom(this); + if (!tabChild) { + return; + } + + const uint64_t layersId = tabChild->LayersId(); + const uint32_t presShellId = GetPresShellId(); + + // Retrieve the CompositorBridgeChild. + LayerManager* layerManager = GetLayerManager(); + if (!layerManager) { + return; + } + + ClientLayerManager* clientLayerManager = layerManager->AsClientLayerManager(); + if (!clientLayerManager) { + return; + } + + CompositorBridgeChild* compositorChild = clientLayerManager->GetCompositorBridgeChild(); + if (!compositorChild) { + return; + } + + // Clear the old visible regions associated with this document. + compositorChild->SendClearVisibleRegions(layersId, presShellId); + + // Send the new visible regions to the compositor. + for (auto iter = mVisibleRegions->mApproximate.ConstIter(); + !iter.Done(); + iter.Next()) { + const ViewID viewId = iter.Key(); + const CSSIntRegion* region = iter.UserData(); + MOZ_ASSERT(region); + + const ScrollableLayerGuid guid(layersId, presShellId, viewId); + + compositorChild->SendUpdateVisibleRegion(VisibilityCounter::MAY_BECOME_VISIBLE, + guid, *region); + } + + for (auto iter = mVisibleRegions->mInDisplayPort.ConstIter(); + !iter.Done(); + iter.Next()) { + const ViewID viewId = iter.Key(); + const CSSIntRegion* region = iter.UserData(); + MOZ_ASSERT(region); + + const ScrollableLayerGuid guid(layersId, presShellId, viewId); + + compositorChild->SendUpdateVisibleRegion(VisibilityCounter::IN_DISPLAYPORT, + guid, *region); + } +} + nsresult PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags, nscolor aBackgroundColor, @@ -4686,6 +4746,9 @@ PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags, nsLayoutUtils::PaintFrame(&rc, rootFrame, nsRegion(aRect), aBackgroundColor, flags); + // We don't call NotifyCompositorOfVisibleRegionsChange here because we're + // not painting to the window, and hence there should be no change. + return NS_OK; } @@ -4838,12 +4901,12 @@ PresShell::CreateRangePaintInfo(nsIDOMRange* aRange, ancestorFrame = ancestorFrame->GetParent(); } - if (!ancestorFrame) + if (!ancestorFrame) { return nullptr; - - auto info = MakeUnique(range, ancestorFrame); + } // get a display list containing the range + auto info = MakeUnique(range, ancestorFrame); info->mBuilder.SetIncludeAllOutOfFlows(); if (aForPrimarySelection) { info->mBuilder.SetSelectedFramesOnly(); @@ -5576,17 +5639,14 @@ PresShell::ProcessSynthMouseMoveEvent(bool aFromScroll) } } -static void -AddFrameToVisibleRegions(nsIFrame* aFrame, - nsViewManager* aViewManager, - Maybe& aVisibleRegions) +void +PresShell::AddFrameToVisibleRegions(nsIFrame* aFrame, VisibilityCounter aForCounter) { - if (!aVisibleRegions) { + if (!mVisibleRegions) { return; } MOZ_ASSERT(aFrame); - MOZ_ASSERT(aViewManager); // Retrieve the view ID for this frame (which we obtain from the enclosing // scrollable frame). @@ -5621,20 +5681,22 @@ AddFrameToVisibleRegions(nsIFrame* aFrame, return; } - CSSIntRegion* regionForView = aVisibleRegions->LookupOrAdd(viewID); + VisibleRegions& regions = aForCounter == VisibilityCounter::MAY_BECOME_VISIBLE + ? mVisibleRegions->mApproximate + : mVisibleRegions->mInDisplayPort; + CSSIntRegion* regionForView = regions.LookupOrAdd(viewID); MOZ_ASSERT(regionForView); regionForView->OrWith(CSSPixel::FromAppUnitsRounded(frameRectInScrolledFrameSpace)); } /* static */ void -PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList, - Maybe& aVisibleRegions) +PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList) { for (nsDisplayItem* item = aList.GetBottom(); item; item = item->GetAbove()) { nsDisplayList* sublist = item->GetChildren(); if (sublist) { - MarkFramesInListApproximatelyVisible(*sublist, aVisibleRegions); + MarkFramesInListApproximatelyVisible(*sublist); continue; } @@ -5652,128 +5714,56 @@ PresShell::MarkFramesInListApproximatelyVisible(const nsDisplayList& aList, presShell->mApproximatelyVisibleFrames.PutEntry(frame); if (presShell->mApproximatelyVisibleFrames.Count() > count) { // The frame was added to mApproximatelyVisibleFrames, so increment its visible count. - frame->IncApproximateVisibleCount(); + frame->IncVisibilityCount(VisibilityCounter::MAY_BECOME_VISIBLE); } - AddFrameToVisibleRegions(frame, presShell->mViewManager, aVisibleRegions); - } -} - -void -PresShell::ReportBadStateDuringVisibilityUpdate() -{ - if (!NS_IsMainThread()) { - gfxCriticalNote << "Got null frame in frame visibility: off-main-thread"; - } - if (mIsZombie) { - gfxCriticalNote << "Got null frame in frame visibility: mIsZombie"; - } - if (mIsDestroying) { - gfxCriticalNote << "Got null frame in frame visibility: mIsDestroying"; - } - if (mIsReflowing) { - gfxCriticalNote << "Got null frame in frame visibility: mIsReflowing"; - } - if (mPaintingIsFrozen) { - gfxCriticalNote << "Got null frame in frame visibility: mPaintingIsFrozen"; - } - if (mForwardingContainer) { - gfxCriticalNote << "Got null frame in frame visibility: mForwardingContainer"; - } - if (mIsNeverPainting) { - gfxCriticalNote << "Got null frame in frame visibility: mIsNeverPainting"; - } - if (mIsDocumentGone) { - gfxCriticalNote << "Got null frame in frame visibility: mIsDocumentGone"; - } - if (!nsContentUtils::IsSafeToRunScript()) { - gfxCriticalNote << "Got null frame in frame visibility: not safe to run script"; - } -} - -void -PresShell::SetInFrameVisibilityUpdate(bool aState) -{ - mInFrameVisibilityUpdate = aState; -} - -static void -NotifyCompositorOfVisibleRegionsChange(PresShell* aPresShell, - const Maybe& aRegions) -{ - if (!aRegions) { - return; - } - - MOZ_ASSERT(aPresShell); - - // Retrieve the layers ID and pres shell ID. - TabChild* tabChild = TabChild::GetFrom(aPresShell); - if (!tabChild) { - return; - } - - const uint64_t layersId = tabChild->LayersId(); - const uint32_t presShellId = aPresShell->GetPresShellId(); - - // Retrieve the CompositorBridgeChild. - LayerManager* layerManager = aPresShell->GetLayerManager(); - if (!layerManager) { - return; - } - - ClientLayerManager* clientLayerManager = layerManager->AsClientLayerManager(); - if (!clientLayerManager) { - return; - } - - CompositorBridgeChild* compositorChild = clientLayerManager->GetCompositorBridgeChild(); - if (!compositorChild) { - return; - } - - // Clear the old approximately visible regions associated with this document. - compositorChild->SendClearApproximatelyVisibleRegions(layersId, presShellId); - - // Send the new approximately visible regions to the compositor. - for (auto iter = aRegions->ConstIter(); !iter.Done(); iter.Next()) { - const ViewID viewId = iter.Key(); - const CSSIntRegion* region = iter.UserData(); - MOZ_ASSERT(region); - - const ScrollableLayerGuid guid(layersId, presShellId, viewId); - - compositorChild->SendNotifyApproximatelyVisibleRegion(guid, *region); + presShell->AddFrameToVisibleRegions(frame, VisibilityCounter::MAY_BECOME_VISIBLE); } } /* static */ void -PresShell::DecApproximateVisibleCount(VisibleFrames& aFrames, - Maybe aNonvisibleAction - /* = Nothing() */) +PresShell::DecVisibleCount(const VisibleFrames& aFrames, + VisibilityCounter aCounter, + Maybe aNonvisibleAction /* = Nothing() */) { - for (auto iter = aFrames.Iter(); !iter.Done(); iter.Next()) { + for (auto iter = aFrames.ConstIter(); !iter.Done(); iter.Next()) { nsIFrame* frame = iter.Get()->GetKey(); - - if (MOZ_UNLIKELY(!frame)) { - // We are about to crash, annotate crash report with some info that might - // help debug the crash (bug 1251150) - ReportBadStateDuringVisibilityUpdate(); - } - - SetInFrameVisibilityUpdate(true); - // Decrement the frame's visible count if we're still tracking its // visibility. (We may not be, if the frame disabled visibility tracking // after we added it to the visible frames list.) if (frame->TrackingVisibility()) { - frame->DecApproximateVisibleCount(aNonvisibleAction); + frame->DecVisibilityCount(aCounter, aNonvisibleAction); } - - SetInFrameVisibilityUpdate(false); } } +void +PresShell::InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter aForCounter) +{ + // If we're visualizing visible regions, initialize a + // VisibleRegionsContainer to store them. Visibility-related functions we + // call will only do the work of populating this object and sending it to + // the compositor if we've created it, so we don't need to check the prefs + // everywhere. + if (!gfxPrefs::APZMinimap() || + !gfxPrefs::APZMinimapVisibilityEnabled()) { + mVisibleRegions = nullptr; + return; + } + + if (mVisibleRegions) { + // Clear the regions we're about to update. We don't want to clear both, + // or the two visibility tracking methods will interfere with each other. + VisibleRegions& regions = aForCounter == VisibilityCounter::MAY_BECOME_VISIBLE + ? mVisibleRegions->mApproximate + : mVisibleRegions->mInDisplayPort; + regions.Clear(); + return; + } + + mVisibleRegions = MakeUnique(); +} + void PresShell::RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aList) { @@ -5785,70 +5775,72 @@ PresShell::RebuildApproximateFrameVisibilityDisplayList(const nsDisplayList& aLi VisibleFrames oldApproximatelyVisibleFrames; mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames); - // If we're visualizing visible regions, create a VisibleRegions object to - // store information about them. The functions we call will populate this - // object and send it to the compositor only if it's Some(), so we don't - // need to check the prefs everywhere. - Maybe visibleRegions; - if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) { - visibleRegions.emplace(); - } + InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter::MAY_BECOME_VISIBLE); - MarkFramesInListApproximatelyVisible(aList, visibleRegions); + MarkFramesInListApproximatelyVisible(aList); - DecApproximateVisibleCount(oldApproximatelyVisibleFrames); + DecVisibleCount(oldApproximatelyVisibleFrames, + VisibilityCounter::MAY_BECOME_VISIBLE); - NotifyCompositorOfVisibleRegionsChange(this, visibleRegions); + NotifyCompositorOfVisibleRegionsChange(); } /* static */ void -PresShell::ClearApproximateFrameVisibilityVisited(nsView* aView, bool aClear) +PresShell::ClearVisibleFramesForUnvisitedPresShells(nsView* aView, bool aClear) { nsViewManager* vm = aView->GetViewManager(); if (aClear) { PresShell* presShell = static_cast(vm->GetPresShell()); if (!presShell->mApproximateFrameVisibilityVisited) { - presShell->ClearApproximatelyVisibleFramesList(); + presShell->ClearVisibleFramesSets(); } presShell->mApproximateFrameVisibilityVisited = false; } for (nsView* v = aView->GetFirstChild(); v; v = v->GetNextSibling()) { - ClearApproximateFrameVisibilityVisited(v, v->GetViewManager() != vm); + ClearVisibleFramesForUnvisitedPresShells(v, v->GetViewManager() != vm); } } void -PresShell::ClearApproximatelyVisibleFramesList(Maybe aNonvisibleAction - /* = Nothing() */) +PresShell::ClearVisibleFramesSets(Maybe aNonvisibleAction + /* = Nothing() */) { - if (mInFrameVisibilityUpdate) { - gfxCriticalNoteOnce << "ClearApproximatelyVisibleFramesList is re-entering on " - << (NS_IsMainThread() ? "" : "non-") << "main thread"; - } - DecApproximateVisibleCount(mApproximatelyVisibleFrames, aNonvisibleAction); + DecVisibleCount(mApproximatelyVisibleFrames, + VisibilityCounter::MAY_BECOME_VISIBLE, + aNonvisibleAction); mApproximatelyVisibleFrames.Clear(); + + DecVisibleCount(mInDisplayPortFrames, + VisibilityCounter::IN_DISPLAYPORT, + aNonvisibleAction); + mInDisplayPortFrames.Clear(); + + if (mVisibleRegions) { + mVisibleRegions->mApproximate.Clear(); + mVisibleRegions->mInDisplayPort.Clear(); + NotifyCompositorOfVisibleRegionsChange(); + } } void PresShell::MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame, const nsRect& aRect, - Maybe& aVisibleRegions, bool aRemoveOnly /* = false */) { MOZ_ASSERT(aFrame->PresContext()->PresShell() == this, "wrong presshell"); if (aFrame->TrackingVisibility() && aFrame->StyleVisibility()->IsVisible() && - (!aRemoveOnly || aFrame->GetVisibility() == Visibility::APPROXIMATELY_VISIBLE)) { + (!aRemoveOnly || aFrame->IsVisibleOrMayBecomeVisibleSoon())) { MOZ_ASSERT(!AssumeAllFramesVisible()); uint32_t count = mApproximatelyVisibleFrames.Count(); mApproximatelyVisibleFrames.PutEntry(aFrame); if (mApproximatelyVisibleFrames.Count() > count) { // The frame was added to mApproximatelyVisibleFrames, so increment its visible count. - aFrame->IncApproximateVisibleCount(); + aFrame->IncVisibilityCount(VisibilityCounter::MAY_BECOME_VISIBLE); } - AddFrameToVisibleRegions(aFrame, mViewManager, aVisibleRegions); + AddFrameToVisibleRegions(aFrame, VisibilityCounter::MAY_BECOME_VISIBLE); } nsSubDocumentFrame* subdocFrame = do_QueryFrame(aFrame); @@ -5917,7 +5909,7 @@ PresShell::MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame, } } } - MarkFramesInSubtreeApproximatelyVisible(child, r, aVisibleRegions); + MarkFramesInSubtreeApproximatelyVisible(child, r); } } } @@ -5934,35 +5926,24 @@ PresShell::RebuildApproximateFrameVisibility(nsRect* aRect, return; } - if (mInFrameVisibilityUpdate) { - gfxCriticalNoteOnce << "RebuildApproximateFrameVisibility is re-entering on " - << (NS_IsMainThread() ? "" : "non-") << "main thread"; - } - // Remove the entries of the mApproximatelyVisibleFrames hashtable and put // them in oldApproximatelyVisibleFrames. VisibleFrames oldApproximatelyVisibleFrames; mApproximatelyVisibleFrames.SwapElements(oldApproximatelyVisibleFrames); - // If we're visualizing visible regions, create a VisibleRegions object to - // store information about them. The functions we call will populate this - // object and send it to the compositor only if it's Some(), so we don't - // need to check the prefs everywhere. - Maybe visibleRegions; - if (gfxPrefs::APZMinimap() && gfxPrefs::APZMinimapVisibilityEnabled()) { - visibleRegions.emplace(); - } + InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter::MAY_BECOME_VISIBLE); nsRect vis(nsPoint(0, 0), rootFrame->GetSize()); if (aRect) { vis = *aRect; } - MarkFramesInSubtreeApproximatelyVisible(rootFrame, vis, visibleRegions, aRemoveOnly); + MarkFramesInSubtreeApproximatelyVisible(rootFrame, vis, aRemoveOnly); - DecApproximateVisibleCount(oldApproximatelyVisibleFrames); + DecVisibleCount(oldApproximatelyVisibleFrames, + VisibilityCounter::MAY_BECOME_VISIBLE); - NotifyCompositorOfVisibleRegionsChange(this, visibleRegions); + NotifyCompositorOfVisibleRegionsChange(); } void @@ -5986,12 +5967,12 @@ PresShell::DoUpdateApproximateFrameVisibility(bool aRemoveOnly) // call update on that frame nsIFrame* rootFrame = GetRootFrame(); if (!rootFrame) { - ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DISCARD_IMAGES)); + ClearVisibleFramesSets(Some(OnNonvisible::DISCARD_IMAGES)); return; } RebuildApproximateFrameVisibility(/* aRect = */ nullptr, aRemoveOnly); - ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true); + ClearVisibleFramesForUnvisitedPresShells(rootFrame->GetView(), true); #ifdef DEBUG_FRAME_VISIBILITY_DISPLAY_LIST // This can be used to debug the frame walker by comparing beforeFrameList @@ -6005,7 +5986,8 @@ PresShell::DoUpdateApproximateFrameVisibility(bool aRemoveOnly) if (rootScroll) { nsIContent* content = rootScroll->GetContent(); if (content) { - Unused << nsLayoutUtils::GetDisplayPort(content, &updateRect, RelativeTo::ScrollFrame); + Unused << nsLayoutUtils::GetDisplayPortForVisibilityTesting(content, &updateRect, + RelativeTo::ScrollFrame); } if (IgnoringViewportScrolling()) { @@ -6020,7 +6002,7 @@ PresShell::DoUpdateApproximateFrameVisibility(bool aRemoveOnly) RebuildApproximateFrameVisibilityDisplayList(list); - ClearApproximateFrameVisibilityVisited(rootFrame->GetView(), true); + ClearVisibleFramesForUnvisitedPresShells(rootFrame->GetView(), true); list.DeleteAll(); #endif @@ -6125,14 +6107,16 @@ PresShell::ScheduleApproximateFrameVisibilityUpdateNow() } void -PresShell::EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame) +PresShell::MarkFrameVisibleInDisplayPort(nsIFrame* aFrame) { if (!aFrame->TrackingVisibility()) { return; } if (AssumeAllFramesVisible()) { - aFrame->IncApproximateVisibleCount(); + if (aFrame->GetVisibility() != Visibility::IN_DISPLAYPORT) { + aFrame->IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT); + } return; } @@ -6145,20 +6129,31 @@ PresShell::EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame) } #endif - if (mInFrameVisibilityUpdate) { - gfxCriticalNoteOnce << "EnsureFrameInApproximatelyVisibleList is re-entering on " - << (NS_IsMainThread() ? "" : "non-") << "main thread"; + if (!mInDisplayPortFrames.Contains(aFrame)) { + MOZ_ASSERT(!AssumeAllFramesVisible()); + mInDisplayPortFrames.PutEntry(aFrame); + aFrame->IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT); } - if (!mApproximatelyVisibleFrames.Contains(aFrame)) { - MOZ_ASSERT(!AssumeAllFramesVisible()); - mApproximatelyVisibleFrames.PutEntry(aFrame); - aFrame->IncApproximateVisibleCount(); + AddFrameToVisibleRegions(aFrame, VisibilityCounter::IN_DISPLAYPORT); +} + +static void +RemoveFrameFromVisibleSet(nsIFrame* aFrame, + VisibleFrames& aSet, + VisibilityCounter aCounter) +{ + uint32_t count = aSet.Count(); + aSet.RemoveEntry(aFrame); + + if (aFrame->TrackingVisibility() && aSet.Count() < count) { + aFrame->DecVisibilityCount(aCounter); } + } void -PresShell::RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) +PresShell::MarkFrameNonvisible(nsIFrame* aFrame) { #ifdef DEBUG // Make sure it's in this pres shell. @@ -6171,24 +6166,16 @@ PresShell::RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) if (AssumeAllFramesVisible()) { MOZ_ASSERT(mApproximatelyVisibleFrames.Count() == 0, - "Shouldn't have any frames in the table"); + "Shouldn't have any frames in the approximate visibility set"); + MOZ_ASSERT(mInDisplayPortFrames.Count() == 0, + "Shouldn't have any frames in the in-displayport visibility set"); return; } - if (mInFrameVisibilityUpdate) { - gfxCriticalNoteOnce << "RemoveFrameFromApproximatelyVisibleList is re-entering on " - << (NS_IsMainThread() ? "" : "non-") << "main thread"; - } - - uint32_t count = mApproximatelyVisibleFrames.Count(); - mApproximatelyVisibleFrames.RemoveEntry(aFrame); - - if (aFrame->TrackingVisibility() && - mApproximatelyVisibleFrames.Count() < count) { - // aFrame was in the hashtable, and we're still tracking its visibility, - // so we need to decrement its visible count. - aFrame->DecApproximateVisibleCount(); - } + RemoveFrameFromVisibleSet(aFrame, mApproximatelyVisibleFrames, + VisibilityCounter::MAY_BECOME_VISIBLE); + RemoveFrameFromVisibleSet(aFrame, mInDisplayPortFrames, + VisibilityCounter::IN_DISPLAYPORT); } class nsAutoNotifyDidPaint @@ -6376,8 +6363,30 @@ PresShell::Paint(nsView* aViewToPaint, } if (frame) { + // Remove the entries of the mInDisplayPortFrames hashtable and put them + // in oldInDisplayPortFrames. + VisibleFrames oldInDisplayPortFrames; + mInDisplayPortFrames.SwapElements(oldInDisplayPortFrames); + + InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter::IN_DISPLAYPORT); + // We can paint directly into the widget using its layer manager. nsLayoutUtils::PaintFrame(nullptr, frame, aDirtyRegion, bgcolor, flags); + + DecVisibleCount(oldInDisplayPortFrames, VisibilityCounter::IN_DISPLAYPORT); + + if (mVisibleRegions && + !mNotifyCompositorOfVisibleRegionsChangeEvent.IsPending()) { + // Asynchronously notify the compositor of the new visible regions, + // since this is happening during a paint and updating the visible + // regions triggers a recomposite. + RefPtr> event = + NS_NewRunnableMethod(this, &PresShell::NotifyCompositorOfVisibleRegionsChange); + if (NS_SUCCEEDED(NS_DispatchToMainThread(event))) { + mNotifyCompositorOfVisibleRegionsChangeEvent = event; + } + } + return; } @@ -9024,6 +9033,7 @@ void PresShell::Freeze() { mUpdateApproximateFrameVisibilityEvent.Revoke(); + mNotifyCompositorOfVisibleRegionsChangeEvent.Revoke(); MaybeReleaseCapturingContent(); @@ -11047,11 +11057,6 @@ PresShell::UpdateImageLockingState() nsresult rv = mDocument->SetImageLockingState(locked); if (locked) { - if (mInFrameVisibilityUpdate) { - gfxCriticalNoteOnce << "UpdateImageLockingState is re-entering on " - << (NS_IsMainThread() ? "" : "non-") << "main thread"; - } - // Request decodes for visible image frames; we want to start decoding as // quickly as possible when we get foregrounded to minimize flashing. for (auto iter = mApproximatelyVisibleFrames.Iter(); !iter.Done(); iter.Next()) { @@ -11091,6 +11096,11 @@ PresShell::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, *aPresShellSize += mCaret->SizeOfIncludingThis(aMallocSizeOf); } *aPresShellSize += mApproximatelyVisibleFrames.ShallowSizeOfExcludingThis(aMallocSizeOf); + *aPresShellSize += mInDisplayPortFrames.ShallowSizeOfExcludingThis(aMallocSizeOf); + *aPresShellSize += mVisibleRegions + ? mVisibleRegions->mApproximate.ShallowSizeOfIncludingThis(aMallocSizeOf) + + mVisibleRegions->mInDisplayPort.ShallowSizeOfIncludingThis(aMallocSizeOf) + : 0; *aPresShellSize += mFramesToDirty.ShallowSizeOfExcludingThis(aMallocSizeOf); *aPresShellSize += aArenaObjectsSize->mOther; diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index a23a310117..70548741c8 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -38,6 +38,7 @@ #include "mozilla/StyleSetHandle.h" #include "mozilla/UniquePtr.h" #include "MobileViewportManager.h" +#include "Visibility.h" #include "ZoomConstraintsClient.h" class nsRange; @@ -79,6 +80,8 @@ class PresShell final : public nsIPresShell, template using Maybe = mozilla::Maybe; using Nothing = mozilla::Nothing; using OnNonvisible = mozilla::OnNonvisible; + template using UniquePtr = mozilla::UniquePtr; + using VisibilityCounter = mozilla::VisibilityCounter; using VisibleFrames = mozilla::VisibleFrames; using VisibleRegions = mozilla::VisibleRegions; @@ -402,8 +405,8 @@ public: void RebuildApproximateFrameVisibility(nsRect* aRect = nullptr, bool aRemoveOnly = false) override; - void EnsureFrameInApproximatelyVisibleList(nsIFrame* aFrame) override; - void RemoveFrameFromApproximatelyVisibleList(nsIFrame* aFrame) override; + void MarkFrameVisibleInDisplayPort(nsIFrame* aFrame) override; + void MarkFrameNonvisible(nsIFrame* aFrame) override; bool AssumeAllFramesVisible() override; @@ -765,27 +768,46 @@ protected: void UpdateApproximateFrameVisibility(); void DoUpdateApproximateFrameVisibility(bool aRemoveOnly); - void ClearApproximatelyVisibleFramesList(Maybe aNonvisibleAction - = Nothing()); - static void ClearApproximateFrameVisibilityVisited(nsView* aView, bool aClear); - static void MarkFramesInListApproximatelyVisible(const nsDisplayList& aList, - Maybe& aVisibleRegions); + void ClearVisibleFramesSets(Maybe aNonvisibleAction = Nothing()); + static void ClearVisibleFramesForUnvisitedPresShells(nsView* aView, bool aClear); + static void MarkFramesInListApproximatelyVisible(const nsDisplayList& aList); void MarkFramesInSubtreeApproximatelyVisible(nsIFrame* aFrame, const nsRect& aRect, - Maybe& aVisibleRegions, bool aRemoveOnly = false); - void DecApproximateVisibleCount(VisibleFrames& aFrames, - Maybe aNonvisibleAction = Nothing()); - void ReportBadStateDuringVisibilityUpdate(); - void SetInFrameVisibilityUpdate(bool aState); + void DecVisibleCount(const VisibleFrames& aFrames, + VisibilityCounter aCounter, + Maybe aNonvisibleAction = Nothing()); + + void InitVisibleRegionsIfVisualizationEnabled(VisibilityCounter aForCounter); + void AddFrameToVisibleRegions(nsIFrame* aFrame, VisibilityCounter aForCounter); + void NotifyCompositorOfVisibleRegionsChange(); nsRevocableEventPtr> mUpdateApproximateFrameVisibilityEvent; + nsRevocableEventPtr> mNotifyCompositorOfVisibleRegionsChangeEvent; // A set of frames that were visible or could be visible soon at the time // that we last did an approximate frame visibility update. VisibleFrames mApproximatelyVisibleFrames; + // A set of frames that were visible in the displayport the last time we painted. + VisibleFrames mInDisplayPortFrames; + + struct VisibleRegionsContainer + { + // The approximately visible regions calculated during the last update to + // approximate frame visibility. + VisibleRegions mApproximate; + + // The in-displayport visible regions calculated during the last paint. + VisibleRegions mInDisplayPort; + }; + + // The most recent visible regions we've computed. Only non-null if the APZ + // minimap visibility visualization was enabled during the last visibility + // update. + UniquePtr mVisibleRegions; + ////////////////////////////////////////////////////////////////////////////// // Methods for dispatching KeyboardEvent and BeforeAfterKeyboardEvent. @@ -952,8 +974,6 @@ protected: // Whether the widget has received a paint message yet. bool mHasReceivedPaintMessage : 1; - bool mInFrameVisibilityUpdate : 1; - static bool sDisableNonTestMouseEvents; }; diff --git a/layout/forms/nsColorControlFrame.cpp b/layout/forms/nsColorControlFrame.cpp index 9c0972dca5..e0bae43a98 100644 --- a/layout/forms/nsColorControlFrame.cpp +++ b/layout/forms/nsColorControlFrame.cpp @@ -20,8 +20,8 @@ using mozilla::dom::Element; -nsColorControlFrame::nsColorControlFrame(nsStyleContext* aContext): - nsColorControlFrameSuper(aContext) +nsColorControlFrame::nsColorControlFrame(nsStyleContext* aContext) + : nsHTMLButtonControlFrame(aContext) { } @@ -36,14 +36,14 @@ NS_IMPL_FRAMEARENA_HELPERS(nsColorControlFrame) NS_QUERYFRAME_HEAD(nsColorControlFrame) NS_QUERYFRAME_ENTRY(nsColorControlFrame) NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator) -NS_QUERYFRAME_TAIL_INHERITING(nsColorControlFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsHTMLButtonControlFrame) void nsColorControlFrame::DestroyFrom(nsIFrame* aDestructRoot) { nsFormControlFrame::RegUnRegAccessKey(static_cast(this), false); nsContentUtils::DestroyAnonymousContent(&mColorContent); - nsColorControlFrameSuper::DestroyFrom(aDestructRoot); + nsHTMLButtonControlFrame::DestroyFrom(aDestructRoot); } nsIAtom* @@ -126,7 +126,7 @@ nsColorControlFrame::AttributeChanged(int32_t aNameSpaceID, aNameSpaceID == kNameSpaceID_None && nsGkAtoms::value == aAttribute) { UpdateColor(); } - return nsColorControlFrameSuper::AttributeChanged(aNameSpaceID, aAttribute, + return nsHTMLButtonControlFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); } diff --git a/layout/forms/nsColorControlFrame.h b/layout/forms/nsColorControlFrame.h index 568485c033..238347ce35 100644 --- a/layout/forms/nsColorControlFrame.h +++ b/layout/forms/nsColorControlFrame.h @@ -14,11 +14,9 @@ namespace mozilla { enum class CSSPseudoElementType : uint8_t; } // namespace mozilla -typedef nsHTMLButtonControlFrame nsColorControlFrameSuper; - // Class which implements the input type=color -class nsColorControlFrame final : public nsColorControlFrameSuper, +class nsColorControlFrame final : public nsHTMLButtonControlFrame, public nsIAnonymousContentCreator { typedef mozilla::CSSPseudoElementType CSSPseudoElementType; diff --git a/layout/forms/nsFormControlFrame.cpp b/layout/forms/nsFormControlFrame.cpp index 77ef2ec645..3d8e8bfdd6 100644 --- a/layout/forms/nsFormControlFrame.cpp +++ b/layout/forms/nsFormControlFrame.cpp @@ -17,8 +17,8 @@ using namespace mozilla; //#define FCF_NOISY -nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext) : - nsFormControlFrameSuper(aContext) +nsFormControlFrame::nsFormControlFrame(nsStyleContext* aContext) + : nsAtomicContainerFrame(aContext) { } @@ -29,7 +29,7 @@ nsFormControlFrame::~nsFormControlFrame() nsIAtom* nsFormControlFrame::GetType() const { - return nsGkAtoms::formControlFrame; + return nsGkAtoms::formControlFrame; } void @@ -37,12 +37,12 @@ nsFormControlFrame::DestroyFrom(nsIFrame* aDestructRoot) { // Unregister the access key registered in reflow nsFormControlFrame::RegUnRegAccessKey(static_cast(this), false); - nsFormControlFrameSuper::DestroyFrom(aDestructRoot); + nsAtomicContainerFrame::DestroyFrom(aDestructRoot); } NS_QUERYFRAME_HEAD(nsFormControlFrame) NS_QUERYFRAME_ENTRY(nsIFormControlFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsFormControlFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame) /* virtual */ nscoord nsFormControlFrame::GetMinISize(nsRenderingContext *aRenderingContext) diff --git a/layout/forms/nsFormControlFrame.h b/layout/forms/nsFormControlFrame.h index 9d3a3034bc..9ca7909b92 100644 --- a/layout/forms/nsFormControlFrame.h +++ b/layout/forms/nsFormControlFrame.h @@ -11,14 +11,12 @@ #include "nsAtomicContainerFrame.h" #include "nsDisplayList.h" -typedef nsAtomicContainerFrame nsFormControlFrameSuper; - -/** +/** * nsFormControlFrame is the base class for radio buttons and * checkboxes. It also has two static methods (RegUnRegAccessKey and * GetScreenHeight) that are used by other form controls. */ -class nsFormControlFrame : public nsFormControlFrameSuper, +class nsFormControlFrame : public nsAtomicContainerFrame, public nsIFormControlFrame { public: @@ -33,7 +31,7 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { - return nsFormControlFrameSuper::IsFrameOfType(aFlags & + return nsAtomicContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedContainsBlock)); } @@ -68,11 +66,11 @@ public: const mozilla::LogicalSize& aPadding, bool aShrinkWrap) override; - /** + /** * Respond to a gui event * @see nsIFrame::HandleEvent */ - virtual nsresult HandleEvent(nsPresContext* aPresContext, + virtual nsresult HandleEvent(nsPresContext* aPresContext, mozilla::WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) override; @@ -117,7 +115,7 @@ protected: //------------------------------------------------------------------------------------- // Utility methods for managing checkboxes and radiobuttons //------------------------------------------------------------------------------------- -// +// /** * Get the state of the checked attribute. * @param aState set to true if the checked attribute is set, diff --git a/layout/forms/nsImageControlFrame.cpp b/layout/forms/nsImageControlFrame.cpp index 02f6ce2ba2..589b4e7a90 100644 --- a/layout/forms/nsImageControlFrame.cpp +++ b/layout/forms/nsImageControlFrame.cpp @@ -15,8 +15,7 @@ using namespace mozilla; -typedef nsImageFrame nsImageControlFrameSuper; -class nsImageControlFrame : public nsImageControlFrameSuper, +class nsImageControlFrame : public nsImageFrame, public nsIFormControlFrame { public: @@ -56,13 +55,13 @@ public: nsIFrame::Cursor& aCursor) override; // nsIFormContromFrame virtual void SetFocus(bool aOn, bool aRepaint) override; - virtual nsresult SetFormProperty(nsIAtom* aName, + virtual nsresult SetFormProperty(nsIAtom* aName, const nsAString& aValue) override; }; -nsImageControlFrame::nsImageControlFrame(nsStyleContext* aContext): - nsImageControlFrameSuper(aContext) +nsImageControlFrame::nsImageControlFrame(nsStyleContext* aContext) + : nsImageFrame(aContext) { } @@ -76,7 +75,7 @@ nsImageControlFrame::DestroyFrom(nsIFrame* aDestructRoot) if (!GetPrevInFlow()) { nsFormControlFrame::RegUnRegAccessKey(this, false); } - nsImageControlFrameSuper::DestroyFrom(aDestructRoot); + nsImageFrame::DestroyFrom(aDestructRoot); } nsIFrame* @@ -92,12 +91,12 @@ nsImageControlFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) { - nsImageControlFrameSuper::Init(aContent, aParent, aPrevInFlow); + nsImageFrame::Init(aContent, aParent, aPrevInFlow); if (aPrevInFlow) { return; } - + mContent->SetProperty(nsGkAtoms::imageClickedPoint, new nsIntPoint(0, 0), nsINode::DeleteProperty); @@ -105,7 +104,7 @@ nsImageControlFrame::Init(nsIContent* aContent, NS_QUERYFRAME_HEAD(nsImageControlFrame) NS_QUERYFRAME_ENTRY(nsIFormControlFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsImageControlFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsImageFrame) #ifdef ACCESSIBILITY a11y::AccType @@ -122,7 +121,7 @@ nsImageControlFrame::AccessibleType() nsIAtom* nsImageControlFrame::GetType() const { - return nsGkAtoms::imageControlFrame; + return nsGkAtoms::imageControlFrame; } void @@ -136,10 +135,10 @@ nsImageControlFrame::Reflow(nsPresContext* aPresContext, if (!GetPrevInFlow() && (mState & NS_FRAME_FIRST_REFLOW)) { nsFormControlFrame::RegUnRegAccessKey(this, true); } - return nsImageControlFrameSuper::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); + return nsImageFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); } -nsresult +nsresult nsImageControlFrame::HandleEvent(nsPresContext* aPresContext, WidgetGUIEvent* aEvent, nsEventStatus* aEventStatus) @@ -175,11 +174,10 @@ nsImageControlFrame::HandleEvent(nsPresContext* aPresContext, TranslateEventCoords(pt, *lastClickPoint); } } - return nsImageControlFrameSuper::HandleEvent(aPresContext, aEvent, - aEventStatus); + return nsImageFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } -void +void nsImageControlFrame::SetFocus(bool aOn, bool aRepaint) { } diff --git a/layout/generic/Visibility.h b/layout/generic/Visibility.h index ddb8932523..c3687f0009 100644 --- a/layout/generic/Visibility.h +++ b/layout/generic/Visibility.h @@ -8,6 +8,8 @@ * possible visibility states of a frame. @OnNonvisible is an enumeration that * allows callers to request a specific action when a frame transitions from * visible to nonvisible. + * + * IPC serializers are available in VisibilityIPC.h. */ #ifndef mozilla_layout_generic_Visibility_h @@ -18,21 +20,35 @@ namespace mozilla { // Visibility states for frames. enum class Visibility : uint8_t { - // Indicates that we're not tracking visibility for this frame. + // We're not tracking visibility for this frame. UNTRACKED, - // Indicates that the frame is probably nonvisible. Visible frames *may* be - // APPROXIMATELY_NONVISIBLE because approximate visibility is not updated - // synchronously. Some truly nonvisible frames may be marked - // APPROXIMATELY_VISIBLE instead if our heuristics lead us to think they may - // be visible soon. - APPROXIMATELY_NONVISIBLE, + // This frame is nonvisible - i.e., it was not within the displayport as of + // the last paint (in which case it'd be IN_DISPLAYPORT) and our heuristics + // aren't telling us that it may become visible soon (in which case it'd be + // MAY_BECOME_VISIBLE). + NONVISIBLE, - // Indicates that the frame is either visible now or is likely to be visible - // soon according to our heuristics. As with APPROXIMATELY_NONVISIBLE, it's - // important to note that approximately visibility is not updated - // synchronously, so this information may be out of date. - APPROXIMATELY_VISIBLE + // This frame is nonvisible now, but our heuristics tell us it may become + // visible soon. These heuristics are updated on a relatively slow timer, so a + // frame being marked MAY_BECOME_VISIBLE does not imply any particular + // relationship between the frame and the displayport. + MAY_BECOME_VISIBLE, + + // This frame was within the displayport as of the last paint. That doesn't + // necessarily mean that the frame is visible - it may still lie outside the + // viewport - but it does mean that the user may scroll the frame into view + // asynchronously at any time (due to APZ), so for most purposes such a frame + // should be treated as truly visible. + IN_DISPLAYPORT +}; + +// The subset of the states in @Visibility which have a per-frame counter. This +// is used in the implementation of visibility tracking. +enum class VisibilityCounter : uint8_t +{ + MAY_BECOME_VISIBLE, + IN_DISPLAYPORT }; // Requested actions when frames transition to the nonvisible state. diff --git a/layout/generic/VisibilityIPC.h b/layout/generic/VisibilityIPC.h new file mode 100644 index 0000000000..d874a53e14 --- /dev/null +++ b/layout/generic/VisibilityIPC.h @@ -0,0 +1,45 @@ +/* -*- 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/. */ + +/** + * Declares IPC serializers for the visibility-related types in Visibility.h. + * These are separated out to reduce the number of moz.build files that need to + * include chromium IPC headers, since Visibility.h is included from nsIFrame.h + * which is widely included. + */ + +#ifndef mozilla_layout_generic_VisibilityIPC_h +#define mozilla_layout_generic_VisibilityIPC_h + +#include "ipc/IPCMessageUtils.h" + +#include "Visibility.h" + +namespace IPC { + +template<> +struct ParamTraits +{ + typedef mozilla::VisibilityCounter paramType; + + static void Write(Message* aMsg, const paramType& aParam) + { + WriteParam(aMsg, uint8_t(aParam)); + } + + static bool Read(const Message* aMsg, void** aIter, paramType* aResult) + { + uint8_t valueAsByte; + if (ReadParam(aMsg, aIter, &valueAsByte)) { + *aResult = paramType(valueAsByte); + return true; + } + return false; + } +}; + +} // namespace IPC + +#endif // mozilla_layout_generic_VisibilityIPC_h diff --git a/layout/generic/moz.build b/layout/generic/moz.build index c8d0bd2530..25cb57e631 100644 --- a/layout/generic/moz.build +++ b/layout/generic/moz.build @@ -98,6 +98,7 @@ EXPORTS += [ 'ScrollbarActivity.h', 'ScrollSnap.h', 'Visibility.h', + 'VisibilityIPC.h', ] EXPORTS.mozilla += [ diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp index b7b2ad0b1b..d15a7a7909 100644 --- a/layout/generic/nsFlexContainerFrame.cpp +++ b/layout/generic/nsFlexContainerFrame.cpp @@ -78,6 +78,89 @@ kAxisOrientationToSidesMap[eNumAxisOrientationTypes][eNumAxisEdges] = { // Helper structs / classes / methods // ================================== +// Returns true iff the given nsStyleDisplay has display:-webkit-{inline-}-box. +static inline bool +IsDisplayValueLegacyBox(const nsStyleDisplay* aStyleDisp) +{ + return aStyleDisp->mDisplay == NS_STYLE_DISPLAY_WEBKIT_BOX || + aStyleDisp->mDisplay == NS_STYLE_DISPLAY_WEBKIT_INLINE_BOX; +} + +// Helper to check whether our nsFlexContainerFrame is emulating a legacy +// -webkit-{inline-}box, in which case we should use legacy CSS properties +// instead of the modern ones. The params are are the nsStyleDisplay and the +// nsStyleContext associated with the nsFlexContainerFrame itself. +static inline bool +IsLegacyBox(const nsStyleDisplay* aStyleDisp, + nsStyleContext* aStyleContext) +{ + // Trivial case: just check "display" directly. + if (IsDisplayValueLegacyBox(aStyleDisp)) { + return true; + } + + // If this frame is for a scrollable element, then it will actually have + // "display:block", and its *parent* will have the real flex-flavored display + // value. So in that case, check the parent to find out if we're legacy. + if (aStyleDisp->mDisplay == NS_STYLE_DISPLAY_BLOCK) { + nsStyleContext* parentStyleContext = aStyleContext->GetParent(); + NS_ASSERTION(parentStyleContext && + aStyleContext->GetPseudo() == nsCSSAnonBoxes::scrolledContent, + "The only way a nsFlexContainerFrame can have 'display:block' " + "should be if it's the inner part of a scrollable element"); + if (IsDisplayValueLegacyBox(parentStyleContext->StyleDisplay())) { + return true; + } + } + + return false; +} + +// Returns the "align-items" value that's equivalent to the legacy "box-align" +// value in the given style struct. +static uint8_t +ConvertLegacyStyleToAlignItems(const nsStyleXUL* aStyleXUL) +{ + // -[moz|webkit]-box-align corresponds to modern "align-items" + switch (aStyleXUL->mBoxAlign) { + case NS_STYLE_BOX_ALIGN_STRETCH: + return NS_STYLE_ALIGN_STRETCH; + case NS_STYLE_BOX_ALIGN_START: + return NS_STYLE_ALIGN_FLEX_START; + case NS_STYLE_BOX_ALIGN_CENTER: + return NS_STYLE_ALIGN_CENTER; + case NS_STYLE_BOX_ALIGN_BASELINE: + return NS_STYLE_ALIGN_BASELINE; + case NS_STYLE_BOX_ALIGN_END: + return NS_STYLE_ALIGN_FLEX_END; + } + + MOZ_ASSERT_UNREACHABLE("Unrecognized mBoxAlign enum value"); + // Fall back to default value of "align-items" property: + return NS_STYLE_ALIGN_STRETCH; +} + +// Returns the "justify-content" value that's equivalent to the legacy +// "box-pack" value in the given style struct. +static uint8_t +ConvertLegacyStyleToJustifyContent(const nsStyleXUL* aStyleXUL) +{ + // -[moz|webkit]-box-pack corresponds to modern "justify-content" + switch (aStyleXUL->mBoxPack) { + case NS_STYLE_BOX_PACK_START: + return NS_STYLE_ALIGN_FLEX_START; + case NS_STYLE_BOX_PACK_CENTER: + return NS_STYLE_ALIGN_CENTER; + case NS_STYLE_BOX_PACK_END: + return NS_STYLE_ALIGN_FLEX_END; + case NS_STYLE_BOX_PACK_JUSTIFY: + return NS_STYLE_ALIGN_SPACE_BETWEEN; + } + + MOZ_ASSERT_UNREACHABLE("Unrecognized mBoxPack enum value"); + // Fall back to default value of "justify-content" property: + return NS_STYLE_ALIGN_FLEX_START; +} // Indicates whether advancing along the given axis is equivalent to // increasing our X or Y position (as opposed to decreasing it). @@ -156,7 +239,7 @@ PhysicalCoordFromFlexRelativeCoord(nscoord aFlexRelativeCoord, // Encapsulates our flex container's main & cross axes. class MOZ_STACK_CLASS nsFlexContainerFrame::FlexboxAxisTracker { public: - FlexboxAxisTracker(const nsStylePosition* aStylePosition, + FlexboxAxisTracker(const nsFlexContainerFrame* aFlexContainer, const WritingMode& aWM); // Accessors: @@ -287,6 +370,15 @@ private: FlexboxAxisTracker(const FlexboxAxisTracker&) = delete; FlexboxAxisTracker& operator=(const FlexboxAxisTracker&) = delete; + // Helpers for constructor which determine the orientation of our axes, based + // on legacy box properties (-webkit-box-orient, -webkit-box-direction) or + // modern flexbox properties (flex-direction, flex-wrap) depending on whether + // the flex container is a "legacy box" (as determined by IsLegacyBox). + void InitAxesFromLegacyProps(const nsFlexContainerFrame* aFlexContainer, + const WritingMode& aWM); + void InitAxesFromModernProps(const nsFlexContainerFrame* aFlexContainer, + const WritingMode& aWM); + // XXXdholbert [BEGIN DEPRECATED] AxisOrientationType mMainAxis; AxisOrientationType mCrossAxis; @@ -890,6 +982,29 @@ BuildStrutInfoFromCollapsedItems(const FlexLine* aFirstLine, } } +// Convenience function to get either the "order" or the "box-ordinal-group" +// property-value for a flex item (depending on whether the container is a +// modern flex container or a legacy box). +static int32_t +GetOrderOrBoxOrdinalGroup(nsIFrame* aFlexItem, bool aIsLegacyBox) +{ + if (aIsLegacyBox) { + // We'll be using mBoxOrdinal, which has type uint32_t. However, the modern + // 'order' property (whose functionality we're co-opting) has type int32_t. + // So: if we happen to have a uint32_t value that's greater than INT32_MAX, + // we clamp it rather than letting it overflow. Chances are, this is just + // an author using BIG_VALUE anyway, so the clamped value should be fine. + // (particularly since sufficiently-huge values are busted in Chrome/WebKit + // per https://bugs.chromium.org/p/chromium/issues/detail?id=599645 ) + uint32_t clampedBoxOrdinal = std::min(aFlexItem->StyleXUL()->mBoxOrdinal, + static_cast(INT32_MAX)); + return static_cast(clampedBoxOrdinal); + } + + // Normal case: just use modern 'order' property. + return aFlexItem->StylePosition()->mOrder; +} + // Helper-function to find the first non-anonymous-box descendent of aFrame. static nsIFrame* GetFirstNonAnonBoxDescendant(nsIFrame* aFrame) @@ -954,6 +1069,11 @@ IsOrderLEQWithDOMFallback(nsIFrame* aFrame1, { MOZ_ASSERT(aFrame1->IsFlexItem() && aFrame2->IsFlexItem(), "this method only intended for comparing flex items"); + MOZ_ASSERT(aFrame1->GetParent() == aFrame2->GetParent(), + "this method only intended for comparing siblings"); + nsStyleContext* parentFrameSC = aFrame1->GetParent()->StyleContext(); + bool isInLegacyBox = IsLegacyBox(parentFrameSC->StyleDisplay(), + parentFrameSC); if (aFrame1 == aFrame2) { // Anything is trivially LEQ itself, so we return "true" here... but it's @@ -967,8 +1087,8 @@ IsOrderLEQWithDOMFallback(nsIFrame* aFrame1, nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1); nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2); - int32_t order1 = aRealFrame1->StylePosition()->mOrder; - int32_t order2 = aRealFrame2->StylePosition()->mOrder; + int32_t order1 = GetOrderOrBoxOrdinalGroup(aRealFrame1, isInLegacyBox); + int32_t order2 = GetOrderOrBoxOrdinalGroup(aRealFrame2, isInLegacyBox); if (order1 != order2) { return order1 < order2; @@ -1035,13 +1155,18 @@ IsOrderLEQ(nsIFrame* aFrame1, { MOZ_ASSERT(aFrame1->IsFlexItem() && aFrame2->IsFlexItem(), "this method only intended for comparing flex items"); + MOZ_ASSERT(aFrame1->GetParent() == aFrame2->GetParent(), + "this method only intended for comparing siblings"); + nsStyleContext* parentFrameSC = aFrame1->GetParent()->StyleContext(); + bool isInLegacyBox = IsLegacyBox(parentFrameSC->StyleDisplay(), + parentFrameSC); // If we've got a placeholder frame, use its out-of-flow frame's 'order' val. nsIFrame* aRealFrame1 = nsPlaceholderFrame::GetRealFrameFor(aFrame1); nsIFrame* aRealFrame2 = nsPlaceholderFrame::GetRealFrameFor(aFrame2); - int32_t order1 = aRealFrame1->StylePosition()->mOrder; - int32_t order2 = aRealFrame2->StylePosition()->mOrder; + int32_t order1 = GetOrderOrBoxOrdinalGroup(aRealFrame1, isInLegacyBox); + int32_t order2 = GetOrderOrBoxOrdinalGroup(aRealFrame2, isInLegacyBox); return order1 <= order2; } @@ -1049,7 +1174,7 @@ IsOrderLEQ(nsIFrame* aFrame1, bool nsFlexContainerFrame::IsHorizontal() { - const FlexboxAxisTracker axisTracker(StylePosition(), GetWritingMode()); + const FlexboxAxisTracker axisTracker(this, GetWritingMode()); return axisTracker.IsMainAxisHorizontal(); } @@ -1069,9 +1194,15 @@ nsFlexContainerFrame::GenerateFlexItemForChild( // FLEX GROW & SHRINK WEIGHTS // -------------------------- - const nsStylePosition* stylePos = aChildFrame->StylePosition(); - float flexGrow = stylePos->mFlexGrow; - float flexShrink = stylePos->mFlexShrink; + float flexGrow, flexShrink; + if (IsLegacyBox(aParentReflowState.mStyleDisplay, mStyleContext)) { + flexGrow = flexShrink = aChildFrame->StyleXUL()->mBoxFlex; + } else { + const nsStylePosition* stylePos = aChildFrame->StylePosition(); + flexGrow = stylePos->mFlexGrow; + flexShrink = stylePos->mFlexShrink; + } + WritingMode childWM = childRS.GetWritingMode(); // MAIN SIZES (flex base size, min/max size) @@ -1576,14 +1707,28 @@ FlexItem::FlexItem(nsHTMLReflowState& aFlexItemReflowState, MOZ_ASSERT(!(mFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW), "out-of-flow frames should not be treated as flex items"); - mAlignSelf = aFlexItemReflowState.mStylePosition->ComputedAlignSelf( - mFrame->StyleContext()->GetParent()); - if (MOZ_LIKELY(mAlignSelf == NS_STYLE_ALIGN_NORMAL)) { - mAlignSelf = NS_STYLE_ALIGN_STRETCH; - } + const nsHTMLReflowState* containerRS = aFlexItemReflowState.parentReflowState; + if (IsLegacyBox(containerRS->mStyleDisplay, + containerRS->frame->StyleContext())) { + // For -webkit-box/-webkit-inline-box, we need to: + // (1) Use "-webkit-box-align" instead of "align-items" to determine the + // container's cross-axis alignment behavior. + // (2) Suppress the ability for flex items to override that with their own + // cross-axis alignment. (The legacy box model doesn't support this.) + // So, each FlexItem simply copies the container's converted "align-items" + // value and disregards their own "align-self" property. + const nsStyleXUL* containerStyleXUL = containerRS->frame->StyleXUL(); + mAlignSelf = ConvertLegacyStyleToAlignItems(containerStyleXUL); + } else { + mAlignSelf = aFlexItemReflowState.mStylePosition->ComputedAlignSelf( + mFrame->StyleContext()->GetParent()); + if (MOZ_LIKELY(mAlignSelf == NS_STYLE_ALIGN_NORMAL)) { + mAlignSelf = NS_STYLE_ALIGN_STRETCH; + } - // XXX strip off the bit until we implement that - mAlignSelf &= ~NS_STYLE_ALIGN_FLAG_BITS; + // XXX strip off the bit until we implement that + mAlignSelf &= ~NS_STYLE_ALIGN_FLAG_BITS; + } SetFlexBaseSizeAndMainSize(aFlexBaseSize); CheckForMinSizeAuto(aFlexItemReflowState, aAxisTracker); @@ -1940,7 +2085,7 @@ public: NS_QUERYFRAME_HEAD(nsFlexContainerFrame) NS_QUERYFRAME_ENTRY(nsFlexContainerFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsFlexContainerFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) NS_IMPL_FRAMEARENA_HELPERS(nsFlexContainerFrame) @@ -3058,12 +3203,92 @@ BlockDirToAxisOrientation(WritingMode::BlockDir aBlockDir) return eAxis_TB; // in case of unforseen error, assume English TTB block-flow } -FlexboxAxisTracker::FlexboxAxisTracker(const nsStylePosition* aStylePosition, - const WritingMode& aWM) +FlexboxAxisTracker::FlexboxAxisTracker( + const nsFlexContainerFrame* aFlexContainer, + const WritingMode& aWM) : mWM(aWM), mAreAxesInternallyReversed(false) { - uint32_t flexDirection = aStylePosition->mFlexDirection; + if (IsLegacyBox(aFlexContainer->StyleDisplay(), + aFlexContainer->StyleContext())) { + InitAxesFromLegacyProps(aFlexContainer, aWM); + } else { + InitAxesFromModernProps(aFlexContainer, aWM); + } + + // Master switch to enable/disable bug 983427's code for reversing our axes + // and reversing some logic, to avoid reflowing children in bottom-to-top + // order. (This switch can be removed eventually, but for now, it allows + // this special-case code path to be compared against the normal code path.) + static bool sPreventBottomToTopChildOrdering = true; + + if (sPreventBottomToTopChildOrdering) { + // If either axis is bottom-to-top, we flip both axes (and set a flag + // so that we can flip some logic to make the reversal transparent). + if (eAxis_BT == mMainAxis || eAxis_BT == mCrossAxis) { + mMainAxis = GetReverseAxis(mMainAxis); + mCrossAxis = GetReverseAxis(mCrossAxis); + mAreAxesInternallyReversed = true; + mIsMainAxisReversed = !mIsMainAxisReversed; + mIsCrossAxisReversed = !mIsCrossAxisReversed; + } + } +} + +void +FlexboxAxisTracker::InitAxesFromLegacyProps( + const nsFlexContainerFrame* aFlexContainer, + const WritingMode& aWM) +{ + const nsStyleXUL* styleXUL = aFlexContainer->StyleXUL(); + + const bool boxOrientIsVertical = (styleXUL->mBoxOrient == + NS_STYLE_BOX_ORIENT_VERTICAL); + const bool wmIsVertical = aWM.IsVertical(); + + // If box-orient agrees with our writing-mode, then we're "row-oriented" + // (i.e. the flexbox main axis is the same as our writing mode's inline + // direction). Otherwise, we're column-oriented (i.e. the flexbox's main + // axis is perpendicular to the writing-mode's inline direction). + mIsRowOriented = (boxOrientIsVertical == wmIsVertical); + + // XXXdholbert BEGIN CODE TO SET DEPRECATED MEMBER-VARS + if (boxOrientIsVertical) { + mMainAxis = eAxis_TB; + mCrossAxis = eAxis_LR; + } else { + mMainAxis = eAxis_LR; + mCrossAxis = eAxis_TB; + } + // "direction: rtl" (in a horizontal -webkit-box) reverses the main axis. + // (Note this we don't toggle "mIsMainAxisReversed" for this condition, + // because the main axis will still match aWM's inline direction.) + if (aWM.IsBidiLTR()) { + mMainAxis = GetReverseAxis(mMainAxis); + } + // XXXdholbert END CODE TO SET DEPRECATED MEMBER-VARS + + // Legacy flexbox can use "-webkit-box-direction: reverse" to reverse the + // main axis (so it runs in the reverse direction of the inline axis): + if (styleXUL->mBoxDirection == NS_STYLE_BOX_DIRECTION_REVERSE) { + mMainAxis = GetReverseAxis(mMainAxis); + mIsMainAxisReversed = true; + } else { + mIsMainAxisReversed = false; + } + + // Legacy flexbox does not support reversing the cross axis -- it has no + // equivalent of modern flexbox's "flex-wrap: wrap-reverse". + mIsCrossAxisReversed = false; +} + +void +FlexboxAxisTracker::InitAxesFromModernProps( + const nsFlexContainerFrame* aFlexContainer, + const WritingMode& aWM) +{ + const nsStylePosition* stylePos = aFlexContainer->StylePosition(); + uint32_t flexDirection = stylePos->mFlexDirection; // Inline dimension ("start-to-end"): // (NOTE: I'm intentionally not calling these "inlineAxis"/"blockAxis", since @@ -3111,30 +3336,12 @@ FlexboxAxisTracker::FlexboxAxisTracker(const nsStylePosition* aStylePosition, } // "flex-wrap: wrap-reverse" reverses our cross axis. - if (aStylePosition->mFlexWrap == NS_STYLE_FLEX_WRAP_WRAP_REVERSE) { + if (stylePos->mFlexWrap == NS_STYLE_FLEX_WRAP_WRAP_REVERSE) { mCrossAxis = GetReverseAxis(mCrossAxis); mIsCrossAxisReversed = true; } else { mIsCrossAxisReversed = false; } - - // Master switch to enable/disable bug 983427's code for reversing our axes - // and reversing some logic, to avoid reflowing children in bottom-to-top - // order. (This switch can be removed eventually, but for now, it allows - // this special-case code path to be compared against the normal code path.) - static bool sPreventBottomToTopChildOrdering = true; - - if (sPreventBottomToTopChildOrdering) { - // If either axis is bottom-to-top, we flip both axes (and set a flag - // so that we can flip some logic to make the reversal transparent). - if (eAxis_BT == mMainAxis || eAxis_BT == mCrossAxis) { - mMainAxis = GetReverseAxis(mMainAxis); - mCrossAxis = GetReverseAxis(mCrossAxis); - mAreAxesInternallyReversed = true; - mIsMainAxisReversed = !mIsMainAxisReversed; - mIsCrossAxisReversed = !mIsCrossAxisReversed; - } - } } // Allocates a new FlexLine, adds it to the given LinkedList (at the front or @@ -3647,8 +3854,7 @@ nsFlexContainerFrame::Reflow(nsPresContext* aPresContext, SortChildrenIfNeeded(); } - const FlexboxAxisTracker axisTracker(aReflowState.mStylePosition, - aReflowState.GetWritingMode()); + const FlexboxAxisTracker axisTracker(this, aReflowState.GetWritingMode()); // If we're being fragmented into a constrained BSize, then subtract off // borderpadding BStart from that constrained BSize, to get the available @@ -3858,11 +4064,14 @@ nsFlexContainerFrame::DoFlexLayout(nsPresContext* aPresContext, } } - for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) { + const auto justifyContent = IsLegacyBox(aReflowState.mStyleDisplay, + mStyleContext) ? + ConvertLegacyStyleToJustifyContent(StyleXUL()) : + aReflowState.mStylePosition->ComputedJustifyContent(); + for (FlexLine* line = lines.getFirst(); line; line = line->getNext()) { // Main-Axis Alignment - Flexbox spec section 9.5 // ============================================== - auto justifyContent = aReflowState.mStylePosition->ComputedJustifyContent(); line->PositionItemsInMainAxis(justifyContent, aContentBoxMainSize, aAxisTracker); @@ -4069,6 +4278,7 @@ nsFlexContainerFrame::MoveFlexItemToFinalPosition( logicalOffsets, &aFramePos, aContainerSize); aItem.Frame()->SetPosition(outerWM, aFramePos, aContainerSize); + PositionFrameView(aItem.Frame()); PositionChildViews(aItem.Frame()); } @@ -4186,7 +4396,7 @@ nsFlexContainerFrame::GetMinISize(nsRenderingContext* aRenderingContext) DISPLAY_MIN_WIDTH(this, minWidth); const nsStylePosition* stylePos = StylePosition(); - const FlexboxAxisTracker axisTracker(stylePos, GetWritingMode()); + const FlexboxAxisTracker axisTracker(this, GetWritingMode()); for (nsIFrame* childFrame : mFrames) { nscoord childMinWidth = @@ -4217,7 +4427,7 @@ nsFlexContainerFrame::GetPrefISize(nsRenderingContext* aRenderingContext) // Whenever anything happens that might change it, set it to // NS_INTRINSIC_WIDTH_UNKNOWN (like nsBlockFrame::MarkIntrinsicISizesDirty // does) - const FlexboxAxisTracker axisTracker(StylePosition(), GetWritingMode()); + const FlexboxAxisTracker axisTracker(this, GetWritingMode()); for (nsIFrame* childFrame : mFrames) { nscoord childPrefWidth = diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index ee24052c2c..6153ce0c68 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -5,7 +5,7 @@ * version 2.0 (the "License"). You can obtain a copy of the License at * http://mozilla.org/MPL/2.0/. */ -/* rendering object for CSS "display: flex" */ +/* rendering object for CSS "display: flex" and "display: -webkit-box" */ #ifndef nsFlexContainerFrame_h___ #define nsFlexContainerFrame_h___ @@ -20,9 +20,27 @@ class LogicalPoint; nsContainerFrame* NS_NewFlexContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); -typedef nsContainerFrame nsFlexContainerFrameSuper; -class nsFlexContainerFrame : public nsFlexContainerFrameSuper { +/** + * This is the rendering object used for laying out elements with + * "display: flex" or "display: inline-flex". + * + * We also use this class for elements with "display: -webkit-box" or + * "display: -webkit-inline-box" (but not "-moz-box" / "-moz-inline-box" -- + * those are rendered with old-school XUL frame classes). + * + * Note: we represent the -webkit-box family of properties (-webkit-box-orient, + * -webkit-box-flex, etc.) as aliases for their -moz equivalents. And for + * -webkit-{inline-}box containers, nsFlexContainerFrame will honor those + * "legacy" properties for alignment/flexibility/etc. *instead of* honoring the + * modern flexbox & alignment properties. For brevity, many comments in + * nsFlexContainerFrame.cpp simply refer to these properties using their + * "-webkit" versions, since we're mostly expecting to encounter them in that + * form. (Technically, the "-moz" versions of these properties *can* influence + * layout here as well (since that's what the -webkit versions are aliased to) + * -- but only inside of a "display:-webkit-{inline-}box" container.) + */ +class nsFlexContainerFrame : public nsContainerFrame { public: NS_DECL_FRAMEARENA_HELPERS NS_DECL_QUERYFRAME_TARGET(nsFlexContainerFrame) @@ -62,8 +80,8 @@ public: protected: // Protected constructor & destructor - explicit nsFlexContainerFrame(nsStyleContext* aContext) : - nsFlexContainerFrameSuper(aContext) + explicit nsFlexContainerFrame(nsStyleContext* aContext) + : nsContainerFrame(aContext) {} virtual ~nsFlexContainerFrame(); diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index f6a29413e5..84ba0ef4dd 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -414,7 +414,7 @@ nsFrame::~nsFrame() { MOZ_COUNT_DTOR(nsFrame); - MOZ_ASSERT(GetVisibility() != Visibility::APPROXIMATELY_VISIBLE, + MOZ_ASSERT(!IsVisibleOrMayBecomeVisibleSoon(), "Visible nsFrame is being destroyed"); NS_IF_RELEASE(mContent); @@ -553,7 +553,7 @@ nsFrame::Init(nsIContent* aContent, if (HasAnyStateBits(NS_FRAME_IN_POPUP) && TrackingVisibility()) { // Assume all frames in popups are visible. - IncApproximateVisibleCount(); + IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT); } } const nsStyleDisplay *disp = StyleDisplay(); @@ -606,7 +606,7 @@ nsFrame::Init(nsIContent* aContent, if (PresContext()->PresShell()->AssumeAllFramesVisible() && TrackingVisibility()) { - IncApproximateVisibleCount(); + IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT); } DidSetStyleContext(nullptr); @@ -733,8 +733,8 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot) // frame reconstruction induced by style changes. DisableVisibilityTracking(); - // Ensure that we're not in the approximately visible list anymore. - PresContext()->GetPresShell()->RemoveFrameFromApproximatelyVisibleList(this); + // Ensure that we're not in the visible list anymore. + PresContext()->GetPresShell()->MarkFrameNonvisible(this); shell->NotifyDestroyingFrame(this); @@ -1476,6 +1476,18 @@ nsIFrame::GetCrossDocChildLists(nsTArray* aLists) GetChildLists(aLists); } +static Visibility +VisibilityStateAsVisibility(const nsIFrame::VisibilityState& aState) +{ + if (aState.mInDisplayPortCounter > 0) { + return Visibility::IN_DISPLAYPORT; // Takes priority over MAY_BECOME_VISIBLE. + } + if (aState.mApproximateCounter > 0) { + return Visibility::MAY_BECOME_VISIBLE; + } + return Visibility::NONVISIBLE; +} + Visibility nsIFrame::GetVisibility() const { @@ -1485,14 +1497,12 @@ nsIFrame::GetVisibility() const bool isSet = false; FrameProperties props = Properties(); - uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet); + VisibilityState state = props.Get(VisibilityStateProperty(), &isSet); MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"); - return visibleCount > 0 - ? Visibility::APPROXIMATELY_VISIBLE - : Visibility::APPROXIMATELY_NONVISIBLE; + return VisibilityStateAsVisibility(state); } void @@ -1504,7 +1514,7 @@ nsIFrame::UpdateVisibilitySynchronously() } if (presShell->AssumeAllFramesVisible()) { - presShell->EnsureFrameInApproximatelyVisibleList(this); + presShell->MarkFrameVisibleInDisplayPort(this); return; } @@ -1545,9 +1555,9 @@ nsIFrame::UpdateVisibilitySynchronously() } if (visible) { - presShell->EnsureFrameInApproximatelyVisibleList(this); + presShell->MarkFrameVisibleInDisplayPort(this); } else { - presShell->RemoveFrameFromApproximatelyVisibleList(this); + presShell->MarkFrameNonvisible(this); } } @@ -1566,7 +1576,7 @@ nsIFrame::EnableVisibilityTracking() // Add the state bit so we know to track visibility for this frame, and // initialize the frame property. AddStateBits(NS_FRAME_VISIBILITY_IS_TRACKED); - props.Set(VisibilityStateProperty(), 0); + props.Set(VisibilityStateProperty(), VisibilityState{0, 0}); nsIPresShell* presShell = PresContext()->PresShell(); if (!presShell) { @@ -1589,66 +1599,87 @@ nsIFrame::DisableVisibilityTracking() bool isSet = false; FrameProperties props = Properties(); - uint32_t visibleCount = props.Remove(VisibilityStateProperty(), &isSet); + VisibilityState state = props.Remove(VisibilityStateProperty(), &isSet); MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"); RemoveStateBits(NS_FRAME_VISIBILITY_IS_TRACKED); - if (visibleCount == 0) { - return; // We were nonvisible. + Visibility previousVisibility = VisibilityStateAsVisibility(state); + if (previousVisibility == Visibility::NONVISIBLE) { + return; // We were already nonvisible. } // We were visible, so send an OnVisibilityChange() notification. - OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE); + OnVisibilityChange(Visibility::NONVISIBLE); } void -nsIFrame::DecApproximateVisibleCount(Maybe aNonvisibleAction - /* = Nothing() */) +nsIFrame::DecVisibilityCount(VisibilityCounter aCounter, + Maybe aNonvisibleAction /* = Nothing() */) { MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED); bool isSet = false; FrameProperties props = Properties(); - uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet); + VisibilityState state = props.Get(VisibilityStateProperty(), &isSet); MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"); - MOZ_ASSERT(visibleCount > 0, "Frame is already nonvisible and we're " - "decrementing its visible count?"); + MOZ_ASSERT_IF(aCounter == VisibilityCounter::MAY_BECOME_VISIBLE, + state.mApproximateCounter > 0); + MOZ_ASSERT_IF(aCounter == VisibilityCounter::IN_DISPLAYPORT, + state.mInDisplayPortCounter > 0); - visibleCount--; - props.Set(VisibilityStateProperty(), visibleCount); - if (visibleCount > 0) { - return; + Visibility previousVisibility = VisibilityStateAsVisibility(state); + + if (aCounter == VisibilityCounter::MAY_BECOME_VISIBLE) { + state.mApproximateCounter--; + } else { + state.mInDisplayPortCounter--; } - // We just became nonvisible, so send an OnVisibilityChange() notification. - OnVisibilityChange(Visibility::APPROXIMATELY_NONVISIBLE, aNonvisibleAction); + props.Set(VisibilityStateProperty(), state); + + Visibility newVisibility = VisibilityStateAsVisibility(state); + if (newVisibility == previousVisibility) { + return; // Nothing changed. + } + + // Our visibility just changed, so send an OnVisibilityChange() notification. + OnVisibilityChange(newVisibility, aNonvisibleAction); } void -nsIFrame::IncApproximateVisibleCount() +nsIFrame::IncVisibilityCount(VisibilityCounter aCounter) { MOZ_ASSERT(GetStateBits() & NS_FRAME_VISIBILITY_IS_TRACKED); bool isSet = false; FrameProperties props = Properties(); - uint32_t visibleCount = props.Get(VisibilityStateProperty(), &isSet); + VisibilityState state = props.Get(VisibilityStateProperty(), &isSet); MOZ_ASSERT(isSet, "Should have a VisibilityStateProperty value " "if NS_FRAME_VISIBILITY_IS_TRACKED is set"); - visibleCount++; - props.Set(VisibilityStateProperty(), visibleCount); - if (visibleCount > 1) { - return; + Visibility previousVisibility = VisibilityStateAsVisibility(state); + + if (aCounter == VisibilityCounter::MAY_BECOME_VISIBLE) { + state.mApproximateCounter++; + } else { + state.mInDisplayPortCounter++; } - // We just became visible, so send an OnVisibilityChange() notification. - OnVisibilityChange(Visibility::APPROXIMATELY_VISIBLE); + props.Set(VisibilityStateProperty(), state); + + Visibility newVisibility = VisibilityStateAsVisibility(state); + if (newVisibility == previousVisibility) { + return; // Nothing changed. + } + + // Our visibility just changed, so send an OnVisibilityChange() notification. + OnVisibilityChange(newVisibility); } void @@ -2683,6 +2714,14 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance)) return; + // Since we're now sure that we're adding this frame to the display list + // (which means we're painting it, modulo occlusion), mark it as visible + // within the displayport. + if (aBuilder->IsPaintingToWindow() && child->TrackingVisibility()) { + nsIPresShell* shell = child->PresContext()->PresShell(); + shell->MarkFrameVisibleInDisplayPort(child); + } + // Child is composited if it's transformed, partially transparent, or has // SVG effects or a blend mode.. const nsStyleDisplay* disp = child->StyleDisplay(); @@ -9166,7 +9205,7 @@ nsIFrame::AddInPopupStateBitToDescendants(nsIFrame* aFrame) if (!aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP) && aFrame->TrackingVisibility()) { // Assume all frames in popups are visible. - aFrame->IncApproximateVisibleCount(); + aFrame->IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT); } aFrame->AddStateBits(NS_FRAME_IN_POPUP); @@ -9196,7 +9235,7 @@ nsIFrame::RemoveInPopupStateBitFromDescendants(nsIFrame* aFrame) if (aFrame->TrackingVisibility()) { // We assume all frames in popups are visible, so this decrement balances // out the increment in AddInPopupStateBitToDescendants above. - aFrame->DecApproximateVisibleCount(); + aFrame->DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT); } AutoTArray childListArray; diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h index 86f6c6da09..35c987235d 100644 --- a/layout/generic/nsIFrame.h +++ b/layout/generic/nsIFrame.h @@ -424,6 +424,7 @@ public: template using PropertyDescriptor = const mozilla::FramePropertyDescriptor*; using Visibility = mozilla::Visibility; + using VisibilityCounter = mozilla::VisibilityCounter; typedef mozilla::FrameProperties FrameProperties; typedef mozilla::layers::Layer Layer; @@ -1106,6 +1107,15 @@ public: /// for the possible return values and their meanings. Visibility GetVisibility() const; + /// @return true if this frame is either in the displayport now or may + /// become visible soon. + bool IsVisibleOrMayBecomeVisibleSoon() const + { + Visibility visibility = GetVisibility(); + return visibility == Visibility::MAY_BECOME_VISIBLE || + visibility == Visibility::IN_DISPLAYPORT; + } + /// Update the visibility state of this frame synchronously. /// XXX(seth): Avoid using this method; we should be relying on the refresh /// driver for visibility updates. This method, which replaces @@ -1114,11 +1124,17 @@ public: /// the old image visibility code. void UpdateVisibilitySynchronously(); - // A frame property which stores the visibility state of this frame. Right - // now that consists of an approximate visibility counter represented as a - // uint32_t. When the visibility of this frame is not being tracked, this - // property is absent. - NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(VisibilityStateProperty, uint32_t); + struct VisibilityState + { + unsigned int mApproximateCounter : 16; + unsigned int mInDisplayPortCounter : 16; + }; + + // A frame property which stores the visibility state of this frame, which + // consists of a VisibilityState value that stores counters for each type of + // visibility we track. When the visibility of this frame is not being + // tracked, this property is absent. + NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(VisibilityStateProperty, VisibilityState); protected: @@ -1163,12 +1179,19 @@ public: /////////////////////////////////////////////////////////////////////////////// /** - * We track the approximate visibility of frames using a counter; if it's - * non-zero, then the frame is considered visible. Using a counter allows us - * to account for situations where the frame may be visible in more than one - * place (for example, via -moz-element), and it simplifies the + * We track the visibility of frames using counters; if any of the counters + * are non-zero, then the frame is considered visible. Using counters allows + * us to account for situations where the frame may be visible in more than + * one place (for example, via -moz-element), and it simplifies the * implementation of our approximate visibility tracking algorithms. * + * There are two visibility counters for each frame: the approximate counter + * (which is based on our heuristics for which frames may become visible + * "soon"), and the in-displayport counter (which records if the frame was + * within the displayport at the last paint). + * + * + * @param aCounter Which counter to increment or decrement. * @param aNonvisibleAction A requested action if the frame has become * nonvisible. If Nothing(), no action is * requested. If DISCARD_IMAGES is specified, the @@ -1176,8 +1199,9 @@ public: * associated with to discard their surfaces if * possible. */ - void DecApproximateVisibleCount(Maybe aNonvisibleAction = Nothing()); - void IncApproximateVisibleCount(); + void DecVisibilityCount(VisibilityCounter aCounter, + Maybe aNonvisibleAction = Nothing()); + void IncVisibilityCount(VisibilityCounter aCounter); /** diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 3c42ad2ee1..f591d09316 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -136,7 +136,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsImageFrame) nsImageFrame::nsImageFrame(nsStyleContext* aContext) : - ImageFrameSuper(aContext), + nsAtomicContainerFrame(aContext), mComputedSize(0, 0), mIntrinsicRatio(0, 0), mDisplayingIcon(false), @@ -158,7 +158,7 @@ nsImageFrame::~nsImageFrame() NS_QUERYFRAME_HEAD(nsImageFrame) NS_QUERYFRAME_ENTRY(nsImageFrame) -NS_QUERYFRAME_TAIL_INHERITING(ImageFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame) #ifdef ACCESSIBILITY a11y::AccType @@ -222,13 +222,13 @@ nsImageFrame::DestroyFrom(nsIFrame* aDestructRoot) if (mDisplayingIcon) gIconLoad->RemoveIconObserver(this); - ImageFrameSuper::DestroyFrom(aDestructRoot); + nsAtomicContainerFrame::DestroyFrom(aDestructRoot); } void nsImageFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) { - ImageFrameSuper::DidSetStyleContext(aOldStyleContext); + nsAtomicContainerFrame::DidSetStyleContext(aOldStyleContext); if (!mImage) { // We'll pick this change up whenever we do get an image. @@ -258,7 +258,7 @@ nsImageFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) { - ImageFrameSuper::Init(aContent, aParent, aPrevInFlow); + nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow); mListener = new nsImageListener(this); @@ -557,12 +557,12 @@ nsImageFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage) // This is valid and for the current request, so update our stored image // container, orienting according to our style. mImage = nsLayoutUtils::OrientImage(aImage, StyleVisibility()->mImageOrientation); - + intrinsicSizeChanged = UpdateIntrinsicSize(mImage); intrinsicSizeChanged = UpdateIntrinsicRatio(mImage) || intrinsicSizeChanged; } else { // We no longer have a valid image, so release our stored image container. - mImage = nullptr; + mImage = mPrevImage = nullptr; // Have to size to 0,0 so that GetDesiredSize recalculates the size. mIntrinsicSize.width.SetCoordValue(0); @@ -586,6 +586,8 @@ nsImageFrame::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage) // so we're ready to request a decode. MaybeDecodeForPredictedSize(); } + + mPrevImage = nullptr; } return NS_OK; @@ -675,7 +677,7 @@ nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest, intrinsicSizeChanged = UpdateIntrinsicRatio(mImage) || intrinsicSizeChanged; } else { // We no longer have a valid image, so release our stored image container. - mImage = nullptr; + mImage = mPrevImage = nullptr; // Have to size to 0,0 so that GetDesiredSize recalculates the size mIntrinsicSize.width.SetCoordValue(0); @@ -696,6 +698,8 @@ nsImageFrame::NotifyNewCurrentRequest(imgIRequest *aRequest, // so we're ready to request a decode. MaybeDecodeForPredictedSize(); } + + mPrevImage = nullptr; } // Update border+content to account for image change InvalidateFrame(); @@ -714,7 +718,7 @@ nsImageFrame::MaybeDecodeForPredictedSize() return; // We won't draw anything, so no point in decoding. } - if (GetVisibility() != Visibility::APPROXIMATELY_VISIBLE) { + if (!IsVisibleOrMayBecomeVisibleSoon()) { return; // We're not visible, so don't decode. } @@ -1486,7 +1490,8 @@ static void PaintDebugImageMap(nsIFrame* aFrame, DrawTarget* aDrawTarget, void nsDisplayImage::Paint(nsDisplayListBuilder* aBuilder, - nsRenderingContext* aCtx) { + nsRenderingContext* aCtx) +{ uint32_t flags = imgIContainer::FLAG_NONE; if (aBuilder->ShouldSyncDecodeImages()) { flags |= imgIContainer::FLAG_SYNC_DECODE; @@ -1498,6 +1503,17 @@ nsDisplayImage::Paint(nsDisplayListBuilder* aBuilder, DrawResult result = static_cast(mFrame)-> PaintImage(*aCtx, ToReferenceFrame(), mVisibleRect, mImage, flags); + if (result == DrawResult::NOT_READY || + result == DrawResult::INCOMPLETE || + result == DrawResult::TEMPORARY_ERROR) { + // If the current image failed to paint because it's still loading or + // decoding, try painting the previous image. + if (mPrevImage) { + result = static_cast(mFrame)-> + PaintImage(*aCtx, ToReferenceFrame(), mVisibleRect, mPrevImage, flags); + } + } + nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result); } @@ -1692,6 +1708,12 @@ nsImageFrame::PaintImage(nsRenderingContext& aRenderingContext, nsPoint aPt, map->Draw(this, *drawTarget, black, strokeOptions); } + if (result == DrawResult::SUCCESS) { + mPrevImage = aImage; + } else if (result == DrawResult::BAD_IMAGE) { + mPrevImage = nullptr; + } + return result; } @@ -1746,7 +1768,7 @@ nsImageFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, } } else { aLists.Content()->AppendNewToTop(new (aBuilder) - nsDisplayImage(aBuilder, this, mImage)); + nsDisplayImage(aBuilder, this, mImage, mPrevImage)); // If we were previously displaying an icon, we're not anymore if (mDisplayingIcon) { @@ -1998,7 +2020,7 @@ nsImageFrame::HandleEvent(nsPresContext* aPresContext, } } - return ImageFrameSuper::HandleEvent(aPresContext, aEvent, aEventStatus); + return nsAtomicContainerFrame::HandleEvent(aPresContext, aEvent, aEventStatus); } nsresult @@ -2035,8 +2057,8 @@ nsImageFrame::AttributeChanged(int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType) { - nsresult rv = ImageFrameSuper::AttributeChanged(aNameSpaceID, - aAttribute, aModType); + nsresult rv = nsAtomicContainerFrame::AttributeChanged(aNameSpaceID, + aAttribute, aModType); if (NS_FAILED(rv)) { return rv; } @@ -2057,16 +2079,18 @@ nsImageFrame::OnVisibilityChange(Visibility aNewVisibility, nsCOMPtr imageLoader = do_QueryInterface(mContent); if (!imageLoader) { MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent"); + nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction); return; } imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction); - if (aNewVisibility == Visibility::APPROXIMATELY_VISIBLE) { + if (aNewVisibility == Visibility::MAY_BECOME_VISIBLE || + aNewVisibility == Visibility::IN_DISPLAYPORT) { MaybeDecodeForPredictedSize(); } - ImageFrameSuper::OnVisibilityChange(aNewVisibility, aNonvisibleAction); + nsAtomicContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction); } nsIAtom* diff --git a/layout/generic/nsImageFrame.h b/layout/generic/nsImageFrame.h index 175b9b019c..404eda8f40 100644 --- a/layout/generic/nsImageFrame.h +++ b/layout/generic/nsImageFrame.h @@ -58,10 +58,8 @@ private: nsImageFrame *mFrame; }; -typedef nsAtomicContainerFrame ImageFrameSuper; - -class nsImageFrame : public ImageFrameSuper, - public nsIReflowCallback { +class nsImageFrame : public nsAtomicContainerFrame + , public nsIReflowCallback { public: template using Maybe = mozilla::Maybe; using Nothing = mozilla::Nothing; @@ -119,7 +117,7 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { - return ImageFrameSuper::IsFrameOfType(aFlags & + return nsAtomicContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing)); } @@ -333,6 +331,7 @@ private: nsCOMPtr mListener; nsCOMPtr mImage; + nsCOMPtr mPrevImage; nsSize mComputedSize; mozilla::IntrinsicSize mIntrinsicSize; nsSize mIntrinsicRatio; @@ -413,8 +412,11 @@ public: typedef mozilla::layers::LayerManager LayerManager; nsDisplayImage(nsDisplayListBuilder* aBuilder, nsImageFrame* aFrame, - imgIContainer* aImage) - : nsDisplayImageContainer(aBuilder, aFrame), mImage(aImage) { + imgIContainer* aImage, imgIContainer* aPrevImage) + : nsDisplayImageContainer(aBuilder, aFrame) + , mImage(aImage) + , mPrevImage(aPrevImage) + { MOZ_COUNT_CTOR(nsDisplayImage); } virtual ~nsDisplayImage() { @@ -463,6 +465,7 @@ public: NS_DISPLAY_DECL_NAME("Image", TYPE_IMAGE) private: nsCOMPtr mImage; + nsCOMPtr mPrevImage; }; #endif /* nsImageFrame_h___ */ diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp index ca46f6c234..2eeea33501 100644 --- a/layout/generic/nsInlineFrame.cpp +++ b/layout/generic/nsInlineFrame.cpp @@ -71,7 +71,7 @@ nsInlineFrame::InvalidateFrame(uint32_t aDisplayItemKey) svgTextFrame->InvalidateFrame(); return; } - nsInlineFrameBase::InvalidateFrame(aDisplayItemKey); + nsContainerFrame::InvalidateFrame(aDisplayItemKey); } void @@ -84,7 +84,7 @@ nsInlineFrame::InvalidateFrameWithRect(const nsRect& aRect, uint32_t aDisplayIte svgTextFrame->InvalidateFrame(); return; } - nsInlineFrameBase::InvalidateFrameWithRect(aRect, aDisplayItemKey); + nsContainerFrame::InvalidateFrameWithRect(aRect, aDisplayItemKey); } static inline bool @@ -482,7 +482,7 @@ nsInlineFrame::AttributeChanged(int32_t aNameSpaceID, int32_t aModType) { nsresult rv = - nsInlineFrameBase::AttributeChanged(aNameSpaceID, aAttribute, aModType); + nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); if (NS_FAILED(rv)) { return rv; diff --git a/layout/generic/nsInlineFrame.h b/layout/generic/nsInlineFrame.h index 67a0d113ba..ae6701772c 100644 --- a/layout/generic/nsInlineFrame.h +++ b/layout/generic/nsInlineFrame.h @@ -13,15 +13,13 @@ class nsLineLayout; -typedef nsContainerFrame nsInlineFrameBase; - /** * Inline frame class. * * This class manages a list of child frames that are inline frames. Working with * nsLineLayout, the class will reflow and place inline frames on a line. */ -class nsInlineFrame : public nsInlineFrameBase +class nsInlineFrame : public nsContainerFrame { public: NS_DECL_QUERYFRAME_TARGET(nsInlineFrame) diff --git a/layout/generic/nsPluginFrame.cpp b/layout/generic/nsPluginFrame.cpp index d3cf5f6d5a..a89c87fdeb 100644 --- a/layout/generic/nsPluginFrame.cpp +++ b/layout/generic/nsPluginFrame.cpp @@ -150,7 +150,7 @@ protected: }; nsPluginFrame::nsPluginFrame(nsStyleContext* aContext) - : nsPluginFrameSuper(aContext) + : nsFrame(aContext) , mInstanceOwner(nullptr) , mReflowCallbackPosted(false) , mIsHiddenDueToScroll(false) @@ -168,7 +168,7 @@ nsPluginFrame::~nsPluginFrame() NS_QUERYFRAME_HEAD(nsPluginFrame) NS_QUERYFRAME_ENTRY(nsPluginFrame) NS_QUERYFRAME_ENTRY(nsIObjectFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsPluginFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsFrame) #ifdef ACCESSIBILITY a11y::AccType @@ -194,7 +194,7 @@ nsPluginFrame::Init(nsIContent* aContent, MOZ_LOG(sPluginFrameLog, LogLevel::Debug, ("Initializing nsPluginFrame %p for content %p\n", this, aContent)); - nsPluginFrameSuper::Init(aContent, aParent, aPrevInFlow); + nsFrame::Init(aContent, aParent, aPrevInFlow); } void @@ -223,7 +223,7 @@ nsPluginFrame::DestroyFrom(nsIFrame* aDestructRoot) mBackgroundSink->Destroy(); } - nsPluginFrameSuper::DestroyFrom(aDestructRoot); + nsFrame::DestroyFrom(aDestructRoot); } /* virtual */ void @@ -239,7 +239,7 @@ nsPluginFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) } } - nsPluginFrameSuper::DidSetStyleContext(aOldStyleContext); + nsFrame::DidSetStyleContext(aOldStyleContext); } nsIAtom* @@ -737,7 +737,7 @@ nsPluginFrame::IsFocusable(int32_t *aTabIndex, bool aWithMouse) { if (aTabIndex) *aTabIndex = -1; - return nsPluginFrameSuper::IsFocusable(aTabIndex, aWithMouse); + return nsFrame::IsFocusable(aTabIndex, aWithMouse); } bool @@ -853,7 +853,7 @@ nsPluginFrame::DidReflow(nsPresContext* aPresContext, objContent->HasNewFrame(this); } - nsPluginFrameSuper::DidReflow(aPresContext, aReflowState, aStatus); + nsFrame::DidReflow(aPresContext, aReflowState, aStatus); // The view is created hidden; once we have reflowed it and it has been // positioned then we show it. @@ -1674,7 +1674,7 @@ nsPluginFrame::HandleEvent(nsPresContext* aPresContext, } #ifdef XP_WIN - rv = nsPluginFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus); + rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus); return rv; #endif @@ -1698,10 +1698,10 @@ nsPluginFrame::HandleEvent(nsPresContext* aPresContext, } #endif - rv = nsPluginFrameSuper::HandleEvent(aPresContext, anEvent, anEventStatus); + rv = nsFrame::HandleEvent(aPresContext, anEvent, anEventStatus); // We need to be careful from this point because the call to - // nsPluginFrameSuper::HandleEvent() might have killed us. + // nsFrame::HandleEvent() might have killed us. #ifdef XP_MACOSX if (anEvent->mMessage == eMouseUp) { @@ -1786,7 +1786,7 @@ nsPluginFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor) return NS_ERROR_FAILURE; } - return nsPluginFrameSuper::GetCursor(aPoint, aCursor); + return nsFrame::GetCursor(aPoint, aCursor); } void diff --git a/layout/generic/nsPluginFrame.h b/layout/generic/nsPluginFrame.h index 1758b84043..d640e450de 100644 --- a/layout/generic/nsPluginFrame.h +++ b/layout/generic/nsPluginFrame.h @@ -42,13 +42,11 @@ class LayerManager; } // namespace layers } // namespace mozilla -typedef nsFrame nsPluginFrameSuper; - class PluginFrameDidCompositeObserver; -class nsPluginFrame : public nsPluginFrameSuper, - public nsIObjectFrame, - public nsIReflowCallback +class nsPluginFrame : public nsFrame + , public nsIObjectFrame + , public nsIReflowCallback { public: typedef mozilla::LayerState LayerState; @@ -91,7 +89,7 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { - return nsPluginFrameSuper::IsFrameOfType(aFlags & + return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing)); } diff --git a/layout/generic/nsRubyBaseFrame.cpp b/layout/generic/nsRubyBaseFrame.cpp index 7eeb31ea5c..668bf77fda 100644 --- a/layout/generic/nsRubyBaseFrame.cpp +++ b/layout/generic/nsRubyBaseFrame.cpp @@ -22,7 +22,7 @@ using namespace mozilla; NS_QUERYFRAME_HEAD(nsRubyBaseFrame) NS_QUERYFRAME_ENTRY(nsRubyBaseFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsRubyBaseFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsRubyContentFrame) NS_IMPL_FRAMEARENA_HELPERS(nsRubyBaseFrame) diff --git a/layout/generic/nsRubyBaseFrame.h b/layout/generic/nsRubyBaseFrame.h index 8f9951c300..b6dde10293 100644 --- a/layout/generic/nsRubyBaseFrame.h +++ b/layout/generic/nsRubyBaseFrame.h @@ -11,8 +11,6 @@ #include "nsRubyContentFrame.h" -typedef nsRubyContentFrame nsRubyBaseFrameSuper; - /** * Factory function. * @return a newly allocated nsRubyBaseFrame (infallible) @@ -20,7 +18,7 @@ typedef nsRubyContentFrame nsRubyBaseFrameSuper; nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); -class nsRubyBaseFrame final : public nsRubyBaseFrameSuper +class nsRubyBaseFrame final : public nsRubyContentFrame { public: NS_DECL_FRAMEARENA_HELPERS @@ -38,7 +36,7 @@ protected: friend nsContainerFrame* NS_NewRubyBaseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); explicit nsRubyBaseFrame(nsStyleContext* aContext) - : nsRubyBaseFrameSuper(aContext) {} + : nsRubyContentFrame(aContext) {} }; #endif /* nsRubyBaseFrame_h___ */ diff --git a/layout/generic/nsRubyContentFrame.cpp b/layout/generic/nsRubyContentFrame.cpp index ce806553c0..c7f0774bb8 100644 --- a/layout/generic/nsRubyContentFrame.cpp +++ b/layout/generic/nsRubyContentFrame.cpp @@ -24,7 +24,7 @@ nsRubyContentFrame::IsFrameOfType(uint32_t aFlags) const if (aFlags & eBidiInlineContainer) { return false; } - return nsRubyContentFrameSuper::IsFrameOfType(aFlags); + return nsInlineFrame::IsFrameOfType(aFlags); } bool diff --git a/layout/generic/nsRubyContentFrame.h b/layout/generic/nsRubyContentFrame.h index b33e6b0993..05f8a566d1 100644 --- a/layout/generic/nsRubyContentFrame.h +++ b/layout/generic/nsRubyContentFrame.h @@ -11,9 +11,7 @@ #include "nsInlineFrame.h" -typedef nsInlineFrame nsRubyContentFrameSuper; - -class nsRubyContentFrame : public nsRubyContentFrameSuper +class nsRubyContentFrame : public nsInlineFrame { public: NS_DECL_ABSTRACT_FRAME(nsRubyContentFrame) @@ -30,7 +28,7 @@ public: protected: explicit nsRubyContentFrame(nsStyleContext* aContext) - : nsRubyContentFrameSuper(aContext) {} + : nsInlineFrame(aContext) {} }; #endif /* nsRubyContentFrame_h___ */ diff --git a/layout/generic/nsRubyFrame.cpp b/layout/generic/nsRubyFrame.cpp index 9872e20958..8014b4fb1b 100644 --- a/layout/generic/nsRubyFrame.cpp +++ b/layout/generic/nsRubyFrame.cpp @@ -26,7 +26,7 @@ using namespace mozilla; NS_QUERYFRAME_HEAD(nsRubyFrame) NS_QUERYFRAME_ENTRY(nsRubyFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsRubyFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsInlineFrame) NS_IMPL_FRAMEARENA_HELPERS(nsRubyFrame) @@ -54,7 +54,7 @@ nsRubyFrame::IsFrameOfType(uint32_t aFlags) const if (aFlags & eBidiInlineContainer) { return false; } - return nsRubyFrameSuper::IsFrameOfType(aFlags); + return nsInlineFrame::IsFrameOfType(aFlags); } #ifdef DEBUG_FRAME_DUMP diff --git a/layout/generic/nsRubyFrame.h b/layout/generic/nsRubyFrame.h index 125c08afac..cf002ef48a 100644 --- a/layout/generic/nsRubyFrame.h +++ b/layout/generic/nsRubyFrame.h @@ -13,8 +13,6 @@ class nsRubyBaseContainerFrame; -typedef nsInlineFrame nsRubyFrameSuper; - /** * Factory function. * @return a newly allocated nsRubyFrame (infallible) @@ -22,7 +20,7 @@ typedef nsInlineFrame nsRubyFrameSuper; nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); -class nsRubyFrame final : public nsRubyFrameSuper +class nsRubyFrame final : public nsInlineFrame { public: NS_DECL_FRAMEARENA_HELPERS @@ -55,7 +53,7 @@ protected: friend nsContainerFrame* NS_NewRubyFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); explicit nsRubyFrame(nsStyleContext* aContext) - : nsRubyFrameSuper(aContext) {} + : nsInlineFrame(aContext) {} void ReflowSegment(nsPresContext* aPresContext, const nsHTMLReflowState& aReflowState, diff --git a/layout/generic/nsRubyTextContainerFrame.cpp b/layout/generic/nsRubyTextContainerFrame.cpp index 3c8bd80075..1630c3203d 100644 --- a/layout/generic/nsRubyTextContainerFrame.cpp +++ b/layout/generic/nsRubyTextContainerFrame.cpp @@ -60,14 +60,14 @@ nsRubyTextContainerFrame::IsFrameOfType(uint32_t aFlags) const if (aFlags & eSupportsCSSTransforms) { return false; } - return nsRubyTextContainerFrameSuper::IsFrameOfType(aFlags); + return nsContainerFrame::IsFrameOfType(aFlags); } /* virtual */ void nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID, nsFrameList& aChildList) { - nsRubyTextContainerFrameSuper::SetInitialChildList(aListID, aChildList); + nsContainerFrame::SetInitialChildList(aListID, aChildList); if (aListID == kPrincipalList) { UpdateSpanFlag(); } @@ -77,7 +77,7 @@ nsRubyTextContainerFrame::SetInitialChildList(ChildListID aListID, nsRubyTextContainerFrame::AppendFrames(ChildListID aListID, nsFrameList& aFrameList) { - nsRubyTextContainerFrameSuper::AppendFrames(aListID, aFrameList); + nsContainerFrame::AppendFrames(aListID, aFrameList); UpdateSpanFlag(); } @@ -86,7 +86,7 @@ nsRubyTextContainerFrame::InsertFrames(ChildListID aListID, nsIFrame* aPrevFrame, nsFrameList& aFrameList) { - nsRubyTextContainerFrameSuper::InsertFrames(aListID, aPrevFrame, aFrameList); + nsContainerFrame::InsertFrames(aListID, aPrevFrame, aFrameList); UpdateSpanFlag(); } @@ -94,7 +94,7 @@ nsRubyTextContainerFrame::InsertFrames(ChildListID aListID, nsRubyTextContainerFrame::RemoveFrame(ChildListID aListID, nsIFrame* aOldFrame) { - nsRubyTextContainerFrameSuper::RemoveFrame(aListID, aOldFrame); + nsContainerFrame::RemoveFrame(aListID, aOldFrame); UpdateSpanFlag(); } diff --git a/layout/generic/nsRubyTextContainerFrame.h b/layout/generic/nsRubyTextContainerFrame.h index c738d79d60..08ffab9e0e 100644 --- a/layout/generic/nsRubyTextContainerFrame.h +++ b/layout/generic/nsRubyTextContainerFrame.h @@ -11,8 +11,6 @@ #include "nsBlockFrame.h" -typedef nsContainerFrame nsRubyTextContainerFrameSuper; - /** * Factory function. * @return a newly allocated nsRubyTextContainerFrame (infallible) @@ -20,7 +18,7 @@ typedef nsContainerFrame nsRubyTextContainerFrameSuper; nsContainerFrame* NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); -class nsRubyTextContainerFrame final : public nsRubyTextContainerFrameSuper +class nsRubyTextContainerFrame final : public nsContainerFrame { public: NS_DECL_FRAMEARENA_HELPERS @@ -59,7 +57,7 @@ protected: NS_NewRubyTextContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); explicit nsRubyTextContainerFrame(nsStyleContext* aContext) - : nsRubyTextContainerFrameSuper(aContext) + : nsContainerFrame(aContext) , mISize(0) {} void UpdateSpanFlag(); diff --git a/layout/generic/nsRubyTextFrame.cpp b/layout/generic/nsRubyTextFrame.cpp index ad34ea3e66..690f8ea4e8 100644 --- a/layout/generic/nsRubyTextFrame.cpp +++ b/layout/generic/nsRubyTextFrame.cpp @@ -22,7 +22,7 @@ using namespace mozilla; NS_QUERYFRAME_HEAD(nsRubyTextFrame) NS_QUERYFRAME_ENTRY(nsRubyTextFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsRubyTextFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsRubyContentFrame) NS_IMPL_FRAMEARENA_HELPERS(nsRubyTextFrame) @@ -70,7 +70,7 @@ nsRubyTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder, return; } - nsRubyTextFrameSuper::BuildDisplayList(aBuilder, aDirtyRect, aLists); + nsRubyContentFrame::BuildDisplayList(aBuilder, aDirtyRect, aLists); } /* virtual */ void @@ -85,8 +85,7 @@ nsRubyTextFrame::Reflow(nsPresContext* aPresContext, // the content is no longer the same, until next reflow triggered by // some other change. In general, we always reflow all the frames we // created. There might be other problems if we don't do that. - nsRubyTextFrameSuper::Reflow(aPresContext, aDesiredSize, - aReflowState, aStatus); + nsRubyContentFrame::Reflow(aPresContext, aDesiredSize, aReflowState, aStatus); if (IsAutoHidden()) { // Reset the ISize. The BSize is not changed so that it won't diff --git a/layout/generic/nsRubyTextFrame.h b/layout/generic/nsRubyTextFrame.h index b615c571ec..ea8784cc2f 100644 --- a/layout/generic/nsRubyTextFrame.h +++ b/layout/generic/nsRubyTextFrame.h @@ -11,8 +11,6 @@ #include "nsRubyContentFrame.h" -typedef nsRubyContentFrame nsRubyTextFrameSuper; - /** * Factory function. * @return a newly allocated nsRubyTextFrame (infallible) @@ -20,7 +18,7 @@ typedef nsRubyContentFrame nsRubyTextFrameSuper; nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); -class nsRubyTextFrame final : public nsRubyTextFrameSuper +class nsRubyTextFrame final : public nsRubyContentFrame { public: NS_DECL_FRAMEARENA_HELPERS @@ -53,7 +51,7 @@ protected: friend nsContainerFrame* NS_NewRubyTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext); explicit nsRubyTextFrame(nsStyleContext* aContext) - : nsRubyTextFrameSuper(aContext) {} + : nsRubyContentFrame(aContext) {} }; #endif /* nsRubyTextFrame_h___ */ diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 0521cda857..0a1eb7ef95 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -57,7 +57,7 @@ GetDocumentFromView(nsView* aView) } nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext) - : nsSubDocumentFrameSuper(aContext) + : nsAtomicContainerFrame(aContext) , mIsInline(false) , mPostedReflowCallback(false) , mDidCreateDoc(false) @@ -75,7 +75,7 @@ nsSubDocumentFrame::AccessibleType() NS_QUERYFRAME_HEAD(nsSubDocumentFrame) NS_QUERYFRAME_ENTRY(nsSubDocumentFrame) -NS_QUERYFRAME_TAIL_INHERITING(nsSubDocumentFrameSuper) +NS_QUERYFRAME_TAIL_INHERITING(nsAtomicContainerFrame) class AsyncFrameInit : public nsRunnable { @@ -108,7 +108,7 @@ nsSubDocumentFrame::Init(nsIContent* aContent, nsCOMPtr frameElem = do_QueryInterface(aContent); mIsInline = frameElem ? false : true; - nsSubDocumentFrameSuper::Init(aContent, aParent, aPrevInFlow); + nsAtomicContainerFrame::Init(aContent, aParent, aPrevInFlow); // We are going to create an inner view. If we need a view for the // OuterFrame but we wait for the normal view creation path in @@ -689,7 +689,7 @@ nsSubDocumentFrame::GetIntrinsicSize() if (subDocRoot) { return subDocRoot->GetIntrinsicSize(); } - return nsSubDocumentFrameSuper::GetIntrinsicSize(); + return nsAtomicContainerFrame::GetIntrinsicSize(); } /* virtual */ nsSize @@ -699,7 +699,7 @@ nsSubDocumentFrame::GetIntrinsicRatio() if (subDocRoot) { return subDocRoot->GetIntrinsicRatio(); } - return nsSubDocumentFrameSuper::GetIntrinsicRatio(); + return nsAtomicContainerFrame::GetIntrinsicRatio(); } /* virtual */ @@ -747,10 +747,10 @@ nsSubDocumentFrame::ComputeSize(nsRenderingContext *aRenderingContext, aBorder, aPadding); } - return nsSubDocumentFrameSuper::ComputeSize(aRenderingContext, aWM, - aCBSize, aAvailableISize, - aMargin, aBorder, aPadding, - aFlags); + return nsAtomicContainerFrame::ComputeSize(aRenderingContext, aWM, + aCBSize, aAvailableISize, + aMargin, aBorder, aPadding, + aFlags); } void @@ -955,18 +955,16 @@ public: if (!mPresShell->IsDestroying() && mFrameElement->IsInComposedDoc()) { mPresShell->FlushPendingNotifications(Flush_Frames); } - - // Either the frame has been constructed by now, or it never will be. - // Either way, we want to clear the stashed views. + + // Either the frame has been constructed by now, or it never will be, + // either way we want to clear the stashed views. mFrameLoader->SetDetachedSubdocFrame(nullptr, nullptr); - nsSubDocumentFrame* frame = do_QueryFrame(mFrameElement->GetPrimaryFrame()); if ((!frame && mHideViewerIfFrameless) || mPresShell->IsDestroying()) { // Either the frame element has no nsIFrame or the presshell is being - // destroyed. Hide the nsFrameLoader, which destroys the presentation, - // and clear our references to the stashed presentation. + // destroyed. Hide the nsFrameLoader, which destroys the presentation. mFrameLoader->Hide(); } return NS_OK; @@ -1015,7 +1013,7 @@ nsSubDocumentFrame::DestroyFrom(nsIFrame* aDestructRoot) } } - nsSubDocumentFrameSuper::DestroyFrom(aDestructRoot); + nsAtomicContainerFrame::DestroyFrom(aDestructRoot); } CSSIntSize diff --git a/layout/generic/nsSubDocumentFrame.h b/layout/generic/nsSubDocumentFrame.h index 98916cfb99..6274bb448d 100644 --- a/layout/generic/nsSubDocumentFrame.h +++ b/layout/generic/nsSubDocumentFrame.h @@ -12,12 +12,10 @@ #include "nsFrameLoader.h" #include "Units.h" -typedef nsAtomicContainerFrame nsSubDocumentFrameSuper; - /****************************************************************************** * nsSubDocumentFrame *****************************************************************************/ -class nsSubDocumentFrame : public nsSubDocumentFrameSuper, +class nsSubDocumentFrame : public nsAtomicContainerFrame, public nsIReflowCallback { public: @@ -37,7 +35,7 @@ public: virtual bool IsFrameOfType(uint32_t aFlags) const override { - return nsSubDocumentFrameSuper::IsFrameOfType(aFlags & + return nsAtomicContainerFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced | nsIFrame::eReplacedSizing | nsIFrame::eReplacedContainsBlock)); diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp index cb6fec48c2..e0db7d6304 100644 --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -75,7 +75,7 @@ SwapScaleWidthHeightForRotation(IntSize& aSize, VideoInfo::Rotation aDegrees) } nsVideoFrame::nsVideoFrame(nsStyleContext* aContext) - : nsVideoFrameBase(aContext) + : nsContainerFrame(aContext) { EnableVisibilityTracking(); } @@ -87,7 +87,7 @@ nsVideoFrame::~nsVideoFrame() NS_QUERYFRAME_HEAD(nsVideoFrame) NS_QUERYFRAME_ENTRY(nsVideoFrame) NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator) -NS_QUERYFRAME_TAIL_INHERITING(nsVideoFrameBase) +NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame) nsresult nsVideoFrame::CreateAnonymousContent(nsTArray& aElements) @@ -178,7 +178,7 @@ nsVideoFrame::DestroyFrom(nsIFrame* aDestructRoot) nsContentUtils::DestroyAnonymousContent(&mCaptionDiv); nsContentUtils::DestroyAnonymousContent(&mVideoControls); nsContentUtils::DestroyAnonymousContent(&mPosterImage); - nsVideoFrameBase::DestroyFrom(aDestructRoot); + nsContainerFrame::DestroyFrom(aDestructRoot); } bool @@ -655,7 +655,7 @@ nsVideoFrame::AttributeChanged(int32_t aNameSpaceID, if (aAttribute == nsGkAtoms::poster && HasVideoElement()) { UpdatePosterSource(true); } - return nsVideoFrameBase::AttributeChanged(aNameSpaceID, + return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType); } @@ -666,12 +666,13 @@ nsVideoFrame::OnVisibilityChange(Visibility aNewVisibility, { nsCOMPtr imageLoader = do_QueryInterface(mPosterImage); if (!imageLoader) { + nsContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction); return; } imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction); - nsVideoFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction); + nsContainerFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction); } bool nsVideoFrame::HasVideoElement() { diff --git a/layout/generic/nsVideoFrame.h b/layout/generic/nsVideoFrame.h index 68c9009175..2a1ea54f8c 100644 --- a/layout/generic/nsVideoFrame.h +++ b/layout/generic/nsVideoFrame.h @@ -26,9 +26,8 @@ class nsAString; class nsPresContext; class nsDisplayItem; -typedef nsContainerFrame nsVideoFrameBase; - -class nsVideoFrame : public nsVideoFrameBase, public nsIAnonymousContentCreator +class nsVideoFrame : public nsContainerFrame + , public nsIAnonymousContentCreator { public: template using Maybe = mozilla::Maybe; diff --git a/layout/generic/nsViewportFrame.cpp b/layout/generic/nsViewportFrame.cpp index 25466f9092..98124f2c6e 100644 --- a/layout/generic/nsViewportFrame.cpp +++ b/layout/generic/nsViewportFrame.cpp @@ -36,7 +36,7 @@ ViewportFrame::Init(nsIContent* aContent, nsContainerFrame* aParent, nsIFrame* aPrevInFlow) { - Super::Init(aContent, aParent, aPrevInFlow); + nsContainerFrame::Init(aContent, aParent, aPrevInFlow); nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(this); if (parent) { diff --git a/layout/generic/nsViewportFrame.h b/layout/generic/nsViewportFrame.h index e56aa68661..7698e374e1 100644 --- a/layout/generic/nsViewportFrame.h +++ b/layout/generic/nsViewportFrame.h @@ -27,8 +27,6 @@ public: NS_DECL_QUERYFRAME NS_DECL_FRAMEARENA_HELPERS - typedef nsContainerFrame Super; - explicit ViewportFrame(nsStyleContext* aContext) : nsContainerFrame(aContext) {} diff --git a/layout/reftests/async-scrolling/perspective-scrolling-4-ref.html b/layout/reftests/async-scrolling/perspective-scrolling-4-ref.html new file mode 100644 index 0000000000..4601b68051 --- /dev/null +++ b/layout/reftests/async-scrolling/perspective-scrolling-4-ref.html @@ -0,0 +1,44 @@ + + + +Reference: Perspective scrolling with nested clips + + + +
+
+
+
+ + diff --git a/layout/reftests/async-scrolling/perspective-scrolling-4.html b/layout/reftests/async-scrolling/perspective-scrolling-4.html new file mode 100644 index 0000000000..49453d74df --- /dev/null +++ b/layout/reftests/async-scrolling/perspective-scrolling-4.html @@ -0,0 +1,49 @@ + + + +Perspective scrolling with nested clips + + + +
+ +
+
+ +
diff --git a/layout/reftests/async-scrolling/reftest.list b/layout/reftests/async-scrolling/reftest.list index 1af9bff06a..8a77daef99 100644 --- a/layout/reftests/async-scrolling/reftest.list +++ b/layout/reftests/async-scrolling/reftest.list @@ -30,6 +30,7 @@ skip-if(!asyncPan) == position-fixed-iframe-2.html position-fixed-iframe-2-ref.h skip-if(!asyncPan) == position-fixed-in-scroll-container.html position-fixed-in-scroll-container-ref.html fuzzy(1,60000) skip-if(!asyncPan) == group-opacity-surface-size-1.html group-opacity-surface-size-1-ref.html skip-if(!asyncPan) == offscreen-prerendered-active-opacity.html offscreen-prerendered-active-opacity-ref.html +fuzzy-if(Android,7,4) skip-if(!asyncPan) == perspective-scrolling-4.html perspective-scrolling-4-ref.html # for the following tests, we want to disable the low-precision buffer # as it will expand the displayport beyond what the test specifies in diff --git a/layout/reftests/forms/textarea/reftest.list b/layout/reftests/forms/textarea/reftest.list index ae050a145a..6807fba3e1 100644 --- a/layout/reftests/forms/textarea/reftest.list +++ b/layout/reftests/forms/textarea/reftest.list @@ -1,11 +1,11 @@ -skip-if(B2G||Mulet) fails-if(Android) == resize.html resize-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) == resize.html resize-ref.html # Initial mulet triage: parity with B2G/B2G Desktop # an offset seems to apply to the native resizer on windows so skip this test for now -skip-if(B2G||Mulet) fails-if(Android) skip-if(winWidget) fuzzy-if(cocoaWidget,1,33) == resize-background.html resize-background-ref.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) != ltr.html rtl.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) != ltr-scrollbar.html rtl-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) != in-ltr-doc-scrollbar.html in-rtl-doc-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) != ltr.html no-resize.html # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(B2G||Mulet) fails-if(Android) fails-if(gtkWidget) != rtl.html no-resize.html # bug 834724 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) skip-if(winWidget) fuzzy-if(cocoaWidget,1,33) == resize-background.html resize-background-ref.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) != ltr.html rtl.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) != ltr-scrollbar.html rtl-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) != in-ltr-doc-scrollbar.html in-rtl-doc-scrollbar.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) != ltr.html no-resize.html # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) fails-if(xulRuntime.widgetToolkit=="gtk2") != rtl.html no-resize.html # bug 834724 # Initial mulet triage: parity with B2G/B2G Desktop == rtl.html rtl-dynamic-attr.html == rtl.html rtl-dynamic-style.html == rtl.html in-dynamic-rtl-doc.html diff --git a/layout/reftests/forms/textbox/reftest.list b/layout/reftests/forms/textbox/reftest.list index a63bbb434e..f5c2c58a89 100644 --- a/layout/reftests/forms/textbox/reftest.list +++ b/layout/reftests/forms/textbox/reftest.list @@ -1,10 +1,11 @@ # access-key tests are no use on OS X because access keys are not indicated visually -skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)) != accesskey-1.xul accesskey-1-notref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)) == accesskey-2.xul accesskey-2-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop +# no real XUL theme on Android so we just skip +skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)||Android) != accesskey-1.xul accesskey-1-notref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)||Android) == accesskey-2.xul accesskey-2-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop # accesskey-3 fails because of defects in XUL bidi support -fails-if(!cocoaWidget) skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)) == accesskey-3.xul accesskey-3-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)) != accesskey-3.xul accesskey-3-notref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)) == accesskey-4.xul accesskey-4-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop -skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)) != accesskey-4.xul accesskey-4-notref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop -skip-if((B2G&&browserIsRemote)||Mulet) == align-baseline-1.xul align-baseline-1-ref.xul # test for bug 494901 # Initial mulet triage: parity with B2G/B2G Desktop -fails-if(Android) skip-if(B2G||Mulet) == setsize.xul setsize-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop +fails-if(!cocoaWidget) skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)||Android) == accesskey-3.xul accesskey-3-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)||Android) != accesskey-3.xul accesskey-3-notref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)||Android) == accesskey-4.xul accesskey-4-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(cocoaWidget||((B2G&&browserIsRemote)||Mulet)||Android) != accesskey-4.xul accesskey-4-notref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if((B2G&&browserIsRemote)||Mulet||Android) == align-baseline-1.xul align-baseline-1-ref.xul # test for bug 494901 # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Mulet||Android) == setsize.xul setsize-ref.xul # bug 974780 # Initial mulet triage: parity with B2G/B2G Desktop diff --git a/layout/reftests/reftest.list b/layout/reftests/reftest.list index ef5df23332..3e0227903d 100644 --- a/layout/reftests/reftest.list +++ b/layout/reftests/reftest.list @@ -246,7 +246,7 @@ include marquee/reftest.list # native-theme/ # skipping for B2G since something around radio-nonnative.html makes the whole suite hang -skip-if(B2G||Mulet) include native-theme/reftest.list # Initial mulet triage: parity with B2G/B2G Desktop +skip-if(B2G||Android||Mulet) include native-theme/reftest.list # Initial mulet triage: parity with B2G/B2G Desktop # netwerk/ include ../../netwerk/test/reftest/reftest.list @@ -373,17 +373,20 @@ include ../../widget/reftests/reftest.list # xml-stylesheet/ include ../../content/test/reftest/xml-stylesheet/reftest.list -# xul-document-load/ -include xul-document-load/reftest.list +# xul-document-load/ (no XUL theme on Android) +skip-if(Android) include xul-document-load/reftest.list -# xul/ -include xul/reftest.list +# xul/ (no XUL theme on Android) +skip-if(Android) include xul/reftest.list -# xul -include ../xul/reftest/reftest.list +# xul (no XUL theme on Android) +skip-if(Android) include ../xul/reftest/reftest.list -# xul grid -include ../xul/grid/reftests/reftest.list +# xul grid (no XUL theme on Android) +skip-if(Android) include ../xul/grid/reftests/reftest.list + +# -webkit-box & associated properties (mapped to modern flexbox) +include webkit-box/reftest.list # -webkit-gradient expressions include webkit-gradient/reftest.list diff --git a/layout/reftests/webkit-box/reftest.list b/layout/reftests/webkit-box/reftest.list index 5f1cac5692..8412328480 100644 --- a/layout/reftests/webkit-box/reftest.list +++ b/layout/reftests/webkit-box/reftest.list @@ -19,6 +19,22 @@ fails == webkit-box-anon-flex-items-3.html webkit-box-anon-flex-items-3-ref.html == webkit-box-align-horiz-1b.html webkit-box-align-horiz-1-ref.html == webkit-box-align-vert-1.html webkit-box-align-vert-1-ref.html +# Tests for "-webkit-box-direction": +== webkit-box-direction-1.html webkit-box-direction-1-ref.html + +# Tests for "-webkit-box-flex" (flexibility of items) +== webkit-box-flex-1.html webkit-box-flex-1-ref.html + +# Tests for "-webkit-box-ordinal-group" +== webkit-box-ordinal-group-1.html webkit-box-ordinal-group-1-ref.html +# XXXdholbert The following test fails because we accept "0" as a valid value +# for -webkit-box-ordinal-group (unlike Chrome/Blink), because that's simply +# how its aliased property (-moz-box-ordinal-group) behaves. This shouldn't +# matter in practice; it could only cause trouble if sites accidentally depend +# on the "0" value being rejected. +fails == webkit-box-ordinal-group-2.html webkit-box-ordinal-group-2-ref.html +== webkit-box-ordinal-group-3.html webkit-box-ordinal-group-3-ref.html + # Tests for "-webkit-box-pack" (main-axis alignment): == webkit-box-pack-horiz-1a.html webkit-box-pack-horiz-1-ref.html == webkit-box-pack-horiz-1b.html webkit-box-pack-horiz-1-ref.html diff --git a/layout/reftests/webkit-box/webkit-box-align-horiz-1-ref.html b/layout/reftests/webkit-box/webkit-box-align-horiz-1-ref.html new file mode 100644 index 0000000000..2ee021a63e --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-align-horiz-1-ref.html @@ -0,0 +1,172 @@ + + + + + + CSS Reference + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-align-horiz-1a.html b/layout/reftests/webkit-box/webkit-box-align-horiz-1a.html new file mode 100644 index 0000000000..eb2dc06f74 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-align-horiz-1a.html @@ -0,0 +1,173 @@ + + + + + + CSS Test: horizontally-oriented "display: -webkit-box" container, + with all the various -webkit-box-align values. + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-align-horiz-1b.html b/layout/reftests/webkit-box/webkit-box-align-horiz-1b.html new file mode 100644 index 0000000000..9d200346d0 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-align-horiz-1b.html @@ -0,0 +1,174 @@ + + + + + + CSS Test: horizontally-oriented "display: -webkit-box" container, + with all the various -webkit-box-align values. + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-align-vert-1-ref.html b/layout/reftests/webkit-box/webkit-box-align-vert-1-ref.html new file mode 100644 index 0000000000..f71af621b3 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-align-vert-1-ref.html @@ -0,0 +1,173 @@ + + + + + + CSS Reference + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-align-vert-1.html b/layout/reftests/webkit-box/webkit-box-align-vert-1.html new file mode 100644 index 0000000000..63d4ff0b4d --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-align-vert-1.html @@ -0,0 +1,174 @@ + + + + + + CSS Test: vertically-oriented "display: -webkit-box" container, + with all the various -webkit-box-align values. + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-direction-1-ref.html b/layout/reftests/webkit-box/webkit-box-direction-1-ref.html new file mode 100644 index 0000000000..4ef84affa2 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-direction-1-ref.html @@ -0,0 +1,82 @@ + + + + + + CSS Reference + + + + + +
+
a
b
+
+
+
a
b
+
+ +
+ + +
+
a
b
+
+
+
a
b
+
+ +
+ + +
+
a
b
+
+
+
a
b
+
+ +
+ + +
+
a
b
+
+
+
a
b
+
+ + diff --git a/layout/reftests/webkit-box/webkit-box-direction-1.html b/layout/reftests/webkit-box/webkit-box-direction-1.html new file mode 100644 index 0000000000..ca45019be6 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-direction-1.html @@ -0,0 +1,87 @@ + + + + + + CSS Test: "-webkit-box-direction" property + in a -webkit-box with default writing-mode + + + + + +
+
a
b
+
+
+
a
b
+
+ +
+ + +
+
a
b
+
+
+
a
b
+
+ +
+ + +
+
a
b
+
+
+
a
b
+
+ +
+ + +
+
a
b
+
+
+
a
b
+
+ + diff --git a/layout/reftests/webkit-box/webkit-box-flex-1-ref.html b/layout/reftests/webkit-box/webkit-box-flex-1-ref.html new file mode 100644 index 0000000000..646d6a54b5 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-flex-1-ref.html @@ -0,0 +1,101 @@ + + + + + + CSS Reference + + + + + +
+
a
+
+ +
+
a
b
+
+ +
+
a
+
+ +
+ + +
+
a
+
+ +
+
a
b
+
+ +
+
a
+
+ +
+ + +
+
a
b
+
+ +
+
a
b
c
+
+ +
+
a
+
b
+
c
+
+ +
+ + +
+
a
b
+
+ +
+
a
b
+
+ +
+
a
+
b
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-flex-1.html b/layout/reftests/webkit-box/webkit-box-flex-1.html new file mode 100644 index 0000000000..10f2c63e32 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-flex-1.html @@ -0,0 +1,94 @@ + + + + + + CSS Test: "-webkit-box-flex" in a "display: -webkit-box" container + + + + + +
+
a
+
+ +
+
a
b
+
+ +
+
a
+
+ +
+ + +
+
a
+
+ +
+
a
b
+
+ +
+
a
+
+ +
+ + +
+
a
b
+
+ +
+
a
b
c
+
+ +
+
a
+
b
+
c
+
+ +
+ + +
+
a
b
+
+ +
+
a
b
+
+ +
+
a
+
b
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-ordinal-group-1-ref.html b/layout/reftests/webkit-box/webkit-box-ordinal-group-1-ref.html new file mode 100644 index 0000000000..e69c4d37a7 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-1-ref.html @@ -0,0 +1,84 @@ + + + + + + CSS Reference + + + + + +
+
*
+
1a
+
*
+
1b
+
*
+
+ +
+
*
+
*
+
*
+
2a
+
2b
+
+ +
+
*
+
*
+
*
+
9a
+
9b
+
+ +
+ + +
+
*
+
1
+
2
+
9
+
+ +
+
1
+
*
+
2
+
9
+
+ +
+
1
+
*
+
2a
+
2b
+
9
+
+ +
+
1
+
2a
+
2b
+
9a
+
9b
+
+ + diff --git a/layout/reftests/webkit-box/webkit-box-ordinal-group-1.html b/layout/reftests/webkit-box/webkit-box-ordinal-group-1.html new file mode 100644 index 0000000000..58a6447536 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-1.html @@ -0,0 +1,88 @@ + + + + + + CSS Test: -webkit-box-ordinal-group inside a -webkit-box + + + + + +
+
*
+
1a
+
*
+
1b
+
*
+
+ +
+
*
+
2a
+
*
+
2b
+
*
+
+ +
+
*
+
9a
+
*
+
9b
+
*
+
+ +
+ + +
+
*
+
1
+
2
+
9
+
+ +
+
9
+
2
+
1
+
*
+
+ +
+
2a
+
9
+
2b
+
1
+
*
+
+ +
+
2a
+
9a
+
9b
+
2b
+
1
+
+ + diff --git a/layout/reftests/webkit-box/webkit-box-ordinal-group-2-ref.html b/layout/reftests/webkit-box/webkit-box-ordinal-group-2-ref.html new file mode 100644 index 0000000000..c548d5e2d4 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-2-ref.html @@ -0,0 +1,29 @@ + + + + + + CSS Reference + + + + +
+
1
+
0
+
+ + diff --git a/layout/reftests/webkit-box/webkit-box-ordinal-group-2.html b/layout/reftests/webkit-box/webkit-box-ordinal-group-2.html new file mode 100644 index 0000000000..bfdde3d80a --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-2.html @@ -0,0 +1,36 @@ + + + + + + CSS Test: -webkit-box-ordinal-group:0 inside a -webkit-box + + + + + +
+
1
+
0
+
+ + diff --git a/layout/reftests/webkit-box/webkit-box-ordinal-group-3-ref.html b/layout/reftests/webkit-box/webkit-box-ordinal-group-3-ref.html new file mode 100644 index 0000000000..2129070ac6 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-3-ref.html @@ -0,0 +1,83 @@ + + + + + + CSS Reference + + + + +
+
*
+
10
+
A
+
+
+
*
+
10
+
B
+
+
+
*
+
10
+
C
+
+ +
+ +
+
*
+
10
+
D
+
+
+
*
+
10
+
E
+
+
+
*
+
10
+
F
+
+ +
+ +
+
A
+
B
+
+
+
A
+
C
+
+
+
A
+
D
+
+
+
A
+
E
+
+
+
A
+
F
+
+ + diff --git a/layout/reftests/webkit-box/webkit-box-ordinal-group-3.html b/layout/reftests/webkit-box/webkit-box-ordinal-group-3.html new file mode 100644 index 0000000000..3455365da0 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-ordinal-group-3.html @@ -0,0 +1,103 @@ + + + + + + CSS Test: -webkit-box-ordinal-group with huge values inside a -webkit-box + + + + + +
+
A
+
10
+
*
+
+
+
B
+
10
+
*
+
+
+
C
+
10
+
*
+
+ +
+ +
+
D
+
10
+
*
+
+
+
E
+
10
+
*
+
+
+
F
+
10
+
*
+
+ +
+ + +
+
B
+
A
+
+
+
C
+
A
+
+
+
D
+
A
+
+
+
E
+
A
+
+
+
F
+
A
+
+ + diff --git a/layout/reftests/webkit-box/webkit-box-pack-horiz-1-ref.html b/layout/reftests/webkit-box/webkit-box-pack-horiz-1-ref.html new file mode 100644 index 0000000000..1fe5090aff --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-pack-horiz-1-ref.html @@ -0,0 +1,150 @@ + + + + + + CSS Reference + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-pack-horiz-1a.html b/layout/reftests/webkit-box/webkit-box-pack-horiz-1a.html new file mode 100644 index 0000000000..8a1330154e --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-pack-horiz-1a.html @@ -0,0 +1,151 @@ + + + + + + CSS Test: horizontally-oriented "display: -webkit-box" container, + with all the various -webkit-box-pack values. + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-pack-horiz-1b.html b/layout/reftests/webkit-box/webkit-box-pack-horiz-1b.html new file mode 100644 index 0000000000..0332ab12e5 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-pack-horiz-1b.html @@ -0,0 +1,152 @@ + + + + + + CSS Test: horizontally-oriented "display: -webkit-box" container, + with all the various -webkit-box-pack values. + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-pack-vert-1-ref.html b/layout/reftests/webkit-box/webkit-box-pack-vert-1-ref.html new file mode 100644 index 0000000000..ed8fe20b3e --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-pack-vert-1-ref.html @@ -0,0 +1,151 @@ + + + + + + CSS Reference + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/reftests/webkit-box/webkit-box-pack-vert-1.html b/layout/reftests/webkit-box/webkit-box-pack-vert-1.html new file mode 100644 index 0000000000..41b5273431 --- /dev/null +++ b/layout/reftests/webkit-box/webkit-box-pack-vert-1.html @@ -0,0 +1,152 @@ + + + + + + CSS Test: vertically-oriented "display: -webkit-box" container, + with all the various -webkit-box-pack values. + + + + + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+ + +
+
a
b
+
+
+ + + diff --git a/layout/style/nsCSSDataBlock.cpp b/layout/style/nsCSSDataBlock.cpp index 6431c745cc..2bdbb18957 100644 --- a/layout/style/nsCSSDataBlock.cpp +++ b/layout/style/nsCSSDataBlock.cpp @@ -14,7 +14,6 @@ #include "CSSVariableImageTable.h" #include "mozilla/css/Declaration.h" #include "mozilla/css/ImageLoader.h" -#include "mozilla/Maybe.h" #include "mozilla/MemoryReporting.h" #include "mozilla/WritingModes.h" #include "nsIDocument.h" @@ -41,50 +40,6 @@ MoveValue(nsCSSValue* aSource, nsCSSValue* aDest) return changed; } -/** - * This function maps "-webkit-box-orient" values to "flex-direction" values, - * for a given writing-mode (taken from aRuleData). - * - * Specifically: - * - If aBoxOrientVal is an enumerated value (representing a physical axis), - * then we'll map it to the appropriate logical "flex-direction" value, using - * the writing mode. The converted value will be emplace()'d into in the - * outparam aConvertedValStorage, and we'll return a pointer to that value. - * - Otherwise (e.g. if we have "inherit" or "initial"), we won't do any - * mapping, and we'll directly return the passed-in aBoxOrientVal. - * - * Either way, the idea is that our caller can treat the returned value as if - * it were a value for "flex-direction". - */ -static const nsCSSValue* -ConvertBoxOrientToFlexDirection(const nsCSSValue* aBoxOrientVal, - const nsRuleData* aRuleData, - Maybe& aConvertedValStorage) -{ - MOZ_ASSERT(aBoxOrientVal, "expecting a non-null value to convert"); - MOZ_ASSERT(aConvertedValStorage.isNothing(), - "expecting outparam for converted-value to be initially empty"); - - if (aBoxOrientVal->GetUnit() != eCSSUnit_Enumerated) { - // We probably have "inherit" or "initial" -- just return that & have the - // caller directly use it as a "flex-direction" value. - return aBoxOrientVal; - } - - // OK, we have an enumerated value -- "horizontal" or "vertical". - - WritingMode wm(aRuleData->mStyleContext); - // In a horizontal writing-mode, "horizontal" maps to "row". - // In a vertical writing-mode, "horizontal" maps to "column". - bool isRow = wm.IsVertical() != - (aBoxOrientVal->GetIntValue() == NS_STYLE_BOX_ORIENT_HORIZONTAL); - - aConvertedValStorage.emplace(isRow ? NS_STYLE_FLEX_DIRECTION_ROW : - NS_STYLE_FLEX_DIRECTION_COLUMN, - eCSSUnit_Enumerated); - return aConvertedValStorage.ptr(); -} - static bool ShouldIgnoreColors(nsRuleData *aRuleData) { @@ -170,32 +125,15 @@ ShouldStartImageLoads(nsRuleData *aRuleData, nsCSSProperty aProperty) } static void -MapSinglePropertyInto(nsCSSProperty aSrcProp, +MapSinglePropertyInto(nsCSSProperty aTargetProp, const nsCSSValue* aSrcValue, - nsCSSProperty aTargetProp, nsCSSValue* aTargetValue, nsRuleData* aRuleData) { MOZ_ASSERT(!nsCSSProps::PropHasFlags(aTargetProp, CSS_PROPERTY_LOGICAL), "Can't map into a logical property"); - MOZ_ASSERT(aSrcProp == aTargetProp || - nsCSSProps::PropHasFlags(aSrcProp, CSS_PROPERTY_LOGICAL), - "Source & target property must be the same, except when we're " - "doing a logical-to-physical property mapping"); MOZ_ASSERT(aSrcValue->GetUnit() != eCSSUnit_Null, "oops"); - // Handle logical properties that have custom value-mapping behavior: - Maybe convertedVal; // storage for converted value, if needed - bool hasCustomValMapping = - nsCSSProps::PropHasFlags(aSrcProp, - CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING); - if (hasCustomValMapping) { - if (aSrcProp == eCSSProperty_webkit_box_orient) { - aSrcValue = ConvertBoxOrientToFlexDirection(aSrcValue, aRuleData, - convertedVal); - } - } - // Although aTargetValue is the nsCSSValue we are going to write into, // we also look at its value before writing into it. This is done // when aTargetValue is a token stream value, which is the case when we @@ -234,20 +172,13 @@ MapSinglePropertyInto(nsCSSProperty aSrcProp, } /** - * If aProperty is a logical property, returns the equivalent physical + * If aProperty is a logical property, converts it to the equivalent physical * property based on writing mode information obtained from aRuleData's * style context. */ -static inline nsCSSProperty -EnsurePhysicalProperty(nsCSSProperty aProperty, nsRuleData* aRuleData) +static inline void +EnsurePhysicalProperty(nsCSSProperty& aProperty, nsRuleData* aRuleData) { - if (!nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL)) { - return aProperty; - } - - bool isSingleProperty = - nsCSSProps::PropHasFlags(aProperty, - CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING); bool isAxisProperty = nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_LOGICAL_AXIS); bool isBlock = @@ -255,9 +186,7 @@ EnsurePhysicalProperty(nsCSSProperty aProperty, nsRuleData* aRuleData) int index; - if (isSingleProperty) { - index = 0; // We always map to the same physical property. - } else if (isAxisProperty) { + if (isAxisProperty) { LogicalAxis logicalAxis = isBlock ? eLogicalAxisBlock : eLogicalAxisInline; uint8_t wm = aRuleData->mStyleContext->StyleVisibility()->mWritingMode; PhysicalAxis axis = @@ -295,19 +224,43 @@ EnsurePhysicalProperty(nsCSSProperty aProperty, nsRuleData* aRuleData) } const nsCSSProperty* props = nsCSSProps::LogicalGroup(aProperty); + size_t len = isAxisProperty ? 2 : 4; #ifdef DEBUG - { - // Table-length is 1 for single prop, 2 for axis prop, 4 for block prop. - size_t len = isSingleProperty ? 1 : (isAxisProperty ? 2 : 4); for (size_t i = 0; i < len; i++) { - MOZ_ASSERT(props[i] != eCSSProperty_UNKNOWN, - "unexpected logical group length"); - } - MOZ_ASSERT(props[len] == eCSSProperty_UNKNOWN, + MOZ_ASSERT(props[i] != eCSSProperty_UNKNOWN, "unexpected logical group length"); } + MOZ_ASSERT(props[len] == eCSSProperty_UNKNOWN, + "unexpected logical group length"); #endif - return props[index]; + + for (size_t i = 0; i < len; i++) { + if (aRuleData->ValueFor(props[i])->GetUnit() == eCSSUnit_Null) { + // A declaration of one of the logical properties in this logical + // group (but maybe not aProperty) would be the winning + // declaration in the cascade. This means that it's reasonably + // likely that this logical property could be the winning + // declaration in the cascade for some values of writing-mode, + // direction, and text-orientation. (It doesn't mean that for + // sure, though. For example, if this is a block-start logical + // property, and all but the bottom physical property were set. + // But the common case we want to hit here is logical declarations + // that are completely overridden by a shorthand.) + // + // If this logical property could be the winning declaration in + // the cascade for some values of writing-mode, direction, and + // text-orientation, then we have to fault the resulting style + // struct out of the rule tree. We can't cache anything on the + // rule tree if it depends on data from the style context, since + // data cached in the rule tree could be used with a style context + // with a different value of the depended-upon data. + uint8_t wm = WritingMode(aRuleData->mStyleContext).GetBits(); + aRuleData->mConditions.SetWritingModeDependency(wm); + break; + } + } + + aProperty = props[index]; } void @@ -327,16 +280,10 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const nsCSSProperty iProp = PropertyAtIndex(i); if (nsCachedStyleData::GetBitForSID(nsCSSProps::kSIDTable[iProp]) & aRuleData->mSIDs) { - nsCSSProperty physicalProp = EnsurePhysicalProperty(iProp, - aRuleData); - if (physicalProp != iProp) { - // We can't cache anything on the rule tree if we use any data from - // the style context, since data cached in the rule tree could be - // used with a style context with a different value. - uint8_t wm = WritingMode(aRuleData->mStyleContext).GetBits(); - aRuleData->mConditions.SetWritingModeDependency(wm); + if (nsCSSProps::PropHasFlags(iProp, CSS_PROPERTY_LOGICAL)) { + EnsurePhysicalProperty(iProp, aRuleData); } - nsCSSValue* target = aRuleData->ValueFor(physicalProp); + nsCSSValue* target = aRuleData->ValueFor(iProp); if (target->GetUnit() == eCSSUnit_Null) { const nsCSSValue *val = ValueAtIndex(i); // In order for variable resolution to have the right information @@ -348,8 +295,7 @@ nsCSSCompressedDataBlock::MapRuleInfoInto(nsRuleData *aRuleData) const if (val->GetUnit() == eCSSUnit_TokenStream) { val->GetTokenStreamValue()->mLevel = aRuleData->mLevel; } - MapSinglePropertyInto(iProp, val, physicalProp, target, - aRuleData); + MapSinglePropertyInto(iProp, val, target, aRuleData); } } } @@ -791,10 +737,9 @@ nsCSSExpandedDataBlock::MapRuleInfoInto(nsCSSProperty aPropID, const nsCSSValue* src = PropertyAt(aPropID); MOZ_ASSERT(src->GetUnit() != eCSSUnit_Null); - nsCSSProperty physicalProp = EnsurePhysicalProperty(aPropID, aRuleData); - if (physicalProp != aPropID) { - uint8_t wm = WritingMode(aRuleData->mStyleContext).GetBits(); - aRuleData->mConditions.SetWritingModeDependency(wm); + nsCSSProperty physicalProp = aPropID; + if (nsCSSProps::PropHasFlags(aPropID, CSS_PROPERTY_LOGICAL)) { + EnsurePhysicalProperty(physicalProp, aRuleData); } nsCSSValue* dest = aRuleData->ValueFor(physicalProp); @@ -802,7 +747,7 @@ nsCSSExpandedDataBlock::MapRuleInfoInto(nsCSSProperty aPropID, dest->GetTokenStreamValue()->mPropertyID == aPropID); CSSVariableImageTable::ReplaceAll(aRuleData->mStyleContext, aPropID, [=] { - MapSinglePropertyInto(aPropID, src, physicalProp, dest, aRuleData); + MapSinglePropertyInto(physicalProp, src, dest, aRuleData); }); } diff --git a/layout/style/nsCSSPropAliasList.h b/layout/style/nsCSSPropAliasList.h index 73a75ceb8b..0ff732f6da 100644 --- a/layout/style/nsCSSPropAliasList.h +++ b/layout/style/nsCSSPropAliasList.h @@ -296,10 +296,6 @@ CSS_PROP_ALIAS(-webkit-border-bottom-right-radius, WebkitBorderBottomRightRadius, // really no dom property WEBKIT_PREFIX_PREF) -CSS_PROP_ALIAS(-webkit-appearance, - appearance, - WebkitAppearance, - WEBKIT_PREFIX_PREF) CSS_PROP_ALIAS(-webkit-background-clip, background_clip, WebkitBackgroundClip, @@ -327,21 +323,33 @@ CSS_PROP_ALIAS(-webkit-box-sizing, WebkitBoxSizing, WEBKIT_PREFIX_PREF) -// Alias old flexbox properties to modern flexbox pseudo-equivalents: +// Alias -webkit-box properties to their -moz-box equivalents. +// (NOTE: Even though they're aliases, in practice these -webkit properties +// will behave a bit differently from their -moz versions, if they're +// accompanied by "display:-webkit-box", because we generate a different frame +// for those two display values.) CSS_PROP_ALIAS(-webkit-box-flex, - flex_grow, + box_flex, WebkitBoxFlex, WEBKIT_PREFIX_PREF) CSS_PROP_ALIAS(-webkit-box-ordinal-group, - order, + box_ordinal_group, WebkitBoxOrdinalGroup, WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-box-orient, + box_orient, + WebkitBoxOrient, + WEBKIT_PREFIX_PREF) +CSS_PROP_ALIAS(-webkit-box-direction, + box_direction, + WebkitBoxDirection, + WEBKIT_PREFIX_PREF) CSS_PROP_ALIAS(-webkit-box-align, - align_items, + box_align, WebkitBoxAlign, WEBKIT_PREFIX_PREF) CSS_PROP_ALIAS(-webkit-box-pack, - justify_content, + box_pack, WebkitBoxPack, WEBKIT_PREFIX_PREF) diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h index c71927de70..3a76a486ef 100644 --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -1330,22 +1330,6 @@ CSS_PROP_XUL( kBoxOrientKTable, CSS_PROP_NO_OFFSET, eStyleAnimType_None) // XXX bug 3935 -/* We treat -webkit-box-orient as a writing-mode-aware logical alias - * for "flex-direction": */ -CSS_PROP_LOGICAL( - -webkit-box-orient, - webkit_box_orient, - WebkitBoxOrient, - CSS_PROPERTY_PARSE_VALUE | - CSS_PROPERTY_LOGICAL | - CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING, - "layout.css.prefixes.webkit", - VARIANT_HK, - kBoxOrientKTable, - WebkitBoxOrient, - Position, - CSS_PROP_NO_OFFSET, - eStyleAnimType_None) CSS_PROP_XUL( -moz-box-pack, box_pack, diff --git a/layout/style/nsCSSPropLogicalGroupList.h b/layout/style/nsCSSPropLogicalGroupList.h index 05371d9442..3d8a52bc90 100644 --- a/layout/style/nsCSSPropLogicalGroupList.h +++ b/layout/style/nsCSSPropLogicalGroupList.h @@ -44,17 +44,6 @@ // defined in nCSSProps.cpp named gLogicalGroupTable // containing the two physical properties in vertical/horizontal // order, followed by an nsCSSProperty_UNKNOWN entry. -// -// CSS_PROP_LOGICAL_GROUP_SINGLE(name_) -// Defines a logical property group in which the logical property always -// maps to the same physical property. For such properties, the -// "logicalness" is in the value-mapping, not in the property-mapping. For -// example, the logical property "-webkit-box-orient" is always mapped to -// "flex-direction", but its values ("horizontal", "vertical") map to -// different flex-direction values ("row", "column") depending on the -// writing-mode. A table must be defined in nsCSSProps.cpp named -// gLogicalGroupTable containing the one physical property, -// followed by an nsCSSProperty_UNKNOWN entry. CSS_PROP_LOGICAL_GROUP_SHORTHAND(BorderColor) CSS_PROP_LOGICAL_GROUP_SHORTHAND(BorderStyle) @@ -65,4 +54,3 @@ CSS_PROP_LOGICAL_GROUP_BOX(Offset) CSS_PROP_LOGICAL_GROUP_SHORTHAND(Padding) CSS_PROP_LOGICAL_GROUP_AXIS(MinSize) CSS_PROP_LOGICAL_GROUP_AXIS(Size) -CSS_PROP_LOGICAL_GROUP_SINGLE(WebkitBoxOrient) diff --git a/layout/style/nsCSSProperty.h b/layout/style/nsCSSProperty.h index aef29c96ee..0e0536da78 100644 --- a/layout/style/nsCSSProperty.h +++ b/layout/style/nsCSSProperty.h @@ -103,13 +103,10 @@ enum nsCSSPropertyLogicalGroup { eCSSPropertyLogicalGroup_##name_, #define CSS_PROP_LOGICAL_GROUP_BOX(name_) \ eCSSPropertyLogicalGroup_##name_, -#define CSS_PROP_LOGICAL_GROUP_SINGLE(name_) \ - eCSSPropertyLogicalGroup_##name_, #define CSS_PROP_LOGICAL_GROUP_SHORTHAND(name_) \ eCSSPropertyLogicalGroup_##name_, #include "nsCSSPropLogicalGroupList.h" #undef CSS_PROP_LOGICAL_GROUP_SHORTHAND -#undef CSS_PROP_LOGICAL_GROUP_SINGLE #undef CSS_PROP_LOGICAL_GROUP_BOX #undef CSS_PROP_LOGICAL_GROUP_AXIS eCSSPropertyLogicalGroup_COUNT diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp index 8dce5c61bc..5d7e99e97e 100644 --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -3026,19 +3026,12 @@ static const nsCSSProperty gSizeLogicalGroupTable[] = { eCSSProperty_UNKNOWN }; -static const nsCSSProperty gWebkitBoxOrientLogicalGroupTable[] = { - eCSSProperty_flex_direction, - eCSSProperty_UNKNOWN -}; - const nsCSSProperty* const nsCSSProps::kLogicalGroupTable[eCSSPropertyLogicalGroup_COUNT] = { #define CSS_PROP_LOGICAL_GROUP_SHORTHAND(id_) g##id_##SubpropTable, #define CSS_PROP_LOGICAL_GROUP_AXIS(name_) g##name_##LogicalGroupTable, #define CSS_PROP_LOGICAL_GROUP_BOX(name_) g##name_##LogicalGroupTable, -#define CSS_PROP_LOGICAL_GROUP_SINGLE(name_) g##name_##LogicalGroupTable, #include "nsCSSPropLogicalGroupList.h" -#undef CSS_PROP_LOGICAL_GROUP_SINGLE #undef CSS_PROP_LOGICAL_GROUP_BOX #undef CSS_PROP_LOGICAL_GROUP_AXIS #undef CSS_PROP_LOGICAL_GROUP_SHORTHAND @@ -3339,10 +3332,7 @@ nsCSSProps::gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands] = { "the CSS_PROPERTY_LOGICAL_BLOCK_AXIS flag"); \ static_assert(!((flags_) & CSS_PROPERTY_LOGICAL_END_EDGE), \ "only properties defined with CSS_PROP_LOGICAL can use " \ - "the CSS_PROPERTY_LOGICAL_END_EDGE flag"); \ - static_assert(!((flags_) & CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING),\ - "only properties defined with CSS_PROP_LOGICAL can use " \ - "the CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING flag"); + "the CSS_PROPERTY_LOGICAL_END_EDGE flag"); #define CSS_PROP_LOGICAL(name_, id_, method_, flags_, pref_, parsevariant_, \ kwtable_, group_, stylestruct_, \ stylestructoffset_, animtype_) \ @@ -3355,21 +3345,7 @@ nsCSSProps::gPropertyUseCounter[eCSSProperty_COUNT_no_shorthands] = { static_assert(!(((flags_) & CSS_PROPERTY_LOGICAL_AXIS) && \ ((flags_) & CSS_PROPERTY_LOGICAL_END_EDGE)), \ "CSS_PROPERTY_LOGICAL_END_EDGE makes no sense when used " \ - "with CSS_PROPERTY_LOGICAL_AXIS"); \ - /* Make sure CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING isn't used */ \ - /* with other mutually-exclusive flags: */ \ - static_assert(!(((flags_) & CSS_PROPERTY_LOGICAL_AXIS) && \ - ((flags_) & CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING)),\ - "CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING makes no " \ - "sense when used with CSS_PROPERTY_LOGICAL_AXIS"); \ - static_assert(!(((flags_) & CSS_PROPERTY_LOGICAL_BLOCK_AXIS) && \ - ((flags_) & CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING)),\ - "CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING makes no " \ - "sense when used with CSS_PROPERTY_LOGICAL_BLOCK_AXIS"); \ - static_assert(!(((flags_) & CSS_PROPERTY_LOGICAL_END_EDGE) && \ - ((flags_) & CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING)),\ - "CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING makes no " \ - "sense when used with CSS_PROPERTY_LOGICAL_END_EDGE"); + "with CSS_PROPERTY_LOGICAL_AXIS"); #include "nsCSSPropList.h" #undef CSS_PROP_LOGICAL #undef CSS_PROP diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h index f928407346..9c8a68bb01 100644 --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -226,6 +226,10 @@ static_assert((CSS_PROPERTY_PARSE_PROPERTY_MASK & // wrapped in "#ifndef CSS_PROP_LIST_EXCLUDE_INTERNAL". // Note that, these flags have no effect on the use of aliases of this // property. +// Furthermore, for the purposes of animation (including triggering +// transitions) these flags are ignored. That is, if the property is disabled +// by a pref, we will *not* run animations or transitions on it even in +// UA sheets or chrome. #define CSS_PROPERTY_ENABLED_MASK (3<<22) #define CSS_PROPERTY_ENABLED_IN_UA_SHEETS (1<<22) #define CSS_PROPERTY_ENABLED_IN_CHROME (1<<23) @@ -250,26 +254,20 @@ static_assert((CSS_PROPERTY_PARSE_PROPERTY_MASK & // margin-block-start or margin-inline-start). #define CSS_PROPERTY_LOGICAL_END_EDGE (1<<26) -// This property is a logical property which always maps to the same physical -// property, and its values have some custom processing when being mapped to -// the physical property's values. Must not be used in conjunction with -// CSS_PROPERTY_LOGICAL_{AXIS,BLOCK_AXIS,END_EDGE}. -#define CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING (1<<27) - // This property can be animated on the compositor. -#define CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR (1<<28) +#define CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR (1<<27) // This property is an internal property that is not represented // in the DOM. Properties with this flag must be defined in an #ifndef // CSS_PROP_LIST_EXCLUDE_INTERNAL section of nsCSSPropList.h. -#define CSS_PROPERTY_INTERNAL (1<<29) +#define CSS_PROPERTY_INTERNAL (1<<28) // This property has values that can establish a containing block for // fixed positioned and absolutely positioned elements. // This should be set for any properties that can cause an element to be // such a containing block, as implemented in // nsStyleDisplay::IsFixedPosContainingBlock. -#define CSS_PROPERTY_FIXPOS_CB (1<<30) +#define CSS_PROPERTY_FIXPOS_CB (1<<29) // This property has values that can establish a containing block for // absolutely positioned elements. @@ -278,10 +276,7 @@ static_assert((CSS_PROPERTY_PARSE_PROPERTY_MASK & // nsStyleDisplay::IsAbsPosContainingBlock. // It does not need to be set for properties that also have // CSS_PROPERTY_FIXPOS_CB set. -#define CSS_PROPERTY_ABSPOS_CB (1u<<31) - -// NOTE: Before adding any new CSS_PROPERTY_* flags here, we'll need to -// upgrade kFlagsTable to 64-bits -- see bug 1231384. +#define CSS_PROPERTY_ABSPOS_CB (1<<30) /** * Types of animatable values. @@ -555,11 +550,8 @@ public: * by the sentinel. * * When called with a property that has the CSS_PROPERTY_LOGICAL_AXIS - * flag, the returned array will have two values preceding the sentinel. - * When called with a property that has the - * CSS_PROPERTY_LOGICAL_SINGLE_CUSTOM_VALMAPPING flag, the returned array - * will have one value preceding the sentinel. - * Otherwise it will have four values preceding the sentinel. + * flag, the returned array will have two values preceding the sentinel; + * otherwise it will have four. * * (Note that the running time of this function is proportional to the * number of logical longhand properties that exist. If we start diff --git a/layout/style/nsCSSRuleProcessor.cpp b/layout/style/nsCSSRuleProcessor.cpp index 9f99b0ec03..9402c7e403 100644 --- a/layout/style/nsCSSRuleProcessor.cpp +++ b/layout/style/nsCSSRuleProcessor.cpp @@ -3209,7 +3209,7 @@ nsCSSRuleProcessor::ClearRuleCascades() // We rely on our caller (perhaps indirectly) to do something that // will rebuild style data and the user font set (either - // nsIPresShell::ReconstructStyleData or + // nsIPresShell::RestyleForCSSRuleChanges or // nsPresContext::RebuildAllStyleData). RuleCascadeData *data = mRuleCascades; mRuleCascades = nullptr; diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index 607fc70147..a51d93d7b6 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -5303,7 +5303,7 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct, display, parentDisplay, aRuleData, conditions); - display->mTransitions.SetLength(numTransitions); + display->mTransitions.SetLengthNonZero(numTransitions); FOR_ALL_TRANSITION_PROPS(p) { const TransitionPropInfo& i = transitionPropInfo[p]; @@ -5460,7 +5460,7 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct, display, parentDisplay, aRuleData, conditions); - display->mAnimations.SetLength(numAnimations); + display->mAnimations.SetLengthNonZero(numAnimations); FOR_ALL_ANIMATION_PROPS(p) { const TransitionPropInfo& i = animationPropInfo[p]; @@ -6779,8 +6779,8 @@ template static void SetImageLayerList(nsStyleContext* aStyleContext, const nsCSSValue& aValue, - AutoTArray< nsStyleImageLayers::Layer, 1> &aLayers, - const AutoTArray &aParentLayers, + nsStyleAutoArray& aLayers, + const nsStyleAutoArray& aParentLayers, ComputedValueItem nsStyleImageLayers::Layer::* aResultLocation, ComputedValueItem aInitialValue, uint32_t aParentItemCount, @@ -6844,9 +6844,8 @@ template static void SetImageLayerPairList(nsStyleContext* aStyleContext, const nsCSSValue& aValue, - AutoTArray< nsStyleImageLayers::Layer, 1> &aLayers, - const AutoTArray - &aParentLayers, + nsStyleAutoArray& aLayers, + const nsStyleAutoArray& aParentLayers, ComputedValueItem nsStyleImageLayers::Layer::* aResultLocation, ComputedValueItem aInitialValue, @@ -6911,7 +6910,8 @@ SetImageLayerPairList(nsStyleContext* aStyleContext, template static void -FillBackgroundList(AutoTArray< nsStyleImageLayers::Layer, 1> &aLayers, +FillBackgroundList( + nsStyleAutoArray& aLayers, ComputedValueItem nsStyleImageLayers::Layer::* aResultLocation, uint32_t aItemCount, uint32_t aFillCount) { @@ -7033,7 +7033,7 @@ nsRuleNode::ComputeBackgroundData(void* aStartStruct, if (rebuild) { // Delete any extra items. We need to keep layers in which any // property was specified. - bg->mImage.mLayers.TruncateLength(maxItemCount); + bg->mImage.mLayers.TruncateLengthNonZero(maxItemCount); uint32_t fillCount = bg->mImage.mImageCount; FillBackgroundList(bg->mImage.mLayers, @@ -9852,7 +9852,7 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct, if (rebuild) { // Delete any extra items. We need to keep layers in which any // property was specified. - svgReset->mMask.mLayers.TruncateLength(maxItemCount); + svgReset->mMask.mLayers.TruncateLengthNonZero(maxItemCount); uint32_t fillCount = svgReset->mMask.mImageCount; diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 6e8b8a5405..ea0306bb74 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2317,10 +2317,9 @@ nsStyleImageLayers::nsStyleImageLayers() , mMaskModeCount(1) , mBlendModeCount(1) , mCompositeCount(1) + , mLayers(nsStyleAutoArray::WITH_SINGLE_INITIAL_ELEMENT) { MOZ_COUNT_CTOR(nsStyleImageLayers); - mLayers.AppendElement(); - NS_ASSERTION(mLayers.Length() == 1, "auto array must have room for 1 element"); } nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers &aSource) @@ -2388,7 +2387,8 @@ nsStyleImageLayers::CalcDifference(const nsStyleImageLayers& aOther) const return hint; } - if (mBlendModeCount != aOther.mBlendModeCount || + if (mAttachmentCount != aOther.mAttachmentCount || + mBlendModeCount != aOther.mBlendModeCount || mClipCount != aOther.mClipCount || mCompositeCount != aOther.mCompositeCount || mMaskModeCount != aOther.mMaskModeCount || @@ -2406,7 +2406,12 @@ bool nsStyleImageLayers::HasLayerWithImage() const { for (uint32_t i = 0; i < mImageCount; i++) { - if (mLayers[i].mSourceURI) { + // mLayers[i].mSourceURI can be nullptr if mask-image prop value is + // or + // mLayers[i].mImage can be empty if mask-image prop value is a reference + // to SVG mask element. + // So we need to test both mSourceURI and mImage. + if (mLayers[i].mSourceURI || !mLayers[i].mImage.IsEmpty()) { return true; } } @@ -2832,6 +2837,8 @@ mozilla::StyleAnimation::operator==(const mozilla::StyleAnimation& aOther) const nsStyleDisplay::nsStyleDisplay(StyleStructContext aContext) : mWillChangeBitField(0) + , mTransitions(nsStyleAutoArray::WITH_SINGLE_INITIAL_ELEMENT) + , mAnimations(nsStyleAutoArray::WITH_SINGLE_INITIAL_ELEMENT) { MOZ_COUNT_CTOR(nsStyleDisplay); mAppearance = NS_THEME_NONE; @@ -2872,18 +2879,12 @@ nsStyleDisplay::nsStyleDisplay(StyleStructContext aContext) // Initial value for mScrollSnapDestination is "0px 0px" mScrollSnapDestination.SetInitialZeroValues(); - mTransitions.AppendElement(); - MOZ_ASSERT(mTransitions.Length() == 1, - "appending within auto buffer should never fail"); mTransitions[0].SetInitialValues(); mTransitionTimingFunctionCount = 1; mTransitionDurationCount = 1; mTransitionDelayCount = 1; mTransitionPropertyCount = 1; - mAnimations.AppendElement(); - MOZ_ASSERT(mAnimations.Length() == 1, - "appending within auto buffer should never fail"); mAnimations[0].SetInitialValues(); mAnimationTimingFunctionCount = 1; mAnimationDurationCount = 1; diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index a17fa45755..f530ee98a6 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -152,7 +152,7 @@ static_assert(offsetof(nsRect_Simple, width) == offsetof(nsRect, width), "Wrong static_assert(offsetof(nsRect_Simple, height) == offsetof(nsRect, height), "Wrong nsRect_Simple member alignment"); // The lifetime of these objects is managed by the presshell's arena. -struct nsStyleFont +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleFont { nsStyleFont(const nsFont& aFont, StyleStructContext aContext); nsStyleFont(const nsStyleFont& aStyleFont); @@ -421,7 +421,7 @@ private: #endif }; -struct nsStyleColor +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColor { explicit nsStyleColor(StyleStructContext aContext); nsStyleColor(const nsStyleColor& aOther); @@ -455,6 +455,65 @@ struct nsStyleColor nscolor mColor; // [inherited] }; +/** + * An array of objects, similar to AutoTArray but which is memmovable. It + * always has length >= 1. + */ +template +class nsStyleAutoArray +{ +public: + // This constructor places a single element in mFirstElement. + enum WithSingleInitialElement { WITH_SINGLE_INITIAL_ELEMENT }; + explicit nsStyleAutoArray(WithSingleInitialElement) {} + nsStyleAutoArray(const nsStyleAutoArray& aOther) { *this = aOther; } + nsStyleAutoArray& operator=(const nsStyleAutoArray& aOther) { + mFirstElement = aOther.mFirstElement; + mOtherElements = aOther.mOtherElements; + return *this; + } + + bool operator==(const nsStyleAutoArray& aOther) const { + return Length() == aOther.Length() && + mFirstElement == aOther.mFirstElement && + mOtherElements == aOther.mOtherElements; + } + bool operator!=(const nsStyleAutoArray& aOther) const { + return !(*this == aOther); + } + + size_t Length() const { + return mOtherElements.Length() + 1; + } + const T& operator[](size_t aIndex) const { + return aIndex == 0 ? mFirstElement : mOtherElements[aIndex - 1]; + } + T& operator[](size_t aIndex) { + return aIndex == 0 ? mFirstElement : mOtherElements[aIndex - 1]; + } + + void EnsureLengthAtLeast(size_t aMinLen) { + if (aMinLen > 0) { + mOtherElements.EnsureLengthAtLeast(aMinLen - 1); + } + } + + void SetLengthNonZero(size_t aNewLen) { + MOZ_ASSERT(aNewLen > 0); + mOtherElements.SetLength(aNewLen - 1); + } + + void TruncateLengthNonZero(size_t aNewLen) { + MOZ_ASSERT(aNewLen > 0); + MOZ_ASSERT(aNewLen <= Length()); + mOtherElements.TruncateLength(aNewLen - 1); + } + +private: + T mFirstElement; + nsTArray mOtherElements; +}; + struct nsStyleImageLayers { nsStyleImageLayers(); nsStyleImageLayers(const nsStyleImageLayers &aSource); @@ -695,7 +754,7 @@ struct nsStyleImageLayers { // layer. In layers below the bottom layer, properties will be // uninitialized unless their count, above, indicates that they are // present. - AutoTArray mLayers; + nsStyleAutoArray mLayers; const Layer& BottomLayer() const { return mLayers[mImageCount - 1]; } @@ -724,7 +783,7 @@ struct nsStyleImageLayers { for (uint32_t var_ = (start_) + 1; var_-- != (uint32_t)((start_) + 1 - (count_)); ) }; -struct nsStyleBackground { +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBackground { explicit nsStyleBackground(StyleStructContext aContext); nsStyleBackground(const nsStyleBackground& aOther); ~nsStyleBackground(); @@ -777,7 +836,7 @@ struct nsStyleBackground { #define NS_SPACING_BORDER 2 -struct nsStyleMargin +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleMargin { explicit nsStyleMargin(StyleStructContext aContext); nsStyleMargin(const nsStyleMargin& aMargin); @@ -823,7 +882,7 @@ protected: }; -struct nsStylePadding +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePadding { explicit nsStylePadding(StyleStructContext aContext); nsStylePadding(const nsStylePadding& aPadding); @@ -1026,7 +1085,7 @@ static bool IsVisibleBorderStyle(uint8_t aStyle) aStyle != NS_STYLE_BORDER_STYLE_HIDDEN); } -struct nsStyleBorder +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder { explicit nsStyleBorder(StyleStructContext aContext); nsStyleBorder(const nsStyleBorder& aBorder); @@ -1253,7 +1312,7 @@ private: }; -struct nsStyleOutline +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleOutline { explicit nsStyleOutline(StyleStructContext aContext); nsStyleOutline(const nsStyleOutline& aOutline); @@ -1364,7 +1423,7 @@ private: ~nsStyleQuoteValues() {} }; -struct nsStyleList +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList { explicit nsStyleList(StyleStructContext aContext); nsStyleList(const nsStyleList& aStyleList); @@ -1570,7 +1629,7 @@ struct nsStyleTextOverflow bool mLogicalDirections; // true when only one value was specified }; -struct nsStyleTextReset +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTextReset { explicit nsStyleTextReset(StyleStructContext aContext); nsStyleTextReset(const nsStyleTextReset& aOther); @@ -1655,7 +1714,7 @@ protected: nscolor mTextDecorationColor; // [reset] the colors to use for a decoration lines, not used at currentColor }; -struct nsStyleText +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText { explicit nsStyleText(StyleStructContext aContext); nsStyleText(const nsStyleText& aOther); @@ -1872,7 +1931,7 @@ protected: uint8_t mOrientation; }; -struct nsStyleVisibility +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleVisibility { explicit nsStyleVisibility(StyleStructContext aContext); nsStyleVisibility(const nsStyleVisibility& aVisibility); @@ -2153,7 +2212,7 @@ private: } // namespace mozilla -struct nsStyleDisplay +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay { explicit nsStyleDisplay(StyleStructContext aContext); nsStyleDisplay(const nsStyleDisplay& aOther); @@ -2224,7 +2283,7 @@ struct nsStyleDisplay // match mWillChange. Also tracks if any of the // properties in the will-change list require // a stacking context. - AutoTArray mWillChange; + nsTArray mWillChange; uint8_t mTouchAction; // [reset] see nsStyleConsts.h uint8_t mScrollBehavior; // [reset] see nsStyleConsts.h NS_STYLE_SCROLL_BEHAVIOR_* @@ -2249,7 +2308,7 @@ struct nsStyleDisplay nsStyleCoord mVerticalAlign; // [reset] coord, percent, calc, enum (see nsStyleConsts.h) - AutoTArray mTransitions; // [reset] + nsStyleAutoArray mTransitions; // [reset] // The number of elements in mTransitions that are not from repeating // a list due to another property being longer. uint32_t mTransitionTimingFunctionCount, @@ -2257,7 +2316,7 @@ struct nsStyleDisplay mTransitionDelayCount, mTransitionPropertyCount; - AutoTArray mAnimations; // [reset] + nsStyleAutoArray mAnimations; // [reset] // The number of elements in mAnimations that are not from repeating // a list due to another property being longer. uint32_t mAnimationTimingFunctionCount, @@ -2425,7 +2484,7 @@ struct nsStyleDisplay inline uint8_t PhysicalBreakType(mozilla::WritingMode aWM) const; }; -struct nsStyleTable +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTable { explicit nsStyleTable(StyleStructContext aContext); nsStyleTable(const nsStyleTable& aOther); @@ -2536,7 +2595,7 @@ struct nsStyleGridTemplate } }; -struct nsStylePosition +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition { explicit nsStylePosition(StyleStructContext aContext); nsStylePosition(const nsStylePosition& aOther); @@ -2730,7 +2789,7 @@ private: }; -struct nsStyleTableBorder +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTableBorder { explicit nsStyleTableBorder(StyleStructContext aContext); nsStyleTableBorder(const nsStyleTableBorder& aOther); @@ -2830,7 +2889,7 @@ struct nsStyleCounterData #define DELETE_ARRAY_IF(array) if (array) { delete[] array; array = nullptr; } -struct nsStyleContent +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent { explicit nsStyleContent(StyleStructContext aContext); nsStyleContent(const nsStyleContent& aContent); @@ -2941,7 +3000,7 @@ protected: uint32_t mResetCount; }; -struct nsStyleUIReset +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset { explicit nsStyleUIReset(StyleStructContext aContext); nsStyleUIReset(const nsStyleUIReset& aOther); @@ -3007,7 +3066,7 @@ private: nsCOMPtr mImage; }; -struct nsStyleUserInterface +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUserInterface { explicit nsStyleUserInterface(StyleStructContext aContext); nsStyleUserInterface(const nsStyleUserInterface& aOther); @@ -3058,7 +3117,7 @@ struct nsStyleUserInterface inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const; }; -struct nsStyleXUL +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleXUL { explicit nsStyleXUL(StyleStructContext aContext); nsStyleXUL(const nsStyleXUL& aSource); @@ -3096,7 +3155,7 @@ struct nsStyleXUL bool mStretchStack; // [reset] see nsStyleConsts.h }; -struct nsStyleColumn +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColumn { explicit nsStyleColumn(StyleStructContext aContext); nsStyleColumn(const nsStyleColumn& aSource); @@ -3191,7 +3250,7 @@ struct nsStyleSVGPaint } }; -struct nsStyleSVG +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG { explicit nsStyleSVG(StyleStructContext aContext); nsStyleSVG(const nsStyleSVG& aSource); @@ -3477,7 +3536,7 @@ struct nsTArray_CopyChooser typedef nsTArray_CopyWithConstructors Type; }; -struct nsStyleSVGReset +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVGReset { explicit nsStyleSVGReset(StyleStructContext aContext); nsStyleSVGReset(const nsStyleSVGReset& aSource); @@ -3527,7 +3586,7 @@ struct nsStyleSVGReset uint8_t mMaskType; // [reset] see nsStyleConsts.h }; -struct nsStyleVariables +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleVariables { explicit nsStyleVariables(StyleStructContext aContext); nsStyleVariables(const nsStyleVariables& aSource); @@ -3557,7 +3616,7 @@ struct nsStyleVariables mozilla::CSSVariableValues mVariables; }; -struct nsStyleEffects +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleEffects { explicit nsStyleEffects(StyleStructContext aContext); nsStyleEffects(const nsStyleEffects& aSource); diff --git a/layout/style/nsStyleTransformMatrix.cpp b/layout/style/nsStyleTransformMatrix.cpp index 60d15e2330..d1d14078ae 100644 --- a/layout/style/nsStyleTransformMatrix.cpp +++ b/layout/style/nsStyleTransformMatrix.cpp @@ -639,6 +639,7 @@ MatrixForTransformFunction(Matrix4x4& aMatrix, break; case eCSSKeyword_rotatez: *aContains3dTransform = true; + MOZ_FALLTHROUGH; case eCSSKeyword_rotate: ProcessRotateZ(aMatrix, aData); break; diff --git a/layout/style/nsTransitionManager.cpp b/layout/style/nsTransitionManager.cpp index 67c8937333..76c4beaf81 100644 --- a/layout/style/nsTransitionManager.cpp +++ b/layout/style/nsTransitionManager.cpp @@ -63,13 +63,11 @@ ElementPropertyTransition::CurrentValuePortion() const MOZ_ASSERT(!computedTiming.mProgress.IsNull(), "Got a null progress for a fill mode of 'both'"); - MOZ_ASSERT(mProperties.Length() == 1, - "Should have one animation property for a transition"); - MOZ_ASSERT(mProperties[0].mSegments.Length() == 1, - "Animation property should have one segment for a transition"); - return ComputedTimingFunction::GetPortion( - mProperties[0].mSegments[0].mTimingFunction, - computedTiming.mProgress.Value(), computedTiming.mBeforeFlag); + MOZ_ASSERT(mFrames.Length() == 2, + "Should have two animation frames for a transition"); + return ComputedTimingFunction::GetPortion(mFrames[0].mTimingFunction, + computedTiming.mProgress.Value(), + computedTiming.mBeforeFlag); } ////////////////////////// CSSTransition //////////////////////////// @@ -135,16 +133,6 @@ CSSTransition::QueueEvents() mOwningElement.GetElement(owningElement, owningPseudoType); MOZ_ASSERT(owningElement, "Owning element should be set"); - // Do not queue any event for disabled properties. This could happen - // if the property has a default value which derives value from other - // property, e.g. color. - nsCSSProperty property = TransitionProperty(); - if (!nsCSSProps::IsEnabled(property, nsCSSProps::eEnabledForAllContent) && - (!nsContentUtils::IsSystemPrincipal(owningElement->NodePrincipal()) || - !nsCSSProps::IsEnabled(property, nsCSSProps::eEnabledInChrome))) { - return; - } - nsPresContext* presContext = mOwningElement.GetRenderedPresContext(); if (!presContext) { return; @@ -152,7 +140,7 @@ CSSTransition::QueueEvents() nsTransitionManager* manager = presContext->TransitionManager(); manager->QueueEvent(TransitionEventInfo(owningElement, owningPseudoType, - property, + TransitionProperty(), mEffect->GetComputedTiming() .mDuration, AnimationTimeToTimeStamp(EffectEnd()), @@ -178,6 +166,17 @@ CSSTransition::TransitionProperty() const return effect->AsTransition()->TransitionProperty(); } +StyleAnimationValue +CSSTransition::ToValue() const +{ + // FIXME: Once we support replacing/removing the effect (bug 1049975) + // the following assertion will no longer hold. + dom::KeyframeEffectReadOnly* effect = GetEffect(); + MOZ_ASSERT(effect && effect->AsTransition(), + "Transition should have a transition effect"); + return effect->AsTransition()->ToValue(); +} + bool CSSTransition::HasLowerCompositeOrderThan(const CSSTransition& aOther) const { @@ -335,131 +334,12 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement, nsAutoAnimationMutationBatch mb(aElement->OwnerDoc()); - // Per http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html - // I'll consider only the transitions from the number of items in - // 'transition-property' on down, and later ones will override earlier - // ones (tracked using |whichStarted|). - bool startedAny = false; - nsCSSPropertySet whichStarted; - for (uint32_t i = disp->mTransitionPropertyCount; i-- != 0; ) { - const StyleTransition& t = disp->mTransitions[i]; - // Check the combined duration (combination of delay and duration) - // first, since it defaults to zero, which means we can ignore the - // transition. - if (t.GetCombinedDuration() > 0.0f) { - // We might have something to transition. See if any of the - // properties in question changed and are animatable. - // FIXME: Would be good to find a way to share code between this - // interpretation of transition-property and the one below. - nsCSSProperty property = t.GetProperty(); - if (property == eCSSPropertyExtra_no_properties || - property == eCSSPropertyExtra_variable || - property == eCSSProperty_UNKNOWN) { - // Nothing to do, but need to exclude this from cases below. - } else if (property == eCSSPropertyExtra_all_properties) { - for (nsCSSProperty p = nsCSSProperty(0); - p < eCSSProperty_COUNT_no_shorthands; - p = nsCSSProperty(p + 1)) { - ConsiderStartingTransition(p, t, aElement, collection, - aOldStyleContext, afterChangeStyle, - &startedAny, &whichStarted); - } - } else if (nsCSSProps::IsShorthand(property)) { - CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES( - subprop, property, nsCSSProps::eEnabledForAllContent) { - ConsiderStartingTransition(*subprop, t, aElement, collection, - aOldStyleContext, afterChangeStyle, - &startedAny, &whichStarted); - } - } else { - ConsiderStartingTransition(property, t, aElement, collection, - aOldStyleContext, afterChangeStyle, - &startedAny, &whichStarted); - } - } - } - - // Stop any transitions for properties that are no longer in - // 'transition-property', including finished transitions. - // Also stop any transitions (and remove any finished transitions) - // for properties that just changed (and are still in the set of - // properties to transition), but for which we didn't just start the - // transition. This can happen delay and duration are both zero, or - // because the new value is not interpolable. - // Note that we also do the latter set of work in - // nsTransitionManager::PruneCompletedTransitions. - if (collection) { - bool checkProperties = - disp->mTransitions[0].GetProperty() != eCSSPropertyExtra_all_properties; - nsCSSPropertySet allTransitionProperties; - if (checkProperties) { - for (uint32_t i = disp->mTransitionPropertyCount; i-- != 0; ) { - const StyleTransition& t = disp->mTransitions[i]; - // FIXME: Would be good to find a way to share code between this - // interpretation of transition-property and the one above. - nsCSSProperty property = t.GetProperty(); - if (property == eCSSPropertyExtra_no_properties || - property == eCSSPropertyExtra_variable || - property == eCSSProperty_UNKNOWN) { - // Nothing to do, but need to exclude this from cases below. - } else if (property == eCSSPropertyExtra_all_properties) { - for (nsCSSProperty p = nsCSSProperty(0); - p < eCSSProperty_COUNT_no_shorthands; - p = nsCSSProperty(p + 1)) { - allTransitionProperties.AddProperty(p); - } - } else if (nsCSSProps::IsShorthand(property)) { - CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES( - subprop, property, nsCSSProps::eEnabledForAllContent) { - allTransitionProperties.AddProperty(*subprop); - } - } else { - allTransitionProperties.AddProperty(property); - } - } - } - - OwningCSSTransitionPtrArray& animations = collection->mAnimations; - size_t i = animations.Length(); - MOZ_ASSERT(i != 0, "empty transitions list?"); - StyleAnimationValue currentValue; - do { - --i; - CSSTransition* anim = animations[i]; - dom::KeyframeEffectReadOnly* effect = anim->GetEffect(); - MOZ_ASSERT(effect && effect->Properties().Length() == 1, - "Should have one animation property for a transition"); - MOZ_ASSERT(effect && effect->Properties()[0].mSegments.Length() == 1, - "Animation property should have one segment for a transition"); - const AnimationProperty& prop = effect->Properties()[0]; - const AnimationPropertySegment& segment = prop.mSegments[0]; - // properties no longer in 'transition-property' - if ((checkProperties && - !allTransitionProperties.HasProperty(prop.mProperty)) || - // properties whose computed values changed but for which we - // did not start a new transition (because delay and - // duration are both zero, or because the new value is not - // interpolable); a new transition would have segment.mToValue - // matching currentValue - !ExtractComputedValueForTransition(prop.mProperty, afterChangeStyle, - currentValue) || - currentValue != segment.mToValue) { - // stop the transition - if (anim->HasCurrentEffect()) { - EffectSet* effectSet = EffectSet::GetEffectSet(aElement, pseudoType); - if (effectSet) { - effectSet->UpdateAnimationGeneration(mPresContext); - } - } - anim->CancelFromStyle(); - animations.RemoveElementAt(i); - } - } while (i != 0); - - if (animations.IsEmpty()) { - collection->Destroy(); - collection = nullptr; - } + DebugOnly startedAny = false; + // We don't have to update transitions if display:none, although we will + // cancel them after restyling. + if (!afterChangeStyle->IsInDisplayNoneSubtree()) { + startedAny = UpdateTransitions(disp, aElement, collection, + aOldStyleContext, afterChangeStyle); } MOZ_ASSERT(!startedAny || collection, @@ -491,6 +371,145 @@ nsTransitionManager::StyleContextChanged(dom::Element *aElement, } } +bool +nsTransitionManager::UpdateTransitions( + const nsStyleDisplay* aDisp, + dom::Element* aElement, + CSSTransitionCollection*& aElementTransitions, + nsStyleContext* aOldStyleContext, + nsStyleContext* aNewStyleContext) +{ + MOZ_ASSERT(aDisp, "Null nsStyleDisplay"); + MOZ_ASSERT(!aElementTransitions || + aElementTransitions->mElement == aElement, "Element mismatch"); + + // Per http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html + // I'll consider only the transitions from the number of items in + // 'transition-property' on down, and later ones will override earlier + // ones (tracked using |whichStarted|). + bool startedAny = false; + nsCSSPropertySet whichStarted; + for (uint32_t i = aDisp->mTransitionPropertyCount; i-- != 0; ) { + const StyleTransition& t = aDisp->mTransitions[i]; + // Check the combined duration (combination of delay and duration) + // first, since it defaults to zero, which means we can ignore the + // transition. + if (t.GetCombinedDuration() > 0.0f) { + // We might have something to transition. See if any of the + // properties in question changed and are animatable. + // FIXME: Would be good to find a way to share code between this + // interpretation of transition-property and the one below. + nsCSSProperty property = t.GetProperty(); + if (property == eCSSPropertyExtra_no_properties || + property == eCSSPropertyExtra_variable || + property == eCSSProperty_UNKNOWN) { + // Nothing to do, but need to exclude this from cases below. + } else if (property == eCSSPropertyExtra_all_properties) { + for (nsCSSProperty p = nsCSSProperty(0); + p < eCSSProperty_COUNT_no_shorthands; + p = nsCSSProperty(p + 1)) { + ConsiderStartingTransition(p, t, aElement, aElementTransitions, + aOldStyleContext, aNewStyleContext, + &startedAny, &whichStarted); + } + } else if (nsCSSProps::IsShorthand(property)) { + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subprop, property, + nsCSSProps::eEnabledForAllContent) + { + ConsiderStartingTransition(*subprop, t, aElement, aElementTransitions, + aOldStyleContext, aNewStyleContext, + &startedAny, &whichStarted); + } + } else { + ConsiderStartingTransition(property, t, aElement, aElementTransitions, + aOldStyleContext, aNewStyleContext, + &startedAny, &whichStarted); + } + } + } + + // Stop any transitions for properties that are no longer in + // 'transition-property', including finished transitions. + // Also stop any transitions (and remove any finished transitions) + // for properties that just changed (and are still in the set of + // properties to transition), but for which we didn't just start the + // transition. This can happen delay and duration are both zero, or + // because the new value is not interpolable. + // Note that we also do the latter set of work in + // nsTransitionManager::PruneCompletedTransitions. + if (aElementTransitions) { + bool checkProperties = + aDisp->mTransitions[0].GetProperty() != eCSSPropertyExtra_all_properties; + nsCSSPropertySet allTransitionProperties; + if (checkProperties) { + for (uint32_t i = aDisp->mTransitionPropertyCount; i-- != 0; ) { + const StyleTransition& t = aDisp->mTransitions[i]; + // FIXME: Would be good to find a way to share code between this + // interpretation of transition-property and the one above. + nsCSSProperty property = t.GetProperty(); + if (property == eCSSPropertyExtra_no_properties || + property == eCSSPropertyExtra_variable || + property == eCSSProperty_UNKNOWN) { + // Nothing to do, but need to exclude this from cases below. + } else if (property == eCSSPropertyExtra_all_properties) { + for (nsCSSProperty p = nsCSSProperty(0); + p < eCSSProperty_COUNT_no_shorthands; + p = nsCSSProperty(p + 1)) { + allTransitionProperties.AddProperty(p); + } + } else if (nsCSSProps::IsShorthand(property)) { + CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES( + subprop, property, nsCSSProps::eEnabledForAllContent) { + allTransitionProperties.AddProperty(*subprop); + } + } else { + allTransitionProperties.AddProperty(property); + } + } + } + + OwningCSSTransitionPtrArray& animations = aElementTransitions->mAnimations; + size_t i = animations.Length(); + MOZ_ASSERT(i != 0, "empty transitions list?"); + StyleAnimationValue currentValue; + do { + --i; + CSSTransition* anim = animations[i]; + // properties no longer in 'transition-property' + if ((checkProperties && + !allTransitionProperties.HasProperty(anim->TransitionProperty())) || + // properties whose computed values changed but for which we + // did not start a new transition (because delay and + // duration are both zero, or because the new value is not + // interpolable); a new transition would have anim->ToValue() + // matching currentValue + !ExtractComputedValueForTransition(anim->TransitionProperty(), + aNewStyleContext, + currentValue) || + currentValue != anim->ToValue()) { + // stop the transition + if (anim->HasCurrentEffect()) { + EffectSet* effectSet = + EffectSet::GetEffectSet(aElement, + aNewStyleContext->GetPseudoType()); + if (effectSet) { + effectSet->UpdateAnimationGeneration(mPresContext); + } + } + anim->CancelFromStyle(); + animations.RemoveElementAt(i); + } + } while (i != 0); + + if (animations.IsEmpty()) { + aElementTransitions->Destroy(); + aElementTransitions = nullptr; + } + } + + return startedAny; +} + void nsTransitionManager::ConsiderStartingTransition( nsCSSProperty aProperty, @@ -508,6 +527,13 @@ nsTransitionManager::ConsiderStartingTransition( NS_ASSERTION(!aElementTransitions || aElementTransitions->mElement == aElement, "Element mismatch"); + // Ignore disabled properties. We can arrive here if the transition-property + // is 'all' and the disabled property has a default value which derives value + // from another property, e.g. color. + if (!nsCSSProps::IsEnabled(aProperty, nsCSSProps::eEnabledForAllContent)) { + return; + } + if (aWhichStarted->HasProperty(aProperty)) { // A later item in transition-property already started a // transition for this property, so we ignore this one. @@ -667,19 +693,9 @@ nsTransitionManager::ConsiderStartingTransition( aNewStyleContext->GetPseudoType(), timing, startForReversingTest, reversePortion); - AnimationProperty& prop = *pt->Properties().AppendElement(); - prop.mProperty = aProperty; - - AnimationPropertySegment& segment = *prop.mSegments.AppendElement(); - segment.mFromValue = startValue; - segment.mToValue = endValue; - segment.mFromKey = 0; - segment.mToKey = 1; - if (tf.mType != nsTimingFunction::Type::Linear) { - ComputedTimingFunction computedTimingFunction; - computedTimingFunction.Init(tf); - segment.mTimingFunction = Some(computedTimingFunction); - } + pt->SetFrames(GetTransitionKeyframes(aNewStyleContext, aProperty, + Move(startValue), Move(endValue), tf), + aNewStyleContext); MOZ_ASSERT(mPresContext->RestyleManager()->IsGecko(), "ServoRestyleManager should not use nsTransitionManager " @@ -747,6 +763,43 @@ nsTransitionManager::ConsiderStartingTransition( aWhichStarted->AddProperty(aProperty); } +static Keyframe& +AppendKeyframe(double aOffset, nsCSSProperty aProperty, + StyleAnimationValue&& aValue, nsTArray& aKeyframes) +{ + Keyframe& frame = *aKeyframes.AppendElement(); + frame.mOffset.emplace(aOffset); + PropertyValuePair& pv = *frame.mPropertyValues.AppendElement(); + pv.mProperty = aProperty; + DebugOnly uncomputeResult = + StyleAnimationValue::UncomputeValue(aProperty, Move(aValue), pv.mValue); + MOZ_ASSERT(uncomputeResult, + "Unable to get specified value from computed value"); + return frame; +} + +nsTArray +nsTransitionManager::GetTransitionKeyframes( + nsStyleContext* aStyleContext, + nsCSSProperty aProperty, + StyleAnimationValue&& aStartValue, + StyleAnimationValue&& aEndValue, + const nsTimingFunction& aTimingFunction) +{ + nsTArray keyframes(2); + + Keyframe& fromFrame = AppendKeyframe(0.0, aProperty, Move(aStartValue), + keyframes); + if (aTimingFunction.mType != nsTimingFunction::Type::Linear) { + fromFrame.mTimingFunction.emplace(); + fromFrame.mTimingFunction->Init(aTimingFunction); + } + + AppendKeyframe(1.0, aProperty, Move(aEndValue), keyframes); + + return keyframes; +} + void nsTransitionManager::PruneCompletedTransitions(mozilla::dom::Element* aElement, CSSPseudoElementType aPseudoType, @@ -775,20 +828,13 @@ nsTransitionManager::PruneCompletedTransitions(mozilla::dom::Element* aElement, continue; } - dom::KeyframeEffectReadOnly* effect = anim->GetEffect(); - MOZ_ASSERT(effect->Properties().Length() == 1, - "Should have one animation property for a transition"); - MOZ_ASSERT(effect->Properties()[0].mSegments.Length() == 1, - "Animation property should have one segment for a transition"); - const AnimationProperty& prop = effect->Properties()[0]; - const AnimationPropertySegment& segment = prop.mSegments[0]; - // Since effect is a finished transition, we know it didn't // influence style. StyleAnimationValue currentValue; - if (!ExtractComputedValueForTransition(prop.mProperty, aNewStyleContext, + if (!ExtractComputedValueForTransition(anim->TransitionProperty(), + aNewStyleContext, currentValue) || - currentValue != segment.mToValue) { + currentValue != anim->ToValue()) { anim->CancelFromStyle(); animations.RemoveElementAt(i); } diff --git a/layout/style/nsTransitionManager.h b/layout/style/nsTransitionManager.h index a33b9bbbd0..6617cbb5bc 100644 --- a/layout/style/nsTransitionManager.h +++ b/layout/style/nsTransitionManager.h @@ -23,6 +23,7 @@ class nsCSSPropertySet; namespace mozilla { enum class CSSPseudoElementType : uint8_t; +struct Keyframe; struct StyleTransition; } // namespace mozilla @@ -52,19 +53,28 @@ struct ElementPropertyTransition : public dom::KeyframeEffectReadOnly } nsCSSProperty TransitionProperty() const { - MOZ_ASSERT(mProperties.Length() == 1, - "Transitions should have exactly one animation property. " + MOZ_ASSERT(mFrames.Length() == 2, + "Transitions should have exactly two animation frames. " "Perhaps we are using an un-initialized transition?"); - return mProperties[0].mProperty; + MOZ_ASSERT(mFrames[0].mPropertyValues.Length() == 1, + "Transitions should have exactly one property in their first " + "frame"); + return mFrames[0].mPropertyValues[0].mProperty; } StyleAnimationValue ToValue() const { - MOZ_ASSERT(mProperties.Length() == 1, - "Transitions should have exactly one animation property"); - MOZ_ASSERT(mProperties[0].mSegments.Length() == 1, - "Transitions should have one animation property segment "); + // If we failed to generate properties from the transition frames, + // return a null value but also show a warning since we should be + // detecting that kind of situation in advance and not generating a + // transition in the first place. + if (mProperties.Length() < 1 || + mProperties[0].mSegments.Length() < 1) { + NS_WARNING("Failed to generate transition property values"); + return StyleAnimationValue(); + } return mProperties[0].mSegments[0].mToValue; } + // This is the start value to be used for a check for whether a // transition is being reversed. Normally the same as // mProperties[0].mSegments[0].mFromValue, except when this transition @@ -147,6 +157,7 @@ public: void Tick() override; nsCSSProperty TransitionProperty() const; + StyleAnimationValue ToValue() const; bool HasLowerCompositeOrderThan(const CSSTransition& aOther) const; EffectCompositor::CascadeLevel CascadeLevel() const override @@ -250,10 +261,10 @@ struct TransitionEventInfo { , mTimeStamp(aTimeStamp) { // XXX Looks like nobody initialize WidgetEvent::time - mEvent.propertyName = + mEvent.mPropertyName = NS_ConvertUTF8toUTF16(nsCSSProps::GetStringValue(aProperty)); - mEvent.elapsedTime = aDuration.ToSeconds(); - mEvent.pseudoElement = + mEvent.mElapsedTime = aDuration.ToSeconds(); + mEvent.mPseudoElement = AnimationCollection::PseudoTypeAsString(aPseudoType); } @@ -351,6 +362,17 @@ protected: typedef nsTArray> OwningCSSTransitionPtrArray; + // Update the transitions. It'd start new, replace, or stop current + // transitions if need. aDisp and aElement shouldn't be nullptr. + // aElementTransitions is the collection of current transitions, and it + // could be a nullptr if we don't have any transitions. + bool + UpdateTransitions(const nsStyleDisplay* aDisp, + mozilla::dom::Element* aElement, + CSSTransitionCollection*& aElementTransitions, + nsStyleContext* aOldStyleContext, + nsStyleContext* aNewStyleContext); + void ConsiderStartingTransition(nsCSSProperty aProperty, const mozilla::StyleTransition& aTransition, @@ -361,6 +383,13 @@ protected: bool* aStartedAny, nsCSSPropertySet* aWhichStarted); + nsTArray GetTransitionKeyframes( + nsStyleContext* aStyleContext, + nsCSSProperty aProperty, + mozilla::StyleAnimationValue&& aStartValue, + mozilla::StyleAnimationValue&& aEndValue, + const nsTimingFunction& aTimingFunction); + bool mInAnimationOnlyStyleUpdate; mozilla::DelayedEventDispatcher diff --git a/layout/style/test/mochitest.ini b/layout/style/test/mochitest.ini index 98d20728bd..5eb83a158a 100644 --- a/layout/style/test/mochitest.ini +++ b/layout/style/test/mochitest.ini @@ -264,6 +264,8 @@ skip-if = (android_version == '18' && debug) # bug 1159532 [test_transitions_per_property.html] skip-if = buildapp == 'b2g' || toolkit == 'android' #bug 775227 # b2g(times out, needs more time + various failures) b2g-debug(times out, needs more time + various failures) b2g-desktop(times out, needs more time + various failures) [test_transitions_step_functions.html] +[test_transitions_with_displaynone.html] +[test_transitions_with_disabled_properties.html] [test_unclosed_parentheses.html] [test_unicode_range_loading.html] support-files = ../../reftests/fonts/markA.woff ../../reftests/fonts/markB.woff ../../reftests/fonts/markC.woff ../../reftests/fonts/markD.woff @@ -298,6 +300,5 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(bug 870262, skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(bug 870262, :visited support) b2g-debug(bug 870262, :visited support) b2g-desktop(bug 870262, :visited support) [test_visited_reftests.html] skip-if = buildapp == 'b2g' || toolkit == 'android' #TIMED_OUT # b2g(bug 870262, :visited support) b2g-debug(bug 870262, :visited support) b2g-desktop(bug 870262, :visited support) -[test_webkit_box_orient.html] [test_webkit_device_pixel_ratio.html] [test_asyncopen2.html] diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js index 42ea3f4441..c19c0f2858 100644 --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -665,7 +665,7 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) { "-webkit-gradient(linear, 1 2, 3 4, color-stop(0, rgb(1,2,3)))", "-webkit-gradient(linear, 1 2, 3 4, color-stop(0, #00ff00))", "-webkit-gradient(linear, 1 2, 3 4, color-stop(0, #00f))", - "-webkit-gradient(linear, 1 2, 3 4, color-stop(0, hsla(240, 30%, 50%, 0.9)))", + "-webkit-gradient(linear, 1 2, 3 4, color-stop(0, hsla(240, 30%, 50%, 0.8)))", "-webkit-gradient(linear, 1 2, 3 4, color-stop(0, rgba(255, 230, 10, 0.5)))", // linear w/ multiple color stops: @@ -4331,7 +4331,7 @@ var gCSSProperties = { initial_values: [ "auto", "normal" ], other_values: [ "start", "end", "flex-start", "flex-end", "self-start", "self-end", "center", "left", "right", "baseline", - "last-baseline", "stretch", "left true", "true right", + "last-baseline", "stretch", "left unsafe", "unsafe right", "safe right", "center safe" ], invalid_values: [ "space-between", "abc", "30px", "none", "legacy left", "right legacy" ] @@ -4875,25 +4875,6 @@ function logical_box_prop_get_computed(cs, property) return cs.getPropertyValue(property); } -// Helper to get computed style of "-webkit-box-orient" from "flex-direction" -// and the "writing-mode". -function webkit_orient_get_computed(cs, property) -{ - var writingMode = cs.getPropertyValue("writing-mode") || "horizontal-tb"; - - var mapping; // map from flex-direction values to -webkit-box-orient values. - if (writingMode == "horizontal-tb") { - // Horizontal writing-mode - mapping = { "row" : "horizontal", "column" : "vertical"}; - } else { - // Vertical writing-mode - mapping = { "row" : "vertical", "column" : "horizontal"}; - } - - var flexDirection = cs.getPropertyValue("flex-direction"); - return mapping[flexDirection]; -} - // Get the computed value for a property. For shorthands, return the // computed values of all the subproperties, delimited by " ; ". function get_computed_value(cs, property) @@ -6590,17 +6571,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.background-blend-mode.enabled")) { }; } -if (SpecialPowers.getBoolPref("layout.css.will-change.enabled")) { - gCSSProperties["will-change"] = { - domProp: "willChange", - inherited: false, - type: CSS_TYPE_LONGHAND, - initial_values: [ "auto" ], - other_values: [ "scroll-position", "contents", "transform", "opacity", "scroll-position, transform", "transform, opacity", "contents, transform", "property-that-doesnt-exist-yet" ], - invalid_values: [ "none", "all", "default", "auto, scroll-position", "scroll-position, auto", "transform scroll-position", ",", "trailing,", "will-change", "transform, will-change" ] - }; -} - if (IsCSSPropertyPrefEnabled("layout.css.object-fit-and-position.enabled")) { gCSSProperties["object-fit"] = { domProp: "objectFit", @@ -7216,13 +7186,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) { alias_for: "border-bottom-right-radius", subproperties: [ "border-bottom-right-radius" ], }; - gCSSProperties["-webkit-appearance"] = { - domProp: "webkitAppearance", - inherited: false, - type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "-moz-appearance", - subproperties: [ "-moz-appearance" ], - }; gCSSProperties["-webkit-background-clip"] = { domProp: "webkitBackgroundClip", inherited: false, @@ -7269,44 +7232,43 @@ if (IsCSSPropertyPrefEnabled("layout.css.prefixes.webkit")) { domProp: "webkitBoxFlex", inherited: false, type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "flex-grow", - subproperties: [ "flex-grow" ], + alias_for: "-moz-box-flex", + subproperties: [ "-moz-box-flex" ], }; gCSSProperties["-webkit-box-ordinal-group"] = { domProp: "webkitBoxOrdinalGroup", inherited: false, type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "order", - subproperties: [ "order" ], + alias_for: "-moz-box-ordinal-group", + subproperties: [ "-moz-box-ordinal-group" ], }; - /* This one is not an alias - it's implemented as a logical property: */ gCSSProperties["-webkit-box-orient"] = { domProp: "webkitBoxOrient", inherited: false, - type: CSS_TYPE_LONGHAND, - logical: true, - get_computed: webkit_orient_get_computed, - initial_values: [ "horizontal" ], - other_values: [ "vertical" ], - invalid_values: [ - "0", "0px", "auto", - /* Flex-direction values: */ - "row", "column", "row-reverse", "column-reverse", - ], + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "-moz-box-orient", + subproperties: [ "-moz-box-orient" ], + }; + gCSSProperties["-webkit-box-direction"] = { + domProp: "webkitBoxDirection", + inherited: false, + type: CSS_TYPE_SHORTHAND_AND_LONGHAND, + alias_for: "-moz-box-direction", + subproperties: [ "-moz-box-direction" ], }; gCSSProperties["-webkit-box-align"] = { domProp: "webkitBoxAlign", inherited: false, type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "align-items", - subproperties: [ "align-items" ], + alias_for: "-moz-box-align", + subproperties: [ "-moz-box-align" ], }; gCSSProperties["-webkit-box-pack"] = { domProp: "webkitBoxPack", inherited: false, type: CSS_TYPE_SHORTHAND_AND_LONGHAND, - alias_for: "justify-content", - subproperties: [ "justify-content" ], + alias_for: "-moz-box-pack", + subproperties: [ "-moz-box-pack" ], }; gCSSProperties["-webkit-user-select"] = { domProp: "webkitUserSelect", diff --git a/layout/style/test/test_transitions.html b/layout/style/test/test_transitions.html index e655a50f2f..36a3228a0c 100644 --- a/layout/style/test/test_transitions.html +++ b/layout/style/test/test_transitions.html @@ -738,18 +738,15 @@ add_future_call(8, check_number_tests); function check_display_tests(time) { - var tf = timingFunctions["ease-in-out"]; for (var i in display_tests) { var p = display_tests[i]; - check_transition_value(tf, 0, 8, 0, 100, - getComputedStyle(p, "").textIndent, - "display test for test with " + - p.childNodes[0].data, - // TODO: Making transitions work on 'display:none' elements is - // still not implemented. - function(range) { return p != to_none_test && - range[1] < 100 }); + // There is no transition if the old or new style is display:none, so + // the computed value is always the end value. + var computedValue = getComputedStyle(p, "").textIndent; + is(computedValue, "100px", + "display test for test with " + p.childNodes[0].data + + ": computed value " + computedValue + " should be 100px."); } } diff --git a/layout/style/test/test_transitions_with_disabled_properties.html b/layout/style/test/test_transitions_with_disabled_properties.html new file mode 100644 index 0000000000..45f1196c60 --- /dev/null +++ b/layout/style/test/test_transitions_with_disabled_properties.html @@ -0,0 +1,56 @@ + + + + + + Test for bug 1265611 + + + + + +Mozilla Bug + 1265611 + +
+
+
+
+ + diff --git a/layout/style/test/test_transitions_with_displaynone.html b/layout/style/test/test_transitions_with_displaynone.html new file mode 100644 index 0000000000..331e49238b --- /dev/null +++ b/layout/style/test/test_transitions_with_displaynone.html @@ -0,0 +1,71 @@ + + + + + Test for Bug 1182856 + + + + + + +Mozilla Bug 1182856 + +
+

+
+
+
+
diff --git a/layout/style/test/test_webkit_box_orient.html b/layout/style/test/test_webkit_box_orient.html
deleted file mode 100644
index 63eadf551b..0000000000
--- a/layout/style/test/test_webkit_box_orient.html
+++ /dev/null
@@ -1,54 +0,0 @@
-
-
-
-  Test the writing-mode-dependent mapping of '-webkit-box-orient' values to
-  'flex-direction' values, when emulating -webkit-box styles with modern flexbox
-
-
-
-
-
-
diff --git a/layout/svg/AutoReferenceLimiter.h b/layout/svg/AutoReferenceLimiter.h
new file mode 100644
index 0000000000..cff70aabba
--- /dev/null
+++ b/layout/svg/AutoReferenceLimiter.h
@@ -0,0 +1,127 @@
+/* -*- 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 NS_AUTOREFERENCELIMITER_H
+#define NS_AUTOREFERENCELIMITER_H
+
+#include "mozilla/Assertions.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/ReentrancyGuard.h"
+#include "nsDebug.h"
+
+namespace mozilla {
+
+/**
+ * This helper allows us to handle two related issues in SVG content: reference
+ * loops, and reference chains that we deem to be too long.
+ *
+ * SVG content may contain reference loops where an SVG effect (a clipPath,
+ * say) may reference itself either directly or, perhaps more likely,
+ * indirectly via a reference chain to other elements that eventually leads
+ * back to itself.  This helper class allows us to detect and immediately break
+ * such reference loops when applying an effect so that we can prevent
+ * reference loops causing us to recurse until we run out of stack space and
+ * crash.
+ *
+ * SVG also allows for (non-loop) reference chains of arbitrary length, the
+ * length depending entirely on the SVG content.  Some SVG authoring tools have
+ * been known to create absurdly long reference chains.  (For example, bug
+ * 1253590 details a case where Adobe Illustrator created an SVG with a chain
+ * of 5000 clip paths which could cause us to run out of stack space and
+ * crash.)  This helper class also allows us to limit the number of times we
+ * recurse into a function, thereby allowing us to limit the length ofreference
+ * chains.
+ *
+ * Consumers that need to handle the reference loop case should add a member
+ * variable (mReferencing, say) to the class that represents and applies the
+ * SVG effect in question (typically an nsIFrame sub-class), initialize that
+ * member to AutoReferenceLimiter::notReferencing in the class' constructor
+ * (and never touch that variable again), and then add something like the
+ * following at the top of the method(s) that may recurse to follow references
+ * when applying an effect:
+ *
+ *   AutoReferenceLimiter refLoopDetector(&mInUse, 1); // only one ref allowed
+ *   if (!refLoopDetector.Reference()) {
+ *     return; // reference loop
+ *   }
+ *
+ * Consumers that need to limit reference chain lengths should add something
+ * like the following code at the top of the method(s) that may recurse to
+ * follow references when applying an effect:
+ *
+ *   static int16_t sChainLengthCounter = AutoReferenceLimiter::notReferencing;
+ *
+ *   AutoReferenceLimiter refChainLengthLimiter(&sChainLengthCounter, MAX_LEN);
+ *   if (!refChainLengthLimiter.Reference()) {
+ *     return; // reference chain too long
+ *   }
+ */
+class MOZ_RAII AutoReferenceLimiter
+{
+public:
+  static const int16_t notReferencing = -2;
+
+  AutoReferenceLimiter(int16_t* aRefCounter, int16_t aMaxReferenceCount)
+  {
+    MOZ_ASSERT(aMaxReferenceCount > 0 &&
+               aRefCounter &&
+               (*aRefCounter == notReferencing ||
+                (*aRefCounter >= 0 && *aRefCounter < aMaxReferenceCount)));
+
+    if (*aRefCounter == notReferencing) {
+      // initialize
+      *aRefCounter = aMaxReferenceCount;
+    }
+    mRefCounter = aRefCounter;
+    mMaxReferenceCount = aMaxReferenceCount;
+  }
+
+  ~AutoReferenceLimiter() {
+    // If we fail this assert then there were more destructor calls than
+    // Reference() calls (a consumer forgot to to call Reference()), or else
+    // someone messed with the variable pointed to by mRefCounter.
+    MOZ_ASSERT(*mRefCounter < mMaxReferenceCount);
+
+    (*mRefCounter)++;
+
+    if (*mRefCounter == mMaxReferenceCount) {
+      *mRefCounter = notReferencing; // reset ready for use next time
+    }
+  }
+
+  /**
+   * Returns true on success (no reference loop/reference chain length is
+   * within the specified limits), else returns false on failure (there is a
+   * reference loop/the reference chain has exceeded the specified limits).
+   */
+  MOZ_WARN_UNUSED_RESULT bool Reference() {
+    // If we fail this assertion then either a consumer failed to break a
+    // reference loop/chain, or else they called Reference() more than once
+    MOZ_ASSERT(*mRefCounter >= 0);
+
+    (*mRefCounter)--;
+
+    if (*mRefCounter < 0) {
+      // TODO: This is an issue with the document, not with Mozilla code. We
+      // should stop using NS_WARNING and send a message to the console
+      // instead (but only once per document, not over and over as we repaint).
+      if (mMaxReferenceCount == 1) {
+        NS_WARNING("Reference loop detected!");
+      } else {
+        NS_WARNING("Reference chain length limit exceeded!");
+      }
+      return false;
+    }
+    return true;
+  }
+
+private:
+  int16_t* mRefCounter;
+  int16_t mMaxReferenceCount;
+};
+
+} // namespace mozilla
+
+#endif // NS_AUTOREFERENCELIMITER_H
diff --git a/layout/svg/SVGFEContainerFrame.cpp b/layout/svg/SVGFEContainerFrame.cpp
index 699676efbb..f1914e5d75 100644
--- a/layout/svg/SVGFEContainerFrame.cpp
+++ b/layout/svg/SVGFEContainerFrame.cpp
@@ -11,19 +11,17 @@
 #include "nsSVGEffects.h"
 #include "nsSVGFilters.h"
 
-typedef nsContainerFrame SVGFEContainerFrameBase;
-
 /*
  * This frame is used by filter primitive elements that
  * have special child elements that provide parameters.
  */
-class SVGFEContainerFrame : public SVGFEContainerFrameBase
+class SVGFEContainerFrame : public nsContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGFEContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGFEContainerFrame(nsStyleContext* aContext)
-    : SVGFEContainerFrameBase(aContext)
+    : nsContainerFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
   }
@@ -33,7 +31,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGFEContainerFrameBase::IsFrameOfType(
+    return nsContainerFrame::IsFrameOfType(
             aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
   }
 
@@ -84,7 +82,7 @@ SVGFEContainerFrame::Init(nsIContent*       aContent,
                "Trying to construct an SVGFEContainerFrame for a "
                "content element that doesn't support the right interfaces");
 
-  SVGFEContainerFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -106,6 +104,5 @@ SVGFEContainerFrame::AttributeChanged(int32_t  aNameSpaceID,
     nsSVGEffects::InvalidateDirectRenderingObservers(GetParent());
   }
 
-  return SVGFEContainerFrameBase::AttributeChanged(aNameSpaceID,
-                                                     aAttribute, aModType);
+  return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
diff --git a/layout/svg/SVGFEImageFrame.cpp b/layout/svg/SVGFEImageFrame.cpp
index 5316ad17ed..28f0a2c839 100644
--- a/layout/svg/SVGFEImageFrame.cpp
+++ b/layout/svg/SVGFEImageFrame.cpp
@@ -16,15 +16,13 @@
 using namespace mozilla;
 using namespace mozilla::dom;
 
-typedef nsFrame SVGFEImageFrameBase;
-
-class SVGFEImageFrame : public SVGFEImageFrameBase
+class SVGFEImageFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGFEImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGFEImageFrame(nsStyleContext* aContext)
-    : SVGFEImageFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
 
@@ -45,7 +43,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGFEImageFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
@@ -86,15 +84,15 @@ NS_IMPL_FRAMEARENA_HELPERS(SVGFEImageFrame)
 /* virtual */ void
 SVGFEImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
-  DecApproximateVisibleCount();
+  DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
 
   nsCOMPtr imageLoader =
-    do_QueryInterface(SVGFEImageFrameBase::mContent);
+    do_QueryInterface(nsFrame::mContent);
   if (imageLoader) {
     imageLoader->FrameDestroyed(this);
   }
 
-  SVGFEImageFrameBase::DestroyFrom(aDestructRoot);
+  nsFrame::DestroyFrom(aDestructRoot);
 }
 
 void
@@ -106,13 +104,13 @@ SVGFEImageFrame::Init(nsIContent*       aContent,
                "Trying to construct an SVGFEImageFrame for a "
                "content element that doesn't support the right interfaces");
 
-  SVGFEImageFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 
   // We assume that feImage's are always visible.
-  IncApproximateVisibleCount();
+  IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
 
   nsCOMPtr imageLoader =
-    do_QueryInterface(SVGFEImageFrameBase::mContent);
+    do_QueryInterface(nsFrame::mContent);
   if (imageLoader) {
     imageLoader->FrameCreated(this);
   }
@@ -144,8 +142,7 @@ SVGFEImageFrame::AttributeChanged(int32_t  aNameSpaceID,
     }
   }
 
-  return SVGFEImageFrameBase::AttributeChanged(aNameSpaceID,
-                                               aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 void
@@ -153,13 +150,14 @@ SVGFEImageFrame::OnVisibilityChange(Visibility aNewVisibility,
                                     Maybe aNonvisibleAction)
 {
   nsCOMPtr imageLoader =
-    do_QueryInterface(SVGFEImageFrameBase::mContent);
+    do_QueryInterface(nsFrame::mContent);
   if (!imageLoader) {
     MOZ_ASSERT_UNREACHABLE("Should have an nsIImageLoadingContent");
+    nsFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
-  SVGFEImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+  nsFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
diff --git a/layout/svg/SVGFELeafFrame.cpp b/layout/svg/SVGFELeafFrame.cpp
index 95ff719a2d..3d6c765a7c 100644
--- a/layout/svg/SVGFELeafFrame.cpp
+++ b/layout/svg/SVGFELeafFrame.cpp
@@ -10,19 +10,17 @@
 #include "nsSVGEffects.h"
 #include "nsSVGFilters.h"
 
-typedef nsFrame SVGFELeafFrameBase;
-
 /*
  * This frame is used by filter primitive elements that don't
  * have special child elements that provide parameters.
  */
-class SVGFELeafFrame : public SVGFELeafFrameBase
+class SVGFELeafFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGFELeafFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGFELeafFrame(nsStyleContext* aContext)
-    : SVGFELeafFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_NONDISPLAY);
   }
@@ -38,7 +36,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGFELeafFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
@@ -83,7 +81,7 @@ SVGFELeafFrame::Init(nsIContent*       aContent,
                "Trying to construct an SVGFELeafFrame for a "
                "content element that doesn't support the right interfaces");
 
-  SVGFELeafFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -105,6 +103,5 @@ SVGFELeafFrame::AttributeChanged(int32_t  aNameSpaceID,
     nsSVGEffects::InvalidateDirectRenderingObservers(GetParent());
   }
 
-  return SVGFELeafFrameBase::AttributeChanged(aNameSpaceID,
-                                              aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
diff --git a/layout/svg/SVGTextFrame.cpp b/layout/svg/SVGTextFrame.cpp
index 3e8fb5715d..fc54fb50c6 100644
--- a/layout/svg/SVGTextFrame.cpp
+++ b/layout/svg/SVGTextFrame.cpp
@@ -3209,7 +3209,7 @@ nsDisplaySVGText::Paint(nsDisplayListBuilder* aBuilder,
 
 NS_QUERYFRAME_HEAD(SVGTextFrame)
   NS_QUERYFRAME_ENTRY(SVGTextFrame)
-NS_QUERYFRAME_TAIL_INHERITING(SVGTextFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
 
 // ---------------------------------------------------------------------
 // Implementation
@@ -3232,7 +3232,7 @@ SVGTextFrame::Init(nsIContent*       aContent,
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::text), "Content is not an SVG text");
 
-  SVGTextFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
   AddStateBits((aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) |
                NS_FRAME_SVG_LAYOUT | NS_FRAME_IS_SVG_TEXT);
 
@@ -3922,7 +3922,7 @@ SVGTextFrame::ReflowSVG()
   // XXX nsSVGContainerFrame::ReflowSVG only looks at its nsISVGChildFrame
   // children, and calls ConsiderChildOverflow on them.  Does it matter
   // that ConsiderChildOverflow won't be called on our children?
-  SVGTextFrameBase::ReflowSVG();
+  nsSVGDisplayContainerFrame::ReflowSVG();
 }
 
 /**
diff --git a/layout/svg/SVGTextFrame.h b/layout/svg/SVGTextFrame.h
index 72a822af46..90213fa8f0 100644
--- a/layout/svg/SVGTextFrame.h
+++ b/layout/svg/SVGTextFrame.h
@@ -22,8 +22,6 @@ class nsDisplaySVGText;
 class SVGTextFrame;
 class nsTextFrame;
 
-typedef nsSVGDisplayContainerFrame SVGTextFrameBase;
-
 namespace mozilla {
 
 class CharIterator;
@@ -246,7 +244,7 @@ public:
  * itself do the painting.  Otherwise, a DrawPathCallback is passed to
  * PaintText so that we can fill the text geometry with SVG paint servers.
  */
-class SVGTextFrame final : public SVGTextFrameBase
+class SVGTextFrame final : public nsSVGDisplayContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
@@ -268,10 +266,10 @@ class SVGTextFrame final : public SVGTextFrameBase
 
 protected:
   explicit SVGTextFrame(nsStyleContext* aContext)
-    : SVGTextFrameBase(aContext),
-      mFontSizeScaleFactor(1.0f),
-      mLastContextScale(1.0f),
-      mLengthAdjustScaleFactor(1.0f)
+    : nsSVGDisplayContainerFrame(aContext)
+    , mFontSizeScaleFactor(1.0f)
+    , mLastContextScale(1.0f)
+    , mLengthAdjustScaleFactor(1.0f)
   {
     AddStateBits(NS_STATE_SVG_POSITIONING_DIRTY);
   }
diff --git a/layout/svg/SVGViewFrame.cpp b/layout/svg/SVGViewFrame.cpp
index 256f6ed9eb..ff876f3eb7 100644
--- a/layout/svg/SVGViewFrame.cpp
+++ b/layout/svg/SVGViewFrame.cpp
@@ -10,8 +10,6 @@
 #include "mozilla/dom/SVGSVGElement.h"
 #include "mozilla/dom/SVGViewElement.h"
 
-typedef nsFrame SVGViewFrameBase;
-
 using namespace mozilla::dom;
 
 /**
@@ -20,13 +18,13 @@ using namespace mozilla::dom;
  * identifier. The SVGViewFrame class passes on any attribute changes
  * the view receives to the overridden  element (if there is one).
  **/
-class SVGViewFrame : public SVGViewFrameBase
+class SVGViewFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGViewFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit SVGViewFrame(nsStyleContext* aContext)
-    : SVGViewFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
@@ -42,7 +40,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return SVGViewFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
@@ -86,7 +84,7 @@ SVGViewFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::view),
                "Content is not an SVG view");
 
-  SVGViewFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -125,6 +123,5 @@ SVGViewFrame::AttributeChanged(int32_t  aNameSpaceID,
     }
   }
 
-  return SVGViewFrameBase::AttributeChanged(aNameSpaceID,
-                                            aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
diff --git a/layout/svg/nsSVGAFrame.cpp b/layout/svg/nsSVGAFrame.cpp
index a7ad04c72d..a3e22a4c51 100644
--- a/layout/svg/nsSVGAFrame.cpp
+++ b/layout/svg/nsSVGAFrame.cpp
@@ -13,15 +13,13 @@
 
 using namespace mozilla;
 
-typedef nsSVGDisplayContainerFrame nsSVGAFrameBase;
-
-class nsSVGAFrame : public nsSVGAFrameBase
+class nsSVGAFrame : public nsSVGDisplayContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGAFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  explicit nsSVGAFrame(nsStyleContext* aContext) :
-    nsSVGAFrameBase(aContext) {}
+  explicit nsSVGAFrame(nsStyleContext* aContext)
+    : nsSVGDisplayContainerFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
@@ -83,7 +81,7 @@ nsSVGAFrame::Init(nsIContent*       aContent,
                "Trying to construct an SVGAFrame for a "
                "content element that doesn't support the right interfaces");
 
-  nsSVGAFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -124,7 +122,7 @@ nsSVGAFrame::NotifySVGChanged(uint32_t aFlags)
     mCanvasTM = nullptr;
   }
 
-  nsSVGAFrameBase::NotifySVGChanged(aFlags);
+  nsSVGDisplayContainerFrame::NotifySVGChanged(aFlags);
 }
 
 //----------------------------------------------------------------------
diff --git a/layout/svg/nsSVGClipPathFrame.cpp b/layout/svg/nsSVGClipPathFrame.cpp
index cc5c879476..39f0a672bd 100644
--- a/layout/svg/nsSVGClipPathFrame.cpp
+++ b/layout/svg/nsSVGClipPathFrame.cpp
@@ -19,6 +19,9 @@ using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gfx;
 
+// Arbitrary number
+#define MAX_SVG_CLIP_PATH_REFERENCE_CHAIN_LENGTH int16_t(512)
+
 //----------------------------------------------------------------------
 // Implementation
 
@@ -39,7 +42,7 @@ nsSVGClipPathFrame::ApplyClipPath(gfxContext& aContext,
 
   DrawTarget& aDrawTarget = *aContext.GetDrawTarget();
 
-  // No need for AutoReferenceLoopDetector since simple clip paths can't create
+  // No need for AutoReferenceLimiter since simple clip paths can't create
   // a reference loop (they don't reference other clip paths).
 
   // Restore current transform after applying clip path:
@@ -90,10 +93,21 @@ nsSVGClipPathFrame::GetClipMask(gfxContext& aReferenceContext,
 
   DrawTarget& aReferenceDT = *aReferenceContext.GetDrawTarget();
 
-  AutoReferenceLoopDetector loopDetector;
-  if (!loopDetector.MarkAsInUse(this)) {
-    // Reference loop! This reference should be ignored, so return nullptr.
-    return nullptr;
+  // A clipPath can reference another clipPath.  We re-enter this method for
+  // each clipPath in a reference chain, so here we limit chain length:
+  static int16_t sRefChainLengthCounter = AutoReferenceLimiter::notReferencing;
+  AutoReferenceLimiter
+    refChainLengthLimiter(&sRefChainLengthCounter,
+                          MAX_SVG_CLIP_PATH_REFERENCE_CHAIN_LENGTH);
+  if (!refChainLengthLimiter.Reference()) {
+    return nullptr; // Reference chain is too long!
+  }
+
+  // And to prevent reference loops we check that this clipPath only appears
+  // once in the reference chain (if any) that we're currently processing:
+  AutoReferenceLimiter refLoopDetector(&mReferencing, 1);
+  if (!refLoopDetector.Reference()) {
+    return nullptr; // Reference loop!
   }
 
   IntRect devSpaceClipExtents;
@@ -242,11 +256,21 @@ bool
 nsSVGClipPathFrame::PointIsInsideClipPath(nsIFrame* aClippedFrame,
                                           const gfxPoint &aPoint)
 {
-  AutoReferenceLoopDetector loopDetector;
-  if (!loopDetector.MarkAsInUse(this)) {
-    // Reference loop! This reference is ignored, so return true (point not
-    // clipped out).
-    return true;
+  // A clipPath can reference another clipPath.  We re-enter this method for
+  // each clipPath in a reference chain, so here we limit chain length:
+  static int16_t sRefChainLengthCounter = AutoReferenceLimiter::notReferencing;
+  AutoReferenceLimiter
+    refChainLengthLimiter(&sRefChainLengthCounter,
+                          MAX_SVG_CLIP_PATH_REFERENCE_CHAIN_LENGTH);
+  if (!refChainLengthLimiter.Reference()) {
+    return false; // Reference chain is too long!
+  }
+
+  // And to prevent reference loops we check that this clipPath only appears
+  // once in the reference chain (if any) that we're currently processing:
+  AutoReferenceLimiter refLoopDetector(&mReferencing, 1);
+  if (!refLoopDetector.Reference()) {
+    return true; // Reference loop!
   }
 
   gfxMatrix matrix = GetClipPathTransform(aClippedFrame);
@@ -326,8 +350,20 @@ nsSVGClipPathFrame::IsTrivial(nsISVGChildFrame **aSingleChild)
 bool
 nsSVGClipPathFrame::IsValid()
 {
-  AutoReferenceLoopDetector loopDetector;
-  if (!loopDetector.MarkAsInUse(this)) {
+  // A clipPath can reference another clipPath.  We re-enter this method for
+  // each clipPath in a reference chain, so here we limit chain length:
+  static int16_t sRefChainLengthCounter = AutoReferenceLimiter::notReferencing;
+  AutoReferenceLimiter
+    refChainLengthLimiter(&sRefChainLengthCounter,
+                          MAX_SVG_CLIP_PATH_REFERENCE_CHAIN_LENGTH);
+  if (!refChainLengthLimiter.Reference()) {
+    return false; // Reference chain is too long!
+  }
+
+  // And to prevent reference loops we check that this clipPath only appears
+  // once in the reference chain (if any) that we're currently processing:
+  AutoReferenceLimiter refLoopDetector(&mReferencing, 1);
+  if (!refLoopDetector.Reference()) {
     return false; // Reference loop!
   }
 
@@ -378,8 +414,8 @@ nsSVGClipPathFrame::AttributeChanged(int32_t         aNameSpaceID,
     }
   }
 
-  return nsSVGClipPathFrameBase::AttributeChanged(aNameSpaceID,
-                                                  aAttribute, aModType);
+  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
+                                               aAttribute, aModType);
 }
 
 void
@@ -391,7 +427,7 @@ nsSVGClipPathFrame::Init(nsIContent*       aContent,
                "Content is not an SVG clipPath!");
 
   AddStateBits(NS_STATE_SVG_CLIPPATH_CHILD);
-  nsSVGClipPathFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 nsIAtom *
diff --git a/layout/svg/nsSVGClipPathFrame.h b/layout/svg/nsSVGClipPathFrame.h
index 14d189db5a..c5b3633d34 100644
--- a/layout/svg/nsSVGClipPathFrame.h
+++ b/layout/svg/nsSVGClipPathFrame.h
@@ -6,17 +6,16 @@
 #ifndef __NS_SVGCLIPPATHFRAME_H__
 #define __NS_SVGCLIPPATHFRAME_H__
 
-#include "mozilla/Attributes.h"
+#include "AutoReferenceLimiter.h"
 #include "gfxMatrix.h"
+#include "mozilla/Attributes.h"
 #include "nsSVGContainerFrame.h"
 #include "nsSVGUtils.h"
 
 class gfxContext;
 class nsISVGChildFrame;
 
-typedef nsSVGContainerFrame nsSVGClipPathFrameBase;
-
-class nsSVGClipPathFrame : public nsSVGClipPathFrameBase
+class nsSVGClipPathFrame : public nsSVGContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGClipPathFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
@@ -26,8 +25,8 @@ class nsSVGClipPathFrame : public nsSVGClipPathFrameBase
 
 protected:
   explicit nsSVGClipPathFrame(nsStyleContext* aContext)
-    : nsSVGClipPathFrameBase(aContext)
-    , mInUse(false)
+    : nsSVGContainerFrame(aContext)
+    , mReferencing(mozilla::AutoReferenceLimiter::notReferencing)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
@@ -135,60 +134,6 @@ private:
   // nsSVGContainerFrame methods:
   virtual gfxMatrix GetCanvasTM() override;
 
-  /**
-   * SVG content may contain reference loops where an SVG effect (a clipPath,
-   * say) may reference itself (directly or indirectly via a reference chain).
-   * This helper class allows us to detect and break such reference loops when
-   * applying an effect so that we can safely do so without the reference loop
-   * causing us to recurse until we run out of stack space and crash.
-   * The helper automatically sets and clears the mInUse flag on the frame.
-   */
-  class MOZ_RAII AutoReferenceLoopDetector
-  {
-  public:
-    explicit AutoReferenceLoopDetector()
-       : mFrame(nullptr)
-#ifdef DEBUG
-       , mMarkAsInUseCalled(false)
-#endif
-    {}
-
-    ~AutoReferenceLoopDetector() {
-      MOZ_ASSERT(mMarkAsInUseCalled,
-                 "Instances of this class are useless if MarkAsInUse() is "
-                 "not called on them");
-      if (mFrame) {
-        mFrame->mInUse = false;
-      }
-    }
-
-    /**
-     * Returns true on success (no reference loop), else returns false on
-     * failure (aFrame is already in use; that is, there is a reference loop).
-     */
-    MOZ_WARN_UNUSED_RESULT bool MarkAsInUse(nsSVGClipPathFrame* aFrame) {
-#ifdef DEBUG
-      MOZ_ASSERT(!mMarkAsInUseCalled, "Must only be called once");
-      mMarkAsInUseCalled = true;
-#endif
-      if (aFrame->mInUse) {
-        // XXX This is an error in the document, not in Mozilla code, so stop
-        // using NS_WARNING and send a message to the console instead.
-        NS_WARNING("clipPath reference loop!");
-        return false;
-      }
-      aFrame->mInUse = true;
-      mFrame = aFrame;
-      return true;
-    }
-
-  private:
-    nsSVGClipPathFrame* mFrame;
-#ifdef DEBUG
-    bool mMarkAsInUseCalled;
-#endif
-  };
-
   // Set, during a GetClipMask() call, to the transform that still needs to be
   // concatenated to the transform of the DrawTarget that was passed to
   // GetClipMask in order to establish the coordinate space that the clipPath
@@ -204,8 +149,9 @@ private:
   // may not even be called soon/any more.
   gfxMatrix mMatrixForChildren;
 
-  // Flag used by AutoReferenceLoopDetector to protect against reference loops:
-  bool mInUse;
+  // Flag used by AutoReferenceLimiter while we're processing an instance of
+  // this class to protect against (break) reference loops.
+  int16_t mReferencing;
 };
 
 #endif
diff --git a/layout/svg/nsSVGContainerFrame.cpp b/layout/svg/nsSVGContainerFrame.cpp
index 21758a1156..278aa1261f 100644
--- a/layout/svg/nsSVGContainerFrame.cpp
+++ b/layout/svg/nsSVGContainerFrame.cpp
@@ -20,7 +20,7 @@ using namespace mozilla;
 
 NS_QUERYFRAME_HEAD(nsSVGContainerFrame)
   NS_QUERYFRAME_ENTRY(nsSVGContainerFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGContainerFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 NS_QUERYFRAME_HEAD(nsSVGDisplayContainerFrame)
   NS_QUERYFRAME_ENTRY(nsSVGDisplayContainerFrame)
@@ -78,7 +78,7 @@ nsSVGContainerFrame::UpdateOverflow()
     // XXX It would have be better if the restyle request hadn't even happened.
     return false;
   }
-  return nsSVGContainerFrameBase::UpdateOverflow();
+  return nsContainerFrame::UpdateOverflow();
 }
 
 /**
diff --git a/layout/svg/nsSVGContainerFrame.h b/layout/svg/nsSVGContainerFrame.h
index 1f059fcd39..c617377fe1 100644
--- a/layout/svg/nsSVGContainerFrame.h
+++ b/layout/svg/nsSVGContainerFrame.h
@@ -23,8 +23,6 @@ class nsStyleContext;
 
 struct nsRect;
 
-typedef nsContainerFrame nsSVGContainerFrameBase;
-
 /**
  * Base class for SVG container frames. Frame sub-classes that do not
  * display their contents directly (such as the frames for  or
@@ -37,13 +35,13 @@ typedef nsContainerFrame nsSVGContainerFrameBase;
  * Do *not* blindly cast to SVG element types in this class's methods (see the
  * warning comment for nsSVGDisplayContainerFrame below). 
  */
-class nsSVGContainerFrame : public nsSVGContainerFrameBase
+class nsSVGContainerFrame : public nsContainerFrame
 {
   friend nsIFrame* NS_NewSVGContainerFrame(nsIPresShell* aPresShell,
                                            nsStyleContext* aContext);
 protected:
   explicit nsSVGContainerFrame(nsStyleContext* aContext)
-    : nsSVGContainerFrameBase(aContext)
+    : nsContainerFrame(aContext)
   {
     AddStateBits(NS_FRAME_SVG_LAYOUT);
   }
@@ -80,7 +78,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGContainerFrameBase::IsFrameOfType(
+    return nsContainerFrame::IsFrameOfType(
             aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGContainer));
   }
 
diff --git a/layout/svg/nsSVGFilterFrame.cpp b/layout/svg/nsSVGFilterFrame.cpp
index c65314ce9b..8ebffa358e 100644
--- a/layout/svg/nsSVGFilterFrame.cpp
+++ b/layout/svg/nsSVGFilterFrame.cpp
@@ -179,8 +179,8 @@ nsSVGFilterFrame::AttributeChanged(int32_t  aNameSpaceID,
     // And update whoever references us
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
-  return nsSVGFilterFrameBase::AttributeChanged(aNameSpaceID,
-                                                aAttribute, aModType);
+  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
+                                               aAttribute, aModType);
 }
 
 #ifdef DEBUG
@@ -192,7 +192,7 @@ nsSVGFilterFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::filter),
                "Content is not an SVG filter");
 
-  nsSVGFilterFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
diff --git a/layout/svg/nsSVGFilterFrame.h b/layout/svg/nsSVGFilterFrame.h
index b0e334d466..223c787f6e 100644
--- a/layout/svg/nsSVGFilterFrame.h
+++ b/layout/svg/nsSVGFilterFrame.h
@@ -27,17 +27,15 @@ class SVGFilterElement;
 } // namespace dom
 } // namespace mozilla
 
-typedef nsSVGContainerFrame nsSVGFilterFrameBase;
-
-class nsSVGFilterFrame : public nsSVGFilterFrameBase
+class nsSVGFilterFrame : public nsSVGContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGFilterFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit nsSVGFilterFrame(nsStyleContext* aContext)
-    : nsSVGFilterFrameBase(aContext),
-      mLoopFlag(false),
-      mNoHRefURI(false)
+    : nsSVGContainerFrame(aContext)
+    , mLoopFlag(false)
+    , mNoHRefURI(false)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
diff --git a/layout/svg/nsSVGForeignObjectFrame.cpp b/layout/svg/nsSVGForeignObjectFrame.cpp
index 0649b39fff..87533ec4ed 100644
--- a/layout/svg/nsSVGForeignObjectFrame.cpp
+++ b/layout/svg/nsSVGForeignObjectFrame.cpp
@@ -37,8 +37,8 @@ NS_NewSVGForeignObjectFrame(nsIPresShell   *aPresShell,
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGForeignObjectFrame)
 
 nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
-  : nsSVGForeignObjectFrameBase(aContext),
-    mInReflow(false)
+  : nsContainerFrame(aContext)
+  , mInReflow(false)
 {
   AddStateBits(NS_FRAME_REFLOW_ROOT | NS_FRAME_MAY_BE_TRANSFORMED |
                NS_FRAME_SVG_LAYOUT);
@@ -49,7 +49,7 @@ nsSVGForeignObjectFrame::nsSVGForeignObjectFrame(nsStyleContext* aContext)
 
 NS_QUERYFRAME_HEAD(nsSVGForeignObjectFrame)
   NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGForeignObjectFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
 
 void
 nsSVGForeignObjectFrame::Init(nsIContent*       aContent,
@@ -59,7 +59,7 @@ nsSVGForeignObjectFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::foreignObject),
                "Content is not an SVG foreignObject!");
 
-  nsSVGForeignObjectFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
   AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
   AddStateBits(NS_FRAME_FONT_INFLATION_CONTAINER |
                NS_FRAME_FONT_INFLATION_FLOW_ROOT);
@@ -74,7 +74,7 @@ void nsSVGForeignObjectFrame::DestroyFrom(nsIFrame* aDestructRoot)
   if (!(mState & NS_FRAME_IS_NONDISPLAY)) {
       nsSVGUtils::GetOuterSVGFrame(this)->UnregisterForeignObject(this);
   }
-  nsSVGForeignObjectFrameBase::DestroyFrom(aDestructRoot);
+  nsContainerFrame::DestroyFrom(aDestructRoot);
 }
 
 nsIAtom *
diff --git a/layout/svg/nsSVGForeignObjectFrame.h b/layout/svg/nsSVGForeignObjectFrame.h
index 3cd3b03bdf..34d67eb477 100644
--- a/layout/svg/nsSVGForeignObjectFrame.h
+++ b/layout/svg/nsSVGForeignObjectFrame.h
@@ -15,10 +15,8 @@
 
 class gfxContext;
 
-typedef nsContainerFrame nsSVGForeignObjectFrameBase;
-
-class nsSVGForeignObjectFrame : public nsSVGForeignObjectFrameBase,
-                                public nsISVGChildFrame
+class nsSVGForeignObjectFrame : public nsContainerFrame
+                              , public nsISVGChildFrame
 {
   friend nsContainerFrame*
   NS_NewSVGForeignObjectFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
@@ -60,7 +58,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGForeignObjectFrameBase::IsFrameOfType(aFlags &
+    return nsContainerFrame::IsFrameOfType(aFlags &
       ~(nsIFrame::eSVG | nsIFrame::eSVGForeignObject));
   }
 
diff --git a/layout/svg/nsSVGGFrame.cpp b/layout/svg/nsSVGGFrame.cpp
index 76daf71f95..1fc1249564 100644
--- a/layout/svg/nsSVGGFrame.cpp
+++ b/layout/svg/nsSVGGFrame.cpp
@@ -21,7 +21,7 @@ using namespace mozilla::dom;
 
 nsIFrame*
 NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
-{  
+{
   return new (aPresShell) nsSVGGFrame(aContext);
 }
 
@@ -37,7 +37,7 @@ nsSVGGFrame::Init(nsIContent*       aContent,
                static_cast(aContent)->IsTransformable(),
                "The element doesn't support nsIDOMSVGTransformable");
 
-  nsSVGGFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -61,7 +61,7 @@ nsSVGGFrame::NotifySVGChanged(uint32_t aFlags)
     mCanvasTM = nullptr;
   }
 
-  nsSVGGFrameBase::NotifySVGChanged(aFlags);
+  nsSVGDisplayContainerFrame::NotifySVGChanged(aFlags);
 }
 
 gfxMatrix
@@ -93,6 +93,6 @@ nsSVGGFrame::AttributeChanged(int32_t         aNameSpaceID,
     // and cause DoApplyRenderingChangeToTree to make the SchedulePaint call.
     NotifySVGChanged(TRANSFORM_CHANGED);
   }
-  
+
   return NS_OK;
 }
diff --git a/layout/svg/nsSVGGFrame.h b/layout/svg/nsSVGGFrame.h
index 9875925897..c80e4ef861 100644
--- a/layout/svg/nsSVGGFrame.h
+++ b/layout/svg/nsSVGGFrame.h
@@ -10,15 +10,13 @@
 #include "gfxMatrix.h"
 #include "nsSVGContainerFrame.h"
 
-typedef nsSVGDisplayContainerFrame nsSVGGFrameBase;
-
-class nsSVGGFrame : public nsSVGGFrameBase
+class nsSVGGFrame : public nsSVGDisplayContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  explicit nsSVGGFrame(nsStyleContext* aContext) :
-    nsSVGGFrameBase(aContext) {}
+  explicit nsSVGGFrame(nsStyleContext* aContext)
+    : nsSVGDisplayContainerFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
diff --git a/layout/svg/nsSVGGenericContainerFrame.h b/layout/svg/nsSVGGenericContainerFrame.h
index 0285df53ea..eff7375baf 100644
--- a/layout/svg/nsSVGGenericContainerFrame.h
+++ b/layout/svg/nsSVGGenericContainerFrame.h
@@ -18,15 +18,15 @@ class nsIFrame;
 class nsIPresShell;
 class nsStyleContext;
 
-typedef nsSVGDisplayContainerFrame nsSVGGenericContainerFrameBase;
-
-class nsSVGGenericContainerFrame : public nsSVGGenericContainerFrameBase
+class nsSVGGenericContainerFrame : public nsSVGDisplayContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGGenericContainerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
+
 protected:
-  explicit nsSVGGenericContainerFrame(nsStyleContext* aContext) : nsSVGGenericContainerFrameBase(aContext) {}
-  
+  explicit nsSVGGenericContainerFrame(nsStyleContext* aContext)
+    : nsSVGDisplayContainerFrame(aContext) {}
+
 public:
   NS_DECL_FRAMEARENA_HELPERS
 
diff --git a/layout/svg/nsSVGGradientFrame.cpp b/layout/svg/nsSVGGradientFrame.cpp
index f16a8a6586..e4e337f0e7 100644
--- a/layout/svg/nsSVGGradientFrame.cpp
+++ b/layout/svg/nsSVGGradientFrame.cpp
@@ -48,10 +48,10 @@ private:
 //----------------------------------------------------------------------
 // Implementation
 
-nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext) :
-  nsSVGGradientFrameBase(aContext),
-  mLoopFlag(false),
-  mNoHRefURI(false)
+nsSVGGradientFrame::nsSVGGradientFrame(nsStyleContext* aContext)
+  : nsSVGPaintServerFrame(aContext)
+  , mLoopFlag(false)
+  , mNoHRefURI(false)
 {
 }
 
@@ -77,8 +77,8 @@ nsSVGGradientFrame::AttributeChanged(int32_t         aNameSpaceID,
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
 
-  return nsSVGGradientFrameBase::AttributeChanged(aNameSpaceID,
-                                                  aAttribute, aModType);
+  return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID,
+                                                 aAttribute, aModType);
 }
 
 //----------------------------------------------------------------------
@@ -405,7 +405,7 @@ nsSVGLinearGradientFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::linearGradient),
                "Content is not an SVG linearGradient");
 
-  nsSVGLinearGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGGradientFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -474,8 +474,7 @@ nsSVGLinearGradientFrame::GetLinearGradientWithLength(uint32_t aIndex,
     return thisElement;
   }
 
-  return nsSVGLinearGradientFrameBase::GetLinearGradientWithLength(aIndex,
-                                                                   aDefault);
+  return nsSVGGradientFrame::GetLinearGradientWithLength(aIndex, aDefault);
 }
 
 bool
@@ -514,7 +513,7 @@ nsSVGRadialGradientFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::radialGradient),
                "Content is not an SVG radialGradient");
 
-  nsSVGRadialGradientFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGGradientFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -601,8 +600,7 @@ nsSVGRadialGradientFrame::GetRadialGradientWithLength(uint32_t aIndex,
     return thisElement;
   }
 
-  return nsSVGRadialGradientFrameBase::GetRadialGradientWithLength(aIndex,
-                                                                   aDefault);
+  return nsSVGGradientFrame::GetRadialGradientWithLength(aIndex, aDefault);
 }
 
 bool
diff --git a/layout/svg/nsSVGGradientFrame.h b/layout/svg/nsSVGGradientFrame.h
index 8e6eba9766..f12b132533 100644
--- a/layout/svg/nsSVGGradientFrame.h
+++ b/layout/svg/nsSVGGradientFrame.h
@@ -31,13 +31,11 @@ class SVGRadialGradientElement;
 } // namespace dom
 } // namespace mozilla
 
-typedef nsSVGPaintServerFrame nsSVGGradientFrameBase;
-
 /**
  * Gradients can refer to other gradients. We create an nsSVGPaintingProperty
  * with property type nsGkAtoms::href to track the referenced gradient.
  */
-class nsSVGGradientFrame : public nsSVGGradientFrameBase
+class nsSVGGradientFrame : public nsSVGPaintServerFrame
 {
   typedef mozilla::gfx::ExtendMode ExtendMode;
 
@@ -126,15 +124,13 @@ private:
 // Linear Gradients
 // -------------------------------------------------------------------------
 
-typedef nsSVGGradientFrame nsSVGLinearGradientFrameBase;
-
-class nsSVGLinearGradientFrame : public nsSVGLinearGradientFrameBase
+class nsSVGLinearGradientFrame : public nsSVGGradientFrame
 {
   friend nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
                                                 nsStyleContext* aContext);
 protected:
-  explicit nsSVGLinearGradientFrame(nsStyleContext* aContext) :
-    nsSVGLinearGradientFrameBase(aContext) {}
+  explicit nsSVGLinearGradientFrame(nsStyleContext* aContext)
+    : nsSVGGradientFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
@@ -171,15 +167,13 @@ protected:
 // Radial Gradients
 // -------------------------------------------------------------------------
 
-typedef nsSVGGradientFrame nsSVGRadialGradientFrameBase;
-
-class nsSVGRadialGradientFrame : public nsSVGRadialGradientFrameBase
+class nsSVGRadialGradientFrame : public nsSVGGradientFrame
 {
   friend nsIFrame* NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
                                                 nsStyleContext* aContext);
 protected:
-  explicit nsSVGRadialGradientFrame(nsStyleContext* aContext) :
-    nsSVGRadialGradientFrameBase(aContext) {}
+  explicit nsSVGRadialGradientFrame(nsStyleContext* aContext)
+    : nsSVGGradientFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
diff --git a/layout/svg/nsSVGImageFrame.cpp b/layout/svg/nsSVGImageFrame.cpp
index 78f71626d3..631d58ac3e 100644
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -45,17 +45,15 @@ private:
   nsSVGImageFrame *mFrame;
 };
 
-typedef nsSVGPathGeometryFrame nsSVGImageFrameBase;
-
-class nsSVGImageFrame : public nsSVGImageFrameBase,
-                        public nsIReflowCallback
+class nsSVGImageFrame : public nsSVGPathGeometryFrame
+                      , public nsIReflowCallback
 {
   friend nsIFrame*
   NS_NewSVGImageFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 protected:
   explicit nsSVGImageFrame(nsStyleContext* aContext)
-    : nsSVGImageFrameBase(aContext)
+    : nsSVGPathGeometryFrame(aContext)
     , mReflowCallbackPosted(false)
   {
     EnableVisibilityTracking();
@@ -155,7 +153,13 @@ nsSVGImageFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::image),
                "Content is not an SVG image!");
 
-  nsSVGImageFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGPathGeometryFrame::Init(aContent, aParent, aPrevInFlow);
+
+  if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
+    // Non-display frames are likely to be patterns, masks or the like.
+    // Treat them as always visible.
+    IncVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+  }
 
   mListener = new nsSVGImageListener(this);
   nsCOMPtr imageLoader = do_QueryInterface(mContent);
@@ -173,6 +177,10 @@ nsSVGImageFrame::Init(nsIContent*       aContent,
 /* virtual */ void
 nsSVGImageFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
+  if (GetStateBits() & NS_FRAME_IS_NONDISPLAY) {
+    DecVisibilityCount(VisibilityCounter::IN_DISPLAYPORT);
+  }
+
   if (mReflowCallbackPosted) {
     PresContext()->PresShell()->CancelReflowCallback(this);
     mReflowCallbackPosted = false;
@@ -227,8 +235,8 @@ nsSVGImageFrame::AttributeChanged(int32_t         aNameSpaceID,
     }
   }
 
-  return nsSVGImageFrameBase::AttributeChanged(aNameSpaceID,
-                                               aAttribute, aModType);
+  return nsSVGPathGeometryFrame::AttributeChanged(aNameSpaceID,
+                                                  aAttribute, aModType);
 }
 
 void
@@ -237,12 +245,13 @@ nsSVGImageFrame::OnVisibilityChange(Visibility aNewVisibility,
 {
   nsCOMPtr imageLoader = do_QueryInterface(mContent);
   if (!imageLoader) {
+    nsSVGPathGeometryFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
     return;
   }
 
   imageLoader->OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 
-  nsSVGImageFrameBase::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
+  nsSVGPathGeometryFrame::OnVisibilityChange(aNewVisibility, aNonvisibleAction);
 }
 
 gfx::Matrix
diff --git a/layout/svg/nsSVGInnerSVGFrame.cpp b/layout/svg/nsSVGInnerSVGFrame.cpp
index f1f3084020..2a6965655b 100644
--- a/layout/svg/nsSVGInnerSVGFrame.cpp
+++ b/layout/svg/nsSVGInnerSVGFrame.cpp
@@ -33,7 +33,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGInnerSVGFrame)
 NS_QUERYFRAME_HEAD(nsSVGInnerSVGFrame)
   NS_QUERYFRAME_ENTRY(nsSVGInnerSVGFrame)
   NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGInnerSVGFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
 
 #ifdef DEBUG
 void
@@ -44,7 +44,7 @@ nsSVGInnerSVGFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::svg),
                "Content is not an SVG 'svg' element!");
 
-  nsSVGInnerSVGFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -84,7 +84,7 @@ nsSVGInnerSVGFrame::PaintSVG(gfxContext& aContext,
     nsSVGUtils::SetClipRect(&aContext, aTransform, clipRect);
   }
 
-  return nsSVGInnerSVGFrameBase::PaintSVG(aContext, aTransform, aDirtyRect);
+  return nsSVGDisplayContainerFrame::PaintSVG(aContext, aTransform, aDirtyRect);
 }
 
 nsRect
@@ -124,7 +124,7 @@ nsSVGInnerSVGFrame::ReflowSVG()
     InvalidateFrame();
   }
 
-  nsSVGInnerSVGFrameBase::ReflowSVG();
+  nsSVGDisplayContainerFrame::ReflowSVG();
 }
 
 void
@@ -181,7 +181,7 @@ nsSVGInnerSVGFrame::NotifySVGChanged(uint32_t aFlags)
     mCanvasTM = nullptr;
   }
 
-  nsSVGInnerSVGFrameBase::NotifySVGChanged(aFlags);
+  nsSVGDisplayContainerFrame::NotifySVGChanged(aFlags);
 }
 
 nsresult
@@ -269,7 +269,7 @@ nsSVGInnerSVGFrame::GetFrameForPoint(const gfxPoint& aPoint)
     }
   }
 
-  return nsSVGInnerSVGFrameBase::GetFrameForPoint(aPoint);
+  return nsSVGDisplayContainerFrame::GetFrameForPoint(aPoint);
 }
 
 //----------------------------------------------------------------------
diff --git a/layout/svg/nsSVGInnerSVGFrame.h b/layout/svg/nsSVGInnerSVGFrame.h
index a683f7266c..acab7b4111 100644
--- a/layout/svg/nsSVGInnerSVGFrame.h
+++ b/layout/svg/nsSVGInnerSVGFrame.h
@@ -12,17 +12,15 @@
 
 class gfxContext;
 
-typedef nsSVGDisplayContainerFrame nsSVGInnerSVGFrameBase;
-
-class nsSVGInnerSVGFrame : public nsSVGInnerSVGFrameBase,
-                           public nsISVGSVGFrame
+class nsSVGInnerSVGFrame : public nsSVGDisplayContainerFrame
+                         , public nsISVGSVGFrame
 {
   friend nsIFrame*
   NS_NewSVGInnerSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  explicit nsSVGInnerSVGFrame(nsStyleContext* aContext) :
-    nsSVGInnerSVGFrameBase(aContext) {}
-  
+  explicit nsSVGInnerSVGFrame(nsStyleContext* aContext)
+    : nsSVGDisplayContainerFrame(aContext) {}
+
 public:
   NS_DECL_QUERYFRAME_TARGET(nsSVGInnerSVGFrame)
   NS_DECL_QUERYFRAME
diff --git a/layout/svg/nsSVGMarkerFrame.cpp b/layout/svg/nsSVGMarkerFrame.cpp
index 46a114e137..4eba42c7be 100644
--- a/layout/svg/nsSVGMarkerFrame.cpp
+++ b/layout/svg/nsSVGMarkerFrame.cpp
@@ -44,8 +44,8 @@ nsSVGMarkerFrame::AttributeChanged(int32_t  aNameSpaceID,
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
 
-  return nsSVGMarkerFrameBase::AttributeChanged(aNameSpaceID,
-                                                aAttribute, aModType);
+  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
+                                               aAttribute, aModType);
 }
 
 #ifdef DEBUG
@@ -56,7 +56,7 @@ nsSVGMarkerFrame::Init(nsIContent*       aContent,
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::marker), "Content is not an SVG marker");
 
-  nsSVGMarkerFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -267,7 +267,7 @@ nsSVGMarkerAnonChildFrame::Init(nsIContent*       aContent,
 {
   MOZ_ASSERT(aParent->GetType() == nsGkAtoms::svgMarkerFrame,
              "Unexpected parent");
-  nsSVGMarkerAnonChildFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif
 
diff --git a/layout/svg/nsSVGMarkerFrame.h b/layout/svg/nsSVGMarkerFrame.h
index a40c09c510..22ac017090 100644
--- a/layout/svg/nsSVGMarkerFrame.h
+++ b/layout/svg/nsSVGMarkerFrame.h
@@ -26,16 +26,14 @@ class SVGSVGElement;
 
 struct nsSVGMark;
 
-typedef nsSVGContainerFrame nsSVGMarkerFrameBase;
-
-class nsSVGMarkerFrame : public nsSVGMarkerFrameBase
+class nsSVGMarkerFrame : public nsSVGContainerFrame
 {
   friend class nsSVGMarkerAnonChildFrame;
   friend nsContainerFrame*
   NS_NewSVGMarkerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit nsSVGMarkerFrame(nsStyleContext* aContext)
-    : nsSVGMarkerFrameBase(aContext)
+    : nsSVGContainerFrame(aContext)
     , mMarkedFrame(nullptr)
     , mInUse(false)
     , mInUse2(false)
@@ -135,19 +133,14 @@ private:
 ////////////////////////////////////////////////////////////////////////
 // nsMarkerAnonChildFrame class
 
-typedef nsSVGDisplayContainerFrame nsSVGMarkerAnonChildFrameBase;
-
-/**
- */
-class nsSVGMarkerAnonChildFrame
-  : public nsSVGMarkerAnonChildFrameBase
+class nsSVGMarkerAnonChildFrame : public nsSVGDisplayContainerFrame
 {
   friend nsContainerFrame*
   NS_NewSVGMarkerAnonChildFrame(nsIPresShell* aPresShell,
                                 nsStyleContext* aContext);
 
   explicit nsSVGMarkerAnonChildFrame(nsStyleContext* aContext)
-    : nsSVGMarkerAnonChildFrameBase(aContext)
+    : nsSVGDisplayContainerFrame(aContext)
   {}
 
 public:
diff --git a/layout/svg/nsSVGMaskFrame.cpp b/layout/svg/nsSVGMaskFrame.cpp
index ba2af4c406..5cc8292587 100644
--- a/layout/svg/nsSVGMaskFrame.cpp
+++ b/layout/svg/nsSVGMaskFrame.cpp
@@ -360,8 +360,8 @@ nsSVGMaskFrame::AttributeChanged(int32_t  aNameSpaceID,
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
 
-  return nsSVGMaskFrameBase::AttributeChanged(aNameSpaceID,
-                                              aAttribute, aModType);
+  return nsSVGContainerFrame::AttributeChanged(aNameSpaceID,
+                                               aAttribute, aModType);
 }
 
 #ifdef DEBUG
@@ -373,7 +373,7 @@ nsSVGMaskFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::mask),
                "Content is not an SVG mask");
 
-  nsSVGMaskFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
diff --git a/layout/svg/nsSVGMaskFrame.h b/layout/svg/nsSVGMaskFrame.h
index fbd37edd3c..295808f40c 100644
--- a/layout/svg/nsSVGMaskFrame.h
+++ b/layout/svg/nsSVGMaskFrame.h
@@ -16,8 +16,6 @@
 
 class gfxContext;
 
-typedef nsSVGContainerFrame nsSVGMaskFrameBase;
-
 /**
  * Byte offsets of channels in a native packed gfxColor or cairo image surface.
  */
@@ -33,7 +31,7 @@ typedef nsSVGContainerFrame nsSVGMaskFrameBase;
 #define GFX_ARGB32_OFFSET_B 0
 #endif
 
-class nsSVGMaskFrame final : public nsSVGMaskFrameBase
+class nsSVGMaskFrame final : public nsSVGContainerFrame
 {
   friend nsIFrame*
   NS_NewSVGMaskFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
@@ -43,7 +41,7 @@ class nsSVGMaskFrame final : public nsSVGMaskFrameBase
 
 protected:
   explicit nsSVGMaskFrame(nsStyleContext* aContext)
-    : nsSVGMaskFrameBase(aContext)
+    : nsSVGContainerFrame(aContext)
     , mInUse(false)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
diff --git a/layout/svg/nsSVGOuterSVGFrame.cpp b/layout/svg/nsSVGOuterSVGFrame.cpp
index 4f1f5b1f09..fdcd107f5d 100644
--- a/layout/svg/nsSVGOuterSVGFrame.cpp
+++ b/layout/svg/nsSVGOuterSVGFrame.cpp
@@ -57,14 +57,14 @@ nsSVGOuterSVGFrame::UnregisterForeignObject(nsSVGForeignObjectFrame* aFrame)
 
 nsContainerFrame*
 NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
-{  
+{
   return new (aPresShell) nsSVGOuterSVGFrame(aContext);
 }
 
 NS_IMPL_FRAMEARENA_HELPERS(nsSVGOuterSVGFrame)
 
 nsSVGOuterSVGFrame::nsSVGOuterSVGFrame(nsStyleContext* aContext)
-    : nsSVGOuterSVGFrameBase(aContext)
+    : nsSVGDisplayContainerFrame(aContext)
     , mFullZoom(aContext->PresContext()->GetFullZoom())
     , mViewportInitialized(false)
     , mIsRootContent(false)
@@ -113,7 +113,7 @@ nsSVGOuterSVGFrame::Init(nsIContent*       aContent,
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
 
-  nsSVGOuterSVGFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 
   nsIDocument* doc = mContent->GetUncomposedDoc();
   if (doc) {
@@ -142,11 +142,10 @@ nsSVGOuterSVGFrame::Init(nsIContent*       aContent,
 
 NS_QUERYFRAME_HEAD(nsSVGOuterSVGFrame)
   NS_QUERYFRAME_ENTRY(nsISVGSVGFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGOuterSVGFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGDisplayContainerFrame)
 
 //----------------------------------------------------------------------
 // nsIFrame methods
-  
 //----------------------------------------------------------------------
 // reflowing
 
@@ -259,7 +258,7 @@ nsSVGOuterSVGFrame::GetIntrinsicRatio()
                   NSToCoordRoundWithClamp(viewBoxHeight));
   }
 
-  return nsSVGOuterSVGFrameBase::GetIntrinsicRatio();
+  return nsSVGDisplayContainerFrame::GetIntrinsicRatio();
 }
 
 /* virtual */
@@ -491,7 +490,7 @@ nsSVGOuterSVGFrame::DidReflow(nsPresContext*   aPresContext,
                               const nsHTMLReflowState*  aReflowState,
                               nsDidReflowStatus aStatus)
 {
-  nsSVGOuterSVGFrameBase::DidReflow(aPresContext,aReflowState,aStatus);
+  nsSVGDisplayContainerFrame::DidReflow(aPresContext,aReflowState,aStatus);
 
   // Make sure elements styled by :hover get updated if script/animation moves
   // them under or out from under the pointer:
@@ -940,7 +939,7 @@ nsSVGOuterSVGAnonChildFrame::Init(nsIContent*       aContent,
 {
   MOZ_ASSERT(aParent->GetType() == nsGkAtoms::svgOuterSVGFrame,
              "Unexpected parent");
-  nsSVGOuterSVGAnonChildFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGDisplayContainerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif
 
diff --git a/layout/svg/nsSVGOuterSVGFrame.h b/layout/svg/nsSVGOuterSVGFrame.h
index 5602665e8c..81b1446ef6 100644
--- a/layout/svg/nsSVGOuterSVGFrame.h
+++ b/layout/svg/nsSVGOuterSVGFrame.h
@@ -17,10 +17,8 @@ class nsSVGForeignObjectFrame;
 ////////////////////////////////////////////////////////////////////////
 // nsSVGOuterSVGFrame class
 
-typedef nsSVGDisplayContainerFrame nsSVGOuterSVGFrameBase;
-
-class nsSVGOuterSVGFrame final : public nsSVGOuterSVGFrameBase,
-                                 public nsISVGSVGFrame
+class nsSVGOuterSVGFrame final : public nsSVGDisplayContainerFrame
+                               , public nsISVGSVGFrame
 {
   friend nsContainerFrame*
   NS_NewSVGOuterSVGFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
@@ -209,8 +207,6 @@ protected:
 ////////////////////////////////////////////////////////////////////////
 // nsSVGOuterSVGAnonChildFrame class
 
-typedef nsSVGDisplayContainerFrame nsSVGOuterSVGAnonChildFrameBase;
-
 /**
  * nsSVGOuterSVGFrames have a single direct child that is an instance of this
  * class, and which is used to wrap their real child frames. Such anonymous
@@ -234,15 +230,14 @@ typedef nsSVGDisplayContainerFrame nsSVGOuterSVGAnonChildFrameBase;
  * example, the implementations of IsSVGTransformed and GetCanvasTM assume
  * nsSVGContainerFrame instances all the way up to the nsSVGOuterSVGFrame.
  */
-class nsSVGOuterSVGAnonChildFrame
-  : public nsSVGOuterSVGAnonChildFrameBase
+class nsSVGOuterSVGAnonChildFrame : public nsSVGDisplayContainerFrame
 {
   friend nsContainerFrame*
   NS_NewSVGOuterSVGAnonChildFrame(nsIPresShell* aPresShell,
                                   nsStyleContext* aContext);
 
   explicit nsSVGOuterSVGAnonChildFrame(nsStyleContext* aContext)
-    : nsSVGOuterSVGAnonChildFrameBase(aContext)
+    : nsSVGDisplayContainerFrame(aContext)
   {}
 
 public:
diff --git a/layout/svg/nsSVGPaintServerFrame.h b/layout/svg/nsSVGPaintServerFrame.h
index caf6a82164..6b568f8727 100644
--- a/layout/svg/nsSVGPaintServerFrame.h
+++ b/layout/svg/nsSVGPaintServerFrame.h
@@ -26,15 +26,13 @@ class nsStyleContext;
 
 struct gfxRect;
 
-typedef nsSVGContainerFrame nsSVGPaintServerFrameBase;
-
-class nsSVGPaintServerFrame : public nsSVGPaintServerFrameBase
+class nsSVGPaintServerFrame : public nsSVGContainerFrame
 {
 protected:
   typedef mozilla::gfx::DrawTarget DrawTarget;
 
   explicit nsSVGPaintServerFrame(nsStyleContext* aContext)
-    : nsSVGPaintServerFrameBase(aContext)
+    : nsSVGContainerFrame(aContext)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
@@ -65,7 +63,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGPaintServerFrameBase::IsFrameOfType(aFlags & ~nsIFrame::eSVGPaintServer);
+    return nsSVGContainerFrame::IsFrameOfType(aFlags & ~nsIFrame::eSVGPaintServer);
   }
 };
 
diff --git a/layout/svg/nsSVGPathGeometryFrame.cpp b/layout/svg/nsSVGPathGeometryFrame.cpp
index c1b0def8c7..cd418a2c43 100644
--- a/layout/svg/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/nsSVGPathGeometryFrame.cpp
@@ -50,7 +50,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsSVGPathGeometryFrame)
 NS_QUERYFRAME_HEAD(nsSVGPathGeometryFrame)
   NS_QUERYFRAME_ENTRY(nsISVGChildFrame)
   NS_QUERYFRAME_ENTRY(nsSVGPathGeometryFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGPathGeometryFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsFrame)
 
 //----------------------------------------------------------------------
 // Display list item:
@@ -123,7 +123,7 @@ nsSVGPathGeometryFrame::Init(nsIContent*       aContent,
                              nsIFrame*         aPrevInFlow)
 {
   AddStateBits(aParent->GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD);
-  nsSVGPathGeometryFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 nsresult
@@ -150,7 +150,7 @@ nsSVGPathGeometryFrame::AttributeChanged(int32_t         aNameSpaceID,
 /* virtual */ void
 nsSVGPathGeometryFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
-  nsSVGPathGeometryFrameBase::DidSetStyleContext(aOldStyleContext);
+  nsFrame::DidSetStyleContext(aOldStyleContext);
 
   if (aOldStyleContext) {
     auto oldStyleEffects = aOldStyleContext->PeekStyleEffects();
diff --git a/layout/svg/nsSVGPathGeometryFrame.h b/layout/svg/nsSVGPathGeometryFrame.h
index ac895db9c3..d1764f685a 100644
--- a/layout/svg/nsSVGPathGeometryFrame.h
+++ b/layout/svg/nsSVGPathGeometryFrame.h
@@ -32,10 +32,8 @@ class nsSVGMarkerProperty;
 
 struct nsRect;
 
-typedef nsFrame nsSVGPathGeometryFrameBase;
-
-class nsSVGPathGeometryFrame : public nsSVGPathGeometryFrameBase,
-                               public nsISVGChildFrame
+class nsSVGPathGeometryFrame : public nsFrame
+                             , public nsISVGChildFrame
 {
   typedef mozilla::gfx::DrawTarget DrawTarget;
 
@@ -46,7 +44,7 @@ class nsSVGPathGeometryFrame : public nsSVGPathGeometryFrameBase,
 
 protected:
   explicit nsSVGPathGeometryFrame(nsStyleContext* aContext)
-    : nsSVGPathGeometryFrameBase(aContext)
+    : nsFrame(aContext)
   {
      AddStateBits(NS_FRAME_SVG_LAYOUT | NS_FRAME_MAY_BE_TRANSFORMED);
   }
@@ -63,7 +61,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGPathGeometryFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGGeometry));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG | nsIFrame::eSVGGeometry));
   }
 
   virtual nsresult  AttributeChanged(int32_t         aNameSpaceID,
diff --git a/layout/svg/nsSVGPatternFrame.cpp b/layout/svg/nsSVGPatternFrame.cpp
index b07b73e9fc..dbb5c83ea7 100644
--- a/layout/svg/nsSVGPatternFrame.cpp
+++ b/layout/svg/nsSVGPatternFrame.cpp
@@ -55,10 +55,10 @@ private:
 //----------------------------------------------------------------------
 // Implementation
 
-nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext) :
-  nsSVGPatternFrameBase(aContext),
-  mLoopFlag(false),
-  mNoHRefURI(false)
+nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext)
+  : nsSVGPaintServerFrame(aContext)
+  , mLoopFlag(false)
+  , mNoHRefURI(false)
 {
 }
 
@@ -94,7 +94,7 @@ nsSVGPatternFrame::AttributeChanged(int32_t         aNameSpaceID,
     nsSVGEffects::InvalidateDirectRenderingObservers(this);
   }
 
-  return nsSVGPatternFrameBase::AttributeChanged(aNameSpaceID,
+  return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID,
                                                  aAttribute, aModType);
 }
 
@@ -106,7 +106,7 @@ nsSVGPatternFrame::Init(nsIContent*       aContent,
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::pattern), "Content is not an SVG pattern");
 
-  nsSVGPatternFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGPaintServerFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
diff --git a/layout/svg/nsSVGPatternFrame.h b/layout/svg/nsSVGPatternFrame.h
index ed832a591c..4e2b358eb1 100644
--- a/layout/svg/nsSVGPatternFrame.h
+++ b/layout/svg/nsSVGPatternFrame.h
@@ -22,13 +22,11 @@ class SVGAnimatedPreserveAspectRatio;
 class nsSVGAnimatedTransformList;
 } // namespace mozilla
 
-typedef nsSVGPaintServerFrame  nsSVGPatternFrameBase;
-
 /**
  * Patterns can refer to other patterns. We create an nsSVGPaintingProperty
  * with property type nsGkAtoms::href to track the referenced pattern.
  */
-class nsSVGPatternFrame : public nsSVGPatternFrameBase
+class nsSVGPatternFrame : public nsSVGPaintServerFrame
 {
   typedef mozilla::gfx::SourceSurface SourceSurface;
 
diff --git a/layout/svg/nsSVGStopFrame.cpp b/layout/svg/nsSVGStopFrame.cpp
index 7997160420..1b75fa1028 100644
--- a/layout/svg/nsSVGStopFrame.cpp
+++ b/layout/svg/nsSVGStopFrame.cpp
@@ -14,15 +14,13 @@
 // events and propagate them to the parent.  Most of the heavy lifting is done
 // within the nsSVGGradientFrame, which is the parent for this frame
 
-typedef nsFrame  nsSVGStopFrameBase;
-
-class nsSVGStopFrame : public nsSVGStopFrameBase
+class nsSVGStopFrame : public nsFrame
 {
   friend nsIFrame*
   NS_NewSVGStopFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
   explicit nsSVGStopFrame(nsStyleContext* aContext)
-    : nsSVGStopFrameBase(aContext)
+    : nsFrame(aContext)
   {
     AddStateBits(NS_FRAME_IS_NONDISPLAY);
   }
@@ -54,7 +52,7 @@ public:
 
   virtual bool IsFrameOfType(uint32_t aFlags) const override
   {
-    return nsSVGStopFrameBase::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
+    return nsFrame::IsFrameOfType(aFlags & ~(nsIFrame::eSVG));
   }
 
 #ifdef DEBUG_FRAME_DUMP
@@ -81,7 +79,7 @@ nsSVGStopFrame::Init(nsIContent*       aContent,
 {
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::stop), "Content is not a stop element");
 
-  nsSVGStopFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
@@ -104,8 +102,7 @@ nsSVGStopFrame::AttributeChanged(int32_t         aNameSpaceID,
     nsSVGEffects::InvalidateDirectRenderingObservers(GetParent());
   }
 
-  return nsSVGStopFrameBase::AttributeChanged(aNameSpaceID,
-                                              aAttribute, aModType);
+  return nsFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 // -------------------------------------------------------------------------
diff --git a/layout/svg/nsSVGSwitchFrame.cpp b/layout/svg/nsSVGSwitchFrame.cpp
index a0f447ca7f..2a35e0f528 100644
--- a/layout/svg/nsSVGSwitchFrame.cpp
+++ b/layout/svg/nsSVGSwitchFrame.cpp
@@ -12,15 +12,13 @@
 
 using namespace mozilla::gfx;
 
-typedef nsSVGGFrame nsSVGSwitchFrameBase;
-
-class nsSVGSwitchFrame : public nsSVGSwitchFrameBase
+class nsSVGSwitchFrame : public nsSVGGFrame
 {
   friend nsIFrame*
   NS_NewSVGSwitchFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 protected:
-  explicit nsSVGSwitchFrame(nsStyleContext* aContext) :
-    nsSVGSwitchFrameBase(aContext) {}
+  explicit nsSVGSwitchFrame(nsStyleContext* aContext)
+    : nsSVGGFrame(aContext) {}
 
 public:
   NS_DECL_FRAMEARENA_HELPERS
@@ -83,7 +81,7 @@ nsSVGSwitchFrame::Init(nsIContent*       aContent,
   NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::svgSwitch),
                "Content is not an SVG switch");
 
-  nsSVGSwitchFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGGFrame::Init(aContent, aParent, aPrevInFlow);
 }
 #endif /* DEBUG */
 
diff --git a/layout/svg/nsSVGUseFrame.cpp b/layout/svg/nsSVGUseFrame.cpp
index c0f14c51fb..5c15ade423 100644
--- a/layout/svg/nsSVGUseFrame.cpp
+++ b/layout/svg/nsSVGUseFrame.cpp
@@ -10,27 +10,24 @@
 #include "mozilla/dom/SVGUseElement.h"
 #include "nsContentList.h"
 
-typedef nsSVGGFrame nsSVGUseFrameBase;
-
 using namespace mozilla::dom;
 
-class nsSVGUseFrame : public nsSVGUseFrameBase,
-                      public nsIAnonymousContentCreator
+class nsSVGUseFrame : public nsSVGGFrame
+                    , public nsIAnonymousContentCreator
 {
   friend nsIFrame*
   NS_NewSVGUseFrame(nsIPresShell* aPresShell, nsStyleContext* aContext);
 
 protected:
-  explicit nsSVGUseFrame(nsStyleContext* aContext) :
-    nsSVGUseFrameBase(aContext),
-    mHasValidDimensions(true)
+  explicit nsSVGUseFrame(nsStyleContext* aContext)
+    : nsSVGGFrame(aContext)
+    , mHasValidDimensions(true)
   {}
 
 public:
   NS_DECL_QUERYFRAME
   NS_DECL_FRAMEARENA_HELPERS
 
-  
   // nsIFrame interface:
   virtual void Init(nsIContent*       aContent,
                     nsContainerFrame* aParent,
@@ -93,7 +90,7 @@ nsSVGUseFrame::GetType() const
 
 NS_QUERYFRAME_HEAD(nsSVGUseFrame)
   NS_QUERYFRAME_ENTRY(nsIAnonymousContentCreator)
-NS_QUERYFRAME_TAIL_INHERITING(nsSVGUseFrameBase)
+NS_QUERYFRAME_TAIL_INHERITING(nsSVGGFrame)
 
 //----------------------------------------------------------------------
 // nsIFrame methods:
@@ -109,7 +106,7 @@ nsSVGUseFrame::Init(nsIContent*       aContent,
   mHasValidDimensions =
     static_cast(aContent)->HasValidDimensions();
 
-  nsSVGUseFrameBase::Init(aContent, aParent, aPrevInFlow);
+  nsSVGGFrame::Init(aContent, aParent, aPrevInFlow);
 }
 
 nsresult
@@ -159,15 +156,14 @@ nsSVGUseFrame::AttributeChanged(int32_t         aNameSpaceID,
     useElement->TriggerReclone();
   }
 
-  return nsSVGUseFrameBase::AttributeChanged(aNameSpaceID,
-                                             aAttribute, aModType);
+  return nsSVGGFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
 }
 
 void
 nsSVGUseFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
   RefPtr use = static_cast(mContent);
-  nsSVGUseFrameBase::DestroyFrom(aDestructRoot);
+  nsSVGGFrame::DestroyFrom(aDestructRoot);
   use->DestroyAnonymousContent();
 }
 
@@ -200,7 +196,7 @@ nsSVGUseFrame::ReflowSVG()
     InvalidateFrame();
   }
 
-  nsSVGUseFrameBase::ReflowSVG();
+  nsSVGGFrame::ReflowSVG();
 }
 
 void
@@ -228,7 +224,7 @@ nsSVGUseFrame::NotifySVGChanged(uint32_t aFlags)
   // non-percentage width/height, since if they're set then they are cloned to
   // an anonymous child , and its nsSVGInnerSVGFrame will do that.
 
-  nsSVGUseFrameBase::NotifySVGChanged(aFlags);
+  nsSVGGFrame::NotifySVGChanged(aFlags);
 }
 
 //----------------------------------------------------------------------
diff --git a/layout/xul/nsTextBoxFrame.cpp b/layout/xul/nsTextBoxFrame.cpp
index 71177c1d10..40754799ad 100644
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -68,7 +68,7 @@ NS_IMPL_FRAMEARENA_HELPERS(nsTextBoxFrame)
 
 NS_QUERYFRAME_HEAD(nsTextBoxFrame)
   NS_QUERYFRAME_ENTRY(nsTextBoxFrame)
-NS_QUERYFRAME_TAIL_INHERITING(nsTextBoxFrameSuper)
+NS_QUERYFRAME_TAIL_INHERITING(nsLeafBoxFrame)
 
 nsresult
 nsTextBoxFrame::AttributeChanged(int32_t         aNameSpaceID,
@@ -115,7 +115,7 @@ nsTextBoxFrame::Init(nsIContent*       aContent,
                      nsContainerFrame* aParent,
                      nsIFrame*         aPrevInFlow)
 {
-    nsTextBoxFrameSuper::Init(aContent, aParent, aPrevInFlow);
+    nsLeafBoxFrame::Init(aContent, aParent, aPrevInFlow);
 
     bool aResize;
     bool aRedraw;
@@ -130,7 +130,7 @@ nsTextBoxFrame::DestroyFrom(nsIFrame* aDestructRoot)
 {
     // unregister access key
     RegUnregAccessKey(false);
-    nsTextBoxFrameSuper::DestroyFrom(aDestructRoot);
+    nsLeafBoxFrame::DestroyFrom(aDestructRoot);
 }
 
 bool
@@ -1021,7 +1021,7 @@ nsTextBoxFrame::ComputesOwnOverflowArea()
 nsTextBoxFrame::MarkIntrinsicISizesDirty()
 {
     mNeedsRecalc = true;
-    nsTextBoxFrameSuper::MarkIntrinsicISizesDirty();
+    nsLeafBoxFrame::MarkIntrinsicISizesDirty();
 }
 
 void
diff --git a/layout/xul/nsTextBoxFrame.h b/layout/xul/nsTextBoxFrame.h
index e404bb0cda..ca1b887484 100644
--- a/layout/xul/nsTextBoxFrame.h
+++ b/layout/xul/nsTextBoxFrame.h
@@ -12,8 +12,7 @@ class nsAccessKeyInfo;
 class nsAsyncAccesskeyUpdate;
 class nsFontMetrics;
 
-typedef nsLeafBoxFrame nsTextBoxFrameSuper;
-class nsTextBoxFrame : public nsTextBoxFrameSuper
+class nsTextBoxFrame : public nsLeafBoxFrame
 {
 public:
   NS_DECL_QUERYFRAME_TARGET(nsTextBoxFrame)
diff --git a/layout/xul/test/mochitest.ini b/layout/xul/test/mochitest.ini
index cabb243e1d..41d1df97f2 100644
--- a/layout/xul/test/mochitest.ini
+++ b/layout/xul/test/mochitest.ini
@@ -8,4 +8,4 @@ skip-if = toolkit == 'android' #bug 798806
 [test_bug563416.html]
 [test_resizer_incontent.xul]
 [test_splitter.xul]
-skip-if = android_version == '18' # bug 1147982
+skip-if = toolkit == 'android' # no XUL theme
diff --git a/tools/profiler/core/platform.h b/tools/profiler/core/platform.h
index 4d6354addf..e00c562254 100644
--- a/tools/profiler/core/platform.h
+++ b/tools/profiler/core/platform.h
@@ -59,16 +59,18 @@
 #include 
 #include "StackTop.h"
 
-// We need a definition of gettid(), but glibc doesn't provide a
-// wrapper for it.
-#if defined(__GLIBC__)
+// We need a definition of gettid(), but Linux libc implementations don't
+// provide a wrapper for it (except for Bionic)
+#if defined(__linux__)
 #include 
+#if !defined(__BIONIC__)
 #include 
 static inline pid_t gettid()
 {
   return (pid_t) syscall(SYS_gettid);
 }
 #endif
+#endif
 
 #ifdef XP_WIN
 #include 
diff --git a/widget/ContentEvents.h b/widget/ContentEvents.h
index c9647374ec..542974cf70 100644
--- a/widget/ContentEvents.h
+++ b/widget/ContentEvents.h
@@ -242,7 +242,7 @@ public:
 
   InternalTransitionEvent(bool aIsTrusted, EventMessage aMessage)
     : WidgetEvent(aIsTrusted, aMessage, eTransitionEventClass)
-    , elapsedTime(0.0)
+    , mElapsedTime(0.0)
   {
     mFlags.mCancelable = false;
   }
@@ -258,18 +258,18 @@ public:
     return result;
   }
 
-  nsString propertyName;
-  float elapsedTime;
-  nsString pseudoElement;
+  nsString mPropertyName;
+  nsString mPseudoElement;
+  float mElapsedTime;
 
   void AssignTransitionEventData(const InternalTransitionEvent& aEvent,
                                  bool aCopyTargets)
   {
     AssignEventData(aEvent, aCopyTargets);
 
-    propertyName = aEvent.propertyName;
-    elapsedTime = aEvent.elapsedTime;
-    pseudoElement = aEvent.pseudoElement;
+    mPropertyName = aEvent.mPropertyName;
+    mElapsedTime = aEvent.mElapsedTime;
+    mPseudoElement = aEvent.mPseudoElement;
   }
 };