summaryrefslogtreecommitdiffstats
path: root/layout
diff options
context:
space:
mode:
Diffstat (limited to 'layout')
-rw-r--r--layout/base/AccessibleCaretManager.cpp33
-rw-r--r--layout/base/MotionPathUtils.cpp35
-rw-r--r--layout/base/PositionedEventTargeting.cpp56
-rw-r--r--layout/base/PresShell.cpp182
-rw-r--r--layout/base/PresShell.h18
-rw-r--r--layout/base/RestyleManager.cpp142
-rw-r--r--layout/base/RestyleManager.h17
-rw-r--r--layout/base/ViewportUtils.cpp3
-rw-r--r--layout/base/ZoomConstraintsClient.cpp16
-rw-r--r--layout/base/crashtests/crashtests.list12
-rw-r--r--layout/base/metrics.yaml16
-rw-r--r--layout/base/nsCSSFrameConstructor.cpp46
-rw-r--r--layout/base/nsCSSFrameConstructor.h17
-rw-r--r--layout/base/nsCaret.cpp275
-rw-r--r--layout/base/nsCaret.h143
-rw-r--r--layout/base/nsCounterManager.cpp6
-rw-r--r--layout/base/nsDocumentViewer.cpp47
-rw-r--r--layout/base/nsGenConList.cpp13
-rw-r--r--layout/base/nsLayoutUtils.cpp141
-rw-r--r--layout/base/nsLayoutUtils.h57
-rw-r--r--layout/base/nsPresContext.cpp9
-rw-r--r--layout/base/nsRefreshDriver.cpp53
-rw-r--r--layout/base/nsRefreshDriver.h5
-rw-r--r--layout/base/tests/browser.toml6
-rw-r--r--layout/base/tests/browser_animatedImageLeak.js226
-rw-r--r--layout/base/tests/bug1896051-ref.html29
-rw-r--r--layout/base/tests/bug1896051.html38
-rw-r--r--layout/base/tests/chrome/chrome.toml6
-rw-r--r--layout/base/tests/chrome/printpreview_helper.xhtml243
-rw-r--r--layout/base/tests/chrome/printpreview_scale_test_001.html21
-rw-r--r--layout/base/tests/chrome/printpreview_scale_test_001_ref.html20
-rw-r--r--layout/base/tests/chrome/printpreview_scale_test_002.html21
-rw-r--r--layout/base/tests/chrome/printpreview_scale_test_002_ref.html26
-rw-r--r--layout/base/tests/chrome/printpreview_scale_test_003.html21
-rw-r--r--layout/base/tests/chrome/printpreview_scale_test_003_ref.html21
-rw-r--r--layout/base/tests/chrome/test_bug420499.xhtml2
-rw-r--r--layout/base/tests/helper_animatedImageLeak.html10
-rw-r--r--layout/base/tests/helper_bug1733509.html30
-rw-r--r--layout/base/tests/mochitest.toml3
-rw-r--r--layout/base/tests/test_event_target_radius.html56
-rw-r--r--layout/base/tests/test_reftests_with_caret.html1
-rw-r--r--layout/build/nsLayoutStatics.cpp6
-rw-r--r--layout/docs/DynamicChangeHandling.md83
-rw-r--r--layout/docs/LayoutOverview.md529
-rw-r--r--layout/docs/StyleSystemOverview.md173
-rw-r--r--layout/docs/index.rst14
-rw-r--r--layout/forms/nsCheckboxRadioFrame.cpp26
-rw-r--r--layout/forms/nsComboboxControlFrame.cpp2
-rw-r--r--layout/forms/nsDateTimeControlFrame.cpp29
-rw-r--r--layout/forms/nsFieldSetFrame.cpp15
-rw-r--r--layout/forms/nsHTMLButtonControlFrame.cpp26
-rw-r--r--layout/forms/nsImageControlFrame.cpp1
-rw-r--r--layout/forms/nsListControlFrame.cpp16
-rw-r--r--layout/forms/nsMeterFrame.cpp64
-rw-r--r--layout/forms/nsMeterFrame.h39
-rw-r--r--layout/forms/nsProgressFrame.cpp71
-rw-r--r--layout/forms/nsProgressFrame.h38
-rw-r--r--layout/forms/nsRangeFrame.cpp280
-rw-r--r--layout/forms/nsRangeFrame.h50
-rw-r--r--layout/forms/nsTextControlFrame.cpp110
-rw-r--r--layout/forms/nsTextControlFrame.h14
-rw-r--r--layout/forms/test/mochitest.toml2
-rw-r--r--layout/forms/test/test_bug869314.html55
-rw-r--r--layout/generic/AspectRatio.cpp2
-rw-r--r--layout/generic/AspectRatio.h2
-rw-r--r--layout/generic/BRFrame.cpp13
-rw-r--r--layout/generic/CSSAlignUtils.cpp6
-rw-r--r--layout/generic/ColumnSetWrapperFrame.cpp2
-rw-r--r--layout/generic/MiddleCroppingBlockFrame.cpp11
-rw-r--r--layout/generic/PrintedSheetFrame.cpp1
-rw-r--r--layout/generic/ReflowInput.cpp219
-rw-r--r--layout/generic/ReflowInput.h48
-rw-r--r--layout/generic/ScrollAnchorContainer.cpp12
-rw-r--r--layout/generic/ScrollGeneration.h5
-rw-r--r--layout/generic/ScrollSnapTargetId.h1
-rw-r--r--layout/generic/StickyScrollContainer.cpp6
-rw-r--r--layout/generic/ViewportFrame.cpp23
-rw-r--r--layout/generic/WritingModes.h415
-rw-r--r--layout/generic/crashtests/1410243-1.html26
-rw-r--r--layout/generic/crashtests/1741488-1.html23
-rw-r--r--layout/generic/crashtests/1881375-1-helper.html38
-rw-r--r--layout/generic/crashtests/1881375-1.html25
-rw-r--r--layout/generic/crashtests/481921.oggbin42852 -> 0 bytes
-rw-r--r--layout/generic/crashtests/crashtests.list9
-rw-r--r--layout/generic/nsAbsoluteContainingBlock.cpp12
-rw-r--r--layout/generic/nsBackdropFrame.cpp1
-rw-r--r--layout/generic/nsBlockFrame.cpp38
-rw-r--r--layout/generic/nsCanvasFrame.cpp35
-rw-r--r--layout/generic/nsColumnSetFrame.cpp13
-rw-r--r--layout/generic/nsContainerFrame.cpp46
-rw-r--r--layout/generic/nsContainerFrame.h122
-rw-r--r--layout/generic/nsContainerFrameInlines.h4
-rw-r--r--layout/generic/nsFirstLetterFrame.cpp11
-rw-r--r--layout/generic/nsFlexContainerFrame.cpp419
-rw-r--r--layout/generic/nsFlexContainerFrame.h9
-rw-r--r--layout/generic/nsFloatManager.cpp8
-rw-r--r--layout/generic/nsFrameSelection.cpp35
-rw-r--r--layout/generic/nsFrameSelection.h32
-rw-r--r--layout/generic/nsFrameSetFrame.cpp2
-rw-r--r--layout/generic/nsGfxScrollFrame.cpp62
-rw-r--r--layout/generic/nsGfxScrollFrame.h2
-rw-r--r--layout/generic/nsGridContainerFrame.cpp527
-rw-r--r--layout/generic/nsGridContainerFrame.h71
-rw-r--r--layout/generic/nsHTMLCanvasFrame.cpp3
-rw-r--r--layout/generic/nsIFrame.cpp1254
-rw-r--r--layout/generic/nsIFrame.h55
-rw-r--r--layout/generic/nsIFrameInlines.h2
-rw-r--r--layout/generic/nsImageFrame.cpp21
-rw-r--r--layout/generic/nsInlineFrame.cpp11
-rw-r--r--layout/generic/nsLeafFrame.cpp10
-rw-r--r--layout/generic/nsLineBox.cpp2
-rw-r--r--layout/generic/nsLineBox.h48
-rw-r--r--layout/generic/nsLineLayout.cpp8
-rw-r--r--layout/generic/nsPageContentFrame.cpp1
-rw-r--r--layout/generic/nsPageFrame.cpp84
-rw-r--r--layout/generic/nsPageSequenceFrame.cpp1
-rw-r--r--layout/generic/nsPlaceholderFrame.cpp1
-rw-r--r--layout/generic/nsRubyBaseContainerFrame.cpp1
-rw-r--r--layout/generic/nsRubyFrame.cpp23
-rw-r--r--layout/generic/nsRubyTextContainerFrame.cpp1
-rw-r--r--layout/generic/nsSplittableFrame.cpp8
-rw-r--r--layout/generic/nsSubDocumentFrame.cpp63
-rw-r--r--layout/generic/nsTextFrame.cpp66
-rw-r--r--layout/generic/nsTextPaintStyle.cpp18
-rw-r--r--layout/generic/nsTextPaintStyle.h1
-rw-r--r--layout/generic/nsTextRunTransformations.cpp20
-rw-r--r--layout/generic/nsTextRunTransformations.h3
-rw-r--r--layout/generic/nsVideoFrame.cpp8
-rw-r--r--layout/generic/test/mochitest.toml37
-rw-r--r--layout/generic/test/selection_cross_shadow_boundary_helper.js28
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_1_backward_click.html36
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_1_backward_drag.html40
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_1_forward_click.html35
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_1_forward_drag.html39
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_2_backward_click.html47
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_2_backward_drag.html48
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_2_forward_click.html46
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_2_forward_drag.html48
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_backward_click.html61
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_backward_drag.html65
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_forward_click.html59
-rw-r--r--layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_forward_drag.html65
-rw-r--r--layout/inspector/InspectorCSSParser.cpp70
-rw-r--r--layout/inspector/InspectorCSSParser.h47
-rw-r--r--layout/inspector/InspectorUtils.cpp31
-rw-r--r--layout/inspector/InspectorUtils.h15
-rw-r--r--layout/inspector/ServoStyleRuleMap.cpp8
-rw-r--r--layout/inspector/moz.build2
-rw-r--r--layout/inspector/tests/chrome/chrome.toml2
-rw-r--r--layout/inspector/tests/chrome/test_CSSStyleRule_querySelectorAll.html121
-rw-r--r--layout/inspector/tests/mochitest.toml3
-rw-r--r--layout/inspector/tests/test_bug877690.html7
-rw-r--r--layout/inspector/tests/test_getCSSPseudoElementNames.html1
-rw-r--r--layout/inspector/tests/test_replaceBlockRuleBodyTextInStylesheet.html209
-rw-r--r--layout/mathml/nsMathMLContainerFrame.cpp22
-rw-r--r--layout/mathml/nsMathMLContainerFrame.h15
-rw-r--r--layout/mathml/nsMathMLmoFrame.cpp33
-rw-r--r--layout/mathml/nsMathMLmtableFrame.h3
-rw-r--r--layout/painting/RetainedDisplayListBuilder.cpp19
-rw-r--r--layout/painting/RetainedDisplayListBuilder.h6
-rw-r--r--layout/painting/crashtests/1862277-1.html6
-rw-r--r--layout/painting/crashtests/1870415-1.html35
-rw-r--r--layout/painting/crashtests/crashtests.list7
-rw-r--r--layout/painting/nsCSSRenderingGradients.cpp30
-rw-r--r--layout/painting/nsCSSRenderingGradients.h37
-rw-r--r--layout/painting/nsDisplayList.cpp174
-rw-r--r--layout/painting/nsDisplayList.h51
-rw-r--r--layout/printing/crashtests/1758199-1.html55
-rw-r--r--layout/printing/crashtests/crashtests.list2
-rw-r--r--layout/reftests/async-scrolling/reftest.list18
-rw-r--r--layout/reftests/bidi/dirAuto/reftest.list2
-rw-r--r--layout/reftests/bugs/1888941-text-transform-emergency-wrap-ref.html2
-rw-r--r--layout/reftests/bugs/1888941-text-transform-emergency-wrap.html2
-rw-r--r--layout/reftests/bugs/307102-2-ref.html8
-rw-r--r--layout/reftests/bugs/307102-2.html8
-rw-r--r--layout/reftests/bugs/385870-1-ref.html51
-rw-r--r--layout/reftests/bugs/385870-1.html55
-rw-r--r--layout/reftests/bugs/385870-2-ref.html51
-rw-r--r--layout/reftests/bugs/385870-2.html55
-rw-r--r--layout/reftests/bugs/404553-1-ref.html2
-rw-r--r--layout/reftests/bugs/404553-1.html2
-rw-r--r--layout/reftests/bugs/reftest.list16
-rw-r--r--layout/reftests/counters/counter-hebrew-reference.html5
-rw-r--r--layout/reftests/counters/counters-hebrew-reference.html93
-rw-r--r--layout/reftests/counters/t1202-counter-06-b-reference.html4
-rw-r--r--layout/reftests/counters/t1202-counter-07-b-reference.html8
-rw-r--r--layout/reftests/counters/t1202-counter-08-b-reference.html8
-rw-r--r--layout/reftests/counters/t1202-counters-06-b-reference.html28
-rw-r--r--layout/reftests/counters/t1202-counters-07-b-reference.html36
-rw-r--r--layout/reftests/counters/t1202-counters-08-b-reference.html36
-rw-r--r--layout/reftests/counters/t1202-counters-09-b-reference.html78
-rw-r--r--layout/reftests/counters/t1202-counters-10-b-reference.html76
-rw-r--r--layout/reftests/counters/t1204-reset-00-c-o-reference.html2
-rw-r--r--layout/reftests/counters/t120401-scope-01-c-reference.html2
-rw-r--r--layout/reftests/counters/t120401-scope-02-c-reference.html2
-rw-r--r--layout/reftests/css-gradients/reftest.list4
-rw-r--r--layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001-ref.html2
-rw-r--r--layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001.html2
-rw-r--r--layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html2
-rw-r--r--layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002.html2
-rw-r--r--layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003-ref.html2
-rw-r--r--layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003.html2
-rw-r--r--layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html2
-rw-r--r--layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004.html2
-rw-r--r--layout/reftests/dom/reftest.list2
-rw-r--r--layout/reftests/flexbox/reftest.list1
-rw-r--r--layout/reftests/forms/input/file/reftest.list2
-rw-r--r--layout/reftests/forms/input/range/1887539-ref.html30
-rw-r--r--layout/reftests/forms/input/range/1887539.html35
-rw-r--r--layout/reftests/forms/input/range/reftest.list2
-rw-r--r--layout/reftests/forms/input/text/autofill-author-background.html4
-rw-r--r--layout/reftests/forms/input/text/autofill-blank.html2
-rw-r--r--layout/reftests/forms/input/text/autofill-prefilled-value.html4
-rw-r--r--layout/reftests/forms/input/text/autofill-preview-blank.html2
-rw-r--r--layout/reftests/forms/input/text/autofill-preview-line-height.html4
-rw-r--r--layout/reftests/forms/input/text/autofill-preview.html4
-rw-r--r--layout/reftests/forms/input/text/autofill.html4
-rw-r--r--layout/reftests/forms/input/text/reftest.list2
-rw-r--r--layout/reftests/forms/input/text/suppress-password-button-notref.html1
-rw-r--r--layout/reftests/forms/input/text/suppress-password-button.html1
-rw-r--r--layout/reftests/forms/textarea/in-ltr-doc-scrollbar.html5
-rw-r--r--layout/reftests/forms/textarea/in-rtl-doc-scrollbar.html6
-rw-r--r--layout/reftests/forms/textarea/ltr-scrollbar.html5
-rw-r--r--layout/reftests/forms/textarea/rtl-scrollbar.html5
-rw-r--r--layout/reftests/marquee/336736-1a-ref.html5
-rw-r--r--layout/reftests/marquee/336736-1b-ref.html (renamed from layout/reftests/marquee/336736-1-ref.html)0
-rw-r--r--layout/reftests/marquee/reftest.list4
-rw-r--r--layout/reftests/moz.build2
-rw-r--r--layout/reftests/ogg-video/444-1-ref.html20
-rw-r--r--layout/reftests/ogg-video/444-1.html20
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-1-ref.html6
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-1a.xhtml14
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-1b.xhtml14
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-2-ref.html6
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-2a.xhtml14
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-2b.xhtml14
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-3-ref.xhtml14
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-3a.xhtml14
-rw-r--r--layout/reftests/ogg-video/aspect-ratio-3b.xhtml14
-rw-r--r--layout/reftests/ogg-video/basic-1-ref.html6
-rw-r--r--layout/reftests/ogg-video/basic-1.xhtml14
-rw-r--r--layout/reftests/ogg-video/black100x100-aspect3to2.ogvbin3428 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/black140x100.ogvbin2871 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/black29x19offset.ogvbin3988 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/blue140x100.pngbin277 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/blue250x200.pngbin1157 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/canvas-1a.xhtml29
-rw-r--r--layout/reftests/ogg-video/canvas-1b.xhtml27
-rw-r--r--layout/reftests/ogg-video/clipping-1-ref.html9
-rw-r--r--layout/reftests/ogg-video/clipping-1a.html8
-rw-r--r--layout/reftests/ogg-video/empty-1-ref.html5
-rw-r--r--layout/reftests/ogg-video/empty-1a.html6
-rw-r--r--layout/reftests/ogg-video/empty-1b.html6
-rw-r--r--layout/reftests/ogg-video/encoded-aspect-ratio-1-ref.html19
-rw-r--r--layout/reftests/ogg-video/encoded-aspect-ratio-1.html29
-rw-r--r--layout/reftests/ogg-video/green70x30.pngbin224 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/object-aspect-ratio-1a.xhtml14
-rw-r--r--layout/reftests/ogg-video/object-aspect-ratio-1b.xhtml14
-rw-r--r--layout/reftests/ogg-video/object-aspect-ratio-2a.xhtml14
-rw-r--r--layout/reftests/ogg-video/object-aspect-ratio-2b.xhtml14
-rw-r--r--layout/reftests/ogg-video/offset-1-ref.html6
-rw-r--r--layout/reftests/ogg-video/offset-1.xhtml14
-rw-r--r--layout/reftests/ogg-video/poster-1.html7
-rw-r--r--layout/reftests/ogg-video/poster-10.html18
-rw-r--r--layout/reftests/ogg-video/poster-11.html29
-rw-r--r--layout/reftests/ogg-video/poster-12.html38
-rw-r--r--layout/reftests/ogg-video/poster-13.html8
-rw-r--r--layout/reftests/ogg-video/poster-15.html13
-rw-r--r--layout/reftests/ogg-video/poster-2.html7
-rw-r--r--layout/reftests/ogg-video/poster-3.html11
-rw-r--r--layout/reftests/ogg-video/poster-4.html14
-rw-r--r--layout/reftests/ogg-video/poster-5.html13
-rw-r--r--layout/reftests/ogg-video/poster-6.html12
-rw-r--r--layout/reftests/ogg-video/poster-7.html14
-rw-r--r--layout/reftests/ogg-video/poster-8.html12
-rw-r--r--layout/reftests/ogg-video/poster-ref-black140x100.html6
-rw-r--r--layout/reftests/ogg-video/poster-ref-blue125x100.html6
-rw-r--r--layout/reftests/ogg-video/poster-ref-blue140x100.html6
-rw-r--r--layout/reftests/ogg-video/poster-ref-blue250x200.html6
-rw-r--r--layout/reftests/ogg-video/poster-ref-blue400x300.html8
-rw-r--r--layout/reftests/ogg-video/poster-ref-green70x30.html6
-rw-r--r--layout/reftests/ogg-video/poster-ref-red140x100.html6
-rw-r--r--layout/reftests/ogg-video/red140x100.pngbin274 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/red160x120.pngbin720 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/reftest.list35
-rw-r--r--layout/reftests/ogg-video/seek420.ogvbin30163 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/seek444.ogvbin30408 -> 0 bytes
-rw-r--r--layout/reftests/ogg-video/zoomed-1-ref.html6
-rw-r--r--layout/reftests/ogg-video/zoomed-1.xhtml15
-rw-r--r--layout/reftests/position-sticky/reftest.list4
-rw-r--r--layout/reftests/printing/1900028-text-mask-pdf-ref.html15
-rw-r--r--layout/reftests/printing/1900028-text-mask-pdf.html17
-rw-r--r--layout/reftests/printing/reftest.list1
-rw-r--r--layout/reftests/reftest-sanity/reftest.list5
-rw-r--r--layout/reftests/reftest.list12
-rw-r--r--layout/reftests/scrolling/reftest.list8
-rw-r--r--layout/reftests/svg/1630900-1-ref.html27
-rw-r--r--layout/reftests/svg/1630900-1.html42
-rw-r--r--layout/reftests/svg/reftest.list4
-rw-r--r--layout/reftests/svg/smil/anim-feComponentTransfer-01.svg10
-rw-r--r--layout/reftests/svg/smil/anim-feComposite-operator-01.svg10
-rw-r--r--layout/reftests/svg/smil/anim-feConvolveMatrix-order-01.svg10
-rw-r--r--layout/reftests/svg/smil/anim-feDistantLight-01.svg10
-rw-r--r--layout/reftests/svg/smil/anim-feFuncR-tableValues-01.svg9
-rw-r--r--layout/reftests/svg/smil/anim-feGaussianBlur-01.svg10
-rw-r--r--layout/reftests/svg/smil/anim-feOffset-01.svg10
-rw-r--r--layout/reftests/svg/smil/anim-feSpotLight-01.svg10
-rw-r--r--layout/reftests/svg/smil/anim-feTurbulence-numOctaves-01.svg9
-rw-r--r--layout/reftests/svg/smil/anim-feTurbulence-numOctaves-02.svg10
-rw-r--r--layout/reftests/svg/smil/anim-filter-filterUnits-01.svg10
-rw-r--r--layout/reftests/svg/smil/anim-filter-href-01.svg9
-rw-r--r--layout/reftests/svg/text/reftest.list4
-rw-r--r--layout/reftests/text/reftest.list4
-rw-r--r--layout/reftests/transform-3d/reftest.list1
-rw-r--r--layout/style/CSSKeyframeRule.cpp3
-rw-r--r--layout/style/CSSMarginRule.cpp183
-rw-r--r--layout/style/CSSMarginRule.h107
-rw-r--r--layout/style/CSSPageRule.cpp22
-rw-r--r--layout/style/CSSPageRule.h10
-rw-r--r--layout/style/CSSScopeRule.cpp66
-rw-r--r--layout/style/CSSScopeRule.h49
-rw-r--r--layout/style/CSSStartingStyleRule.cpp47
-rw-r--r--layout/style/CSSStartingStyleRule.h54
-rw-r--r--layout/style/CSSStyleRule.cpp14
-rw-r--r--layout/style/CSSStyleRule.h2
-rw-r--r--layout/style/FontFaceImpl.cpp47
-rw-r--r--layout/style/FontFaceImpl.h20
-rw-r--r--layout/style/FontFaceSetDocumentImpl.cpp2
-rw-r--r--layout/style/FontFaceSetImpl.cpp5
-rw-r--r--layout/style/FontFaceSetImpl.h7
-rw-r--r--layout/style/FontFaceSetWorkerImpl.cpp8
-rw-r--r--layout/style/GeckoBindings.cpp38
-rw-r--r--layout/style/GeckoBindings.h21
-rw-r--r--layout/style/GenerateServoCSSPropList.py2
-rw-r--r--layout/style/ImageLoader.cpp10
-rw-r--r--layout/style/Loader.cpp25
-rw-r--r--layout/style/PreferenceSheet.cpp3
-rw-r--r--layout/style/Rule.cpp10
-rw-r--r--layout/style/ServoBindingTypes.h3
-rw-r--r--layout/style/ServoBindings.h5
-rw-r--r--layout/style/ServoBindings.toml8
-rw-r--r--layout/style/ServoCSSRuleList.cpp28
-rw-r--r--layout/style/ServoElementSnapshot.cpp7
-rw-r--r--layout/style/ServoElementSnapshot.h7
-rw-r--r--layout/style/ServoLockedArcTypeList.h1
-rw-r--r--layout/style/ServoStyleConstsForwards.h5
-rw-r--r--layout/style/ServoStyleConstsInlines.h44
-rw-r--r--layout/style/ServoStyleSet.cpp24
-rw-r--r--layout/style/ServoStyleSet.h14
-rw-r--r--layout/style/SharedSubResourceCache.h3
-rw-r--r--layout/style/SheetLoadData.h8
-rw-r--r--layout/style/crashtests/crashtests.list22
-rw-r--r--layout/style/moz.build7
-rw-r--r--layout/style/nsCSSPseudoElementList.h1
-rw-r--r--layout/style/nsCSSPseudoElements.h2
-rw-r--r--layout/style/nsCSSValue.h18
-rw-r--r--layout/style/nsComputedDOMStyle.cpp153
-rw-r--r--layout/style/nsComputedDOMStyle.h6
-rw-r--r--layout/style/nsDOMCSSAttrDeclaration.h2
-rw-r--r--layout/style/nsDOMCSSDeclaration.h2
-rw-r--r--layout/style/nsMediaFeatures.cpp11
-rw-r--r--layout/style/nsROCSSPrimitiveValue.cpp8
-rw-r--r--layout/style/nsROCSSPrimitiveValue.h2
-rw-r--r--layout/style/nsStyleStruct.cpp14
-rw-r--r--layout/style/nsStyleStruct.h69
-rw-r--r--layout/style/res/forms.css13
-rw-r--r--layout/style/res/html.css14
-rw-r--r--layout/style/res/quirk.css6
-rw-r--r--layout/style/test/chrome/chrome-only-media-queries.js1
-rw-r--r--layout/style/test/mochitest.toml5
-rw-r--r--layout/style/test/property_database.js308
-rw-r--r--layout/style/test/test_hover_quirk.html32
-rw-r--r--layout/style/test/test_non_content_accessible_pseudos.html1
-rw-r--r--layout/style/test/test_selectors.html1
-rw-r--r--layout/style/test/test_style_struct_copy_constructors.html14
-rw-r--r--layout/svg/CSSClipPathInstance.cpp43
-rw-r--r--layout/svg/CSSClipPathInstance.h3
-rw-r--r--layout/svg/SVGAFrame.cpp14
-rw-r--r--layout/svg/SVGContextPaint.cpp2
-rw-r--r--layout/svg/SVGFEImageFrame.cpp18
-rw-r--r--layout/svg/SVGGeometryFrame.cpp8
-rw-r--r--layout/svg/SVGGradientFrame.cpp9
-rw-r--r--layout/svg/SVGImageFrame.cpp20
-rw-r--r--layout/svg/SVGOuterSVGFrame.cpp13
-rw-r--r--layout/svg/SVGUseFrame.cpp13
-rw-r--r--layout/svg/SVGUseFrame.h2
-rw-r--r--layout/svg/SVGUtils.cpp4
-rw-r--r--layout/svg/crashtests/crashtests.list6
-rw-r--r--layout/tables/BasicTableLayoutStrategy.cpp14
-rw-r--r--layout/tables/FixedTableLayoutStrategy.cpp5
-rw-r--r--layout/tables/celldata.h4
-rw-r--r--layout/tables/nsCellMap.cpp34
-rw-r--r--layout/tables/nsTableCellFrame.cpp56
-rw-r--r--layout/tables/nsTableCellFrame.h90
-rw-r--r--layout/tables/nsTableColFrame.cpp1
-rw-r--r--layout/tables/nsTableColGroupFrame.cpp5
-rw-r--r--layout/tables/nsTableFrame.cpp381
-rw-r--r--layout/tables/nsTableRowFrame.cpp26
-rw-r--r--layout/tables/nsTableRowFrame.h14
-rw-r--r--layout/tables/nsTableRowGroupFrame.cpp7
-rw-r--r--layout/tables/nsTableWrapperFrame.cpp9
-rw-r--r--layout/tools/reftest/jar.mn1
-rw-r--r--layout/tools/reftest/mach_commands.py4
-rw-r--r--layout/tools/reftest/manifest.sys.mjs115
-rw-r--r--layout/tools/reftest/reftest.sys.mjs6
-rw-r--r--layout/tools/reftest/reftestcommandline.py5
-rw-r--r--layout/tools/reftest/runreftest.py49
-rw-r--r--layout/xul/nsMenuPopupFrame.cpp20
-rw-r--r--layout/xul/nsXULPopupManager.cpp1
-rw-r--r--layout/xul/tree/crashtests/crashtests.list2
-rw-r--r--layout/xul/tree/nsTreeBodyFrame.cpp318
-rw-r--r--layout/xul/tree/nsTreeBodyFrame.h8
412 files changed, 7947 insertions, 6229 deletions
diff --git a/layout/base/AccessibleCaretManager.cpp b/layout/base/AccessibleCaretManager.cpp
index 17597d287d..7c125cf023 100644
--- a/layout/base/AccessibleCaretManager.cpp
+++ b/layout/base/AccessibleCaretManager.cpp
@@ -19,6 +19,7 @@
#include "mozilla/dom/NodeFilterBinding.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/TreeWalker.h"
+#include "mozilla/FocusModel.h"
#include "mozilla/IMEStateManager.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/PresShell.h"
@@ -222,27 +223,17 @@ bool AccessibleCaretManager::IsCaretDisplayableInCursorMode(
if (!caret || !caret->IsVisible()) {
return false;
}
-
- int32_t offset = 0;
- nsIFrame* frame =
- nsCaret::GetFrameAndOffset(GetSelection(), nullptr, 0, &offset);
-
- if (!frame) {
- return false;
- }
-
- if (!GetEditingHostForFrame(frame)) {
+ auto frameData =
+ nsCaret::GetFrameAndOffset(nsCaret::CaretPositionFor(GetSelection()));
+ if (!GetEditingHostForFrame(frameData.mFrame)) {
return false;
}
-
if (aOutFrame) {
- *aOutFrame = frame;
+ *aOutFrame = frameData.mFrame;
}
-
if (aOutOffset) {
- *aOutOffset = offset;
+ *aOutOffset = frameData.mOffsetInFrameContent;
}
-
return true;
}
@@ -889,7 +880,7 @@ nsIFrame* AccessibleCaretManager::GetFocusableFrame(nsIFrame* aFrame) const {
// Look for the nearest enclosing focusable frame.
nsIFrame* focusableFrame = aFrame;
while (focusableFrame) {
- if (focusableFrame->IsFocusable(/* aWithMouse = */ true)) {
+ if (focusableFrame->IsFocusable(IsFocusableFlags::WithMouse)) {
break;
}
focusableFrame = focusableFrame->GetParent();
@@ -1333,10 +1324,9 @@ nsPoint AccessibleCaretManager::AdjustDragBoundary(
const nsPoint& aPoint) const {
nsPoint adjustedPoint = aPoint;
- int32_t focusOffset = 0;
- nsIFrame* focusFrame =
- nsCaret::GetFrameAndOffset(GetSelection(), nullptr, 0, &focusOffset);
- Element* editingHost = GetEditingHostForFrame(focusFrame);
+ auto frameData =
+ nsCaret::GetFrameAndOffset(nsCaret::CaretPositionFor(GetSelection()));
+ Element* editingHost = GetEditingHostForFrame(frameData.mFrame);
if (editingHost) {
nsIFrame* editingHostFrame = editingHost->GetPrimaryFrame();
@@ -1471,8 +1461,7 @@ void AccessibleCaretManager::DispatchCaretStateChangedEvent(
// Send isEditable info w/ event detail. This info can help determine
// whether to show cut command on selection dialog or not.
- init.mSelectionEditable =
- commonAncestorFrame && GetEditingHostForFrame(commonAncestorFrame);
+ init.mSelectionEditable = GetEditingHostForFrame(commonAncestorFrame);
init.mBoundingClientRect = domRect;
init.mReason = aReason;
diff --git a/layout/base/MotionPathUtils.cpp b/layout/base/MotionPathUtils.cpp
index 4045f2304a..d620064b73 100644
--- a/layout/base/MotionPathUtils.cpp
+++ b/layout/base/MotionPathUtils.cpp
@@ -434,7 +434,7 @@ Maybe<ResolvedMotionPathData> MotionPathUtils::ResolveMotionPath(
static inline bool IsClosedLoop(const StyleSVGPathData& aPathData) {
return !aPathData._0.AsSpan().empty() &&
- aPathData._0.AsSpan().rbegin()->IsClosePath();
+ aPathData._0.AsSpan().rbegin()->IsClose();
}
// Create a path for "inset(0 round X)", where X is the value of border-radius
@@ -466,8 +466,8 @@ static already_AddRefed<gfx::Path> BuildDefaultPathForURL(
return nullptr;
}
- Array<const StylePathCommand, 1> array(StylePathCommand::MoveTo(
- StyleCoordPair(gfx::Point{0.0, 0.0}), StyleIsAbsolute::No));
+ Array<const StylePathCommand, 1> array(StylePathCommand::Move(
+ StyleByTo::By, StyleCoordinatePair<StyleCSSFloat>{0.0, 0.0}));
return SVGPathData::BuildPath(array, aBuilder, StyleStrokeLinecap::Butt, 0.0);
}
@@ -695,6 +695,21 @@ already_AddRefed<gfx::Path> MotionPathUtils::BuildSVGPath(
0.0);
}
+static already_AddRefed<gfx::Path> BuildShape(
+ const Span<const StyleShapeCommand>& aShape, gfx::PathBuilder* aPathBuilder,
+ const nsRect& aCoordBox) {
+ if (!aPathBuilder) {
+ return nullptr;
+ }
+
+ // For motion path, we always use CSSPixel unit to compute the offset
+ // transform (i.e. motion path transform).
+ const auto rect = CSSRect::FromAppUnits(aCoordBox);
+ return SVGPathData::BuildPath(aShape, aPathBuilder, StyleStrokeLinecap::Butt,
+ 0.0, rect.Size(),
+ rect.TopLeft().ToUnknownPoint());
+}
+
/* static */
already_AddRefed<gfx::Path> MotionPathUtils::BuildPath(
const StyleBasicShape& aBasicShape,
@@ -725,12 +740,22 @@ already_AddRefed<gfx::Path> MotionPathUtils::BuildPath(
case StyleBasicShape::Tag::Polygon:
return ShapeUtils::BuildPolygonPath(aBasicShape, aCoordBox,
AppUnitsPerCSSPixel(), aPathBuilder);
- case StyleBasicShape::Tag::Path:
+ case StyleBasicShape::Tag::PathOrShape: {
// FIXME: Bug 1836847. Once we support "at <position>" for path(), we have
// to also check its containing block as well. For now, we are still
// building its gfx::Path directly by its SVGPathData without other
// reference. https://github.com/w3c/fxtf-drafts/issues/504
- return BuildSVGPath(aBasicShape.AsPath().path, aPathBuilder);
+ const auto& pathOrShape = aBasicShape.AsPathOrShape();
+ if (pathOrShape.IsPath()) {
+ return BuildSVGPath(pathOrShape.AsPath().path, aPathBuilder);
+ }
+
+ // Note that shape() always defines the initial position, i.e. "from x y",
+ // by its first move command, so |aOffsetPosition|, i.e. offset-position
+ // property, is ignored.
+ return BuildShape(pathOrShape.AsShape().commands.AsSpan(), aPathBuilder,
+ aCoordBox);
+ }
}
return nullptr;
diff --git a/layout/base/PositionedEventTargeting.cpp b/layout/base/PositionedEventTargeting.cpp
index a975372dea..9af132d96d 100644
--- a/layout/base/PositionedEventTargeting.cpp
+++ b/layout/base/PositionedEventTargeting.cpp
@@ -6,6 +6,7 @@
#include "PositionedEventTargeting.h"
+#include "Units.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/Preferences.h"
@@ -13,18 +14,23 @@
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/StaticPrefs_ui.h"
#include "mozilla/ToString.h"
+#include "mozilla/ViewportUtils.h"
#include "mozilla/dom/MouseEventBinding.h"
+#include "mozilla/gfx/Matrix.h"
+#include "mozilla/layers/LayersTypes.h"
#include "nsContainerFrame.h"
+#include "nsCoord.h"
#include "nsFrameList.h" // for DEBUG_FRAME_DUMP
#include "nsHTMLParts.h"
#include "nsLayoutUtils.h"
#include "nsGkAtoms.h"
#include "nsFontMetrics.h"
+#include "nsIContentInlines.h"
+#include "nsPresContext.h"
#include "nsPrintfCString.h"
#include "mozilla/dom/Element.h"
#include "nsRegion.h"
#include "nsDeviceContext.h"
-#include "nsIContentInlines.h"
#include "nsIFrame.h"
#include <algorithm>
@@ -276,15 +282,40 @@ static nsIContent* GetClickableAncestor(
return nullptr;
}
-static nscoord AppUnitsFromMM(RelativeTo aFrame, uint32_t aMM) {
- nsPresContext* pc = aFrame.mFrame->PresContext();
- float result = float(aMM) * (pc->DeviceContext()->AppUnitsPerPhysicalInch() /
- MM_PER_INCH_FLOAT);
- if (aFrame.mViewportType == ViewportType::Layout) {
+static Scale2D AppUnitsToMMScale(RelativeTo aFrame) {
+ nsPresContext* presContext = aFrame.mFrame->PresContext();
+
+ const int32_t appUnitsPerInch =
+ presContext->DeviceContext()->AppUnitsPerPhysicalInch();
+ const float appUnits =
+ static_cast<float>(appUnitsPerInch) / MM_PER_INCH_FLOAT;
+
+ // Visual coordinates are only used for quantities relative to the
+ // cross-process root content document's root frame. There should
+ // not be an enclosing resolution or transform scale above that.
+ if (aFrame.mViewportType != ViewportType::Layout) {
+ const nscoord scale = NSToCoordRound(appUnits);
+ return Scale2D{static_cast<float>(scale), static_cast<float>(scale)};
+ }
+
+ Scale2D localResolution{1.0f, 1.0f};
+ Scale2D enclosingResolution{1.0f, 1.0f};
+
+ if (auto* pc = presContext->GetInProcessRootContentDocumentPresContext()) {
PresShell* presShell = pc->PresShell();
- result = result / presShell->GetResolution();
+ localResolution = {presShell->GetResolution(), presShell->GetResolution()};
+ enclosingResolution = ViewportUtils::TryInferEnclosingResolution(presShell);
}
- return NSToCoordRound(result);
+
+ const gfx::MatrixScales parentScale =
+ nsLayoutUtils::GetTransformToAncestorScale(aFrame.mFrame);
+ const Scale2D resolution =
+ localResolution * parentScale * enclosingResolution;
+
+ const nscoord scaleX = NSToCoordRound(appUnits / resolution.xScale);
+ const nscoord scaleY = NSToCoordRound(appUnits / resolution.yScale);
+
+ return {static_cast<float>(scaleX), static_cast<float>(scaleY)};
}
/**
@@ -303,10 +334,11 @@ static nsRect GetTargetRect(RelativeTo aRootFrame,
const nsPoint& aPointRelativeToRootFrame,
const nsIFrame* aRestrictToDescendants,
const EventRadiusPrefs& aPrefs, uint32_t aFlags) {
- nsMargin m(AppUnitsFromMM(aRootFrame, aPrefs.mRadiusTopmm),
- AppUnitsFromMM(aRootFrame, aPrefs.mRadiusRightmm),
- AppUnitsFromMM(aRootFrame, aPrefs.mRadiusBottommm),
- AppUnitsFromMM(aRootFrame, aPrefs.mRadiusLeftmm));
+ const Scale2D scale = AppUnitsToMMScale(aRootFrame);
+ nsMargin m(aPrefs.mRadiusTopmm * scale.yScale,
+ aPrefs.mRadiusRightmm * scale.xScale,
+ aPrefs.mRadiusBottommm * scale.yScale,
+ aPrefs.mRadiusLeftmm * scale.xScale);
nsRect r(aPointRelativeToRootFrame, nsSize(0, 0));
r.Inflate(m);
if (!(aFlags & INPUT_IGNORE_ROOT_SCROLL_FRAME)) {
diff --git a/layout/base/PresShell.cpp b/layout/base/PresShell.cpp
index 31c21c3377..cd41da3730 100644
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -14,6 +14,7 @@
#include "mozilla/dom/AncestorIterator.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/dom/ElementBinding.h"
+#include "mozilla/dom/FragmentDirective.h"
#include "mozilla/dom/LargestContentfulPaint.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/PerformanceMainThread.h"
@@ -1281,10 +1282,13 @@ void PresShell::Destroy() {
ClearApproximatelyVisibleFramesList(Some(OnNonvisible::DiscardImages));
- if (mCaret) {
+ if (mOriginalCaret) {
+ mOriginalCaret->Terminate();
+ }
+ if (mCaret && mCaret != mOriginalCaret) {
mCaret->Terminate();
- mCaret = nullptr;
}
+ mCaret = mOriginalCaret = nullptr;
mFocusedFrameSelection = nullptr;
@@ -2238,9 +2242,20 @@ PresShell::GetAccessibleCaretEventHub() const {
return eventHub.forget();
}
-void PresShell::SetCaret(nsCaret* aNewCaret) { mCaret = aNewCaret; }
+void PresShell::SetCaret(nsCaret* aNewCaret) {
+ if (mCaret == aNewCaret) {
+ return;
+ }
+ if (mCaret) {
+ mCaret->SchedulePaint();
+ }
+ mCaret = aNewCaret;
+ if (aNewCaret) {
+ aNewCaret->SchedulePaint();
+ }
+}
-void PresShell::RestoreCaret() { mCaret = mOriginalCaret; }
+void PresShell::RestoreCaret() { SetCaret(mOriginalCaret); }
NS_IMETHODIMP PresShell::SetCaretEnabled(bool aInEnable) {
bool oldEnabled = mCaretEnabled;
@@ -3277,6 +3292,46 @@ nsresult PresShell::ScrollToAnchor() {
ScrollAxis(), ScrollFlags::AnchorScrollFlags);
}
+bool PresShell::HighlightAndGoToTextFragment(bool aScrollToTextFragment) {
+ MOZ_ASSERT(mDocument);
+ if (!StaticPrefs::dom_text_fragments_enabled()) {
+ return false;
+ }
+ const RefPtr<FragmentDirective> fragmentDirective =
+ mDocument->FragmentDirective();
+
+ nsTArray<RefPtr<nsRange>> textDirectiveRanges =
+ fragmentDirective->FindTextFragmentsInDocument();
+ if (textDirectiveRanges.IsEmpty()) {
+ return false;
+ }
+
+ const RefPtr<Selection> targetTextSelection =
+ GetCurrentSelection(SelectionType::eTargetText);
+ if (!targetTextSelection) {
+ return false;
+ }
+ for (RefPtr<nsRange> range : textDirectiveRanges) {
+ targetTextSelection->AddRangeAndSelectFramesAndNotifyListeners(
+ *range, IgnoreErrors());
+ }
+ if (!aScrollToTextFragment) {
+ return false;
+ }
+
+ // Scroll the last text directive into view.
+ nsRange* lastRange = textDirectiveRanges.LastElement();
+ MOZ_ASSERT(lastRange);
+ if (RefPtr<nsIContent> lastRangeStartContent =
+ nsIContent::FromNode(lastRange->GetStartContainer())) {
+ return ScrollContentIntoView(
+ lastRangeStartContent,
+ ScrollAxis(WhereToScroll::Center, WhenToScroll::Always),
+ ScrollAxis(), ScrollFlags::AnchorScrollFlags) == NS_OK;
+ }
+ return false;
+}
+
/*
* Helper (per-continuation) for ScrollContentIntoView.
*
@@ -3876,11 +3931,9 @@ void PresShell::ScheduleViewManagerFlush() {
return;
}
- nsPresContext* presContext = GetPresContext();
- if (presContext) {
+ if (nsPresContext* presContext = GetPresContext()) {
presContext->RefreshDriver()->ScheduleViewManagerFlush();
}
- SetNeedLayoutFlush();
}
void PresShell::DispatchSynthMouseMove(WidgetGUIEvent* aEvent) {
@@ -4473,6 +4526,26 @@ MOZ_CAN_RUN_SCRIPT_BOUNDARY void PresShell::ElementStateChanged(
}
}
+MOZ_CAN_RUN_SCRIPT_BOUNDARY void PresShell::CustomStatesWillChange(
+ Element& aElement) {
+ if (MOZ_UNLIKELY(!mDidInitialize)) {
+ return;
+ }
+
+ mPresContext->RestyleManager()->CustomStatesWillChange(aElement);
+}
+
+MOZ_CAN_RUN_SCRIPT_BOUNDARY void PresShell::CustomStateChanged(
+ Element& aElement, nsAtom* aState) {
+ MOZ_ASSERT(!mIsDocumentGone, "Unexpected CustomStateChanged");
+ MOZ_ASSERT(aState, "Unexpected empty state");
+
+ if (mDidInitialize) {
+ nsAutoCauseReflowNotifier crNotifier(this);
+ mPresContext->RestyleManager()->CustomStateChanged(aElement, aState);
+ }
+}
+
void PresShell::DocumentStatesChanged(DocumentState aStateMask) {
MOZ_ASSERT(!mIsDocumentGone, "Unexpected DocumentStatesChanged");
MOZ_ASSERT(mDocument);
@@ -5582,7 +5655,7 @@ nsresult PresShell::SetResolutionAndScaleTo(float aResolution,
// GetResolution handles mResolution being nothing by returning 1 so this
// is checking that the resolution is actually changing.
- bool resolutionUpdated = (aResolution != GetResolution());
+ bool resolutionUpdated = aResolution != GetResolution();
mLastResolutionChangeOrigin = aOrigin;
@@ -5647,7 +5720,9 @@ void PresShell::SetRenderingState(const RenderingState& aState) {
}
void PresShell::SynthesizeMouseMove(bool aFromScroll) {
- if (!StaticPrefs::layout_reflow_synthMouseMove()) return;
+ if (!StaticPrefs::layout_reflow_synthMouseMove()) {
+ return;
+ }
if (mPaintingSuppressed || !mIsActive || !mPresContext) {
return;
@@ -5660,8 +5735,9 @@ void PresShell::SynthesizeMouseMove(bool aFromScroll) {
return;
}
- if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE))
+ if (mMouseLocation == nsPoint(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)) {
return;
+ }
if (!mSynthMouseMoveEvent.IsPending()) {
RefPtr<nsSynthMouseMoveEvent> ev =
@@ -6488,7 +6564,7 @@ void PresShell::PaintInternal(nsView* aViewToPaint, PaintInternalFlags aFlags) {
// We also force sync-decoding via pref for reftests.
if (aFlags & PaintInternalFlags::PaintSyncDecodeImages ||
mDocument->IsStaticDocument() ||
- StaticPrefs::image_decode_sync_enabled()) {
+ StaticPrefs::image_testing_decode_sync_enabled()) {
flags |= PaintFrameFlags::SyncDecodeImages;
}
if (renderer->GetBackendType() == layers::LayersBackend::LAYERS_WR) {
@@ -11182,10 +11258,8 @@ void PresShell::SetIsActive(bool aIsActive) {
#if defined(MOZ_WIDGET_ANDROID)
if (!aIsActive && presContext &&
presContext->IsRootContentDocumentCrossProcess()) {
- if (BrowserChild* browserChild = BrowserChild::GetFrom(this)) {
- // Reset the dynamic toolbar offset state.
- presContext->UpdateDynamicToolbarOffset(0);
- }
+ // Reset the dynamic toolbar offset state.
+ presContext->UpdateDynamicToolbarOffset(0);
}
#endif
}
@@ -11220,8 +11294,7 @@ Maybe<MobileViewportManager::ManagerType> UseMobileViewportManager(
if (nsLayoutUtils::ShouldHandleMetaViewport(aDocument)) {
return Some(MobileViewportManager::ManagerType::VisualAndMetaViewport);
}
- if (StaticPrefs::apz_mvm_force_enabled() ||
- nsLayoutUtils::AllowZoomingForDocument(aDocument)) {
+ if (nsLayoutUtils::AllowZoomingForDocument(aDocument)) {
return Some(MobileViewportManager::ManagerType::VisualViewportOnly);
}
return Nothing();
@@ -11244,6 +11317,11 @@ void PresShell::MaybeRecreateMobileViewportManager(bool aAfterInitialization) {
return;
}
+ if (!mPresContext->IsRootContentDocumentCrossProcess()) {
+ MOZ_ASSERT(!mMobileViewportManager, "We never create MVMs for subframes");
+ return;
+ }
+
if (mMobileViewportManager) {
// We have one, but we need to either destroy it completely to replace it
// with another one of the correct type. So either way, let's destroy the
@@ -11253,16 +11331,6 @@ void PresShell::MaybeRecreateMobileViewportManager(bool aAfterInitialization) {
mMVMContext = nullptr;
ResetVisualViewportSize();
-
- // After we clear out the MVM and the MVMContext, also reset the
- // resolution to its pre-MVM value.
- SetResolutionAndScaleTo(mDocument->GetSavedResolutionBeforeMVM(),
- ResolutionChangeOrigin::MainThreadRestore);
-
- if (aAfterInitialization) {
- // Force a reflow to our correct view manager size.
- ForceResizeReflowWithCurrentDimensions();
- }
}
if (mvmType) {
@@ -11270,32 +11338,33 @@ void PresShell::MaybeRecreateMobileViewportManager(bool aAfterInitialization) {
// have one.
MOZ_ASSERT(!mMobileViewportManager);
- if (mPresContext->IsRootContentDocumentCrossProcess()) {
- // Store the resolution so we can restore to this resolution when
- // the MVM is destroyed.
- mDocument->SetSavedResolutionBeforeMVM(mResolution.valueOr(1.0f));
-
- mMVMContext = new GeckoMVMContext(mDocument, this);
- mMobileViewportManager = new MobileViewportManager(mMVMContext, *mvmType);
- if (MOZ_UNLIKELY(
- MOZ_LOG_TEST(MobileViewportManager::gLog, LogLevel::Debug))) {
- nsIURI* uri = mDocument->GetDocumentURI();
- MOZ_LOG(MobileViewportManager::gLog, LogLevel::Debug,
- ("Created MVM %p (type %d) for URI %s",
- mMobileViewportManager.get(), (int)*mvmType,
- uri ? uri->GetSpecOrDefault().get() : "(null)"));
- }
-
- if (aAfterInitialization) {
- // Setting the initial viewport will trigger a reflow.
- mMobileViewportManager->SetInitialViewport();
- }
+ mMVMContext = new GeckoMVMContext(mDocument, this);
+ mMobileViewportManager = new MobileViewportManager(mMVMContext, *mvmType);
+ if (MOZ_UNLIKELY(
+ MOZ_LOG_TEST(MobileViewportManager::gLog, LogLevel::Debug))) {
+ nsIURI* uri = mDocument->GetDocumentURI();
+ MOZ_LOG(
+ MobileViewportManager::gLog, LogLevel::Debug,
+ ("Created MVM %p (type %d) for URI %s", mMobileViewportManager.get(),
+ (int)*mvmType, uri ? uri->GetSpecOrDefault().get() : "(null)"));
}
}
+ if (aAfterInitialization) {
+ // Setting the initial viewport will trigger a reflow.
+ if (mMobileViewportManager) {
+ mMobileViewportManager->SetInitialViewport();
+ } else {
+ // Force a reflow to our correct view manager size.
+ ForceResizeReflowWithCurrentDimensions();
+ }
+ // After we clear out the MVM and the MVMContext, also reset the
+ // resolution to 1.
+ SetResolutionAndScaleTo(1.0f, ResolutionChangeOrigin::MainThreadRestore);
+ }
}
bool PresShell::UsesMobileViewportSizing() const {
- return mMobileViewportManager != nullptr &&
+ return mMobileViewportManager &&
nsLayoutUtils::ShouldHandleMetaViewport(mDocument);
}
@@ -11708,8 +11777,7 @@ static bool IsTopLevelWidget(nsIWidget* aWidget) {
auto windowType = aWidget->GetWindowType();
return windowType == WindowType::TopLevel ||
- windowType == WindowType::Dialog || windowType == WindowType::Popup ||
- windowType == WindowType::Sheet;
+ windowType == WindowType::Dialog || windowType == WindowType::Popup;
}
PresShell::WindowSizeConstraints PresShell::GetWindowSizeConstraints() {
@@ -11777,10 +11845,9 @@ void PresShell::SyncWindowProperties(bool aSync) {
canvas ? canvas : rootFrame, rootFrame);
windowWidget->SetTransparencyMode(mode);
- // For macOS, apply color scheme overrides to the top level window widget.
- if (auto scheme = pc->GetOverriddenOrEmbedderColorScheme()) {
- windowWidget->SetColorScheme(scheme);
- }
+ // For macOS, apply color scheme to the top level window widget.
+ windowWidget->SetColorScheme(
+ Some(LookAndFeel::ColorSchemeForFrame(rootFrame)));
}
if (!weak.IsAlive()) {
@@ -12030,13 +12097,6 @@ void PresShell::EventHandler::EventTargetData::UpdateWheelEventTarget(
return;
}
- // If the browsing context is no longer the same as the context of the
- // current wheel transaction, do not override the event target.
- if (!groupFrame->PresContext() || !groupFrame->PresShell() ||
- groupFrame->PresContext() != GetPresContext()) {
- return;
- }
-
// If dom.event.wheel-event-groups.enabled is set and whe have a stored
// event target from the wheel transaction, override the event target.
SetFrameAndComputePresShellAndContent(groupFrame, aGUIEvent);
diff --git a/layout/base/PresShell.h b/layout/base/PresShell.h
index 482ace1421..2b43b3c492 100644
--- a/layout/base/PresShell.h
+++ b/layout/base/PresShell.h
@@ -531,6 +531,12 @@ class PresShell final : public nsStubDocumentObserver,
dom::HTMLSlotElement* aOldSlot,
dom::HTMLSlotElement* aNewSlot);
+ /**
+ * Handles when a CustomStateSet state is about to be removed or added.
+ */
+ void CustomStatesWillChange(Element& aElement);
+ void CustomStateChanged(Element& aElement, nsAtom* aState);
+
void PostRecreateFramesFor(Element*);
void RestyleForAnimation(Element*, RestyleHint);
@@ -1604,6 +1610,18 @@ class PresShell final : public nsStubDocumentObserver,
MOZ_CAN_RUN_SCRIPT nsresult ScrollToAnchor();
/**
+ * Finds text fragments ranes in the document, highlights the ranges and
+ * scrolls to the last text fragment range on the page if
+ * `aScrollToTextFragment` is true.
+ *
+ * @param aScrollToTextFragment If true, scrolls the view to the last text
+ * fragment.
+ * @return True if scrolling happened.
+ */
+ MOZ_CAN_RUN_SCRIPT bool HighlightAndGoToTextFragment(
+ bool aScrollToTextFragment);
+
+ /**
* When scroll anchoring adjusts positions in the root frame during page load,
* it may move our scroll position in the root frame.
*
diff --git a/layout/base/RestyleManager.cpp b/layout/base/RestyleManager.cpp
index 8c07512093..e00493467f 100644
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -2087,6 +2087,28 @@ void RestyleManager::AnimationsWithDestroyedFrame ::StopAnimationsWithoutFrame(
}
}
+// When using handled hints by an ancestor, we need to make sure that our
+// ancestor in the DOM tree is actually our ancestor in the flat tree.
+// Otherwise, we can't guarantee that e.g. a repaint from an ancestor in the DOM
+// will really end up repainting us.
+static bool CanUseHandledHintsFromAncestors(const nsIFrame* aFrame) {
+ if (aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW)) {
+ // An out of flow can be parented in other part of the tree.
+ return false;
+ }
+ if (aFrame->IsColumnSpanInMulticolSubtree()) {
+ // Any column-spanner's parent frame is not its DOM parent's primary frame.
+ return false;
+ }
+ if (aFrame->IsTableCaption()) {
+ // This one is more subtle. captions are in-flow children of the table
+ // frame. But they are parented to the table wrapper. So hints handled for
+ // the inner table might not be applicable to us.
+ return false;
+ }
+ return true;
+}
+
#ifdef DEBUG
static bool IsAnonBox(const nsIFrame* aFrame) {
return aFrame->Style()->IsAnonBox();
@@ -2185,8 +2207,7 @@ static bool IsInReplicatedFixedPosTree(const nsIFrame* aFrame) {
void ServoRestyleState::AssertOwner(const ServoRestyleState& aParent) const {
MOZ_ASSERT(mOwner);
- MOZ_ASSERT(!mOwner->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW));
- MOZ_ASSERT(!mOwner->IsColumnSpanInMulticolSubtree());
+ MOZ_ASSERT(CanUseHandledHintsFromAncestors(mOwner));
// We allow aParent.mOwner to be null, for cases when we're not starting at
// the root of the tree. We also allow aParent.mOwner to be somewhere up our
// expected owner chain not our immediate owner, which allows us creating long
@@ -2309,7 +2330,7 @@ size_t ServoRestyleState::ProcessMaybeNestedWrapperRestyle(nsIFrame* aParent,
nsLayoutUtils::FirstContinuationOrIBSplitSibling(parent);
if (parentForRestyle != aParent) {
parentRestyleState.emplace(*parentForRestyle, *this, nsChangeHint_Empty,
- Type::InFlow);
+ CanUseHandledHints::Yes);
}
ServoRestyleState& curRestyleState =
parentRestyleState ? *parentRestyleState : *this;
@@ -2332,7 +2353,7 @@ size_t ServoRestyleState::ProcessMaybeNestedWrapperRestyle(nsIFrame* aParent,
// the other hand, presumably our mChangesHandled already has the bits
// we really want here so in practice it doesn't matter.
ServoRestyleState childState(*cur, curRestyleState, nsChangeHint_Empty,
- Type::InFlow,
+ CanUseHandledHints::Yes,
/* aAssertWrapperRestyleLength = */ false);
numProcessed +=
childState.ProcessMaybeNestedWrapperRestyle(cur, aIndex + 1);
@@ -2652,8 +2673,7 @@ static void UpdateOneAdditionalComputedStyle(nsIFrame* aFrame, uint32_t aIndex,
uint32_t equalStructs; // Not used, actually.
nsChangeHint childHint =
aOldContext.CalcStyleDifference(*newStyle, &equalStructs);
- if (!aFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
- !aFrame->IsColumnSpanInMulticolSubtree()) {
+ if (CanUseHandledHintsFromAncestors(aFrame)) {
childHint = NS_RemoveSubsumedHints(childHint,
aRestyleState.ChangesHandledFor(aFrame));
}
@@ -2812,11 +2832,8 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement,
const bool isOutOfFlow =
primaryFrame && primaryFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
- // We need this because any column-spanner's parent frame is not its DOM
- // parent's primary frame. We need some special check similar to out-of-flow
- // frames.
- const bool isColumnSpan =
- primaryFrame && primaryFrame->IsColumnSpanInMulticolSubtree();
+ const bool canUseHandledHints =
+ primaryFrame && CanUseHandledHintsFromAncestors(primaryFrame);
// Grab the change hint from Servo.
bool wasRestyled = false;
@@ -2848,11 +2865,12 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement,
maybeAnonBoxChild = primaryFrame->GetPlaceholderFrame();
} else {
maybeAnonBoxChild = primaryFrame;
- // Do not subsume change hints for the column-spanner.
- if (!isColumnSpan) {
- changeHint = NS_RemoveSubsumedHints(
- changeHint, aRestyleState.ChangesHandledFor(styleFrame));
- }
+ }
+
+ // Do not subsume change hints for the column-spanner.
+ if (canUseHandledHints) {
+ changeHint = NS_RemoveSubsumedHints(
+ changeHint, aRestyleState.ChangesHandledFor(styleFrame));
}
// If the parent wasn't restyled, the styles of our anon box parents won't
@@ -2944,10 +2962,9 @@ bool RestyleManager::ProcessPostTraversal(Element* aElement,
Maybe<ServoRestyleState> thisFrameRestyleState;
if (styleFrame) {
- auto type = isOutOfFlow || isColumnSpan ? ServoRestyleState::Type::OutOfFlow
- : ServoRestyleState::Type::InFlow;
-
- thisFrameRestyleState.emplace(*styleFrame, aRestyleState, changeHint, type);
+ thisFrameRestyleState.emplace(
+ *styleFrame, aRestyleState, changeHint,
+ ServoRestyleState::CanUseHandledHints(canUseHandledHints));
}
// We can't really assume as used changes from display: contents elements (or
@@ -3229,6 +3246,12 @@ void RestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags) {
// construction).
nsTArray<RefPtr<Element>> anchorsToSuppress;
+ // Unfortunately, the frame constructor and ProcessPostTraversal can
+ // generate new change hints while processing existing ones. We redirect
+ // those into a secondary queue and iterate until there's nothing left.
+ ReentrantChangeList newChanges;
+ mReentrantChanges = &newChanges;
+
{
DocumentStyleRootIterator iter(doc->GetServoRestyleRoot());
while (Element* root = iter.GetNextStyleRoot()) {
@@ -3254,34 +3277,26 @@ void RestyleManager::DoProcessPendingRestyles(ServoTraversalFlags aFlags) {
doc->ClearServoRestyleRoot();
ClearSnapshots();
- // Process the change hints.
- //
- // Unfortunately, the frame constructor can generate new change hints while
- // processing existing ones. We redirect those into a secondary queue and
- // iterate until there's nothing left.
- {
- ReentrantChangeList newChanges;
- mReentrantChanges = &newChanges;
- while (!currentChanges.IsEmpty()) {
- ProcessRestyledFrames(currentChanges);
- MOZ_ASSERT(currentChanges.IsEmpty());
- for (ReentrantChange& change : newChanges) {
- if (!(change.mHint & nsChangeHint_ReconstructFrame) &&
- !change.mContent->GetPrimaryFrame()) {
- // SVG Elements post change hints without ensuring that the primary
- // frame will be there after that (see bug 1366142).
- //
- // Just ignore those, since we can't really process them.
- continue;
- }
- currentChanges.AppendChange(change.mContent->GetPrimaryFrame(),
- change.mContent, change.mHint);
+ while (!currentChanges.IsEmpty()) {
+ ProcessRestyledFrames(currentChanges);
+ MOZ_ASSERT(currentChanges.IsEmpty());
+ for (ReentrantChange& change : newChanges) {
+ if (!(change.mHint & nsChangeHint_ReconstructFrame) &&
+ !change.mContent->GetPrimaryFrame()) {
+ // SVG Elements post change hints without ensuring that the primary
+ // frame will be there after that (see bug 1366142).
+ //
+ // Just ignore those, since we can't really process them.
+ continue;
}
- newChanges.Clear();
+ currentChanges.AppendChange(change.mContent->GetPrimaryFrame(),
+ change.mContent, change.mHint);
}
- mReentrantChanges = nullptr;
+ newChanges.Clear();
}
+ mReentrantChanges = nullptr;
+
// Suppress adjustments in the after-change scroll anchors if needed, now
// that we're done reframing everything.
for (Element* element : anchorsToSuppress) {
@@ -3435,6 +3450,45 @@ void RestyleManager::ElementStateChanged(Element* aElement,
MaybeRestyleForRelativeSelectorState(styleSet, aElement, aChangedBits);
}
+void RestyleManager::CustomStatesWillChange(Element& aElement) {
+ MOZ_DIAGNOSTIC_ASSERT(!mInStyleRefresh);
+
+ IncrementUndisplayedRestyleGeneration();
+
+ // Relative selector invalidation travels ancestor and earlier sibling
+ // direction, so it's very possible that it invalidates a styled element.
+ if (!aElement.HasServoData() &&
+ !(aElement.GetSelectorFlags() &
+ NodeSelectorFlags::RelativeSelectorSearchDirectionAncestorSibling)) {
+ return;
+ }
+
+ ServoElementSnapshot& snapshot = SnapshotFor(aElement);
+ snapshot.AddCustomStates(aElement);
+}
+
+void RestyleManager::CustomStateChanged(Element& aElement, nsAtom* aState) {
+ ServoStyleSet& styleSet = *StyleSet();
+ MaybeRestyleForNthOfCustomState(styleSet, aElement, aState);
+ styleSet.MaybeInvalidateRelativeSelectorCustomStateDependency(
+ aElement, aState, Snapshots());
+}
+
+void RestyleManager::MaybeRestyleForNthOfCustomState(ServoStyleSet& aStyleSet,
+ Element& aChild,
+ nsAtom* aState) {
+ const auto* parentNode = aChild.GetParentNode();
+ MOZ_ASSERT(parentNode);
+ const auto parentFlags = parentNode->GetSelectorFlags();
+ if (!(parentFlags & NodeSelectorFlags::HasSlowSelectorNthOf)) {
+ return;
+ }
+
+ if (aStyleSet.HasNthOfCustomStateDependency(aChild, aState)) {
+ RestyleSiblingsForNthOf(&aChild, parentFlags);
+ }
+}
+
void RestyleManager::MaybeRestyleForNthOfState(ServoStyleSet& aStyleSet,
Element* aChild,
ElementState aChangedBits) {
diff --git a/layout/base/RestyleManager.h b/layout/base/RestyleManager.h
index 62fef15a16..8485fe18a0 100644
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -66,13 +66,11 @@ class ServoRestyleState {
// our children too if we're out of flow since they aren't necessarily
// parented in DOM order, and thus a change handled by a DOM ancestor doesn't
// necessarily mean that it's handled for an ancestor frame.
- enum class Type {
- InFlow,
- OutOfFlow,
- };
+ enum class CanUseHandledHints : bool { No = false, Yes };
ServoRestyleState(const nsIFrame& aOwner, ServoRestyleState& aParentState,
- nsChangeHint aHintForThisFrame, Type aType,
+ nsChangeHint aHintForThisFrame,
+ CanUseHandledHints aCanUseHandledHints,
bool aAssertWrapperRestyleLength = true)
: mStyleSet(aParentState.mStyleSet),
mChangeList(aParentState.mChangeList),
@@ -81,7 +79,7 @@ class ServoRestyleState {
aParentState.mPendingScrollAnchorSuppressions),
mPendingWrapperRestyleOffset(
aParentState.mPendingWrapperRestyles.Length()),
- mChangesHandled(aType == Type::InFlow
+ mChangesHandled(bool(aCanUseHandledHints)
? aParentState.mChangesHandled | aHintForThisFrame
: aHintForThisFrame)
#ifdef DEBUG
@@ -90,7 +88,7 @@ class ServoRestyleState {
mAssertWrapperRestyleLength(aAssertWrapperRestyleLength)
#endif
{
- if (aType == Type::InFlow) {
+ if (bool(aCanUseHandledHints)) {
AssertOwner(aParentState);
}
}
@@ -361,6 +359,11 @@ class RestyleManager {
void ElementStateChanged(Element*, dom::ElementState);
+ void CustomStatesWillChange(Element&);
+ void CustomStateChanged(Element&, nsAtom* aState);
+ void MaybeRestyleForNthOfCustomState(ServoStyleSet&, Element&,
+ nsAtom* aState);
+
/**
* Posts restyle hints for siblings of an element and their descendants if the
* element's parent has NODE_HAS_SLOW_SELECTOR_NTH_OF and the element has a
diff --git a/layout/base/ViewportUtils.cpp b/layout/base/ViewportUtils.cpp
index f0d18510bf..8b8e4a4d27 100644
--- a/layout/base/ViewportUtils.cpp
+++ b/layout/base/ViewportUtils.cpp
@@ -260,6 +260,9 @@ const nsIFrame* ViewportUtils::IsZoomedContentRoot(const nsIFrame* aFrame) {
}
Scale2D ViewportUtils::TryInferEnclosingResolution(PresShell* aShell) {
+ if (!XRE_IsContentProcess()) {
+ return {1.0f, 1.0f};
+ }
MOZ_ASSERT(aShell && aShell->GetPresContext());
MOZ_ASSERT(!aShell->GetPresContext()->GetParentPresContext(),
"TryInferEnclosingResolution can only be called for a root pres "
diff --git a/layout/base/ZoomConstraintsClient.cpp b/layout/base/ZoomConstraintsClient.cpp
index e695c7755e..e9be0c2073 100644
--- a/layout/base/ZoomConstraintsClient.cpp
+++ b/layout/base/ZoomConstraintsClient.cpp
@@ -53,9 +53,20 @@ static nsIWidget* GetWidget(PresShell* aPresShell) {
return nullptr;
}
if (nsIFrame* rootFrame = aPresShell->GetRootFrame()) {
+#if defined(MOZ_WIDGET_ANDROID)
+ // On Android in cases of about:XX pages loaded in the browser parent
+ // process we need to return the nearest widget since it's the widget owning
+ // an IAPZCTreeManager to communicate with the APZCTreeManager for the
+ // browser.
+ // In bug 1648427 we will apply this code to desktops as well to make
+ // about pages zoomable on desktops, but it will be involving more works,
+ // see https://bugzilla.mozilla.org/show_bug.cgi?id=1648427#c7 .
+ return rootFrame->GetNearestWidget();
+#else
if (nsView* view = rootFrame->GetView()) {
return view->GetWidget();
}
+#endif
}
return nullptr;
}
@@ -199,6 +210,11 @@ void ZoomConstraintsClient::RefreshZoomConstraints() {
return;
}
+ // Ignore documents which has been removed from the doc shell.
+ if (!mDocument->IsActive()) {
+ return;
+ }
+
uint32_t presShellId = 0;
ScrollableLayerGuid::ViewID viewId = ScrollableLayerGuid::NULL_SCROLL_ID;
bool scrollIdentifiersValid =
diff --git a/layout/base/crashtests/crashtests.list b/layout/base/crashtests/crashtests.list
index d9cf87f4d2..a379b981b6 100644
--- a/layout/base/crashtests/crashtests.list
+++ b/layout/base/crashtests/crashtests.list
@@ -385,11 +385,7 @@ load 836990-1.html
load 840480.html
load 842114.html
load 847242.html
-# This test is slow, because it uses setTimeout a lot.
-# After bug 1875100, on windows, it times out because there's a left-over
-# window or so, and that bug causes us to throttle timers. Disable window
-# occlusion to work around this for now, see bug 1864255.
-pref(widget.windows.window_occlusion_tracking.enabled,false) skip-if(ThreadSanitizer) load 852293.html
+skip-if(ThreadSanitizer) load 852293.html
pref(layers.force-active,true) load 859526-1.html
pref(layers.force-active,true) load 859630-1.html
load 860579-1.html
@@ -494,7 +490,7 @@ load 1463940.html
HTTP load 1464641.html
load 1464737.html
load 1466638.html
-pref(layout.css.motion-path-ray.enabled,true) asserts(1-1) load 1467519.html # bogus size
+asserts(1-1) load 1467519.html # bogus size
load 1467688.html
load 1467964.html
load 1469354.html
@@ -528,7 +524,7 @@ load 1539303.html
load 1541679.html
load 1547261.html
load 1547391.html
-pref(widget.windows.window_occlusion_tracking.enabled,false) load 1548057.html # Bug 1819154
+load 1548057.html
load 1549867.html
load 1553874.html
load 1560328.html
@@ -547,7 +543,7 @@ load 1599532.html
pref(layout.accessiblecaret.enabled,true) load 1606492.html
load 1654315.html
load 1676301-1.html
-pref(apz.mvm.force-enabled,false) pref(dom.meta-viewport.enabled,false) pref(apz.allow_zooming,false) pref(layout.dynamic-toolbar-max-height,100) load 1689371.html
+pref(dom.meta-viewport.enabled,false) pref(apz.allow_zooming,false) pref(layout.dynamic-toolbar-max-height,100) load 1689371.html
load 1685146.html
load 1689912.html
load 1690163.html
diff --git a/layout/base/metrics.yaml b/layout/base/metrics.yaml
index 856ff77965..631200bd48 100644
--- a/layout/base/metrics.yaml
+++ b/layout/base/metrics.yaml
@@ -29,6 +29,22 @@ performance.pageload:
- perf-telemetry-alerts@mozilla.com
expires: never
+ async_sheet_load:
+ type: timing_distribution
+ time_unit: millisecond
+ description: >
+ Time spent in milliseconds since a style sheet started loading async
+ until it finished.
+ bugs:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1892660
+ data_reviews:
+ - https://bugzilla.mozilla.org/show_bug.cgi?id=1892660
+ data_sensitivity:
+ - technical
+ notification_emails:
+ - emilio@mozilla.com
+ - perf-telemetry-alerts@mozilla.com
+ expires: 132
performance.responsiveness:
req_anim_frame_callback:
diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp
index 149f2f24bf..ba43eb70b9 100644
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -1537,12 +1537,11 @@ already_AddRefed<nsIContent> nsCSSFrameConstructor::CreateGenConTextNode(
void nsCSSFrameConstructor::CreateGeneratedContent(
nsFrameConstructorState& aState, Element& aOriginatingElement,
- ComputedStyle& aPseudoStyle, uint32_t aContentIndex,
- const FunctionRef<void(nsIContent*)> aAddChild) {
+ ComputedStyle& aPseudoStyle, const StyleContentItem& aItem,
+ size_t aContentIndex, const FunctionRef<void(nsIContent*)> aAddChild) {
using Type = StyleContentItem::Tag;
// Get the content value
- const auto& item = aPseudoStyle.StyleContent()->ContentAt(aContentIndex);
- const Type type = item.tag;
+ const Type type = aItem.tag;
switch (type) {
case Type::Image: {
@@ -1552,7 +1551,7 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
}
case Type::String: {
- const auto string = item.AsString().AsString();
+ const auto string = aItem.AsString().AsString();
if (string.IsEmpty()) {
return;
}
@@ -1563,7 +1562,7 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
}
case Type::Attr: {
- const auto& attr = item.AsAttr();
+ const auto& attr = aItem.AsAttr();
RefPtr<nsAtom> attrName = attr.attribute.AsAtom();
int32_t attrNameSpace = kNameSpaceID_None;
RefPtr<nsAtom> ns = attr.namespace_url.AsAtom();
@@ -1592,11 +1591,11 @@ void nsCSSFrameConstructor::CreateGeneratedContent(
CounterStylePtr ptr;
nsString separator;
if (type == Type::Counter) {
- auto& counter = item.AsCounter();
+ auto& counter = aItem.AsCounter();
name = counter._0.AsAtom();
ptr = CounterStylePtr::FromStyle(counter._1);
} else {
- auto& counters = item.AsCounters();
+ auto& counters = aItem.AsCounters();
name = counters._0.AsAtom();
CopyUTF8toUTF16(counters._1.AsString(), separator);
ptr = CounterStylePtr::FromStyle(counters._2);
@@ -1947,13 +1946,14 @@ void nsCSSFrameConstructor::CreateGeneratedContentItem(
mPresShell->StyleSet()->StyleNewSubtree(childElement);
}
};
- const uint32_t contentCount = pseudoStyle->StyleContent()->ContentCount();
- for (uint32_t contentIndex = 0; contentIndex < contentCount; contentIndex++) {
- CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle,
- contentIndex, AppendChild);
+ auto items = pseudoStyle->StyleContent()->NonAltContentItems();
+ size_t index = 0;
+ for (const auto& item : items) {
+ CreateGeneratedContent(aState, aOriginatingElement, *pseudoStyle, item,
+ index++, AppendChild);
}
// If a ::marker has no 'content' then generate it from its 'list-style-*'.
- if (contentCount == 0 && aPseudoElement == PseudoStyleType::marker) {
+ if (index == 0 && aPseudoElement == PseudoStyleType::marker) {
CreateGeneratedContentFromListStyle(aState, aOriginatingElement,
*pseudoStyle, AppendChild);
}
@@ -4985,9 +4985,8 @@ nsCSSFrameConstructor::FindSVGData(const Element& aElement,
return data;
}
-void nsCSSFrameConstructor::InsertPageBreakItem(
- nsIContent* aContent, FrameConstructionItemList& aItems,
- InsertPageBreakLocation location) {
+void nsCSSFrameConstructor::AppendPageBreakItem(
+ nsIContent* aContent, FrameConstructionItemList& aItems) {
RefPtr<ComputedStyle> pseudoStyle =
mPresShell->StyleSet()->ResolveNonInheritingAnonymousBoxStyle(
PseudoStyleType::pageBreak);
@@ -4997,13 +4996,8 @@ void nsCSSFrameConstructor::InsertPageBreakItem(
static constexpr FrameConstructionData sPageBreakData(NS_NewPageBreakFrame,
FCDATA_SKIP_FRAMESET);
- if (location == InsertPageBreakLocation::eBefore) {
- aItems.PrependItem(this, &sPageBreakData, aContent, pseudoStyle.forget(),
- true);
- } else {
- aItems.AppendItem(this, &sPageBreakData, aContent, pseudoStyle.forget(),
- true);
- }
+ aItems.AppendItem(this, &sPageBreakData, aContent, pseudoStyle.forget(),
+ true);
}
bool nsCSSFrameConstructor::ShouldCreateItemsForChild(
@@ -5289,7 +5283,7 @@ void nsCSSFrameConstructor::AddFrameConstructionItemsInternal(
aFlags.contains(ItemFlag::AllowPageBreak) &&
aState.mPresContext->IsPaginated() &&
!display.IsAbsolutelyPositionedStyle() &&
- !(aParentFrame && aParentFrame->IsGridContainerFrame()) &&
+ !(aParentFrame && aParentFrame->IsFlexOrGridContainer()) &&
!(bits & FCDATA_IS_TABLE_PART) && !(bits & FCDATA_IS_SVG_TEXT);
if (canHavePageBreak && display.BreakBefore()) {
AppendPageBreakItem(aContent, aItems);
@@ -6012,7 +6006,7 @@ nsIFrame* nsCSSFrameConstructor::GetInsertionPrevSibling(
// Find the frame that precedes the insertion point.
FlattenedChildIterator iter(aInsertion->mContainer);
- if (iter.ShadowDOMInvolved() || !aChild->IsRootOfNativeAnonymousSubtree()) {
+ if (!aChild->IsRootOfNativeAnonymousSubtree()) {
// The check for IsRootOfNativeAnonymousSubtree() is because editor is
// severely broken and calls us directly for native anonymous
// nodes that it creates.
@@ -8390,7 +8384,7 @@ void nsCSSFrameConstructor::RecreateFramesForContent(
}
// TODO(emilio): We technically can find the right insertion point nowadays
- // using StyleChildrenIterator rather than FlattenedTreeIterator. But we'd
+ // using StyleChildrenIterator rather than FlattenedChildIterator. But we'd
// need to tweak the setup to insert into replaced elements to filter which
// anonymous roots can be allowed, and which can't.
//
diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h
index 283d1385ce..5fdea315b8 100644
--- a/layout/base/nsCSSFrameConstructor.h
+++ b/layout/base/nsCSSFrameConstructor.h
@@ -477,7 +477,8 @@ class nsCSSFrameConstructor final : public nsFrameManager {
*/
void CreateGeneratedContent(
nsFrameConstructorState& aState, Element& aOriginatingElement,
- ComputedStyle& aPseudoStyle, uint32_t aContentIndex,
+ ComputedStyle& aPseudoStyle, const mozilla::StyleContentItem& aItem,
+ size_t aContentIndex,
const mozilla::FunctionRef<void(nsIContent*)> aAddChild);
/**
@@ -1423,18 +1424,8 @@ class nsCSSFrameConstructor final : public nsFrameManager {
// for it.
void ReframeTextIfNeeded(nsIContent* aContent);
- enum InsertPageBreakLocation { eBefore, eAfter };
- inline void AppendPageBreakItem(nsIContent* aContent,
- FrameConstructionItemList& aItems) {
- InsertPageBreakItem(aContent, aItems, InsertPageBreakLocation::eAfter);
- }
- inline void PrependPageBreakItem(nsIContent* aContent,
- FrameConstructionItemList& aItems) {
- InsertPageBreakItem(aContent, aItems, InsertPageBreakLocation::eBefore);
- }
- void InsertPageBreakItem(nsIContent* aContent,
- FrameConstructionItemList& aItems,
- InsertPageBreakLocation location);
+ void AppendPageBreakItem(nsIContent* aContent,
+ FrameConstructionItemList& aItems);
// Function to find FrameConstructionData for aElement. Will return
// null if aElement is not HTML.
diff --git a/layout/base/nsCaret.cpp b/layout/base/nsCaret.cpp
index d66d55d6bb..8707dcba5f 100644
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -50,16 +50,7 @@ using BidiEmbeddingLevel = mozilla::intl::BidiEmbeddingLevel;
// like an insignificant dot
static const int32_t kMinBidiIndicatorPixels = 2;
-nsCaret::nsCaret()
- : mOverrideOffset(0),
- mBlinkCount(-1),
- mBlinkRate(0),
- mHideCount(0),
- mIsBlinkOn(false),
- mVisible(false),
- mReadOnly(false),
- mShowDuringSelection(false),
- mIgnoreUserModify(true) {}
+nsCaret::nsCaret() = default;
nsCaret::~nsCaret() { StopBlinking(); }
@@ -70,10 +61,6 @@ nsresult nsCaret::Init(PresShell* aPresShell) {
do_GetWeakReference(aPresShell); // the presshell owns us, so no addref
NS_ASSERTION(mPresShell, "Hey, pres shell should support weak refs");
- mShowDuringSelection =
- LookAndFeel::GetInt(LookAndFeel::IntID::ShowCaretDuringSelection,
- mShowDuringSelection ? 1 : 0) != 0;
-
RefPtr<Selection> selection =
aPresShell->GetSelection(nsISelectionController::SELECTION_NORMAL);
if (!selection) {
@@ -82,6 +69,7 @@ nsresult nsCaret::Init(PresShell* aPresShell) {
selection->AddSelectionListener(this);
mDomSelectionWeak = selection;
+ UpdateCaretPositionFromSelectionIfNeeded();
return NS_OK;
}
@@ -137,8 +125,7 @@ void nsCaret::Terminate() {
}
mDomSelectionWeak = nullptr;
mPresShell = nullptr;
-
- mOverrideContent = nullptr;
+ mCaretPosition = {};
}
NS_IMPL_ISUPPORTS(nsCaret, nsISelectionListener)
@@ -148,15 +135,30 @@ Selection* nsCaret::GetSelection() { return mDomSelectionWeak; }
void nsCaret::SetSelection(Selection* aDOMSel) {
MOZ_ASSERT(aDOMSel);
mDomSelectionWeak = aDOMSel;
+ UpdateCaretPositionFromSelectionIfNeeded();
ResetBlinking();
- SchedulePaint(aDOMSel);
+ SchedulePaint();
}
-void nsCaret::SetVisible(bool inMakeVisible) {
- mVisible = inMakeVisible;
- mIgnoreUserModify = mVisible;
+void nsCaret::SetVisible(bool aVisible) {
+ const bool wasVisible = mVisible;
+ mVisible = aVisible;
+ mIgnoreUserModify = aVisible;
+ if (mVisible != wasVisible) {
+ CaretVisibilityMaybeChanged();
+ }
+}
+
+bool nsCaret::IsVisible() const { return mVisible && !mHideCount; }
+
+void nsCaret::CaretVisibilityMaybeChanged() {
ResetBlinking();
SchedulePaint();
+ if (IsVisible()) {
+ // We ignore caret position updates when the caret is not visible, so we
+ // update the caret position here if needed.
+ UpdateCaretPositionFromSelectionIfNeeded();
+ }
}
void nsCaret::AddForceHide() {
@@ -164,20 +166,18 @@ void nsCaret::AddForceHide() {
if (++mHideCount > 1) {
return;
}
- ResetBlinking();
- SchedulePaint();
+ CaretVisibilityMaybeChanged();
}
void nsCaret::RemoveForceHide() {
if (!mHideCount || --mHideCount) {
return;
}
- ResetBlinking();
- SchedulePaint();
+ CaretVisibilityMaybeChanged();
}
-void nsCaret::SetCaretReadOnly(bool inMakeReadonly) {
- mReadOnly = inMakeReadonly;
+void nsCaret::SetCaretReadOnly(bool aReadOnly) {
+ mReadOnly = aReadOnly;
ResetBlinking();
SchedulePaint();
}
@@ -333,61 +333,48 @@ nsRect nsCaret::GetGeometryForFrame(nsIFrame* aFrame, int32_t aFrameOffset,
return rect;
}
-nsIFrame* nsCaret::GetFrameAndOffset(const Selection* aSelection,
- nsINode* aOverrideNode,
- int32_t aOverrideOffset,
- int32_t* aFrameOffset,
- nsIFrame** aUnadjustedFrame) {
- if (aUnadjustedFrame) {
- *aUnadjustedFrame = nullptr;
+auto nsCaret::CaretPositionFor(const Selection* aSelection) -> CaretPosition {
+ if (!aSelection) {
+ return {};
}
-
- nsINode* focusNode;
- int32_t focusOffset;
-
- if (aOverrideNode) {
- focusNode = aOverrideNode;
- focusOffset = aOverrideOffset;
- } else if (aSelection) {
- focusNode = aSelection->GetFocusNode();
- focusOffset = aSelection->FocusOffset();
- } else {
- return nullptr;
+ const nsFrameSelection* frameSelection = aSelection->GetFrameSelection();
+ if (!frameSelection) {
+ return {};
}
+ nsINode* node = aSelection->GetFocusNode();
+ if (!node) {
+ return {};
+ }
+ return {
+ node,
+ int32_t(aSelection->FocusOffset()),
+ frameSelection->GetHint(),
+ frameSelection->GetCaretBidiLevel(),
+ };
+}
- if (!focusNode || !focusNode->IsContent() || !aSelection) {
- return nullptr;
+CaretFrameData nsCaret::GetFrameAndOffset(const CaretPosition& aPosition) {
+ nsINode* focusNode = aPosition.mContent;
+ int32_t focusOffset = aPosition.mOffset;
+
+ if (!focusNode || !focusNode->IsContent()) {
+ return {};
}
nsIContent* contentNode = focusNode->AsContent();
- nsFrameSelection* frameSelection = aSelection->GetFrameSelection();
- BidiEmbeddingLevel bidiLevel = frameSelection->GetCaretBidiLevel();
- const CaretFrameData result =
- SelectionMovementUtils::GetCaretFrameForNodeOffset(
- frameSelection, contentNode, focusOffset, frameSelection->GetHint(),
- bidiLevel, ForceEditableRegion::No);
- // FIXME: It's odd to update nsFrameSelection within this method which is
- // named as a getter.
- if (result.mFrame) {
- frameSelection->SetHint(result.mHint);
- }
- if (aUnadjustedFrame) {
- *aUnadjustedFrame = result.mUnadjustedFrame;
- }
- if (aFrameOffset) {
- *aFrameOffset = result.mOffsetInFrameContent;
- }
- return result.mFrame;
+ return SelectionMovementUtils::GetCaretFrameForNodeOffset(
+ nullptr, contentNode, focusOffset, aPosition.mHint, aPosition.mBidiLevel,
+ ForceEditableRegion::No);
}
/* static */
nsIFrame* nsCaret::GetGeometry(const Selection* aSelection, nsRect* aRect) {
- int32_t frameOffset;
- nsIFrame* frame = GetFrameAndOffset(aSelection, nullptr, 0, &frameOffset);
- if (frame) {
- *aRect = GetGeometryForFrame(frame, frameOffset, nullptr);
+ auto data = GetFrameAndOffset(CaretPositionFor(aSelection));
+ if (data.mFrame) {
+ *aRect =
+ GetGeometryForFrame(data.mFrame, data.mOffsetInFrameContent, nullptr);
}
- return frame;
+ return data.mFrame;
}
[[nodiscard]] static nsIFrame* GetContainingBlockIfNeeded(nsIFrame* aFrame) {
@@ -397,39 +384,56 @@ nsIFrame* nsCaret::GetGeometry(const Selection* aSelection, nsRect* aRect) {
return aFrame->GetContainingBlock();
}
-void nsCaret::SchedulePaint(Selection* aSelection) {
- Selection* selection;
- if (aSelection) {
- selection = aSelection;
- } else {
- selection = GetSelection();
+void nsCaret::SchedulePaint() {
+ if (mLastPaintedFrame) {
+ mLastPaintedFrame->SchedulePaint();
+ mLastPaintedFrame = nullptr;
}
-
- int32_t frameOffset;
- nsIFrame* frame = GetFrameAndOffset(selection, mOverrideContent,
- mOverrideOffset, &frameOffset);
- if (!frame) {
+ auto data = GetFrameAndOffset(mCaretPosition);
+ if (!data.mFrame) {
return;
}
-
+ nsIFrame* frame = data.mFrame;
if (nsIFrame* cb = GetContainingBlockIfNeeded(frame)) {
- cb->SchedulePaint();
- } else {
- frame->SchedulePaint();
+ frame = cb;
}
+ frame->SchedulePaint();
}
void nsCaret::SetVisibilityDuringSelection(bool aVisibility) {
+ if (mShowDuringSelection == aVisibility) {
+ return;
+ }
mShowDuringSelection = aVisibility;
+ if (mHiddenDuringSelection && aVisibility) {
+ RemoveForceHide();
+ mHiddenDuringSelection = false;
+ }
SchedulePaint();
}
-void nsCaret::SetCaretPosition(nsINode* aNode, int32_t aOffset) {
- mOverrideContent = aNode;
- mOverrideOffset = aOffset;
+void nsCaret::UpdateCaretPositionFromSelectionIfNeeded() {
+ if (mFixedCaretPosition) {
+ return;
+ }
+ CaretPosition newPos = CaretPositionFor(GetSelection());
+ if (newPos == mCaretPosition) {
+ return;
+ }
+ mCaretPosition = newPos;
+ SchedulePaint();
+}
+void nsCaret::SetCaretPosition(nsINode* aNode, int32_t aOffset) {
+ // Schedule a paint with the old position to invalidate.
+ mFixedCaretPosition = !!aNode;
+ if (mFixedCaretPosition) {
+ mCaretPosition = {aNode, aOffset};
+ SchedulePaint();
+ } else {
+ UpdateCaretPositionFromSelectionIfNeeded();
+ }
ResetBlinking();
- SchedulePaint();
}
void nsCaret::CheckSelectionLanguageChange() {
@@ -478,16 +482,15 @@ nsIFrame* nsCaret::GetPaintGeometry(nsRect* aCaretRect, nsRect* aHookRect,
// taken into account when computing the caret position below.
CheckSelectionLanguageChange();
- int32_t frameOffset;
- nsIFrame* unadjustedFrame = nullptr;
- nsIFrame* frame =
- GetFrameAndOffset(GetSelection(), mOverrideContent, mOverrideOffset,
- &frameOffset, &unadjustedFrame);
- MOZ_ASSERT(!!frame == !!unadjustedFrame);
- if (!frame) {
+ auto data = GetFrameAndOffset(mCaretPosition);
+ MOZ_ASSERT(!!data.mFrame == !!data.mUnadjustedFrame);
+ if (!data.mFrame) {
return nullptr;
}
+ nsIFrame* frame = data.mFrame;
+ nsIFrame* unadjustedFrame = data.mUnadjustedFrame;
+ int32_t frameOffset(data.mOffsetInFrameContent);
// Now we have a frame, check whether it's appropriate to show the caret here.
// Note we need to check the unadjusted frame, otherwise consider the
// following case:
@@ -555,26 +558,35 @@ void nsCaret::PaintCaret(DrawTarget& aDrawTarget, nsIFrame* aForFrame,
NS_IMETHODIMP
nsCaret::NotifySelectionChanged(Document*, Selection* aDomSel, int16_t aReason,
int32_t aAmount) {
- // Note that aDomSel, per the comment below may not be the same as our
- // selection, but that's OK since if that is the case, it wouldn't have
- // mattered what IsVisible() returns here, so we just opt for checking
- // the selection later down below.
- if ((aReason & nsISelectionListener::MOUSEUP_REASON) ||
- !IsVisible(aDomSel)) // this wont do
- return NS_OK;
-
// The same caret is shared amongst the document and any text widgets it
// may contain. This means that the caret could get notifications from
// multiple selections.
//
// If this notification is for a selection that is not the one the
- // the caret is currently interested in (mDomSelectionWeak), then there
- // is nothing to do!
+ // the caret is currently interested in (mDomSelectionWeak), or the caret
+ // position is fixed, then there is nothing to do!
+ if (mDomSelectionWeak != aDomSel) {
+ return NS_OK;
+ }
- if (mDomSelectionWeak != aDomSel) return NS_OK;
+ // Check if we need to hide / un-hide the caret due to the selection being
+ // collapsed.
+ if (!mShowDuringSelection &&
+ !aDomSel->IsCollapsed() != mHiddenDuringSelection) {
+ if (mHiddenDuringSelection) {
+ RemoveForceHide();
+ } else {
+ AddForceHide();
+ }
+ mHiddenDuringSelection = !mHiddenDuringSelection;
+ }
- ResetBlinking();
- SchedulePaint(aDomSel);
+ // We don't bother computing the caret position when invisible. We'll do it if
+ // we become visible in CaretVisibilityMaybeChanged().
+ if (IsVisible()) {
+ UpdateCaretPositionFromSelectionIfNeeded();
+ ResetBlinking();
+ }
return NS_OK;
}
@@ -589,7 +601,7 @@ void nsCaret::ResetBlinking() {
mIsBlinkOn = true;
- if (mReadOnly || !mVisible || mHideCount) {
+ if (mReadOnly || !IsVisible()) {
StopBlinking();
return;
}
@@ -647,49 +659,6 @@ size_t nsCaret::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
return total;
}
-bool nsCaret::IsMenuPopupHidingCaret() {
- // Check if there are open popups.
- nsXULPopupManager* popMgr = nsXULPopupManager::GetInstance();
- nsTArray<nsIFrame*> popups;
- popMgr->GetVisiblePopups(popups);
-
- if (popups.Length() == 0)
- return false; // No popups, so caret can't be hidden by them.
-
- // Get the selection focus content, that's where the caret would
- // go if it was drawn.
- if (!mDomSelectionWeak) {
- return true; // No selection/caret to draw.
- }
- nsCOMPtr<nsIContent> caretContent =
- nsIContent::FromNodeOrNull(mDomSelectionWeak->GetFocusNode());
- if (!caretContent) return true; // No selection/caret to draw.
-
- // If there's a menu popup open before the popup with
- // the caret, don't show the caret.
- for (uint32_t i = 0; i < popups.Length(); i++) {
- nsMenuPopupFrame* popupFrame = static_cast<nsMenuPopupFrame*>(popups[i]);
- nsIContent* popupContent = popupFrame->GetContent();
-
- if (caretContent->IsInclusiveDescendantOf(popupContent)) {
- // The caret is in this popup. There were no menu popups before this
- // popup, so don't hide the caret.
- return false;
- }
-
- if (popupFrame->GetPopupType() == widget::PopupType::Menu &&
- !popupFrame->IsContextMenu()) {
- // This is an open menu popup. It does not contain the caret (else we'd
- // have returned above). Even if the caret is in a subsequent popup,
- // or another document/frame, it should be hidden.
- return true;
- }
- }
-
- // There are no open menu popups, no need to hide the caret.
- return false;
-}
-
void nsCaret::ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
nsRect* aCaretRect, nsRect* aHookRect) {
NS_ASSERTION(aFrame, "Should have a frame here");
diff --git a/layout/base/nsCaret.h b/layout/base/nsCaret.h
index 43329c827f..cba719962c 100644
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -10,10 +10,10 @@
#define nsCaret_h__
#include "mozilla/MemoryReporting.h"
-#include "mozilla/dom/Selection.h"
+#include "mozilla/SelectionMovementUtils.h"
#include "nsCoord.h"
+#include "nsIFrame.h"
#include "nsISelectionListener.h"
-#include "nsIWeakReferenceUtils.h"
#include "nsPoint.h"
#include "nsRect.h"
@@ -46,10 +46,10 @@ class nsCaret final : public nsISelectionListener {
using CaretAssociationHint = mozilla::CaretAssociationHint;
- nsresult Init(mozilla::PresShell* aPresShell);
+ nsresult Init(mozilla::PresShell*);
void Terminate();
- void SetSelection(mozilla::dom::Selection* aDOMSel);
+ void SetSelection(mozilla::dom::Selection*);
mozilla::dom::Selection* GetSelection();
/**
@@ -61,40 +61,18 @@ class nsCaret final : public nsISelectionListener {
* those with user-modify: read-only
*/
void SetIgnoreUserModify(bool aIgnoreUserModify);
- /** SetVisible will set the visibility of the caret
- * @param inMakeVisible true to show the caret, false to hide it
+ /**
+ * SetVisible will set the visibility of the caret
+ * @param aVisible true to show the caret, false to hide it
*/
- void SetVisible(bool intMakeVisible);
- /** IsVisible will get the visibility of the caret.
- * This returns false if the caret is hidden because it was set
- * to not be visible, or because the selection is not collapsed, or
- * because an open popup is hiding the caret.
- * It does not take account of blinking or the caret being hidden
- * because we're in non-editable/disabled content.
+ void SetVisible(bool aVisible);
+ /**
+ * IsVisible will get the visibility of the caret.
+ * It does not take account of blinking or the caret being hidden because
+ * we're in non-editable/disabled content.
*/
- bool IsVisible(mozilla::dom::Selection* aSelection = nullptr) {
- if (!mVisible || mHideCount) {
- return false;
- }
-
- if (!mShowDuringSelection) {
- mozilla::dom::Selection* selection;
- if (aSelection) {
- selection = aSelection;
- } else {
- selection = GetSelection();
- }
- if (!selection || !selection->IsCollapsed()) {
- return false;
- }
- }
-
- if (IsMenuPopupHidingCaret()) {
- return false;
- }
+ bool IsVisible() const;
- return true;
- }
/**
* AddForceHide() increases mHideCount and hide the caret even if
* SetVisible(true) has been or will be called. This is useful when the
@@ -114,7 +92,7 @@ class nsCaret final : public nsISelectionListener {
* @param inMakeReadonly true to show the caret in a 'read only' state,
* false to show the caret in normal, editing state
*/
- void SetCaretReadOnly(bool inMakeReadonly);
+ void SetCaretReadOnly(bool aReadOnly);
/**
* @param aVisibility true if the caret should be visible even when the
* selection is not collapsed.
@@ -132,7 +110,10 @@ class nsCaret final : public nsISelectionListener {
* Schedule a repaint for the frame where the caret would appear.
* Does not check visibility etc.
*/
- void SchedulePaint(mozilla::dom::Selection* aSelection = nullptr);
+ void SchedulePaint();
+
+ nsIFrame* GetLastPaintedFrame() { return mLastPaintedFrame; }
+ void SetLastPaintedFrame(nsIFrame* aFrame) { mLastPaintedFrame = aFrame; }
/**
* Returns a frame to paint in, and the bounds of the painted caret
@@ -142,6 +123,7 @@ class nsCaret final : public nsISelectionListener {
* off).
*/
nsIFrame* GetPaintGeometry(nsRect* aRect);
+
/**
* Same as the overload above, but returns the caret and hook rects
* separately, and also computes the color if requested.
@@ -165,6 +147,22 @@ class nsCaret final : public nsISelectionListener {
// nsISelectionListener interface
NS_DECL_NSISELECTIONLISTENER
+ /** The current caret position. */
+ struct CaretPosition {
+ nsCOMPtr<nsINode> mContent;
+ int32_t mOffset = 0;
+ CaretAssociationHint mHint{0};
+ mozilla::intl::BidiEmbeddingLevel mBidiLevel;
+
+ bool operator==(const CaretPosition& aOther) const {
+ return mContent == aOther.mContent && mOffset == aOther.mOffset &&
+ mHint == aOther.mHint && mBidiLevel == aOther.mBidiLevel;
+ }
+ explicit operator bool() const { return !!mContent; }
+ };
+
+ static CaretPosition CaretPositionFor(const mozilla::dom::Selection*);
+
/**
* Gets the position and size of the caret that would be drawn for
* the focus node/offset of aSelection (assuming it would be drawn,
@@ -181,18 +179,9 @@ class nsCaret final : public nsISelectionListener {
static nsRect GetGeometryForFrame(nsIFrame* aFrame, int32_t aFrameOffset,
nscoord* aBidiIndicatorSize);
- // Get the frame and frame offset based on the focus node and focus offset
- // of aSelection. If aOverrideNode and aOverride are provided, use them
- // instead.
- // @param aFrameOffset return the frame offset if non-null.
- // @param aUnadjustedFrame return the original frame that the selection is
- // targeting, without any adjustment for painting.
- // @return the frame of the focus node.
- static nsIFrame* GetFrameAndOffset(const mozilla::dom::Selection* aSelection,
- nsINode* aOverrideNode,
- int32_t aOverrideOffset,
- int32_t* aFrameOffset,
- nsIFrame** aUnadjustedFrame = nullptr);
+ // Get the frame and frame offset based on aPosition.
+ static mozilla::CaretFrameData GetFrameAndOffset(
+ const CaretPosition& aPosition);
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
@@ -200,6 +189,7 @@ class nsCaret final : public nsISelectionListener {
static void CaretBlinkCallback(nsITimer* aTimer, void* aClosure);
void CheckSelectionLanguageChange();
+ void CaretVisibilityMaybeChanged();
void ResetBlinking();
void StopBlinking();
@@ -213,72 +203,73 @@ class nsCaret final : public nsISelectionListener {
void ComputeCaretRects(nsIFrame* aFrame, int32_t aFrameOffset,
nsRect* aCaretRect, nsRect* aHookRect);
- // Returns true if we should not draw the caret because of XUL menu popups.
- // The caret should be hidden if:
- // 1. An open popup contains the caret, but a menu popup exists before the
- // caret-owning popup in the popup list (i.e. a menu is in front of the
- // popup with the caret). If the menu itself contains the caret we don't
- // hide it.
- // 2. A menu popup is open, but there is no caret present in any popup.
- // 3. The caret selection is empty.
- bool IsMenuPopupHidingCaret();
+ // If we're tracking the selection, this updates the caret position and
+ // invalidates paint as needed.
+ void UpdateCaretPositionFromSelectionIfNeeded();
nsWeakPtr mPresShell;
mozilla::WeakPtr<mozilla::dom::Selection> mDomSelectionWeak;
nsCOMPtr<nsITimer> mBlinkTimer;
- /**
- * The content to draw the caret at. If null, we use mDomSelectionWeak's
- * focus node instead.
- */
- nsCOMPtr<nsINode> mOverrideContent;
- /**
- * The character offset to draw the caret at.
- * Ignored if mOverrideContent is null.
- */
- int32_t mOverrideOffset;
+ CaretPosition mCaretPosition;
+
+ // The last frame we painted the caret in.
+ WeakFrame mLastPaintedFrame;
+
/**
* mBlinkCount is used to control the number of times to blink the caret
* before stopping the blink. This is reset each time we reset the
* blinking.
*/
- int32_t mBlinkCount;
+ int32_t mBlinkCount = -1;
/**
* mBlinkRate is the rate of the caret blinking the last time we read it.
* It is used as a way to optimize whether we need to reset the blinking
* timer. 0 or a negative value means no blinking.
*/
- int32_t mBlinkRate;
+ int32_t mBlinkRate = 0;
/**
* mHideCount is not 0, it means that somebody doesn't want the caret
* to be visible. See AddForceHide() and RemoveForceHide().
*/
- uint32_t mHideCount;
+ uint32_t mHideCount = 0;
/**
* mIsBlinkOn is true when we're in a blink cycle where the caret is on.
*/
- bool mIsBlinkOn;
+ bool mIsBlinkOn = false;
/**
* mIsVisible is true when SetVisible was last called with 'true'.
*/
- bool mVisible;
+ bool mVisible = false;
/**
* mReadOnly is true when the caret is set to "read only" mode (i.e.,
* it doesn't blink).
*/
- bool mReadOnly;
+ bool mReadOnly = false;
/**
* mShowDuringSelection is true when the caret should be shown even when
* the selection is not collapsed.
*/
- bool mShowDuringSelection;
+ bool mShowDuringSelection = false;
/**
* mIgnoreUserModify is true when the caret should be shown even when
* it's in non-user-modifiable content.
*/
- bool mIgnoreUserModify;
+ bool mIgnoreUserModify = true;
+
+ /**
+ * If the caret position is fixed, it's been overridden externally and it
+ * will not track the selection.
+ */
+ bool mFixedCaretPosition = false;
+
+ /**
+ * If we're currently hiding the caret due to the selection not being
+ * collapsed. Can only be true if mShowDuringSelection is false.
+ */
+ bool mHiddenDuringSelection = false;
};
#endif // nsCaret_h__
diff --git a/layout/base/nsCounterManager.cpp b/layout/base/nsCounterManager.cpp
index 7c2e9bb776..f2bbb5e50e 100644
--- a/layout/base/nsCounterManager.cpp
+++ b/layout/base/nsCounterManager.cpp
@@ -203,7 +203,11 @@ void nsCounterList::SetScope(nsCounterNode* aNode) {
// the element itself, then we use that scope.
// Otherwise, fall through to consider scopes created by siblings (and
// their descendants) in reverse document order.
- if (aNode->mType != nsCounterNode::USE &&
+ // Do this only for the list-item counter, while the CSSWG discusses what the
+ // right thing to do here is, see bug 1548753 and
+ // https://github.com/w3c/csswg-drafts/issues/5477.
+ if (mCounterName == nsGkAtoms::list_item &&
+ aNode->mType != nsCounterNode::USE &&
StaticPrefs::layout_css_counter_ancestor_scope_enabled()) {
for (auto* p = aNode->mPseudoFrame; p; p = p->GetParent()) {
// This relies on the fact that a RESET node is always the first
diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp
index d1cf9bf237..bbd43a830e 100644
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -449,6 +449,7 @@ class nsDocumentViewer final : public nsIDocumentViewer,
#ifdef NS_PRINTING
unsigned mClosingWhilePrinting : 1;
+ unsigned mCloseWindowAfterPrint : 1;
# if NS_PRINT_PREVIEW
RefPtr<nsPrintJob> mPrintJob;
@@ -520,6 +521,7 @@ nsDocumentViewer::nsDocumentViewer()
mInPermitUnloadPrompt(false),
#ifdef NS_PRINTING
mClosingWhilePrinting(false),
+ mCloseWindowAfterPrint(false),
#endif // NS_PRINTING
mReloadEncodingSource(kCharsetUninitialized),
mReloadEncoding(nullptr),
@@ -2424,7 +2426,7 @@ NS_IMETHODIMP nsDocumentViewer::CopyLinkLocation() {
NS_ENSURE_SUCCESS(rv, rv);
// copy the href onto the clipboard
- return clipboard->CopyString(locationText);
+ return clipboard->CopyString(locationText, mDocument->GetWindowContext());
}
NS_IMETHODIMP nsDocumentViewer::CopyImage(int32_t aCopyFlags) {
@@ -2434,7 +2436,8 @@ NS_IMETHODIMP nsDocumentViewer::CopyImage(int32_t aCopyFlags) {
NS_ENSURE_TRUE(node, NS_ERROR_FAILURE);
nsCOMPtr<nsILoadContext> loadContext(mContainer);
- return nsCopySupport::ImageCopy(node, loadContext, aCopyFlags);
+ return nsCopySupport::ImageCopy(node, loadContext, aCopyFlags,
+ mDocument->GetWindowContext());
}
NS_IMETHODIMP nsDocumentViewer::GetCopyable(bool* aCopyable) {
@@ -3140,6 +3143,20 @@ nsDocumentViewer::GetDoingPrintPreview(bool* aDoingPrintPreview) {
}
NS_IMETHODIMP
+nsDocumentViewer::GetCloseWindowAfterPrint(bool* aCloseWindowAfterPrint) {
+ NS_ENSURE_ARG_POINTER(aCloseWindowAfterPrint);
+
+ *aCloseWindowAfterPrint = mCloseWindowAfterPrint;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDocumentViewer::SetCloseWindowAfterPrint(bool aCloseWindowAfterPrint) {
+ mCloseWindowAfterPrint = aCloseWindowAfterPrint;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
nsDocumentViewer::ExitPrintPreview() {
NS_ENSURE_TRUE(mPrintJob, NS_ERROR_FAILURE);
@@ -3301,15 +3318,23 @@ void nsDocumentViewer::OnDonePrinting() {
printJob->Destroy();
}
- // We are done printing, now clean up.
- //
- // For non-print-preview jobs, we are actually responsible for cleaning up
- // our whole <browser> or window (see the OPEN_PRINT_BROWSER code), so gotta
- // run window.close(), which will take care of this.
- //
- // For print preview jobs the front-end code is responsible for cleaning the
- // UI.
- if (!printJob->CreatedForPrintPreview()) {
+// We are done printing, now clean up.
+//
+// If the original document to print was not a static clone, we opened a new
+// window and are responsible for cleaning up the whole <browser> or window
+// (see the OPEN_PRINT_BROWSER code, specifically
+// handleStaticCloneCreatedForPrint()), so gotta run window.close(), which
+// will take care of this.
+//
+// Otherwise the front-end code is responsible for cleaning the UI.
+# ifdef ANDROID
+ // Android doesn't support Content Analysis and prints in a different way,
+ // so use different logic to clean up.
+ bool closeWindowAfterPrint = !printJob->CreatedForPrintPreview();
+# else
+ bool closeWindowAfterPrint = GetCloseWindowAfterPrint();
+# endif
+ if (closeWindowAfterPrint) {
if (mContainer) {
if (nsCOMPtr<nsPIDOMWindowOuter> win = mContainer->GetWindow()) {
win->Close();
diff --git a/layout/base/nsGenConList.cpp b/layout/base/nsGenConList.cpp
index b770ee539a..175e6fe7d5 100644
--- a/layout/base/nsGenConList.cpp
+++ b/layout/base/nsGenConList.cpp
@@ -12,12 +12,13 @@
#include "nsIFrame.h"
void nsGenConNode::CheckFrameAssertions() {
- NS_ASSERTION(
- mContentIndex < int32_t(mPseudoFrame->StyleContent()->ContentCount()) ||
- // Special-case for the USE node created for the legacy markers,
- // which don't use the content property.
- mContentIndex == 0,
- "index out of range");
+ NS_ASSERTION(mContentIndex < int32_t(mPseudoFrame->StyleContent()
+ ->NonAltContentItems()
+ .Length()) ||
+ // Special-case for the USE node created for the legacy
+ // markers, which don't use the content property.
+ mContentIndex == 0,
+ "index out of range");
// We allow negative values of mContentIndex for 'counter-reset' and
// 'counter-increment'.
diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp
index db766f6603..3f84a97250 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -714,12 +714,9 @@ bool nsLayoutUtils::AllowZoomingForDocument(
return false;
}
// True if we allow zooming for all documents on this platform, or if we are
- // in RDM and handling meta viewports, which force zoom under some
- // circumstances.
- BrowsingContext* bc = aDocument ? aDocument->GetBrowsingContext() : nullptr;
- return StaticPrefs::apz_allow_zooming() ||
- (bc && bc->InRDMPane() &&
- nsLayoutUtils::ShouldHandleMetaViewport(aDocument));
+ // in RDM.
+ BrowsingContext* bc = aDocument->GetBrowsingContext();
+ return StaticPrefs::apz_allow_zooming() || (bc && bc->InRDMPane());
}
static bool HasVisibleAnonymousContents(Document* aDoc) {
@@ -903,7 +900,7 @@ void nsLayoutUtils::GetMarkerSpokenText(const nsIContent* aContent,
return;
}
- if (frame->StyleContent()->ContentCount() > 0) {
+ if (!frame->StyleContent()->NonAltContentItems().IsEmpty()) {
for (nsIFrame* child : frame->PrincipalChildList()) {
nsIFrame::RenderedText text = child->GetRenderedText();
aText += text.mString;
@@ -2134,6 +2131,7 @@ const nsIFrame* nsLayoutUtils::FindNearestCommonAncestorFrameWithinBlock(
bool nsLayoutUtils::AuthorSpecifiedBorderBackgroundDisablesTheming(
StyleAppearance aAppearance) {
return aAppearance == StyleAppearance::NumberInput ||
+ aAppearance == StyleAppearance::PasswordInput ||
aAppearance == StyleAppearance::Button ||
aAppearance == StyleAppearance::Textfield ||
aAppearance == StyleAppearance::Textarea ||
@@ -3501,7 +3499,7 @@ nsIFrame* nsLayoutUtils::GetFirstNonAnonymousFrame(nsIFrame* aFrame) {
struct BoxToRect : public nsLayoutUtils::BoxCallback {
const nsIFrame* mRelativeTo;
RectCallback* mCallback;
- uint32_t mFlags;
+ nsLayoutUtils::GetAllInFlowRectsFlags mFlags;
// If the frame we're measuring relative to is the root, we know all frames
// are descendants of it, so we don't need to compute the common ancestor
// between a frame and mRelativeTo.
@@ -3513,7 +3511,8 @@ struct BoxToRect : public nsLayoutUtils::BoxCallback {
bool mRelativeToIsTarget;
BoxToRect(const nsIFrame* aTargetFrame, const nsIFrame* aRelativeTo,
- RectCallback* aCallback, uint32_t aFlags)
+ RectCallback* aCallback,
+ nsLayoutUtils::GetAllInFlowRectsFlags aFlags)
: mRelativeTo(aRelativeTo),
mCallback(aCallback),
mFlags(aFlags),
@@ -3526,21 +3525,34 @@ struct BoxToRect : public nsLayoutUtils::BoxCallback {
const bool usingSVGOuterFrame = !!outer;
if (!outer) {
outer = aFrame;
- switch (mFlags & nsLayoutUtils::RECTS_WHICH_BOX_MASK) {
- case nsLayoutUtils::RECTS_USE_CONTENT_BOX:
- r = aFrame->GetContentRectRelativeToSelf();
- break;
- case nsLayoutUtils::RECTS_USE_PADDING_BOX:
- r = aFrame->GetPaddingRectRelativeToSelf();
- break;
- case nsLayoutUtils::RECTS_USE_MARGIN_BOX:
- r = aFrame->GetMarginRectRelativeToSelf();
- break;
- default: // Use the border box
- r = aFrame->GetRectRelativeToSelf();
+ if (mFlags.contains(
+ nsLayoutUtils::GetAllInFlowRectsFlag::UseContentBox)) {
+ r = aFrame->GetContentRectRelativeToSelf();
+ } else if (mFlags.contains(
+ nsLayoutUtils::GetAllInFlowRectsFlag::UsePaddingBox)) {
+ r = aFrame->GetPaddingRectRelativeToSelf();
+ } else if (mFlags.contains(
+ nsLayoutUtils::GetAllInFlowRectsFlag::UseMarginBox)) {
+ r = aFrame->GetMarginRectRelativeToSelf();
+ } else if (mFlags.contains(nsLayoutUtils::GetAllInFlowRectsFlag::
+ UseMarginBoxWithAutoResolvedAsZero)) {
+ r = aFrame->GetRectRelativeToSelf();
+ const auto& styleMargin = aFrame->StyleMargin()->mMargin;
+ nsMargin usedMargin =
+ aFrame->GetUsedMargin().ApplySkipSides(aFrame->GetSkipSides());
+ for (const Side side : AllPhysicalSides()) {
+ if (styleMargin.Get(side).IsAuto()) {
+ usedMargin.Side(side) = 0;
+ }
+ }
+ r.Inflate(usedMargin);
+ } else {
+ // Use the border-box.
+ r = aFrame->GetRectRelativeToSelf();
}
}
- if (mFlags & nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS) {
+ if (mFlags.contains(
+ nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms)) {
const bool isAncestorKnown = [&] {
if (mRelativeToIsRoot) {
return true;
@@ -3571,7 +3583,7 @@ struct MOZ_RAII BoxToRectAndText : public BoxToRect {
BoxToRectAndText(const nsIFrame* aTargetFrame, const nsIFrame* aRelativeTo,
RectCallback* aCallback, Sequence<nsString>* aTextList,
- uint32_t aFlags)
+ nsLayoutUtils::GetAllInFlowRectsFlags aFlags)
: BoxToRect(aTargetFrame, aRelativeTo, aCallback, aFlags),
mTextList(aTextList) {}
@@ -3612,7 +3624,7 @@ struct MOZ_RAII BoxToRectAndText : public BoxToRect {
void nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame,
const nsIFrame* aRelativeTo,
RectCallback* aCallback,
- uint32_t aFlags) {
+ GetAllInFlowRectsFlags aFlags) {
BoxToRect converter(aFrame, aRelativeTo, aCallback, aFlags);
GetAllInFlowBoxes(aFrame, &converter);
}
@@ -3621,7 +3633,7 @@ void nsLayoutUtils::GetAllInFlowRectsAndTexts(nsIFrame* aFrame,
const nsIFrame* aRelativeTo,
RectCallback* aCallback,
Sequence<nsString>* aTextList,
- uint32_t aFlags) {
+ GetAllInFlowRectsFlags aFlags) {
BoxToRectAndText converter(aFrame, aRelativeTo, aCallback, aTextList, aFlags);
GetAllInFlowBoxes(aFrame, &converter);
}
@@ -3652,7 +3664,7 @@ nsIFrame* nsLayoutUtils::GetContainingBlockForClientRect(nsIFrame* aFrame) {
nsRect nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame,
const nsIFrame* aRelativeTo,
- uint32_t aFlags) {
+ GetAllInFlowRectsFlags aFlags) {
RectAccumulator accumulator;
GetAllInFlowRects(aFrame, aRelativeTo, &accumulator, aFlags);
return accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect
@@ -4613,7 +4625,7 @@ static nscoord AddIntrinsicSizeOffset(
LayoutDeviceIntSize devSize = pc->Theme()->GetMinimumWidgetSize(
pc, aFrame, disp->EffectiveAppearance());
nscoord themeSize = pc->DevPixelsToAppUnits(
- aAxis == eAxisVertical ? devSize.height : devSize.width);
+ aAxis == PhysicalAxis::Vertical ? devSize.height : devSize.width);
// GetMinimumWidgetSize() returns a border-box width.
themeSize += aOffsets.margin;
if (themeSize > result) {
@@ -4644,7 +4656,7 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
aPercentageBasis.isSome(),
"grid layout should always pass a percentage basis");
- const bool horizontalAxis = MOZ_LIKELY(aAxis == eAxisHorizontal);
+ const bool horizontalAxis = MOZ_LIKELY(aAxis == PhysicalAxis::Horizontal);
#ifdef DEBUG_INTRINSIC_WIDTH
nsIFrame::IndentBy(stderr, gNoiseIndent);
aFrame->ListTag(stderr);
@@ -4676,7 +4688,7 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
horizontalAxis ? stylePos->mMaxWidth : stylePos->mMaxHeight;
PhysicalAxis ourInlineAxis =
- aFrame->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
+ aFrame->GetWritingMode().PhysicalAxis(LogicalAxis::Inline);
const bool isInlineAxis = aAxis == ourInlineAxis;
auto resetIfKeywords = [](StyleSize& aSize, StyleSize& aMinSize,
@@ -4897,8 +4909,8 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
// We are computing the size of |aFrame|, so we use the inline & block
// dimensions of |aFrame|.
result = ratio.ComputeRatioDependentSize(
- isInlineAxis ? eLogicalAxisInline : eLogicalAxisBlock, childWM, h,
- *contentBoxSizeToBoxSizingAdjust);
+ isInlineAxis ? LogicalAxis::Inline : LogicalAxis::Block, childWM,
+ h, *contentBoxSizeToBoxSizingAdjust);
// We have get the inlineSizeForAspectRatio value, so we don't have to
// recompute this again below.
inlineSizeFromAspectRatio.emplace(result);
@@ -4910,8 +4922,8 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
GetPercentBSize(styleMaxBSize, aFrame, horizontalAxis, h))) {
h = std::max(0, h - bSizeTakenByBoxSizing);
nscoord maxISize = ratio.ComputeRatioDependentSize(
- isInlineAxis ? eLogicalAxisInline : eLogicalAxisBlock, childWM, h,
- *contentBoxSizeToBoxSizingAdjust);
+ isInlineAxis ? LogicalAxis::Inline : LogicalAxis::Block, childWM,
+ h, *contentBoxSizeToBoxSizingAdjust);
if (maxISize < result) {
result = maxISize;
}
@@ -4926,8 +4938,8 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
GetPercentBSize(styleMinBSize, aFrame, horizontalAxis, h))) {
h = std::max(0, h - bSizeTakenByBoxSizing);
nscoord minISize = ratio.ComputeRatioDependentSize(
- isInlineAxis ? eLogicalAxisInline : eLogicalAxisBlock, childWM, h,
- *contentBoxSizeToBoxSizingAdjust);
+ isInlineAxis ? LogicalAxis::Inline : LogicalAxis::Block, childWM,
+ h, *contentBoxSizeToBoxSizingAdjust);
if (minISize > result) {
result = minISize;
}
@@ -4990,9 +5002,9 @@ nscoord nsLayoutUtils::IntrinsicForAxis(
GetDefiniteSizeTakenByBoxSizing(boxSizingForAR, aFrame, !isInlineAxis,
ignorePadding, aPercentageBasis);
bSize -= bSizeTakenByBoxSizing;
- inlineSizeFromAspectRatio.emplace(ar.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, childWM, bSize,
- *contentBoxSizeToBoxSizingAdjust));
+ inlineSizeFromAspectRatio.emplace(
+ ar.ComputeRatioDependentSize(LogicalAxis::Inline, childWM, bSize,
+ *contentBoxSizeToBoxSizingAdjust));
}
}
@@ -5027,7 +5039,7 @@ nscoord nsLayoutUtils::IntrinsicForContainer(gfxContext* aRenderingContext,
MOZ_ASSERT(aFrame && aFrame->GetParent());
// We want the size aFrame will contribute to its parent's inline-size.
PhysicalAxis axis =
- aFrame->GetParent()->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
+ aFrame->GetParent()->GetWritingMode().PhysicalAxis(LogicalAxis::Inline);
return IntrinsicForAxis(axis, aRenderingContext, aFrame, aType, Nothing(),
aFlags);
}
@@ -5051,12 +5063,13 @@ nscoord nsLayoutUtils::MinSizeContributionForAxis(
// Note: this method is only meant for grid/flex items.
const nsStylePosition* const stylePos = aFrame->StylePosition();
- StyleSize size =
- aAxis == eAxisHorizontal ? stylePos->mMinWidth : stylePos->mMinHeight;
- StyleMaxSize maxSize =
- aAxis == eAxisHorizontal ? stylePos->mMaxWidth : stylePos->mMaxHeight;
+ StyleSize size = aAxis == PhysicalAxis::Horizontal ? stylePos->mMinWidth
+ : stylePos->mMinHeight;
+ StyleMaxSize maxSize = aAxis == PhysicalAxis::Horizontal
+ ? stylePos->mMaxWidth
+ : stylePos->mMaxHeight;
auto childWM = aFrame->GetWritingMode();
- PhysicalAxis ourInlineAxis = childWM.PhysicalAxis(eLogicalAxisInline);
+ PhysicalAxis ourInlineAxis = childWM.PhysicalAxis(LogicalAxis::Inline);
// According to the spec, max-content and min-content should behave as the
// property's initial values in block axis.
// It also make senses to use the initial values for -moz-fit-content and
@@ -5080,7 +5093,8 @@ nscoord nsLayoutUtils::MinSizeContributionForAxis(
minSize = 0;
fixedMinSize = &minSize;
} else {
- size = aAxis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight;
+ size = aAxis == PhysicalAxis::Horizontal ? stylePos->mWidth
+ : stylePos->mHeight;
// This is same as above: keywords should behaves as property's initial
// values in block axis.
if (aAxis != ourInlineAxis && size.BehavesLikeInitialValueOnBlockAxis()) {
@@ -5323,7 +5337,6 @@ nscoord nsLayoutUtils::MinISizeFromInline(nsIFrame* aFrame,
"should not be container for font size inflation");
nsIFrame::InlineMinISizeData data;
- DISPLAY_MIN_INLINE_SIZE(aFrame, data.mPrevLines);
aFrame->AddInlineMinISize(aRenderingContext, &data);
data.ForceBreak();
return data.mPrevLines;
@@ -5336,7 +5349,6 @@ nscoord nsLayoutUtils::PrefISizeFromInline(nsIFrame* aFrame,
"should not be container for font size inflation");
nsIFrame::InlinePrefISizeData data;
- DISPLAY_PREF_INLINE_SIZE(aFrame, data.mPrevLines);
aFrame->AddInlinePrefISize(aRenderingContext, &data);
data.ForceBreak();
return data.mPrevLines;
@@ -7449,7 +7461,7 @@ SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
HTMLVideoElement* aElement, uint32_t aSurfaceFlags,
- RefPtr<DrawTarget>& aTarget) {
+ RefPtr<DrawTarget>& aTarget, bool aOptimizeSourceSurface) {
SurfaceFromElementResult result;
result.mAlphaType = gfxAlphaType::Opaque; // Assume opaque.
@@ -7484,7 +7496,7 @@ SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(
result.mIsWriteOnly = CanvasUtils::CheckWriteOnlySecurity(
result.mCORSUsed, result.mPrincipal, result.mHadCrossOriginRedirects);
- if (aTarget) {
+ if (aTarget && aOptimizeSourceSurface) {
// They gave us a DrawTarget to optimize for, so even though we have a
// layers::Image, we should unconditionally try to grab a SourceSurface and
// try to optimize it.
@@ -8901,13 +8913,7 @@ ScrollMetadata nsLayoutUtils::ComputeScrollMetadata(
}
if (primaryFrame) {
WritingMode writingModeOfRootScrollFrame = primaryFrame->GetWritingMode();
- WritingMode::BlockDir blockDirOfRootScrollFrame =
- writingModeOfRootScrollFrame.GetBlockDir();
- WritingMode::InlineDir inlineDirOfRootScrollFrame =
- writingModeOfRootScrollFrame.GetInlineDir();
- if (blockDirOfRootScrollFrame == WritingMode::BlockDir::eBlockRL ||
- (blockDirOfRootScrollFrame == WritingMode::BlockDir::eBlockTB &&
- inlineDirOfRootScrollFrame == WritingMode::InlineDir::eInlineRTL)) {
+ if (writingModeOfRootScrollFrame.IsPhysicalRTL()) {
metadata.SetIsAutoDirRootContentRTL(true);
}
}
@@ -9228,7 +9234,8 @@ CSSRect nsLayoutUtils::GetBoundingFrameRect(
CSSRect result;
nsIFrame* relativeTo = aRootScrollFrame->GetScrolledFrame();
result = CSSRect::FromAppUnits(nsLayoutUtils::GetAllInFlowRectsUnion(
- aFrame, relativeTo, nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS));
+ aFrame, relativeTo,
+ nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms));
// If the element is contained in a scrollable frame that is not
// the root scroll frame, make sure to clip the result so that it is
@@ -9769,24 +9776,8 @@ void nsLayoutUtils::ComputeSystemFont(nsFont* aSystemFont,
/* static */
bool nsLayoutUtils::ShouldHandleMetaViewport(const Document* aDocument) {
- auto metaViewportOverride = nsIDocShell::META_VIEWPORT_OVERRIDE_NONE;
- if (aDocument) {
- if (nsIDocShell* docShell = aDocument->GetDocShell()) {
- metaViewportOverride = docShell->GetMetaViewportOverride();
- }
- }
- switch (metaViewportOverride) {
- case nsIDocShell::META_VIEWPORT_OVERRIDE_ENABLED:
- return true;
- case nsIDocShell::META_VIEWPORT_OVERRIDE_DISABLED:
- return false;
- default:
- MOZ_ASSERT(metaViewportOverride ==
- nsIDocShell::META_VIEWPORT_OVERRIDE_NONE);
- // The META_VIEWPORT_OVERRIDE_NONE case means that there is no override
- // and we rely solely on the StaticPrefs.
- return StaticPrefs::dom_meta_viewport_enabled();
- }
+ BrowsingContext* bc = aDocument->GetBrowsingContext();
+ return StaticPrefs::dom_meta_viewport_enabled() || (bc && bc->InRDMPane());
}
/* static */
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
index 697b139ed9..6b6e45b3e4 100644
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1241,52 +1241,57 @@ class nsLayoutUtils {
static nsIFrame* GetContainingBlockForClientRect(nsIFrame* aFrame);
- enum {
- RECTS_ACCOUNT_FOR_TRANSFORMS = 0x01,
- // Two bits for specifying which box type to use.
- // With neither bit set (default), use the border box.
- RECTS_USE_CONTENT_BOX = 0x02,
- RECTS_USE_PADDING_BOX = 0x04,
- RECTS_USE_MARGIN_BOX = 0x06, // both bits set
- RECTS_WHICH_BOX_MASK = 0x06 // bitmask for these two bits
- };
/**
* Collect all CSS boxes (content, padding, border, or margin) associated
* with aFrame and its continuations, "drilling down" through table wrapper
* frames and some anonymous blocks since they're not real CSS boxes.
+ *
* The boxes are positioned relative to aRelativeTo (taking scrolling
* into account) and passed to the callback in frame-tree order.
* If aFrame is null, no boxes are returned.
+ *
* For SVG frames, returns one rectangle, the bounding box.
- * If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting
- * the boxes into aRelativeTo coordinates, transforms (including CSS
- * and SVG transforms) are taken into account.
- * If aFlags includes one of RECTS_USE_CONTENT_BOX, RECTS_USE_PADDING_BOX,
- * or RECTS_USE_MARGIN_BOX, the corresponding type of box is used.
- * Otherwise (by default), the border box is used.
- */
+ *
+ * If aFlags includes 'AccountForTransforms', then when converting the boxes
+ * into aRelativeTo coordinates, transforms (including CSS and SVG transforms)
+ * are taken into account.
+ *
+ * If aFlags includes one of 'UseContentBox', 'UsePaddingBox', 'UseMarginBox',
+ * or 'UseMarginBoxWithAutoResolvedAsZero', the corresponding type of box is
+ * used. Otherwise (by default), the border box is used. Note that these "Box"
+ * flags are meant to be mutually exclusive, though we don't enforce that. If
+ * multiple "Box" flags are used, we'll gracefully just use the first one in
+ * the order of the enum.
+ */
+ enum class GetAllInFlowRectsFlag : uint8_t {
+ AccountForTransforms,
+ UseContentBox,
+ UsePaddingBox,
+ UseMarginBox,
+ // Similar to UseMarginBox, but the 'auto' margins are resolved as zero.
+ UseMarginBoxWithAutoResolvedAsZero,
+ };
+ using GetAllInFlowRectsFlags = mozilla::EnumSet<GetAllInFlowRectsFlag>;
static void GetAllInFlowRects(nsIFrame* aFrame, const nsIFrame* aRelativeTo,
mozilla::RectCallback* aCallback,
- uint32_t aFlags = 0);
+ GetAllInFlowRectsFlags aFlags = {});
static void GetAllInFlowRectsAndTexts(
nsIFrame* aFrame, const nsIFrame* aRelativeTo,
mozilla::RectCallback* aCallback,
- mozilla::dom::Sequence<nsString>* aTextList, uint32_t aFlags = 0);
+ mozilla::dom::Sequence<nsString>* aTextList,
+ GetAllInFlowRectsFlags aFlags = {});
/**
* Computes the union of all rects returned by GetAllInFlowRects. If
* the union is empty, returns the first rect.
- * If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting
- * the boxes into aRelativeTo coordinates, transforms (including CSS
- * and SVG transforms) are taken into account.
- * If aFlags includes one of RECTS_USE_CONTENT_BOX, RECTS_USE_PADDING_BOX,
- * or RECTS_USE_MARGIN_BOX, the corresponding type of box is used.
- * Otherwise (by default), the border box is used.
+ *
+ * See GetAllInFlowRects() documentation for the meaning of aRelativeTo and
+ * aFlags.
*/
static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame,
const nsIFrame* aRelativeTo,
- uint32_t aFlags = 0);
+ GetAllInFlowRectsFlags aFlags = {});
enum { EXCLUDE_BLUR_SHADOWS = 0x01 };
/**
@@ -2230,7 +2235,7 @@ class nsLayoutUtils {
}
static mozilla::SurfaceFromElementResult SurfaceFromElement(
mozilla::dom::HTMLVideoElement* aElement, uint32_t aSurfaceFlags,
- RefPtr<DrawTarget>& aTarget);
+ RefPtr<DrawTarget>& aTarget, bool aOptimizeSourceSurface = true);
/**
* When the document is editable by contenteditable attribute of its root
diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp
index 7d9515c495..0786ec25d9 100644
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -336,6 +336,7 @@ static const char* gExactCallbackPrefs[] = {
"intl.accept_languages",
"layout.css.devPixelsPerPx",
"layout.css.dpi",
+ "layout.css.letter-spacing.model",
"layout.css.text-transform.uppercase-eszett.enabled",
"privacy.trackingprotection.enabled",
"ui.use_standins_for_native_colors",
@@ -608,7 +609,8 @@ void nsPresContext::PreferenceChanged(const char* aPrefName) {
}
if (prefName.EqualsLiteral(
- "layout.css.text-transform.uppercase-eszett.enabled")) {
+ "layout.css.text-transform.uppercase-eszett.enabled") ||
+ prefName.EqualsLiteral("layout.css.letter-spacing.model")) {
changeHint |= NS_STYLE_HINT_REFLOW;
}
@@ -1410,6 +1412,11 @@ void nsPresContext::SetInRDMPane(bool aInRDMPane) {
}
mInRDMPane = aInRDMPane;
RecomputeTheme();
+ if (mPresShell) {
+ nsContentUtils::AddScriptRunner(NewRunnableMethod<bool>(
+ "PresShell::MaybeRecreateMobileViewportManager", mPresShell,
+ &PresShell::MaybeRecreateMobileViewportManager, true));
+ }
}
float nsPresContext::GetDeviceFullZoom() {
diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp
index a5c2b1ded9..218d158a47 100644
--- a/layout/base/nsRefreshDriver.cpp
+++ b/layout/base/nsRefreshDriver.cpp
@@ -831,11 +831,11 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
const TimeDuration previousRate = mVsyncRate;
const TimeDuration rate = GetTimerRate();
- hal::PerformanceHintSession* const performanceHintSession =
- GetPerformanceHintSession();
- if (performanceHintSession && rate != previousRate) {
- performanceHintSession->UpdateTargetWorkDuration(
- ContentChild::GetPerformanceHintTarget(rate));
+ if (rate != previousRate) {
+ if (auto* const performanceHintSession = GetPerformanceHintSession()) {
+ performanceHintSession->UpdateTargetWorkDuration(
+ ContentChild::GetPerformanceHintTarget(rate));
+ }
}
if (TimeDuration::FromMilliseconds(nsRefreshDriver::DefaultInterval()) >
@@ -862,7 +862,7 @@ class VsyncRefreshDriverTimer : public RefreshDriverTimer {
TimeStamp tickEnd = TimeStamp::Now();
- if (performanceHintSession) {
+ if (auto* const performanceHintSession = GetPerformanceHintSession()) {
performanceHintSession->ReportActualWorkDuration(tickEnd - tickStart);
}
@@ -1528,6 +1528,16 @@ void nsRefreshDriver::PostScrollEvent(mozilla::Runnable* aScrollEvent,
}
}
+void nsRefreshDriver::PostScrollEndEvent(mozilla::Runnable* aScrollEndEvent,
+ bool aDelayed) {
+ if (aDelayed) {
+ mDelayedScrollEndEvents.AppendElement(aScrollEndEvent);
+ } else {
+ mScrollEndEvents.AppendElement(aScrollEndEvent);
+ EnsureTimerStarted();
+ }
+}
+
void nsRefreshDriver::DispatchScrollEvents() {
// Scroll events are one-shot, so after running them we can drop them.
// However, dispatching a scroll event can potentially cause more scroll
@@ -1539,6 +1549,13 @@ void nsRefreshDriver::DispatchScrollEvents() {
}
}
+void nsRefreshDriver::DispatchScrollEndEvents() {
+ ScrollEventArray events = std::move(mScrollEndEvents);
+ for (auto& event : events) {
+ event->Run();
+ }
+}
+
void nsRefreshDriver::PostVisualViewportScrollEvent(
VVPScrollEvent* aScrollEvent) {
mVisualViewportScrollEvents.AppendElement(aScrollEvent);
@@ -1673,6 +1690,9 @@ void nsRefreshDriver::RunDelayedEventsSoon() {
mScrollEvents.AppendElements(mDelayedScrollEvents);
mDelayedScrollEvents.Clear();
+ mScrollEndEvents.AppendElements(mDelayedScrollEvents);
+ mDelayedScrollEndEvents.Clear();
+
mResizeEventFlushObservers.AppendElements(mDelayedResizeEventFlushObservers);
mDelayedResizeEventFlushObservers.Clear();
@@ -2008,7 +2028,7 @@ auto nsRefreshDriver::GetReasonsToTick() const -> TickReasons {
if (!mVisualViewportResizeEvents.IsEmpty()) {
reasons |= TickReasons::eHasVisualViewportResizeEvents;
}
- if (!mScrollEvents.IsEmpty()) {
+ if (!mScrollEvents.IsEmpty() || !mScrollEndEvents.IsEmpty()) {
reasons |= TickReasons::eHasScrollEvents;
}
if (!mVisualViewportScrollEvents.IsEmpty()) {
@@ -2208,23 +2228,7 @@ void nsRefreshDriver::RunFullscreenSteps() {
void nsRefreshDriver::UpdateIntersectionObservations(TimeStamp aNowTime) {
AUTO_PROFILER_LABEL_RELEVANT_FOR_JS("Compute intersections", LAYOUT);
-
- AutoTArray<RefPtr<Document>, 32> documents;
-
- if (mPresContext->Document()->HasIntersectionObservers()) {
- documents.AppendElement(mPresContext->Document());
- }
-
- mPresContext->Document()->CollectDescendantDocuments(
- documents, [](const Document* document) -> bool {
- return document->HasIntersectionObservers();
- });
-
- for (const auto& doc : documents) {
- doc->UpdateIntersectionObservations(aNowTime);
- doc->ScheduleIntersectionObserverNotification();
- }
-
+ mPresContext->Document()->UpdateIntersections(aNowTime);
mNeedToUpdateIntersectionObservations = false;
}
@@ -2476,6 +2480,7 @@ bool nsRefreshDriver::TickObserverArray(uint32_t aIdx, TimeStamp aNowTime) {
FlushAutoFocusDocuments();
DispatchScrollEvents();
DispatchVisualViewportScrollEvents();
+ DispatchScrollEndEvents();
EvaluateMediaQueriesAndReportChanges();
DispatchAnimationEvents();
RunFullscreenSteps();
diff --git a/layout/base/nsRefreshDriver.h b/layout/base/nsRefreshDriver.h
index cd050f7431..7bd0f883f4 100644
--- a/layout/base/nsRefreshDriver.h
+++ b/layout/base/nsRefreshDriver.h
@@ -114,7 +114,10 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
void DispatchVisualViewportResizeEvents();
void PostScrollEvent(mozilla::Runnable* aScrollEvent, bool aDelayed = false);
+ void PostScrollEndEvent(mozilla::Runnable* aScrollEndEvent,
+ bool aDelayed = false);
void DispatchScrollEvents();
+ void DispatchScrollEndEvents();
void PostVisualViewportScrollEvent(VVPScrollEvent* aScrollEvent);
void DispatchVisualViewportScrollEvents();
@@ -694,10 +697,12 @@ class nsRefreshDriver final : public mozilla::layers::TransactionIdAllocator,
AutoTArray<nsCOMPtr<nsIRunnable>, 16> mEarlyRunners;
VisualViewportResizeEventArray mVisualViewportResizeEvents;
ScrollEventArray mScrollEvents;
+ ScrollEventArray mScrollEndEvents;
VisualViewportScrollEventArray mVisualViewportScrollEvents;
// Scroll events on documents that might have events suppressed.
ScrollEventArray mDelayedScrollEvents;
+ ScrollEventArray mDelayedScrollEndEvents;
AutoTArray<mozilla::PresShell*, 16> mResizeEventFlushObservers;
AutoTArray<mozilla::PresShell*, 16> mDelayedResizeEventFlushObservers;
diff --git a/layout/base/tests/browser.toml b/layout/base/tests/browser.toml
index a5b279145f..cc8df52306 100644
--- a/layout/base/tests/browser.toml
+++ b/layout/base/tests/browser.toml
@@ -3,6 +3,12 @@ prefs = [
"layout.css.properties-and-values.enabled=true",
]
+["browser_animatedImageLeak.js"]
+skip-if = ["!debug"]
+support-files = [
+ "helper_animatedImageLeak.html"
+]
+
["browser_bug617076.js"]
["browser_bug1701027-1.js"]
diff --git a/layout/base/tests/browser_animatedImageLeak.js b/layout/base/tests/browser_animatedImageLeak.js
new file mode 100644
index 0000000000..2c34ed9d89
--- /dev/null
+++ b/layout/base/tests/browser_animatedImageLeak.js
@@ -0,0 +1,226 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+requestLongerTimeout(4);
+
+/*
+ * This tests that when we have an animated image in a minimized window we
+ * don't leak.
+ * We've encountered this bug in 3 different ways:
+ * -bug 1830753 - images in top level chrome processes
+ * (we avoid processing them due to their CompositorBridgeChild being paused)
+ * -bug 1839109 - images in content processes
+ * (we avoid processing them due to their refresh driver being throttled, this
+ * would also fix the above case)
+ * -bug 1875100 - images that are in a content iframe that is not the content
+ * of a tab, so something like an extension iframe in the sidebar
+ * (this was fixed by making the content of a tab declare that it manually
+ * manages its activeness and having all other iframes inherit their
+ * activeness from their parent)
+ * In order to hit this bug we require
+ * -the same image to be in a minimized window and in a non-mininmized window
+ * so that the image is animated.
+ * -the animated image to go over the
+ * image.animated.decode-on-demand.threshold-kb threshold so that we do not
+ * keep all of its frames around (if we keep all its frame around then we
+ * don't try to keep allocating frames and not freeing the old ones)
+ * -it has to be the same Image object in memory, not just the same uri
+ * Then the visible copy of the image keeps generating new frames, those frames
+ * get sent to the minimized copies of the image but they never get processed
+ * or marked displayed so they can never be freed/reused.
+ *
+ * Note that due to bug 1889840, in order to test this we can't use an image
+ * loaded at the top level (see the last point above). We must use an html page
+ * that contains the image.
+ */
+
+// this test is based in part on https://searchfox.org/mozilla-central/rev/c09764753ea40725eb50decad2c51edecbd33308/browser/components/extensions/test/browser/browser_ext_sidebarAction.js
+
+async function pushPrefs1() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["image.animated.decode-on-demand.threshold-kb", 1],
+ ["image.animated.decode-on-demand.batch-size", 2],
+ ],
+ });
+}
+
+async function openWindowsAndMinimize(taskToPerformBeforeMinimize) {
+ let wins = [null, null, null, null];
+ for (let i = 0; i < wins.length; i++) {
+ let win = await BrowserTestUtils.openNewBrowserWindow();
+ await win.delayedStartupPromise;
+ await taskToPerformBeforeMinimize(win);
+
+ // Leave the last window un-minimized.
+ if (i < wins.length - 1) {
+ let promiseSizeModeChange = BrowserTestUtils.waitForEvent(
+ win,
+ "sizemodechange"
+ );
+ win.minimize();
+ await promiseSizeModeChange;
+ }
+
+ wins[i] = win;
+ }
+ return wins;
+}
+
+async function pushPrefs2() {
+ // wait so that at least one frame of the animation has been shown while the
+ // below pref is not set so that the counter gets reset.
+ await new Promise(resolve => setTimeout(resolve, 500));
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["gfx.testing.assert-render-textures-increase", 75]],
+ });
+}
+
+async function waitForEnoughFrames() {
+ // we want to wait for over 75 frames of the image, it has a delay of 200ms
+ // Windows debug test machines seem to animate at about 10 fps though
+ await new Promise(resolve => setTimeout(resolve, 20000));
+}
+
+async function closeWindows(wins) {
+ for (let i = 0; i < wins.length; i++) {
+ await BrowserTestUtils.closeWindow(wins[i]);
+ }
+}
+
+async function popPrefs() {
+ await SpecialPowers.popPrefEnv();
+ await SpecialPowers.popPrefEnv();
+}
+
+add_task(async () => {
+ async function runTest(theTestPath) {
+ await pushPrefs1();
+
+ let wins = await openWindowsAndMinimize(async function (win) {
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ win.gBrowser,
+ theTestPath
+ );
+ });
+
+ await pushPrefs2();
+
+ await waitForEnoughFrames();
+
+ await closeWindows(wins);
+
+ await popPrefs();
+
+ ok(true, "got here without assserting");
+ }
+
+ function fileURL(filename) {
+ let ifile = getChromeDir(getResolvedURI(gTestPath));
+ ifile.append(filename);
+ return Services.io.newFileURI(ifile).spec;
+ }
+
+ // This tests the image in content process case
+ await runTest(fileURL("helper_animatedImageLeak.html"));
+ // This tests the image in chrome process case
+ await runTest(getRootDirectory(gTestPath) + "helper_animatedImageLeak.html");
+});
+
+// Now we test the image in a sidebar loaded via an extension case.
+
+/*
+ * The data uri below is a 2kb apng that is 3000x200 with 22 frames with delay
+ * of 200ms, it just toggles the color of one pixel from black to red so it's
+ * tiny. We use the same data uri (although that is not important to this test)
+ * in helper_animatedImageLeak.html.
+ */
+
+/*
+ * This is just data to create a simple extension that creates a sidebar with
+ * an image in it.
+ */
+let extData = {
+ manifest: {
+ sidebar_action: {
+ default_panel: "sidebar.html",
+ },
+ },
+ useAddonManager: "temporary",
+
+ files: {
+ "sidebar.html": `
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="UTF-8">
+ <script src="sidebar.js"></script>
+ </head>
+ <body><p>Sidebar</p>
+ <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAC7gAAADICAMAAABP7lxwAAAACGFjVEwAAAAWAAAAAGbtojIAAAAJUExURQAAAAAAAP8AAD373S0AAAABdFJOUwBA5thmAAAAGmZjVEwAAAAAAAALuAAAAMgAAAAAAAAAAADIA+gAALdBHhgAAAJgSURBVHja7dABCQAAAAKg+n+6HYFOMAEAAA5UAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArwZGYwACQRkAGQAAABpmY1RMAAAAAQAAAAEAAAABAAAAAQAAAAEAyAPoAAD6Iy/6AAAADmZkQVQAAAACeNpjYAIAAAQAAzBzKbkAAAAaZmNUTAAAAAMAAAABAAAAAQAAAAEAAAABAMgD6AAAF7X8EwAAAA5mZEFUAAAABHjaY2AEAAADAAJ81yb0AAAAGmZjVEwAAAAFAAAAAQAAAAEAAAABAAAAAQDIA+gAAPp/jmkAAAAOZmRBVAAAAAZ42mNgAgAABAADgKpaOwAAABpmY1RMAAAABwAAAAEAAAABAAAAAQAAAAEAyAPoAAAX6V2AAAAADmZkQVQAAAAIeNpjYAQAAAMAAnbNtDMAAAAaZmNUTAAAAAkAAAABAAAAAQAAAAEAAAABAMgD6AAA+pps3AAAAA5mZEFUAAAACnjaY2ACAAAEAAOKsMj8AAAAGmZjVEwAAAALAAAAAQAAAAEAAAABAAAAAQDIA+gAABcMvzUAAAAOZmRBVAAAAAx42mNgBAAAAwACxhTHsQAAABpmY1RMAAAADQAAAAEAAAABAAAAAQAAAAEAyAPoAAD6xs1PAAAADmZkQVQAAAAOeNpjYAIAAAQAAzppu34AAAAaZmNUTAAAAA8AAAABAAAAAQAAAAEAAAABAMgD6AAAF1AepgAAAA5mZEFUAAAAEHjaY2AEAAADAAJi+JG9AAAAGmZjVEwAAAARAAAAAQAAAAEAAAABAAAAAQDIA+gAAPtRqbYAAAAOZmRBVAAAABJ42mNgAgAABAADnoXtcgAAABpmY1RMAAAAEwAAAAEAAAABAAAAAQAAAAEAyAPoAAAWx3pfAAAADmZkQVQAAAAUeNpjYAQAAAMAAtIh4j8AAAAaZmNUTAAAABUAAAABAAAAAQAAAAEAAAABAMgD6AAA+w0IJQAAAA5mZEFUAAAAFnjaY2ACAAAEAAMuXJ7wAAAAGmZjVEwAAAAXAAAAAQAAAAEAAAABAAAAAQDIA+gAABab28wAAAAOZmRBVAAAABh42mNgBAAAAwAC2Dtw+AAAABpmY1RMAAAAGQAAAAEAAAABAAAAAQAAAAEAyAPoAAD76OqQAAAADmZkQVQAAAAaeNpjYAIAAAQAAyRGDDcAAAAaZmNUTAAAABsAAAABAAAAAQAAAAEAAAABAMgD6AAAFn45eQAAAA5mZEFUAAAAHHjaY2AEAAADAAJo4gN6AAAAGmZjVEwAAAAdAAAAAQAAAAEAAAABAAAAAQDIA+gAAPu0SwMAAAAOZmRBVAAAAB542mNgAgAABAADlJ9/tQAAABpmY1RMAAAAHwAAAAEAAAABAAAAAQAAAAEAyAPoAAAWIpjqAAAADmZkQVQAAAAgeNpjYAQAAAMAAkqS2qEAAAAaZmNUTAAAACEAAAABAAAAAQAAAAEAAAABAMgD6AAA+MYjYgAAAA5mZEFUAAAAInjaY2ACAAAEAAO276ZuAAAAGmZjVEwAAAAjAAAAAQAAAAEAAAABAAAAAQDIA+gAABVQ8IsAAAAOZmRBVAAAACR42mNgBAAAAwAC+kupIwAAABpmY1RMAAAAJQAAAAEAAAABAAAAAQAAAAEAyAPoAAD4moLxAAAADmZkQVQAAAAmeNpjYAIAAAQAAwY21ewAAAAaZmNUTAAAACcAAAABAAAAAQAAAAEAAAABAMgD6AAAFQxRGAAAAA5mZEFUAAAAKHjaY2AEAAADAALwUTvkAAAAGmZjVEwAAAApAAAAAQAAAAEAAAABAAAAAQDIA+gAAPh/YEQAAAAOZmRBVAAAACp42mNgAgAABAADDCxHKwAAABt0RVh0U29mdHdhcmUAQVBORyBBc3NlbWJsZXIgMy4wXkUsHAAAAABJRU5ErkJggg=="/>
+ </body>
+</html>
+ `,
+
+ "sidebar.js": function () {
+ window.onload = () => {
+ browser.test.sendMessage("sidebar");
+ };
+ },
+ },
+};
+
+function getExtData(manifestUpdates = {}) {
+ return {
+ ...extData,
+ manifest: {
+ ...extData.manifest,
+ ...manifestUpdates,
+ },
+ };
+}
+
+async function sendMessage(ext, msg, data = undefined) {
+ ext.sendMessage({ msg, data });
+ await ext.awaitMessage("done");
+}
+
+add_task(async function sidebar_initial_install() {
+ await pushPrefs1();
+
+ ok(
+ document.getElementById("sidebar-box").hidden,
+ "sidebar box is not visible"
+ );
+
+ let extension = ExtensionTestUtils.loadExtension(getExtData());
+ await extension.startup();
+ await extension.awaitMessage("sidebar");
+
+ // Test sidebar is opened on install
+ ok(!document.getElementById("sidebar-box").hidden, "sidebar box is visible");
+
+ // the sidebar appears on all new windows automatically.
+ let wins = await openWindowsAndMinimize(async function (win) {
+ await extension.awaitMessage("sidebar");
+ });
+
+ await pushPrefs2();
+
+ await waitForEnoughFrames();
+
+ await extension.unload();
+ // Test that the sidebar was closed on unload.
+ ok(
+ document.getElementById("sidebar-box").hidden,
+ "sidebar box is not visible"
+ );
+
+ await closeWindows(wins);
+
+ await popPrefs();
+
+ ok(true, "got here without assserting");
+});
diff --git a/layout/base/tests/bug1896051-ref.html b/layout/base/tests/bug1896051-ref.html
new file mode 100644
index 0000000000..39b26f148d
--- /dev/null
+++ b/layout/base/tests/bug1896051-ref.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<html class="reftest-wait">
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<style>
+ textarea {
+ font: 13px / 1 monospace;
+ border: 1px solid;
+ padding: 0;
+ overflow: hidden;
+ resize: none;
+ }
+</style>
+<textarea rows=5>
+a
+b
+c
+d
+</textarea>
+<script>
+SimpleTest.waitForFocus(function() {
+ let textarea = document.querySelector("textarea");
+ textarea.focus();
+ textarea.selectionStart = textarea.selectionEnd = textarea.value.length;
+ setTimeout(() => {
+ document.documentElement.removeAttribute("class");
+ }, 0);
+});
+</script>
diff --git a/layout/base/tests/bug1896051.html b/layout/base/tests/bug1896051.html
new file mode 100644
index 0000000000..ba35339475
--- /dev/null
+++ b/layout/base/tests/bug1896051.html
@@ -0,0 +1,38 @@
+<!doctype html>
+<html class="reftest-wait">
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<style>
+ textarea {
+ font: 13px / 1 monospace;
+ border: 1px solid;
+ padding: 0;
+ overflow: hidden;
+ resize: none;
+ }
+</style>
+<textarea rows=5>
+a
+b
+c
+d
+</textarea>
+<script>
+SimpleTest.waitForFocus(function() {
+ let textarea = document.querySelector("textarea");
+ textarea.focus();
+ if (navigator.platform.startsWith("Mac")) {
+ // On mac there is no page down key that moves the selection, afaict.
+ // (Fn+Arrow moves the scroll position but not selection).
+ // Do the next thing which would be something like Cmd+Down to move to the
+ // end. That tests a different code-path altogether, but for this test it
+ // doesn't matter.
+ synthesizeKey("KEY_ArrowDown", { metaKey: true });
+ } else {
+ synthesizeKey("KEY_PageDown");
+ }
+ setTimeout(() => {
+ document.documentElement.removeAttribute("class")
+ }, 0);
+});
+</script>
diff --git a/layout/base/tests/chrome/chrome.toml b/layout/base/tests/chrome/chrome.toml
index 6636b224e6..63e3da9609 100644
--- a/layout/base/tests/chrome/chrome.toml
+++ b/layout/base/tests/chrome/chrome.toml
@@ -66,6 +66,12 @@ support-files = [
"printpreview_pps16_ref.html",
"printpreview_prettyprint.xml",
"printpreview_prettyprint_ref.xhtml",
+ "printpreview_scale_test_001.html",
+ "printpreview_scale_test_001_ref.html",
+ "printpreview_scale_test_002.html",
+ "printpreview_scale_test_002_ref.html",
+ "printpreview_scale_test_003.html",
+ "printpreview_scale_test_003_ref.html",
"printpreview_mask.html",
"print_page_size1.html",
"print_page_size1_ref.html",
diff --git a/layout/base/tests/chrome/printpreview_helper.xhtml b/layout/base/tests/chrome/printpreview_helper.xhtml
index e40d2e4d5b..119c55d777 100644
--- a/layout/base/tests/chrome/printpreview_helper.xhtml
+++ b/layout/base/tests/chrome/printpreview_helper.xhtml
@@ -1708,9 +1708,252 @@ async function runTest58() {
let test = "printpreview_mixed_page_size_002.html";
// The params are just to give the file unique URLs.
await compareFiles(test + "?test", test + "?ref");
+ requestAnimationFrame(() => setTimeout(runTest59));
+}
+
+// Creates a data URL that has a single div of |divSize| em square, on a page
+// of size |pageSize| inches square.
+// |center| determines if the div should be centered horizontally.
+function createScalingTestSource(pageSize, center, name) {
+ // Styling always used.
+ let baseStyle = 'background: blue;';
+ if (center) {
+ baseStyle += 'margin: auto;';
+ }
+ const div = '<div style="width: 100px; height: 100px;' + baseStyle + '"></div>';
+ const style = '<style>@page{size:' + pageSize + 'in}body{margin:0}</style>';
+ // Add the name as a comment, to ensure every test has a unique source even
+ // if the parameters are identical.
+ const comment = '<!-- ' + name + ' -->';
+ return 'data:text/html,' + style + div + comment;
+}
+
+async function runScalingCenteredTest(refPageSize, testPageSize, paperSize,
+ name, center = true, fuzz = null) {
+ const printSettings = {
+ settings: {
+ paperWidth: paperSize,
+ paperHeight: paperSize,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ }
+ };
+ let settings = Object.create(fuzz, {
+ ref: {value: printSettings},
+ test: {value: printSettings}
+ });
+ const testSrc = createScalingTestSource(testPageSize, center, name);
+ const refSrc = createScalingTestSource(refPageSize, center, name);
+ return compareFiles(testSrc, refSrc, settings);
+}
+
+// Tests that auto-detection and use of page centering.
+// Has a smaller page on a larger sheet, where the difference is within the
+// tolerance for auto-detection.
+async function runTest59() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["print.center_page_on_sheet", 2]]
+ });
+ // See bug 1680838
+ const fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 180, maxDifference: 255 } :
+ null;
+ await runScalingCenteredTest(10, 9.5, 10, "runTest59", true, fuzz);
+ await SpecialPowers.popPrefEnv();
+ requestAnimationFrame(() => setTimeout(runTest60));
+}
+
+// Tests that centering won't occur when the pref disables it, using the same
+// values as runTest59.
+async function runTest60() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["print.center_page_on_sheet", 0]]
+ });
+ // See bug 1680838
+ const fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 180, maxDifference: 255 } :
+ null;
+ await runScalingCenteredTest(10, 9.5, 10, "runTest60", false, fuzz);
+ await SpecialPowers.popPrefEnv();
+ requestAnimationFrame(() => setTimeout(runTest61));
+}
+
+// Tests that auto-detection will reject too big a difference for page
+// centering. Has a much smaller page on a larger sheet, where the difference
+// is outside the threshold for auto-detection.
+async function runTest61() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["print.center_page_on_sheet", 2]]
+ });
+ // See bug 1680838
+ const fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 450, maxDifference: 255 } :
+ null;
+ await runScalingCenteredTest(10, 8.9, 10, "runTest61", false, fuzz);
+ await SpecialPowers.popPrefEnv();
+ requestAnimationFrame(() => setTimeout(runTest62));
+}
+
+// Tests that we can force page centering with the pref, using the same values
+// as runTest61.
+async function runTest62() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["print.center_page_on_sheet", 1]]
+ });
+ // See bug 1680838
+ const fuzz = navigator.platform.includes("Win") ?
+ { maxDifferent: 450, maxDifference: 255 } :
+ null;
+ await runScalingCenteredTest(10, 8.9, 10, "runTest62", true, fuzz);
+ await SpecialPowers.popPrefEnv();
+ requestAnimationFrame(() => setTimeout(runTest63));
+}
+
+// Tests that centering will always happen if the pref forces it.
+// The sizes used in these files are very large and the scale factor very high
+// here to ensure that any errors in the calculation for centering will be
+// magnified.
+async function runTest63() {
+ let test = "printpreview_scale_test_001.html";
+ let ref = "printpreview_scale_test_001_ref.html";
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["print.center_page_on_sheet", 1]]
+ });
+ await compareFiles(test, ref, {
+ test: {
+ settings: {
+ paperWidth: 8.5,
+ paperHeight: 11,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8.5,
+ paperHeight: 11,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+ await SpecialPowers.popPrefEnv();
+ requestAnimationFrame(() => setTimeout(runTest64));
+}
+
+// Tests that printing A4 pages on US Letter will be a close enough fit
+// that we will automatically center the page.
+async function runTest64() {
+ let test = "printpreview_scale_test_002.html";
+ let ref = "printpreview_scale_test_002_ref.html";
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["print.center_page_on_sheet", 2]]
+ });
+ await compareFiles(test, ref, {
+ test: {
+ settings: {
+ paperWidth: 8.5,
+ paperHeight: 11,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8.5,
+ paperHeight: 11,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+ await SpecialPowers.popPrefEnv();
+ requestAnimationFrame(() => setTimeout(runTest65));
+}
+
+// Tests that auto-detection will reject a large enough difference in width
+// when downscaling is used to make the page fit on the paper.
+async function runTest65() {
+ let test = "printpreview_scale_test_003.html";
+ let ref = "printpreview_scale_test_003_ref.html";
+
+ await SpecialPowers.pushPrefEnv({
+ set: [["print.center_page_on_sheet", 2]]
+ });
+ await compareFiles(test, ref, {
+ test: {
+ settings: {
+ paperWidth: 8.5,
+ paperHeight: 11,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ ref: {
+ settings: {
+ paperWidth: 8.5,
+ paperHeight: 11,
+ paperSizeUnit: Ci.nsIPrintSettings.kPaperSizeInches,
+ marginTop: 0,
+ marginRight: 0,
+ marginBottom: 0,
+ marginLeft: 0,
+ unwriteableMarginTop: 0,
+ unwriteableMarginRight: 0,
+ unwriteableMarginBottom: 0,
+ unwriteableMarginLeft: 0,
+ },
+ },
+ });
+ await SpecialPowers.popPrefEnv();
finish();
}
+
]]></script>
<table style="border: 1px solid black;" xmlns="http://www.w3.org/1999/xhtml">
<tr><th>Print preview canvas 1</th><th>Print preview canvas 2</th></tr>
diff --git a/layout/base/tests/chrome/printpreview_scale_test_001.html b/layout/base/tests/chrome/printpreview_scale_test_001.html
new file mode 100644
index 0000000000..e9d3122b6b
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_scale_test_001.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<head>
+ <style>
+@page {
+ size: 10in 22in;
+ margin: 0;
+}
+body{
+ margin:0;
+}
+div{
+ width: 2in;
+ height: 2in;
+ background: blue;
+ margin-left: 4in;
+}
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/printpreview_scale_test_001_ref.html b/layout/base/tests/chrome/printpreview_scale_test_001_ref.html
new file mode 100644
index 0000000000..2ed4571ef1
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_scale_test_001_ref.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<head>
+ <style>
+@page {
+ size: 4in 44in;
+ margin: 0;
+}
+body{
+ margin:0;
+}
+div{
+ height: 4in;
+ width: 4in;
+ background: blue;
+}
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/printpreview_scale_test_002.html b/layout/base/tests/chrome/printpreview_scale_test_002.html
new file mode 100644
index 0000000000..94c35ab3c3
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_scale_test_002.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<head>
+ <style>
+@page {
+ size: A4;
+ margin: 0;
+}
+body{
+ margin:0;
+}
+div{
+ height: 200px;
+ width: 200px;
+ background: blue;
+ margin: auto;
+}
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/printpreview_scale_test_002_ref.html b/layout/base/tests/chrome/printpreview_scale_test_002_ref.html
new file mode 100644
index 0000000000..d73de86fe5
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_scale_test_002_ref.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<head>
+ <style>
+@page {
+ size: letter;
+ margin: 0;
+}
+body{
+ margin:0;
+}
+div{
+ /* A4-on-letter requires a 0.9407 downscale. 11in = 279.4mm, and
+ * 279.4mm / 297mm = 0.9407407407..
+ * The unscaled reference case has a 200px square div, so reverse the scale
+ * to match that (rounding to 0.940741)
+ */
+ height: calc(0.940741 * 200px);
+ width: calc(0.940741 * 200px);
+ background: blue;
+ margin: auto;
+}
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/printpreview_scale_test_003.html b/layout/base/tests/chrome/printpreview_scale_test_003.html
new file mode 100644
index 0000000000..2b1d68ff60
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_scale_test_003.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<head>
+ <style>
+@page {
+ size: 8.5in 13in;
+ margin: 0;
+}
+body{
+ margin:0;
+}
+div{
+ /* 13in / 11in = 1.1818181... */
+ height: calc(1.1818182 * 200px);
+ width: calc(1.1818182 * 200px);
+ background: blue;
+}
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/printpreview_scale_test_003_ref.html b/layout/base/tests/chrome/printpreview_scale_test_003_ref.html
new file mode 100644
index 0000000000..41a3f87889
--- /dev/null
+++ b/layout/base/tests/chrome/printpreview_scale_test_003_ref.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<head>
+ <style>
+@page {
+ size: 8.5in 11in;
+ margin: 0;
+}
+body{
+ margin:0;
+}
+div{
+ /* 11in / 13in = 0.8461538 */
+ height: 200px;
+ width: 200px;
+ background: blue;
+}
+ </style>
+</head>
+<body>
+ <div></div>
+</body>
diff --git a/layout/base/tests/chrome/test_bug420499.xhtml b/layout/base/tests/chrome/test_bug420499.xhtml
index 22fefd7987..8db69ff6c1 100644
--- a/layout/base/tests/chrome/test_bug420499.xhtml
+++ b/layout/base/tests/chrome/test_bug420499.xhtml
@@ -84,7 +84,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=420499
function popupMenuShownHandler() {
window.removeEventListener("popupshown", popupMenuShownHandler);
- ok(!isCaretVisible(), "Caret shouldn't be visible when menu open");
+ ok(isCaretVisible(), "Caret shouldn't be visible when menu open");
window.addEventListener("popuphidden", ensureParagraphFocused);
$("menu").open = false;
}
diff --git a/layout/base/tests/helper_animatedImageLeak.html b/layout/base/tests/helper_animatedImageLeak.html
new file mode 100644
index 0000000000..a5555f1fbb
--- /dev/null
+++ b/layout/base/tests/helper_animatedImageLeak.html
@@ -0,0 +1,10 @@
+<html>
+<!--
+ The data uri below is a 2kb apng that is 3000x200 with 22 frames with delay
+ of 200ms, it just toggles the color of one pixel from black to red so it's
+ tiny. We use the same data uri (although that is not important to this test)
+ in browser_animatedImageLeak.js.
+-->
+
+<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAC7gAAADICAMAAABP7lxwAAAACGFjVEwAAAAWAAAAAGbtojIAAAAJUExURQAAAAAAAP8AAD373S0AAAABdFJOUwBA5thmAAAAGmZjVEwAAAAAAAALuAAAAMgAAAAAAAAAAADIA+gAALdBHhgAAAJgSURBVHja7dABCQAAAAKg+n+6HYFOMAEAAA5UAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArwZGYwACQRkAGQAAABpmY1RMAAAAAQAAAAEAAAABAAAAAQAAAAEAyAPoAAD6Iy/6AAAADmZkQVQAAAACeNpjYAIAAAQAAzBzKbkAAAAaZmNUTAAAAAMAAAABAAAAAQAAAAEAAAABAMgD6AAAF7X8EwAAAA5mZEFUAAAABHjaY2AEAAADAAJ81yb0AAAAGmZjVEwAAAAFAAAAAQAAAAEAAAABAAAAAQDIA+gAAPp/jmkAAAAOZmRBVAAAAAZ42mNgAgAABAADgKpaOwAAABpmY1RMAAAABwAAAAEAAAABAAAAAQAAAAEAyAPoAAAX6V2AAAAADmZkQVQAAAAIeNpjYAQAAAMAAnbNtDMAAAAaZmNUTAAAAAkAAAABAAAAAQAAAAEAAAABAMgD6AAA+pps3AAAAA5mZEFUAAAACnjaY2ACAAAEAAOKsMj8AAAAGmZjVEwAAAALAAAAAQAAAAEAAAABAAAAAQDIA+gAABcMvzUAAAAOZmRBVAAAAAx42mNgBAAAAwACxhTHsQAAABpmY1RMAAAADQAAAAEAAAABAAAAAQAAAAEAyAPoAAD6xs1PAAAADmZkQVQAAAAOeNpjYAIAAAQAAzppu34AAAAaZmNUTAAAAA8AAAABAAAAAQAAAAEAAAABAMgD6AAAF1AepgAAAA5mZEFUAAAAEHjaY2AEAAADAAJi+JG9AAAAGmZjVEwAAAARAAAAAQAAAAEAAAABAAAAAQDIA+gAAPtRqbYAAAAOZmRBVAAAABJ42mNgAgAABAADnoXtcgAAABpmY1RMAAAAEwAAAAEAAAABAAAAAQAAAAEAyAPoAAAWx3pfAAAADmZkQVQAAAAUeNpjYAQAAAMAAtIh4j8AAAAaZmNUTAAAABUAAAABAAAAAQAAAAEAAAABAMgD6AAA+w0IJQAAAA5mZEFUAAAAFnjaY2ACAAAEAAMuXJ7wAAAAGmZjVEwAAAAXAAAAAQAAAAEAAAABAAAAAQDIA+gAABab28wAAAAOZmRBVAAAABh42mNgBAAAAwAC2Dtw+AAAABpmY1RMAAAAGQAAAAEAAAABAAAAAQAAAAEAyAPoAAD76OqQAAAADmZkQVQAAAAaeNpjYAIAAAQAAyRGDDcAAAAaZmNUTAAAABsAAAABAAAAAQAAAAEAAAABAMgD6AAAFn45eQAAAA5mZEFUAAAAHHjaY2AEAAADAAJo4gN6AAAAGmZjVEwAAAAdAAAAAQAAAAEAAAABAAAAAQDIA+gAAPu0SwMAAAAOZmRBVAAAAB542mNgAgAABAADlJ9/tQAAABpmY1RMAAAAHwAAAAEAAAABAAAAAQAAAAEAyAPoAAAWIpjqAAAADmZkQVQAAAAgeNpjYAQAAAMAAkqS2qEAAAAaZmNUTAAAACEAAAABAAAAAQAAAAEAAAABAMgD6AAA+MYjYgAAAA5mZEFUAAAAInjaY2ACAAAEAAO276ZuAAAAGmZjVEwAAAAjAAAAAQAAAAEAAAABAAAAAQDIA+gAABVQ8IsAAAAOZmRBVAAAACR42mNgBAAAAwAC+kupIwAAABpmY1RMAAAAJQAAAAEAAAABAAAAAQAAAAEAyAPoAAD4moLxAAAADmZkQVQAAAAmeNpjYAIAAAQAAwY21ewAAAAaZmNUTAAAACcAAAABAAAAAQAAAAEAAAABAMgD6AAAFQxRGAAAAA5mZEFUAAAAKHjaY2AEAAADAALwUTvkAAAAGmZjVEwAAAApAAAAAQAAAAEAAAABAAAAAQDIA+gAAPh/YEQAAAAOZmRBVAAAACp42mNgAgAABAADDCxHKwAAABt0RVh0U29mdHdhcmUAQVBORyBBc3NlbWJsZXIgMy4wXkUsHAAAAABJRU5ErkJggg=="/>
+</html>
diff --git a/layout/base/tests/helper_bug1733509.html b/layout/base/tests/helper_bug1733509.html
new file mode 100644
index 0000000000..4fbdacdb46
--- /dev/null
+++ b/layout/base/tests/helper_bug1733509.html
@@ -0,0 +1,30 @@
+<html>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/paint_listener.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
+<style>
+ body {
+ margin: 0;
+ padding: 20;
+ background-color: blueviolet;
+ }
+
+ button {
+ margin: 0;
+ }
+</style>
+
+<body>
+ <button id="btn">Click me</button>
+</body>
+
+<script>
+ // Silence SimpleTest warning about missing assertions by having it wait
+ // indefinitely. We don't need to give it an explicit finish because the
+ // entire window this test runs in will be closed after the main browser test
+ // finished.
+ SimpleTest.waitForExplicitFinish();
+</script>
+
+</html>
diff --git a/layout/base/tests/mochitest.toml b/layout/base/tests/mochitest.toml
index 24924809c0..f74c6b030d 100644
--- a/layout/base/tests/mochitest.toml
+++ b/layout/base/tests/mochitest.toml
@@ -247,6 +247,7 @@ support-files = ["file_dynamic_toolbar_max_height.html"]
["test_emulate_color_scheme.html"]
["test_event_target_radius.html"]
+support-files = ["helper_bug1733509.html"]
skip-if = ["xorigin"] # JavaScript error: resource://specialpowers/SpecialPowersChild.sys.mjs, line 73: SecurityError: Permission denied to access property "windowUtils" on cross-origin object
["test_frame_reconstruction_body_table.html"]
@@ -558,6 +559,8 @@ support-files = [
"bug1518339-2-ref.html",
"bug1529492-1.html",
"bug1529492-1-ref.html",
+ "bug1896051.html",
+ "bug1896051-ref.html",
"chrome/blue-32x32.png",
]
diff --git a/layout/base/tests/test_event_target_radius.html b/layout/base/tests/test_event_target_radius.html
index caf046cf99..a1e8d9c16c 100644
--- a/layout/base/tests/test_event_target_radius.html
+++ b/layout/base/tests/test_event_target_radius.html
@@ -2,14 +2,19 @@
<html id="html" style="height:100%">
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=780847
+https://bugzilla.mozilla.org/show_bug.cgi?id=1733509
-->
<head>
<title>Test radii for mouse events</title>
- <script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
+ <script src="/tests/SimpleTest/paint_listener.js"></script>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/gfx/layers/apz/test/mochitest/apz_test_utils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
.target { position:absolute; left:100px; top:100px; width:100px; height:100px; background:blue; }
+ .scaled { background: green; transform: scale(0.5); }
+ iframe { margin:0; padding:0; width:50; height:50; border:1px solid black; background:yellowgreen; }
</style>
</head>
<body id="body" onload="setTimeout(startTest, 0)" style="margin:0; width:100%; height:100%; overflow:hidden">
@@ -73,6 +78,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=780847
<div id="t13_touchlistener" style="width: 50px; height: 50px; background:red" ontouchend="x=1"></div>
<div id="t13_notouchlistener" style="width: 50px; height: 50px; background:green"></div>
</div>
+
+ <div id="t14" class="target scaled" hidden>
+ <iframe id="t14iframe"></iframe>
+ </div>
</div>
<pre id="test">
<script type="application/javascript">
@@ -414,7 +423,50 @@ function testTouchable() {
testTouch("t13", 10, 50 - (2*mm), "t13_touchlistener", "touch inside t13_touchlistener bottom edge");
setShowing("t13", false);
- endTest();
+ test4();
+}
+
+// https://bugzilla.mozilla.org/show_bug.cgi?id=1733509
+function test4() {
+ // Skip non-Fission for now because of bug 1890522
+ if (SpecialPowers.Services.appinfo.fissionAutostart) {
+ waitUntilApzStable().then(async () => doTest4()).then(endTest);
+ } else {
+ endTest();
+ }
+}
+
+async function doTest4() {
+ setShowing("t14", true);
+
+ let iframeURL = SimpleTest.getTestFileURL("helper_bug1733509.html");
+ // todo: Also perform this test for an in-process iframe
+ // once bug 1890522 is fixed.
+ const iframe = document.querySelector("#t14iframe");
+ iframeURL = iframeURL.replace(window.location.origin, "https://example.com");
+ await setupIframe(iframe, iframeURL);
+
+ var result = await SpecialPowers.spawn(iframe, [], async () => {
+ await content.wrappedJSObject.waitUntilApzStable();
+ var iframeEventTarget = null;
+ content.window.onmousedown = function (event) { iframeEventTarget = event.target; };
+ content.wrappedJSObject.synthesizeMouse(content.document.documentElement, 2, 2, {});
+ return iframeEventTarget && iframeEventTarget.id === "btn";
+ });
+
+ ok(result, "Failed to target button inside iframe");
+ setShowing("t14", false);
+}
+
+async function setupIframe(aIFrame, aURL) {
+ const iframeLoadPromise = promiseOneEvent(aIFrame, "load", null);
+ aIFrame.src = aURL;
+ await iframeLoadPromise;
+
+ await SpecialPowers.spawn(aIFrame, [], async () => {
+ await content.wrappedJSObject.waitUntilApzStable();
+ await SpecialPowers.contentTransformsReceived(content);
+ });
}
</script>
</pre>
diff --git a/layout/base/tests/test_reftests_with_caret.html b/layout/base/tests/test_reftests_with_caret.html
index 3935380e5d..d134bd2eb9 100644
--- a/layout/base/tests/test_reftests_with_caret.html
+++ b/layout/base/tests/test_reftests_with_caret.html
@@ -112,6 +112,7 @@ var tests = [
[ 'bug613807-1.html' , 'bug613807-1-ref.html' ] ,
[ 'bug1082486-1.html', 'bug1082486-1-ref.html'] ,
[ 'bug1082486-2.html', 'bug1082486-2-ref.html'] ,
+ [ 'bug1896051.html', 'bug1896051-ref.html'],
// The following test cases uses mouse events. We need to make
// AccessibleCaret unhide for them.
function() {SpecialPowers.pushPrefEnv({'set': [['layout.accessiblecaret.hide_carets_for_mouse_input', false]]}, nextTest);} ,
diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp
index 1738098ed2..ecc84ad286 100644
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -183,9 +183,6 @@ nsresult nsLayoutStatics::Initialize() {
nsMathMLOperators::AddRefTable();
-#ifdef DEBUG
- nsIFrame::DisplayReflowStartup();
-#endif
Attr::Initialize();
PopupBlocker::Initialize();
@@ -320,9 +317,6 @@ void nsLayoutStatics::Shutdown() {
HTMLDNSPrefetch::Shutdown();
nsCSSRendering::Shutdown();
StaticPresData::Shutdown();
-#ifdef DEBUG
- nsIFrame::DisplayReflowShutdown();
-#endif
nsCellMap::Shutdown();
ActiveLayerTracker::Shutdown();
diff --git a/layout/docs/DynamicChangeHandling.md b/layout/docs/DynamicChangeHandling.md
new file mode 100644
index 0000000000..50df613412
--- /dev/null
+++ b/layout/docs/DynamicChangeHandling.md
@@ -0,0 +1,83 @@
+# Dynamic change handling along the rendering pipeline
+
+The ability to make changes to the DOM from script is a major feature of
+the Web platform. Web authors rely on the concept (though there are a
+few exceptions, such as animations) that changing the DOM from script
+leads to the same rendering that would have resulted from starting from
+that DOM tree. They also rely on the performance characteristics of
+these changes: small changes to the DOM that have small effects should
+have proportionally small processing time. This means that Gecko needs
+to efficiently propagate changes from the content tree to style, the
+frame tree, the geometry of the frame tree, and the screen.
+
+For many types of changes, however, there is substantial overhead to
+processing a change, no matter how small. For example, reflow must
+propagate from the top of the frame tree down to the frames that are
+dirty, no matter how small the change. One very common way around this
+is to batch up changes. We batch up changes in lots of ways, for
+example:
+
+- The content sink adds multiple nodes to the DOM tree before
+ notifying listeners that they\'ve been added. This allows notifying
+ once about an ancestor rather than for each of its descendants, or
+ notifying about a group of descendants all at once, which speeds up
+ the processing of those notifications.
+- We batch up nodes that require style reresolution (recomputation of
+ selector matching and processing the resulting style changes). This
+ batching is tree based, so it not only merges multiple notifications
+ on the same element, but also merges a notification on an ancestor
+ with a notification on its descendant (since *some* of these
+ notifications imply that style reresolution is required on all
+ descendants).
+- We wait to reconstruct frames that require reconstruction (after
+ destroying frames eagerly). This, like the tree-based style
+ reresolution batching, avoids duplication both for same-element
+ notifications and ancestor-descendant notifications, even though it
+ doesn\'t actually do any tree-based caching.
+- We postpone doing reflows until needed. As for style reresolution,
+ this maintains tree-based dirty bits (see the description of
+ NS\_FRAME\_IS\_DIRTY and NS\_FRAME\_HAS\_DIRTY\_CHILDREN under
+ Reflow).
+- We allow the OS to queue up multiple invalidates before repainting
+ (though we will likely switch to controlling that ourselves). This
+ leads to a single repaint of some set of pixels where there might
+ otherwise have been multiple (though it may also lead to more pixels
+ being repainted if multiple rectangles are merged to a single one).
+
+Having changes buffered up means, however, that various pieces of
+information (layout, style, etc.) may not be up-to-date. Some things
+require up-to-date information: for example, we don\'t want to expose
+the details of our buffering to Web page script since the programming
+model of Web page script assumes that DOM changes take effect
+\"immediately\", i.e., that the script shouldn\'t be able to detect any
+buffering. Many Web pages depend on this.
+
+We therefore have ways to flush these different sorts of buffers. There
+are methods called FlushPendingNotifications on nsIDocument and
+nsIPresShell, that take an argument of what things to flush:
+
+- Flush\_Content: create all the content nodes from data buffered in
+ the parser
+- Flush\_ContentAndNotify: the above, plus notify document observers
+ about the creation of all nodes created so far
+- Flush\_Style: the above, plus make sure style data are up-to-date
+- Flush\_Frames: the above, plus make sure all frame construction has
+ happened (currently the same as Flush\_Style)
+- Flush\_InterruptibleLayout: the above, plus perform layout (Reflow),
+ but allow interrupting layout if it takes too long
+- Flush\_Layout: the above, plus ensure layout (Reflow) runs to
+ completion
+- Flush\_Display (should never be used): the above, plus ensure
+ repainting happens
+
+The major way that notifications of changes propagate from the content
+code to layout and other areas of code is through the
+nsIDocumentObserver and nsIMutationObserver interfaces. Classes can
+implement this interface to listen to notifications of changes for an
+entire document or for a subtree of the content tree.
+
+WRITE ME: \... layout document observer implementations
+
+TODO: how style system optimizes away rerunning selector matching
+
+TODO: style changes and nsChangeHint
diff --git a/layout/docs/LayoutOverview.md b/layout/docs/LayoutOverview.md
new file mode 100644
index 0000000000..0375ab5480
--- /dev/null
+++ b/layout/docs/LayoutOverview.md
@@ -0,0 +1,529 @@
+# Layout Overview
+
+Much of the layout code deals with operations on the frame tree (or
+rendering tree). In the frame tree, each node represents a rectangle
+(or, for SVG, other shapes). The frame tree has a shape similar to the
+content tree, since many content nodes have one corresponding frame,
+though it differs in a few ways, since some content nodes have more than
+one frame or don\'t have any frames at all. When elements are
+display:none in CSS or undisplayed for certain other reasons, they
+won\'t have any frames. When elements are broken across lines or pages,
+they have multiple frames; elements may also have multiple frames when
+multiple frames nested inside each other are needed to display a single
+element (for example, a table, a table cell, or many types of form
+controls).
+
+Each node in the frame tree is an instance of a class derived from
+`nsIFrame`. As with the content tree, there is a substantial type
+hierarchy, but the type hierarchy is very different: it includes types
+like text frames, blocks and inlines, the various parts of tables, flex
+and grid containers, and the various types of HTML form controls.
+
+Frames are allocated within an arena owned by the PresShell. Each frame
+is owned by its parent; frames are not reference counted, and code must
+not hold on to pointers to frames. To mitigate potential security bugs
+when pointers to destroyed frames, we use [frame
+poisoning](http://robert.ocallahan.org/2010/10/mitigating-dangling-pointer-bugs-using_15.html),
+which takes two parts. When a frame is destroyed other than at the end
+of life of the presentation, we fill its memory with a pattern
+consisting of a repeated pointer to inaccessible memory, and then put
+the memory on a per-frame-class freelist. This means that if code
+accesses the memory through a dangling pointer, it will either crash
+quickly by dereferencing the poison pattern or it will find a valid
+frame.
+
+Like the content tree, frames must be accessed only from the UI thread.
+
+The frame tree should not store any important data, i.e. any data that
+cannot be recomputed on-the-fly. While the frame tree does usually
+persist while a page is being displayed, frames are often destroyed and
+recreated in response to certain style changes, and in the future we may
+do the same to reduce memory use for pages that are currently inactive.
+There were a number of cases where this rule was violated in the past
+and we stored important data in the frame tree; however, most (though
+not quite all) such cases are now fixed.
+
+The rectangle represented by the frame is what CSS calls the element\'s
+border box. This is the outside edge of the border (or the inside edge
+of the margin). The margin lives outside the border; and the padding
+lives inside the border. In addition to nsIFrame::GetRect, we also have
+the APIs nsIFrame::GetPaddingRect to get the padding box (the outside
+edge of the padding, or inside edge of the border) and
+nsIFrame::GetContentRect to get the content box (the outside edge of the
+content, or inside edge of the padding). These APIs may produce out of
+date results when reflow is needed (or has not yet occurred).
+
+In addition to tracking a rectangle, frames also track two overflow
+areas: ink overflow and scrollable overflow. These overflow areas
+represent the union of the area needed by the frame and by all its
+descendants. The ink overflow is used for painting-related
+optimizations: it is a rectangle covering all of the area that might be
+painted when the frame and all of its descendants paint. The scrollable
+overflow represents the area that the user should be able to scroll to
+to see the frame and all of its descendants. In some cases differences
+between the frame\'s rect and its overflow happen because of descendants
+that stick out of the frame; in other cases they occur because of some
+characteristic of the frame itself. The two overflow areas are similar,
+but there are differences: for example, margins are part of scrollable
+overflow but not ink overflow, whereas text-shadows are part of ink
+overflow but not scrollable overflow.
+
+When frames are broken across lines, columns, or pages, we create
+multiple frames representing the multiple rectangles of the element. The
+first one is the primary frame, and the rest are its continuations
+(which are more likely to be destroyed and recreated during reflow).
+These frames are linked together as continuations: they have a
+doubly-linked list that can be used to traverse the continuations using
+nsIFrame::GetPrevContinuation and nsIFrame::GetNextContinuation.
+(Currently continuations always have the same style data, though we may
+at some point want to break that invariant.)
+
+Continuations are sometimes siblings of each other (i.e.
+nsIFrame::GetNextContinuation and nsIFrame::GetNextSibling might return
+the same frame), and sometimes not. For example, if a paragraph contains
+a span which contains a link, and the link is split across lines, then
+the continuations of the span are siblings (since they are both children
+of the paragraph), but the continuations of the link are not siblings
+(since each continuation of the link is descended from a different
+continuation of the span). Traversing the entire frame tree does **not**
+require explicit traversal of any frames\' continuations-list, since all
+of the continuations are descendants of the element containing the
+break.
+
+We also use continuations for cases (most importantly, bidi reordering,
+where left-to-right text and right-to-left text need to be separated
+into different continuations since they may not form a contiguous
+rectangle) where the continuations should not be rewrapped during
+reflow: we call these continuations fixed rather than fluid.
+nsIFrame::GetNextInFlow and nsIFrame::GetPrevInFlow traverse only the
+fluid continuations and do not cross fixed continuation boundaries.
+
+If an inline frame has non-inline children, then we split the original
+inline frame into parts. The original inline\'s children are distributed
+into these parts like so: The children of the original inline are
+grouped into runs of inline and non-inline, and runs of inline get an
+inline parent, while runs of non-inline get an anonymous block parent.
+We call this \'ib-splitting\' or \'block-inside-inline splitting\'. This
+splitting proceeds recursively up the frame tree until all non-inlines
+inside inlines are ancestors of a block frame with anonymous block
+wrappers in between. This splitting maintains the relative order between
+these child frames, and the relationship between the parts of a split
+inline is maintained using an ib-sibling chain. It is important to note
+that any wrappers created during frame construction (such as for tables)
+might not be included in the ib-sibling chain depending on when this
+wrapper creation takes place.
+
+TODO: nsBox craziness from
+<https://bugzilla.mozilla.org/show_bug.cgi?id=524925#c64>
+
+TODO: link to documentation of block and inline layout
+
+TODO: link to documentation of scrollframes
+
+TODO: link to documentation of XUL frame classes
+
+Code (note that most files in base and generic have useful one line
+descriptions at the top that show up in DXR):
+
+- [layout/base/](http://dxr.mozilla.org/mozilla-central/source/layout/base/)
+ contains objects that coordinate everything and a bunch of other
+ miscellaneous things
+- [layout/generic/](http://dxr.mozilla.org/mozilla-central/source/layout/generic/)
+ contains the basic frame classes as well as support code for their
+ reflow methods (ReflowInput, ReflowOutput)
+- [layout/forms/](http://dxr.mozilla.org/mozilla-central/source/layout/forms/)
+ contains frame classes for HTML form controls
+- [layout/tables/](http://dxr.mozilla.org/mozilla-central/source/layout/tables/)
+ contains frame classes for CSS/HTML tables
+- [layout/mathml/](http://dxr.mozilla.org/mozilla-central/source/layout/mathml/)
+ contains frame classes for MathML
+- [layout/svg/](http://dxr.mozilla.org/mozilla-central/source/layout/svg/)
+ contains frame classes for SVG
+- [layout/xul/](http://dxr.mozilla.org/mozilla-central/source/layout/xul/)
+ contains frame classes for the XUL box model and for various XUL
+ widgets
+
+Bugzilla:
+
+- All of the components whose names begin with \"Layout\" in the
+ \"Core\" product
+
+Further documentation:
+
+- Talk: [Introduction to graphics/layout
+ architecture](https://air.mozilla.org/introduction-to-graphics-layout-architecture/)
+ (Robert O\'Callahan, 2014-04-18)
+- Talk: [Layout and
+ Styles](https://air.mozilla.org/bz-layout-and-styles/) (Boris
+ Zbarsky, 2014-10-14)
+
+## Frame Construction
+
+Frame construction is the process of creating frames. This is done when
+styles change in ways that require frames to be created or recreated or
+when nodes are inserted into the document. The content tree and the
+frame tree don\'t have quite the same shape, and the frame construction
+process does some of the work of creating the right shape for the frame
+tree. It handles the aspects of creating the right shape that don\'t
+depend on layout information. So for example, frame construction handles
+the work needed to implement [table anonymous
+objects](http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes) but
+does not handle frames that need to be created when an element is broken
+across lines or pages.
+
+The basic unit of frame construction is a run of contiguous children of
+a single parent element. When asked to construct frames for such a run
+of children, the frame constructor first determines, based on the
+siblings and parent of the nodes involved, where in the frame tree the
+new frames should be inserted. Then the frame constructor walks through
+the list of content nodes involved and for each one creates a temporary
+data structure called a **frame construction item**. The frame
+construction item encapsulates various information needed to create the
+frames for the content node: its style data, some metadata about how one
+would create a frame for this node based on its namespace, tag name, and
+styles, and some data about what sort of frame will be created. This
+list of frame construction items is then analyzed to see whether
+constructing frames based on it and inserting them at the chosen
+insertion point will produce a valid frame tree. If it will not, the
+frame constructor either fixes up the list of frame construction items
+so that the resulting frame tree would be valid or throws away the list
+of frame construction items and requests the destruction and re-creation
+of the frame for the parent element so that it has a chance to create a
+list of frame construction items that it `<em>`{=html}can`</em>`{=html}
+fix up.
+
+Once the frame constructor has a list of frame construction items and an
+insertion point that would lead to a valid frame tree, it goes ahead and
+creates frames based on those items. Creation of a non-leaf frame
+recursively attempts to create frames for the children of that frame\'s
+element, so in effect frames are created in a depth-first traversal of
+the content tree.
+
+The vast majority of the code in the frame constructor, therefore, falls
+into one of these categories:
+
+- Code to determine the correct insertion point in the frame tree for
+ new frames.
+- Code to create, for a given content node, frame construction items.
+ This involves some searches through static data tables for metadata
+ about the frame to be created.
+- Code to analyze the list of frame construction items.
+- Code to fix up the list of frame construction items.
+- Code to create frames from frame construction items.
+
+Code:
+[layout/base/nsCSSFrameConstructor.h](http://dxr.mozilla.org/mozilla-central/source/layout/base/nsCSSFrameConstructor.h)
+and
+[layout/base/nsCSSFrameConstructor.cpp](http://dxr.mozilla.org/mozilla-central/source/layout/base/nsCSSFrameConstructor.cpp)
+
+## Physical Sizes vs. Logical Sizes
+
+TODO: Discuss inline-size (typically width) and block size (typically
+height), writing modes, and the various logical vs. physical size/rect
+types.
+
+## Reflow
+
+Reflow is the process of computing the positions and sizes of frames.
+(After all, frames represent rectangles, and at some point we need to
+figure out exactly \*what\* rectangle.) Reflow is done recursively, with
+each frame\'s Reflow method calling the Reflow methods on that frame\'s
+descendants.
+
+In many cases, the correct results are defined by CSS specifications
+(particularly [CSS 2.1](http://www.w3.org/TR/CSS21/visudet.html)). In
+some cases, the details are not defined by CSS, though in some (but not
+all) of those cases we are constrained by Web compatibility. When the
+details are defined by CSS, however, the code to compute the layout is
+generally structured somewhat differently from the way it is described
+in the CSS specifications, since the CSS specifications are generally
+written in terms of constraints, whereas our layout code consists of
+algorithms optimized for incremental recomputation.
+
+The reflow generally starts from the root of the frame tree, though some
+other types of frame can act as \"reflow roots\" and start a reflow from
+them (nsTextControlFrame is one example; see the
+[NS\_FRAME\_REFLOW\_ROOT](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_REFLOW_ROOT&redirect=true)
+frame state bit). Reflow roots must obey the invariant that a change
+inside one of their descendants never changes their rect or overflow
+areas (though currently scrollbars are reflow roots but don\'t quite
+obey this invariant).
+
+In many cases, we want to reflow a part of the frame tree, and we want
+this reflow to be efficient. For example, when content is added or
+removed from the document tree or when styles change, we want the amount
+of work we need to redo to be proportional to the amount of content. We
+also want to efficiently handle a series of changes to the same content.
+
+To do this, we maintain two bits on frames:
+[NS\_FRAME\_IS\_DIRTY](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_IS_DIRTY&redirect=true)
+indicates that a frame and all of its descendants require reflow.
+[NS\_FRAME\_HAS\_DIRTY\_CHILDREN](https://searchfox.org/mozilla-central/search?q=symbol:E_%3CT_nsFrameState%3E_NS_FRAME_HAS_DIRTY_CHILDREN&redirect=true)
+indicates that a frame has a descendant that is dirty or has had a
+descendant removed (i.e., that it has a child that has
+NS\_FRAME\_IS\_DIRTY or NS\_FRAME\_HAS\_DIRTY\_CHILDREN or it had a
+child removed). These bits allow coalescing of multiple updates; this
+coalescing is done in PresShell, which tracks the set of reflow roots
+that require reflow. The bits are set during calls to
+[PresShell::FrameNeedsReflow](https://searchfox.org/mozilla-central/search?q=PresShell%3A%3AFrameNeedsReflow&path=)
+and are cleared during reflow.
+
+The layout algorithms used by many of the frame classes are those
+specified in CSS, which are based on the traditional document formatting
+model, where widths are input and heights are output.
+
+In some cases, however, widths need to be determined based on the
+content. This depends on two *intrinsic widths*: the minimum intrinsic
+width (see
+[nsIFrame::GetMinISize](https://searchfox.org/mozilla-central/search?q=nsIFrame%3A%3AGetMinISize&path=))
+and the preferred intrinsic width (see
+[nsIFrame::GetPrefISize](https://searchfox.org/mozilla-central/search?q=nsIFrame%3A%3AGetPrefISize&path=)).
+The concept of what these widths represent is best explained by
+describing what they are on a paragraph containing only text: in such a
+paragraph the minimum intrinsic width is the width of the longest word,
+and the preferred intrinsic width is the width of the entire paragraph
+laid out on one line.
+
+Intrinsic widths are invalidated separately from the dirty bits
+described above. When a caller informs the pres shell that a frame needs
+reflow (PresShell::FrameNeedsReflow), it passes one of three options:
+
+- eResize indicates that no intrinsic widths are dirty
+- eTreeChange indicates that intrinsic widths on it and its ancestors
+ are dirty (which happens, for example, if new children are added to
+ it)
+- eStyleChange indicates that intrinsic widths on it, its ancestors,
+ and its descendants are dirty (for example, if the font-size
+ changes)
+
+Reflow is the area where the XUL frame classes (those that inherit from
+nsBoxFrame or nsLeafBoxFrame) are most different from the rest. Instead
+of using nsIFrame::Reflow, they do their layout computations using
+intrinsic size methods called GetMinSize, GetPrefSize, and GetMaxSize
+(which report intrinsic sizes in two dimensions) and a final layout
+method called Layout. In many cases these methods defer some of the
+computation to a separate object called a layout manager.
+
+When an individual frame\'s Reflow method is called, most of the input
+is provided on an object called ReflowInput and the output is filled in
+to an object called ReflowOutput. After reflow, the caller (usually the
+parent) is responsible for setting the frame\'s size based on the
+metrics reported. (This can make some computations during reflow
+difficult, since the new size is found in either the reflow state or the
+metrics, but the frame\'s size is still the old size. However, it\'s
+useful for invalidating the correct areas that need to be repainted.)
+
+One major difference worth noting is that in XUL layout, the size of the
+child is set prior to its parent calling its Layout method. (Once
+invalidation uses display lists and is no longer tangled up in Reflow,
+it may be worth switching non-XUL layout to work this way as well.)
+
+## Painting
+
+TODO: display lists (and event handling)
+
+TODO: layers
+
+## Pagination
+
+Pagination (also known as fragmentation) is a concept used in printing,
+print-preview, and multicolumn layout.
+
+### Continuations in the Frame Tree
+
+To render a DOM node, represented as `nsIContent` object, Gecko creates
+zero or more frames (`nsIFrame` objects). Each frame represents a
+rectangular area usually corresponding to the node\'s CSS box as
+described by the CSS specs. Simple elements are often representable with
+exactly one frame, but sometimes an element needs to be represented with
+more than one frame. For example, text breaking across lines:
+
+ xxxxxx AAAA
+ AAA xxxxxxx
+
+The A element is a single DOM node but obviously a single rectangular
+frame isn\'t going to represent its layout precisely.
+
+Similarly, consider text breaking across pages:
+
+ | BBBBBBBBBB |
+ | BBBBBBBBBB |
+ +------------+
+
+ +------------+
+ | BBBBBBBBBB |
+ | BBBBBBBBBB |
+ | |
+
+Again, a single rectangular frame cannot represent the layout of the
+node. Columns are similar.
+
+Another case where a single DOM node is represented by multiple frames
+is when a text node contains bidirectional text (e.g. both Hebrew and
+English text). In this case, the text node and its inline ancestors are
+split so that each frame contains only unidirectional text.
+
+The first frame for an element is called the **primary frame**. The
+other frames are called **continuation frames**. Primary frames are
+created by `nsCSSFrameConstructor` in response to content insertion
+notifications. Continuation frames are created during bidi resolution,
+and during reflow, when reflow detects that a content element cannot be
+fully laid out within the constraints assigned (e.g., when inline text
+will not fit within a particular width constraint, or when a block
+cannot be laid out within a particular height constraint).
+
+Continuation frames created during reflow are called \"fluid\"
+continuations (or \"in-flows\"). Other continuation frames (currently,
+those created during bidi resolution), are, in contrast, \"non-fluid\".
+The `NS_FRAME_IS_FLUID_CONTINUATION` state bit indicates whether a
+continuation frame is fluid or not.
+
+The frames for an element are put in a doubly-linked list. The links are
+accessible via `nsIFrame::GetNextContinuation` and
+`nsIFrame::GetPrevContinuation`. If only fluid continuations are to be
+accessed, `nsIFrame::GetNextInFlow` and `nsIFrame::GetPrevInFlow` are
+used instead.
+
+The following diagram shows the relationship between the original frame
+tree considering just primary frames, and a possible layout with
+breaking and continuations:
+
+ Original frame tree Frame tree with A broken into three parts
+ Root Root
+ | / | \
+ A A1 A2 A3
+ / \ / | | |
+ B C B C1 C2 C3
+ | /|\ | | | \ |
+ D E F G D E F G1 G2
+
+Certain kinds of frames create multiple child frames for the same
+content element:
+
+- `nsPageSequenceFrame` creates multiple page children, each one
+ associated with the entire document, separated by page breaks
+- `nsColumnSetFrame` creates multiple block children, each one
+ associated with the column element, separated by column breaks
+- `nsBlockFrame` creates multiple inline children, each one associated
+ with the same inline element, separated by line breaks, or by
+ changes in text direction
+- `nsTableColFrame` creates non-fluid continuations for itself if it
+ has span=\"N\" and N \> 1
+- If a block frame is a multi-column container and has
+ `column-span:all` children, it creates multiple `nsColumnSetFrame`
+ children, which are linked together as non-fluid continuations.
+ Similarly, if a block frame is within a multi-column formatting
+ context and has `column-span:all` children, it is chopped into
+ several flows, which are linked together as non-fluid continuations
+ as well. See documentation and example frame trees in
+ [`nsCSSFrameConstructor::ConstructBlock()`](https://searchfox.org/mozilla-central/rev/d24696b5abaf9fb75f7985952eab50d5f4ed52ac/layout/base/nsCSSFrameConstructor.cpp#10431).
+
+#### Overflow Container Continuations
+
+Sometimes the content of a frame needs to break across pages even though
+the frame itself is complete. This usually happens if an element with
+fixed height has overflow that doesn\'t fit on one page. In this case,
+the completed frame is \"overflow incomplete\", and special
+continuations are created to hold its overflow. These continuations are
+called \"overflow containers\". They are invisible, and are kept on a
+special list in their parent. See documentation in
+[nsContainerFrame.h](https://searchfox.org/mozilla-central/source/layout/generic/nsContainerFrame.h)
+and example trees in [bug 379349 comment
+3](https://bugzilla.mozilla.org/show_bug.cgi?id=379349#c3).
+
+This infrastructure was extended in [bug
+154892](https://bugzilla.mozilla.org/show_bug.cgi?id=154892) to also
+manage continuations for absolutely-positioned frames.
+
+#### Relationship of continuations to frame tree structure
+
+It is worth emphasizing two points about the relationship of the
+prev-continuation / next-continuation linkage to the existing frame tree
+structure.
+
+First, if you want to traverse the frame tree or a subtree thereof to
+examine all the frames once, you do `<em>`{=html}not`</em>`{=html} want
+to traverse next-continuation links. All continuations are reachable by
+traversing the `GetNextSibling` links from the result of `GetFirstChild`
+for all child lists.
+
+Second, the following property holds:
+
+- Consider two frames F1 and F2 where F1\'s next-continuation is F2
+ and their respective parent frames are P1 and P2. Then either P1\'s
+ next continuation is P2, or P1 == P2, because P is responsible for
+ breaking F1 and F2.
+
+In other words, continuations are sometimes siblings of each other, and
+sometimes not. If their parent content was broken at the same point,
+then they are not siblings, since they are children of different
+continuations of the parent. So in the frame tree for the markup
+
+` <p>This is <b><i>some <br/>text</i></b>.</p>`
+
+the two continuations for the `b` element are siblings (unless the line
+break is also a page break), but the two continuations for the `i`
+element are not.
+
+There is an exception to that property when F1 is a first-in-flow float
+placeholder. In that case F2\'s parent will be the next-in-flow of F1\'s
+containing block.
+
+### Reflow statuses
+
+The aStatus argument of Reflow reflects that. `IsComplete()` means that
+we reflowed all the content and no more next-in-flows are needed. At
+that point there may still be next in flows, but the parent will delete
+them. `IsIncomplete()` means \"some content did not fit in this frame\".
+`IsOverflowIncomplete()` means that the frame is itself complete, but
+some of its content didn\'t fit: this triggers the creation of overflow
+containers for the frame\'s continuations. `IsIncomplete()` and
+`NextInFlowNeedsReflow()` means \"some content did not fit in this frame
+AND it must be reflowed\". These values are defined and documented in
+[nsIFrame.h](https://searchfox.org/mozilla-central/source/layout/generic/nsIFrame.h)
+(search for \"Reflow status\").
+
+### Dynamic Reflow Considerations
+
+When we reflow a frame F with fluid continuations, two things can
+happen:
+
+- Some child frames do not fit in the passed-in width or height
+ constraint. These frames must be \"pushed\" to F\'s next-in-flow. If
+ F has no next-in-flow, we must create one under F\'s parent\'s
+ next-in-flow \-\-- or if F\'s parent is managing the breaking of F,
+ then we create F\'s next in flow directly under F\'s parent. If F is
+ a block, it pushes overflowing child frames to its \"overflow\"
+ child list and forces F\'s next in flow to be reflowed. When we
+ reflow a block, we pull the child frames from the prev-in-flow\'s
+ overflow list into the current frame.
+- All child frames fit in the passed-in width or height constraint.
+ Then child frames must be \"pulled\" from F\'s next-in-flow to fill
+ in the available space. If F\'s next-in-flow becomes empty, we may
+ be able to delete it.
+
+In both of these situations we might end up with a frame F containing
+two child frames, one of which is a continuation of the other. This is
+incorrect. We might also create holes, where there are frames P1 P2 and
+P3, P1 has child F1 and P3 has child F2, but P2 has no F child.
+
+A strategy for avoiding these issues is this: When pulling a frame F2
+from parent P2 to prev-in-flow P1, if F2 is a breakable container, then:
+
+- If F2 has no prev-in-flow F1 in P1, then create a new primary frame
+ F1 in P1 for F2\'s content, with F2 as its next-in-flow.
+- Pull children from F2 to F1 until F2 is empty or we run out of
+ space. If F2 goes empty, pull from the next non-empty next-in-flow.
+ Empty continuations with no next-in-flows can be deleted.
+
+When pushing a frame F1 from parent P1 to P2, where F1 has a
+next-in-flow F2 (which must be a child of P2):
+
+- Merge F2 into F1 by moving all F2\'s children into F1, then deleting
+ F2
+
+For inline frames F, we have our own custom strategy that coalesces
+adjacent inline frames. This need not change.
+
+We do need to implement this strategy when F is a normal in-flow block,
+a floating block, and eventually an absolutely positioned block.
diff --git a/layout/docs/StyleSystemOverview.md b/layout/docs/StyleSystemOverview.md
new file mode 100644
index 0000000000..bed5fd057f
--- /dev/null
+++ b/layout/docs/StyleSystemOverview.md
@@ -0,0 +1,173 @@
+# Style System Overview
+
+## Quantum CSS (Stylo)
+
+Starting with Firefox 57 and later, Gecko makes use of the parallel
+style system written in Rust that comes from Servo. There\'s an
+[overview](https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-quantum-css-aka-stylo/)
+of this with graphics to help explain what\'s going on. The [Servo
+wiki](https://github.com/servo/servo/wiki/Layout-Overview) has some more
+details.
+
+## Gecko
+
+The rest of the style section section describes the Gecko style system
+used in Firefox 56 and earlier. Some bits may still apply, but it likely
+needs revising.
+
+In order to display the content, Gecko needs to compute the styles
+relevant to each DOM node. It does this based on the model described in
+the CSS specifications: this model applies to style specified in CSS
+(e.g. by a \'style\' element, an \'xml-stylesheet\' processing
+instruction or a \'style\' attribute), style specified by presentation
+attributes, and the default style specified by our own user agent style
+sheets. There are two major sets of data structures within the style
+system:
+
+- first, data structures that represent sources of style data, such as
+ CSS style sheets or data from stylistic HTML attributes
+- second, data structures that represent computed style for a given
+ DOM node.
+
+These sets of data structures are mostly distinct (for example, they
+store values in different ways).
+
+The loading of CSS style sheets from the network is managed by the [CSS
+loader](https://dxr.mozilla.org/mozilla-central/source/layout/style/Loader.h);
+they are then tokenized by the [CSS
+scanner](https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSScanner.h)
+and parsed by the [CSS
+parser](https://dxr.mozilla.org/mozilla-central/source/layout/style/nsCSSParser.h).
+Those that are attached to the document also expose APIs to script that
+are known as the CSS Object Model, or CSSOM.
+
+The style sheets that apply to a document are managed by a class called
+the [style
+set](https://dxr.mozilla.org/mozilla-central/source/layout/style/nsStyleSet.h).
+The style set interacts with the different types of style sheets
+(representing CSS style sheets, presentational attributes, and \'style\'
+attributes) through two interfaces:
+[nsIStyleSheet](http://dxr.mozilla.org/mozilla-central/source/layout/style/nsIStyleSheet.h)
+for basic management of style sheets and
+[nsIStyleRuleProcessor](http://dxr.mozilla.org/mozilla-central/source/layout/style/nsIStyleRuleProcessor.h)
+for getting the style data out of them. Usually the same object
+implements both interfaces, except in the most important case, CSS style
+sheets, where there is a single rule processor for all of the CSS style
+sheets in each origin (user/UA/author) of the CSS cascade.
+
+The computed style data for an element/frame are exposed to the rest of
+Gecko through the class mozilla::ComputedStyle (previously called
+nsStyleContext). Rather than having a member variable for each CSS
+property, it breaks up the properties into groups of related properties
+called style structs. These style structs obey the rule that all of the
+properties in a single struct either inherit by default (what the CSS
+specifications call \"Inherited: yes\" in the definition of properties;
+we call these inherited structs) or all are not inherited by default (we
+call these reset structs). Separating the properties in this way
+improves the ability to share the structs between similar ComputedStyle
+objects and reduce the amount of memory needed to store the style data.
+The ComputedStyle API exposes a method for getting each struct, so
+you\'ll see code like `sc->GetStyleText()->mTextAlign` for getting the
+value of the text-align CSS property. (Frames (see the Layout section
+below) also have the same GetStyle\* methods, which just forward the
+call to the frame\'s ComputedStyle.)
+
+The ComputedStyles form a tree structure, in a shape somewhat like the
+content tree (except that we coalesce identical sibling ComputedStyles
+rather than keeping two of them around; if the parents have been
+coalesced then this can apply recursively and coalasce cousins, etc.; we
+do not coalesce parent/child ComputedStyles). The parent of a
+ComputedStyle has the style data that the ComputedStyle inherits from
+when CSS inheritance occurs. This means that the parent of the
+ComputedStyle for a DOM element is generally the ComputedStyle for that
+DOM element\'s parent, since that\'s how CSS says inheritance works.
+
+The process of turning the style sheets into computed style data goes
+through three main steps, the first two of which closely relate to the
+[nsIStyleRule](http://dxr.mozilla.org/mozilla-central/source/layout/style/nsIStyleRule.h)
+interface, which represents an immutable source of style data,
+conceptually representing (and for CSS style rules, directly storing) a
+set of property:value pairs. (It is similar to the idea of a CSS style
+rule, except that it is immutable; this immutability allows for
+significant optimization. When a CSS style rule is changed through
+script, we create a new style rule.)
+
+The first step of going from style sheets to computed style data is
+finding the ordered sequence of style rules that apply to an element.
+The order represents which rules override which other rules: if two
+rules have a value for the same property, the higher ranking one wins.
+(Note that there\'s another difference from CSS style rules:
+declarations with !important are represented using a separate style
+rule.) This is done by calling one of the
+nsIStyleRuleProcessor::RulesMatching methods. The ordered sequence is
+stored in a [trie](http://en.wikipedia.org/wiki/Trie) called the rule
+tree: the path from the root of the rule tree to any (leaf or non-leaf)
+node in the rule tree represents a sequence of rules, with the highest
+ranking farthest from the root. Each rule node (except for the root) has
+a pointer to a rule, but since a rule may appear in many sequences,
+there are sometimes many rule nodes pointing to the same rule. Once we
+have this list we create a ComputedStyle (or find an appropriate
+existing sibling) with the correct parent pointer (for inheritance) and
+rule node pointer (for the list of rules), and a few other pieces of
+information (like the pseudo-element).
+
+The second step of going from style sheets to computed style data is
+getting the winning property:value pairs from the rules. (This only
+provides property:value pairs for some of the properties; the remaining
+properties will fall back to inheritance or to their initial values
+depending on whether the property is inherited by default.) We do this
+step (and the third) for each style struct, the first time it is needed.
+This is done in nsRuleNode::WalkRuleTree, where we ask each style rule
+to fill in its property:value pairs by calling its MapRuleInfoInto
+function. When called, the rule fills in only those pairs that haven\'t
+been filled in already, since we\'re calling from the highest priority
+rule to the lowest (since in many cases this allows us to stop before
+going through the whole list, or to do partial computation that just
+adds to data cached higher in the rule tree).
+
+The third step of going from style sheets to computed style data (which
+various caching optimizations allow us to skip in many cases) is
+actually doing the computation; this generally means we transform the
+style data into the data type described in the \"Computed Value\" line
+in the property\'s definition in the CSS specifications. This
+transformation happens in functions called nsRuleNode::Compute\*Data,
+where the \* in the middle represents the name of the style struct. This
+is where the transformation from the style sheet value storage format to
+the computed value storage format happens.
+
+Once we have the computed style data, we then store it: if a style
+struct in the computed style data doesn\'t depend on inherited values or
+on data from other style structs, then we can cache it in the rule tree
+(and then reuse it, without recomputing it, for any ComputedStyles
+pointing to that rule node). Otherwise, we store it on the ComputedStyle
+(in which case it may be shared with the ComputedStyle\'s descendant
+ComputedStyles). This is where keeping inherited and non-inherited
+properties separate is useful: in the common case of relatively few
+properties being specified, we can generally cache the non-inherited
+structs in the rule tree, and we can generally share the inherited
+structs up and down the ComputedStyle tree.
+
+The ownership models in style sheet structures are a mix of reference
+counted structures (for things accessible from script) and directly
+owned structures. ComputedStyles are reference counted, and own their
+parents (from which they inherit), and rule nodes are garbage collected
+with a simple mark and sweep collector (which often never needs to run).
+
+- code:
+ [layout/style/](http://dxr.mozilla.org/mozilla-central/source/layout/style/),
+ where most files have useful one line descriptions at the top that
+ show up in DXR
+- Bugzilla: Style System (CSS)
+- specifications
+ - [CSS 2.1](http://www.w3.org/TR/CSS21/)
+ - [CSS 2010, listing stable css3
+ modules](http://www.w3.org/TR/css-2010/)
+ - [CSS WG editors drafts](http://dev.w3.org/csswg/) (often more
+ current, but sometimes more unstable than the drafts on the
+ technical reports page)
+ - [Preventing attacks on a user\'s history through CSS :visited
+ selectors](http://dbaron.org/mozilla/visited-privacy)
+- documentation
+ - [style system
+ documentation](http://www-archive.mozilla.org/newlayout/doc/style-system.html)
+ (somewhat out of date)
diff --git a/layout/docs/index.rst b/layout/docs/index.rst
index 16d9df8b05..39455a1075 100644
--- a/layout/docs/index.rst
+++ b/layout/docs/index.rst
@@ -1,8 +1,9 @@
-Layout & CSS
-============
+Style system (CSS) & Layout
+===========================
-Here contains design documents for the Gecko's style system and layout engine.
-They live in the mozilla-central repository under layout/docs directory.
+Here contains the overview and design documents for Firefox's layout engine and
+style system. They live in the mozilla-central repository under `layout/docs
+<https://searchfox.org/mozilla-central/source/layout/docs>`__ directory.
`Layout page <https://wiki.mozilla.org/Platform/Layout>`__ on mozilla wiki
contains general information about layout and the layout team at Mozilla.
@@ -10,6 +11,9 @@ contains general information about layout and the layout team at Mozilla.
.. toctree::
:maxdepth: 1
- AccessibleCaret
+ StyleSystemOverview
+ LayoutOverview
+ DynamicChangeHandling
Reftest
LayoutDebugger
+ AccessibleCaret
diff --git a/layout/forms/nsCheckboxRadioFrame.cpp b/layout/forms/nsCheckboxRadioFrame.cpp
index e2b8541613..4bf15099aa 100644
--- a/layout/forms/nsCheckboxRadioFrame.cpp
+++ b/layout/forms/nsCheckboxRadioFrame.cpp
@@ -52,18 +52,12 @@ void nsCheckboxRadioFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
/* virtual */
nscoord nsCheckboxRadioFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
- result = StyleDisplay()->HasAppearance() ? DefaultSize() : 0;
- return result;
+ return StyleDisplay()->HasAppearance() ? DefaultSize() : 0;
}
/* virtual */
nscoord nsCheckboxRadioFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
- result = StyleDisplay()->HasAppearance() ? DefaultSize() : 0;
- return result;
+ return StyleDisplay()->HasAppearance() ? DefaultSize() : 0;
}
/* virtual */
@@ -76,13 +70,9 @@ LogicalSize nsCheckboxRadioFrame::ComputeAutoSize(
if (!StyleDisplay()->HasAppearance()) {
return size;
}
-
- // Note: this call always set the BSize to NS_UNCONSTRAINEDSIZE.
- size = nsAtomicContainerFrame::ComputeAutoSize(
+ return nsAtomicContainerFrame::ComputeAutoSize(
aRC, aWM, aCBSize, aAvailableISize, aMargin, aBorderPadding,
aSizeOverrides, aFlags);
- size.BSize(aWM) = DefaultSize();
- return size;
}
Maybe<nscoord> nsCheckboxRadioFrame::GetNaturalBaselineBOffset(
@@ -125,7 +115,6 @@ void nsCheckboxRadioFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsCheckboxRadioFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE(
NS_FRAME_TRACE_CALLS,
@@ -133,10 +122,13 @@ void nsCheckboxRadioFrame::Reflow(nsPresContext* aPresContext,
aReflowInput.AvailableWidth(), aReflowInput.AvailableHeight()));
const auto wm = aReflowInput.GetWritingMode();
- aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
-
+ const auto contentBoxSize =
+ aReflowInput.ComputedSizeWithBSizeFallback([&] { return DefaultSize(); });
+ aDesiredSize.SetSize(
+ wm,
+ contentBoxSize + aReflowInput.ComputedLogicalBorderPadding(wm).Size(wm));
if (nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) {
- float inflation = nsLayoutUtils::FontSizeInflationFor(this);
+ const float inflation = nsLayoutUtils::FontSizeInflationFor(this);
aDesiredSize.Width() *= inflation;
aDesiredSize.Height() *= inflation;
}
diff --git a/layout/forms/nsComboboxControlFrame.cpp b/layout/forms/nsComboboxControlFrame.cpp
index 1d4ff15b4f..98486255d0 100644
--- a/layout/forms/nsComboboxControlFrame.cpp
+++ b/layout/forms/nsComboboxControlFrame.cpp
@@ -190,14 +190,12 @@ nscoord nsComboboxControlFrame::GetIntrinsicISize(gfxContext* aRenderingContext,
nscoord nsComboboxControlFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord minISize;
- DISPLAY_MIN_INLINE_SIZE(this, minISize);
minISize = GetIntrinsicISize(aRenderingContext, IntrinsicISizeType::MinISize);
return minISize;
}
nscoord nsComboboxControlFrame::GetPrefISize(gfxContext* aRenderingContext) {
nscoord prefISize;
- DISPLAY_PREF_INLINE_SIZE(this, prefISize);
prefISize =
GetIntrinsicISize(aRenderingContext, IntrinsicISizeType::PrefISize);
return prefISize;
diff --git a/layout/forms/nsDateTimeControlFrame.cpp b/layout/forms/nsDateTimeControlFrame.cpp
index b19f787dbc..d8cdf5f277 100644
--- a/layout/forms/nsDateTimeControlFrame.cpp
+++ b/layout/forms/nsDateTimeControlFrame.cpp
@@ -35,33 +35,21 @@ nsDateTimeControlFrame::nsDateTimeControlFrame(ComputedStyle* aStyle,
: nsContainerFrame(aStyle, aPresContext, kClassID) {}
nscoord nsDateTimeControlFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
-
nsIFrame* kid = mFrames.FirstChild();
- if (kid) { // display:none?
- result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, kid,
- IntrinsicISizeType::MinISize);
- } else {
- result = 0;
+ if (!kid) {
+ return 0;
}
-
- return result;
+ return nsLayoutUtils::IntrinsicForContainer(aRenderingContext, kid,
+ IntrinsicISizeType::MinISize);
}
nscoord nsDateTimeControlFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
-
nsIFrame* kid = mFrames.FirstChild();
- if (kid) { // display:none?
- result = nsLayoutUtils::IntrinsicForContainer(
- aRenderingContext, kid, IntrinsicISizeType::PrefISize);
- } else {
- result = 0;
+ if (!kid) {
+ return 0;
}
-
- return result;
+ return nsLayoutUtils::IntrinsicForContainer(aRenderingContext, kid,
+ IntrinsicISizeType::PrefISize);
}
Maybe<nscoord> nsDateTimeControlFrame::GetNaturalBaselineBOffset(
@@ -78,7 +66,6 @@ void nsDateTimeControlFrame::Reflow(nsPresContext* aPresContext,
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsDateTimeControlFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE(
NS_FRAME_TRACE_CALLS,
diff --git a/layout/forms/nsFieldSetFrame.cpp b/layout/forms/nsFieldSetFrame.cpp
index c96b293e82..2648cb4dd3 100644
--- a/layout/forms/nsFieldSetFrame.cpp
+++ b/layout/forms/nsFieldSetFrame.cpp
@@ -58,7 +58,7 @@ nsRect nsFieldSetFrame::VisualBorderRectRelativeToSelf() const {
auto legendMargin = legend->GetLogicalUsedMargin(wm);
nscoord legendStartMargin = legendMargin.BStart(wm);
nscoord legendEndMargin = legendMargin.BEnd(wm);
- nscoord border = GetUsedBorder().Side(wm.PhysicalSide(eLogicalSideBStart));
+ nscoord border = GetUsedBorder().Side(wm.PhysicalSide(LogicalSide::BStart));
// Calculate the offset from the border area block-axis start edge needed to
// center-align our border with the legend's border-box (in the block-axis).
nscoord off = (legendStartMargin + legendSize / 2) - border / 2;
@@ -348,19 +348,11 @@ nscoord nsFieldSetFrame::GetIntrinsicISize(gfxContext* aRenderingContext,
}
nscoord nsFieldSetFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_MIN_INLINE_SIZE(this, result);
-
- result = GetIntrinsicISize(aRenderingContext, IntrinsicISizeType::MinISize);
- return result;
+ return GetIntrinsicISize(aRenderingContext, IntrinsicISizeType::MinISize);
}
nscoord nsFieldSetFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_PREF_INLINE_SIZE(this, result);
-
- result = GetIntrinsicISize(aRenderingContext, IntrinsicISizeType::PrefISize);
- return result;
+ return GetIntrinsicISize(aRenderingContext, IntrinsicISizeType::PrefISize);
}
/* virtual */
@@ -372,7 +364,6 @@ void nsFieldSetFrame::Reflow(nsPresContext* aPresContext,
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsFieldSetFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_WARNING_ASSERTION(aReflowInput.ComputedISize() != NS_UNCONSTRAINEDSIZE,
"Should have a precomputed inline-size!");
diff --git a/layout/forms/nsHTMLButtonControlFrame.cpp b/layout/forms/nsHTMLButtonControlFrame.cpp
index cb24ccbfb9..5201e420e2 100644
--- a/layout/forms/nsHTMLButtonControlFrame.cpp
+++ b/layout/forms/nsHTMLButtonControlFrame.cpp
@@ -51,6 +51,7 @@ void nsHTMLButtonControlFrame::Init(nsIContent* aContent,
}
NS_QUERYFRAME_HEAD(nsHTMLButtonControlFrame)
+ NS_QUERYFRAME_ENTRY(nsHTMLButtonControlFrame)
NS_QUERYFRAME_ENTRY(nsIFormControlFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
@@ -238,29 +239,21 @@ void nsHTMLButtonControlFrame::BuildDisplayList(
}
nscoord nsHTMLButtonControlFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
if (Maybe<nscoord> containISize = ContainIntrinsicISize()) {
- result = *containISize;
- } else {
- nsIFrame* kid = mFrames.FirstChild();
- result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, kid,
- IntrinsicISizeType::MinISize);
+ return *containISize;
}
- return result;
+ nsIFrame* kid = mFrames.FirstChild();
+ return nsLayoutUtils::IntrinsicForContainer(aRenderingContext, kid,
+ IntrinsicISizeType::MinISize);
}
nscoord nsHTMLButtonControlFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
if (Maybe<nscoord> containISize = ContainIntrinsicISize()) {
- result = *containISize;
- } else {
- nsIFrame* kid = mFrames.FirstChild();
- result = nsLayoutUtils::IntrinsicForContainer(
- aRenderingContext, kid, IntrinsicISizeType::PrefISize);
+ return *containISize;
}
- return result;
+ nsIFrame* kid = mFrames.FirstChild();
+ return nsLayoutUtils::IntrinsicForContainer(aRenderingContext, kid,
+ IntrinsicISizeType::PrefISize);
}
void nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
@@ -269,7 +262,6 @@ void nsHTMLButtonControlFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsHTMLButtonControlFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// Reflow the child
diff --git a/layout/forms/nsImageControlFrame.cpp b/layout/forms/nsImageControlFrame.cpp
index 17e3893a2f..8207a427f1 100644
--- a/layout/forms/nsImageControlFrame.cpp
+++ b/layout/forms/nsImageControlFrame.cpp
@@ -97,7 +97,6 @@ void nsImageControlFrame::Reflow(nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
DO_GLOBAL_REFLOW_COUNT("nsImageControlFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
return nsImageFrame::Reflow(aPresContext, aDesiredSize, aReflowInput,
aStatus);
diff --git a/layout/forms/nsListControlFrame.cpp b/layout/forms/nsListControlFrame.cpp
index 44ce9fde13..3020e99888 100644
--- a/layout/forms/nsListControlFrame.cpp
+++ b/layout/forms/nsListControlFrame.cpp
@@ -230,34 +230,30 @@ nscoord nsListControlFrame::CalcBSizeOfARow() {
}
nscoord nsListControlFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
-
// Always add scrollbar inline sizes to the pref-inline-size of the
// scrolled content. Combobox frames depend on this happening in the
// dropdown, and standalone listboxes are overflow:scroll so they need
// it too.
WritingMode wm = GetWritingMode();
Maybe<nscoord> containISize = ContainIntrinsicISize();
- result = containISize ? *containISize
- : GetScrolledFrame()->GetPrefISize(aRenderingContext);
+ nscoord result = containISize
+ ? *containISize
+ : GetScrolledFrame()->GetPrefISize(aRenderingContext);
LogicalMargin scrollbarSize(wm, GetDesiredScrollbarSizes());
result = NSCoordSaturatingAdd(result, scrollbarSize.IStartEnd(wm));
return result;
}
nscoord nsListControlFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
-
// Always add scrollbar inline sizes to the min-inline-size of the
// scrolled content. Combobox frames depend on this happening in the
// dropdown, and standalone listboxes are overflow:scroll so they need
// it too.
WritingMode wm = GetWritingMode();
Maybe<nscoord> containISize = ContainIntrinsicISize();
- result = containISize ? *containISize
- : GetScrolledFrame()->GetMinISize(aRenderingContext);
+ nscoord result = containISize
+ ? *containISize
+ : GetScrolledFrame()->GetMinISize(aRenderingContext);
LogicalMargin scrollbarSize(wm, GetDesiredScrollbarSizes());
result += scrollbarSize.IStartEnd(wm);
diff --git a/layout/forms/nsMeterFrame.cpp b/layout/forms/nsMeterFrame.cpp
index a72a6816d5..31ef52a000 100644
--- a/layout/forms/nsMeterFrame.cpp
+++ b/layout/forms/nsMeterFrame.cpp
@@ -82,7 +82,6 @@ void nsMeterFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsMeterFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_ASSERTION(mBarDiv, "Meter bar div must exist!");
@@ -93,13 +92,19 @@ void nsMeterFrame::Reflow(nsPresContext* aPresContext,
nsIFrame* barFrame = mBarDiv->GetPrimaryFrame();
NS_ASSERTION(barFrame, "The meter frame should have a child with a frame!");
- ReflowBarFrame(barFrame, aPresContext, aReflowInput, aStatus);
-
const auto wm = aReflowInput.GetWritingMode();
- aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
-
+ const auto contentBoxSize = aReflowInput.ComputedSizeWithBSizeFallback([&] {
+ nscoord em = OneEmInAppUnits();
+ return ResolvedOrientationIsVertical() == wm.IsVertical() ? em : 5 * em;
+ });
+ aDesiredSize.SetSize(
+ wm,
+ contentBoxSize + aReflowInput.ComputedLogicalBorderPadding(wm).Size(wm));
aDesiredSize.SetOverflowAreasToDesiredBounds();
+
+ ReflowBarFrame(barFrame, aPresContext, aReflowInput, contentBoxSize, aStatus);
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, barFrame);
+
FinishAndStoreOverflow(&aDesiredSize);
aStatus.Reset(); // This type of frame can't be split.
@@ -108,14 +113,19 @@ void nsMeterFrame::Reflow(nsPresContext* aPresContext,
void nsMeterFrame::ReflowBarFrame(nsIFrame* aBarFrame,
nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
+ const LogicalSize& aParentContentBoxSize,
nsReflowStatus& aStatus) {
bool vertical = ResolvedOrientationIsVertical();
- WritingMode wm = aBarFrame->GetWritingMode();
- LogicalSize availSize = aReflowInput.ComputedSize(wm);
+ const WritingMode wm = aBarFrame->GetWritingMode();
+ const LogicalSize parentSizeInChildWM =
+ aParentContentBoxSize.ConvertTo(wm, aReflowInput.GetWritingMode());
+ const nsSize parentPhysicalSize = parentSizeInChildWM.GetPhysicalSize(wm);
+ LogicalSize availSize = parentSizeInChildWM;
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
- ReflowInput reflowInput(aPresContext, aReflowInput, aBarFrame, availSize);
+ ReflowInput reflowInput(aPresContext, aReflowInput, aBarFrame, availSize,
+ Some(parentSizeInChildWM));
nscoord size =
- vertical ? aReflowInput.ComputedHeight() : aReflowInput.ComputedWidth();
+ vertical ? parentPhysicalSize.Height() : parentPhysicalSize.Width();
nscoord xoffset = aReflowInput.ComputedPhysicalBorderPadding().left;
nscoord yoffset = aReflowInput.ComputedPhysicalBorderPadding().top;
@@ -123,14 +133,13 @@ void nsMeterFrame::ReflowBarFrame(nsIFrame* aBarFrame,
size = NSToCoordRound(size * meterElement->Position());
if (!vertical && wm.IsPhysicalRTL()) {
- xoffset += aReflowInput.ComputedWidth() - size;
+ xoffset += parentPhysicalSize.Width() - size;
}
// The bar position is *always* constrained.
if (vertical) {
// We want the bar to begin at the bottom.
- yoffset += aReflowInput.ComputedHeight() - size;
-
+ yoffset += parentPhysicalSize.Height() - size;
size -= reflowInput.ComputedPhysicalMargin().TopBottom() +
reflowInput.ComputedPhysicalBorderPadding().TopBottom();
size = std::max(size, 0);
@@ -169,39 +178,12 @@ nsresult nsMeterFrame::AttributeChanged(int32_t aNameSpaceID,
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
}
-LogicalSize nsMeterFrame::ComputeAutoSize(
- gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
- nscoord aAvailableISize, const LogicalSize& aMargin,
- const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
- ComputeSizeFlags aFlags) {
- RefPtr<nsFontMetrics> fontMet =
- nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
-
- const WritingMode wm = GetWritingMode();
- LogicalSize autoSize(wm);
- autoSize.BSize(wm) = autoSize.ISize(wm) =
- fontMet->Font().size.ToAppUnits(); // 1em
-
- if (ResolvedOrientationIsVertical() == wm.IsVertical()) {
- autoSize.ISize(wm) *= 5; // 5em
- } else {
- autoSize.BSize(wm) *= 5; // 5em
- }
-
- return autoSize.ConvertTo(aWM, wm);
-}
-
nscoord nsMeterFrame::GetMinISize(gfxContext* aRenderingContext) {
- RefPtr<nsFontMetrics> fontMet =
- nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
-
- nscoord minISize = fontMet->Font().size.ToAppUnits(); // 1em
-
+ nscoord minISize = OneEmInAppUnits();
if (ResolvedOrientationIsVertical() == GetWritingMode().IsVertical()) {
// The orientation is inline
- minISize *= 5; // 5em
+ minISize *= 5;
}
-
return minISize;
}
diff --git a/layout/forms/nsMeterFrame.h b/layout/forms/nsMeterFrame.h
index 4aa82c1384..7a15878beb 100644
--- a/layout/forms/nsMeterFrame.h
+++ b/layout/forms/nsMeterFrame.h
@@ -7,17 +7,15 @@
#ifndef nsMeterFrame_h___
#define nsMeterFrame_h___
-#include "mozilla/Attributes.h"
#include "nsContainerFrame.h"
#include "nsIAnonymousContentCreator.h"
#include "nsCOMPtr.h"
-#include "nsCSSPseudoElements.h"
class nsMeterFrame final : public nsContainerFrame,
public nsIAnonymousContentCreator
{
- typedef mozilla::dom::Element Element;
+ using Element = mozilla::dom::Element;
public:
NS_DECL_QUERYFRAME
@@ -27,36 +25,25 @@ class nsMeterFrame final : public nsContainerFrame,
virtual ~nsMeterFrame();
void Destroy(DestroyContext&) override;
-
- virtual void Reflow(nsPresContext* aCX, ReflowOutput& aDesiredSize,
- const ReflowInput& aReflowInput,
- nsReflowStatus& aStatus) override;
+ void Reflow(nsPresContext*, ReflowOutput&, const ReflowInput&,
+ nsReflowStatus&) override;
#ifdef DEBUG_FRAME_DUMP
- virtual nsresult GetFrameName(nsAString& aResult) const override {
+ nsresult GetFrameName(nsAString& aResult) const override {
return MakeFrameName(u"Meter"_ns, aResult);
}
#endif
// nsIAnonymousContentCreator
- virtual nsresult CreateAnonymousContent(
- nsTArray<ContentInfo>& aElements) override;
- virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
- uint32_t aFilter) override;
+ nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
+ void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
+ uint32_t aFilter) override;
- virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
- int32_t aModType) override;
+ nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
+ int32_t aModType) override;
- virtual mozilla::LogicalSize ComputeAutoSize(
- gfxContext* aRenderingContext, mozilla::WritingMode aWM,
- const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
- const mozilla::LogicalSize& aMargin,
- const mozilla::LogicalSize& aBorderPadding,
- const mozilla::StyleSizeOverrides& aSizeOverrides,
- mozilla::ComputeSizeFlags aFlags) override;
-
- virtual nscoord GetMinISize(gfxContext* aRenderingContext) override;
- virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override;
+ nscoord GetMinISize(gfxContext* aRenderingContext) override;
+ nscoord GetPrefISize(gfxContext* aRenderingContext) override;
/**
* Returns whether the frame and its child should use the native style.
@@ -66,7 +53,9 @@ class nsMeterFrame final : public nsContainerFrame,
protected:
// Helper function which reflow the anonymous div frame.
void ReflowBarFrame(nsIFrame* aBarFrame, nsPresContext* aPresContext,
- const ReflowInput& aReflowInput, nsReflowStatus& aStatus);
+ const ReflowInput& aReflowInput,
+ const mozilla::LogicalSize& aParentContentBoxSize,
+ nsReflowStatus& aStatus);
/**
* The div used to show the meter bar.
* @see nsMeterFrame::CreateAnonymousContent
diff --git a/layout/forms/nsProgressFrame.cpp b/layout/forms/nsProgressFrame.cpp
index 2f0d727473..1cf6bf1447 100644
--- a/layout/forms/nsProgressFrame.cpp
+++ b/layout/forms/nsProgressFrame.cpp
@@ -86,7 +86,6 @@ void nsProgressFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsProgressFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_ASSERTION(mBarDiv, "Progress bar div must exist!");
@@ -99,11 +98,18 @@ void nsProgressFrame::Reflow(nsPresContext* aPresContext,
"need to call RegUnregAccessKey only for the first.");
const auto wm = aReflowInput.GetWritingMode();
- aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
+ const auto contentBoxSize = aReflowInput.ComputedSizeWithBSizeFallback([&] {
+ nscoord em = OneEmInAppUnits();
+ return ResolvedOrientationIsVertical() == wm.IsVertical() ? em : 10 * em;
+ });
+ aDesiredSize.SetSize(
+ wm,
+ contentBoxSize + aReflowInput.ComputedLogicalBorderPadding(wm).Size(wm));
aDesiredSize.SetOverflowAreasToDesiredBounds();
- for (auto childFrame : PrincipalChildList()) {
- ReflowChildFrame(childFrame, aPresContext, aReflowInput, aStatus);
+ for (nsIFrame* childFrame : PrincipalChildList()) {
+ ReflowChildFrame(childFrame, aPresContext, aReflowInput, contentBoxSize,
+ aStatus);
ConsiderChildOverflow(aDesiredSize.mOverflowAreas, childFrame);
}
@@ -115,14 +121,19 @@ void nsProgressFrame::Reflow(nsPresContext* aPresContext,
void nsProgressFrame::ReflowChildFrame(nsIFrame* aChild,
nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
+ const LogicalSize& aParentContentBoxSize,
nsReflowStatus& aStatus) {
bool vertical = ResolvedOrientationIsVertical();
- WritingMode wm = aChild->GetWritingMode();
- LogicalSize availSize = aReflowInput.ComputedSize(wm);
+ const WritingMode wm = aChild->GetWritingMode();
+ const LogicalSize parentSizeInChildWM =
+ aParentContentBoxSize.ConvertTo(wm, aReflowInput.GetWritingMode());
+ const nsSize parentPhysicalSize = parentSizeInChildWM.GetPhysicalSize(wm);
+ LogicalSize availSize = parentSizeInChildWM;
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
- ReflowInput reflowInput(aPresContext, aReflowInput, aChild, availSize);
+ ReflowInput reflowInput(aPresContext, aReflowInput, aChild, availSize,
+ Some(parentSizeInChildWM));
nscoord size =
- vertical ? aReflowInput.ComputedHeight() : aReflowInput.ComputedWidth();
+ vertical ? parentPhysicalSize.Height() : parentPhysicalSize.Width();
nscoord xoffset = aReflowInput.ComputedPhysicalBorderPadding().left;
nscoord yoffset = aReflowInput.ComputedPhysicalBorderPadding().top;
@@ -135,7 +146,7 @@ void nsProgressFrame::ReflowChildFrame(nsIFrame* aChild,
}
if (!vertical && wm.IsPhysicalRTL()) {
- xoffset += aReflowInput.ComputedWidth() - size;
+ xoffset += parentPhysicalSize.Width() - size;
}
// The bar size is fixed in these cases:
@@ -148,8 +159,7 @@ void nsProgressFrame::ReflowChildFrame(nsIFrame* aChild,
if (position != -1 || ShouldUseNativeStyle()) {
if (vertical) {
// We want the bar to begin at the bottom.
- yoffset += aReflowInput.ComputedHeight() - size;
-
+ yoffset += parentPhysicalSize.Height() - size;
size -= reflowInput.ComputedPhysicalMargin().TopBottom() +
reflowInput.ComputedPhysicalBorderPadding().TopBottom();
size = std::max(size, 0);
@@ -161,10 +171,12 @@ void nsProgressFrame::ReflowChildFrame(nsIFrame* aChild,
reflowInput.SetComputedWidth(size);
}
} else if (vertical) {
- // For vertical progress bars, we need to position the bar specificly when
+ // For vertical progress bars, we need to position the bar specifically when
// the width isn't constrained (position == -1 and !ShouldUseNativeStyle())
- // because aReflowInput.ComputedHeight() - size == 0.
- yoffset += aReflowInput.ComputedHeight() - reflowInput.ComputedHeight();
+ // because parentPhysiscalSize.Height() - size == 0.
+ // FIXME(emilio): This assumes that the bar's height is constrained, which
+ // seems like a wrong assumption?
+ yoffset += parentPhysicalSize.Height() - reflowInput.ComputedHeight();
}
xoffset += reflowInput.ComputedPhysicalMargin().left;
@@ -195,38 +207,11 @@ nsresult nsProgressFrame::AttributeChanged(int32_t aNameSpaceID,
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
}
-LogicalSize nsProgressFrame::ComputeAutoSize(
- gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
- nscoord aAvailableISize, const LogicalSize& aMargin,
- const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
- ComputeSizeFlags aFlags) {
- const WritingMode wm = GetWritingMode();
- LogicalSize autoSize(wm);
- autoSize.BSize(wm) = autoSize.ISize(wm) =
- StyleFont()
- ->mFont.size.ScaledBy(nsLayoutUtils::FontSizeInflationFor(this))
- .ToAppUnits(); // 1em
-
- if (ResolvedOrientationIsVertical() == wm.IsVertical()) {
- autoSize.ISize(wm) *= 10; // 10em
- } else {
- autoSize.BSize(wm) *= 10; // 10em
- }
-
- return autoSize.ConvertTo(aWM, wm);
-}
-
nscoord nsProgressFrame::GetMinISize(gfxContext* aRenderingContext) {
- RefPtr<nsFontMetrics> fontMet =
- nsLayoutUtils::GetFontMetricsForFrame(this, 1.0f);
-
- nscoord minISize = fontMet->Font().size.ToAppUnits(); // 1em
-
+ nscoord minISize = OneEmInAppUnits();
if (ResolvedOrientationIsVertical() == GetWritingMode().IsVertical()) {
- // The orientation is inline
- minISize *= 10; // 10em
+ minISize *= 10;
}
-
return minISize;
}
diff --git a/layout/forms/nsProgressFrame.h b/layout/forms/nsProgressFrame.h
index 7d3618ee96..f8917ba4f2 100644
--- a/layout/forms/nsProgressFrame.h
+++ b/layout/forms/nsProgressFrame.h
@@ -18,8 +18,7 @@ enum class PseudoStyleType : uint8_t;
class nsProgressFrame final : public nsContainerFrame,
public nsIAnonymousContentCreator {
- typedef mozilla::PseudoStyleType PseudoStyleType;
- typedef mozilla::dom::Element Element;
+ using Element = mozilla::dom::Element;
public:
NS_DECL_QUERYFRAME
@@ -30,38 +29,28 @@ class nsProgressFrame final : public nsContainerFrame,
void Destroy(DestroyContext&) override;
- virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
- const nsDisplayListSet& aLists) override;
+ void BuildDisplayList(nsDisplayListBuilder* aBuilder,
+ const nsDisplayListSet& aLists) override;
- virtual void Reflow(nsPresContext* aCX, ReflowOutput& aDesiredSize,
- const ReflowInput& aReflowInput,
- nsReflowStatus& aStatus) override;
+ void Reflow(nsPresContext*, ReflowOutput&, const ReflowInput&,
+ nsReflowStatus&) override;
#ifdef DEBUG_FRAME_DUMP
- virtual nsresult GetFrameName(nsAString& aResult) const override {
+ nsresult GetFrameName(nsAString& aResult) const override {
return MakeFrameName(u"Progress"_ns, aResult);
}
#endif
// nsIAnonymousContentCreator
- virtual nsresult CreateAnonymousContent(
- nsTArray<ContentInfo>& aElements) override;
- virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
- uint32_t aFilter) override;
+ nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
+ void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
+ uint32_t aFilter) override;
- virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
- int32_t aModType) override;
+ nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
+ int32_t aModType) override;
- virtual mozilla::LogicalSize ComputeAutoSize(
- gfxContext* aRenderingContext, mozilla::WritingMode aWM,
- const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
- const mozilla::LogicalSize& aMargin,
- const mozilla::LogicalSize& aBorderPadding,
- const mozilla::StyleSizeOverrides& aSizeOverrides,
- mozilla::ComputeSizeFlags aFlags) override;
-
- virtual nscoord GetMinISize(gfxContext* aRenderingContext) override;
- virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override;
+ nscoord GetMinISize(gfxContext* aRenderingContext) override;
+ nscoord GetPrefISize(gfxContext* aRenderingContext) override;
/**
* Returns whether the frame and its child should use the native style.
@@ -72,6 +61,7 @@ class nsProgressFrame final : public nsContainerFrame,
// Helper function to reflow a child frame.
void ReflowChildFrame(nsIFrame* aChild, nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
+ const mozilla::LogicalSize& aParentContentBoxSize,
nsReflowStatus& aStatus);
/**
diff --git a/layout/forms/nsRangeFrame.cpp b/layout/forms/nsRangeFrame.cpp
index 2cccff715a..3238d0372f 100644
--- a/layout/forms/nsRangeFrame.cpp
+++ b/layout/forms/nsRangeFrame.cpp
@@ -155,7 +155,6 @@ void nsRangeFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsRangeFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_ASSERTION(mTrackDiv, "::-moz-range-track div must exist!");
@@ -166,35 +165,17 @@ void nsRangeFrame::Reflow(nsPresContext* aPresContext,
"need to call RegUnregAccessKey only for the first.");
WritingMode wm = aReflowInput.GetWritingMode();
- nscoord computedBSize = aReflowInput.ComputedBSize();
- if (computedBSize == NS_UNCONSTRAINEDSIZE) {
- computedBSize = 0;
- }
- const auto borderPadding = aReflowInput.ComputedLogicalBorderPadding(wm);
- LogicalSize finalSize(
- wm, aReflowInput.ComputedISize() + borderPadding.IStartEnd(wm),
- computedBSize + borderPadding.BStartEnd(wm));
- aDesiredSize.SetSize(wm, finalSize);
-
- ReflowAnonymousContent(aPresContext, aDesiredSize, aReflowInput);
-
+ const auto contentBoxSize = aReflowInput.ComputedSizeWithBSizeFallback([&] {
+ return IsInlineOriented() ? AutoCrossSize()
+ : OneEmInAppUnits() * MAIN_AXIS_EM_SIZE;
+ });
+ aDesiredSize.SetSize(
+ wm,
+ contentBoxSize + aReflowInput.ComputedLogicalBorderPadding(wm).Size(wm));
aDesiredSize.SetOverflowAreasToDesiredBounds();
- nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame();
- if (trackFrame) {
- ConsiderChildOverflow(aDesiredSize.mOverflowAreas, trackFrame);
- }
-
- nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame();
- if (rangeProgressFrame) {
- ConsiderChildOverflow(aDesiredSize.mOverflowAreas, rangeProgressFrame);
- }
-
- nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();
- if (thumbFrame) {
- ConsiderChildOverflow(aDesiredSize.mOverflowAreas, thumbFrame);
- }
-
+ ReflowAnonymousContent(aPresContext, aDesiredSize, contentBoxSize,
+ aReflowInput);
FinishAndStoreOverflow(&aDesiredSize);
MOZ_ASSERT(aStatus.IsEmpty(), "This type of frame can't be split.");
@@ -202,111 +183,71 @@ void nsRangeFrame::Reflow(nsPresContext* aPresContext,
void nsRangeFrame::ReflowAnonymousContent(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
+ const LogicalSize& aContentBoxSize,
const ReflowInput& aReflowInput) {
+ const auto parentWM = aReflowInput.GetWritingMode();
// The width/height of our content box, which is the available width/height
- // for our anonymous content:
- nscoord rangeFrameContentBoxWidth = aReflowInput.ComputedWidth();
- nscoord rangeFrameContentBoxHeight = aReflowInput.ComputedHeight();
- if (rangeFrameContentBoxHeight == NS_UNCONSTRAINEDSIZE) {
- rangeFrameContentBoxHeight = 0;
- }
-
- nsIFrame* trackFrame = mTrackDiv->GetPrimaryFrame();
-
- if (trackFrame) { // display:none?
-
- // Position the track:
- // The idea here is that we allow content authors to style the width,
- // height, border and padding of the track, but we ignore margin and
- // positioning properties and do the positioning ourself to keep the center
- // of the track's border box on the center of the nsRangeFrame's content
- // box.
-
- WritingMode wm = trackFrame->GetWritingMode();
- LogicalSize availSize = aReflowInput.ComputedSize(wm);
- availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
- ReflowInput trackReflowInput(aPresContext, aReflowInput, trackFrame,
- availSize);
-
- // Find the x/y position of the track frame such that it will be positioned
- // as described above. These coordinates are with respect to the
- // nsRangeFrame's border-box.
- nscoord trackX = rangeFrameContentBoxWidth / 2;
- nscoord trackY = rangeFrameContentBoxHeight / 2;
-
- // Account for the track's border and padding (we ignore its margin):
- trackX -= trackReflowInput.ComputedPhysicalBorderPadding().left +
- trackReflowInput.ComputedWidth() / 2;
- trackY -= trackReflowInput.ComputedPhysicalBorderPadding().top +
- trackReflowInput.ComputedHeight() / 2;
-
- // Make relative to our border box instead of our content box:
- trackX += aReflowInput.ComputedPhysicalBorderPadding().left;
- trackY += aReflowInput.ComputedPhysicalBorderPadding().top;
-
- nsReflowStatus frameStatus;
- ReflowOutput trackDesiredSize(aReflowInput);
- ReflowChild(trackFrame, aPresContext, trackDesiredSize, trackReflowInput,
- trackX, trackY, ReflowChildFlags::Default, frameStatus);
- MOZ_ASSERT(
- frameStatus.IsFullyComplete(),
- "We gave our child unconstrained height, so it should be complete");
- FinishReflowChild(trackFrame, aPresContext, trackDesiredSize,
- &trackReflowInput, trackX, trackY,
- ReflowChildFlags::Default);
- }
-
- nsIFrame* thumbFrame = mThumbDiv->GetPrimaryFrame();
-
- if (thumbFrame) { // display:none?
- WritingMode wm = thumbFrame->GetWritingMode();
- LogicalSize availSize = aReflowInput.ComputedSize(wm);
- availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
- ReflowInput thumbReflowInput(aPresContext, aReflowInput, thumbFrame,
- availSize);
-
- // Where we position the thumb depends on its size, so we first reflow
- // the thumb at {0,0} to obtain its size, then position it afterwards.
-
- nsReflowStatus frameStatus;
- ReflowOutput thumbDesiredSize(aReflowInput);
- ReflowChild(thumbFrame, aPresContext, thumbDesiredSize, thumbReflowInput, 0,
- 0, ReflowChildFlags::Default, frameStatus);
- MOZ_ASSERT(
- frameStatus.IsFullyComplete(),
- "We gave our child unconstrained height, so it should be complete");
- FinishReflowChild(thumbFrame, aPresContext, thumbDesiredSize,
- &thumbReflowInput, 0, 0, ReflowChildFlags::Default);
- DoUpdateThumbPosition(thumbFrame,
- nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
- }
-
- nsIFrame* rangeProgressFrame = mProgressDiv->GetPrimaryFrame();
-
- if (rangeProgressFrame) { // display:none?
- WritingMode wm = rangeProgressFrame->GetWritingMode();
- LogicalSize availSize = aReflowInput.ComputedSize(wm);
+ // for our anonymous content.
+ const nsSize rangeFrameContentBoxSize =
+ aContentBoxSize.GetPhysicalSize(parentWM);
+ for (auto* div : {mTrackDiv.get(), mThumbDiv.get(), mProgressDiv.get()}) {
+ nsIFrame* child = div->GetPrimaryFrame();
+ if (!child) {
+ continue;
+ }
+ const WritingMode wm = child->GetWritingMode();
+ const LogicalSize parentSizeInChildWM =
+ aContentBoxSize.ConvertTo(wm, parentWM);
+ LogicalSize availSize = parentSizeInChildWM;
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
- ReflowInput progressReflowInput(aPresContext, aReflowInput,
- rangeProgressFrame, availSize);
-
- // We first reflow the range-progress frame at {0,0} to obtain its
- // unadjusted dimensions, then we adjust it to so that the appropriate edge
- // ends at the thumb.
+ ReflowInput childReflowInput(aPresContext, aReflowInput, child, availSize,
+ Some(parentSizeInChildWM));
+
+ const nsPoint pos = [&] {
+ if (div != mTrackDiv) {
+ // Where we position the thumb and range-progress depends on its size,
+ // so we first reflow them at {0,0} to obtain the size, then position
+ // them afterwards.
+ return nsPoint();
+ }
+ // Find the x/y position of the track. The idea here is that we allow
+ // content authors to style the width, height, border and padding of the
+ // track, but we ignore margin and positioning properties and do the
+ // positioning ourself to keep the center of the track's border box on the
+ // center of the nsRangeFrame's content. These coordinates are with
+ // respect to the nsRangeFrame's border-box.
+ nscoord trackX = rangeFrameContentBoxSize.Width() / 2;
+ nscoord trackY = rangeFrameContentBoxSize.Height() / 2;
+
+ // Account for the track's border and padding (we ignore its margin):
+ // FIXME(emilio): Assumes the track height is constrained, which might not
+ // be true if authors override it.
+ trackX -= childReflowInput.ComputedPhysicalBorderPadding().left +
+ childReflowInput.ComputedWidth() / 2;
+ trackY -= childReflowInput.ComputedPhysicalBorderPadding().top +
+ childReflowInput.ComputedHeight() / 2;
+
+ // Make relative to our border box instead of our content box:
+ trackX += aReflowInput.ComputedPhysicalBorderPadding().left;
+ trackY += aReflowInput.ComputedPhysicalBorderPadding().top;
+ return nsPoint(trackX, trackY);
+ }();
nsReflowStatus frameStatus;
- ReflowOutput progressDesiredSize(aReflowInput);
- ReflowChild(rangeProgressFrame, aPresContext, progressDesiredSize,
- progressReflowInput, 0, 0, ReflowChildFlags::Default,
- frameStatus);
+ ReflowOutput childDesiredSize(aReflowInput);
+ ReflowChild(child, aPresContext, childDesiredSize, childReflowInput, pos.x,
+ pos.y, ReflowChildFlags::Default, frameStatus);
MOZ_ASSERT(
frameStatus.IsFullyComplete(),
"We gave our child unconstrained height, so it should be complete");
- FinishReflowChild(rangeProgressFrame, aPresContext, progressDesiredSize,
- &progressReflowInput, 0, 0, ReflowChildFlags::Default);
- DoUpdateRangeProgressFrame(
- rangeProgressFrame,
- nsSize(aDesiredSize.Width(), aDesiredSize.Height()));
+ FinishReflowChild(child, aPresContext, childDesiredSize, &childReflowInput,
+ pos.x, pos.y, ReflowChildFlags::Default);
+ if (div == mThumbDiv) {
+ DoUpdateThumbPosition(child, rangeFrameContentBoxSize);
+ } else if (div == mProgressDiv) {
+ DoUpdateRangeProgressFrame(child, rangeFrameContentBoxSize);
+ }
+ ConsiderChildOverflow(aDesiredSize.mOverflowAreas, child);
}
}
@@ -388,7 +329,7 @@ Decimal nsRangeFrame::GetValueAtEventPoint(WidgetGUIEvent* aEvent) {
->GetValueAsDecimal();
}
- nsRect rangeContentRect = GetContentRectRelativeToSelf();
+ const nsRect rangeContentRect = GetContentRectRelativeToSelf();
nsSize thumbSize;
if (IsThemed()) {
@@ -455,11 +396,12 @@ void nsRangeFrame::UpdateForValueChange() {
if (!rangeProgressFrame && !thumbFrame) {
return; // diplay:none?
}
+ const nsSize contentBoxSize = GetContentRect().Size();
if (rangeProgressFrame) {
- DoUpdateRangeProgressFrame(rangeProgressFrame, GetSize());
+ DoUpdateRangeProgressFrame(rangeProgressFrame, contentBoxSize);
}
if (thumbFrame) {
- DoUpdateThumbPosition(thumbFrame, GetSize());
+ DoUpdateThumbPosition(thumbFrame, contentBoxSize);
}
if (IsThemed()) {
// We don't know the exact dimensions or location of the thumb when native
@@ -539,7 +481,7 @@ mozilla::dom::HTMLInputElement& nsRangeFrame::InputElement() const {
}
void nsRangeFrame::DoUpdateThumbPosition(nsIFrame* aThumbFrame,
- const nsSize& aRangeSize) {
+ const nsSize& aRangeContentBoxSize) {
MOZ_ASSERT(aThumbFrame);
// The idea here is that we want to position the thumb so that the center
@@ -553,29 +495,26 @@ void nsRangeFrame::DoUpdateThumbPosition(nsIFrame* aThumbFrame,
nsMargin borderAndPadding = GetUsedBorderAndPadding();
nsPoint newPosition(borderAndPadding.left, borderAndPadding.top);
- nsSize rangeContentBoxSize(aRangeSize);
- rangeContentBoxSize.width -= borderAndPadding.LeftRight();
- rangeContentBoxSize.height -= borderAndPadding.TopBottom();
-
nsSize thumbSize = aThumbFrame->GetSize();
double fraction = GetValueAsFractionOfRange();
MOZ_ASSERT(fraction >= 0.0 && fraction <= 1.0);
if (IsHorizontal()) {
- if (thumbSize.width < rangeContentBoxSize.width) {
- nscoord traversableDistance = rangeContentBoxSize.width - thumbSize.width;
+ if (thumbSize.width < aRangeContentBoxSize.width) {
+ nscoord traversableDistance =
+ aRangeContentBoxSize.width - thumbSize.width;
if (IsRightToLeft()) {
newPosition.x += NSToCoordRound((1.0 - fraction) * traversableDistance);
} else {
newPosition.x += NSToCoordRound(fraction * traversableDistance);
}
- newPosition.y += (rangeContentBoxSize.height - thumbSize.height) / 2;
+ newPosition.y += (aRangeContentBoxSize.height - thumbSize.height) / 2;
}
} else {
- if (thumbSize.height < rangeContentBoxSize.height) {
+ if (thumbSize.height < aRangeContentBoxSize.height) {
nscoord traversableDistance =
- rangeContentBoxSize.height - thumbSize.height;
- newPosition.x += (rangeContentBoxSize.width - thumbSize.width) / 2;
+ aRangeContentBoxSize.height - thumbSize.height;
+ newPosition.x += (aRangeContentBoxSize.width - thumbSize.width) / 2;
if (IsUpwards()) {
newPosition.y += NSToCoordRound((1.0 - fraction) * traversableDistance);
} else {
@@ -586,9 +525,9 @@ void nsRangeFrame::DoUpdateThumbPosition(nsIFrame* aThumbFrame,
aThumbFrame->SetPosition(newPosition);
}
-void nsRangeFrame::DoUpdateRangeProgressFrame(nsIFrame* aRangeProgressFrame,
- const nsSize& aRangeSize) {
- MOZ_ASSERT(aRangeProgressFrame);
+void nsRangeFrame::DoUpdateRangeProgressFrame(
+ nsIFrame* aProgressFrame, const nsSize& aRangeContentBoxSize) {
+ MOZ_ASSERT(aProgressFrame);
// The idea here is that we want to position the ::-moz-range-progress
// pseudo-element so that the center line running along its length is on the
@@ -598,35 +537,30 @@ void nsRangeFrame::DoUpdateRangeProgressFrame(nsIFrame* aRangeProgressFrame,
// nsRangeFrame's content box, and we size the progress element's border-box
// to have a length of GetValueAsFractionOfRange() times the nsRangeFrame's
// content-box size.
-
nsMargin borderAndPadding = GetUsedBorderAndPadding();
- nsSize progSize = aRangeProgressFrame->GetSize();
+ nsSize progSize = aProgressFrame->GetSize();
nsRect progRect(borderAndPadding.left, borderAndPadding.top, progSize.width,
progSize.height);
- nsSize rangeContentBoxSize(aRangeSize);
- rangeContentBoxSize.width -= borderAndPadding.LeftRight();
- rangeContentBoxSize.height -= borderAndPadding.TopBottom();
-
double fraction = GetValueAsFractionOfRange();
MOZ_ASSERT(fraction >= 0.0 && fraction <= 1.0);
if (IsHorizontal()) {
- nscoord progLength = NSToCoordRound(fraction * rangeContentBoxSize.width);
+ nscoord progLength = NSToCoordRound(fraction * aRangeContentBoxSize.width);
if (IsRightToLeft()) {
- progRect.x += rangeContentBoxSize.width - progLength;
+ progRect.x += aRangeContentBoxSize.width - progLength;
}
- progRect.y += (rangeContentBoxSize.height - progSize.height) / 2;
+ progRect.y += (aRangeContentBoxSize.height - progSize.height) / 2;
progRect.width = progLength;
} else {
- nscoord progLength = NSToCoordRound(fraction * rangeContentBoxSize.height);
- progRect.x += (rangeContentBoxSize.width - progSize.width) / 2;
+ nscoord progLength = NSToCoordRound(fraction * aRangeContentBoxSize.height);
+ progRect.x += (aRangeContentBoxSize.width - progSize.width) / 2;
if (IsUpwards()) {
- progRect.y += rangeContentBoxSize.height - progLength;
+ progRect.y += aRangeContentBoxSize.height - progLength;
}
progRect.height = progLength;
}
- aRangeProgressFrame->SetRect(progRect);
+ aProgressFrame->SetRect(progRect);
}
nsresult nsRangeFrame::AttributeChanged(int32_t aNameSpaceID,
@@ -677,7 +611,7 @@ nsresult nsRangeFrame::AttributeChanged(int32_t aNameSpaceID,
return nsContainerFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
}
-nscoord nsRangeFrame::AutoCrossSize(Length aEm) {
+nscoord nsRangeFrame::AutoCrossSize() {
nscoord minCrossSize(0);
if (IsThemed()) {
nsPresContext* pc = PresContext();
@@ -686,33 +620,8 @@ nscoord nsRangeFrame::AutoCrossSize(Length aEm) {
minCrossSize =
pc->DevPixelsToAppUnits(IsHorizontal() ? size.height : size.width);
}
- return std::max(minCrossSize, aEm.ScaledBy(CROSS_AXIS_EM_SIZE).ToAppUnits());
-}
-
-static mozilla::Length OneEm(nsRangeFrame* aFrame) {
- return aFrame->StyleFont()->mFont.size.ScaledBy(
- nsLayoutUtils::FontSizeInflationFor(aFrame));
-}
-
-LogicalSize nsRangeFrame::ComputeAutoSize(
- gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
- nscoord aAvailableISize, const LogicalSize& aMargin,
- const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
- ComputeSizeFlags aFlags) {
- bool isInlineOriented = IsInlineOriented();
- auto em = OneEm(this);
-
- const WritingMode wm = GetWritingMode();
- LogicalSize autoSize(wm);
- if (isInlineOriented) {
- autoSize.ISize(wm) = em.ScaledBy(MAIN_AXIS_EM_SIZE).ToAppUnits();
- autoSize.BSize(wm) = AutoCrossSize(em);
- } else {
- autoSize.ISize(wm) = AutoCrossSize(em);
- autoSize.BSize(wm) = em.ScaledBy(MAIN_AXIS_EM_SIZE).ToAppUnits();
- }
-
- return autoSize.ConvertTo(aWM, wm);
+ return std::max(minCrossSize,
+ NSToCoordRound(OneEmInAppUnits() * CROSS_AXIS_EM_SIZE));
}
nscoord nsRangeFrame::GetMinISize(gfxContext* aRenderingContext) {
@@ -728,11 +637,10 @@ nscoord nsRangeFrame::GetMinISize(gfxContext* aRenderingContext) {
}
nscoord nsRangeFrame::GetPrefISize(gfxContext* aRenderingContext) {
- auto em = OneEm(this);
if (IsInlineOriented()) {
- return em.ScaledBy(MAIN_AXIS_EM_SIZE).ToAppUnits();
+ return OneEmInAppUnits() * MAIN_AXIS_EM_SIZE;
}
- return AutoCrossSize(em);
+ return AutoCrossSize();
}
bool nsRangeFrame::IsHorizontal() const {
diff --git a/layout/forms/nsRangeFrame.h b/layout/forms/nsRangeFrame.h
index 4d2073aa50..206103ea44 100644
--- a/layout/forms/nsRangeFrame.h
+++ b/layout/forms/nsRangeFrame.h
@@ -7,12 +7,10 @@
#ifndef nsRangeFrame_h___
#define nsRangeFrame_h___
-#include "mozilla/Attributes.h"
#include "mozilla/Decimal.h"
#include "mozilla/EventForwards.h"
#include "nsContainerFrame.h"
#include "nsIAnonymousContentCreator.h"
-#include "nsIDOMEventListener.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
@@ -40,8 +38,7 @@ class nsRangeFrame final : public nsContainerFrame,
explicit nsRangeFrame(ComputedStyle* aStyle, nsPresContext* aPresContext);
virtual ~nsRangeFrame();
- typedef mozilla::PseudoStyleType PseudoStyleType;
- typedef mozilla::dom::Element Element;
+ using Element = mozilla::dom::Element;
public:
NS_DECL_QUERYFRAME
@@ -53,39 +50,30 @@ class nsRangeFrame final : public nsContainerFrame,
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists) override;
- virtual void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
- const ReflowInput& aReflowInput,
- nsReflowStatus& aStatus) override;
+ void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
+ const ReflowInput& aReflowInput,
+ nsReflowStatus& aStatus) override;
#ifdef DEBUG_FRAME_DUMP
- virtual nsresult GetFrameName(nsAString& aResult) const override {
+ nsresult GetFrameName(nsAString& aResult) const override {
return MakeFrameName(u"Range"_ns, aResult);
}
#endif
#ifdef ACCESSIBILITY
- virtual mozilla::a11y::AccType AccessibleType() override;
+ mozilla::a11y::AccType AccessibleType() override;
#endif
// nsIAnonymousContentCreator
- virtual nsresult CreateAnonymousContent(
- nsTArray<ContentInfo>& aElements) override;
- virtual void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
- uint32_t aFilter) override;
+ nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements) override;
+ void AppendAnonymousContentTo(nsTArray<nsIContent*>& aElements,
+ uint32_t aFilter) override;
- virtual nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
- int32_t aModType) override;
+ nsresult AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
+ int32_t aModType) override;
- mozilla::LogicalSize ComputeAutoSize(
- gfxContext* aRenderingContext, mozilla::WritingMode aWM,
- const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
- const mozilla::LogicalSize& aMargin,
- const mozilla::LogicalSize& aBorderPadding,
- const mozilla::StyleSizeOverrides& aSizeOverrides,
- mozilla::ComputeSizeFlags aFlags) override;
-
- virtual nscoord GetMinISize(gfxContext* aRenderingContext) override;
- virtual nscoord GetPrefISize(gfxContext* aRenderingContext) override;
+ nscoord GetMinISize(gfxContext* aRenderingContext) override;
+ nscoord GetPrefISize(gfxContext* aRenderingContext) override;
/**
* Returns true if the slider's thumb moves horizontally, or else false if it
@@ -117,8 +105,8 @@ class nsRangeFrame final : public nsContainerFrame,
bool IsUpwards() const {
MOZ_ASSERT(!IsHorizontal());
mozilla::WritingMode wm = GetWritingMode();
- return wm.GetBlockDir() == mozilla::WritingMode::eBlockTB ||
- wm.GetInlineDir() == mozilla::WritingMode::eInlineBTT;
+ return wm.GetBlockDir() == mozilla::WritingMode::BlockDir::TB ||
+ wm.GetInlineDir() == mozilla::WritingMode::InlineDir::BTT;
}
double GetMin() const;
@@ -171,17 +159,19 @@ class nsRangeFrame final : public nsContainerFrame,
private:
// Return our preferred size in the cross-axis (the axis perpendicular
// to the direction of movement of the thumb).
- nscoord AutoCrossSize(mozilla::Length aEm);
+ nscoord AutoCrossSize();
// Helper function which reflows the anonymous div frames.
void ReflowAnonymousContent(nsPresContext* aPresContext,
ReflowOutput& aDesiredSize,
+ const mozilla::LogicalSize& aContentBoxSize,
const ReflowInput& aReflowInput);
- void DoUpdateThumbPosition(nsIFrame* aThumbFrame, const nsSize& aRangeSize);
+ void DoUpdateThumbPosition(nsIFrame* aThumbFrame,
+ const nsSize& aRangeContentBoxSize);
void DoUpdateRangeProgressFrame(nsIFrame* aProgressFrame,
- const nsSize& aRangeSize);
+ const nsSize& aRangeContentBoxSize);
/**
* The div used to show the ::-moz-range-track pseudo-element.
diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp
index c51b94c56a..3c44038d89 100644
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -173,15 +173,14 @@ void nsTextControlFrame::Destroy(DestroyContext& aContext) {
nsContainerFrame::Destroy(aContext);
}
-LogicalSize nsTextControlFrame::CalcIntrinsicSize(
- gfxContext* aRenderingContext, WritingMode aWM,
- float aFontSizeInflation) const {
+LogicalSize nsTextControlFrame::CalcIntrinsicSize(gfxContext* aRenderingContext,
+ WritingMode aWM) const {
LogicalSize intrinsicSize(aWM);
+ const float inflation = nsLayoutUtils::FontSizeInflationFor(this);
RefPtr<nsFontMetrics> fontMet =
- nsLayoutUtils::GetFontMetricsForFrame(this, aFontSizeInflation);
- const nscoord lineHeight =
- ReflowInput::CalcLineHeight(*Style(), PresContext(), GetContent(),
- NS_UNCONSTRAINEDSIZE, aFontSizeInflation);
+ nsLayoutUtils::GetFontMetricsForFrame(this, inflation);
+ const nscoord lineHeight = ReflowInput::CalcLineHeight(
+ *Style(), PresContext(), GetContent(), NS_UNCONSTRAINEDSIZE, inflation);
// Use the larger of the font's "average" char width or the width of the
// zero glyph (if present) as the basis for resolving the size attribute.
const nscoord charWidth =
@@ -418,8 +417,10 @@ nsresult nsTextControlFrame::CreateAnonymousContent(
// background on the placeholder doesn't obscure the caret.
aElements.AppendElement(mRootNode);
- if (StaticPrefs::layout_forms_reveal_password_button_enabled() &&
- IsPasswordTextControl()) {
+ if ((StaticPrefs::layout_forms_reveal_password_button_enabled() ||
+ PresContext()->Document()->ChromeRulesEnabled()) &&
+ IsPasswordTextControl() &&
+ StyleDisplay()->EffectiveAppearance() != StyleAppearance::Textfield) {
mRevealButton =
MakeAnonElement(PseudoStyleType::mozReveal, nullptr, nsGkAtoms::button);
mRevealButton->SetAttr(kNameSpaceID_None, nsGkAtoms::aria_hidden,
@@ -554,58 +555,14 @@ void nsTextControlFrame::AppendAnonymousContentTo(
}
nscoord nsTextControlFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_PREF_INLINE_SIZE(this, result);
- float inflation = nsLayoutUtils::FontSizeInflationFor(this);
WritingMode wm = GetWritingMode();
- result = CalcIntrinsicSize(aRenderingContext, wm, inflation).ISize(wm);
- return result;
+ return CalcIntrinsicSize(aRenderingContext, wm).ISize(wm);
}
nscoord nsTextControlFrame::GetMinISize(gfxContext* aRenderingContext) {
- // Our min inline size is just our preferred width if we have auto inline size
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
- result = GetPrefISize(aRenderingContext);
- return result;
-}
-
-LogicalSize nsTextControlFrame::ComputeAutoSize(
- gfxContext* aRenderingContext, WritingMode aWM, const LogicalSize& aCBSize,
- nscoord aAvailableISize, const LogicalSize& aMargin,
- const LogicalSize& aBorderPadding, const StyleSizeOverrides& aSizeOverrides,
- ComputeSizeFlags aFlags) {
- float inflation = nsLayoutUtils::FontSizeInflationFor(this);
- LogicalSize autoSize = CalcIntrinsicSize(aRenderingContext, aWM, inflation);
-
- // Note: nsContainerFrame::ComputeAutoSize only computes the inline-size (and
- // only for 'auto'), the block-size it returns is always NS_UNCONSTRAINEDSIZE.
- const auto& styleISize = aSizeOverrides.mStyleISize
- ? *aSizeOverrides.mStyleISize
- : StylePosition()->ISize(aWM);
- if (styleISize.IsAuto()) {
- if (aFlags.contains(ComputeSizeFlag::IClampMarginBoxMinSize)) {
- // CalcIntrinsicSize isn't aware of grid-item margin-box clamping, so we
- // fall back to nsContainerFrame's ComputeAutoSize to handle that.
- // XXX maybe a font-inflation issue here? (per the assertion below).
- autoSize.ISize(aWM) =
- nsContainerFrame::ComputeAutoSize(
- aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin,
- aBorderPadding, aSizeOverrides, aFlags)
- .ISize(aWM);
- }
-#ifdef DEBUG
- else {
- LogicalSize ancestorAutoSize = nsContainerFrame::ComputeAutoSize(
- aRenderingContext, aWM, aCBSize, aAvailableISize, aMargin,
- aBorderPadding, aSizeOverrides, aFlags);
- MOZ_ASSERT(inflation != 1.0f ||
- ancestorAutoSize.ISize(aWM) == autoSize.ISize(aWM),
- "Incorrect size computed by ComputeAutoSize?");
- }
-#endif
- }
- return autoSize;
+ // Our min inline size is just our preferred inline-size if we have auto
+ // inline size.
+ return GetPrefISize(aRenderingContext);
}
Maybe<nscoord> nsTextControlFrame::ComputeBaseline(
@@ -641,12 +598,16 @@ void nsTextControlFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTextControlFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// set values of reflow's out parameters
WritingMode wm = aReflowInput.GetWritingMode();
- aDesiredSize.SetSize(wm, aReflowInput.ComputedSizeWithBorderPadding(wm));
+ const auto contentBoxSize = aReflowInput.ComputedSizeWithBSizeFallback([&] {
+ return CalcIntrinsicSize(aReflowInput.mRenderingContext, wm).BSize(wm);
+ });
+ aDesiredSize.SetSize(
+ wm,
+ contentBoxSize + aReflowInput.ComputedLogicalBorderPadding(wm).Size(wm));
{
// Calculate the baseline and store it in mFirstBaseline.
@@ -674,7 +635,7 @@ void nsTextControlFrame::Reflow(nsPresContext* aPresContext,
nscoord buttonBoxISize = 0;
if (buttonBox) {
ReflowTextControlChild(buttonBox, aPresContext, aReflowInput, aStatus,
- aDesiredSize, buttonBoxISize);
+ aDesiredSize, contentBoxSize, buttonBoxISize);
}
// perform reflow on all kids
@@ -684,7 +645,7 @@ void nsTextControlFrame::Reflow(nsPresContext* aPresContext,
MOZ_ASSERT(!IsButtonBox(kid),
"Should only have one button box, and should be last");
ReflowTextControlChild(kid, aPresContext, aReflowInput, aStatus,
- aDesiredSize, buttonBoxISize);
+ aDesiredSize, contentBoxSize, buttonBoxISize);
}
kid = kid->GetNextSibling();
}
@@ -698,22 +659,28 @@ void nsTextControlFrame::Reflow(nsPresContext* aPresContext,
void nsTextControlFrame::ReflowTextControlChild(
nsIFrame* aKid, nsPresContext* aPresContext,
const ReflowInput& aReflowInput, nsReflowStatus& aStatus,
- ReflowOutput& aParentDesiredSize, nscoord& aButtonBoxISize) {
+ ReflowOutput& aParentDesiredSize, const LogicalSize& aParentContentBoxSize,
+ nscoord& aButtonBoxISize) {
const WritingMode outerWM = aReflowInput.GetWritingMode();
// compute available size and frame offsets for child
const WritingMode wm = aKid->GetWritingMode();
- LogicalSize availSize = aReflowInput.ComputedSizeWithPadding(wm);
+ const auto parentPadding = aReflowInput.ComputedLogicalPadding(wm);
+ const LogicalSize contentBoxSize =
+ aParentContentBoxSize.ConvertTo(wm, outerWM);
+ const LogicalSize paddingBoxSize = contentBoxSize + parentPadding.Size(wm);
+ const LogicalSize borderBoxSize =
+ paddingBoxSize + aReflowInput.ComputedLogicalBorder(wm).Size(wm);
+ LogicalSize availSize = paddingBoxSize;
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
- bool isButtonBox = IsButtonBox(aKid);
+ const bool isButtonBox = IsButtonBox(aKid);
ReflowInput kidReflowInput(aPresContext, aReflowInput, aKid, availSize,
Nothing(), ReflowInput::InitFlag::CallerWillInit);
// Override padding with our computed padding in case we got it from theming
// or percentage, if we're not the button box.
- auto overridePadding =
- isButtonBox ? Nothing() : Some(aReflowInput.ComputedLogicalPadding(wm));
+ auto overridePadding = isButtonBox ? Nothing() : Some(parentPadding);
if (!isButtonBox && aButtonBoxISize) {
// Button box respects inline-end-padding, so we don't need to.
overridePadding->IEnd(outerWM) = 0;
@@ -722,8 +689,7 @@ void nsTextControlFrame::ReflowTextControlChild(
// We want to let our button box fill the frame in the block axis, up to the
// edge of the control's border. So, we use the control's padding-box as the
// containing block size for our button box.
- auto overrideCBSize =
- isButtonBox ? Some(aReflowInput.ComputedSizeWithPadding(wm)) : Nothing();
+ auto overrideCBSize = isButtonBox ? Some(paddingBoxSize) : Nothing();
kidReflowInput.Init(aPresContext, overrideCBSize, Nothing(), overridePadding);
LogicalPoint position(wm);
@@ -746,14 +712,12 @@ void nsTextControlFrame::ReflowTextControlChild(
// the only exception, which has an auto size).
kidReflowInput.SetComputedISize(
std::max(0, aReflowInput.ComputedISize() - aButtonBoxISize));
- kidReflowInput.SetComputedBSize(aReflowInput.ComputedBSize());
+ kidReflowInput.SetComputedBSize(contentBoxSize.BSize(wm));
}
// reflow the child
ReflowOutput desiredSize(aReflowInput);
- const nsSize containerSize =
- aReflowInput.ComputedSizeWithBorderPadding(outerWM).GetPhysicalSize(
- outerWM);
+ const nsSize containerSize = borderBoxSize.GetPhysicalSize(wm);
ReflowChild(aKid, aPresContext, desiredSize, kidReflowInput, wm, position,
containerSize, ReflowChildFlags::Default, aStatus);
@@ -767,7 +731,7 @@ void nsTextControlFrame::ReflowTextControlChild(
buttonRect.ISize(outerWM) = size.ISize(outerWM);
buttonRect.BStart(outerWM) =
bp.BStart(outerWM) +
- (aReflowInput.ComputedBSize() - size.BSize(outerWM)) / 2;
+ (aParentContentBoxSize.BSize(outerWM) - size.BSize(outerWM)) / 2;
// Align to the inline-end of the content box.
buttonRect.IStart(outerWM) =
bp.IStart(outerWM) + aReflowInput.ComputedISize() - size.ISize(outerWM);
diff --git a/layout/forms/nsTextControlFrame.h b/layout/forms/nsTextControlFrame.h
index 0d52e5849f..2eb6f18d15 100644
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -63,14 +63,6 @@ class nsTextControlFrame : public nsContainerFrame,
nscoord GetMinISize(gfxContext* aRenderingContext) override;
nscoord GetPrefISize(gfxContext* aRenderingContext) override;
- mozilla::LogicalSize ComputeAutoSize(
- gfxContext* aRenderingContext, mozilla::WritingMode aWM,
- const mozilla::LogicalSize& aCBSize, nscoord aAvailableISize,
- const mozilla::LogicalSize& aMargin,
- const mozilla::LogicalSize& aBorderPadding,
- const mozilla::StyleSizeOverrides& aSizeOverrides,
- mozilla::ComputeSizeFlags aFlags) override;
-
void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;
@@ -180,10 +172,11 @@ class nsTextControlFrame : public nsContainerFrame,
/**
* Launch the reflow on the child frames - see nsTextControlFrame::Reflow()
*/
- void ReflowTextControlChild(nsIFrame* aFrame, nsPresContext* aPresContext,
+ void ReflowTextControlChild(nsIFrame* aKid, nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus,
ReflowOutput& aParentDesiredSize,
+ const mozilla::LogicalSize& aParentContentBoxSize,
nscoord& aButtonBoxISize);
public:
@@ -278,8 +271,7 @@ class nsTextControlFrame : public nsContainerFrame,
// etc. Just the size of our actual area for the text (and the scrollbars,
// for <textarea>).
mozilla::LogicalSize CalcIntrinsicSize(gfxContext* aRenderingContext,
- mozilla::WritingMode aWM,
- float aFontSizeInflation) const;
+ mozilla::WritingMode aWM) const;
private:
// helper methods
diff --git a/layout/forms/test/mochitest.toml b/layout/forms/test/mochitest.toml
index 0748041524..5eddbf6a7b 100644
--- a/layout/forms/test/mochitest.toml
+++ b/layout/forms/test/mochitest.toml
@@ -75,8 +75,6 @@ skip-if = ["os == 'android'"] # Bug 1635771
["test_bug717878_input_scroll.html"]
-["test_bug869314.html"]
-
["test_bug903715.html"]
skip-if = ["true"]
diff --git a/layout/forms/test/test_bug869314.html b/layout/forms/test/test_bug869314.html
deleted file mode 100644
index 7c786fccfc..0000000000
--- a/layout/forms/test/test_bug869314.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=869314
--->
-<head>
- <meta charset="utf-8">
- <title>Test for Bug 869314</title>
- <script src="/tests/SimpleTest/SimpleTest.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
-
- <style type="text/css">
- .selectbox {
- background-color: #00FF00;
- }
- </style>
-
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=869314">Mozilla Bug 869314</a>
-<p id="display"></p>
-<div id="content">
-
- <select id="selectbox1" name="non-native selectbox" class="selectbox">
- <option value="item">test item</option>
- </select>
-
- <select id="selectbox2" name="native selectbox">
- <option value="item">test item</option>
- </select>
-
- <script type="application/javascript">
- let Cc = SpecialPowers.Cc;
- let Ci = SpecialPowers.Ci;
- let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
- let osName = sysInfo.getProperty("name");
- let isNNT = SpecialPowers.getBoolPref("widget.non-native-theme.enabled");
- if (osName == "Darwin" && !isNNT) { // Native styled macOS form controls.
- // This test is for macOS with native styled form controls only. See bug for more info.
- ok(document.getElementById("selectbox1").clientWidth >
- document.getElementById("selectbox2").clientWidth,
- "Non-native styled combobox does not have enough space for a " +
- "dropmarker!");
- } else {
- // We need to call at least one test function to make the test harness
- // happy.
- ok(true, "Test wasn't ignored but should have been.");
- }
- </script>
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
diff --git a/layout/generic/AspectRatio.cpp b/layout/generic/AspectRatio.cpp
index 2fe51fed5e..0a8ef181e4 100644
--- a/layout/generic/AspectRatio.cpp
+++ b/layout/generic/AspectRatio.cpp
@@ -20,7 +20,7 @@ nscoord AspectRatio::ComputeRatioDependentSize(
const LogicalSize& boxSizingAdjust = mUseBoxSizing == UseBoxSizing::No
? LogicalSize(aWM)
: aContentBoxSizeToBoxSizingAdjust;
- return aRatioDependentAxis == LogicalAxis::eLogicalAxisInline
+ return aRatioDependentAxis == LogicalAxis::Inline
? ConvertToWritingMode(aWM).ApplyTo(aRatioDeterminingSize +
boxSizingAdjust.BSize(aWM)) -
boxSizingAdjust.ISize(aWM)
diff --git a/layout/generic/AspectRatio.h b/layout/generic/AspectRatio.h
index 6f48a07da3..daafd06ba8 100644
--- a/layout/generic/AspectRatio.h
+++ b/layout/generic/AspectRatio.h
@@ -22,7 +22,7 @@ struct ParamTraits;
namespace mozilla {
-enum LogicalAxis : uint8_t;
+enum class LogicalAxis : uint8_t;
class LogicalSize;
class WritingMode;
diff --git a/layout/generic/BRFrame.cpp b/layout/generic/BRFrame.cpp
index 52cc3a0b46..13b3fbb9a4 100644
--- a/layout/generic/BRFrame.cpp
+++ b/layout/generic/BRFrame.cpp
@@ -98,7 +98,6 @@ void BRFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
const ReflowInput& aReflowInput, nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("BRFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
WritingMode wm = aReflowInput.GetWritingMode();
@@ -186,18 +185,10 @@ void BRFrame::AddInlinePrefISize(gfxContext* aRenderingContext,
}
/* virtual */
-nscoord BRFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_MIN_INLINE_SIZE(this, result);
- return result;
-}
+nscoord BRFrame::GetMinISize(gfxContext* aRenderingContext) { return 0; }
/* virtual */
-nscoord BRFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_PREF_INLINE_SIZE(this, result);
- return result;
-}
+nscoord BRFrame::GetPrefISize(gfxContext* aRenderingContext) { return 0; }
Maybe<nscoord> BRFrame::GetNaturalBaselineBOffset(
WritingMode aWM, BaselineSharingGroup aBaselineGroup,
diff --git a/layout/generic/CSSAlignUtils.cpp b/layout/generic/CSSAlignUtils.cpp
index b88ec8bfa4..090cba3a2a 100644
--- a/layout/generic/CSSAlignUtils.cpp
+++ b/layout/generic/CSSAlignUtils.cpp
@@ -56,7 +56,7 @@ nscoord CSSAlignUtils::AlignJustifySelf(const StyleAlignFlags& aAlignment,
WritingMode wm = aRI.GetWritingMode();
const LogicalMargin margin = aRI.ComputedLogicalMargin(wm);
const auto startSide = MakeLogicalSide(
- aAxis, MOZ_LIKELY(isSameSide) ? eLogicalEdgeStart : eLogicalEdgeEnd);
+ aAxis, MOZ_LIKELY(isSameSide) ? LogicalEdge::Start : LogicalEdge::End);
const nscoord marginStart = margin.Side(startSide, wm);
const auto endSide = GetOppositeSide(startSide);
const nscoord marginEnd = margin.Side(endSide, wm);
@@ -68,10 +68,10 @@ nscoord CSSAlignUtils::AlignJustifySelf(const StyleAlignFlags& aAlignment,
// (Note: ReflowInput will have treated "auto" margins as 0, so we
// don't need to do anything special to avoid expanding them.)
hasAutoMarginStart = hasAutoMarginEnd = false;
- } else if (aAxis == eLogicalAxisBlock) {
+ } else if (aAxis == LogicalAxis::Block) {
hasAutoMarginStart = styleMargin.GetBStart(wm).IsAuto();
hasAutoMarginEnd = styleMargin.GetBEnd(wm).IsAuto();
- } else { /* aAxis == eLogicalAxisInline */
+ } else { /* aAxis == LogicalAxis::Inline */
hasAutoMarginStart = styleMargin.GetIStart(wm).IsAuto();
hasAutoMarginEnd = styleMargin.GetIEnd(wm).IsAuto();
}
diff --git a/layout/generic/ColumnSetWrapperFrame.cpp b/layout/generic/ColumnSetWrapperFrame.cpp
index 7717f14df8..9f22222925 100644
--- a/layout/generic/ColumnSetWrapperFrame.cpp
+++ b/layout/generic/ColumnSetWrapperFrame.cpp
@@ -151,7 +151,6 @@ void ColumnSetWrapperFrame::MarkIntrinsicISizesDirty() {
nscoord ColumnSetWrapperFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord iSize = 0;
- DISPLAY_MIN_INLINE_SIZE(this, iSize);
if (Maybe<nscoord> containISize =
ContainIntrinsicISize(NS_UNCONSTRAINEDSIZE)) {
@@ -193,7 +192,6 @@ nscoord ColumnSetWrapperFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord ColumnSetWrapperFrame::GetPrefISize(gfxContext* aRenderingContext) {
nscoord iSize = 0;
- DISPLAY_PREF_INLINE_SIZE(this, iSize);
if (Maybe<nscoord> containISize =
ContainIntrinsicISize(NS_UNCONSTRAINEDSIZE)) {
diff --git a/layout/generic/MiddleCroppingBlockFrame.cpp b/layout/generic/MiddleCroppingBlockFrame.cpp
index 4cbbb684aa..75dc205a4f 100644
--- a/layout/generic/MiddleCroppingBlockFrame.cpp
+++ b/layout/generic/MiddleCroppingBlockFrame.cpp
@@ -57,18 +57,11 @@ void MiddleCroppingBlockFrame::UpdateDisplayedValueToUncroppedValue(
}
nscoord MiddleCroppingBlockFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
-
// Our min inline size is our pref inline size
- result = GetPrefISize(aRenderingContext);
- return result;
+ return GetPrefISize(aRenderingContext);
}
nscoord MiddleCroppingBlockFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
-
nsAutoString prevValue;
bool restoreOldValue = false;
@@ -79,7 +72,7 @@ nscoord MiddleCroppingBlockFrame::GetPrefISize(gfxContext* aRenderingContext) {
UpdateDisplayedValueToUncroppedValue(false);
}
- result = nsBlockFrame::GetPrefISize(aRenderingContext);
+ nscoord result = nsBlockFrame::GetPrefISize(aRenderingContext);
if (restoreOldValue) {
UpdateDisplayedValue(prevValue, /* aIsCropped = */ true, false);
diff --git a/layout/generic/PrintedSheetFrame.cpp b/layout/generic/PrintedSheetFrame.cpp
index 5b8151bbd0..384e63e361 100644
--- a/layout/generic/PrintedSheetFrame.cpp
+++ b/layout/generic/PrintedSheetFrame.cpp
@@ -86,7 +86,6 @@ void PrintedSheetFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("PrintedSheetFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// If we have a prev-in-flow, take its overflowing content:
diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp
index ed7dbd2656..bdfd39aff1 100644
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -13,10 +13,8 @@
#include "CounterStyleManager.h"
#include "LayoutLogging.h"
#include "mozilla/dom/HTMLInputElement.h"
-#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/WritingModes.h"
#include "nsBlockFrame.h"
-#include "nsCSSAnonBoxes.h"
#include "nsFlexContainerFrame.h"
#include "nsFontInflationData.h"
#include "nsFontMetrics.h"
@@ -31,7 +29,6 @@
#include "nsLineBox.h"
#include "nsPresContext.h"
#include "nsStyleConsts.h"
-#include "nsTableCellFrame.h"
#include "nsTableFrame.h"
#include "StickyScrollContainer.h"
@@ -956,21 +953,10 @@ void ReflowInput::ApplyRelativePositioning(nsIFrame* aFrame,
const nsStyleDisplay* display = aFrame->StyleDisplay();
if (StylePositionProperty::Relative == display->mPosition) {
*aPosition += nsPoint(aComputedOffsets.left, aComputedOffsets.top);
- } else if (StylePositionProperty::Sticky == display->mPosition &&
- !aFrame->GetNextContinuation() && !aFrame->GetPrevContinuation() &&
- !aFrame->HasAnyStateBits(NS_FRAME_PART_OF_IBSPLIT)) {
- // Sticky positioning for elements with multiple frames needs to be
- // computed all at once. We can't safely do that here because we might be
- // partway through (re)positioning the frames, so leave it until the scroll
- // container reflows and calls StickyScrollContainer::UpdatePositions.
- // For single-frame sticky positioned elements, though, go ahead and apply
- // it now to avoid unnecessary overflow updates later.
- StickyScrollContainer* ssc =
- StickyScrollContainer::GetStickyScrollContainerForFrame(aFrame);
- if (ssc) {
- *aPosition = ssc->ComputePosition(aFrame);
- }
}
+ // For sticky positioned elements, we'll leave them until the scroll container
+ // reflows and calls StickyScrollContainer::UpdatePositions() to update their
+ // positions.
}
// static
@@ -1126,9 +1112,9 @@ void ReflowInput::CalculateBorderPaddingMargin(
nscoord* aOutsideBoxSizing) const {
WritingMode wm = GetWritingMode();
mozilla::Side startSide =
- wm.PhysicalSide(MakeLogicalSide(aAxis, eLogicalEdgeStart));
+ wm.PhysicalSide(MakeLogicalSide(aAxis, LogicalEdge::Start));
mozilla::Side endSide =
- wm.PhysicalSide(MakeLogicalSide(aAxis, eLogicalEdgeEnd));
+ wm.PhysicalSide(MakeLogicalSide(aAxis, LogicalEdge::End));
nsMargin styleBorder = mStyleBorder->GetComputedBorder();
nscoord borderStartEnd =
@@ -1231,18 +1217,18 @@ static bool AxisPolarityFlipped(LogicalAxis aThisAxis, WritingMode aThisWm,
aThisWm.PhysicalAxis(aThisAxis) == aOtherWm.PhysicalAxis(otherAxis),
"Physical axes must match!");
Side thisStartSide =
- aThisWm.PhysicalSide(MakeLogicalSide(aThisAxis, eLogicalEdgeStart));
+ aThisWm.PhysicalSide(MakeLogicalSide(aThisAxis, LogicalEdge::Start));
Side otherStartSide =
- aOtherWm.PhysicalSide(MakeLogicalSide(otherAxis, eLogicalEdgeStart));
+ aOtherWm.PhysicalSide(MakeLogicalSide(otherAxis, LogicalEdge::Start));
return thisStartSide != otherStartSide;
}
static bool InlinePolarityFlipped(WritingMode aThisWm, WritingMode aOtherWm) {
- return AxisPolarityFlipped(eLogicalAxisInline, aThisWm, aOtherWm);
+ return AxisPolarityFlipped(LogicalAxis::Inline, aThisWm, aOtherWm);
}
static bool BlockPolarityFlipped(WritingMode aThisWm, WritingMode aOtherWm) {
- return AxisPolarityFlipped(eLogicalAxisBlock, aThisWm, aOtherWm);
+ return AxisPolarityFlipped(LogicalAxis::Block, aThisWm, aOtherWm);
}
// Calculate the position of the hypothetical box that the element would have
@@ -1292,7 +1278,6 @@ void ReflowInput::CalculateHypotheticalPosition(
// For non-replaced inline-level elements the 'inline size' property
// doesn't apply, so we don't know what the inline size would have
// been without reflowing it
-
} else {
// It's either a replaced inline-level element or a block-level element
@@ -1301,17 +1286,17 @@ void ReflowInput::CalculateHypotheticalPosition(
// been in the flow. Note that we ignore any 'auto' and 'inherit'
// values
nscoord insideBoxISizing, outsideBoxISizing;
- CalculateBorderPaddingMargin(eLogicalAxisInline, blockContentSize.ISize(wm),
- &insideBoxISizing, &outsideBoxISizing);
+ CalculateBorderPaddingMargin(LogicalAxis::Inline,
+ blockContentSize.ISize(wm), &insideBoxISizing,
+ &outsideBoxISizing);
if (mFlags.mIsReplaced && isAutoISize) {
- // It's a replaced element with an 'auto' inline size so the box
- // inline size is its intrinsic size plus any border/padding/margin
+ // It's a replaced element with an 'auto' inline size so the box inline
+ // size is its intrinsic size plus any border/padding/margin
if (intrinsicSize) {
boxISize.emplace(LogicalSize(wm, *intrinsicSize).ISize(wm) +
outsideBoxISizing + insideBoxISizing);
}
-
} else if (isAutoISize) {
// The box inline size is the containing block inline size
boxISize.emplace(blockContentSize.ISize(wm));
@@ -1320,7 +1305,7 @@ void ReflowInput::CalculateHypotheticalPosition(
// percentage based this computed value may be different from the computed
// value calculated using the absolute containing block width
nscoord insideBoxBSizing, dummy;
- CalculateBorderPaddingMargin(eLogicalAxisBlock,
+ CalculateBorderPaddingMargin(LogicalAxis::Block,
blockContentSize.ISize(wm),
&insideBoxBSizing, &dummy);
boxISize.emplace(
@@ -1500,7 +1485,7 @@ void ReflowInput::CalculateHypotheticalPosition(
// been in the flow. Note that we ignore any 'auto' and 'inherit'
// values.
nscoord insideBoxSizing, outsideBoxSizing;
- CalculateBorderPaddingMargin(eLogicalAxisBlock, blockContentSize.BSize(wm),
+ CalculateBorderPaddingMargin(LogicalAxis::Block, blockContentSize.BSize(wm),
&insideBoxSizing, &outsideBoxSizing);
nscoord boxBSize;
@@ -1627,7 +1612,7 @@ LogicalSize ReflowInput::CalculateAbsoluteSizeWithResolvedAutoBlockSize(
: LogicalSize(wm);
auto transferredISize =
mStylePosition->mAspectRatio.ToLayoutRatio().ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, wm, aAutoBSize, boxSizingAdjust);
+ LogicalAxis::Inline, wm, aAutoBSize, boxSizingAdjust);
resultSize.ISize(wm) = ApplyMinMaxISize(transferredISize);
MOZ_ASSERT(mFlags.mIsBSizeSetByAspectRatio,
@@ -2167,8 +2152,6 @@ void ReflowInput::InitConstraints(
WritingMode wm = GetWritingMode();
LogicalSize cbSize = aContainingBlockSize.valueOr(
LogicalSize(mWritingMode, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE));
- DISPLAY_INIT_CONSTRAINTS(mFrame, this, cbSize.ISize(wm), cbSize.BSize(wm),
- aBorder, aPadding);
// If this is a reflow root, then set the computed width and
// height equal to the available space
@@ -2239,7 +2222,7 @@ void ReflowInput::InitConstraints(
// eStyleUnit_Auto;" used to be called exclusively.
if (mFlags.mIsReplaced && mStyleDisplay->IsInlineOutsideStyle()) {
// Get the containing block's reflow input
- NS_ASSERTION(nullptr != cbri, "no containing block");
+ NS_ASSERTION(cbri, "no containing block");
// in quirks mode, get the cb height using the special quirk method
if (!wm.IsVertical() &&
eCompatibility_NavQuirks == aPresContext->CompatibilityMode()) {
@@ -2359,46 +2342,79 @@ void ReflowInput::InitConstraints(
} else {
AutoMaybeDisableFontInflation an(mFrame);
- const bool isBlockLevel =
- ((!mStyleDisplay->IsInlineOutsideStyle() &&
- // internal table values on replaced elements behaves as inline
- // https://drafts.csswg.org/css-tables-3/#table-structure
- // "... it is handled instead as though the author had declared
- // either 'block' (for 'table' display) or 'inline' (for all
- // other values)"
- !(mFlags.mIsReplaced && (mStyleDisplay->IsInnerTableStyle() ||
- mStyleDisplay->DisplayOutside() ==
- StyleDisplayOutside::TableCaption))) ||
- // The inner table frame always fills its outer wrapper table frame,
- // even for 'inline-table'.
- mFrame->IsTableFrame()) &&
- // XXX abs.pos. continuations treated like blocks, see comment in
- // the else-if condition above.
- (!mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) ||
- mStyleDisplay->IsAbsolutelyPositionedStyle());
-
- if (!isBlockLevel) {
- mComputeSizeFlags += ComputeSizeFlag::ShrinkWrap;
- }
+ nsIFrame* const alignCB = [&] {
+ nsIFrame* cb = mFrame->GetParent();
+ if (cb->IsTableWrapperFrame()) {
+ nsIFrame* alignCBParent = cb->GetParent();
+ if (alignCBParent && alignCBParent->IsGridContainerFrame()) {
+ return alignCBParent;
+ }
+ }
+ return cb;
+ }();
- nsIFrame* alignCB = mFrame->GetParent();
- if (alignCB->IsTableWrapperFrame()) {
- nsIFrame* alignCBParent = alignCB->GetParent();
- if (alignCBParent && alignCBParent->IsGridContainerFrame()) {
- alignCB = alignCBParent;
+ const bool isInlineLevel = [&] {
+ if (mFrame->IsTableFrame()) {
+ // An inner table frame is not inline-level, even if it happens to
+ // have 'display:inline-table'. (That makes its table-wrapper frame be
+ // inline-level, but not the inner table frame)
+ return false;
}
- }
- if (!alignCB->IsGridContainerFrame()) {
- // Shrink-wrap blocks that are orthogonal to their container.
- if (isBlockLevel && mCBReflowInput &&
+ if (mStyleDisplay->IsInlineOutsideStyle()) {
+ return true;
+ }
+ if (mFlags.mIsReplaced && (mStyleDisplay->IsInnerTableStyle() ||
+ mStyleDisplay->DisplayOutside() ==
+ StyleDisplayOutside::TableCaption)) {
+ // Internal table values on replaced elements behave as inline
+ // https://drafts.csswg.org/css-tables-3/#table-structure
+ //
+ // ... it is handled instead as though the author had declared
+ // either 'block' (for 'table' display) or 'inline' (for all
+ // other values)"
+ //
+ // FIXME(emilio): The only test that covers this is
+ // table-anonymous-objects-211.xht, which fails on other browsers (but
+ // differently to us, if you just remove this condition).
+ return true;
+ }
+ if (mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW) &&
+ !mStyleDisplay->IsAbsolutelyPositionedStyle()) {
+ // Floats are treated as inline-level and also shrink-wrap.
+ return true;
+ }
+ return false;
+ }();
+
+ const bool shouldShrinkWrap = [&] {
+ if (isInlineLevel) {
+ return true;
+ }
+ if (mFlags.mIsReplaced && !alignCB->IsFlexOrGridContainer()) {
+ // Shrink-wrap replaced elements when in-flow (out of flows are
+ // handled above). We exclude replaced elements in grid or flex
+ // contexts, where we don't want to shrink-wrap unconditionally (so
+ // that stretching can happen). When grid/flex explicitly want
+ // shrink-wrapping, they can request it directly using the relevant
+ // flag.
+ return true;
+ }
+ if (!alignCB->IsGridContainerFrame() && mCBReflowInput &&
mCBReflowInput->GetWritingMode().IsOrthogonalTo(mWritingMode)) {
- mComputeSizeFlags += ComputeSizeFlag::ShrinkWrap;
+ // Shrink-wrap blocks that are orthogonal to their container (unless
+ // we're in a grid?)
+ return true;
}
+ return false;
+ }();
+
+ if (shouldShrinkWrap) {
+ mComputeSizeFlags += ComputeSizeFlag::ShrinkWrap;
}
if (cbSize.ISize(wm) == NS_UNCONSTRAINEDSIZE) {
- // For orthogonal flows, where we found a parent orthogonal-limit
- // for AvailableISize() in Init(), we'll use the same here as well.
+ // For orthogonal flows, where we found a parent orthogonal-limit for
+ // AvailableISize() in Init(), we'll use the same here as well.
cbSize.ISize(wm) = AvailableISize();
}
@@ -2418,10 +2434,7 @@ void ReflowInput::InitConstraints(
size.mAspectRatioUsage == nsIFrame::AspectRatioUsage::ToComputeBSize;
const bool shouldCalculateBlockSideMargins = [&]() {
- if (!isBlockLevel) {
- return false;
- }
- if (mStyleDisplay->mDisplay == StyleDisplay::InlineTable) {
+ if (isInlineLevel) {
return false;
}
if (mFrame->IsTableFrame()) {
@@ -2475,7 +2488,6 @@ void SizeComputationInput::InitOffsets(WritingMode aCBWM, nscoord aPercentBasis,
const Maybe<LogicalMargin>& aBorder,
const Maybe<LogicalMargin>& aPadding,
const nsStyleDisplay* aDisplay) {
- DISPLAY_INIT_OFFSETS(mFrame, this, aPercentBasis, aCBWM, aBorder, aPadding);
nsPresContext* presContext = mFrame->PresContext();
// Compute margins from the specified margin style information. These
@@ -2526,14 +2538,14 @@ void SizeComputationInput::InitOffsets(WritingMode aCBWM, nscoord aPercentBasis,
NS_ASSERTION(val != nscoord(0), "zero in this property is useless");
LogicalSide side;
if (val > 0) {
- side = MakeLogicalSide(aAxis, eLogicalEdgeStart);
+ side = MakeLogicalSide(aAxis, LogicalEdge::Start);
} else {
- side = MakeLogicalSide(aAxis, eLogicalEdgeEnd);
+ side = MakeLogicalSide(aAxis, LogicalEdge::End);
val = -val;
}
mComputedPadding.Side(side, wm) += val;
needPaddingProp = true;
- if (aAxis == eLogicalAxisBlock && val > 0) {
+ if (aAxis == LogicalAxis::Block && val > 0) {
// We have a baseline-adjusted block-axis start padding, so
// we need this to mark lines dirty when mIsBResize is true:
this->mFrame->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
@@ -2541,10 +2553,10 @@ void SizeComputationInput::InitOffsets(WritingMode aCBWM, nscoord aPercentBasis,
}
};
if (!aFlags.contains(ComputeSizeFlag::IsGridMeasuringReflow)) {
- ApplyBaselinePadding(eLogicalAxisBlock, nsIFrame::BBaselinePadProperty());
+ ApplyBaselinePadding(LogicalAxis::Block, nsIFrame::BBaselinePadProperty());
}
if (!aFlags.contains(ComputeSizeFlag::ShrinkWrap)) {
- ApplyBaselinePadding(eLogicalAxisInline, nsIFrame::IBaselinePadProperty());
+ ApplyBaselinePadding(LogicalAxis::Inline, nsIFrame::IBaselinePadProperty());
}
LogicalMargin border(wm);
@@ -2719,27 +2731,28 @@ void ReflowInput::CalculateBlockSideMargins() {
// zeros, we should compensate this by creating extra (external) leading.
// This is necessary because without this compensation, normal line height might
// look too tight.
-constexpr float kNormalLineHeightFactor = 1.2f;
static nscoord GetNormalLineHeight(nsFontMetrics* aFontMetrics) {
MOZ_ASSERT(aFontMetrics, "no font metrics");
nscoord externalLeading = aFontMetrics->ExternalLeading();
nscoord internalLeading = aFontMetrics->InternalLeading();
nscoord emHeight = aFontMetrics->EmHeight();
if (!internalLeading && !externalLeading) {
- return NSToCoordRound(emHeight * kNormalLineHeightFactor);
+ return NSToCoordRound(static_cast<float>(emHeight) *
+ ReflowInput::kNormalLineHeightFactor);
}
return emHeight + internalLeading + externalLeading;
}
static inline nscoord ComputeLineHeight(const StyleLineHeight& aLh,
- const nsStyleFont& aRelativeToFont,
+ const nsFont& aFont, nsAtom* aLanguage,
+ bool aExplicitLanguage,
nsPresContext* aPresContext,
bool aIsVertical, nscoord aBlockBSize,
float aFontSizeInflation) {
if (aLh.IsLength()) {
nscoord result = aLh.AsLength().ToAppUnits();
if (aFontSizeInflation != 1.0f) {
- result = NSToCoordRound(result * aFontSizeInflation);
+ result = NSToCoordRound(static_cast<float>(result) * aFontSizeInflation);
}
return result;
}
@@ -2748,8 +2761,7 @@ static inline nscoord ComputeLineHeight(const StyleLineHeight& aLh,
// For factor units the computed value of the line-height property
// is found by multiplying the factor by the font's computed size
// (adjusted for min-size prefs and text zoom).
- return aRelativeToFont.mFont.size
- .ScaledBy(aLh.AsNumber() * aFontSizeInflation)
+ return aFont.size.ScaledBy(aLh.AsNumber() * aFontSizeInflation)
.ToAppUnits();
}
@@ -2758,17 +2770,25 @@ static inline nscoord ComputeLineHeight(const StyleLineHeight& aLh,
return aBlockBSize;
}
- auto size = aRelativeToFont.mFont.size;
+ auto size = aFont.size;
size.ScaleBy(aFontSizeInflation);
if (aPresContext) {
- RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
- aPresContext, aIsVertical, &aRelativeToFont, size,
- /* aUseUserFontSet = */ true);
+ nsFont font = aFont;
+ font.size = size;
+ nsFontMetrics::Params params;
+ params.language = aLanguage;
+ params.explicitLanguage = aExplicitLanguage;
+ params.orientation =
+ aIsVertical ? nsFontMetrics::eVertical : nsFontMetrics::eHorizontal;
+ params.userFontSet = aPresContext->GetUserFontSet();
+ params.textPerf = aPresContext->GetTextPerfMetrics();
+ params.featureValueLookup = aPresContext->GetFontFeatureValuesLookup();
+ RefPtr<nsFontMetrics> fm = aPresContext->GetMetricsFor(font, params);
return GetNormalLineHeight(fm);
}
// If we don't have a pres context, use a 1.2em fallback.
- size.ScaleBy(kNormalLineHeightFactor);
+ size.ScaleBy(ReflowInput::kNormalLineHeightFactor);
return size.ToAppUnits();
}
@@ -2816,8 +2836,9 @@ nscoord ReflowInput::CalcLineHeight(
nsPresContext* aPresContext, bool aIsVertical, const nsIContent* aContent,
nscoord aBlockBSize, float aFontSizeInflation) {
nscoord lineHeight =
- ComputeLineHeight(aLh, aRelativeToFont, aPresContext, aIsVertical,
- aBlockBSize, aFontSizeInflation);
+ ComputeLineHeight(aLh, aRelativeToFont.mFont, aRelativeToFont.mLanguage,
+ aRelativeToFont.mExplicitLanguage, aPresContext,
+ aIsVertical, aBlockBSize, aFontSizeInflation);
NS_ASSERTION(lineHeight >= 0, "ComputeLineHeight screwed up");
@@ -2827,8 +2848,9 @@ nscoord ReflowInput::CalcLineHeight(
// have a line-height smaller than 'normal'.
if (!aLh.IsNormal()) {
nscoord normal = ComputeLineHeight(
- StyleLineHeight::Normal(), aRelativeToFont, aPresContext, aIsVertical,
- aBlockBSize, aFontSizeInflation);
+ StyleLineHeight::Normal(), aRelativeToFont.mFont,
+ aRelativeToFont.mLanguage, aRelativeToFont.mExplicitLanguage,
+ aPresContext, aIsVertical, aBlockBSize, aFontSizeInflation);
if (lineHeight < normal) {
lineHeight = normal;
}
@@ -2838,6 +2860,17 @@ nscoord ReflowInput::CalcLineHeight(
return lineHeight;
}
+nscoord ReflowInput::CalcLineHeightForCanvas(const StyleLineHeight& aLh,
+ const nsFont& aRelativeToFont,
+ nsAtom* aLanguage,
+ bool aExplicitLanguage,
+ nsPresContext* aPresContext,
+ mozilla::WritingMode aWM) {
+ return ComputeLineHeight(aLh, aRelativeToFont, aLanguage, aExplicitLanguage,
+ aPresContext, aWM.IsVertical() && !aWM.IsSideways(),
+ NS_UNCONSTRAINEDSIZE, 1.0f);
+}
+
bool SizeComputationInput::ComputeMargin(WritingMode aCBWM,
nscoord aPercentBasis,
LayoutFrameType aFrameType) {
diff --git a/layout/generic/ReflowInput.h b/layout/generic/ReflowInput.h
index 620ad0f413..7bf7c4fc73 100644
--- a/layout/generic/ReflowInput.h
+++ b/layout/generic/ReflowInput.h
@@ -178,20 +178,6 @@ struct SizeComputationInput {
const mozilla::Maybe<mozilla::LogicalMargin>& aPadding =
mozilla::Nothing());
-#ifdef DEBUG
- // Reflow trace methods. Defined in nsFrame.cpp so they have access
- // to the display-reflow infrastructure.
- static void* DisplayInitOffsetsEnter(nsIFrame* aFrame,
- SizeComputationInput* aState,
- nscoord aPercentBasis,
- mozilla::WritingMode aCBWritingMode,
- const nsMargin* aBorder,
- const nsMargin* aPadding);
- static void DisplayInitOffsetsExit(nsIFrame* aFrame,
- SizeComputationInput* aState,
- void* aValue);
-#endif
-
private:
/**
* Computes margin values from the specified margin style information, and
@@ -367,6 +353,16 @@ struct ReflowInput : public SizeComputationInput {
mozilla::LogicalSize AvailableSize() const { return mAvailableSize; }
mozilla::LogicalSize ComputedSize() const { return mComputedSize; }
+
+ template <typename F>
+ mozilla::LogicalSize ComputedSizeWithBSizeFallback(F&& aFallback) const {
+ auto size = mComputedSize;
+ if (size.BSize(mWritingMode) == NS_UNCONSTRAINEDSIZE) {
+ size.BSize(mWritingMode) = ApplyMinMaxBSize(aFallback());
+ }
+ return size;
+ }
+
mozilla::LogicalSize ComputedMinSize() const { return mComputedMinSize; }
mozilla::LogicalSize ComputedMaxSize() const { return mComputedMaxSize; }
@@ -745,6 +741,15 @@ struct ReflowInput : public SizeComputationInput {
const nsIContent* aContent, nscoord aBlockBSize,
float aFontSizeInflation);
+ static nscoord CalcLineHeightForCanvas(const StyleLineHeight& aLh,
+ const nsFont& aRelativeToFont,
+ nsAtom* aLanguage,
+ bool aExplicitLanguage,
+ nsPresContext* aPresContext,
+ mozilla::WritingMode aWM);
+
+ static constexpr float kNormalLineHeightFactor = 1.2f;
+
mozilla::LogicalSize ComputeContainingBlockRectangle(
nsPresContext* aPresContext, const ReflowInput* aContainingBlockRI) const;
@@ -888,21 +893,6 @@ struct ReflowInput : public SizeComputationInput {
LogicalMargin& aMargin,
LogicalMargin& aOffsets);
-#ifdef DEBUG
- // Reflow trace methods. Defined in nsFrame.cpp so they have access
- // to the display-reflow infrastructure.
- static void* DisplayInitConstraintsEnter(nsIFrame* aFrame,
- ReflowInput* aState,
- nscoord aCBISize, nscoord aCBBSize,
- const nsMargin* aBorder,
- const nsMargin* aPadding);
- static void DisplayInitConstraintsExit(nsIFrame* aFrame, ReflowInput* aState,
- void* aValue);
- static void* DisplayInitFrameTypeEnter(nsIFrame* aFrame, ReflowInput* aState);
- static void DisplayInitFrameTypeExit(nsIFrame* aFrame, ReflowInput* aState,
- void* aValue);
-#endif
-
protected:
void InitCBReflowInput();
void InitResizeFlags(nsPresContext* aPresContext,
diff --git a/layout/generic/ScrollAnchorContainer.cpp b/layout/generic/ScrollAnchorContainer.cpp
index 93336480f7..9bf17ec3d5 100644
--- a/layout/generic/ScrollAnchorContainer.cpp
+++ b/layout/generic/ScrollAnchorContainer.cpp
@@ -178,15 +178,15 @@ static nsRect FindScrollAnchoringBoundingRect(const nsIFrame* aScrollFrame,
// axis of the scroll frame
WritingMode writingMode = aScrollFrame->GetWritingMode();
switch (writingMode.GetBlockDir()) {
- case WritingMode::eBlockTB: {
+ case WritingMode::BlockDir::TB: {
overflowRect.SetBoxY(borderRect.Y(), overflowRect.YMost());
break;
}
- case WritingMode::eBlockLR: {
+ case WritingMode::BlockDir::LR: {
overflowRect.SetBoxX(borderRect.X(), overflowRect.XMost());
break;
}
- case WritingMode::eBlockRL: {
+ case WritingMode::BlockDir::RL: {
overflowRect.SetBoxX(overflowRect.X(), borderRect.XMost());
break;
}
@@ -522,15 +522,15 @@ void ScrollAnchorContainer::ApplyAdjustments() {
nsPoint physicalAdjustment;
switch (writingMode.GetBlockDir()) {
- case WritingMode::eBlockTB: {
+ case WritingMode::BlockDir::TB: {
physicalAdjustment.y = logicalAdjustment;
break;
}
- case WritingMode::eBlockLR: {
+ case WritingMode::BlockDir::LR: {
physicalAdjustment.x = logicalAdjustment;
break;
}
- case WritingMode::eBlockRL: {
+ case WritingMode::BlockDir::RL: {
physicalAdjustment.x = -logicalAdjustment;
break;
}
diff --git a/layout/generic/ScrollGeneration.h b/layout/generic/ScrollGeneration.h
index 90eb243e9e..5f14844e33 100644
--- a/layout/generic/ScrollGeneration.h
+++ b/layout/generic/ScrollGeneration.h
@@ -7,6 +7,7 @@
#include <cstdint>
#include <iosfwd>
+#include <tuple>
namespace mozilla {
@@ -23,7 +24,7 @@ std::ostream& operator<<(std::ostream& aStream,
const ScrollGeneration<Tag>& aGen);
template <typename Tag>
-struct ScrollGeneration {
+struct ScrollGeneration final {
friend struct ScrollGenerationCounter;
private:
@@ -43,6 +44,8 @@ struct ScrollGeneration {
friend std::ostream& operator<< <>(std::ostream& aStream,
const ScrollGeneration<Tag>& aGen);
+ auto MutTiedFields() { return std::tie(mValue); }
+
private:
uint64_t mValue;
};
diff --git a/layout/generic/ScrollSnapTargetId.h b/layout/generic/ScrollSnapTargetId.h
index f53e736fa1..a4a281f5e7 100644
--- a/layout/generic/ScrollSnapTargetId.h
+++ b/layout/generic/ScrollSnapTargetId.h
@@ -17,6 +17,7 @@ namespace mozilla {
enum class ScrollSnapTargetId : uintptr_t {
None = 0,
};
+inline constexpr bool IsEnumCase(ScrollSnapTargetId) { return true; }
struct ScrollSnapTargetIds {
CopyableTArray<ScrollSnapTargetId> mIdsOnX;
diff --git a/layout/generic/StickyScrollContainer.cpp b/layout/generic/StickyScrollContainer.cpp
index 416bbbf4c4..e16c3af585 100644
--- a/layout/generic/StickyScrollContainer.cpp
+++ b/layout/generic/StickyScrollContainer.cpp
@@ -200,11 +200,13 @@ void StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame,
nsLayoutUtils::TransformRect(cbFrame, aFrame->GetParent(), *aContain);
} else {
*aContain = nsLayoutUtils::GetAllInFlowRectsUnion(
- cbFrame, aFrame->GetParent(), nsLayoutUtils::RECTS_USE_CONTENT_BOX);
+ cbFrame, aFrame->GetParent(),
+ nsLayoutUtils::GetAllInFlowRectsFlag::UseContentBox);
}
nsRect marginRect = nsLayoutUtils::GetAllInFlowRectsUnion(
- aFrame, aFrame->GetParent(), nsLayoutUtils::RECTS_USE_MARGIN_BOX);
+ aFrame, aFrame->GetParent(),
+ nsLayoutUtils::GetAllInFlowRectsFlag::UseMarginBoxWithAutoResolvedAsZero);
// Deflate aContain by the difference between the union of aFrame's
// continuations' margin boxes and the union of their border boxes, so that
diff --git a/layout/generic/ViewportFrame.cpp b/layout/generic/ViewportFrame.cpp
index 812aaa8e33..d71842d013 100644
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -271,26 +271,16 @@ void ViewportFrame::RemoveFrame(DestroyContext& aContext, ChildListID aListID,
/* virtual */
nscoord ViewportFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
- if (mFrames.IsEmpty())
- result = 0;
- else
- result = mFrames.FirstChild()->GetMinISize(aRenderingContext);
-
- return result;
+ return mFrames.IsEmpty()
+ ? 0
+ : mFrames.FirstChild()->GetMinISize(aRenderingContext);
}
/* virtual */
nscoord ViewportFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
- if (mFrames.IsEmpty())
- result = 0;
- else
- result = mFrames.FirstChild()->GetPrefISize(aRenderingContext);
-
- return result;
+ return mFrames.IsEmpty()
+ ? 0
+ : mFrames.FirstChild()->GetPrefISize(aRenderingContext);
}
nsPoint ViewportFrame::AdjustReflowInputForScrollbars(
@@ -330,7 +320,6 @@ void ViewportFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("ViewportFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow");
diff --git a/layout/generic/WritingModes.h b/layout/generic/WritingModes.h
index e84c5e276d..4f6e9eaec1 100644
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -11,10 +11,8 @@
#include "mozilla/intl/BidiEmbeddingLevel.h"
#include "mozilla/ComputedStyle.h"
-#include "mozilla/EnumeratedRange.h"
-
+#include "mozilla/EnumSet.h"
#include "nsRect.h"
-#include "nsBidiUtils.h"
#include "nsStyleStruct.h"
// It is the caller's responsibility to operate on logical-coordinate objects
@@ -46,21 +44,18 @@ struct IMENotification;
} // namespace widget
// Logical axis, edge, side and corner constants for use in various places.
-enum LogicalAxis : uint8_t {
- eLogicalAxisBlock = 0x0,
- eLogicalAxisInline = 0x1
+enum class LogicalAxis : uint8_t {
+ Block,
+ Inline,
};
-enum LogicalEdge { eLogicalEdgeStart = 0x0, eLogicalEdgeEnd = 0x1 };
-enum LogicalSide : uint8_t {
- eLogicalSideBStart = (eLogicalAxisBlock << 1) | eLogicalEdgeStart, // 0x0
- eLogicalSideBEnd = (eLogicalAxisBlock << 1) | eLogicalEdgeEnd, // 0x1
- eLogicalSideIStart = (eLogicalAxisInline << 1) | eLogicalEdgeStart, // 0x2
- eLogicalSideIEnd = (eLogicalAxisInline << 1) | eLogicalEdgeEnd // 0x3
+enum class LogicalEdge : uint8_t { Start, End };
+
+enum class LogicalSide : uint8_t {
+ BStart,
+ BEnd,
+ IStart,
+ IEnd,
};
-constexpr auto AllLogicalSides() {
- return mozilla::MakeInclusiveEnumeratedRange(eLogicalSideBStart,
- eLogicalSideIEnd);
-}
enum class LogicalCorner : uint8_t {
BStartIStart,
@@ -70,7 +65,7 @@ enum class LogicalCorner : uint8_t {
};
// Physical axis constants.
-enum PhysicalAxis { eAxisVertical = 0x0, eAxisHorizontal = 0x1 };
+enum class PhysicalAxis : uint8_t { Vertical, Horizontal };
// Represents zero or more physical axes.
enum class PhysicalAxes : uint8_t {
@@ -82,51 +77,50 @@ enum class PhysicalAxes : uint8_t {
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(PhysicalAxes)
inline LogicalAxis GetOrthogonalAxis(LogicalAxis aAxis) {
- return aAxis == eLogicalAxisBlock ? eLogicalAxisInline : eLogicalAxisBlock;
+ return aAxis == LogicalAxis::Block ? LogicalAxis::Inline : LogicalAxis::Block;
+}
+
+inline bool IsInline(LogicalSide aSide) {
+ return (aSide == LogicalSide::IStart) || (aSide == LogicalSide::IEnd);
}
-inline bool IsInline(LogicalSide aSide) { return aSide & 0x2; }
inline bool IsBlock(LogicalSide aSide) { return !IsInline(aSide); }
-inline bool IsEnd(LogicalSide aSide) { return aSide & 0x1; }
+
+inline bool IsEnd(LogicalSide aSide) {
+ return (aSide == LogicalSide::BEnd) || (aSide == LogicalSide::IEnd);
+}
+
inline bool IsStart(LogicalSide aSide) { return !IsEnd(aSide); }
inline LogicalAxis GetAxis(LogicalSide aSide) {
- return IsInline(aSide) ? eLogicalAxisInline : eLogicalAxisBlock;
+ return IsInline(aSide) ? LogicalAxis::Inline : LogicalAxis::Block;
}
inline LogicalEdge GetEdge(LogicalSide aSide) {
- return IsEnd(aSide) ? eLogicalEdgeEnd : eLogicalEdgeStart;
+ return IsEnd(aSide) ? LogicalEdge::End : LogicalEdge::Start;
}
inline LogicalEdge GetOppositeEdge(LogicalEdge aEdge) {
- // This relies on the only two LogicalEdge enum values being 0 and 1.
- return LogicalEdge(1 - aEdge);
+ return aEdge == LogicalEdge::Start ? LogicalEdge::End : LogicalEdge::Start;
}
inline LogicalSide MakeLogicalSide(LogicalAxis aAxis, LogicalEdge aEdge) {
- return LogicalSide((aAxis << 1) | aEdge);
+ if (aAxis == LogicalAxis::Inline) {
+ return aEdge == LogicalEdge::Start ? LogicalSide::IStart
+ : LogicalSide::IEnd;
+ }
+ return aEdge == LogicalEdge::Start ? LogicalSide::BStart : LogicalSide::BEnd;
}
inline LogicalSide GetOppositeSide(LogicalSide aSide) {
return MakeLogicalSide(GetAxis(aSide), GetOppositeEdge(GetEdge(aSide)));
}
-enum LogicalSideBits {
- eLogicalSideBitsNone = 0,
- eLogicalSideBitsBStart = 1 << eLogicalSideBStart,
- eLogicalSideBitsBEnd = 1 << eLogicalSideBEnd,
- eLogicalSideBitsIEnd = 1 << eLogicalSideIEnd,
- eLogicalSideBitsIStart = 1 << eLogicalSideIStart,
- eLogicalSideBitsBBoth = eLogicalSideBitsBStart | eLogicalSideBitsBEnd,
- eLogicalSideBitsIBoth = eLogicalSideBitsIStart | eLogicalSideBitsIEnd,
- eLogicalSideBitsAll = eLogicalSideBitsBBoth | eLogicalSideBitsIBoth
-};
-
-enum LineRelativeDir {
- eLineRelativeDirOver = eLogicalSideBStart,
- eLineRelativeDirUnder = eLogicalSideBEnd,
- eLineRelativeDirLeft = eLogicalSideIStart,
- eLineRelativeDirRight = eLogicalSideIEnd
+enum class LineRelativeDir : uint8_t {
+ Over = static_cast<uint8_t>(LogicalSide::BStart),
+ Under = static_cast<uint8_t>(LogicalSide::BEnd),
+ Left = static_cast<uint8_t>(LogicalSide::IStart),
+ Right = static_cast<uint8_t>(LogicalSide::IEnd)
};
/**
@@ -146,54 +140,41 @@ class WritingMode {
/**
* Absolute inline flow direction
*/
- enum InlineDir {
- eInlineLTR = 0x00, // text flows horizontally left to right
- eInlineRTL = 0x02, // text flows horizontally right to left
- eInlineTTB = 0x01, // text flows vertically top to bottom
- eInlineBTT = 0x03, // text flows vertically bottom to top
+ enum class InlineDir : uint8_t {
+ LTR, // text flows horizontally left to right
+ RTL, // text flows horizontally right to left
+ TTB, // text flows vertically top to bottom
+ BTT, // text flows vertically bottom to top
};
/**
* Absolute block flow direction
*/
- enum BlockDir {
- eBlockTB = 0x00, // horizontal lines stack top to bottom
- eBlockRL = 0x01, // vertical lines stack right to left
- eBlockLR = 0x05, // vertical lines stack left to right
+ enum class BlockDir : uint8_t {
+ TB, // horizontal lines stack top to bottom
+ RL, // vertical lines stack right to left
+ LR, // vertical lines stack left to right
};
/**
- * Line-relative (bidi-relative) inline flow direction
- */
- enum BidiDir {
- eBidiLTR = 0x00, // inline flow matches bidi LTR text
- eBidiRTL = 0x10, // inline flow matches bidi RTL text
- };
-
- /**
- * Unknown writing mode (should never actually be stored or used anywhere).
- */
- enum { eUnknownWritingMode = 0xff };
-
- /**
* Return the absolute inline flow direction as an InlineDir
*/
InlineDir GetInlineDir() const {
- return InlineDir(mWritingMode._0 & eInlineMask);
+ if (IsVertical()) {
+ return IsInlineReversed() ? InlineDir::BTT : InlineDir::TTB;
+ }
+ return IsInlineReversed() ? InlineDir::RTL : InlineDir::LTR;
}
/**
* Return the absolute block flow direction as a BlockDir
*/
BlockDir GetBlockDir() const {
- return BlockDir(mWritingMode._0 & eBlockMask);
- }
-
- /**
- * Return the line-relative inline flow direction as a BidiDir
- */
- BidiDir GetBidiDir() const {
- return BidiDir((mWritingMode & StyleWritingMode::RTL)._0);
+ if (IsVertical()) {
+ return mWritingMode & StyleWritingMode::VERTICAL_LR ? BlockDir::LR
+ : BlockDir::RL;
+ }
+ return BlockDir::TB;
}
/**
@@ -207,14 +188,14 @@ class WritingMode {
}
/**
- * Return true if bidi direction is LTR. (Convenience method)
+ * Return true if bidi direction is LTR.
*/
- bool IsBidiLTR() const { return eBidiLTR == GetBidiDir(); }
+ bool IsBidiLTR() const { return !IsBidiRTL(); }
/**
- * Return true if bidi direction is RTL. (Convenience method)
+ * Return true if bidi direction is RTL.
*/
- bool IsBidiRTL() const { return eBidiRTL == GetBidiDir(); }
+ bool IsBidiRTL() const { return !!(mWritingMode & StyleWritingMode::RTL); }
/**
* True if it is vertical and vertical-lr, or is horizontal and bidi LTR.
@@ -233,12 +214,12 @@ class WritingMode {
/**
* True if vertical-mode block direction is LR (convenience method).
*/
- bool IsVerticalLR() const { return eBlockLR == GetBlockDir(); }
+ bool IsVerticalLR() const { return GetBlockDir() == BlockDir::LR; }
/**
* True if vertical-mode block direction is RL (convenience method).
*/
- bool IsVerticalRL() const { return eBlockRL == GetBlockDir(); }
+ bool IsVerticalRL() const { return GetBlockDir() == BlockDir::RL; }
/**
* True if vertical writing mode, i.e. when
@@ -329,11 +310,13 @@ class WritingMode {
static_assert(uint8_t(StyleWritingModeProperty::HorizontalTb) == 0 &&
uint8_t(StyleWritingModeProperty::VerticalRl) == 1 &&
uint8_t(StyleWritingModeProperty::VerticalLr) == 3 &&
- eLogicalAxisBlock == 0 && eLogicalAxisInline == 1 &&
- eAxisVertical == 0 && eAxisHorizontal == 1,
+ uint8_t(LogicalAxis::Block) == 0 &&
+ uint8_t(LogicalAxis::Inline) == 1 &&
+ uint8_t(PhysicalAxis::Vertical) == 0 &&
+ uint8_t(PhysicalAxis::Horizontal) == 1,
"unexpected writing-mode, logical axis or physical axis "
"constant values");
- return mozilla::PhysicalAxis((aWritingModeValue ^ aAxis) & 0x1);
+ return mozilla::PhysicalAxis((aWritingModeValue ^ uint8_t(aAxis)) & 0x1);
}
mozilla::PhysicalAxis PhysicalAxis(LogicalAxis aAxis) const {
@@ -366,7 +349,7 @@ class WritingMode {
// What's left of the writing-mode should be in the range 0-3:
NS_ASSERTION(aWritingModeValue < 4, "invalid aWritingModeValue value");
- return kLogicalBlockSides[aWritingModeValue][aEdge];
+ return kLogicalBlockSides[aWritingModeValue][static_cast<uint8_t>(aEdge)];
}
mozilla::Side PhysicalSideForInlineAxis(LogicalEdge aEdge) const {
@@ -403,13 +386,13 @@ class WritingMode {
// StyleWritingMode::INLINE_REVERSED, StyleWritingMode::VERTICAL_LR and
// StyleWritingMode::LINE_INVERTED bits. Use these four bits to index into
// kLogicalInlineSides.
- MOZ_ASSERT(StyleWritingMode::VERTICAL._0 == 0x01 &&
- StyleWritingMode::INLINE_REVERSED._0 == 0x02 &&
- StyleWritingMode::VERTICAL_LR._0 == 0x04 &&
- StyleWritingMode::LINE_INVERTED._0 == 0x08,
- "unexpected mask values");
- int index = mWritingMode._0 & 0x0F;
- return kLogicalInlineSides[index][aEdge];
+ static_assert(StyleWritingMode::VERTICAL._0 == 0x01 &&
+ StyleWritingMode::INLINE_REVERSED._0 == 0x02 &&
+ StyleWritingMode::VERTICAL_LR._0 == 0x04 &&
+ StyleWritingMode::LINE_INVERTED._0 == 0x08,
+ "Unexpected values for StyleWritingMode constants!");
+ uint8_t index = mWritingMode._0 & 0x0F;
+ return kLogicalInlineSides[index][static_cast<uint8_t>(aEdge)];
}
/**
@@ -418,9 +401,9 @@ class WritingMode {
*/
mozilla::Side PhysicalSide(LogicalSide aSide) const {
if (IsBlock(aSide)) {
- MOZ_ASSERT(StyleWritingMode::VERTICAL._0 == 0x01 &&
- StyleWritingMode::VERTICAL_LR._0 == 0x04,
- "unexpected mask values");
+ static_assert(StyleWritingMode::VERTICAL._0 == 0x01 &&
+ StyleWritingMode::VERTICAL_LR._0 == 0x04,
+ "Unexpected values for StyleWritingMode constants!");
const uint8_t wm =
((mWritingMode & StyleWritingMode::VERTICAL_LR)._0 >> 1) |
(mWritingMode & StyleWritingMode::VERTICAL)._0;
@@ -445,47 +428,47 @@ class WritingMode {
static const LogicalSide kPhysicalToLogicalSides[][4] = {
// top right
// bottom left
- { eLogicalSideBStart, eLogicalSideIEnd,
- eLogicalSideBEnd, eLogicalSideIStart }, // horizontal-tb ltr
- { eLogicalSideIStart, eLogicalSideBStart,
- eLogicalSideIEnd, eLogicalSideBEnd }, // vertical-rl ltr
- { eLogicalSideBStart, eLogicalSideIStart,
- eLogicalSideBEnd, eLogicalSideIEnd }, // horizontal-tb rtl
- { eLogicalSideIEnd, eLogicalSideBStart,
- eLogicalSideIStart, eLogicalSideBEnd }, // vertical-rl rtl
- { eLogicalSideBEnd, eLogicalSideIStart,
- eLogicalSideBStart, eLogicalSideIEnd }, // (horizontal-bt) (inv) ltr
- { eLogicalSideIStart, eLogicalSideBEnd,
- eLogicalSideIEnd, eLogicalSideBStart }, // vertical-lr sw-left rtl
- { eLogicalSideBEnd, eLogicalSideIEnd,
- eLogicalSideBStart, eLogicalSideIStart }, // (horizontal-bt) (inv) rtl
- { eLogicalSideIEnd, eLogicalSideBEnd,
- eLogicalSideIStart, eLogicalSideBStart }, // vertical-lr sw-left ltr
- { eLogicalSideBStart, eLogicalSideIEnd,
- eLogicalSideBEnd, eLogicalSideIStart }, // horizontal-tb (inv) rtl
- { eLogicalSideIStart, eLogicalSideBStart,
- eLogicalSideIEnd, eLogicalSideBEnd }, // vertical-rl sw-left rtl
- { eLogicalSideBStart, eLogicalSideIStart,
- eLogicalSideBEnd, eLogicalSideIEnd }, // horizontal-tb (inv) ltr
- { eLogicalSideIEnd, eLogicalSideBStart,
- eLogicalSideIStart, eLogicalSideBEnd }, // vertical-rl sw-left ltr
- { eLogicalSideBEnd, eLogicalSideIEnd,
- eLogicalSideBStart, eLogicalSideIStart }, // (horizontal-bt) ltr
- { eLogicalSideIStart, eLogicalSideBEnd,
- eLogicalSideIEnd, eLogicalSideBStart }, // vertical-lr ltr
- { eLogicalSideBEnd, eLogicalSideIStart,
- eLogicalSideBStart, eLogicalSideIEnd }, // (horizontal-bt) rtl
- { eLogicalSideIEnd, eLogicalSideBEnd,
- eLogicalSideIStart, eLogicalSideBStart }, // vertical-lr rtl
+ { LogicalSide::BStart, LogicalSide::IEnd,
+ LogicalSide::BEnd, LogicalSide::IStart }, // horizontal-tb ltr
+ { LogicalSide::IStart, LogicalSide::BStart,
+ LogicalSide::IEnd, LogicalSide::BEnd }, // vertical-rl ltr
+ { LogicalSide::BStart, LogicalSide::IStart,
+ LogicalSide::BEnd, LogicalSide::IEnd }, // horizontal-tb rtl
+ { LogicalSide::IEnd, LogicalSide::BStart,
+ LogicalSide::IStart, LogicalSide::BEnd }, // vertical-rl rtl
+ { LogicalSide::BEnd, LogicalSide::IStart,
+ LogicalSide::BStart, LogicalSide::IEnd }, // (horizontal-bt) (inv) ltr
+ { LogicalSide::IStart, LogicalSide::BEnd,
+ LogicalSide::IEnd, LogicalSide::BStart }, // vertical-lr sw-left rtl
+ { LogicalSide::BEnd, LogicalSide::IEnd,
+ LogicalSide::BStart, LogicalSide::IStart }, // (horizontal-bt) (inv) rtl
+ { LogicalSide::IEnd, LogicalSide::BEnd,
+ LogicalSide::IStart, LogicalSide::BStart }, // vertical-lr sw-left ltr
+ { LogicalSide::BStart, LogicalSide::IEnd,
+ LogicalSide::BEnd, LogicalSide::IStart }, // horizontal-tb (inv) rtl
+ { LogicalSide::IStart, LogicalSide::BStart,
+ LogicalSide::IEnd, LogicalSide::BEnd }, // vertical-rl sw-left rtl
+ { LogicalSide::BStart, LogicalSide::IStart,
+ LogicalSide::BEnd, LogicalSide::IEnd }, // horizontal-tb (inv) ltr
+ { LogicalSide::IEnd, LogicalSide::BStart,
+ LogicalSide::IStart, LogicalSide::BEnd }, // vertical-rl sw-left ltr
+ { LogicalSide::BEnd, LogicalSide::IEnd,
+ LogicalSide::BStart, LogicalSide::IStart }, // (horizontal-bt) ltr
+ { LogicalSide::IStart, LogicalSide::BEnd,
+ LogicalSide::IEnd, LogicalSide::BStart }, // vertical-lr ltr
+ { LogicalSide::BEnd, LogicalSide::IStart,
+ LogicalSide::BStart, LogicalSide::IEnd }, // (horizontal-bt) rtl
+ { LogicalSide::IEnd, LogicalSide::BEnd,
+ LogicalSide::IStart, LogicalSide::BStart }, // vertical-lr rtl
};
// clang-format on
- MOZ_ASSERT(StyleWritingMode::VERTICAL._0 == 0x01 &&
- StyleWritingMode::INLINE_REVERSED._0 == 0x02 &&
- StyleWritingMode::VERTICAL_LR._0 == 0x04 &&
- StyleWritingMode::LINE_INVERTED._0 == 0x08,
- "unexpected mask values");
- int index = mWritingMode._0 & 0x0F;
+ static_assert(StyleWritingMode::VERTICAL._0 == 0x01 &&
+ StyleWritingMode::INLINE_REVERSED._0 == 0x02 &&
+ StyleWritingMode::VERTICAL_LR._0 == 0x04 &&
+ StyleWritingMode::LINE_INVERTED._0 == 0x08,
+ "Unexpected values for StyleWritingMode constants!");
+ uint8_t index = mWritingMode._0 & 0x0F;
return kPhysicalToLogicalSides[index][aSide];
}
@@ -570,7 +553,7 @@ class WritingMode {
bool ParallelAxisStartsOnSameSide(LogicalAxis aLogicalAxis,
const WritingMode& aOther) const {
mozilla::Side myStartSide =
- this->PhysicalSide(MakeLogicalSide(aLogicalAxis, eLogicalEdgeStart));
+ this->PhysicalSide(MakeLogicalSide(aLogicalAxis, LogicalEdge::Start));
// Figure out which of aOther's axes is parallel to |this| WritingMode's
// aLogicalAxis, and get its physical start side as well.
@@ -578,7 +561,7 @@ class WritingMode {
? GetOrthogonalAxis(aLogicalAxis)
: aLogicalAxis;
mozilla::Side otherWMStartSide =
- aOther.PhysicalSide(MakeLogicalSide(otherWMAxis, eLogicalEdgeStart));
+ aOther.PhysicalSide(MakeLogicalSide(otherWMAxis, LogicalEdge::Start));
NS_ASSERTION(myStartSide % 2 == otherWMStartSide % 2,
"Should end up with sides in the same physical axis");
@@ -601,10 +584,15 @@ class WritingMode {
friend struct widget::IMENotification;
/**
+ * Unknown writing mode (should never actually be stored or used anywhere).
+ */
+ static constexpr uint8_t kUnknownWritingMode = 0xff;
+
+ /**
* Return a WritingMode representing an unknown value.
*/
static inline WritingMode Unknown() {
- return WritingMode(eUnknownWritingMode);
+ return WritingMode(kUnknownWritingMode);
}
/**
@@ -614,12 +602,6 @@ class WritingMode {
explicit WritingMode(uint8_t aValue) : mWritingMode{aValue} {}
StyleWritingMode mWritingMode;
-
- enum Masks {
- // Masks for output enums
- eInlineMask = 0x03, // VERTICAL | INLINE_REVERSED
- eBlockMask = 0x05, // VERTICAL | VERTICAL_LR
- };
};
inline std::ostream& operator<<(std::ostream& aStream, const WritingMode& aWM) {
@@ -732,7 +714,7 @@ class LogicalPoint {
return mPoint.y;
}
nscoord Pos(LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == eLogicalAxisInline ? I(aWM) : B(aWM);
+ return aAxis == LogicalAxis::Inline ? I(aWM) : B(aWM);
}
nscoord LineRelative(WritingMode aWritingMode,
const nsSize& aContainerSize) const // line-axis
@@ -761,7 +743,7 @@ class LogicalPoint {
return mPoint.y;
}
nscoord& Pos(LogicalAxis aAxis, WritingMode aWM) {
- return aAxis == eLogicalAxisInline ? I(aWM) : B(aWM);
+ return aAxis == LogicalAxis::Inline ? I(aWM) : B(aWM);
}
/**
@@ -808,7 +790,7 @@ class LogicalPoint {
LogicalPoint operator+(const LogicalPoint& aOther) const {
CHECK_WRITING_MODE(aOther.GetWritingMode());
// In non-debug builds, LogicalPoint does not store the WritingMode,
- // so the first parameter here (which will always be eUnknownWritingMode)
+ // so the first parameter here (which will always be WritingMode::Unknown())
// is ignored.
return LogicalPoint(GetWritingMode(), mPoint.x + aOther.mPoint.x,
mPoint.y + aOther.mPoint.y);
@@ -824,7 +806,7 @@ class LogicalPoint {
LogicalPoint operator-(const LogicalPoint& aOther) const {
CHECK_WRITING_MODE(aOther.GetWritingMode());
// In non-debug builds, LogicalPoint does not store the WritingMode,
- // so the first parameter here (which will always be eUnknownWritingMode)
+ // so the first parameter here (which will always be WritingMode::Unknown())
// is ignored.
return LogicalPoint(GetWritingMode(), mPoint.x - aOther.mPoint.x,
mPoint.y - aOther.mPoint.y);
@@ -847,7 +829,7 @@ class LogicalPoint {
/**
* NOTE that in non-DEBUG builds, GetWritingMode() always returns
- * eUnknownWritingMode, as the current mode is not stored in the logical-
+ * WritingMode::Unknown(), as the current mode is not stored in the logical-
* geometry classes. Therefore, this method is private; it is used ONLY
* by the DEBUG-mode checking macros in this class and its friends;
* other code is not allowed to ask a logical point for its writing mode,
@@ -952,7 +934,7 @@ class LogicalSize {
return mSize.height;
}
nscoord Size(LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == eLogicalAxisInline ? ISize(aWM) : BSize(aWM);
+ return aAxis == LogicalAxis::Inline ? ISize(aWM) : BSize(aWM);
}
nscoord Width(WritingMode aWritingMode) const {
@@ -978,7 +960,7 @@ class LogicalSize {
return mSize.height;
}
nscoord& Size(LogicalAxis aAxis, WritingMode aWM) {
- return aAxis == eLogicalAxisInline ? ISize(aWM) : BSize(aWM);
+ return aAxis == LogicalAxis::Inline ? ISize(aWM) : BSize(aWM);
}
/**
@@ -1097,48 +1079,51 @@ class LogicalSize {
* LogicalSides represents a set of logical sides.
*/
struct LogicalSides final {
+ static constexpr EnumSet<LogicalSide> BBoth{LogicalSide::BStart,
+ LogicalSide::BEnd};
+ static constexpr EnumSet<LogicalSide> IBoth{LogicalSide::IStart,
+ LogicalSide::IEnd};
+ static constexpr EnumSet<LogicalSide> All{
+ LogicalSide::BStart, LogicalSide::BEnd, LogicalSide::IStart,
+ LogicalSide::IEnd};
+
explicit LogicalSides(WritingMode aWritingMode)
+#ifdef DEBUG
+ : mWritingMode(aWritingMode)
+#endif
+ {
+ }
+ LogicalSides(WritingMode aWritingMode, LogicalSides aSides)
:
#ifdef DEBUG
mWritingMode(aWritingMode),
#endif
- mBits(0) {
+ mSides(aSides.mSides) {
}
- LogicalSides(WritingMode aWritingMode, LogicalSideBits aSideBits)
+ LogicalSides(WritingMode aWritingMode, EnumSet<LogicalSide> aSides)
:
#ifdef DEBUG
mWritingMode(aWritingMode),
#endif
- mBits(aSideBits) {
- MOZ_ASSERT((aSideBits & ~eLogicalSideBitsAll) == 0, "illegal side bits");
- }
- bool IsEmpty() const { return mBits == 0; }
- bool BStart() const { return mBits & eLogicalSideBitsBStart; }
- bool BEnd() const { return mBits & eLogicalSideBitsBEnd; }
- bool IStart() const { return mBits & eLogicalSideBitsIStart; }
- bool IEnd() const { return mBits & eLogicalSideBitsIEnd; }
- bool Contains(LogicalSideBits aSideBits) const {
- MOZ_ASSERT((aSideBits & ~eLogicalSideBitsAll) == 0, "illegal side bits");
- return (mBits & aSideBits) == aSideBits;
- }
- LogicalSides operator|(LogicalSides aOther) const {
- CHECK_WRITING_MODE(aOther.GetWritingMode());
- return *this | LogicalSideBits(aOther.mBits);
- }
- LogicalSides operator|(LogicalSideBits aSideBits) const {
- return LogicalSides(GetWritingMode(), LogicalSideBits(mBits | aSideBits));
- }
- LogicalSides& operator|=(LogicalSides aOther) {
- CHECK_WRITING_MODE(aOther.GetWritingMode());
- return *this |= LogicalSideBits(aOther.mBits);
+ mSides(aSides) {
+ }
+ bool IsEmpty() const { return mSides.isEmpty(); }
+ bool BStart() const { return mSides.contains(LogicalSide::BStart); }
+ bool BEnd() const { return mSides.contains(LogicalSide::BEnd); }
+ bool IStart() const { return mSides.contains(LogicalSide::IStart); }
+ bool IEnd() const { return mSides.contains(LogicalSide::IEnd); }
+ bool Contains(LogicalSide aSide) const { return mSides.contains(aSide); }
+ LogicalSides& operator+=(LogicalSides aOther) {
+ mSides += aOther.mSides;
+ return *this;
}
- LogicalSides& operator|=(LogicalSideBits aSideBits) {
- mBits |= aSideBits;
+ LogicalSides& operator+=(LogicalSide aOther) {
+ mSides += aOther;
return *this;
}
bool operator==(LogicalSides aOther) const {
CHECK_WRITING_MODE(aOther.GetWritingMode());
- return mBits == aOther.mBits;
+ return mSides == aOther.mSides;
}
bool operator!=(LogicalSides aOther) const {
CHECK_WRITING_MODE(aOther.GetWritingMode());
@@ -1155,7 +1140,7 @@ struct LogicalSides final {
#ifdef DEBUG
WritingMode mWritingMode;
#endif
- uint8_t mBits;
+ EnumSet<LogicalSide> mSides;
};
/**
@@ -1234,10 +1219,10 @@ class LogicalMargin {
return mMargin.bottom;
}
nscoord Start(LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == eLogicalAxisInline ? IStart(aWM) : BStart(aWM);
+ return aAxis == LogicalAxis::Inline ? IStart(aWM) : BStart(aWM);
}
nscoord End(LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == eLogicalAxisInline ? IEnd(aWM) : BEnd(aWM);
+ return aAxis == LogicalAxis::Inline ? IEnd(aWM) : BEnd(aWM);
}
nscoord& IStart(WritingMode aWritingMode) // inline-start margin
@@ -1261,10 +1246,10 @@ class LogicalMargin {
return mMargin.bottom;
}
nscoord& Start(LogicalAxis aAxis, WritingMode aWM) {
- return aAxis == eLogicalAxisInline ? IStart(aWM) : BStart(aWM);
+ return aAxis == LogicalAxis::Inline ? IStart(aWM) : BStart(aWM);
}
nscoord& End(LogicalAxis aAxis, WritingMode aWM) {
- return aAxis == eLogicalAxisInline ? IEnd(aWM) : BEnd(aWM);
+ return aAxis == LogicalAxis::Inline ? IEnd(aWM) : BEnd(aWM);
}
nscoord IStartEnd(WritingMode aWritingMode) const // inline margins
@@ -1278,18 +1263,18 @@ class LogicalMargin {
return mMargin.TopBottom();
}
nscoord StartEnd(LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == eLogicalAxisInline ? IStartEnd(aWM) : BStartEnd(aWM);
+ return aAxis == LogicalAxis::Inline ? IStartEnd(aWM) : BStartEnd(aWM);
}
nscoord Side(LogicalSide aSide, WritingMode aWM) const {
switch (aSide) {
- case eLogicalSideBStart:
+ case LogicalSide::BStart:
return BStart(aWM);
- case eLogicalSideBEnd:
+ case LogicalSide::BEnd:
return BEnd(aWM);
- case eLogicalSideIStart:
+ case LogicalSide::IStart:
return IStart(aWM);
- case eLogicalSideIEnd:
+ case LogicalSide::IEnd:
return IEnd(aWM);
}
@@ -1298,13 +1283,13 @@ class LogicalMargin {
}
nscoord& Side(LogicalSide aSide, WritingMode aWM) {
switch (aSide) {
- case eLogicalSideBStart:
+ case LogicalSide::BStart:
return BStart(aWM);
- case eLogicalSideBEnd:
+ case LogicalSide::BEnd:
return BEnd(aWM);
- case eLogicalSideIStart:
+ case LogicalSide::IStart:
return IStart(aWM);
- case eLogicalSideIEnd:
+ case LogicalSide::IEnd:
return IEnd(aWM);
}
@@ -1646,13 +1631,13 @@ class LogicalRect {
}
nscoord Start(LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == eLogicalAxisInline ? IStart(aWM) : BStart(aWM);
+ return aAxis == LogicalAxis::Inline ? IStart(aWM) : BStart(aWM);
}
nscoord End(LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == eLogicalAxisInline ? IEnd(aWM) : BEnd(aWM);
+ return aAxis == LogicalAxis::Inline ? IEnd(aWM) : BEnd(aWM);
}
nscoord Size(LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == eLogicalAxisInline ? ISize(aWM) : BSize(aWM);
+ return aAxis == LogicalAxis::Inline ? ISize(aWM) : BSize(aWM);
}
/**
@@ -1680,10 +1665,10 @@ class LogicalRect {
return mBSize;
}
nscoord& Start(LogicalAxis aAxis, WritingMode aWM) {
- return aAxis == eLogicalAxisInline ? IStart(aWM) : BStart(aWM);
+ return aAxis == LogicalAxis::Inline ? IStart(aWM) : BStart(aWM);
}
nscoord& Size(LogicalAxis aAxis, WritingMode aWM) {
- return aAxis == eLogicalAxisInline ? ISize(aWM) : BSize(aWM);
+ return aAxis == LogicalAxis::Inline ? ISize(aWM) : BSize(aWM);
}
/**
@@ -2055,22 +2040,22 @@ const T& StyleRect<T>::Get(WritingMode aWM, LogicalSide aSide) const {
template <typename T>
const T& StyleRect<T>::GetIStart(WritingMode aWM) const {
- return Get(aWM, eLogicalSideIStart);
+ return Get(aWM, LogicalSide::IStart);
}
template <typename T>
const T& StyleRect<T>::GetBStart(WritingMode aWM) const {
- return Get(aWM, eLogicalSideBStart);
+ return Get(aWM, LogicalSide::BStart);
}
template <typename T>
const T& StyleRect<T>::GetIEnd(WritingMode aWM) const {
- return Get(aWM, eLogicalSideIEnd);
+ return Get(aWM, LogicalSide::IEnd);
}
template <typename T>
const T& StyleRect<T>::GetBEnd(WritingMode aWM) const {
- return Get(aWM, eLogicalSideBEnd);
+ return Get(aWM, LogicalSide::BEnd);
}
template <typename T>
@@ -2080,38 +2065,38 @@ T& StyleRect<T>::Get(WritingMode aWM, LogicalSide aSide) {
template <typename T>
T& StyleRect<T>::GetIStart(WritingMode aWM) {
- return Get(aWM, eLogicalSideIStart);
+ return Get(aWM, LogicalSide::IStart);
}
template <typename T>
T& StyleRect<T>::GetBStart(WritingMode aWM) {
- return Get(aWM, eLogicalSideBStart);
+ return Get(aWM, LogicalSide::BStart);
}
template <typename T>
T& StyleRect<T>::GetIEnd(WritingMode aWM) {
- return Get(aWM, eLogicalSideIEnd);
+ return Get(aWM, LogicalSide::IEnd);
}
template <typename T>
T& StyleRect<T>::GetBEnd(WritingMode aWM) {
- return Get(aWM, eLogicalSideBEnd);
+ return Get(aWM, LogicalSide::BEnd);
}
template <typename T>
const T& StyleRect<T>::Start(mozilla::LogicalAxis aAxis,
mozilla::WritingMode aWM) const {
- return Get(aWM, aAxis == mozilla::eLogicalAxisInline
- ? mozilla::eLogicalSideIStart
- : mozilla::eLogicalSideBStart);
+ return Get(aWM, aAxis == mozilla::LogicalAxis::Inline
+ ? mozilla::LogicalSide::IStart
+ : mozilla::LogicalSide::BStart);
}
template <typename T>
const T& StyleRect<T>::End(mozilla::LogicalAxis aAxis,
mozilla::WritingMode aWM) const {
- return Get(aWM, aAxis == mozilla::eLogicalAxisInline
- ? mozilla::eLogicalSideIEnd
- : mozilla::eLogicalSideBEnd);
+ return Get(aWM, aAxis == mozilla::LogicalAxis::Inline
+ ? mozilla::LogicalSide::IEnd
+ : mozilla::LogicalSide::BEnd);
}
inline AspectRatio AspectRatio::ConvertToWritingMode(
@@ -2147,15 +2132,15 @@ inline const mozilla::StyleMaxSize& nsStylePosition::MaxBSize(
}
inline const mozilla::StyleSize& nsStylePosition::Size(
mozilla::LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == mozilla::eLogicalAxisInline ? ISize(aWM) : BSize(aWM);
+ return aAxis == mozilla::LogicalAxis::Inline ? ISize(aWM) : BSize(aWM);
}
inline const mozilla::StyleSize& nsStylePosition::MinSize(
mozilla::LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == mozilla::eLogicalAxisInline ? MinISize(aWM) : MinBSize(aWM);
+ return aAxis == mozilla::LogicalAxis::Inline ? MinISize(aWM) : MinBSize(aWM);
}
inline const mozilla::StyleMaxSize& nsStylePosition::MaxSize(
mozilla::LogicalAxis aAxis, WritingMode aWM) const {
- return aAxis == mozilla::eLogicalAxisInline ? MaxISize(aWM) : MaxBSize(aWM);
+ return aAxis == mozilla::LogicalAxis::Inline ? MaxISize(aWM) : MaxBSize(aWM);
}
inline bool nsStylePosition::ISizeDependsOnContainer(WritingMode aWM) const {
@@ -2205,26 +2190,26 @@ inline bool nsStyleMargin::HasInlineAxisAuto(mozilla::WritingMode aWM) const {
}
inline bool nsStyleMargin::HasAuto(mozilla::LogicalAxis aAxis,
mozilla::WritingMode aWM) const {
- return aAxis == mozilla::eLogicalAxisInline ? HasInlineAxisAuto(aWM)
- : HasBlockAxisAuto(aWM);
+ return aAxis == mozilla::LogicalAxis::Inline ? HasInlineAxisAuto(aWM)
+ : HasBlockAxisAuto(aWM);
}
inline mozilla::StyleAlignFlags nsStylePosition::UsedSelfAlignment(
mozilla::LogicalAxis aAxis, const mozilla::ComputedStyle* aParent) const {
- return aAxis == mozilla::eLogicalAxisBlock ? UsedAlignSelf(aParent)._0
- : UsedJustifySelf(aParent)._0;
+ return aAxis == mozilla::LogicalAxis::Block ? UsedAlignSelf(aParent)._0
+ : UsedJustifySelf(aParent)._0;
}
inline mozilla::StyleContentDistribution nsStylePosition::UsedContentAlignment(
mozilla::LogicalAxis aAxis) const {
- return aAxis == mozilla::eLogicalAxisBlock ? mAlignContent : mJustifyContent;
+ return aAxis == mozilla::LogicalAxis::Block ? mAlignContent : mJustifyContent;
}
inline mozilla::StyleContentDistribution nsStylePosition::UsedTracksAlignment(
mozilla::LogicalAxis aAxis, uint32_t aIndex) const {
using T = mozilla::StyleAlignFlags;
const auto& tracksAlignment =
- aAxis == mozilla::eLogicalAxisBlock ? mAlignTracks : mJustifyTracks;
+ aAxis == mozilla::LogicalAxis::Block ? mAlignTracks : mJustifyTracks;
if (MOZ_LIKELY(tracksAlignment.IsEmpty())) {
// An empty array encodes the initial value, 'normal', which behaves as
// 'start' for Grid containers.
diff --git a/layout/generic/crashtests/1410243-1.html b/layout/generic/crashtests/1410243-1.html
new file mode 100644
index 0000000000..42a005e85b
--- /dev/null
+++ b/layout/generic/crashtests/1410243-1.html
@@ -0,0 +1,26 @@
+<!-- //DDBEGIN -->
+<style>
+* { margin-bottom: -1em; font-size: xx-large; }
+.cl1 { Max-height: 93; column-width: 0; position: fixed; }
+</style>
+<script>
+function eventhandler1() {
+try { htmlvar0002.style.setProperty("display", "grid"); } catch(e) { }
+try { svgvar0001.clientWidth; } catch(e) { }
+try { htmlvar0002.style.setProperty("grid-template", "0px/0px"); } catch(e) { }
+}
+</script>
+<details class="cl1" open="" ontoggle="eventhandler1()">
+<summary id="svgvar0001"/></summary>
+<a>
+<ol id="htmlvar0002">
+<keygen>
+>
+A
+AA
+A
+A
+A
+A
+<a>
+<!-- //DDEND -->
diff --git a/layout/generic/crashtests/1741488-1.html b/layout/generic/crashtests/1741488-1.html
new file mode 100644
index 0000000000..74d7c49feb
--- /dev/null
+++ b/layout/generic/crashtests/1741488-1.html
@@ -0,0 +1,23 @@
+<html class="reftest-wait">
+<style>
+#b {
+ writing-mode: vertical-rl;
+ content: url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=);
+}
+</style>
+<script>
+let pp;
+document.addEventListener("MozReftestInvalidate", () => {
+ a.after("1")
+ a.insertAdjacentHTML("afterEnd", b.outerHTML);
+ pp = SpecialPowers.wrap(self).printPreview();
+ setTimeout(function() {
+ pp.close();
+ document.documentElement.className = "";
+ }, 400);
+})
+</script>
+<math>
+<munder>
+<mn id="a">2</mn>
+<dl id="b"></dl>
diff --git a/layout/generic/crashtests/1881375-1-helper.html b/layout/generic/crashtests/1881375-1-helper.html
new file mode 100644
index 0000000000..5c79e4981f
--- /dev/null
+++ b/layout/generic/crashtests/1881375-1-helper.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<script>
+// Notify our parent and reload ourselves.
+function notifyAndReload() {
+ if (window.parent) {
+ window.parent.postMessage("reloaded", "*");
+ }
+ window.location.reload(true)
+}
+</script>
+<style>
+*:nth-child(even) {
+ height: 16em;
+ list-style-image: url(data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=);
+}
+#a {
+ display: inline-grid;
+ grid-auto-flow: column dense;
+}
+#b {
+ padding-top: 8192vmax;
+}
+* {
+ align-content: center;
+ column-width: 1em;
+ float: inline-end;
+}
+</style>
+<body onload="setTimeout(notifyAndReload, 0)">
+<picture></picture>
+<iframe></iframe>
+<isindex>
+<svg></svg>
+<samp id="a">
+<q>
+<a id="b">
+</q>
+<li>
diff --git a/layout/generic/crashtests/1881375-1.html b/layout/generic/crashtests/1881375-1.html
new file mode 100644
index 0000000000..8cef260433
--- /dev/null
+++ b/layout/generic/crashtests/1881375-1.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<script>
+// Loop count for the handler below. This value seems to be enough for the
+// crashtest to be likely to trigger the crash.
+const MAX_LOADS = 3;
+let loadCount = 0;
+
+// Handler which gets invoked by the iframe whenever it completes a load
+// (and dynamically reloads itself). This lets us allow the testcase to
+// reload over and over (as seems to be required to trigger the crash),
+// while also keeping the test duration reasonably bounded.
+window.addEventListener(
+ "message",
+ (event) => {
+ if (loadCount++ == MAX_LOADS) {
+ // After MAX_LOADS reloads of the iframe, call ourselves done.
+ myIframe.remove();
+ document.documentElement.className = "";
+ }
+ }
+);
+
+</script>
+<iframe id="myIframe" src="1881375-1-helper.html"></iframe>
diff --git a/layout/generic/crashtests/481921.ogg b/layout/generic/crashtests/481921.ogg
deleted file mode 100644
index 0c41c3cd6b..0000000000
--- a/layout/generic/crashtests/481921.ogg
+++ /dev/null
Binary files differ
diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list
index 1c184739d7..9044b12f8d 100644
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -394,7 +394,7 @@ load 571618-1.svg
asserts(0-1) load 571975-1.html # bug 574889
load 571995.xhtml
load 574958.xhtml
-asserts(0-6) load 578977.html # bug 757305
+asserts(0-8) load 578977.html # bug 757305
load 580504-1.xhtml
load 582793-1.html
load 585598-1.xhtml
@@ -622,8 +622,8 @@ load flex-nested-abspos-1.html
pref(dom.meta-viewport.enabled,true) test-pref(font.size.inflation.emPerLine,15) asserts(0-100) load font-inflation-762332.html # bug 762332
asserts-if(Android||cocoaWidget,0-2) load outline-on-frameset.xhtml # bug 762332, bug 1594135
load summary-position-out-of-flow.html
-pref(widget.windows.window_occlusion_tracking.enabled,false) load text-overflow-bug666751-1.html # Bug 1819154
-pref(widget.windows.window_occlusion_tracking.enabled,false) load text-overflow-bug666751-2.html # Bug 1819154
+load text-overflow-bug666751-1.html
+load text-overflow-bug666751-2.html
load text-overflow-bug670564.xhtml
load text-overflow-bug671796.xhtml
load text-overflow-bug713610.html
@@ -678,6 +678,7 @@ load 1405443.html
load 1405813.html
load 1405896.html
load 1406252-1.html
+asserts(2) load 1410243-1.html # assertion is bug 574889
load 1415185.html
load 1416544.html
load 1427824.html
@@ -804,6 +805,7 @@ load 1728319.html
asserts(2-8) load 1730506.html # asserts from integer overflow & bogus sizes
asserts(1-4) load 1730570.html # asserts from integer overflow & bogus sizes
load 1734015.html
+skip-if(Android) load 1741488-1.html # printPreview doesn't work on android
load 1776079.html
asserts(0-2) load 1791606.html
load 1799749.html
@@ -812,3 +814,4 @@ load 1816574.html
load 1821603.html
load 1822118.html
load 1825434.html
+asserts(0-85) load 1881375-1.html # bug 1890687 - assertions about fragmentation invariants, failing many times because the test runs in a loop
diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp
index 3cfe7b5b2d..5afd9f33f2 100644
--- a/layout/generic/nsAbsoluteContainingBlock.cpp
+++ b/layout/generic/nsAbsoluteContainingBlock.cpp
@@ -372,8 +372,8 @@ bool nsAbsoluteContainingBlock::FrameDependsOnContainer(nsIFrame* f,
// and be positioned relative to the containing block right edge.
// 'left' length and 'right' auto is the only combination we can be
// sure of.
- if ((wm.GetInlineDir() == WritingMode::eInlineRTL ||
- wm.GetBlockDir() == WritingMode::eBlockRL) &&
+ if ((wm.GetInlineDir() == WritingMode::InlineDir::RTL ||
+ wm.GetBlockDir() == WritingMode::BlockDir::RL) &&
!pos->mOffset.Get(eSideRight).IsAuto()) {
return true;
}
@@ -383,7 +383,7 @@ bool nsAbsoluteContainingBlock::FrameDependsOnContainer(nsIFrame* f,
return true;
}
// See comment above for width changes.
- if (wm.GetInlineDir() == WritingMode::eInlineBTT &&
+ if (wm.GetInlineDir() == WritingMode::InlineDir::BTT &&
!pos->mOffset.Get(eSideBottom).IsAuto()) {
return true;
}
@@ -522,7 +522,7 @@ static nscoord OffsetToAlignedStaticPos(const ReflowInput& aKidReflowInput,
return 0; // (leave the child at the start of its alignment container)
}
- nscoord alignAreaSizeInAxis = (pcAxis == eLogicalAxisInline)
+ nscoord alignAreaSizeInAxis = (pcAxis == LogicalAxis::Inline)
? alignAreaSize.ISize(pcWM)
: alignAreaSize.BSize(pcWM);
@@ -619,7 +619,7 @@ void nsAbsoluteContainingBlock::ResolveSizeDependentOffsets(
placeholderContainer = GetPlaceholderContainer(aKidReflowInput.mFrame);
nscoord offset = OffsetToAlignedStaticPos(
aKidReflowInput, aKidSize, logicalCBSizeOuterWM, placeholderContainer,
- outerWM, eLogicalAxisInline);
+ outerWM, LogicalAxis::Inline);
// Shift IStart from its current position (at start corner of the
// alignment container) by the returned offset. And set IEnd to the
// distance between the kid's end edge to containing block's end edge.
@@ -639,7 +639,7 @@ void nsAbsoluteContainingBlock::ResolveSizeDependentOffsets(
}
nscoord offset = OffsetToAlignedStaticPos(
aKidReflowInput, aKidSize, logicalCBSizeOuterWM, placeholderContainer,
- outerWM, eLogicalAxisBlock);
+ outerWM, LogicalAxis::Block);
// Shift BStart from its current position (at start corner of the
// alignment container) by the returned offset. And set BEnd to the
// distance between the kid's end edge to containing block's end edge.
diff --git a/layout/generic/nsBackdropFrame.cpp b/layout/generic/nsBackdropFrame.cpp
index 20d3fcd368..178caa3e0c 100644
--- a/layout/generic/nsBackdropFrame.cpp
+++ b/layout/generic/nsBackdropFrame.cpp
@@ -70,7 +70,6 @@ void nsBackdropFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsBackdropFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// Note that this frame is a child of the viewport frame.
diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp
index a25e4e996e..4b314bfcaf 100644
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -813,8 +813,6 @@ nscoord nsBlockFrame::GetMinISize(gfxContext* aRenderingContext) {
return firstInFlow->GetMinISize(aRenderingContext);
}
- DISPLAY_MIN_INLINE_SIZE(this, mCachedMinISize);
-
CheckIntrinsicCacheAgainstShrinkWrapState();
if (mCachedMinISize != NS_INTRINSIC_ISIZE_UNKNOWN) {
@@ -902,8 +900,6 @@ nscoord nsBlockFrame::GetPrefISize(gfxContext* aRenderingContext) {
return firstInFlow->GetPrefISize(aRenderingContext);
}
- DISPLAY_PREF_INLINE_SIZE(this, mCachedPrefISize);
-
CheckIntrinsicCacheAgainstShrinkWrapState();
if (mCachedPrefISize != NS_INTRINSIC_ISIZE_UNKNOWN) {
@@ -1190,7 +1186,8 @@ static bool IsLineClampRoot(const nsBlockFrame* aFrame) {
return false;
}
- if (StaticPrefs::layout_css_webkit_line_clamp_block_enabled()) {
+ if (StaticPrefs::layout_css_webkit_line_clamp_block_enabled() ||
+ aFrame->PresContext()->Document()->ChromeRulesEnabled()) {
return true;
}
@@ -1348,7 +1345,6 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsBlockFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
#ifdef DEBUG
@@ -1453,14 +1449,18 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
// maintain when doing text-wrap: balance.
struct BalanceTarget {
// If line-clamp is in effect, mContent and mOffset indicate the starting
- // position of the first line after the clamp limit. If line-clamp is not
- // in use, mContent is null and mOffset is the total number of lines that
- // the block must contain.
+ // position of the first line after the clamp limit, and mBlockCoord is the
+ // block-axis offset of its position.
+ // If line-clamp is not in use, mContent is null, mOffset is the total
+ // number of lines that the block must contain, and mBlockCoord is its end
+ // edge in the block direction.
nsIContent* mContent = nullptr;
int32_t mOffset = -1;
+ nscoord mBlockCoord = 0;
bool operator==(const BalanceTarget& aOther) const {
- return mContent == aOther.mContent && mOffset == aOther.mOffset;
+ return mContent == aOther.mContent && mOffset == aOther.mOffset &&
+ mBlockCoord == aOther.mBlockCoord;
}
bool operator!=(const BalanceTarget& aOther) const {
return !(*this == aOther);
@@ -1506,7 +1506,7 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
auto* textFrame = static_cast<nsTextFrame*>(firstChild);
offset = textFrame->GetContentOffset();
}
- return BalanceTarget{content, offset};
+ return BalanceTarget{content, offset, iter.get()->BStart()};
};
// "balancing" is implemented by shortening the effective inline-size of the
@@ -1545,6 +1545,7 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
// no balancing is needed; just break from the balance loop.
break;
}
+ balanceTarget.mBlockCoord = mLines.back()->BEnd();
// Initialize the amount of inset to try, and the iteration step size.
balanceStep = aReflowInput.ComputedISize() / balanceTarget.mOffset;
trialState.ResetForBalance(balanceStep);
@@ -1581,7 +1582,8 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
}
int32_t numLines =
countLinesUpTo(StaticPrefs::layout_css_text_wrap_balance_limit());
- return numLines == balanceTarget.mOffset;
+ return numLines == balanceTarget.mOffset &&
+ mLines.back()->BEnd() == balanceTarget.mBlockCoord;
};
// If we're in the process of a balance operation, check whether we've
@@ -2817,7 +2819,7 @@ void nsBlockFrame::PropagateFloatDamage(BlockReflowState& aState,
static bool LineHasClear(nsLineBox* aLine) {
return aLine->IsBlock()
- ? (aLine->HasForcedLineBreakBefore() ||
+ ? (aLine->HasFloatClearTypeBefore() ||
aLine->mFirstChild->HasAnyStateBits(
NS_BLOCK_HAS_CLEAR_CHILDREN) ||
!nsBlockFrame::BlockCanIntersectFloats(aLine->mFirstChild))
@@ -2984,7 +2986,7 @@ bool nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
// We have to reflow the line if it's a block whose clearance
// might have changed, so detect that.
if (!line->IsDirty() &&
- (line->HasForcedLineBreakBefore() || floatAvoidingBlock)) {
+ (line->HasFloatClearTypeBefore() || floatAvoidingBlock)) {
nscoord curBCoord = aState.mBCoord;
// See where we would be after applying any clearance due to
// BRs.
@@ -3934,9 +3936,9 @@ bool nsBlockFrame::IsSelfEmpty() {
const nsStyleBorder* border = StyleBorder();
const nsStylePadding* padding = StylePadding();
- if (border->GetComputedBorderWidth(wm.PhysicalSide(eLogicalSideBStart)) !=
+ if (border->GetComputedBorderWidth(wm.PhysicalSide(LogicalSide::BStart)) !=
0 ||
- border->GetComputedBorderWidth(wm.PhysicalSide(eLogicalSideBEnd)) != 0 ||
+ border->GetComputedBorderWidth(wm.PhysicalSide(LogicalSide::BEnd)) != 0 ||
!nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBStart(wm)) ||
!nsLayoutUtils::IsPaddingZero(padding->mPadding.GetBEnd(wm))) {
return false;
@@ -4051,7 +4053,7 @@ void nsBlockFrame::ReflowBlockFrame(BlockReflowState& aState,
// Clear past floats before the block if the clear style is not none
aLine->ClearForcedLineBreak();
if (clearType != StyleClear::None) {
- aLine->SetForcedLineBreakBefore(clearType);
+ aLine->SetFloatClearTypeBefore(clearType);
}
// See if we should apply the block-start margin. If the block frame being
@@ -7978,7 +7980,7 @@ bool nsBlockFrame::MarkerIsEmpty() const {
const nsStyleList* list = marker->StyleList();
return marker->StyleContent()->mContent.IsNone() ||
(list->mCounterStyle.IsNone() && list->mListStyleImage.IsNone() &&
- marker->StyleContent()->ContentCount() == 0);
+ marker->StyleContent()->NonAltContentItems().IsEmpty());
}
void nsBlockFrame::ReflowOutsideMarker(nsIFrame* aMarkerFrame,
diff --git a/layout/generic/nsCanvasFrame.cpp b/layout/generic/nsCanvasFrame.cpp
index 64c56b1c00..36b579ed60 100644
--- a/layout/generic/nsCanvasFrame.cpp
+++ b/layout/generic/nsCanvasFrame.cpp
@@ -546,6 +546,8 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
layers.mImageCount > 0 &&
layers.mLayers[0].mAttachment == StyleImageLayerAttachment::Fixed;
+ nsDisplayList list(aBuilder);
+
if (!hasFixedBottomLayer || needBlendContainer) {
// Put a scrolled background color item in place, at the bottom of the
// list. The color of this item will be filled in during
@@ -557,20 +559,18 @@ void nsCanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// interleaving the two with a scrolled background color.
// PresShell::AddCanvasBackgroundColorItem makes sure there always is a
// non-scrolled background color item at the bottom.
- aLists.BorderBackground()->AppendNewToTop<nsDisplayCanvasBackgroundColor>(
- aBuilder, this);
+ list.AppendNewToTop<nsDisplayCanvasBackgroundColor>(aBuilder, this);
}
- aLists.BorderBackground()->AppendToTop(&layerItems);
+ list.AppendToTop(&layerItems);
if (needBlendContainer) {
const ActiveScrolledRoot* containerASR = contASRTracker.GetContainerASR();
DisplayListClipState::AutoSaveRestore blendContainerClip(aBuilder);
- aLists.BorderBackground()->AppendToTop(
- nsDisplayBlendContainer::CreateForBackgroundBlendMode(
- aBuilder, this, nullptr, aLists.BorderBackground(),
- containerASR));
+ list.AppendToTop(nsDisplayBlendContainer::CreateForBackgroundBlendMode(
+ aBuilder, this, nullptr, &list, containerASR));
}
+ aLists.BorderBackground()->AppendToTop(&list);
}
for (nsIFrame* kid : PrincipalChildList()) {
@@ -606,24 +606,16 @@ void nsCanvasFrame::PaintFocus(DrawTarget* aDrawTarget, nsPoint aPt) {
/* virtual */
nscoord nsCanvasFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
- if (mFrames.IsEmpty())
- result = 0;
- else
- result = mFrames.FirstChild()->GetMinISize(aRenderingContext);
- return result;
+ return mFrames.IsEmpty()
+ ? 0
+ : mFrames.FirstChild()->GetMinISize(aRenderingContext);
}
/* virtual */
nscoord nsCanvasFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
- if (mFrames.IsEmpty())
- result = 0;
- else
- result = mFrames.FirstChild()->GetPrefISize(aRenderingContext);
- return result;
+ return mFrames.IsEmpty()
+ ? 0
+ : mFrames.FirstChild()->GetPrefISize(aRenderingContext);
}
void nsCanvasFrame::Reflow(nsPresContext* aPresContext,
@@ -632,7 +624,6 @@ void nsCanvasFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsCanvasFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE_REFLOW_IN("nsCanvasFrame::Reflow");
diff --git a/layout/generic/nsColumnSetFrame.cpp b/layout/generic/nsColumnSetFrame.cpp
index cd97519a98..d78a5cb992 100644
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -408,7 +408,6 @@ static void MoveChildTo(nsIFrame* aChild, LogicalPoint aOrigin, WritingMode aWM,
nscoord nsColumnSetFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord iSize = 0;
- DISPLAY_MIN_INLINE_SIZE(this, iSize);
if (mFrames.FirstChild()) {
// We want to ignore this in the case that we're size contained
@@ -443,8 +442,6 @@ nscoord nsColumnSetFrame::GetPrefISize(gfxContext* aRenderingContext) {
// the child's preferred width, times the number of columns, plus the width
// of any required column gaps
// XXX what about forced column breaks here?
- nscoord result = 0;
- DISPLAY_PREF_INLINE_SIZE(this, result);
const nsStyleColumn* colStyle = StyleColumn();
nscoord colISize;
@@ -466,8 +463,7 @@ nscoord nsColumnSetFrame::GetPrefISize(gfxContext* aRenderingContext) {
? 1
: colStyle->mColumnCount;
nscoord colGap = ColumnUtils::GetColumnGap(this, NS_UNCONSTRAINEDSIZE);
- result = ColumnUtils::IntrinsicISize(numColumns, colGap, colISize);
- return result;
+ return ColumnUtils::IntrinsicISize(numColumns, colGap, colISize);
}
nsColumnSetFrame::ColumnBalanceData nsColumnSetFrame::ReflowColumns(
@@ -574,17 +570,17 @@ nsColumnSetFrame::ColumnBalanceData nsColumnSetFrame::ReflowColumns(
// this is a calculation that affects layout.
if (!reflowChild && shrinkingBSize) {
switch (wm.GetBlockDir()) {
- case WritingMode::eBlockTB:
+ case WritingMode::BlockDir::TB:
if (child->ScrollableOverflowRect().YMost() > aConfig.mColBSize) {
reflowChild = true;
}
break;
- case WritingMode::eBlockLR:
+ case WritingMode::BlockDir::LR:
if (child->ScrollableOverflowRect().XMost() > aConfig.mColBSize) {
reflowChild = true;
}
break;
- case WritingMode::eBlockRL:
+ case WritingMode::BlockDir::RL:
// XXX not sure how to handle this, so for now just don't attempt
// the optimization
reflowChild = true;
@@ -1202,7 +1198,6 @@ void nsColumnSetFrame::Reflow(nsPresContext* aPresContext,
nsPresContext::InterruptPreventer noInterrupts(aPresContext);
DO_GLOBAL_REFLOW_COUNT("nsColumnSetFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
MOZ_ASSERT(aReflowInput.mCBReflowInput->mFrame->StyleColumn()
diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp
index 2577a7a00d..3cebfae2e7 100644
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -780,7 +780,7 @@ void nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
if (!(aFlags & ReflowChildFlags::NoSizeView)) {
nsViewManager* vm = aView->GetViewManager();
- vm->ResizeView(aView, aInkOverflowArea, true);
+ vm->ResizeView(aView, aInkOverflowArea);
}
}
@@ -814,8 +814,7 @@ LogicalSize nsContainerFrame::ComputeAutoSize(
LogicalSize result(aWM, 0xdeadbeef, NS_UNCONSTRAINEDSIZE);
nscoord availBased =
aAvailableISize - aMargin.ISize(aWM) - aBorderPadding.ISize(aWM);
- // replaced elements always shrink-wrap
- if (aFlags.contains(ComputeSizeFlag::ShrinkWrap) || IsReplaced()) {
+ if (aFlags.contains(ComputeSizeFlag::ShrinkWrap)) {
// Only bother computing our 'auto' ISize if the result will be used.
const auto& styleISize = aSizeOverrides.mStyleISize
? *aSizeOverrides.mStyleISize
@@ -2201,9 +2200,9 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
// This variable only gets meaningfully set if isFlexItem is true. It
// indicates which axis (in this frame's own WM) corresponds to its
// flex container's main axis.
- LogicalAxis flexMainAxis = eLogicalAxisBlock;
+ LogicalAxis flexMainAxis = LogicalAxis::Block;
if (isFlexItem && nsFlexContainerFrame::IsItemInlineAxisMainAxis(this)) {
- flexMainAxis = eLogicalAxisInline;
+ flexMainAxis = LogicalAxis::Inline;
}
// Handle intrinsic sizes and their interaction with
@@ -2263,8 +2262,8 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
aSizeOverrides, aFlags)
.mISize;
} else if (MOZ_UNLIKELY(isGridItem) &&
- !parentFrame->IsMasonry(isOrthogonal ? eLogicalAxisBlock
- : eLogicalAxisInline)) {
+ !parentFrame->IsMasonry(isOrthogonal ? LogicalAxis::Block
+ : LogicalAxis::Inline)) {
MOZ_ASSERT(!IsTrueOverflowContainer());
// 'auto' inline-size for grid-level box - apply 'stretch' as needed:
auto cbSize = aCBSize.ISize(aWM);
@@ -2291,7 +2290,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
const auto& maxISizeCoord = stylePos->MaxISize(aWM);
if (!maxISizeCoord.IsNone() &&
- !(isFlexItem && flexMainAxis == eLogicalAxisInline)) {
+ !(isFlexItem && flexMainAxis == LogicalAxis::Inline)) {
maxISize = ComputeISizeValue(aRenderingContext, aWM, aCBSize,
boxSizingAdjust, boxSizingToMarginEdgeISize,
maxISizeCoord, aSizeOverrides, aFlags)
@@ -2307,7 +2306,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
const auto& minISizeCoord = stylePos->MinISize(aWM);
if (!minISizeCoord.IsAuto() &&
- !(isFlexItem && flexMainAxis == eLogicalAxisInline)) {
+ !(isFlexItem && flexMainAxis == LogicalAxis::Inline)) {
minISize = ComputeISizeValue(aRenderingContext, aWM, aCBSize,
boxSizingAdjust, boxSizingToMarginEdgeISize,
minISizeCoord, aSizeOverrides, aFlags)
@@ -2326,8 +2325,8 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
boxSizingAdjust.BSize(aWM),
styleBSize.AsLengthPercentage());
} else if (MOZ_UNLIKELY(isGridItem) &&
- !parentFrame->IsMasonry(isOrthogonal ? eLogicalAxisInline
- : eLogicalAxisBlock)) {
+ !parentFrame->IsMasonry(isOrthogonal ? LogicalAxis::Inline
+ : LogicalAxis::Block)) {
MOZ_ASSERT(!IsTrueOverflowContainer());
// 'auto' block-size for grid-level box - apply 'stretch' as needed:
auto cbSize = aCBSize.BSize(aWM);
@@ -2354,7 +2353,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
const auto& maxBSizeCoord = stylePos->MaxBSize(aWM);
if (!nsLayoutUtils::IsAutoBSize(maxBSizeCoord, aCBSize.BSize(aWM)) &&
- !(isFlexItem && flexMainAxis == eLogicalAxisBlock)) {
+ !(isFlexItem && flexMainAxis == LogicalAxis::Block)) {
maxBSize = nsLayoutUtils::ComputeBSizeValue(
aCBSize.BSize(aWM), boxSizingAdjust.BSize(aWM),
maxBSizeCoord.AsLengthPercentage());
@@ -2365,7 +2364,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
const auto& minBSizeCoord = stylePos->MinBSize(aWM);
if (!nsLayoutUtils::IsAutoBSize(minBSizeCoord, aCBSize.BSize(aWM)) &&
- !(isFlexItem && flexMainAxis == eLogicalAxisBlock)) {
+ !(isFlexItem && flexMainAxis == LogicalAxis::Block)) {
minBSize = nsLayoutUtils::ComputeBSizeValue(
aCBSize.BSize(aWM), boxSizingAdjust.BSize(aWM),
minBSizeCoord.AsLengthPercentage());
@@ -2389,8 +2388,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
tentISize = intrinsicISize;
} else if (hasIntrinsicBSize && aspectRatio) {
tentISize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, intrinsicBSize,
- boxSizingAdjust);
+ LogicalAxis::Inline, aWM, intrinsicBSize, boxSizingAdjust);
} else if (aspectRatio) {
tentISize =
aCBSize.ISize(aWM) - boxSizingToMarginEdgeISize; // XXX scrollbar?
@@ -2413,7 +2411,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
tentBSize = intrinsicBSize;
} else if (aspectRatio) {
tentBSize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisBlock, aWM, tentISize, boxSizingAdjust);
+ LogicalAxis::Block, aWM, tentISize, boxSizingAdjust);
} else {
tentBSize = fallbackIntrinsicSize.BSize(aWM);
}
@@ -2431,29 +2429,29 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
} else if (stretchB == eStretchPreservingRatio && aspectRatio) {
// 'normal' / 'stretch'
tentBSize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisBlock, aWM, iSize, boxSizingAdjust);
+ LogicalAxis::Block, aWM, iSize, boxSizingAdjust);
}
} else if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / * (except 'stretch')
if (stretchI == eStretchPreservingRatio && aspectRatio) {
// 'stretch' / 'normal'
tentISize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, bSize, boxSizingAdjust);
+ LogicalAxis::Inline, aWM, bSize, boxSizingAdjust);
}
} else if (stretchI == eStretchPreservingRatio && aspectRatio) {
tentISize = iSize; // * (except 'stretch') / 'normal'
tentBSize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisBlock, aWM, iSize, boxSizingAdjust);
+ LogicalAxis::Block, aWM, iSize, boxSizingAdjust);
if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
// Stretch within the CB size with preserved intrinsic ratio.
tentBSize = bSize; // 'normal' / 'normal'
tentISize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, bSize, boxSizingAdjust);
+ LogicalAxis::Inline, aWM, bSize, boxSizingAdjust);
}
} else if (stretchB == eStretchPreservingRatio && aspectRatio) {
tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
tentISize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, bSize, boxSizingAdjust);
+ LogicalAxis::Inline, aWM, bSize, boxSizingAdjust);
}
// ComputeAutoSizeWithIntrinsicDimensions preserves the ratio when
@@ -2480,7 +2478,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
if (stretchI != eStretch) {
if (aspectRatio) {
iSize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, bSize, boxSizingAdjust);
+ LogicalAxis::Inline, aWM, bSize, boxSizingAdjust);
} else if (hasIntrinsicISize) {
if (!(aFlags.contains(ComputeSizeFlag::IClampMarginBoxMinSize) &&
intrinsicISize > iSize)) {
@@ -2498,8 +2496,8 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
iSize = NS_CSS_MINMAX(iSize, minISize, maxISize);
if (stretchB != eStretch) {
if (aspectRatio) {
- bSize = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisBlock, aWM, iSize, boxSizingAdjust);
+ bSize = aspectRatio.ComputeRatioDependentSize(LogicalAxis::Block, aWM,
+ iSize, boxSizingAdjust);
} else if (hasIntrinsicBSize) {
if (!(aFlags.contains(ComputeSizeFlag::BClampMarginBoxMinSize) &&
intrinsicBSize > bSize)) {
diff --git a/layout/generic/nsContainerFrame.h b/layout/generic/nsContainerFrame.h
index 09f6cf76f5..cb0a09db20 100644
--- a/layout/generic/nsContainerFrame.h
+++ b/layout/generic/nsContainerFrame.h
@@ -1076,126 +1076,4 @@ class nsOverflowContinuationTracker {
bool mWalkOOFFrames;
};
-// Start Display Reflow Debugging
-#ifdef DEBUG
-
-struct DR_cookie {
- DR_cookie(nsPresContext* aPresContext, nsIFrame* aFrame,
- const mozilla::ReflowInput& aReflowInput,
- mozilla::ReflowOutput& aMetrics, nsReflowStatus& aStatus);
- ~DR_cookie();
- void Change() const;
-
- nsPresContext* mPresContext;
- nsIFrame* mFrame;
- const mozilla::ReflowInput& mReflowInput;
- mozilla::ReflowOutput& mMetrics;
- nsReflowStatus& mStatus;
- void* mValue;
-};
-
-struct DR_layout_cookie {
- explicit DR_layout_cookie(nsIFrame* aFrame);
- ~DR_layout_cookie();
-
- nsIFrame* mFrame;
- void* mValue;
-};
-
-struct DR_intrinsic_inline_size_cookie {
- DR_intrinsic_inline_size_cookie(nsIFrame* aFrame, const char* aType,
- nscoord& aResult);
- ~DR_intrinsic_inline_size_cookie();
-
- nsIFrame* mFrame;
- const char* mType;
- nscoord& mResult;
- void* mValue;
-};
-
-struct DR_intrinsic_size_cookie {
- DR_intrinsic_size_cookie(nsIFrame* aFrame, const char* aType,
- nsSize& aResult);
- ~DR_intrinsic_size_cookie();
-
- nsIFrame* mFrame;
- const char* mType;
- nsSize& mResult;
- void* mValue;
-};
-
-struct DR_init_constraints_cookie {
- DR_init_constraints_cookie(
- nsIFrame* aFrame, mozilla::ReflowInput* aState, nscoord aCBWidth,
- nscoord aCBHeight, const mozilla::Maybe<mozilla::LogicalMargin> aBorder,
- const mozilla::Maybe<mozilla::LogicalMargin> aPadding);
- ~DR_init_constraints_cookie();
-
- nsIFrame* mFrame;
- mozilla::ReflowInput* mState;
- void* mValue;
-};
-
-struct DR_init_offsets_cookie {
- DR_init_offsets_cookie(nsIFrame* aFrame,
- mozilla::SizeComputationInput* aState,
- nscoord aPercentBasis,
- mozilla::WritingMode aCBWritingMode,
- const mozilla::Maybe<mozilla::LogicalMargin> aBorder,
- const mozilla::Maybe<mozilla::LogicalMargin> aPadding);
- ~DR_init_offsets_cookie();
-
- nsIFrame* mFrame;
- mozilla::SizeComputationInput* mState;
- void* mValue;
-};
-
-# define DISPLAY_REFLOW(dr_pres_context, dr_frame, dr_rf_state, \
- dr_rf_metrics, dr_rf_status) \
- DR_cookie dr_cookie(dr_pres_context, dr_frame, dr_rf_state, dr_rf_metrics, \
- dr_rf_status);
-# define DISPLAY_REFLOW_CHANGE() dr_cookie.Change();
-# define DISPLAY_LAYOUT(dr_frame) DR_layout_cookie dr_cookie(dr_frame);
-# define DISPLAY_MIN_INLINE_SIZE(dr_frame, dr_result) \
- DR_intrinsic_inline_size_cookie dr_cookie(dr_frame, "Min", dr_result)
-# define DISPLAY_PREF_INLINE_SIZE(dr_frame, dr_result) \
- DR_intrinsic_inline_size_cookie dr_cookie(dr_frame, "Pref", dr_result)
-# define DISPLAY_PREF_SIZE(dr_frame, dr_result) \
- DR_intrinsic_size_cookie dr_cookie(dr_frame, "Pref", dr_result)
-# define DISPLAY_MIN_SIZE(dr_frame, dr_result) \
- DR_intrinsic_size_cookie dr_cookie(dr_frame, "Min", dr_result)
-# define DISPLAY_MAX_SIZE(dr_frame, dr_result) \
- DR_intrinsic_size_cookie dr_cookie(dr_frame, "Max", dr_result)
-# define DISPLAY_INIT_CONSTRAINTS(dr_frame, dr_state, dr_cbw, dr_cbh, dr_bdr, \
- dr_pad) \
- DR_init_constraints_cookie dr_cookie(dr_frame, dr_state, dr_cbw, dr_cbh, \
- dr_bdr, dr_pad)
-# define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_cbwm, dr_bdr, \
- dr_pad) \
- DR_init_offsets_cookie dr_cookie(dr_frame, dr_state, dr_pb, dr_cbwm, \
- dr_bdr, dr_pad)
-
-#else
-
-# define DISPLAY_REFLOW(dr_pres_context, dr_frame, dr_rf_state, \
- dr_rf_metrics, dr_rf_status)
-# define DISPLAY_REFLOW_CHANGE()
-# define DISPLAY_LAYOUT(dr_frame) PR_BEGIN_MACRO PR_END_MACRO
-# define DISPLAY_MIN_INLINE_SIZE(dr_frame, dr_result) \
- PR_BEGIN_MACRO PR_END_MACRO
-# define DISPLAY_PREF_INLINE_SIZE(dr_frame, dr_result) \
- PR_BEGIN_MACRO PR_END_MACRO
-# define DISPLAY_PREF_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
-# define DISPLAY_MIN_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
-# define DISPLAY_MAX_SIZE(dr_frame, dr_result) PR_BEGIN_MACRO PR_END_MACRO
-# define DISPLAY_INIT_CONSTRAINTS(dr_frame, dr_state, dr_cbw, dr_cbh, dr_bdr, \
- dr_pad) \
- PR_BEGIN_MACRO PR_END_MACRO
-# define DISPLAY_INIT_OFFSETS(dr_frame, dr_state, dr_pb, dr_cbwm, dr_bdr, \
- dr_pad) \
- PR_BEGIN_MACRO PR_END_MACRO
-
-#endif
-// End Display Reflow Debugging
-
#endif /* nsContainerFrame_h___ */
diff --git a/layout/generic/nsContainerFrameInlines.h b/layout/generic/nsContainerFrameInlines.h
index f6c85d791e..bc544fa6f8 100644
--- a/layout/generic/nsContainerFrameInlines.h
+++ b/layout/generic/nsContainerFrameInlines.h
@@ -21,8 +21,8 @@ void nsContainerFrame::DoInlineIntrinsicISize(ISizeData* aData,
if (GetPrevInFlow()) return; // Already added.
WritingMode wm = GetWritingMode();
- Side startSide = wm.PhysicalSideForInlineAxis(eLogicalEdgeStart);
- Side endSide = wm.PhysicalSideForInlineAxis(eLogicalEdgeEnd);
+ Side startSide = wm.PhysicalSideForInlineAxis(LogicalEdge::Start);
+ Side endSide = wm.PhysicalSideForInlineAxis(LogicalEdge::End);
const nsStylePadding* stylePadding = StylePadding();
const nsStyleBorder* styleBorder = StyleBorder();
diff --git a/layout/generic/nsFirstLetterFrame.cpp b/layout/generic/nsFirstLetterFrame.cpp
index fe294652c7..c08950121a 100644
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -197,7 +197,6 @@ void nsFirstLetterFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aReflowStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsFirstLetterFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aReflowStatus);
MOZ_ASSERT(aReflowStatus.IsEmpty(),
"Caller should pass a fresh reflow status!");
@@ -448,12 +447,12 @@ Maybe<nscoord> nsFirstLetterFrame::GetNaturalBaselineBOffset(
LogicalSides nsFirstLetterFrame::GetLogicalSkipSides() const {
if (GetPrevContinuation()) {
- // We shouldn't get calls to GetSkipSides for later continuations since
- // they have separate ComputedStyles with initial values for all the
- // properties that could trigger a call to GetSkipSides. Then again,
- // it's not really an error to call GetSkipSides on any frame, so
+ // We shouldn't get calls to GetLogicalSkipSides for later continuations
+ // since they have separate ComputedStyles with initial values for all the
+ // properties that could trigger a call to GetLogicalSkipSides. Then again,
+ // it's not really an error to call GetLogicalSkipSides on any frame, so
// that's why we handle it properly.
- return LogicalSides(mWritingMode, eLogicalSideBitsAll);
+ return LogicalSides(mWritingMode, LogicalSides::All);
}
return LogicalSides(mWritingMode); // first continuation displays all sides
}
diff --git a/layout/generic/nsFlexContainerFrame.cpp b/layout/generic/nsFlexContainerFrame.cpp
index e5a719fee2..4604106a4a 100644
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -14,14 +14,12 @@
#include "mozilla/Baseline.h"
#include "mozilla/ComputedStyle.h"
#include "mozilla/CSSOrderAwareFrameIterator.h"
-#include "mozilla/FloatingPoint.h"
#include "mozilla/Logging.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/WritingModes.h"
#include "nsBlockFrame.h"
#include "nsContentUtils.h"
-#include "nsCSSAnonBoxes.h"
#include "nsDebug.h"
#include "nsDisplayList.h"
#include "nsFieldSetFrame.h"
@@ -43,10 +41,25 @@ using CachedBAxisMeasurement = nsFlexContainerFrame::CachedBAxisMeasurement;
using CachedFlexItemData = nsFlexContainerFrame::CachedFlexItemData;
static mozilla::LazyLogModule gFlexContainerLog("FlexContainer");
-#define FLEX_LOG(...) \
- MOZ_LOG(gFlexContainerLog, LogLevel::Debug, (__VA_ARGS__));
-#define FLEX_LOGV(...) \
- MOZ_LOG(gFlexContainerLog, LogLevel::Verbose, (__VA_ARGS__));
+
+// FLEX_LOG is a top-level general log print.
+#define FLEX_LOG(message, ...) \
+ MOZ_LOG(gFlexContainerLog, LogLevel::Debug, (message, ##__VA_ARGS__));
+
+// FLEX_ITEM_LOG is a top-level log print for flex item.
+#define FLEX_ITEM_LOG(item_frame, message, ...) \
+ MOZ_LOG(gFlexContainerLog, LogLevel::Debug, \
+ ("Flex item %p: " message, item_frame, ##__VA_ARGS__));
+
+// FLEX_LOGV is a verbose log print with built-in two spaces indentation. The
+// convention to use FLEX_LOGV is that FLEX_LOGV statements should generally be
+// preceded by one FLEX_LOG or FLEX_ITEM_LOG so that there's no need to repeat
+// information presented in the preceding LOG statement. If you want extra level
+// of indentation, just add two extra spaces at the start of the message string.
+#define FLEX_LOGV(message, ...) \
+ MOZ_LOG(gFlexContainerLog, LogLevel::Verbose, (" " message, ##__VA_ARGS__));
+
+static const char* BoolToYesNo(bool aArg) { return aArg ? "yes" : "no"; }
// Returns true if aFlexContainer is a frame for some element that has
// display:-webkit-{inline-}box (or -moz-{inline-}box). aFlexContainer is
@@ -143,10 +156,10 @@ class MOZ_STACK_CLASS nsFlexContainerFrame::FlexboxAxisTracker {
// Accessors:
LogicalAxis MainAxis() const {
- return IsRowOriented() ? eLogicalAxisInline : eLogicalAxisBlock;
+ return IsRowOriented() ? LogicalAxis::Inline : LogicalAxis::Block;
}
LogicalAxis CrossAxis() const {
- return IsRowOriented() ? eLogicalAxisBlock : eLogicalAxisInline;
+ return IsRowOriented() ? LogicalAxis::Block : LogicalAxis::Inline;
}
LogicalSide MainAxisStartSide() const;
@@ -299,7 +312,7 @@ class MOZ_STACK_CLASS nsFlexContainerFrame::FlexboxAxisTracker {
return StyleAlignFlags::START;
}
- MOZ_ASSERT(wm.PhysicalAxis(MainAxis()) == eAxisHorizontal,
+ MOZ_ASSERT(wm.PhysicalAxis(MainAxis()) == PhysicalAxis::Horizontal,
"Vertical column-oriented flex container's main axis should "
"be parallel to physical left <-> right axis!");
// Map 'left' or 'right' to 'start' or 'end', depending on its block flow
@@ -308,7 +321,7 @@ class MOZ_STACK_CLASS nsFlexContainerFrame::FlexboxAxisTracker {
: StyleAlignFlags::END;
}
- MOZ_ASSERT(MainAxis() == eLogicalAxisInline,
+ MOZ_ASSERT(MainAxis() == LogicalAxis::Inline,
"Row-oriented flex container's main axis should be parallel to "
"line-left <-> line-right axis!");
@@ -682,9 +695,8 @@ class nsFlexContainerFrame::FlexItem final {
// to the [min,max] range:
mMainSize = NS_CSS_MINMAX(mFlexBaseSize, mMainMinSize, mMainMaxSize);
- FLEX_LOGV(
- "Set flex base size: %d, hypothetical main size: %d for flex item %p",
- mFlexBaseSize, mMainSize, mFrame);
+ FLEX_ITEM_LOG(mFrame, "Set flex base size: %d, hypothetical main size: %d",
+ mFlexBaseSize, mMainSize);
}
// Setters used while we're resolving flexible lengths
@@ -1305,7 +1317,7 @@ StyleAlignFlags nsFlexContainerFrame::CSSAlignmentForAbsPosChild(
// block axis), then the caller is really asking about our *main* axis.
// Otherwise, the caller is asking about our cross axis.
const bool isMainAxis =
- (axisTracker.IsRowOriented() == (aLogicalAxis == eLogicalAxisInline));
+ (axisTracker.IsRowOriented() == (aLogicalAxis == LogicalAxis::Inline));
const nsStylePosition* containerStylePos = StylePosition();
const bool isAxisReversed = isMainAxis ? axisTracker.IsMainAxisReversed()
: axisTracker.IsCrossAxisReversed();
@@ -1592,7 +1604,7 @@ static nscoord PartiallyResolveAutoMinSize(
if (specifiedSizeSuggestion != nscoord_MAX) {
// We have the specified size suggestion. Return it now since we don't need
// to consider transferred size suggestion.
- FLEX_LOGV(" Specified size suggestion: %d", specifiedSizeSuggestion);
+ FLEX_LOGV("Specified size suggestion: %d", specifiedSizeSuggestion);
return specifiedSizeSuggestion;
}
@@ -1611,7 +1623,7 @@ static nscoord PartiallyResolveAutoMinSize(
transferredSizeSuggestion = aFlexItem.ClampMainSizeViaCrossAxisConstraints(
transferredSizeSuggestion, aItemReflowInput);
- FLEX_LOGV(" Transferred size suggestion: %d", transferredSizeSuggestion);
+ FLEX_LOGV("Transferred size suggestion: %d", transferredSizeSuggestion);
return transferredSizeSuggestion;
}
@@ -1638,8 +1650,10 @@ void nsFlexContainerFrame::ResolveAutoFlexBasisAndMinSize(
return;
}
- FLEX_LOGV("Resolving auto main size or auto min main size for flex item %p",
- aFlexItem.Frame());
+ FLEX_ITEM_LOG(
+ aFlexItem.Frame(),
+ "Resolving auto main size? %s; resolving auto min main size? %s",
+ BoolToYesNo(isMainSizeAuto), BoolToYesNo(isMainMinSizeAuto));
nscoord resolvedMinSize; // (only set/used if isMainMinSizeAuto==true)
bool minSizeNeedsToMeasureContent = false; // assume the best
@@ -1725,7 +1739,7 @@ void nsFlexContainerFrame::ResolveAutoFlexBasisAndMinSize(
contentSizeSuggestion, aItemReflowInput);
}
- FLEX_LOGV(" Content size suggestion: %d", contentSizeSuggestion);
+ FLEX_LOGV("Content size suggestion: %d", contentSizeSuggestion);
resolvedMinSize = std::min(resolvedMinSize, contentSizeSuggestion);
// Clamp the resolved min main size by the max main size if it's definite.
@@ -1739,7 +1753,7 @@ void nsFlexContainerFrame::ResolveAutoFlexBasisAndMinSize(
// nscoord_MAX sentinel value if we reach this point).
resolvedMinSize = nscoord_MAX;
}
- FLEX_LOGV(" Resolved auto min main size: %d", resolvedMinSize);
+ FLEX_LOGV("Resolved auto min main size: %d", resolvedMinSize);
if (resolvedMinSize == contentSizeSuggestion) {
// When we are here, we've measured the item's content-based size, and
@@ -1992,18 +2006,22 @@ const CachedBAxisMeasurement& nsFlexContainerFrame::MeasureBSizeForFlexItem(
if (cachedData && cachedData->mBAxisMeasurement) {
if (!aItem.Frame()->IsSubtreeDirty() &&
cachedData->mBAxisMeasurement->IsValidFor(aChildReflowInput)) {
- FLEX_LOG("[perf] MeasureBSizeForFlexItem accepted cached value");
+ FLEX_ITEM_LOG(aItem.Frame(),
+ "[perf] Accepted cached measurement: block-size %d",
+ cachedData->mBAxisMeasurement->BSize());
return *(cachedData->mBAxisMeasurement);
}
- FLEX_LOG("[perf] MeasureBSizeForFlexItem rejected cached value");
+ FLEX_ITEM_LOG(aItem.Frame(),
+ "[perf] Rejected cached measurement: block-size %d",
+ cachedData->mBAxisMeasurement->BSize());
} else {
- FLEX_LOG("[perf] MeasureBSizeForFlexItem didn't have a cached value");
+ FLEX_ITEM_LOG(aItem.Frame(), "[perf] No cached measurement");
}
// CachedFlexItemData is stored in item's writing mode, so we pass
// aChildReflowInput into ReflowOutput's constructor.
ReflowOutput childReflowOutput(aChildReflowInput);
- nsReflowStatus childReflowStatus;
+ nsReflowStatus childStatus;
const ReflowChildFlags flags = ReflowChildFlags::NoMoveFrame;
const WritingMode outerWM = GetWritingMode();
@@ -2014,12 +2032,12 @@ const CachedBAxisMeasurement& nsFlexContainerFrame::MeasureBSizeForFlexItem(
// unimportant.
ReflowChild(aItem.Frame(), PresContext(), childReflowOutput,
aChildReflowInput, outerWM, dummyPosition, dummyContainerSize,
- flags, childReflowStatus);
+ flags, childStatus);
aItem.SetHadMeasuringReflow();
// We always use unconstrained available block-size to measure flex items,
// which means they should always complete.
- MOZ_ASSERT(childReflowStatus.IsComplete(),
+ MOZ_ASSERT(childStatus.IsComplete(),
"We gave flex item unconstrained available block-size, so it "
"should be complete");
@@ -2055,7 +2073,7 @@ void nsFlexContainerFrame::MarkIntrinsicISizesDirty() {
nscoord nsFlexContainerFrame::MeasureFlexItemContentBSize(
FlexItem& aFlexItem, bool aForceBResizeForMeasuringReflow,
const ReflowInput& aParentReflowInput) {
- FLEX_LOG("Measuring flex item's content block-size");
+ FLEX_ITEM_LOG(aFlexItem.Frame(), "Measuring item's content block-size");
// Set up a reflow input for measuring the flex item's content block-size:
WritingMode wm = aFlexItem.Frame()->GetWritingMode();
@@ -2070,7 +2088,7 @@ nscoord nsFlexContainerFrame::MeasureFlexItemContentBSize(
// block-size, because that would prevent us from measuring the content
// block-size.
sizeOverrides.mAspectRatio.emplace(AspectRatio());
- FLEX_LOGV(" Cross size override: %d", aFlexItem.CrossSize());
+ FLEX_LOGV("Cross size override: %d", aFlexItem.CrossSize());
}
sizeOverrides.mStyleBSize.emplace(StyleSize::Auto());
@@ -2209,7 +2227,7 @@ FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput, float aFlexGrow,
// (We'll resolve them later; until then, we want to treat them as 0-sized.)
#ifdef DEBUG
{
- for (const auto side : AllLogicalSides()) {
+ for (const auto side : LogicalSides::All) {
if (styleMargin->mMargin.Get(mCBWM, side).IsAuto()) {
MOZ_ASSERT(GetMarginComponentForSide(side) == 0,
"Someone else tried to resolve our auto margin");
@@ -2234,12 +2252,12 @@ FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput, float aFlexGrow,
// getting the physical side that corresponds to these axes' "logical
// start" sides, and we compare those physical sides to find out if
// they're the same vs. opposite.
- mozilla::Side itemBlockStartSide = mWM.PhysicalSide(eLogicalSideBStart);
+ mozilla::Side itemBlockStartSide = mWM.PhysicalSide(LogicalSide::BStart);
// (Note: this is *not* the "flex-start" side; rather, it's the *logical*
// i.e. WM-relative block-start or inline-start side.)
mozilla::Side containerStartSideInCrossAxis = mCBWM.PhysicalSide(
- MakeLogicalSide(aAxisTracker.CrossAxis(), eLogicalEdgeStart));
+ MakeLogicalSide(aAxisTracker.CrossAxis(), LogicalEdge::Start));
// We already know these two Sides (the item's block-start and the
// container's 'logical start' side for its cross axis) are in the same
@@ -2336,7 +2354,7 @@ nscoord FlexItem::BaselineOffsetFromOuterCrossEdge(
// column-oriented flex container. We need to synthesize the item's baseline
// from its border-box edge.
const bool isMainAxisHorizontal =
- mCBWM.PhysicalAxis(MainAxis()) == mozilla::eAxisHorizontal;
+ mCBWM.PhysicalAxis(MainAxis()) == PhysicalAxis::Horizontal;
// When the main axis is horizontal, the synthesized baseline is the bottom
// edge of the item's border-box. Otherwise, when the main axis is vertical,
@@ -2363,7 +2381,7 @@ nscoord FlexItem::BaselineOffsetFromOuterCrossEdge(
"Only expecting to be doing baseline computations when the "
"cross axis is the block axis");
- mozilla::Side itemBlockStartSide = mWM.PhysicalSide(eLogicalSideBStart);
+ mozilla::Side itemBlockStartSide = mWM.PhysicalSide(LogicalSide::BStart);
nscoord marginBStartToBaseline = ResolvedAscent(aUseFirstLineBaseline) +
PhysicalMargin().Side(itemBlockStartSide);
@@ -2430,7 +2448,7 @@ void FlexItem::ResolveFlexBaseSizeFromAspectRatio(
uint32_t FlexItem::NumAutoMarginsInAxis(LogicalAxis aAxis) const {
uint32_t numAutoMargins = 0;
const auto& styleMargin = mFrame->StyleMargin()->mMargin;
- for (const auto edge : {eLogicalEdgeStart, eLogicalEdgeEnd}) {
+ for (const auto edge : {LogicalEdge::Start, LogicalEdge::End}) {
const auto side = MakeLogicalSide(aAxis, edge);
if (styleMargin.Get(mCBWM, side).IsAuto()) {
numAutoMargins++;
@@ -2537,18 +2555,17 @@ static bool FrameHasRelativeBSizeDependency(nsIFrame* aFrame) {
bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
if (!StaticPrefs::layout_flexbox_item_final_reflow_optimization_enabled()) {
- FLEX_LOG(
- "[perf] Flex item %p needed a final reflow due to optimization being "
- "disabled via the preference",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[perf] Item needed a final reflow due to optimization being "
+ "disabled via the preference");
return true;
}
// NOTE: We can have continuations from an earlier constrained reflow.
if (mFrame->GetPrevInFlow() || mFrame->GetNextInFlow()) {
// This is an item has continuation(s). Reflow it.
- FLEX_LOG("[frag] Flex item %p needed a final reflow due to continuation(s)",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[frag] Item needed a final reflow due to continuation(s)");
return true;
}
@@ -2560,10 +2577,9 @@ bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
// prevent triggering O(n^2) behavior when printing a deeply-nested flex
// container.
if (aParentReflowInput.IsInFragmentedContext()) {
- FLEX_LOG(
- "[frag] Flex item %p needed both a measuring reflow and a final "
- "reflow due to being in a fragmented context.",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[frag] Item needed both a measuring reflow and a final "
+ "reflow due to being in a fragmented context");
return true;
}
@@ -2579,10 +2595,9 @@ bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
if (finalSize != mFrame->ContentSize(mWM)) {
// The measuring reflow left the item with a different size than its
// final flexed size. So, we need to reflow to give it the correct size.
- FLEX_LOG(
- "[perf] Flex item %p needed both a measuring reflow and a final "
- "reflow due to measured size disagreeing with final size",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[perf] Item needed both a measuring reflow and a final "
+ "reflow due to measured size disagreeing with final size");
return true;
}
@@ -2590,10 +2605,9 @@ bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
// This item has descendants with relative BSizes who may care that its
// size may now be considered "definite" in the final reflow (whereas it
// was indefinite during the measuring reflow).
- FLEX_LOG(
- "[perf] Flex item %p needed both a measuring reflow and a final "
- "reflow due to BSize potentially becoming definite",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[perf] Item needed both a measuring reflow and a final "
+ "reflow due to BSize potentially becoming definite");
return true;
}
@@ -2621,10 +2635,9 @@ bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
// definiteness.
// Let's check for each condition that would still require us to reflow:
if (mFrame->IsSubtreeDirty()) {
- FLEX_LOG(
- "[perf] Flex item %p needed a final reflow due to its subtree "
- "being dirty",
- mFrame);
+ FLEX_ITEM_LOG(
+ mFrame,
+ "[perf] Item needed a final reflow due to its subtree being dirty");
return true;
}
@@ -2634,19 +2647,17 @@ bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
// Did we cache the metrics from its most recent "final reflow"?
auto* cache = mFrame->GetProperty(CachedFlexItemData::Prop());
if (!cache || !cache->mFinalReflowMetrics) {
- FLEX_LOG(
- "[perf] Flex item %p needed a final reflow due to lacking a "
- "cached mFinalReflowMetrics (maybe cache was cleared)",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[perf] Item needed a final reflow due to lacking a cached "
+ "mFinalReflowMetrics (maybe cache was cleared)");
return true;
}
// Does the cached size match our current size?
if (cache->mFinalReflowMetrics->Size() != finalSize) {
- FLEX_LOG(
- "[perf] Flex item %p needed a final reflow due to having a "
- "different content box size vs. its most recent final reflow",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[perf] Item needed a final reflow due to having a different "
+ "content box size vs. its most recent final reflow");
return true;
}
@@ -2659,10 +2670,9 @@ bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
// reflow.
if (cache->mFinalReflowMetrics->BorderPadding() !=
BorderPadding().ConvertTo(mWM, mCBWM)) {
- FLEX_LOG(
- "[perf] Flex item %p needed a final reflow due to having a "
- "different border and padding vs. its most recent final reflow",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[perf] Item needed a final reflow due to having a different "
+ "border and padding vs. its most recent final reflow");
return true;
}
@@ -2672,10 +2682,9 @@ bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
if (cache->mFinalReflowMetrics->TreatBSizeAsIndefinite() !=
mTreatBSizeAsIndefinite &&
FrameHasRelativeBSizeDependency(mFrame)) {
- FLEX_LOG(
- "[perf] Flex item %p needed a final reflow due to having "
- "its BSize change definiteness & having a rel-BSize child",
- mFrame);
+ FLEX_ITEM_LOG(mFrame,
+ "[perf] Item needed a final reflow due to having its BSize "
+ "change definiteness & having a rel-BSize child");
return true;
}
@@ -2683,7 +2692,7 @@ bool FlexItem::NeedsFinalReflow(const ReflowInput& aParentReflowInput) const {
// dirty, and our current conditions are sufficiently similar to the most
// recent "final reflow" that it should have left our subtree in the correct
// state.)
- FLEX_LOG("[perf] Flex item %p didn't need a final reflow", mFrame);
+ FLEX_ITEM_LOG(mFrame, "[perf] Item didn't need a final reflow");
return false;
}
@@ -2699,12 +2708,12 @@ class MOZ_STACK_CLASS PositionTracker {
inline LogicalSide StartSide() {
return MakeLogicalSide(
- mAxis, mIsAxisReversed ? eLogicalEdgeEnd : eLogicalEdgeStart);
+ mAxis, mIsAxisReversed ? LogicalEdge::End : LogicalEdge::Start);
}
inline LogicalSide EndSide() {
return MakeLogicalSide(
- mAxis, mIsAxisReversed ? eLogicalEdgeStart : eLogicalEdgeEnd);
+ mAxis, mIsAxisReversed ? LogicalEdge::Start : LogicalEdge::End);
}
// Advances our position across the start edge of the given margin, in the
@@ -2757,7 +2766,7 @@ class MOZ_STACK_CLASS PositionTracker {
const WritingMode mWM;
// The axis along which we're moving.
- const LogicalAxis mAxis = eLogicalAxisInline;
+ const LogicalAxis mAxis = LogicalAxis::Inline;
// Is the axis along which we're moving reversed (e.g. LTR vs RTL) with
// respect to the corresponding axis on the flex container's WM?
@@ -3150,8 +3159,8 @@ void FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize,
availableFreeSpace -= item.MainSize();
}
- FLEX_LOG(" available free space: %" PRId64 "; flex items should \"%s\"",
- availableFreeSpace.value, isUsingFlexGrow ? "grow" : "shrink");
+ FLEX_LOGV("Available free space: %" PRId64 "; flex items should \"%s\"",
+ availableFreeSpace.value, isUsingFlexGrow ? "grow" : "shrink");
// The sign of our free space should agree with the type of flexing
// (grow/shrink) that we're doing. Any disagreement should've made us use
@@ -3276,7 +3285,7 @@ void FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize,
}
}
- FLEX_LOG(" Distributing available space:");
+ FLEX_LOGV("Distributing available space:");
// Since this loop only operates on unfrozen flex items, we can break as
// soon as we have seen all of them.
numUnfrozenItemsToBeSeen = NumItems() - mNumFrozenItems;
@@ -3323,8 +3332,8 @@ void FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize,
item.SetMainSize(item.MainSize() +
nscoord(sizeDelta.ToMinMaxClamped()));
- FLEX_LOG(" flex item %p receives %" PRId64 ", for a total of %d",
- item.Frame(), sizeDelta.value, item.MainSize());
+ FLEX_LOGV(" Flex item %p receives %" PRId64 ", for a total of %d",
+ item.Frame(), sizeDelta.value, item.MainSize());
}
}
@@ -3360,7 +3369,7 @@ void FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize,
// Fix min/max violations:
nscoord totalViolation = 0; // keeps track of adjustments for min/max
- FLEX_LOG(" Checking for violations:");
+ FLEX_LOGV("Checking for violations:");
// Since this loop only operates on unfrozen flex items, we can break as
// soon as we have seen all of them.
@@ -3392,7 +3401,7 @@ void FlexLine::ResolveFlexibleLengths(nscoord aFlexContainerMainSize,
FreezeOrRestoreEachFlexibleSize(totalViolation,
iterationCounter + 1 == NumItems());
- FLEX_LOG(" Total violation: %d", totalViolation);
+ FLEX_LOGV("Total violation: %d", totalViolation);
if (mNumFrozenItems == NumItems()) {
break;
@@ -3952,7 +3961,7 @@ void SingleLineCrossAxisPositionTracker::EnterAlignPackingSpace(
if (alignSelf == StyleAlignFlags::SELF_START ||
alignSelf == StyleAlignFlags::SELF_END) {
const LogicalAxis logCrossAxis =
- aAxisTracker.IsRowOriented() ? eLogicalAxisBlock : eLogicalAxisInline;
+ aAxisTracker.IsRowOriented() ? LogicalAxis::Block : LogicalAxis::Inline;
const WritingMode cWM = aAxisTracker.GetWritingMode();
const bool sameStart =
cWM.ParallelAxisStartsOnSameSide(logCrossAxis, aItem.GetWritingMode());
@@ -4102,12 +4111,13 @@ FlexboxAxisTracker::FlexboxAxisTracker(
LogicalSide FlexboxAxisTracker::MainAxisStartSide() const {
return MakeLogicalSide(
- MainAxis(), IsMainAxisReversed() ? eLogicalEdgeEnd : eLogicalEdgeStart);
+ MainAxis(), IsMainAxisReversed() ? LogicalEdge::End : LogicalEdge::Start);
}
LogicalSide FlexboxAxisTracker::CrossAxisStartSide() const {
- return MakeLogicalSide(
- CrossAxis(), IsCrossAxisReversed() ? eLogicalEdgeEnd : eLogicalEdgeStart);
+ return MakeLogicalSide(CrossAxis(), IsCrossAxisReversed()
+ ? LogicalEdge::End
+ : LogicalEdge::Start);
}
void nsFlexContainerFrame::GenerateFlexLines(
@@ -4560,7 +4570,6 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsFlexContainerFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
MOZ_ASSERT(aPresContext == PresContext());
NS_WARNING_ASSERTION(
@@ -4568,7 +4577,7 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
"Unconstrained inline size; this should only result from huge sizes "
"(not intrinsic sizing w/ orthogonal flows)");
- FLEX_LOG("Reflow() for nsFlexContainerFrame %p", this);
+ FLEX_LOG("Reflowing flex container frame %p ...", this);
if (IsFrameTreeTooDeep(aReflowInput, aReflowOutput, aStatus)) {
return;
@@ -4877,8 +4886,14 @@ void nsFlexContainerFrame::UnionInFlowChildOverflow(
bool anyScrolledContentItem = false;
// Union of normal-positioned margin boxes for all the items.
nsRect itemMarginBoxes;
- // Union of relative-positioned margin boxes for the relpos items only.
- nsRect relPosItemMarginBoxes;
+ // Overflow areas containing the union of relative-positioned and
+ // stick-positioned margin boxes of relpos items.
+ //
+ // Note for sticky-positioned margin boxes, we only union it with the ink
+ // overflow to avoid circular dependencies with the scroll container. (The
+ // scroll position and the scroll container's size impact the sticky position,
+ // so we don't want the sticky position to impact them.)
+ OverflowAreas relPosItemMarginBoxes;
const bool useMozBoxCollapseBehavior =
StyleVisibility()->UseLegacyCollapseBehavior();
for (nsIFrame* f : mFrames) {
@@ -4897,8 +4912,13 @@ void nsFlexContainerFrame::UnionInFlowChildOverflow(
const nsRect marginRect = f->GetMarginRectRelativeToSelf();
itemMarginBoxes =
itemMarginBoxes.Union(marginRect + f->GetNormalPosition());
- relPosItemMarginBoxes =
- relPosItemMarginBoxes.Union(marginRect + f->GetPosition());
+ if (f->IsRelativelyPositioned()) {
+ relPosItemMarginBoxes.UnionAllWith(marginRect + f->GetPosition());
+ } else {
+ MOZ_ASSERT(f->IsStickyPositioned());
+ relPosItemMarginBoxes.UnionWith(
+ OverflowAreas(marginRect + f->GetPosition(), nsRect()));
+ }
} else {
itemMarginBoxes = itemMarginBoxes.Union(f->GetMarginRect());
}
@@ -4907,7 +4927,7 @@ void nsFlexContainerFrame::UnionInFlowChildOverflow(
if (anyScrolledContentItem) {
itemMarginBoxes.Inflate(GetUsedPadding());
aOverflowAreas.UnionAllWith(itemMarginBoxes);
- aOverflowAreas.UnionAllWith(relPosItemMarginBoxes);
+ aOverflowAreas.UnionWith(relPosItemMarginBoxes);
}
}
@@ -5276,8 +5296,8 @@ nsFlexContainerFrame::FlexLayoutResult nsFlexContainerFrame::DoFlexLayout(
} else {
sizeOverrides.mStyleBSize.emplace(item.StyleMainSize());
}
- FLEX_LOG("Sizing flex item %p in cross axis", item.Frame());
- FLEX_LOGV(" Main size override: %d", item.MainSize());
+ FLEX_ITEM_LOG(item.Frame(), "Sizing item in cross axis");
+ FLEX_LOGV("Main size override: %d", item.MainSize());
const WritingMode wm = item.GetWritingMode();
LogicalSize availSize = aReflowInput.ComputedSize(wm);
@@ -5507,14 +5527,19 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
const bool isSingleLine =
StyleFlexWrap::Nowrap == aReflowInput.mStylePosition->mFlexWrap;
-
- // FINAL REFLOW: Give each child frame another chance to reflow, now that
- // we know its final size and position.
const FlexLine& startmostLine = StartmostLine(aFlr.mLines, aAxisTracker);
+ const FlexLine& endmostLine = EndmostLine(aFlr.mLines, aAxisTracker);
const FlexItem* startmostItem =
startmostLine.IsEmpty() ? nullptr
: &startmostLine.StartmostItem(aAxisTracker);
+ const FlexItem* endmostItem =
+ endmostLine.IsEmpty() ? nullptr : &endmostLine.EndmostItem(aAxisTracker);
+ bool endmostItemOrLineHasBreakAfter = false;
+ // If true, push all remaining flex items to the container's next-in-flow.
+ bool shouldPushRemainingItems = false;
+
+ // FINAL REFLOW: Give each child frame another chance to reflow.
const size_t numLines = aFlr.mLines.Length();
for (size_t lineIdx = 0; lineIdx < numLines; ++lineIdx) {
// Iterate flex lines from the startmost to endmost (relative to flex
@@ -5525,6 +5550,11 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
MOZ_ASSERT(lineIdx != 0 || &line == &startmostLine,
"Logic for finding startmost line should be consistent!");
+ // These two variables can be set when we are a row-oriented flex container
+ // during fragmentation.
+ bool lineHasBreakBefore = false;
+ bool lineHasBreakAfter = false;
+
const size_t numItems = line.Items().Length();
for (size_t itemIdx = 0; itemIdx < numItems; ++itemIdx) {
// Iterate flex items from the startmost to endmost (relative to flex
@@ -5623,15 +5653,22 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
// (i.e. its frame rect), instead of the container's content-box:
framePos += containerContentBoxOrigin;
- // Check if we actually need to reflow the item -- if the item's position
- // is below the available space's block-end, push it to our next-in-flow;
- // if it does need a reflow, and we already reflowed it with the right
- // content-box size.
- const bool childBPosExceedAvailableSpaceBEnd =
- availableBSizeForItem != NS_UNCONSTRAINEDSIZE &&
- availableBSizeForItem <= 0;
+ // Check if we can skip reflowing the item because it will be pushed to
+ // our next-in-flow -- i.e. if there was a forced break before it, or its
+ // position is beyond the available space's block-end.
bool itemInPushedItems = false;
- if (childBPosExceedAvailableSpaceBEnd) {
+ if (shouldPushRemainingItems) {
+ FLEX_ITEM_LOG(
+ item.Frame(),
+ "[frag] Item needed to be pushed to container's next-in-flow due "
+ "to a forced break before it");
+ pushedItems.Insert(item.Frame());
+ itemInPushedItems = true;
+ } else if (availableBSizeForItem != NS_UNCONSTRAINEDSIZE &&
+ availableBSizeForItem <= 0) {
+ // The item's position is beyond the available space, so we have to push
+ // it.
+ //
// Note: Even if all of our items are beyond the available space & get
// pushed here, we'll be guaranteed to place at least one of them (and
// make progress) in one of the flex container's *next* fragment. It's
@@ -5640,10 +5677,10 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
// block-size and add it to
// PerFragmentFlexData::mCumulativeContentBoxBSize even if we are not
// laying out any child.
- FLEX_LOG(
- "[frag] Flex item %p needed to be pushed to container's "
- "next-in-flow due to position below available space's block-end",
- item.Frame());
+ FLEX_ITEM_LOG(
+ item.Frame(),
+ "[frag] Item needed to be pushed to container's next-in-flow due "
+ "to being positioned beyond block-end edge of available space");
pushedItems.Insert(item.Frame());
itemInPushedItems = true;
} else if (item.NeedsFinalReflow(aReflowInput)) {
@@ -5654,17 +5691,50 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
availableBSizeForItem)
.ConvertTo(itemWM, flexWM);
- const nsReflowStatus childReflowStatus =
+ const bool isAdjacentWithBStart =
+ framePos.B(flexWM) == containerContentBoxOrigin.B(flexWM);
+ const nsReflowStatus childStatus =
ReflowFlexItem(aAxisTracker, aReflowInput, item, framePos,
- availableSize, aContainerSize);
+ isAdjacentWithBStart, availableSize, aContainerSize);
+
+ if (aReflowInput.IsInFragmentedContext()) {
+ const bool itemHasBreakBefore =
+ item.Frame()->ShouldBreakBefore(aReflowInput.mBreakType) ||
+ childStatus.IsInlineBreakBefore();
+ if (itemHasBreakBefore) {
+ if (aAxisTracker.IsRowOriented()) {
+ lineHasBreakBefore = true;
+ } else if (isSingleLine) {
+ if (&item == startmostItem) {
+ if (!GetPrevInFlow() && !aReflowInput.mFlags.mIsTopOfPage) {
+ // If we are first-in-flow and not at top-of-page, early
+ // return here to propagate forced break-before from the
+ // startmost item to the flex container.
+ nsReflowStatus childrenStatus;
+ childrenStatus.SetInlineLineBreakBeforeAndReset();
+ return {0, childrenStatus};
+ }
+ } else {
+ shouldPushRemainingItems = true;
+ }
+ } else {
+ // Bug 1806717: We haven't implemented fragmentation for
+ // multi-line column-oriented flex container, so we just ignore
+ // forced breaks for now.
+ }
+ }
+ }
const bool shouldPushItem = [&]() {
+ if (shouldPushRemainingItems) {
+ return true;
+ }
if (availableBSizeForItem == NS_UNCONSTRAINEDSIZE) {
// If the available block-size is unconstrained, then we're not
// fragmenting and we don't want to push the item.
return false;
}
- if (framePos.B(flexWM) == containerContentBoxOrigin.B(flexWM)) {
+ if (isAdjacentWithBStart) {
// The flex item is adjacent with block-start of the container's
// content-box. Don't push it, or we'll trap in an infinite loop.
return false;
@@ -5680,19 +5750,41 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
return true;
}();
if (shouldPushItem) {
- FLEX_LOG(
- "[frag] Flex item %p needed to be pushed to container's "
- "next-in-flow because its block-size is larger than the "
- "available space",
- item.Frame());
+ FLEX_ITEM_LOG(
+ item.Frame(),
+ "[frag] Item needed to be pushed to container's next-in-flow "
+ "because it encounters a forced break before it, or its "
+ "block-size is larger than the available space");
pushedItems.Insert(item.Frame());
itemInPushedItems = true;
- } else if (childReflowStatus.IsIncomplete()) {
+ } else if (childStatus.IsIncomplete()) {
incompleteItems.Insert(item.Frame());
- } else if (childReflowStatus.IsOverflowIncomplete()) {
+ } else if (childStatus.IsOverflowIncomplete()) {
overflowIncompleteItems.Insert(item.Frame());
}
+
+ if (aReflowInput.IsInFragmentedContext()) {
+ const bool itemHasBreakAfter =
+ item.Frame()->ShouldBreakAfter(aReflowInput.mBreakType) ||
+ childStatus.IsInlineBreakAfter();
+ if (itemHasBreakAfter) {
+ if (aAxisTracker.IsRowOriented()) {
+ lineHasBreakAfter = true;
+ } else if (isSingleLine) {
+ shouldPushRemainingItems = true;
+ if (&item == endmostItem) {
+ endmostItemOrLineHasBreakAfter = true;
+ }
+ } else {
+ // Bug 1806717: We haven't implemented fragmentation for
+ // multi-line column-oriented flex container, so we just ignore
+ // forced breaks for now.
+ }
+ }
+ }
} else {
+ // We already reflowed the item with the right content-box size, so we
+ // can simply move it into place.
MoveFlexItemToFinalPosition(item, framePos, aContainerSize);
}
@@ -5780,6 +5872,37 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
}
}
+ if (aReflowInput.IsInFragmentedContext() && aAxisTracker.IsRowOriented()) {
+ // Propagate forced break values from the flex items to its flex line.
+ if (lineHasBreakBefore) {
+ if (&line == &startmostLine) {
+ if (!GetPrevInFlow() && !aReflowInput.mFlags.mIsTopOfPage) {
+ // If we are first-in-flow and not at top-of-page, early return here
+ // to propagate forced break-before from the startmost line to the
+ // flex container.
+ nsReflowStatus childrenStatus;
+ childrenStatus.SetInlineLineBreakBeforeAndReset();
+ return {0, childrenStatus};
+ }
+ } else {
+ // Current non-startmost line has forced break-before, so push all the
+ // items in this line.
+ for (const FlexItem& item : line.Items()) {
+ pushedItems.Insert(item.Frame());
+ incompleteItems.Remove(item.Frame());
+ overflowIncompleteItems.Remove(item.Frame());
+ }
+ shouldPushRemainingItems = true;
+ }
+ }
+ if (lineHasBreakAfter) {
+ shouldPushRemainingItems = true;
+ if (&line == &endmostLine) {
+ endmostItemOrLineHasBreakAfter = true;
+ }
+ }
+ }
+
// Now we've finished processing all the items in the startmost line.
// Determine the amount by which the startmost line's block-end edge has
// shifted, so we can apply the same shift for the remaining lines.
@@ -5801,6 +5924,8 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
childrenStatus.SetIncomplete();
} else if (!overflowIncompleteItems.IsEmpty()) {
childrenStatus.SetOverflowIncomplete();
+ } else if (endmostItemOrLineHasBreakAfter) {
+ childrenStatus.SetInlineLineBreakAfter();
}
PushIncompleteChildren(pushedItems, incompleteItems, overflowIncompleteItems);
@@ -5945,6 +6070,14 @@ void nsFlexContainerFrame::PopulateReflowOutput(
return;
}
+ // Propagate forced break values from flex items or flex lines.
+ if (aChildrenStatus.IsInlineBreakBefore()) {
+ aStatus.SetInlineLineBreakBeforeAndReset();
+ }
+ if (aChildrenStatus.IsInlineBreakAfter()) {
+ aStatus.SetInlineLineBreakAfter();
+ }
+
// If we haven't established a baseline for the container yet, i.e. if we
// don't have any flex item in the startmost flex line that participates in
// baseline alignment, then use the startmost flex item to derive the
@@ -6050,8 +6183,8 @@ void nsFlexContainerFrame::MoveFlexItemToFinalPosition(
logicalOffsets, &pos, aContainerSize);
}
- FLEX_LOG("Moving flex item %p to its desired position %s", aItem.Frame(),
- ToString(pos).c_str());
+ FLEX_ITEM_LOG(aItem.Frame(), "Moving item to its desired position %s",
+ ToString(pos).c_str());
aItem.Frame()->SetPosition(outerWM, pos, aContainerSize);
PositionFrameView(aItem.Frame());
PositionChildViews(aItem.Frame());
@@ -6060,8 +6193,9 @@ void nsFlexContainerFrame::MoveFlexItemToFinalPosition(
nsReflowStatus nsFlexContainerFrame::ReflowFlexItem(
const FlexboxAxisTracker& aAxisTracker, const ReflowInput& aReflowInput,
const FlexItem& aItem, const LogicalPoint& aFramePos,
- const LogicalSize& aAvailableSize, const nsSize& aContainerSize) {
- FLEX_LOG("Doing final reflow for flex item %p", aItem.Frame());
+ const bool aIsAdjacentWithBStart, const LogicalSize& aAvailableSize,
+ const nsSize& aContainerSize) {
+ FLEX_ITEM_LOG(aItem.Frame(), "Doing final reflow");
// Returns true if we should use 'auto' in block axis's StyleSizeOverrides to
// allow fragmentation-imposed block-size growth.
@@ -6131,15 +6265,15 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem(
// Override flex item's main size.
if (aItem.IsInlineAxisMainAxis()) {
sizeOverrides.mStyleISize.emplace(aItem.StyleMainSize());
- FLEX_LOGV(" Main size (inline-size) override: %d", aItem.MainSize());
+ FLEX_LOGV("Main size (inline-size) override: %d", aItem.MainSize());
} else {
overrideBSizeWithAuto = ComputeBSizeOverrideWithAuto();
if (overrideBSizeWithAuto) {
sizeOverrides.mStyleBSize.emplace(StyleSize::Auto());
- FLEX_LOGV(" Main size (block-size) override: Auto");
+ FLEX_LOGV("Main size (block-size) override: Auto");
} else {
sizeOverrides.mStyleBSize.emplace(aItem.StyleMainSize());
- FLEX_LOGV(" Main size (block-size) override: %d", aItem.MainSize());
+ FLEX_LOGV("Main size (block-size) override: %d", aItem.MainSize());
}
}
@@ -6148,15 +6282,15 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem(
if (aItem.IsStretched()) {
if (aItem.IsInlineAxisCrossAxis()) {
sizeOverrides.mStyleISize.emplace(aItem.StyleCrossSize());
- FLEX_LOGV(" Cross size (inline-size) override: %d", aItem.CrossSize());
+ FLEX_LOGV("Cross size (inline-size) override: %d", aItem.CrossSize());
} else {
overrideBSizeWithAuto = ComputeBSizeOverrideWithAuto();
if (overrideBSizeWithAuto) {
sizeOverrides.mStyleBSize.emplace(StyleSize::Auto());
- FLEX_LOGV(" Cross size (block-size) override: Auto");
+ FLEX_LOGV("Cross size (block-size) override: Auto");
} else {
sizeOverrides.mStyleBSize.emplace(aItem.StyleCrossSize());
- FLEX_LOGV(" Cross size (block-size) override: %d", aItem.CrossSize());
+ FLEX_LOGV("Cross size (block-size) override: %d", aItem.CrossSize());
}
}
}
@@ -6199,21 +6333,28 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem(
aItem.Frame()->AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
}
+ if (!aIsAdjacentWithBStart) {
+ // mIsTopOfPage bit in childReflowInput is carried over from aReflowInput.
+ // However, if this item's position is not adjacent with the flex
+ // container's content-box block-start edge, we should clear it.
+ childReflowInput.mFlags.mIsTopOfPage = false;
+ }
+
// NOTE: Be very careful about doing anything else with childReflowInput
// after this point, because some of its methods (e.g. SetComputedWidth)
// internally call InitResizeFlags and stomp on mVResize & mHResize.
- FLEX_LOG("Reflowing flex item %p at its desired position %s", aItem.Frame(),
- ToString(aFramePos).c_str());
+ FLEX_ITEM_LOG(aItem.Frame(), "Reflowing item at its desired position %s",
+ ToString(aFramePos).c_str());
// CachedFlexItemData is stored in item's writing mode, so we pass
// aChildReflowInput into ReflowOutput's constructor.
ReflowOutput childReflowOutput(childReflowInput);
- nsReflowStatus childReflowStatus;
+ nsReflowStatus childStatus;
WritingMode outerWM = aReflowInput.GetWritingMode();
ReflowChild(aItem.Frame(), PresContext(), childReflowOutput, childReflowInput,
outerWM, aFramePos, aContainerSize, ReflowChildFlags::Default,
- childReflowStatus);
+ childStatus);
// XXXdholbert Perhaps we should call CheckForInterrupt here; see bug 1495532.
@@ -6233,7 +6374,7 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem(
aItem.Frame()->SetProperty(CachedFlexItemData::Prop(), cached);
}
- return childReflowStatus;
+ return childStatus;
}
void nsFlexContainerFrame::ReflowPlaceholders(
@@ -6253,10 +6394,10 @@ void nsFlexContainerFrame::ReflowPlaceholders(
// No need to set the -webkit-line-clamp related flags when reflowing
// a placeholder.
ReflowOutput childReflowOutput(outerWM);
- nsReflowStatus childReflowStatus;
+ nsReflowStatus childStatus;
ReflowChild(placeholder, PresContext(), childReflowOutput, childReflowInput,
outerWM, aContentBoxOrigin, aContainerSize,
- ReflowChildFlags::Default, childReflowStatus);
+ ReflowChildFlags::Default, childStatus);
FinishReflowChild(placeholder, PresContext(), childReflowOutput,
&childReflowInput, outerWM, aContentBoxOrigin,
@@ -6332,7 +6473,6 @@ nscoord nsFlexContainerFrame::IntrinsicISize(gfxContext* aRenderingContext,
/* virtual */
nscoord nsFlexContainerFrame::GetMinISize(gfxContext* aRenderingContext) {
- DISPLAY_MIN_INLINE_SIZE(this, mCachedMinISize);
if (mCachedMinISize == NS_INTRINSIC_ISIZE_UNKNOWN) {
if (Maybe<nscoord> containISize = ContainIntrinsicISize()) {
mCachedMinISize = *containISize;
@@ -6347,7 +6487,6 @@ nscoord nsFlexContainerFrame::GetMinISize(gfxContext* aRenderingContext) {
/* virtual */
nscoord nsFlexContainerFrame::GetPrefISize(gfxContext* aRenderingContext) {
- DISPLAY_PREF_INLINE_SIZE(this, mCachedPrefISize);
if (mCachedPrefISize == NS_INTRINSIC_ISIZE_UNKNOWN) {
if (Maybe<nscoord> containISize = ContainIntrinsicISize()) {
mCachedPrefISize = *containISize;
diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h
index 30e440b401..2771098255 100644
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -12,15 +12,9 @@
#include <tuple>
#include "mozilla/dom/FlexBinding.h"
-#include "mozilla/UniquePtr.h"
#include "nsContainerFrame.h"
#include "nsILineIterator.h"
-namespace mozilla {
-class LogicalPoint;
-class PresShell;
-} // namespace mozilla
-
nsContainerFrame* NS_NewFlexContainerFrame(mozilla::PresShell* aPresShell,
mozilla::ComputedStyle* aStyle);
@@ -610,6 +604,8 @@ class nsFlexContainerFrame final : public nsContainerFrame,
* @param aItem The flex item to be reflowed.
* @param aFramePos The position where the flex item's frame should
* be placed. (pre-relative positioning)
+ * @param aIsAdjacentWithBStart True if aFramePos is adjacent with the flex
+ * container's content-box block-start edge.
* @param aAvailableSize The available size to reflow the child frame (in the
* child frame's writing-mode).
* @param aContainerSize The flex container's size (required by some methods
@@ -620,6 +616,7 @@ class nsFlexContainerFrame final : public nsContainerFrame,
const ReflowInput& aReflowInput,
const FlexItem& aItem,
const mozilla::LogicalPoint& aFramePos,
+ const bool aIsAdjacentWithBStart,
const mozilla::LogicalSize& aAvailableSize,
const nsSize& aContainerSize);
diff --git a/layout/generic/nsFloatManager.cpp b/layout/generic/nsFloatManager.cpp
index b6612ca6f5..88a8b20b4c 100644
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -2507,7 +2507,7 @@ nsFloatManager::ShapeInfo::CreateBasicShape(const StyleBasicShape& aBasicShape,
case StyleBasicShape::Tag::Rect:
return CreateInset(aBasicShape, aShapeMargin, aFrame, aShapeBoxRect, aWM,
aContainerSize);
- case StyleBasicShape::Tag::Path:
+ case StyleBasicShape::Tag::PathOrShape:
MOZ_ASSERT_UNREACHABLE("Unsupported basic shape");
}
return nullptr;
@@ -2834,8 +2834,8 @@ nsFloatManager::ShapeInfo::ConvertToFloatLogical(const nscoord aRadii[8],
// Get the physical side for line-left and line-right since border radii
// are on the physical axis.
- Side lineLeftSide =
- aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
+ Side lineLeftSide = aWM.PhysicalSide(
+ aWM.LogicalSideForLineRelativeDir(LineRelativeDir::Left));
logicalRadii[eCornerTopLeftX] =
aRadii[SideToHalfCorner(lineLeftSide, true, false)];
logicalRadii[eCornerTopLeftY] =
@@ -2846,7 +2846,7 @@ nsFloatManager::ShapeInfo::ConvertToFloatLogical(const nscoord aRadii[8],
aRadii[SideToHalfCorner(lineLeftSide, false, true)];
Side lineRightSide = aWM.PhysicalSide(
- aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
+ aWM.LogicalSideForLineRelativeDir(LineRelativeDir::Right));
logicalRadii[eCornerTopRightX] =
aRadii[SideToHalfCorner(lineRightSide, false, false)];
logicalRadii[eCornerTopRightY] =
diff --git a/layout/generic/nsFrameSelection.cpp b/layout/generic/nsFrameSelection.cpp
index f1a8c7e27c..94cf368480 100644
--- a/layout/generic/nsFrameSelection.cpp
+++ b/layout/generic/nsFrameSelection.cpp
@@ -156,9 +156,10 @@ PeekOffsetStruct::PeekOffsetStruct(nsSelectionAmount aAmount,
} // namespace mozilla
-// Array which contains index of each SelecionType in Selection::mDOMSelections.
-// For avoiding using if nor switch to retrieve the index, this needs to have
-// -1 for SelectionTypes which won't be created its Selection instance.
+// Array which contains index of each SelectionType in
+// Selection::mDOMSelections. For avoiding using if nor switch to retrieve the
+// index, this needs to have -1 for SelectionTypes which won't be created its
+// Selection instance.
static const int8_t kIndexOfSelections[] = {
-1, // SelectionType::eInvalid
-1, // SelectionType::eNone
@@ -172,6 +173,7 @@ static const int8_t kIndexOfSelections[] = {
7, // SelectionType::eFind
8, // SelectionType::eURLSecondary
9, // SelectionType::eURLStrikeout
+ 10, // SelectionType::eTargetText
-1, // SelectionType::eHighlight
};
@@ -539,7 +541,11 @@ nsresult nsFrameSelection::ConstrainFrameAndPointToAnchorSubtree(
NS_ENSURE_STATE(mPresShell);
RefPtr<PresShell> presShell = mPresShell;
- nsIContent* anchorRoot = anchorContent->GetSelectionRootContent(presShell);
+ nsIContent* anchorRoot =
+ anchorContent
+ ->GetSelectionRootContent(
+ presShell,
+ StaticPrefs::dom_shadowdom_selection_across_boundary_enabled() /* aAllowCrossShadowBoundary */);
NS_ENSURE_TRUE(anchorRoot, NS_ERROR_UNEXPECTED);
//
@@ -549,7 +555,10 @@ nsresult nsFrameSelection::ConstrainFrameAndPointToAnchorSubtree(
nsCOMPtr<nsIContent> content = aFrame->GetContent();
if (content) {
- nsIContent* contentRoot = content->GetSelectionRootContent(presShell);
+ nsIContent* contentRoot =
+ content->GetSelectionRootContent(
+ presShell, StaticPrefs::
+ dom_shadowdom_selection_across_boundary_enabled() /* aAllowCrossShadowBoundary */);
NS_ENSURE_TRUE(contentRoot, NS_ERROR_UNEXPECTED);
if (anchorRoot == contentRoot) {
@@ -573,8 +582,9 @@ nsresult nsFrameSelection::ConstrainFrameAndPointToAnchorSubtree(
if (cursorFrame && cursorFrame->PresShell() == presShell) {
nsCOMPtr<nsIContent> cursorContent = cursorFrame->GetContent();
NS_ENSURE_TRUE(cursorContent, NS_ERROR_FAILURE);
- nsIContent* cursorContentRoot =
- cursorContent->GetSelectionRootContent(presShell);
+ nsIContent* cursorContentRoot = cursorContent->GetSelectionRootContent(
+ presShell, StaticPrefs::
+ dom_shadowdom_selection_across_boundary_enabled() /* aAllowCrossShadowBoundary */);
NS_ENSURE_TRUE(cursorContentRoot, NS_ERROR_UNEXPECTED);
if (cursorContentRoot == anchorRoot) {
*aRetFrame = cursorFrame;
@@ -1431,11 +1441,6 @@ nsresult nsFrameSelection::TakeFocus(nsIContent& aNewFocus,
}
}
- // Don't notify selection listeners if batching is on:
- if (IsBatching()) {
- return NS_OK;
- }
-
// Be aware, the Selection instance may be destroyed after this call.
return NotifySelectionListeners(SelectionType::eNormal);
}
@@ -1493,11 +1498,11 @@ void nsFrameSelection::SetDragState(bool aState) {
// Notify that reason is mouse up.
SetChangeReasons(nsISelectionListener::MOUSEUP_REASON);
- // flag is set to false in `NotifySelectionListeners`.
+ // flag is set to NotApplicable in `Selection::NotifySelectionListeners`.
// since this function call is part of click event, this would immediately
// reset the flag, rendering it useless.
- AutoRestore<bool> restoreIsDoubleClickSelectionFlag(
- mIsDoubleClickSelection);
+ AutoRestore<ClickSelectionType> restoreClickSelectionType(
+ mClickSelectionType);
// Be aware, the Selection instance may be destroyed after this call.
NotifySelectionListeners(SelectionType::eNormal);
}
diff --git a/layout/generic/nsFrameSelection.h b/layout/generic/nsFrameSelection.h
index e8c55d53b5..3ba6fa72ca 100644
--- a/layout/generic/nsFrameSelection.h
+++ b/layout/generic/nsFrameSelection.h
@@ -200,6 +200,7 @@ class SelectionChangeEventDispatcher;
namespace dom {
class Highlight;
class Selection;
+enum class ClickSelectionType { NotApplicable, Double, Triple };
} // namespace dom
/**
@@ -259,14 +260,17 @@ class nsFrameSelection final {
public:
/**
- * Sets flag to true if a selection is created by doubleclick or
- * long tapping a word.
+ * Sets the type of the selection based on whether a selection is created
+ * by doubleclick, long tapping a word or tripleclick.
*
- * @param aIsDoubleClickSelection True if the selection is created by
- * doubleclick or long tap over a word.
+ * @param aClickSelectionType ClickSelectionType::Double if the selection
+ * is created by doubleclick,
+ * ClickSelectionType::Triple if the selection
+ * is created by tripleclick.
*/
- void SetIsDoubleClickSelection(bool aIsDoubleClickSelection) {
- mIsDoubleClickSelection = aIsDoubleClickSelection;
+ void SetClickSelectionType(
+ mozilla::dom::ClickSelectionType aClickSelectionType) {
+ mClickSelectionType = aClickSelectionType;
}
/**
@@ -274,7 +278,14 @@ class nsFrameSelection final {
* long tap over a word.
*/
[[nodiscard]] bool IsDoubleClickSelection() const {
- return mIsDoubleClickSelection;
+ return mClickSelectionType == mozilla::dom::ClickSelectionType::Double;
+ }
+
+ /**
+ * Returns true if the selection was created by triple click
+ */
+ [[nodiscard]] bool IsTripleClickSelection() const {
+ return mClickSelectionType == mozilla::dom::ClickSelectionType::Triple;
}
/**
@@ -1102,11 +1113,12 @@ class nsFrameSelection final {
bool mDragState = false; // for drag purposes
bool mAccessibleCaretEnabled = false;
- // Records if a selection was created by doubleclicking a word.
- // This information is needed later on to determine if a leading
+ // Records if a selection was created by doubleclicking or tripleclicking
+ // a word. This information is needed later on to determine if a leading
// or trailing whitespace needs to be removed as well to achieve
// native behaviour on macOS.
- bool mIsDoubleClickSelection{false};
+ mozilla::dom::ClickSelectionType mClickSelectionType =
+ mozilla::dom::ClickSelectionType::NotApplicable;
};
/**
diff --git a/layout/generic/nsFrameSetFrame.cpp b/layout/generic/nsFrameSetFrame.cpp
index f292988c55..be561a6c32 100644
--- a/layout/generic/nsFrameSetFrame.cpp
+++ b/layout/generic/nsFrameSetFrame.cpp
@@ -760,7 +760,6 @@ void nsHTMLFramesetFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
mozilla::PresShell* presShell = aPresContext->PresShell();
@@ -1312,7 +1311,6 @@ void nsHTMLFramesetBorderFrame::Reflow(nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
DO_GLOBAL_REFLOW_COUNT("nsHTMLFramesetBorderFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// Override Reflow(), since we don't want to deal with what our
diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp
index 361847b753..97e6b614dc 100644
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -170,7 +170,7 @@ class nsHTMLScrollFrame::ScrollEvent : public Runnable {
class nsHTMLScrollFrame::ScrollEndEvent : public Runnable {
public:
NS_DECL_NSIRUNNABLE
- explicit ScrollEndEvent(nsHTMLScrollFrame* aHelper);
+ explicit ScrollEndEvent(nsHTMLScrollFrame* aHelper, bool aDelayed);
void Revoke() { mHelper = nullptr; }
private:
@@ -964,7 +964,7 @@ void nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowInput& aState,
nsRect childScrollableOverflow = childOverflow.ScrollableOverflow();
const LogicalMargin inlinePadding =
- padding.ApplySkipSides(LogicalSides(wm, eLogicalSideBitsBBoth));
+ padding.ApplySkipSides(LogicalSides(wm, LogicalSides::BBoth));
childScrollableOverflow.Inflate(inlinePadding.GetPhysicalMargin(wm));
nsRect& so = aMetrics->ScrollableOverflow();
@@ -1265,17 +1265,7 @@ nsMargin nsHTMLScrollFrame::ComputeStableScrollbarGutter(
// Legacy, this sucks!
static bool IsMarqueeScrollbox(const nsIFrame& aScrollFrame) {
- if (!aScrollFrame.GetContent()) {
- return false;
- }
- if (MOZ_LIKELY(!aScrollFrame.GetContent()->HasBeenInUAWidget())) {
- return false;
- }
- MOZ_ASSERT(aScrollFrame.GetParent() &&
- aScrollFrame.GetParent()->GetContent());
- return aScrollFrame.GetParent() &&
- HTMLMarqueeElement::FromNodeOrNull(
- aScrollFrame.GetParent()->GetContent());
+ return HTMLMarqueeElement::FromNodeOrNull(aScrollFrame.GetContent());
}
/* virtual */
@@ -1290,7 +1280,6 @@ nscoord nsHTMLScrollFrame::GetMinISize(gfxContext* aRenderingContext) {
return mScrolledFrame->GetMinISize(aRenderingContext);
}();
- DISPLAY_MIN_INLINE_SIZE(this, result);
return result + IntrinsicScrollbarGutterSizeAtInlineEdges();
}
@@ -1300,7 +1289,6 @@ nscoord nsHTMLScrollFrame::GetPrefISize(gfxContext* aRenderingContext) {
nscoord result = containISize
? *containISize
: mScrolledFrame->GetPrefISize(aRenderingContext);
- DISPLAY_PREF_INLINE_SIZE(this, result);
return NSCoordSaturatingAdd(result,
IntrinsicScrollbarGutterSizeAtInlineEdges());
}
@@ -1497,7 +1485,6 @@ void nsHTMLScrollFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsHTMLScrollFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
HandleScrollbarStyleSwitching();
@@ -5224,15 +5211,19 @@ nsSize nsHTMLScrollFrame::GetPageScrollAmount() const {
}
nsSize lineScrollAmount = GetLineScrollAmount();
+ const int32_t maxOverlapPercent = std::clamp(
+ StaticPrefs::toolkit_scrollbox_pagescroll_maxOverlapPercent(), 0, 80);
+ const int32_t maxOverlapLines =
+ std::max(StaticPrefs::toolkit_scrollbox_pagescroll_maxOverlapLines(), 0);
- // The page increment is the size of the page, minus the smaller of
- // 10% of the size or 2 lines.
- return nsSize(effectiveScrollPortSize.width -
- std::min(effectiveScrollPortSize.width / 10,
- 2 * lineScrollAmount.width),
- effectiveScrollPortSize.height -
- std::min(effectiveScrollPortSize.height / 10,
- 2 * lineScrollAmount.height));
+ // The page increment is the size of the page, minus some overlap.
+ return nsSize(
+ effectiveScrollPortSize.width -
+ std::min(effectiveScrollPortSize.width * maxOverlapPercent / 100,
+ maxOverlapLines * lineScrollAmount.width),
+ effectiveScrollPortSize.height -
+ std::min(effectiveScrollPortSize.height * maxOverlapPercent / 100,
+ maxOverlapLines * lineScrollAmount.height));
}
/**
@@ -5429,23 +5420,31 @@ nsresult nsHTMLScrollFrame::FireScrollPortEvent() {
return EventDispatcher::Dispatch(content, presContext, &event);
}
-void nsHTMLScrollFrame::PostScrollEndEvent() {
+void nsHTMLScrollFrame::PostScrollEndEvent(bool aDelayed) {
if (mScrollEndEvent) {
return;
}
// The ScrollEndEvent constructor registers itself with the refresh driver.
- mScrollEndEvent = new ScrollEndEvent(this);
+ mScrollEndEvent = new ScrollEndEvent(this, aDelayed);
}
void nsHTMLScrollFrame::FireScrollEndEvent() {
- MOZ_ASSERT(GetContent());
- MOZ_ASSERT(mScrollEndEvent);
+ RefPtr<nsIContent> content = GetContent();
+ MOZ_ASSERT(content);
- RefPtr<nsPresContext> presContext = PresContext();
+ MOZ_ASSERT(mScrollEndEvent);
mScrollEndEvent->Revoke();
mScrollEndEvent = nullptr;
+ if (content->GetComposedDoc() &&
+ content->GetComposedDoc()->EventHandlingSuppressed()) {
+ content->GetComposedDoc()->SetHasDelayedRefreshEvent();
+ PostScrollEndEvent(/* aDelayed = */ true);
+ return;
+ }
+
+ RefPtr<nsPresContext> presContext = PresContext();
nsEventStatus status = nsEventStatus_eIgnore;
WidgetGUIEvent event(true, eScrollend, nullptr);
event.mFlags.mBubbles = mIsRoot;
@@ -5895,9 +5894,10 @@ nsHTMLScrollFrame::ScrollEvent::Run() {
return NS_OK;
}
-nsHTMLScrollFrame::ScrollEndEvent::ScrollEndEvent(nsHTMLScrollFrame* aHelper)
+nsHTMLScrollFrame::ScrollEndEvent::ScrollEndEvent(nsHTMLScrollFrame* aHelper,
+ bool aDelayed)
: Runnable("nsHTMLScrollFrame::ScrollEndEvent"), mHelper(aHelper) {
- mHelper->PresContext()->RefreshDriver()->PostScrollEvent(this);
+ mHelper->PresContext()->RefreshDriver()->PostScrollEvent(this, aDelayed);
}
MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHODIMP
diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h
index ce2a75a3df..9d619de4e5 100644
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -500,7 +500,7 @@ class nsHTMLScrollFrame : public nsContainerFrame,
OverflowState GetOverflowState() const;
MOZ_CAN_RUN_SCRIPT nsresult FireScrollPortEvent();
- void PostScrollEndEvent();
+ void PostScrollEndEvent(bool aDelayed = false);
MOZ_CAN_RUN_SCRIPT void FireScrollEndEvent();
void PostOverflowEvent();
diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp
index 5eb9cde7da..48c70cd479 100644
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -28,6 +28,7 @@
#include "nsCSSFrameConstructor.h"
#include "nsDisplayList.h"
#include "nsFieldSetFrame.h"
+#include "nsHTMLButtonControlFrame.h"
#include "nsGfxScrollFrame.h"
#include "nsHashKeys.h"
#include "nsIFrameInlines.h" // for nsIFrame::GetLogicalNormalPosition (don't remove)
@@ -168,7 +169,7 @@ static nscoord ResolveToDefiniteSize(const StyleTrackBreadth& aBreadth,
// block axis; e.g. for English horizontal-tb text, a traditional baseline
// would be a y-axis measurement. But in some cases (e.g. orthogonal WMs), we
// may need to synthesize a baseline in a child's inline axis, which is when
-// this function might receive an aAxis of eLogicalAxisInline. In that case, we
+// this function might receive an aAxis of LogicalAxis::Inline. In that case, we
// assume that the writing mode's preference for central vs. alphabetic
// baselines is irrelevant, since that's a choice about its block-axis
// baselines, and we just unconditionally use the alphabetic baseline
@@ -178,7 +179,7 @@ static nscoord SynthesizeBaselineFromBorderBox(BaselineSharingGroup aGroup,
LogicalAxis aAxis,
nscoord aBorderBoxSize) {
const bool useAlphabeticBaseline =
- (aAxis == eLogicalAxisInline) ? true : aWM.IsAlphabeticalBaseline();
+ (aAxis == LogicalAxis::Inline) ? true : aWM.IsAlphabeticalBaseline();
if (aGroup == BaselineSharingGroup::First) {
return useAlphabeticBaseline ? aBorderBoxSize : aBorderBoxSize / 2;
@@ -218,7 +219,7 @@ struct RepeatTrackSizingInput {
// We can use zero percentage basis since this is only called from
// intrinsic sizing code.
const nscoord percentageBasis = 0;
- if (aAxis == eLogicalAxisInline) {
+ if (aAxis == LogicalAxis::Inline) {
bp = std::max(padding.GetIStart(aWM).Resolve(percentageBasis), 0) +
std::max(padding.GetIEnd(aWM).Resolve(percentageBasis), 0) +
border.IStartEnd(aWM);
@@ -234,17 +235,17 @@ struct RepeatTrackSizingInput {
nscoord& size = mSize.Size(aAxis, aWM);
nscoord& max = mMax.Size(aAxis, aWM);
const auto& minCoord =
- aAxis == eLogicalAxisInline ? pos->MinISize(aWM) : pos->MinBSize(aWM);
+ aAxis == LogicalAxis::Inline ? pos->MinISize(aWM) : pos->MinBSize(aWM);
if (minCoord.ConvertsToLength()) {
min = adjustForBoxSizing(minCoord.ToLength());
}
const auto& maxCoord =
- aAxis == eLogicalAxisInline ? pos->MaxISize(aWM) : pos->MaxBSize(aWM);
+ aAxis == LogicalAxis::Inline ? pos->MaxISize(aWM) : pos->MaxBSize(aWM);
if (maxCoord.ConvertsToLength()) {
max = std::max(min, adjustForBoxSizing(maxCoord.ToLength()));
}
const auto& sizeCoord =
- aAxis == eLogicalAxisInline ? pos->ISize(aWM) : pos->BSize(aWM);
+ aAxis == LogicalAxis::Inline ? pos->ISize(aWM) : pos->BSize(aWM);
if (sizeCoord.ConvertsToLength()) {
size = Clamp(adjustForBoxSizing(sizeCoord.ToLength()), min, max);
}
@@ -576,10 +577,10 @@ struct nsGridContainerFrame::GridArea {
: mCols(aCols), mRows(aRows) {}
bool IsDefinite() const { return mCols.IsDefinite() && mRows.IsDefinite(); }
LineRange& LineRangeForAxis(LogicalAxis aAxis) {
- return aAxis == eLogicalAxisInline ? mCols : mRows;
+ return aAxis == LogicalAxis::Inline ? mCols : mRows;
}
const LineRange& LineRangeForAxis(LogicalAxis aAxis) const {
- return aAxis == eLogicalAxisInline ? mCols : mRows;
+ return aAxis == LogicalAxis::Inline ? mCols : mRows;
}
LineRange mCols;
LineRange mRows;
@@ -665,12 +666,12 @@ struct nsGridContainerFrame::GridItemInfo {
*/
GridItemInfo Transpose() const {
GridItemInfo info(mFrame, GridArea(mArea.mRows, mArea.mCols));
- info.mState[eLogicalAxisBlock] = mState[eLogicalAxisInline];
- info.mState[eLogicalAxisInline] = mState[eLogicalAxisBlock];
- info.mBaselineOffset[eLogicalAxisBlock] =
- mBaselineOffset[eLogicalAxisInline];
- info.mBaselineOffset[eLogicalAxisInline] =
- mBaselineOffset[eLogicalAxisBlock];
+ info.mState[LogicalAxis::Block] = mState[LogicalAxis::Inline];
+ info.mState[LogicalAxis::Inline] = mState[LogicalAxis::Block];
+ info.mBaselineOffset[LogicalAxis::Block] =
+ mBaselineOffset[LogicalAxis::Inline];
+ info.mBaselineOffset[LogicalAxis::Inline] =
+ mBaselineOffset[LogicalAxis::Block];
return info;
}
@@ -684,7 +685,7 @@ struct nsGridContainerFrame::GridItemInfo {
// Is this item a subgrid in either axis?
bool IsSubgrid() const {
- return IsSubgrid(eLogicalAxisInline) || IsSubgrid(eLogicalAxisBlock);
+ return IsSubgrid(LogicalAxis::Inline) || IsSubgrid(LogicalAxis::Block);
}
// Return the (inner) grid container frame associated with this subgrid item.
@@ -725,7 +726,7 @@ struct nsGridContainerFrame::GridItemInfo {
bool ShouldApplyAutoMinSize(WritingMode aContainerWM,
LogicalAxis aContainerAxis,
nscoord aPercentageBasis) const {
- const bool isInlineAxis = aContainerAxis == eLogicalAxisInline;
+ const bool isInlineAxis = aContainerAxis == LogicalAxis::Inline;
const auto* pos =
mFrame->IsTableWrapperFrame()
? mFrame->PrincipalChildList().FirstChild()->StylePosition()
@@ -793,9 +794,9 @@ struct nsGridContainerFrame::GridItemInfo {
return isContinuationA;
}
auto masonryA = a->mArea.mRows.mStart;
- auto gridA = a->mState[eLogicalAxisInline] & StateBits::eAutoPlacement;
+ auto gridA = a->mState[LogicalAxis::Inline] & StateBits::eAutoPlacement;
auto masonryB = b->mArea.mRows.mStart;
- auto gridB = b->mState[eLogicalAxisInline] & StateBits::eAutoPlacement;
+ auto gridB = b->mState[LogicalAxis::Inline] & StateBits::eAutoPlacement;
return (masonryA == 0 ? masonryB != 0 : (masonryB != 0 && gridA < gridB)) &&
!a->mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
}
@@ -804,9 +805,9 @@ struct nsGridContainerFrame::GridItemInfo {
MOZ_ASSERT(!a->mFrame->GetPrevInFlow() && !b->mFrame->GetPrevInFlow(),
"fragmentation not supported in inline axis");
auto masonryA = a->mArea.mCols.mStart;
- auto gridA = a->mState[eLogicalAxisBlock] & StateBits::eAutoPlacement;
+ auto gridA = a->mState[LogicalAxis::Block] & StateBits::eAutoPlacement;
auto masonryB = b->mArea.mCols.mStart;
- auto gridB = b->mState[eLogicalAxisBlock] & StateBits::eAutoPlacement;
+ auto gridB = b->mState[LogicalAxis::Block] & StateBits::eAutoPlacement;
return (masonryA == 0 ? masonryB != 0 : (masonryB != 0 && gridA < gridB)) &&
!a->mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW);
}
@@ -847,20 +848,20 @@ MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ItemState)
GridItemInfo::GridItemInfo(nsIFrame* aFrame, const GridArea& aArea)
: mFrame(aFrame), mArea(aArea), mBaselineOffset{0, 0} {
- mState[eLogicalAxisBlock] =
+ mState[LogicalAxis::Block] =
StateBits(mArea.mRows.mStart == kAutoLine ? eAutoPlacement : 0);
- mState[eLogicalAxisInline] =
+ mState[LogicalAxis::Inline] =
StateBits(mArea.mCols.mStart == kAutoLine ? eAutoPlacement : 0);
if (auto* gridFrame = GetGridContainerFrame(mFrame)) {
auto parentWM = aFrame->GetParent()->GetWritingMode();
bool isOrthogonal = parentWM.IsOrthogonalTo(gridFrame->GetWritingMode());
if (gridFrame->IsColSubgrid()) {
- mState[isOrthogonal ? eLogicalAxisBlock : eLogicalAxisInline] |=
+ mState[isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline] |=
StateBits::eIsSubgrid;
}
if (gridFrame->IsRowSubgrid()) {
- mState[isOrthogonal ? eLogicalAxisInline : eLogicalAxisBlock] |=
+ mState[isOrthogonal ? LogicalAxis::Inline : LogicalAxis::Block] |=
StateBits::eIsSubgrid;
}
}
@@ -884,7 +885,7 @@ void GridItemInfo::InhibitSubgrid(nsGridContainerFrame* aParent,
MOZ_ASSERT(IsSubgrid(aAxis));
auto bit = NS_STATE_GRID_IS_COL_SUBGRID;
if (aParent->GetWritingMode().IsOrthogonalTo(mFrame->GetWritingMode()) !=
- (aAxis == eLogicalAxisBlock)) {
+ (aAxis == LogicalAxis::Block)) {
bit = NS_STATE_GRID_IS_ROW_SUBGRID;
}
MOZ_ASSERT(SubgridFrame()->HasAnyStateBits(bit));
@@ -894,16 +895,18 @@ void GridItemInfo::InhibitSubgrid(nsGridContainerFrame* aParent,
void GridItemInfo::MaybeInhibitSubgridInMasonry(nsGridContainerFrame* aParent,
uint32_t aGridAxisTrackCount) {
- if (IsSubgrid(eLogicalAxisInline) && aParent->IsMasonry(eLogicalAxisBlock) &&
- mArea.mRows.mStart != 0 && mArea.mCols.Extent() != aGridAxisTrackCount &&
- (mState[eLogicalAxisInline] & eAutoPlacement)) {
- InhibitSubgrid(aParent, eLogicalAxisInline);
+ if (IsSubgrid(LogicalAxis::Inline) &&
+ aParent->IsMasonry(LogicalAxis::Block) && mArea.mRows.mStart != 0 &&
+ mArea.mCols.Extent() != aGridAxisTrackCount &&
+ (mState[LogicalAxis::Inline] & eAutoPlacement)) {
+ InhibitSubgrid(aParent, LogicalAxis::Inline);
return;
}
- if (IsSubgrid(eLogicalAxisBlock) && aParent->IsMasonry(eLogicalAxisInline) &&
- mArea.mCols.mStart != 0 && mArea.mRows.Extent() != aGridAxisTrackCount &&
- (mState[eLogicalAxisBlock] & eAutoPlacement)) {
- InhibitSubgrid(aParent, eLogicalAxisBlock);
+ if (IsSubgrid(LogicalAxis::Block) &&
+ aParent->IsMasonry(LogicalAxis::Inline) && mArea.mCols.mStart != 0 &&
+ mArea.mRows.Extent() != aGridAxisTrackCount &&
+ (mState[LogicalAxis::Block] & eAutoPlacement)) {
+ InhibitSubgrid(aParent, LogicalAxis::Block);
}
}
@@ -1061,9 +1064,9 @@ void nsGridContainerFrame::GridItemInfo::Dump() const {
printf("\n");
};
printf("grid-row: %d %d\n", mArea.mRows.mStart, mArea.mRows.mEnd);
- Dump1(" grid block-axis: ", eLogicalAxisBlock);
+ Dump1(" grid block-axis: ", LogicalAxis::Block);
printf("grid-column: %d %d\n", mArea.mCols.mStart, mArea.mCols.mEnd);
- Dump1(" grid inline-axis: ", eLogicalAxisInline);
+ Dump1(" grid inline-axis: ", LogicalAxis::Inline);
}
#endif
@@ -1150,8 +1153,9 @@ struct nsGridContainerFrame::TrackSizingFunctions {
parent->GetWritingMode().ParallelAxisStartsOnSameSide(parentAxis,
grandParentWM);
if (MOZ_UNLIKELY(!isSameDirInAxis)) {
- auto end = parentAxis == eLogicalAxisBlock ? parentSubgrid->mGridRowEnd
- : parentSubgrid->mGridColEnd;
+ auto end = parentAxis == LogicalAxis::Block
+ ? parentSubgrid->mGridRowEnd
+ : parentSubgrid->mGridColEnd;
range.ReverseDirection(end);
// range is now in the same direction as the grand-parent's axis
}
@@ -1166,7 +1170,7 @@ struct nsGridContainerFrame::TrackSizingFunctions {
parent = grandParent;
}
const auto* pos = parent->StylePosition();
- const auto isInlineAxis = parentAxis == eLogicalAxisInline;
+ const auto isInlineAxis = parentAxis == LogicalAxis::Inline;
const auto& szf =
isInlineAxis ? pos->mGridTemplateRows : pos->mGridTemplateColumns;
const auto& autoSizing =
@@ -2707,7 +2711,7 @@ struct nsGridContainerFrame::Tracks {
* gap before aRow to zero (and shift all rows after it by the removed gap).
*/
void BreakBeforeRow(uint32_t aRow) {
- MOZ_ASSERT(mAxis == eLogicalAxisBlock,
+ MOZ_ASSERT(mAxis == LogicalAxis::Block,
"Should only be fragmenting in the block axis (between rows)");
nscoord prevRowEndPos = 0;
if (aRow != 0) {
@@ -2728,7 +2732,7 @@ struct nsGridContainerFrame::Tracks {
* Set the size of aRow to aSize and adjust the position of all rows after it.
*/
void ResizeRow(uint32_t aRow, nscoord aNewSize) {
- MOZ_ASSERT(mAxis == eLogicalAxisBlock,
+ MOZ_ASSERT(mAxis == LogicalAxis::Block,
"Should only be fragmenting in the block axis (between rows)");
MOZ_ASSERT(aNewSize >= 0);
auto& sz = mSizes[aRow];
@@ -2775,7 +2779,7 @@ struct nsGridContainerFrame::Tracks {
#ifdef DEBUG
void nsGridContainerFrame::Tracks::Dump() const {
printf("%zu %s %s ", mSizes.Length(), mIsMasonry ? "masonry" : "grid",
- mAxis == eLogicalAxisBlock ? "rows" : "columns");
+ mAxis == LogicalAxis::Block ? "rows" : "columns");
TrackSize::DumpStateBits(mStateUnion);
printf("\n");
for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
@@ -2805,8 +2809,8 @@ void nsGridContainerFrame::Tracks::Dump() const {
*/
struct nsGridContainerFrame::SharedGridData {
SharedGridData()
- : mCols(eLogicalAxisInline),
- mRows(eLogicalAxisBlock),
+ : mCols(LogicalAxis::Inline),
+ mRows(LogicalAxis::Block),
mGenerateComputedGridInfo(false) {}
Tracks mCols;
Tracks mRows;
@@ -2884,7 +2888,7 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
}
}
if (mStartRow == numRows ||
- aGridContainerFrame->IsMasonry(eLogicalAxisBlock)) {
+ aGridContainerFrame->IsMasonry(LogicalAxis::Block)) {
// All of the grid's rows fit inside of previous grid-container fragments,
// or it's a masonry axis.
mFragBStart = aConsumedBSize;
@@ -2904,8 +2908,8 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
aGridContainerFrame->SetProperty(UsedTrackSizes::Prop(), prop);
}
prop->mCanResolveLineRangeSize = {true, true};
- prop->mSizes[eLogicalAxisInline].Assign(mCols.mSizes);
- prop->mSizes[eLogicalAxisBlock].Assign(mRows.mSizes);
+ prop->mSizes[LogicalAxis::Inline].Assign(mCols.mSizes);
+ prop->mSizes[LogicalAxis::Block].Assign(mRows.mSizes);
}
// Copy item data from each child's first-in-flow data in mSharedGridData.
@@ -2921,18 +2925,19 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
mGridItems.AppendElement(GridItemInfo(child, itemInfo.mArea));
// Copy the item's baseline data so that the item's last fragment can
// do 'last baseline' alignment if necessary.
- item->mState[eLogicalAxisBlock] |=
- itemInfo.mState[eLogicalAxisBlock] & ItemState::eAllBaselineBits;
- item->mState[eLogicalAxisInline] |=
- itemInfo.mState[eLogicalAxisInline] & ItemState::eAllBaselineBits;
- item->mBaselineOffset[eLogicalAxisBlock] =
- itemInfo.mBaselineOffset[eLogicalAxisBlock];
- item->mBaselineOffset[eLogicalAxisInline] =
- itemInfo.mBaselineOffset[eLogicalAxisInline];
- item->mState[eLogicalAxisBlock] |=
- itemInfo.mState[eLogicalAxisBlock] & ItemState::eAutoPlacement;
- item->mState[eLogicalAxisInline] |=
- itemInfo.mState[eLogicalAxisInline] & ItemState::eAutoPlacement;
+ item->mState[LogicalAxis::Block] |=
+ itemInfo.mState[LogicalAxis::Block] & ItemState::eAllBaselineBits;
+ item->mState[LogicalAxis::Inline] |=
+ itemInfo.mState[LogicalAxis::Inline] &
+ ItemState::eAllBaselineBits;
+ item->mBaselineOffset[LogicalAxis::Block] =
+ itemInfo.mBaselineOffset[LogicalAxis::Block];
+ item->mBaselineOffset[LogicalAxis::Inline] =
+ itemInfo.mBaselineOffset[LogicalAxis::Inline];
+ item->mState[LogicalAxis::Block] |=
+ itemInfo.mState[LogicalAxis::Block] & ItemState::eAutoPlacement;
+ item->mState[LogicalAxis::Inline] |=
+ itemInfo.mState[LogicalAxis::Inline] & ItemState::eAutoPlacement;
break;
}
}
@@ -2975,7 +2980,7 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
/**
* Return the percentage basis for a grid item in its writing-mode.
- * If aAxis is eLogicalAxisInline then we return NS_UNCONSTRAINEDSIZE in
+ * If aAxis is LogicalAxis::Inline then we return NS_UNCONSTRAINEDSIZE in
* both axes since we know all track sizes are indefinite at this point
* (we calculate column sizes before row sizes). Otherwise, assert that
* column sizes are known and calculate the size for aGridItem.mArea.mCols
@@ -3218,10 +3223,10 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
}
Tracks& TracksFor(LogicalAxis aAxis) {
- return aAxis == eLogicalAxisBlock ? mRows : mCols;
+ return aAxis == LogicalAxis::Block ? mRows : mCols;
}
const Tracks& TracksFor(LogicalAxis aAxis) const {
- return aAxis == eLogicalAxisBlock ? mRows : mCols;
+ return aAxis == LogicalAxis::Block ? mRows : mCols;
}
CSSOrderAwareFrameIterator mIter;
@@ -3275,13 +3280,13 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
const nsStylePosition* aGridStyle, const WritingMode& aWM)
: mIter(aFrame, FrameChildListID::Principal),
mGridStyle(aGridStyle),
- mCols(eLogicalAxisInline),
- mRows(eLogicalAxisBlock),
+ mCols(LogicalAxis::Inline),
+ mRows(LogicalAxis::Block),
mColFunctions(mGridStyle->mGridTemplateColumns,
mGridStyle->mGridAutoColumns,
- aFrame->IsSubgrid(eLogicalAxisInline)),
+ aFrame->IsSubgrid(LogicalAxis::Inline)),
mRowFunctions(mGridStyle->mGridTemplateRows, mGridStyle->mGridAutoRows,
- aFrame->IsSubgrid(eLogicalAxisBlock)),
+ aFrame->IsSubgrid(LogicalAxis::Block)),
mReflowInput(aReflowInput),
mRenderingContext(aRenderingContext),
mFrame(aFrame),
@@ -3299,8 +3304,8 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput {
mSkipSides = aFrame->PreReflowBlockLevelLogicalSkipSides();
mBorderPadding.ApplySkipSides(mSkipSides);
}
- mCols.mIsMasonry = aFrame->IsMasonry(eLogicalAxisInline);
- mRows.mIsMasonry = aFrame->IsMasonry(eLogicalAxisBlock);
+ mCols.mIsMasonry = aFrame->IsMasonry(LogicalAxis::Inline);
+ mRows.mIsMasonry = aFrame->IsMasonry(LogicalAxis::Block);
MOZ_ASSERT(!(mCols.mIsMasonry && mRows.mIsMasonry),
"can't have masonry layout in both axes");
}
@@ -3463,7 +3468,7 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::Grid {
* @param aFromIndex the zero-based index to start counting from
* @param aLineNameList the explicit named lines
* @param aSide the axis+edge we're resolving names for (e.g. if we're
- resolving a grid-row-start line, pass eLogicalSideBStart)
+ resolving a grid-row-start line, pass LogicalSide::BStart)
* @param aExplicitGridEnd the last line in the explicit grid
* @param aStyle the StylePosition() for the grid container
* @return a definite line (1-based), clamped to
@@ -3546,7 +3551,7 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::Grid {
if (!mParentGrid) {
return nullptr;
}
- bool isRows = aIsOrthogonal == (aAxis == eLogicalAxisInline);
+ bool isRows = aIsOrthogonal == (aAxis == LogicalAxis::Inline);
return isRows ? mParentGrid->mRowNameMap : mParentGrid->mColNameMap;
}
@@ -3684,38 +3689,56 @@ static Subgrid* SubgridComputeMarginBorderPadding(
SizeComputationInput sz(subgridFrame, nullptr, cbWM, pmPercentageBasis);
subgrid->mMarginBorderPadding =
sz.ComputedLogicalMargin(cbWM) + sz.ComputedLogicalBorderPadding(cbWM);
+ if (aGridItem.mFrame == subgridFrame) {
+ return subgrid;
+ }
- if (aGridItem.mFrame != subgridFrame) {
- nsHTMLScrollFrame* scrollFrame =
- do_QueryFrame(aGridItem.mFrame->GetScrollTargetFrame());
- if (scrollFrame) {
- MOZ_ASSERT(
- sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) &&
- sz.ComputedLogicalBorder(cbWM) == LogicalMargin(cbWM),
- "A scrolled inner frame should not have any margin or border!");
-
- // Add the margin and border from the (outer) scroll frame.
- SizeComputationInput szScrollFrame(aGridItem.mFrame, nullptr, cbWM,
- pmPercentageBasis);
- subgrid->mMarginBorderPadding +=
- szScrollFrame.ComputedLogicalMargin(cbWM) +
- szScrollFrame.ComputedLogicalBorder(cbWM);
-
- nsMargin ssz = scrollFrame->IntrinsicScrollbarGutterSize();
+ bool scroller = false;
+ nsIFrame* outerFrame = [&]() -> nsIFrame* {
+ if (nsHTMLScrollFrame* scrollFrame =
+ do_QueryFrame(aGridItem.mFrame->GetScrollTargetFrame())) {
+ scroller = true;
+ return scrollFrame;
+ }
+ if (nsHTMLButtonControlFrame* f = do_QueryFrame(aGridItem.mFrame)) {
+ return f;
+ }
+ return nullptr;
+ }();
+
+ if (outerFrame) {
+ MOZ_ASSERT(sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) &&
+ sz.ComputedLogicalBorder(cbWM) == LogicalMargin(cbWM),
+ "A scrolled inner frame / button content frame "
+ "should not have any margin or border / padding!");
+
+ // Add the margin and border from the (outer) frame. Padding is factored-in
+ // for scrollers already (except for the scrollbar gutter), but not for
+ // button-content.
+ SizeComputationInput szOuterFrame(outerFrame, nullptr, cbWM,
+ pmPercentageBasis);
+ subgrid->mMarginBorderPadding += szOuterFrame.ComputedLogicalMargin(cbWM) +
+ szOuterFrame.ComputedLogicalBorder(cbWM);
+ if (scroller) {
+ nsMargin ssz = static_cast<nsHTMLScrollFrame*>(outerFrame)
+ ->IntrinsicScrollbarGutterSize();
subgrid->mMarginBorderPadding += LogicalMargin(cbWM, ssz);
+ } else {
+ subgrid->mMarginBorderPadding +=
+ szOuterFrame.ComputedLogicalPadding(cbWM);
}
+ }
- if (aGridItem.mFrame->IsFieldSetFrame()) {
- const auto* f = static_cast<nsFieldSetFrame*>(aGridItem.mFrame);
- const auto* inner = f->GetInner();
- auto wm = inner->GetWritingMode();
- LogicalPoint pos = inner->GetLogicalPosition(aGridItem.mFrame->GetSize());
- // The legend is always on the BStart side and it inflates the fieldset's
- // "border area" size. The inner frame's b-start pos equals that size.
- LogicalMargin offsets(wm, pos.B(wm), 0, 0, 0);
- subgrid->mMarginBorderPadding += offsets.ConvertTo(cbWM, wm);
- }
+ if (nsFieldSetFrame* f = do_QueryFrame(aGridItem.mFrame)) {
+ const auto* inner = f->GetInner();
+ auto wm = inner->GetWritingMode();
+ LogicalPoint pos = inner->GetLogicalPosition(aGridItem.mFrame->GetSize());
+ // The legend is always on the BStart side and it inflates the fieldset's
+ // "border area" size. The inner frame's b-start pos equals that size.
+ LogicalMargin offsets(wm, pos.B(wm), 0, 0, 0);
+ subgrid->mMarginBorderPadding += offsets.ConvertTo(cbWM, wm);
}
+
return subgrid;
}
@@ -3727,8 +3750,9 @@ static void CopyUsedTrackSizes(nsTArray<TrackSize>& aResult,
LogicalAxis aSubgridAxis) {
MOZ_ASSERT(aSubgridFrame->ParentGridContainerForSubgrid() ==
aUsedTrackSizesFrame);
- aResult.SetLength(aSubgridAxis == eLogicalAxisInline ? aSubgrid->mGridColEnd
- : aSubgrid->mGridRowEnd);
+ aResult.SetLength(aSubgridAxis == LogicalAxis::Inline
+ ? aSubgrid->mGridColEnd
+ : aSubgrid->mGridRowEnd);
auto parentAxis =
aSubgrid->mIsOrthogonal ? GetOrthogonalAxis(aSubgridAxis) : aSubgridAxis;
const auto& parentSizes = aUsedTrackSizes->mSizes[parentAxis];
@@ -3740,7 +3764,7 @@ static void CopyUsedTrackSizes(nsTArray<TrackSize>& aResult,
const auto cbwm = aUsedTrackSizesFrame->GetWritingMode();
const auto wm = aSubgridFrame->GetWritingMode();
// Recompute the MBP to resolve percentages against the resolved track sizes.
- if (parentAxis == eLogicalAxisInline) {
+ if (parentAxis == LogicalAxis::Inline) {
// Find the subgrid's grid item frame in its parent grid container. This
// is usually the same as aSubgridFrame but it may also have a ScrollFrame,
// FieldSetFrame etc. We just loop until we see the first ancestor
@@ -3856,7 +3880,7 @@ void nsGridContainerFrame::UsedTrackSizes::ResolveSubgridTrackSizesForAxis(
grid.mGridRowEnd = aSubgrid->mGridRowEnd;
state.CalculateTrackSizesForAxis(aAxis, grid, aContentBoxSize,
SizingConstraint::NoConstraint);
- const auto& tracks = aAxis == eLogicalAxisInline ? state.mCols : state.mRows;
+ const auto& tracks = aAxis == LogicalAxis::Inline ? state.mCols : state.mRows;
mSizes[aAxis].Assign(tracks.mSizes);
mCanResolveLineRangeSize[aAxis] = tracks.mCanResolveLineRangeSize;
MOZ_ASSERT(mCanResolveLineRangeSize[aAxis]);
@@ -3865,11 +3889,11 @@ void nsGridContainerFrame::UsedTrackSizes::ResolveSubgridTrackSizesForAxis(
void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
LogicalAxis aAxis, const Grid& aGrid, nscoord aContentBoxSize,
SizingConstraint aConstraint) {
- auto& tracks = aAxis == eLogicalAxisInline ? mCols : mRows;
+ auto& tracks = aAxis == LogicalAxis::Inline ? mCols : mRows;
const auto& sizingFunctions =
- aAxis == eLogicalAxisInline ? mColFunctions : mRowFunctions;
- const auto& gapStyle = aAxis == eLogicalAxisInline ? mGridStyle->mColumnGap
- : mGridStyle->mRowGap;
+ aAxis == LogicalAxis::Inline ? mColFunctions : mRowFunctions;
+ const auto& gapStyle = aAxis == LogicalAxis::Inline ? mGridStyle->mColumnGap
+ : mGridStyle->mRowGap;
if (tracks.mIsMasonry) {
// See comment on nsGridContainerFrame::MasonryLayout().
tracks.Initialize(sizingFunctions, gapStyle, 2, aContentBoxSize);
@@ -3877,7 +3901,7 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
return;
}
uint32_t gridEnd =
- aAxis == eLogicalAxisInline ? aGrid.mGridColEnd : aGrid.mGridRowEnd;
+ aAxis == LogicalAxis::Inline ? aGrid.mGridColEnd : aGrid.mGridRowEnd;
Maybe<TrackSizingFunctions> fallbackTrackSizing;
bool useParentGaps = false;
@@ -3919,7 +3943,7 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
*this, mGridItems,
fallbackTrackSizing ? *fallbackTrackSizing : sizingFunctions,
aContentBoxSize,
- aAxis == eLogicalAxisInline ? &GridArea::mCols : &GridArea::mRows,
+ aAxis == LogicalAxis::Inline ? &GridArea::mCols : &GridArea::mRows,
aConstraint);
if (hasSubgridItems &&
@@ -3976,9 +4000,9 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis(
void nsGridContainerFrame::GridReflowInput::CalculateTrackSizes(
const Grid& aGrid, const LogicalSize& aContentBox,
SizingConstraint aConstraint) {
- CalculateTrackSizesForAxis(eLogicalAxisInline, aGrid, aContentBox.ISize(mWM),
+ CalculateTrackSizesForAxis(LogicalAxis::Inline, aGrid, aContentBox.ISize(mWM),
aConstraint);
- CalculateTrackSizesForAxis(eLogicalAxisBlock, aGrid, aContentBox.BSize(mWM),
+ CalculateTrackSizesForAxis(LogicalAxis::Block, aGrid, aContentBox.BSize(mWM),
aConstraint);
}
@@ -3999,7 +4023,7 @@ static void AlignJustifySelf(StyleAlignFlags aAlignment, LogicalAxis aAxis,
// Set the position (aPos) for the requested alignment.
if (offset != 0) {
WritingMode wm = aRI.GetWritingMode();
- nscoord& pos = aAxis == eLogicalAxisBlock ? aPos->B(wm) : aPos->I(wm);
+ nscoord& pos = aAxis == LogicalAxis::Block ? aPos->B(wm) : aPos->I(wm);
pos += MOZ_LIKELY(aFlags & AlignJustifyFlags::SameSide) ? offset : -offset;
}
}
@@ -4016,7 +4040,7 @@ static void AlignSelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
aAlignSelf &= ~StyleAlignFlags::FLAG_BITS;
WritingMode childWM = aRI.GetWritingMode();
- if (aCBWM.ParallelAxisStartsOnSameSide(eLogicalAxisBlock, childWM)) {
+ if (aCBWM.ParallelAxisStartsOnSameSide(LogicalAxis::Block, childWM)) {
flags |= AlignJustifyFlags::SameSide;
}
@@ -4032,12 +4056,12 @@ static void AlignSelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
nscoord baselineAdjust = 0;
if (aAlignSelf == StyleAlignFlags::BASELINE ||
aAlignSelf == StyleAlignFlags::LAST_BASELINE) {
- aAlignSelf = aGridItem.GetSelfBaseline(aAlignSelf, eLogicalAxisBlock,
+ aAlignSelf = aGridItem.GetSelfBaseline(aAlignSelf, LogicalAxis::Block,
&baselineAdjust);
}
bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
- LogicalAxis axis = isOrthogonal ? eLogicalAxisInline : eLogicalAxisBlock;
+ LogicalAxis axis = isOrthogonal ? LogicalAxis::Inline : LogicalAxis::Block;
AlignJustifySelf(aAlignSelf, axis, flags, baselineAdjust, aCBSize, aRI, aSize,
aPos);
}
@@ -4054,7 +4078,7 @@ static void JustifySelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
aJustifySelf &= ~StyleAlignFlags::FLAG_BITS;
WritingMode childWM = aRI.GetWritingMode();
- if (aCBWM.ParallelAxisStartsOnSameSide(eLogicalAxisInline, childWM)) {
+ if (aCBWM.ParallelAxisStartsOnSameSide(LogicalAxis::Inline, childWM)) {
flags |= AlignJustifyFlags::SameSide;
}
@@ -4073,12 +4097,12 @@ static void JustifySelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
aCBWM.IsBidiLTR() ? StyleAlignFlags::END : StyleAlignFlags::START;
} else if (aJustifySelf == StyleAlignFlags::BASELINE ||
aJustifySelf == StyleAlignFlags::LAST_BASELINE) {
- aJustifySelf = aGridItem.GetSelfBaseline(aJustifySelf, eLogicalAxisInline,
+ aJustifySelf = aGridItem.GetSelfBaseline(aJustifySelf, LogicalAxis::Inline,
&baselineAdjust);
}
bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
- LogicalAxis axis = isOrthogonal ? eLogicalAxisBlock : eLogicalAxisInline;
+ LogicalAxis axis = isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline;
AlignJustifySelf(aJustifySelf, axis, flags, baselineAdjust, aCBSize, aRI,
aSize, aPos);
}
@@ -4245,8 +4269,8 @@ void nsGridContainerFrame::InitImplicitNamedAreas(
AddImplicitNamedAreas(aTemplate.AsSubgrid()->line_names.AsSpan());
}
};
- Add(aStyle->mGridTemplateColumns, IsSubgrid(eLogicalAxisInline));
- Add(aStyle->mGridTemplateRows, IsSubgrid(eLogicalAxisBlock));
+ Add(aStyle->mGridTemplateColumns, IsSubgrid(LogicalAxis::Inline));
+ Add(aStyle->mGridTemplateRows, IsSubgrid(LogicalAxis::Block));
if (areas && areas->count() == 0) {
RemoveProperty(ImplicitNamedAreasProperty());
}
@@ -4293,7 +4317,7 @@ int32_t nsGridContainerFrame::Grid::ResolveLine(
bool useStart = IsNameWithStartSuffix(aLine.LineName(), &index);
if (useStart || IsNameWithEndSuffix(aLine.LineName(), &index)) {
auto side = MakeLogicalSide(
- GetAxis(aSide), useStart ? eLogicalEdgeStart : eLogicalEdgeEnd);
+ GetAxis(aSide), useStart ? LogicalEdge::Start : LogicalEdge::End);
RefPtr<nsAtom> name = NS_Atomize(nsDependentSubstring(
nsDependentAtomString(aLine.LineName()), 0, index));
aNameMap.FindNamedAreas(name, side, implicitLines);
@@ -4353,7 +4377,7 @@ nsGridContainerFrame::Grid::ResolveLineRangeHelper(
uint32_t from = aEnd.line_num < 0 ? aExplicitGridEnd + 1 : 0;
auto end = ResolveLine(aEnd, aEnd.line_num, from, aNameMap,
- MakeLogicalSide(aAxis, eLogicalEdgeEnd),
+ MakeLogicalSide(aAxis, LogicalEdge::End),
aExplicitGridEnd, aStyle);
int32_t span = aStart.line_num == 0 ? 1 : aStart.line_num;
if (end <= 1) {
@@ -4363,7 +4387,7 @@ nsGridContainerFrame::Grid::ResolveLineRangeHelper(
return LinePair(start, end);
}
auto start = ResolveLine(aStart, -span, end, aNameMap,
- MakeLogicalSide(aAxis, eLogicalEdgeStart),
+ MakeLogicalSide(aAxis, LogicalEdge::Start),
aExplicitGridEnd, aStyle);
return LinePair(start, end);
}
@@ -4387,7 +4411,7 @@ nsGridContainerFrame::Grid::ResolveLineRangeHelper(
} else {
uint32_t from = aStart.line_num < 0 ? aExplicitGridEnd + 1 : 0;
start = ResolveLine(aStart, aStart.line_num, from, aNameMap,
- MakeLogicalSide(aAxis, eLogicalEdgeStart),
+ MakeLogicalSide(aAxis, LogicalEdge::Start),
aExplicitGridEnd, aStyle);
if (aEnd.IsAuto()) {
// A "definite line / auto" should resolve the auto to 'span 1'.
@@ -4417,7 +4441,7 @@ nsGridContainerFrame::Grid::ResolveLineRangeHelper(
from = aEnd.line_num < 0 ? aExplicitGridEnd + 1 : 0;
}
auto end = ResolveLine(aEnd, nth, from, aNameMap,
- MakeLogicalSide(aAxis, eLogicalEdgeEnd),
+ MakeLogicalSide(aAxis, LogicalEdge::End),
aExplicitGridEnd, aStyle);
if (start == int32_t(kAutoLine)) {
// auto / definite line
@@ -4485,10 +4509,10 @@ nsGridContainerFrame::GridArea nsGridContainerFrame::Grid::PlaceDefinite(
const nsStylePosition* itemStyle = aChild->StylePosition();
return GridArea(
ResolveLineRange(itemStyle->mGridColumnStart, itemStyle->mGridColumnEnd,
- aColLineNameMap, eLogicalAxisInline, mExplicitGridColEnd,
- aStyle),
+ aColLineNameMap, LogicalAxis::Inline,
+ mExplicitGridColEnd, aStyle),
ResolveLineRange(itemStyle->mGridRowStart, itemStyle->mGridRowEnd,
- aRowLineNameMap, eLogicalAxisBlock, mExplicitGridRowEnd,
+ aRowLineNameMap, LogicalAxis::Block, mExplicitGridRowEnd,
aStyle));
}
@@ -4503,7 +4527,7 @@ nsGridContainerFrame::Grid::ResolveAbsPosLineRange(
}
uint32_t from = aEnd.line_num < 0 ? aExplicitGridEnd + 1 : 0;
int32_t end = ResolveLine(aEnd, aEnd.line_num, from, aNameMap,
- MakeLogicalSide(aAxis, eLogicalEdgeEnd),
+ MakeLogicalSide(aAxis, LogicalEdge::End),
aExplicitGridEnd, aStyle);
if (aEnd.is_span) {
++end;
@@ -4516,7 +4540,7 @@ nsGridContainerFrame::Grid::ResolveAbsPosLineRange(
if (aEnd.IsAuto()) {
uint32_t from = aStart.line_num < 0 ? aExplicitGridEnd + 1 : 0;
int32_t start = ResolveLine(aStart, aStart.line_num, from, aNameMap,
- MakeLogicalSide(aAxis, eLogicalEdgeStart),
+ MakeLogicalSide(aAxis, LogicalEdge::Start),
aExplicitGridEnd, aStyle);
if (aStart.is_span) {
start = std::max(aGridEnd - start, aGridStart);
@@ -4548,11 +4572,11 @@ nsGridContainerFrame::GridArea nsGridContainerFrame::Grid::PlaceAbsPos(
int32_t gridRowStart = 1 - mExplicitGridOffsetRow;
return GridArea(ResolveAbsPosLineRange(
itemStyle->mGridColumnStart, itemStyle->mGridColumnEnd,
- aColLineNameMap, eLogicalAxisInline, mExplicitGridColEnd,
+ aColLineNameMap, LogicalAxis::Inline, mExplicitGridColEnd,
gridColStart, mGridColEnd, aStyle),
ResolveAbsPosLineRange(
itemStyle->mGridRowStart, itemStyle->mGridRowEnd,
- aRowLineNameMap, eLogicalAxisBlock, mExplicitGridRowEnd,
+ aRowLineNameMap, LogicalAxis::Block, mExplicitGridRowEnd,
gridRowStart, mGridRowEnd, aStyle));
}
@@ -4736,10 +4760,10 @@ void nsGridContainerFrame::Grid::SubgridPlaceGridItems(
MOZ_ASSERT(aGridItem.mArea.IsDefinite() ||
aGridItem.mFrame->HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),
"the subgrid's lines should be resolved by now");
- if (aGridItem.IsSubgrid(eLogicalAxisInline)) {
+ if (aGridItem.IsSubgrid(LogicalAxis::Inline)) {
aParentState.mFrame->AddStateBits(NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
}
- if (aGridItem.IsSubgrid(eLogicalAxisBlock)) {
+ if (aGridItem.IsSubgrid(LogicalAxis::Block)) {
aParentState.mFrame->AddStateBits(NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM);
}
auto* childGrid = aGridItem.SubgridFrame();
@@ -4787,11 +4811,11 @@ void nsGridContainerFrame::Grid::SubgridPlaceGridItems(
// computing them otherwise.
RepeatTrackSizingInput repeatSizing(state.mWM);
if (!childGrid->IsColSubgrid() && state.mColFunctions.mHasRepeatAuto) {
- repeatSizing.InitFromStyle(eLogicalAxisInline, state.mWM,
+ repeatSizing.InitFromStyle(LogicalAxis::Inline, state.mWM,
state.mFrame->Style());
}
if (!childGrid->IsRowSubgrid() && state.mRowFunctions.mHasRepeatAuto) {
- repeatSizing.InitFromStyle(eLogicalAxisBlock, state.mWM,
+ repeatSizing.InitFromStyle(LogicalAxis::Block, state.mWM,
state.mFrame->Style());
}
@@ -4812,8 +4836,8 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
if (aState.mFrame->HasSubgridItems() || aState.mFrame->IsSubgrid()) {
if (auto* uts = aState.mFrame->GetUsedTrackSizes()) {
uts->mCanResolveLineRangeSize = {false, false};
- uts->mSizes[eLogicalAxisInline].ClearAndRetainStorage();
- uts->mSizes[eLogicalAxisBlock].ClearAndRetainStorage();
+ uts->mSizes[LogicalAxis::Inline].ClearAndRetainStorage();
+ uts->mSizes[LogicalAxis::Block].ClearAndRetainStorage();
}
}
@@ -4847,11 +4871,11 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
uint32_t extent = subgridRange->Extent();
mExplicitGridColEnd = extent + 1; // the grid is 1-based at this point
parentLineNameMap =
- ParentLineMapForAxis(subgrid->mIsOrthogonal, eLogicalAxisInline);
+ ParentLineMapForAxis(subgrid->mIsOrthogonal, LogicalAxis::Inline);
auto parentWM =
aState.mFrame->ParentGridContainerForSubgrid()->GetWritingMode();
subgridAxisIsSameDirection =
- aState.mWM.ParallelAxisStartsOnSameSide(eLogicalAxisInline, parentWM);
+ aState.mWM.ParallelAxisStartsOnSameSide(LogicalAxis::Inline, parentWM);
}
mGridColEnd = mExplicitGridColEnd;
LineNameMap colLineNameMap(gridStyle, mAreas, aState.mColFunctions,
@@ -4882,11 +4906,11 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
uint32_t extent = subgridRange->Extent();
mExplicitGridRowEnd = extent + 1; // the grid is 1-based at this point
parentLineNameMap =
- ParentLineMapForAxis(subgrid->mIsOrthogonal, eLogicalAxisBlock);
+ ParentLineMapForAxis(subgrid->mIsOrthogonal, LogicalAxis::Block);
auto parentWM =
aState.mFrame->ParentGridContainerForSubgrid()->GetWritingMode();
subgridAxisIsSameDirection =
- aState.mWM.ParallelAxisStartsOnSameSide(eLogicalAxisBlock, parentWM);
+ aState.mWM.ParallelAxisStartsOnSameSide(LogicalAxis::Block, parentWM);
}
mGridRowEnd = mExplicitGridRowEnd;
LineNameMap rowLineNameMap(gridStyle, mAreas, aState.mRowFunctions,
@@ -4900,16 +4924,16 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
if (isSubgridOrItemInSubgrid) {
const auto& area = aItem.mArea;
if (area.mCols.mStart == 0) {
- aItem.mState[eLogicalAxisInline] |= ItemState::eStartEdge;
+ aItem.mState[LogicalAxis::Inline] |= ItemState::eStartEdge;
}
if (area.mCols.mEnd == mGridColEnd) {
- aItem.mState[eLogicalAxisInline] |= ItemState::eEndEdge;
+ aItem.mState[LogicalAxis::Inline] |= ItemState::eEndEdge;
}
if (area.mRows.mStart == 0) {
- aItem.mState[eLogicalAxisBlock] |= ItemState::eStartEdge;
+ aItem.mState[LogicalAxis::Block] |= ItemState::eStartEdge;
}
if (area.mRows.mEnd == mGridRowEnd) {
- aItem.mState[eLogicalAxisBlock] |= ItemState::eEndEdge;
+ aItem.mState[LogicalAxis::Block] |= ItemState::eEndEdge;
}
}
};
@@ -4945,8 +4969,8 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
aState.mRowFunctions.mExplicitGridOffset = mExplicitGridOffsetRow;
const int32_t offsetToColZero = int32_t(mExplicitGridOffsetCol) - 1;
const int32_t offsetToRowZero = int32_t(mExplicitGridOffsetRow) - 1;
- const bool isRowMasonry = aState.mFrame->IsMasonry(eLogicalAxisBlock);
- const bool isColMasonry = aState.mFrame->IsMasonry(eLogicalAxisInline);
+ const bool isRowMasonry = aState.mFrame->IsMasonry(LogicalAxis::Block);
+ const bool isColMasonry = aState.mFrame->IsMasonry(LogicalAxis::Inline);
const bool isMasonry = isColMasonry || isRowMasonry;
mGridColEnd += offsetToColZero;
mGridRowEnd += offsetToRowZero;
@@ -5100,7 +5124,7 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
// Force all items into the 1st/2nd track and have span 1 in the masonry axis.
// (See comment on nsGridContainerFrame::MasonryLayout().)
if (isMasonry) {
- auto masonryAxis = isRowMasonry ? eLogicalAxisBlock : eLogicalAxisInline;
+ auto masonryAxis = isRowMasonry ? LogicalAxis::Block : LogicalAxis::Inline;
aState.mIter.Reset();
for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
auto& item = aState.mGridItems[aState.mIter.ItemIndex()];
@@ -5168,16 +5192,16 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
// An abs.pos. subgrid with placement auto/1 or -1/auto technically
// doesn't span any parent tracks. Inhibit subgridding in this case.
- if (info->IsSubgrid(eLogicalAxisInline)) {
+ if (info->IsSubgrid(LogicalAxis::Inline)) {
if (info->mArea.mCols.mStart == zeroOffsetGridColEnd.SavedValue() ||
info->mArea.mCols.mEnd == 0) {
- info->InhibitSubgrid(aState.mFrame, eLogicalAxisInline);
+ info->InhibitSubgrid(aState.mFrame, LogicalAxis::Inline);
}
}
- if (info->IsSubgrid(eLogicalAxisBlock)) {
+ if (info->IsSubgrid(LogicalAxis::Block)) {
if (info->mArea.mRows.mStart == zeroOffsetGridRowEnd.SavedValue() ||
info->mArea.mRows.mEnd == 0) {
- info->InhibitSubgrid(aState.mFrame, eLogicalAxisBlock);
+ info->InhibitSubgrid(aState.mFrame, LogicalAxis::Block);
}
}
@@ -5219,18 +5243,18 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
// Adjust the line numbers in the grid areas.
for (auto& item : aState.mGridItems) {
if (numEmptyCols) {
- item.AdjustForRemovedTracks(eLogicalAxisInline, *colAdjust);
+ item.AdjustForRemovedTracks(LogicalAxis::Inline, *colAdjust);
}
if (numEmptyRows) {
- item.AdjustForRemovedTracks(eLogicalAxisBlock, *rowAdjust);
+ item.AdjustForRemovedTracks(LogicalAxis::Block, *rowAdjust);
}
}
for (auto& item : aState.mAbsPosItems) {
if (numEmptyCols) {
- item.AdjustForRemovedTracks(eLogicalAxisInline, *colAdjust);
+ item.AdjustForRemovedTracks(LogicalAxis::Inline, *colAdjust);
}
if (numEmptyRows) {
- item.AdjustForRemovedTracks(eLogicalAxisBlock, *rowAdjust);
+ item.AdjustForRemovedTracks(LogicalAxis::Block, *rowAdjust);
}
}
// Adjust the grid size.
@@ -5258,11 +5282,11 @@ void nsGridContainerFrame::Grid::PlaceGridItems(
LineRange columnLines =
ResolveLineRange(lineStartAndEnd, lineStartAndEnd, colLineNameMap,
- eLogicalAxisInline, mExplicitGridColEnd, gridStyle);
+ LogicalAxis::Inline, mExplicitGridColEnd, gridStyle);
LineRange rowLines =
ResolveLineRange(lineStartAndEnd, lineStartAndEnd, rowLineNameMap,
- eLogicalAxisBlock, mExplicitGridRowEnd, gridStyle);
+ LogicalAxis::Block, mExplicitGridRowEnd, gridStyle);
// Put the resolved line indices back into the area structure.
areaInfo.columns.start = columnLines.mStart + mExplicitGridOffsetCol;
@@ -5322,7 +5346,7 @@ static nscoord MeasuringReflow(nsIFrame* aChild,
ComputeSizeFlags csFlags = ComputeSizeFlag::IsGridMeasuringReflow;
// Shrink-wrap grid items that will be aligned (rather than stretched) in
// their own inline axis.
- if (!parent->GridItemShouldStretch(aChild, eLogicalAxisInline)) {
+ if (!parent->GridItemShouldStretch(aChild, LogicalAxis::Inline)) {
csFlags += ComputeSizeFlag::ShrinkWrap;
}
if (aAvailableSize.ISize(wm) == INFINITE_ISIZE_COORD) {
@@ -5434,7 +5458,7 @@ static void PostReflowStretchChild(
}
ReflowInput ri(pc, aReflowInput, aChild, aAvailableSize, Some(aCBSize), {},
{}, csFlags);
- if (aChildAxis == eLogicalAxisBlock) {
+ if (aChildAxis == LogicalAxis::Block) {
ri.SetComputedBSize(ri.ApplyMinMaxBSize(aNewContentBoxSize));
} else {
ri.SetComputedISize(ri.ApplyMinMaxISize(aNewContentBoxSize));
@@ -5542,18 +5566,18 @@ static nscoord ContentContribution(
auto subgridAxis = aCBWM.IsOrthogonalTo(subgridFrame->GetWritingMode())
? GetOrthogonalAxis(aAxis)
: aAxis;
- auto& gapStyle = subgridAxis == eLogicalAxisBlock
+ auto& gapStyle = subgridAxis == LogicalAxis::Block
? subgridFrame->StylePosition()->mRowGap
: subgridFrame->StylePosition()->mColumnGap;
if (!gapStyle.IsNormal()) {
- auto subgridExtent = subgridAxis == eLogicalAxisBlock
+ auto subgridExtent = subgridAxis == LogicalAxis::Block
? subgrid->mGridRowEnd
: subgrid->mGridColEnd;
if (subgridExtent > 1) {
nscoord subgridGap =
nsLayoutUtils::ResolveGapToLength(gapStyle, NS_UNCONSTRAINEDSIZE);
auto& tracks =
- aAxis == eLogicalAxisBlock ? aState.mRows : aState.mCols;
+ aAxis == LogicalAxis::Block ? aState.mRows : aState.mCols;
auto gapDelta = subgridGap - tracks.mGridGap;
if (!itemEdgeBits) {
extraMargin += gapDelta;
@@ -5572,7 +5596,7 @@ static nscoord ContentContribution(
auto childWM = child->GetWritingMode();
const bool isOrthogonal = childWM.IsOrthogonalTo(aCBWM);
auto childAxis = isOrthogonal ? GetOrthogonalAxis(aAxis) : aAxis;
- if (size == NS_INTRINSIC_ISIZE_UNKNOWN && childAxis == eLogicalAxisBlock) {
+ if (size == NS_INTRINSIC_ISIZE_UNKNOWN && childAxis == LogicalAxis::Block) {
// We need to reflow the child to find its BSize contribution.
// XXX this will give mostly correct results for now (until bug 1174569).
nscoord availISize = INFINITE_ISIZE_COORD;
@@ -5595,8 +5619,8 @@ static nscoord ContentContribution(
}
// The grid-item's inline-axis as expressed in the subgrid's WM.
auto subgridAxis = childWM.IsOrthogonalTo(subgridFrame->GetWritingMode())
- ? eLogicalAxisBlock
- : eLogicalAxisInline;
+ ? LogicalAxis::Block
+ : LogicalAxis::Inline;
uts->ResolveTrackSizesForAxis(subgridFrame, subgridAxis, *aRC);
if (uts->mCanResolveLineRangeSize[subgridAxis]) {
auto* subgrid =
@@ -5642,7 +5666,7 @@ static nscoord ContentContribution(
}
}
}
- if (isOrthogonal == (aAxis == eLogicalAxisInline)) {
+ if (isOrthogonal == (aAxis == LogicalAxis::Inline)) {
bMinSizeClamp = aMinSizeClamp;
} else {
iMinSizeClamp = aMinSizeClamp;
@@ -5737,9 +5761,10 @@ static nscoord MinSize(const GridItemInfo& aGridItem,
PhysicalAxis axis(aCBWM.PhysicalAxis(aAxis));
const nsStylePosition* stylePos = child->StylePosition();
StyleSize sizeStyle =
- axis == eAxisHorizontal ? stylePos->mWidth : stylePos->mHeight;
+ axis == PhysicalAxis::Horizontal ? stylePos->mWidth : stylePos->mHeight;
- auto ourInlineAxis = child->GetWritingMode().PhysicalAxis(eLogicalAxisInline);
+ auto ourInlineAxis =
+ child->GetWritingMode().PhysicalAxis(LogicalAxis::Inline);
// max-content and min-content should behave as initial value in block axis.
// FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
// for block size dimension on sizing properties (e.g. height), so we
@@ -5775,8 +5800,9 @@ static nscoord MinSize(const GridItemInfo& aGridItem,
nsLayoutUtils::MinSizeContributionForAxis(
axis, aRC, child, IntrinsicISizeType::MinISize,
*aCache->mPercentageBasis);
- const StyleSize& style =
- axis == eAxisHorizontal ? stylePos->mMinWidth : stylePos->mMinHeight;
+ const StyleSize& style = axis == PhysicalAxis::Horizontal
+ ? stylePos->mMinWidth
+ : stylePos->mMinHeight;
// max-content and min-content should behave as initial value in block axis.
// FIXME: Bug 567039: moz-fit-content and -moz-available are not supported
// for block size dimension on sizing properties (e.g. height), so we
@@ -5992,7 +6018,7 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines(
// against the physical block start side of the child to determine its
// baseline sharing group.
auto containerBlockStartSide =
- containerWM.PhysicalSide(MakeLogicalSide(mAxis, eLogicalEdgeStart));
+ containerWM.PhysicalSide(MakeLogicalSide(mAxis, LogicalEdge::Start));
for (GridItemInfo& gridItem : aGridItems) {
if (gridItem.IsSubgrid(mAxis)) {
@@ -6006,7 +6032,7 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines(
const auto childWM = child->GetWritingMode();
const bool isOrthogonal = containerWM.IsOrthogonalTo(childWM);
- const bool isInlineAxis = mAxis == eLogicalAxisInline; // i.e. columns
+ const bool isInlineAxis = mAxis == LogicalAxis::Inline; // i.e. columns
// XXX update the line below to include orthogonal grid/table boxes
// XXX since they have baselines in both dimensions. And flexbox with
@@ -6099,7 +6125,7 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines(
{
auto childAxis = isOrthogonal ? GetOrthogonalAxis(mAxis) : mAxis;
auto childBlockStartSide = childWM.PhysicalSide(
- MakeLogicalSide(childAxis, eLogicalEdgeStart));
+ MakeLogicalSide(childAxis, LogicalEdge::Start));
bool isFirstBaseline = (state & ItemState::eFirstBaseline) != 0;
const bool containerAndChildHasEqualBaselineSide =
containerBlockStartSide == childBlockStartSide;
@@ -6281,7 +6307,7 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselinesInMasonryAxis(
auto state = ItemState(0);
auto childWM = child->GetWritingMode();
const bool isOrthogonal = wm.IsOrthogonalTo(childWM);
- const bool isInlineAxis = mAxis == eLogicalAxisInline; // i.e. columns
+ const bool isInlineAxis = mAxis == LogicalAxis::Inline; // i.e. columns
// XXX update the line below to include orthogonal grid/table boxes
// XXX since they have baselines in both dimensions. And flexbox with
// XXX reversed main/cross axis?
@@ -6449,10 +6475,10 @@ void nsGridContainerFrame::Tracks::AlignBaselineSubtree(
const bool isFirstBaseline = state & ItemState::eFirstBaseline;
if (isFirstBaseline) {
baselineTrack =
- mAxis == eLogicalAxisBlock ? area.mRows.mStart : area.mCols.mStart;
+ mAxis == LogicalAxis::Block ? area.mRows.mStart : area.mCols.mStart;
} else {
baselineTrack =
- (mAxis == eLogicalAxisBlock ? area.mRows.mEnd : area.mCols.mEnd) - 1;
+ (mAxis == LogicalAxis::Block ? area.mRows.mEnd : area.mCols.mEnd) - 1;
}
const TrackSize& sz = mSizes[baselineTrack];
auto baselineGroup = isFirstBaseline ? BaselineSharingGroup::First
@@ -6855,7 +6881,7 @@ float nsGridContainerFrame::Tracks::FindUsedFlexFraction(
nscoord spaceToFill = ContentContribution(item, aState, rc, wm, mAxis, pb,
IntrinsicISizeType::PrefISize);
const LineRange& range =
- mAxis == eLogicalAxisInline ? item.mArea.mCols : item.mArea.mRows;
+ mAxis == LogicalAxis::Inline ? item.mArea.mCols : item.mArea.mRows;
MOZ_ASSERT(range.Extent() >= 1);
const auto spannedGaps = range.Extent() - 1;
if (spannedGaps > 0) {
@@ -6898,10 +6924,10 @@ void nsGridContainerFrame::Tracks::StretchFlexibleTracks(
nscoord maxSize = NS_UNCONSTRAINEDSIZE;
if (aState.mReflowInput) {
auto* ri = aState.mReflowInput;
- minSize = mAxis == eLogicalAxisBlock ? ri->ComputedMinBSize()
- : ri->ComputedMinISize();
- maxSize = mAxis == eLogicalAxisBlock ? ri->ComputedMaxBSize()
- : ri->ComputedMaxISize();
+ minSize = mAxis == LogicalAxis::Block ? ri->ComputedMinBSize()
+ : ri->ComputedMinISize();
+ maxSize = mAxis == LogicalAxis::Block ? ri->ComputedMaxBSize()
+ : ri->ComputedMaxISize();
}
Maybe<CopyableAutoTArray<TrackSize, 32>> origSizes;
bool applyMinMax = (minSize != 0 || maxSize != NS_UNCONSTRAINEDSIZE) &&
@@ -6958,7 +6984,7 @@ void nsGridContainerFrame::Tracks::StretchFlexibleTracks(
void nsGridContainerFrame::Tracks::AlignJustifyContent(
const nsStylePosition* aStyle, StyleContentDistribution aAligmentStyleValue,
WritingMode aWM, nscoord aContentBoxSize, bool aIsSubgriddedAxis) {
- const bool isAlign = mAxis == eLogicalAxisBlock;
+ const bool isAlign = mAxis == LogicalAxis::Block;
// Align-/justify-content doesn't apply in a subgridded axis.
// Gap properties do apply though so we need to stretch/position the tracks
// to center-align the gaps with the parent's gaps.
@@ -7223,25 +7249,25 @@ LogicalSize nsGridContainerFrame::GridReflowInput::PercentageBasisFor(
if (auto* uts = subgridFrame->GetUsedTrackSizes()) {
auto subgridWM = subgridFrame->GetWritingMode();
LogicalSize cbSize(subgridWM, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
- if (!subgridFrame->IsSubgrid(eLogicalAxisInline) &&
- uts->mCanResolveLineRangeSize[eLogicalAxisInline]) {
+ if (!subgridFrame->IsSubgrid(LogicalAxis::Inline) &&
+ uts->mCanResolveLineRangeSize[LogicalAxis::Inline]) {
// NOTE: At this point aGridItem.mArea is in this->mFrame coordinates
// and thus may have been transposed. The range values in a non-
// subgridded axis still has its original values in subgridFrame's
// coordinates though.
- auto rangeAxis = subgridWM.IsOrthogonalTo(mWM) ? eLogicalAxisBlock
- : eLogicalAxisInline;
+ auto rangeAxis = subgridWM.IsOrthogonalTo(mWM) ? LogicalAxis::Block
+ : LogicalAxis::Inline;
const auto& range = aGridItem.mArea.LineRangeForAxis(rangeAxis);
cbSize.ISize(subgridWM) =
- range.ToLength(uts->mSizes[eLogicalAxisInline]);
+ range.ToLength(uts->mSizes[LogicalAxis::Inline]);
}
- if (!subgridFrame->IsSubgrid(eLogicalAxisBlock) &&
- uts->mCanResolveLineRangeSize[eLogicalAxisBlock]) {
- auto rangeAxis = subgridWM.IsOrthogonalTo(mWM) ? eLogicalAxisInline
- : eLogicalAxisBlock;
+ if (!subgridFrame->IsSubgrid(LogicalAxis::Block) &&
+ uts->mCanResolveLineRangeSize[LogicalAxis::Block]) {
+ auto rangeAxis = subgridWM.IsOrthogonalTo(mWM) ? LogicalAxis::Inline
+ : LogicalAxis::Block;
const auto& range = aGridItem.mArea.LineRangeForAxis(rangeAxis);
cbSize.BSize(subgridWM) =
- range.ToLength(uts->mSizes[eLogicalAxisBlock]);
+ range.ToLength(uts->mSizes[LogicalAxis::Block]);
}
return cbSize.ConvertTo(wm, subgridWM);
}
@@ -7249,7 +7275,7 @@ LogicalSize nsGridContainerFrame::GridReflowInput::PercentageBasisFor(
return LogicalSize(wm, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
- if (aAxis == eLogicalAxisInline || !mCols.mCanResolveLineRangeSize) {
+ if (aAxis == LogicalAxis::Inline || !mCols.mCanResolveLineRangeSize) {
return LogicalSize(wm, NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE);
}
// Note: for now, we only resolve transferred percentages to row sizing.
@@ -7428,7 +7454,7 @@ void nsGridContainerFrame::GridReflowInput::AlignJustifyTracksInMasonryAxis(
ContainingBlockFor(item->mArea).Size(wm).ConvertTo(childWM, wm);
LogicalSize availableSize = cb;
cb.Size(masonryChildAxis, childWM) = alignmentContainerSize;
- availableSize.Size(eLogicalAxisBlock, childWM) =
+ availableSize.Size(LogicalAxis::Block, childWM) =
NS_UNCONSTRAINEDSIZE;
const auto& bp = child->GetLogicalUsedBorderAndPadding(childWM);
newSize -= bp.StartEnd(masonryChildAxis, childWM);
@@ -7626,9 +7652,9 @@ void nsGridContainerFrame::ReflowInFlowChild(
aChild->RemoveProperty(aProp);
}
};
- SetProp(eLogicalAxisBlock,
+ SetProp(LogicalAxis::Block,
isOrthogonal ? IBaselinePadProperty() : BBaselinePadProperty());
- SetProp(eLogicalAxisInline,
+ SetProp(LogicalAxis::Inline,
isOrthogonal ? BBaselinePadProperty() : IBaselinePadProperty());
} else {
// By convention, for frames that perform CSS Box Alignment, we position
@@ -7654,9 +7680,9 @@ void nsGridContainerFrame::ReflowInFlowChild(
ComputeSizeFlags csFlags;
if (aGridItemInfo) {
const auto childIAxisInWM =
- isOrthogonal ? eLogicalAxisBlock : eLogicalAxisInline;
+ isOrthogonal ? LogicalAxis::Block : LogicalAxis::Inline;
// Clamp during reflow if we're stretching in that axis.
- if (GridItemShouldStretch(aChild, eLogicalAxisInline)) {
+ if (GridItemShouldStretch(aChild, LogicalAxis::Inline)) {
if (aGridItemInfo->mState[childIAxisInWM] &
ItemState::eClampMarginBoxMinSize) {
csFlags += ComputeSizeFlag::IClampMarginBoxMinSize;
@@ -7666,7 +7692,7 @@ void nsGridContainerFrame::ReflowInFlowChild(
}
const auto childBAxisInWM = GetOrthogonalAxis(childIAxisInWM);
- if (GridItemShouldStretch(aChild, eLogicalAxisBlock) &&
+ if (GridItemShouldStretch(aChild, LogicalAxis::Block) &&
aGridItemInfo->mState[childBAxisInWM] &
ItemState::eClampMarginBoxMinSize) {
csFlags += ComputeSizeFlag::BClampMarginBoxMinSize;
@@ -7702,7 +7728,7 @@ void nsGridContainerFrame::ReflowInFlowChild(
// nsBlockFrame::ComputeFinalSize the size.
if (isConstrainedBSize && !wm.IsOrthogonalTo(childWM)) {
const bool stretch = childRI.mStylePosition->BSize(childWM).IsAuto() &&
- GridItemShouldStretch(aChild, eLogicalAxisBlock);
+ GridItemShouldStretch(aChild, LogicalAxis::Block);
if (stretch) {
aChild->SetProperty(FragStretchBSizeProperty(), *aStretchBSize);
} else {
@@ -7750,7 +7776,7 @@ void nsGridContainerFrame::ReflowInFlowChild(
? StyleAlignFlags::SELF_START
: StyleAlignFlags::SELF_END};
}
- if (aAxis == eLogicalAxisBlock) {
+ if (aAxis == LogicalAxis::Block) {
AlignSelf(*aGridItemInfo, align, aCBSize, wm, childRI, size, flags,
&childPos);
} else {
@@ -7759,10 +7785,10 @@ void nsGridContainerFrame::ReflowInFlowChild(
}
};
if (aStatus.IsComplete()) {
- applyItemSelfAlignment(eLogicalAxisBlock,
+ applyItemSelfAlignment(LogicalAxis::Block,
cb.BSize(wm) - consumedGridAreaBSize);
}
- applyItemSelfAlignment(eLogicalAxisInline, cb.ISize(wm));
+ applyItemSelfAlignment(LogicalAxis::Inline, cb.ISize(wm));
} // else, nsAbsoluteContainingBlock.cpp will handle align/justify-self.
FinishReflowChild(aChild, pc, childSize, &childRI, childWM, childPos,
@@ -8006,7 +8032,7 @@ nscoord nsGridContainerFrame::ReflowRowsInFragmentainer(
const auto rowCount = aState.mRows.mSizes.Length();
nscoord masonryAxisGap;
const auto wm = aState.mWM;
- const bool isColMasonry = IsMasonry(eLogicalAxisInline);
+ const bool isColMasonry = IsMasonry(LogicalAxis::Inline);
if (isColMasonry) {
for (auto& sz : aState.mCols.mSizes) {
sz.mPosition = 0;
@@ -8174,15 +8200,15 @@ nscoord nsGridContainerFrame::ReflowRowsInFragmentainer(
}
if (isColMasonry) {
auto childWM = child->GetWritingMode();
- auto childAxis =
- !childWM.IsOrthogonalTo(wm) ? eLogicalAxisInline : eLogicalAxisBlock;
+ auto childAxis = !childWM.IsOrthogonalTo(wm) ? LogicalAxis::Inline
+ : LogicalAxis::Block;
auto normalPos = child->GetLogicalNormalPosition(wm, aContainerSize);
auto sz =
- childAxis == eLogicalAxisBlock ? child->BSize() : child->ISize();
- auto pos = normalPos.Pos(eLogicalAxisInline, wm) + sz +
+ childAxis == LogicalAxis::Block ? child->BSize() : child->ISize();
+ auto pos = normalPos.Pos(LogicalAxis::Inline, wm) + sz +
child->GetLogicalUsedMargin(childWM).End(childAxis, childWM);
masonryAxisPos.ref()[row] =
- pos + masonryAxisGap - aContentArea.Start(eLogicalAxisInline, wm);
+ pos + masonryAxisGap - aContentArea.Start(LogicalAxis::Inline, wm);
}
}
@@ -8281,7 +8307,7 @@ nscoord nsGridContainerFrame::MasonryLayout(GridReflowInput& aState,
aState.mIter.Reset(CSSOrderAwareFrameIterator::ChildFilter::IncludeAll);
size_t absposIndex = 0;
const LogicalAxis masonryAxis =
- IsMasonry(eLogicalAxisBlock) ? eLogicalAxisBlock : eLogicalAxisInline;
+ IsMasonry(LogicalAxis::Block) ? LogicalAxis::Block : LogicalAxis::Inline;
const auto wm = aState.mWM;
for (; !aState.mIter.AtEnd(); aState.mIter.Next()) {
nsIFrame* child = *aState.mIter;
@@ -8323,7 +8349,7 @@ nscoord nsGridContainerFrame::MasonryLayout(GridReflowInput& aState,
const auto masonryAutoFlow = aState.mGridStyle->mMasonryAutoFlow;
const bool definiteFirst =
masonryAutoFlow.order == StyleMasonryItemOrder::DefiniteFirst;
- if (masonryAxis == eLogicalAxisBlock) {
+ if (masonryAxis == LogicalAxis::Block) {
std::stable_sort(sortedItems.begin(), sortedItems.end(),
definiteFirst ? GridItemInfo::RowMasonryDefiniteFirst
: GridItemInfo::RowMasonryOrdered);
@@ -8366,8 +8392,8 @@ nscoord nsGridContainerFrame::MasonryLayout(GridReflowInput& aState,
lastItems.SetLength(gridAxisTrackCount);
PodZero(lastItems.Elements(), gridAxisTrackCount);
const nscoord gap = nsLayoutUtils::ResolveGapToLength(
- masonryAxis == eLogicalAxisBlock ? aState.mGridStyle->mRowGap
- : aState.mGridStyle->mColumnGap,
+ masonryAxis == LogicalAxis::Block ? aState.mGridStyle->mRowGap
+ : aState.mGridStyle->mColumnGap,
masonryTracks.mContentBoxSize);
masonryTracks.mGridGap = gap;
uint32_t cursor = 0;
@@ -8495,7 +8521,7 @@ nscoord nsGridContainerFrame::MasonryLayout(GridReflowInput& aState,
auto childAxis = !childWM.IsOrthogonalTo(wm) ? masonryAxis : gridAxis;
auto normalPos = aChild->GetLogicalNormalPosition(wm, aContainerSize);
auto sz =
- childAxis == eLogicalAxisBlock ? aChild->BSize() : aChild->ISize();
+ childAxis == LogicalAxis::Block ? aChild->BSize() : aChild->ISize();
return containerToMasonryBoxOffset + normalPos.Pos(masonryAxis, wm) + sz +
aChild->GetLogicalUsedMargin(childWM).End(childAxis, childWM);
};
@@ -8668,7 +8694,7 @@ nscoord nsGridContainerFrame::MasonryLayout(GridReflowInput& aState,
consumeAllSpace ? toFragmentainerEnd : offsetToMarginBoxEnd(child);
} else {
LogicalSize percentBasis(
- aState.PercentageBasisFor(eLogicalAxisInline, *item));
+ aState.PercentageBasisFor(LogicalAxis::Inline, *item));
IntrinsicISizeType type = aConstraint == SizingConstraint::MaxContent
? IntrinsicISizeType::PrefISize
: IntrinsicISizeType::MinISize;
@@ -8775,19 +8801,19 @@ nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aState,
// so we let ReflowInFragmentainer() deal with grid-axis fragmentation
// in the else-clause below.
if (IsMasonry() &&
- !(IsMasonry(eLogicalAxisInline) && fragmentainer.isSome())) {
+ !(IsMasonry(LogicalAxis::Inline) && fragmentainer.isSome())) {
aState.mInFragmentainer = fragmentainer.isSome();
nscoord sz = MasonryLayout(
aState, aContentArea, SizingConstraint::NoConstraint, aDesiredSize,
aStatus, fragmentainer.ptrOr(nullptr), aContainerSize);
- if (IsMasonry(eLogicalAxisBlock)) {
+ if (IsMasonry(LogicalAxis::Block)) {
bSize = aState.mReflowInput->ComputedBSize();
if (bSize == NS_UNCONSTRAINEDSIZE) {
bSize = aState.mReflowInput->ApplyMinMaxBSize(sz);
}
}
} else if (MOZ_UNLIKELY(fragmentainer.isSome())) {
- if (IsMasonry(eLogicalAxisInline) && !GetPrevInFlow()) {
+ if (IsMasonry(LogicalAxis::Inline) && !GetPrevInFlow()) {
// First we do an unconstrained reflow to resolve the item placement
// which is then kept as-is in the constrained reflow below.
MasonryLayout(aState, aContentArea, SizingConstraint::NoConstraint,
@@ -8804,10 +8830,12 @@ nscoord nsGridContainerFrame::ReflowChildren(GridReflowInput& aState,
if (!child->IsPlaceholderFrame()) {
info = &aState.mGridItems[aState.mIter.ItemIndex()];
}
+ nsReflowStatus childStatus;
ReflowInFlowChild(child, info, aContainerSize, Nothing(), nullptr, aState,
- aContentArea, aDesiredSize, aStatus);
- MOZ_ASSERT(aStatus.IsComplete(),
+ aContentArea, aDesiredSize, childStatus);
+ MOZ_ASSERT(childStatus.IsComplete(),
"child should be complete in unconstrained reflow");
+ aStatus.MergeCompletionStatusFrom(childStatus);
}
}
@@ -8868,7 +8896,6 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsGridContainerFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
if (IsFrameTreeTooDeep(aReflowInput, aDesiredSize, aStatus)) {
@@ -8952,11 +8979,11 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
if (containBSize) {
bSize = *containBSize;
} else {
- if (IsMasonry(eLogicalAxisBlock)) {
+ if (IsMasonry(LogicalAxis::Block)) {
bSize = computedBSize;
} else {
const auto& rowSizes = gridReflowInput.mRows.mSizes;
- if (MOZ_LIKELY(!IsSubgrid(eLogicalAxisBlock))) {
+ if (MOZ_LIKELY(!IsSubgrid(LogicalAxis::Block))) {
// Note: we can't use GridLineEdge here since we haven't calculated
// the rows' mPosition yet (happens in AlignJustifyContent below).
for (const auto& sz : rowSizes) {
@@ -9025,7 +9052,7 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
}
// Save the final row sizes for use by subgrids, if needed.
if (HasSubgridItems() || IsSubgrid()) {
- StoreUsedTrackSizes(eLogicalAxisBlock, rowSizes);
+ StoreUsedTrackSizes(LogicalAxis::Block, rowSizes);
}
}
@@ -9122,8 +9149,8 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
}
// TODO: fix align-tracks alignment in fragments
- if ((IsMasonry(eLogicalAxisBlock) && !prevInFlow) ||
- IsMasonry(eLogicalAxisInline)) {
+ if ((IsMasonry(LogicalAxis::Block) && !prevInFlow) ||
+ IsMasonry(LogicalAxis::Inline)) {
gridReflowInput.AlignJustifyTracksInMasonryAxis(
contentArea.Size(wm), aDesiredSize.PhysicalSize());
}
@@ -9221,7 +9248,7 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
// the ComputedGridTrackInfo and related properties
const auto* subgrid = GetProperty(Subgrid::Prop());
- const auto* subgridColRange = subgrid && IsSubgrid(eLogicalAxisInline)
+ const auto* subgridColRange = subgrid && IsSubgrid(LogicalAxis::Inline)
? &subgrid->SubgridCols()
: nullptr;
@@ -9252,7 +9279,7 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
// taken by rvalue, but computing the size first prevents any changes in the
// argument types of the constructor from breaking this.
const uint32_t numColExplicitTracks =
- IsSubgrid(eLogicalAxisInline)
+ IsSubgrid(LogicalAxis::Inline)
? colTrackSizes.Length()
: gridReflowInput.mColFunctions.NumExplicitTracks();
ComputedGridTrackInfo* colInfo = new ComputedGridTrackInfo(
@@ -9261,10 +9288,10 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
std::move(colTrackStates), std::move(colRemovedRepeatTracks),
gridReflowInput.mColFunctions.mRepeatAutoStart,
colLineNameMap.GetResolvedLineNamesForComputedGridTrackInfo(),
- IsSubgrid(eLogicalAxisInline), IsMasonry(eLogicalAxisInline));
+ IsSubgrid(LogicalAxis::Inline), IsMasonry(LogicalAxis::Inline));
SetProperty(GridColTrackInfo(), colInfo);
- const auto* subgridRowRange = subgrid && IsSubgrid(eLogicalAxisBlock)
+ const auto* subgridRowRange = subgrid && IsSubgrid(LogicalAxis::Block)
? &subgrid->SubgridRows()
: nullptr;
LineNameMap rowLineNameMap(
@@ -9294,7 +9321,7 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
// taken by rvalue, but computing the size first prevents any changes in the
// argument types of the constructor from breaking this.
const uint32_t numRowExplicitTracks =
- IsSubgrid(eLogicalAxisBlock)
+ IsSubgrid(LogicalAxis::Block)
? rowTrackSizes.Length()
: gridReflowInput.mRowFunctions.NumExplicitTracks();
// Row info has to accommodate fragmentation of the grid, which may happen
@@ -9307,7 +9334,7 @@ void nsGridContainerFrame::Reflow(nsPresContext* aPresContext,
std::move(rowRemovedRepeatTracks),
gridReflowInput.mRowFunctions.mRepeatAutoStart,
rowLineNameMap.GetResolvedLineNamesForComputedGridTrackInfo(),
- IsSubgrid(eLogicalAxisBlock), IsMasonry(eLogicalAxisBlock));
+ IsSubgrid(LogicalAxis::Block), IsMasonry(LogicalAxis::Block));
SetProperty(GridRowTrackInfo(), rowInfo);
if (prevInFlow) {
@@ -9613,16 +9640,16 @@ nscoord nsGridContainerFrame::IntrinsicISize(gfxContext* aRenderingContext,
// They're only used for auto-repeat so we skip computing them otherwise.
RepeatTrackSizingInput repeatSizing(state.mWM);
if (!IsColSubgrid() && state.mColFunctions.mHasRepeatAuto) {
- repeatSizing.InitFromStyle(eLogicalAxisInline, state.mWM,
+ repeatSizing.InitFromStyle(LogicalAxis::Inline, state.mWM,
state.mFrame->Style());
}
if ((!IsRowSubgrid() && state.mRowFunctions.mHasRepeatAuto &&
!(state.mGridStyle->mGridAutoFlow & StyleGridAutoFlow::ROW)) ||
- IsMasonry(eLogicalAxisInline)) {
+ IsMasonry(LogicalAxis::Inline)) {
// Only 'grid-auto-flow:column' can create new implicit columns, so that's
// the only case where our block-size can affect the number of columns.
// Masonry layout always depends on how many rows we have though.
- repeatSizing.InitFromStyle(eLogicalAxisBlock, state.mWM,
+ repeatSizing.InitFromStyle(LogicalAxis::Block, state.mWM,
state.mFrame->Style());
}
@@ -9640,13 +9667,13 @@ nscoord nsGridContainerFrame::IntrinsicISize(gfxContext* aRenderingContext,
auto constraint = aType == IntrinsicISizeType::MinISize
? SizingConstraint::MinContent
: SizingConstraint::MaxContent;
- if (IsMasonry(eLogicalAxisInline)) {
+ if (IsMasonry(LogicalAxis::Inline)) {
ReflowOutput desiredSize(state.mWM);
nsSize containerSize;
LogicalRect contentArea(state.mWM);
nsReflowStatus status;
state.mRows.mSizes.SetLength(grid.mGridRowEnd);
- state.CalculateTrackSizesForAxis(eLogicalAxisInline, grid,
+ state.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid,
NS_UNCONSTRAINEDSIZE, constraint);
return MasonryLayout(state, contentArea, constraint, desiredSize, status,
nullptr, containerSize);
@@ -9656,7 +9683,7 @@ nscoord nsGridContainerFrame::IntrinsicISize(gfxContext* aRenderingContext,
return nscoord(0);
}
- state.CalculateTrackSizesForAxis(eLogicalAxisInline, grid,
+ state.CalculateTrackSizesForAxis(LogicalAxis::Inline, grid,
NS_UNCONSTRAINEDSIZE, constraint);
if (MOZ_LIKELY(!IsSubgrid())) {
@@ -9672,7 +9699,6 @@ nscoord nsGridContainerFrame::GetMinISize(gfxContext* aRC) {
return f->GetMinISize(aRC);
}
- DISPLAY_MIN_INLINE_SIZE(this, mCachedMinISize);
if (mCachedMinISize == NS_INTRINSIC_ISIZE_UNKNOWN) {
Maybe<nscoord> containISize = ContainIntrinsicISize();
mCachedMinISize = containISize
@@ -9688,7 +9714,6 @@ nscoord nsGridContainerFrame::GetPrefISize(gfxContext* aRC) {
return f->GetPrefISize(aRC);
}
- DISPLAY_PREF_INLINE_SIZE(this, mCachedPrefISize);
if (mCachedPrefISize == NS_INTRINSIC_ISIZE_UNKNOWN) {
Maybe<nscoord> containISize = ContainIntrinsicISize();
mCachedPrefISize = containISize
@@ -9770,7 +9795,7 @@ StyleAlignFlags nsGridContainerFrame::CSSAlignmentForAbsPosChild(
"This method should only be called for abspos children");
StyleAlignFlags alignment =
- (aLogicalAxis == eLogicalAxisInline)
+ (aLogicalAxis == LogicalAxis::Inline)
? aChildRI.mStylePosition->UsedJustifySelf(Style())._0
: aChildRI.mStylePosition->UsedAlignSelf(Style())._0;
@@ -9792,7 +9817,7 @@ StyleAlignFlags nsGridContainerFrame::CSSAlignmentForAbsPosChild(
alignment = StyleAlignFlags::END;
} else if (alignment == StyleAlignFlags::LEFT ||
alignment == StyleAlignFlags::RIGHT) {
- if (aLogicalAxis == eLogicalAxisInline) {
+ if (aLogicalAxis == LogicalAxis::Inline) {
const bool isLeft = (alignment == StyleAlignFlags::LEFT);
WritingMode wm = GetWritingMode();
alignment = (isLeft == wm.IsBidiLTR()) ? StyleAlignFlags::START
@@ -9827,7 +9852,7 @@ nscoord nsGridContainerFrame::SynthesizeBaseline(
nscoord start;
nscoord size;
- if (aAxis == eLogicalAxisBlock) {
+ if (aAxis == LogicalAxis::Block) {
start = child->GetLogicalNormalPosition(aCBWM, aCBPhysicalSize).B(aCBWM);
size = child->BSize(aCBWM);
if (grid && aGridOrderItem.mIsInEdgeTrack) {
@@ -9836,13 +9861,13 @@ nscoord nsGridContainerFrame::SynthesizeBaseline(
} else if (!isOrthogonal && aGridOrderItem.mIsInEdgeTrack) {
// This assertion is mostly for documentation purposes; it must hold,
// given the checks in our 'if' statements. (We know aAxis is
- // eLogicalAxisBlock, and isOrthogonal is false, which means childAxis
- // must be eLogicalAxisBlock). If instead we got here with a childAxis of
- // eLogicalAxisInline, then our call to
+ // LogicalAxis::Block, and isOrthogonal is false, which means childAxis
+ // must be LogicalAxis::Block). If instead we got here with a childAxis of
+ // LogicalAxis::Inline, then our call to
// Baseline::SynthesizeBaselineFromBorderBox might incorrectly think
// it makes sense to use a central baseline, in an axis where that
// doesn't make sense.
- MOZ_ASSERT(childAxis == eLogicalAxisBlock, "unexpected childAxis");
+ MOZ_ASSERT(childAxis == LogicalAxis::Block, "unexpected childAxis");
baseline = child
->GetNaturalBaselineBOffset(childWM, aGroup,
BaselineExportContext::Other)
@@ -9893,8 +9918,8 @@ void nsGridContainerFrame::CalculateBaselines(
} else if (firstBaseline == NS_INTRINSIC_ISIZE_UNKNOWN) {
FindItemInGridOrderResult gridOrderFirstItem = FindFirstItemInGridOrder(
*aIter, *aGridItems,
- axis == eLogicalAxisBlock ? &GridArea::mRows : &GridArea::mCols,
- axis == eLogicalAxisBlock ? &GridArea::mCols : &GridArea::mRows,
+ axis == LogicalAxis::Block ? &GridArea::mRows : &GridArea::mCols,
+ axis == LogicalAxis::Block ? &GridArea::mCols : &GridArea::mRows,
aFragmentStartTrack);
mBaseline[axis][BaselineSharingGroup::First] = SynthesizeBaseline(
gridOrderFirstItem, axis, BaselineSharingGroup::First, aCBPhysicalSize,
@@ -9929,8 +9954,8 @@ void nsGridContainerFrame::CalculateBaselines(
iter.SetItemCount(aGridItems->Length());
FindItemInGridOrderResult gridOrderLastItem = FindLastItemInGridOrder(
iter, *aGridItems,
- axis == eLogicalAxisBlock ? &GridArea::mRows : &GridArea::mCols,
- axis == eLogicalAxisBlock ? &GridArea::mCols : &GridArea::mRows,
+ axis == LogicalAxis::Block ? &GridArea::mRows : &GridArea::mCols,
+ axis == LogicalAxis::Block ? &GridArea::mCols : &GridArea::mRows,
aFragmentStartTrack, aFirstExcludedTrack);
mBaseline[axis][BaselineSharingGroup::Last] =
SynthesizeBaseline(gridOrderLastItem, axis, BaselineSharingGroup::Last,
@@ -10124,7 +10149,7 @@ bool nsGridContainerFrame::GridItemShouldStretch(const nsIFrame* aChild,
}
const auto* pos = aChild->StylePosition();
- const auto alignment = (aAxis == eLogicalAxisInline) == !isOrthogonal
+ const auto alignment = (aAxis == LogicalAxis::Inline) == !isOrthogonal
? pos->UsedJustifySelf(Style())._0
: pos->UsedAlignSelf(Style())._0;
return alignment == StyleAlignFlags::NORMAL ||
diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h
index cf3a3b5776..1fa7bbe487 100644
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -233,12 +233,12 @@ class nsGridContainerFrame final : public nsContainerFrame,
/** Return true if this frame is subgridded in its aAxis. */
bool IsSubgrid(LogicalAxis aAxis) const {
- return HasAnyStateBits(aAxis == mozilla::eLogicalAxisBlock
+ return HasAnyStateBits(aAxis == mozilla::LogicalAxis::Block
? NS_STATE_GRID_IS_ROW_SUBGRID
: NS_STATE_GRID_IS_COL_SUBGRID);
}
- bool IsColSubgrid() const { return IsSubgrid(mozilla::eLogicalAxisInline); }
- bool IsRowSubgrid() const { return IsSubgrid(mozilla::eLogicalAxisBlock); }
+ bool IsColSubgrid() const { return IsSubgrid(mozilla::LogicalAxis::Inline); }
+ bool IsRowSubgrid() const { return IsSubgrid(mozilla::LogicalAxis::Block); }
/** Return true if this frame is subgridded in any axis. */
bool IsSubgrid() const {
return HasAnyStateBits(NS_STATE_GRID_IS_ROW_SUBGRID |
@@ -247,7 +247,7 @@ class nsGridContainerFrame final : public nsContainerFrame,
/** Return true if this frame has an item that is subgridded in our aAxis. */
bool HasSubgridItems(LogicalAxis aAxis) const {
- return HasAnyStateBits(aAxis == mozilla::eLogicalAxisBlock
+ return HasAnyStateBits(aAxis == mozilla::LogicalAxis::Block
? NS_STATE_GRID_HAS_ROW_SUBGRID_ITEM
: NS_STATE_GRID_HAS_COL_SUBGRID_ITEM);
}
@@ -375,10 +375,10 @@ class nsGridContainerFrame final : public nsContainerFrame,
mozilla::IntrinsicISizeType aConstraint);
nscoord GetBBaseline(BaselineSharingGroup aBaselineGroup) const {
- return mBaseline[mozilla::eLogicalAxisBlock][aBaselineGroup];
+ return mBaseline[mozilla::LogicalAxis::Block][aBaselineGroup];
}
nscoord GetIBaseline(BaselineSharingGroup aBaselineGroup) const {
- return mBaseline[mozilla::eLogicalAxisInline][aBaselineGroup];
+ return mBaseline[mozilla::LogicalAxis::Inline][aBaselineGroup];
}
/**
@@ -566,12 +566,8 @@ class nsGridContainerFrame final : public nsContainerFrame,
if (aFrame->IsSubtreeDirty()) {
return false;
}
-
- if (!CanCacheMeasurement(aFrame, aCBSize)) {
- return false;
- }
-
- return mKey == Key(aFrame, aCBSize);
+ const mozilla::Maybe<Key> maybeKey = Key::TryHash(aFrame, aCBSize);
+ return maybeKey.isSome() && mKey == *maybeKey;
}
static bool CanCacheMeasurement(const nsIFrame* aFrame,
@@ -583,55 +579,54 @@ class nsGridContainerFrame final : public nsContainerFrame,
void Update(const nsIFrame* aFrame, const LogicalSize& aCBSize,
const nscoord aBSize) {
- MOZ_ASSERT(CanCacheMeasurement(aFrame, aCBSize));
- mKey.mHashKey = Key::GenerateHash(aFrame, aCBSize);
+ mKey.UpdateHash(aFrame, aCBSize);
mBSize = aBSize;
}
private:
- struct Key {
+ class Key {
// mHashKey is generated by combining these 2 variables together
// 1. The containing block size in the item's inline axis used
// for measuring reflow
// 2. The item's baseline padding property
uint32_t mHashKey;
+ explicit Key(uint32_t aHashKey) : mHashKey(aHashKey) {}
+
+ public:
Key() = default;
Key(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
- MOZ_ASSERT(CanHash(aFrame, aCBSize));
- mHashKey = GenerateHash(aFrame, aCBSize);
+ UpdateHash(aFrame, aCBSize);
}
void UpdateHash(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
- MOZ_ASSERT(CanHash(aFrame, aCBSize));
- mHashKey = GenerateHash(aFrame, aCBSize);
+ const mozilla::Maybe<Key> maybeKey = TryHash(aFrame, aCBSize);
+ MOZ_ASSERT(maybeKey.isSome());
+ mHashKey = maybeKey->mHashKey;
}
- static uint32_t GenerateHash(const nsIFrame* aFrame,
- const LogicalSize& aCBSize) {
- MOZ_ASSERT(CanHash(aFrame, aCBSize));
-
- nscoord gridAreaISize = aCBSize.ISize(aFrame->GetWritingMode());
- nscoord bBaselinePaddingProperty =
+ static mozilla::Maybe<Key> TryHash(const nsIFrame* aFrame,
+ const LogicalSize& aCBSize) {
+ const nscoord gridAreaISize = aCBSize.ISize(aFrame->GetWritingMode());
+ const nscoord bBaselinePaddingProperty =
abs(aFrame->GetProperty(nsIFrame::BBaselinePadProperty()));
- uint_fast8_t bitsNeededForISize = mozilla::FloorLog2(gridAreaISize) + 1;
-
- return (gridAreaISize << (32 - bitsNeededForISize)) |
- bBaselinePaddingProperty;
+ const uint_fast8_t bitsNeededForISize =
+ mozilla::FloorLog2(gridAreaISize) + 1;
+
+ const uint_fast8_t bitsNeededForBBaselinePadding =
+ mozilla::FloorLog2(bBaselinePaddingProperty) + 1;
+ if (bitsNeededForISize + bitsNeededForBBaselinePadding > 32) {
+ return mozilla::Nothing();
+ }
+ const uint32_t hashKey = (gridAreaISize << (32 - bitsNeededForISize)) |
+ bBaselinePaddingProperty;
+ return mozilla::Some(Key(hashKey));
}
static bool CanHash(const nsIFrame* aFrame, const LogicalSize& aCBSize) {
- uint_fast8_t bitsNeededForISize =
- mozilla::FloorLog2(aCBSize.ISize(aFrame->GetWritingMode())) + 1;
-
- uint_fast8_t bitsNeededForBBaselinePadding =
- mozilla::FloorLog2(
- abs(aFrame->GetProperty(nsIFrame::BBaselinePadProperty()))) +
- 1;
-
- return bitsNeededForISize + bitsNeededForBBaselinePadding <= 32;
+ return TryHash(aFrame, aCBSize).isSome();
}
bool operator==(const Key& aOther) const {
diff --git a/layout/generic/nsHTMLCanvasFrame.cpp b/layout/generic/nsHTMLCanvasFrame.cpp
index 07aeabec07..4b646359e5 100644
--- a/layout/generic/nsHTMLCanvasFrame.cpp
+++ b/layout/generic/nsHTMLCanvasFrame.cpp
@@ -382,7 +382,6 @@ nscoord nsHTMLCanvasFrame::GetMinISize(gfxContext* aRenderingContext) {
result = nsPresContext::CSSPixelsToAppUnits(
vertical ? GetCanvasSize().height : GetCanvasSize().width);
}
- DISPLAY_MIN_INLINE_SIZE(this, result);
return result;
}
@@ -398,7 +397,6 @@ nscoord nsHTMLCanvasFrame::GetPrefISize(gfxContext* aRenderingContext) {
result = nsPresContext::CSSPixelsToAppUnits(
vertical ? GetCanvasSize().height : GetCanvasSize().width);
}
- DISPLAY_PREF_INLINE_SIZE(this, result);
return result;
}
@@ -438,7 +436,6 @@ void nsHTMLCanvasFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsHTMLCanvasFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE(
NS_FRAME_TRACE_CALLS,
diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
index 479c26d18b..28c328c9e2 100644
--- a/layout/generic/nsIFrame.cpp
+++ b/layout/generic/nsIFrame.cpp
@@ -19,6 +19,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/DisplayPortUtils.h"
#include "mozilla/EventForwards.h"
+#include "mozilla/FocusModel.h"
#include "mozilla/dom/CSSAnimation.h"
#include "mozilla/dom/CSSTransition.h"
#include "mozilla/dom/ContentVisibilityAutoStateChangeEvent.h"
@@ -2017,6 +2018,12 @@ bool nsIFrame::GetShapeBoxBorderRadii(nscoord aRadii[8]) const {
}
}
+nscoord nsIFrame::OneEmInAppUnits() const {
+ return StyleFont()
+ ->mFont.size.ScaledBy(nsLayoutUtils::FontSizeInflationFor(this))
+ .ToAppUnits();
+}
+
ComputedStyle* nsIFrame::GetAdditionalComputedStyle(int32_t aIndex) const {
MOZ_ASSERT(aIndex >= 0, "invalid index number");
return nullptr;
@@ -2396,6 +2403,15 @@ already_AddRefed<ComputedStyle> nsIFrame::ComputeHighlightSelectionStyle(
*element, PseudoStyleType::highlight, aHighlightName, Style());
}
+already_AddRefed<ComputedStyle> nsIFrame::ComputeTargetTextStyle() const {
+ const Element* element = FindElementAncestorForMozSelection(GetContent());
+ if (!element) {
+ return nullptr;
+ }
+ return PresContext()->StyleSet()->ProbePseudoElementStyle(
+ *element, PseudoStyleType::targetText, nullptr, Style());
+}
+
template <typename SizeOrMaxSize>
static inline bool IsIntrinsicKeyword(const SizeOrMaxSize& aSize) {
// All keywords other than auto/none/-moz-available depend on intrinsic sizes.
@@ -4039,6 +4055,13 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
return;
}
+ nsIFrame* child = aChild;
+ auto* placeholder = child->IsPlaceholderFrame()
+ ? static_cast<nsPlaceholderFrame*>(child)
+ : nullptr;
+ nsIFrame* childOrOutOfFlow =
+ placeholder ? placeholder->GetOutOfFlowFrame() : child;
+
// If we're generating a display list for printing, include Link items for
// frames that correspond to HTML link elements so that we can have active
// links in saved PDF output. Note that the state of "within a link" is
@@ -4050,17 +4073,10 @@ void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
Maybe<nsDisplayListBuilder::Linkifier> linkifier;
if (StaticPrefs::print_save_as_pdf_links_enabled() &&
aBuilder->IsForPrinting()) {
- linkifier.emplace(aBuilder, aChild, aLists.Content());
- linkifier->MaybeAppendLink(aBuilder, aChild);
+ linkifier.emplace(aBuilder, childOrOutOfFlow, aLists.Content());
+ linkifier->MaybeAppendLink(aBuilder, childOrOutOfFlow);
}
- nsIFrame* child = aChild;
- auto* placeholder = child->IsPlaceholderFrame()
- ? static_cast<nsPlaceholderFrame*>(child)
- : nullptr;
- nsIFrame* childOrOutOfFlow =
- placeholder ? placeholder->GetOutOfFlowFrame() : child;
-
nsIFrame* parent = childOrOutOfFlow->GetParent();
const auto* parentDisplay = parent->StyleDisplay();
const auto overflowClipAxes =
@@ -4913,12 +4929,14 @@ bool nsIFrame::MovingCaretToEventPointAllowedIfSecondaryButtonEvent(
: aContentAtEventPoint.GetClosestNativeAnonymousSubtreeRoot());
if (Selection* selection =
aFrameSelection.GetSelection(SelectionType::eNormal)) {
- const bool selectionIsCollapsed = selection->IsCollapsed();
- // If right click in a selection range, we should not collapse selection.
- if (!selectionIsCollapsed &&
- nsContentUtils::IsPointInSelection(
- *selection, aContentAtEventPoint,
- static_cast<uint32_t>(aOffsetAtEventPoint))) {
+ const bool selectionIsCollapsed =
+ selection->AreNormalAndCrossShadowBoundaryRangesCollapsed();
+ // If right click in a selection range, we should not collapse
+ // selection.
+ if (!selectionIsCollapsed && nsContentUtils::IsPointInSelection(
+ *selection, aContentAtEventPoint,
+ static_cast<uint32_t>(aOffsetAtEventPoint),
+ true /* aAllowCrossShadowBoundary */)) {
return false;
}
const bool wantToPreventMoveCaret =
@@ -5120,7 +5138,9 @@ nsresult nsIFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
return rv;
}
if (aAmountBack == eSelectWord) {
- frameSelection->SetIsDoubleClickSelection(true);
+ frameSelection->SetClickSelectionType(ClickSelectionType::Double);
+ } else if (aAmountBack == eSelectParagraph) {
+ frameSelection->SetClickSelectionType(ClickSelectionType::Triple);
}
// maintain selection
@@ -5989,18 +6009,10 @@ void nsIFrame::MarkSubtreeDirty() {
}
/* virtual */
-nscoord nsIFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_MIN_INLINE_SIZE(this, result);
- return result;
-}
+nscoord nsIFrame::GetMinISize(gfxContext* aRenderingContext) { return 0; }
/* virtual */
-nscoord nsIFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_PREF_INLINE_SIZE(this, result);
- return result;
-}
+nscoord nsIFrame::GetPrefISize(gfxContext* aRenderingContext) { return 0; }
/* virtual */
void nsIFrame::AddInlineMinISize(gfxContext* aRenderingContext,
@@ -6319,14 +6331,12 @@ static MinMaxSize ComputeTransferredMinMaxInlineSize(
if (aMinMaxBSize.mMinSize > 0) {
transferredISize.mMinSize = aAspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, aMinMaxBSize.mMinSize,
- aBoxSizingAdjustment);
+ LogicalAxis::Inline, aWM, aMinMaxBSize.mMinSize, aBoxSizingAdjustment);
}
if (aMinMaxBSize.mMaxSize != NS_UNCONSTRAINEDSIZE) {
transferredISize.mMaxSize = aAspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, aMinMaxBSize.mMaxSize,
- aBoxSizingAdjustment);
+ LogicalAxis::Inline, aWM, aMinMaxBSize.mMaxSize, aBoxSizingAdjustment);
}
// Minimum size wins over maximum size.
@@ -6393,11 +6403,11 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
// indicates which axis (in this frame's own WM) corresponds to its
// flex container's main axis.
LogicalAxis flexMainAxis =
- eLogicalAxisInline; // (init to make valgrind happy)
+ LogicalAxis::Inline; // (init to make valgrind happy)
if (isFlexItem) {
flexMainAxis = nsFlexContainerFrame::IsItemInlineAxisMainAxis(this)
- ? eLogicalAxisInline
- : eLogicalAxisBlock;
+ ? LogicalAxis::Inline
+ : LogicalAxis::Block;
}
const bool isOrthogonal = aWM.IsOrthogonalTo(alignCB->GetWritingMode());
@@ -6426,8 +6436,8 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
bool mayUseAspectRatio = aspectRatio && !isAutoBSize;
if (!aFlags.contains(ComputeSizeFlag::ShrinkWrap) &&
!StyleMargin()->HasInlineAxisAuto(aWM) &&
- !alignCB->IsMasonry(isOrthogonal ? eLogicalAxisBlock
- : eLogicalAxisInline)) {
+ !alignCB->IsMasonry(isOrthogonal ? LogicalAxis::Block
+ : LogicalAxis::Inline)) {
auto inlineAxisAlignment =
isOrthogonal ? StylePosition()->UsedAlignSelf(alignCB->Style())._0
: StylePosition()->UsedJustifySelf(alignCB->Style())._0;
@@ -6451,7 +6461,7 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
aCBSize.BSize(aWM), boxSizingAdjust.BSize(aWM),
styleBSize.AsLengthPercentage());
result.ISize(aWM) = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, bSize, boxSizingAdjust);
+ LogicalAxis::Inline, aWM, bSize, boxSizingAdjust);
aspectRatioUsage = AspectRatioUsage::ToComputeISize;
}
@@ -6468,7 +6478,7 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
aCBSize.BSize(aWM), boxSizingAdjust.BSize(aWM),
styleBSize.AsLengthPercentage());
result.ISize(aWM) = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, bSize, boxSizingAdjust);
+ LogicalAxis::Inline, aWM, bSize, boxSizingAdjust);
aspectRatioUsage = AspectRatioUsage::ToComputeISize;
}
@@ -6523,7 +6533,7 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
// flex container's main-axis. (Those properties get applied later in
// the flexbox algorithm.)
const bool isFlexItemInlineAxisMainAxis =
- isFlexItem && flexMainAxis == eLogicalAxisInline;
+ isFlexItem && flexMainAxis == LogicalAxis::Inline;
// Grid items that are subgridded in inline-axis also ignore their min & max
// sizing properties in that axis.
const bool shouldIgnoreMinMaxISize =
@@ -6602,8 +6612,8 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
} else if (MOZ_UNLIKELY(isGridItem) && styleBSize.IsAuto() &&
!aFlags.contains(ComputeSizeFlag::IsGridMeasuringReflow) &&
!IsTrueOverflowContainer() &&
- !alignCB->IsMasonry(isOrthogonal ? eLogicalAxisInline
- : eLogicalAxisBlock)) {
+ !alignCB->IsMasonry(isOrthogonal ? LogicalAxis::Inline
+ : LogicalAxis::Block)) {
auto cbSize = aCBSize.BSize(aWM);
if (cbSize != NS_UNCONSTRAINEDSIZE) {
// 'auto' block-size for grid-level box - fill the CB for 'stretch' /
@@ -6628,8 +6638,7 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
// https://drafts.csswg.org/css-grid/#grid-item-sizing
if (!stretch && mayUseAspectRatio) {
result.BSize(aWM) = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisBlock, aWM, result.ISize(aWM),
- boxSizingAdjust);
+ LogicalAxis::Block, aWM, result.ISize(aWM), boxSizingAdjust);
MOZ_ASSERT(aspectRatioUsage == AspectRatioUsage::None);
aspectRatioUsage = AspectRatioUsage::ToComputeBSize;
}
@@ -6651,8 +6660,7 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
// applied (so aspectRatioUsage flag is set as expected). That's why we
// apply aspect-ratio unconditionally for auto block size here.
result.BSize(aWM) = aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisBlock, aWM, result.ISize(aWM),
- boxSizingAdjust);
+ LogicalAxis::Block, aWM, result.ISize(aWM), boxSizingAdjust);
MOZ_ASSERT(aspectRatioUsage == AspectRatioUsage::None);
aspectRatioUsage = AspectRatioUsage::ToComputeBSize;
}
@@ -6662,7 +6670,7 @@ nsIFrame::SizeComputationResult nsIFrame::ComputeSize(
// container's main-axis. (Those properties get applied later in the flexbox
// algorithm.)
const bool isFlexItemBlockAxisMainAxis =
- isFlexItem && flexMainAxis == eLogicalAxisBlock;
+ isFlexItem && flexMainAxis == LogicalAxis::Block;
// Grid items that are subgridded in block-axis also ignore their min & max
// sizing properties in that axis.
const bool shouldIgnoreMinMaxBSize =
@@ -6789,7 +6797,7 @@ Maybe<nscoord> nsIFrame::ComputeInlineSizeFromAspectRatio(
aCBSize.BSize(aWM), aContentEdgeToBoxSizing.BSize(aWM),
styleBSize.AsLengthPercentage());
return Some(aspectRatio.ComputeRatioDependentSize(
- LogicalAxis::eLogicalAxisInline, aWM, bSize, aContentEdgeToBoxSizing));
+ LogicalAxis::Inline, aWM, bSize, aContentEdgeToBoxSizing));
}
nsIFrame::ISizeComputationResult nsIFrame::ComputeISizeValue(
@@ -7884,7 +7892,7 @@ nsRect nsIFrame::GetNormalRect() const {
nsRect nsIFrame::GetBoundingClientRect() {
return nsLayoutUtils::GetAllInFlowRectsUnion(
this, nsLayoutUtils::GetContainingBlockForClientRect(this),
- nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
+ nsLayoutUtils::GetAllInFlowRectsFlag::AccountForTransforms);
}
nsPoint nsIFrame::GetPositionIgnoringScrolling() const {
@@ -7945,8 +7953,19 @@ OverflowAreas nsIFrame::GetActualAndNormalOverflowAreasRelativeToParent()
}
const OverflowAreas overflows = GetOverflowAreas();
- OverflowAreas actualAndNormalOverflows = overflows + GetPosition();
- actualAndNormalOverflows.UnionWith(overflows + GetNormalPosition());
+ OverflowAreas actualAndNormalOverflows = overflows + GetNormalPosition();
+ if (IsRelativelyPositioned()) {
+ actualAndNormalOverflows.UnionWith(overflows + GetPosition());
+ } else {
+ // For sticky positioned elements, we only use the normal position for the
+ // scrollable overflow. This avoids circular dependencies between sticky
+ // positioned elements and their scroll container. (The scroll position and
+ // the scroll container's size impact the sticky position, so we don't want
+ // the sticky position to impact them.)
+ MOZ_ASSERT(IsStickyPositioned());
+ actualAndNormalOverflows.UnionWith(
+ OverflowAreas(overflows.InkOverflow() + GetPosition(), nsRect()));
+ }
return actualAndNormalOverflows;
}
@@ -8003,7 +8022,7 @@ bool nsIFrame::UpdateOverflow() {
if (nsView* view = GetView()) {
// Make sure the frame's view is properly sized.
nsViewManager* vm = view->GetViewManager();
- vm->ResizeView(view, overflowAreas.InkOverflow(), true);
+ vm->ResizeView(view, overflowAreas.InkOverflow());
}
return true;
@@ -8560,6 +8579,12 @@ const nsFrameSelection* nsIFrame::GetConstFrameSelection() const {
bool nsIFrame::IsFrameSelected() const {
NS_ASSERTION(!GetContent() || GetContent()->IsMaybeSelected(),
"use the public IsSelected() instead");
+ if (StaticPrefs::dom_shadowdom_selection_across_boundary_enabled()) {
+ if (const ShadowRoot* shadowRoot =
+ GetContent()->GetShadowRootForSelection()) {
+ return shadowRoot->IsSelected(0, shadowRoot->GetChildCount());
+ }
+ }
return GetContent()->IsSelected(0, GetContent()->GetChildCount());
}
@@ -8983,6 +9008,13 @@ nsresult nsIFrame::PeekOffsetForParagraph(PeekOffsetStruct* aPos) {
if (reachedLimit) { // no "stop frame" found
aPos->mResultContent = frame->GetContent();
+ if (ShadowRoot* shadowRoot =
+ aPos->mResultContent->GetShadowRootForSelection()) {
+ // Even if there's no children for this node,
+ // the elements inside the shadow root is still
+ // selectable
+ aPos->mResultContent = shadowRoot;
+ }
if (aPos->mDirection == eDirPrevious) {
aPos->mContentOffset = 0;
} else if (aPos->mResultContent) {
@@ -10698,21 +10730,27 @@ ComputedStyle* nsIFrame::DoGetParentComputedStyle(
}
void nsIFrame::GetLastLeaf(nsIFrame** aFrame) {
- if (!aFrame || !*aFrame) return;
- nsIFrame* child = *aFrame;
- // if we are a block frame then go for the last line of 'this'
- while (1) {
- child = child->PrincipalChildList().FirstChild();
- if (!child) return; // nothing to do
- nsIFrame* siblingFrame;
- nsIContent* content;
- // ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
- // see bug 278197 comment #12 #13 for details
- while ((siblingFrame = child->GetNextSibling()) &&
- (content = siblingFrame->GetContent()) &&
- !content->IsRootOfNativeAnonymousSubtree())
- child = siblingFrame;
- *aFrame = child;
+ if (!aFrame || !*aFrame) {
+ return;
+ }
+ for (nsIFrame* maybeLastLeaf = (*aFrame)->PrincipalChildList().LastChild();
+ maybeLastLeaf;) {
+ nsIFrame* lastChildNotInSubTree = nullptr;
+ for (nsIFrame* child = maybeLastLeaf; child;
+ child = child->GetPrevSibling()) {
+ nsIContent* content = child->GetContent();
+ // ignore anonymous elements, e.g. mozTableAdd* mozTableRemove*
+ // see bug 278197 comment #12 #13 for details
+ if (content && !content->IsRootOfNativeAnonymousSubtree()) {
+ lastChildNotInSubTree = child;
+ break;
+ }
+ }
+ if (!lastChildNotInSubTree) {
+ return;
+ }
+ *aFrame = lastChildNotInSubTree;
+ maybeLastLeaf = lastChildNotInSubTree->PrincipalChildList().LastChild();
}
}
@@ -10771,7 +10809,7 @@ bool nsIFrame::IsFocusableDueToScrollFrame() {
return true;
}
-Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) {
+Focusable nsIFrame::IsFocusable(IsFocusableFlags aFlags) {
// cannot focus content in print preview mode. Only the root can be focused,
// but that's handled elsewhere.
if (PresContext()->Type() == nsPresContext::eContext_PrintPreview) {
@@ -10782,7 +10820,8 @@ Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) {
return {};
}
- if (aCheckVisibility && !IsVisibleConsideringAncestors()) {
+ if (!(aFlags & IsFocusableFlags::IgnoreVisibility) &&
+ !IsVisibleConsideringAncestors()) {
return {};
}
@@ -10802,14 +10841,14 @@ Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) {
// As a legacy special-case, -moz-user-focus controls focusability and
// tabability of XUL elements in some circumstances (which default to
// -moz-user-focus: ignore).
- auto focusability = xul->GetXULFocusability(aWithMouse);
+ auto focusability = xul->GetXULFocusability(aFlags);
focusable.mFocusable =
focusability.mForcedFocusable.valueOr(uf == StyleUserFocus::Normal);
if (focusable) {
focusable.mTabIndex = focusability.mForcedTabIndexIfFocusable.valueOr(0);
}
} else {
- focusable = mContent->IsFocusableWithoutStyle(aWithMouse);
+ focusable = mContent->IsFocusableWithoutStyle(aFlags);
}
if (focusable) {
@@ -10817,7 +10856,8 @@ Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) {
}
// If we're focusing with the mouse we never focus scroll areas.
- if (!aWithMouse && IsFocusableDueToScrollFrame()) {
+ if (!(aFlags & IsFocusableFlags::WithMouse) &&
+ IsFocusableDueToScrollFrame()) {
return {true, 0};
}
@@ -10907,7 +10947,7 @@ void nsIFrame::UpdateStyleOfChildAnonBox(nsIFrame* aChildFrame,
// Now that we've updated the style on aChildFrame, check whether it itself
// has anon boxes to deal with.
ServoRestyleState childrenState(*aChildFrame, aRestyleState, childHint,
- ServoRestyleState::Type::InFlow);
+ ServoRestyleState::CanUseHandledHints::Yes);
aChildFrame->UpdateStyleOfOwnedAnonBoxes(childrenState);
// Assuming anon boxes don't have ::backdrop associated with them... if that
@@ -11603,6 +11643,47 @@ bool nsIFrame::HasUnreflowedContainerQueryAncestor() const {
return false;
}
+bool nsIFrame::ShouldBreakBefore(
+ const ReflowInput::BreakType aBreakType) const {
+ const auto* display = StyleDisplay();
+ return ShouldBreakBetween(display, display->mBreakBefore, aBreakType);
+}
+
+bool nsIFrame::ShouldBreakAfter(const ReflowInput::BreakType aBreakType) const {
+ const auto* display = StyleDisplay();
+ return ShouldBreakBetween(display, display->mBreakAfter, aBreakType);
+}
+
+bool nsIFrame::ShouldBreakBetween(
+ const nsStyleDisplay* aDisplay, const StyleBreakBetween aBreakBetween,
+ const ReflowInput::BreakType aBreakType) const {
+ const bool shouldBreakBetween = [&] {
+ switch (aBreakBetween) {
+ case StyleBreakBetween::Always:
+ return true;
+ case StyleBreakBetween::Auto:
+ case StyleBreakBetween::Avoid:
+ return false;
+ case StyleBreakBetween::Page:
+ case StyleBreakBetween::Left:
+ case StyleBreakBetween::Right:
+ return aBreakType == ReflowInput::BreakType::Page;
+ }
+ MOZ_ASSERT_UNREACHABLE("Unknown break-between value!");
+ return false;
+ }();
+
+ if (!shouldBreakBetween) {
+ return false;
+ }
+ if (IsAbsolutelyPositioned(aDisplay)) {
+ // 'break-before' and 'break-after' properties does not apply to
+ // absolutely-positioned boxes.
+ return false;
+ }
+ return true;
+}
+
#ifdef DEBUG
static void GetTagName(nsIFrame* aFrame, nsIContent* aContent, int aResultSize,
char* aResult) {
@@ -11655,1037 +11736,6 @@ void nsIFrame::VerifyDirtyBitSet(const nsFrameList& aFrameList) {
}
}
-// Start Display Reflow
-DR_cookie::DR_cookie(nsPresContext* aPresContext, nsIFrame* aFrame,
- const ReflowInput& aReflowInput, ReflowOutput& aMetrics,
- nsReflowStatus& aStatus)
- : mPresContext(aPresContext),
- mFrame(aFrame),
- mReflowInput(aReflowInput),
- mMetrics(aMetrics),
- mStatus(aStatus) {
- MOZ_COUNT_CTOR(DR_cookie);
- mValue = nsIFrame::DisplayReflowEnter(aPresContext, mFrame, mReflowInput);
-}
-
-DR_cookie::~DR_cookie() {
- MOZ_COUNT_DTOR(DR_cookie);
- nsIFrame::DisplayReflowExit(mPresContext, mFrame, mMetrics, mStatus, mValue);
-}
-
-DR_layout_cookie::DR_layout_cookie(nsIFrame* aFrame) : mFrame(aFrame) {
- MOZ_COUNT_CTOR(DR_layout_cookie);
- mValue = nsIFrame::DisplayLayoutEnter(mFrame);
-}
-
-DR_layout_cookie::~DR_layout_cookie() {
- MOZ_COUNT_DTOR(DR_layout_cookie);
- nsIFrame::DisplayLayoutExit(mFrame, mValue);
-}
-
-DR_intrinsic_inline_size_cookie::DR_intrinsic_inline_size_cookie(
- nsIFrame* aFrame, const char* aType, nscoord& aResult)
- : mFrame(aFrame), mType(aType), mResult(aResult) {
- MOZ_COUNT_CTOR(DR_intrinsic_inline_size_cookie);
- mValue = nsIFrame::DisplayIntrinsicISizeEnter(mFrame, mType);
-}
-
-DR_intrinsic_inline_size_cookie::~DR_intrinsic_inline_size_cookie() {
- MOZ_COUNT_DTOR(DR_intrinsic_inline_size_cookie);
- nsIFrame::DisplayIntrinsicISizeExit(mFrame, mType, mResult, mValue);
-}
-
-DR_intrinsic_size_cookie::DR_intrinsic_size_cookie(nsIFrame* aFrame,
- const char* aType,
- nsSize& aResult)
- : mFrame(aFrame), mType(aType), mResult(aResult) {
- MOZ_COUNT_CTOR(DR_intrinsic_size_cookie);
- mValue = nsIFrame::DisplayIntrinsicSizeEnter(mFrame, mType);
-}
-
-DR_intrinsic_size_cookie::~DR_intrinsic_size_cookie() {
- MOZ_COUNT_DTOR(DR_intrinsic_size_cookie);
- nsIFrame::DisplayIntrinsicSizeExit(mFrame, mType, mResult, mValue);
-}
-
-DR_init_constraints_cookie::DR_init_constraints_cookie(
- nsIFrame* aFrame, ReflowInput* aState, nscoord aCBWidth, nscoord aCBHeight,
- const mozilla::Maybe<mozilla::LogicalMargin> aBorder,
- const mozilla::Maybe<mozilla::LogicalMargin> aPadding)
- : mFrame(aFrame), mState(aState) {
- MOZ_COUNT_CTOR(DR_init_constraints_cookie);
- nsMargin border;
- if (aBorder) {
- border = aBorder->GetPhysicalMargin(aFrame->GetWritingMode());
- }
- nsMargin padding;
- if (aPadding) {
- padding = aPadding->GetPhysicalMargin(aFrame->GetWritingMode());
- }
- mValue = ReflowInput::DisplayInitConstraintsEnter(
- mFrame, mState, aCBWidth, aCBHeight, aBorder ? &border : nullptr,
- aPadding ? &padding : nullptr);
-}
-
-DR_init_constraints_cookie::~DR_init_constraints_cookie() {
- MOZ_COUNT_DTOR(DR_init_constraints_cookie);
- ReflowInput::DisplayInitConstraintsExit(mFrame, mState, mValue);
-}
-
-DR_init_offsets_cookie::DR_init_offsets_cookie(
- nsIFrame* aFrame, SizeComputationInput* aState, nscoord aPercentBasis,
- WritingMode aCBWritingMode,
- const mozilla::Maybe<mozilla::LogicalMargin> aBorder,
- const mozilla::Maybe<mozilla::LogicalMargin> aPadding)
- : mFrame(aFrame), mState(aState) {
- MOZ_COUNT_CTOR(DR_init_offsets_cookie);
- nsMargin border;
- if (aBorder) {
- border = aBorder->GetPhysicalMargin(aFrame->GetWritingMode());
- }
- nsMargin padding;
- if (aPadding) {
- padding = aPadding->GetPhysicalMargin(aFrame->GetWritingMode());
- }
- mValue = SizeComputationInput::DisplayInitOffsetsEnter(
- mFrame, mState, aPercentBasis, aCBWritingMode,
- aBorder ? &border : nullptr, aPadding ? &padding : nullptr);
-}
-
-DR_init_offsets_cookie::~DR_init_offsets_cookie() {
- MOZ_COUNT_DTOR(DR_init_offsets_cookie);
- SizeComputationInput::DisplayInitOffsetsExit(mFrame, mState, mValue);
-}
-
-struct DR_Rule;
-
-struct DR_FrameTypeInfo {
- DR_FrameTypeInfo(LayoutFrameType aFrameType, const char* aFrameNameAbbrev,
- const char* aFrameName);
- ~DR_FrameTypeInfo();
-
- LayoutFrameType mType;
- char mNameAbbrev[16];
- char mName[32];
- nsTArray<DR_Rule*> mRules;
-
- private:
- DR_FrameTypeInfo& operator=(const DR_FrameTypeInfo&) = delete;
-};
-
-struct DR_FrameTreeNode;
-struct DR_Rule;
-
-struct DR_State {
- DR_State();
- ~DR_State();
- void Init();
- void AddFrameTypeInfo(LayoutFrameType aFrameType,
- const char* aFrameNameAbbrev, const char* aFrameName);
- DR_FrameTypeInfo* GetFrameTypeInfo(LayoutFrameType aFrameType);
- DR_FrameTypeInfo* GetFrameTypeInfo(char* aFrameName);
- void InitFrameTypeTable();
- DR_FrameTreeNode* CreateTreeNode(nsIFrame* aFrame,
- const ReflowInput* aReflowInput);
- void FindMatchingRule(DR_FrameTreeNode& aNode);
- bool RuleMatches(DR_Rule& aRule, DR_FrameTreeNode& aNode);
- bool GetToken(FILE* aFile, char* aBuf, size_t aBufSize);
- DR_Rule* ParseRule(FILE* aFile);
- void ParseRulesFile();
- void AddRule(nsTArray<DR_Rule*>& aRules, DR_Rule& aRule);
- bool IsWhiteSpace(int c);
- bool GetNumber(char* aBuf, int32_t& aNumber);
- void PrettyUC(nscoord aSize, char* aBuf, int aBufSize);
- void PrintMargin(const char* tag, const nsMargin* aMargin);
- void DisplayFrameTypeInfo(nsIFrame* aFrame, int32_t aIndent);
- void DeleteTreeNode(DR_FrameTreeNode& aNode);
-
- bool mInited;
- bool mActive;
- int32_t mCount;
- int32_t mAssert;
- int32_t mIndent;
- bool mIndentUndisplayedFrames;
- bool mDisplayPixelErrors;
- nsTArray<DR_Rule*> mWildRules;
- nsTArray<DR_FrameTypeInfo> mFrameTypeTable;
- // reflow specific state
- nsTArray<DR_FrameTreeNode*> mFrameTreeLeaves;
-};
-
-static DR_State* DR_state; // the one and only DR_State
-
-struct DR_RulePart {
- explicit DR_RulePart(LayoutFrameType aFrameType)
- : mFrameType(aFrameType), mNext(0) {}
-
- void Destroy();
-
- LayoutFrameType mFrameType;
- DR_RulePart* mNext;
-};
-
-void DR_RulePart::Destroy() {
- if (mNext) {
- mNext->Destroy();
- }
- delete this;
-}
-
-struct DR_Rule {
- DR_Rule() : mLength(0), mTarget(nullptr), mDisplay(false) {
- MOZ_COUNT_CTOR(DR_Rule);
- }
- ~DR_Rule() {
- if (mTarget) mTarget->Destroy();
- MOZ_COUNT_DTOR(DR_Rule);
- }
- void AddPart(LayoutFrameType aFrameType);
-
- uint32_t mLength;
- DR_RulePart* mTarget;
- bool mDisplay;
-};
-
-void DR_Rule::AddPart(LayoutFrameType aFrameType) {
- DR_RulePart* newPart = new DR_RulePart(aFrameType);
- newPart->mNext = mTarget;
- mTarget = newPart;
- mLength++;
-}
-
-DR_FrameTypeInfo::~DR_FrameTypeInfo() {
- int32_t numElements;
- numElements = mRules.Length();
- for (int32_t i = numElements - 1; i >= 0; i--) {
- delete mRules.ElementAt(i);
- }
-}
-
-DR_FrameTypeInfo::DR_FrameTypeInfo(LayoutFrameType aFrameType,
- const char* aFrameNameAbbrev,
- const char* aFrameName) {
- mType = aFrameType;
- PL_strncpyz(mNameAbbrev, aFrameNameAbbrev, sizeof(mNameAbbrev));
- PL_strncpyz(mName, aFrameName, sizeof(mName));
-}
-
-struct DR_FrameTreeNode {
- DR_FrameTreeNode(nsIFrame* aFrame, DR_FrameTreeNode* aParent)
- : mFrame(aFrame), mParent(aParent), mDisplay(0), mIndent(0) {
- MOZ_COUNT_CTOR(DR_FrameTreeNode);
- }
-
- MOZ_COUNTED_DTOR(DR_FrameTreeNode)
-
- nsIFrame* mFrame;
- DR_FrameTreeNode* mParent;
- bool mDisplay;
- uint32_t mIndent;
-};
-
-// DR_State implementation
-
-DR_State::DR_State()
- : mInited(false),
- mActive(false),
- mCount(0),
- mAssert(-1),
- mIndent(0),
- mIndentUndisplayedFrames(false),
- mDisplayPixelErrors(false) {
- MOZ_COUNT_CTOR(DR_State);
-}
-
-void DR_State::Init() {
- char* env = PR_GetEnv("GECKO_DISPLAY_REFLOW_ASSERT");
- int32_t num;
- if (env) {
- if (GetNumber(env, num))
- mAssert = num;
- else
- printf("GECKO_DISPLAY_REFLOW_ASSERT - invalid value = %s", env);
- }
-
- env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_START");
- if (env) {
- if (GetNumber(env, num))
- mIndent = num;
- else
- printf("GECKO_DISPLAY_REFLOW_INDENT_START - invalid value = %s", env);
- }
-
- env = PR_GetEnv("GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES");
- if (env) {
- if (GetNumber(env, num))
- mIndentUndisplayedFrames = num;
- else
- printf(
- "GECKO_DISPLAY_REFLOW_INDENT_UNDISPLAYED_FRAMES - invalid value = %s",
- env);
- }
-
- env = PR_GetEnv("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS");
- if (env) {
- if (GetNumber(env, num))
- mDisplayPixelErrors = num;
- else
- printf("GECKO_DISPLAY_REFLOW_FLAG_PIXEL_ERRORS - invalid value = %s",
- env);
- }
-
- InitFrameTypeTable();
- ParseRulesFile();
- mInited = true;
-}
-
-DR_State::~DR_State() {
- MOZ_COUNT_DTOR(DR_State);
- int32_t numElements, i;
- numElements = mWildRules.Length();
- for (i = numElements - 1; i >= 0; i--) {
- delete mWildRules.ElementAt(i);
- }
- numElements = mFrameTreeLeaves.Length();
- for (i = numElements - 1; i >= 0; i--) {
- delete mFrameTreeLeaves.ElementAt(i);
- }
-}
-
-bool DR_State::GetNumber(char* aBuf, int32_t& aNumber) {
- if (sscanf(aBuf, "%d", &aNumber) > 0)
- return true;
- else
- return false;
-}
-
-bool DR_State::IsWhiteSpace(int c) {
- return (c == ' ') || (c == '\t') || (c == '\n') || (c == '\r');
-}
-
-bool DR_State::GetToken(FILE* aFile, char* aBuf, size_t aBufSize) {
- bool haveToken = false;
- aBuf[0] = 0;
- // get the 1st non whitespace char
- int c = -1;
- for (c = getc(aFile); (c > 0) && IsWhiteSpace(c); c = getc(aFile)) {
- }
-
- if (c > 0) {
- haveToken = true;
- aBuf[0] = c;
- // get everything up to the next whitespace char
- size_t cX;
- for (cX = 1; cX + 1 < aBufSize; cX++) {
- c = getc(aFile);
- if (c < 0) { // EOF
- ungetc(' ', aFile);
- break;
- } else {
- if (IsWhiteSpace(c)) {
- break;
- } else {
- aBuf[cX] = c;
- }
- }
- }
- aBuf[cX] = 0;
- }
- return haveToken;
-}
-
-DR_Rule* DR_State::ParseRule(FILE* aFile) {
- char buf[128];
- int32_t doDisplay;
- DR_Rule* rule = nullptr;
- while (GetToken(aFile, buf, sizeof(buf))) {
- if (GetNumber(buf, doDisplay)) {
- if (rule) {
- rule->mDisplay = !!doDisplay;
- break;
- } else {
- printf("unexpected token - %s \n", buf);
- }
- } else {
- if (!rule) {
- rule = new DR_Rule;
- }
- if (strcmp(buf, "*") == 0) {
- rule->AddPart(LayoutFrameType::None);
- } else {
- DR_FrameTypeInfo* info = GetFrameTypeInfo(buf);
- if (info) {
- rule->AddPart(info->mType);
- } else {
- printf("invalid frame type - %s \n", buf);
- }
- }
- }
- }
- return rule;
-}
-
-void DR_State::AddRule(nsTArray<DR_Rule*>& aRules, DR_Rule& aRule) {
- int32_t numRules = aRules.Length();
- for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
- DR_Rule* rule = aRules.ElementAt(ruleX);
- NS_ASSERTION(rule, "program error");
- if (aRule.mLength > rule->mLength) {
- aRules.InsertElementAt(ruleX, &aRule);
- return;
- }
- }
- aRules.AppendElement(&aRule);
-}
-
-static Maybe<bool> ShouldLogReflow(const char* processes) {
- switch (processes[0]) {
- case 'A':
- case 'a':
- return Some(true);
- case 'P':
- case 'p':
- return Some(XRE_IsParentProcess());
- case 'C':
- case 'c':
- return Some(XRE_IsContentProcess());
- default:
- return Nothing{};
- }
-}
-
-void DR_State::ParseRulesFile() {
- char* processes = PR_GetEnv("GECKO_DISPLAY_REFLOW_PROCESSES");
- if (processes) {
- Maybe<bool> enableLog = ShouldLogReflow(processes);
- if (enableLog.isNothing()) {
- MOZ_CRASH("GECKO_DISPLAY_REFLOW_PROCESSES: [a]ll [p]arent [c]ontent");
- } else if (enableLog.value()) {
- DR_Rule* rule = new DR_Rule;
- rule->AddPart(LayoutFrameType::None);
- rule->mDisplay = true;
- AddRule(mWildRules, *rule);
- mActive = true;
- }
- return;
- }
-
- char* path = PR_GetEnv("GECKO_DISPLAY_REFLOW_RULES_FILE");
- if (path) {
- FILE* inFile = fopen(path, "r");
- if (!inFile) {
- MOZ_CRASH(
- "Failed to open the specified rules file; Try `--setpref "
- "security.sandbox.content.level=2` if the sandbox is at cause");
- }
- for (DR_Rule* rule = ParseRule(inFile); rule; rule = ParseRule(inFile)) {
- if (rule->mTarget) {
- LayoutFrameType fType = rule->mTarget->mFrameType;
- if (fType != LayoutFrameType::None) {
- DR_FrameTypeInfo* info = GetFrameTypeInfo(fType);
- AddRule(info->mRules, *rule);
- } else {
- AddRule(mWildRules, *rule);
- }
- mActive = true;
- }
- }
-
- fclose(inFile);
- }
-}
-
-void DR_State::AddFrameTypeInfo(LayoutFrameType aFrameType,
- const char* aFrameNameAbbrev,
- const char* aFrameName) {
- mFrameTypeTable.EmplaceBack(aFrameType, aFrameNameAbbrev, aFrameName);
-}
-
-DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(LayoutFrameType aFrameType) {
- int32_t numEntries = mFrameTypeTable.Length();
- NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
- for (int32_t i = 0; i < numEntries; i++) {
- DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
- if (info.mType == aFrameType) {
- return &info;
- }
- }
- return &mFrameTypeTable.ElementAt(numEntries -
- 1); // return unknown frame type
-}
-
-DR_FrameTypeInfo* DR_State::GetFrameTypeInfo(char* aFrameName) {
- int32_t numEntries = mFrameTypeTable.Length();
- NS_ASSERTION(numEntries != 0, "empty FrameTypeTable");
- for (int32_t i = 0; i < numEntries; i++) {
- DR_FrameTypeInfo& info = mFrameTypeTable.ElementAt(i);
- if ((strcmp(aFrameName, info.mName) == 0) ||
- (strcmp(aFrameName, info.mNameAbbrev) == 0)) {
- return &info;
- }
- }
- return &mFrameTypeTable.ElementAt(numEntries -
- 1); // return unknown frame type
-}
-
-void DR_State::InitFrameTypeTable() {
- AddFrameTypeInfo(LayoutFrameType::Block, "block", "block");
- AddFrameTypeInfo(LayoutFrameType::Br, "br", "br");
- AddFrameTypeInfo(LayoutFrameType::ColorControl, "color", "colorControl");
- AddFrameTypeInfo(LayoutFrameType::GfxButtonControl, "button",
- "gfxButtonControl");
- AddFrameTypeInfo(LayoutFrameType::HTMLButtonControl, "HTMLbutton",
- "HTMLButtonControl");
- AddFrameTypeInfo(LayoutFrameType::HTMLCanvas, "HTMLCanvas", "HTMLCanvas");
- AddFrameTypeInfo(LayoutFrameType::SubDocument, "subdoc", "subDocument");
- AddFrameTypeInfo(LayoutFrameType::Image, "img", "image");
- AddFrameTypeInfo(LayoutFrameType::Inline, "inline", "inline");
- AddFrameTypeInfo(LayoutFrameType::Letter, "letter", "letter");
- AddFrameTypeInfo(LayoutFrameType::Line, "line", "line");
- AddFrameTypeInfo(LayoutFrameType::ListControl, "select", "select");
- AddFrameTypeInfo(LayoutFrameType::Page, "page", "page");
- AddFrameTypeInfo(LayoutFrameType::Placeholder, "place", "placeholder");
- AddFrameTypeInfo(LayoutFrameType::Canvas, "canvas", "canvas");
- AddFrameTypeInfo(LayoutFrameType::Scroll, "scroll", "scroll");
- AddFrameTypeInfo(LayoutFrameType::TableCell, "cell", "tableCell");
- AddFrameTypeInfo(LayoutFrameType::TableCol, "col", "tableCol");
- AddFrameTypeInfo(LayoutFrameType::TableColGroup, "colG", "tableColGroup");
- AddFrameTypeInfo(LayoutFrameType::Table, "tbl", "table");
- AddFrameTypeInfo(LayoutFrameType::TableWrapper, "tblW", "tableWrapper");
- AddFrameTypeInfo(LayoutFrameType::TableRowGroup, "rowG", "tableRowGroup");
- AddFrameTypeInfo(LayoutFrameType::TableRow, "row", "tableRow");
- AddFrameTypeInfo(LayoutFrameType::TextInput, "textCtl", "textInput");
- AddFrameTypeInfo(LayoutFrameType::Text, "text", "text");
- AddFrameTypeInfo(LayoutFrameType::Viewport, "VP", "viewport");
- AddFrameTypeInfo(LayoutFrameType::Slider, "Slider", "Slider");
- AddFrameTypeInfo(LayoutFrameType::None, "unknown", "unknown");
-}
-
-void DR_State::DisplayFrameTypeInfo(nsIFrame* aFrame, int32_t aIndent) {
- DR_FrameTypeInfo* frameTypeInfo = GetFrameTypeInfo(aFrame->Type());
- if (frameTypeInfo) {
- for (int32_t i = 0; i < aIndent; i++) {
- printf(" ");
- }
- if (!strcmp(frameTypeInfo->mNameAbbrev, "unknown")) {
- if (aFrame) {
- nsAutoString name;
- aFrame->GetFrameName(name);
- printf("%s %p ", NS_LossyConvertUTF16toASCII(name).get(),
- (void*)aFrame);
- } else {
- printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
- }
- } else {
- printf("%s %p ", frameTypeInfo->mNameAbbrev, (void*)aFrame);
- }
- }
-}
-
-bool DR_State::RuleMatches(DR_Rule& aRule, DR_FrameTreeNode& aNode) {
- NS_ASSERTION(aRule.mTarget, "program error");
-
- DR_RulePart* rulePart;
- DR_FrameTreeNode* parentNode;
- for (rulePart = aRule.mTarget->mNext, parentNode = aNode.mParent;
- rulePart && parentNode;
- rulePart = rulePart->mNext, parentNode = parentNode->mParent) {
- if (rulePart->mFrameType != LayoutFrameType::None) {
- if (parentNode->mFrame) {
- if (rulePart->mFrameType != parentNode->mFrame->Type()) {
- return false;
- }
- } else
- NS_ASSERTION(false, "program error");
- }
- // else wild card match
- }
- return true;
-}
-
-void DR_State::FindMatchingRule(DR_FrameTreeNode& aNode) {
- if (!aNode.mFrame) {
- NS_ASSERTION(false, "invalid DR_FrameTreeNode \n");
- return;
- }
-
- bool matchingRule = false;
-
- DR_FrameTypeInfo* info = GetFrameTypeInfo(aNode.mFrame->Type());
- NS_ASSERTION(info, "program error");
- int32_t numRules = info->mRules.Length();
- for (int32_t ruleX = 0; ruleX < numRules; ruleX++) {
- DR_Rule* rule = info->mRules.ElementAt(ruleX);
- if (rule && RuleMatches(*rule, aNode)) {
- aNode.mDisplay = rule->mDisplay;
- matchingRule = true;
- break;
- }
- }
- if (!matchingRule) {
- int32_t numWildRules = mWildRules.Length();
- for (int32_t ruleX = 0; ruleX < numWildRules; ruleX++) {
- DR_Rule* rule = mWildRules.ElementAt(ruleX);
- if (rule && RuleMatches(*rule, aNode)) {
- aNode.mDisplay = rule->mDisplay;
- break;
- }
- }
- }
-}
-
-DR_FrameTreeNode* DR_State::CreateTreeNode(nsIFrame* aFrame,
- const ReflowInput* aReflowInput) {
- // find the frame of the parent reflow input (usually just the parent of
- // aFrame)
- nsIFrame* parentFrame;
- if (aReflowInput) {
- const ReflowInput* parentRI = aReflowInput->mParentReflowInput;
- parentFrame = (parentRI) ? parentRI->mFrame : nullptr;
- } else {
- parentFrame = aFrame->GetParent();
- }
-
- // find the parent tree node leaf
- DR_FrameTreeNode* parentNode = nullptr;
-
- DR_FrameTreeNode* lastLeaf = nullptr;
- if (mFrameTreeLeaves.Length())
- lastLeaf = mFrameTreeLeaves.ElementAt(mFrameTreeLeaves.Length() - 1);
- if (lastLeaf) {
- for (parentNode = lastLeaf;
- parentNode && (parentNode->mFrame != parentFrame);
- parentNode = parentNode->mParent) {
- }
- }
- DR_FrameTreeNode* newNode = new DR_FrameTreeNode(aFrame, parentNode);
- FindMatchingRule(*newNode);
-
- newNode->mIndent = mIndent;
- if (newNode->mDisplay || mIndentUndisplayedFrames) {
- ++mIndent;
- }
-
- if (lastLeaf && (lastLeaf == parentNode)) {
- mFrameTreeLeaves.RemoveLastElement();
- }
- mFrameTreeLeaves.AppendElement(newNode);
- mCount++;
-
- return newNode;
-}
-
-void DR_State::PrettyUC(nscoord aSize, char* aBuf, int aBufSize) {
- if (NS_UNCONSTRAINEDSIZE == aSize) {
- strcpy(aBuf, "UC");
- } else {
- if ((nscoord)0xdeadbeefU == aSize) {
- strcpy(aBuf, "deadbeef");
- } else {
- snprintf(aBuf, aBufSize, "%d", aSize);
- }
- }
-}
-
-void DR_State::PrintMargin(const char* tag, const nsMargin* aMargin) {
- if (aMargin) {
- char t[16], r[16], b[16], l[16];
- PrettyUC(aMargin->top, t, 16);
- PrettyUC(aMargin->right, r, 16);
- PrettyUC(aMargin->bottom, b, 16);
- PrettyUC(aMargin->left, l, 16);
- printf(" %s=%s,%s,%s,%s", tag, t, r, b, l);
- } else {
- // use %p here for consistency with other null-pointer printouts
- printf(" %s=%p", tag, (void*)aMargin);
- }
-}
-
-void DR_State::DeleteTreeNode(DR_FrameTreeNode& aNode) {
- mFrameTreeLeaves.RemoveElement(&aNode);
- int32_t numLeaves = mFrameTreeLeaves.Length();
- if ((0 == numLeaves) ||
- (aNode.mParent != mFrameTreeLeaves.ElementAt(numLeaves - 1))) {
- mFrameTreeLeaves.AppendElement(aNode.mParent);
- }
-
- if (aNode.mDisplay || mIndentUndisplayedFrames) {
- --mIndent;
- }
- // delete the tree node
- delete &aNode;
-}
-
-static void CheckPixelError(nscoord aSize, int32_t aPixelToTwips) {
- if (NS_UNCONSTRAINEDSIZE != aSize) {
- if ((aSize % aPixelToTwips) > 0) {
- printf("VALUE %d is not a whole pixel \n", aSize);
- }
- }
-}
-
-static void DisplayReflowEnterPrint(nsPresContext* aPresContext,
- nsIFrame* aFrame,
- const ReflowInput& aReflowInput,
- DR_FrameTreeNode& aTreeNode,
- bool aChanged) {
- if (aTreeNode.mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, aTreeNode.mIndent);
-
- char width[16];
- char height[16];
-
- DR_state->PrettyUC(aReflowInput.AvailableWidth(), width, 16);
- DR_state->PrettyUC(aReflowInput.AvailableHeight(), height, 16);
- printf("Reflow a=%s,%s ", width, height);
-
- DR_state->PrettyUC(aReflowInput.ComputedWidth(), width, 16);
- DR_state->PrettyUC(aReflowInput.ComputedHeight(), height, 16);
- printf("c=%s,%s ", width, height);
-
- if (aFrame->HasAnyStateBits(NS_FRAME_IS_DIRTY)) printf("dirty ");
-
- if (aFrame->HasAnyStateBits(NS_FRAME_HAS_DIRTY_CHILDREN))
- printf("dirty-children ");
-
- if (aReflowInput.mFlags.mSpecialBSizeReflow) printf("special-bsize ");
-
- if (aReflowInput.IsHResize()) printf("h-resize ");
-
- if (aReflowInput.IsVResize()) printf("v-resize ");
-
- nsIFrame* inFlow = aFrame->GetPrevInFlow();
- if (inFlow) {
- printf("pif=%p ", (void*)inFlow);
- }
- inFlow = aFrame->GetNextInFlow();
- if (inFlow) {
- printf("nif=%p ", (void*)inFlow);
- }
- if (aChanged)
- printf("CHANGED \n");
- else
- printf("cnt=%d \n", DR_state->mCount);
- if (DR_state->mDisplayPixelErrors) {
- int32_t d2a = aPresContext->AppUnitsPerDevPixel();
- CheckPixelError(aReflowInput.AvailableWidth(), d2a);
- CheckPixelError(aReflowInput.AvailableHeight(), d2a);
- CheckPixelError(aReflowInput.ComputedWidth(), d2a);
- CheckPixelError(aReflowInput.ComputedHeight(), d2a);
- }
- }
-}
-
-void* nsIFrame::DisplayReflowEnter(nsPresContext* aPresContext,
- nsIFrame* aFrame,
- const ReflowInput& aReflowInput) {
- if (!DR_state->mInited) DR_state->Init();
- if (!DR_state->mActive) return nullptr;
-
- NS_ASSERTION(aFrame, "invalid call");
-
- DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, &aReflowInput);
- if (treeNode) {
- DisplayReflowEnterPrint(aPresContext, aFrame, aReflowInput, *treeNode,
- false);
- }
- return treeNode;
-}
-
-void* nsIFrame::DisplayLayoutEnter(nsIFrame* aFrame) {
- if (!DR_state->mInited) DR_state->Init();
- if (!DR_state->mActive) return nullptr;
-
- NS_ASSERTION(aFrame, "invalid call");
-
- DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
- if (treeNode && treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
- printf("XULLayout\n");
- }
- return treeNode;
-}
-
-void* nsIFrame::DisplayIntrinsicISizeEnter(nsIFrame* aFrame,
- const char* aType) {
- if (!DR_state->mInited) DR_state->Init();
- if (!DR_state->mActive) return nullptr;
-
- NS_ASSERTION(aFrame, "invalid call");
-
- DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
- if (treeNode && treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
- printf("Get%sISize\n", aType);
- }
- return treeNode;
-}
-
-void* nsIFrame::DisplayIntrinsicSizeEnter(nsIFrame* aFrame, const char* aType) {
- if (!DR_state->mInited) DR_state->Init();
- if (!DR_state->mActive) return nullptr;
-
- NS_ASSERTION(aFrame, "invalid call");
-
- DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
- if (treeNode && treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
- printf("Get%sSize\n", aType);
- }
- return treeNode;
-}
-
-void nsIFrame::DisplayReflowExit(nsPresContext* aPresContext, nsIFrame* aFrame,
- ReflowOutput& aMetrics,
- const nsReflowStatus& aStatus,
- void* aFrameTreeNode) {
- if (!DR_state->mActive) return;
-
- NS_ASSERTION(aFrame, "DisplayReflowExit - invalid call");
- if (!aFrameTreeNode) return;
-
- DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
- if (treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
-
- char width[16];
- char height[16];
- char x[16];
- char y[16];
- DR_state->PrettyUC(aMetrics.Width(), width, 16);
- DR_state->PrettyUC(aMetrics.Height(), height, 16);
- printf("Reflow d=%s,%s", width, height);
-
- if (!aStatus.IsEmpty()) {
- printf(" status=%s", ToString(aStatus).c_str());
- }
- if (aFrame->HasOverflowAreas()) {
- DR_state->PrettyUC(aMetrics.InkOverflow().x, x, 16);
- DR_state->PrettyUC(aMetrics.InkOverflow().y, y, 16);
- DR_state->PrettyUC(aMetrics.InkOverflow().width, width, 16);
- DR_state->PrettyUC(aMetrics.InkOverflow().height, height, 16);
- printf(" vis-o=(%s,%s) %s x %s", x, y, width, height);
-
- nsRect storedOverflow = aFrame->InkOverflowRect();
- DR_state->PrettyUC(storedOverflow.x, x, 16);
- DR_state->PrettyUC(storedOverflow.y, y, 16);
- DR_state->PrettyUC(storedOverflow.width, width, 16);
- DR_state->PrettyUC(storedOverflow.height, height, 16);
- printf(" vis-sto=(%s,%s) %s x %s", x, y, width, height);
-
- DR_state->PrettyUC(aMetrics.ScrollableOverflow().x, x, 16);
- DR_state->PrettyUC(aMetrics.ScrollableOverflow().y, y, 16);
- DR_state->PrettyUC(aMetrics.ScrollableOverflow().width, width, 16);
- DR_state->PrettyUC(aMetrics.ScrollableOverflow().height, height, 16);
- printf(" scr-o=(%s,%s) %s x %s", x, y, width, height);
-
- storedOverflow = aFrame->ScrollableOverflowRect();
- DR_state->PrettyUC(storedOverflow.x, x, 16);
- DR_state->PrettyUC(storedOverflow.y, y, 16);
- DR_state->PrettyUC(storedOverflow.width, width, 16);
- DR_state->PrettyUC(storedOverflow.height, height, 16);
- printf(" scr-sto=(%s,%s) %s x %s", x, y, width, height);
- }
- printf("\n");
- if (DR_state->mDisplayPixelErrors) {
- int32_t d2a = aPresContext->AppUnitsPerDevPixel();
- CheckPixelError(aMetrics.Width(), d2a);
- CheckPixelError(aMetrics.Height(), d2a);
- }
- }
- DR_state->DeleteTreeNode(*treeNode);
-}
-
-void nsIFrame::DisplayLayoutExit(nsIFrame* aFrame, void* aFrameTreeNode) {
- if (!DR_state->mActive) return;
-
- NS_ASSERTION(aFrame, "non-null frame required");
- if (!aFrameTreeNode) return;
-
- DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
- if (treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
- nsRect rect = aFrame->GetRect();
- printf("XULLayout=%d,%d,%d,%d\n", rect.x, rect.y, rect.width, rect.height);
- }
- DR_state->DeleteTreeNode(*treeNode);
-}
-
-void nsIFrame::DisplayIntrinsicISizeExit(nsIFrame* aFrame, const char* aType,
- nscoord aResult,
- void* aFrameTreeNode) {
- if (!DR_state->mActive) return;
-
- NS_ASSERTION(aFrame, "non-null frame required");
- if (!aFrameTreeNode) return;
-
- DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
- if (treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
- char iSize[16];
- DR_state->PrettyUC(aResult, iSize, 16);
- printf("Get%sISize=%s\n", aType, iSize);
- }
- DR_state->DeleteTreeNode(*treeNode);
-}
-
-void nsIFrame::DisplayIntrinsicSizeExit(nsIFrame* aFrame, const char* aType,
- nsSize aResult, void* aFrameTreeNode) {
- if (!DR_state->mActive) return;
-
- NS_ASSERTION(aFrame, "non-null frame required");
- if (!aFrameTreeNode) return;
-
- DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aFrameTreeNode;
- if (treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
-
- char width[16];
- char height[16];
- DR_state->PrettyUC(aResult.width, width, 16);
- DR_state->PrettyUC(aResult.height, height, 16);
- printf("Get%sSize=%s,%s\n", aType, width, height);
- }
- DR_state->DeleteTreeNode(*treeNode);
-}
-
-/* static */
-void nsIFrame::DisplayReflowStartup() { DR_state = new DR_State(); }
-
-/* static */
-void nsIFrame::DisplayReflowShutdown() {
- delete DR_state;
- DR_state = nullptr;
-}
-
-void DR_cookie::Change() const {
- DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)mValue;
- if (treeNode && treeNode->mDisplay) {
- DisplayReflowEnterPrint(mPresContext, mFrame, mReflowInput, *treeNode,
- true);
- }
-}
-
-/* static */
-void* ReflowInput::DisplayInitConstraintsEnter(nsIFrame* aFrame,
- ReflowInput* aState,
- nscoord aContainingBlockWidth,
- nscoord aContainingBlockHeight,
- const nsMargin* aBorder,
- const nsMargin* aPadding) {
- MOZ_ASSERT(aFrame, "non-null frame required");
- MOZ_ASSERT(aState, "non-null state required");
-
- if (!DR_state->mInited) DR_state->Init();
- if (!DR_state->mActive) return nullptr;
-
- DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, aState);
- if (treeNode && treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
-
- printf("InitConstraints parent=%p", (void*)aState->mParentReflowInput);
-
- char width[16];
- char height[16];
-
- DR_state->PrettyUC(aContainingBlockWidth, width, 16);
- DR_state->PrettyUC(aContainingBlockHeight, height, 16);
- printf(" cb=%s,%s", width, height);
-
- DR_state->PrettyUC(aState->AvailableWidth(), width, 16);
- DR_state->PrettyUC(aState->AvailableHeight(), height, 16);
- printf(" as=%s,%s", width, height);
-
- DR_state->PrintMargin("b", aBorder);
- DR_state->PrintMargin("p", aPadding);
- putchar('\n');
- }
- return treeNode;
-}
-
-/* static */
-void ReflowInput::DisplayInitConstraintsExit(nsIFrame* aFrame,
- ReflowInput* aState,
- void* aValue) {
- MOZ_ASSERT(aFrame, "non-null frame required");
- MOZ_ASSERT(aState, "non-null state required");
-
- if (!DR_state->mActive) return;
- if (!aValue) return;
-
- DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
- if (treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
- char cmiw[16], cw[16], cmxw[16], cmih[16], ch[16], cmxh[16];
- DR_state->PrettyUC(aState->ComputedMinWidth(), cmiw, 16);
- DR_state->PrettyUC(aState->ComputedWidth(), cw, 16);
- DR_state->PrettyUC(aState->ComputedMaxWidth(), cmxw, 16);
- DR_state->PrettyUC(aState->ComputedMinHeight(), cmih, 16);
- DR_state->PrettyUC(aState->ComputedHeight(), ch, 16);
- DR_state->PrettyUC(aState->ComputedMaxHeight(), cmxh, 16);
- printf("InitConstraints= cw=(%s <= %s <= %s) ch=(%s <= %s <= %s)", cmiw, cw,
- cmxw, cmih, ch, cmxh);
- const nsMargin m = aState->ComputedPhysicalOffsets();
- DR_state->PrintMargin("co", &m);
- putchar('\n');
- }
- DR_state->DeleteTreeNode(*treeNode);
-}
-
-/* static */
-void* SizeComputationInput::DisplayInitOffsetsEnter(
- nsIFrame* aFrame, SizeComputationInput* aState, nscoord aPercentBasis,
- WritingMode aCBWritingMode, const nsMargin* aBorder,
- const nsMargin* aPadding) {
- MOZ_ASSERT(aFrame, "non-null frame required");
- MOZ_ASSERT(aState, "non-null state required");
-
- if (!DR_state->mInited) DR_state->Init();
- if (!DR_state->mActive) return nullptr;
-
- // aState is not necessarily a ReflowInput
- DR_FrameTreeNode* treeNode = DR_state->CreateTreeNode(aFrame, nullptr);
- if (treeNode && treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
-
- char pctBasisStr[16];
- DR_state->PrettyUC(aPercentBasis, pctBasisStr, 16);
- printf("InitOffsets pct_basis=%s", pctBasisStr);
-
- DR_state->PrintMargin("b", aBorder);
- DR_state->PrintMargin("p", aPadding);
- putchar('\n');
- }
- return treeNode;
-}
-
-/* static */
-void SizeComputationInput::DisplayInitOffsetsExit(nsIFrame* aFrame,
- SizeComputationInput* aState,
- void* aValue) {
- MOZ_ASSERT(aFrame, "non-null frame required");
- MOZ_ASSERT(aState, "non-null state required");
-
- if (!DR_state->mActive) return;
- if (!aValue) return;
-
- DR_FrameTreeNode* treeNode = (DR_FrameTreeNode*)aValue;
- if (treeNode->mDisplay) {
- DR_state->DisplayFrameTypeInfo(aFrame, treeNode->mIndent);
- printf("InitOffsets=");
- const auto m = aState->ComputedPhysicalMargin();
- DR_state->PrintMargin("m", &m);
- const auto p = aState->ComputedPhysicalPadding();
- DR_state->PrintMargin("p", &p);
- const auto bp = aState->ComputedPhysicalBorderPadding();
- DR_state->PrintMargin("b+p", &bp);
- putchar('\n');
- }
- DR_state->DeleteTreeNode(*treeNode);
-}
-
-// End Display Reflow
-
// Validation of SideIsVertical.
# define CASE(side, result) \
static_assert(SideIsVertical(side) == result, "SideIsVertical is wrong")
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index 16f3d17d64..801e80c7e0 100644
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -127,6 +127,7 @@ struct CharacterDataChangeInfo;
namespace mozilla {
enum class CaretAssociationHint;
+enum class IsFocusableFlags : uint8_t;
enum class PeekOffsetOption : uint16_t;
enum class PseudoStyleType : uint8_t;
enum class TableSelectionMode : uint32_t;
@@ -937,6 +938,8 @@ class nsIFrame : public nsQueryFrame {
already_AddRefed<ComputedStyle> ComputeHighlightSelectionStyle(
nsAtom* aHighlightName);
+ already_AddRefed<ComputedStyle> ComputeTargetTextStyle() const;
+
/**
* Accessor functions for geometric parent.
*/
@@ -1384,7 +1387,25 @@ class nsIFrame : public nsQueryFrame {
bool HasUnreflowedContainerQueryAncestor() const;
+ // Return True if this frame has a forced break value before it.
+ //
+ // Note: this method only checks 'break-before' property on *this* frame, and
+ // it doesn't handle forced break value propagation from its first child.
+ // Callers should handle the propagation in reflow.
+ bool ShouldBreakBefore(const ReflowInput::BreakType aBreakType) const;
+
+ // Return True if this frame has a forced break value after it.
+ //
+ // Note: this method only checks 'break-after' property on *this* frame, and
+ // it doesn't handle forced break value propagation from its last child.
+ // Callers should handle the propagation in reflow.
+ bool ShouldBreakAfter(const ReflowInput::BreakType aBreakType) const;
+
private:
+ bool ShouldBreakBetween(const nsStyleDisplay* aDisplay,
+ const mozilla::StyleBreakBetween aBreakBetween,
+ const ReflowInput::BreakType aBreakType) const;
+
// The value that the CSS page-name "auto" keyword resolves to for children
// of this frame.
//
@@ -1586,6 +1607,11 @@ class nsIFrame : public nsQueryFrame {
bool GetShapeBoxBorderRadii(nscoord aRadii[8]) const;
/**
+ * Returns one em unit, adjusted for font inflation if needed, in app units.
+ */
+ nscoord OneEmInAppUnits() const;
+
+ /**
* `GetNaturalBaselineBOffset`, but determines the baseline sharing group
* through `GetDefaultBaselineSharingGroup` (If not specified), assuming line
* layout context, and never fails, returning a synthesized baseline through
@@ -3932,6 +3958,9 @@ class nsIFrame : public nsQueryFrame {
public:
// given a frame five me the first/last leaf available
// XXX Robert O'Callahan wants to move these elsewhere
+ // FIXME: Only GetLastLeaf() never returns a leaf frame in native anonymous
+ // subtrees under aFrame. However, GetFirstLeaf() may return a leaf frame
+ // in a native anonymous subtree.
static void GetLastLeaf(nsIFrame** aFrame);
static void GetFirstLeaf(nsIFrame** aFrame);
@@ -4359,13 +4388,10 @@ class nsIFrame : public nsQueryFrame {
* Also, depending on the pref accessibility.tabfocus some widgets may be
* focusable but removed from the tab order. This is the default on
* Mac OS X, where fewer items are focusable.
- * @param [in, optional] aWithMouse, is this focus query for mouse clicking
- * @param [in, optional] aCheckVisibility, whether to treat an invisible
- * frame as not focusable
* @return whether the frame is focusable via mouse, kbd or script.
*/
- [[nodiscard]] Focusable IsFocusable(bool aWithMouse = false,
- bool aCheckVisibility = true);
+ [[nodiscard]] Focusable IsFocusable(
+ mozilla::IsFocusableFlags = mozilla::IsFocusableFlags(0));
protected:
// Helper for IsFocusable.
@@ -5482,25 +5508,6 @@ class nsIFrame : public nsQueryFrame {
// NS_FRAME_IS_DIRTY bit set
static void VerifyDirtyBitSet(const nsFrameList& aFrameList);
- // Display Reflow Debugging
- static void* DisplayReflowEnter(nsPresContext* aPresContext, nsIFrame* aFrame,
- const ReflowInput& aReflowInput);
- static void* DisplayLayoutEnter(nsIFrame* aFrame);
- static void* DisplayIntrinsicISizeEnter(nsIFrame* aFrame, const char* aType);
- static void* DisplayIntrinsicSizeEnter(nsIFrame* aFrame, const char* aType);
- static void DisplayReflowExit(nsPresContext* aPresContext, nsIFrame* aFrame,
- ReflowOutput& aMetrics,
- const nsReflowStatus& aStatus,
- void* aFrameTreeNode);
- static void DisplayLayoutExit(nsIFrame* aFrame, void* aFrameTreeNode);
- static void DisplayIntrinsicISizeExit(nsIFrame* aFrame, const char* aType,
- nscoord aResult, void* aFrameTreeNode);
- static void DisplayIntrinsicSizeExit(nsIFrame* aFrame, const char* aType,
- nsSize aResult, void* aFrameTreeNode);
-
- static void DisplayReflowStartup();
- static void DisplayReflowShutdown();
-
static mozilla::LazyLogModule sFrameLogModule;
#endif
};
diff --git a/layout/generic/nsIFrameInlines.h b/layout/generic/nsIFrameInlines.h
index e187f0dfb0..f53ba607c0 100644
--- a/layout/generic/nsIFrameInlines.h
+++ b/layout/generic/nsIFrameInlines.h
@@ -36,7 +36,7 @@ bool nsIFrame::IsFlexOrGridItem() const {
bool nsIFrame::IsMasonry(mozilla::LogicalAxis aAxis) const {
MOZ_DIAGNOSTIC_ASSERT(IsGridContainerFrame());
- return HasAnyStateBits(aAxis == mozilla::eLogicalAxisBlock
+ return HasAnyStateBits(aAxis == mozilla::LogicalAxis::Block
? NS_STATE_GRID_IS_ROW_MASONRY
: NS_STATE_GRID_IS_COL_MASONRY);
}
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index c1e69df6c9..c330f1ce6b 100644
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -645,8 +645,9 @@ const StyleImage* nsImageFrame::GetImageFromStyle() const {
nonAnonymousParent->GetContent());
styleContent = nonAnonymousParent->StyleContent();
}
- MOZ_RELEASE_ASSERT(contentIndex < styleContent->ContentCount());
- auto& contentItem = styleContent->ContentAt(contentIndex);
+ auto items = styleContent->NonAltContentItems();
+ MOZ_RELEASE_ASSERT(contentIndex < items.Length());
+ const auto& contentItem = items[contentIndex];
MOZ_RELEASE_ASSERT(contentItem.IsImage());
return &contentItem.AsImage();
}
@@ -1055,11 +1056,8 @@ bool nsImageFrame::ShouldCreateImageFrameForContentProperty(
if (aElement.IsRootOfNativeAnonymousSubtree()) {
return false;
}
- const auto& content = aStyle.StyleContent()->mContent;
- if (!content.IsItems()) {
- return false;
- }
- Span<const StyleContentItem> items = content.AsItems().AsSpan();
+ Span<const StyleContentItem> items =
+ aStyle.StyleContent()->NonAltContentItems();
return items.Length() == 1 && items[0].IsImage();
}
@@ -1476,8 +1474,6 @@ nscoord nsImageFrame::GetContinuationOffset() const {
nscoord nsImageFrame::GetMinISize(gfxContext* aRenderingContext) {
// XXX The caller doesn't account for constraints of the block-size,
// min-block-size, and max-block-size properties.
- DebugOnly<nscoord> result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
EnsureIntrinsicSizeAndRatio();
const auto& iSize = GetWritingMode().IsVertical() ? mIntrinsicSize.height
: mIntrinsicSize.width;
@@ -1487,8 +1483,6 @@ nscoord nsImageFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord nsImageFrame::GetPrefISize(gfxContext* aRenderingContext) {
// XXX The caller doesn't account for constraints of the block-size,
// min-block-size, and max-block-size properties.
- DebugOnly<nscoord> result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
EnsureIntrinsicSizeAndRatio();
const auto& iSize = GetWritingMode().IsVertical() ? mIntrinsicSize.height
: mIntrinsicSize.width;
@@ -1526,7 +1520,6 @@ void nsImageFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsImageFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE(
NS_FRAME_TRACE_CALLS,
@@ -2862,10 +2855,10 @@ LogicalSides nsImageFrame::GetLogicalSkipSides() const {
return skip;
}
if (GetPrevInFlow()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
if (GetNextInFlow()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
return skip;
}
diff --git a/layout/generic/nsInlineFrame.cpp b/layout/generic/nsInlineFrame.cpp
index 7a99ecbe5d..44fce51931 100644
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -270,7 +270,6 @@ void nsInlineFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsInlineFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
if (!aReflowInput.mLineLayout) {
@@ -798,7 +797,7 @@ LogicalSides nsInlineFrame::GetLogicalSkipSides() const {
(prev && (prev->mRect.height || prev->mRect.width))) {
// Prev continuation is not empty therefore we don't render our start
// border edge.
- skip |= eLogicalSideBitsIStart;
+ skip += LogicalSide::IStart;
} else {
// If the prev continuation is empty, then go ahead and let our start
// edge border render.
@@ -810,7 +809,7 @@ LogicalSides nsInlineFrame::GetLogicalSkipSides() const {
(next && (next->mRect.height || next->mRect.width))) {
// Next continuation is not empty therefore we don't render our end
// border edge.
- skip |= eLogicalSideBitsIEnd;
+ skip += LogicalSide::IEnd;
} else {
// If the next continuation is empty, then go ahead and let our end
// edge border render.
@@ -823,15 +822,15 @@ LogicalSides nsInlineFrame::GetLogicalSkipSides() const {
// a split should skip the "start" side. But figuring out which part of
// the split we are involves getting our first continuation, which might be
// expensive. So don't bother if we already have the relevant bits set.
- if (skip != LogicalSides(mWritingMode, eLogicalSideBitsIBoth)) {
+ if (skip != LogicalSides(mWritingMode, LogicalSides::IBoth)) {
// We're missing one of the skip bits, so check whether we need to set it.
// Only get the first continuation once, as an optimization.
nsIFrame* firstContinuation = FirstContinuation();
if (firstContinuation->FrameIsNonLastInIBSplit()) {
- skip |= eLogicalSideBitsIEnd;
+ skip += LogicalSide::IEnd;
}
if (firstContinuation->FrameIsNonFirstInIBSplit()) {
- skip |= eLogicalSideBitsIStart;
+ skip += LogicalSide::IStart;
}
}
}
diff --git a/layout/generic/nsLeafFrame.cpp b/layout/generic/nsLeafFrame.cpp
index 2688da3d4b..6125f6b800 100644
--- a/layout/generic/nsLeafFrame.cpp
+++ b/layout/generic/nsLeafFrame.cpp
@@ -24,18 +24,12 @@ void nsLeafFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
/* virtual */
nscoord nsLeafFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
- result = GetIntrinsicISize();
- return result;
+ return GetIntrinsicISize();
}
/* virtual */
nscoord nsLeafFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
- result = GetIntrinsicISize();
- return result;
+ return GetIntrinsicISize();
}
/* virtual */
diff --git a/layout/generic/nsLineBox.cpp b/layout/generic/nsLineBox.cpp
index 18051aa69a..53a6914030 100644
--- a/layout/generic/nsLineBox.cpp
+++ b/layout/generic/nsLineBox.cpp
@@ -217,7 +217,7 @@ void nsLineBox::List(FILE* out, const char* aPrefix,
IsPreviousMarginDirty() ? "prevmargindirty" : "prevmarginclean",
IsImpactedByFloat() ? "impacted" : "not-impacted",
IsLineWrapped() ? "wrapped" : "not-wrapped",
- HasForcedLineBreak() ? "forced-break" : "no-break",
+ HasForcedLineBreakAfter() ? "forced-break-after" : "no-break",
StyleClearToString(FloatClearTypeBefore()),
StyleClearToString(FloatClearTypeAfter()));
diff --git a/layout/generic/nsLineBox.h b/layout/generic/nsLineBox.h
index d46cf9604a..e35f36a481 100644
--- a/layout/generic/nsLineBox.h
+++ b/layout/generic/nsLineBox.h
@@ -238,42 +238,40 @@ class nsLineBox final : public nsLineLink {
}
}
- // mHasForcedLineBreak bit & mFloatClearType value
- // Break information is applied *before* the line if the line is a block,
- // or *after* the line if the line is an inline.
- bool HasForcedLineBreak() const { return mFlags.mHasForcedLineBreak; }
+ // mHasForcedLineBreakAfter bit & mFloatClearType value
void ClearForcedLineBreak() {
- mFlags.mHasForcedLineBreak = false;
+ mFlags.mHasForcedLineBreakAfter = false;
mFlags.mFloatClearType = mozilla::StyleClear::None;
}
- bool HasForcedLineBreakBefore() const {
- return IsBlock() && HasForcedLineBreak();
+ bool HasFloatClearTypeBefore() const {
+ return FloatClearTypeBefore() != mozilla::StyleClear::None;
}
- void SetForcedLineBreakBefore(mozilla::StyleClear aClearType) {
- MOZ_ASSERT(IsBlock(), "Only blocks have break-before");
+ void SetFloatClearTypeBefore(mozilla::StyleClear aClearType) {
+ MOZ_ASSERT(IsBlock(), "Only block lines have break-before status!");
MOZ_ASSERT(aClearType != mozilla::StyleClear::None,
"Only StyleClear:Left/Right/Both are allowed before a line");
- mFlags.mHasForcedLineBreak = true;
mFlags.mFloatClearType = aClearType;
}
mozilla::StyleClear FloatClearTypeBefore() const {
- return IsBlock() ? FloatClearType() : mozilla::StyleClear::None;
+ return IsBlock() ? mFlags.mFloatClearType : mozilla::StyleClear::None;
}
bool HasForcedLineBreakAfter() const {
- return IsInline() && HasForcedLineBreak();
+ MOZ_ASSERT(IsInline() || !mFlags.mHasForcedLineBreakAfter,
+ "A block line shouldn't set mHasForcedLineBreakAfter bit!");
+ return IsInline() && mFlags.mHasForcedLineBreakAfter;
}
void SetForcedLineBreakAfter(mozilla::StyleClear aClearType) {
- MOZ_ASSERT(IsInline(), "Only inlines have break-after");
- mFlags.mHasForcedLineBreak = true;
+ MOZ_ASSERT(IsInline(), "Only inline lines have break-after status!");
+ mFlags.mHasForcedLineBreakAfter = true;
mFlags.mFloatClearType = aClearType;
}
bool HasFloatClearTypeAfter() const {
- return IsInline() && FloatClearType() != mozilla::StyleClear::None;
+ return FloatClearTypeAfter() != mozilla::StyleClear::None;
}
mozilla::StyleClear FloatClearTypeAfter() const {
- return IsInline() ? FloatClearType() : mozilla::StyleClear::None;
+ return IsInline() ? mFlags.mFloatClearType : mozilla::StyleClear::None;
}
// mCarriedOutBEndMargin value
@@ -316,7 +314,7 @@ class nsLineBox final : public nsLineLink {
nsRect InkOverflowRect() const {
return GetOverflowArea(mozilla::OverflowType::Ink);
}
- nsRect ScrollableOverflowRect() {
+ nsRect ScrollableOverflowRect() const {
return GetOverflowArea(mozilla::OverflowType::Scrollable);
}
@@ -520,11 +518,15 @@ class nsLineBox final : public nsLineLink {
// Has this line moved to a different fragment of the block since
// the last time it was reflowed?
bool mMovedFragments : 1;
- // mHasForcedLineBreak indicates that this line has either a break-before or
- // a break-after.
- bool mHasForcedLineBreak : 1;
- // mFloatClearType indicates that there's a float clearance before or after
- // this line.
+ // mHasForcedLineBreakAfter indicates that this *inline* line has a
+ // break-after status due to a float clearance or ending with <br>. A block
+ // line shouldn't set this bit.
+ //
+ // Note: This bit is unrelated to CSS break-after property because it is all
+ // about line break-after for inline-level boxes.
+ bool mHasForcedLineBreakAfter : 1;
+ // mFloatClearType indicates that there's a float clearance before a block
+ // line, or after an inline line.
mozilla::StyleClear mFloatClearType;
};
@@ -570,8 +572,6 @@ class nsLineBox final : public nsLineLink {
FlagBits mFlags;
};
- mozilla::StyleClear FloatClearType() const { return mFlags.mFloatClearType; };
-
union {
ExtraData* mData;
ExtraBlockData* mBlockData;
diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp
index ab6924faa4..a452568f57 100644
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -396,8 +396,10 @@ nsLineLayout::PerSpanData* nsLineLayout::NewPerSpanData() {
psd->mFrame = nullptr;
psd->mFirstFrame = nullptr;
psd->mLastFrame = nullptr;
+ psd->mReflowInput = nullptr;
psd->mContainsFloat = false;
psd->mHasNonemptyContent = false;
+ psd->mBaseline = nullptr;
#ifdef DEBUG
outerLineLayout->mSpansAllocated++;
@@ -1713,10 +1715,10 @@ void nsLineLayout::AdjustLeadings(nsIFrame* spanFrame, PerSpanData* psd,
if (aStyleText->HasEffectiveTextEmphasis()) {
nscoord bsize = GetBSizeOfEmphasisMarks(spanFrame, aInflation);
LogicalSide side = aStyleText->TextEmphasisSide(mRootSpan->mWritingMode);
- if (side == eLogicalSideBStart) {
+ if (side == LogicalSide::BStart) {
requiredStartLeading += bsize;
} else {
- MOZ_ASSERT(side == eLogicalSideBEnd,
+ MOZ_ASSERT(side == LogicalSide::BEnd,
"emphasis marks must be in block axis");
requiredEndLeading += bsize;
}
@@ -2341,7 +2343,7 @@ void nsLineLayout::VerticalAlignFrames(PerSpanData* psd) {
delta = emphasisHeight;
}
LogicalSide side = mStyleText->TextEmphasisSide(lineWM);
- if (side == eLogicalSideBStart) {
+ if (side == LogicalSide::BStart) {
blockStart -= delta;
} else {
blockEnd += delta;
diff --git a/layout/generic/nsPageContentFrame.cpp b/layout/generic/nsPageContentFrame.cpp
index 11e634894d..1c82ca1523 100644
--- a/layout/generic/nsPageContentFrame.cpp
+++ b/layout/generic/nsPageContentFrame.cpp
@@ -35,7 +35,6 @@ void nsPageContentFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsPageContentFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
MOZ_ASSERT(mPD, "Need a pointer to nsSharedPageData before reflow starts");
diff --git a/layout/generic/nsPageFrame.cpp b/layout/generic/nsPageFrame.cpp
index fb9cfa2e81..de573962af 100644
--- a/layout/generic/nsPageFrame.cpp
+++ b/layout/generic/nsPageFrame.cpp
@@ -9,6 +9,7 @@
#include "mozilla/AppUnits.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_layout.h"
+#include "mozilla/StaticPrefs_print.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/intl/Segmenter.h"
#include "gfxContext.h"
@@ -213,7 +214,6 @@ void nsPageFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsPageFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
MOZ_ASSERT(mPD, "Need a pointer to nsSharedPageData before reflow starts");
@@ -540,6 +540,69 @@ static std::tuple<uint32_t, uint32_t> GetRowAndColFromIdx(uint32_t aIdxOnSheet,
return {aIdxOnSheet / aNumCols, aIdxOnSheet % aNumCols};
}
+// The minimum ratio for which we will center the page on the sheet when using
+// auto-detect logic.
+// Note that this ratio is of the content's size to the sheet size scaled to be
+// in content space, and so the actual ratio will always be from 0.0 to 1.0,
+// with this marking the smallest ratio we consider a near-miss.
+// The ratio of A4 on Letter is 0.915034. A threshold of 0.9 will ensure that
+// A4 on Letter works, as well as other near-misses.
+//
+// The ratio is computed as so:
+// scale = min(1, sheetHeight / pageHeight, sheetWidth / pageWidth)
+//
+// Where pageSize is pageWidth or pageHeight, and sheetSize is sheetWidth or
+// sheetHeight, respectively:
+// scaledPageSize = pageSize * scale
+// ratio = scaledPageSize / sheetSize
+//
+// A4 (210mm x 297mm) on US Letter (215.9mm x 279.4mm) is derived as so:
+// scale = min(1, 215.9 / 210, 279.4 / 297) = 0.9407407407..
+//
+// Using the widths:
+// scaledPageSize = (210 * 0.940741) = 197.556
+// ratio = 197.556 / 215.9 = 0.915034
+//
+// See nsPageFrame::ComputeSinglePPSPageSizeScale for scale calculation, and
+// OffsetToCenterPage for ratio calculation.
+constexpr float kCenterPageRatioThreshold = 0.9f;
+
+// Numeric values for the pref "print.center_page_on_sheet"
+enum {
+ kPrintCenterPageOnSheetNever = 0,
+ kPrintCenterPageOnSheetAlways = 1,
+ kPrintCenterPageOnSheetAuto = 2
+};
+
+// Returns an offset to center the page on the sheet, with a given scale.
+// When no centering can/should happen, this will avoid extra calculations and
+// return 0.0f.
+// This takes into account the value of the pref "print.center_page_on_sheet".
+static float OffsetToCenterPage(nscoord aContentSize, nscoord aSheetSize,
+ float aScale, float aAppUnitsPerPixel) {
+ MOZ_ASSERT(aScale <= 1.0f && aScale > 0.0f,
+ "Scale must be in the range (0,1]");
+ const unsigned centerPagePref = StaticPrefs::print_center_page_on_sheet();
+ if (centerPagePref == kPrintCenterPageOnSheetNever) {
+ return 0.0f;
+ }
+
+ // Determine the ratio of scaled page to the sheet size.
+ const float sheetSize =
+ NSAppUnitsToFloatPixels(aSheetSize, aAppUnitsPerPixel);
+ const float scaledContentSize =
+ NSAppUnitsToFloatPixels(aContentSize, aAppUnitsPerPixel) * aScale;
+ const float ratio = scaledContentSize / sheetSize;
+
+ // If the ratio is within the threshold, or the pref indicates we should
+ // always center the page, return half the difference to form the offset.
+ if (centerPagePref == kPrintCenterPageOnSheetAlways ||
+ ratio >= kCenterPageRatioThreshold) {
+ return (sheetSize - scaledContentSize) * 0.5f;
+ }
+ return 0.0f;
+}
+
// Helper for BuildDisplayList:
static gfx::Matrix4x4 ComputePagesPerSheetAndPageSizeTransform(
const nsIFrame* aFrame, float aAppUnitsPerPixel) {
@@ -561,8 +624,8 @@ static gfx::Matrix4x4 ComputePagesPerSheetAndPageSizeTransform(
gfx::Matrix4x4 transform;
if (ppsInfo->mNumPages == 1) {
+ const nsSize sheetSize = sheetFrame->GetSizeForChildren();
if (rotation != 0.0) {
- const nsSize sheetSize = sheetFrame->GetSizeForChildren();
const bool sheetIsPortrait = sheetSize.width < sheetSize.height;
const bool rotatingClockwise = rotation > 0.0;
@@ -584,7 +647,21 @@ static gfx::Matrix4x4 ComputePagesPerSheetAndPageSizeTransform(
NSAppUnitsToFloatPixels(-y, aAppUnitsPerPixel), 0);
}
- float scale = pageFrame->ComputeSinglePPSPageSizeScale(contentPageSize);
+ // If the difference in horizontal size, after scaling, is relatively small
+ // then center the page on the sheet.
+ const float scale =
+ pageFrame->ComputeSinglePPSPageSizeScale(contentPageSize);
+ const float centeringOffset = OffsetToCenterPage(
+ contentPageSize.width, sheetSize.width, scale, aAppUnitsPerPixel);
+
+ // Only bother with the translation if it is at least one pixel.
+ // It's possible for a mismatch in the paper size reported by the print
+ // server and the paper size from Gecko to lead to small offsets, or
+ // even (in combination with floating point error) a very small negative
+ // offset. Do not apply an offset in those cases.
+ if (centeringOffset >= 1.0f) {
+ transform.PreTranslate(centeringOffset, 0, 0);
+ }
transform.PreScale(scale, scale, 1);
return transform;
}
@@ -937,7 +1014,6 @@ void nsPageBreakFrame::Reflow(nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
DO_GLOBAL_REFLOW_COUNT("nsPageBreakFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// Override reflow, since we don't want to deal with what our
diff --git a/layout/generic/nsPageSequenceFrame.cpp b/layout/generic/nsPageSequenceFrame.cpp
index a3348433cb..cd3c2cd6a5 100644
--- a/layout/generic/nsPageSequenceFrame.cpp
+++ b/layout/generic/nsPageSequenceFrame.cpp
@@ -266,7 +266,6 @@ void nsPageSequenceFrame::Reflow(nsPresContext* aPresContext,
MOZ_ASSERT(aPresContext->IsRootPaginatedDocument(),
"A Page Sequence is only for real pages");
DO_GLOBAL_REFLOW_COUNT("nsPageSequenceFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aReflowOutput, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE_REFLOW_IN("nsPageSequenceFrame::Reflow");
diff --git a/layout/generic/nsPlaceholderFrame.cpp b/layout/generic/nsPlaceholderFrame.cpp
index f6b4d53193..aad2c816e5 100644
--- a/layout/generic/nsPlaceholderFrame.cpp
+++ b/layout/generic/nsPlaceholderFrame.cpp
@@ -124,7 +124,6 @@ void nsPlaceholderFrame::Reflow(nsPresContext* aPresContext,
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsPlaceholderFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
aDesiredSize.ClearSize();
}
diff --git a/layout/generic/nsRubyBaseContainerFrame.cpp b/layout/generic/nsRubyBaseContainerFrame.cpp
index 6e29152bc9..50b08b6f5b 100644
--- a/layout/generic/nsRubyBaseContainerFrame.cpp
+++ b/layout/generic/nsRubyBaseContainerFrame.cpp
@@ -275,7 +275,6 @@ void nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsRubyBaseContainerFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
if (!aReflowInput.mLineLayout) {
diff --git a/layout/generic/nsRubyFrame.cpp b/layout/generic/nsRubyFrame.cpp
index d7da5bc321..fc74ce8184 100644
--- a/layout/generic/nsRubyFrame.cpp
+++ b/layout/generic/nsRubyFrame.cpp
@@ -94,7 +94,6 @@ void nsRubyFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsRubyFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
if (!aReflowInput.mLineLayout) {
@@ -301,25 +300,25 @@ void nsRubyFrame::ReflowSegment(nsPresContext* aPresContext,
Maybe<LineRelativeDir> lineSide;
switch (textContainer->StyleText()->mRubyPosition) {
case StyleRubyPosition::Over:
- lineSide.emplace(eLineRelativeDirOver);
+ lineSide.emplace(LineRelativeDir::Over);
break;
case StyleRubyPosition::Under:
- lineSide.emplace(eLineRelativeDirUnder);
+ lineSide.emplace(LineRelativeDir::Under);
break;
case StyleRubyPosition::AlternateOver:
if (lastLineSide.isSome() &&
- lastLineSide.value() == eLineRelativeDirOver) {
- lineSide.emplace(eLineRelativeDirUnder);
+ lastLineSide.value() == LineRelativeDir::Over) {
+ lineSide.emplace(LineRelativeDir::Under);
} else {
- lineSide.emplace(eLineRelativeDirOver);
+ lineSide.emplace(LineRelativeDir::Over);
}
break;
case StyleRubyPosition::AlternateUnder:
if (lastLineSide.isSome() &&
- lastLineSide.value() == eLineRelativeDirUnder) {
- lineSide.emplace(eLineRelativeDirOver);
+ lastLineSide.value() == LineRelativeDir::Under) {
+ lineSide.emplace(LineRelativeDir::Over);
} else {
- lineSide.emplace(eLineRelativeDirUnder);
+ lineSide.emplace(LineRelativeDir::Under);
}
break;
default:
@@ -334,7 +333,7 @@ void nsRubyFrame::ReflowSegment(nsPresContext* aPresContext,
lineWM.LogicalSideForLineRelativeDir(lineSide.value());
if (StaticPrefs::layout_css_ruby_intercharacter_enabled() &&
rtcWM.IsVerticalRL() &&
- lineWM.GetInlineDir() == WritingMode::eInlineLTR) {
+ lineWM.GetInlineDir() == WritingMode::InlineDir::LTR) {
// Inter-character ruby annotations are only supported for vertical-rl
// in ltr horizontal writing. Fall back to non-inter-character behavior
// otherwise.
@@ -345,11 +344,11 @@ void nsRubyFrame::ReflowSegment(nsPresContext* aPresContext,
: 0);
position = offsetRect.Origin(lineWM) + offset;
aReflowInput.mLineLayout->AdvanceICoord(size.ISize(lineWM));
- } else if (logicalSide == eLogicalSideBStart) {
+ } else if (logicalSide == LogicalSide::BStart) {
offsetRect.BStart(lineWM) -= size.BSize(lineWM);
offsetRect.BSize(lineWM) += size.BSize(lineWM);
position = offsetRect.Origin(lineWM);
- } else if (logicalSide == eLogicalSideBEnd) {
+ } else if (logicalSide == LogicalSide::BEnd) {
position = offsetRect.Origin(lineWM) +
LogicalPoint(lineWM, 0, offsetRect.BSize(lineWM));
offsetRect.BSize(lineWM) += size.BSize(lineWM);
diff --git a/layout/generic/nsRubyTextContainerFrame.cpp b/layout/generic/nsRubyTextContainerFrame.cpp
index 855d7c1825..8494b36a28 100644
--- a/layout/generic/nsRubyTextContainerFrame.cpp
+++ b/layout/generic/nsRubyTextContainerFrame.cpp
@@ -105,7 +105,6 @@ void nsRubyTextContainerFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsRubyTextContainerFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// Although a ruby text container may have continuations, returning
diff --git a/layout/generic/nsSplittableFrame.cpp b/layout/generic/nsSplittableFrame.cpp
index 4054e45f8c..abc3b5bf6e 100644
--- a/layout/generic/nsSplittableFrame.cpp
+++ b/layout/generic/nsSplittableFrame.cpp
@@ -316,7 +316,7 @@ LogicalSides nsSplittableFrame::GetBlockLevelLogicalSkipSides(
bool aAfterReflow) const {
LogicalSides skip(mWritingMode);
if (MOZ_UNLIKELY(IsTrueOverflowContainer())) {
- skip |= eLogicalSideBitsBBoth;
+ skip += LogicalSides(mWritingMode, LogicalSides::BBoth);
return skip;
}
@@ -326,19 +326,19 @@ LogicalSides nsSplittableFrame::GetBlockLevelLogicalSkipSides(
}
if (GetPrevContinuation()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
// Always skip block-end side if we have a *later* sibling across column-span
// split.
if (HasColumnSpanSiblings()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
if (aAfterReflow) {
nsIFrame* nif = GetNextContinuation();
if (nif && !nif->IsTrueOverflowContainer()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
}
diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp
index bfbd7763a9..731d31a16f 100644
--- a/layout/generic/nsSubDocumentFrame.cpp
+++ b/layout/generic/nsSubDocumentFrame.cpp
@@ -322,30 +322,29 @@ void nsSubDocumentFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
return;
}
- nsFrameLoader* frameLoader = FrameLoader();
- bool isRemoteFrame = frameLoader && frameLoader->IsRemoteFrame();
-
- // If we are pointer-events:none then we don't need to HitTest background
const bool pointerEventsNone =
Style()->PointerEvents() == StylePointerEvents::None;
- if (!aBuilder->IsForEventDelivery() || !pointerEventsNone) {
- nsDisplayListCollection decorations(aBuilder);
- DisplayBorderBackgroundOutline(aBuilder, decorations);
- if (isRemoteFrame) {
- // Wrap background colors of <iframe>s with remote subdocuments in their
- // own layer so we generate a ColorLayer. This is helpful for optimizing
- // compositing; we can skip compositing the ColorLayer when the
- // remote content is opaque.
- WrapBackgroundColorInOwnLayer(aBuilder, this,
- decorations.BorderBackground());
- }
- decorations.MoveTo(aLists);
- }
-
if (aBuilder->IsForEventDelivery() && pointerEventsNone) {
+ // If we are pointer-events:none then we don't need to HitTest background or
+ // anything else.
return;
}
+ nsFrameLoader* frameLoader = FrameLoader();
+ const bool isRemoteFrame = frameLoader && frameLoader->IsRemoteFrame();
+
+ nsDisplayListCollection decorations(aBuilder);
+ DisplayBorderBackgroundOutline(aBuilder, decorations);
+ if (isRemoteFrame) {
+ // Wrap background colors of <iframe>s with remote subdocuments in their
+ // own layer so we generate a ColorLayer. This is helpful for optimizing
+ // compositing; we can skip compositing the ColorLayer when the
+ // remote content is opaque.
+ WrapBackgroundColorInOwnLayer(aBuilder, this,
+ decorations.BorderBackground());
+ }
+ decorations.MoveTo(aLists);
+
if (HidesContent()) {
return;
}
@@ -554,39 +553,18 @@ nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const {
/* virtual */
nscoord nsSubDocumentFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
-
- nsCOMPtr<nsIObjectLoadingContent> iolc = do_QueryInterface(mContent);
- auto olc = static_cast<nsObjectLoadingContent*>(iolc.get());
-
- if (olc && olc->GetSubdocumentIntrinsicSize()) {
- // The subdocument is an SVG document, so technically we should call
- // SVGOuterSVGFrame::GetMinISize() on its root frame. That method always
- // returns 0, though, so we can just do that & don't need to bother with
- // the cross-doc communication.
- result = 0;
- } else {
- result = GetIntrinsicISize();
- }
-
- return result;
+ return GetIntrinsicISize();
}
/* virtual */
nscoord nsSubDocumentFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
-
// If the subdocument is an SVG document, then in theory we want to return
// the same thing that SVGOuterSVGFrame::GetPrefISize does. That method
// has some special handling of percentage values to avoid unhelpful zero
// sizing in the presence of orthogonal writing modes. We don't bother
// with that for SVG documents in <embed> and <object>, since that special
// handling doesn't look up across document boundaries anyway.
- result = GetIntrinsicISize();
-
- return result;
+ return GetIntrinsicISize();
}
/* virtual */
@@ -676,7 +654,6 @@ void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsSubDocumentFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE(
NS_FRAME_TRACE_CALLS,
@@ -713,7 +690,7 @@ void nsSubDocumentFrame::Reflow(nsPresContext* aPresContext,
nsViewManager* vm = mInnerView->GetViewManager();
vm->MoveViewTo(mInnerView, destRect.x, destRect.y);
- vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()), true);
+ vm->ResizeView(mInnerView, nsRect(nsPoint(0, 0), destRect.Size()));
}
aDesiredSize.SetOverflowAreasToDesiredBounds();
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index 9afefc5c28..0ad527e842 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -1929,8 +1929,8 @@ bool BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1,
// Map inline-end and inline-start to physical sides for checking presence
// of non-zero margin/border/padding.
- Side side1 = wm.PhysicalSide(eLogicalSideIEnd);
- Side side2 = wm.PhysicalSide(eLogicalSideIStart);
+ Side side1 = wm.PhysicalSide(LogicalSide::IEnd);
+ Side side2 = wm.PhysicalSide(LogicalSide::IStart);
// If the frames have an embedding level that is opposite to the writing
// mode, we need to swap which sides we're checking.
if (aFrame1->GetEmbeddingLevel().IsRTL() == wm.IsBidiLTR()) {
@@ -3611,6 +3611,20 @@ void nsTextFrame::PropertyProvider::GetSpacing(Range aRange,
!(mTextRun->GetFlags2() & nsTextFrameUtils::Flags::HasTab));
}
+static bool CanAddSpacingBefore(const gfxTextRun* aTextRun, uint32_t aOffset,
+ bool aNewlineIsSignificant) {
+ const auto* g = aTextRun->GetCharacterGlyphs();
+ MOZ_ASSERT(aOffset < aTextRun->GetLength());
+ if (aNewlineIsSignificant && g[aOffset].CharIsNewline()) {
+ return false;
+ }
+ if (!aOffset) {
+ return true;
+ }
+ return g[aOffset].IsClusterStart() && g[aOffset].IsLigatureGroupStart() &&
+ !g[aOffset - 1].CharIsFormattingControl() && !g[aOffset].CharIsTab();
+}
+
static bool CanAddSpacingAfter(const gfxTextRun* aTextRun, uint32_t aOffset,
bool aNewlineIsSignificant) {
const auto* g = aTextRun->GetCharacterGlyphs();
@@ -3683,14 +3697,45 @@ void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange,
nsSkipCharsRunIterator run(
start, nsSkipCharsRunIterator::LENGTH_UNSKIPPED_ONLY, aRange.Length());
bool newlineIsSignificant = mTextStyle->NewlineIsSignificant(mFrame);
+ // Which letter-spacing model are we using?
+ // 0 - Gecko legacy model, spacing added to trailing side of letter
+ // 1 - WebKit/Blink-compatible, spacing added to right-hand side
+ // 2 - Symmetrical spacing, half added to each side
+ gfxFloat before, after;
+ switch (StaticPrefs::layout_css_letter_spacing_model()) {
+ default: // use Gecko legacy behavior if pref value is unknown
+ case 0:
+ before = 0.0;
+ after = mLetterSpacing;
+ break;
+ case 1:
+ if (mTextRun->IsRightToLeft()) {
+ before = mLetterSpacing;
+ after = 0.0;
+ } else {
+ before = 0.0;
+ after = mLetterSpacing;
+ }
+ break;
+ case 2:
+ before = mLetterSpacing / 2.0;
+ after = mLetterSpacing - before;
+ break;
+ }
while (run.NextRun()) {
uint32_t runOffsetInSubstring = run.GetSkippedOffset() - aRange.start;
gfxSkipCharsIterator iter = run.GetPos();
for (int32_t i = 0; i < run.GetRunLength(); ++i) {
- if (CanAddSpacingAfter(mTextRun, run.GetSkippedOffset() + i,
+ if (before != 0.0 &&
+ CanAddSpacingBefore(mTextRun, run.GetSkippedOffset() + i,
+ newlineIsSignificant)) {
+ aSpacing[runOffsetInSubstring + i].mBefore += before;
+ }
+ if (after != 0.0 &&
+ CanAddSpacingAfter(mTextRun, run.GetSkippedOffset() + i,
newlineIsSignificant)) {
// End of a cluster, not in a ligature: put letter-spacing after it
- aSpacing[runOffsetInSubstring + i].mAfter += mLetterSpacing;
+ aSpacing[runOffsetInSubstring + i].mAfter += after;
}
if (IsCSSWordSpacingSpace(mFrag, i + run.GetOriginalOffset(), mFrame,
mTextStyle)) {
@@ -5050,25 +5095,25 @@ nsRect nsTextFrame::UpdateTextEmphasis(WritingMode aWM,
: do_AddRef(aProvider.GetFontMetrics());
// When the writing mode is vertical-lr the line is inverted, and thus
// the ascent and descent are swapped.
- nscoord absOffset = (side == eLogicalSideBStart) != aWM.IsLineInverted()
+ nscoord absOffset = (side == LogicalSide::BStart) != aWM.IsLineInverted()
? baseFontMetrics->MaxAscent() + fm->MaxDescent()
: baseFontMetrics->MaxDescent() + fm->MaxAscent();
RubyBlockLeadings leadings;
if (nsRubyFrame* ruby = FindFurthestInlineRubyAncestor(this)) {
leadings = ruby->GetBlockLeadings();
}
- if (side == eLogicalSideBStart) {
+ if (side == LogicalSide::BStart) {
info->baselineOffset = -absOffset - leadings.mStart;
overflowRect.BStart(aWM) = -overflowRect.BSize(aWM) - leadings.mStart;
} else {
- MOZ_ASSERT(side == eLogicalSideBEnd);
+ MOZ_ASSERT(side == LogicalSide::BEnd);
info->baselineOffset = absOffset + leadings.mEnd;
overflowRect.BStart(aWM) = frameSize.BSize(aWM) + leadings.mEnd;
}
// If text combined, fix the gap between the text frame and its parent.
if (isTextCombined) {
nscoord gap = (baseFontMetrics->MaxHeight() - frameSize.BSize(aWM)) / 2;
- overflowRect.BStart(aWM) += gap * (side == eLogicalSideBStart ? -1 : 1);
+ overflowRect.BStart(aWM) += gap * (side == LogicalSide::BStart ? -1 : 1);
}
SetProperty(EmphasisMarkProperty(), info);
@@ -5676,6 +5721,10 @@ bool nsTextFrame::GetSelectionTextColors(SelectionType aSelectionType,
aHighlightName, aBackground);
return hasForeground || hasBackground;
}
+ case SelectionType::eTargetText: {
+ aTextPaintStyle.GetTargetTextColors(aForeground, aBackground);
+ return true;
+ }
case SelectionType::eURLSecondary:
aTextPaintStyle.GetURLSecondaryColor(aForeground);
*aBackground = NS_RGBA(0, 0, 0, 0);
@@ -9216,7 +9265,6 @@ void nsTextFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTextFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
InvalidateSelectionState();
diff --git a/layout/generic/nsTextPaintStyle.cpp b/layout/generic/nsTextPaintStyle.cpp
index e97a059b07..f29fa753d0 100644
--- a/layout/generic/nsTextPaintStyle.cpp
+++ b/layout/generic/nsTextPaintStyle.cpp
@@ -213,6 +213,24 @@ void nsTextPaintStyle::GetHighlightColors(nscolor* aForeColor,
*aBackColor = NS_TRANSPARENT;
}
+void nsTextPaintStyle::GetTargetTextColors(nscolor* aForeColor,
+ nscolor* aBackColor) {
+ NS_ASSERTION(aForeColor, "aForeColor is null");
+ NS_ASSERTION(aBackColor, "aBackColor is null");
+ const RefPtr<const ComputedStyle> targetTextStyle =
+ mFrame->ComputeTargetTextStyle();
+ if (targetTextStyle) {
+ *aForeColor = targetTextStyle->GetVisitedDependentColor(
+ &nsStyleText::mWebkitTextFillColor);
+ *aBackColor = targetTextStyle->GetVisitedDependentColor(
+ &nsStyleBackground::mBackgroundColor);
+ return;
+ }
+ // XXX(:jjaschke): Before shipping this feature, a sensible set of colors must
+ // be set (Bug 1867940).
+ // in the meantime, use the colors of find selection.
+ GetHighlightColors(aForeColor, aBackColor);
+}
bool nsTextPaintStyle::GetCustomHighlightTextColor(nsAtom* aHighlightName,
nscolor* aForeColor) {
NS_ASSERTION(aForeColor, "aForeColor is null");
diff --git a/layout/generic/nsTextPaintStyle.h b/layout/generic/nsTextPaintStyle.h
index adf28fdad8..94cd3cf322 100644
--- a/layout/generic/nsTextPaintStyle.h
+++ b/layout/generic/nsTextPaintStyle.h
@@ -65,6 +65,7 @@ class MOZ_STACK_CLASS nsTextPaintStyle {
*/
bool GetSelectionColors(nscolor* aForeColor, nscolor* aBackColor);
void GetHighlightColors(nscolor* aForeColor, nscolor* aBackColor);
+ void GetTargetTextColors(nscolor* aForeColor, nscolor* aBackColor);
// Computes colors for custom highlights.
// Returns false if there are no rules associated with `aHighlightName`.
bool GetCustomHighlightTextColor(nsAtom* aHighlightName, nscolor* aForeColor);
diff --git a/layout/generic/nsTextRunTransformations.cpp b/layout/generic/nsTextRunTransformations.cpp
index d18a7ec293..de9fd31fda 100644
--- a/layout/generic/nsTextRunTransformations.cpp
+++ b/layout/generic/nsTextRunTransformations.cpp
@@ -80,6 +80,26 @@ bool nsTransformedTextRun::SetPotentialLineBreaks(Range aRange,
return changed;
}
+void nsTransformedTextRun::SetEmergencyWrapPositions() {
+ // This parallels part of what gfxShapedText::SetupClusterBoundaries() does
+ // for normal textruns.
+ bool prevWasHyphen = false;
+ for (uint32_t pos : IntegerRange(mString.Length())) {
+ const char16_t ch = mString[pos];
+ if (prevWasHyphen) {
+ if (nsContentUtils::IsAlphanumeric(ch)) {
+ mCharacterGlyphs[pos].SetCanBreakBefore(
+ CompressedGlyph::FLAG_BREAK_TYPE_EMERGENCY_WRAP);
+ }
+ prevWasHyphen = false;
+ }
+ if (nsContentUtils::IsHyphen(ch) && pos &&
+ nsContentUtils::IsAlphanumeric(mString[pos - 1])) {
+ prevWasHyphen = true;
+ }
+ }
+}
+
size_t nsTransformedTextRun::SizeOfExcludingThis(
mozilla::MallocSizeOf aMallocSizeOf) {
size_t total = gfxTextRun::SizeOfExcludingThis(aMallocSizeOf);
diff --git a/layout/generic/nsTextRunTransformations.h b/layout/generic/nsTextRunTransformations.h
index 915211c6af..6bcf26a8c0 100644
--- a/layout/generic/nsTextRunTransformations.h
+++ b/layout/generic/nsTextRunTransformations.h
@@ -202,7 +202,10 @@ class nsTransformedTextRun final : public gfxTextRun {
mOwnsFactory(aOwnsFactory),
mNeedsRebuild(true) {
mCharacterGlyphs = reinterpret_cast<CompressedGlyph*>(this + 1);
+ SetEmergencyWrapPositions();
}
+
+ void SetEmergencyWrapPositions();
};
/**
diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp
index d5bcc45969..e003058c3e 100644
--- a/layout/generic/nsVideoFrame.cpp
+++ b/layout/generic/nsVideoFrame.cpp
@@ -226,7 +226,6 @@ void nsVideoFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsVideoFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aMetrics, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE(
NS_FRAME_TRACE_CALLS,
@@ -375,14 +374,9 @@ nsIFrame::SizeComputationResult nsVideoFrame::ComputeSize(
}
nscoord nsVideoFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- // Bind the result variable to a RAII-based debug object - the variable
- // therefore must match the function's return value.
- DISPLAY_MIN_INLINE_SIZE(this, result);
// This call handles size-containment
nsSize size = GetIntrinsicSize().ToSize().valueOr(nsSize());
- result = GetWritingMode().IsVertical() ? size.height : size.width;
- return result;
+ return GetWritingMode().IsVertical() ? size.height : size.width;
}
nscoord nsVideoFrame::GetPrefISize(gfxContext* aRenderingContext) {
diff --git a/layout/generic/test/mochitest.toml b/layout/generic/test/mochitest.toml
index 5c06c90eb7..dcaac3de7a 100644
--- a/layout/generic/test/mochitest.toml
+++ b/layout/generic/test/mochitest.toml
@@ -12,6 +12,7 @@ support-files = [
"file_SlowTallImage.sjs",
"bug1174521.html",
"!/gfx/layers/apz/test/mochitest/apz_test_utils.js",
+ "selection_cross_shadow_boundary_helper.js",
]
["test_bug240933.html"]
@@ -265,6 +266,42 @@ support-files = [
["test_selection_changes_with_middle_mouse_button.html"]
+["test_selection_cross_shadow_boundary_1_backward_click.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_1_backward_drag.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_1_forward_click.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_1_forward_drag.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_2_backward_click.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_2_backward_drag.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_2_forward_click.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_2_forward_drag.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_multi_ranges_forward_drag.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_multi_ranges_forward_click.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_multi_ranges_backward_drag.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
+["test_selection_cross_shadow_boundary_multi_ranges_backward_click.html"]
+skip-if = ["release_or_beta"] # requires Selection.getComposedRanges to be enabled (Nightly only)
+
["test_selection_doubleclick.html"]
["test_selection_expanding.html"]
diff --git a/layout/generic/test/selection_cross_shadow_boundary_helper.js b/layout/generic/test/selection_cross_shadow_boundary_helper.js
new file mode 100644
index 0000000000..b2a596a27f
--- /dev/null
+++ b/layout/generic/test/selection_cross_shadow_boundary_helper.js
@@ -0,0 +1,28 @@
+// Helper file for test_selection_cross_shadow_boundary_* related tests
+
+function drag(
+ fromTarget,
+ fromX,
+ fromY,
+ toTarget,
+ toX,
+ toY,
+ withAccelKey = false
+) {
+ synthesizeMouse(fromTarget, fromX, fromY, {
+ type: "mousemove",
+ accelKey: withAccelKey,
+ });
+ synthesizeMouse(fromTarget, fromX, fromY, {
+ type: "mousedown",
+ accelKey: withAccelKey,
+ });
+ synthesizeMouse(toTarget, toX, toY, {
+ type: "mousemove",
+ accelKey: withAccelKey,
+ });
+ synthesizeMouse(toTarget, toX, toY, {
+ type: "mouseup",
+ accelKey: withAccelKey,
+ });
+}
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_1_backward_click.html b/layout/generic/test/test_selection_cross_shadow_boundary_1_backward_click.html
new file mode 100644
index 0000000000..ee724b344c
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_1_backward_click.html
@@ -0,0 +1,36 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+function run() {
+ document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = "<span>InnerText</span>";
+
+ const inner = host.shadowRoot.firstChild;
+ const rect = inner.getBoundingClientRect();
+
+ // Click the bottom right of "InnerText"
+ synthesizeMouse(inner, rect.width, rect.height, { type: "mousedown"});
+ synthesizeMouse(inner, rect.width, rect.height, { type: "mouseup" });
+
+ // Click the top left of "OuterText"
+ synthesizeMouse(document.getElementById("outer"), 0, 0, { type: "mousedown" , shiftKey: true});
+ synthesizeMouse(document.getElementById("outer"), 0, 0, { type: "mouseup" , shiftKey: true});
+
+ // Above two clicks should select both "OuterText" and "InnerText"
+ const sel = document.getSelection().getComposedRanges(host.shadowRoot)[0];
+
+ // backward selection
+ is(sel.endContainer, inner.firstChild, "endContainer is the InnerText");
+ is(sel.endOffset, 9, "endOffset ends at the last character");
+ is(sel.startContainer, outer.firstChild, "startContainer is the OuterText");
+ is(sel.startOffset, 0, "startOffset starts at the first character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer">OuterText</span>
+ <div id="host"></div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_1_backward_drag.html b/layout/generic/test/test_selection_cross_shadow_boundary_1_backward_drag.html
new file mode 100644
index 0000000000..f1737eaefa
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_1_backward_drag.html
@@ -0,0 +1,40 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function run() {
+ document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = "<span>InnerText</span>";
+
+ const inner = host.shadowRoot.firstChild;
+ const rect = inner.getBoundingClientRect();
+
+ // Drag from the bottom right of InnerText to the
+ // top left of OuterText.
+ drag(
+ inner,
+ rect.width,
+ rect.height,
+ document.getElementById("outer"),
+ 0,
+ 0);
+
+ // Above drag selects both "OuterText" and "InnerText"
+ const sel = document.getSelection().getComposedRanges(host.shadowRoot)[0];
+
+ // backward selection
+ is(sel.endContainer, inner.firstChild, "endContainer is the InnerText");
+ is(sel.endOffset, 9, "endOffset ends at the last character");
+ is(sel.startContainer, outer.firstChild, "startContainer is the OuterText");
+ is(sel.startOffset, 0, "startOffset starts at the first character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer">OuterText</span>
+ <div id="host"></div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_1_forward_click.html b/layout/generic/test/test_selection_cross_shadow_boundary_1_forward_click.html
new file mode 100644
index 0000000000..dcf4f9ad16
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_1_forward_click.html
@@ -0,0 +1,35 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+function run() {
+ document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = "<span>InnerText</span>";
+
+ // Click the top left of "OuterText"
+ synthesizeMouse(document.getElementById("outer"), 0, 0, { type: "mousedown" });
+ synthesizeMouse(document.getElementById("outer"), 0, 0, { type: "mouseup" });
+
+ // Click the bottom right of "InnerText"
+ const inner = host.shadowRoot.firstChild;
+ const rect = inner.getBoundingClientRect();
+ synthesizeMouse(inner, rect.width, rect.height, { type: "mousedown", shiftKey: true});
+ synthesizeMouse(inner, rect.width, rect.height, { type: "mouseup" , shiftKey: true});
+
+ // Above two clicks should select both "OuterText" and "InnerText"
+ const sel = document.getSelection().getComposedRanges(host.shadowRoot)[0];
+
+ // forward selection
+ is(sel.startContainer, outer.firstChild, "startContainer is the OuterText");
+ is(sel.startOffset, 0, "startOffset starts at the first character");
+ is(sel.endContainer, inner.firstChild, "endContainer is the InnerText");
+ is(sel.endOffset, 9, "endOffset ends at the last character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer">OuterText</span>
+ <div id="host"></div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_1_forward_drag.html b/layout/generic/test/test_selection_cross_shadow_boundary_1_forward_drag.html
new file mode 100644
index 0000000000..6a351ff16b
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_1_forward_drag.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+function run() {
+ document.getElementById("host").attachShadow({ mode: "open" }).innerHTML = "<span>InnerText</span>";
+
+ const inner = host.shadowRoot.firstChild;
+ const rect = inner.getBoundingClientRect();
+
+ // drag from the top left of OuterText
+ // to the bottom right of InnerText
+ drag(
+ document.getElementById("outer"),
+ 0,
+ 0,
+ inner,
+ rect.width,
+ rect.height);
+
+ // Above drag selects should select both "OuterText" and "InnerText"
+ const sel = document.getSelection().getComposedRanges(host.shadowRoot)[0];
+
+ // forward selection
+ is(sel.startContainer, outer.firstChild, "startContainer is the OuterText");
+ is(sel.startOffset, 0, "startOffset starts at the first character");
+ is(sel.endContainer, inner.firstChild, "endContainer is the InnerText");
+ is(sel.endOffset, 9, "endOffset ends at the last character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer">OuterText</span>
+ <div id="host"></div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_2_backward_click.html b/layout/generic/test/test_selection_cross_shadow_boundary_2_backward_click.html
new file mode 100644
index 0000000000..8df867a0a5
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_2_backward_click.html
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function run() {
+ const root1 = document.getElementById("host1").attachShadow({ mode: "open" });
+ root1.innerHTML = "InnerText1";
+
+ const root2 = document.getElementById("host2").attachShadow({ mode: "open" });
+ root2.innerHTML = "<span>InnerText2</span>";
+
+
+
+ const inner2 = root2.firstChild;
+ const rect = inner2.getBoundingClientRect();
+
+ // Click the bottom right of "InnerText2"
+ synthesizeMouse(inner2, rect.width, rect.height, { type: "mousedown" });
+ synthesizeMouse(inner2, rect.width, rect.height, { type: "mouseup" });
+
+ // Click the top left of "OuterText1"
+ synthesizeMouse(document.getElementById("outer1"), 0, 0, { type: "mousedown", shiftKey: true});
+ synthesizeMouse(document.getElementById("outer1"), 0, 0, { type: "mouseup" , shiftKey: true});
+
+ // Above clicks selects should select
+ // "OuterText1", "OuterText2", "InnerText1" and "InnerText2".
+ const sel = document.getSelection().getComposedRanges(root2)[0];
+
+ // backward selection
+ is(sel.endContainer, inner2.firstChild, "endContainer is the InnerText2");
+ is(sel.endOffset, 10, "endOffset ends at the last character");
+ is(sel.startContainer, outer1.firstChild, "startContainer is the OuterText1");
+ is(sel.startOffset, 0, "startOffset starts at the first character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer1">OuterText1</span>
+ <div id="host1"></div>
+ <span id="outer2">OuterText2</span>
+ <div id="host2"></div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_2_backward_drag.html b/layout/generic/test/test_selection_cross_shadow_boundary_2_backward_drag.html
new file mode 100644
index 0000000000..f79512d35e
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_2_backward_drag.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function run() {
+ const root1 = document.getElementById("host1").attachShadow({ mode: "open" });
+ root1.innerHTML = "InnerText1";
+
+ const root2 = document.getElementById("host2").attachShadow({ mode: "open" });
+ root2.innerHTML = "<span>InnerText2</span>";
+
+ const inner2 = root2.firstChild;
+ const rect = inner2.getBoundingClientRect();
+
+ const outer1 = document.getElementById("outer1");
+ // Drag from the bottom right of InnerText2 to
+ // the top left of OuterText1.
+ drag(
+ inner2,
+ rect.width,
+ rect.height,
+ outer1,
+ 0,
+ 0);
+
+ // Above drag should selects
+ // "OuterText1", "OuterText2", "InnerText1" and "InnerText2".
+ const sel = document.getSelection().getComposedRanges(root2)[0];
+
+ // backward selection
+ is(sel.endContainer, inner2.firstChild, "endContainer is the InnerText2");
+ is(sel.endOffset, 10, "endOffset ends at the last character");
+ is(sel.startContainer, outer1.firstChild, "startContainer is the OuterText1");
+ is(sel.startOffset, 0, "startOffset starts at the first character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer1">OuterText1</span>
+ <div id="host1"></div>
+ <span id="outer2">OuterText2</span>
+ <div id="host2"></div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_2_forward_click.html b/layout/generic/test/test_selection_cross_shadow_boundary_2_forward_click.html
new file mode 100644
index 0000000000..2ca2eaeda9
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_2_forward_click.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function run() {
+ const root1 = document.getElementById("host1").attachShadow({ mode: "open" });
+ root1.innerHTML = "InnerText1";
+
+ const root2 = document.getElementById("host2").attachShadow({ mode: "open" });
+ root2.innerHTML = "<span>InnerText2</span>";
+
+ const outer1 = document.getElementById("outer1");
+ // Click the top left of "OuterText1"
+ synthesizeMouse(outer1, 0, 0, { type: "mousedown" });
+ synthesizeMouse(outer1, 0, 0, { type: "mouseup" });
+
+ const inner2 = root2.firstChild;
+ const rect = inner2.getBoundingClientRect();
+
+ // Click the bottom right of "InnerText2"
+ synthesizeMouse(inner2, rect.width, rect.height, { type: "mousedown", shiftKey: true});
+ synthesizeMouse(inner2, rect.width, rect.height, { type: "mouseup" , shiftKey: true});
+
+ // Above clicks should select
+ // "OuterText1", "OuterText2", "InnerText1" and "InnerText2".
+ const sel = document.getSelection().getComposedRanges(root2)[0];
+
+ // forward selection
+ is(sel.startContainer, outer1.firstChild, "startContainer is the OuterText1");
+ is(sel.startOffset, 0, "startOffset starts at the first character");
+ is(sel.endContainer, inner2.firstChild, "endContainer is the InnerText2");
+ is(sel.endOffset, 10, "endOffset ends at the last character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer1">OuterText1</span>
+ <div id="host1"></div>
+ <span id="outer2">OuterText2</span>
+ <div id="host2"></div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_2_forward_drag.html b/layout/generic/test/test_selection_cross_shadow_boundary_2_forward_drag.html
new file mode 100644
index 0000000000..b92108de95
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_2_forward_drag.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+
+function run() {
+ const root1 = document.getElementById("host1").attachShadow({ mode: "open" });
+ root1.innerHTML = "InnerText1";
+
+ const root2 = document.getElementById("host2").attachShadow({ mode: "open" });
+ root2.innerHTML = "<span>InnerText2</span>";
+
+ const inner2 = root2.firstChild;
+ const rect = inner2.getBoundingClientRect();
+
+ const outer1 = document.getElementById("outer1");
+ // Drag from the top lef of OuterText1 to the
+ // bottom right of InnerText2.
+ drag(
+ outer1,
+ 0,
+ 0,
+ inner2,
+ rect.width,
+ rect.height);
+
+ // Above drag should select
+ // "OuterText1", "OuterText2", "InnerText1" and "InnerText2".
+ const sel = document.getSelection().getComposedRanges(root2)[0];
+
+ // forward selection
+ is(sel.startContainer, outer1.firstChild, "startContainer is the OuterText1");
+ is(sel.startOffset, 0, "startOffset starts at the first character");
+ is(sel.endContainer, inner2.firstChild, "endContainer is the InnerText2");
+ is(sel.endOffset, 10, "endOffset ends at the last character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer1">OuterText1</span>
+ <div id="host1"></div>
+ <span id="outer2">OuterText2</span>
+ <div id="host2"></div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_backward_click.html b/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_backward_click.html
new file mode 100644
index 0000000000..a2a0d0e2be
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_backward_click.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+function run() {
+ const inner1 = host1.shadowRoot.querySelector("span");
+ const rect1 = inner1.getBoundingClientRect();
+
+ // Click the bottom right of "InnerText1"
+ synthesizeMouse(inner1, rect1.width - 1, rect1.height - 1, { type: "mousedown" });
+ synthesizeMouse(inner1, rect1.width - 1, rect1.height - 1, { type: "mouseup" });
+
+ // Click the top left of "OuterText1"
+ synthesizeMouse(document.getElementById("outer1"), 0, 0, { type: "mousedown", shiftKey: true });
+ synthesizeMouse(document.getElementById("outer1"), 0, 0, { type: "mouseup", shiftKey: true });
+
+ const inner2 = host2.shadowRoot.querySelector("span");
+ const rect2 = inner2.getBoundingClientRect();
+
+ // Click the bottom right of "InnerText2" with accelKey
+ synthesizeMouse(inner2, rect2.width, rect2.height, { type: "mousedown", accelKey: true});
+ synthesizeMouse(inner2, rect2.width, rect2.height, { type: "mouseup" , accelKey: true});
+
+ // Click the top left of "OuterText2"
+ synthesizeMouse(document.getElementById("outer2"), 1, 1, { type: "mousedown", shiftKey: true});
+ synthesizeMouse(document.getElementById("outer2"), 1, 1, { type: "mouseup", shiftKey: true});
+
+ const ranges = document.getSelection().getComposedRanges(host1.shadowRoot, host2.shadowRoot);
+ is(ranges.length, 2, "Above two drag selection should produce two ranges");
+
+ is(ranges[0].startContainer, outer1.firstChild, "startContainer is the OuterText1");
+ is(ranges[0].startOffset, 0, "startOffset starts at the first character");
+ is(ranges[0].endContainer, inner1.firstChild, "endContainer is the InnerText1");
+ is(ranges[0].endOffset, 10, "endOffset ends at the last character");
+
+ is(ranges[1].startContainer, outer2.firstChild, "startContainer is the OuterText2");
+ is(ranges[1].startOffset, 0, "startOffset starts at the first character");
+ is(ranges[1].endContainer, inner2.firstChild, "endContainer is the InnerText2");
+ is(ranges[1].endOffset, 10, "endOffset ends at the last character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer1">OuterText1</span>
+ <div id="host1">
+ <template shadowrootmode="open">
+ <span>InnerText1</span>
+ </template>
+ </div>
+ <br>
+ <span id="outer2">OuterText2</span>
+ <div id="host2">
+ <template shadowrootmode="open">
+ <span>InnerText2</span>
+ </template>
+ </div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_backward_drag.html b/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_backward_drag.html
new file mode 100644
index 0000000000..317ee4f973
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_backward_drag.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+function run() {
+ const inner1 = host1.shadowRoot.querySelector("span");
+ const rect1 = inner1.getBoundingClientRect();
+
+ // drag from the bottom right of InnerText1
+ // to the top left of OuterText1
+ drag(
+ inner1,
+ rect1.width - 1,
+ rect1.height - 1,
+ document.getElementById("outer1"),
+ 1,
+ 1);
+
+ const inner2 = host2.shadowRoot.querySelector("span");
+ const rect2 = inner2.getBoundingClientRect();
+ // drag from the bottom right of InnerText2
+ // to the top left of OuterText2
+ drag(
+ inner2,
+ rect2.width,
+ rect2.height,
+ document.getElementById("outer2"),
+ 1,
+ 1,
+ true /* accelKey */);
+
+ const ranges = document.getSelection().getComposedRanges(host1.shadowRoot, host2.shadowRoot);
+ is(ranges.length, 2, "Above two drag selection should produce two ranges");
+
+ is(ranges[0].startContainer, outer1.firstChild, "startContainer is the OuterText1");
+ is(ranges[0].startOffset, 0, "startOffset starts at the first character");
+ is(ranges[0].endContainer, inner1.firstChild, "endContainer is the InnerText1");
+ is(ranges[0].endOffset, 10, "endOffset ends at the last character");
+
+ is(ranges[1].startContainer, outer2.firstChild, "startContainer is the OuterText2");
+ is(ranges[1].startOffset, 0, "startOffset starts at the first character");
+ is(ranges[1].endContainer, inner2.firstChild, "endContainer is the InnerText2");
+ is(ranges[1].endOffset, 10, "endOffset ends at the last character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer1">OuterText1</span>
+ <div id="host1">
+ <template shadowrootmode="open">
+ <span>InnerText1</span>
+ </template>
+ </div>
+ <br>
+ <span id="outer2">OuterText2</span>
+ <div id="host2">
+ <template shadowrootmode="open">
+ <span>InnerText2</span>
+ </template>
+ </div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_forward_click.html b/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_forward_click.html
new file mode 100644
index 0000000000..931c01fca0
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_forward_click.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+function run() {
+ // Click the top left of "OuterText1"
+ synthesizeMouse(document.getElementById("outer1"), 1, 1, { type: "mousedown" });
+ synthesizeMouse(document.getElementById("outer1"), 1, 1, { type: "mouseup" });
+
+ const inner1 = host1.shadowRoot.querySelector("span");
+ const rect1 = inner1.getBoundingClientRect();
+ // Click the bottom right of "InnerText1"
+ synthesizeMouse(inner1, rect1.width - 1, rect1.height - 1, { type: "mousedown", shiftKey: true});
+ synthesizeMouse(inner1, rect1.width - 1, rect1.height - 1, { type: "mouseup" , shiftKey: true});
+
+ // Click the top left of "OuterText2" with accelKey
+ synthesizeMouse(document.getElementById("outer2"), 1, 1, { type: "mousedown", accelKey: true});
+ synthesizeMouse(document.getElementById("outer2"), 1, 1, { type: "mouseup", accelKey: true});
+
+ const inner2 = host2.shadowRoot.querySelector("span");
+ const rect2 = inner2.getBoundingClientRect();
+ // Click the bottom right of "InnerText2"
+ synthesizeMouse(inner2, rect2.width, rect2.height, { type: "mousedown", shiftKey: true});
+ synthesizeMouse(inner2, rect2.width, rect2.height, { type: "mouseup" , shiftKey: true});
+
+ const ranges = document.getSelection().getComposedRanges(host1.shadowRoot, host2.shadowRoot);
+ is(ranges.length, 2, "Above two drag selection should produce two ranges");
+
+ is(ranges[0].startContainer, outer1.firstChild, "startContainer is the OuterText1");
+ is(ranges[0].startOffset, 0, "startOffset starts at the first character");
+ is(ranges[0].endContainer, inner1.firstChild, "endContainer is the InnerText1");
+ is(ranges[0].endOffset, 10, "endOffset ends at the last character");
+
+ is(ranges[1].startContainer, outer2.firstChild, "startContainer is the OuterText2");
+ is(ranges[1].startOffset, 0, "startOffset starts at the first character");
+ is(ranges[1].endContainer, inner2.firstChild, "endContainer is the InnerText2");
+ is(ranges[1].endOffset, 10, "endOffset ends at the last character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer1">OuterText1</span>
+ <div id="host1">
+ <template shadowrootmode="open">
+ <span>InnerText1</span>
+ </template>
+ </div>
+ <br>
+ <span id="outer2">OuterText2</span>
+ <div id="host2">
+ <template shadowrootmode="open">
+ <span>InnerText2</span>
+ </template>
+ </div>
+</body>
diff --git a/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_forward_drag.html b/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_forward_drag.html
new file mode 100644
index 0000000000..b45e588685
--- /dev/null
+++ b/layout/generic/test/test_selection_cross_shadow_boundary_multi_ranges_forward_drag.html
@@ -0,0 +1,65 @@
+<!DOCTYPE HTML>
+<script src="/tests/SimpleTest/EventUtils.js"></script>
+<script src="/tests/SimpleTest/SimpleTest.js"></script>
+<script type="application/javascript" src="/tests/layout/generic/test/selection_cross_shadow_boundary_helper.js"></script>
+<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+<script>
+SimpleTest.waitForExplicitFinish();
+function run() {
+ const inner1 = host1.shadowRoot.querySelector("span");
+ const rect1 = inner1.getBoundingClientRect();
+
+ // drag from the top left of OuterText1
+ // to the bottom right of InnerText1
+ drag(
+ document.getElementById("outer1"),
+ 1,
+ 1,
+ inner1,
+ rect1.width - 1,
+ rect1.height - 1);
+
+ const inner2 = host2.shadowRoot.querySelector("span");
+ const rect2 = inner2.getBoundingClientRect();
+ // drag from the top left of OuterText2
+ // to the bottom right of InnerText2
+ drag(
+ document.getElementById("outer2"),
+ 1,
+ 1,
+ inner2,
+ rect2.width,
+ rect2.height,
+ true /* accelKey */);
+
+ const ranges = document.getSelection().getComposedRanges(host1.shadowRoot, host2.shadowRoot);
+ is(ranges.length, 2, "Above two drag selection should produce two ranges");
+
+ is(ranges[0].startContainer, outer1.firstChild, "startContainer is the OuterText1");
+ is(ranges[0].startOffset, 0, "startOffset starts at the first character");
+ is(ranges[0].endContainer, inner1.firstChild, "endContainer is the InnerText1");
+ is(ranges[0].endOffset, 10, "endOffset ends at the last character");
+
+ is(ranges[1].startContainer, outer2.firstChild, "startContainer is the OuterText2");
+ is(ranges[1].startOffset, 0, "startOffset starts at the first character");
+ is(ranges[1].endContainer, inner2.firstChild, "endContainer is the InnerText2");
+ is(ranges[1].endOffset, 10, "endOffset ends at the last character");
+
+ SimpleTest.finish();
+}
+</script>
+<body onload="SimpleTest.waitForFocus(run);">
+ <span id="outer1">OuterText1</span>
+ <div id="host1">
+ <template shadowrootmode="open">
+ <span>InnerText1</span>
+ </template>
+ </div>
+ <br>
+ <span id="outer2">OuterText2</span>
+ <div id="host2">
+ <template shadowrootmode="open">
+ <span>InnerText2</span>
+ </template>
+ </div>
+</body>
diff --git a/layout/inspector/InspectorCSSParser.cpp b/layout/inspector/InspectorCSSParser.cpp
new file mode 100644
index 0000000000..bc9cbf1487
--- /dev/null
+++ b/layout/inspector/InspectorCSSParser.cpp
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/InspectorCSSParser.h"
+
+#include "mozilla/ServoBindings.h"
+#include "mozilla/ServoStyleConsts.h"
+#include "mozilla/UniquePtr.h"
+
+namespace mozilla::dom {
+
+InspectorCSSParser::InspectorCSSParser(const nsACString& aText)
+ : mInput(aText) {
+ mParserState = Servo_CSSParser_create(&mInput);
+}
+
+UniquePtr<InspectorCSSParser> InspectorCSSParser::Constructor(
+ const GlobalObject& aGlobal, const nsACString& aText) {
+ return MakeUnique<InspectorCSSParser>(aText);
+}
+
+InspectorCSSParser::~InspectorCSSParser() {
+ Servo_CSSParser_destroy(mParserState);
+ mParserState = nullptr;
+}
+
+uint32_t InspectorCSSParser::LineNumber() const { return mLineNumber; }
+
+uint32_t InspectorCSSParser::ColumnNumber() const {
+ // mColumnNumber is 1-based, but consumers expect 0-based.
+ return mColumnNumber - 1;
+}
+
+void InspectorCSSParser::NextToken(Nullable<InspectorCSSToken>& aResult) {
+ StyleCSSToken cssToken;
+ if (!Servo_CSSParser_NextToken(&mInput, mParserState, &cssToken)) {
+ aResult.SetNull();
+
+ mLineNumber = Servo_CSSParser_GetCurrentLine(mParserState);
+ mColumnNumber = Servo_CSSParser_GetCurrentColumn(mParserState);
+
+ return;
+ }
+
+ InspectorCSSToken& inspectorCssToken = aResult.SetValue();
+ inspectorCssToken.mText.Append(cssToken.text);
+ inspectorCssToken.mTokenType.Append(cssToken.token_type);
+ if (cssToken.has_value) {
+ inspectorCssToken.mValue.Append(cssToken.value);
+ } else {
+ inspectorCssToken.mValue.SetIsVoid(true);
+ }
+ if (cssToken.has_unit) {
+ inspectorCssToken.mUnit.Append(cssToken.unit);
+ } else {
+ inspectorCssToken.mUnit.SetIsVoid(true);
+ }
+ if (cssToken.has_number) {
+ // Reduce precision to avoid floating point inprecision
+ inspectorCssToken.mNumber = round(cssToken.number * 100) / 100.0;
+ }
+
+ mLineNumber = cssToken.line;
+ mColumnNumber = cssToken.column;
+}
+
+} // namespace mozilla::dom
diff --git a/layout/inspector/InspectorCSSParser.h b/layout/inspector/InspectorCSSParser.h
new file mode 100644
index 0000000000..e11bc9a898
--- /dev/null
+++ b/layout/inspector/InspectorCSSParser.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 InspectorCSSParser_h___
+#define InspectorCSSParser_h___
+
+#include "mozilla/dom/InspectorUtilsBinding.h"
+#include "mozilla/dom/NonRefcountedDOMObject.h"
+
+namespace mozilla {
+
+class StyleParserState;
+
+namespace dom {
+
+class InspectorCSSParser final : public NonRefcountedDOMObject {
+ public:
+ explicit InspectorCSSParser(const nsACString&);
+ // The WebIDL constructor.
+ static UniquePtr<InspectorCSSParser> Constructor(const GlobalObject& aGlobal,
+ const nsACString& aText);
+
+ ~InspectorCSSParser();
+
+ bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
+ JS::MutableHandle<JSObject*> aReflector) {
+ return InspectorCSSParser_Binding::Wrap(aCx, this, aGivenProto, aReflector);
+ }
+
+ uint32_t LineNumber() const;
+ uint32_t ColumnNumber() const;
+ void NextToken(Nullable<InspectorCSSToken>& aResult);
+
+ private:
+ const nsCString mInput;
+ StyleParserState* mParserState;
+ uint32_t mLineNumber = 0;
+ uint32_t mColumnNumber = 0;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif /* InspectorCSSParser_h___ */
diff --git a/layout/inspector/InspectorUtils.cpp b/layout/inspector/InspectorUtils.cpp
index f1886a0dd0..d174c16424 100644
--- a/layout/inspector/InspectorUtils.cpp
+++ b/layout/inspector/InspectorUtils.cpp
@@ -415,6 +415,7 @@ static uint32_t CollectAtRules(ServoCSSRuleList& aRuleList,
case StyleCssRuleType::Media:
case StyleCssRuleType::Supports:
case StyleCssRuleType::LayerBlock:
+ case StyleCssRuleType::Property:
case StyleCssRuleType::Container: {
Unused << aResult.AppendElement(OwningNonNull(*rule), fallible);
break;
@@ -425,7 +426,6 @@ static uint32_t CollectAtRules(ServoCSSRuleList& aRuleList,
case StyleCssRuleType::LayerStatement:
case StyleCssRuleType::FontFace:
case StyleCssRuleType::Page:
- case StyleCssRuleType::Property:
case StyleCssRuleType::Keyframes:
case StyleCssRuleType::Keyframe:
case StyleCssRuleType::Margin:
@@ -433,6 +433,8 @@ static uint32_t CollectAtRules(ServoCSSRuleList& aRuleList,
case StyleCssRuleType::CounterStyle:
case StyleCssRuleType::FontFeatureValues:
case StyleCssRuleType::FontPaletteValues:
+ case StyleCssRuleType::Scope:
+ case StyleCssRuleType::StartingStyle:
break;
}
@@ -1000,22 +1002,19 @@ void InspectorUtils::GetCSSRegisteredProperties(
}
/* static */
-void InspectorUtils::GetRuleBodyTextOffsets(
- GlobalObject&, const nsACString& aInitialText,
- Nullable<InspectorGetRuleBodyTextResult>& aResult) {
- uint32_t resultStartOffset;
- uint32_t resultEndOffset;
-
- if (!Servo_GetRuleBodyTextOffsets(&aInitialText, &resultStartOffset,
- &resultEndOffset)) {
- aResult.SetNull();
- return;
- }
-
- InspectorGetRuleBodyTextResult& offsets = aResult.SetValue();
- offsets.mStartOffset = resultStartOffset;
- offsets.mEndOffset = resultEndOffset;
+void InspectorUtils::GetRuleBodyText(GlobalObject&,
+ const nsACString& aInitialText,
+ nsACString& aBodyText) {
+ Servo_GetRuleBodyText(&aInitialText, &aBodyText);
}
+/* static */
+void InspectorUtils::ReplaceBlockRuleBodyTextInStylesheet(
+ GlobalObject&, const nsACString& aStyleSheetText, uint32_t aLine,
+ uint32_t aColumn, const nsACString& aNewBodyText,
+ nsACString& aNewStyleSheetText) {
+ Servo_ReplaceBlockRuleBodyTextInStylesheetText(
+ &aStyleSheetText, aLine, aColumn, &aNewBodyText, &aNewStyleSheetText);
+}
} // namespace dom
} // namespace mozilla
diff --git a/layout/inspector/InspectorUtils.h b/layout/inspector/InspectorUtils.h
index f375e51472..9d64823fc4 100644
--- a/layout/inspector/InspectorUtils.h
+++ b/layout/inspector/InspectorUtils.h
@@ -270,11 +270,18 @@ class InspectorUtils {
nsTArray<InspectorCSSPropertyDefinition>& aResult);
/**
- * Get the rule body text start and end offsets within aInitialText
+ * Get the rule body text within aInitialText
*/
- static void GetRuleBodyTextOffsets(
- GlobalObject&, const nsACString& aInitialText,
- Nullable<InspectorGetRuleBodyTextResult>& aResult);
+ static void GetRuleBodyText(GlobalObject&, const nsACString& aInitialText,
+ nsACString& aBodyText);
+
+ /**
+ * Replace the rule body text in aStyleSheetText at passed line and column
+ */
+ static void ReplaceBlockRuleBodyTextInStylesheet(
+ GlobalObject&, const nsACString& aStyleSheetText, uint32_t aLine,
+ uint32_t aColumn, const nsACString& aNewBodyText,
+ nsACString& aNewStyleSheetText);
};
} // namespace mozilla::dom
diff --git a/layout/inspector/ServoStyleRuleMap.cpp b/layout/inspector/ServoStyleRuleMap.cpp
index b67d0c98fc..188c4f5329 100644
--- a/layout/inspector/ServoStyleRuleMap.cpp
+++ b/layout/inspector/ServoStyleRuleMap.cpp
@@ -86,7 +86,9 @@ void ServoStyleRuleMap::RuleRemoved(StyleSheet& aStyleSheet,
case StyleCssRuleType::Supports:
case StyleCssRuleType::LayerBlock:
case StyleCssRuleType::Container:
- case StyleCssRuleType::Document: {
+ case StyleCssRuleType::Document:
+ case StyleCssRuleType::Scope:
+ case StyleCssRuleType::StartingStyle: {
// See the comment in SheetRemoved.
mTable.Clear();
break;
@@ -124,7 +126,9 @@ void ServoStyleRuleMap::FillTableFromRule(css::Rule& aRule) {
case StyleCssRuleType::Media:
case StyleCssRuleType::Supports:
case StyleCssRuleType::Container:
- case StyleCssRuleType::Document: {
+ case StyleCssRuleType::Document:
+ case StyleCssRuleType::Scope:
+ case StyleCssRuleType::StartingStyle: {
auto& rule = static_cast<css::GroupRule&>(aRule);
FillTableFromRuleList(*rule.CssRules());
break;
diff --git a/layout/inspector/moz.build b/layout/inspector/moz.build
index 45d31eb090..9a6634204c 100644
--- a/layout/inspector/moz.build
+++ b/layout/inspector/moz.build
@@ -19,6 +19,7 @@ EXPORTS.mozilla += [
]
EXPORTS.mozilla.dom += [
+ "InspectorCSSParser.h",
"InspectorFontFace.h",
"InspectorUtils.h",
]
@@ -26,6 +27,7 @@ EXPORTS.mozilla.dom += [
UNIFIED_SOURCES += [
"inDeepTreeWalker.cpp",
"inLayoutUtils.cpp",
+ "InspectorCSSParser.cpp",
"InspectorFontFace.cpp",
"InspectorUtils.cpp",
"ServoStyleRuleMap.cpp",
diff --git a/layout/inspector/tests/chrome/chrome.toml b/layout/inspector/tests/chrome/chrome.toml
index 193be351cb..4326401918 100644
--- a/layout/inspector/tests/chrome/chrome.toml
+++ b/layout/inspector/tests/chrome/chrome.toml
@@ -14,6 +14,8 @@ support-files = ["test_bug708874.css"]
["test_bug727834.xhtml"]
support-files = ["test_bug727834.css"]
+["test_CSSStyleRule_querySelectorAll.html"]
+
["test_fontFaceGeneric.xhtml"]
["test_fontFaceRanges.xhtml"]
diff --git a/layout/inspector/tests/chrome/test_CSSStyleRule_querySelectorAll.html b/layout/inspector/tests/chrome/test_CSSStyleRule_querySelectorAll.html
new file mode 100644
index 0000000000..dcddc5744b
--- /dev/null
+++ b/layout/inspector/tests/chrome/test_CSSStyleRule_querySelectorAll.html
@@ -0,0 +1,121 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8" />
+ <title>Test CSSStyleRule::QuerySelectorAll</title>
+ <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+ <style>
+ .test-simple {
+ }
+ .test-nested-parent {
+ .test-nested-child {
+ .test-nested-and-non-nested {
+ }
+ }
+ }
+ .test-nested-and-non-nested {
+ }
+ .test-no-match {
+ }
+ </style>
+ <script>
+ SimpleTest.waitForExplicitFinish();
+ addLoadEvent(doTest);
+
+ function doTest() {
+ let { cssRules } = document.styleSheets[1];
+
+ info("Testing simple case");
+ let rule = cssRules[0];
+ let result = rule.querySelectorAll(document);
+ is(result.length, 2, `2 elements are matching "${rule.selectorText}"`);
+ is(
+ result[0].id,
+ "a",
+ `Got expected id for first element matching "${rule.selectorText}"`
+ );
+ is(
+ result[1].id,
+ "b",
+ `Got expected id for second element matching "${rule.selectorText}"`
+ );
+
+ info("Testing nested rule");
+ rule = cssRules[1].cssRules[0];
+ result = rule.querySelectorAll(document);
+ is(result.length, 1, `1 element is matching "${rule.selectorText}"`);
+ is(
+ result[0].id,
+ "d",
+ `Got expected id for element matching "${rule.selectorText}"`
+ );
+
+ info("Testing multi-level deep nested rule");
+ rule = cssRules[1].cssRules[0].cssRules[0];
+ result = rule.querySelectorAll(document);
+ // Check that we're not retrieving `f`, as the rule selectorText is `.test-nested-and-non-nested`,
+ // but it is nested inside `.test-nested-child`.
+ is(result.length, 1, `1 element is matching "${rule.selectorText}"`);
+ is(
+ result[0].id,
+ "e",
+ `Got expected id for element matching "${rule.selectorText}"`
+ );
+
+ info(
+ "Testing rule matching multiple elements with the same class, some nested, some not"
+ );
+ rule = cssRules[2];
+ result = rule.querySelectorAll(document);
+ is(result.length, 2, `2 elements are matching "${rule.selectorText}"`);
+ is(
+ result[0].id,
+ "e",
+ `Got expected id for first element matching "${rule.selectorText}"`
+ );
+ is(
+ result[1].id,
+ "f",
+ `Got expected id for second element matching "${rule.selectorText}"`
+ );
+
+ info("Testing that search results are limited by the passed root node");
+ rule = cssRules[2];
+ result = rule.querySelectorAll(document.querySelector("#c"));
+ is(
+ result.length,
+ 1,
+ `An element is matching "${rule.selectorText}" in #c`
+ );
+ is(
+ result[0].id,
+ "e",
+ `Got expected id for element matching "${rule.selectorText}"`
+ );
+
+ info("Testing rule with no matching elements");
+ rule = cssRules[3];
+ result = rule.querySelectorAll(document);
+ is(result.length, 0, `No elements matching "${rule.selectorText}"`);
+
+ SimpleTest.finish();
+ }
+ </script>
+ </head>
+ <body>
+ <h1>Test CSSStyleRule::QuerySelectorAll</h1>
+ <p id="display"></p>
+ <div id="content" style="display: none">
+ <div id="a" class="test-simple"></div>
+ <div id="b" class="test-simple"></div>
+ <div id="c" class="test-nested-parent">
+ <span id="d" class="test-nested-child">
+ <b id="e" class="test-nested-and-non-nested"></b>
+ </span>
+ </div>
+ <b id="f" class="test-nested-and-non-nested"></b>
+ </div>
+ <pre id="test"></pre>
+ </body>
+</html>
diff --git a/layout/inspector/tests/mochitest.toml b/layout/inspector/tests/mochitest.toml
index e51941752b..b45742b727 100644
--- a/layout/inspector/tests/mochitest.toml
+++ b/layout/inspector/tests/mochitest.toml
@@ -1,6 +1,7 @@
[DEFAULT]
prefs = [
"layout.css.basic-shape-rect.enabled=true",
+ "layout.css.basic-shape-shape.enabled=true",
"layout.css.basic-shape-xywh.enabled=true",
"layout.css.properties-and-values.enabled=true",
"layout.css.transition-behavior.enabled=true",
@@ -78,6 +79,8 @@ skip-if = ["os == 'android'"]
["test_parseStyleSheet_nested.html"]
+["test_replaceBlockRuleBodyTextInStylesheet.html"]
+
["test_rgba_to_color_name.html"]
["test_selectormatcheselement.html"]
diff --git a/layout/inspector/tests/test_bug877690.html b/layout/inspector/tests/test_bug877690.html
index 9e5efca0d3..668d18200e 100644
--- a/layout/inspector/tests/test_bug877690.html
+++ b/layout/inspector/tests/test_bug877690.html
@@ -217,10 +217,13 @@ function do_test() {
ok(testValues(values, expected), "property box-shadow's values");
// Regression test for bug 1255379.
+ var shapeFunction = [ "close", "evenodd", "nonzero", "by", "to", "cw", "ccw",
+ "small", "large" ];
var expected = [ "inherit", "initial", "unset", "revert", "revert-layer",
"none", "url", "polygon", "circle", "ellipse", "inset",
- "path", "rect", "xywh", "fill-box", "stroke-box", "view-box",
- "margin-box", "border-box", "padding-box", "content-box" ];
+ "path", "rect", "xywh", "fill-box", "stroke-box",
+ "view-box", "margin-box", "border-box", "padding-box",
+ "content-box", ...shapeFunction ];
var values = InspectorUtils.getCSSValuesForProperty("clip-path");
ok(testValues(values, expected), "property clip-path's values");
diff --git a/layout/inspector/tests/test_getCSSPseudoElementNames.html b/layout/inspector/tests/test_getCSSPseudoElementNames.html
index 255f58b889..356d4a89bc 100644
--- a/layout/inspector/tests/test_getCSSPseudoElementNames.html
+++ b/layout/inspector/tests/test_getCSSPseudoElementNames.html
@@ -22,6 +22,7 @@
"::highlight",
"::placeholder",
"::selection",
+ "::target-text",
"::-moz-color-swatch",
"::-moz-focus-inner",
"::-moz-meter-bar",
diff --git a/layout/inspector/tests/test_replaceBlockRuleBodyTextInStylesheet.html b/layout/inspector/tests/test_replaceBlockRuleBodyTextInStylesheet.html
new file mode 100644
index 0000000000..e6385978ba
--- /dev/null
+++ b/layout/inspector/tests/test_replaceBlockRuleBodyTextInStylesheet.html
@@ -0,0 +1,209 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Test InspectorUtils::replaceBlockRuleBodyTextInStylesheet</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
+ <style>
+#test-simple {
+ color: #f0c;
+}
+#test-unicode,[data-unicode="🦄👨‍👩‍👧‍👦"]::after {
+ content: /* test comment */ "👨‍👩‍👧‍👦🦄";
+ outline: 2px solid salmon;
+}
+#test-empty {} /* 🛠️⚒️🛠️ */ #test-same-line { font-size: 3em; }
+#test-nested-parent {
+ color: tomato;
+ #test-nested-child {
+ background: gold;
+ }
+}#test-after-closing-bracket{--modified:false}
+ </style>
+ <script>SimpleTest.waitForExplicitFinish();</script>
+ <script defer>
+ const InspectorUtils = SpecialPowers.InspectorUtils;
+ let stylesheet = document.styleSheets[1];
+ let authoredStyleSheetText = document.querySelector("style").textContent;
+
+ const existingRulesAuthoredText = [
+`#test-simple {
+ color: #f0c;
+}`,
+`#test-unicode,[data-unicode="🦄👨‍👩‍👧‍👦"]::after {
+ content: /* test comment */ "👨‍👩‍👧‍👦🦄";
+ outline: 2px solid salmon;
+}`,
+`#test-empty {}`,
+`#test-same-line { font-size: 3em; }`,
+`#test-nested-parent {
+ color: tomato;
+ #test-nested-child {
+ background: gold;
+ }
+}`,
+`#test-nested-child {
+ background: gold;
+ }`,
+`#test-after-closing-bracket{--modified:false}`,
+];
+
+ const replaceBlockRuleBodyTextInStylesheet = (rule, newBodyText) => {
+ return InspectorUtils.replaceBlockRuleBodyTextInStylesheet(
+ authoredStyleSheetText,
+ InspectorUtils.getRelativeRuleLine(rule),
+ InspectorUtils.getRuleColumn(rule),
+ newBodyText
+ )};
+
+ info("Check a simple case");
+ let newBodyText = `border-color: cyan;`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[0], newBodyText),
+ authoredStyleSheetText.replace(
+ existingRulesAuthoredText[0],
+ `#test-simple {${newBodyText}}`,
+ ),
+ "Got the expected result for #test-simple"
+ );
+
+ info("Check that the rule body can be emptied");
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[0], ""),
+ authoredStyleSheetText.replace(
+ existingRulesAuthoredText[0],
+ `#test-simple {}`,
+ ),
+ "Successfuly removed rule content for #test-simple"
+ );
+
+ info("Check that it can handle unicode characters");
+ newBodyText = `content: "o 🦊 o";`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[1], newBodyText),
+ authoredStyleSheetText.replace(existingRulesAuthoredText[1],
+ `#test-unicode,[data-unicode="🦄👨‍👩‍👧‍👦"]::after {${newBodyText}}`,
+ ),
+ "Got the expected result for #test-unicode"
+ );
+
+ info("Check that it can replace content of an empty rule");
+ newBodyText = `font-family: "Zilla;"`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[2], newBodyText),
+ authoredStyleSheetText.replace(
+ existingRulesAuthoredText[2],
+ `#test-empty {${newBodyText}}`,
+ ),
+ "Got the expected result for #test-empty"
+ );
+
+ info("Check that it can handle a rule on a same line as another rule");
+ newBodyText = `color: pink;`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[3], newBodyText),
+ authoredStyleSheetText.replace(
+ existingRulesAuthoredText[3],
+ `#test-same-line {${newBodyText}}`,
+ ),
+ "Got the expected result for #test-same-line"
+ );
+
+ info("Check that it can handle a rule with a child rule");
+ newBodyText = `background: silver;
+ & > span {
+ color: white;
+ }`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[4], newBodyText),
+ authoredStyleSheetText.replace(
+ existingRulesAuthoredText[4],
+ `#test-nested-parent {${newBodyText}}`,
+ ),
+ "Got the expected result for #test-nested-parent"
+ );
+
+ info("Check that it can handle a nested rule");
+ newBodyText = `color: white;height: 100%;`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[4].cssRules[0], newBodyText),
+ authoredStyleSheetText.replace(
+ existingRulesAuthoredText[5],
+ `#test-nested-child {${newBodyText}}`,
+ ),
+ "Got the expected result for #test-nested-child"
+ );
+
+ // Covering fix for Bug 1890775
+ info("Check that it can handle rules whose declaration is directly after the } of the previous rule, without spaces");
+ isnot(
+ InspectorUtils.getRelativeRuleLine(stylesheet.cssRules[5]),
+ 1,
+ "The rule should not be on the first line of the stylesheet to check the issue it covers"
+ );
+ newBodyText = `--modified:true`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[5], newBodyText),
+ authoredStyleSheetText.replace(
+ existingRulesAuthoredText[6],
+ `#test-after-closing-bracket{${newBodyText}}`,
+ ),
+ "Got the expected result for #test-after-closing-bracket"
+ );
+
+ info("Checking fix for files with crlf EOL sequence");
+ let styleEl = document.createElement("style");
+ let ruleText = `#test-after-closing-bracket-crlf{--modified-crlf:false}`
+ authoredStyleSheetText = `\r\nhtml{}${ruleText}`;
+ styleEl.append(document.createTextNode(authoredStyleSheetText));
+ document.head.append(styleEl);
+ stylesheet = document.styleSheets[2];
+ isnot(
+ InspectorUtils.getRelativeRuleLine(stylesheet.cssRules[1]),
+ 1,
+ "The rule should not be on the first line of the stylesheet to check the issue it covers"
+ );
+ newBodyText = `--modified-crlf:true`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[1], newBodyText),
+ authoredStyleSheetText.replace(
+ ruleText,
+ `#test-after-closing-bracket-crlf{${newBodyText}}`,
+ ),
+ "Got the expected result for #test-after-closing-bracket-crlf"
+ );
+
+ info("Checking fix for files with cr EOL sequence");
+ ruleText = `#test-after-closing-bracket-cr{--modified-cr:false}`
+ authoredStyleSheetText = `\rhtml{}${ruleText}`;
+ styleEl.innerText = "";
+ styleEl.append(document.createTextNode(authoredStyleSheetText));
+ isnot(
+ InspectorUtils.getRelativeRuleLine(stylesheet.cssRules[1]),
+ 1,
+ "The rule should not be on the first line of the stylesheet to check the issue it covers"
+ );
+ newBodyText = `--modified-cr:true`;
+ is(
+ replaceBlockRuleBodyTextInStylesheet(stylesheet.cssRules[1], newBodyText),
+ authoredStyleSheetText.replace(
+ ruleText,
+ `#test-after-closing-bracket-cr{${newBodyText}}`,
+ ),
+ "Got the expected result for #test-after-closing-bracket-cr"
+ );
+
+ SimpleTest.finish();
+ </script>
+</head>
+<body>
+<h1>Test InspectorUtils::replaceBlockRuleBodyTextInStylesheet</h1>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/layout/mathml/nsMathMLContainerFrame.cpp b/layout/mathml/nsMathMLContainerFrame.cpp
index b63792c288..fc334d1cae 100644
--- a/layout/mathml/nsMathMLContainerFrame.cpp
+++ b/layout/mathml/nsMathMLContainerFrame.cpp
@@ -829,39 +829,33 @@ static nscoord AddInterFrameSpacingToSize(ReflowOutput& aDesiredSize,
/* virtual */
void nsMathMLContainerFrame::MarkIntrinsicISizesDirty() {
- mIntrinsicWidth = NS_INTRINSIC_ISIZE_UNKNOWN;
+ mIntrinsicISize = NS_INTRINSIC_ISIZE_UNKNOWN;
nsContainerFrame::MarkIntrinsicISizesDirty();
}
-void nsMathMLContainerFrame::UpdateIntrinsicWidth(
+void nsMathMLContainerFrame::UpdateIntrinsicISize(
gfxContext* aRenderingContext) {
- if (mIntrinsicWidth == NS_INTRINSIC_ISIZE_UNKNOWN) {
+ if (mIntrinsicISize == NS_INTRINSIC_ISIZE_UNKNOWN) {
ReflowOutput desiredSize(GetWritingMode());
GetIntrinsicISizeMetrics(aRenderingContext, desiredSize);
// Include the additional width added by FixInterFrameSpacing to ensure
// consistent width calculations.
AddInterFrameSpacingToSize(desiredSize, this);
- mIntrinsicWidth = desiredSize.ISize(GetWritingMode());
+ mIntrinsicISize = desiredSize.ISize(GetWritingMode());
}
}
/* virtual */
nscoord nsMathMLContainerFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
- UpdateIntrinsicWidth(aRenderingContext);
- result = mIntrinsicWidth;
- return result;
+ UpdateIntrinsicISize(aRenderingContext);
+ return mIntrinsicISize;
}
/* virtual */
nscoord nsMathMLContainerFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
- UpdateIntrinsicWidth(aRenderingContext);
- result = mIntrinsicWidth;
- return result;
+ UpdateIntrinsicISize(aRenderingContext);
+ return mIntrinsicISize;
}
/* virtual */
diff --git a/layout/mathml/nsMathMLContainerFrame.h b/layout/mathml/nsMathMLContainerFrame.h
index 805d7e03ca..24bc86c338 100644
--- a/layout/mathml/nsMathMLContainerFrame.h
+++ b/layout/mathml/nsMathMLContainerFrame.h
@@ -37,9 +37,7 @@ class nsMathMLContainerFrame : public nsContainerFrame, public nsMathMLFrame {
public:
nsMathMLContainerFrame(ComputedStyle* aStyle, nsPresContext* aPresContext,
ClassID aID)
- : nsContainerFrame(aStyle, aPresContext, aID),
- mIntrinsicWidth(NS_INTRINSIC_ISIZE_UNKNOWN),
- mBlockStartAscent(0) {}
+ : nsContainerFrame(aStyle, aPresContext, aID) {}
NS_DECL_QUERYFRAME_TARGET(nsMathMLContainerFrame)
NS_DECL_QUERYFRAME
@@ -341,13 +339,13 @@ class nsMathMLContainerFrame : public nsContainerFrame, public nsMathMLFrame {
static void DidReflowChildren(nsIFrame* aFirst, nsIFrame* aStop = nullptr);
/**
- * Recompute mIntrinsicWidth if it's not already up to date.
+ * Recompute mIntrinsicISize if it's not already up to date.
*/
- void UpdateIntrinsicWidth(gfxContext* aRenderingContext);
+ void UpdateIntrinsicISize(gfxContext* aRenderingContext);
- nscoord mIntrinsicWidth;
+ nscoord mIntrinsicISize = NS_INTRINSIC_ISIZE_UNKNOWN;
- nscoord mBlockStartAscent;
+ nscoord mBlockStartAscent = 0;
private:
class RowChildFrameIterator;
@@ -429,8 +427,7 @@ class nsMathMLmathBlockFrame final : public nsBlockFrame {
protected:
explicit nsMathMLmathBlockFrame(ComputedStyle* aStyle,
nsPresContext* aPresContext)
- : nsBlockFrame(aStyle, aPresContext, kClassID) {
- }
+ : nsBlockFrame(aStyle, aPresContext, kClassID) {}
virtual ~nsMathMLmathBlockFrame() = default;
};
diff --git a/layout/mathml/nsMathMLmoFrame.cpp b/layout/mathml/nsMathMLmoFrame.cpp
index e0d68234ae..e27709c0b0 100644
--- a/layout/mathml/nsMathMLmoFrame.cpp
+++ b/layout/mathml/nsMathMLmoFrame.cpp
@@ -8,6 +8,7 @@
#include "gfxContext.h"
#include "mozilla/PresShell.h"
+#include "mozilla/StaticPrefs_mathml.h"
#include "nsCSSValue.h"
#include "nsLayoutUtils.h"
#include "nsPresContext.h"
@@ -145,15 +146,17 @@ void nsMathMLmoFrame::ProcessTextData() {
mFlags |= allFlags & NS_MATHML_OPERATOR_ACCENT;
mFlags |= allFlags & NS_MATHML_OPERATOR_MOVABLELIMITS;
- // see if this is an operator that should be centered to cater for
- // fonts that are not math-aware
- if (1 == length) {
- if ((ch == '+') || (ch == '=') || (ch == '*') ||
- (ch == 0x2212) || // &minus;
- (ch == 0x2264) || // &le;
- (ch == 0x2265) || // &ge;
- (ch == 0x00D7)) { // &times;
- mFlags |= NS_MATHML_OPERATOR_CENTERED;
+ if (!StaticPrefs::mathml_centered_operators_disabled()) {
+ // see if this is an operator that should be centered to cater for
+ // fonts that are not math-aware
+ if (1 == length) {
+ if ((ch == '+') || (ch == '=') || (ch == '*') ||
+ (ch == 0x2212) || // &minus;
+ (ch == 0x2264) || // &le;
+ (ch == 0x2265) || // &ge;
+ (ch == 0x00D7)) { // &times;
+ mFlags |= NS_MATHML_OPERATOR_CENTERED;
+ }
}
}
@@ -593,9 +596,15 @@ nsMathMLmoFrame::Stretch(DrawTarget* aDrawTarget,
// get the leading to be left at the top and the bottom of the stretched char
// this seems more reliable than using fm->GetLeading() on suspicious fonts
- nscoord em;
- GetEmHeight(fm, em);
- nscoord leading = NSToCoordRound(0.2f * em);
+ const nscoord leading = [&fm] {
+ if (StaticPrefs::
+ mathml_top_bottom_spacing_for_stretchy_operators_disabled()) {
+ return 0;
+ }
+ nscoord em;
+ GetEmHeight(fm, em);
+ return NSToCoordRound(0.2f * (float)em);
+ }();
// Operators that are stretchy, or those that are to be centered
// to cater for fonts that are not math-aware, are handled by the MathMLChar
diff --git a/layout/mathml/nsMathMLmtableFrame.h b/layout/mathml/nsMathMLmtableFrame.h
index 1a801de8fc..dee6c5ba7a 100644
--- a/layout/mathml/nsMathMLmtableFrame.h
+++ b/layout/mathml/nsMathMLmtableFrame.h
@@ -222,7 +222,8 @@ class nsMathMLmtdFrame final : public nsTableCellFrame {
mozilla::nsDisplayListBuilder* aBuilder,
const mozilla::nsDisplayListSet& aLists) override;
- LogicalMargin GetBorderWidth(WritingMode aWM) const override;
+ mozilla::LogicalMargin GetBorderWidth(
+ mozilla::WritingMode aWM) const override;
nsMargin GetBorderOverflow() override;
diff --git a/layout/painting/RetainedDisplayListBuilder.cpp b/layout/painting/RetainedDisplayListBuilder.cpp
index ca8f37a252..18e9612ff2 100644
--- a/layout/painting/RetainedDisplayListBuilder.cpp
+++ b/layout/painting/RetainedDisplayListBuilder.cpp
@@ -1313,23 +1313,6 @@ bool RetainedDisplayListBuilder::ShouldBuildPartial(
return true;
}
-void RetainedDisplayListBuilder::InvalidateCaretFramesIfNeeded() {
- if (mPreviousCaret == mBuilder.GetCaretFrame()) {
- // The current caret frame is the same as the previous one.
- return;
- }
-
- if (mPreviousCaret) {
- mPreviousCaret->MarkNeedsDisplayItemRebuild();
- }
-
- if (mBuilder.GetCaretFrame()) {
- mBuilder.GetCaretFrame()->MarkNeedsDisplayItemRebuild();
- }
-
- mPreviousCaret = mBuilder.GetCaretFrame();
-}
-
class AutoClearFramePropsArray {
public:
explicit AutoClearFramePropsArray(size_t aCapacity) : mFrames(aCapacity) {}
@@ -1585,7 +1568,7 @@ PartialUpdateResult RetainedDisplayListBuilder::AttemptPartialUpdate(
MarkFramesWithItemsAndImagesModified(&mList);
}
- InvalidateCaretFramesIfNeeded();
+ mBuilder.InvalidateCaretFramesIfNeeded();
// We set the override dirty regions during ComputeRebuildRegion or in
// DisplayPortUtils::InvalidateForDisplayPortChange. The display port change
diff --git a/layout/painting/RetainedDisplayListBuilder.h b/layout/painting/RetainedDisplayListBuilder.h
index e9f5b56d1b..e255c4d3aa 100644
--- a/layout/painting/RetainedDisplayListBuilder.h
+++ b/layout/painting/RetainedDisplayListBuilder.h
@@ -200,11 +200,6 @@ class RetainedDisplayListBuilder {
void IncrementSubDocPresShellPaintCount(nsDisplayItem* aItem);
/**
- * Invalidates the current and previous caret frame if they have changed.
- */
- void InvalidateCaretFramesIfNeeded();
-
- /**
* A simple early exit heuristic to avoid slow partial display list rebuilds.
* Returns true if a partial display list build should be attempted.
*/
@@ -272,7 +267,6 @@ class RetainedDisplayListBuilder {
nsDisplayListBuilder mBuilder;
RetainedDisplayList mList;
- WeakFrame mPreviousCaret;
RetainedDisplayListMetrics mMetrics;
RetainedDisplayListData mData;
};
diff --git a/layout/painting/crashtests/1862277-1.html b/layout/painting/crashtests/1862277-1.html
index 820bade2fd..f732bb71b6 100644
--- a/layout/painting/crashtests/1862277-1.html
+++ b/layout/painting/crashtests/1862277-1.html
@@ -15,11 +15,7 @@ that is affected by the clip path a couple times. The retained display list won'
container, but the modified display list will have the nsDisplayMask, this will confuse merging when the
same item appears inside two different containers.
-Note that we set widget.windows.window_occlusion_tracking.enabled=false for this test because
-crashtests leave windows open and occlud the crashtest window, which means the refresh driver doesn't
-run, which means the requestAnimationFrame don't run. Bug 1864255 tracks fixing this.
-
-Note that we image.decode-sync.enabled=false for this test because sync decoding triggers extra
+Note that we image.testing.decode-sync.enabled=false for this test because sync decoding triggers extra
invalidation which "fixes" this bug before it gets a chance to appear. Bug 1866411 tracks this.
-->
diff --git a/layout/painting/crashtests/1870415-1.html b/layout/painting/crashtests/1870415-1.html
new file mode 100644
index 0000000000..ef379dad4d
--- /dev/null
+++ b/layout/painting/crashtests/1870415-1.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait" >
+
+<style>
+HTML {
+ border: lch(53% 16 none) solid 472288419.0851412mm;
+ background-blend-mode: difference
+}
+* {
+ overflow-y: hidden;
+ position: sticky;
+ content-visibility: auto;
+ background: url(#x) local, scroll repeat-x bottom / contain, left 3% center / contain scroll padding-box, image-set('\E0FAEt\1BA3F\E0379o8' type('c\1D242+\6F0\A8E6**=\D\A\11D5D\1F9D4*\A0\FFF9 2\1F500\6F9\26F1C\2F220 0\D\1FE4C\2064*|\301\62DC\1DD1\101FD 3\643X\E00E6\E0998\2B4C7Y\6F0+*=\23DD6 A>\1615A\101FD\E0C32\1DE4\2F51D\A34A\1D908\1D244\1F9FB*"\135F-=%Z\1D172\1BF1C\C7D\A16B\669\FFFF\A21F\161BF\E0E63\3099\1BBDB\1924\E006C 4\20F9D-\101FD\E3F7\D\3099\2F97E\B>>=5\669\2998A\E0A33\E0450\1D1AC\2FDC2\2FE9E\D\1F973\E0918>\E0493\346\209BC\1D244 c4\1F469\669\E0563\D\Al3\2027\66A') 249dppx, '\E0E1B\E0500\2CC7\E020A+\FDDE\66A 0\A 5\200E\2FD7A/*\1F82 91\2F69F\D\1A7F\FE20(\D-\2F9B0\202A,\3099\FFF9\2FFEA 99G\FE22\11A03 e\16D58]7\1B7D8y\ED25\E08AB\D\A\7F2\235FE\1DBB1\3000\1B71\2029\E08A1vH|=\B751\D\0\66A' type('\23A\2F300\BCC\B48E\1D187 7\E0969\98D3\BBC5\133DF?[\2F36E\1F252\E04CE>>=\2F94D.\660\1D243\E029A 3\27048L\2BF98\2FF8B\7F1\66A\1D168 9\2826\101FD\390\1B07D 29\669\7E5DZ\2029\6F9\6F0\11F0D\27DA2\2F7EB\29A96\E05A5sA\D;\253CB\660\166D6\E0C9C*=\2F046\A682\2044\660o\296A9p\2011{\202D\202F\9\2F8BD C\\#\2A9A7\645') 75dpcm, '\301\4430\301\2F40D\1D943\16DFC 8R\12ED6\1FC45\2426\2FEA8 0<<=\29E7D\2AC8E\D\2028\66A\1D244\1125A\16FE7\D\D\16ED4\66B\1D0BA|=\FB2C\E0C77\BF-\2F93B\23A\A\D^=s\F6D5\E02EB\E008D\36A\0\\\1B885\205F/=\E0FD5\3000#8]n\6F9s\2F9B7\1A7F\B^\1D574!U4\2F645\E0A65\2060B;\FDFA\D>>=\1648A\D3EC\24A09\E05AE\E02FF\A0\E078E{\E0135\2FB3F\1D16E f\1D1AA\4FFB\3A7A\16943\A\D\E032B' 11dppx type('\489\5932\E0A6B\6F9\1F7A0\66A\1F182\205F\D\A\7F3\1DD7\16110\1D11B\1BADC\72E5\12CDB\E034E\25E85\8\669\AD\3000 9')), border-box repeat-x;
+ rotate: 2116778118.5570207grad 32 20208 64
+}
+</style>
+<script>
+window.addEventListener("load", () => {
+ let a = document.createElementNS("http://www.w3.org/1999/xhtml", "form")
+ document.documentElement.appendChild(a)
+ let b = document.createElementNS("http://www.w3.org/1999/xhtml", "p")
+ let c = document.createElementNS("http://www.w3.org/1999/xhtml", "span")
+ let d = document.createElementNS("http://www.w3.org/1999/xhtml", "bdo")
+ d.contentEditable = true
+ d.setAttribute("autofocus", true)
+ c.appendChild(d)
+ b.appendChild(c)
+ a.appendChild(b)
+ setTimeout(finish, 1000);
+});
+function finish() {
+ document.documentElement.className = "";
+}
+</script>
+</html>
diff --git a/layout/painting/crashtests/crashtests.list b/layout/painting/crashtests/crashtests.list
index af2df7830c..b51fa60007 100644
--- a/layout/painting/crashtests/crashtests.list
+++ b/layout/painting/crashtests/crashtests.list
@@ -8,7 +8,7 @@ load 1418722-1.html
load 1419917.html
load 1425271-1.html
load 1428906-1.html
-pref(widget.windows.window_occlusion_tracking.enabled,false) load 1430589-1.html # Bug 1819154
+load 1430589-1.html
load 1454105-1.html
load 1455944-1.html
load 1458145.html
@@ -18,7 +18,7 @@ load 1469472.html
load 1477831-1.html
load 1504033.html
load 1514544-1.html
-asserts(0-1) asserts-if(Android,0-2) load 1547420-1.html
+asserts(0-10) load 1547420-1.html # bug 1524064
load 1549909.html
load 1551389-1.html
asserts(0-2) load 1555819-1.html
@@ -31,4 +31,5 @@ load 1714584-1.html
load 1763006-1.html
load 1819957-1.html
load 1851726-1.html
-pref(widget.windows.window_occlusion_tracking.enabled,false) pref(image.decode-sync.enabled,false) load 1862277-1.html
+pref(image.testing.decode-sync.enabled,false) load 1862277-1.html
+needs-focus pref(ui.caretBlinkTime,200) pref(image.testing.decode-sync.enabled,false) asserts(0-2) load 1870415-1.html
diff --git a/layout/painting/nsCSSRenderingGradients.cpp b/layout/painting/nsCSSRenderingGradients.cpp
index 2fb2f0b024..db30d4fefc 100644
--- a/layout/painting/nsCSSRenderingGradients.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -1195,15 +1195,16 @@ class MOZ_STACK_CLASS WrColorStopInterpolator
WrColorStopInterpolator(
const nsTArray<ColorStop>& aStops,
const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
- float aOpacity, nsTArray<wr::GradientStop>& aResult)
- : ColorStopInterpolator(aStops, aStyleColorInterpolationMethod),
+ float aOpacity, nsTArray<wr::GradientStop>& aResult, bool aExtendLastStop)
+ : ColorStopInterpolator(aStops, aStyleColorInterpolationMethod,
+ aExtendLastStop),
mResult(aResult),
mOpacity(aOpacity),
mOutputStop(0) {}
void CreateStops() {
mResult.SetLengthAndRetainStorage(0);
- // we always emit at least two stops (start and end) for each input stop,
+ // We always emit at least two stops (start and end) for each input stop,
// which avoids ambiguity with incomplete oklch/lch/hsv/hsb color stops for
// the last stop pair, where the last color stop can't be interpreted on its
// own because it actually depends on the previous stop.
@@ -1257,11 +1258,26 @@ void nsCSSGradientRenderer::BuildWebRenderParameters(
// * https://bugzilla.mozilla.org/show_bug.cgi?id=1248178
StyleColorInterpolationMethod styleColorInterpolationMethod =
mGradient->ColorInterpolationMethod();
- if (mStops.Length() >= 2 &&
- (styleColorInterpolationMethod.space != StyleColorSpace::Srgb ||
- gfxPlatform::GetCMSMode() == CMSMode::All)) {
+ // For colorspaces supported by WebRender (Srgb, Hsl, Hwb) we technically do
+ // not need to add extra stops, but the only one of those colorspaces that
+ // appears frequently is Srgb, and Srgb still needs extra stops if CMS is
+ // enabled. Hsl/Hwb need extra stops if StyleHueInterpolationMethod is not
+ // Shorter, or if CMS is enabled.
+ //
+ // It's probably best to keep this logic as simple as possible, see
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1885716 for an example of
+ // what can happen if we try to be clever here.
+ if (styleColorInterpolationMethod.space != StyleColorSpace::Srgb ||
+ gfxPlatform::GetCMSMode() == CMSMode::All) {
+ // For the specific case of longer hue interpolation on a CSS non-repeating
+ // gradient, we have to pretend there is another stop at position=1.0 that
+ // duplicates the last stop, this is probably only used for things like a
+ // color wheel. No such problem for SVG as it doesn't have that complexity.
+ bool extendLastStop = aMode == wr::ExtendMode::Clamp &&
+ styleColorInterpolationMethod.hue ==
+ StyleHueInterpolationMethod::Longer;
WrColorStopInterpolator interpolator(mStops, styleColorInterpolationMethod,
- aOpacity, aStops);
+ aOpacity, aStops, extendLastStop);
interpolator.CreateStops();
} else {
aStops.SetLength(mStops.Length());
diff --git a/layout/painting/nsCSSRenderingGradients.h b/layout/painting/nsCSSRenderingGradients.h
index 549cd8c4b6..68ecab07ae 100644
--- a/layout/painting/nsCSSRenderingGradients.h
+++ b/layout/painting/nsCSSRenderingGradients.h
@@ -44,23 +44,38 @@ class MOZ_STACK_CLASS ColorStopInterpolator {
public:
ColorStopInterpolator(
const nsTArray<ColorStop>& aStops,
- const StyleColorInterpolationMethod& aStyleColorInterpolationMethod)
+ const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
+ bool aExtendLastStop)
: mStyleColorInterpolationMethod(aStyleColorInterpolationMethod),
- mStops(aStops) {}
+ mStops(aStops),
+ mExtendLastStop(aExtendLastStop) {}
void CreateStops() {
- for (uint32_t i = 0; i < mStops.Length() - 1; i++) {
+ // This loop intentionally iterates the last stop if extending.
+ uint32_t iterStops = mStops.Length() - (mExtendLastStop ? 0 : 1);
+ for (uint32_t i = 0; i < iterStops; i++) {
+ auto nextindex = i + 1 < mStops.Length() ? i + 1 : i;
const auto& start = mStops[i];
- const auto& end = mStops[i + 1];
+ const auto& end = mStops[nextindex];
+ float startPosition = start.mPosition;
+ float endPosition = end.mPosition;
+ // For CSS non-repeating gradients with longer hue specified, we have to
+ // pretend there is a stop beyond the last stop. This is never the case
+ // on SVG gradients as they only use shorter hue.
+ //
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1885716 for more info.
+ if (i == mStops.Length() - 1 && mExtendLastStop) {
+ endPosition = 1.0f;
+ }
uint32_t extraStops =
- (uint32_t)(floor(end.mPosition * kFullRangeExtraStops) -
- floor(start.mPosition * kFullRangeExtraStops));
+ (uint32_t)(floor(endPosition * kFullRangeExtraStops) -
+ floor(startPosition * kFullRangeExtraStops));
extraStops = clamped(extraStops, 1U, kFullRangeExtraStops);
float step = 1.0f / (float)extraStops;
for (uint32_t extraStop = 0; extraStop <= extraStops; extraStop++) {
auto progress = (float)extraStop * step;
auto position =
- start.mPosition + progress * (end.mPosition - start.mPosition);
+ startPosition + progress * (endPosition - startPosition);
StyleAbsoluteColor color =
Servo_InterpolateColor(mStyleColorInterpolationMethod, &end.mColor,
&start.mColor, progress);
@@ -73,11 +88,15 @@ class MOZ_STACK_CLASS ColorStopInterpolator {
protected:
StyleColorInterpolationMethod mStyleColorInterpolationMethod;
const nsTArray<ColorStop>& mStops;
+ // This indicates that we want to extend the endPosition on the last stop,
+ // which only matters if this is a CSS non-repeating gradient with
+ // StyleHueInterpolationMethod::Longer (only valid for hsl/hwb/lch/oklch).
+ bool mExtendLastStop;
- // this could be made tunable, but at 1.0/128 the error is largely
+ // This could be made tunable, but at 1.0/128 the error is largely
// irrelevant, as WebRender re-encodes it to 128 pairs of stops.
//
- // note that we don't attempt to place the positions of these stops
+ // Note that we don't attempt to place the positions of these stops
// precisely at intervals, we just add this many extra stops across the
// range where it is convenient.
inline static const uint32_t kFullRangeExtraStops = 128;
diff --git a/layout/painting/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
index 78388d2185..0007f86c5e 100644
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -383,6 +383,36 @@ nsDisplayWrapList* nsDisplayListBuilder::MergeItems(
return merged;
}
+// FIXME(emilio): This whole business should ideally not be needed at all, but
+// there are a variety of hard-to-deal-with caret invalidation issues, like
+// bug 1888583, and caret changes are relatively uncommon, enough that it
+// probably isn't worth chasing all them down.
+void nsDisplayListBuilder::InvalidateCaretFramesIfNeeded() {
+ if (mPaintedCarets.IsEmpty()) {
+ return;
+ }
+ size_t i = mPaintedCarets.Length();
+ while (i--) {
+ nsCaret* caret = mPaintedCarets[i];
+ nsIFrame* oldCaret = caret->GetLastPaintedFrame();
+ nsRect caretRect;
+ nsIFrame* currentCaret = caret->GetPaintGeometry(&caretRect);
+ if (oldCaret == currentCaret) {
+ // Keep tracking this caret, it hasn't changed.
+ continue;
+ }
+ if (oldCaret) {
+ oldCaret->MarkNeedsDisplayItemRebuild();
+ }
+ if (currentCaret) {
+ currentCaret->MarkNeedsDisplayItemRebuild();
+ }
+ // If / when we paint this caret, we'll track it again.
+ caret->SetLastPaintedFrame(nullptr);
+ mPaintedCarets.RemoveElementAt(i);
+ }
+}
+
void nsDisplayListBuilder::AutoCurrentActiveScrolledRootSetter::
SetCurrentActiveScrolledRoot(
const ActiveScrolledRoot* aActiveScrolledRoot) {
@@ -650,7 +680,6 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mCurrentContainerASR(nullptr),
mCurrentFrame(aReferenceFrame),
mCurrentReferenceFrame(aReferenceFrame),
- mCaretFrame(nullptr),
mScrollInfoItemsForHoisting(nullptr),
mFirstClipChainToDestroy(nullptr),
mTableBackgroundSet(nullptr),
@@ -718,21 +747,6 @@ nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
mRetainingDisplayList && StaticPrefs::layout_display_list_retain_sc();
}
-static PresShell* GetFocusedPresShell() {
- nsPIDOMWindowOuter* focusedWnd =
- nsFocusManager::GetFocusManager()->GetFocusedWindow();
- if (!focusedWnd) {
- return nullptr;
- }
-
- nsCOMPtr<nsIDocShell> focusedDocShell = focusedWnd->GetDocShell();
- if (!focusedDocShell) {
- return nullptr;
- }
-
- return focusedDocShell->GetPresShell();
-}
-
void nsDisplayListBuilder::BeginFrame() {
nsCSSRendering::BeginFrameTreesLocked();
@@ -742,26 +756,6 @@ void nsDisplayListBuilder::BeginFrame() {
mInTransform = false;
mInFilter = false;
mSyncDecodeImages = false;
-
- if (!mBuildCaret) {
- return;
- }
-
- RefPtr<PresShell> presShell = GetFocusedPresShell();
- if (presShell) {
- RefPtr<nsCaret> caret = presShell->GetCaret();
- mCaretFrame = caret->GetPaintGeometry(&mCaretRect);
-
- // The focused pres shell may not be in the document that we're
- // painting, or be in a popup. Check if the display root for
- // the caret matches the display root that we're painting, and
- // only use it if it matches.
- if (mCaretFrame &&
- nsLayoutUtils::GetDisplayRootFrame(mCaretFrame) !=
- nsLayoutUtils::GetDisplayRootFrame(mReferenceFrame)) {
- mCaretFrame = nullptr;
- }
- }
}
void nsDisplayListBuilder::AddEffectUpdate(dom::RemoteBrowser* aBrowser,
@@ -801,7 +795,6 @@ void nsDisplayListBuilder::EndFrame() {
FreeClipChains();
FreeTemporaryItems();
nsCSSRendering::EndFrameTreesLocked();
- mCaretFrame = nullptr;
}
void nsDisplayListBuilder::MarkFrameForDisplay(nsIFrame* aFrame,
@@ -1141,12 +1134,32 @@ void nsDisplayListBuilder::EnterPresShell(const nsIFrame* aReferenceFrame,
return;
}
- // Caret frames add visual area to their frame, but we don't update the
- // overflow area. Use flags to make sure we build display items for that frame
- // instead.
- if (mCaretFrame && mCaretFrame->PresShell() == state->mPresShell) {
- MarkFrameForDisplay(mCaretFrame, aReferenceFrame);
- }
+ state->mCaretFrame = [&]() -> nsIFrame* {
+ RefPtr<nsCaret> caret = state->mPresShell->GetCaret();
+ nsIFrame* currentCaret = caret->GetPaintGeometry(&mCaretRect);
+ if (!currentCaret) {
+ return nullptr;
+ }
+
+ // Check if the display root for the caret matches the display root that
+ // we're painting, and only use it if it matches. Likely we only need this
+ // for carets inside popups.
+ if (nsLayoutUtils::GetDisplayRootFrame(currentCaret) !=
+ nsLayoutUtils::GetDisplayRootFrame(aReferenceFrame)) {
+ return nullptr;
+ }
+
+ // Caret frames add visual area to their frame, but we don't update the
+ // overflow area. Use flags to make sure we build display items for that
+ // frame instead.
+ MOZ_ASSERT(currentCaret->PresShell() == state->mPresShell);
+ MarkFrameForDisplay(currentCaret, aReferenceFrame);
+ caret->SetLastPaintedFrame(currentCaret);
+ if (!mPaintedCarets.Contains(caret)) {
+ mPaintedCarets.AppendElement(std::move(caret));
+ }
+ return currentCaret;
+ }();
}
// A non-blank paint is a paint that does not just contain the canvas
@@ -2534,9 +2547,7 @@ struct ZSortItem {
};
struct ZOrderComparator {
- bool operator()(const ZSortItem& aLeft, const ZSortItem& aRight) const {
- // Note that we can't just take the difference of the two
- // z-indices here, because that might overflow a 32-bit int.
+ bool LessThan(const ZSortItem& aLeft, const ZSortItem& aRight) const {
return aLeft.zIndex < aRight.zIndex;
}
};
@@ -2549,7 +2560,7 @@ struct ContentComparator {
explicit ContentComparator(nsIContent* aCommonAncestor)
: mCommonAncestor(aCommonAncestor) {}
- bool operator()(nsDisplayItem* aLeft, nsDisplayItem* aRight) const {
+ bool LessThan(nsDisplayItem* aLeft, nsDisplayItem* aRight) const {
// It's possible that the nsIContent for aItem1 or aItem2 is in a
// subdocument of commonAncestor, because display items for subdocuments
// have been mixed into the same list. Ensure that we're looking at content
@@ -2562,7 +2573,8 @@ struct ContentComparator {
// Something weird going on
return true;
}
- return nsContentUtils::CompareTreePosition<TreeKind::Flat>(
+ return content1 != content2 &&
+ nsContentUtils::CompareTreePosition<TreeKind::Flat>(
content1, content2, mCommonAncestor) < 0;
}
};
@@ -4134,8 +4146,7 @@ bool nsDisplayCaret::CreateWebRenderCommands(
nscolor caretColor;
nsIFrame* frame =
mCaret->GetPaintGeometry(&caretRect, &hookRect, &caretColor);
- MOZ_ASSERT(frame == mFrame, "We're referring different frame");
- if (!frame) {
+ if (NS_WARN_IF(!frame) || NS_WARN_IF(frame != mFrame)) {
return true;
}
@@ -5196,7 +5207,7 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
Maybe<wr::WrAnimationProperty> prop;
bool needsProp = aManager->LayerManager()->AsyncPanZoomEnabled() &&
(IsScrollThumbLayer() || IsZoomingLayer() ||
- ShouldGetFixedOrStickyAnimationId() ||
+ ShouldGetFixedAnimationId() ||
(IsRootScrollbarContainer() && HasDynamicToolbar()));
if (needsProp) {
@@ -5223,7 +5234,7 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
params.prim_flags |= wr::PrimitiveFlags::IS_SCROLLBAR_CONTAINER;
}
if (IsZoomingLayer() ||
- (ShouldGetFixedOrStickyAnimationId() ||
+ (ShouldGetFixedAnimationId() ||
(IsRootScrollbarContainer() && HasDynamicToolbar()))) {
params.is_2d_scale_translation = true;
params.should_snap = true;
@@ -5239,9 +5250,8 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
bool nsDisplayOwnLayer::UpdateScrollData(WebRenderScrollData* aData,
WebRenderLayerScrollData* aLayerData) {
- bool isRelevantToApz =
- (IsScrollThumbLayer() || IsScrollbarContainer() || IsZoomingLayer() ||
- ShouldGetFixedOrStickyAnimationId());
+ bool isRelevantToApz = (IsScrollThumbLayer() || IsScrollbarContainer() ||
+ IsZoomingLayer() || ShouldGetFixedAnimationId());
if (!isRelevantToApz) {
return false;
@@ -5256,16 +5266,11 @@ bool nsDisplayOwnLayer::UpdateScrollData(WebRenderScrollData* aData,
return true;
}
- if (IsFixedPositionLayer() && ShouldGetFixedOrStickyAnimationId()) {
+ if (IsFixedPositionLayer() && ShouldGetFixedAnimationId()) {
aLayerData->SetFixedPositionAnimationId(mWrAnimationId);
return true;
}
- if (IsStickyPositionLayer() && ShouldGetFixedOrStickyAnimationId()) {
- aLayerData->SetStickyPositionAnimationId(mWrAnimationId);
- return true;
- }
-
MOZ_ASSERT(IsScrollbarContainer() || IsScrollThumbLayer());
aLayerData->SetScrollbarData(mScrollbarData);
@@ -5447,7 +5452,7 @@ bool nsDisplayFixedPosition::UpdateScrollData(
return true;
}
-bool nsDisplayFixedPosition::ShouldGetFixedOrStickyAnimationId() {
+bool nsDisplayFixedPosition::ShouldGetFixedAnimationId() {
#if defined(MOZ_WIDGET_ANDROID)
return mFrame->PresContext()->IsRootContentDocumentCrossProcess() &&
nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext()) ==
@@ -5511,7 +5516,8 @@ nsDisplayStickyPosition::nsDisplayStickyPosition(
: nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot),
mContainerASR(aContainerASR),
mClippedToDisplayPort(aClippedToDisplayPort),
- mShouldFlatten(false) {
+ mShouldFlatten(false),
+ mWrStickyAnimationId(0) {
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
}
@@ -5727,12 +5733,27 @@ bool nsDisplayStickyPosition::CreateWebRenderCommands(
wr::LayoutVector2D applied = {
NSAppUnitsToFloatPixels(appliedOffset.x, auPerDevPixel),
NSAppUnitsToFloatPixels(appliedOffset.y, auPerDevPixel)};
+ bool needsProp = ShouldGetStickyAnimationId();
+ Maybe<wr::WrAnimationProperty> prop;
+ auto spatialKey = wr::SpatialKey(uint64_t(mFrame), GetPerFrameKey(),
+ wr::SpatialKeyKind::Sticky);
+ if (needsProp) {
+ RefPtr<WebRenderAPZAnimationData> animationData =
+ aManager->CommandBuilder()
+ .CreateOrRecycleWebRenderUserData<WebRenderAPZAnimationData>(
+ this);
+ mWrStickyAnimationId = animationData->GetAnimationId();
+
+ prop.emplace();
+ prop->id = mWrStickyAnimationId;
+ prop->key = spatialKey;
+ prop->effect_type = wr::WrAnimationType::Transform;
+ }
wr::WrSpatialId spatialId = aBuilder.DefineStickyFrame(
wr::ToLayoutRect(bounds), topMargin.ptrOr(nullptr),
rightMargin.ptrOr(nullptr), bottomMargin.ptrOr(nullptr),
- leftMargin.ptrOr(nullptr), vBounds, hBounds, applied,
- wr::SpatialKey(uint64_t(mFrame), GetPerFrameKey(),
- wr::SpatialKeyKind::Sticky));
+ leftMargin.ptrOr(nullptr), vBounds, hBounds, applied, spatialKey,
+ prop.ptrOr(nullptr));
saccHelper.emplace(aBuilder, spatialId);
aManager->CommandBuilder().PushOverrideForASR(mContainerASR, spatialId);
@@ -5801,6 +5822,10 @@ bool nsDisplayStickyPosition::UpdateScrollData(
->GetContent());
aLayerData->SetStickyPositionScrollContainerId(scrollId);
}
+
+ if (ShouldGetStickyAnimationId()) {
+ aLayerData->SetStickyPositionAnimationId(mWrStickyAnimationId);
+ }
}
// Return true if either there is a dynamic toolbar affecting this sticky
// item or the OwnLayer base implementation returns true for some other
@@ -5810,21 +5835,8 @@ bool nsDisplayStickyPosition::UpdateScrollData(
return ret;
}
-bool nsDisplayStickyPosition::ShouldGetFixedOrStickyAnimationId() {
-#if defined(MOZ_WIDGET_ANDROID)
- if (HasDynamicToolbar()) { // also implies being in the cross-process RCD
- StickyScrollContainer* stickyScrollContainer = GetStickyScrollContainer();
- if (stickyScrollContainer) {
- ScrollableLayerGuid::ViewID scrollId =
- nsLayoutUtils::FindOrCreateIDFor(stickyScrollContainer->ScrollFrame()
- ->GetScrolledFrame()
- ->GetContent());
- return nsLayoutUtils::ScrollIdForRootScrollFrame(mFrame->PresContext()) ==
- scrollId;
- }
- }
-#endif
- return false;
+bool nsDisplayStickyPosition::ShouldGetStickyAnimationId() const {
+ return HasDynamicToolbar(); // also implies being in the cross-process RCD
}
nsDisplayScrollInfoLayer::nsDisplayScrollInfoLayer(
diff --git a/layout/painting/nsDisplayList.h b/layout/painting/nsDisplayList.h
index 5064677cc7..9862415f61 100644
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -659,7 +659,7 @@ class nsDisplayListBuilder {
* Get the frame that the caret is supposed to draw in.
* If the caret is currently invisible, this will be null.
*/
- nsIFrame* GetCaretFrame() { return mCaretFrame; }
+ nsIFrame* GetCaretFrame() { return CurrentPresShellState()->mCaretFrame; }
/**
* Get the rectangle we're supposed to draw the caret into.
*/
@@ -852,9 +852,9 @@ class nsDisplayListBuilder {
/**
* Notifies the builder that a particular themed widget exists
* at the given rectangle within the currently built display list.
- * For certain appearance values (currently only StyleAppearance::Toolbar and
- * StyleAppearance::WindowTitlebar) this gets called during every display list
- * construction, for every themed widget of the right type within the
+ * For certain appearance values (currently only
+ * StyleAppearance::MozWindowTitlebar) this gets called during every display
+ * list construction, for every themed widget of the right type within the
* display list, except for themed widgets which are transformed or have
* effects applied to them (e.g. CSS opacity or filters).
*
@@ -904,6 +904,11 @@ class nsDisplayListBuilder {
const dom::EffectsInfo& aUpdate);
/**
+ * Invalidates the caret frames from previous paints, if they have changed.
+ */
+ void InvalidateCaretFramesIfNeeded();
+
+ /**
* Allocate memory in our arena. It will only be freed when this display list
* builder is destroyed. This memory holds nsDisplayItems and
* DisplayItemClipChain objects.
@@ -1729,6 +1734,7 @@ class nsDisplayListBuilder {
bool mInsidePointerEventsNoneDoc;
bool mTouchEventPrefEnabledDoc;
nsIFrame* mPresShellIgnoreScrollFrame;
+ nsIFrame* mCaretFrame = nullptr;
};
PresShellState* CurrentPresShellState() {
@@ -1763,7 +1769,6 @@ class nsDisplayListBuilder {
// The reference frame for mCurrentFrame.
const nsIFrame* mCurrentReferenceFrame;
- nsIFrame* mCaretFrame;
// A temporary list that we append scroll info items to while building
// display items for the contents of frames with SVG effects.
// Only non-null when ShouldBuildScrollInfoItemsForHoisting() is true.
@@ -1808,6 +1813,9 @@ class nsDisplayListBuilder {
// Stores reusable items collected during display list preprocessing.
nsTHashSet<nsDisplayItem*> mReuseableItems;
+ // Tracked carets used for retained display list.
+ AutoTArray<RefPtr<nsCaret>, 1> mPaintedCarets;
+
// Tracked regions used for retained display list.
WeakFrameRegion mRetainedWindowDraggingRegion;
WeakFrameRegion mRetainedWindowNoDraggingRegion;
@@ -3195,12 +3203,13 @@ class nsDisplayList {
// array of 20 items should be able to avoid a lot of dynamic allocations
// here.
AutoTArray<Item, 20> items;
+ // Ensure we need just one alloc otherwise, no-op if enough.
+ items.SetCapacity(Length());
for (nsDisplayItem* item : TakeItems()) {
items.AppendElement(Item(item));
}
-
- std::stable_sort(items.begin(), items.end(), aComparator);
+ items.StableSort(aComparator);
for (Item& item : items) {
AppendToTop(item);
@@ -3208,6 +3217,7 @@ class nsDisplayList {
}
nsDisplayList TakeItems() {
+ // This std::move makes this a defined empty list, see assignment operator.
nsDisplayList list = std::move(*this);
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
list.mAllowNonEmptyDestruction = true;
@@ -5465,7 +5475,7 @@ class nsDisplayOwnLayer : public nsDisplayWrapList {
bool IsFixedPositionLayer() const;
bool IsStickyPositionLayer() const;
bool HasDynamicToolbar() const;
- virtual bool ShouldGetFixedOrStickyAnimationId() { return false; }
+ virtual bool ShouldGetFixedAnimationId() { return false; }
bool CreatesStackingContextHelper() override { return true; }
@@ -5481,6 +5491,16 @@ class nsDisplayOwnLayer : public nsDisplayWrapList {
*/
layers::ScrollbarData mScrollbarData;
bool mForceActive;
+
+ // Used for APZ to animate this layer for purposes such as
+ // pinch-zooming or scrollbar thumb movement. Note that setting this
+ // creates a WebRender ReferenceFrame spatial node, and should only
+ // be used for display items that establish a Gecko reference frame
+ // as well (or leaf items like scrollbar thumb nodes where it does not
+ // matter).
+ // FIXME: This is currently also used for adjusting position:fixed items
+ // for dynamic toolbar movement. This may be a problem as position:fixed
+ // items do not establish Gecko reference frames.
uint64_t mWrAnimationId;
};
@@ -5540,7 +5560,8 @@ class nsDisplayStickyPosition : public nsDisplayOwnLayer {
: nsDisplayOwnLayer(aBuilder, aOther),
mContainerASR(aOther.mContainerASR),
mClippedToDisplayPort(aOther.mClippedToDisplayPort),
- mShouldFlatten(false) {
+ mShouldFlatten(false),
+ mWrStickyAnimationId(0) {
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
}
@@ -5565,7 +5586,6 @@ class nsDisplayStickyPosition : public nsDisplayOwnLayer {
bool UpdateScrollData(layers::WebRenderScrollData* aData,
layers::WebRenderLayerScrollData* aLayerData) override;
- bool ShouldGetFixedOrStickyAnimationId() override;
const ActiveScrolledRoot* GetContainerASR() const { return mContainerASR; }
@@ -5581,6 +5601,8 @@ class nsDisplayStickyPosition : public nsDisplayOwnLayer {
return mShouldFlatten;
}
+ bool ShouldGetStickyAnimationId() const;
+
private:
NS_DISPLAY_ALLOW_CLONING()
@@ -5610,6 +5632,13 @@ class nsDisplayStickyPosition : public nsDisplayOwnLayer {
// True if this item should be flattened away.
bool mShouldFlatten;
+
+ // Used for APZ to animate the sticky element in the compositor
+ // for purposes such as dynamic toolbar movement and (in the future)
+ // overscroll-related adjustment. Unlike nsDisplayOwnLayer::mWrAnimationId,
+ // this does not create a WebRender ReferenceFrame, which is important
+ // because sticky elements do not establish Gecko reference frames either.
+ uint64_t mWrStickyAnimationId;
};
class nsDisplayFixedPosition : public nsDisplayOwnLayer {
@@ -5651,7 +5680,7 @@ class nsDisplayFixedPosition : public nsDisplayOwnLayer {
nsDisplayListBuilder* aDisplayListBuilder) override;
bool UpdateScrollData(layers::WebRenderScrollData* aData,
layers::WebRenderLayerScrollData* aLayerData) override;
- bool ShouldGetFixedOrStickyAnimationId() override;
+ bool ShouldGetFixedAnimationId() override;
void WriteDebugInfo(std::stringstream& aStream) override;
protected:
diff --git a/layout/printing/crashtests/1758199-1.html b/layout/printing/crashtests/1758199-1.html
index 3f7c9227a4..67ee0a73a2 100644
--- a/layout/printing/crashtests/1758199-1.html
+++ b/layout/printing/crashtests/1758199-1.html
@@ -1,54 +1 @@
-<html class="reftest-wait">
-<script>
-let pp;
-let documentElements = [];
-documentElements.push(document.documentElement);
-
-window.onload = () => {
- documentElements.push(document.documentElement);
-
- let o = document.getElementById('a')
- o.parentNode.appendChild(o)
- pp = SpecialPowers.wrap(self).printPreview();
- pp?.print()
- window.requestIdleCallback(() => {
- documentElements.push(document.documentElement);
-
- document.write('');
-
- setTimeout(finish, 100);
- });
-}
-
-function finish() {
-
- // The printPreview call above actually opens two print preview windows
- // because the <embed src='#'> below causes a second one to open. At least
- // we close the one window we can access, not sure if there is a way to get
- // ahold of the other window to close it. So this test leaves a window open
- // after it finishes.
- try { pp.close(); } catch (e) {}
-
- if (document.documentElement) {
- try { document.documentElement.className = ""; } catch (e) {}
- }
-
- // The documentElement that the reftest harness looks at to determine if the
- // test is done is not what document.documentElement points to when this code
- // is run. So we save all the document.documentElement's we encounter while
- // running this test and clear all of their class names.
- for (let de of documentElements) {
- if (de) {
- try {
- de.className = "";
- } catch (e) {}
- }
- }
-}
-</script>
-<style>
-:first-of-type { padding-block-start: 99% }
-</style>
-<mark id='a'>
-<embed src='#'>
-</html>
+<!-- file is now located at testing/crashtest/final/dom/base/crashtests/1758199-1.html -->
diff --git a/layout/printing/crashtests/crashtests.list b/layout/printing/crashtests/crashtests.list
index e2c57b282c..ec64509ddb 100644
--- a/layout/printing/crashtests/crashtests.list
+++ b/layout/printing/crashtests/crashtests.list
@@ -6,7 +6,7 @@ skip-if(Android) load 1662259.html
skip-if(Android) pref(dom.window.sizeToContent.enabled,true) load 1663722.html
skip-if(Android) load 1671503.html
load 1748277.html # Bug 1751260
-skip-if(Android) load 1758199-1.html # printPreview doesn't work on android
+# load 1758199-1.html # this test is run at the very end in testing/crashtest/final/crashtests.list
load 1804571.html
load 1804798.html
load 1804794.html
diff --git a/layout/reftests/async-scrolling/reftest.list b/layout/reftests/async-scrolling/reftest.list
index d74a1544b2..421129645a 100644
--- a/layout/reftests/async-scrolling/reftest.list
+++ b/layout/reftests/async-scrolling/reftest.list
@@ -12,7 +12,7 @@ skip-if(useDrawSnapshot) fuzzy-if(gtkWidget,0-1,0-87) fuzzy-if(!gtkWidget,0-1,0-
skip-if(useDrawSnapshot) == bg-fixed-child-no-culling-1.html bg-fixed-child-no-culling-1-ref.html
skip-if(useDrawSnapshot) == bg-fixed-child-no-culling-2.html bg-fixed-child-no-culling-2-ref.html
skip-if(useDrawSnapshot) == bg-fixed-child-no-culling-3.html bg-fixed-child-no-culling-3-ref.html
-fuzzy-if(Android,0-2,0-4000) fuzzy-if(cocoaWidget,0-2,0-179524) fuzzy-if(winWidget,0-1,0-74590) fuzzy-if(gtkWidget&&layersGPUAccelerated,0-1,0-3528) skip-if(useDrawSnapshot) fuzzy-if(geckoview,0-1,0-74590) == bg-fixed-transformed-image.html bg-fixed-transformed-image-ref.html
+fuzzy-if(Android,0-2,0-4000) fuzzy-if(cocoaWidget,0-2,0-179524) fuzzy-if(winWidget,0-1,0-74590) fuzzy-if(gtkWidget,0-1,0-3528) skip-if(useDrawSnapshot) fuzzy-if(geckoview,0-1,0-74590) == bg-fixed-transformed-image.html bg-fixed-transformed-image-ref.html
skip-if(useDrawSnapshot) == contain-paint-scrollable-frame-1.html contain-paint-scrollable-frame-1-ref.html
skip-if(useDrawSnapshot) == element-1.html element-1-ref.html
pref(layers.force-active,true) skip-if(useDrawSnapshot) == iframe-1.html iframe-1-ref.html
@@ -68,12 +68,12 @@ fuzzy-if(Android,0-13,0-465) fuzzy-if(gtkWidget,17-28,24-60) fuzzy-if(cocoaWidge
fuzzy-if(Android,0-13,0-465) fuzzy-if(gtkWidget,17-29,24-60) fuzzy-if(cocoaWidget,15-19,40-75) skip-if(useDrawSnapshot) == fixed-pos-scrolled-clip-4.html fixed-pos-scrolled-clip-4-ref.html # Bug 1604338
skip-if(useDrawSnapshot) == fixed-pos-scrolled-clip-5.html fixed-pos-scrolled-clip-5-ref.html
skip-if(useDrawSnapshot) == position-sticky-bug1434250.html position-sticky-bug1434250-ref.html
-fuzzy-if(Android,0-12,0-11) fuzzy-if(gtkWidget,16-25,12-32) fuzzy-if(cocoaWidget,13-16,20-44) skip-if(useDrawSnapshot) == position-sticky-scrolled-clip-1.html position-sticky-scrolled-clip-1-ref.html # Bug 1604338
+fuzzy-if(Android,0-12,0-45) fuzzy-if(gtkWidget,16-25,12-32) fuzzy-if(cocoaWidget,13-16,20-44) skip-if(useDrawSnapshot) == position-sticky-scrolled-clip-1.html position-sticky-scrolled-clip-1-ref.html # Bug 1604338
fuzzy-if(Android,0-6,0-4) skip == position-sticky-scrolled-clip-2.html position-sticky-scrolled-clip-2-ref.html # bug ?????? - incorrectly applying clip to sticky contents
fuzzy-if(Android,0-8,0-27) fuzzy-if(cocoaWidget,9-11,20-44) skip-if(useDrawSnapshot) == curtain-effect-1.html curtain-effect-1-ref.html
fuzzy-if(Android,0-7,0-9) fuzzy-if(gtkWidget,10-15,12-32) fuzzy-if(cocoaWidget,5-9,20-42) skip-if(useDrawSnapshot) == transformed-1.html transformed-1-ref.html # Bug 1604338
fuzzy-if(Android,2-7,1-12) fuzzy-if(gtkWidget,3-5,12-28) fuzzy-if(cocoaWidget,5-6,18-38) skip-if(useDrawSnapshot) fuzzy-if(swgl&&cocoaWidget&&isDebugBuild,0-6,0-38) == position-sticky-transformed-in-scrollframe-1.html position-sticky-transformed-in-scrollframe-1-ref.html # Bug 1604338
-fuzzy-if(Android,3-3,1-470) fuzzy-if(Android&&swgl&&isDebugBuild&&/^aarch64-gcc3/.test(xulRuntime.XPCOMABI),3-3,457-457) fuzzy-if(gtkWidget,13-20,12-32) fuzzy-if(cocoaWidget,12-16,20-44) skip-if(useDrawSnapshot) == position-sticky-transformed-in-scrollframe-2.html position-sticky-transformed-in-scrollframe-2-ref.html # Bug 1604338
+fuzzy-if(Android,3-3,1-470) fuzzy-if(gtkWidget,13-20,12-32) fuzzy-if(cocoaWidget,12-16,20-44) skip-if(useDrawSnapshot) == position-sticky-transformed-in-scrollframe-2.html position-sticky-transformed-in-scrollframe-2-ref.html # Bug 1604338
fuzzy-if(Android,12-13,4-31) fuzzy-if(gtkWidget,16-27,14-32) fuzzy-if(cocoaWidget,13-16,20-44) skip-if(useDrawSnapshot) == position-sticky-in-transformed-scrollframe-1.html position-sticky-in-transformed-scrollframe-ref.html # Bug 1604338
fuzzy-if(Android,12-13,4-31) fuzzy-if(gtkWidget,16-27,14-32) fuzzy-if(cocoaWidget,13-16,20-44) skip-if(useDrawSnapshot) == position-sticky-in-transformed-scrollframe-2.html position-sticky-in-transformed-scrollframe-ref.html # Bug 1604338
@@ -106,9 +106,9 @@ skip-if(useDrawSnapshot||Android) pref(apz.overscroll.enabled,false) pref(apz.ov
# for this test, apz.allow_zooming is needed to ensure we take the containerless scrolling codepath that creates
# an async zoom container (since we are testing a regression in that codepath)
skip-if(!Android) pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.bottom,50) == dynamic-toolbar-fixed-bottom-1.html dynamic-toolbar-fixed-bottom-1-ref.html
-skip-if(!Android) pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.bottom,50) == dynamic-toolbar-sticky-bottom-1.html dynamic-toolbar-sticky-bottom-1-ref.html
skip-if(!Android) pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.top,50) == dynamic-toolbar-fixed-top-1.html dynamic-toolbar-fixed-top-1-ref.html
-skip-if(!Android) pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.top,50) == dynamic-toolbar-sticky-top-1.html dynamic-toolbar-sticky-top-1-ref.html # bug 1627326 for geckoview&&!webrender
+pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.bottom,50) == dynamic-toolbar-sticky-bottom-1.html dynamic-toolbar-sticky-bottom-1-ref.html
+pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.top,50) == dynamic-toolbar-sticky-top-1.html dynamic-toolbar-sticky-top-1-ref.html
# The next block of tests are based on a single test page which has three
# sticky items (one sticky to the top, one sticky to the bottom, and one sticky
@@ -144,7 +144,7 @@ defaults
# at the top. Only the -5 and -6 scroll offsets are impacted, so the
# reference pages for first 4 scroll offsets are the same as the baseline
# case.
-defaults skip-if(!geckoview) pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.top,50) fuzzy(0-1,0-120000)
+defaults pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.top,50) fuzzy(0-1,0-120000)
== dynamic-toolbar-sticky-1a.html dynamic-toolbar-sticky-1-ref.html
== dynamic-toolbar-sticky-1b.html dynamic-toolbar-sticky-1-ref.html
== dynamic-toolbar-sticky-1c.html dynamic-toolbar-sticky-1-ref.html
@@ -161,17 +161,17 @@ defaults skip-if(!geckoview) pref(apz.allow_zooming,true) test-pref(apz.fixed-ma
== dynamic-toolbar-sticky-5b.html dynamic-toolbar-sticky-5-ref-t.html
== dynamic-toolbar-sticky-5c.html dynamic-toolbar-sticky-5-ref-t.html
== dynamic-toolbar-sticky-6a.html dynamic-toolbar-sticky-6-ref-t.html
-== dynamic-toolbar-sticky-6b.html dynamic-toolbar-sticky-6-ref-t.html # bug 1630274 for non-WR
+ == dynamic-toolbar-sticky-6b.html dynamic-toolbar-sticky-6-ref-t.html
== dynamic-toolbar-sticky-6c.html dynamic-toolbar-sticky-6-ref-t.html
defaults
# Same as above block of tests, except with the dynamic toolbar margin
# at the bottom of the page. This time the -1 and -2 scroll offsets are
# impacted.
-defaults skip-if(!geckoview) pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.bottom,50) fuzzy(0-1,0-120000)
+defaults pref(apz.allow_zooming,true) test-pref(apz.fixed-margin-override.enabled,true) test-pref(apz.fixed-margin-override.bottom,50) fuzzy(0-1,0-120000)
== dynamic-toolbar-sticky-1a.html dynamic-toolbar-sticky-1-ref-b.html
== dynamic-toolbar-sticky-1b.html dynamic-toolbar-sticky-1-ref-b.html
-== dynamic-toolbar-sticky-1c.html dynamic-toolbar-sticky-1-ref-b.html # bug 1630274 for non-WR
+ == dynamic-toolbar-sticky-1c.html dynamic-toolbar-sticky-1-ref-b.html
== dynamic-toolbar-sticky-2a.html dynamic-toolbar-sticky-2-ref-b.html
== dynamic-toolbar-sticky-2b.html dynamic-toolbar-sticky-2-ref-b.html
== dynamic-toolbar-sticky-2c.html dynamic-toolbar-sticky-2-ref-b.html
diff --git a/layout/reftests/bidi/dirAuto/reftest.list b/layout/reftests/bidi/dirAuto/reftest.list
index f47c635124..5fc24b2a2b 100644
--- a/layout/reftests/bidi/dirAuto/reftest.list
+++ b/layout/reftests/bidi/dirAuto/reftest.list
@@ -42,7 +42,7 @@
== dynamicDirAuto-setLTR-InvalidDir5.html dynamicDirAuto-refLTR-LTR.html
== dynamicDirAuto-setLTR-InvalidDir6.html dynamicDirAuto-refLTR-LTR.html
== dynamicDirAuto-setLTR-InvalidDir7.html dynamicDirAuto-refLTR-LTR.html
-== dynamicDirAuto-setLTR-InvalidDir7.html dynamicDirAuto-refLTR-LTR.html
+== dynamicDirAuto-setLTR-InvalidDir8.html dynamicDirAuto-refLTR-LTR.html
== dynamicDirAuto-setRTL-Auto1.html dynamicDirAuto-refRTL-RTL.html
fuzzy-if(Android,0-1,0-1) == dynamicDirAuto-setRTL-Auto2.html dynamicDirAuto-refRTL-RTL.html # android fuzz: bug 1461573
== dynamicDirAuto-setRTL-Auto3.html dynamicDirAuto-refRTL-RTL.html
diff --git a/layout/reftests/bugs/1888941-text-transform-emergency-wrap-ref.html b/layout/reftests/bugs/1888941-text-transform-emergency-wrap-ref.html
new file mode 100644
index 0000000000..1ae7db9050
--- /dev/null
+++ b/layout/reftests/bugs/1888941-text-transform-emergency-wrap-ref.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div>12345-<br>67890-<br>98765-<br>43210</div>
diff --git a/layout/reftests/bugs/1888941-text-transform-emergency-wrap.html b/layout/reftests/bugs/1888941-text-transform-emergency-wrap.html
new file mode 100644
index 0000000000..9e7c49cf57
--- /dev/null
+++ b/layout/reftests/bugs/1888941-text-transform-emergency-wrap.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 1px; text-transform: uppercase">12345-67890-98765-43210</div>
diff --git a/layout/reftests/bugs/307102-2-ref.html b/layout/reftests/bugs/307102-2-ref.html
deleted file mode 100644
index 8b72bc0383..0000000000
--- a/layout/reftests/bugs/307102-2-ref.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<html>
- <body>
- <div style="position: absolute; width: 100px;">
- <input style="position: absolute; top: 0; left: 0;">
- </div>
- </body>
-</html>
diff --git a/layout/reftests/bugs/307102-2.html b/layout/reftests/bugs/307102-2.html
deleted file mode 100644
index cfeb6658a9..0000000000
--- a/layout/reftests/bugs/307102-2.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE html>
-<html>
- <body>
- <div style="position: absolute; width: 100px;">
- <input style="position: absolute; top: 0; left: 0; right: 0">
- </div>
- </body>
-</html>
diff --git a/layout/reftests/bugs/385870-1-ref.html b/layout/reftests/bugs/385870-1-ref.html
deleted file mode 100644
index fcebd34fb2..0000000000
--- a/layout/reftests/bugs/385870-1-ref.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title></title>
-<style>
-#red {
- position: absolute;
- background-color: blue;
- top: 10px;
- left: 10px;
-}
-
-#green {
- position: absolute;
- background-color: blue;
- top: 10px;
- width: 80px;
- right: 10px;
-}
-
-#blue {
- position: absolute;
- background-color: blue;
- left: 10px;
- height: 80px;
- bottom: 10px;
-}
-
-#yellow {
- position: absolute;
- background-color: blue;
- right: 10px;
- width: 80px;
- height: 80px;
- bottom: 10px;
-}
-
-</style>
-<script>
-
-</script>
-</head>
-<body>
-
-<textarea id=red></textarea>
-<textarea id=green></textarea>
-<textarea id=blue></textarea>
-<textarea id=yellow></textarea>
-
-</body>
-</html>
diff --git a/layout/reftests/bugs/385870-1.html b/layout/reftests/bugs/385870-1.html
deleted file mode 100644
index 4d292e1c20..0000000000
--- a/layout/reftests/bugs/385870-1.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title></title>
-<style>
-#red {
- position: absolute;
- background-color: blue;
- top: 10px;
- left: 10px;
- right: 100px;
- bottom: 100px;
-}
-
-#green {
- position: absolute;
- background-color: blue;
- top: 10px;
- width: 80px;
- right: 10px;
- bottom: 100px;
-}
-
-#blue {
- position: absolute;
- background-color: blue;
- left: 10px;
- height: 80px;
- right: 100px;
- bottom: 10px;
-}
-
-#yellow {
- position: absolute;
- background-color: blue;
- right: 10px;
- width: 80px;
- height: 80px;
- bottom: 10px;
-}
-
-</style>
-<script>
-
-</script>
-</head>
-<body>
-
-<textarea id=red></textarea>
-<textarea id=green></textarea>
-<textarea id=blue></textarea>
-<textarea id=yellow></textarea>
-
-</body>
-</html>
diff --git a/layout/reftests/bugs/385870-2-ref.html b/layout/reftests/bugs/385870-2-ref.html
deleted file mode 100644
index eebef3805e..0000000000
--- a/layout/reftests/bugs/385870-2-ref.html
+++ /dev/null
@@ -1,51 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title></title>
-<style>
-#red {
- position: absolute;
- background-color: blue;
- top: 10px;
- left: 10px;
-}
-
-#green {
- position: absolute;
- background-color: blue;
- top: 10px;
- width: 80px;
- right: 10px;
-}
-
-#blue {
- position: absolute;
- background-color: blue;
- left: 10px;
- height: 80px;
- bottom: 10px;
-}
-
-#yellow {
- position: absolute;
- background-color: blue;
- right: 10px;
- width: 80px;
- height: 80px;
- bottom: 10px;
-}
-
-</style>
-<script>
-
-</script>
-</head>
-<body>
-
-<input id=red>
-<input id=green>
-<input id=blue>
-<input id=yellow>
-
-</body>
-</html>
diff --git a/layout/reftests/bugs/385870-2.html b/layout/reftests/bugs/385870-2.html
deleted file mode 100644
index c641abb796..0000000000
--- a/layout/reftests/bugs/385870-2.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<title></title>
-<style>
-#red {
- position: absolute;
- background-color: blue;
- top: 10px;
- left: 10px;
- right: 100px;
- bottom: 100px;
-}
-
-#green {
- position: absolute;
- background-color: blue;
- top: 10px;
- width: 80px;
- right: 10px;
- bottom: 100px;
-}
-
-#blue {
- position: absolute;
- background-color: blue;
- left: 10px;
- height: 80px;
- right: 100px;
- bottom: 10px;
-}
-
-#yellow {
- position: absolute;
- background-color: blue;
- right: 10px;
- width: 80px;
- height: 80px;
- bottom: 10px;
-}
-
-</style>
-<script>
-
-</script>
-</head>
-<body>
-
-<input id=red>
-<input id=green>
-<input id=blue>
-<input id=yellow>
-
-</body>
-</html>
diff --git a/layout/reftests/bugs/404553-1-ref.html b/layout/reftests/bugs/404553-1-ref.html
index cfa0dc8147..ac35a9e4b5 100644
--- a/layout/reftests/bugs/404553-1-ref.html
+++ b/layout/reftests/bugs/404553-1-ref.html
@@ -1 +1 @@
-<div style="background-color: lime; height: 50px;"><div style="background: green; width: 50px; margin-left: auto; margin-right: 0;">&nbsp;</div></div> \ No newline at end of file
+<div style="background-color: lime; height: 50px;"><div style="background: green; width: 50px;">&nbsp;</div></div>
diff --git a/layout/reftests/bugs/404553-1.html b/layout/reftests/bugs/404553-1.html
index 692c63c67c..ab63f1396e 100644
--- a/layout/reftests/bugs/404553-1.html
+++ b/layout/reftests/bugs/404553-1.html
@@ -1 +1 @@
-<table><marquee behavior="alternate" scrollamount="0" style="background-color: lime; height: 50px;"><div style="background: green; width: 50px">&nbsp;</div></marquee><span><title> \ No newline at end of file
+<table><marquee behavior="alternate" scrollamount="0" style="background-color: lime; height: 50px;"><div style="background: green; width: 50px">&nbsp;</div></marquee><span><title>
diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list
index d85d5e7310..84f4ecca9f 100644
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -342,8 +342,7 @@ skip-if(useDrawSnapshot) == 306660-2.html 306660-2-ref.html
== 306660-3.html 306660-3-ref.html
== 307076-1.html 307076-1-ref.html
== 307102-1.html 307102-1-ref.html
-== 307102-2.html 307102-2-ref.html
-== 307102-3.html 307102-3-ref.html
+random == 307102-3.html 307102-3-ref.html
== 307102-4.html 307102-4-ref.html
== 308406-1.html 308406-1-ref.html
== 308406-2.html 308406-2-ref.html
@@ -725,8 +724,6 @@ fuzzy(0-2,0-5) == 381507-1.html 381507-1-ref.html
fuzzy(0-1,0-600) == 385823-2a.html 385823-2-ref.html
fails == 385823-2b.html 385823-2-ref.html
fuzzy(0-1,0-600) == 385823-2c.html 385823-2-ref.html
-fuzzy(0-2,0-11) == 385870-1.html 385870-1-ref.html
-fuzzy(0-2,0-3) == 385870-2.html 385870-2-ref.html
== 386014-1a.html 386014-1-ref.html
== 386014-1b.html 386014-1-ref.html
== 386014-1c.html 386014-1-ref.html
@@ -922,7 +919,7 @@ fuzzy-if(winWidget,0-123,0-1600) fuzzy-if(swgl,0-1,0-39) == 409659-1a.html 40965
!= 409659-1c.html 409659-1-ref.html
fuzzy-if(winWidget,0-123,0-1900) fuzzy-if(swgl,0-1,0-39) == 409659-1d.html 409659-1-ref.html # Bug 1128229
== 410621-1.html 410621-1-ref.html
-== 411059-1.html 411059-1-ref.html
+pref(layout.css.letter-spacing.model,0) == 411059-1.html 411059-1-ref.html
fuzzy-if(winWidget,46-129,652-770) == 411334-1.xml 411334-1-ref.xml
== 411585-1.html 411585-1-ref.html
== 411585-2.html 411585-2-ref.html
@@ -1123,7 +1120,7 @@ fuzzy(0-1,0-3280) == 438987-2c.html 438987-2-ref.html
!= about:blank 438987-2-ref.html # check that backgrounds work at all
== 439004-1.html 439004-1-ref.html
== 439639-1.html 439639-1-ref.html
-fuzzy-if(gtkWidget,0-255,0-6) == 439910.html 439910-ref.html
+pref(layout.css.letter-spacing.model,0) fuzzy-if(gtkWidget,0-255,0-6) == 439910.html 439910-ref.html
fuzzy(0-1,0-1) fuzzy-if(Android,0-1,0-3) == 440112.html 440112-ref.html
== 440149-1.html 440149-1-ref.html
== 441259-1.html 441259-1-ref.html
@@ -1347,7 +1344,7 @@ pref(browser.display.focus_ring_width,1) == 491180-2.html 491180-2-ref.html
fuzzy(0-6,0-97456) == 501627-1.html 501627-1-ref.html # Bug 1481664
== 502288-1.html 502288-1-ref.html
fuzzy-if(gtkWidget,0-1,0-2) == 502447-1.html 502447-1-ref.html #Bug 1315834
-== 502795-1.html 502795-1-ref.html
+pref(layout.css.letter-spacing.model,0) == 502795-1.html 502795-1-ref.html
== 502942-1.html 502942-1-ref.html
== 503364-1a.html 503364-1-ref.html
== 503364-1b.html 503364-1-ref.html
@@ -1370,8 +1367,8 @@ fuzzy(0-1,0-1200) == 512410.html 512410-ref.html
== 512631-1.html 512631-1-ref.html
fuzzy(0-1,0-4) == 513153-1a.html 513153-1-ref.html
fuzzy(0-1,0-4) == 513153-1b.html 513153-1-ref.html
-pref(widget.non-native-theme.webrender,true) == 513153-2a.html 513153-2-ref.html # appleSilicon: bug 1724583
-fuzzy-if(cocoaWidget,0-112,0-108) == 513153-2b.html 513153-2-ref.html # only fuzzy when widget.non-native-theme.webrender=false, snapping difference
+== 513153-2a.html 513153-2-ref.html # appleSilicon: bug 1724583
+== 513153-2b.html 513153-2-ref.html
== chrome://reftest/content/bugs/513318-1.xhtml chrome://reftest/content/bugs/513318-1-ref.xhtml
!= chrome://reftest/content/bugs/513318-2.xhtml chrome://reftest/content/bugs/513318-2-ref.xhtml
== 514917-1.html 514917-1-ref.html
@@ -2165,3 +2162,4 @@ fuzzy-if(!useDrawSnapshot,18-19,294-322) == 1840747-1.html about:blank
# here. That's tracked in bug 1840747.
fuzzy-if(!useDrawSnapshot&&!swgl,254-255,110-121) fuzzy-if(useDrawSnapshot,18-18,93-93) fuzzy-if(swgl,19-19,58-58) == 1841355-1.html about:blank
skip-if(((AddressSanitizer||ThreadSanitizer)&&gtkWidget)||(isDebugBuild&&Android)) fuzzy(0-123,0-1425) == 1878294-1.html 1878294-1-ref.html
+== 1888941-text-transform-emergency-wrap.html 1888941-text-transform-emergency-wrap-ref.html
diff --git a/layout/reftests/counters/counter-hebrew-reference.html b/layout/reftests/counters/counter-hebrew-reference.html
index f2c1326056..0d08f6d49b 100644
--- a/layout/reftests/counters/counter-hebrew-reference.html
+++ b/layout/reftests/counters/counter-hebrew-reference.html
@@ -55,10 +55,7 @@
<span>&#x5d8;&#x05f3;</span>
<span>&#x5d8;&#x05f3;&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;</span>
<span>&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;&#x05f3;&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;</span>
- <style>
- #c18:before { counter-set: c 18; content: counter(c, hebrew); }
- </style>
- <span id="c18"></span>
+ <span>1000000</span>
</div>
</body>
diff --git a/layout/reftests/counters/counters-hebrew-reference.html b/layout/reftests/counters/counters-hebrew-reference.html
index 7e725760e8..9ae6b5e011 100644
--- a/layout/reftests/counters/counters-hebrew-reference.html
+++ b/layout/reftests/counters/counters-hebrew-reference.html
@@ -12,54 +12,51 @@
<p></p>
<div>
<span>&#x5d0;.&#x5d0;</span>
- <span>&#x5d1;</span>
- <span>&#x5d2;</span>
- <span>&#x5d3;</span>
- <span>&#x5d4;</span>
- <span>&#x5d5;</span>
- <span>&#x5d6;</span>
- <span>&#x5d7;</span>
- <span>&#x5d8;</span>
- <span>&#x5d9;</span>
- <span>&#x5d9;&#x5d0;</span>
- <span>&#x5d9;&#x5d1;</span>
- <span>&#x5d9;&#x5d2;</span>
- <span>&#x5d9;&#x5d3;</span>
- <span>&#x5d8;&#x5d5;</span>
- <span>&#x5d8;&#x5d6;</span>
- <span>&#x5d9;&#x5d6;</span>
- <span>&#x5d9;&#x5d6;.&#x5db;</span>
- <span>&#x5d9;&#x5d6;.&#x5dc;</span>
- <span>&#x5d9;&#x5d6;.&#x5de;</span>
- <span>&#x5d9;&#x5d6;.&#x5e0;</span>
- <span>&#x5d9;&#x5d6;.&#x5e1;</span>
- <span>&#x5d9;&#x5d6;.&#x5e2;</span>
- <span>&#x5d9;&#x5d6;.&#x5e4;</span>
- <span>&#x5d9;&#x5d6;.&#x5e6;</span>
- <span>&#x5d9;&#x5d6;.&#x5e7;</span>
- <span>&#x5d9;&#x5d6;.&#x5e8;</span>
- <span>&#x5d9;&#x5d6;.&#x5e9;</span>
- <span>&#x5d9;&#x5d6;.&#x5ea;</span>
- <span>&#x5d9;&#x5d6;.&#x5ea;&#x5e7;</span>
- <span>&#x5d9;&#x5d6;.&#x5ea;&#x5e8;</span>
- <span>&#x5d9;&#x5d6;.&#x5ea;&#x5e9;</span>
- <span>&#x5d9;&#x5d6;.&#x5ea;&#x5ea;</span>
- <span>&#x5d9;&#x5d6;.&#x5ea;&#x5ea;&#x5e7;</span>
- <span>&#x5d9;&#x5d6;.&#x5d0;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d1;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d2;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d3;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d4;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d5;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d6;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d7;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d8;&#x05f3;</span>
- <span>&#x5d9;&#x5d6;.&#x5d8;&#x05f3;&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;</span>
- <span>&#x5d9;&#x5d6;.&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;&#x05f3;&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;</span>
- <style>
- #c18:before { counter-set: c 18; content: counter(c, hebrew); }
- </style>
- <span id="c18"></span>
+ <span>&#x5d0;.&#x5d1;</span>
+ <span>&#x5d0;.&#x5d2;</span>
+ <span>&#x5d0;.&#x5d3;</span>
+ <span>&#x5d0;.&#x5d4;</span>
+ <span>&#x5d0;.&#x5d5;</span>
+ <span>&#x5d0;.&#x5d6;</span>
+ <span>&#x5d0;.&#x5d7;</span>
+ <span>&#x5d0;.&#x5d8;</span>
+ <span>&#x5d0;.&#x5d9;</span>
+ <span>&#x5d0;.&#x5d9;&#x5d0;</span>
+ <span>&#x5d0;.&#x5d9;&#x5d1;</span>
+ <span>&#x5d0;.&#x5d9;&#x5d2;</span>
+ <span>&#x5d0;.&#x5d9;&#x5d3;</span>
+ <span>&#x5d0;.&#x5d8;&#x5d5;</span>
+ <span>&#x5d0;.&#x5d8;&#x5d6;</span>
+ <span>&#x5d0;.&#x5d9;&#x5d6;</span>
+ <span>&#x5d0;.&#x5db;</span>
+ <span>&#x5d0;.&#x5dc;</span>
+ <span>&#x5d0;.&#x5de;</span>
+ <span>&#x5d0;.&#x5e0;</span>
+ <span>&#x5d0;.&#x5e1;</span>
+ <span>&#x5d0;.&#x5e2;</span>
+ <span>&#x5d0;.&#x5e4;</span>
+ <span>&#x5d0;.&#x5e6;</span>
+ <span>&#x5d0;.&#x5e7;</span>
+ <span>&#x5d0;.&#x5e8;</span>
+ <span>&#x5d0;.&#x5e9;</span>
+ <span>&#x5d0;.&#x5ea;</span>
+ <span>&#x5d0;.&#x5ea;&#x5e7;</span>
+ <span>&#x5d0;.&#x5ea;&#x5e8;</span>
+ <span>&#x5d0;.&#x5ea;&#x5e9;</span>
+ <span>&#x5d0;.&#x5ea;&#x5ea;</span>
+ <span>&#x5d0;.&#x5ea;&#x5ea;&#x5e7;</span>
+ <span>&#x5d0;.&#x5d0;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d1;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d2;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d3;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d4;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d5;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d6;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d7;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d8;&#x05f3;</span>
+ <span>&#x5d0;.&#x5d8;&#x05f3;&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;</span>
+ <span>&#x5d0;.&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;&#x05f3;&#x5ea;&#x5ea;&#x5e7;&#x5e6;&#x5d8;</span>
+ <span>&#x5d0;.1000000</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1202-counter-06-b-reference.html b/layout/reftests/counters/t1202-counter-06-b-reference.html
index 78c9300a8b..0fdc2905e2 100644
--- a/layout/reftests/counters/t1202-counter-06-b-reference.html
+++ b/layout/reftests/counters/t1202-counter-06-b-reference.html
@@ -24,8 +24,8 @@
<span>11</span>
<span>12</span>
<span>99</span>
- <span>13</span>
- <span>14</span>
+ <span>100</span>
+ <span>101</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1202-counter-07-b-reference.html b/layout/reftests/counters/t1202-counter-07-b-reference.html
index b0da1fa597..f6429c211a 100644
--- a/layout/reftests/counters/t1202-counter-07-b-reference.html
+++ b/layout/reftests/counters/t1202-counter-07-b-reference.html
@@ -23,12 +23,12 @@
<span>xi</span>
<span>xii</span>
<span>xlix</span>
- <span>xiii</span>
+ <span>l</span>
<span>ccclxxxix</span>
- <span>xiv</span>
+ <span>cccxc</span>
<span>mmmcdlxxxix</span>
- <span>xv</span>
- <span>xvi</span>
+ <span>mmmcdxc</span>
+ <span>mmmcdxci</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1202-counter-08-b-reference.html b/layout/reftests/counters/t1202-counter-08-b-reference.html
index 40a8bf8d53..16be49dcbc 100644
--- a/layout/reftests/counters/t1202-counter-08-b-reference.html
+++ b/layout/reftests/counters/t1202-counter-08-b-reference.html
@@ -23,12 +23,12 @@
<span>XI</span>
<span>XII</span>
<span>XLIX</span>
- <span>XIII</span>
+ <span>L</span>
<span>CCCLXXXIX</span>
- <span>XIV</span>
+ <span>CCCXC</span>
<span>MMMCDLXXXIX</span>
- <span>XV</span>
- <span>XVI</span>
+ <span>MMMCDXC</span>
+ <span>MMMCDXCI</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1202-counters-06-b-reference.html b/layout/reftests/counters/t1202-counters-06-b-reference.html
index 7b3af2409f..b2b5ca1a07 100644
--- a/layout/reftests/counters/t1202-counters-06-b-reference.html
+++ b/layout/reftests/counters/t1202-counters-06-b-reference.html
@@ -13,20 +13,20 @@
<div>
<span>01.01</span>
- <span>02</span>
- <span>03</span>
- <span>04</span>
- <span>05</span>
- <span>06</span>
- <span>07</span>
- <span>08</span>
- <span>09</span>
- <span>10</span>
- <span>11</span>
- <span>12</span>
- <span>12.99</span>
- <span>13</span>
- <span>14</span>
+ <span>01.02</span>
+ <span>01.03</span>
+ <span>01.04</span>
+ <span>01.05</span>
+ <span>01.06</span>
+ <span>01.07</span>
+ <span>01.08</span>
+ <span>01.09</span>
+ <span>01.10</span>
+ <span>01.11</span>
+ <span>01.12</span>
+ <span>01.99</span>
+ <span>01.100</span>
+ <span>01.101</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1202-counters-07-b-reference.html b/layout/reftests/counters/t1202-counters-07-b-reference.html
index 49713c7344..ef08cfbefc 100644
--- a/layout/reftests/counters/t1202-counters-07-b-reference.html
+++ b/layout/reftests/counters/t1202-counters-07-b-reference.html
@@ -13,24 +13,24 @@
<div>
<span>i.i</span>
- <span>ii</span>
- <span>iii</span>
- <span>iv</span>
- <span>v</span>
- <span>vi</span>
- <span>vii</span>
- <span>viii</span>
- <span>ix</span>
- <span>x</span>
- <span>xi</span>
- <span>xii</span>
- <span>xii.xlix</span>
- <span>xiii</span>
- <span>xiii.ccclxxxix</span>
- <span>xiv</span>
- <span>xiv.mmmcdlxxxix</span>
- <span>xv</span>
- <span>xvi</span>
+ <span>i.ii</span>
+ <span>i.iii</span>
+ <span>i.iv</span>
+ <span>i.v</span>
+ <span>i.vi</span>
+ <span>i.vii</span>
+ <span>i.viii</span>
+ <span>i.ix</span>
+ <span>i.x</span>
+ <span>i.xi</span>
+ <span>i.xii</span>
+ <span>i.xlix</span>
+ <span>i.l</span>
+ <span>i.ccclxxxix</span>
+ <span>i.cccxc</span>
+ <span>i.mmmcdlxxxix</span>
+ <span>i.mmmcdxc</span>
+ <span>i.mmmcdxci</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1202-counters-08-b-reference.html b/layout/reftests/counters/t1202-counters-08-b-reference.html
index 92a6429164..7838d10fbb 100644
--- a/layout/reftests/counters/t1202-counters-08-b-reference.html
+++ b/layout/reftests/counters/t1202-counters-08-b-reference.html
@@ -13,24 +13,24 @@
<div>
<span>I.I</span>
- <span>II</span>
- <span>III</span>
- <span>IV</span>
- <span>V</span>
- <span>VI</span>
- <span>VII</span>
- <span>VIII</span>
- <span>IX</span>
- <span>X</span>
- <span>XI</span>
- <span>XII</span>
- <span>XII.XLIX</span>
- <span>XIII</span>
- <span>XIII.CCCLXXXIX</span>
- <span>XIV</span>
- <span>XIV.MMMCDLXXXIX</span>
- <span>XV</span>
- <span>XVI</span>
+ <span>I.II</span>
+ <span>I.III</span>
+ <span>I.IV</span>
+ <span>I.V</span>
+ <span>I.VI</span>
+ <span>I.VII</span>
+ <span>I.VIII</span>
+ <span>I.IX</span>
+ <span>I.X</span>
+ <span>I.XI</span>
+ <span>I.XII</span>
+ <span>I.XLIX</span>
+ <span>I.L</span>
+ <span>I.CCCLXXXIX</span>
+ <span>I.CCCXC</span>
+ <span>I.MMMCDLXXXIX</span>
+ <span>I.MMMCDXC</span>
+ <span>I.MMMCDXCI</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1202-counters-09-b-reference.html b/layout/reftests/counters/t1202-counters-09-b-reference.html
index 928e440ae1..0511df55e4 100644
--- a/layout/reftests/counters/t1202-counters-09-b-reference.html
+++ b/layout/reftests/counters/t1202-counters-09-b-reference.html
@@ -13,45 +13,45 @@
<div>
<span>&#x10D0;.&#x10D0;</span>
- <span>&#x10D1;</span>
- <span>&#x10D2;</span>
- <span>&#x10D3;</span>
- <span>&#x10D4;</span>
- <span>&#x10D5;</span>
- <span>&#x10D6;</span>
- <span>&#x10F1;</span>
- <span>&#x10D7;</span>
- <span>&#x10D8;</span>
- <span>&#x10D8;&#x10D0;</span>
- <span>&#x10D8;&#x10D1;</span>
- <span>&#x10D8;&#x10D1;.&#x10D9;</span>
- <span>&#x10D8;&#x10D1;.&#x10DA;</span>
- <span>&#x10D8;&#x10D1;.&#x10DB;</span>
- <span>&#x10D8;&#x10D1;.&#x10DC;</span>
- <span>&#x10D8;&#x10D1;.&#x10F2;</span>
- <span>&#x10D8;&#x10D1;.&#x10DD;</span>
- <span>&#x10D8;&#x10D1;.&#x10DE;</span>
- <span>&#x10D8;&#x10D1;.&#x10DF;</span>
- <span>&#x10D8;&#x10D1;.&#x10E0;</span>
- <span>&#x10D8;&#x10D1;.&#x10E1;</span>
- <span>&#x10D8;&#x10D1;.&#x10E2;</span>
- <span>&#x10D8;&#x10D1;.&#x10F3;</span>
- <span>&#x10D8;&#x10D1;.&#x10E4;</span>
- <span>&#x10D8;&#x10D1;.&#x10E5;</span>
- <span>&#x10D8;&#x10D1;.&#x10E6;</span>
- <span>&#x10D8;&#x10D1;.&#x10E7;</span>
- <span>&#x10D8;&#x10D1;.&#x10E8;</span>
- <span>&#x10D8;&#x10D1;.&#x10E9;</span>
- <span>&#x10D8;&#x10D1;.&#x10EA;</span>
- <span>&#x10D8;&#x10D1;.&#x10EB;</span>
- <span>&#x10D8;&#x10D1;.&#x10EC;</span>
- <span>&#x10D8;&#x10D1;.&#x10ED;</span>
- <span>&#x10D8;&#x10D1;.&#x10EE;</span>
- <span>&#x10D8;&#x10D1;.&#x10F4;</span>
- <span>&#x10D8;&#x10D1;.&#x10EF;</span>
- <span>&#x10D8;&#x10D1;.&#x10F0;</span>
- <span>&#x10D8;&#x10D1;.&#x10F5;</span>
- <span>&#x10D8;&#x10D1;.&#x10F5;&#x10F0;&#x10E8;&#x10DF;&#x10D7;</span>
+ <span>&#x10D0;.&#x10D1;</span>
+ <span>&#x10D0;.&#x10D2;</span>
+ <span>&#x10D0;.&#x10D3;</span>
+ <span>&#x10D0;.&#x10D4;</span>
+ <span>&#x10D0;.&#x10D5;</span>
+ <span>&#x10D0;.&#x10D6;</span>
+ <span>&#x10D0;.&#x10F1;</span>
+ <span>&#x10D0;.&#x10D7;</span>
+ <span>&#x10D0;.&#x10D8;</span>
+ <span>&#x10D0;.&#x10D8;&#x10D0;</span>
+ <span>&#x10D0;.&#x10D8;&#x10D1;</span>
+ <span>&#x10D0;.&#x10D9;</span>
+ <span>&#x10D0;.&#x10DA;</span>
+ <span>&#x10D0;.&#x10DB;</span>
+ <span>&#x10D0;.&#x10DC;</span>
+ <span>&#x10D0;.&#x10F2;</span>
+ <span>&#x10D0;.&#x10DD;</span>
+ <span>&#x10D0;.&#x10DE;</span>
+ <span>&#x10D0;.&#x10DF;</span>
+ <span>&#x10D0;.&#x10E0;</span>
+ <span>&#x10D0;.&#x10E1;</span>
+ <span>&#x10D0;.&#x10E2;</span>
+ <span>&#x10D0;.&#x10F3;</span>
+ <span>&#x10D0;.&#x10E4;</span>
+ <span>&#x10D0;.&#x10E5;</span>
+ <span>&#x10D0;.&#x10E6;</span>
+ <span>&#x10D0;.&#x10E7;</span>
+ <span>&#x10D0;.&#x10E8;</span>
+ <span>&#x10D0;.&#x10E9;</span>
+ <span>&#x10D0;.&#x10EA;</span>
+ <span>&#x10D0;.&#x10EB;</span>
+ <span>&#x10D0;.&#x10EC;</span>
+ <span>&#x10D0;.&#x10ED;</span>
+ <span>&#x10D0;.&#x10EE;</span>
+ <span>&#x10D0;.&#x10F4;</span>
+ <span>&#x10D0;.&#x10EF;</span>
+ <span>&#x10D0;.&#x10F0;</span>
+ <span>&#x10D0;.&#x10F5;</span>
+ <span>&#x10D0;.&#x10F5;&#x10F0;&#x10E8;&#x10DF;&#x10D7;</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1202-counters-10-b-reference.html b/layout/reftests/counters/t1202-counters-10-b-reference.html
index f3a3fa6dfa..af593dab5c 100644
--- a/layout/reftests/counters/t1202-counters-10-b-reference.html
+++ b/layout/reftests/counters/t1202-counters-10-b-reference.html
@@ -13,44 +13,44 @@
<div>
<span>&#x531;.&#x531;</span>
- <span>&#x532;</span>
- <span>&#x533;</span>
- <span>&#x534;</span>
- <span>&#x535;</span>
- <span>&#x536;</span>
- <span>&#x537;</span>
- <span>&#x538;</span>
- <span>&#x539;</span>
- <span>&#x53A;</span>
- <span>&#x53A;&#x531;</span>
- <span>&#x53A;&#x532;</span>
- <span>&#x53A;&#x532;.&#x53B;</span>
- <span>&#x53A;&#x532;.&#x53C;</span>
- <span>&#x53A;&#x532;.&#x53D;</span>
- <span>&#x53A;&#x532;.&#x53E;</span>
- <span>&#x53A;&#x532;.&#x53F;</span>
- <span>&#x53A;&#x532;.&#x540;</span>
- <span>&#x53A;&#x532;.&#x541;</span>
- <span>&#x53A;&#x532;.&#x542;</span>
- <span>&#x53A;&#x532;.&#x543;</span>
- <span>&#x53A;&#x532;.&#x544;</span>
- <span>&#x53A;&#x532;.&#x545;</span>
- <span>&#x53A;&#x532;.&#x546;</span>
- <span>&#x53A;&#x532;.&#x547;</span>
- <span>&#x53A;&#x532;.&#x548;</span>
- <span>&#x53A;&#x532;.&#x549;</span>
- <span>&#x53A;&#x532;.&#x54A;</span>
- <span>&#x53A;&#x532;.&#x54B;</span>
- <span>&#x53A;&#x532;.&#x54C;</span>
- <span>&#x53A;&#x532;.&#x54D;</span>
- <span>&#x53A;&#x532;.&#x54E;</span>
- <span>&#x53A;&#x532;.&#x54F;</span>
- <span>&#x53A;&#x532;.&#x550;</span>
- <span>&#x53A;&#x532;.&#x551;</span>
- <span>&#x53A;&#x532;.&#x552;</span>
- <span>&#x53A;&#x532;.&#x553;</span>
- <span>&#x53A;&#x532;.&#x554;</span>
- <span>&#x53A;&#x532;.&#x554;&#x54B;&#x542;&#x539;</span>
+ <span>&#x531;.&#x532;</span>
+ <span>&#x531;.&#x533;</span>
+ <span>&#x531;.&#x534;</span>
+ <span>&#x531;.&#x535;</span>
+ <span>&#x531;.&#x536;</span>
+ <span>&#x531;.&#x537;</span>
+ <span>&#x531;.&#x538;</span>
+ <span>&#x531;.&#x539;</span>
+ <span>&#x531;.&#x53A;</span>
+ <span>&#x531;.&#x53A;&#x531;</span>
+ <span>&#x531;.&#x53A;&#x532;</span>
+ <span>&#x531;.&#x53B;</span>
+ <span>&#x531;.&#x53C;</span>
+ <span>&#x531;.&#x53D;</span>
+ <span>&#x531;.&#x53E;</span>
+ <span>&#x531;.&#x53F;</span>
+ <span>&#x531;.&#x540;</span>
+ <span>&#x531;.&#x541;</span>
+ <span>&#x531;.&#x542;</span>
+ <span>&#x531;.&#x543;</span>
+ <span>&#x531;.&#x544;</span>
+ <span>&#x531;.&#x545;</span>
+ <span>&#x531;.&#x546;</span>
+ <span>&#x531;.&#x547;</span>
+ <span>&#x531;.&#x548;</span>
+ <span>&#x531;.&#x549;</span>
+ <span>&#x531;.&#x54A;</span>
+ <span>&#x531;.&#x54B;</span>
+ <span>&#x531;.&#x54C;</span>
+ <span>&#x531;.&#x54D;</span>
+ <span>&#x531;.&#x54E;</span>
+ <span>&#x531;.&#x54F;</span>
+ <span>&#x531;.&#x550;</span>
+ <span>&#x531;.&#x551;</span>
+ <span>&#x531;.&#x552;</span>
+ <span>&#x531;.&#x553;</span>
+ <span>&#x531;.&#x554;</span>
+ <span>&#x531;.&#x554;&#x54B;&#x542;&#x539;</span>
</div>
</body>
diff --git a/layout/reftests/counters/t1204-reset-00-c-o-reference.html b/layout/reftests/counters/t1204-reset-00-c-o-reference.html
index 3be209b7e8..e9afee0b67 100644
--- a/layout/reftests/counters/t1204-reset-00-c-o-reference.html
+++ b/layout/reftests/counters/t1204-reset-00-c-o-reference.html
@@ -9,7 +9,7 @@
</head>
<body>
- <div id="reference"><span>1-</span><span>2-</span><span>3-</span></div>
+ <div id="reference"><span>1-</span><span>1.1-</span><span>1.2-</span></div>
</body>
</html>
diff --git a/layout/reftests/counters/t120401-scope-01-c-reference.html b/layout/reftests/counters/t120401-scope-01-c-reference.html
index 021366aaed..c7488ce4b3 100644
--- a/layout/reftests/counters/t120401-scope-01-c-reference.html
+++ b/layout/reftests/counters/t120401-scope-01-c-reference.html
@@ -10,7 +10,7 @@
<body>
- <div><span>B</span><span>1</span><span>-</span><span>B</span><span>2</span><span>-</span><span>B</span><span>2.1</span><span>-</span><span>B</span><span>2.2</span><span>-</span><span>A</span><span>2.3</span><span>-</span><span>B</span><span>2.4</span><span>-</span><span>A</span><span>2.5</span><span>-</span><span>A</span><span>2.6</span><span>-</span><span>B</span><span>3</span><span>-</span><span>B</span><span>4</span><span>-</span><span>A</span><span>5</span><span>-</span><span>A</span><span>6</span><span>-</span><span>A</span><span>7</span><span>-</span><span>A</span><span>8</span><span>-</span></div>
+ <div><span>B</span><span>1</span><span>-</span><span>B</span><span>2</span><span>-</span><span>B</span><span>2.1</span><span>-</span><span>B</span><span>2.2</span><span>-</span><span>A</span><span>2.3</span><span>-</span><span>B</span><span>2.4</span><span>-</span><span>A</span><span>2.5</span><span>-</span><span>A</span><span>2.6</span><span>-</span><span>B</span><span>2.7</span><span>-</span><span>B</span><span>2.8</span><span>-</span><span>A</span><span>2.9</span><span>-</span><span>A</span><span>2.10</span><span>-</span><span>A</span><span>2.11</span><span>-</span><span>A</span><span>3</span><span>-</span></div>
</body>
</html>
diff --git a/layout/reftests/counters/t120401-scope-02-c-reference.html b/layout/reftests/counters/t120401-scope-02-c-reference.html
index 41fc79875a..ff2281a8cf 100644
--- a/layout/reftests/counters/t120401-scope-02-c-reference.html
+++ b/layout/reftests/counters/t120401-scope-02-c-reference.html
@@ -10,7 +10,7 @@
<body>
- <div><span>B</span><span>1</span><span>-</span><span>B</span><span>1.1</span><span>-</span><span>B</span><span>2</span><span>-</span><span>A</span><span>3</span><span>-</span><span>A</span><span>4</span><span>-</span><span>A</span><span>5</span><span>-</span></div>
+ <div><span>B</span><span>1</span><span>-</span><span>B</span><span>1.1</span><span>-</span><span>B</span><span>1.2</span><span>-</span><span>A</span><span>1.3</span><span>-</span><span>A</span><span>1.4</span><span>-</span><span>A</span><span>2</span><span>-</span></div>
</body>
</html>
diff --git a/layout/reftests/css-gradients/reftest.list b/layout/reftests/css-gradients/reftest.list
index 1574996fa3..0803f7ec35 100644
--- a/layout/reftests/css-gradients/reftest.list
+++ b/layout/reftests/css-gradients/reftest.list
@@ -47,8 +47,8 @@ fuzzy-if(Android,0-8,0-771) == radial-shape-farthest-corner-1a.html radial-shape
fails-if(gtkWidget) fuzzy(0-2,0-500) == radial-shape-farthest-corner-1b.html radial-shape-farthest-corner-1-ref.html
fuzzy(0-2,0-15000) fuzzy-if(Android,0-17,0-13320) == radial-shape-farthest-side-1a.html radial-shape-farthest-side-1-ref.html
fuzzy(0-2,0-15000) fuzzy-if(Android,0-17,0-13320) == radial-shape-farthest-side-1b.html radial-shape-farthest-side-1-ref.html
-== radial-size-1a.html radial-size-1-ref.html
-== radial-size-1b.html radial-size-1-ref.html
+fuzzy(0-1,0-100) == radial-size-1a.html radial-size-1-ref.html
+fuzzy(0-1,0-100) == radial-size-1b.html radial-size-1-ref.html
fuzzy-if(Android,0-4,0-248) == radial-zero-length-1a.html radial-zero-length-1-ref.html
fuzzy-if(Android,0-4,0-248) == radial-zero-length-1b.html radial-zero-length-1-ref.html
fuzzy-if(Android,0-4,0-248) == radial-zero-length-1c.html radial-zero-length-1-ref.html
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001-ref.html
index a157cf074a..20c088ab02 100644
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001-ref.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001-ref.html
@@ -51,7 +51,7 @@ for (var i = 0; i < coltest.length; ++i) {
img.setAttribute("src","support/lime-24x2.png");
img.setAttribute("style",coltest[i] + "; min-width:"+ results[i]);
grid.appendChild(img);
- document.body.appendChild(document.createTextNode("24x2.png -- "+coltest[i]+'\n'));
+ document.body.appendChild(document.createTextNode(`Test ${i+1}: 24x2.png -- ${coltest[i]}`));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(grid);
document.body.appendChild(document.createElement('br'));
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001.html
index 93a251be43..9565253b50 100644
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-001.html
@@ -52,7 +52,7 @@ for (var i = 0; i < coltest.length; ++i) {
img.setAttribute("src","support/lime-24x2.png");
img.setAttribute("style",coltest[i]);
grid.appendChild(img);
- document.body.appendChild(document.createTextNode("24x2.png -- "+coltest[i]+'\n'));
+ document.body.appendChild(document.createTextNode(`Test ${i+1}: 24x2.png -- ${coltest[i]}`));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(grid);
document.body.appendChild(document.createElement('br'));
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html
index 183f00e24f..2b09eb11ee 100644
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002-ref.html
@@ -55,7 +55,7 @@ for (var i = 0; i < coltest.length; ++i) {
img.setAttribute("src","support/lime-24x2.png");
img.setAttribute("style",coltest[i] + "; width:"+ item_width[i]);
grid.appendChild(img);
- document.body.appendChild(document.createTextNode("24x2.png -- "+coltest[i]+'\n'));
+ document.body.appendChild(document.createTextNode(`Test ${i+1}: 24x2.png -- ${coltest[i]}`));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(grid);
document.body.appendChild(document.createElement('br'));
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002.html
index 8809d5b06e..ee69018a93 100644
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-002.html
@@ -53,7 +53,7 @@ for (var i = 0; i < coltest.length; ++i) {
img.setAttribute("src","support/lime-24x2.png");
img.setAttribute("style",coltest[i]);
grid.appendChild(img);
- document.body.appendChild(document.createTextNode("24x2.png -- "+coltest[i]+'\n'));
+ document.body.appendChild(document.createTextNode(`Test ${i+1}: 24x2.png -- ${coltest[i]}`));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(grid);
document.body.appendChild(document.createElement('br'));
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003-ref.html
index 9ec975d62d..e051d4c3ef 100644
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003-ref.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003-ref.html
@@ -52,7 +52,7 @@ for (var i = 0; i < rowtest.length; ++i) {
img.setAttribute("src","support/lime-2x24.png");
img.setAttribute("style",rowtest[i] + "; min-height:"+ results[i]);
grid.appendChild(img);
- document.body.appendChild(document.createTextNode("2x24.png -- "+rowtest[i]+'\n'));
+ document.body.appendChild(document.createTextNode(`Test ${i+1}: 24x2.png -- ${rowtest[i]}`));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(grid);
document.body.appendChild(document.createElement('br'));
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003.html
index ae34753eba..659204c992 100644
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-003.html
@@ -51,7 +51,7 @@ for (var i = 0; i < rowtest.length; ++i) {
img.setAttribute("src","support/lime-2x24.png");
img.setAttribute("style",rowtest[i]);
grid.appendChild(img);
- document.body.appendChild(document.createTextNode("2x24.png -- "+rowtest[i]+'\n'));
+ document.body.appendChild(document.createTextNode(`Test ${i+1}: 24x2.png -- ${rowtest[i]}`));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(grid);
document.body.appendChild(document.createElement('br'));
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html
index 6533c97b67..c1022e53dd 100644
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004-ref.html
@@ -53,7 +53,7 @@ for (var i = 0; i < rowtest.length; ++i) {
img.setAttribute("src","support/lime-2x24.png");
img.setAttribute("style",rowtest[i] + "; max-height:auto; height:"+ item_height[i]);
grid.appendChild(img);
- document.body.appendChild(document.createTextNode("2x24.png -- "+rowtest[i]+'\n'));
+ document.body.appendChild(document.createTextNode(`Test ${i+1}: 24x2.png -- ${rowtest[i]}`));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(grid);
document.body.appendChild(document.createElement('br'));
diff --git a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004.html b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004.html
index c2b650525c..dab114939b 100644
--- a/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004.html
+++ b/layout/reftests/css-grid/grid-auto-min-sizing-min-content-min-size-004.html
@@ -52,7 +52,7 @@ for (var i = 0; i < rowtest.length; ++i) {
img.setAttribute("src","support/lime-2x24.png");
img.setAttribute("style",rowtest[i]);
grid.appendChild(img);
- document.body.appendChild(document.createTextNode("2x24.png -- "+rowtest[i]+'\n'));
+ document.body.appendChild(document.createTextNode(`Test ${i+1}: 24x2.png -- ${rowtest[i]}`));
document.body.appendChild(document.createElement('br'));
document.body.appendChild(grid);
document.body.appendChild(document.createElement('br'));
diff --git a/layout/reftests/dom/reftest.list b/layout/reftests/dom/reftest.list
index 64ac914010..897af84d11 100644
--- a/layout/reftests/dom/reftest.list
+++ b/layout/reftests/dom/reftest.list
@@ -28,7 +28,7 @@
# a range insert and an append
== insertmultiplemultiple-2.html insertmultiplemultiple-ref.html
# multiple range inserts and an append
-== insertmultiplemultiple-2.html insertmultiplemultiple-ref.html
+== insertmultiplemultiple-3.html insertmultiplemultiple-ref.html
# testing bindings that have multiple insertion points
== multipleinsertionpoints-ref2-shadow.xhtml multipleinsertionpoints-ref.xhtml
diff --git a/layout/reftests/flexbox/reftest.list b/layout/reftests/flexbox/reftest.list
index dbd6c705cd..b96dbf4fce 100644
--- a/layout/reftests/flexbox/reftest.list
+++ b/layout/reftests/flexbox/reftest.list
@@ -75,7 +75,6 @@ fuzzy(0-3,0-10) == flexbox-dyn-insertAroundSpan-3.xhtml flexbox-dyn-insertAround
== flexbox-position-absolute-2.xhtml flexbox-position-absolute-2-ref.xhtml
== flexbox-position-absolute-3.xhtml flexbox-position-absolute-3-ref.xhtml
== flexbox-position-absolute-4.xhtml flexbox-position-absolute-4-ref.xhtml
-== flexbox-position-fixed-3.xhtml flexbox-position-fixed-3-ref.xhtml
fuzzy-if(Android,0-16,0-400) == flexbox-position-fixed-1.xhtml flexbox-position-fixed-1-ref.xhtml
fuzzy-if(Android,0-16,0-400) == flexbox-position-fixed-2.xhtml flexbox-position-fixed-2-ref.xhtml
== flexbox-position-fixed-3.xhtml flexbox-position-fixed-3-ref.xhtml
diff --git a/layout/reftests/forms/input/file/reftest.list b/layout/reftests/forms/input/file/reftest.list
index d8276cb941..f16315f5a7 100644
--- a/layout/reftests/forms/input/file/reftest.list
+++ b/layout/reftests/forms/input/file/reftest.list
@@ -5,7 +5,7 @@ fuzzy(0-1,0-10) == background.html chrome://reftest/content/forms/input/file/bac
fuzzy-if(gtkWidget,0-1,0-10) == style.html chrome://reftest/content/forms/input/file/style-ref.xhtml
!= width-clip.html width-clip-ref.html
== color-inherit.html color-inherit-ref.html
-pref(widget.non-native-theme.webrender,true) fuzzy(0-1,0-5) fuzzy-if(cocoaWidget,0-46,0-134) == dynamic-max-width.html dynamic-max-width-ref.html # bug 1496542 for webrender, bug 1724582 for appleSilicon
+fuzzy(0-1,0-5) fuzzy-if(cocoaWidget,0-46,0-134) == dynamic-max-width.html dynamic-max-width-ref.html # bug 1496542 for webrender, bug 1724582 for appleSilicon
== label-min-inline-size.html label-min-inline-size-ref.html
== css-overflow.html css-overflow-ref.html
== css-display.html css-display-ref.html
diff --git a/layout/reftests/forms/input/range/1887539-ref.html b/layout/reftests/forms/input/range/1887539-ref.html
new file mode 100644
index 0000000000..b539a1b5c2
--- /dev/null
+++ b/layout/reftests/forms/input/range/1887539-ref.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<style>
+#scrubber {
+ height: 100px;
+ width: 100%;
+ appearance: none;
+ background-color: black;
+ box-sizing: border-box;
+ padding: 6px 2px;
+ margin: 0;
+
+ &::-moz-range-thumb {
+ border-radius: 14px;
+ background-color: #BFBFC9;
+ width: 8px;
+ height: 8px;
+ border: 3px solid white;
+ padding: 0;
+ }
+
+ &::-moz-range-track {
+ background-color: #969696;
+ }
+
+ &::-moz-range-progress {
+ background-color: white;
+ }
+}
+</style>
+<input type="range" id="scrubber" value="0.5" min="0" max="1" step=".001">
diff --git a/layout/reftests/forms/input/range/1887539.html b/layout/reftests/forms/input/range/1887539.html
new file mode 100644
index 0000000000..9472af203e
--- /dev/null
+++ b/layout/reftests/forms/input/range/1887539.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<style>
+#scrubber {
+ height: 100px;
+ width: 100%;
+ appearance: none;
+ background-color: black;
+ box-sizing: border-box;
+ padding: 6px 2px;
+ margin: 0;
+
+ &::-moz-range-thumb {
+ border-radius: 14px;
+ background-color: #BFBFC9;
+ width: 8px;
+ height: 8px;
+ border: 3px solid white;
+ padding: 0;
+ }
+
+ &::-moz-range-track {
+ background-color: #969696;
+ }
+
+ &::-moz-range-progress {
+ background-color: white;
+ }
+}
+</style>
+<input type="range" id="scrubber" value="0" min="0" max="1" step=".001">
+<script>
+let scrubber = document.getElementById('scrubber');
+scrubber.getBoundingClientRect();
+scrubber.value = 0.5;
+</script>
diff --git a/layout/reftests/forms/input/range/reftest.list b/layout/reftests/forms/input/range/reftest.list
index 181097dc15..f98f345b95 100644
--- a/layout/reftests/forms/input/range/reftest.list
+++ b/layout/reftests/forms/input/range/reftest.list
@@ -59,3 +59,5 @@ skip-if(Android) == range-border-background.html range-border-background-ref.htm
fails-if(Android) fuzzy(0-2,0-80) == auto-size.html auto-size-ref.html # Snapping, bug 1621141
== range-track-bg.html range-track-bg-ref.html
!= track-default-rendering.html track-default-rendering-ref.html
+
+== 1887539.html 1887539-ref.html
diff --git a/layout/reftests/forms/input/text/autofill-author-background.html b/layout/reftests/forms/input/text/autofill-author-background.html
index 691adaa1ff..73eb71ea7c 100644
--- a/layout/reftests/forms/input/text/autofill-author-background.html
+++ b/layout/reftests/forms/input/text/autofill-author-background.html
@@ -2,8 +2,8 @@
<input type=text style="background-color: red; background-image: linear-gradient(red, blue);">
<script>
let input = SpecialPowers.wrap(document.querySelector("input"));
- SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutofillField(input);
- input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutofillField() having being processed...
+ SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutoCompletableField(input);
+ input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutoCompletableField() having being processed...
input.previewValue = "Autofill";
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "-moz-autofill-preview");
</script>
diff --git a/layout/reftests/forms/input/text/autofill-blank.html b/layout/reftests/forms/input/text/autofill-blank.html
index 966d314038..17919875ee 100644
--- a/layout/reftests/forms/input/text/autofill-blank.html
+++ b/layout/reftests/forms/input/text/autofill-blank.html
@@ -2,7 +2,7 @@
<input type=text>
<script>
let input = SpecialPowers.wrap(document.querySelector("input"));
- SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutofillField(input);
+ SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutoCompletableField(input);
input.getBoundingClientRect();
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "autofill");
</script>
diff --git a/layout/reftests/forms/input/text/autofill-prefilled-value.html b/layout/reftests/forms/input/text/autofill-prefilled-value.html
index 42924ac531..07b4ce5310 100644
--- a/layout/reftests/forms/input/text/autofill-prefilled-value.html
+++ b/layout/reftests/forms/input/text/autofill-prefilled-value.html
@@ -2,8 +2,8 @@
<input type=text value="JOHN DOE">
<script>
let input = SpecialPowers.wrap(document.querySelector("input"));
- SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutofillField(input);
- input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutofillField() having being processed...
+ SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutoCompletableField(input);
+ input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutoCompletableField() having being processed...
input.previewValue = "Autofill";
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "-moz-autofill-preview");
</script>
diff --git a/layout/reftests/forms/input/text/autofill-preview-blank.html b/layout/reftests/forms/input/text/autofill-preview-blank.html
index a235b7430f..e441b80700 100644
--- a/layout/reftests/forms/input/text/autofill-preview-blank.html
+++ b/layout/reftests/forms/input/text/autofill-preview-blank.html
@@ -2,7 +2,7 @@
<input type=text>
<script>
let input = SpecialPowers.wrap(document.querySelector("input"));
- SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutofillField(input);
+ SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutoCompletableField(input);
input.getBoundingClientRect();
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "-moz-autofill-preview");
</script>
diff --git a/layout/reftests/forms/input/text/autofill-preview-line-height.html b/layout/reftests/forms/input/text/autofill-preview-line-height.html
index 7ce1cadb2e..40b63e9ede 100644
--- a/layout/reftests/forms/input/text/autofill-preview-line-height.html
+++ b/layout/reftests/forms/input/text/autofill-preview-line-height.html
@@ -5,8 +5,8 @@
<input value="Autofill">
<script>
let input = SpecialPowers.wrap(document.querySelector("input"));
- SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutofillField(input);
- input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutofillField() having being processed...
+ SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutoCompletableField(input);
+ input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutoCompletableField() having being processed...
input.previewValue = "Autofill";
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "-moz-autofill-preview");
</script>
diff --git a/layout/reftests/forms/input/text/autofill-preview.html b/layout/reftests/forms/input/text/autofill-preview.html
index 1382d29abd..540c07423f 100644
--- a/layout/reftests/forms/input/text/autofill-preview.html
+++ b/layout/reftests/forms/input/text/autofill-preview.html
@@ -2,8 +2,8 @@
<input type=text>
<script>
let input = SpecialPowers.wrap(document.querySelector("input"));
- SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutofillField(input);
- input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutofillField() having being processed...
+ SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutoCompletableField(input);
+ input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutoCompletableField() having being processed...
input.previewValue = "Autofill";
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "-moz-autofill-preview");
</script>
diff --git a/layout/reftests/forms/input/text/autofill.html b/layout/reftests/forms/input/text/autofill.html
index ccb2b15b1b..0d9c6a0588 100644
--- a/layout/reftests/forms/input/text/autofill.html
+++ b/layout/reftests/forms/input/text/autofill.html
@@ -2,8 +2,8 @@
<input type=text>
<script>
let input = SpecialPowers.wrap(document.querySelector("input"));
- SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutofillField(input);
- input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutofillField() having being processed...
+ SpecialPowers.Cc["@mozilla.org/satchel/form-fill-controller;1"].getService(SpecialPowers.Ci.nsIFormFillController).markAsAutoCompletableField(input);
+ input.getBoundingClientRect(); // previewValue setter depends on the reframe posted by markAsAutoCompletableField() having being processed...
input.previewValue = "Autofill";
SpecialPowers.wrap(window).windowUtils.addManuallyManagedState(input, "autofill");
</script>
diff --git a/layout/reftests/forms/input/text/reftest.list b/layout/reftests/forms/input/text/reftest.list
index 6c649a5196..e80b881246 100644
--- a/layout/reftests/forms/input/text/reftest.list
+++ b/layout/reftests/forms/input/text/reftest.list
@@ -22,5 +22,7 @@ fuzzy(0-1,0-500) needs-focus == select.html select-ref.html
== pseudo-class-lock.html pseudo-class-lock-ref.html
+pref(layout.forms.reveal-password-button.enabled,true) != suppress-password-button.html suppress-password-button-notref.html
+
needs-focus == focus-on-anchor.html#anchor focus-on-anchor-ref.html
needs-focus == select-overflow.html select-overflow-ref.html
diff --git a/layout/reftests/forms/input/text/suppress-password-button-notref.html b/layout/reftests/forms/input/text/suppress-password-button-notref.html
new file mode 100644
index 0000000000..c0d6fc108a
--- /dev/null
+++ b/layout/reftests/forms/input/text/suppress-password-button-notref.html
@@ -0,0 +1 @@
+<input type="password" value="abc">
diff --git a/layout/reftests/forms/input/text/suppress-password-button.html b/layout/reftests/forms/input/text/suppress-password-button.html
new file mode 100644
index 0000000000..53398e20df
--- /dev/null
+++ b/layout/reftests/forms/input/text/suppress-password-button.html
@@ -0,0 +1 @@
+<input type="password" value="abc" style="appearance: textfield">
diff --git a/layout/reftests/forms/textarea/in-ltr-doc-scrollbar.html b/layout/reftests/forms/textarea/in-ltr-doc-scrollbar.html
index e6b14358ec..c0b294ce73 100644
--- a/layout/reftests/forms/textarea/in-ltr-doc-scrollbar.html
+++ b/layout/reftests/forms/textarea/in-ltr-doc-scrollbar.html
@@ -5,6 +5,9 @@
<title></title>
</head>
<body>
- <textarea cols=20 rows=4 style="overflow: scroll; resize: none"></textarea>
+ <textarea cols=20 rows=4
+ style="overflow: scroll;
+ resize: none;
+ scrollbar-color: pink blue"></textarea>
</body>
</html>
diff --git a/layout/reftests/forms/textarea/in-rtl-doc-scrollbar.html b/layout/reftests/forms/textarea/in-rtl-doc-scrollbar.html
index 8c915b5ee9..5700b37fc2 100644
--- a/layout/reftests/forms/textarea/in-rtl-doc-scrollbar.html
+++ b/layout/reftests/forms/textarea/in-rtl-doc-scrollbar.html
@@ -5,6 +5,10 @@
<title></title>
</head>
<body>
- <textarea cols=20 rows=4 style="float: left; overflow: scroll; resize: none"></textarea>
+ <textarea cols=20 rows=4
+ style="float: left;
+ overflow: scroll;
+ resize: none;
+ scrollbar-color: pink blue"></textarea>
</body>
</html>
diff --git a/layout/reftests/forms/textarea/ltr-scrollbar.html b/layout/reftests/forms/textarea/ltr-scrollbar.html
index 927fbede66..04384ff9d6 100644
--- a/layout/reftests/forms/textarea/ltr-scrollbar.html
+++ b/layout/reftests/forms/textarea/ltr-scrollbar.html
@@ -5,6 +5,9 @@
<title></title>
</head>
<body>
- <textarea dir="ltr" cols=20 rows=4 style="overflow: scroll; resize: none"></textarea>
+ <textarea dir="ltr" cols=20 rows=4
+ style="overflow: scroll;
+ resize: none;
+ scrollbar-color: pink blue"></textarea>
</body>
</html>
diff --git a/layout/reftests/forms/textarea/rtl-scrollbar.html b/layout/reftests/forms/textarea/rtl-scrollbar.html
index 2770dc6941..63462f1ce8 100644
--- a/layout/reftests/forms/textarea/rtl-scrollbar.html
+++ b/layout/reftests/forms/textarea/rtl-scrollbar.html
@@ -5,6 +5,9 @@
<title></title>
</head>
<body>
- <textarea dir="rtl" cols=20 rows=4 style="overflow: scroll; resize: none"></textarea>
+ <textarea dir="rtl" cols=20 rows=4
+ style="overflow: scroll;
+ resize: none;
+ scrollbar-color: pink blue"></textarea>
</body>
</html>
diff --git a/layout/reftests/marquee/336736-1a-ref.html b/layout/reftests/marquee/336736-1a-ref.html
new file mode 100644
index 0000000000..690992b8a5
--- /dev/null
+++ b/layout/reftests/marquee/336736-1a-ref.html
@@ -0,0 +1,5 @@
+<html>
+<body dir="rtl">
+<div style="background: green; width: 50px">&nbsp;</div>
+</body>
+</html>
diff --git a/layout/reftests/marquee/336736-1-ref.html b/layout/reftests/marquee/336736-1b-ref.html
index 116e5ade28..116e5ade28 100644
--- a/layout/reftests/marquee/336736-1-ref.html
+++ b/layout/reftests/marquee/336736-1b-ref.html
diff --git a/layout/reftests/marquee/reftest.list b/layout/reftests/marquee/reftest.list
index ac6772f6c9..c7d2fafd30 100644
--- a/layout/reftests/marquee/reftest.list
+++ b/layout/reftests/marquee/reftest.list
@@ -1,6 +1,6 @@
== 166591-dynamic-1.html 166591-dynamic-1-ref.html
-fuzzy-if(Android,0-8,0-50) == 336736-1a.html 336736-1-ref.html
-fuzzy-if(Android,0-8,0-50) == 336736-1b.html 336736-1-ref.html
+fuzzy-if(Android,0-8,0-50) == 336736-1a.html 336736-1a-ref.html
+fuzzy-if(Android,0-8,0-50) == 336736-1b.html 336736-1b-ref.html
== 406073-1.html 406073-1-ref.html
== 407016-2.html 407016-2-ref.html
fuzzy-if(Android,0-8,0-220) == 413027-4.html 413027-4-ref.html
diff --git a/layout/reftests/moz.build b/layout/reftests/moz.build
index 14b30d92a3..261ea6db09 100644
--- a/layout/reftests/moz.build
+++ b/layout/reftests/moz.build
@@ -171,8 +171,6 @@ with Files("native-theme/**"):
BUG_COMPONENT = ("Core", "Layout")
with Files("object/**"):
BUG_COMPONENT = ("Core", "DOM: Core & HTML")
-with Files("ogg-video/**"):
- BUG_COMPONENT = ("Core", "Audio/Video")
with Files("outline/**"):
BUG_COMPONENT = ("Core", "Layout")
with Files("pagination/**"):
diff --git a/layout/reftests/ogg-video/444-1-ref.html b/layout/reftests/ogg-video/444-1-ref.html
deleted file mode 100644
index 08e4df28ee..0000000000
--- a/layout/reftests/ogg-video/444-1-ref.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<body>
-<video id="v1" style="position:absolute; left:0; top:0"></video>
-<!-- hide bottom of video -->
-<div style="position:absolute; top:120px; left:0; right:0; bottom:0; background:black"></div>
-<script>
-function doTest() {
- // Set source now so that the loadeddata event can't fire before
- // this function runs.
- v1.src = "seek420.ogv";
- v1.play();
- v1.addEventListener("loadeddata", function() {
- setTimeout(function() {
- document.documentElement.removeAttribute('class');
- }, 50);
- });
-}
-document.addEventListener("MozReftestInvalidate", doTest);
-</script>
diff --git a/layout/reftests/ogg-video/444-1.html b/layout/reftests/ogg-video/444-1.html
deleted file mode 100644
index 02e7b3ddb8..0000000000
--- a/layout/reftests/ogg-video/444-1.html
+++ /dev/null
@@ -1,20 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<body>
-<video id="v1" style="position:absolute; left:0; top:0"></video>
-<!-- hide bottom of video -->
-<div style="position:absolute; top:120px; left:0; right:0; bottom:0; background:black"></div>
-<script>
-function doTest() {
- // Set source now so that the loadeddata event can't fire before
- // this function runs.
- v1.src = "seek444.ogv";
- v1.play();
- v1.addEventListener("loadeddata", function() {
- setTimeout(function() {
- document.documentElement.removeAttribute('class');
- }, 50);
- });
-}
-document.addEventListener("MozReftestInvalidate", doTest);
-</script>
diff --git a/layout/reftests/ogg-video/aspect-ratio-1-ref.html b/layout/reftests/ogg-video/aspect-ratio-1-ref.html
deleted file mode 100644
index 93391ed83c..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-1-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<div style="width:140px; height:100px; position:relative; left:100px; top:100px; background:black;"></div>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/aspect-ratio-1a.xhtml b/layout/reftests/ogg-video/aspect-ratio-1a.xhtml
deleted file mode 100644
index c70d3248f5..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-1a.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black140x100.ogv" style="width:340px; height:100px; position:relative; top:100px;"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/aspect-ratio-1b.xhtml b/layout/reftests/ogg-video/aspect-ratio-1b.xhtml
deleted file mode 100644
index b59352b516..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-1b.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black140x100.ogv" style="width:140px; height:300px; position:relative; left:100px;"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/aspect-ratio-2-ref.html b/layout/reftests/ogg-video/aspect-ratio-2-ref.html
deleted file mode 100644
index 4f78ab4d2f..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-2-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<div style="width:280px; height:200px; position:relative; left:200px; top:200px; background:black;"></div>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/aspect-ratio-2a.xhtml b/layout/reftests/ogg-video/aspect-ratio-2a.xhtml
deleted file mode 100644
index f708ec90af..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-2a.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black140x100.ogv" style="width:680px; height:200px; position:relative; top:200px;"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/aspect-ratio-2b.xhtml b/layout/reftests/ogg-video/aspect-ratio-2b.xhtml
deleted file mode 100644
index e7469031a8..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-2b.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black140x100.ogv" style="width:280px; height:600px; position:relative; left:200px;"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/aspect-ratio-3-ref.xhtml b/layout/reftests/ogg-video/aspect-ratio-3-ref.xhtml
deleted file mode 100644
index 73662654f8..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-3-ref.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black140x100.ogv" style="width:280px; height:200px;"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/aspect-ratio-3a.xhtml b/layout/reftests/ogg-video/aspect-ratio-3a.xhtml
deleted file mode 100644
index 3c253e8f81..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-3a.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black140x100.ogv" width="280"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/aspect-ratio-3b.xhtml b/layout/reftests/ogg-video/aspect-ratio-3b.xhtml
deleted file mode 100644
index cc6ec4c750..0000000000
--- a/layout/reftests/ogg-video/aspect-ratio-3b.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black140x100.ogv" height="200"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/basic-1-ref.html b/layout/reftests/ogg-video/basic-1-ref.html
deleted file mode 100644
index aca3dcb9ca..0000000000
--- a/layout/reftests/ogg-video/basic-1-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<div style="width:140px; height:100px; background:black;"></div>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/basic-1.xhtml b/layout/reftests/ogg-video/basic-1.xhtml
deleted file mode 100644
index 4899dc29f7..0000000000
--- a/layout/reftests/ogg-video/basic-1.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black140x100.ogv"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/black100x100-aspect3to2.ogv b/layout/reftests/ogg-video/black100x100-aspect3to2.ogv
deleted file mode 100644
index 81fe51ffb3..0000000000
--- a/layout/reftests/ogg-video/black100x100-aspect3to2.ogv
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/black140x100.ogv b/layout/reftests/ogg-video/black140x100.ogv
deleted file mode 100644
index ab146ebe28..0000000000
--- a/layout/reftests/ogg-video/black140x100.ogv
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/black29x19offset.ogv b/layout/reftests/ogg-video/black29x19offset.ogv
deleted file mode 100644
index b515ebd1f3..0000000000
--- a/layout/reftests/ogg-video/black29x19offset.ogv
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/blue140x100.png b/layout/reftests/ogg-video/blue140x100.png
deleted file mode 100644
index f4c3973fcc..0000000000
--- a/layout/reftests/ogg-video/blue140x100.png
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/blue250x200.png b/layout/reftests/ogg-video/blue250x200.png
deleted file mode 100644
index 5eb0b52511..0000000000
--- a/layout/reftests/ogg-video/blue250x200.png
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/canvas-1a.xhtml b/layout/reftests/ogg-video/canvas-1a.xhtml
deleted file mode 100644
index 9f115e785f..0000000000
--- a/layout/reftests/ogg-video/canvas-1a.xhtml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1" class="reftest-wait">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body>
-<canvas id="canvas" width="200" height="200"></canvas>
-<script>
-var video = document.createElement("video");
-video.src = "black140x100.ogv";
-video.load();
-function draw() {
- var canvas = document.getElementById("canvas");
- var ctx = canvas.getContext("2d");
- try {
- ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
- } catch (e) {
- }
- document.documentElement.removeAttribute("class");
-}
-video.addEventListener("loadeddata", draw, false);
-</script>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/canvas-1b.xhtml b/layout/reftests/ogg-video/canvas-1b.xhtml
deleted file mode 100644
index 4524593e9e..0000000000
--- a/layout/reftests/ogg-video/canvas-1b.xhtml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body>
-<canvas id="canvas" width="200" height="200"></canvas>
-<script>
-function draw() {
- var video = document.getElementById("video");
- var canvas = document.getElementById("canvas");
- var ctx = canvas.getContext("2d");
- try {
- ctx.drawImage(video, 0, 0, video.videoWidth, video.videoHeight);
- } catch (e) {
- }
- document.documentElement.removeAttribute("class");
-}
-</script>
-<video id="video" src="black140x100.ogv" onloadeddata="draw()" style="opacity:0"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/clipping-1-ref.html b/layout/reftests/ogg-video/clipping-1-ref.html
deleted file mode 100644
index 67782811c5..0000000000
--- a/layout/reftests/ogg-video/clipping-1-ref.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white">
-<div style="position:absolute; left:0; top:0; width:200px; height:600px;">
- <video src="black140x100.ogv" style="width:400px; margin-left:-100px;"></video>
-</div>
-<div style="position:absolute; left:200px; top:0; background:white; width:200px; height:600px;"></div>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/clipping-1a.html b/layout/reftests/ogg-video/clipping-1a.html
deleted file mode 100644
index cfae72cedd..0000000000
--- a/layout/reftests/ogg-video/clipping-1a.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white">
-<div style="overflow:hidden; position:absolute; left:0; top:0; width:200px; height:600px;">
- <video src="black140x100.ogv" style="width:400px; margin-left:-100px;"></video>
-</div>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/empty-1-ref.html b/layout/reftests/ogg-video/empty-1-ref.html
deleted file mode 100644
index fcc7693202..0000000000
--- a/layout/reftests/ogg-video/empty-1-ref.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/empty-1a.html b/layout/reftests/ogg-video/empty-1a.html
deleted file mode 100644
index fc1421a810..0000000000
--- a/layout/reftests/ogg-video/empty-1a.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<video src="black140x100.ogv" style="width:0"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/empty-1b.html b/layout/reftests/ogg-video/empty-1b.html
deleted file mode 100644
index 9dd17dbbaa..0000000000
--- a/layout/reftests/ogg-video/empty-1b.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<video src="black140x100.ogv" style="height:0"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/encoded-aspect-ratio-1-ref.html b/layout/reftests/ogg-video/encoded-aspect-ratio-1-ref.html
deleted file mode 100644
index d9c0054eb5..0000000000
--- a/layout/reftests/ogg-video/encoded-aspect-ratio-1-ref.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<div style="background-color: black; width: 150px; height: 100px; position: absolute; left: 10px; top: 10px;"></div>
-
-<!-- Left side vertical. -->
-<div style="position: absolute; left: 9px; top: 9px; width: 2px; height: 102px; z-index: 2; background: red;"></div>
-
-<!-- Right side vertical. -->
-<div style="position: absolute; left: 159px; top: 9px; width: 2px; height: 102px; z-index: 2; background: red;"></div>
-
-<!-- Top horizontal bar. -->
-<div style="position: absolute; left: 9px; top: 9px; width: 152px; height: 2px; z-index: 2; background: red;"></div>
-
-<!-- Bottom horizontal bar. -->
-<div style="position: absolute; left: 9px; top: 109px; width: 152px; height: 2px; z-index: 2; background: red;"></div>
-
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/encoded-aspect-ratio-1.html b/layout/reftests/ogg-video/encoded-aspect-ratio-1.html
deleted file mode 100644
index 238fdbfe8d..0000000000
--- a/layout/reftests/ogg-video/encoded-aspect-ratio-1.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<!--
- Test if video displays correctly with a 3:2 aspect ratio.
- It should display at w=150 h=100.
- On some Linux systems, the scaling to preserve the aspect ratio can sample
- the pixels outside visible region. This results in a thin grey line down
- some sides of the scaled picture. We add red bars over the edges to
- overwrite such happenings, to make the test reliable.
--->
-<video src="black100x100-aspect3to2.ogv"
- style="position:absolute; left: 10px; top: 10px; z-index: 1;">
-</video>
-
-<!-- Left side vertical. -->
-<div style="position: absolute; left: 9px; top: 9px; width: 2px; height: 102px; z-index: 2; background: red;"></div>
-
-<!-- Right side vertical. -->
-<div style="position: absolute; left: 159px; top: 9px; width: 2px; height: 102px; z-index: 2; background: red;"></div>
-
-<!-- Top horizontal bar. -->
-<div style="position: absolute; left: 9px; top: 9px; width: 152px; height: 2px; z-index: 2; background: red;"></div>
-
-<!-- Bottom horizontal bar. -->
-<div style="position: absolute; left: 9px; top: 109px; width: 152px; height: 2px; z-index: 2; background: red;"></div>
-
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/green70x30.png b/layout/reftests/ogg-video/green70x30.png
deleted file mode 100644
index b2bf32762d..0000000000
--- a/layout/reftests/ogg-video/green70x30.png
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/object-aspect-ratio-1a.xhtml b/layout/reftests/ogg-video/object-aspect-ratio-1a.xhtml
deleted file mode 100644
index 29fd619fd7..0000000000
--- a/layout/reftests/ogg-video/object-aspect-ratio-1a.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<object data="black140x100.ogv" style="width:340px; height:100px; position:relative; top:100px;"></object>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/object-aspect-ratio-1b.xhtml b/layout/reftests/ogg-video/object-aspect-ratio-1b.xhtml
deleted file mode 100644
index ea1f02ff74..0000000000
--- a/layout/reftests/ogg-video/object-aspect-ratio-1b.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<object data="black140x100.ogv" style="width:140px; height:300px; position:relative; left:100px;"></object>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/object-aspect-ratio-2a.xhtml b/layout/reftests/ogg-video/object-aspect-ratio-2a.xhtml
deleted file mode 100644
index 36b4cc0c1e..0000000000
--- a/layout/reftests/ogg-video/object-aspect-ratio-2a.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<object data="black140x100.ogv" style="width:680px; height:200px; position:relative; top:200px;"></object>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/object-aspect-ratio-2b.xhtml b/layout/reftests/ogg-video/object-aspect-ratio-2b.xhtml
deleted file mode 100644
index d557921d2f..0000000000
--- a/layout/reftests/ogg-video/object-aspect-ratio-2b.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<object data="black140x100.ogv" style="width:280px; height:600px; position:relative; left:200px;"></object>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/offset-1-ref.html b/layout/reftests/ogg-video/offset-1-ref.html
deleted file mode 100644
index 61a1dc83a7..0000000000
--- a/layout/reftests/ogg-video/offset-1-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<div style="width:29px; height:29px; background:black;"></div>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/offset-1.xhtml b/layout/reftests/ogg-video/offset-1.xhtml
deleted file mode 100644
index 3504734907..0000000000
--- a/layout/reftests/ogg-video/offset-1.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject filter="url(../filters.svg#ThresholdRGB)" x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white;">
-<video src="black29x19offset.ogv"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/ogg-video/poster-1.html b/layout/reftests/ogg-video/poster-1.html
deleted file mode 100644
index 15e3cb5462..0000000000
--- a/layout/reftests/ogg-video/poster-1.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<!-- Ensure video element displays at poster size when video's intrinsic size isn't available. -->
-<video preload="none" src="black140x100.ogv" poster="blue250x200.png"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-10.html b/layout/reftests/ogg-video/poster-10.html
deleted file mode 100644
index 546b96a46f..0000000000
--- a/layout/reftests/ogg-video/poster-10.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<!-- Test: Create video, add poster, load. Should display poster. -->
-<script>
-function runTest() {
- var v = document.createElement('video');
- v.addEventListener('loadeddata', function(){setTimeout(function(){document.documentElement.className = '';}, 0);});
- v.id = 'v';
- v.src = "black140x100.ogv";
- v.poster = "blue250x200.png";
- v.preload = "auto";
- document.body.appendChild(v);
-}
-
-</script>
-<body style="background:white;" onload="runTest();">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-11.html b/layout/reftests/ogg-video/poster-11.html
deleted file mode 100644
index a2f186a4bb..0000000000
--- a/layout/reftests/ogg-video/poster-11.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<!-- Test: Create video, load. Add poster frame, load again, poster should show. -->
-<script>
-function runTest() {
- var v = document.createElement('video');
-
- var endTest = function() {
- setTimeout(function(){document.documentElement.className = '';}, 0);
- };
-
- var addPoster = function() {
- v.removeEventListener('loadeddata', addPoster);
- v.poster = "blue140x100.png";
- v.addEventListener('loadeddata', endTest);
- v.load();
- };
-
- v.addEventListener('loadeddata', addPoster);
- v.id = 'v';
- v.src = "black140x100.ogv";
- v.preload = "auto";
- document.body.appendChild(v);
-}
-
-</script>
-<body style="background:white;" onload="runTest();">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-12.html b/layout/reftests/ogg-video/poster-12.html
deleted file mode 100644
index 49b6dbfebf..0000000000
--- a/layout/reftests/ogg-video/poster-12.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<!-- Test: Create video, load, play. Add poster frame, load again, poster should show. -->
-<script>
-function runTest() {
- var v = document.createElement('video');
-
- var endTest = function() {
- setTimeout(function(){document.documentElement.className = '';}, 0);
- };
-
- var play =
- function() {
- v.removeEventListener('loadeddata', play);
- v.play();
- }
-
- var addPoster = function() {
- v.removeEventListener('playing', addPoster);
- v.poster = "blue140x100.png";
- v.addEventListener('loadeddata', endTest);
- v.load();
- };
-
- v.addEventListener('loadeddata',
- play);
- v.addEventListener('playing',
- addPoster);
- v.id = 'v';
- v.src = "black140x100.ogv";
- v.preload = "auto";
- document.body.appendChild(v);
-}
-
-</script>
-<body style="background:white;" onload="runTest();">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-13.html b/layout/reftests/ogg-video/poster-13.html
deleted file mode 100644
index 79c3b8c582..0000000000
--- a/layout/reftests/ogg-video/poster-13.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<!-- Test that poster is resized, maintaining its aspect ratio. -->
-<video src="black140x100.ogv" poster="blue250x200.png" style="width: 288px; height: 216px;"></video>
-
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-15.html b/layout/reftests/ogg-video/poster-15.html
deleted file mode 100644
index 01c25b660e..0000000000
--- a/layout/reftests/ogg-video/poster-15.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!-- Test that poster is correctly laid out inside borders. Also test that
- poster frames smaller than video don't have the video frame drawn behind
- them etc. -->
-<body style="background:white;">
-<video src="black140x100.ogv"
- poster="green70x30.png"
- preload="none"
- style="border: solid blue 2px;">
-</video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-2.html b/layout/reftests/ogg-video/poster-2.html
deleted file mode 100644
index 28b38f398c..0000000000
--- a/layout/reftests/ogg-video/poster-2.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<!-- Test if poster frame with invalid poster displays video frame. -->
-<video src="black140x100.ogv" poster="not-a-valid-file"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-3.html b/layout/reftests/ogg-video/poster-3.html
deleted file mode 100644
index ae12c1b65d..0000000000
--- a/layout/reftests/ogg-video/poster-3.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<body style="background:white;">
-<!-- Test if poster hides after playing with autoplay. -->
-<video src="black140x100.ogv"
- poster="blue250x200.png"
- preload="auto"
- autoplay
- onplaying="setTimeout(function(){document.documentElement.className = '';},0);"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-4.html b/layout/reftests/ogg-video/poster-4.html
deleted file mode 100644
index 85453638c8..0000000000
--- a/layout/reftests/ogg-video/poster-4.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<body style="background:white;"
- onload="setTimeout(function(){document.documentElement.className = '';}, 0);">
-<!-- Test if we show video frame after removing valid poster. -->
-<video src="black140x100.ogv"
- preload="auto"
- id="v"
- poster="blue250x200.png"></video>
-<script type="text/javascript">
- document.getElementById('v').poster = '';
-</script>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-5.html b/layout/reftests/ogg-video/poster-5.html
deleted file mode 100644
index 94049c92d7..0000000000
--- a/layout/reftests/ogg-video/poster-5.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<body style="background:white;">
-<!-- Test to ensure that changing the poster after video has painted its first
- frame doesn't render the poster. The video frame should not change to the
- poster, since it's already painted its first video frame. -->
-<video src="black140x100.ogv"
- preload="auto"
- id="v"
- autoplay
- onended="document.getElementById('v').poster = 'blue250x200.png'; setTimeout(function(){document.documentElement.className = '';},0);"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-6.html b/layout/reftests/ogg-video/poster-6.html
deleted file mode 100644
index c9ae5b88f5..0000000000
--- a/layout/reftests/ogg-video/poster-6.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<body style="background:white;">
-<!-- Test that poster frame should hide after completing a seek. -->
-<video src="black140x100.ogv"
- preload="auto"
- id="v"
- onloadeddata="var v = document.getElementById('v'); v.currentTime = v.duration;"
- onseeked="setTimeout(function(){document.documentElement.className = '';}, 0);"
- poster="blue250x200.png"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-7.html b/layout/reftests/ogg-video/poster-7.html
deleted file mode 100644
index 4c3e002d37..0000000000
--- a/layout/reftests/ogg-video/poster-7.html
+++ /dev/null
@@ -1,14 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<body style="background:white;"
- onload="setTimeout(function(){document.documentElement.className = '';}, 0);">
-<!-- Test that poster frame changes when you change the poster attribute. -->
-<video src="black140x100.ogv"
- preload="none"
- id="v"
- poster="blue250x200.png"></video>
-<script type="text/javascript">
- document.getElementById('v').poster = 'red140x100.png';
-</script>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-8.html b/layout/reftests/ogg-video/poster-8.html
deleted file mode 100644
index c9e1fa37a0..0000000000
--- a/layout/reftests/ogg-video/poster-8.html
+++ /dev/null
@@ -1,12 +0,0 @@
-<!DOCTYPE HTML>
-<html class="reftest-wait">
-<body style="background:white;">
-<!-- Test if poster hides after playing with play() call. -->
-<video src="black140x100.ogv"
- poster="blue250x200.png"
- id="v"
- preload="auto"
- onloadeddata="document.getElementById('v').play();"
- onplaying="setTimeout(function(){document.documentElement.className = '';}, 0);"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-ref-black140x100.html b/layout/reftests/ogg-video/poster-ref-black140x100.html
deleted file mode 100644
index 98f1a4cba7..0000000000
--- a/layout/reftests/ogg-video/poster-ref-black140x100.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<video src="black140x100.ogv" preload="auto"></video>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-ref-blue125x100.html b/layout/reftests/ogg-video/poster-ref-blue125x100.html
deleted file mode 100644
index 90795ae911..0000000000
--- a/layout/reftests/ogg-video/poster-ref-blue125x100.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<img src="blue140x100.png" alt="poster" style="position: absolute; height: 100px; width: 125px; left: 16px">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-ref-blue140x100.html b/layout/reftests/ogg-video/poster-ref-blue140x100.html
deleted file mode 100644
index 66540b8e85..0000000000
--- a/layout/reftests/ogg-video/poster-ref-blue140x100.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<img src="blue140x100.png" alt="poster">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-ref-blue250x200.html b/layout/reftests/ogg-video/poster-ref-blue250x200.html
deleted file mode 100644
index 050d53dfb3..0000000000
--- a/layout/reftests/ogg-video/poster-ref-blue250x200.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<img src="blue250x200.png" alt="poster">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-ref-blue400x300.html b/layout/reftests/ogg-video/poster-ref-blue400x300.html
deleted file mode 100644
index 8c32ff715d..0000000000
--- a/layout/reftests/ogg-video/poster-ref-blue400x300.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<img src="blue250x200.png" style="position: relative; width: 270px; height: 216px; left: 9px;">
-</body>
-</html>
-
-
diff --git a/layout/reftests/ogg-video/poster-ref-green70x30.html b/layout/reftests/ogg-video/poster-ref-green70x30.html
deleted file mode 100644
index f979220a6a..0000000000
--- a/layout/reftests/ogg-video/poster-ref-green70x30.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<img src="green70x30.png" alt="poster" style="border: solid blue 2px;">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/poster-ref-red140x100.html b/layout/reftests/ogg-video/poster-ref-red140x100.html
deleted file mode 100644
index 3ac08d29e2..0000000000
--- a/layout/reftests/ogg-video/poster-ref-red140x100.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white;">
-<img src="red140x100.png" alt="poster">
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/red140x100.png b/layout/reftests/ogg-video/red140x100.png
deleted file mode 100644
index 20250771f3..0000000000
--- a/layout/reftests/ogg-video/red140x100.png
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/red160x120.png b/layout/reftests/ogg-video/red160x120.png
deleted file mode 100644
index 21737a0e8e..0000000000
--- a/layout/reftests/ogg-video/red160x120.png
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/reftest.list b/layout/reftests/ogg-video/reftest.list
deleted file mode 100644
index 2c9a96f8ee..0000000000
--- a/layout/reftests/ogg-video/reftest.list
+++ /dev/null
@@ -1,35 +0,0 @@
-# NOTE: bug 1084564 covers "fails"/"skip" annotations for android below:
-fuzzy(0-255,0-5000) == 444-1.html 444-1-ref.html
-fails-if(Android) == aspect-ratio-1a.xhtml aspect-ratio-1-ref.html
-fails-if(Android) == aspect-ratio-1b.xhtml aspect-ratio-1-ref.html
-fails-if(Android) skip-if(gtkWidget) == aspect-ratio-2a.xhtml aspect-ratio-2-ref.html
-fails-if(Android) skip-if(gtkWidget) == aspect-ratio-2b.xhtml aspect-ratio-2-ref.html
-== aspect-ratio-3a.xhtml aspect-ratio-3-ref.xhtml
-== aspect-ratio-3b.xhtml aspect-ratio-3-ref.xhtml
-fails-if(Android) random == encoded-aspect-ratio-1.html encoded-aspect-ratio-1-ref.html
-fails-if(Android) == basic-1.xhtml basic-1-ref.html
-== canvas-1a.xhtml basic-1-ref.html
-fails-if(Android) == canvas-1b.xhtml basic-1-ref.html
-== clipping-1a.html clipping-1-ref.html
-== empty-1a.html empty-1-ref.html
-== empty-1b.html empty-1-ref.html
-#these is skipped because we hang on the htmlparser tests when this is ran
-random == object-aspect-ratio-1a.xhtml aspect-ratio-1-ref.html
-random == object-aspect-ratio-1b.xhtml aspect-ratio-1-ref.html
-== offset-1.xhtml offset-1-ref.html
-random == object-aspect-ratio-2a.xhtml aspect-ratio-2-ref.html
-random == object-aspect-ratio-2b.xhtml aspect-ratio-2-ref.html
-fuzzy-if(winWidget,0-1,0-56000) fuzzy-if(cocoaWidget,0-1,0-56000) == zoomed-1.xhtml zoomed-1-ref.html # bug 778995 for fuzzy
-== poster-1.html poster-ref-blue250x200.html
-== poster-2.html poster-ref-black140x100.html
-== poster-3.html poster-ref-black140x100.html
-== poster-4.html poster-ref-black140x100.html
-== poster-5.html poster-ref-black140x100.html
-== poster-6.html poster-ref-black140x100.html
-== poster-7.html poster-ref-red140x100.html
-== poster-8.html poster-ref-black140x100.html
-random == poster-10.html poster-ref-blue125x100.html
-random == poster-11.html poster-ref-blue140x100.html
-random == poster-12.html poster-ref-blue140x100.html
-== poster-13.html poster-ref-blue400x300.html
-== poster-15.html poster-ref-green70x30.html
diff --git a/layout/reftests/ogg-video/seek420.ogv b/layout/reftests/ogg-video/seek420.ogv
deleted file mode 100644
index 2221cfef42..0000000000
--- a/layout/reftests/ogg-video/seek420.ogv
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/seek444.ogv b/layout/reftests/ogg-video/seek444.ogv
deleted file mode 100644
index a2453afeae..0000000000
--- a/layout/reftests/ogg-video/seek444.ogv
+++ /dev/null
Binary files differ
diff --git a/layout/reftests/ogg-video/zoomed-1-ref.html b/layout/reftests/ogg-video/zoomed-1-ref.html
deleted file mode 100644
index 01929db7e7..0000000000
--- a/layout/reftests/ogg-video/zoomed-1-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<body style="background:white; margin:0;">
-<div style="width:280px; height:200px; background:#010101;"></div>
-</body>
-</html>
diff --git a/layout/reftests/ogg-video/zoomed-1.xhtml b/layout/reftests/ogg-video/zoomed-1.xhtml
deleted file mode 100644
index e68e1290f4..0000000000
--- a/layout/reftests/ogg-video/zoomed-1.xhtml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg"
- xmlns:xlink="http://www.w3.org/1999/xlink"
- version="1.1" reftest-zoom="2"
- width="50%" height="50%">
-<!-- use an empty g to force filters.svg to load before onload -->
-<use xlink:href="../filters.svg#empty" />
-<foreignObject x="0" y="0" height="100%" width="100%">
-<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
-<body style="background:white; margin:0">
-<video src="black140x100.ogv"></video>
-</body>
-</html>
-</foreignObject>
-</svg>
diff --git a/layout/reftests/position-sticky/reftest.list b/layout/reftests/position-sticky/reftest.list
index bd9aadc1d0..d6ed9617fe 100644
--- a/layout/reftests/position-sticky/reftest.list
+++ b/layout/reftests/position-sticky/reftest.list
@@ -51,5 +51,5 @@ fuzzy(0-1,0-220) == block-in-inline-3.html block-in-inline-3-ref.html
== iframe-1.html iframe-1-ref.html
== transformed-1.html transformed-1-ref.html
fuzzy-if(Android,0-8,0-9) fuzzy-if(gtkWidget,10-17,12-32) fuzzy-if(cocoaWidget,7-8,18-42) skip-if(useDrawSnapshot) fails-if(useDrawSnapshot) == transformed-2.html transformed-2-ref.html # Bug 1604644
-skip-if(useDrawSnapshot) fuzzy-if(Android,0-14,0-11) fuzzy-if(gtkWidget,19-30,12-32) fuzzy-if(cocoaWidget,13-16,20-44) fails-if(useDrawSnapshot) == nested-sticky-1.html nested-sticky-1-ref.html # Bug 1604644
-skip-if(useDrawSnapshot) fuzzy-if(Android,0-14,0-11) fuzzy-if(gtkWidget,19-30,12-32) fuzzy-if(cocoaWidget,13-16,20-44) fails-if(useDrawSnapshot) == nested-sticky-2.html nested-sticky-2-ref.html # Bug 1604644
+skip-if(useDrawSnapshot) fuzzy-if(Android,0-14,0-17) fuzzy-if(gtkWidget,19-30,12-32) fuzzy-if(cocoaWidget,13-16,20-44) fails-if(useDrawSnapshot) == nested-sticky-1.html nested-sticky-1-ref.html # Bug 1604644
+skip-if(useDrawSnapshot) fuzzy-if(Android,0-14,0-96) fuzzy-if(gtkWidget,19-30,12-32) fuzzy-if(cocoaWidget,13-16,20-44) fails-if(useDrawSnapshot) == nested-sticky-2.html nested-sticky-2-ref.html # Bug 1604644
diff --git a/layout/reftests/printing/1900028-text-mask-pdf-ref.html b/layout/reftests/printing/1900028-text-mask-pdf-ref.html
new file mode 100644
index 0000000000..5cd8dc37d3
--- /dev/null
+++ b/layout/reftests/printing/1900028-text-mask-pdf-ref.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <link href="print.css" rel="stylesheet">
+ <style>
+ .test {
+ font-size: 50px;
+ height: 2em;
+ }
+ </style>
+</head>
+<p>Some text</p>
+<p class=test><!-- This will not be visible in the print output,
+ unless backgrounds are explicitly enabled. --></p>
+<p>More text after the test</p>
diff --git a/layout/reftests/printing/1900028-text-mask-pdf.html b/layout/reftests/printing/1900028-text-mask-pdf.html
new file mode 100644
index 0000000000..3e32d98c16
--- /dev/null
+++ b/layout/reftests/printing/1900028-text-mask-pdf.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<head>
+ <meta charset="utf-8">
+ <link href="print.css" rel="stylesheet">
+ <style>
+ .test {
+ color: transparent;
+ font-size: 50px;
+ background: blue;
+ background-clip: text;
+ height: 2em;
+ }
+ </style>
+</head>
+<p>Some text</p>
+<p class=test>background-clip:text</p>
+<p>More text after the test</p>
diff --git a/layout/reftests/printing/reftest.list b/layout/reftests/printing/reftest.list
index eb571f067a..3e474ae47a 100644
--- a/layout/reftests/printing/reftest.list
+++ b/layout/reftests/printing/reftest.list
@@ -19,3 +19,4 @@ fails print test-unexpected-text.html test-unexpected-text-noref.html
fails print test-missing-text.html test-missing-text-noref.html
test-pref(print.print_in_color,false) fails print test-color-text-01.html test-color-text-01.html
print testcase-1696844.html testcase-1696844.html
+print 1900028-text-mask-pdf.html 1900028-text-mask-pdf-ref.html
diff --git a/layout/reftests/reftest-sanity/reftest.list b/layout/reftests/reftest-sanity/reftest.list
index 52b6982aac..df657fd683 100644
--- a/layout/reftests/reftest-sanity/reftest.list
+++ b/layout/reftests/reftest-sanity/reftest.list
@@ -46,11 +46,6 @@ fails-if(geckoview&&device) == filter-2.xhtml filter-2-ref.xhtml
== invalidation.html about:blank
fails-if(useDrawSnapshot) == zoom-invalidation.html zoom-invalidation-ref.html # bug 773482
-# test that xulRuntime.OS works
-fails-if(xulRuntime.OS!="Linux"&&!Android) == data:text/html,<body>Linux data:text/html,<script>document.write(navigator.platform.substr(0,5))</script>
-fails-if(xulRuntime.OS!="WINNT") == data:text/html,<body>Win data:text/html,<script>document.write(navigator.platform.substr(0,3))</script>
-fails-if(xulRuntime.OS!="Darwin") == data:text/html,<body>Mac data:text/html,<script>document.write(navigator.platform.substr(0,3))</script>
-
# test parsing of asserts() expressions
asserts(0) load about:blank
asserts(0-5) load about:blank
diff --git a/layout/reftests/reftest.list b/layout/reftests/reftest.list
index 9587c70798..c8911b2f20 100644
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -18,7 +18,8 @@ include position-relative/reftest.list
# apng-mime
include apng-mime/reftest.list
-skip-if(unsupportedWithDrawSnapshot) include async-scrolling/reftest.list
+# unsupported with draw snapshot
+skip-if(useDrawSnapshot) include async-scrolling/reftest.list
# backgrounds/
include backgrounds/reftest.list
@@ -273,9 +274,6 @@ include outline/reftest.list
# object/
include object/reftest.list
-# ogg-video/
-skip include ogg-video/reftest.list
-
# webm-video/
skip include webm-video/reftest.list
@@ -363,9 +361,6 @@ include text-svgglyphs/reftest.list
# text-transform/
include text-transform/reftest.list
-# theme (osx)
-include ../../toolkit/themes/osx/reftests/reftest.list
-
include ../../toolkit/content/tests/reftests/reftest.list
# transform/
@@ -434,7 +429,8 @@ include invalidation/reftest.list
include ../../dom/encoding/test/reftest/reftest.list
# APZ/async positioning tests
-skip-if(unsupportedWithDrawSnapshot) include ../../gfx/layers/apz/test/reftest/reftest.list
+# unsupported with draw snapshot
+skip-if(useDrawSnapshot) include ../../gfx/layers/apz/test/reftest/reftest.list
# Display list building
include display-list/reftest.list
diff --git a/layout/reftests/scrolling/reftest.list b/layout/reftests/scrolling/reftest.list
index 159f480416..d88bc2e038 100644
--- a/layout/reftests/scrolling/reftest.list
+++ b/layout/reftests/scrolling/reftest.list
@@ -34,10 +34,10 @@ fuzzy-if(Android,0-5,0-20000) == uncovering-2.html uncovering-2-ref.html
== less-than-scrollbar-height.html less-than-scrollbar-height-ref.html
== huge-horizontal-overflow.html huge-horizontal-overflow-ref.html
== huge-vertical-overflow.html huge-vertical-overflow-ref.html
-pref(apz.allow_zooming,true) fuzzy-if(gtkWidget,0-1,0-80) fuzzy-if(winWidget,0-4,0-170) fuzzy-if(winWidget&&fission,0-96,0-1109) == iframe-scrolling-attr-1.html iframe-scrolling-attr-ref.html # fission: Bug 1717856
-pref(apz.allow_zooming,true) fuzzy-if(gtkWidget,0-1,0-80) fuzzy-if(winWidget,0-4,0-170) fuzzy-if(winWidget&&fission,0-96,0-1109) == iframe-scrolling-attr-2.html iframe-scrolling-attr-ref.html # fission: Bug 1717856
-pref(apz.allow_zooming,true) fuzzy(0-1,0-2) fuzzy-if(geckoview,0-1,0-15) fuzzy-if(gtkWidget,0-1,0-48) fuzzy-if(winWidget,0-4,0-108) fuzzy-if(winWidget&&fission,0-92,0-1280) == frame-scrolling-attr-1.html frame-scrolling-attr-ref.html
-pref(apz.allow_zooming,true) fuzzy(0-1,0-2) fuzzy-if(geckoview,0-1,0-88) fuzzy-if(gtkWidget,0-1,0-48) fuzzy-if(winWidget,0-4,0-108) fuzzy-if(winWidget&&fission,0-92,0-1920) == frame-scrolling-attr-2.html frame-scrolling-attr-ref.html
+pref(apz.allow_zooming,true) fuzzy-if(gtkWidget,0-1,0-80) fuzzy-if(winWidget,0-4,0-170) fuzzy-if(winWidget,0-96,0-1109) == iframe-scrolling-attr-1.html iframe-scrolling-attr-ref.html # win/fission: Bug 1717856
+pref(apz.allow_zooming,true) fuzzy-if(gtkWidget,0-1,0-80) fuzzy-if(winWidget,0-4,0-170) fuzzy-if(winWidget,0-96,0-1109) == iframe-scrolling-attr-2.html iframe-scrolling-attr-ref.html # win/fission: Bug 1717856
+pref(apz.allow_zooming,true) fuzzy(0-1,0-2) fuzzy-if(geckoview,0-1,0-15) fuzzy-if(gtkWidget,0-1,0-48) fuzzy-if(winWidget,0-4,0-108) fuzzy-if(winWidget,0-92,0-1280) == frame-scrolling-attr-1.html frame-scrolling-attr-ref.html
+pref(apz.allow_zooming,true) fuzzy(0-1,0-2) fuzzy-if(geckoview,0-1,0-88) fuzzy-if(gtkWidget,0-1,0-48) fuzzy-if(winWidget,0-4,0-108) fuzzy-if(winWidget,0-92,0-1920) == frame-scrolling-attr-2.html frame-scrolling-attr-ref.html
== move-item.html move-item-ref.html # bug 1125750
== fractional-scroll-area.html?top=-0.4&outerBottom=100&innerBottom=200 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200
== fractional-scroll-area.html?top=0.4&outerBottom=100&innerBottom=200 fractional-scroll-area.html?top=0&outerBottom=100&innerBottom=200
diff --git a/layout/reftests/svg/1630900-1-ref.html b/layout/reftests/svg/1630900-1-ref.html
new file mode 100644
index 0000000000..aa471c548b
--- /dev/null
+++ b/layout/reftests/svg/1630900-1-ref.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+
+ .loader {
+ height: 480px;
+ }
+
+ rect {
+ fill: #000;
+ opacity: 0.5;
+ }
+
+ </style>
+ </head>
+ <body>
+ <svg
+ class="loader"
+ x="0px"
+ y="0px"
+ viewBox="0 0 100 100"
+ >
+ <rect x="0" y="0" width="100" height="100"/>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/svg/1630900-1.html b/layout/reftests/svg/1630900-1.html
new file mode 100644
index 0000000000..ce86050ee1
--- /dev/null
+++ b/layout/reftests/svg/1630900-1.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <style>
+
+ .loader {
+ height: 480px;
+ }
+
+ rect {
+ fill: #000;
+ opacity: 0.5;
+ }
+ .anim {
+ animation: fade 10.5s infinite;
+ }
+
+ @keyframes fade {
+ 0% {
+ opacity: 0.5;
+ }
+ 50% {
+ opacity: 0.51;
+ }
+ 100% {
+ opacity: 0.5;
+ }
+ }
+
+ </style>
+ </head>
+ <body>
+ <svg
+ class="loader"
+ x="0px"
+ y="0px"
+ viewBox="0 0 100 100"
+ >
+ <rect class="anim" x="0" y="0" width="100" height="100"/>
+ </svg>
+ </body>
+</html>
diff --git a/layout/reftests/svg/reftest.list b/layout/reftests/svg/reftest.list
index 5f1da97375..27f00455f5 100644
--- a/layout/reftests/svg/reftest.list
+++ b/layout/reftests/svg/reftest.list
@@ -634,3 +634,7 @@ skip-if(Android) skip-if(cocoaWidget) skip-if(winWidget) == transform-animation-
fuzzy(0-20,0-110) == 1792313.svg 1792313-ref.svg
pref(svg.use-element.recursive-clone-limit.enabled,1) != about:blank explosive-use.svg
+
+# do not increase fuzz significantly, test was designed to be within 1 color unit
+fuzzy(0-1,0-230400) == 1630900-1.html 1630900-1-ref.html
+# do not increase fuzz significantly, test was designed to be within 1 color unit
diff --git a/layout/reftests/svg/smil/anim-feComponentTransfer-01.svg b/layout/reftests/svg/smil/anim-feComponentTransfer-01.svg
index 69f879d804..a2f686dc99 100644
--- a/layout/reftests/svg/smil/anim-feComponentTransfer-01.svg
+++ b/layout/reftests/svg/smil/anim-feComponentTransfer-01.svg
@@ -4,8 +4,7 @@
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1, true)">
+ class="reftest-wait">
<title>Test animation of the "intercept" attribute of the "feComponentTransfer" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<filter id="flood_filter" x="0%" y="0%" width="100%" height="100%">
@@ -29,4 +28,11 @@
</filter>
<rect width="100%" height="100%" fill="red"/>
<rect width="100%" height="100%" fill="red" filter="url(#flood_filter)"/>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feComposite-operator-01.svg b/layout/reftests/svg/smil/anim-feComposite-operator-01.svg
index 0223cea931..bc93b4a7f7 100644
--- a/layout/reftests/svg/smil/anim-feComposite-operator-01.svg
+++ b/layout/reftests/svg/smil/anim-feComposite-operator-01.svg
@@ -1,7 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1, true)">
+ class="reftest-wait">
<title>Test animation of the "operator" enum attribute on the "feComposite" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<filter id="composite_filter_1" x="-100%" y="0%" width="200%" height="100%">
@@ -35,4 +34,11 @@
<!-- 50% through discrete animation simple duration - test animation affects the element now -->
<rect y="100" width="100" height="100" fill="red"/>
<rect y="100" width="100" height="100" fill="red" filter="url(#composite_filter_2)"/>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feConvolveMatrix-order-01.svg b/layout/reftests/svg/smil/anim-feConvolveMatrix-order-01.svg
index d24eb3b8d7..9a98a57c93 100644
--- a/layout/reftests/svg/smil/anim-feConvolveMatrix-order-01.svg
+++ b/layout/reftests/svg/smil/anim-feConvolveMatrix-order-01.svg
@@ -4,8 +4,7 @@
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(2, true)">
+ class="reftest-wait">
<title>Testcase for animation of the "order" attribute of the "feConvolveMatrix" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<defs>
@@ -50,4 +49,11 @@
<rect x="10" y="10" width="50" height="100" fill="orange"/>
<rect x="60" y="10" width="50" height="100" fill="blue"/>
</g>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(2, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feDistantLight-01.svg b/layout/reftests/svg/smil/anim-feDistantLight-01.svg
index 42221cdb48..2edcb4ab54 100644
--- a/layout/reftests/svg/smil/anim-feDistantLight-01.svg
+++ b/layout/reftests/svg/smil/anim-feDistantLight-01.svg
@@ -4,8 +4,7 @@
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1, true)">
+ class="reftest-wait">
<title>Testcase for animation of the "elevation" attribute of the "feDistantLight" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<defs>
@@ -22,4 +21,11 @@
</filter>
</defs>
<path d="M0,0 h100 v100 h-100 z" filter="url(#f)"/>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feFuncR-tableValues-01.svg b/layout/reftests/svg/smil/anim-feFuncR-tableValues-01.svg
index 512e1ab074..2b51091862 100644
--- a/layout/reftests/svg/smil/anim-feFuncR-tableValues-01.svg
+++ b/layout/reftests/svg/smil/anim-feFuncR-tableValues-01.svg
@@ -1,7 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1, true)">
+ class="reftest-wait">
<title>Test animation of the &lt;number-list&gt; attribute on the 'text' element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
@@ -98,4 +97,10 @@
<rect x="20" y="140" width="256" height="20" fill="url(#gradient)"
filter="url(#f_calcMode_discrete)"/>
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feGaussianBlur-01.svg b/layout/reftests/svg/smil/anim-feGaussianBlur-01.svg
index 40f804d74c..f80f46075a 100644
--- a/layout/reftests/svg/smil/anim-feGaussianBlur-01.svg
+++ b/layout/reftests/svg/smil/anim-feGaussianBlur-01.svg
@@ -4,8 +4,7 @@
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1.9999, true)">
+ class="reftest-wait">
<title>Test animation of the "stdDeviation" &lt;number-optional-number&gt; attribute on "feGaussianBlur" elements</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<filter id="filter" x="0" y="0" width="1" height="1">
@@ -22,4 +21,11 @@
<circle fill="red" cx="100" cy="100" r="98" transform="translate(50, 0)" filter="url(#filter)"/>
</g>
<circle fill="lime" cx="200" cy="100" r="100"/>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1.9999, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feOffset-01.svg b/layout/reftests/svg/smil/anim-feOffset-01.svg
index 30c8795670..e2f3055af8 100644
--- a/layout/reftests/svg/smil/anim-feOffset-01.svg
+++ b/layout/reftests/svg/smil/anim-feOffset-01.svg
@@ -1,7 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1, true)">
+ class="reftest-wait">
<title>Test animation of the "dx" and "dy" attributes on the "feOffset" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<filter id="offset_filter_1" x="0%" y="0%" width="300%" height="100%">
@@ -31,4 +30,11 @@
<!-- test 100% completed animation -->
<rect y="100" width="100" height="100" fill="red"/>
<rect width="100" height="100" fill="lime" filter="url(#offset_filter_2)"/>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feSpotLight-01.svg b/layout/reftests/svg/smil/anim-feSpotLight-01.svg
index 011a9ecff9..4169c3bb36 100644
--- a/layout/reftests/svg/smil/anim-feSpotLight-01.svg
+++ b/layout/reftests/svg/smil/anim-feSpotLight-01.svg
@@ -4,8 +4,7 @@
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1, true)">
+ class="reftest-wait">
<title>Testcase for animation of the "elevation" attribute of the "feSpotLight" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<defs>
@@ -23,4 +22,11 @@
</filter>
</defs>
<path d="M0,0 h100 v100 h-100 z" filter="url(#f)"/>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-01.svg b/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-01.svg
index e48a6bd55e..9589ea38b1 100644
--- a/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-01.svg
+++ b/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-01.svg
@@ -1,7 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(5, true)">
+ class="reftest-wait">
<title>Test animation of the "numOctaves" &lt;integer&gt; attribute on the "feTurbulence" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
@@ -214,4 +213,10 @@
</filter>
<rect x="20" y="100" width="20" height="20" filter="url(#filter_12)"/>
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(5, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-02.svg b/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-02.svg
index ffade083b0..2e9f2329dc 100644
--- a/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-02.svg
+++ b/layout/reftests/svg/smil/anim-feTurbulence-numOctaves-02.svg
@@ -1,7 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(3, true)">
+ class="reftest-wait">
<title>Test animation of the "numOctaves" &lt;integer&gt; attribute on the "feTurbulence" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
@@ -199,4 +198,11 @@
</filter>
<rect x="20" y="60" width="20" height="20" filter="url(#filter_12)"/>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(3, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-filter-filterUnits-01.svg b/layout/reftests/svg/smil/anim-filter-filterUnits-01.svg
index 641f711931..4d508c38f4 100644
--- a/layout/reftests/svg/smil/anim-filter-filterUnits-01.svg
+++ b/layout/reftests/svg/smil/anim-filter-filterUnits-01.svg
@@ -1,7 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1, true)">
+ class="reftest-wait">
<title>Test animation of the "filterUnits" enum attributes of the "filter" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<filter id="flood_filter_1" filterUnits="userSpaceOnUse"
@@ -39,4 +38,11 @@
<svg y="50" height="50">
<rect width="50%" height="100%" fill="red" filter="url(#flood_filter_2)"/>
</svg>
+
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/smil/anim-filter-href-01.svg b/layout/reftests/svg/smil/anim-filter-href-01.svg
index fa259de4ee..39f7ae7dcf 100644
--- a/layout/reftests/svg/smil/anim-filter-href-01.svg
+++ b/layout/reftests/svg/smil/anim-filter-href-01.svg
@@ -4,8 +4,7 @@
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
- class="reftest-wait"
- onload="setTimeAndSnapshot(1, true)">
+ class="reftest-wait">
<title>Test animation of the "in" and "result" &lt;string&gt; attributes on "filter" elements</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
@@ -31,4 +30,10 @@
<rect width="100%" height="100%" fill="red"/>
<rect width="100%" height="100%" fill="red" filter="url(#filt)"/>
+ <script type="text/javascript">
+ function doTest() {
+ setTimeAndSnapshot(1, true);
+ }
+ window.addEventListener("MozReftestInvalidate", doTest, false);
+ </script>
</svg>
diff --git a/layout/reftests/svg/text/reftest.list b/layout/reftests/svg/text/reftest.list
index 14b3c68b34..0b749fe20a 100644
--- a/layout/reftests/svg/text/reftest.list
+++ b/layout/reftests/svg/text/reftest.list
@@ -209,8 +209,8 @@ needs-focus == multiple-chunks-selection.svg multiple-chunks-selection-ref.svg
fuzzy(0-1,0-200) needs-focus == textpath-selection.svg textpath-selection-ref.svg
# letter-spacing and word-spacing
-== simple-letter-spacing.svg simple-letter-spacing-ref.svg
+pref(layout.css.letter-spacing.model,0) == simple-letter-spacing.svg simple-letter-spacing-ref.svg
== simple-word-spacing.svg simple-word-spacing-ref.svg
-== multiple-chunks-letter-spacing.svg multiple-chunks-letter-spacing-ref.svg
+pref(layout.css.letter-spacing.model,0) == multiple-chunks-letter-spacing.svg multiple-chunks-letter-spacing-ref.svg
== tspan-shaping.svg tspan-shaping-ref.svg
diff --git a/layout/reftests/text/reftest.list b/layout/reftests/text/reftest.list
index 1402cc7ad7..5c3aba84f4 100644
--- a/layout/reftests/text/reftest.list
+++ b/layout/reftests/text/reftest.list
@@ -146,8 +146,8 @@ random-if(!winWidget) == arial-bold-lam-alef-1.html arial-bold-lam-alef-1-ref.ht
== 1320665-cmap-format-13.html 1320665-cmap-format-13-ref.html # see bug 1320665 comments 8-9
== 1331339-script-extensions-shaping-1.html 1331339-script-extensions-shaping-1-ref.html
skip-if(!cocoaWidget) != 1349308-1.html 1349308-notref.html # macOS-specific test for -apple-system glyph metrics
-fuzzy-if(Android,0-128,0-233) == 1463020-letter-spacing-text-transform-1.html 1463020-letter-spacing-text-transform-1-ref.html
-fails-if(Android) == 1463020-letter-spacing-text-transform-2.html 1463020-letter-spacing-text-transform-2-ref.html # missing font coverage on Android
+pref(layout.css.letter-spacing.model,0) fuzzy-if(Android,0-128,0-233) == 1463020-letter-spacing-text-transform-1.html 1463020-letter-spacing-text-transform-1-ref.html
+pref(layout.css.letter-spacing.model,0) fails-if(Android) == 1463020-letter-spacing-text-transform-2.html 1463020-letter-spacing-text-transform-2-ref.html # missing font coverage on Android
pref(intl.icu4x.segmenter.enabled,false) == 1507661-spurious-hyphenation-after-explicit.html 1507661-spurious-hyphenation-after-explicit-ref.html
fuzzy-if(useDrawSnapshot,255-255,50-50) == 1522857-1.html 1522857-1-ref.html # antialiasing fuzz in non-webrender cases
!= 1637405-pua-shaping-1.html 1637405-pua-shaping-1-notref.html
diff --git a/layout/reftests/transform-3d/reftest.list b/layout/reftests/transform-3d/reftest.list
index affea05d0b..1f865ac3a7 100644
--- a/layout/reftests/transform-3d/reftest.list
+++ b/layout/reftests/transform-3d/reftest.list
@@ -10,7 +10,6 @@ fuzzy(0-1,0-6) == rotatey-1a.html rotatey-1-ref.html
# perspective should only apply to child elements
== rotatex-perspective-1c.html rotatex-1-ref.html
== rotatex-perspective-3a.html rotatex-perspective-3-ref.html
-== scalez-1a.html scalez-1-ref.html
fuzzy(0-16,0-346) fuzzy-if(cocoaWidget,0-200,0-310) fuzzy-if(winWidget,0-175,0-250) == preserve3d-1a.html preserve3d-1-ref.html
== preserve3d-1b.html about:blank
== preserve3d-clipped.html about:blank
diff --git a/layout/style/CSSKeyframeRule.cpp b/layout/style/CSSKeyframeRule.cpp
index e6ae2bada0..b70c6543b0 100644
--- a/layout/style/CSSKeyframeRule.cpp
+++ b/layout/style/CSSKeyframeRule.cpp
@@ -16,7 +16,7 @@ namespace mozilla::dom {
// CSSKeyframeDeclaration
//
-class CSSKeyframeDeclaration : public nsDOMCSSDeclaration {
+class CSSKeyframeDeclaration final : public nsDOMCSSDeclaration {
public:
explicit CSSKeyframeDeclaration(CSSKeyframeRule* aRule) : mRule(aRule) {
mDecls =
@@ -63,7 +63,6 @@ class CSSKeyframeDeclaration : public nsDOMCSSDeclaration {
nsIPrincipal* aSubjectPrincipal) const final {
return GetParsingEnvironmentForRule(mRule, StyleCssRuleType::Keyframe);
}
- Document* DocToUpdate() final { return nullptr; }
nsINode* GetAssociatedNode() const final {
return mRule ? mRule->GetAssociatedDocumentOrShadowRoot() : nullptr;
diff --git a/layout/style/CSSMarginRule.cpp b/layout/style/CSSMarginRule.cpp
new file mode 100644
index 0000000000..64a706666c
--- /dev/null
+++ b/layout/style/CSSMarginRule.cpp
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/CSSMarginRule.h"
+#include "mozilla/dom/CSSMarginRuleBinding.h"
+
+#include "mozilla/DeclarationBlock.h"
+#include "mozilla/ServoBindings.h"
+
+namespace mozilla::dom {
+
+// -- CSSMarginRuleDeclaration ---------------------------------------
+
+CSSMarginRuleDeclaration::CSSMarginRuleDeclaration(
+ already_AddRefed<StyleLockedDeclarationBlock> aDecls)
+ : mDecls(new DeclarationBlock(std::move(aDecls))) {
+ mDecls->SetOwningRule(Rule());
+}
+
+CSSMarginRuleDeclaration::~CSSMarginRuleDeclaration() {
+ mDecls->SetOwningRule(nullptr);
+}
+
+// QueryInterface implementation for CSSMarginRuleDeclaration
+NS_INTERFACE_MAP_BEGIN(CSSMarginRuleDeclaration)
+ NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+ // We forward the cycle collection interfaces to Rule(), which is
+ // never null (in fact, we're part of that object!)
+ if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ||
+ aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) {
+ return Rule()->QueryInterface(aIID, aInstancePtr);
+ }
+NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration)
+
+NS_IMPL_ADDREF_USING_AGGREGATOR(CSSMarginRuleDeclaration, Rule())
+NS_IMPL_RELEASE_USING_AGGREGATOR(CSSMarginRuleDeclaration, Rule())
+
+/* nsDOMCSSDeclaration implementation */
+css::Rule* CSSMarginRuleDeclaration::GetParentRule() { return Rule(); }
+
+nsINode* CSSMarginRuleDeclaration::GetAssociatedNode() const {
+ return Rule()->GetAssociatedDocumentOrShadowRoot();
+}
+
+nsISupports* CSSMarginRuleDeclaration::GetParentObject() const {
+ return Rule()->GetParentObject();
+}
+
+DeclarationBlock* CSSMarginRuleDeclaration::GetOrCreateCSSDeclaration(
+ Operation aOperation, DeclarationBlock** aCreated) {
+ if (aOperation != Operation::Read) {
+ if (StyleSheet* sheet = Rule()->GetStyleSheet()) {
+ sheet->WillDirty();
+ }
+ }
+ return mDecls;
+}
+
+void CSSMarginRuleDeclaration::SetRawAfterClone(
+ RefPtr<StyleLockedDeclarationBlock> aDeclarationBlock) {
+ mDecls->SetOwningRule(nullptr);
+ mDecls = new DeclarationBlock(aDeclarationBlock.forget());
+ mDecls->SetOwningRule(Rule());
+}
+
+nsresult CSSMarginRuleDeclaration::SetCSSDeclaration(
+ DeclarationBlock* aDecl, MutationClosureData* aClosureData) {
+ MOZ_ASSERT(aDecl, "must be non-null");
+ CSSMarginRule* rule = Rule();
+
+ if (aDecl != mDecls) {
+ mDecls->SetOwningRule(nullptr);
+ RefPtr<DeclarationBlock> decls = aDecl;
+ // TODO alaskanemily: bug 1890418 for implementing this and margin-rule
+ // style properties in general.
+ // Servo_MarginRule_SetStyle(rule->Raw(), decls->Raw());
+ mDecls = std::move(decls);
+ mDecls->SetOwningRule(rule);
+ }
+
+ return NS_OK;
+}
+
+nsDOMCSSDeclaration::ParsingEnvironment
+CSSMarginRuleDeclaration::GetParsingEnvironment(
+ nsIPrincipal* aSubjectPrincipal) const {
+ return GetParsingEnvironmentForRule(Rule(), StyleCssRuleType::Margin);
+}
+
+// -- CSSMarginRule --------------------------------------------------
+
+CSSMarginRule::CSSMarginRule(RefPtr<StyleMarginRule> aRawRule,
+ StyleSheet* aSheet, css::Rule* aParentRule,
+ uint32_t aLine, uint32_t aColumn)
+ : css::Rule(aSheet, aParentRule, aLine, aColumn),
+ mRawRule(std::move(aRawRule)),
+ mDecls(Servo_MarginRule_GetStyle(mRawRule).Consume()) {}
+
+NS_IMPL_ADDREF_INHERITED(CSSMarginRule, css::Rule)
+NS_IMPL_RELEASE_INHERITED(CSSMarginRule, css::Rule)
+
+// QueryInterface implementation for MarginRule
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSMarginRule)
+NS_INTERFACE_MAP_END_INHERITING(css::Rule)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(CSSMarginRule)
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(CSSMarginRule, css::Rule)
+ // Keep this in sync with IsCCLeaf.
+
+ // Trace the wrapper for our declaration. This just expands out
+ // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
+ // directly because the wrapper is on the declaration, not on us.
+ tmp->mDecls.TraceWrapper(aCallbacks, aClosure);
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSMarginRule)
+ // Keep this in sync with IsCCLeaf.
+
+ // Unlink the wrapper for our declaration.
+ //
+ // Note that this has to happen before unlinking css::Rule.
+ tmp->UnlinkDeclarationWrapper(tmp->mDecls);
+ tmp->mDecls.mDecls->SetOwningRule(nullptr);
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(css::Rule)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSMarginRule, css::Rule)
+ // Keep this in sync with IsCCLeaf.
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+bool CSSMarginRule::IsCCLeaf() const {
+ if (!Rule::IsCCLeaf()) {
+ return false;
+ }
+
+ return !mDecls.PreservingWrapper();
+}
+
+void CSSMarginRule::SetRawAfterClone(RefPtr<StyleMarginRule> aRaw) {
+ mRawRule = std::move(aRaw);
+ mDecls.SetRawAfterClone(Servo_MarginRule_GetStyle(mRawRule.get()).Consume());
+}
+
+// WebIDL interfaces
+StyleCssRuleType CSSMarginRule::Type() const {
+ return StyleCssRuleType::Margin;
+}
+
+// CSSRule implementation
+
+void CSSMarginRule::GetCssText(nsACString& aCssText) const {
+ Servo_MarginRule_GetCssText(mRawRule, &aCssText);
+}
+
+void CSSMarginRule::GetName(nsACString& aRuleName) const {
+ Servo_MarginRule_GetName(mRawRule, &aRuleName);
+}
+
+size_t CSSMarginRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
+ // TODO Implement this!
+ return aMallocSizeOf(this);
+}
+
+#ifdef DEBUG
+void CSSMarginRule::List(FILE* out, int32_t aIndent) const {
+ nsAutoCString str;
+ for (int32_t i = 0; i < aIndent; i++) {
+ str.AppendLiteral(" ");
+ }
+ Servo_MarginRule_Debug(mRawRule, &str);
+ fprintf_stderr(out, "%s\n", str.get());
+}
+#endif
+
+JSObject* CSSMarginRule::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return CSSMarginRule_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace mozilla::dom
diff --git a/layout/style/CSSMarginRule.h b/layout/style/CSSMarginRule.h
new file mode 100644
index 0000000000..0ad5f60dbd
--- /dev/null
+++ b/layout/style/CSSMarginRule.h
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* 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 mozilla_dom_CSSMarginRule_h
+#define mozilla_dom_CSSMarginRule_h
+
+#include "mozilla/css/Rule.h"
+#include "mozilla/ServoBindingTypes.h"
+
+#include "nsDOMCSSDeclaration.h"
+#include "nsICSSDeclaration.h"
+
+namespace mozilla {
+class DeclarationBlock;
+
+namespace dom {
+class CSSMarginRule;
+
+class CSSMarginRuleDeclaration final : public nsDOMCSSDeclaration {
+ public:
+ NS_DECL_ISUPPORTS_INHERITED
+
+ css::Rule* GetParentRule() final;
+ nsINode* GetAssociatedNode() const final;
+ nsISupports* GetParentObject() const final;
+
+ protected:
+ DeclarationBlock* GetOrCreateCSSDeclaration(
+ Operation aOperation, DeclarationBlock** aCreated) final;
+ nsresult SetCSSDeclaration(DeclarationBlock* aDecl,
+ MutationClosureData* aClosureData) final;
+ Document* DocToUpdate() final { return nullptr; }
+ nsDOMCSSDeclaration::ParsingEnvironment GetParsingEnvironment(
+ nsIPrincipal* aSubjectPrincipal) const final;
+
+ private:
+ // For accessing the constructor.
+ friend class CSSMarginRule;
+
+ explicit CSSMarginRuleDeclaration(
+ already_AddRefed<StyleLockedDeclarationBlock> aDecls);
+ void SetRawAfterClone(RefPtr<StyleLockedDeclarationBlock>);
+
+ ~CSSMarginRuleDeclaration();
+
+ inline CSSMarginRule* Rule();
+ inline const CSSMarginRule* Rule() const;
+
+ RefPtr<DeclarationBlock> mDecls;
+};
+
+class CSSMarginRule final : public css::Rule {
+ public:
+ CSSMarginRule(RefPtr<StyleMarginRule> aRawRule, StyleSheet* aSheet,
+ css::Rule* aParentRule, uint32_t aLine, uint32_t aColumn);
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(CSSMarginRule,
+ css::Rule)
+
+ bool IsCCLeaf() const final;
+
+ StyleMarginRule* Raw() const { return mRawRule; }
+ void SetRawAfterClone(RefPtr<StyleMarginRule>);
+
+ // WebIDL interfaces
+ StyleCssRuleType Type() const final;
+ void GetCssText(nsACString& aCssText) const final;
+ nsICSSDeclaration* Style() { return &mDecls; }
+
+ void GetName(nsACString& aRuleName) const;
+
+ size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const final;
+
+#ifdef DEBUG
+ void List(FILE* out = stdout, int32_t aIndent = 0) const final;
+#endif
+
+ JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
+
+ private:
+ ~CSSMarginRule() = default;
+
+ // For computing the offset of mDecls.
+ friend class CSSMarginRuleDeclaration;
+
+ RefPtr<StyleMarginRule> mRawRule;
+ CSSMarginRuleDeclaration mDecls;
+};
+
+CSSMarginRule* CSSMarginRuleDeclaration::Rule() {
+ return reinterpret_cast<CSSMarginRule*>(reinterpret_cast<uint8_t*>(this) -
+ offsetof(CSSMarginRule, mDecls));
+}
+
+const CSSMarginRule* CSSMarginRuleDeclaration::Rule() const {
+ return reinterpret_cast<const CSSMarginRule*>(
+ reinterpret_cast<const uint8_t*>(this) - offsetof(CSSMarginRule, mDecls));
+}
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_CSSMarginRule_h
diff --git a/layout/style/CSSPageRule.cpp b/layout/style/CSSPageRule.cpp
index 04d064b362..fb7dcbc38b 100644
--- a/layout/style/CSSPageRule.cpp
+++ b/layout/style/CSSPageRule.cpp
@@ -94,20 +94,20 @@ CSSPageRuleDeclaration::GetParsingEnvironment(
CSSPageRule::CSSPageRule(RefPtr<StyleLockedPageRule> aRawRule,
StyleSheet* aSheet, css::Rule* aParentRule,
uint32_t aLine, uint32_t aColumn)
- : css::Rule(aSheet, aParentRule, aLine, aColumn),
+ : css::GroupRule(aSheet, aParentRule, aLine, aColumn),
mRawRule(std::move(aRawRule)),
mDecls(Servo_PageRule_GetStyle(mRawRule).Consume()) {}
-NS_IMPL_ADDREF_INHERITED(CSSPageRule, css::Rule)
-NS_IMPL_RELEASE_INHERITED(CSSPageRule, css::Rule)
+NS_IMPL_ADDREF_INHERITED(CSSPageRule, css::GroupRule)
+NS_IMPL_RELEASE_INHERITED(CSSPageRule, css::GroupRule)
// QueryInterface implementation for PageRule
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSPageRule)
-NS_INTERFACE_MAP_END_INHERITING(css::Rule)
+NS_INTERFACE_MAP_END_INHERITING(css::GroupRule)
NS_IMPL_CYCLE_COLLECTION_CLASS(CSSPageRule)
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(CSSPageRule, css::Rule)
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(CSSPageRule, css::GroupRule)
// Keep this in sync with IsCCLeaf.
// Trace the wrapper for our declaration. This just expands out
@@ -124,14 +124,14 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSPageRule)
// Note that this has to happen before unlinking css::Rule.
tmp->UnlinkDeclarationWrapper(tmp->mDecls);
tmp->mDecls.mDecls->SetOwningRule(nullptr);
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(css::Rule)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(css::GroupRule)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSPageRule, css::Rule)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSPageRule, css::GroupRule)
// Keep this in sync with IsCCLeaf.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
bool CSSPageRule::IsCCLeaf() const {
- if (!Rule::IsCCLeaf()) {
+ if (!GroupRule::IsCCLeaf()) {
return false;
}
@@ -147,7 +147,7 @@ StyleCssRuleType CSSPageRule::Type() const { return StyleCssRuleType::Page; }
size_t CSSPageRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
// TODO Implement this!
- return aMallocSizeOf(this);
+ return GroupRule::SizeOfExcludingThis(aMallocSizeOf) + aMallocSizeOf(this);
}
#ifdef DEBUG
@@ -188,6 +188,10 @@ void CSSPageRule::SetSelectorText(const nsACString& aSelectorText) {
}
}
+already_AddRefed<StyleLockedCssRules> CSSPageRule::GetOrCreateRawRules() {
+ return Servo_PageRule_GetRules(mRawRule).Consume();
+}
+
nsICSSDeclaration* CSSPageRule::Style() { return &mDecls; }
JSObject* CSSPageRule::WrapObject(JSContext* aCx,
diff --git a/layout/style/CSSPageRule.h b/layout/style/CSSPageRule.h
index 705d526bdf..b133111244 100644
--- a/layout/style/CSSPageRule.h
+++ b/layout/style/CSSPageRule.h
@@ -7,7 +7,7 @@
#ifndef mozilla_dom_CSSPageRule_h
#define mozilla_dom_CSSPageRule_h
-#include "mozilla/css/Rule.h"
+#include "mozilla/css/GroupRule.h"
#include "mozilla/ServoBindingTypes.h"
#include "nsDOMCSSDeclaration.h"
@@ -33,7 +33,6 @@ class CSSPageRuleDeclaration final : public nsDOMCSSDeclaration {
Operation aOperation, DeclarationBlock** aCreated) final;
nsresult SetCSSDeclaration(DeclarationBlock* aDecl,
MutationClosureData* aClosureData) final;
- Document* DocToUpdate() final { return nullptr; }
nsDOMCSSDeclaration::ParsingEnvironment GetParsingEnvironment(
nsIPrincipal* aSubjectPrincipal) const final;
@@ -53,13 +52,14 @@ class CSSPageRuleDeclaration final : public nsDOMCSSDeclaration {
RefPtr<DeclarationBlock> mDecls;
};
-class CSSPageRule final : public css::Rule {
+class CSSPageRule final : public css::GroupRule {
public:
CSSPageRule(RefPtr<StyleLockedPageRule> aRawRule, StyleSheet* aSheet,
css::Rule* aParentRule, uint32_t aLine, uint32_t aColumn);
NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(CSSPageRule, css::Rule)
+ NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(CSSPageRule,
+ css::GroupRule)
bool IsCCLeaf() const final;
@@ -76,6 +76,8 @@ class CSSPageRule final : public css::Rule {
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const final;
+ already_AddRefed<StyleLockedCssRules> GetOrCreateRawRules() final;
+
#ifdef DEBUG
void List(FILE* out = stdout, int32_t aIndent = 0) const final;
#endif
diff --git a/layout/style/CSSScopeRule.cpp b/layout/style/CSSScopeRule.cpp
new file mode 100644
index 0000000000..18047a582b
--- /dev/null
+++ b/layout/style/CSSScopeRule.cpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/CSSScopeRule.h"
+#include "mozilla/dom/CSSScopeRuleBinding.h"
+#include "mozilla/ServoBindings.h"
+
+namespace mozilla::dom {
+
+CSSScopeRule::CSSScopeRule(RefPtr<StyleScopeRule> aRawRule, StyleSheet* aSheet,
+ css::Rule* aParentRule, uint32_t aLine,
+ uint32_t aColumn)
+ : css::GroupRule(aSheet, aParentRule, aLine, aColumn),
+ mRawRule(std::move(aRawRule)) {}
+
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(CSSScopeRule, css::GroupRule)
+
+// QueryInterface implementation for SupportsRule
+
+#ifdef DEBUG
+void CSSScopeRule::List(FILE* out, int32_t aIndent) const {
+ nsAutoCString str;
+ for (int32_t i = 0; i < aIndent; i++) {
+ str.AppendLiteral(" ");
+ }
+ Servo_ScopeRule_Debug(mRawRule, &str);
+ fprintf_stderr(out, "%s\n", str.get());
+}
+#endif
+
+StyleCssRuleType CSSScopeRule::Type() const { return StyleCssRuleType::Scope; }
+
+already_AddRefed<StyleLockedCssRules> CSSScopeRule::GetOrCreateRawRules() {
+ return Servo_ScopeRule_GetRules(mRawRule).Consume();
+}
+
+void CSSScopeRule::SetRawAfterClone(RefPtr<StyleScopeRule> aRaw) {
+ mRawRule = std::move(aRaw);
+ css::GroupRule::DidSetRawAfterClone();
+}
+
+void CSSScopeRule::GetCssText(nsACString& aCssText) const {
+ Servo_ScopeRule_GetCssText(mRawRule.get(), &aCssText);
+}
+
+void CSSScopeRule::GetStart(nsACString& aStart) const {
+ Servo_ScopeRule_GetStart(mRawRule.get(), &aStart);
+}
+
+void CSSScopeRule::GetEnd(nsACString& aEnd) const {
+ Servo_ScopeRule_GetEnd(mRawRule.get(), &aEnd);
+}
+
+size_t CSSScopeRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
+ return aMallocSizeOf(this);
+}
+
+JSObject* CSSScopeRule::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return CSSScopeRule_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace mozilla::dom
diff --git a/layout/style/CSSScopeRule.h b/layout/style/CSSScopeRule.h
new file mode 100644
index 0000000000..2cb1fa7e40
--- /dev/null
+++ b/layout/style/CSSScopeRule.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 CSSScopeRule_h___
+#define CSSScopeRule_h___
+
+#include "mozilla/css/GroupRule.h"
+#include "mozilla/ServoBindingTypes.h"
+
+namespace mozilla::dom {
+
+class CSSScopeRule final : public css::GroupRule {
+ public:
+ CSSScopeRule(RefPtr<StyleScopeRule> aRawRule, StyleSheet* aSheet,
+ css::Rule* aParentRule, uint32_t aLine, uint32_t aColumn);
+
+ NS_DECL_ISUPPORTS_INHERITED
+
+#ifdef DEBUG
+ void List(FILE* out = stdout, int32_t aIndent = 0) const final;
+#endif
+
+ StyleScopeRule* Raw() const { return mRawRule; }
+ void SetRawAfterClone(RefPtr<StyleScopeRule>);
+
+ already_AddRefed<StyleLockedCssRules> GetOrCreateRawRules() final;
+
+ // WebIDL interface
+ StyleCssRuleType Type() const final;
+ void GetCssText(nsACString& aCssText) const final;
+
+ void GetStart(nsACString& aStart) const;
+ void GetEnd(nsACString& aEnd) const;
+
+ size_t SizeOfIncludingThis(MallocSizeOf) const override;
+ JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
+
+ private:
+ ~CSSScopeRule() = default;
+
+ RefPtr<StyleScopeRule> mRawRule;
+};
+
+} // namespace mozilla::dom
+
+#endif
diff --git a/layout/style/CSSStartingStyleRule.cpp b/layout/style/CSSStartingStyleRule.cpp
new file mode 100644
index 0000000000..5c5ec311c9
--- /dev/null
+++ b/layout/style/CSSStartingStyleRule.cpp
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/CSSStartingStyleRule.h"
+#include "mozilla/dom/CSSStartingStyleRuleBinding.h"
+#include "mozilla/ServoBindings.h"
+
+namespace mozilla::dom {
+
+NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(CSSStartingStyleRule,
+ css::GroupRule)
+
+// QueryInterface implementation for SupportsRule
+
+#ifdef DEBUG
+void CSSStartingStyleRule::List(FILE* out, int32_t aIndent) const {
+ nsAutoCString str;
+ for (int32_t i = 0; i < aIndent; i++) {
+ str.AppendLiteral(" ");
+ }
+ Servo_StartingStyleRule_Debug(mRawRule, &str);
+ fprintf_stderr(out, "%s\n", str.get());
+}
+#endif
+
+StyleCssRuleType CSSStartingStyleRule::Type() const {
+ return StyleCssRuleType::StartingStyle;
+}
+
+already_AddRefed<StyleLockedCssRules>
+CSSStartingStyleRule::GetOrCreateRawRules() {
+ return Servo_StartingStyleRule_GetRules(mRawRule).Consume();
+}
+
+void CSSStartingStyleRule::GetCssText(nsACString& aCssText) const {
+ Servo_StartingStyleRule_GetCssText(mRawRule.get(), &aCssText);
+}
+
+JSObject* CSSStartingStyleRule::WrapObject(JSContext* aCx,
+ JS::Handle<JSObject*> aGivenProto) {
+ return CSSStartingStyleRule_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace mozilla::dom
diff --git a/layout/style/CSSStartingStyleRule.h b/layout/style/CSSStartingStyleRule.h
new file mode 100644
index 0000000000..9ecccf505c
--- /dev/null
+++ b/layout/style/CSSStartingStyleRule.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 CSSStaringStyleRule_h___
+#define CSSStaringStyleRule_h___
+
+#include "mozilla/css/GroupRule.h"
+#include "mozilla/ServoBindingTypes.h"
+
+namespace mozilla::dom {
+
+class CSSStartingStyleRule final : public css::GroupRule {
+ public:
+ CSSStartingStyleRule(RefPtr<StyleStartingStyleRule> aRawRule,
+ StyleSheet* aSheet, css::Rule* aParentRule,
+ uint32_t aLine, uint32_t aColumn)
+ : css::GroupRule(aSheet, aParentRule, aLine, aColumn),
+ mRawRule(std::move(aRawRule)) {}
+
+ NS_DECL_ISUPPORTS_INHERITED
+
+#ifdef DEBUG
+ void List(FILE* out = stdout, int32_t aIndent = 0) const final;
+#endif
+
+ StyleStartingStyleRule* Raw() const { return mRawRule; }
+ void SetRawAfterClone(RefPtr<StyleStartingStyleRule> aRaw) {
+ mRawRule = std::move(aRaw);
+ css::GroupRule::DidSetRawAfterClone();
+ }
+
+ already_AddRefed<StyleLockedCssRules> GetOrCreateRawRules() final;
+
+ // WebIDL interface
+ StyleCssRuleType Type() const final;
+ void GetCssText(nsACString& aCssText) const final;
+
+ size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override {
+ return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+ }
+ JSObject* WrapObject(JSContext*, JS::Handle<JSObject*>) override;
+
+ private:
+ ~CSSStartingStyleRule() = default;
+
+ RefPtr<StyleStartingStyleRule> mRawRule;
+};
+
+} // namespace mozilla::dom
+
+#endif
diff --git a/layout/style/CSSStyleRule.cpp b/layout/style/CSSStyleRule.cpp
index 5cdb47fddb..5a3dbfad01 100644
--- a/layout/style/CSSStyleRule.cpp
+++ b/layout/style/CSSStyleRule.cpp
@@ -101,8 +101,6 @@ nsresult CSSStyleRuleDeclaration::SetCSSDeclaration(
return NS_OK;
}
-Document* CSSStyleRuleDeclaration::DocToUpdate() { return nullptr; }
-
nsDOMCSSDeclaration::ParsingEnvironment
CSSStyleRuleDeclaration::GetParsingEnvironment(
nsIPrincipal* aSubjectPrincipal) const {
@@ -314,6 +312,18 @@ void CSSStyleRule::GetSelectorWarnings(
}
}
+already_AddRefed<nsINodeList> CSSStyleRule::QuerySelectorAll(nsINode& aRoot) {
+ AutoTArray<const StyleLockedStyleRule*, 8> rules;
+ CollectStyleRules(*this, /* aDesugared = */ true, rules);
+ StyleSelectorList* list = Servo_StyleRule_GetSelectorList(&rules);
+
+ RefPtr<nsSimpleContentList> contentList = new nsSimpleContentList(&aRoot);
+ Servo_SelectorList_QueryAll(&aRoot, list, contentList.get(),
+ /* useInvalidation */ false);
+ Servo_SelectorList_Drop(list);
+ return contentList.forget();
+}
+
/* virtual */
JSObject* CSSStyleRule::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
diff --git a/layout/style/CSSStyleRule.h b/layout/style/CSSStyleRule.h
index 05eaae5c10..9d8a1478e6 100644
--- a/layout/style/CSSStyleRule.h
+++ b/layout/style/CSSStyleRule.h
@@ -36,7 +36,6 @@ class CSSStyleRuleDeclaration final : public nsDOMCSSDeclaration {
Operation aOperation, mozilla::DeclarationBlock** aCreated) final;
nsresult SetCSSDeclaration(DeclarationBlock* aDecl,
MutationClosureData* aClosureData) final;
- Document* DocToUpdate() final;
ParsingEnvironment GetParsingEnvironment(
nsIPrincipal* aSubjectPrincipal) const final;
@@ -76,6 +75,7 @@ class CSSStyleRule final : public css::GroupRule, public SupportsWeakPtr {
bool aRelevantLinkVisited);
NotNull<DeclarationBlock*> GetDeclarationBlock() const;
void GetSelectorWarnings(nsTArray<SelectorWarning>& aResult) const;
+ already_AddRefed<nsINodeList> QuerySelectorAll(nsINode& aRoot);
// WebIDL interface
StyleCssRuleType Type() const final;
diff --git a/layout/style/FontFaceImpl.cpp b/layout/style/FontFaceImpl.cpp
index 9d1f7c8c5b..5650b62afd 100644
--- a/layout/style/FontFaceImpl.cpp
+++ b/layout/style/FontFaceImpl.cpp
@@ -675,25 +675,40 @@ bool FontFaceImpl::IsInFontFaceSet(FontFaceSetImpl* aFontFaceSet) const {
void FontFaceImpl::AddFontFaceSet(FontFaceSetImpl* aFontFaceSet) {
MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet));
- if (mFontFaceSet == aFontFaceSet) {
- mInFontFaceSet = true;
+ auto doAddFontFaceSet = [&]() {
+ if (mFontFaceSet == aFontFaceSet) {
+ mInFontFaceSet = true;
+ } else {
+ mOtherFontFaceSets.AppendElement(aFontFaceSet);
+ }
+ };
+
+ if (mUserFontEntry) {
+ AutoWriteLock lock(mUserFontEntry->Lock());
+ doAddFontFaceSet();
} else {
- mOtherFontFaceSets.AppendElement(aFontFaceSet);
+ doAddFontFaceSet();
}
}
void FontFaceImpl::RemoveFontFaceSet(FontFaceSetImpl* aFontFaceSet) {
MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
- if (mFontFaceSet == aFontFaceSet) {
- mInFontFaceSet = false;
- } else {
- mOtherFontFaceSets.RemoveElement(aFontFaceSet);
- }
+ auto doRemoveFontFaceSet = [&]() {
+ if (mFontFaceSet == aFontFaceSet) {
+ mInFontFaceSet = false;
+ } else {
+ mOtherFontFaceSets.RemoveElement(aFontFaceSet);
+ }
+ };
- // The caller should be holding a strong reference to the FontFaceSetImpl.
if (mUserFontEntry) {
- mUserFontEntry->CheckUserFontSet();
+ AutoWriteLock lock(mUserFontEntry->Lock());
+ doRemoveFontFaceSet();
+ // The caller should be holding a strong reference to the FontFaceSetImpl.
+ mUserFontEntry->CheckUserFontSetLocked();
+ } else {
+ doRemoveFontFaceSet();
}
}
@@ -736,7 +751,7 @@ void FontFaceImpl::Entry::SetLoadState(UserFontLoadState aLoadState) {
nsTArray<RefPtr<FontFaceImpl>> fontFaces;
{
- MutexAutoLock lock(mMutex);
+ AutoReadLock lock(mLock);
fontFaces.SetCapacity(mFontFaces.Length());
for (FontFaceImpl* f : mFontFaces) {
fontFaces.AppendElement(f);
@@ -758,7 +773,7 @@ void FontFaceImpl::Entry::SetLoadState(UserFontLoadState aLoadState) {
/* virtual */
void FontFaceImpl::Entry::GetUserFontSets(
nsTArray<RefPtr<gfxUserFontSet>>& aResult) {
- MutexAutoLock lock(mMutex);
+ AutoReadLock lock(mLock);
aResult.Clear();
@@ -783,7 +798,7 @@ void FontFaceImpl::Entry::GetUserFontSets(
/* virtual */ already_AddRefed<gfxUserFontSet>
FontFaceImpl::Entry::GetUserFontSet() const {
- MutexAutoLock lock(mMutex);
+ AutoReadLock lock(mLock);
if (mFontSet) {
return do_AddRef(mFontSet);
}
@@ -816,7 +831,7 @@ void FontFaceImpl::Entry::CheckUserFontSetLocked() {
}
void FontFaceImpl::Entry::FindFontFaceOwners(nsTHashSet<FontFace*>& aOwners) {
- MutexAutoLock lock(mMutex);
+ AutoReadLock lock(mLock);
for (FontFaceImpl* f : mFontFaces) {
if (FontFace* owner = f->GetOwner()) {
aOwners.Insert(owner);
@@ -825,13 +840,13 @@ void FontFaceImpl::Entry::FindFontFaceOwners(nsTHashSet<FontFace*>& aOwners) {
}
void FontFaceImpl::Entry::AddFontFace(FontFaceImpl* aFontFace) {
- MutexAutoLock lock(mMutex);
+ AutoWriteLock lock(mLock);
mFontFaces.AppendElement(aFontFace);
CheckUserFontSetLocked();
}
void FontFaceImpl::Entry::RemoveFontFace(FontFaceImpl* aFontFace) {
- MutexAutoLock lock(mMutex);
+ AutoWriteLock lock(mLock);
mFontFaces.RemoveElement(aFontFace);
CheckUserFontSetLocked();
}
diff --git a/layout/style/FontFaceImpl.h b/layout/style/FontFaceImpl.h
index 70c06609e9..7f1279a248 100644
--- a/layout/style/FontFaceImpl.h
+++ b/layout/style/FontFaceImpl.h
@@ -10,7 +10,7 @@
#include "mozilla/dom/FontFaceBinding.h"
#include "mozilla/FontPropertyTypes.h"
#include "mozilla/Maybe.h"
-#include "mozilla/Mutex.h"
+#include "mozilla/RWLock.h"
#include "mozilla/ServoStyleConsts.h"
#include "gfxUserFontSet.h"
#include "nsCSSPropertyID.h"
@@ -50,21 +50,15 @@ class FontFaceImpl final {
Entry(gfxUserFontSet* aFontSet, nsTArray<gfxFontFaceSrc>&& aFontFaceSrcList,
gfxUserFontAttributes&& aAttr)
: gfxUserFontEntry(std::move(aFontFaceSrcList), std::move(aAttr)),
- mMutex("FontFaceImpl::Entry::mMutex"),
mFontSet(aFontSet) {}
void SetLoadState(UserFontLoadState aLoadState) override;
void GetUserFontSets(nsTArray<RefPtr<gfxUserFontSet>>& aResult) override;
already_AddRefed<gfxUserFontSet> GetUserFontSet() const override;
- void CheckUserFontSet() {
- MutexAutoLock lock(mMutex);
- CheckUserFontSetLocked();
- }
-
#ifdef DEBUG
bool HasUserFontSet(gfxUserFontSet* aFontSet) const {
- MutexAutoLock lock(mMutex);
+ AutoReadLock lock(mLock);
return mFontSet == aFontSet;
}
#endif
@@ -73,19 +67,19 @@ class FontFaceImpl final {
void RemoveFontFace(FontFaceImpl* aOwner);
void FindFontFaceOwners(nsTHashSet<FontFace*>& aOwners);
- protected:
- void CheckUserFontSetLocked() MOZ_REQUIRES(mMutex);
+ RWLock& Lock() const MOZ_RETURN_CAPABILITY(mLock) { return mLock; }
- mutable Mutex mMutex;
+ protected:
+ void CheckUserFontSetLocked() MOZ_REQUIRES(mLock);
// Font set which owns this entry;
- gfxUserFontSet* MOZ_NON_OWNING_REF mFontSet MOZ_GUARDED_BY(mMutex);
+ gfxUserFontSet* MOZ_NON_OWNING_REF mFontSet MOZ_GUARDED_BY(mLock);
// The FontFace objects that use this user font entry. We need to store
// an array of these, not just a single pointer, since the user font
// cache can return the same entry for different FontFaces that have
// the same descriptor values and come from the same origin.
- AutoTArray<FontFaceImpl*, 1> mFontFaces MOZ_GUARDED_BY(mMutex);
+ AutoTArray<FontFaceImpl*, 1> mFontFaces MOZ_GUARDED_BY(mLock);
};
#ifdef DEBUG
diff --git a/layout/style/FontFaceSetDocumentImpl.cpp b/layout/style/FontFaceSetDocumentImpl.cpp
index 33f7404c7c..cd1d5959d2 100644
--- a/layout/style/FontFaceSetDocumentImpl.cpp
+++ b/layout/style/FontFaceSetDocumentImpl.cpp
@@ -496,7 +496,7 @@ bool FontFaceSetDocumentImpl::UpdateRules(
}
if (modified) {
- IncrementGeneration(true);
+ IncrementGenerationLocked(true);
mHasLoadingFontFacesIsDirty = true;
CheckLoadingStarted();
CheckLoadingFinished();
diff --git a/layout/style/FontFaceSetImpl.cpp b/layout/style/FontFaceSetImpl.cpp
index 7383842a41..5dabf25d38 100644
--- a/layout/style/FontFaceSetImpl.cpp
+++ b/layout/style/FontFaceSetImpl.cpp
@@ -70,8 +70,7 @@ using namespace mozilla::dom;
NS_IMPL_ISUPPORTS0(FontFaceSetImpl)
FontFaceSetImpl::FontFaceSetImpl(FontFaceSet* aOwner)
- : mMutex("mozilla::dom::FontFaceSetImpl"),
- mOwner(aOwner),
+ : mOwner(aOwner),
mStatus(FontFaceSetLoadStatus::Loaded),
mNonRuleFacesDirty(false),
mHasLoadingFontFaces(false),
@@ -891,7 +890,7 @@ void FontFaceSetImpl::OnLoadingFinished() {
void FontFaceSetImpl::RefreshStandardFontLoadPrincipal() {
RecursiveMutexAutoLock lock(mMutex);
mAllowedFontLoads.Clear();
- IncrementGeneration(false);
+ IncrementGenerationLocked(false);
}
// -- gfxUserFontSet
diff --git a/layout/style/FontFaceSetImpl.h b/layout/style/FontFaceSetImpl.h
index 6f245c6599..dd412dd721 100644
--- a/layout/style/FontFaceSetImpl.h
+++ b/layout/style/FontFaceSetImpl.h
@@ -92,9 +92,10 @@ class FontFaceSetImpl : public nsISupports, public gfxUserFontSet {
virtual void DispatchToOwningThread(const char* aName,
std::function<void()>&& aFunc) = 0;
- // Called by nsFontFaceLoader when the loader has completed normally.
+ // Called by nsFontFaceLoader when the loader has completed normally,
+ // or by gfxUserFontSet if it cancels the loader.
// It's removed from the mLoaders set.
- virtual void RemoveLoader(nsFontFaceLoader* aLoader);
+ void RemoveLoader(nsFontFaceLoader* aLoader) override;
virtual bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules) {
MOZ_ASSERT_UNREACHABLE("Not implemented!");
@@ -247,8 +248,6 @@ class FontFaceSetImpl : public nsISupports, public gfxUserFontSet {
virtual TimeStamp GetNavigationStartTimeStamp() = 0;
- mutable RecursiveMutex mMutex;
-
FontFaceSet* MOZ_NON_OWNING_REF mOwner MOZ_GUARDED_BY(mMutex);
// The document's node principal, which is the principal font loads for
diff --git a/layout/style/FontFaceSetWorkerImpl.cpp b/layout/style/FontFaceSetWorkerImpl.cpp
index 015c9e5b18..cd11e1f584 100644
--- a/layout/style/FontFaceSetWorkerImpl.cpp
+++ b/layout/style/FontFaceSetWorkerImpl.cpp
@@ -177,11 +177,11 @@ void FontFaceSetWorkerImpl::DispatchToOwningThread(
return;
}
- class FontFaceSetWorkerRunnable final : public WorkerRunnable {
+ class FontFaceSetWorkerRunnable final : public WorkerThreadRunnable {
public:
FontFaceSetWorkerRunnable(WorkerPrivate* aWorkerPrivate,
std::function<void()>&& aFunc)
- : WorkerRunnable(aWorkerPrivate, "FontFaceSetWorkerRunnable"),
+ : WorkerThreadRunnable("FontFaceSetWorkerRunnable"),
mFunc(std::move(aFunc)) {}
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
@@ -195,7 +195,7 @@ void FontFaceSetWorkerImpl::DispatchToOwningThread(
RefPtr<FontFaceSetWorkerRunnable> runnable =
new FontFaceSetWorkerRunnable(workerPrivate, std::move(aFunc));
- runnable->Dispatch();
+ runnable->Dispatch(workerPrivate);
}
uint64_t FontFaceSetWorkerImpl::GetInnerWindowID() {
@@ -227,7 +227,7 @@ void FontFaceSetWorkerImpl::FlushUserFontSet() {
}
if (modified) {
- IncrementGeneration(true);
+ IncrementGenerationLocked(true);
mHasLoadingFontFacesIsDirty = true;
CheckLoadingStarted();
CheckLoadingFinished();
diff --git a/layout/style/GeckoBindings.cpp b/layout/style/GeckoBindings.cpp
index dc43e9cf6a..17ba5c952e 100644
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -988,34 +988,6 @@ const AnonymousCounterStyle* Gecko_CounterStyle_GetAnonymous(
return aPtr->AsAnonymous();
}
-void Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity,
- size_t aElemSize) {
- auto base =
- reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
- nsTArray_RelocateUsingMemutils>*>(aArray);
-
- base->EnsureCapacity<nsTArrayInfallibleAllocator>(aCapacity, aElemSize);
-}
-
-void Gecko_ClearPODTArray(void* aArray, size_t aElementSize,
- size_t aElementAlign) {
- auto base =
- reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
- nsTArray_RelocateUsingMemutils>*>(aArray);
-
- base->template ShiftData<nsTArrayInfallibleAllocator>(
- 0, base->Length(), 0, aElementSize, aElementAlign);
-}
-
-void Gecko_ResizeTArrayForStrings(nsTArray<nsString>* aArray,
- uint32_t aLength) {
- aArray->SetLength(aLength);
-}
-
-void Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>>* aArray, uint32_t aLength) {
- aArray->SetLength(aLength);
-}
-
void Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen,
nsStyleImageLayers::LayerType aLayerType) {
size_t oldLength = aLayers->mLayers.Length();
@@ -1135,16 +1107,6 @@ Keyframe* Gecko_GetOrCreateFinalKeyframe(
KeyframeInsertPosition::LastForOffset);
}
-PropertyValuePair* Gecko_AppendPropertyValuePair(
- nsTArray<PropertyValuePair>* aProperties,
- const mozilla::AnimatedPropertyID* aProperty) {
- MOZ_ASSERT(aProperties);
- MOZ_ASSERT(
- aProperty->IsCustom() ||
- !nsCSSProps::PropHasFlags(aProperty->mID, CSSPropFlags::IsLogical));
- return aProperties->AppendElement(PropertyValuePair{*aProperty});
-}
-
void Gecko_GetComputedURLSpec(const StyleComputedUrl* aURL, nsCString* aOut) {
MOZ_ASSERT(aURL);
MOZ_ASSERT(aOut);
diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h
index 7bb839ae18..8ba7fcc5c6 100644
--- a/layout/style/GeckoBindings.h
+++ b/layout/style/GeckoBindings.h
@@ -375,20 +375,6 @@ const mozilla::ServoElementSnapshot* Gecko_GetElementSnapshot(
// Have we seen this pointer before?
bool Gecko_HaveSeenPtr(mozilla::SeenPtrs* table, const void* ptr);
-// `array` must be an nsTArray
-// If changing this signature, please update the
-// friend function declaration in nsTArray.h
-void Gecko_EnsureTArrayCapacity(void* array, size_t capacity, size_t elem_size);
-
-// Same here, `array` must be an nsTArray<T>, for some T.
-//
-// Important note: Only valid for POD types, since destructors won't be run
-// otherwise. This is ensured with rust traits for the relevant structs.
-void Gecko_ClearPODTArray(void* array, size_t elem_size, size_t elem_align);
-
-void Gecko_ResizeTArrayForStrings(nsTArray<nsString>* array, uint32_t length);
-void Gecko_ResizeAtomArray(nsTArray<RefPtr<nsAtom>>* array, uint32_t length);
-
void Gecko_EnsureImageLayersLength(nsStyleImageLayers* layers, size_t len,
nsStyleImageLayers::LayerType layer_type);
@@ -438,13 +424,6 @@ mozilla::Keyframe* Gecko_GetOrCreateFinalKeyframe(
const mozilla::StyleComputedTimingFunction* timingFunction,
const mozilla::dom::CompositeOperationOrAuto composition);
-// Appends and returns a new PropertyValuePair to |aProperties| initialized with
-// its mProperty member set to |aProperty| and all other members initialized to
-// their default values.
-mozilla::PropertyValuePair* Gecko_AppendPropertyValuePair(
- nsTArray<mozilla::PropertyValuePair>*,
- const mozilla::AnimatedPropertyID* aProperty);
-
void Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len);
void Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest);
diff --git a/layout/style/GenerateServoCSSPropList.py b/layout/style/GenerateServoCSSPropList.py
index 0e9678ac5c..4dba1f0a8f 100644
--- a/layout/style/GenerateServoCSSPropList.py
+++ b/layout/style/GenerateServoCSSPropList.py
@@ -30,7 +30,7 @@ def generate_data(output, template):
)
# Add all relevant files into the dependencies of the generated file.
- DEP_EXTS = [".py", ".rs", ".zip"]
+ DEP_EXTS = [".py", ".rs"]
deps = set()
for path, dirs, files in os.walk(SERVO_PROP_BASE):
for file in files:
diff --git a/layout/style/ImageLoader.cpp b/layout/style/ImageLoader.cpp
index 2ae1822b02..1a59a5bcf3 100644
--- a/layout/style/ImageLoader.cpp
+++ b/layout/style/ImageLoader.cpp
@@ -565,6 +565,16 @@ static void InvalidateImages(nsIFrame* aFrame, imgIRequest* aRequest,
}
}
}
+#ifdef XP_MACOSX
+ else if (aFrame->HasAnyStateBits(NS_FRAME_IN_POPUP)) {
+ // On macOS popups are painted with fallback rendering so they don't have
+ // webrender user data to tell us if the frame was painted last time, so we
+ // just have to invalidate always. Bug 1754796 tracks making popups on macOS
+ // use webrender. (On other platforms tooltips type popups are still
+ // rendered with fallback, but we don't expect them to have images.)
+ invalidateFrame = true;
+ }
+#endif
// Update ancestor rendering observers (-moz-element etc)
//
diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp
index 1ea37b094f..3133dd8631 100644
--- a/layout/style/Loader.cpp
+++ b/layout/style/Loader.cpp
@@ -18,12 +18,11 @@
#include "mozilla/AutoRestore.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/Logging.h"
+#include "mozilla/glean/GleanMetrics.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/PreloadHashKey.h"
#include "mozilla/ResultExtensions.h"
-#include "mozilla/SchedulerGroup.h"
#include "mozilla/URLPreloader.h"
-#include "nsIChildChannel.h"
#include "nsIPrincipal.h"
#include "nsISupportsPriority.h"
#include "nsITimedChannel.h"
@@ -47,8 +46,6 @@
#include "nsMimeTypes.h"
#include "nsICSSLoaderObserver.h"
#include "nsThreadUtils.h"
-#include "nsGkAtoms.h"
-#include "nsIThreadInternal.h"
#include "nsINetworkPredictor.h"
#include "nsQueryActor.h"
#include "nsStringStream.h"
@@ -62,13 +59,10 @@
#include "mozilla/StyleSheet.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/ConsoleReportCollector.h"
-#include "mozilla/ServoUtils.h"
#include "mozilla/css/StreamLoader.h"
#include "mozilla/SharedStyleSheetCache.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/StaticPrefs_network.h"
-#include "mozilla/StaticPrefs_dom.h"
-#include "mozilla/StaticPrefs_network.h"
#include "mozilla/Try.h"
#include "ReferrerInfo.h"
@@ -417,6 +411,23 @@ SheetLoadData::~SheetLoadData() {
"dropping the load");
}
+void SheetLoadData::StartLoading() {
+ MOZ_ASSERT(!mIsLoading, "Already loading? How?");
+ mIsLoading = true;
+ mLoadStart = TimeStamp::Now();
+}
+
+void SheetLoadData::SetLoadCompleted() {
+ MOZ_ASSERT(mIsLoading, "Not loading?");
+ MOZ_ASSERT(!mLoadStart.IsNull());
+ mIsLoading = false;
+ // Belts and suspenders just in case.
+ if (MOZ_LIKELY(!mLoadStart.IsNull())) {
+ glean::performance_pageload::async_sheet_load.AccumulateRawDuration(
+ TimeStamp::Now() - mLoadStart);
+ }
+}
+
RefPtr<StyleSheet> SheetLoadData::ValueForCache() const {
// We need to clone the sheet on insertion to the cache because otherwise the
// stylesheets can keep full windows alive via either their JS wrapper, or via
diff --git a/layout/style/PreferenceSheet.cpp b/layout/style/PreferenceSheet.cpp
index a206209885..8b0179a029 100644
--- a/layout/style/PreferenceSheet.cpp
+++ b/layout/style/PreferenceSheet.cpp
@@ -11,7 +11,6 @@
#include "mozilla/Encoding.h"
#include "mozilla/Preferences.h"
#include "mozilla/StaticPrefs_browser.h"
-#include "mozilla/StaticPrefs_devtools.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/StaticPrefs_widget.h"
#include "mozilla/StaticPrefs_ui.h"
@@ -205,7 +204,7 @@ void PreferenceSheet::Prefs::Load(bool aIsChrome) {
// as those are the colors exposed to the user in the colors dialog.
mMustUseLightColorSet = mUsePrefColors && !mUseDocumentColors;
#ifdef XP_WIN
- if (mUseAccessibilityTheme) {
+ if (mUseAccessibilityTheme && (mIsChrome || !mUseDocumentColors)) {
// Windows overrides the light colors with the HCM colors when HCM is
// active, so make sure to always use the light system colors in that case,
// and also make sure that we always use the light color set for the same
diff --git a/layout/style/Rule.cpp b/layout/style/Rule.cpp
index 0a7de42789..deaa46576c 100644
--- a/layout/style/Rule.cpp
+++ b/layout/style/Rule.cpp
@@ -95,9 +95,10 @@ Rule* Rule::GetParentRule() const { return mParentRule; }
#ifdef DEBUG
void Rule::AssertParentRuleType() {
- // Would be nice to check that this->Type() is KEYFRAME_RULE when
- // mParentRule->Tye() is KEYFRAMES_RULE, but we can't call
+ // Would be nice to check that this->Type() is StyleCssRuleType::Keyframe
+ // when mParentRule->Tye() is StyleCssRuleType::Keyframes, but we can't call
// this->Type() here since it's virtual.
+ // Same for StyleCssRuleType::Margin and StyleCssRuleType::Page.
if (mParentRule) {
auto type = mParentRule->Type();
MOZ_ASSERT(type == StyleCssRuleType::Media ||
@@ -106,7 +107,10 @@ void Rule::AssertParentRuleType() {
type == StyleCssRuleType::Supports ||
type == StyleCssRuleType::Keyframes ||
type == StyleCssRuleType::LayerBlock ||
- type == StyleCssRuleType::Container);
+ type == StyleCssRuleType::Container ||
+ type == StyleCssRuleType::Scope ||
+ type == StyleCssRuleType::StartingStyle ||
+ type == StyleCssRuleType::Page);
}
}
#endif
diff --git a/layout/style/ServoBindingTypes.h b/layout/style/ServoBindingTypes.h
index fe4f96cf0b..e2443ef526 100644
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -123,12 +123,15 @@ UNLOCKED_RULE_TYPE(Property)
UNLOCKED_RULE_TYPE(LayerBlock)
UNLOCKED_RULE_TYPE(LayerStatement)
UNLOCKED_RULE_TYPE(Namespace)
+UNLOCKED_RULE_TYPE(Margin)
UNLOCKED_RULE_TYPE(Container)
UNLOCKED_RULE_TYPE(Media)
UNLOCKED_RULE_TYPE(Supports)
UNLOCKED_RULE_TYPE(Document)
UNLOCKED_RULE_TYPE(FontFeatureValues)
UNLOCKED_RULE_TYPE(FontPaletteValues)
+UNLOCKED_RULE_TYPE(Scope)
+UNLOCKED_RULE_TYPE(StartingStyle)
SERVO_ARC_TYPE(AnimationValue, mozilla::StyleAnimationValue)
SERVO_ARC_TYPE(ComputedStyle, mozilla::ComputedStyle)
diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h
index 6f19006512..2c0abbe0db 100644
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -77,7 +77,8 @@ BASIC_RULE_FUNCS_LOCKED(Keyframes)
GROUP_RULE_FUNCS_UNLOCKED(Media)
GROUP_RULE_FUNCS_UNLOCKED(Document)
BASIC_RULE_FUNCS_UNLOCKED(Namespace)
-BASIC_RULE_FUNCS_LOCKED(Page)
+BASIC_RULE_FUNCS_UNLOCKED(Margin)
+GROUP_RULE_FUNCS_LOCKED(Page)
BASIC_RULE_FUNCS_UNLOCKED(Property)
GROUP_RULE_FUNCS_UNLOCKED(Supports)
GROUP_RULE_FUNCS_UNLOCKED(LayerBlock)
@@ -87,6 +88,8 @@ BASIC_RULE_FUNCS_UNLOCKED(FontPaletteValues)
BASIC_RULE_FUNCS_LOCKED(FontFace)
BASIC_RULE_FUNCS_LOCKED(CounterStyle)
GROUP_RULE_FUNCS_UNLOCKED(Container)
+GROUP_RULE_FUNCS_UNLOCKED(Scope)
+GROUP_RULE_FUNCS_UNLOCKED(StartingStyle)
#undef GROUP_RULE_FUNCS_LOCKED
#undef GROUP_RULE_FUNCS_UNLOCKED
diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml
index 20e1ca4116..833fbd0272 100644
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -54,6 +54,7 @@ hide-types = [
"mozilla::StyleTimingFunction.*",
# https://github.com/rust-lang/rust-bindgen/issues/1559
"mozilla::StyleGeneric.*",
+ "nsTArray_.*",
".*ErrorResult.*",
]
bitfield-enums = [
@@ -290,7 +291,6 @@ allowlist-types = [
"nsStyleUI",
"nsStyleVisibility",
"nsStyleXUL",
- "nsTArrayHeader",
"mozilla::UniquePtr",
"mozilla::DeclarationBlock",
"mozilla::DefaultDelete",
@@ -403,6 +403,7 @@ cbindgen-types = [
{ gecko = "StyleOffsetRotate", servo = "crate::values::computed::motion::OffsetRotate" },
{ gecko = "StylePathCommand", servo = "crate::values::specified::svg_path::PathCommand" },
{ gecko = "StyleRayFunction", servo = "crate::values::computed::motion::RayFunction" },
+ { gecko = "StyleParserState", servo = "cssparser::ParserState" },
{ gecko = "StyleUnicodeRange", servo = "cssparser::UnicodeRange" },
{ gecko = "StyleOverflowWrap", servo = "crate::values::computed::OverflowWrap" },
{ gecko = "StyleWordBreak", servo = "crate::values::computed::WordBreak" },
@@ -515,6 +516,9 @@ cbindgen-types = [
{ gecko = "StyleBasicShape", servo = "crate::values::computed::basic_shape::BasicShape" },
{ gecko = "StyleGenericInsetRect", servo = "crate::values::generics::basic_shape::InsetRect" },
{ gecko = "StyleInsetRect", servo = "crate::values::computed::basic_shape::InsetRect" },
+ { gecko = "StyleShape", servo = "crate::values::computed::basic_shape::Shape" },
+ { gecko = "StyleShapeCommand", servo = "crate::values::computed::basic_shape::ShapeCommand" },
+ { gecko = "StyleGenericShapeCommand", servo = "crate::values::generics::basic_shape::ShapeCommand" },
{ gecko = "StyleArcSlice", servo = "style_traits::arc_slice::ArcSlice" },
{ gecko = "StyleForgottenArcSlicePtr", servo = "style_traits::arc_slice::ForgottenArcSlicePtr" },
{ gecko = "StyleOwnedSlice", servo = "style_traits::owned_slice::OwnedSlice" },
@@ -628,6 +632,8 @@ mapped-generic-types = [
{ generic = false, gecko = "nsAString", servo = "nsstring::nsAString" },
{ generic = false, gecko = "nsCString", servo = "nsstring::nsCString" },
{ generic = false, gecko = "nsString", servo = "nsstring::nsString" },
+ { generic = true, gecko = "nsTArray", servo = "thin_vec::ThinVec" },
+ { generic = true, gecko = "CopyableTArray", servo = "thin_vec::ThinVec" },
]
allowlist-functions = ["Servo_.*", "Gecko_.*"]
diff --git a/layout/style/ServoCSSRuleList.cpp b/layout/style/ServoCSSRuleList.cpp
index 6fcdfdd4b5..b7172879de 100644
--- a/layout/style/ServoCSSRuleList.cpp
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -17,11 +17,14 @@
#include "mozilla/dom/CSSLayerStatementRule.h"
#include "mozilla/dom/CSSKeyframesRule.h"
#include "mozilla/dom/CSSContainerRule.h"
+#include "mozilla/dom/CSSMarginRule.h"
#include "mozilla/dom/CSSMediaRule.h"
#include "mozilla/dom/CSSMozDocumentRule.h"
#include "mozilla/dom/CSSNamespaceRule.h"
#include "mozilla/dom/CSSPageRule.h"
#include "mozilla/dom/CSSPropertyRule.h"
+#include "mozilla/dom/CSSScopeRule.h"
+#include "mozilla/dom/CSSStartingStyleRule.h"
#include "mozilla/dom/CSSStyleRule.h"
#include "mozilla/dom/CSSSupportsRule.h"
#include "mozilla/IntegerRange.h"
@@ -86,6 +89,7 @@ css::Rule* ServoCSSRuleList::GetRule(uint32_t aIndex) {
CASE_RULE_LOCKED(Keyframes, Keyframes)
CASE_RULE_UNLOCKED(Media, Media)
CASE_RULE_UNLOCKED(Namespace, Namespace)
+ CASE_RULE_UNLOCKED(Margin, Margin)
CASE_RULE_LOCKED(Page, Page)
CASE_RULE_UNLOCKED(Property, Property)
CASE_RULE_UNLOCKED(Supports, Supports)
@@ -98,15 +102,14 @@ css::Rule* ServoCSSRuleList::GetRule(uint32_t aIndex) {
CASE_RULE_UNLOCKED(LayerBlock, LayerBlock)
CASE_RULE_UNLOCKED(LayerStatement, LayerStatement)
CASE_RULE_UNLOCKED(Container, Container)
+ CASE_RULE_UNLOCKED(Scope, Scope)
+ CASE_RULE_UNLOCKED(StartingStyle, StartingStyle)
#undef CASE_RULE_LOCKED
#undef CASE_RULE_UNLOCKED
#undef CASE_RULE_WITH_PREFIX
case StyleCssRuleType::Keyframe:
MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
return nullptr;
- case StyleCssRuleType::Margin:
- // Margin rules not implemented yet, see bug 1864737
- return nullptr;
}
rule = CastToUint(ruleObj.forget().take());
mRules[aIndex] = rule;
@@ -208,12 +211,21 @@ nsresult ServoCSSRuleList::InsertRule(const nsACString& aRule,
}
StyleCssRuleType type;
uint32_t containingTypes = 0;
+ Maybe<StyleCssRuleType> parseRelativeRuleType;
for (css::Rule* rule = mParentRule; rule; rule = rule->GetParentRule()) {
- containingTypes |= (1 << uint32_t(rule->Type()));
+ const auto ruleType = rule->Type();
+ containingTypes |= (1 << uint32_t(ruleType));
+ if (parseRelativeRuleType.isNothing() &&
+ (ruleType == StyleCssRuleType::Style ||
+ ruleType == StyleCssRuleType::Scope)) {
+ // Only the closest applicable type to this rule matters.
+ parseRelativeRuleType = Some(ruleType);
+ }
}
nsresult rv = Servo_CssRules_InsertRule(
mRawRules, mStyleSheet->RawContents(), &aRule, aIndex, containingTypes,
- loader, allowImportRules, mStyleSheet, &type);
+ parseRelativeRuleType.ptrOr(nullptr), loader, allowImportRules,
+ mStyleSheet, &type);
NS_ENSURE_SUCCESS(rv, rv);
mRules.InsertElementAt(aIndex, uintptr_t(type));
return rv;
@@ -264,6 +276,7 @@ void ServoCSSRuleList::SetRawContents(RefPtr<StyleLockedCssRules> aNewRules,
RULE_CASE_LOCKED(Keyframes, Keyframes)
RULE_CASE_UNLOCKED(Media, Media)
RULE_CASE_UNLOCKED(Namespace, Namespace)
+ RULE_CASE_UNLOCKED(Margin, Margin)
RULE_CASE_LOCKED(Page, Page)
RULE_CASE_UNLOCKED(Property, Property)
RULE_CASE_UNLOCKED(Supports, Supports)
@@ -276,12 +289,11 @@ void ServoCSSRuleList::SetRawContents(RefPtr<StyleLockedCssRules> aNewRules,
RULE_CASE_UNLOCKED(LayerBlock, LayerBlock)
RULE_CASE_UNLOCKED(LayerStatement, LayerStatement)
RULE_CASE_UNLOCKED(Container, Container)
+ RULE_CASE_UNLOCKED(Scope, Scope)
+ RULE_CASE_UNLOCKED(StartingStyle, StartingStyle)
case StyleCssRuleType::Keyframe:
MOZ_ASSERT_UNREACHABLE("keyframe rule cannot be here");
break;
- case StyleCssRuleType::Margin:
- // Margin rules not implemented yet, see bug 1864737
- break;
}
#undef RULE_CASE_WITH_PREFIX
#undef RULE_CASE_LOCKED
diff --git a/layout/style/ServoElementSnapshot.cpp b/layout/style/ServoElementSnapshot.cpp
index e0ef2849f9..a5251d9349 100644
--- a/layout/style/ServoElementSnapshot.cpp
+++ b/layout/style/ServoElementSnapshot.cpp
@@ -82,4 +82,11 @@ void ServoElementSnapshot::AddAttrs(const Element& aElement,
}
}
+void ServoElementSnapshot::AddCustomStates(Element& aElement) {
+ if (mContains & Flags::CustomState) {
+ return;
+ }
+ mCustomStates = aElement.EnsureCustomStates().Clone();
+ mContains |= Flags::CustomState;
+}
} // namespace mozilla
diff --git a/layout/style/ServoElementSnapshot.h b/layout/style/ServoElementSnapshot.h
index b702975c4b..5a86b4c13d 100644
--- a/layout/style/ServoElementSnapshot.h
+++ b/layout/style/ServoElementSnapshot.h
@@ -33,6 +33,7 @@ enum class ServoElementSnapshotFlags : uint8_t {
Id = 1 << 2,
MaybeClass = 1 << 3,
OtherPseudoClassState = 1 << 4,
+ CustomState = 1 << 5,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoElementSnapshotFlags)
@@ -89,6 +90,11 @@ class ServoElementSnapshot {
void AddAttrs(const Element&, int32_t aNameSpaceID, nsAtom* aAttribute);
/**
+ * Captures the given element custom states.
+ */
+ void AddCustomStates(Element&);
+
+ /**
* Captures some other pseudo-class matching state not included in
* ElementState.
*/
@@ -155,6 +161,7 @@ class ServoElementSnapshot {
// snapshots.
nsTArray<AttrArray::InternalAttr> mAttrs;
nsTArray<RefPtr<nsAtom>> mChangedAttrNames;
+ nsTArray<RefPtr<nsAtom>> mCustomStates;
nsAttrValue mClass;
ServoStateType mState;
Flags mContains;
diff --git a/layout/style/ServoLockedArcTypeList.h b/layout/style/ServoLockedArcTypeList.h
index 2d356aabf9..70adc7bd8e 100644
--- a/layout/style/ServoLockedArcTypeList.h
+++ b/layout/style/ServoLockedArcTypeList.h
@@ -19,6 +19,7 @@ SERVO_LOCKED_ARC_TYPE(StyleRule)
SERVO_LOCKED_ARC_TYPE(ImportRule)
SERVO_LOCKED_ARC_TYPE(Keyframe)
SERVO_LOCKED_ARC_TYPE(KeyframesRule)
+SERVO_LOCKED_ARC_TYPE(MarginList)
SERVO_LOCKED_ARC_TYPE(MediaList)
SERVO_LOCKED_ARC_TYPE(PageRule)
SERVO_LOCKED_ARC_TYPE(FontFaceRule)
diff --git a/layout/style/ServoStyleConstsForwards.h b/layout/style/ServoStyleConstsForwards.h
index 65128e1377..cd2958618f 100644
--- a/layout/style/ServoStyleConstsForwards.h
+++ b/layout/style/ServoStyleConstsForwards.h
@@ -83,12 +83,13 @@ struct PropertyStyleAnimationValuePair;
using ComputedKeyframeValues = nsTArray<PropertyStyleAnimationValuePair>;
class ComputedStyle;
-enum LogicalAxis : uint8_t;
+enum class LogicalAxis : uint8_t;
class SeenPtrs;
class SharedFontList;
class StyleSheet;
class WritingMode;
class ServoElementSnapshotTable;
+class StyleParserState;
template <typename T>
struct StyleForgottenArcSlicePtr;
@@ -100,7 +101,7 @@ struct ComputedTiming;
struct URLExtraData;
enum HalfCorner : uint8_t;
-enum LogicalSide : uint8_t;
+enum class LogicalSide : uint8_t;
enum class PseudoStyleType : uint8_t;
enum class OriginFlags : uint8_t;
enum class UseBoxSizing : uint8_t;
diff --git a/layout/style/ServoStyleConstsInlines.h b/layout/style/ServoStyleConstsInlines.h
index 1985e8fbeb..50893f5112 100644
--- a/layout/style/ServoStyleConstsInlines.h
+++ b/layout/style/ServoStyleConstsInlines.h
@@ -45,6 +45,7 @@ template struct StyleStrong<StyleLockedKeyframesRule>;
template struct StyleStrong<StyleMediaRule>;
template struct StyleStrong<StyleDocumentRule>;
template struct StyleStrong<StyleNamespaceRule>;
+template struct StyleStrong<StyleMarginRule>;
template struct StyleStrong<StyleLockedPageRule>;
template struct StyleStrong<StylePropertyRule>;
template struct StyleStrong<StyleSupportsRule>;
@@ -53,6 +54,8 @@ template struct StyleStrong<StyleFontPaletteValuesRule>;
template struct StyleStrong<StyleLockedFontFaceRule>;
template struct StyleStrong<StyleLockedCounterStyleRule>;
template struct StyleStrong<StyleContainerRule>;
+template struct StyleStrong<StyleScopeRule>;
+template struct StyleStrong<StyleStartingStyleRule>;
template <typename T>
inline void StyleOwnedSlice<T>::Clear() {
@@ -697,9 +700,12 @@ CSSCoord StyleCalcLengthPercentage::ResolveToCSSPixels(CSSCoord aBasis) const {
return Servo_ResolveCalcLengthPercentage(this, aBasis);
}
-nscoord StyleCalcLengthPercentage::Resolve(nscoord aBasis) const {
- return detail::DefaultLengthToAppUnits(
- ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis)));
+template <typename Rounder>
+nscoord StyleCalcLengthPercentage::Resolve(nscoord aBasis,
+ Rounder aRounder) const {
+ static_assert(std::is_same_v<decltype(aRounder(1.0f)), nscoord>);
+ CSSCoord result = ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis));
+ return aRounder(result * AppUnitsPerCSSPixel());
}
template <>
@@ -724,11 +730,10 @@ CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const {
return ResolveToCSSPixels(aPercentageGetter());
}
-template <typename T, typename PercentRounder>
-nscoord LengthPercentage::Resolve(T aPercentageGetter,
- PercentRounder aPercentRounder) const {
+template <typename T, typename Rounder>
+nscoord LengthPercentage::Resolve(T aPercentageGetter, Rounder aRounder) const {
static_assert(std::is_same_v<decltype(aPercentageGetter()), nscoord>);
- static_assert(std::is_same_v<decltype(aPercentRounder(1.0f)), nscoord>);
+ static_assert(std::is_same_v<decltype(aRounder(1.0f)), nscoord>);
if (ConvertsToLength()) {
return ToLength();
}
@@ -737,9 +742,9 @@ nscoord LengthPercentage::Resolve(T aPercentageGetter,
}
nscoord basis = aPercentageGetter();
if (IsPercentage()) {
- return aPercentRounder(basis * AsPercentage()._0);
+ return aRounder(basis * AsPercentage()._0);
}
- return AsCalc().Resolve(basis);
+ return AsCalc().Resolve(basis, aRounder);
}
nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const {
@@ -752,11 +757,10 @@ nscoord LengthPercentage::Resolve(T aPercentageGetter) const {
return Resolve(aPercentageGetter, detail::DefaultPercentLengthToAppUnits);
}
-template <typename PercentRounder>
+template <typename Rounder>
nscoord LengthPercentage::Resolve(nscoord aPercentageBasis,
- PercentRounder aPercentRounder) const {
- return Resolve([aPercentageBasis] { return aPercentageBasis; },
- aPercentRounder);
+ Rounder aRounder) const {
+ return Resolve([aPercentageBasis] { return aPercentageBasis; }, aRounder);
}
void LengthPercentage::ScaleLengthsBy(float aScale) {
@@ -1201,6 +1205,20 @@ inline nsRect StyleZoom::Unzoom(const nsRect& aValue) const {
UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height()));
}
+template <>
+inline gfx::Point StyleCoordinatePair<StyleCSSFloat>::ToGfxPoint(
+ const CSSSize* aBasis) const {
+ return gfx::Point(x, y);
+}
+
+template <>
+inline gfx::Point StyleCoordinatePair<LengthPercentage>::ToGfxPoint(
+ const CSSSize* aBasis) const {
+ MOZ_ASSERT(aBasis);
+ return gfx::Point(x.ResolveToCSSPixels(aBasis->Width()),
+ y.ResolveToCSSPixels(aBasis->Height()));
+}
+
} // namespace mozilla
#endif
diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp
index cfc38849b8..22359fa82d 100644
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -34,6 +34,7 @@
#include "mozilla/dom/CSSContainerRule.h"
#include "mozilla/dom/CSSLayerBlockRule.h"
#include "mozilla/dom/CSSLayerStatementRule.h"
+#include "mozilla/dom/CSSMarginRule.h"
#include "mozilla/dom/CSSMediaRule.h"
#include "mozilla/dom/CSSMozDocumentRule.h"
#include "mozilla/dom/CSSKeyframesRule.h"
@@ -41,7 +42,9 @@
#include "mozilla/dom/CSSNamespaceRule.h"
#include "mozilla/dom/CSSPageRule.h"
#include "mozilla/dom/CSSPropertyRule.h"
+#include "mozilla/dom/CSSScopeRule.h"
#include "mozilla/dom/CSSSupportsRule.h"
+#include "mozilla/dom/CSSStartingStyleRule.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ElementInlines.h"
@@ -764,7 +767,7 @@ bool ServoStyleSet::GeneratedContentPseudoExists(
if (!aPseudoStyle.StyleContent()->mContent.IsItems()) {
return false;
}
- MOZ_ASSERT(aPseudoStyle.StyleContent()->ContentCount() > 0,
+ MOZ_ASSERT(!aPseudoStyle.StyleContent()->NonAltContentItems().IsEmpty(),
"IsItems() implies we have at least one item");
// display:none is equivalent to not having a pseudo at all.
if (aPseudoStyle.StyleDisplay()->mDisplay == StyleDisplay::None) {
@@ -992,6 +995,7 @@ void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule,
CASE_FOR(Import, Import)
CASE_FOR(Media, Media)
CASE_FOR(Keyframes, Keyframes)
+ CASE_FOR(Margin, Margin)
CASE_FOR(FontFeatureValues, FontFeatureValues)
CASE_FOR(FontPaletteValues, FontPaletteValues)
CASE_FOR(FontFace, FontFace)
@@ -1002,6 +1006,8 @@ void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule,
CASE_FOR(LayerBlock, LayerBlock)
CASE_FOR(LayerStatement, LayerStatement)
CASE_FOR(Container, Container)
+ CASE_FOR(Scope, Scope)
+ CASE_FOR(StartingStyle, StartingStyle)
// @namespace can only be inserted / removed when there are only other
// @namespace and @import rules, and can't be mutated.
case StyleCssRuleType::Namespace:
@@ -1010,9 +1016,6 @@ void ServoStyleSet::RuleChangedInternal(StyleSheet& aSheet, css::Rule& aRule,
// FIXME: We should probably just forward to the parent @keyframes rule? I
// think that'd do the right thing, but meanwhile...
return MarkOriginsDirty(ToOriginFlags(aSheet.GetOrigin()));
- case StyleCssRuleType::Margin:
- // Margin rules not implemented yet, see bug 1864737
- break;
}
#undef CASE_FOR
@@ -1394,6 +1397,13 @@ void ServoStyleSet::MaybeInvalidateRelativeSelectorClassDependency(
mRawData.get(), &aElement, &aSnapshots);
}
+void ServoStyleSet::MaybeInvalidateRelativeSelectorCustomStateDependency(
+ const Element& aElement, nsAtom* state,
+ const ServoElementSnapshotTable& aSnapshots) {
+ Servo_StyleSet_MaybeInvalidateRelativeSelectorCustomStateDependency(
+ mRawData.get(), &aElement, state, &aSnapshots);
+}
+
void ServoStyleSet::MaybeInvalidateRelativeSelectorAttributeDependency(
const Element& aElement, nsAtom* aAttribute,
const ServoElementSnapshotTable& aSnapshots) {
@@ -1465,6 +1475,12 @@ bool ServoStyleSet::HasNthOfStateDependency(const Element& aElement,
aState.GetInternalValue());
}
+bool ServoStyleSet::HasNthOfCustomStateDependency(const Element& aElement,
+ nsAtom* aState) const {
+ return Servo_StyleSet_HasNthOfCustomStateDependency(mRawData.get(), &aElement,
+ aState);
+}
+
void ServoStyleSet::RestyleSiblingsForNthOf(const Element& aElement,
uint32_t aFlags) const {
Servo_StyleSet_RestyleSiblingsForNthOf(&aElement, aFlags);
diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h
index eee6cba0f7..f3159c97ec 100644
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -477,6 +477,14 @@ class ServoStyleSet {
const dom::Element&, const ServoElementSnapshotTable& aSnapshots);
/**
+ * Maybe invalidate if a modification to a Custom State might require us to
+ * restyle the relative selector it refers to.
+ */
+ void MaybeInvalidateRelativeSelectorCustomStateDependency(
+ const dom::Element&, nsAtom* state,
+ const ServoElementSnapshotTable& aSnapshots);
+
+ /**
* Maybe invalidate if a modification to an ID might require us to restyle
* the relative selector it refers to.
*/
@@ -550,6 +558,12 @@ class ServoStyleSet {
bool HasNthOfStateDependency(const dom::Element&, dom::ElementState) const;
/**
+ * Returns true if a change in Custom State on an element might require
+ * us to restyle the element's siblings.
+ */
+ bool HasNthOfCustomStateDependency(const dom::Element&, nsAtom*) const;
+
+ /**
* Restyle this element's siblings in order to propagate any potential change
* in :nth-child(of) styling.
*/
diff --git a/layout/style/SharedSubResourceCache.h b/layout/style/SharedSubResourceCache.h
index 32919b8863..896eacbcb5 100644
--- a/layout/style/SharedSubResourceCache.h
+++ b/layout/style/SharedSubResourceCache.h
@@ -58,6 +58,9 @@ struct SharedSubResourceCacheLoadingValueBase {
virtual void SetLoadCompleted() = 0;
virtual void Cancel() = 0;
+ // Return the next sub-resource which has the same key.
+ Derived* GetNextSubResource() { return mNext; }
+
~SharedSubResourceCacheLoadingValueBase() {
// Do this iteratively to avoid blowing up the stack.
RefPtr<Derived> next = std::move(mNext);
diff --git a/layout/style/SheetLoadData.h b/layout/style/SheetLoadData.h
index 6621af35bd..2f829d746e 100644
--- a/layout/style/SheetLoadData.h
+++ b/layout/style/SheetLoadData.h
@@ -239,6 +239,9 @@ class SheetLoadData final
// listening for the load.
bool mIntentionallyDropped = false;
+ // The start timestamp for the load.
+ TimeStamp mLoadStart;
+
const bool mRecordErrors;
bool ShouldDefer() const { return mWasAlternate || !mMediaMatched; }
@@ -269,8 +272,9 @@ class SheetLoadData final
bool IsLoading() const override { return mIsLoading; }
bool IsCancelled() const override { return mIsCancelled; }
- void StartLoading() override { mIsLoading = true; }
- void SetLoadCompleted() override { mIsLoading = false; }
+ void StartLoading() override;
+ void SetLoadCompleted() override;
+
void Cancel() override { mIsCancelled = true; }
private:
diff --git a/layout/style/crashtests/crashtests.list b/layout/style/crashtests/crashtests.list
index d54f053f1b..2568a6e036 100644
--- a/layout/style/crashtests/crashtests.list
+++ b/layout/style/crashtests/crashtests.list
@@ -166,7 +166,7 @@ load 1290994-4.html
load 1314531.html
load 1315889-1.html
load 1315894-1.html
-pref(widget.windows.window_occlusion_tracking.enabled,false) skip-if(wayland) load 1319072-1.html # Bug 1819154, wayland: bug 1856389
+load 1319072-1.html
HTTP load 1320423-1.html
load 1321357-1.html
load 1328535-1.html
@@ -174,8 +174,8 @@ load 1331272.html
load 1332550.html
HTTP load 1333001-1.html
load 1340248.html
-skip-if(wayland) load 1340344.html # wayland: bug 1856389
-skip-if(wayland) load 1342316-1.html # wayland: bug 1856389
+load 1340344.html
+load 1342316-1.html
load 1344210.html
load 1353312.html
load 1356601-1.html
@@ -185,19 +185,19 @@ load 1374175-1.html
load 1375812-1.html
load 1377053-1.html
load 1377256-1.html
-skip-if(wayland) load 1378064-1.html # wayland: bug 1856389
+load 1378064-1.html
load 1378814.html
load 1380800.html
load link-transition-before.html
-skip-if(wayland) load 1381420-1.html # wayland: bug 1856389
+load 1381420-1.html
load 1381682.html
load 1382672.html
load 1382710.html
pref(dom.animations-api.compositing.enabled,true) load 1383493-1.html
-skip-if(wayland) load 1383001.html # wayland: bug 1856389
+load 1383001.html
load 1383001-2.html
load 1383319.html
-skip-if(wayland) load 1383589-1.html # wayland: bug 1856389
+load 1383589-1.html
load 1383975.html
load border-image-visited-link.html
load content-only-on-link-before.html
@@ -206,7 +206,7 @@ load font-face-truncated-src.html
load large_border_image_width.html
load link-transition-before.html
load long-url-list-stack-overflow.html #Bug 1525117
-skip-if(wayland) load scale-on-block-continuation.html # wayland: bug 1856389
+load scale-on-block-continuation.html
skip-if(AddressSanitizer) skip-if(ThreadSanitizer) load 1383981.html # Very sensitive to stack size.
skip-if(AddressSanitizer) skip-if(ThreadSanitizer) load 1383981-2.html
skip-if(AddressSanitizer) skip-if(ThreadSanitizer) load 1383981-3.html
@@ -239,7 +239,7 @@ load 1400936-1.html
load 1400936-2.html
load 1401256.html
load 1401706.html
-skip-if(wayland) load 1401801.html # wayland: bug 1856389
+load 1401801.html
load 1401825.html
load 1402218-1.html
load 1402366.html
@@ -270,8 +270,8 @@ load 1413288.html
load 1413361.html
load 1413670.html
load 1415353.html
-skip-if(wayland) load 1418059.html # wayland: bug 1856389
-skip-if(wayland) load 1418867.html # wayland: bug 1856389
+load 1418059.html
+load 1418867.html
load 1419554.html
load 1426312.html
load 1439793.html
diff --git a/layout/style/moz.build b/layout/style/moz.build
index a14ab6a7ac..ce9ee36cea 100644
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -56,6 +56,7 @@ EXPORTS += [
"nsCSSValue.h",
"nsDOMCSSAttrDeclaration.h",
"nsDOMCSSDeclaration.h",
+ "nsFontFaceLoader.h",
"nsICSSDeclaration.h",
"nsICSSLoaderObserver.h",
"nsStyleAutoArray.h",
@@ -137,12 +138,15 @@ EXPORTS.mozilla.dom += [
"CSSKeyframesRule.h",
"CSSLayerBlockRule.h",
"CSSLayerStatementRule.h",
+ "CSSMarginRule.h",
"CSSMediaRule.h",
"CSSMozDocumentRule.h",
"CSSNamespaceRule.h",
"CSSPageRule.h",
"CSSPropertyRule.h",
"CSSRuleList.h",
+ "CSSScopeRule.h",
+ "CSSStartingStyleRule.h",
"CSSStyleRule.h",
"CSSSupportsRule.h",
"CSSValue.h",
@@ -188,12 +192,15 @@ UNIFIED_SOURCES += [
"CSSKeyframesRule.cpp",
"CSSLayerBlockRule.cpp",
"CSSLayerStatementRule.cpp",
+ "CSSMarginRule.cpp",
"CSSMediaRule.cpp",
"CSSMozDocumentRule.cpp",
"CSSNamespaceRule.cpp",
"CSSPageRule.cpp",
"CSSPropertyRule.cpp",
"CSSRuleList.cpp",
+ "CSSScopeRule.cpp",
+ "CSSStartingStyleRule.cpp",
"CSSStyleRule.cpp",
"CSSSupportsRule.cpp",
"DeclarationBlock.cpp",
diff --git a/layout/style/nsCSSPseudoElementList.h b/layout/style/nsCSSPseudoElementList.h
index 9514dd6c4b..7492523c58 100644
--- a/layout/style/nsCSSPseudoElementList.h
+++ b/layout/style/nsCSSPseudoElementList.h
@@ -51,6 +51,7 @@ CSS_PSEUDO_ELEMENT(highlight, ":highlight", 0)
CSS_PSEUDO_ELEMENT(selection, ":selection",
CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS)
+CSS_PSEUDO_ELEMENT(targetText, ":target-text", 0)
// XXXbz should we really allow random content to style these? Maybe
// use our flags to prevent that?
CSS_PSEUDO_ELEMENT(mozFocusInner, ":-moz-focus-inner", 0)
diff --git a/layout/style/nsCSSPseudoElements.h b/layout/style/nsCSSPseudoElements.h
index 9866fbfb7e..baeee9d4de 100644
--- a/layout/style/nsCSSPseudoElements.h
+++ b/layout/style/nsCSSPseudoElements.h
@@ -130,6 +130,8 @@ class nsCSSPseudoElements {
switch (aType) {
case Type::highlight:
return mozilla::StaticPrefs::dom_customHighlightAPI_enabled();
+ case Type::targetText:
+ return mozilla::StaticPrefs::dom_text_fragments_enabled();
case Type::sliderTrack:
case Type::sliderThumb:
case Type::sliderFill:
diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h
index bc8914bbc1..540ac91a49 100644
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -55,14 +55,16 @@ enum nsCSSUnit : uint32_t {
// different behavior than percent)
// Font relative measure
- eCSSUnit_EM = 800, // == current font size
- eCSSUnit_XHeight = 801, // distance from top of lower case x to
- // baseline
- eCSSUnit_Char = 802, // number of characters, used for width with
- // monospace font
- eCSSUnit_RootEM = 803, // == root element font size
- eCSSUnit_Ideographic = 804, // == CJK water ideograph width
- eCSSUnit_CapHeight = 805, // == Capital letter height
+ eCSSUnit_EM = 800, // == current font size
+ eCSSUnit_XHeight = 801, // distance from top of lower case x to
+ // baseline
+ eCSSUnit_Char = 802, // number of characters, used for width with
+ // monospace font
+ eCSSUnit_RootEM = 803, // == root element font size
+ eCSSUnit_Ideographic = 804, // == CJK water ideograph width
+ eCSSUnit_CapHeight = 805, // == Capital letter height
+ eCSSUnit_LineHeight = 806, // == Line height
+ eCSSUnit_RootLineHeight = 807, // == Root line height
// Screen relative measure
eCSSUnit_Point = 900, // 4/3 of a CSS pixel
diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp
index d40d4bc801..876f32cd7a 100644
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1358,11 +1358,28 @@ already_AddRefed<nsROCSSPrimitiveValue> nsComputedDOMStyle::MatrixToCSSValue(
/* Create a value to hold our result. */
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
val->SetString(resultString);
return val.forget();
}
+already_AddRefed<nsROCSSPrimitiveValue> nsComputedDOMStyle::AppUnitsToCSSValue(
+ nscoord aAppUnits) {
+ return PixelsToCSSValue(CSSPixel::FromAppUnits(aAppUnits));
+}
+
+already_AddRefed<nsROCSSPrimitiveValue> nsComputedDOMStyle::PixelsToCSSValue(
+ float aPixels) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToPixels(val, aPixels);
+ return val.forget();
+}
+
+void nsComputedDOMStyle::SetValueToPixels(nsROCSSPrimitiveValue* aValue,
+ float aPixels) {
+ MOZ_ASSERT(mComputedStyle);
+ aValue->SetPixels(mComputedStyle->EffectiveZoom().Unzoom(aPixels));
+}
+
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetMozOsxFontSmoothing() {
if (nsContentUtils::ShouldResistFingerprinting(
mPresShell->GetPresContext()->GetDocShell(),
@@ -1614,9 +1631,7 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetGridTemplateColumnsRows(
// Add any leading implicit tracks.
if (serializeImplicit) {
for (uint32_t i = 0; i < numLeadingImplicitTracks; ++i) {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetAppUnits(trackSizes[i]);
- valueList->AppendCSSValue(val.forget());
+ valueList->AppendCSSValue(AppUnitsToCSSValue(trackSizes[i]));
}
}
@@ -1652,8 +1667,7 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetGridTemplateColumnsRows(
for (uint32_t i = 0; i < repeatStart; i++) {
AppendGridLineNames(valueList, aTrackInfo.mResolvedLineNames[i]);
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetAppUnits(*trackSizeIter++);
- valueList->AppendCSSValue(val.forget());
+ valueList->AppendCSSValue(AppUnitsToCSSValue(*trackSizeIter++));
}
auto lineNameIter = aTrackInfo.mResolvedLineNames.cbegin() + repeatStart;
// Write the track names at the start of the repeat, including the names
@@ -1666,9 +1680,7 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetGridTemplateColumnsRows(
// track).
const nscoord firstRepeatTrackSize =
(!aTrackInfo.mRemovedRepeatTracks[0]) ? *trackSizeIter++ : 0;
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetAppUnits(firstRepeatTrackSize);
- valueList->AppendCSSValue(val.forget());
+ valueList->AppendCSSValue(AppUnitsToCSSValue(firstRepeatTrackSize));
}
// Write the line names and track sizes inside the repeat, checking for
// removed tracks (size 0).
@@ -1688,9 +1700,7 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetGridTemplateColumnsRows(
trackSizeIter != explicitTrackSizeEnd);
const nscoord repeatTrackSize =
(!aTrackInfo.mRemovedRepeatTracks[i]) ? *trackSizeIter++ : 0;
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetAppUnits(repeatTrackSize);
- valueList->AppendCSSValue(val.forget());
+ valueList->AppendCSSValue(AppUnitsToCSSValue(repeatTrackSize));
}
// The resolved line names include a single repetition of the auto-repeat
// line names. Skip over those.
@@ -1698,9 +1708,7 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetGridTemplateColumnsRows(
// Write out any more tracks after the repeat.
while (trackSizeIter != explicitTrackSizeEnd) {
AppendGridLineNames(valueList, *lineNameIter++);
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetAppUnits(*trackSizeIter++);
- valueList->AppendCSSValue(val.forget());
+ valueList->AppendCSSValue(AppUnitsToCSSValue(*trackSizeIter++));
}
// Write the final trailing line name.
AppendGridLineNames(valueList, *lineNameIter++);
@@ -1711,18 +1719,15 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetGridTemplateColumnsRows(
if (i == numExplicitTracks) {
break;
}
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetAppUnits(trackSizes[i + numLeadingImplicitTracks]);
- valueList->AppendCSSValue(val.forget());
+ valueList->AppendCSSValue(
+ AppUnitsToCSSValue(trackSizes[i + numLeadingImplicitTracks]));
}
}
// Add any trailing implicit tracks.
if (serializeImplicit) {
for (uint32_t i = numLeadingImplicitTracks + numExplicitTracks;
i < numSizes; ++i) {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetAppUnits(trackSizes[i]);
- valueList->AppendCSSValue(val.forget());
+ valueList->AppendCSSValue(AppUnitsToCSSValue(trackSizes[i]));
}
}
@@ -1787,15 +1792,9 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetPaddingRight() {
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetBorderSpacing() {
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
- RefPtr<nsROCSSPrimitiveValue> xSpacing = new nsROCSSPrimitiveValue;
- RefPtr<nsROCSSPrimitiveValue> ySpacing = new nsROCSSPrimitiveValue;
-
const nsStyleTableBorder* border = StyleTableBorder();
- xSpacing->SetAppUnits(border->mBorderSpacingCol);
- ySpacing->SetAppUnits(border->mBorderSpacingRow);
-
- valueList->AppendCSSValue(xSpacing.forget());
- valueList->AppendCSSValue(ySpacing.forget());
+ valueList->AppendCSSValue(AppUnitsToCSSValue(border->mBorderSpacingCol));
+ valueList->AppendCSSValue(AppUnitsToCSSValue(border->mBorderSpacingRow));
return valueList.forget();
}
@@ -1833,32 +1832,26 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetMarginRight() {
}
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetHeight() {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
if (mInnerFrame && !IsNonReplacedInline(mInnerFrame)) {
AssertFlushedPendingReflows();
- nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
- val->SetAppUnits(mInnerFrame->GetContentRect().height +
- adjustedValues.TopBottom());
- } else {
- SetValueToSize(val, StylePosition()->mHeight);
+ const nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
+ return AppUnitsToCSSValue(mInnerFrame->GetContentRect().height +
+ adjustedValues.TopBottom());
}
-
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToSize(val, StylePosition()->mHeight);
return val.forget();
}
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetWidth() {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
if (mInnerFrame && !IsNonReplacedInline(mInnerFrame)) {
AssertFlushedPendingReflows();
nsMargin adjustedValues = GetAdjustedValuesForBoxSizing();
- val->SetAppUnits(mInnerFrame->GetContentRect().width +
- adjustedValues.LeftRight());
- } else {
- SetValueToSize(val, StylePosition()->mWidth);
+ return AppUnitsToCSSValue(mInnerFrame->GetContentRect().width +
+ adjustedValues.LeftRight());
}
-
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+ SetValueToSize(val, StylePosition()->mWidth);
return val.forget();
}
@@ -1895,7 +1888,8 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetMinHeight() {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
StyleSize minHeight = StylePosition()->mMinHeight;
- if (minHeight.IsAuto() && !ShouldHonorMinSizeAutoInAxis(eAxisVertical)) {
+ if (minHeight.IsAuto() &&
+ !ShouldHonorMinSizeAutoInAxis(PhysicalAxis::Vertical)) {
minHeight = StyleSize::LengthPercentage(LengthPercentage::Zero());
}
@@ -1908,7 +1902,8 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetMinWidth() {
StyleSize minWidth = StylePosition()->mMinWidth;
- if (minWidth.IsAuto() && !ShouldHonorMinSizeAutoInAxis(eAxisHorizontal)) {
+ if (minWidth.IsAuto() &&
+ !ShouldHonorMinSizeAutoInAxis(PhysicalAxis::Horizontal)) {
minWidth = StyleSize::LengthPercentage(LengthPercentage::Zero());
}
@@ -1968,14 +1963,13 @@ static_assert(eSideTop == 0 && eSideRight == 1 && eSideBottom == 2 &&
already_AddRefed<CSSValue> nsComputedDOMStyle::GetNonStaticPositionOffset(
mozilla::Side aSide, bool aResolveAuto, PercentageBaseGetter aWidthGetter,
PercentageBaseGetter aHeightGetter) {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
const nsStylePosition* positionData = StylePosition();
int32_t sign = 1;
LengthPercentageOrAuto coord = positionData->mOffset.Get(aSide);
if (coord.IsAuto()) {
if (!aResolveAuto) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetString("auto");
return val.forget();
}
@@ -1983,14 +1977,12 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetNonStaticPositionOffset(
sign = -1;
}
if (!coord.IsLengthPercentage()) {
- val->SetPixels(0.0f);
- return val.forget();
+ return PixelsToCSSValue(0.0f);
}
- auto& lp = coord.AsLengthPercentage();
+ const auto& lp = coord.AsLengthPercentage();
if (lp.ConvertsToLength()) {
- val->SetPixels(sign * lp.ToLengthInCSSPixels());
- return val.forget();
+ return PixelsToCSSValue(sign * lp.ToLengthInCSSPixels());
}
PercentageBaseGetter baseGetter = (aSide == eSideLeft || aSide == eSideRight)
@@ -1998,12 +1990,10 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetNonStaticPositionOffset(
: aHeightGetter;
nscoord percentageBase;
if (!(this->*baseGetter)(percentageBase)) {
- val->SetPixels(0.0f);
- return val.forget();
+ return PixelsToCSSValue(0.0f);
}
nscoord result = lp.Resolve(percentageBase);
- val->SetAppUnits(sign * result);
- return val.forget();
+ return AppUnitsToCSSValue(sign * result);
}
already_AddRefed<CSSValue> nsComputedDOMStyle::GetAbsoluteOffset(
@@ -2013,9 +2003,7 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetAbsoluteOffset(
const auto& oppositeCoord = offset.Get(NS_OPPOSITE_SIDE(aSide));
if (coord.IsAuto() || oppositeCoord.IsAuto()) {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
- val->SetAppUnits(GetUsedAbsoluteOffset(aSide));
- return val.forget();
+ return AppUnitsToCSSValue(GetUsedAbsoluteOffset(aSide));
}
return GetNonStaticPositionOffset(
@@ -2096,23 +2084,18 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetStaticOffset(
already_AddRefed<CSSValue> nsComputedDOMStyle::GetPaddingWidthFor(
mozilla::Side aSide) {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
- auto& padding = StylePadding()->mPadding.Get(aSide);
+ const auto& padding = StylePadding()->mPadding.Get(aSide);
if (!mInnerFrame || !PaddingNeedsUsedValue(padding, *mComputedStyle)) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
SetValueToLengthPercentage(val, padding, true);
- } else {
- AssertFlushedPendingReflows();
- val->SetAppUnits(mInnerFrame->GetUsedPadding().Side(aSide));
+ return val.forget();
}
-
- return val.forget();
+ AssertFlushedPendingReflows();
+ return AppUnitsToCSSValue(mInnerFrame->GetUsedPadding().Side(aSide));
}
already_AddRefed<CSSValue> nsComputedDOMStyle::GetBorderWidthFor(
mozilla::Side aSide) {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
nscoord width;
if (mInnerFrame && mComputedStyle->StyleDisplay()->HasAppearance()) {
AssertFlushedPendingReflows();
@@ -2120,29 +2103,23 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::GetBorderWidthFor(
} else {
width = StyleBorder()->GetComputedBorderWidth(aSide);
}
- val->SetAppUnits(width);
-
- return val.forget();
+ return AppUnitsToCSSValue(width);
}
already_AddRefed<CSSValue> nsComputedDOMStyle::GetMarginFor(Side aSide) {
- RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
- auto& margin = StyleMargin()->mMargin.Get(aSide);
+ const auto& margin = StyleMargin()->mMargin.Get(aSide);
if (!mInnerFrame || margin.ConvertsToLength()) {
+ RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
SetValueToLengthPercentageOrAuto(val, margin, false);
- } else {
- AssertFlushedPendingReflows();
-
- // For tables, GetUsedMargin always returns an empty margin, so we
- // should read the margin from the table wrapper frame instead.
- val->SetAppUnits(mOuterFrame->GetUsedMargin().Side(aSide));
- NS_ASSERTION(mOuterFrame == mInnerFrame ||
- mInnerFrame->GetUsedMargin() == nsMargin(0, 0, 0, 0),
- "Inner tables must have zero margins");
+ return val.forget();
}
-
- return val.forget();
+ AssertFlushedPendingReflows();
+ // For tables, GetUsedMargin always returns an empty margin, so we
+ // should read the margin from the table wrapper frame instead.
+ NS_ASSERTION(
+ mOuterFrame == mInnerFrame || mInnerFrame->GetUsedMargin() == nsMargin(),
+ "Inner tables must have zero margins");
+ return AppUnitsToCSSValue(mOuterFrame->GetUsedMargin().Side(aSide));
}
static void SetValueToExtremumLength(nsROCSSPrimitiveValue* aValue,
@@ -2223,7 +2200,7 @@ void nsComputedDOMStyle::SetValueToLengthPercentage(
if (aClampNegativeCalc) {
length = std::max(float(length), 0.0f);
}
- return aValue->SetPixels(length);
+ return SetValueToPixels(aValue, length);
}
if (aLength.ConvertsToPercentage()) {
float result = aLength.ToPercentage();
diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h
index 4f135a3aca..14dc400418 100644
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -133,7 +133,7 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
Operation aOperation, mozilla::DeclarationBlock** aCreated) final;
virtual nsresult SetCSSDeclaration(mozilla::DeclarationBlock*,
mozilla::MutationClosureData*) override;
- virtual mozilla::dom::Document* DocToUpdate() override;
+ virtual mozilla::dom::Document* DocToUpdate() final;
nsDOMCSSDeclaration::ParsingEnvironment GetParsingEnvironment(
nsIPrincipal* aSubjectPrincipal) const final;
@@ -148,6 +148,10 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
private:
+ already_AddRefed<nsROCSSPrimitiveValue> AppUnitsToCSSValue(nscoord);
+ already_AddRefed<nsROCSSPrimitiveValue> PixelsToCSSValue(float);
+ void SetValueToPixels(nsROCSSPrimitiveValue*, float);
+
void GetPropertyValue(const nsCSSPropertyID aPropID,
const nsACString& aMaybeCustomPropertyNme,
nsACString& aValue);
diff --git a/layout/style/nsDOMCSSAttrDeclaration.h b/layout/style/nsDOMCSSAttrDeclaration.h
index ebae280bf0..b2e9154a2d 100644
--- a/layout/style/nsDOMCSSAttrDeclaration.h
+++ b/layout/style/nsDOMCSSAttrDeclaration.h
@@ -83,7 +83,7 @@ class nsDOMCSSAttributeDeclaration final : public nsDOMCSSDeclaration {
nsresult SetCSSDeclaration(
mozilla::DeclarationBlock* aDecl,
mozilla::MutationClosureData* aClosureData) override;
- mozilla::dom::Document* DocToUpdate() override;
+ mozilla::dom::Document* DocToUpdate() final;
RefPtr<Element> mElement;
diff --git a/layout/style/nsDOMCSSDeclaration.h b/layout/style/nsDOMCSSDeclaration.h
index 28810c280a..66134982a0 100644
--- a/layout/style/nsDOMCSSDeclaration.h
+++ b/layout/style/nsDOMCSSDeclaration.h
@@ -138,7 +138,7 @@ class nsDOMCSSDeclaration : public nsICSSDeclaration {
// Document that we must call BeginUpdate/EndUpdate on around the
// calls to SetCSSDeclaration and the style rule mutation that leads
// to it.
- virtual mozilla::dom::Document* DocToUpdate() = 0;
+ virtual mozilla::dom::Document* DocToUpdate() { return nullptr; }
// mUrlExtraData returns URL data for parsing url values in
// CSS. Returns nullptr on failure. If mUrlExtraData is nullptr,
diff --git a/layout/style/nsMediaFeatures.cpp b/layout/style/nsMediaFeatures.cpp
index f888c127d4..cc86d1abf6 100644
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -336,18 +336,19 @@ StyleDynamicRange Gecko_MediaFeatures_DynamicRange(const Document* aDocument) {
StyleDynamicRange Gecko_MediaFeatures_VideoDynamicRange(
const Document* aDocument) {
- if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSVideoDynamicRange)) {
+ if (aDocument->ShouldResistFingerprinting(RFPTarget::CSSVideoDynamicRange) ||
+ !StaticPrefs::layout_css_video_dynamic_range_allows_high()) {
return StyleDynamicRange::Standard;
}
// video-dynamic-range: high has 3 requirements:
// 1) high peak brightness
// 2) high contrast ratio
// 3) color depth > 24
- // We check the color depth requirement before asking the LookAndFeel
- // if it is HDR capable.
+
+ // As a proxy for those requirements, return 'High' if the screen associated
+ // with the device context claims to be HDR capable.
if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) {
- if (dx->GetDepth() > 24 &&
- LookAndFeel::GetInt(LookAndFeel::IntID::VideoDynamicRange)) {
+ if (dx->GetScreenIsHDR()) {
return StyleDynamicRange::High;
}
}
diff --git a/layout/style/nsROCSSPrimitiveValue.cpp b/layout/style/nsROCSSPrimitiveValue.cpp
index 84911d209b..3b31a14dd2 100644
--- a/layout/style/nsROCSSPrimitiveValue.cpp
+++ b/layout/style/nsROCSSPrimitiveValue.cpp
@@ -102,20 +102,12 @@ void nsROCSSPrimitiveValue::SetDegree(float aValue) {
mType = CSS_DEG;
}
-void nsROCSSPrimitiveValue::SetAppUnits(nscoord aValue) {
- SetPixels(nsPresContext::AppUnitsToFloatCSSPixels(aValue));
-}
-
void nsROCSSPrimitiveValue::SetPixels(float aValue) {
Reset();
mValue.mFloat = aValue;
mType = CSS_PX;
}
-void nsROCSSPrimitiveValue::SetAppUnits(float aValue) {
- SetAppUnits(NSToCoordRound(aValue));
-}
-
void nsROCSSPrimitiveValue::SetString(const nsACString& aString) {
Reset();
mValue.mString = ToNewUnicode(aString, mozilla::fallible);
diff --git a/layout/style/nsROCSSPrimitiveValue.h b/layout/style/nsROCSSPrimitiveValue.h
index d782a23469..79e6fd6a10 100644
--- a/layout/style/nsROCSSPrimitiveValue.h
+++ b/layout/style/nsROCSSPrimitiveValue.h
@@ -48,8 +48,6 @@ class nsROCSSPrimitiveValue final : public mozilla::dom::CSSValue {
void SetPercent(float aValue);
void SetDegree(float aValue);
void SetPixels(float aValue);
- void SetAppUnits(nscoord aValue);
- void SetAppUnits(float aValue);
void SetString(const nsACString& aString);
void SetString(const nsAString& aString);
diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp
index 39f5b1a760..94d120e378 100644
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2237,6 +2237,7 @@ static bool AppearanceValueAffectsFrames(StyleAppearance aAppearance,
// We need to reframe since this affects the spinbox creation in
// nsNumber/SearchControlFrame::CreateAnonymousContent.
return aDefaultAppearance == StyleAppearance::NumberInput ||
+ aDefaultAppearance == StyleAppearance::PasswordInput ||
aDefaultAppearance == StyleAppearance::Searchfield;
case StyleAppearance::Menulist:
// This affects the menulist button creation.
@@ -2697,12 +2698,11 @@ void nsStyleContent::TriggerImageLoads(Document& aDoc,
}
Span<const StyleContentItem> oldItems;
- if (aOld && aOld->mContent.IsItems()) {
- oldItems = aOld->mContent.AsItems().AsSpan();
+ if (aOld) {
+ oldItems = aOld->NonAltContentItems();
}
- auto items = mContent.AsItems().AsSpan();
-
+ auto items = NonAltContentItems();
for (size_t i = 0; i < items.Length(); ++i) {
const auto& item = items[i];
if (!item.IsImage()) {
@@ -3536,7 +3536,7 @@ static nscoord Resolve(const StyleContainIntrinsicSize& aSize,
}
MOZ_ASSERT(aSize.HasAuto());
if (const auto* element = Element::FromNodeOrNull(aFrame.GetContent())) {
- Maybe<float> lastSize = aAxis == eLogicalAxisBlock
+ Maybe<float> lastSize = aAxis == LogicalAxis::Block
? element->GetLastRememberedBSize()
: element->GetLastRememberedISize();
if (lastSize && aFrame.HidesContent()) {
@@ -3556,7 +3556,7 @@ Maybe<nscoord> ContainSizeAxes::ContainIntrinsicBSize(
}
const StyleContainIntrinsicSize& bSize =
aFrame.StylePosition()->ContainIntrinsicBSize(aFrame.GetWritingMode());
- return Some(Resolve(bSize, aNoneValue, aFrame, eLogicalAxisBlock));
+ return Some(Resolve(bSize, aNoneValue, aFrame, LogicalAxis::Block));
}
Maybe<nscoord> ContainSizeAxes::ContainIntrinsicISize(
@@ -3566,7 +3566,7 @@ Maybe<nscoord> ContainSizeAxes::ContainIntrinsicISize(
}
const StyleContainIntrinsicSize& iSize =
aFrame.StylePosition()->ContainIntrinsicISize(aFrame.GetWritingMode());
- return Some(Resolve(iSize, aNoneValue, aFrame, eLogicalAxisInline));
+ return Some(Resolve(iSize, aNoneValue, aFrame, LogicalAxis::Inline));
}
nsSize ContainSizeAxes::ContainSize(const nsSize& aUncontainedSize,
diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h
index 8835934eaf..efca723852 100644
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1356,17 +1356,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
return mDefaultAppearance;
case mozilla::StyleAppearance::Textfield:
// `appearance: textfield` should behave like `auto` on all elements
- // except <input type=search> elements, which we identify using the
- // internal -moz-default-appearance property. (In the browser chrome
- // we have some other elements that set `-moz-default-appearance:
- // searchfield`, but not in content documents.)
- if (mDefaultAppearance == mozilla::StyleAppearance::Searchfield) {
- return mAppearance;
- }
- // We also need to support `appearance: textfield` on <input
- // type=number>, since that is the only way in Gecko to disable the
- // spinners.
- if (mDefaultAppearance == mozilla::StyleAppearance::NumberInput) {
+ // except <input type=search/number/password> elements, which we
+ // identify using the internal -moz-default-appearance property.
+ if (mDefaultAppearance == mozilla::StyleAppearance::Searchfield ||
+ mDefaultAppearance == mozilla::StyleAppearance::NumberInput ||
+ mDefaultAppearance == mozilla::StyleAppearance::PasswordInput) {
return mAppearance;
}
return mDefaultAppearance;
@@ -1533,8 +1527,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
}
}
+ // These two methods are deprecated since they do not differentiate paginated
+ // context and multi-column context. Use nsIFrame::ShouldBreakBefore() /
+ // nsIFrame::ShouldBreakAfter() instead.
bool BreakBefore() const { return ShouldBreak(mBreakBefore); }
-
bool BreakAfter() const { return ShouldBreak(mBreakAfter); }
// These are defined in nsStyleStructInlines.h.
@@ -1607,12 +1603,22 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent {
using CounterPair = mozilla::StyleGenericCounterPair<int32_t>;
- size_t ContentCount() const {
- return mContent.IsItems() ? mContent.AsItems().Length() : 0;
+ /// Returns the content items that aren't alternative content.
+ mozilla::Span<const mozilla::StyleContentItem> NonAltContentItems() const {
+ if (!mContent.IsItems()) {
+ return {};
+ }
+ const auto& items = mContent.AsItems();
+ return mozilla::Span(items.items).To(items.alt_start);
}
- const mozilla::StyleContentItem& ContentAt(size_t aIndex) const {
- return mContent.AsItems().AsSpan()[aIndex];
+ /// Returns the content items that /are/ alternative content.
+ mozilla::Span<const mozilla::StyleContentItem> AltContentItems() const {
+ if (!mContent.IsItems()) {
+ return {};
+ }
+ const auto& items = mContent.AsItems();
+ return mozilla::Span(items.items).From(items.alt_start);
}
mozilla::StyleContent mContent;
@@ -2058,35 +2064,4 @@ struct UniquePtr_Simple {
STATIC_ASSERT_TYPE_LAYOUTS_MATCH(mozilla::UniquePtr<int>,
UniquePtr_Simple<int>);
-/**
- * <div rustbindgen replaces="nsTArray"></div>
- */
-template <typename T>
-class nsTArray_Simple {
- protected:
- T* mBuffer;
-
- public:
- ~nsTArray_Simple() {
- // The existence of a user-provided, and therefore non-trivial, destructor
- // here prevents bindgen from deriving the Clone trait via a simple memory
- // copy.
- }
-};
-
-/**
- * <div rustbindgen replaces="CopyableTArray"></div>
- */
-template <typename T>
-class CopyableTArray_Simple : public nsTArray_Simple<T> {};
-
-STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<nsStyleImageLayers::Layer>,
- nsTArray_Simple<nsStyleImageLayers::Layer>);
-STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<mozilla::StyleTransition>,
- nsTArray_Simple<mozilla::StyleTransition>);
-STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<mozilla::StyleAnimation>,
- nsTArray_Simple<mozilla::StyleAnimation>);
-STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<mozilla::StyleViewTimeline>,
- nsTArray_Simple<mozilla::StyleViewTimeline>);
-
#endif /* nsStyleStruct_h___ */
diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css
index 587534e9f3..7a5c25fc6e 100644
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -73,6 +73,8 @@ fieldset {
label {
cursor: default;
+ /* If you add declarations here, consider whether the select > label and file
+ * input label need them as well. */
}
/* Default inputs, text inputs, and selects */
@@ -190,6 +192,10 @@ input::-moz-text-control-preview {
line-height: -moz-block-height !important;
}
+input[type=password] {
+ -moz-default-appearance: password-input;
+}
+
input[type=password]::-moz-text-control-editing-root,
input[type=password]::-moz-text-control-preview {
/*
@@ -281,6 +287,7 @@ select > button {
select > label {
display: inline-block;
overflow: clip;
+ cursor: unset;
}
option[label]::before {
@@ -627,10 +634,7 @@ input[type=file] > label {
min-inline-size: 12em;
text-align: match-parent;
- color: unset;
- font-size: unset;
- letter-spacing: unset;
-
+ cursor: unset;
user-select: none;
unicode-bidi: plaintext;
}
@@ -838,7 +842,6 @@ input[type=range]::slider-thumb {
}
input[type=number] {
- appearance: auto;
-moz-default-appearance: number-input;
}
diff --git a/layout/style/res/html.css b/layout/style/res/html.css
index ff58ecd4d1..769ebece45 100644
--- a/layout/style/res/html.css
+++ b/layout/style/res/html.css
@@ -136,7 +136,7 @@ body {
margin: 8px;
}
-p, dl, multicol {
+p, dl {
display: block;
margin-block-start: 1em;
margin-block-end: 1em;
@@ -765,7 +765,7 @@ video > .caption-box {
* The pseudo element won't inherit CSS styles from its direct parent, `::cue`
* would actually inherit styles from video because it's video's pseudo element.
* Therefore, we have to explicitly set some styles which are already defined
- * in its parent element in vtt.jsm.
+ * in its parent element in vtt.sys.mjs.
*/
::cue {
color: rgba(255, 255, 255, 1);
@@ -816,15 +816,21 @@ dialog::backdrop {
background: rgba(0, 0, 0, 0.1);
}
+/* https://html.spec.whatwg.org/#the-marquee-element-2 */
marquee {
- inline-size: -moz-available;
display: inline-block;
+ text-align: initial;
+ overflow: hidden !important;
+
+ /* See https://github.com/whatwg/html/issues/10249 */
+ inline-size: -moz-available;
vertical-align: text-bottom;
- text-align: start;
+ white-space: nowrap;
}
marquee:is([direction="up"], [direction="down"]) {
block-size: 200px;
+ white-space: unset;
}
/* Ruby */
diff --git a/layout/style/res/quirk.css b/layout/style/res/quirk.css
index 6e74839ee3..0379033515 100644
--- a/layout/style/res/quirk.css
+++ b/layout/style/res/quirk.css
@@ -59,7 +59,7 @@ table {
* selectors will be hashed in the selector maps and things will be much more
* efficient.
*/
-:is(body, td, th) > :is(p, dl, multicol, blockquote, h1, h2, h3, h4, h5, h6, listing, plaintext, xmp, pre, ul, menu, dir, ol):-moz-first-node {
+:is(body, td, th) > :is(p, dl, blockquote, h1, h2, h3, h4, h5, h6, listing, plaintext, xmp, pre, ul, menu, dir, ol):-moz-first-node {
margin-block-start: 0;
}
@@ -71,11 +71,11 @@ td > p:-moz-last-node, th > p:-moz-last-node {
* collapse the bottom or top margins of empty elements
* - see bug 97361
*/
-:is(body, td, th) > :is(p, dl, multicol, blockquote, h1, h2, h3, h4, h5, h6, listing, plaintext, xmp, pre, ul, menu, dir, ol):-moz-only-whitespace:-moz-first-node {
+:is(body, td, th) > :is(p, dl, blockquote, h1, h2, h3, h4, h5, h6, listing, plaintext, xmp, pre, ul, menu, dir, ol):-moz-only-whitespace:-moz-first-node {
margin-block-end: 0;
}
-:is(td, th) > :is(p, dl, multicol, blockquote, h1, h2, h3, h4, h5, h6, listing, plaintext, xmp, pre, ul, menu, dir, ol):-moz-only-whitespace:-moz-last-node {
+:is(td, th) > :is(p, dl, blockquote, h1, h2, h3, h4, h5, h6, listing, plaintext, xmp, pre, ul, menu, dir, ol):-moz-only-whitespace:-moz-last-node {
margin-block-start: 0;
}
diff --git a/layout/style/test/chrome/chrome-only-media-queries.js b/layout/style/test/chrome/chrome-only-media-queries.js
index aaf313a526..d17976149b 100644
--- a/layout/style/test/chrome/chrome-only-media-queries.js
+++ b/layout/style/test/chrome/chrome-only-media-queries.js
@@ -31,4 +31,5 @@ const CHROME_ONLY_QUERIES = [
"(-moz-gtk-theme-family: adwaita)",
"(-moz-gtk-theme-family: breeze)",
"(-moz-gtk-theme-family: yaru)",
+ "(forced-colors: requested)",
];
diff --git a/layout/style/test/mochitest.toml b/layout/style/test/mochitest.toml
index 54ad9736f2..cc5f26708f 100644
--- a/layout/style/test/mochitest.toml
+++ b/layout/style/test/mochitest.toml
@@ -6,16 +6,13 @@ prefs = [
"gfx.font_loader.delay=0",
"layout.css.container-queries.enabled=true",
"layout.css.individual-transform.enabled=true",
- "layout.css.motion-path-ray.enabled=true",
- "layout.css.motion-path-basic-shapes.enabled=true",
- "layout.css.motion-path-coord-box.enabled=true",
- "layout.css.motion-path-offset-position.enabled=true",
"layout.css.motion-path-url.enabled=true",
"layout.css.backdrop-filter.enabled=true",
"layout.css.fit-content-function.enabled=true",
"layout.css.scroll-driven-animations.enabled=true",
"layout.css.animation-composition.enabled=true",
"layout.css.basic-shape-rect.enabled=true",
+ "layout.css.basic-shape-shape.enabled=true",
"layout.css.basic-shape-xywh.enabled=true",
"layout.css.transform-box-content-stroke.enabled=true",
"layout.css.transition-behavior.enabled=true",
diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js
index 2e8b4c71a3..302bd48b42 100644
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -1035,6 +1035,36 @@ if (IsCSSPropertyPrefEnabled("layout.css.basic-shape-rect.enabled")) {
);
}
+var basicShapeShapeValues = [];
+var basicShapeShapeValuesWithFillRule = [];
+if (IsCSSPropertyPrefEnabled("layout.css.basic-shape-shape.enabled")) {
+ basicShapeShapeValuesWithFillRule.push(
+ "shape(evenodd from 0px 0px, line to 10px 10px)",
+ "shape(nonzero from 0px 0px, line to 10px 10px)"
+ );
+
+ basicShapeShapeValues.push(
+ "shape(from 0px 0%, line to 10px 10%)",
+ "shape(from 10px 10px, move by 10px 5px, line by 20px 40%, close)",
+ "shape(from 10px 10px, hline by 10px, vline to 5rem)",
+ "shape(from 10px 10px, vline by 5%, hline to 1vw)",
+ "shape(from 10px 10px, curve to 50px 20px via 10rem 1%)",
+ "shape(from 10px 10px, smooth to 50px 20px via 10rem 1%)",
+ "shape(from 10% 1rem, arc to 50px 1pt of 20% cw large rotate 25deg)"
+ );
+
+ // It's fine to include this for properties which don't support shape(),
+ // e.g. shape-outside, because they must reject these values.
+ basicShapeInvalidValues.push(
+ "shape()",
+ "shape(evenodd, from 0px 0px)",
+ "shape(from 0px 0px line to 10px 10px)",
+ "shape(from 0px 0px)",
+ "shape(close)",
+ "shape(nonzero, close)"
+ );
+}
+
if (/* mozGradientsEnabled */ true) {
// Maybe one day :(
// Extend gradient lists with valid/invalid moz-prefixed expressions:
@@ -5352,7 +5382,6 @@ var gCSSProperties = {
"counter(\\()",
"counters(a\\+b, '.')",
"counter(\\}, upper-alpha)",
- "-moz-alt-content",
"counter(foo, symbols('*'))",
"counter(foo, symbols(numeric '0' '1'))",
"counters(foo, '.', symbols('*'))",
@@ -5370,6 +5399,7 @@ var gCSSProperties = {
"attr(-2)",
"counter(2)",
"counters(-2, '.')",
+ "-moz-alt-content",
"-moz-alt-content 'foo'",
"'foo' -moz-alt-content",
"counter(one, two, three) 'foo'",
@@ -6841,6 +6871,130 @@ var gCSSProperties = {
"left 10px top",
],
},
+ offset: {
+ domProp: "offset",
+ inherited: false,
+ type: CSS_TYPE_TRUE_SHORTHAND,
+ subproperties: [
+ "offset-path",
+ "offset-distance",
+ "offset-rotate",
+ "offset-anchor",
+ "offset-position",
+ ],
+ initial_values: ["none"],
+ other_values: [
+ "none 30deg reverse",
+ "none 50px reverse 30deg",
+ "none calc(10px + 20%) auto",
+ "none reverse",
+ "none / left center",
+ "path('M 0 0 H 1') -200% auto",
+ "path('M 0 0 H 1') -200%",
+ "path('M 0 0 H 1') 50px",
+ "path('M 0 0 H 1') auto",
+ "path('M 0 0 H 1') reverse 30deg 50px",
+ "path('M 0 0 H 1')",
+ "path('m 20 0 h 100') -7rad 8px / auto",
+ "path('m 0 30 v 100') -7rad 8px / left top",
+ "path('m 0 0 h 100') -7rad 8px",
+ "path('M 0 0 H 100') 100px 0deg",
+ "top right / top left",
+ "top right ray(45deg closest-side)",
+ "50% 50% ray(0rad farthest-side)",
+ ],
+ invalid_values: [
+ "100px 0deg path('m 0 0 h 100')",
+ "30deg",
+ "auto 30deg 100px",
+ "auto / none",
+ "none /",
+ "none / 100px 20px 30deg",
+ "path('M 20 30 A 60 70 80') bottom",
+ "path('M 20 30 A 60 70 80') bottom top",
+ "path('M 20 30 A 60 70 80') 100px 200px",
+ "path('M 20 30 A 60 70 80') reverse auto",
+ "path('M 20 30 A 60 70 80') reverse 10px 30deg",
+ "path('M 20 30 A 60 70 80') /",
+ ],
+ },
+ "offset-anchor": {
+ domProp: "offsetAnchor",
+ inherited: false,
+ type: CSS_TYPE_LONGHAND,
+ initial_values: ["auto"],
+ other_values: [
+ "left bottom",
+ "center center",
+ "calc(20% + 10px) center",
+ "right 30em",
+ "10px 20%",
+ "left -10px top -20%",
+ "right 10% bottom 20em",
+ ],
+ invalid_values: ["none", "10deg", "left 10% top"],
+ },
+ "offset-distance": {
+ domProp: "offsetDistance",
+ inherited: false,
+ type: CSS_TYPE_LONGHAND,
+ initial_values: ["0"],
+ other_values: ["10px", "10%", "190%", "-280%", "calc(30px + 40%)"],
+ invalid_values: ["none", "45deg"],
+ },
+ "offset-path": {
+ domProp: "offsetPath",
+ inherited: false,
+ type: CSS_TYPE_LONGHAND,
+ initial_values: ["none"],
+ other_values: [
+ "ray(0deg)",
+ "ray(45deg closest-side)",
+ "ray(0rad farthest-side)",
+ "ray(0.5turn closest-corner contain)",
+ "ray(200grad farthest-corner)",
+ "ray(sides 180deg)",
+ "ray(contain farthest-side 180deg)",
+ "ray(calc(180deg - 45deg) farthest-side)",
+ "ray(0deg at center center)",
+ "ray(at 10% 10% 1rad)",
+ ]
+ .concat(pathValues.other_values)
+ .concat(basicShapeOtherValues)
+ .concat(basicShapeXywhRectValues)
+ .concat(basicShapeShapeValues),
+ invalid_values: [
+ "path('')",
+ "ray(closest-side)",
+ "ray(0deg, closest-side)",
+ "ray(contain 0deg closest-side contain)",
+ ].concat(pathValues.invalid_values),
+ },
+ "offset-position": {
+ domProp: "offsetPosition",
+ inherited: false,
+ type: CSS_TYPE_LONGHAND,
+ initial_values: ["normal"],
+ other_values: [
+ "auto",
+ "left bottom",
+ "center center",
+ "calc(20% + 10px) center",
+ "right 30em",
+ "10px 20%",
+ "left -10px top -20%",
+ "right 10% bottom 20em",
+ ],
+ invalid_values: ["none", "10deg", "left 10% top"],
+ },
+ "offset-rotate": {
+ domProp: "offsetRotate",
+ inherited: false,
+ type: CSS_TYPE_LONGHAND,
+ initial_values: ["auto"],
+ other_values: ["reverse", "0deg", "0rad reverse", "-45deg", "5turn auto"],
+ invalid_values: ["none", "10px", "reverse 0deg reverse", "reverse auto"],
+ },
opacity: {
domProp: "opacity",
inherited: false,
@@ -8827,7 +8981,9 @@ var gCSSProperties = {
.concat(basicShapeSVGBoxValues)
.concat(basicShapeOtherValues)
.concat(basicShapeOtherValuesWithFillRule)
- .concat(basicShapeXywhRectValues),
+ .concat(basicShapeXywhRectValues)
+ .concat(basicShapeShapeValues)
+ .concat(basicShapeShapeValuesWithFillRule),
invalid_values: [
"path(nonzero)",
"path(abs, 'M 10 10 L 10 10 z')",
@@ -13409,158 +13565,10 @@ gCSSProperties["scrollbar-width"] = {
invalid_values: ["1px"],
};
-gCSSProperties["offset"] = {
- domProp: "offset",
- inherited: false,
- type: CSS_TYPE_TRUE_SHORTHAND,
- subproperties: [
- "offset-path",
- "offset-distance",
- "offset-rotate",
- "offset-anchor",
- ],
- initial_values: ["none"],
- other_values: [
- "none 30deg reverse",
- "none 50px reverse 30deg",
- "none calc(10px + 20%) auto",
- "none reverse",
- "none / left center",
- "path('M 0 0 H 1') -200% auto",
- "path('M 0 0 H 1') -200%",
- "path('M 0 0 H 1') 50px",
- "path('M 0 0 H 1') auto",
- "path('M 0 0 H 1') reverse 30deg 50px",
- "path('M 0 0 H 1')",
- "path('m 20 0 h 100') -7rad 8px / auto",
- "path('m 0 30 v 100') -7rad 8px / left top",
- "path('m 0 0 h 100') -7rad 8px",
- "path('M 0 0 H 100') 100px 0deg",
- ],
- invalid_values: [
- "100px 0deg path('m 0 0 h 100')",
- "30deg",
- "auto 30deg 100px",
- "auto / none",
- "none /",
- "none / 100px 20px 30deg",
- "path('M 20 30 A 60 70 80') bottom",
- "path('M 20 30 A 60 70 80') bottom top",
- "path('M 20 30 A 60 70 80') 100px 200px",
- "path('M 20 30 A 60 70 80') reverse auto",
- "path('M 20 30 A 60 70 80') reverse 10px 30deg",
- "path('M 20 30 A 60 70 80') /",
- ],
-};
-
-gCSSProperties["offset-path"] = {
- domProp: "offsetPath",
- inherited: false,
- type: CSS_TYPE_LONGHAND,
- initial_values: ["none"],
- other_values: [...pathValues.other_values],
- invalid_values: ["path('')"].concat(pathValues.invalid_values),
-};
-
-if (IsCSSPropertyPrefEnabled("layout.css.motion-path-ray.enabled")) {
- gCSSProperties["offset-path"]["other_values"].push(
- "ray(0deg)",
- "ray(45deg closest-side)",
- "ray(0rad farthest-side)",
- "ray(0.5turn closest-corner contain)",
- "ray(200grad farthest-corner)",
- "ray(sides 180deg)",
- "ray(contain farthest-side 180deg)",
- "ray(calc(180deg - 45deg) farthest-side)",
- "ray(0deg at center center)",
- "ray(at 10% 10% 1rad)"
- );
-
- gCSSProperties["offset-path"]["invalid_values"].push(
- "ray(closest-side)",
- "ray(0deg, closest-side)",
- "ray(contain 0deg closest-side contain)"
- );
-}
-
-if (IsCSSPropertyPrefEnabled("layout.css.motion-path-basic-shapes.enabled")) {
- gCSSProperties["offset-path"]["other_values"].push(
- ...basicShapeOtherValues,
- ...basicShapeXywhRectValues
- );
-}
-
if (IsCSSPropertyPrefEnabled("layout.css.motion-path-url.enabled")) {
gCSSProperties["offset-path"]["other_values"].push("url(#svgPath)");
}
-gCSSProperties["offset-distance"] = {
- domProp: "offsetDistance",
- inherited: false,
- type: CSS_TYPE_LONGHAND,
- initial_values: ["0"],
- other_values: ["10px", "10%", "190%", "-280%", "calc(30px + 40%)"],
- invalid_values: ["none", "45deg"],
-};
-
-gCSSProperties["offset-rotate"] = {
- domProp: "offsetRotate",
- inherited: false,
- type: CSS_TYPE_LONGHAND,
- initial_values: ["auto"],
- other_values: ["reverse", "0deg", "0rad reverse", "-45deg", "5turn auto"],
- invalid_values: ["none", "10px", "reverse 0deg reverse", "reverse auto"],
-};
-
-gCSSProperties["offset-anchor"] = {
- domProp: "offsetAnchor",
- inherited: false,
- type: CSS_TYPE_LONGHAND,
- initial_values: ["auto"],
- other_values: [
- "left bottom",
- "center center",
- "calc(20% + 10px) center",
- "right 30em",
- "10px 20%",
- "left -10px top -20%",
- "right 10% bottom 20em",
- ],
- invalid_values: ["none", "10deg", "left 10% top"],
-};
-
-if (
- IsCSSPropertyPrefEnabled("layout.css.motion-path-offset-position.enabled")
-) {
- gCSSProperties["offset"]["subproperties"].push("offset-position");
- gCSSProperties["offset"]["other_values"].push("top right / top left");
-
- if (IsCSSPropertyPrefEnabled("layout.css.motion-path-ray.enabled")) {
- gCSSProperties["offset"]["other_values"].push(
- "top right ray(45deg closest-side)",
- "50% 50% ray(0rad farthest-side)"
- );
- }
-
- gCSSProperties["offset-position"] = {
- domProp: "offsetPosition",
- inherited: false,
- type: CSS_TYPE_LONGHAND,
- initial_values: ["normal"],
- other_values: [
- "auto",
- "left bottom",
- "center center",
- "calc(20% + 10px) center",
- "right 30em",
- "10px 20%",
- "left -10px top -20%",
- "right 10% bottom 20em",
- ],
- invalid_values: ["none", "10deg", "left 10% top"],
- };
-}
-
{
let linear_function_other_values = [
"linear(0, 1)",
diff --git a/layout/style/test/test_hover_quirk.html b/layout/style/test/test_hover_quirk.html
index 61e19f2a60..7a78185178 100644
--- a/layout/style/test/test_hover_quirk.html
+++ b/layout/style/test/test_hover_quirk.html
@@ -54,6 +54,18 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783213
#dynamic-test:hover > * {
background: rgb(0, 255, 0);
}
+
+ #dynamic-test-2 :is(button,input,a){
+ background-color:yellow !important;
+ }
+
+ #dynamic-test-2 :is(button,input,a):hover{
+ background-color:lime !important;
+ }
+
+ #dynamic-test-2 :is(button,input):focus{
+ background-color:skyblue !important;
+ }
</style>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
@@ -97,6 +109,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783213
is(getComputedStyle(document.getElementById('should-be-green-on-hover')).backgroundColor,
"rgb(0, 255, 0)",
"Dynamic change should invalidate properly");
+
+ synthesizeMouseAtCenter(document.getElementById('button'), {type: "mousemove"});
+ is(getComputedStyle(document.getElementById('button')).backgroundColor,
+ "rgb(0, 255, 0)",
+ "Button hover should be green");
+
+ synthesizeMouseAtCenter(document.getElementById('input'), {type: "mousemove"});
+ is(getComputedStyle(document.getElementById('input')).backgroundColor,
+ "rgb(0, 255, 0)",
+ "Input hover should be green");
+
+ synthesizeMouseAtCenter(document.getElementById('link-2'), {type: "mousemove"});
+ is(getComputedStyle(document.getElementById('link-2')).backgroundColor,
+ "rgb(0, 255, 0)",
+ "Link hover should be green");
SimpleTest.finish();
});
</script>
@@ -113,6 +140,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=783213
<a id="link" href="#">Link<span class="child"></span></a><br>
<div id="div" class="parent">Div <span><span class="child"></span></span></div><br>
</div>
+ <div id="dynamic-test-2">
+ <button id="button">Button</button>
+ <input id="input" value="Input">
+ <a id="link-2"href="">Link</a>
+ </div>
<pre id="test"></pre>
</body>
</html>
diff --git a/layout/style/test/test_non_content_accessible_pseudos.html b/layout/style/test/test_non_content_accessible_pseudos.html
index 81493b1a4a..5f2d15d6a2 100644
--- a/layout/style/test/test_non_content_accessible_pseudos.html
+++ b/layout/style/test/test_non_content_accessible_pseudos.html
@@ -30,7 +30,6 @@ const NON_CONTENT_ACCESIBLE_PSEUDOS = [
":-moz-dir-attr-rtl",
":-moz-dir-attr-like-auto",
":-moz-autofill-preview",
- ":-moz-lwtheme",
":-moz-is-html",
":-moz-locale-dir(rtl)",
":-moz-locale-dir(ltr)",
diff --git a/layout/style/test/test_selectors.html b/layout/style/test/test_selectors.html
index d688139d3c..684e9d6524 100644
--- a/layout/style/test/test_selectors.html
+++ b/layout/style/test/test_selectors.html
@@ -1077,7 +1077,6 @@ function runTests() {
test_balanced_unparseable(":dir");
// Test chrome-only -moz-lwtheme
- test_balanced_unparseable(":-moz-lwtheme");
test_balanced_unparseable(":-moz-broken");
test_balanced_unparseable(":-moz-tree-row(selected)");
diff --git a/layout/style/test/test_style_struct_copy_constructors.html b/layout/style/test/test_style_struct_copy_constructors.html
index 95f727a58d..bce5a4e32c 100644
--- a/layout/style/test/test_style_struct_copy_constructors.html
+++ b/layout/style/test/test_style_struct_copy_constructors.html
@@ -64,6 +64,12 @@ for (var prop in gCSSProperties) {
}
/** Test using inheritance **/
+
+// TODO(bug 1887221): Zoom right now doesn't apply to explicitly inherited
+// values, so remove it to get consistent results.
+gRule1.style.removeProperty("zoom");
+gRule2.style.removeProperty("zoom");
+
for (var prop in gCSSProperties) {
var info = gCSSProperties[prop];
if (info.inherited && !("subproperties" in info)) {
@@ -79,14 +85,6 @@ for (var prop in gCSSProperties) {
}
}
-for (var prop in gCSSProperties) {
- var info = gCSSProperties[prop];
- if (!("subproperties" in info)) {
- gRule1.style.removeProperty(prop);
- gRule2.style.removeProperty(prop);
- }
-}
-
</script>
</pre>
</body>
diff --git a/layout/svg/CSSClipPathInstance.cpp b/layout/svg/CSSClipPathInstance.cpp
index 77bde2bb54..a8e0306d3e 100644
--- a/layout/svg/CSSClipPathInstance.cpp
+++ b/layout/svg/CSSClipPathInstance.cpp
@@ -66,7 +66,7 @@ bool CSSClipPathInstance::HitTestBasicShapeOrPathClip(nsIFrame* aFrame,
RefPtr<Path> path = instance.CreateClipPath(
drawTarget, SVGUtils::GetCSSPxToDevPxMatrix(aFrame));
float pixelRatio = float(AppUnitsPerCSSPixel()) /
- aFrame->PresContext()->AppUnitsPerDevPixel();
+ float(aFrame->PresContext()->AppUnitsPerDevPixel());
return path && path->ContainsPoint(ToPoint(aPoint) * pixelRatio, Matrix());
}
@@ -121,8 +121,10 @@ already_AddRefed<Path> CSSClipPathInstance::CreateClipPath(
return CreateClipPathPolygon(aDrawTarget, r);
case StyleBasicShape::Tag::Rect:
return CreateClipPathInset(aDrawTarget, r);
- case StyleBasicShape::Tag::Path:
- return CreateClipPathPath(aDrawTarget, r);
+ case StyleBasicShape::Tag::PathOrShape:
+ return basicShape.AsPathOrShape().IsPath()
+ ? CreateClipPathPath(aDrawTarget, r)
+ : CreateClipPathShape(aDrawTarget, r);
default:
MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unexpected shape type");
}
@@ -175,18 +177,41 @@ already_AddRefed<Path> CSSClipPathInstance::CreateClipPathInset(
already_AddRefed<Path> CSSClipPathInstance::CreateClipPathPath(
DrawTarget* aDrawTarget, const nsRect& aRefBox) {
- const auto& path = mClipPathStyle.AsShape()._0->AsPath();
+ const auto& path = mClipPathStyle.AsShape()._0->AsPathOrShape().AsPath();
RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(
path.fill == StyleFillRule::Nonzero ? FillRule::FILL_WINDING
: FillRule::FILL_EVEN_ODD);
- nscoord appUnitsPerDevPixel =
+ const nscoord appUnitsPerDevPixel =
mTargetFrame->PresContext()->AppUnitsPerDevPixel();
- float scale = float(AppUnitsPerCSSPixel()) / appUnitsPerDevPixel;
- Point offset = Point(aRefBox.x, aRefBox.y) / appUnitsPerDevPixel;
-
+ const Point offset =
+ LayoutDevicePoint::FromAppUnits(aRefBox.TopLeft(), appUnitsPerDevPixel)
+ .ToUnknownPoint();
+ const float scale = mTargetFrame->Style()->EffectiveZoom().Zoom(
+ float(AppUnitsPerCSSPixel()) / float(appUnitsPerDevPixel));
return SVGPathData::BuildPath(path.path._0.AsSpan(), builder,
- StyleStrokeLinecap::Butt, 0.0, offset, scale);
+ StyleStrokeLinecap::Butt, 0.0, {}, offset,
+ scale);
+}
+
+already_AddRefed<Path> CSSClipPathInstance::CreateClipPathShape(
+ DrawTarget* aDrawTarget, const nsRect& aRefBox) {
+ const auto& shape = mClipPathStyle.AsShape()._0->AsPathOrShape().AsShape();
+
+ RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder(
+ shape.fill == StyleFillRule::Nonzero ? FillRule::FILL_WINDING
+ : FillRule::FILL_EVEN_ODD);
+ const nscoord appUnitsPerDevPixel =
+ mTargetFrame->PresContext()->AppUnitsPerDevPixel();
+ const CSSSize basis = CSSSize::FromAppUnits(aRefBox.Size());
+ const Point offset =
+ LayoutDevicePoint::FromAppUnits(aRefBox.TopLeft(), appUnitsPerDevPixel)
+ .ToUnknownPoint();
+ const float scale = mTargetFrame->Style()->EffectiveZoom().Zoom(
+ float(AppUnitsPerCSSPixel()) / float(appUnitsPerDevPixel));
+ return SVGPathData::BuildPath(shape.commands.AsSpan(), builder,
+ StyleStrokeLinecap::Butt, 0.0, basis, offset,
+ scale);
}
} // namespace mozilla
diff --git a/layout/svg/CSSClipPathInstance.h b/layout/svg/CSSClipPathInstance.h
index 2d1e16c62f..2cec8c125f 100644
--- a/layout/svg/CSSClipPathInstance.h
+++ b/layout/svg/CSSClipPathInstance.h
@@ -58,6 +58,9 @@ class MOZ_STACK_CLASS CSSClipPathInstance {
already_AddRefed<Path> CreateClipPathPath(DrawTarget* aDrawTarget,
const nsRect& aRefBox);
+ already_AddRefed<Path> CreateClipPathShape(DrawTarget* aDrawTarget,
+ const nsRect& aRefBox);
+
/**
* The frame for the element that is currently being clipped.
*/
diff --git a/layout/svg/SVGAFrame.cpp b/layout/svg/SVGAFrame.cpp
index 02ff68d7e7..3d09cdc3f5 100644
--- a/layout/svg/SVGAFrame.cpp
+++ b/layout/svg/SVGAFrame.cpp
@@ -82,20 +82,6 @@ nsresult SVGAFrame::AttributeChanged(int32_t aNameSpaceID, nsAtom* aAttribute,
NotifySVGChanged(TRANSFORM_CHANGED);
}
- // Currently our SMIL implementation does not modify the DOM attributes. Once
- // we implement the SVG 2 SMIL behaviour this can be removed
- // SVGAElement::SetAttr/UnsetAttr's ResetLinkState() call will be sufficient.
- if (aModType == dom::MutationEvent_Binding::SMIL &&
- aAttribute == nsGkAtoms::href &&
- (aNameSpaceID == kNameSpaceID_None ||
- aNameSpaceID == kNameSpaceID_XLink)) {
- auto* content = static_cast<dom::SVGAElement*>(GetContent());
-
- // SMIL may change whether an <a> element is a link, in which case we will
- // need to update the link state.
- content->ResetLinkState(true, content->ElementHasHref());
- }
-
return NS_OK;
}
diff --git a/layout/svg/SVGContextPaint.cpp b/layout/svg/SVGContextPaint.cpp
index 0d7a610df9..e135ea2db3 100644
--- a/layout/svg/SVGContextPaint.cpp
+++ b/layout/svg/SVGContextPaint.cpp
@@ -80,7 +80,7 @@ bool SVGContextPaint::IsAllowedForImageFromURI(nsIURI* aURI) {
// Only allowed for extensions that have the
// internal:svgContextPropertiesAllowed permission (added internally from
// to Mozilla-owned extensions, see `isMozillaExtension` function
- // defined in Extension.jsm for the exact criteria).
+ // defined in Extension.sys.mjs for the exact criteria).
return addonPolicy->HasPermission(
nsGkAtoms::svgContextPropertiesAllowedPermission);
}
diff --git a/layout/svg/SVGFEImageFrame.cpp b/layout/svg/SVGFEImageFrame.cpp
index 50fb42cd68..d89ed566f1 100644
--- a/layout/svg/SVGFEImageFrame.cpp
+++ b/layout/svg/SVGFEImageFrame.cpp
@@ -121,24 +121,6 @@ nsresult SVGFEImageFrame::AttributeChanged(int32_t aNameSpaceID,
SVGObserverUtils::InvalidateRenderingObservers(GetParent());
}
- // Currently our SMIL implementation does not modify the DOM attributes. Once
- // we implement the SVG 2 SMIL behaviour this can be removed
- // SVGFEImageElement::AfterSetAttr's implementation will be sufficient.
- if (aModType == MutationEvent_Binding::SMIL &&
- aAttribute == nsGkAtoms::href &&
- (aNameSpaceID == kNameSpaceID_XLink ||
- aNameSpaceID == kNameSpaceID_None)) {
- bool hrefIsSet =
- element->mStringAttributes[SVGFEImageElement::HREF].IsExplicitlySet() ||
- element->mStringAttributes[SVGFEImageElement::XLINK_HREF]
- .IsExplicitlySet();
- if (hrefIsSet) {
- element->LoadSVGImage(true, true);
- } else {
- element->CancelImageRequests(true);
- }
- }
-
return nsIFrame::AttributeChanged(aNameSpaceID, aAttribute, aModType);
}
diff --git a/layout/svg/SVGGeometryFrame.cpp b/layout/svg/SVGGeometryFrame.cpp
index 3d6d6aef7e..0e00d60a31 100644
--- a/layout/svg/SVGGeometryFrame.cpp
+++ b/layout/svg/SVGGeometryFrame.cpp
@@ -114,6 +114,7 @@ void SVGGeometryFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
if (element->IsGeometryChangedViaCSS(*Style(), *aOldComputedStyle)) {
element->ClearAnyCachedPath();
+ SVGObserverUtils::InvalidateRenderingObservers(this);
}
}
@@ -772,7 +773,12 @@ bool SVGGeometryFrame::CreateWebRenderCommands(
// At the moment this code path doesn't support strokes so it fine to
// combine the rectangle's opacity (which has to be applied on the result)
// of (filling + stroking) with the fill opacity.
- float elemOpacity = StyleEffects()->mOpacity;
+
+ float elemOpacity = 1.0f;
+ if (SVGUtils::CanOptimizeOpacity(this)) {
+ elemOpacity = StyleEffects()->mOpacity;
+ }
+
float fillOpacity = SVGUtils::GetOpacity(style->mFillOpacity, contextPaint);
float opacity = elemOpacity * fillOpacity;
diff --git a/layout/svg/SVGGradientFrame.cpp b/layout/svg/SVGGradientFrame.cpp
index 92558cefcd..be6f395cda 100644
--- a/layout/svg/SVGGradientFrame.cpp
+++ b/layout/svg/SVGGradientFrame.cpp
@@ -244,8 +244,10 @@ class MOZ_STACK_CLASS SVGColorStopInterpolator
public:
SVGColorStopInterpolator(
gfxPattern* aGradient, const nsTArray<ColorStop>& aStops,
- const StyleColorInterpolationMethod& aStyleColorInterpolationMethod)
- : ColorStopInterpolator(aStops, aStyleColorInterpolationMethod),
+ const StyleColorInterpolationMethod& aStyleColorInterpolationMethod,
+ bool aExtendLastStop)
+ : ColorStopInterpolator(aStops, aStyleColorInterpolationMethod,
+ aExtendLastStop),
mGradient(aGradient) {}
void CreateStop(float aPosition, DeviceColor aColor) {
@@ -327,7 +329,8 @@ already_AddRefed<gfxPattern> SVGGradientFrame::GetPaintServerPattern(
if (StyleSVG()->mColorInterpolation == StyleColorInterpolation::Linearrgb) {
static constexpr auto interpolationMethod = StyleColorInterpolationMethod{
StyleColorSpace::SrgbLinear, StyleHueInterpolationMethod::Shorter};
- SVGColorStopInterpolator interpolator(gradient, stops, interpolationMethod);
+ SVGColorStopInterpolator interpolator(gradient, stops, interpolationMethod,
+ false);
interpolator.CreateStops();
} else {
// setup standard sRGB stops
diff --git a/layout/svg/SVGImageFrame.cpp b/layout/svg/SVGImageFrame.cpp
index 242ee6e25e..35693e87c0 100644
--- a/layout/svg/SVGImageFrame.cpp
+++ b/layout/svg/SVGImageFrame.cpp
@@ -191,26 +191,6 @@ nsresult SVGImageFrame::AttributeChanged(int32_t aNameSpaceID,
}
}
- // Currently our SMIL implementation does not modify the DOM attributes. Once
- // we implement the SVG 2 SMIL behaviour this can be removed
- // SVGImageElement::AfterSetAttr's implementation will be sufficient.
- if (aModType == MutationEvent_Binding::SMIL &&
- aAttribute == nsGkAtoms::href &&
- (aNameSpaceID == kNameSpaceID_XLink ||
- aNameSpaceID == kNameSpaceID_None)) {
- SVGImageElement* element = static_cast<SVGImageElement*>(GetContent());
-
- bool hrefIsSet =
- element->mStringAttributes[SVGImageElement::HREF].IsExplicitlySet() ||
- element->mStringAttributes[SVGImageElement::XLINK_HREF]
- .IsExplicitlySet();
- if (hrefIsSet) {
- element->LoadSVGImage(true, true);
- } else {
- element->CancelImageRequests(true);
- }
- }
-
return NS_OK;
}
diff --git a/layout/svg/SVGOuterSVGFrame.cpp b/layout/svg/SVGOuterSVGFrame.cpp
index ea0879c0c2..00d7663901 100644
--- a/layout/svg/SVGOuterSVGFrame.cpp
+++ b/layout/svg/SVGOuterSVGFrame.cpp
@@ -126,20 +126,14 @@ NS_QUERYFRAME_TAIL_INHERITING(SVGDisplayContainerFrame)
/* virtual */
nscoord SVGOuterSVGFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result;
- DISPLAY_MIN_INLINE_SIZE(this, result);
-
- // If this ever changes to return something other than zero, then
- // nsSubDocumentFrame::GetMinISize will also need to change.
- result = nscoord(0);
-
- return result;
+ auto size = GetIntrinsicSize();
+ const auto& iSize = GetWritingMode().IsVertical() ? size.height : size.width;
+ return iSize.valueOr(0);
}
/* virtual */
nscoord SVGOuterSVGFrame::GetPrefISize(gfxContext* aRenderingContext) {
nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
SVGSVGElement* svg = static_cast<SVGSVGElement*>(GetContent());
WritingMode wm = GetWritingMode();
@@ -325,7 +319,6 @@ void SVGOuterSVGFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("SVGOuterSVGFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_FRAME_TRACE(
NS_FRAME_TRACE_CALLS,
diff --git a/layout/svg/SVGUseFrame.cpp b/layout/svg/SVGUseFrame.cpp
index c655f7b24f..e356895208 100644
--- a/layout/svg/SVGUseFrame.cpp
+++ b/layout/svg/SVGUseFrame.cpp
@@ -42,19 +42,6 @@ void SVGUseFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
SVGGFrame::Init(aContent, aParent, aPrevInFlow);
}
-nsresult SVGUseFrame::AttributeChanged(int32_t aNamespaceID, nsAtom* aAttribute,
- int32_t aModType) {
- // Currently our SMIL implementation does not modify the DOM attributes. Once
- // we implement the SVG 2 SMIL behaviour this can be removed
- // SVGUseElement::AfterSetAttr's implementation will be sufficient.
- if (aModType == MutationEvent_Binding::SMIL) {
- auto* content = SVGUseElement::FromNode(GetContent());
- content->ProcessAttributeChange(aNamespaceID, aAttribute);
- }
-
- return SVGGFrame::AttributeChanged(aNamespaceID, aAttribute, aModType);
-}
-
void SVGUseFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
SVGGFrame::DidSetComputedStyle(aOldComputedStyle);
diff --git a/layout/svg/SVGUseFrame.h b/layout/svg/SVGUseFrame.h
index b72d29247a..a528522991 100644
--- a/layout/svg/SVGUseFrame.h
+++ b/layout/svg/SVGUseFrame.h
@@ -41,8 +41,6 @@ class SVGUseFrame final : public SVGGFrame {
void DimensionAttributeChanged(bool aHadValidDimensions,
bool aAttributeIsUsed);
- nsresult AttributeChanged(int32_t aNamespaceID, nsAtom* aAttribute,
- int32_t aModType) override;
void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
#ifdef DEBUG_FRAME_DUMP
diff --git a/layout/svg/SVGUtils.cpp b/layout/svg/SVGUtils.cpp
index 2967bac780..7c0d864b20 100644
--- a/layout/svg/SVGUtils.cpp
+++ b/layout/svg/SVGUtils.cpp
@@ -1080,8 +1080,8 @@ bool SVGUtils::GetNonScalingStrokeTransform(const nsIFrame* aFrame,
MOZ_ASSERT(aFrame->GetContent()->IsSVGElement(), "should be an SVG element");
- *aUserToOuterSVG = ThebesMatrix(SVGContentUtils::GetCTM(
- static_cast<SVGElement*>(aFrame->GetContent()), true));
+ *aUserToOuterSVG = ThebesMatrix(
+ SVGContentUtils::GetCTM(static_cast<SVGElement*>(aFrame->GetContent())));
return aUserToOuterSVG->HasNonTranslation();
}
diff --git a/layout/svg/crashtests/crashtests.list b/layout/svg/crashtests/crashtests.list
index 0d38fed5ab..690faec32e 100644
--- a/layout/svg/crashtests/crashtests.list
+++ b/layout/svg/crashtests/crashtests.list
@@ -223,8 +223,8 @@ load 1467552-1.html
load 1474982.html
load conditional-outer-svg-nondirty-reflow-assert.xhtml
load extref-test-1.xhtml
-skip-if(wayland) pref(widget.windows.window_occlusion_tracking.enabled,false) load blob-merging-and-retained-display-list.html # Bug 1819154, wayland: Bug 1857256
-skip-if(wayland) load empty-blob-merging.html # wayland: Bug 1857256
+load blob-merging-and-retained-display-list.html
+load empty-blob-merging.html
load grouping-empty-bounds.html
load 1480275.html
load 1480224.html
@@ -243,7 +243,7 @@ load 1539318-1.svg
load 1548985-1.html
load 1548985-2.svg
load 1555851.html
-skip-if(wayland) pref(widget.windows.window_occlusion_tracking.enabled,false) load invalidation-of-opacity-0.html # Bug 1819154, wayland: Bug 1857256
+load invalidation-of-opacity-0.html
load 1563779.html
load 1600855.html
load 1601824.html
diff --git a/layout/tables/BasicTableLayoutStrategy.cpp b/layout/tables/BasicTableLayoutStrategy.cpp
index 5cb890c234..b6fe51db59 100644
--- a/layout/tables/BasicTableLayoutStrategy.cpp
+++ b/layout/tables/BasicTableLayoutStrategy.cpp
@@ -37,7 +37,6 @@ BasicTableLayoutStrategy::~BasicTableLayoutStrategy() = default;
/* virtual */
nscoord BasicTableLayoutStrategy::GetMinISize(gfxContext* aRenderingContext) {
- DISPLAY_MIN_INLINE_SIZE(mTableFrame, mMinISize);
if (mMinISize == NS_INTRINSIC_ISIZE_UNKNOWN) {
ComputeIntrinsicISizes(aRenderingContext);
}
@@ -47,7 +46,6 @@ nscoord BasicTableLayoutStrategy::GetMinISize(gfxContext* aRenderingContext) {
/* virtual */
nscoord BasicTableLayoutStrategy::GetPrefISize(gfxContext* aRenderingContext,
bool aComputingSize) {
- DISPLAY_PREF_INLINE_SIZE(mTableFrame, mPrefISize);
NS_ASSERTION((mPrefISize == NS_INTRINSIC_ISIZE_UNKNOWN) ==
(mPrefISizePctExpand == NS_INTRINSIC_ISIZE_UNKNOWN),
"dirtyness out of sync");
@@ -97,18 +95,10 @@ static CellISizeInfo GetISizeInfo(gfxContext* aRenderingContext,
// XXX Should we ignore percentage padding?
nsIFrame::IntrinsicSizeOffsetData offsets = aFrame->IntrinsicISizeOffsets();
-
- // In quirks mode, table cell isize should be content-box,
- // but bsize should be border box.
- // Because of this historic anomaly, we do not use quirk.css.
- // (We can't specify one value of box-sizing for isize and another
- // for bsize).
- // For this reason, we also do not use box-sizing for just one of
- // them, as this may be confusing.
- if (isQuirks || stylePos->mBoxSizing == StyleBoxSizing::Content) {
+ if (stylePos->mBoxSizing == StyleBoxSizing::Content) {
boxSizingToBorderEdge = offsets.padding + offsets.border;
} else {
- // StyleBoxSizing::Border and standards-mode
+ // StyleBoxSizing::Border
minCoord += offsets.padding + offsets.border;
prefCoord += offsets.padding + offsets.border;
}
diff --git a/layout/tables/FixedTableLayoutStrategy.cpp b/layout/tables/FixedTableLayoutStrategy.cpp
index 8d74e3ba12..5eda3b001e 100644
--- a/layout/tables/FixedTableLayoutStrategy.cpp
+++ b/layout/tables/FixedTableLayoutStrategy.cpp
@@ -32,7 +32,6 @@ FixedTableLayoutStrategy::~FixedTableLayoutStrategy() = default;
/* virtual */
nscoord FixedTableLayoutStrategy::GetMinISize(gfxContext* aRenderingContext) {
- DISPLAY_MIN_INLINE_SIZE(mTableFrame, mMinISize);
if (mMinISize != NS_INTRINSIC_ISIZE_UNKNOWN) {
return mMinISize;
}
@@ -119,9 +118,7 @@ nscoord FixedTableLayoutStrategy::GetPrefISize(gfxContext* aRenderingContext,
// algorithm to find the narrowest inline size that would hold all of
// those intrinsic inline sizes), but it wouldn't be compatible with
// other browsers.
- nscoord result = nscoord_MAX;
- DISPLAY_PREF_INLINE_SIZE(mTableFrame, result);
- return result;
+ return nscoord_MAX;
}
/* virtual */
diff --git a/layout/tables/celldata.h b/layout/tables/celldata.h
index 681f0e9f28..22cdb4217d 100644
--- a/layout/tables/celldata.h
+++ b/layout/tables/celldata.h
@@ -347,7 +347,7 @@ inline BCData::BCData() {
SetBStartStart(true);
SetIStartStart(true);
mIStartSize = mCornerSubSize = mBStartSize = 0;
- mCornerSide = mozilla::eLogicalSideBStart;
+ mCornerSide = static_cast<uint8_t>(mozilla::LogicalSide::BStart);
mCornerBevel = false;
}
@@ -393,7 +393,7 @@ inline BCPixelSize BCData::GetCorner(mozilla::LogicalSide& aOwnerSide,
inline void BCData::SetCorner(BCPixelSize aSubSize,
mozilla::LogicalSide aOwnerSide, bool aBevel) {
mCornerSubSize = aSubSize;
- mCornerSide = aOwnerSide;
+ mCornerSide = static_cast<uint8_t>(aOwnerSide);
mCornerBevel = aBevel;
}
diff --git a/layout/tables/nsCellMap.cpp b/layout/tables/nsCellMap.cpp
index 7c29baa5b0..60496d3ae0 100644
--- a/layout/tables/nsCellMap.cpp
+++ b/layout/tables/nsCellMap.cpp
@@ -678,7 +678,8 @@ void nsTableCellMap::Dump(char* aString) const {
printf("l=%d%X%d ", int32_t(size), owner, segStart);
} else {
size = cd.GetCorner(side, bevel);
- printf("c=%d%X%d ", int32_t(size), side, bevel);
+ printf("c=%d%hhX%d ", int32_t(size), static_cast<uint8_t>(side),
+ bevel);
}
}
BCData& cd = mBCInfo->mBEndIEndCorner;
@@ -690,7 +691,7 @@ void nsTableCellMap::Dump(char* aString) const {
printf("l=%d%X%d ", int32_t(size), owner, segStart);
} else {
size = cd.GetCorner(side, bevel);
- printf("c=%d%X%d ", int32_t(size), side, bevel);
+ printf("c=%d%hhX%d ", int32_t(size), static_cast<uint8_t>(side), bevel);
}
}
printf("\n");
@@ -818,7 +819,7 @@ bool nsTableCellMap::RowHasSpanningCells(int32_t aRowIndex,
return false;
}
-// FIXME: The only value callers pass for aSide is eLogicalSideBEnd.
+// FIXME: The only value callers pass for aSide is LogicalSide::BEnd.
// Consider removing support for the other three values.
void nsTableCellMap::ResetBStartStart(LogicalSide aSide, nsCellMap& aCellMap,
uint32_t aRowGroupStart,
@@ -829,16 +830,16 @@ void nsTableCellMap::ResetBStartStart(LogicalSide aSide, nsCellMap& aCellMap,
BCData* bcData = nullptr;
switch (aSide) {
- case eLogicalSideBEnd:
+ case LogicalSide::BEnd:
aRowIndex++;
[[fallthrough]];
- case eLogicalSideBStart:
+ case LogicalSide::BStart:
cellData = (BCCellData*)aCellMap.GetDataAt(aRowIndex - aRowGroupStart,
aColIndex);
if (cellData) {
bcData = &cellData->mData;
} else {
- NS_ASSERTION(aSide == eLogicalSideBEnd, "program error");
+ NS_ASSERTION(aSide == LogicalSide::BEnd, "program error");
// try the next row group
nsCellMap* cellMap = aCellMap.GetNextSibling();
if (cellMap) {
@@ -851,16 +852,16 @@ void nsTableCellMap::ResetBStartStart(LogicalSide aSide, nsCellMap& aCellMap,
}
}
break;
- case eLogicalSideIEnd:
+ case LogicalSide::IEnd:
aColIndex++;
[[fallthrough]];
- case eLogicalSideIStart:
+ case LogicalSide::IStart:
cellData = (BCCellData*)aCellMap.GetDataAt(aRowIndex - aRowGroupStart,
aColIndex);
if (cellData) {
bcData = &cellData->mData;
} else {
- NS_ASSERTION(aSide == eLogicalSideIEnd, "program error");
+ NS_ASSERTION(aSide == LogicalSide::IEnd, "program error");
bcData = GetIEndMostBorder(aRowIndex);
}
break;
@@ -890,11 +891,11 @@ void nsTableCellMap::SetBCBorderEdge(LogicalSide aSide, nsCellMap& aCellMap,
bool changed;
switch (aSide) {
- case eLogicalSideBEnd:
+ case LogicalSide::BEnd:
rgYPos++;
yPos++;
[[fallthrough]];
- case eLogicalSideBStart:
+ case LogicalSide::BStart:
lastIndex = xPos + aLength - 1;
for (xIndex = xPos; xIndex <= lastIndex; xIndex++) {
changed = aChanged && (xIndex == xPos);
@@ -908,7 +909,7 @@ void nsTableCellMap::SetBCBorderEdge(LogicalSide aSide, nsCellMap& aCellMap,
false, 0, damageArea);
if (!cellData) ABORT0();
} else {
- NS_ASSERTION(aSide == eLogicalSideBEnd, "program error");
+ NS_ASSERTION(aSide == LogicalSide::BEnd, "program error");
// try the next non empty row group
nsCellMap* cellMap = aCellMap.GetNextSibling();
while (cellMap && (0 == cellMap->GetRowCount())) {
@@ -935,10 +936,10 @@ void nsTableCellMap::SetBCBorderEdge(LogicalSide aSide, nsCellMap& aCellMap,
NS_ERROR("Cellmap: BStart edge not found");
}
break;
- case eLogicalSideIEnd:
+ case LogicalSide::IEnd:
xPos++;
[[fallthrough]];
- case eLogicalSideIStart:
+ case LogicalSide::IStart:
// since bStart, bEnd borders were set, there should already be a cellData
// entry
lastIndex = rgYPos + aLength - 1;
@@ -948,7 +949,7 @@ void nsTableCellMap::SetBCBorderEdge(LogicalSide aSide, nsCellMap& aCellMap,
if (cellData) {
cellData->mData.SetIStartEdge(aOwner, aSize, changed);
} else {
- NS_ASSERTION(aSide == eLogicalSideIEnd, "program error");
+ NS_ASSERTION(aSide == LogicalSide::IEnd, "program error");
BCData* bcData = GetIEndMostBorder(yIndex + aCellMapStart);
if (bcData) {
bcData->SetIStartEdge(aOwner, aSize, changed);
@@ -2225,7 +2226,8 @@ void nsCellMap::Dump(bool aIsBorderCollapse) const {
printf("l=%d%d%d ", int32_t(size), owner, segStart);
} else {
size = cd->mData.GetCorner(side, bevel);
- printf("c=%d%d%d ", int32_t(size), side, bevel);
+ printf("c=%d%hhu%d ", int32_t(size), static_cast<uint8_t>(side),
+ bevel);
}
}
}
diff --git a/layout/tables/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp
index 6eb1c3146a..86ce48d47b 100644
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -48,9 +48,6 @@ nsTableCellFrame::nsTableCellFrame(ComputedStyle* aStyle,
nsTableFrame* aTableFrame, ClassID aID)
: nsContainerFrame(aStyle, aTableFrame->PresContext(), aID),
mDesiredSize(aTableFrame->GetWritingMode()) {
- mColIndex = 0;
- mPriorAvailISize = 0;
-
SetContentEmpty(false);
}
@@ -381,10 +378,10 @@ LogicalSides nsTableCellFrame::GetLogicalSkipSides() const {
}
if (GetPrevInFlow()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
if (GetNextInFlow()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
return skip;
}
@@ -392,9 +389,14 @@ LogicalSides nsTableCellFrame::GetLogicalSkipSides() const {
/* virtual */
nsMargin nsTableCellFrame::GetBorderOverflow() { return nsMargin(0, 0, 0, 0); }
-// Align the cell's child frame within the cell
+void nsTableCellFrame::BlockDirAlignChild(
+ WritingMode aWM, nscoord aMaxAscent,
+ ForceAlignTopForTableCell aForceAlignTop) {
+ MOZ_ASSERT(aForceAlignTop != ForceAlignTopForTableCell::Yes ||
+ PresContext()->IsPaginated(),
+ "We shouldn't force table-cells to do 'vertical-align:top' if "
+ "we're not in printing!");
-void nsTableCellFrame::BlockDirAlignChild(WritingMode aWM, nscoord aMaxAscent) {
/* It's the 'border-collapse' on the table that matters */
const LogicalMargin border = GetLogicalUsedBorder(GetWritingMode())
.ApplySkipSides(GetLogicalSkipSides())
@@ -413,8 +415,11 @@ void nsTableCellFrame::BlockDirAlignChild(WritingMode aWM, nscoord aMaxAscent) {
nscoord childBSize = kidRect.BSize(aWM);
// Vertically align the child
+ const auto verticalAlign = aForceAlignTop == ForceAlignTopForTableCell::Yes
+ ? StyleVerticalAlignKeyword::Top
+ : GetVerticalAlign();
nscoord kidBStart = 0;
- switch (GetVerticalAlign()) {
+ switch (verticalAlign) {
case StyleVerticalAlignKeyword::Baseline:
if (!GetContentEmpty()) {
// Align the baselines of the child frame with the baselines of
@@ -590,26 +595,18 @@ nsIScrollableFrame* nsTableCellFrame::GetScrollTargetFrame() const {
/* virtual */
nscoord nsTableCellFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_MIN_INLINE_SIZE(this, result);
-
nsIFrame* inner = mFrames.FirstChild();
- result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
- IntrinsicISizeType::MinISize,
- nsLayoutUtils::IGNORE_PADDING);
- return result;
+ return nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
+ IntrinsicISizeType::MinISize,
+ nsLayoutUtils::IGNORE_PADDING);
}
/* virtual */
nscoord nsTableCellFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord result = 0;
- DISPLAY_PREF_INLINE_SIZE(this, result);
-
nsIFrame* inner = mFrames.FirstChild();
- result = nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
- IntrinsicISizeType::PrefISize,
- nsLayoutUtils::IGNORE_PADDING);
- return result;
+ return nsLayoutUtils::IntrinsicForContainer(aRenderingContext, inner,
+ IntrinsicISizeType::PrefISize,
+ nsLayoutUtils::IGNORE_PADDING);
}
/* virtual */ nsIFrame::IntrinsicSizeOffsetData
@@ -675,7 +672,6 @@ void nsTableCellFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTableCellFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
if (aReflowInput.mFlags.mSpecialBSizeReflow) {
@@ -708,14 +704,12 @@ void nsTableCellFrame::Reflow(nsPresContext* aPresContext,
if (aReflowInput.mFlags.mSpecialBSizeReflow) {
const_cast<ReflowInput&>(aReflowInput)
.SetComputedBSize(BSize(wm) - bp.BStartEnd(wm));
- DISPLAY_REFLOW_CHANGE();
} else {
const nscoord computedUnpaginatedBSize =
CalcUnpaginatedBSize(*this, *tableFrame, bp.BStartEnd(wm));
if (computedUnpaginatedBSize > 0) {
const_cast<ReflowInput&>(aReflowInput)
.SetComputedBSize(computedUnpaginatedBSize);
- DISPLAY_REFLOW_CHANGE();
}
}
}
@@ -977,11 +971,11 @@ LogicalMargin nsBCTableCellFrame::GetBorderWidth(WritingMode aWM) const {
BCPixelSize nsBCTableCellFrame::GetBorderWidth(LogicalSide aSide) const {
switch (aSide) {
- case eLogicalSideBStart:
+ case LogicalSide::BStart:
return BC_BORDER_END_HALF(mBStartBorder);
- case eLogicalSideIEnd:
+ case LogicalSide::IEnd:
return BC_BORDER_START_HALF(mIEndBorder);
- case eLogicalSideBEnd:
+ case LogicalSide::BEnd:
return BC_BORDER_START_HALF(mBEndBorder);
default:
return BC_BORDER_END_HALF(mIStartBorder);
@@ -990,13 +984,13 @@ BCPixelSize nsBCTableCellFrame::GetBorderWidth(LogicalSide aSide) const {
void nsBCTableCellFrame::SetBorderWidth(LogicalSide aSide, BCPixelSize aValue) {
switch (aSide) {
- case eLogicalSideBStart:
+ case LogicalSide::BStart:
mBStartBorder = aValue;
break;
- case eLogicalSideIEnd:
+ case LogicalSide::IEnd:
mIEndBorder = aValue;
break;
- case eLogicalSideBEnd:
+ case LogicalSide::BEnd:
mBEndBorder = aValue;
break;
default:
diff --git a/layout/tables/nsTableCellFrame.h b/layout/tables/nsTableCellFrame.h
index f9b6f3ccac..ae1a881819 100644
--- a/layout/tables/nsTableCellFrame.h
+++ b/layout/tables/nsTableCellFrame.h
@@ -34,9 +34,6 @@ class PresShell;
class nsTableCellFrame : public nsContainerFrame,
public nsITableCellLayout,
public nsIPercentBSizeObserver {
- typedef mozilla::gfx::DrawTarget DrawTarget;
- typedef mozilla::image::ImgDrawResult ImgDrawResult;
-
friend nsTableCellFrame* NS_NewTableCellFrame(mozilla::PresShell* aPresShell,
ComputedStyle* aStyle,
nsTableFrame* aTableFrame);
@@ -44,11 +41,6 @@ class nsTableCellFrame : public nsContainerFrame,
nsTableCellFrame(ComputedStyle* aStyle, nsTableFrame* aTableFrame)
: nsTableCellFrame(aStyle, aTableFrame, kClassID) {}
- protected:
- typedef mozilla::WritingMode WritingMode;
- typedef mozilla::LogicalSide LogicalSide;
- typedef mozilla::LogicalMargin LogicalMargin;
-
public:
NS_DECL_QUERYFRAME
NS_DECL_FRAMEARENA_HELPERS(nsTableCellFrame)
@@ -122,7 +114,9 @@ class nsTableCellFrame : public nsContainerFrame,
nsresult GetFrameName(nsAString& aResult) const override;
#endif
- void BlockDirAlignChild(mozilla::WritingMode aWM, nscoord aMaxAscent);
+ // Align the cell's child frame within the cell.
+ void BlockDirAlignChild(mozilla::WritingMode aWM, nscoord aMaxAscent,
+ mozilla::ForceAlignTopForTableCell aForceAlignTop);
/*
* Get the value of vertical-align adjusted for CSS 2's rules for a
@@ -193,20 +187,24 @@ class nsTableCellFrame : public nsContainerFrame,
void SetColIndex(int32_t aColIndex);
- /** return the available isize given to this frame during its last reflow */
- inline nscoord GetPriorAvailISize();
-
- /** set the available isize given to this frame during its last reflow */
- inline void SetPriorAvailISize(nscoord aPriorAvailISize);
-
- /** return the desired size returned by this frame during its last reflow */
- inline mozilla::LogicalSize GetDesiredSize();
+ // Get or set the available isize given to this frame during its last reflow.
+ nscoord GetPriorAvailISize() const { return mPriorAvailISize; }
+ void SetPriorAvailISize(nscoord aPriorAvailISize) {
+ mPriorAvailISize = aPriorAvailISize;
+ }
- /** set the desired size returned by this frame during its last reflow */
- inline void SetDesiredSize(const ReflowOutput& aDesiredSize);
+ // Get or set the desired size returned by this frame during its last reflow.
+ mozilla::LogicalSize GetDesiredSize() const { return mDesiredSize; }
+ void SetDesiredSize(const ReflowOutput& aDesiredSize) {
+ mDesiredSize = aDesiredSize.Size(GetWritingMode());
+ }
- bool GetContentEmpty() const;
- void SetContentEmpty(bool aContentEmpty);
+ bool GetContentEmpty() const {
+ return HasAnyStateBits(NS_TABLE_CELL_CONTENT_EMPTY);
+ }
+ void SetContentEmpty(bool aContentEmpty) {
+ AddOrRemoveStateBits(NS_TABLE_CELL_CONTENT_EMPTY, aContentEmpty);
+ }
nsTableCellFrame* GetNextCell() const {
nsIFrame* sibling = GetNextSibling();
@@ -216,7 +214,7 @@ class nsTableCellFrame : public nsContainerFrame,
return static_cast<nsTableCellFrame*>(sibling);
}
- virtual LogicalMargin GetBorderWidth(WritingMode aWM) const;
+ virtual mozilla::LogicalMargin GetBorderWidth(mozilla::WritingMode aWM) const;
void DecorateForSelection(DrawTarget* aDrawTarget, nsPoint aPt);
@@ -251,44 +249,17 @@ class nsTableCellFrame : public nsContainerFrame,
friend class nsTableRowFrame;
- uint32_t mColIndex; // the starting column for this cell
-
- nscoord mPriorAvailISize; // the avail isize during the last reflow
- mozilla::LogicalSize mDesiredSize; // the last desired inline and block size
-};
-
-inline nscoord nsTableCellFrame::GetPriorAvailISize() {
- return mPriorAvailISize;
-}
-
-inline void nsTableCellFrame::SetPriorAvailISize(nscoord aPriorAvailISize) {
- mPriorAvailISize = aPriorAvailISize;
-}
-
-inline mozilla::LogicalSize nsTableCellFrame::GetDesiredSize() {
- return mDesiredSize;
-}
-
-inline void nsTableCellFrame::SetDesiredSize(const ReflowOutput& aDesiredSize) {
- mDesiredSize = aDesiredSize.Size(GetWritingMode());
-}
+ // The starting column for this cell
+ uint32_t mColIndex = 0;
-inline bool nsTableCellFrame::GetContentEmpty() const {
- return HasAnyStateBits(NS_TABLE_CELL_CONTENT_EMPTY);
-}
+ // The avail isize during the last reflow
+ nscoord mPriorAvailISize = 0;
-inline void nsTableCellFrame::SetContentEmpty(bool aContentEmpty) {
- if (aContentEmpty) {
- AddStateBits(NS_TABLE_CELL_CONTENT_EMPTY);
- } else {
- RemoveStateBits(NS_TABLE_CELL_CONTENT_EMPTY);
- }
-}
+ // The last desired inline and block size
+ mozilla::LogicalSize mDesiredSize;
+};
-// nsBCTableCellFrame
class nsBCTableCellFrame final : public nsTableCellFrame {
- typedef mozilla::image::ImgDrawResult ImgDrawResult;
-
public:
NS_DECL_FRAMEARENA_HELPERS(nsBCTableCellFrame)
@@ -299,13 +270,14 @@ class nsBCTableCellFrame final : public nsTableCellFrame {
nsMargin GetUsedBorder() const override;
// Get the *inner half of the border only*, in twips.
- LogicalMargin GetBorderWidth(WritingMode aWM) const override;
+ mozilla::LogicalMargin GetBorderWidth(
+ mozilla::WritingMode aWM) const override;
// Get the *inner half of the border only*, in pixels.
- BCPixelSize GetBorderWidth(LogicalSide aSide) const;
+ BCPixelSize GetBorderWidth(mozilla::LogicalSide aSide) const;
// Set the full (both halves) width of the border
- void SetBorderWidth(LogicalSide aSide, BCPixelSize aPixelValue);
+ void SetBorderWidth(mozilla::LogicalSide aSide, BCPixelSize aPixelValue);
nsMargin GetBorderOverflow() override;
diff --git a/layout/tables/nsTableColFrame.cpp b/layout/tables/nsTableColFrame.cpp
index 16eab74cab..8031d4c47c 100644
--- a/layout/tables/nsTableColFrame.cpp
+++ b/layout/tables/nsTableColFrame.cpp
@@ -82,7 +82,6 @@ void nsTableColFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTableColFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
aDesiredSize.ClearSize();
const nsStyleVisibility* colVis = StyleVisibility();
diff --git a/layout/tables/nsTableColGroupFrame.cpp b/layout/tables/nsTableColGroupFrame.cpp
index 54fe53a5c4..965960a58d 100644
--- a/layout/tables/nsTableColGroupFrame.cpp
+++ b/layout/tables/nsTableColGroupFrame.cpp
@@ -315,10 +315,10 @@ nsIFrame::LogicalSides nsTableColGroupFrame::GetLogicalSkipSides() const {
}
if (GetPrevInFlow()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
if (GetNextInFlow()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
return skip;
}
@@ -329,7 +329,6 @@ void nsTableColGroupFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTableColGroupFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
NS_ASSERTION(nullptr != mContent, "bad state -- null content for frame");
diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp
index e7fd7340bf..a2f8b2b625 100644
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -1235,10 +1235,10 @@ LogicalSides nsTableFrame::GetLogicalSkipSides() const {
// frame attribute was accounted for in nsHTMLTableElement::MapTableBorderInto
// account for pagination
if (GetPrevInFlow()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
if (GetNextInFlow()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
return skip;
}
@@ -1615,7 +1615,6 @@ void nsTableFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTableFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
MOZ_ASSERT(!HasAnyStateBits(NS_FRAME_OUT_OF_FLOW),
"The nsTableWrapperFrame should be the out-of-flow if needed");
@@ -2393,8 +2392,11 @@ nsMargin nsTableFrame::GetUsedMargin() const {
return nsMargin(0, 0, 0, 0);
}
-// TODO(TYLin): Should this property only be set on the first-in-flow of
-// nsTableFrame?
+// TODO(TYLin, dshin): This ideally should be set only in first-in-flow.
+// However, the current implementation of border-collapsed table does not
+// handle continuation gracefully. One concrete issue is shown in bug 1881157
+// comment 3. It is also unclear if the damage area, current included in this
+// property, should be stored separately per-continuation.
NS_DECLARE_FRAME_PROPERTY_DELETABLE(TableBCDataProperty, TableBCData)
TableBCData* nsTableFrame::GetTableBCData() const {
@@ -3800,24 +3802,29 @@ class BCMapCellIterator;
/*****************************************************************
* BCMapCellInfo
- * This structure stores information about the cellmap and all involved
- * table related frames that are used during the computation of winning borders
- * in CalcBCBorders so that they do need to be looked up again and again when
- * iterating over the cells.
+ * This structure stores information during the computation of winning borders
+ * in CalcBCBorders, so that they don't need to be looked up repeatedly.
****************************************************************/
-struct BCMapCellInfo {
+struct BCMapCellInfo final {
explicit BCMapCellInfo(nsTableFrame* aTableFrame);
void ResetCellInfo();
void SetInfo(nsTableRowFrame* aNewRow, int32_t aColIndex,
BCCellData* aCellData, BCMapCellIterator* aIter,
nsCellMap* aCellMap = nullptr);
- // functions to set the border widths on the table related frames, where the
- // knowledge about the current position in the table is used.
- void SetTableBStartBorderWidth(BCPixelSize aWidth);
- void SetTableIStartBorderWidth(int32_t aRowB, BCPixelSize aWidth);
- void SetTableIEndBorderWidth(int32_t aRowB, BCPixelSize aWidth);
- void SetTableBEndBorderWidth(BCPixelSize aWidth);
+ // Functions to (re)set the border widths on the table related cell frames,
+ // where the knowledge about the current position in the table is used.
+ // For most "normal" cells that have row/colspan of 1, these functions
+ // are called once at most during the reflow, setting the value as given
+ // (Discarding the value from the previous reflow, which is now irrelevant).
+ // However, for cells spanning multiple rows/coluns, the maximum border
+ // width seen is stored. This is controlled by calling the reset functions
+ // before the cell's border is computed the first time.
+ void ResetIStartBorderWidths();
+ void ResetIEndBorderWidths();
+ void ResetBStartBorderWidths();
+ void ResetBEndBorderWidths();
+
void SetIStartBorderWidths(BCPixelSize aWidth);
void SetIEndBorderWidths(BCPixelSize aWidth);
void SetBStartBorderWidths(BCPixelSize aWidth);
@@ -3845,12 +3852,12 @@ struct BCMapCellInfo {
int32_t GetCellEndRowIndex() const;
int32_t GetCellEndColIndex() const;
- // storage of table information
+ // Storage of table information required to compute individual cell
+ // information.
nsTableFrame* mTableFrame;
nsTableFrame* mTableFirstInFlow;
int32_t mNumTableRows;
int32_t mNumTableCols;
- TableBCData* mTableBCData;
WritingMode mTableWM;
// a cell can only belong to one rowgroup
@@ -3893,7 +3900,6 @@ BCMapCellInfo::BCMapCellInfo(nsTableFrame* aTableFrame)
mTableFirstInFlow(static_cast<nsTableFrame*>(aTableFrame->FirstInFlow())),
mNumTableRows(aTableFrame->GetRowCount()),
mNumTableCols(aTableFrame->GetColCount()),
- mTableBCData(mTableFirstInFlow->GetTableBCData()),
mTableWM(aTableFrame->Style()),
mCurrentRowFrame(nullptr),
mCurrentColGroupFrame(nullptr),
@@ -3922,6 +3928,36 @@ inline int32_t BCMapCellInfo::GetCellEndColIndex() const {
return mColIndex + mColSpan - 1;
}
+static TableBCData* GetTableBCData(nsTableFrame* aTableFrame) {
+ auto* firstInFlow = static_cast<nsTableFrame*>(aTableFrame->FirstInFlow());
+ return firstInFlow->GetTableBCData();
+}
+
+/*****************************************************************
+ * BCMapTableInfo
+ * This structure stores controls border information global to the
+ * table computed during the border-collapsed border calcuation.
+ ****************************************************************/
+struct BCMapTableInfo final {
+ explicit BCMapTableInfo(nsTableFrame* aTableFrame)
+ : mTableBCData{GetTableBCData(aTableFrame)} {}
+
+ void ResetTableIStartBorderWidth() { mTableBCData->mIStartBorderWidth = 0; }
+
+ void ResetTableIEndBorderWidth() { mTableBCData->mIEndBorderWidth = 0; }
+
+ void ResetTableBStartBorderWidth() { mTableBCData->mBStartBorderWidth = 0; }
+
+ void ResetTableBEndBorderWidth() { mTableBCData->mBEndBorderWidth = 0; }
+
+ void SetTableIStartBorderWidth(int32_t aRowB, BCPixelSize aWidth);
+ void SetTableIEndBorderWidth(int32_t aRowB, BCPixelSize aWidth);
+ void SetTableBStartBorderWidth(BCPixelSize aWidth);
+ void SetTableBEndBorderWidth(BCPixelSize aWidth);
+
+ TableBCData* mTableBCData;
+};
+
class BCMapCellIterator {
public:
BCMapCellIterator(nsTableFrame* aTableFrame, const TableArea& aDamageArea);
@@ -4537,7 +4573,7 @@ struct BCCornerInfo {
ownerColor = 0;
ownerWidth = subWidth = ownerElem = subSide = subElem = hasDashDot =
numSegs = bevel = 0;
- ownerSide = eLogicalSideBStart;
+ ownerSide = static_cast<uint16_t>(LogicalSide::BStart);
ownerStyle = BORDER_STYLE_UNSET;
subStyle = StyleBorderStyle::Solid;
}
@@ -4552,7 +4588,7 @@ struct BCCornerInfo {
// border perpendicular to ownerSide
StyleBorderStyle subStyle; // border style of subElem
StyleBorderStyle ownerStyle; // border style of ownerElem
- uint16_t ownerSide : 2; // LogicalSide (e.g eLogicalSideBStart, etc) of the
+ uint16_t ownerSide : 2; // LogicalSide (e.g LogicalSide::BStart, etc) of the
// border owning the corner relative to the corner
uint16_t
ownerElem : 4; // elem type (e.g. eTable, eGroup, etc) owning the corner
@@ -4575,7 +4611,7 @@ void BCCornerInfo::Set(mozilla::LogicalSide aSide, BCCellBorder aBorder) {
ownerStyle = aBorder.style;
ownerWidth = aBorder.width;
ownerColor = aBorder.color;
- ownerSide = aSide;
+ ownerSide = static_cast<uint16_t>(aSide);
hasDashDot = 0;
numSegs = 0;
if (aBorder.width > 0) {
@@ -4586,7 +4622,8 @@ void BCCornerInfo::Set(mozilla::LogicalSide aSide, BCCellBorder aBorder) {
bevel = 0;
subWidth = 0;
// the following will get set later
- subSide = IsInline(aSide) ? eLogicalSideBStart : eLogicalSideIStart;
+ subSide = static_cast<uint16_t>(IsInline(aSide) ? LogicalSide::BStart
+ : LogicalSide::IStart);
subElem = eTableOwner;
subStyle = StyleBorderStyle::Solid;
}
@@ -4631,16 +4668,16 @@ void BCCornerInfo::Update(mozilla::LogicalSide aSide, BCCellBorder aBorder) {
subStyle = tempBorder.style;
subWidth = tempBorder.width;
if (!firstWins) {
- subSide = aSide;
+ subSide = static_cast<uint16_t>(aSide);
}
}
} else { // input args are dominant
- ownerSide = aSide;
+ ownerSide = static_cast<uint16_t>(aSide);
if (::Perpendicular(oldSide, LogicalSide(ownerSide))) {
subElem = oldBorder.owner;
subStyle = oldBorder.style;
subWidth = oldBorder.width;
- subSide = oldSide;
+ subSide = static_cast<uint16_t>(oldSide);
}
}
if (aBorder.width > 0) {
@@ -4858,13 +4895,8 @@ void nsTableFrame::ExpandBCDamageArea(TableArea& aArea) const {
#define ADJACENT true
#define INLINE_DIR true
-void BCMapCellInfo::SetTableBStartBorderWidth(BCPixelSize aWidth) {
- mTableBCData->mBStartBorderWidth =
- std::max(mTableBCData->mBStartBorderWidth, aWidth);
-}
-
-void BCMapCellInfo::SetTableIStartBorderWidth(int32_t aRowB,
- BCPixelSize aWidth) {
+void BCMapTableInfo::SetTableIStartBorderWidth(int32_t aRowB,
+ BCPixelSize aWidth) {
// update the iStart first cell border
if (aRowB == 0) {
mTableBCData->mIStartCellBorderWidth = aWidth;
@@ -4873,7 +4905,8 @@ void BCMapCellInfo::SetTableIStartBorderWidth(int32_t aRowB,
std::max(mTableBCData->mIStartBorderWidth, aWidth);
}
-void BCMapCellInfo::SetTableIEndBorderWidth(int32_t aRowB, BCPixelSize aWidth) {
+void BCMapTableInfo::SetTableIEndBorderWidth(int32_t aRowB,
+ BCPixelSize aWidth) {
// update the iEnd first cell border
if (aRowB == 0) {
mTableBCData->mIEndCellBorderWidth = aWidth;
@@ -4882,38 +4915,83 @@ void BCMapCellInfo::SetTableIEndBorderWidth(int32_t aRowB, BCPixelSize aWidth) {
std::max(mTableBCData->mIEndBorderWidth, aWidth);
}
-void BCMapCellInfo::SetIEndBorderWidths(BCPixelSize aWidth) {
- // update the borders of the cells and cols affected
+void BCMapTableInfo::SetTableBStartBorderWidth(BCPixelSize aWidth) {
+ mTableBCData->mBStartBorderWidth =
+ std::max(mTableBCData->mBStartBorderWidth, aWidth);
+}
+
+void BCMapTableInfo::SetTableBEndBorderWidth(BCPixelSize aWidth) {
+ mTableBCData->mBEndBorderWidth =
+ std::max(mTableBCData->mBEndBorderWidth, aWidth);
+}
+
+void BCMapCellInfo::ResetIStartBorderWidths() {
if (mCell) {
- mCell->SetBorderWidth(
- eLogicalSideIEnd,
- std::max(aWidth, mCell->GetBorderWidth(eLogicalSideIEnd)));
+ mCell->SetBorderWidth(LogicalSide::IStart, 0);
+ }
+ if (mStartCol) {
+ mStartCol->SetIStartBorderWidth(0);
+ }
+}
+
+void BCMapCellInfo::ResetIEndBorderWidths() {
+ if (mCell) {
+ mCell->SetBorderWidth(LogicalSide::IEnd, 0);
}
if (mEndCol) {
- BCPixelSize half = BC_BORDER_START_HALF(aWidth);
- mEndCol->SetIEndBorderWidth(std::max(half, mEndCol->GetIEndBorderWidth()));
+ mEndCol->SetIEndBorderWidth(0);
}
}
-void BCMapCellInfo::SetBEndBorderWidths(BCPixelSize aWidth) {
- // update the borders of the affected cells and rows
+void BCMapCellInfo::ResetBStartBorderWidths() {
if (mCell) {
- mCell->SetBorderWidth(
- eLogicalSideBEnd,
- std::max(aWidth, mCell->GetBorderWidth(eLogicalSideBEnd)));
+ mCell->SetBorderWidth(LogicalSide::BStart, 0);
+ }
+ if (mStartRow) {
+ mStartRow->SetBStartBCBorderWidth(0);
+ }
+}
+
+void BCMapCellInfo::ResetBEndBorderWidths() {
+ if (mCell) {
+ mCell->SetBorderWidth(LogicalSide::BEnd, 0);
}
if (mEndRow) {
+ mEndRow->SetBEndBCBorderWidth(0);
+ }
+}
+
+void BCMapCellInfo::SetIStartBorderWidths(BCPixelSize aWidth) {
+ if (mCell) {
+ mCell->SetBorderWidth(
+ LogicalSide::IStart,
+ std::max(aWidth, mCell->GetBorderWidth(LogicalSide::IStart)));
+ }
+ if (mStartCol) {
+ BCPixelSize half = BC_BORDER_END_HALF(aWidth);
+ mStartCol->SetIStartBorderWidth(
+ std::max(half, mStartCol->GetIStartBorderWidth()));
+ }
+}
+
+void BCMapCellInfo::SetIEndBorderWidths(BCPixelSize aWidth) {
+ // update the borders of the cells and cols affected
+ if (mCell) {
+ mCell->SetBorderWidth(
+ LogicalSide::IEnd,
+ std::max(aWidth, mCell->GetBorderWidth(LogicalSide::IEnd)));
+ }
+ if (mEndCol) {
BCPixelSize half = BC_BORDER_START_HALF(aWidth);
- mEndRow->SetBEndBCBorderWidth(
- std::max(half, mEndRow->GetBEndBCBorderWidth()));
+ mEndCol->SetIEndBorderWidth(std::max(half, mEndCol->GetIEndBorderWidth()));
}
}
void BCMapCellInfo::SetBStartBorderWidths(BCPixelSize aWidth) {
if (mCell) {
mCell->SetBorderWidth(
- eLogicalSideBStart,
- std::max(aWidth, mCell->GetBorderWidth(eLogicalSideBStart)));
+ LogicalSide::BStart,
+ std::max(aWidth, mCell->GetBorderWidth(LogicalSide::BStart)));
}
if (mStartRow) {
BCPixelSize half = BC_BORDER_END_HALF(aWidth);
@@ -4922,24 +5000,20 @@ void BCMapCellInfo::SetBStartBorderWidths(BCPixelSize aWidth) {
}
}
-void BCMapCellInfo::SetIStartBorderWidths(BCPixelSize aWidth) {
+void BCMapCellInfo::SetBEndBorderWidths(BCPixelSize aWidth) {
+ // update the borders of the affected cells and rows
if (mCell) {
mCell->SetBorderWidth(
- eLogicalSideIStart,
- std::max(aWidth, mCell->GetBorderWidth(eLogicalSideIStart)));
+ LogicalSide::BEnd,
+ std::max(aWidth, mCell->GetBorderWidth(LogicalSide::BEnd)));
}
- if (mStartCol) {
- BCPixelSize half = BC_BORDER_END_HALF(aWidth);
- mStartCol->SetIStartBorderWidth(
- std::max(half, mStartCol->GetIStartBorderWidth()));
+ if (mEndRow) {
+ BCPixelSize half = BC_BORDER_START_HALF(aWidth);
+ mEndRow->SetBEndBCBorderWidth(
+ std::max(half, mEndRow->GetBEndBCBorderWidth()));
}
}
-void BCMapCellInfo::SetTableBEndBorderWidth(BCPixelSize aWidth) {
- mTableBCData->mBEndBorderWidth =
- std::max(mTableBCData->mBEndBorderWidth, aWidth);
-}
-
void BCMapCellInfo::SetColumn(int32_t aColX) {
mCurrentColFrame = mTableFirstInFlow->GetColFrame(aColX);
mCurrentColGroupFrame =
@@ -4957,46 +5031,46 @@ void BCMapCellInfo::IncrementRow(bool aResetToBStartRowOfCell) {
BCCellBorder BCMapCellInfo::GetBStartEdgeBorder() {
return CompareBorders(mTableFrame, mCurrentColGroupFrame, mCurrentColFrame,
mRowGroup, mStartRow, mCell, mTableWM,
- eLogicalSideBStart, !ADJACENT);
+ LogicalSide::BStart, !ADJACENT);
}
BCCellBorder BCMapCellInfo::GetBEndEdgeBorder() {
return CompareBorders(mTableFrame, mCurrentColGroupFrame, mCurrentColFrame,
- mRowGroup, mEndRow, mCell, mTableWM, eLogicalSideBEnd,
+ mRowGroup, mEndRow, mCell, mTableWM, LogicalSide::BEnd,
ADJACENT);
}
BCCellBorder BCMapCellInfo::GetIStartEdgeBorder() {
return CompareBorders(mTableFrame, mColGroup, mStartCol, mRowGroup,
- mCurrentRowFrame, mCell, mTableWM, eLogicalSideIStart,
+ mCurrentRowFrame, mCell, mTableWM, LogicalSide::IStart,
!ADJACENT);
}
BCCellBorder BCMapCellInfo::GetIEndEdgeBorder() {
return CompareBorders(mTableFrame, mColGroup, mEndCol, mRowGroup,
- mCurrentRowFrame, mCell, mTableWM, eLogicalSideIEnd,
+ mCurrentRowFrame, mCell, mTableWM, LogicalSide::IEnd,
ADJACENT);
}
BCCellBorder BCMapCellInfo::GetIEndInternalBorder() {
const nsIFrame* cg = mCgAtEnd ? mColGroup : nullptr;
return CompareBorders(nullptr, cg, mEndCol, nullptr, nullptr, mCell, mTableWM,
- eLogicalSideIEnd, ADJACENT);
+ LogicalSide::IEnd, ADJACENT);
}
BCCellBorder BCMapCellInfo::GetIStartInternalBorder() {
const nsIFrame* cg = mCgAtStart ? mColGroup : nullptr;
return CompareBorders(nullptr, cg, mStartCol, nullptr, nullptr, mCell,
- mTableWM, eLogicalSideIStart, !ADJACENT);
+ mTableWM, LogicalSide::IStart, !ADJACENT);
}
BCCellBorder BCMapCellInfo::GetBEndInternalBorder() {
const nsIFrame* rg = mRgAtEnd ? mRowGroup : nullptr;
return CompareBorders(nullptr, nullptr, nullptr, rg, mEndRow, mCell, mTableWM,
- eLogicalSideBEnd, ADJACENT);
+ LogicalSide::BEnd, ADJACENT);
}
BCCellBorder BCMapCellInfo::GetBStartInternalBorder() {
const nsIFrame* rg = mRgAtStart ? mRowGroup : nullptr;
return CompareBorders(nullptr, nullptr, nullptr, rg, mStartRow, mCell,
- mTableWM, eLogicalSideBStart, !ADJACENT);
+ mTableWM, LogicalSide::BStart, !ADJACENT);
}
// Calculate border information for border-collapsed tables.
@@ -5115,6 +5189,10 @@ void nsTableFrame::CalcBCBorders() {
if (!lastBEndBorders.borders) ABORT0();
BCMapCellInfo info(this);
+ // TODO(dshin): This is basically propData, except it uses first-in-flow's
+ // data. Consult the definition of `TableBCDataProperty` regarding
+ // using the first-in-flow only.
+ BCMapTableInfo tableInfo(this);
// Block-start corners of the cell being traversed, indexed by columns.
BCCorners bStartCorners(damageArea.ColCount() + 1, damageArea.StartCol());
@@ -5164,10 +5242,12 @@ void nsTableFrame::CalcBCBorders() {
// table, row group, row if the border is at the bStart of the table,
// otherwise it was processed in a previous row
if (0 == info.mRowIndex) {
- if (!tableBorderReset[eLogicalSideBStart]) {
- propData->mBStartBorderWidth = 0;
- tableBorderReset[eLogicalSideBStart] = true;
+ uint8_t idxBStart = static_cast<uint8_t>(LogicalSide::BStart);
+ if (!tableBorderReset[idxBStart]) {
+ tableInfo.ResetTableBStartBorderWidth();
+ tableBorderReset[idxBStart] = true;
}
+ bool reset = false;
for (int32_t colIdx = info.mColIndex; colIdx <= info.GetCellEndColIndex();
colIdx++) {
info.SetColumn(colIdx);
@@ -5175,9 +5255,9 @@ void nsTableFrame::CalcBCBorders() {
BCCornerInfo& bStartIStartCorner = bStartCorners[colIdx];
// Mark inline-end direction border from this corner.
if (0 == colIdx) {
- bStartIStartCorner.Set(eLogicalSideIEnd, currentBorder);
+ bStartIStartCorner.Set(LogicalSide::IEnd, currentBorder);
} else {
- bStartIStartCorner.Update(eLogicalSideIEnd, currentBorder);
+ bStartIStartCorner.Update(LogicalSide::IEnd, currentBorder);
tableCellMap->SetBCBorderCorner(
LogicalCorner::BStartIStart, *iter.mCellMap, 0, 0, colIdx,
LogicalSide(bStartIStartCorner.ownerSide),
@@ -5186,7 +5266,7 @@ void nsTableFrame::CalcBCBorders() {
// Above, we set the corner `colIndex` column as having a border towards
// inline-end, heading towards the next column. Vice versa is also true,
// where the next column has a border heading towards this column.
- bStartCorners[colIdx + 1].Set(eLogicalSideIStart, currentBorder);
+ bStartCorners[colIdx + 1].Set(LogicalSide::IStart, currentBorder);
MOZ_ASSERT(firstRowBStartEdgeBorder,
"Inline start border tracking not set?");
// update firstRowBStartEdgeBorder and see if a new segment starts
@@ -5196,13 +5276,17 @@ void nsTableFrame::CalcBCBorders() {
firstRowBStartEdgeBorder.ref())
: true;
// store the border segment in the cell map
- tableCellMap->SetBCBorderEdge(eLogicalSideBStart, *iter.mCellMap, 0, 0,
+ tableCellMap->SetBCBorderEdge(LogicalSide::BStart, *iter.mCellMap, 0, 0,
colIdx, 1, currentBorder.owner,
currentBorder.width, startSeg);
// Set border width at block-start (table-wide and for the cell), but
// only if it's the largest we've encountered.
- info.SetTableBStartBorderWidth(currentBorder.width);
+ tableInfo.SetTableBStartBorderWidth(currentBorder.width);
+ if (!reset) {
+ info.ResetBStartBorderWidths();
+ reset = true;
+ }
info.SetBStartBorderWidths(currentBorder.width);
}
} else {
@@ -5225,34 +5309,40 @@ void nsTableFrame::CalcBCBorders() {
// table, col group, col if the border is at the iStart of the table,
// otherwise it was processed in a previous col
if (0 == info.mColIndex) {
- if (!tableBorderReset[eLogicalSideIStart]) {
- propData->mIStartBorderWidth = 0;
- tableBorderReset[eLogicalSideIStart] = true;
+ uint8_t idxIStart = static_cast<uint8_t>(LogicalSide::IStart);
+ if (!tableBorderReset[idxIStart]) {
+ tableInfo.ResetTableIStartBorderWidth();
+ tableBorderReset[idxIStart] = true;
}
info.mCurrentRowFrame = nullptr;
+ bool reset = false;
for (int32_t rowB = info.mRowIndex; rowB <= info.GetCellEndRowIndex();
rowB++) {
info.IncrementRow(rowB == info.mRowIndex);
BCCellBorder currentBorder = info.GetIStartEdgeBorder();
BCCornerInfo& bStartIStartCorner =
(0 == rowB) ? bStartCorners[0] : bEndCorners[0];
- bStartIStartCorner.Update(eLogicalSideBEnd, currentBorder);
+ bStartIStartCorner.Update(LogicalSide::BEnd, currentBorder);
tableCellMap->SetBCBorderCorner(
LogicalCorner::BStartIStart, *iter.mCellMap, iter.mRowGroupStart,
rowB, 0, LogicalSide(bStartIStartCorner.ownerSide),
bStartIStartCorner.subWidth, bStartIStartCorner.bevel);
- bEndCorners[0].Set(eLogicalSideBStart, currentBorder);
+ bEndCorners[0].Set(LogicalSide::BStart, currentBorder);
// update lastBlockDirBorders and see if a new segment starts
bool startSeg = SetBorder(currentBorder, lastBlockDirBorders[0]);
// store the border segment in the cell map
- tableCellMap->SetBCBorderEdge(eLogicalSideIStart, *iter.mCellMap,
+ tableCellMap->SetBCBorderEdge(LogicalSide::IStart, *iter.mCellMap,
iter.mRowGroupStart, rowB, info.mColIndex,
1, currentBorder.owner,
currentBorder.width, startSeg);
// Set border width at inline-start (table-wide and for the cell), but
// only if it's the largest we've encountered.
- info.SetTableIStartBorderWidth(rowB, currentBorder.width);
+ tableInfo.SetTableIStartBorderWidth(rowB, currentBorder.width);
+ if (!reset) {
+ info.ResetIStartBorderWidths();
+ reset = true;
+ }
info.SetIStartBorderWidths(currentBorder.width);
}
}
@@ -5261,11 +5351,13 @@ void nsTableFrame::CalcBCBorders() {
// cells and the table, row group, row
if (info.mNumTableCols == info.GetCellEndColIndex() + 1) {
// touches iEnd edge of table
- if (!tableBorderReset[eLogicalSideIEnd]) {
- propData->mIEndBorderWidth = 0;
- tableBorderReset[eLogicalSideIEnd] = true;
+ uint8_t idxIEnd = static_cast<uint8_t>(LogicalSide::IEnd);
+ if (!tableBorderReset[idxIEnd]) {
+ tableInfo.ResetTableIEndBorderWidth();
+ tableBorderReset[idxIEnd] = true;
}
info.mCurrentRowFrame = nullptr;
+ bool reset = false;
for (int32_t rowB = info.mRowIndex; rowB <= info.GetCellEndRowIndex();
rowB++) {
info.IncrementRow(rowB == info.mRowIndex);
@@ -5275,7 +5367,7 @@ void nsTableFrame::CalcBCBorders() {
BCCornerInfo& bStartIEndCorner =
(0 == rowB) ? bStartCorners[info.GetCellEndColIndex() + 1]
: bEndCorners[info.GetCellEndColIndex() + 1];
- bStartIEndCorner.Update(eLogicalSideBEnd, currentBorder);
+ bStartIEndCorner.Update(LogicalSide::BEnd, currentBorder);
tableCellMap->SetBCBorderCorner(
LogicalCorner::BStartIEnd, *iter.mCellMap, iter.mRowGroupStart,
rowB, info.GetCellEndColIndex(),
@@ -5283,7 +5375,7 @@ void nsTableFrame::CalcBCBorders() {
bStartIEndCorner.bevel);
BCCornerInfo& bEndIEndCorner =
bEndCorners[info.GetCellEndColIndex() + 1];
- bEndIEndCorner.Set(eLogicalSideBStart, currentBorder);
+ bEndIEndCorner.Set(LogicalSide::BStart, currentBorder);
tableCellMap->SetBCBorderCorner(
LogicalCorner::BEndIEnd, *iter.mCellMap, iter.mRowGroupStart, rowB,
info.GetCellEndColIndex(), LogicalSide(bEndIEndCorner.ownerSide),
@@ -5293,12 +5385,16 @@ void nsTableFrame::CalcBCBorders() {
currentBorder, lastBlockDirBorders[info.GetCellEndColIndex() + 1]);
// store the border segment in the cell map and update cellBorders
tableCellMap->SetBCBorderEdge(
- eLogicalSideIEnd, *iter.mCellMap, iter.mRowGroupStart, rowB,
+ LogicalSide::IEnd, *iter.mCellMap, iter.mRowGroupStart, rowB,
info.GetCellEndColIndex(), 1, currentBorder.owner,
currentBorder.width, startSeg);
// Set border width at inline-end (table-wide and for the cell), but
// only if it's the largest we've encountered.
- info.SetTableIEndBorderWidth(rowB, currentBorder.width);
+ tableInfo.SetTableIEndBorderWidth(rowB, currentBorder.width);
+ if (!reset) {
+ info.ResetIEndBorderWidths();
+ reset = true;
+ }
info.SetIEndBorderWidths(currentBorder.width);
}
} else {
@@ -5306,6 +5402,7 @@ void nsTableFrame::CalcBCBorders() {
int32_t segLength = 0;
BCMapCellInfo ajaInfo(this);
BCMapCellInfo priorAjaInfo(this);
+ bool reset = false;
for (int32_t rowB = info.mRowIndex; rowB <= info.GetCellEndRowIndex();
rowB += segLength) {
// Grab the cell adjacent to our inline-end.
@@ -5325,9 +5422,14 @@ void nsTableFrame::CalcBCBorders() {
if (info.GetCellEndColIndex() < damageArea.EndCol() &&
rowB >= damageArea.StartRow() && rowB < damageArea.EndRow()) {
tableCellMap->SetBCBorderEdge(
- eLogicalSideIEnd, *iter.mCellMap, iter.mRowGroupStart, rowB,
+ LogicalSide::IEnd, *iter.mCellMap, iter.mRowGroupStart, rowB,
info.GetCellEndColIndex(), segLength, currentBorder.owner,
currentBorder.width, startSeg);
+ if (!reset) {
+ info.ResetIEndBorderWidths();
+ ajaInfo.ResetIStartBorderWidths();
+ reset = true;
+ }
info.SetIEndBorderWidths(currentBorder.width);
ajaInfo.SetIStartBorderWidths(currentBorder.width);
}
@@ -5346,7 +5448,7 @@ void nsTableFrame::CalcBCBorders() {
? &bStartCorners[info.GetCellEndColIndex() + 1]
: &bEndCorners[info.GetCellEndColIndex() +
1]; // From previous row.
- bStartIEndCorner->Update(eLogicalSideBEnd, currentBorder);
+ bStartIEndCorner->Update(LogicalSide::BEnd, currentBorder);
// If this is a rowspan, need to consider if this "corner" is generating
// an inline segment for the adjacent cell. e.g.
//
@@ -5360,7 +5462,7 @@ void nsTableFrame::CalcBCBorders() {
BCCellBorder adjacentBorder = ajaInfo.GetBStartInternalBorder();
currentBorder = CompareBorders(!CELL_CORNER, currentBorder,
adjacentBorder, INLINE_DIR);
- bStartIEndCorner->Update(eLogicalSideIEnd, currentBorder);
+ bStartIEndCorner->Update(LogicalSide::IEnd, currentBorder);
}
// Check that the spanned area is inside of the invalidation area
if (info.GetCellEndColIndex() < damageArea.EndCol() &&
@@ -5387,7 +5489,7 @@ void nsTableFrame::CalcBCBorders() {
BCCornerInfo& bEndIEndCorner =
(hitsSpanOnIEnd) ? bStartCorners[info.GetCellEndColIndex() + 1]
: bEndCorners[info.GetCellEndColIndex() + 1];
- bEndIEndCorner.Set(eLogicalSideBStart, currentBorder);
+ bEndIEndCorner.Set(LogicalSide::BStart, currentBorder);
priorAjaInfo = ajaInfo;
}
}
@@ -5400,23 +5502,25 @@ void nsTableFrame::CalcBCBorders() {
// cells and the table, row group, row
if (info.mNumTableRows == info.GetCellEndRowIndex() + 1) {
// touches bEnd edge of table
- if (!tableBorderReset[eLogicalSideBEnd]) {
- propData->mBEndBorderWidth = 0;
- tableBorderReset[eLogicalSideBEnd] = true;
+ uint8_t idxBEnd = static_cast<uint8_t>(LogicalSide::BEnd);
+ if (!tableBorderReset[idxBEnd]) {
+ tableInfo.ResetTableBEndBorderWidth();
+ tableBorderReset[idxBEnd] = true;
}
+ bool reset = false;
for (int32_t colIdx = info.mColIndex; colIdx <= info.GetCellEndColIndex();
colIdx++) {
info.SetColumn(colIdx);
BCCellBorder currentBorder = info.GetBEndEdgeBorder();
BCCornerInfo& bEndIStartCorner = bEndCorners[colIdx];
- bEndIStartCorner.Update(eLogicalSideIEnd, currentBorder);
+ bEndIStartCorner.Update(LogicalSide::IEnd, currentBorder);
tableCellMap->SetBCBorderCorner(
LogicalCorner::BEndIStart, *iter.mCellMap, iter.mRowGroupStart,
info.GetCellEndRowIndex(), colIdx,
LogicalSide(bEndIStartCorner.ownerSide), bEndIStartCorner.subWidth,
bEndIStartCorner.bevel);
BCCornerInfo& bEndIEndCorner = bEndCorners[colIdx + 1];
- bEndIEndCorner.Update(eLogicalSideIStart, currentBorder);
+ bEndIEndCorner.Update(LogicalSide::IStart, currentBorder);
// Store the block-end inline-end corner if it also is the block-end
// inline-end of the overall table.
if (info.mNumTableCols == colIdx + 1) {
@@ -5439,7 +5543,7 @@ void nsTableFrame::CalcBCBorders() {
}
// store the border segment in the cell map and update cellBorders
tableCellMap->SetBCBorderEdge(
- eLogicalSideBEnd, *iter.mCellMap, iter.mRowGroupStart,
+ LogicalSide::BEnd, *iter.mCellMap, iter.mRowGroupStart,
info.GetCellEndRowIndex(), colIdx, 1, currentBorder.owner,
currentBorder.width, startSeg);
// update lastBEndBorders
@@ -5449,12 +5553,17 @@ void nsTableFrame::CalcBCBorders() {
// Set border width at block-end (table-wide and for the cell), but
// only if it's the largest we've encountered.
+ if (!reset) {
+ info.ResetBEndBorderWidths();
+ reset = true;
+ }
info.SetBEndBorderWidths(currentBorder.width);
- info.SetTableBEndBorderWidth(currentBorder.width);
+ tableInfo.SetTableBEndBorderWidth(currentBorder.width);
}
} else {
int32_t segLength = 0;
BCMapCellInfo ajaInfo(this);
+ bool reset = false;
for (int32_t colIdx = info.mColIndex; colIdx <= info.GetCellEndColIndex();
colIdx += segLength) {
// Grab the cell adjacent to our block-end.
@@ -5486,12 +5595,12 @@ void nsTableFrame::CalcBCBorders() {
} else if (prevRowIndex < info.GetCellEndRowIndex() + 1) {
// spans below the cell to the iStart side
bStartCorners[colIdx] = bEndIStartCorner;
- bEndIStartCorner.Set(eLogicalSideIEnd, currentBorder);
+ bEndIStartCorner.Set(LogicalSide::IEnd, currentBorder);
update = false;
}
}
if (update) {
- bEndIStartCorner.Update(eLogicalSideIEnd, currentBorder);
+ bEndIStartCorner.Update(LogicalSide::IEnd, currentBorder);
}
// Check that the spanned area is inside of the invalidation area
if (info.GetCellEndRowIndex() < damageArea.EndRow() &&
@@ -5506,7 +5615,7 @@ void nsTableFrame::CalcBCBorders() {
// Propagate this segment down the colspan
for (int32_t c = colIdx + 1; c < colIdx + segLength; c++) {
BCCornerInfo& corner = bEndCorners[c];
- corner.Set(eLogicalSideIEnd, currentBorder);
+ corner.Set(LogicalSide::IEnd, currentBorder);
tableCellMap->SetBCBorderCorner(
LogicalCorner::BEndIStart, *iter.mCellMap, iter.mRowGroupStart,
info.GetCellEndRowIndex(), c, LogicalSide(corner.ownerSide),
@@ -5533,15 +5642,21 @@ void nsTableFrame::CalcBCBorders() {
if (info.GetCellEndRowIndex() < damageArea.EndRow() &&
colIdx >= damageArea.StartCol() && colIdx < damageArea.EndCol()) {
tableCellMap->SetBCBorderEdge(
- eLogicalSideBEnd, *iter.mCellMap, iter.mRowGroupStart,
+ LogicalSide::BEnd, *iter.mCellMap, iter.mRowGroupStart,
info.GetCellEndRowIndex(), colIdx, segLength, currentBorder.owner,
currentBorder.width, startSeg);
+
+ if (!reset) {
+ info.ResetBEndBorderWidths();
+ ajaInfo.ResetBStartBorderWidths();
+ reset = true;
+ }
info.SetBEndBorderWidths(currentBorder.width);
ajaInfo.SetBStartBorderWidths(currentBorder.width);
}
// update bEnd-iEnd corner
BCCornerInfo& bEndIEndCorner = bEndCorners[colIdx + segLength];
- bEndIEndCorner.Update(eLogicalSideIStart, currentBorder);
+ bEndIEndCorner.Update(LogicalSide::IStart, currentBorder);
}
}
// o------o------o
@@ -5570,7 +5685,7 @@ void nsTableFrame::CalcBCBorders() {
// new segment
if (iter.mCellMap) {
tableCellMap->ResetBStartStart(
- eLogicalSideBEnd, *iter.mCellMap, iter.mRowGroupStart,
+ LogicalSide::BEnd, *iter.mCellMap, iter.mRowGroupStart,
info.GetCellEndRowIndex(), nextColIndex);
}
}
@@ -6248,7 +6363,7 @@ static nscoord CalcVerCornerOffset(nsPresContext* aPresContext,
offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
} else {
offset =
- (eLogicalSideBStart == aCornerOwnerSide) ? smallHalf : -largeHalf;
+ (LogicalSide::BStart == aCornerOwnerSide) ? smallHalf : -largeHalf;
}
} else {
DivideBCBorderSize(aHorWidth, smallHalf, largeHalf);
@@ -6283,7 +6398,7 @@ static nscoord CalcHorCornerOffset(nsPresContext* aPresContext,
offset = (aIsStartOfSeg) ? -largeHalf : smallHalf;
} else {
offset =
- (eLogicalSideIStart == aCornerOwnerSide) ? smallHalf : -largeHalf;
+ (LogicalSide::IStart == aCornerOwnerSide) ? smallHalf : -largeHalf;
}
} else {
DivideBCBorderSize(aVerWidth, smallHalf, largeHalf);
@@ -6305,7 +6420,7 @@ BCBlockDirSeg::BCBlockDirSeg()
mCol = nullptr;
mFirstCell = mLastCell = mAjaCell = nullptr;
mOffsetI = mOffsetB = mLength = mWidth = mBStartBevelOffset = 0;
- mBStartBevelSide = eLogicalSideBStart;
+ mBStartBevelSide = LogicalSide::BStart;
mOwner = eCellOwner;
}
@@ -6322,7 +6437,7 @@ void BCBlockDirSeg::Start(BCPaintBorderIterator& aIter,
BCPixelSize aBlockSegISize,
BCPixelSize aInlineSegBSize,
Maybe<nscoord> aEmptyRowEndBSize) {
- LogicalSide ownerSide = eLogicalSideBStart;
+ LogicalSide ownerSide = LogicalSide::BStart;
bool bevel = false;
nscoord cornerSubWidth =
@@ -6339,7 +6454,7 @@ void BCBlockDirSeg::Start(BCPaintBorderIterator& aIter,
bStartBevel ? presContext->DevPixelsToAppUnits(maxInlineSegBSize) : 0;
// XXX this assumes that only corners where 2 segments join can be beveled
mBStartBevelSide =
- (aInlineSegBSize > 0) ? eLogicalSideIEnd : eLogicalSideIStart;
+ (aInlineSegBSize > 0) ? LogicalSide::IEnd : LogicalSide::IStart;
if (aEmptyRowEndBSize && *aEmptyRowEndBSize < offset) {
// This segment is starting from an empty row. This will require the the
// starting segment to overlap with the previously drawn segment, unless the
@@ -6390,7 +6505,7 @@ void BCBlockDirSeg::Initialize(BCPaintBorderIterator& aIter) {
*/
void BCBlockDirSeg::GetBEndCorner(BCPaintBorderIterator& aIter,
BCPixelSize aInlineSegBSize) {
- LogicalSide ownerSide = eLogicalSideBStart;
+ LogicalSide ownerSide = LogicalSide::BStart;
nscoord cornerSubWidth = 0;
bool bevel = false;
if (aIter.mBCData) {
@@ -6410,7 +6525,7 @@ Maybe<BCBorderParameters> BCBlockDirSeg::BuildBorderParameters(
// get the border style, color and paint the segment
LogicalSide side =
- aIter.IsDamageAreaIEndMost() ? eLogicalSideIEnd : eLogicalSideIStart;
+ aIter.IsDamageAreaIEndMost() ? LogicalSide::IEnd : LogicalSide::IStart;
int32_t relColIndex = aIter.GetRelativeColIndex();
nsTableColFrame* col = mCol;
if (!col) ABORT1(Nothing());
@@ -6430,7 +6545,7 @@ Maybe<BCBorderParameters> BCBlockDirSeg::BuildBorderParameters(
owner = aIter.mTable;
break;
case eAjaColGroupOwner:
- side = eLogicalSideIEnd;
+ side = LogicalSide::IEnd;
if (!aIter.IsTableIEndMost() && (relColIndex > 0)) {
col = aIter.mBlockDirInfo[relColIndex - 1].mCol;
}
@@ -6441,7 +6556,7 @@ Maybe<BCBorderParameters> BCBlockDirSeg::BuildBorderParameters(
}
break;
case eAjaColOwner:
- side = eLogicalSideIEnd;
+ side = LogicalSide::IEnd;
if (!aIter.IsTableIEndMost() && (relColIndex > 0)) {
col = aIter.mBlockDirInfo[relColIndex - 1].mCol;
}
@@ -6466,7 +6581,7 @@ Maybe<BCBorderParameters> BCBlockDirSeg::BuildBorderParameters(
owner = mFirstRow;
break;
case eAjaCellOwner:
- side = eLogicalSideIEnd;
+ side = LogicalSide::IEnd;
cell = mAjaCell;
[[fallthrough]];
case eCellOwner:
@@ -6487,7 +6602,7 @@ Maybe<BCBorderParameters> BCBlockDirSeg::BuildBorderParameters(
(mIsBEndBevel) ? presContext->DevPixelsToAppUnits(mBEndInlineSegBSize)
: 0;
LogicalSide bEndBevelSide =
- (aInlineSegBSize > 0) ? eLogicalSideIEnd : eLogicalSideIStart;
+ (aInlineSegBSize > 0) ? LogicalSide::IEnd : LogicalSide::IStart;
// Convert logical to physical sides/coordinates for DrawTableBorderSegment.
@@ -6733,11 +6848,11 @@ void BCBlockDirSeg::IncludeCurrentBorder(BCPaintBorderIterator& aIter) {
BCInlineDirSeg::BCInlineDirSeg()
: mIsIEndBevel(false),
mIEndBevelOffset(0),
- mIEndBevelSide(eLogicalSideBStart),
+ mIEndBevelSide(LogicalSide::BStart),
mEndOffset(0),
mOwner(eTableOwner) {
mOffsetI = mOffsetB = mLength = mWidth = mIStartBevelOffset = 0;
- mIStartBevelSide = eLogicalSideBStart;
+ mIStartBevelSide = LogicalSide::BStart;
mFirstCell = mAjaCell = nullptr;
}
@@ -6751,7 +6866,7 @@ void BCInlineDirSeg::Start(BCPaintBorderIterator& aIter,
BCBorderOwner aBorderOwner,
BCPixelSize aBEndBlockSegISize,
BCPixelSize aInlineSegBSize) {
- LogicalSide cornerOwnerSide = eLogicalSideBStart;
+ LogicalSide cornerOwnerSide = LogicalSide::BStart;
bool bevel = false;
mOwner = aBorderOwner;
@@ -6769,7 +6884,7 @@ void BCInlineDirSeg::Start(BCPaintBorderIterator& aIter,
(iStartBevel && (aInlineSegBSize > 0)) ? maxBlockSegISize : 0;
// XXX this assumes that only corners where 2 segments join can be beveled
mIStartBevelSide =
- (aBEndBlockSegISize > 0) ? eLogicalSideBEnd : eLogicalSideBStart;
+ (aBEndBlockSegISize > 0) ? LogicalSide::BEnd : LogicalSide::BStart;
mOffsetI += offset;
mLength = -offset;
mWidth = aInlineSegBSize;
@@ -6787,7 +6902,7 @@ void BCInlineDirSeg::Start(BCPaintBorderIterator& aIter,
*/
void BCInlineDirSeg::GetIEndCorner(BCPaintBorderIterator& aIter,
BCPixelSize aIStartSegISize) {
- LogicalSide ownerSide = eLogicalSideBStart;
+ LogicalSide ownerSide = LogicalSide::BStart;
nscoord cornerSubWidth = 0;
bool bevel = false;
if (aIter.mBCData) {
@@ -6805,7 +6920,7 @@ void BCInlineDirSeg::GetIEndCorner(BCPaintBorderIterator& aIter,
mIEndBevelOffset =
(mIsIEndBevel) ? presContext->DevPixelsToAppUnits(verWidth) : 0;
mIEndBevelSide =
- (aIStartSegISize > 0) ? eLogicalSideBEnd : eLogicalSideBStart;
+ (aIStartSegISize > 0) ? LogicalSide::BEnd : LogicalSide::BStart;
}
Maybe<BCBorderParameters> BCInlineDirSeg::BuildBorderParameters(
@@ -6814,7 +6929,7 @@ Maybe<BCBorderParameters> BCInlineDirSeg::BuildBorderParameters(
// get the border style, color and paint the segment
LogicalSide side =
- aIter.IsDamageAreaBEndMost() ? eLogicalSideBEnd : eLogicalSideBStart;
+ aIter.IsDamageAreaBEndMost() ? LogicalSide::BEnd : LogicalSide::BStart;
nsIFrame* rg = aIter.mRg;
if (!rg) ABORT1(Nothing());
nsIFrame* row = aIter.mRow;
@@ -6855,21 +6970,21 @@ Maybe<BCBorderParameters> BCInlineDirSeg::BuildBorderParameters(
owner = aIter.mTableFirstInFlow->GetColFrame(aIter.mColIndex - 1);
break;
case eAjaRowGroupOwner:
- side = eLogicalSideBEnd;
+ side = LogicalSide::BEnd;
rg = (aIter.IsTableBEndMost()) ? aIter.mRg : aIter.mPrevRg;
[[fallthrough]];
case eRowGroupOwner:
owner = rg;
break;
case eAjaRowOwner:
- side = eLogicalSideBEnd;
+ side = LogicalSide::BEnd;
row = (aIter.IsTableBEndMost()) ? aIter.mRow : aIter.mPrevRow;
[[fallthrough]];
case eRowOwner:
owner = row;
break;
case eAjaCellOwner:
- side = eLogicalSideBEnd;
+ side = LogicalSide::BEnd;
// if this is null due to the damage area origin-y > 0, then the border
// won't show up anyway
cell = mAjaCell;
@@ -6974,14 +7089,14 @@ void BCPaintBorderIterator::StoreColumnWidth(int32_t aIndex) {
* Determine if a block-dir segment owns the corner
*/
bool BCPaintBorderIterator::BlockDirSegmentOwnsCorner() {
- LogicalSide cornerOwnerSide = eLogicalSideBStart;
+ LogicalSide cornerOwnerSide = LogicalSide::BStart;
bool bevel = false;
if (mBCData) {
mBCData->GetCorner(cornerOwnerSide, bevel);
}
// unitialized ownerside, bevel
- return (eLogicalSideBStart == cornerOwnerSide) ||
- (eLogicalSideBEnd == cornerOwnerSide);
+ return (LogicalSide::BStart == cornerOwnerSide) ||
+ (LogicalSide::BEnd == cornerOwnerSide);
}
/**
diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp
index 1190561ee8..2447ceea15 100644
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -305,7 +305,7 @@ static nscoord GetBSizeOfRowsSpannedBelowFirst(
/**
* Post-reflow hook. This is where the table row does its post-processing
*/
-void nsTableRowFrame::DidResize() {
+void nsTableRowFrame::DidResize(ForceAlignTopForTableCell aForceAlignTop) {
// Resize and re-align the cell frames based on our row bsize
nsTableFrame* tableFrame = GetTableFrame();
@@ -369,7 +369,7 @@ void nsTableRowFrame::DidResize() {
// realign cell content based on the new bsize. We might be able to
// skip this if the bsize didn't change... maybe. Hard to tell.
- cellFrame->BlockDirAlignChild(wm, mMaxCellAscent);
+ cellFrame->BlockDirAlignChild(wm, mMaxCellAscent, aForceAlignTop);
// Always store the overflow, even if the height didn't change, since
// we'll lose part of our overflow area otherwise.
@@ -561,10 +561,10 @@ LogicalSides nsTableRowFrame::GetLogicalSkipSides() const {
}
if (GetPrevInFlow()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
if (GetNextInFlow()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
return skip;
}
@@ -581,11 +581,8 @@ nscoord nsTableRowFrame::CalcCellActualBSize(nsTableCellFrame* aCellFrame,
const auto& bsizeStyleCoord = position->BSize(aWM);
if (bsizeStyleCoord.ConvertsToLength()) {
- // In quirks mode, table cell isize should be content-box, but bsize
- // should be border-box.
- // Because of this historic anomaly, we do not use quirk.css
- // (since we can't specify one value of box-sizing for isize and another
- // for bsize)
+ // In quirks mode, table cell bsize should always be border-box.
+ // https://quirks.spec.whatwg.org/#the-table-cell-height-box-sizing-quirk
specifiedBSize = bsizeStyleCoord.ToLength();
if (PresContext()->CompatibilityMode() != eCompatibility_NavQuirks &&
position->mBoxSizing == StyleBoxSizing::Content) {
@@ -956,7 +953,6 @@ void nsTableRowFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTableRowFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
WritingMode wm = aReflowInput.GetWritingMode();
@@ -999,17 +995,14 @@ void nsTableRowFrame::Reflow(nsPresContext* aPresContext,
PushDirtyBitToAbsoluteFrames();
}
-/**
- * This function is called by the row group frame's SplitRowGroup() code when
- * pushing a row frame that has cell frames that span into it. The cell frame
- * should be reflowed with the specified height
- */
nscoord nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext,
const ReflowInput& aReflowInput,
bool aIsTopOfPage,
nsTableCellFrame* aCellFrame,
nscoord aAvailableBSize,
nsReflowStatus& aStatus) {
+ MOZ_ASSERT(aPresContext->IsPaginated(),
+ "ReflowCellFrame currently supports only paged media!");
MOZ_ASSERT(aAvailableBSize != NS_UNCONSTRAINEDSIZE,
"Why split cell frame if available bsize is unconstrained?");
WritingMode wm = aReflowInput.GetWritingMode();
@@ -1049,7 +1042,8 @@ nscoord nsTableRowFrame::ReflowCellFrame(nsPresContext* aPresContext,
// XXX What happens if this cell has 'vertical-align: baseline' ?
// XXX Why is it assumed that the cell's ascent hasn't changed ?
if (isCompleteAndNotTruncated) {
- aCellFrame->BlockDirAlignChild(wm, mMaxCellAscent);
+ aCellFrame->BlockDirAlignChild(wm, mMaxCellAscent,
+ ForceAlignTopForTableCell::Yes);
}
nsTableFrame::InvalidateTableFrame(
diff --git a/layout/tables/nsTableRowFrame.h b/layout/tables/nsTableRowFrame.h
index 1d68a534c3..e24be1ea23 100644
--- a/layout/tables/nsTableRowFrame.h
+++ b/layout/tables/nsTableRowFrame.h
@@ -15,6 +15,11 @@ class nsTableCellFrame;
namespace mozilla {
class PresShell;
struct TableCellReflowInput;
+
+// Yes if table-cells should use 'vertical-align:top' in
+// nsTableCellFrame::BlockDirAlignChild(). This is a hack to workaround our
+// current table row group fragmentation to avoid data loss.
+enum class ForceAlignTopForTableCell : uint8_t { No, Yes };
} // namespace mozilla
/**
@@ -104,7 +109,8 @@ class nsTableRowFrame : public nsContainerFrame {
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) override;
- void DidResize();
+ void DidResize(mozilla::ForceAlignTopForTableCell aForceAlignTop =
+ mozilla::ForceAlignTopForTableCell::No);
#ifdef DEBUG_FRAME_DUMP
nsresult GetFrameName(nsAString& aResult) const override;
@@ -145,7 +151,11 @@ class nsTableRowFrame : public nsContainerFrame {
// See nsTableFrame.h
void AddDeletedRowIndex();
- /** used by row group frame code */
+ /**
+ * This function is called by the row group frame's SplitRowGroup() code when
+ * pushing a row frame that has cell frames that span into it. The cell frame
+ * should be reflowed with the specified available block-size.
+ */
nscoord ReflowCellFrame(nsPresContext* aPresContext,
const ReflowInput& aReflowInput, bool aIsTopOfPage,
nsTableCellFrame* aCellFrame, nscoord aAvailableBSize,
diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp
index f8dac61386..45cca8c8fa 100644
--- a/layout/tables/nsTableRowGroupFrame.cpp
+++ b/layout/tables/nsTableRowGroupFrame.cpp
@@ -254,10 +254,10 @@ LogicalSides nsTableRowGroupFrame::GetLogicalSkipSides() const {
}
if (GetPrevInFlow()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
if (GetNextInFlow()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
return skip;
}
@@ -1122,7 +1122,7 @@ void nsTableRowGroupFrame::SplitRowGroup(nsPresContext* aPresContext,
FinishReflowChild(rowFrame, aPresContext, rowMetrics, &rowReflowInput,
wm, dummyPos, dummyContainerSize,
ReflowChildFlags::NoMoveFrame);
- rowFrame->DidResize();
+ rowFrame->DidResize(ForceAlignTopForTableCell::Yes);
if (!aRowForcedPageBreak && !aStatus.IsFullyComplete() &&
ShouldAvoidBreakInside(aReflowInput)) {
@@ -1324,7 +1324,6 @@ void nsTableRowGroupFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTableRowGroupFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// Row geometry may be going to change so we need to invalidate any row
diff --git a/layout/tables/nsTableWrapperFrame.cpp b/layout/tables/nsTableWrapperFrame.cpp
index a3e957c4fd..aa898ddf6f 100644
--- a/layout/tables/nsTableWrapperFrame.cpp
+++ b/layout/tables/nsTableWrapperFrame.cpp
@@ -242,7 +242,6 @@ ComputedStyle* nsTableWrapperFrame::GetParentComputedStyle(
nscoord nsTableWrapperFrame::GetMinISize(gfxContext* aRenderingContext) {
nscoord iSize = nsLayoutUtils::IntrinsicForContainer(
aRenderingContext, InnerTableFrame(), IntrinsicISizeType::MinISize);
- DISPLAY_MIN_INLINE_SIZE(this, iSize);
if (mCaptionFrames.NotEmpty()) {
nscoord capISize = nsLayoutUtils::IntrinsicForContainer(
aRenderingContext, mCaptionFrames.FirstChild(),
@@ -256,10 +255,7 @@ nscoord nsTableWrapperFrame::GetMinISize(gfxContext* aRenderingContext) {
/* virtual */
nscoord nsTableWrapperFrame::GetPrefISize(gfxContext* aRenderingContext) {
- nscoord maxISize;
- DISPLAY_PREF_INLINE_SIZE(this, maxISize);
-
- maxISize = nsLayoutUtils::IntrinsicForContainer(
+ nscoord maxISize = nsLayoutUtils::IntrinsicForContainer(
aRenderingContext, InnerTableFrame(), IntrinsicISizeType::PrefISize);
if (mCaptionFrames.NotEmpty()) {
// Don't let the caption's pref isize expand the table's pref isize.
@@ -547,7 +543,7 @@ ComputeSizeFlags nsTableWrapperFrame::CreateComputeSizeFlagsForChild() const {
// Shrink-wrap child frames by default, except if we're a stretched grid item.
if (MOZ_UNLIKELY(IsGridItem())) {
auto* gridContainer = static_cast<nsGridContainerFrame*>(GetParent());
- if (gridContainer->GridItemShouldStretch(this, eLogicalAxisInline)) {
+ if (gridContainer->GridItemShouldStretch(this, LogicalAxis::Inline)) {
return {};
}
}
@@ -691,7 +687,6 @@ void nsTableWrapperFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsTableWrapperFrame");
- DISPLAY_REFLOW(aPresContext, this, aOuterRI, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
// Initialize out parameters
diff --git a/layout/tools/reftest/jar.mn b/layout/tools/reftest/jar.mn
index b879ac1646..4fc1b7e10f 100644
--- a/layout/tools/reftest/jar.mn
+++ b/layout/tools/reftest/jar.mn
@@ -25,7 +25,6 @@ reftest.jar:
content/xul (../../reftests/xul/*)
content/xul/reftest (../../xul/reftest/*)
content/toolkit/reftests (../../../toolkit/content/tests/reftests/*)
- content/osx-theme (../../../toolkit/themes/osx/reftests/*)
content/reftest.xhtml (reftest.xhtml)
# Crash tests
diff --git a/layout/tools/reftest/mach_commands.py b/layout/tools/reftest/mach_commands.py
index 8cb1164332..dd4c8ea63a 100644
--- a/layout/tools/reftest/mach_commands.py
+++ b/layout/tools/reftest/mach_commands.py
@@ -160,10 +160,6 @@ class ReftestRunner(MozbuildObject):
args.e10s = False
print("using e10s=False for non-geckoview app")
- # Disable fission until geckoview supports fission by default.
- # Need fission on Android? Use '--setpref fission.autostart=true'
- args.disableFission = True
-
# A symlink and some path manipulations are required so that test
# manifests can be found both locally and remotely (via a url)
# using the same relative path.
diff --git a/layout/tools/reftest/manifest.sys.mjs b/layout/tools/reftest/manifest.sys.mjs
index 4be0afde57..09ccefd9f7 100644
--- a/layout/tools/reftest/manifest.sys.mjs
+++ b/layout/tools/reftest/manifest.sys.mjs
@@ -155,6 +155,7 @@ function ReadManifest(aURL, aFilter, aManifestID) {
var origLength = items.length;
items = defaults.concat(items);
+ var modifiers = [...items];
while (
items[0].match(
/^(fails|needs-focus|random|skip|asserts|slow|require-or|silentfail|pref|test-pref|ref-pref|fuzzy|chaos-mode|wr-capture|wr-capture-ref|noautofuzz)/
@@ -492,6 +493,7 @@ function ReadManifest(aURL, aFilter, aManifestID) {
chaosMode,
wrCapture,
noAutoFuzz,
+ modifiers,
},
aFilter,
aManifestID
@@ -572,6 +574,7 @@ function ReadManifest(aURL, aFilter, aManifestID) {
chaosMode,
wrCapture,
noAutoFuzz,
+ modifiers,
},
aFilter,
aManifestID
@@ -612,22 +615,7 @@ function BuildConditionSandbox(aURL) {
sandbox.isDebugBuild = g.debug.isDebugBuild;
sandbox.isCoverageBuild = g.isCoverageBuild;
- sandbox.xulRuntime = Cu.cloneInto(
- {
- widgetToolkit: Services.appinfo.widgetToolkit,
- OS: Services.appinfo.OS,
- XPCOMABI: Services.appinfo.XPCOMABI,
- },
- sandbox
- );
-
- sandbox.smallScreen = false;
- if (
- g.containingWindow.innerWidth < 800 ||
- g.containingWindow.innerHeight < 1000
- ) {
- sandbox.smallScreen = true;
- }
+ sandbox.xulRuntime = {};
var gfxInfo =
NS_GFXINFO_CONTRACTID in Cc &&
@@ -640,57 +628,24 @@ function BuildConditionSandbox(aURL) {
};
try {
- sandbox.d2d = readGfxInfo(gfxInfo, "D2DEnabled");
- sandbox.dwrite = readGfxInfo(gfxInfo, "DWriteEnabled");
- sandbox.embeddedInFirefoxReality = readGfxInfo(
- gfxInfo,
- "EmbeddedInFirefoxReality"
- );
- } catch (e) {
- sandbox.d2d = false;
- sandbox.dwrite = false;
- sandbox.embeddedInFirefoxReality = false;
- }
-
- var canvasBackend = readGfxInfo(gfxInfo, "AzureCanvasBackend");
- var contentBackend = readGfxInfo(gfxInfo, "AzureContentBackend");
-
- sandbox.gpuProcess = gfxInfo.usingGPUProcess;
- sandbox.azureCairo = canvasBackend == "cairo";
- sandbox.azureSkia = canvasBackend == "skia";
- sandbox.skiaContent = contentBackend == "skia";
- sandbox.azureSkiaGL = false;
- // true if we are using the same Azure backend for rendering canvas and content
- sandbox.contentSameGfxBackendAsCanvas =
- contentBackend == canvasBackend ||
- (contentBackend == "none" && canvasBackend == "cairo");
-
- try {
var windowProtocol = readGfxInfo(gfxInfo, "windowProtocol");
sandbox.wayland = windowProtocol == "wayland";
} catch (e) {
sandbox.wayland = false;
}
- sandbox.remoteCanvas =
- Services.prefs.getBoolPref("gfx.canvas.remote") &&
- sandbox.d2d &&
- sandbox.gpuProcess;
+ sandbox.mozinfo = Services.prefs.getStringPref("sandbox.mozinfo", null);
+ sandbox.os_version = sandbox.mozinfo.os_version;
- sandbox.layersGPUAccelerated = g.windowUtils.layerManagerType != "Basic";
sandbox.d3d11 = g.windowUtils.layerManagerType == "Direct3D 11";
- sandbox.d3d9 = g.windowUtils.layerManagerType == "Direct3D 9";
- sandbox.layersOpenGL = g.windowUtils.layerManagerType == "OpenGL";
sandbox.swgl = g.windowUtils.layerManagerType.startsWith(
"WebRender (Software"
);
- sandbox.layersOMTC = !!g.windowUtils.layerManagerRemote;
// Shortcuts for widget toolkits.
sandbox.Android = Services.appinfo.OS == "Android";
sandbox.cocoaWidget = Services.appinfo.widgetToolkit == "cocoa";
sandbox.gtkWidget = Services.appinfo.widgetToolkit == "gtk";
- sandbox.qtWidget = Services.appinfo.widgetToolkit == "qt";
sandbox.winWidget = Services.appinfo.widgetToolkit == "windows";
sandbox.is64Bit = Services.appinfo.is64Bit;
@@ -698,27 +653,11 @@ function BuildConditionSandbox(aURL) {
// Use this to annotate reftests that fail in drawSnapshot, but
// the reason hasn't been investigated (or fixed) yet.
sandbox.useDrawSnapshot = g.useDrawSnapshot;
- // Use this to annotate reftests that use functionality
- // that isn't available to drawSnapshot (like any sort of
- // compositor feature such as async scrolling).
- sandbox.unsupportedWithDrawSnapshot = g.useDrawSnapshot;
-
- sandbox.retainedDisplayList =
- Services.prefs.getBoolPref("layout.display-list.retain") &&
- !sandbox.useDrawSnapshot;
-
- // Needed to specifically test the new and old behavior. This will eventually be removed.
- sandbox.retainedDisplayListNew =
- sandbox.retainedDisplayList &&
- Services.prefs.getBoolPref("layout.display-list.retain.sc");
// GeckoView is currently uniquely identified by "android + e10s" but
// we might want to make this condition more precise in the future.
sandbox.geckoview = sandbox.Android && g.browserIsRemote;
- // Scrollbars that are semi-transparent. See bug 1169666.
- sandbox.transparentScrollbars = Services.appinfo.widgetToolkit == "gtk";
-
if (sandbox.Android) {
sandbox.AndroidVersion = Services.sysinfo.getPropertyAsInt32("version");
@@ -731,35 +670,15 @@ function BuildConditionSandbox(aURL) {
// Some reftests need extra fuzz on the Android 13 Pixel 5 devices.
sandbox.Android13 = sandbox.AndroidVersion == "33";
- sandbox.MinGW =
- sandbox.winWidget && Services.sysinfo.getPropertyAsBool("isMinGW");
-
sandbox.AddressSanitizer = AppConstants.ASAN;
sandbox.ThreadSanitizer = AppConstants.TSAN;
sandbox.webrtc = AppConstants.MOZ_WEBRTC;
- sandbox.jxl = AppConstants.MOZ_JXL;
-
- sandbox.compareRetainedDisplayLists = g.compareRetainedDisplayLists;
sandbox.release_or_beta = AppConstants.RELEASE_OR_BETA;
var hh = Cc[NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX + "http"].getService(
Ci.nsIHttpProtocolHandler
);
- var httpProps = [
- "userAgent",
- "appName",
- "appVersion",
- "vendor",
- "vendorSub",
- "product",
- "productSub",
- "oscpu",
- "language",
- "misc",
- ];
- sandbox.http = new sandbox.Object();
- httpProps.forEach(x => (sandbox.http[x] = hh[x]));
// Set OSX to be the Mac OS X version, as an integer, or undefined
// for other platforms. The integer is formed by 100 times the
@@ -776,11 +695,6 @@ function BuildConditionSandbox(aURL) {
false
);
- sandbox.gpuProcessForceEnabled = Services.prefs.getBoolPref(
- "layers.gpu-process.force-enabled",
- false
- );
-
sandbox.prefs = Cu.cloneInto(
{
getBoolPref(p) {
@@ -794,28 +708,11 @@ function BuildConditionSandbox(aURL) {
{ cloneFunctions: true }
);
- // Tests shouldn't care about this except for when they need to
- // crash the content process
- sandbox.browserIsRemote = g.browserIsRemote;
- sandbox.browserIsFission = g.browserIsFission;
-
- try {
- sandbox.asyncPan =
- g.containingWindow.docShell.asyncPanZoomEnabled &&
- !sandbox.useDrawSnapshot;
- } catch (e) {
- sandbox.asyncPan = false;
- }
-
- // Graphics features
- sandbox.usesRepeatResampling = sandbox.d2d;
-
// Running in a test-verify session?
sandbox.verify = Services.prefs.getBoolPref("reftest.verify", false);
// Running with a variant enabled?
sandbox.fission = Services.appinfo.fissionAutostart;
- sandbox.serviceWorkerE10s = true;
if (!g.dumpedConditionSandbox) {
g.logger.info(
diff --git a/layout/tools/reftest/reftest.sys.mjs b/layout/tools/reftest/reftest.sys.mjs
index 1040470967..12bdab98f9 100644
--- a/layout/tools/reftest/reftest.sys.mjs
+++ b/layout/tools/reftest/reftest.sys.mjs
@@ -1423,7 +1423,9 @@ function RecordResult(testRunTime, errorMsg, typeSpecificResults) {
// branch, 'equal' must be false so let's assert that to guard
// against logic errors.
if (equal) {
- throw new Error("Logic error in reftest.jsm fuzzy test handling!");
+ throw new Error(
+ "Logic error in reftest.sys.mjs fuzzy test handling!"
+ );
}
output = { s: ["PASS", "FAIL"], n: "UnexpectedPass" };
} else {
@@ -1510,6 +1512,8 @@ function RecordResult(testRunTime, errorMsg, typeSpecificResults) {
extra.image1 = image1;
}
}
+ extra.modifiers = g.urls[0].modifiers;
+
logger.testStatus(
g.urls[0].identifier,
message,
diff --git a/layout/tools/reftest/reftestcommandline.py b/layout/tools/reftest/reftestcommandline.py
index e2f0baff8c..13154b2456 100644
--- a/layout/tools/reftest/reftestcommandline.py
+++ b/layout/tools/reftest/reftestcommandline.py
@@ -478,11 +478,6 @@ class DesktopArgumentsParser(ReftestArgumentsParser):
help="run tests in parallel if possible",
)
- def _prefs_gpu(self):
- if mozinfo.os != "win":
- return ["layers.acceleration.force-enabled=true"]
- return []
-
def validate(self, options, reftest):
super(DesktopArgumentsParser, self).validate(options, reftest)
diff --git a/layout/tools/reftest/runreftest.py b/layout/tools/reftest/runreftest.py
index cf314c99b5..cac1f7dd3c 100644
--- a/layout/tools/reftest/runreftest.py
+++ b/layout/tools/reftest/runreftest.py
@@ -302,6 +302,7 @@ class RefTest(object):
self.outputHandler = None
self.testDumpFile = os.path.join(tempfile.gettempdir(), "reftests.json")
self.currentManifest = "No test started"
+ self.gtkTheme = self.getGtkTheme()
self.run_by_manifest = True
if suite in ("crashtest", "jstestbrowser"):
@@ -328,6 +329,17 @@ class RefTest(object):
"reftest harness", options, {"tbpl": sys.stdout}, fmt_options
)
+ def getGtkTheme(self):
+ if not platform.system() == "Linux":
+ return ""
+
+ theme_cmd = "gsettings get org.gnome.desktop.interface gtk-theme"
+ theme = subprocess.check_output(theme_cmd, shell=True, universal_newlines=True)
+ if theme:
+ theme = theme.strip("\n")
+ theme = theme.strip("'")
+ return theme.strip()
+
def getFullPath(self, path):
"Get an absolute path relative to self.oldcwd."
return os.path.normpath(os.path.join(self.oldcwd, os.path.expanduser(path)))
@@ -357,14 +369,14 @@ class RefTest(object):
locations.add_host(server, scheme="http", port=port)
locations.add_host(server, scheme="https", port=port)
- sandbox_whitelist_paths = options.sandboxReadWhitelist
+ sandbox_allowlist_paths = options.sandboxReadWhitelist
if platform.system() == "Linux" or platform.system() in (
"Windows",
"Microsoft",
):
# Trailing slashes are needed to indicate directories on Linux and Windows
- sandbox_whitelist_paths = map(
- lambda p: os.path.join(p, ""), sandbox_whitelist_paths
+ sandbox_allowlist_paths = map(
+ lambda p: os.path.join(p, ""), sandbox_allowlist_paths
)
addons = []
@@ -390,7 +402,7 @@ class RefTest(object):
kwargs = {
"addons": addons,
"locations": locations,
- "whitelistpaths": sandbox_whitelist_paths,
+ "allowlistpaths": sandbox_allowlist_paths,
}
if profile_to_clone:
profile = mozprofile.Profile.clone(profile_to_clone, **kwargs)
@@ -462,6 +474,9 @@ class RefTest(object):
# config specific flags
prefs["sandbox.apple_silicon"] = mozinfo.info.get("apple_silicon", False)
+ prefs["sandbox.mozinfo"] = json.dumps(mozinfo.info)
+ prefs["sandbox.os_version"] = mozinfo.info.get("os_version", "")
+
# Set tests to run or manifests to parse.
if tests:
testlist = os.path.join(profile.profile, "reftests.json")
@@ -482,22 +497,6 @@ class RefTest(object):
if options.thisChunk:
prefs["reftest.thisChunk"] = options.thisChunk
- # Bug 1262954: For winXP + e10s disable acceleration
- if (
- platform.system() in ("Windows", "Microsoft")
- and "5.1" in platform.version()
- and options.e10s
- ):
- prefs["layers.acceleration.disabled"] = True
-
- # Bug 1300355: Disable canvas cache for win7 as it uses
- # too much memory and causes OOMs.
- if (
- platform.system() in ("Windows", "Microsoft")
- and "6.1" in platform.version()
- ):
- prefs["reftest.nocache"] = True
-
if options.marionette:
# options.marionette can specify host:port
port = options.marionette.split(":")[1]
@@ -552,6 +551,9 @@ class RefTest(object):
browserEnv["TZ"] = "PST8PDT"
browserEnv["LC_ALL"] = "en_US.UTF-8"
+ # This should help with consistency
+ browserEnv["GTK_THEME"] = "Adwaita"
+
for v in options.environment:
ix = v.find("=")
if ix <= 0:
@@ -1113,6 +1115,13 @@ class RefTest(object):
overall = 0
status = -1
for manifest, tests in tests_by_manifest.items():
+ if self.getGtkTheme() != self.gtkTheme:
+ self.log.error(
+ "Theme (%s) has changed to (%s), terminating job as this is unstable"
+ % (self.gtkTheme, self.getGtkTheme())
+ )
+ return 1
+
self.log.info("Running tests in {}".format(manifest))
self.currentManifest = manifest
status = run(tests=tests)
diff --git a/layout/xul/nsMenuPopupFrame.cpp b/layout/xul/nsMenuPopupFrame.cpp
index 8ebb8b01d5..17993c8466 100644
--- a/layout/xul/nsMenuPopupFrame.cpp
+++ b/layout/xul/nsMenuPopupFrame.cpp
@@ -491,19 +491,13 @@ void nsMenuPopupFrame::TweakMinPrefISize(nscoord& aSize) {
}
nscoord nsMenuPopupFrame::GetMinISize(gfxContext* aRC) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
-
- result = nsBlockFrame::GetMinISize(aRC);
+ nscoord result = nsBlockFrame::GetMinISize(aRC);
TweakMinPrefISize(result);
return result;
}
nscoord nsMenuPopupFrame::GetPrefISize(gfxContext* aRC) {
- nscoord result;
- DISPLAY_PREF_INLINE_SIZE(this, result);
-
- result = nsBlockFrame::GetPrefISize(aRC);
+ nscoord result = nsBlockFrame::GetPrefISize(aRC);
TweakMinPrefISize(result);
return result;
}
@@ -514,7 +508,6 @@ void nsMenuPopupFrame::Reflow(nsPresContext* aPresContext,
nsReflowStatus& aStatus) {
MarkInReflow();
DO_GLOBAL_REFLOW_COUNT("nsMenuPopupFrame");
- DISPLAY_REFLOW(aPresContext, this, aReflowInput, aDesiredSize, aStatus);
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
const auto wm = GetWritingMode();
@@ -2186,6 +2179,12 @@ nsMargin nsMenuPopupFrame::GetMargin() const {
margin.left += auOffset.x;
margin.right += auOffset.x;
}
+ if (mPopupType == PopupType::Tooltip && !IsAnchored()) {
+ const auto auOffset =
+ CSSPixel::ToAppUnits(LookAndFeel::TooltipOffsetVertical());
+ margin.top += auOffset;
+ margin.bottom += auOffset;
+ }
return margin;
}
@@ -2246,7 +2245,8 @@ void nsMenuPopupFrame::MoveTo(const CSSPoint& aPos, bool aUpdateAttrs,
void nsMenuPopupFrame::MoveToAnchor(nsIContent* aAnchorContent,
const nsAString& aPosition, int32_t aXPos,
int32_t aYPos, bool aAttributesOverride) {
- NS_ASSERTION(IsVisible(), "popup must be visible to move it");
+ NS_ASSERTION(IsVisibleOrShowing(),
+ "popup must be visible or showing to move it");
nsPopupState oldstate = mPopupState;
InitializePopup(aAnchorContent, mTriggerContent, aPosition, aXPos, aYPos,
diff --git a/layout/xul/nsXULPopupManager.cpp b/layout/xul/nsXULPopupManager.cpp
index 332d60d363..a6dbeadca7 100644
--- a/layout/xul/nsXULPopupManager.cpp
+++ b/layout/xul/nsXULPopupManager.cpp
@@ -49,6 +49,7 @@
#include "mozilla/dom/XULMenuElement.h"
#include "mozilla/dom/XULMenuBarElement.h"
#include "mozilla/dom/XULPopupElement.h"
+#include "mozilla/AutoRestore.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/LookAndFeel.h"
diff --git a/layout/xul/tree/crashtests/crashtests.list b/layout/xul/tree/crashtests/crashtests.list
index 0b79916cd2..1644c61bf2 100644
--- a/layout/xul/tree/crashtests/crashtests.list
+++ b/layout/xul/tree/crashtests/crashtests.list
@@ -13,5 +13,5 @@ load 399715-1.xhtml
load chrome://reftest/content/crashtests/layout/xul/tree/crashtests/414170-1.xhtml
load 479931-1.xhtml
load 585815.html
-skip-if(wayland) pref(widget.windows.window_occlusion_tracking.enabled,false) load 601427.html # Bug 1819154, wayland: Bug 1857258
+load 601427.html
load chrome://reftest/content/crashtests/layout/xul/tree/crashtests/730441-3.xhtml
diff --git a/layout/xul/tree/nsTreeBodyFrame.cpp b/layout/xul/tree/nsTreeBodyFrame.cpp
index 5ccc1468cc..a7eba30f8b 100644
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -47,13 +47,11 @@
#include "nsContainerFrame.h"
#include "nsView.h"
#include "nsViewManager.h"
-#include "nsVariant.h"
#include "nsWidgetsCID.h"
#include "nsIFrameInlines.h"
#include "nsTreeContentView.h"
#include "nsTreeUtils.h"
#include "nsStyleConsts.h"
-#include "nsITheme.h"
#include "imgIRequest.h"
#include "imgIContainer.h"
#include "mozilla/dom/NodeInfo.h"
@@ -1711,115 +1709,133 @@ void nsTreeBodyFrame::PrefillPropertyArray(int32_t aRowIndex,
mScratchArray.Clear();
// focus
- if (mFocused)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::focus);
- else
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::blur);
+ if (mFocused) {
+ mScratchArray.AppendElement(nsGkAtoms::focus);
+ } else {
+ mScratchArray.AppendElement(nsGkAtoms::blur);
+ }
// sort
bool sorted = false;
mView->IsSorted(&sorted);
- if (sorted) mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::sorted);
+ if (sorted) {
+ mScratchArray.AppendElement(nsGkAtoms::sorted);
+ }
// drag session
- if (mSlots && mSlots->mIsDragging)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::dragSession);
+ if (mSlots && mSlots->mIsDragging) {
+ mScratchArray.AppendElement(nsGkAtoms::dragSession);
+ }
if (aRowIndex != -1) {
- if (aRowIndex == mMouseOverRow)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::hover);
+ if (aRowIndex == mMouseOverRow) {
+ mScratchArray.AppendElement(nsGkAtoms::hover);
+ }
nsCOMPtr<nsITreeSelection> selection = GetSelection();
if (selection) {
// selected
bool isSelected;
selection->IsSelected(aRowIndex, &isSelected);
- if (isSelected)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::selected);
+ if (isSelected) {
+ mScratchArray.AppendElement(nsGkAtoms::selected);
+ }
// current
int32_t currentIndex;
selection->GetCurrentIndex(&currentIndex);
- if (aRowIndex == currentIndex)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::current);
+ if (aRowIndex == currentIndex) {
+ mScratchArray.AppendElement(nsGkAtoms::current);
+ }
}
// container or leaf
bool isContainer = false;
mView->IsContainer(aRowIndex, &isContainer);
if (isContainer) {
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::container);
+ mScratchArray.AppendElement(nsGkAtoms::container);
// open or closed
bool isOpen = false;
mView->IsContainerOpen(aRowIndex, &isOpen);
- if (isOpen)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::open);
- else
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::closed);
+ if (isOpen) {
+ mScratchArray.AppendElement(nsGkAtoms::open);
+ } else {
+ mScratchArray.AppendElement(nsGkAtoms::closed);
+ }
} else {
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::leaf);
+ mScratchArray.AppendElement(nsGkAtoms::leaf);
}
// drop orientation
if (mSlots && mSlots->mDropAllowed && mSlots->mDropRow == aRowIndex) {
- if (mSlots->mDropOrient == nsITreeView::DROP_BEFORE)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::dropBefore);
- else if (mSlots->mDropOrient == nsITreeView::DROP_ON)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::dropOn);
- else if (mSlots->mDropOrient == nsITreeView::DROP_AFTER)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::dropAfter);
+ if (mSlots->mDropOrient == nsITreeView::DROP_BEFORE) {
+ mScratchArray.AppendElement(nsGkAtoms::dropBefore);
+ } else if (mSlots->mDropOrient == nsITreeView::DROP_ON) {
+ mScratchArray.AppendElement(nsGkAtoms::dropOn);
+ } else if (mSlots->mDropOrient == nsITreeView::DROP_AFTER) {
+ mScratchArray.AppendElement(nsGkAtoms::dropAfter);
+ }
}
// odd or even
- if (aRowIndex % 2)
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::odd);
- else
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::even);
+ if (aRowIndex % 2) {
+ mScratchArray.AppendElement(nsGkAtoms::odd);
+ } else {
+ mScratchArray.AppendElement(nsGkAtoms::even);
+ }
XULTreeElement* tree = GetBaseElement();
if (tree && tree->HasAttr(nsGkAtoms::editing)) {
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::editing);
+ mScratchArray.AppendElement(nsGkAtoms::editing);
}
// multiple columns
- if (mColumns->GetColumnAt(1))
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::multicol);
+ if (mColumns->GetColumnAt(1)) {
+ mScratchArray.AppendElement(nsGkAtoms::multicol);
+ }
}
if (aCol) {
mScratchArray.AppendElement(aCol->GetAtom());
- if (aCol->IsPrimary())
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::primary);
+ if (aCol->IsPrimary()) {
+ mScratchArray.AppendElement(nsGkAtoms::primary);
+ }
if (aCol->GetType() == TreeColumn_Binding::TYPE_CHECKBOX) {
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::checkbox);
+ mScratchArray.AppendElement(nsGkAtoms::checkbox);
if (aRowIndex != -1) {
nsAutoString value;
mView->GetCellValue(aRowIndex, aCol, value);
- if (value.EqualsLiteral("true"))
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::checked);
+ if (value.EqualsLiteral("true")) {
+ mScratchArray.AppendElement(nsGkAtoms::checked);
+ }
}
}
+ if (aCol->mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::ordinal,
+ u"1"_ns, eIgnoreCase)) {
+ mScratchArray.AppendElement(nsGkAtoms::firstColumn);
+ }
+
// Read special properties from attributes on the column content node
if (aCol->mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::insertbefore,
- nsGkAtoms::_true, eCaseMatters))
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::insertbefore);
+ nsGkAtoms::_true, eCaseMatters)) {
+ mScratchArray.AppendElement(nsGkAtoms::insertbefore);
+ }
if (aCol->mContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::insertafter,
- nsGkAtoms::_true, eCaseMatters))
- mScratchArray.AppendElement((nsStaticAtom*)nsGkAtoms::insertafter);
+ nsGkAtoms::_true, eCaseMatters)) {
+ mScratchArray.AppendElement(nsGkAtoms::insertafter);
+ }
}
}
-nsITheme* nsTreeBodyFrame::GetTwistyRect(int32_t aRowIndex,
- nsTreeColumn* aColumn,
- nsRect& aImageRect,
- nsRect& aTwistyRect,
- nsPresContext* aPresContext,
- ComputedStyle* aTwistyContext) {
+void nsTreeBodyFrame::GetTwistyRect(int32_t aRowIndex, nsTreeColumn* aColumn,
+ nsRect& aImageRect, nsRect& aTwistyRect,
+ nsPresContext* aPresContext,
+ ComputedStyle* aTwistyContext) {
// The twisty rect extends all the way to the end of the cell. This is
// incorrect. We need to determine the twisty rect's true width. This is
// done by examining the ComputedStyle for a width first. If it has one, we
@@ -1828,40 +1844,14 @@ nsITheme* nsTreeBodyFrame::GetTwistyRect(int32_t aRowIndex,
// a -moz-appearance involved, adjust the rect by the minimum widget size
// provided by the theme implementation.
aImageRect = GetImageSize(aRowIndex, aColumn, true, aTwistyContext);
- if (aImageRect.height > aTwistyRect.height)
+ if (aImageRect.height > aTwistyRect.height) {
aImageRect.height = aTwistyRect.height;
- if (aImageRect.width > aTwistyRect.width)
+ }
+ if (aImageRect.width > aTwistyRect.width) {
aImageRect.width = aTwistyRect.width;
- else
+ } else {
aTwistyRect.width = aImageRect.width;
-
- bool useTheme = false;
- nsITheme* theme = nullptr;
- StyleAppearance appearance =
- aTwistyContext->StyleDisplay()->EffectiveAppearance();
- if (appearance != StyleAppearance::None) {
- theme = aPresContext->Theme();
- if (theme->ThemeSupportsWidget(aPresContext, nullptr, appearance))
- useTheme = true;
- }
-
- if (useTheme) {
- LayoutDeviceIntSize minTwistySizePx =
- theme->GetMinimumWidgetSize(aPresContext, this, appearance);
-
- // GMWS() returns size in pixels, we need to convert it back to app units
- nsSize minTwistySize;
- minTwistySize.width =
- aPresContext->DevPixelsToAppUnits(minTwistySizePx.width);
- minTwistySize.height =
- aPresContext->DevPixelsToAppUnits(minTwistySizePx.height);
-
- if (aTwistyRect.width < minTwistySize.width) {
- aTwistyRect.width = minTwistySize.width;
- }
}
-
- return useTheme ? theme : nullptr;
}
nsresult nsTreeBodyFrame::GetImage(int32_t aRowIndex, nsTreeColumn* aCol,
@@ -2693,21 +2683,8 @@ ImgDrawResult nsTreeBodyFrame::PaintRow(int32_t aRowIndex,
ImgDrawResult result = ImgDrawResult::SUCCESS;
// Paint our borders and background for our row rect.
- nsITheme* theme = nullptr;
- auto appearance = rowContext->StyleDisplay()->EffectiveAppearance();
- if (appearance != StyleAppearance::None) {
- theme = aPresContext->Theme();
- }
-
- if (theme && theme->ThemeSupportsWidget(aPresContext, nullptr, appearance)) {
- nsRect dirty;
- dirty.IntersectRect(rowRect, aDirtyRect);
- theme->DrawWidgetBackground(&aRenderingContext, this, appearance, rowRect,
- dirty);
- } else {
- result &= PaintBackgroundLayer(rowContext, aPresContext, aRenderingContext,
- rowRect, aDirtyRect);
- }
+ result &= PaintBackgroundLayer(rowContext, aPresContext, aRenderingContext,
+ rowRect, aDirtyRect);
// Adjust the rect for its border and padding.
nsRect originalRowRect = rowRect;
@@ -2820,54 +2797,32 @@ ImgDrawResult nsTreeBodyFrame::PaintSeparator(int32_t aRowIndex,
// Resolve style for the separator.
ComputedStyle* separatorContext =
GetPseudoComputedStyle(nsCSSAnonBoxes::mozTreeSeparator());
- bool useTheme = false;
- nsITheme* theme = nullptr;
- StyleAppearance appearance =
- separatorContext->StyleDisplay()->EffectiveAppearance();
- if (appearance != StyleAppearance::None) {
- theme = aPresContext->Theme();
- if (theme->ThemeSupportsWidget(aPresContext, nullptr, appearance))
- useTheme = true;
- }
- ImgDrawResult result = ImgDrawResult::SUCCESS;
+ const nsStylePosition* stylePosition = separatorContext->StylePosition();
- // use -moz-appearance if provided.
- if (useTheme) {
- nsRect dirty;
- dirty.IntersectRect(aSeparatorRect, aDirtyRect);
- theme->DrawWidgetBackground(&aRenderingContext, this, appearance,
- aSeparatorRect, dirty);
+ // Obtain the height for the separator or use the default value.
+ nscoord height;
+ if (stylePosition->mHeight.ConvertsToLength()) {
+ height = stylePosition->mHeight.ToLength();
} else {
- const nsStylePosition* stylePosition = separatorContext->StylePosition();
-
- // Obtain the height for the separator or use the default value.
- nscoord height;
- if (stylePosition->mHeight.ConvertsToLength()) {
- height = stylePosition->mHeight.ToLength();
- } else {
- // Use default height 2px.
- height = nsPresContext::CSSPixelsToAppUnits(2);
- }
-
- // Obtain the margins for the separator and then deflate our rect by that
- // amount. The separator is assumed to be contained within the deflated
- // rect.
- nsRect separatorRect(aSeparatorRect.x, aSeparatorRect.y,
- aSeparatorRect.width, height);
- nsMargin separatorMargin;
- separatorContext->StyleMargin()->GetMargin(separatorMargin);
- separatorRect.Deflate(separatorMargin);
+ // Use default height 2px.
+ height = nsPresContext::CSSPixelsToAppUnits(2);
+ }
- // Center the separator.
- separatorRect.y += (aSeparatorRect.height - height) / 2;
+ // Obtain the margins for the separator and then deflate our rect by that
+ // amount. The separator is assumed to be contained within the deflated
+ // rect.
+ nsRect separatorRect(aSeparatorRect.x, aSeparatorRect.y, aSeparatorRect.width,
+ height);
+ nsMargin separatorMargin;
+ separatorContext->StyleMargin()->GetMargin(separatorMargin);
+ separatorRect.Deflate(separatorMargin);
- result &=
- PaintBackgroundLayer(separatorContext, aPresContext, aRenderingContext,
- separatorRect, aDirtyRect);
- }
+ // Center the separator.
+ separatorRect.y += (aSeparatorRect.height - height) / 2;
- return result;
+ return PaintBackgroundLayer(separatorContext, aPresContext, aRenderingContext,
+ separatorRect, aDirtyRect);
}
ImgDrawResult nsTreeBodyFrame::PaintCell(
@@ -3084,68 +3039,57 @@ ImgDrawResult nsTreeBodyFrame::PaintTwisty(
twistyRect.Deflate(twistyMargin);
nsRect imageSize;
- nsITheme* theme = GetTwistyRect(aRowIndex, aColumn, imageSize, twistyRect,
- aPresContext, twistyContext);
+ GetTwistyRect(aRowIndex, aColumn, imageSize, twistyRect, aPresContext,
+ twistyContext);
// Subtract out the remaining width. This is done even when we don't actually
// paint a twisty in this cell, so that cells in different rows still line up.
nsRect copyRect(twistyRect);
copyRect.Inflate(twistyMargin);
aRemainingWidth -= copyRect.width;
- if (!isRTL) aCurrX += copyRect.width;
+ if (!isRTL) {
+ aCurrX += copyRect.width;
+ }
- ImgDrawResult result = ImgDrawResult::SUCCESS;
+ auto result = ImgDrawResult::SUCCESS;
+ if (!shouldPaint) {
+ return result;
+ }
+ // Paint our borders and background for our image rect.
+ result &= PaintBackgroundLayer(twistyContext, aPresContext, aRenderingContext,
+ twistyRect, aDirtyRect);
- if (shouldPaint) {
- // Paint our borders and background for our image rect.
- result &= PaintBackgroundLayer(twistyContext, aPresContext,
- aRenderingContext, twistyRect, aDirtyRect);
-
- if (theme) {
- if (isRTL) twistyRect.x = rightEdge - twistyRect.width;
- // yeah, I know it says we're drawing a background, but a twisty is really
- // a fg object since it doesn't have anything that gecko would want to
- // draw over it. Besides, we have to prevent imagelib from drawing it.
- nsRect dirty;
- dirty.IntersectRect(twistyRect, aDirtyRect);
- theme->DrawWidgetBackground(
- &aRenderingContext, this,
- twistyContext->StyleDisplay()->EffectiveAppearance(), twistyRect,
- dirty);
- } else {
- // Time to paint the twisty.
- // Adjust the rect for its border and padding.
- nsMargin bp(0, 0, 0, 0);
- GetBorderPadding(twistyContext, bp);
- twistyRect.Deflate(bp);
- if (isRTL) twistyRect.x = rightEdge - twistyRect.width;
- imageSize.Deflate(bp);
-
- // Get the image for drawing.
- nsCOMPtr<imgIContainer> image;
- GetImage(aRowIndex, aColumn, true, twistyContext, getter_AddRefs(image));
- if (image) {
- nsPoint anchorPoint = twistyRect.TopLeft();
-
- // Center the image. XXX Obey vertical-align style prop?
- if (imageSize.height < twistyRect.height) {
- anchorPoint.y += (twistyRect.height - imageSize.height) / 2;
- }
+ // Time to paint the twisty.
+ // Adjust the rect for its border and padding.
+ nsMargin bp;
+ GetBorderPadding(twistyContext, bp);
+ twistyRect.Deflate(bp);
+ if (isRTL) twistyRect.x = rightEdge - twistyRect.width;
+ imageSize.Deflate(bp);
- // Apply context paint if applicable
- SVGImageContext svgContext;
- SVGImageContext::MaybeStoreContextPaint(svgContext, *aPresContext,
- *twistyContext, image);
+ // Get the image for drawing.
+ nsCOMPtr<imgIContainer> image;
+ GetImage(aRowIndex, aColumn, true, twistyContext, getter_AddRefs(image));
+ if (!image) {
+ return result;
+ }
+ nsPoint anchorPoint = twistyRect.TopLeft();
- // Paint the image.
- result &= nsLayoutUtils::DrawSingleUnscaledImage(
- aRenderingContext, aPresContext, image, SamplingFilter::POINT,
- anchorPoint, &aDirtyRect, svgContext, imgIContainer::FLAG_NONE,
- &imageSize);
- }
- }
+ // Center the image. XXX Obey vertical-align style prop?
+ if (imageSize.height < twistyRect.height) {
+ anchorPoint.y += (twistyRect.height - imageSize.height) / 2;
}
+ // Apply context paint if applicable
+ SVGImageContext svgContext;
+ SVGImageContext::MaybeStoreContextPaint(svgContext, *aPresContext,
+ *twistyContext, image);
+
+ // Paint the image.
+ result &= nsLayoutUtils::DrawSingleUnscaledImage(
+ aRenderingContext, aPresContext, image, SamplingFilter::POINT,
+ anchorPoint, &aDirtyRect, svgContext, imgIContainer::FLAG_NONE,
+ &imageSize);
return result;
}
@@ -3895,7 +3839,7 @@ void nsTreeBodyFrame::RemoveImageCacheEntry(int32_t aRowIndex,
nsTreeColumn* aCol) {
nsAutoString imageSrc;
nsCOMPtr<nsITreeView> view = GetExistingView();
- if (NS_FAILED(view->GetImageSrc(aRowIndex, aCol, imageSrc))) {
+ if (!view || NS_FAILED(view->GetImageSrc(aRowIndex, aCol, imageSrc))) {
return;
}
nsTreeImageCacheEntry entry;
diff --git a/layout/xul/tree/nsTreeBodyFrame.h b/layout/xul/tree/nsTreeBodyFrame.h
index dd38644ad9..d7a9498ced 100644
--- a/layout/xul/tree/nsTreeBodyFrame.h
+++ b/layout/xul/tree/nsTreeBodyFrame.h
@@ -295,10 +295,10 @@ class nsTreeBodyFrame final : public mozilla::SimpleXULLeafFrame,
nsCSSAnonBoxPseudoStaticAtom** aChildElt);
// Retrieve the area for the twisty for a cell.
- nsITheme* GetTwistyRect(int32_t aRowIndex, nsTreeColumn* aColumn,
- nsRect& aImageRect, nsRect& aTwistyRect,
- nsPresContext* aPresContext,
- ComputedStyle* aTwistyContext);
+ void GetTwistyRect(int32_t aRowIndex, nsTreeColumn* aColumn,
+ nsRect& aImageRect, nsRect& aTwistyRect,
+ nsPresContext* aPresContext,
+ ComputedStyle* aTwistyContext);
// Fetch an image from the image cache.
nsresult GetImage(int32_t aRowIndex, nsTreeColumn* aCol, bool aUseContext,