summaryrefslogtreecommitdiffstats
path: root/layout
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:37 +0000
commita90a5cba08fdf6c0ceb95101c275108a152a3aed (patch)
tree532507288f3defd7f4dcf1af49698bcb76034855 /layout
parentAdding debian version 126.0.1-1. (diff)
downloadfirefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.tar.xz
firefox-a90a5cba08fdf6c0ceb95101c275108a152a3aed.zip
Merging upstream version 127.0.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'layout')
-rw-r--r--layout/base/AccessibleCaretManager.cpp3
-rw-r--r--layout/base/PositionedEventTargeting.cpp56
-rw-r--r--layout/base/PresShell.cpp26
-rw-r--r--layout/base/RestyleManager.cpp46
-rw-r--r--layout/base/ViewportUtils.cpp3
-rw-r--r--layout/base/ZoomConstraintsClient.cpp16
-rw-r--r--layout/base/crashtests/crashtests.list8
-rw-r--r--layout/base/metrics.yaml16
-rw-r--r--layout/base/nsCSSFrameConstructor.cpp28
-rw-r--r--layout/base/nsCSSFrameConstructor.h3
-rw-r--r--layout/base/nsDocumentViewer.cpp5
-rw-r--r--layout/base/nsGenConList.cpp13
-rw-r--r--layout/base/nsLayoutUtils.cpp82
-rw-r--r--layout/base/nsLayoutUtils.h55
-rw-r--r--layout/base/nsRefreshDriver.cpp30
-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/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/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/nsRangeFrame.h4
-rw-r--r--layout/forms/nsTextControlFrame.cpp6
-rw-r--r--layout/forms/test/mochitest.toml2
-rw-r--r--layout/forms/test/test_bug869314.html55
-rw-r--r--layout/generic/CSSAlignUtils.cpp2
-rw-r--r--layout/generic/ReflowInput.cpp80
-rw-r--r--layout/generic/ReflowInput.h9
-rw-r--r--layout/generic/ScrollAnchorContainer.cpp12
-rw-r--r--layout/generic/StickyScrollContainer.cpp6
-rw-r--r--layout/generic/WritingModes.h227
-rw-r--r--layout/generic/crashtests/crashtests.list6
-rw-r--r--layout/generic/nsAbsoluteContainingBlock.cpp6
-rw-r--r--layout/generic/nsBlockFrame.cpp5
-rw-r--r--layout/generic/nsCanvasFrame.cpp14
-rw-r--r--layout/generic/nsColumnSetFrame.cpp6
-rw-r--r--layout/generic/nsContainerFrame.cpp2
-rw-r--r--layout/generic/nsContainerFrameInlines.h4
-rw-r--r--layout/generic/nsFirstLetterFrame.cpp10
-rw-r--r--layout/generic/nsFlexContainerFrame.cpp216
-rw-r--r--layout/generic/nsFlexContainerFrame.h3
-rw-r--r--layout/generic/nsFloatManager.cpp6
-rw-r--r--layout/generic/nsFrameSelection.cpp5
-rw-r--r--layout/generic/nsGfxScrollFrame.cpp24
-rw-r--r--layout/generic/nsGridContainerFrame.cpp25
-rw-r--r--layout/generic/nsGridContainerFrame.h59
-rw-r--r--layout/generic/nsIFrame.cpp87
-rw-r--r--layout/generic/nsIFrame.h26
-rw-r--r--layout/generic/nsImageFrame.cpp16
-rw-r--r--layout/generic/nsInlineFrame.cpp10
-rw-r--r--layout/generic/nsLineLayout.cpp2
-rw-r--r--layout/generic/nsRubyFrame.cpp18
-rw-r--r--layout/generic/nsSplittableFrame.cpp8
-rw-r--r--layout/generic/nsSubDocumentFrame.cpp54
-rw-r--r--layout/inspector/InspectorCSSParser.cpp70
-rw-r--r--layout/inspector/InspectorCSSParser.h47
-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/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/nsDisplayList.cpp63
-rw-r--r--layout/painting/nsDisplayList.h27
-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/bugs/reftest.list10
-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/forms/input/file/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/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.list9
-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/style/CSSKeyframeRule.cpp3
-rw-r--r--layout/style/CSSMarginRule.cpp183
-rw-r--r--layout/style/CSSMarginRule.h107
-rw-r--r--layout/style/CSSPageRule.h1
-rw-r--r--layout/style/CSSStyleRule.cpp14
-rw-r--r--layout/style/CSSStyleRule.h2
-rw-r--r--layout/style/FontFaceSetWorkerImpl.cpp6
-rw-r--r--layout/style/GeckoBindings.cpp38
-rw-r--r--layout/style/GeckoBindings.h21
-rw-r--r--layout/style/Loader.cpp25
-rw-r--r--layout/style/PreferenceSheet.cpp1
-rw-r--r--layout/style/Rule.cpp8
-rw-r--r--layout/style/ServoBindingTypes.h1
-rw-r--r--layout/style/ServoBindings.h1
-rw-r--r--layout/style/ServoBindings.toml5
-rw-r--r--layout/style/ServoCSSRuleList.cpp9
-rw-r--r--layout/style/ServoLockedArcTypeList.h1
-rw-r--r--layout/style/ServoStyleConstsForwards.h1
-rw-r--r--layout/style/ServoStyleConstsInlines.h1
-rw-r--r--layout/style/ServoStyleSet.cpp7
-rw-r--r--layout/style/SheetLoadData.h8
-rw-r--r--layout/style/crashtests/crashtests.list22
-rw-r--r--layout/style/moz.build2
-rw-r--r--layout/style/nsCSSValue.h18
-rw-r--r--layout/style/nsComputedDOMStyle.cpp6
-rw-r--r--layout/style/nsComputedDOMStyle.h2
-rw-r--r--layout/style/nsDOMCSSAttrDeclaration.h2
-rw-r--r--layout/style/nsDOMCSSDeclaration.h2
-rw-r--r--layout/style/nsMediaFeatures.cpp1
-rw-r--r--layout/style/nsStyleStruct.cpp8
-rw-r--r--layout/style/nsStyleStruct.h69
-rw-r--r--layout/style/res/forms.css9
-rw-r--r--layout/style/res/html.css2
-rw-r--r--layout/style/res/quirk.css6
-rw-r--r--layout/style/test/property_database.js2
-rw-r--r--layout/svg/SVGGeometryFrame.cpp8
-rw-r--r--layout/svg/SVGOuterSVGFrame.cpp6
-rw-r--r--layout/svg/SVGUtils.cpp4
-rw-r--r--layout/svg/crashtests/crashtests.list6
-rw-r--r--layout/tables/nsTableCellFrame.cpp4
-rw-r--r--layout/tables/nsTableColGroupFrame.cpp4
-rw-r--r--layout/tables/nsTableFrame.cpp231
-rw-r--r--layout/tables/nsTableRowFrame.cpp4
-rw-r--r--layout/tables/nsTableRowGroupFrame.cpp4
-rw-r--r--layout/tools/reftest/jar.mn1
-rw-r--r--layout/tools/reftest/manifest.sys.mjs114
-rw-r--r--layout/tools/reftest/reftest.sys.mjs2
-rw-r--r--layout/tools/reftest/reftestcommandline.py5
-rw-r--r--layout/tools/reftest/runreftest.py30
-rw-r--r--layout/xul/tree/crashtests/crashtests.list2
-rw-r--r--layout/xul/tree/nsTreeBodyFrame.cpp316
-rw-r--r--layout/xul/tree/nsTreeBodyFrame.h8
175 files changed, 3373 insertions, 1366 deletions
diff --git a/layout/base/AccessibleCaretManager.cpp b/layout/base/AccessibleCaretManager.cpp
index 99155133cd..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"
@@ -879,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();
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 7674abb3d0..cd41da3730 100644
--- a/layout/base/PresShell.cpp
+++ b/layout/base/PresShell.cpp
@@ -3931,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) {
@@ -6566,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) {
@@ -11260,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
}
@@ -11849,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()) {
@@ -12102,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/RestyleManager.cpp b/layout/base/RestyleManager.cpp
index 81ffebf89a..e00493467f 100644
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -3246,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()) {
@@ -3271,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) {
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 3b1ed1e3d4..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
@@ -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
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 c0f35c278d..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);
}
@@ -5283,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);
diff --git a/layout/base/nsCSSFrameConstructor.h b/layout/base/nsCSSFrameConstructor.h
index 51d5fe32d0..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);
/**
diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp
index 8ae0e001b8..bbd43a830e 100644
--- a/layout/base/nsDocumentViewer.cpp
+++ b/layout/base/nsDocumentViewer.cpp
@@ -2426,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) {
@@ -2436,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) {
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 429ad335cc..3f84a97250 100644
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -900,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;
@@ -2131,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 ||
@@ -3498,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.
@@ -3510,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),
@@ -3523,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;
@@ -3568,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) {}
@@ -3609,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);
}
@@ -3618,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);
}
@@ -3649,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
@@ -4610,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) {
@@ -4641,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);
@@ -5048,10 +5063,11 @@ 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(LogicalAxis::Inline);
// According to the spec, max-content and min-content should behave as the
@@ -5077,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()) {
@@ -8896,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);
}
}
@@ -9223,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
diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h
index 135a9ad9ab..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 };
/**
diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp
index 7885d6b8db..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);
}
@@ -2228,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;
}
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/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/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/nsRangeFrame.h b/layout/forms/nsRangeFrame.h
index 10d0fc0095..206103ea44 100644
--- a/layout/forms/nsRangeFrame.h
+++ b/layout/forms/nsRangeFrame.h
@@ -105,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;
diff --git a/layout/forms/nsTextControlFrame.cpp b/layout/forms/nsTextControlFrame.cpp
index 32e817be8a..3c44038d89 100644
--- a/layout/forms/nsTextControlFrame.cpp
+++ b/layout/forms/nsTextControlFrame.cpp
@@ -417,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,
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/CSSAlignUtils.cpp b/layout/generic/CSSAlignUtils.cpp
index 7dd8999563..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);
diff --git a/layout/generic/ReflowInput.cpp b/layout/generic/ReflowInput.cpp
index c642c77b2c..bdfd39aff1 100644
--- a/layout/generic/ReflowInput.cpp
+++ b/layout/generic/ReflowInput.cpp
@@ -953,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
@@ -1123,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 =
@@ -1228,9 +1217,9 @@ 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;
}
@@ -2549,9 +2538,9 @@ 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;
@@ -2742,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;
}
@@ -2771,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();
}
@@ -2781,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();
}
@@ -2839,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");
@@ -2850,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;
}
@@ -2861,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 ba49edcaf6..7bf7c4fc73 100644
--- a/layout/generic/ReflowInput.h
+++ b/layout/generic/ReflowInput.h
@@ -741,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;
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/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/WritingModes.h b/layout/generic/WritingModes.h
index 0fcf47f1d0..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
@@ -50,7 +48,7 @@ enum class LogicalAxis : uint8_t {
Block,
Inline,
};
-enum LogicalEdge { eLogicalEdgeStart = 0x0, eLogicalEdgeEnd = 0x1 };
+enum class LogicalEdge : uint8_t { Start, End };
enum class LogicalSide : uint8_t {
BStart,
@@ -59,11 +57,6 @@ enum class LogicalSide : uint8_t {
IEnd,
};
-constexpr auto AllLogicalSides() {
- return mozilla::MakeInclusiveEnumeratedRange(LogicalSide::BStart,
- LogicalSide::IEnd);
-}
-
enum class LogicalCorner : uint8_t {
BStartIStart,
BStartIEnd,
@@ -72,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 {
@@ -104,38 +97,30 @@ inline LogicalAxis GetAxis(LogicalSide aSide) {
}
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((uint8_t(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 << static_cast<uint8_t>(LogicalSide::BStart),
- eLogicalSideBitsBEnd = 1 << static_cast<uint8_t>(LogicalSide::BEnd),
- eLogicalSideBitsIEnd = 1 << static_cast<uint8_t>(LogicalSide::IEnd),
- eLogicalSideBitsIStart = 1 << static_cast<uint8_t>(LogicalSide::IStart),
- eLogicalSideBitsBBoth = eLogicalSideBitsBStart | eLogicalSideBitsBEnd,
- eLogicalSideBitsIBoth = eLogicalSideBitsIStart | eLogicalSideBitsIEnd,
- eLogicalSideBitsAll = eLogicalSideBitsBBoth | eLogicalSideBitsIBoth
-};
-
-enum LineRelativeDir {
- eLineRelativeDirOver = static_cast<uint8_t>(LogicalSide::BStart),
- eLineRelativeDirUnder = static_cast<uint8_t>(LogicalSide::BEnd),
- eLineRelativeDirLeft = static_cast<uint8_t>(LogicalSide::IStart),
- eLineRelativeDirRight = static_cast<uint8_t>(LogicalSide::IEnd)
+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)
};
/**
@@ -155,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
- };
-
- /**
- * 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
+ 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
};
/**
- * 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;
}
/**
@@ -216,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.
@@ -242,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
@@ -339,8 +311,9 @@ class WritingMode {
uint8_t(StyleWritingModeProperty::VerticalRl) == 1 &&
uint8_t(StyleWritingModeProperty::VerticalLr) == 3 &&
uint8_t(LogicalAxis::Block) == 0 &&
- uint8_t(LogicalAxis::Inline) == 1 && eAxisVertical == 0 &&
- eAxisHorizontal == 1,
+ 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 ^ uint8_t(aAxis)) & 0x1);
@@ -376,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 {
@@ -413,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)];
}
/**
@@ -428,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;
@@ -490,12 +463,12 @@ class WritingMode {
};
// 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];
}
@@ -580,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.
@@ -588,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");
@@ -611,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);
}
/**
@@ -624,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) {
@@ -818,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);
@@ -834,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);
@@ -857,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,
@@ -1107,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());
@@ -1165,7 +1140,7 @@ struct LogicalSides final {
#ifdef DEBUG
WritingMode mWritingMode;
#endif
- uint8_t mBits;
+ EnumSet<LogicalSide> mSides;
};
/**
diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list
index 2aea090a6f..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
diff --git a/layout/generic/nsAbsoluteContainingBlock.cpp b/layout/generic/nsAbsoluteContainingBlock.cpp
index 4f561688bf..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;
}
diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp
index 4582c29e0b..4b314bfcaf 100644
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1186,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;
}
@@ -7979,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 b4b108905f..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()) {
diff --git a/layout/generic/nsColumnSetFrame.cpp b/layout/generic/nsColumnSetFrame.cpp
index a9d3e28138..d78a5cb992 100644
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -570,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;
diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp
index 2c9e707830..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);
}
}
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 28d1b08a30..c08950121a 100644
--- a/layout/generic/nsFirstLetterFrame.cpp
+++ b/layout/generic/nsFirstLetterFrame.cpp
@@ -447,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 66f1e79609..4604106a4a 100644
--- a/layout/generic/nsFlexContainerFrame.cpp
+++ b/layout/generic/nsFlexContainerFrame.cpp
@@ -312,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
@@ -2021,7 +2021,7 @@ const CachedBAxisMeasurement& nsFlexContainerFrame::MeasureBSizeForFlexItem(
// 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();
@@ -2032,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");
@@ -2227,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");
@@ -2257,7 +2257,7 @@ FlexItem::FlexItem(ReflowInput& aFlexItemReflowInput, float aFlexGrow,
// (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
@@ -2354,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,
@@ -2448,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++;
@@ -2708,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
@@ -4111,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(
@@ -4885,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) {
@@ -4905,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());
}
@@ -4915,7 +4927,7 @@ void nsFlexContainerFrame::UnionInFlowChildOverflow(
if (anyScrolledContentItem) {
itemMarginBoxes.Inflate(GetUsedPadding());
aOverflowAreas.UnionAllWith(itemMarginBoxes);
- aOverflowAreas.UnionAllWith(relPosItemMarginBoxes);
+ aOverflowAreas.UnionWith(relPosItemMarginBoxes);
}
}
@@ -5515,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
@@ -5533,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
@@ -5631,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
@@ -5662,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;
@@ -5691,15 +5753,38 @@ std::tuple<nscoord, nsReflowStatus> nsFlexContainerFrame::ReflowChildren(
FLEX_ITEM_LOG(
item.Frame(),
"[frag] Item needed to be pushed to container's next-in-flow "
- "because its block-size is larger than the available space");
+ "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);
}
@@ -5787,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.
@@ -5808,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);
@@ -5952,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
@@ -6067,7 +6193,8 @@ void nsFlexContainerFrame::MoveFlexItemToFinalPosition(
nsReflowStatus nsFlexContainerFrame::ReflowFlexItem(
const FlexboxAxisTracker& aAxisTracker, const ReflowInput& aReflowInput,
const FlexItem& aItem, const LogicalPoint& aFramePos,
- const LogicalSize& aAvailableSize, const nsSize& aContainerSize) {
+ 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
@@ -6206,6 +6333,13 @@ 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.
@@ -6216,11 +6350,11 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem(
// 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.
@@ -6240,7 +6374,7 @@ nsReflowStatus nsFlexContainerFrame::ReflowFlexItem(
aItem.Frame()->SetProperty(CachedFlexItemData::Prop(), cached);
}
- return childReflowStatus;
+ return childStatus;
}
void nsFlexContainerFrame::ReflowPlaceholders(
@@ -6260,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,
diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h
index 14f91ae064..2771098255 100644
--- a/layout/generic/nsFlexContainerFrame.h
+++ b/layout/generic/nsFlexContainerFrame.h
@@ -604,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
@@ -614,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 e1866b35c1..88a8b20b4c 100644
--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -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 ca4e3d647e..94cf368480 100644
--- a/layout/generic/nsFrameSelection.cpp
+++ b/layout/generic/nsFrameSelection.cpp
@@ -1441,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);
}
diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp
index 2b0c53efe1..97e6b614dc 100644
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -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();
@@ -5211,15 +5211,19 @@ nsSize nsHTMLScrollFrame::GetPageScrollAmount() const {
}
nsSize lineScrollAmount = GetLineScrollAmount();
-
- // 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));
+ 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 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));
}
/**
diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp
index bb6e2150ce..48c70cd479 100644
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -4317,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);
@@ -4377,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) {
@@ -4387,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);
}
@@ -4411,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'.
@@ -4441,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
@@ -4527,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;
@@ -4540,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);
@@ -5761,7 +5761,7 @@ 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(LogicalAxis::Inline);
@@ -5800,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
@@ -6017,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)) {
@@ -6124,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;
diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h
index cb3eef68c3..1fa7bbe487 100644
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -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/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
index 27f09b84f6..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"
@@ -4928,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 =
@@ -7889,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 {
@@ -7950,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;
}
@@ -8008,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;
@@ -10795,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) {
@@ -10806,7 +10820,8 @@ Focusable nsIFrame::IsFocusable(bool aWithMouse, bool aCheckVisibility) {
return {};
}
- if (aCheckVisibility && !IsVisibleConsideringAncestors()) {
+ if (!(aFlags & IsFocusableFlags::IgnoreVisibility) &&
+ !IsVisibleConsideringAncestors()) {
return {};
}
@@ -10826,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) {
@@ -10841,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};
}
@@ -11627,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) {
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index 6e55ebe1c7..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;
@@ -1386,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.
//
@@ -4369,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.
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index 91d8430b60..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();
}
@@ -2857,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 b481c71827..44fce51931 100644
--- a/layout/generic/nsInlineFrame.cpp
+++ b/layout/generic/nsInlineFrame.cpp
@@ -797,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.
@@ -809,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.
@@ -822,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/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp
index be6f64f1fe..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++;
diff --git a/layout/generic/nsRubyFrame.cpp b/layout/generic/nsRubyFrame.cpp
index d6119f44fb..fc74ce8184 100644
--- a/layout/generic/nsRubyFrame.cpp
+++ b/layout/generic/nsRubyFrame.cpp
@@ -300,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:
@@ -333,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.
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 69b4042033..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,22 +553,7 @@ nsresult nsSubDocumentFrame::GetFrameName(nsAString& aResult) const {
/* virtual */
nscoord nsSubDocumentFrame::GetMinISize(gfxContext* aRenderingContext) {
- nscoord 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 */
@@ -706,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/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/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/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 954e2de6e2..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-5) 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/nsDisplayList.cpp b/layout/painting/nsDisplayList.cpp
index 2c2b7cb04c..0007f86c5e 100644
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -5207,7 +5207,7 @@ bool nsDisplayOwnLayer::CreateWebRenderCommands(
Maybe<wr::WrAnimationProperty> prop;
bool needsProp = aManager->LayerManager()->AsyncPanZoomEnabled() &&
(IsScrollThumbLayer() || IsZoomingLayer() ||
- ShouldGetFixedOrStickyAnimationId() ||
+ ShouldGetFixedAnimationId() ||
(IsRootScrollbarContainer() && HasDynamicToolbar()));
if (needsProp) {
@@ -5234,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;
@@ -5250,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;
@@ -5267,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);
@@ -5458,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()) ==
@@ -5522,7 +5516,8 @@ nsDisplayStickyPosition::nsDisplayStickyPosition(
: nsDisplayOwnLayer(aBuilder, aFrame, aList, aActiveScrolledRoot),
mContainerASR(aContainerASR),
mClippedToDisplayPort(aClippedToDisplayPort),
- mShouldFlatten(false) {
+ mShouldFlatten(false),
+ mWrStickyAnimationId(0) {
MOZ_COUNT_CTOR(nsDisplayStickyPosition);
}
@@ -5738,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);
@@ -5812,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
@@ -5821,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 acda6ea863..9862415f61 100644
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -5475,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; }
@@ -5491,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;
};
@@ -5550,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);
}
@@ -5575,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; }
@@ -5591,6 +5601,8 @@ class nsDisplayStickyPosition : public nsDisplayOwnLayer {
return mShouldFlatten;
}
+ bool ShouldGetStickyAnimationId() const;
+
private:
NS_DISPLAY_ALLOW_CLONING()
@@ -5620,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 {
@@ -5661,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/bugs/reftest.list b/layout/reftests/bugs/reftest.list
index 28e96a51da..84f4ecca9f 100644
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -919,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
@@ -1120,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
@@ -1344,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
@@ -1367,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
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/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/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/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 97f04542ff..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
@@ -360,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/
@@ -431,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/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.h b/layout/style/CSSPageRule.h
index 904f94d2c0..b133111244 100644
--- a/layout/style/CSSPageRule.h
+++ b/layout/style/CSSPageRule.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;
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/FontFaceSetWorkerImpl.cpp b/layout/style/FontFaceSetWorkerImpl.cpp
index 7fbfbf0d95..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() {
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/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 eb752b2789..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"
diff --git a/layout/style/Rule.cpp b/layout/style/Rule.cpp
index 4b0f783bd9..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 ||
@@ -108,7 +109,8 @@ void Rule::AssertParentRuleType() {
type == StyleCssRuleType::LayerBlock ||
type == StyleCssRuleType::Container ||
type == StyleCssRuleType::Scope ||
- type == StyleCssRuleType::StartingStyle);
+ type == StyleCssRuleType::StartingStyle ||
+ type == StyleCssRuleType::Page);
}
}
#endif
diff --git a/layout/style/ServoBindingTypes.h b/layout/style/ServoBindingTypes.h
index b081a4981b..e2443ef526 100644
--- a/layout/style/ServoBindingTypes.h
+++ b/layout/style/ServoBindingTypes.h
@@ -123,6 +123,7 @@ 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)
diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h
index 52538cafb8..2c0abbe0db 100644
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -77,6 +77,7 @@ BASIC_RULE_FUNCS_LOCKED(Keyframes)
GROUP_RULE_FUNCS_UNLOCKED(Media)
GROUP_RULE_FUNCS_UNLOCKED(Document)
BASIC_RULE_FUNCS_UNLOCKED(Namespace)
+BASIC_RULE_FUNCS_UNLOCKED(Margin)
GROUP_RULE_FUNCS_LOCKED(Page)
BASIC_RULE_FUNCS_UNLOCKED(Property)
GROUP_RULE_FUNCS_UNLOCKED(Supports)
diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml
index 67fd902e2b..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" },
@@ -631,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 133a962256..b7172879de 100644
--- a/layout/style/ServoCSSRuleList.cpp
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -17,6 +17,7 @@
#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"
@@ -88,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)
@@ -108,9 +110,6 @@ css::Rule* ServoCSSRuleList::GetRule(uint32_t aIndex) {
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;
@@ -277,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)
@@ -294,9 +294,6 @@ void ServoCSSRuleList::SetRawContents(RefPtr<StyleLockedCssRules> aNewRules,
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/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 5bf87d8330..cd2958618f 100644
--- a/layout/style/ServoStyleConstsForwards.h
+++ b/layout/style/ServoStyleConstsForwards.h
@@ -89,6 +89,7 @@ class SharedFontList;
class StyleSheet;
class WritingMode;
class ServoElementSnapshotTable;
+class StyleParserState;
template <typename T>
struct StyleForgottenArcSlicePtr;
diff --git a/layout/style/ServoStyleConstsInlines.h b/layout/style/ServoStyleConstsInlines.h
index 5a86e4ccd0..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>;
diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp
index 91231af2b0..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"
@@ -766,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) {
@@ -994,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)
@@ -1014,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
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 b77fa34983..ce9ee36cea 100644
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -138,6 +138,7 @@ EXPORTS.mozilla.dom += [
"CSSKeyframesRule.h",
"CSSLayerBlockRule.h",
"CSSLayerStatementRule.h",
+ "CSSMarginRule.h",
"CSSMediaRule.h",
"CSSMozDocumentRule.h",
"CSSNamespaceRule.h",
@@ -191,6 +192,7 @@ UNIFIED_SOURCES += [
"CSSKeyframesRule.cpp",
"CSSLayerBlockRule.cpp",
"CSSLayerStatementRule.cpp",
+ "CSSMarginRule.cpp",
"CSSMediaRule.cpp",
"CSSMozDocumentRule.cpp",
"CSSNamespaceRule.cpp",
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 5b71ec54bf..876f32cd7a 100644
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1888,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());
}
@@ -1901,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());
}
diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h
index d1f3458030..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;
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 fbdde4102d..cc86d1abf6 100644
--- a/layout/style/nsMediaFeatures.cpp
+++ b/layout/style/nsMediaFeatures.cpp
@@ -349,7 +349,6 @@ StyleDynamicRange Gecko_MediaFeatures_VideoDynamicRange(
// with the device context claims to be HDR capable.
if (nsDeviceContext* dx = GetDeviceContextFor(aDocument)) {
if (dx->GetScreenIsHDR()) {
- // bjw
return StyleDynamicRange::High;
}
}
diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp
index e46566d471..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()) {
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 044d460ad4..7a5c25fc6e 100644
--- a/layout/style/res/forms.css
+++ b/layout/style/res/forms.css
@@ -192,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 {
/*
@@ -631,10 +635,6 @@ input[type=file] > label {
text-align: match-parent;
cursor: unset;
- color: unset;
- font-size: unset;
- letter-spacing: unset;
-
user-select: none;
unicode-bidi: plaintext;
}
@@ -842,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 18dd1c4855..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;
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/property_database.js b/layout/style/test/property_database.js
index c63d65926e..302bd48b42 100644
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -5382,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('*'))",
@@ -5400,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'",
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/SVGOuterSVGFrame.cpp b/layout/svg/SVGOuterSVGFrame.cpp
index d88327f059..00d7663901 100644
--- a/layout/svg/SVGOuterSVGFrame.cpp
+++ b/layout/svg/SVGOuterSVGFrame.cpp
@@ -126,9 +126,9 @@ NS_QUERYFRAME_TAIL_INHERITING(SVGDisplayContainerFrame)
/* virtual */
nscoord SVGOuterSVGFrame::GetMinISize(gfxContext* aRenderingContext) {
- // If this ever changes to return something other than zero, then
- // nsSubDocumentFrame::GetMinISize will also need to change.
- return 0;
+ auto size = GetIntrinsicSize();
+ const auto& iSize = GetWritingMode().IsVertical() ? size.height : size.width;
+ return iSize.valueOr(0);
}
/* virtual */
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/nsTableCellFrame.cpp b/layout/tables/nsTableCellFrame.cpp
index fdfa5e305e..86ce48d47b 100644
--- a/layout/tables/nsTableCellFrame.cpp
+++ b/layout/tables/nsTableCellFrame.cpp
@@ -378,10 +378,10 @@ LogicalSides nsTableCellFrame::GetLogicalSkipSides() const {
}
if (GetPrevInFlow()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
if (GetNextInFlow()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
return skip;
}
diff --git a/layout/tables/nsTableColGroupFrame.cpp b/layout/tables/nsTableColGroupFrame.cpp
index bf0200e27c..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;
}
diff --git a/layout/tables/nsTableFrame.cpp b/layout/tables/nsTableFrame.cpp
index 84bdbc48af..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;
}
@@ -2392,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 {
@@ -3799,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);
@@ -3844,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
@@ -3892,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),
@@ -3921,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);
@@ -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,30 +4915,75 @@ 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(
- LogicalSide::IEnd,
- std::max(aWidth, mCell->GetBorderWidth(LogicalSide::IEnd)));
+ 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(
- LogicalSide::BEnd,
- std::max(aWidth, mCell->GetBorderWidth(LogicalSide::BEnd)));
+ 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()));
}
}
@@ -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(
- LogicalSide::IStart,
- std::max(aWidth, mCell->GetBorderWidth(LogicalSide::IStart)));
+ 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 =
@@ -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());
@@ -5166,9 +5244,10 @@ void nsTableFrame::CalcBCBorders() {
if (0 == info.mRowIndex) {
uint8_t idxBStart = static_cast<uint8_t>(LogicalSide::BStart);
if (!tableBorderReset[idxBStart]) {
- propData->mBStartBorderWidth = 0;
+ tableInfo.ResetTableBStartBorderWidth();
tableBorderReset[idxBStart] = true;
}
+ bool reset = false;
for (int32_t colIdx = info.mColIndex; colIdx <= info.GetCellEndColIndex();
colIdx++) {
info.SetColumn(colIdx);
@@ -5203,7 +5282,11 @@ void nsTableFrame::CalcBCBorders() {
// 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 {
@@ -5228,10 +5311,11 @@ void nsTableFrame::CalcBCBorders() {
if (0 == info.mColIndex) {
uint8_t idxIStart = static_cast<uint8_t>(LogicalSide::IStart);
if (!tableBorderReset[idxIStart]) {
- propData->mIStartBorderWidth = 0;
+ 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);
@@ -5254,7 +5338,11 @@ void nsTableFrame::CalcBCBorders() {
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);
}
}
@@ -5265,10 +5353,11 @@ void nsTableFrame::CalcBCBorders() {
// touches iEnd edge of table
uint8_t idxIEnd = static_cast<uint8_t>(LogicalSide::IEnd);
if (!tableBorderReset[idxIEnd]) {
- propData->mIEndBorderWidth = 0;
+ 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);
@@ -5301,7 +5390,11 @@ void nsTableFrame::CalcBCBorders() {
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 {
@@ -5309,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.
@@ -5331,6 +5425,11 @@ void nsTableFrame::CalcBCBorders() {
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);
}
@@ -5405,9 +5504,10 @@ void nsTableFrame::CalcBCBorders() {
// touches bEnd edge of table
uint8_t idxBEnd = static_cast<uint8_t>(LogicalSide::BEnd);
if (!tableBorderReset[idxBEnd]) {
- propData->mBEndBorderWidth = 0;
+ tableInfo.ResetTableBEndBorderWidth();
tableBorderReset[idxBEnd] = true;
}
+ bool reset = false;
for (int32_t colIdx = info.mColIndex; colIdx <= info.GetCellEndColIndex();
colIdx++) {
info.SetColumn(colIdx);
@@ -5453,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.
@@ -5540,6 +5645,12 @@ void nsTableFrame::CalcBCBorders() {
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);
}
diff --git a/layout/tables/nsTableRowFrame.cpp b/layout/tables/nsTableRowFrame.cpp
index a6f4647429..2447ceea15 100644
--- a/layout/tables/nsTableRowFrame.cpp
+++ b/layout/tables/nsTableRowFrame.cpp
@@ -561,10 +561,10 @@ LogicalSides nsTableRowFrame::GetLogicalSkipSides() const {
}
if (GetPrevInFlow()) {
- skip |= eLogicalSideBitsBStart;
+ skip += LogicalSide::BStart;
}
if (GetNextInFlow()) {
- skip |= eLogicalSideBitsBEnd;
+ skip += LogicalSide::BEnd;
}
return skip;
}
diff --git a/layout/tables/nsTableRowGroupFrame.cpp b/layout/tables/nsTableRowGroupFrame.cpp
index 9ae8a59a90..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;
}
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/manifest.sys.mjs b/layout/tools/reftest/manifest.sys.mjs
index a4a8ed126f..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,60 +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;
@@ -701,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");
@@ -734,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
@@ -779,11 +695,6 @@ function BuildConditionSandbox(aURL) {
false
);
- sandbox.gpuProcessForceEnabled = Services.prefs.getBoolPref(
- "layers.gpu-process.force-enabled",
- false
- );
-
sandbox.prefs = Cu.cloneInto(
{
getBoolPref(p) {
@@ -797,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 0f103c5816..12bdab98f9 100644
--- a/layout/tools/reftest/reftest.sys.mjs
+++ b/layout/tools/reftest/reftest.sys.mjs
@@ -1512,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 e97a6de5d7..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)
@@ -539,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:
@@ -1100,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/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 f585009600..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;
}
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,