summaryrefslogtreecommitdiffstats
path: root/layout/generic
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic')
-rw-r--r--layout/generic/BlockReflowState.cpp31
-rw-r--r--layout/generic/BlockReflowState.h20
-rw-r--r--layout/generic/FrameClasses.py18
-rw-r--r--layout/generic/ScrollAnchorContainer.cpp7
-rw-r--r--layout/generic/ScrollAnimationMSDPhysics.cpp14
-rw-r--r--layout/generic/ScrollOrigin.h2
-rw-r--r--layout/generic/ScrollPositionUpdate.cpp15
-rw-r--r--layout/generic/ScrollPositionUpdate.h6
-rw-r--r--layout/generic/StickyScrollContainer.cpp11
-rw-r--r--layout/generic/TextOverflow.cpp16
-rw-r--r--layout/generic/ViewportFrame.cpp1
-rw-r--r--layout/generic/WritingModes.h10
-rw-r--r--layout/generic/crashtests/1140268-1.html18
-rw-r--r--layout/generic/crashtests/364686-1.xhtml12
-rw-r--r--layout/generic/crashtests/368461-1.xhtml11
-rw-r--r--layout/generic/crashtests/370884-1.xhtml14
-rw-r--r--layout/generic/crashtests/382208-1.xhtml7
-rw-r--r--layout/generic/crashtests/382396-1.xhtml7
-rw-r--r--layout/generic/crashtests/385265-1.xhtml13
-rw-r--r--layout/generic/crashtests/395450-1.xhtml28
-rw-r--r--layout/generic/crashtests/467914-1.html3
-rw-r--r--layout/generic/crashtests/547843-1.xhtml1
-rw-r--r--layout/generic/crashtests/700031.xhtml9
-rw-r--r--layout/generic/crashtests/crashtests.list17
-rw-r--r--layout/generic/nsBlockFrame.cpp506
-rw-r--r--layout/generic/nsBlockFrame.h31
-rw-r--r--layout/generic/nsBlockReflowContext.cpp2
-rw-r--r--layout/generic/nsContainerFrame.cpp52
-rw-r--r--layout/generic/nsFloatManager.h4
-rw-r--r--layout/generic/nsFrameSelection.cpp2
-rw-r--r--layout/generic/nsFrameStateBits.h31
-rw-r--r--layout/generic/nsGfxScrollFrame.cpp91
-rw-r--r--layout/generic/nsGfxScrollFrame.h8
-rw-r--r--layout/generic/nsGridContainerFrame.cpp87
-rw-r--r--layout/generic/nsGridContainerFrame.h6
-rw-r--r--layout/generic/nsHTMLParts.h4
-rw-r--r--layout/generic/nsIFrame.cpp108
-rw-r--r--layout/generic/nsIFrame.h15
-rw-r--r--layout/generic/nsImageFrame.cpp14
-rw-r--r--layout/generic/nsLineLayout.cpp5
-rw-r--r--layout/generic/nsTextFrame.cpp22
-rw-r--r--layout/generic/nsTextFrame.h8
-rw-r--r--layout/generic/nsTextPaintStyle.cpp4
-rw-r--r--layout/generic/nsTextPaintStyle.h5
44 files changed, 686 insertions, 610 deletions
diff --git a/layout/generic/BlockReflowState.cpp b/layout/generic/BlockReflowState.cpp
index 6163a200a3..78dab82e98 100644
--- a/layout/generic/BlockReflowState.cpp
+++ b/layout/generic/BlockReflowState.cpp
@@ -47,7 +47,8 @@ BlockReflowState::BlockReflowState(
mMinLineHeight(aReflowInput.GetLineHeight()),
mLineNumber(0),
mTrailingClearFromPIF(StyleClear::None),
- mConsumedBSize(aConsumedBSize) {
+ mConsumedBSize(aConsumedBSize),
+ mAlignContentShift(mBlock->GetAlignContentShift()) {
NS_ASSERTION(mConsumedBSize != NS_UNCONSTRAINEDSIZE,
"The consumed block-size should be constrained!");
@@ -87,8 +88,8 @@ BlockReflowState::BlockReflowState(
// the "overflow" property. When we don't have a specified style block-size,
// then we may end up limiting our block-size if the available block-size is
// constrained (this situation occurs when we are paginated).
- if (const nscoord availableBSize = aReflowInput.AvailableBSize();
- availableBSize != NS_UNCONSTRAINEDSIZE) {
+ const nscoord availableBSize = aReflowInput.AvailableBSize();
+ if (availableBSize != NS_UNCONSTRAINEDSIZE) {
// We are in a paginated situation. The block-end edge of the available
// space to reflow the children is within our block-end border and padding.
// If we're cloning our border and padding, and we're going to request
@@ -112,10 +113,34 @@ BlockReflowState::BlockReflowState(
mContentArea.IStart(wm) = mBorderPadding.IStart(wm);
mBCoord = mContentArea.BStart(wm) = mBorderPadding.BStart(wm);
+ // Account for existing cached shift, we'll re-position in AlignContent() if
+ // needed.
+ if (mAlignContentShift) {
+ mBCoord += mAlignContentShift;
+ mContentArea.BStart(wm) += mAlignContentShift;
+
+ if (availableBSize != NS_UNCONSTRAINEDSIZE) {
+ mContentArea.BSize(wm) += mAlignContentShift;
+ }
+ }
+
mPrevChild = nullptr;
mCurrentLine = aFrame->LinesEnd();
}
+void BlockReflowState::UndoAlignContentShift() {
+ if (!mAlignContentShift) {
+ return;
+ }
+
+ mBCoord -= mAlignContentShift;
+ mContentArea.BStart(mReflowInput.GetWritingMode()) -= mAlignContentShift;
+
+ if (mReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE) {
+ mContentArea.BSize(mReflowInput.GetWritingMode()) -= mAlignContentShift;
+ }
+}
+
void BlockReflowState::ComputeFloatAvoidingOffsets(
nsIFrame* aFloatAvoidingBlock, const LogicalRect& aFloatAvailableSpace,
nscoord& aIStartResult, nscoord& aIEndResult) const {
diff --git a/layout/generic/BlockReflowState.h b/layout/generic/BlockReflowState.h
index 1dfaa4d9ad..6f05b6ab0a 100644
--- a/layout/generic/BlockReflowState.h
+++ b/layout/generic/BlockReflowState.h
@@ -41,16 +41,16 @@ class BlockReflowState {
mCanHaveOverflowMarkers(false) {}
// Set in the BlockReflowState constructor when reflowing a "block margin
- // root" frame (i.e. a frame with any of the NS_BLOCK_BFC_STATE_BITS flag
- // set, for which margins apply by default).
+ // root" frame (i.e. a frame with any of the NS_BLOCK_BFC flag set, for
+ // which margins apply by default).
//
// The flag is also set when reflowing a frame whose computed BStart border
// padding is non-zero.
bool mIsBStartMarginRoot : 1;
// Set in the BlockReflowState constructor when reflowing a "block margin
- // root" frame (i.e. a frame with any of the NS_BLOCK_BFC_STATE_BITS flag
- // set, for which margins apply by default).
+ // root" frame (i.e. a frame with any of the NS_BLOCK_BFC flag set, for
+ // which margins apply by default).
//
// The flag is also set when reflowing a frame whose computed BEnd border
// padding is non-zero.
@@ -102,6 +102,13 @@ class BlockReflowState {
const nscoord aInset = 0);
/**
+ * Unshifts coords, restores availableBSize to reality.
+ * (Constructor applies any cached shift before reflow
+ * so that frames are reflowed with cached shift)
+ */
+ void UndoAlignContentShift();
+
+ /**
* Get the available reflow space (the area not occupied by floats)
* for the current y coordinate. The available space is relative to
* our coordinate system, which is the content box, with (0, 0) in the
@@ -407,6 +414,11 @@ class BlockReflowState {
// continuations.
const nscoord mConsumedBSize;
+ // The amount of block-axis alignment shift to assume during reflow.
+ // Cached between reflows in the AlignContentShift property.
+ // (This system optimizes reflow for not changing the shift.)
+ nscoord mAlignContentShift;
+
// Cache the current line's BSize if nsBlockFrame::PlaceLine() fails to
// place the line. When redoing the line, it will be used to query the
// accurate float available space in AddFloat() and
diff --git a/layout/generic/FrameClasses.py b/layout/generic/FrameClasses.py
index d1d0a0b13b..36c1af10d1 100644
--- a/layout/generic/FrameClasses.py
+++ b/layout/generic/FrameClasses.py
@@ -14,6 +14,7 @@ COMMON = {
LEAF = {"Leaf"}
MATHML = {"MathML"}
SVG = {"SVG"}
+BFC = {"BlockFormattingContext"}
BLOCK = COMMON | {"CanContainOverflowContainers"}
@@ -54,18 +55,13 @@ FRAME_CLASSES = [
Frame("nsCheckboxRadioFrame", "CheckboxRadio", REPLACED_WITH_BLOCK | LEAF),
Frame("nsColorControlFrame", "ColorControl", REPLACED_WITH_BLOCK | LEAF),
Frame("nsColumnSetFrame", "ColumnSet", COMMON),
- Frame("ColumnSetWrapperFrame", "ColumnSetWrapper", BLOCK),
- Frame("nsComboboxControlFrame", "ComboboxControl", BLOCK | REPLACED_WITH_BLOCK),
- # FIXME(emilio, bug 1362907): Revisit these after that bug, this is the
- # only frame that has ReplacedContainsBlock but not Replaced, which is
- # sketchy.
- Frame(
- "nsComboboxDisplayFrame", "ComboboxDisplay", REPLACED_WITH_BLOCK - {"Replaced"}
- ),
+ Frame("ColumnSetWrapperFrame", "ColumnSetWrapper", BLOCK | BFC),
+ Frame("nsComboboxControlFrame", "ComboboxControl", REPLACED_WITH_BLOCK | LEAF),
+ Frame("ComboboxLabelFrame", "Block", BLOCK),
Frame("nsContinuingTextFrame", "Text", TEXT),
Frame("nsDateTimeControlFrame", "DateTimeControl", REPLACED_WITH_BLOCK),
Frame("nsFieldSetFrame", "FieldSet", BLOCK),
- Frame("nsFileControlFrame", "Block", REPLACED_WITH_BLOCK | LEAF),
+ Frame("nsFileControlFrame", "Block", REPLACED_WITH_BLOCK | LEAF | BFC),
Frame("FileControlLabelFrame", "Block", BLOCK | LEAF),
Frame("nsFirstLetterFrame", "Letter", INLINE),
Frame("nsFloatingFirstLetterFrame", "Letter", INLINE - {"LineParticipant"}),
@@ -84,7 +80,7 @@ FRAME_CLASSES = [
Frame("nsImageFrame", "Image", REPLACED_SIZING | {"LeafDynamic"}),
Frame("nsInlineFrame", "Inline", INLINE),
Frame("nsListControlFrame", "ListControl", REPLACED_WITH_BLOCK),
- Frame("nsMathMLmathBlockFrame", "Block", BLOCK | MATHML),
+ Frame("nsMathMLmathBlockFrame", "Block", BLOCK | MATHML | BFC),
Frame("nsMathMLmathInlineFrame", "Inline", INLINE | MATHML),
Frame("nsMathMLmencloseFrame", "None", MATHML_CONTAINER),
Frame("nsMathMLmfracFrame", "None", MATHML_CONTAINER),
@@ -120,7 +116,7 @@ FRAME_CLASSES = [
Frame("nsScrollbarButtonFrame", "SimpleXULLeaf", COMMON | LEAF),
Frame("nsScrollbarFrame", "Scrollbar", COMMON),
Frame("nsSearchControlFrame", "SearchControl", LEAF),
- Frame("nsSelectsAreaFrame", "Block", BLOCK),
+ Frame("nsSelectsAreaFrame", "Block", BLOCK | BFC),
Frame("nsPageSequenceFrame", "PageSequence", COMMON),
Frame("nsSliderFrame", "Slider", COMMON),
Frame("nsSplitterFrame", "SimpleXULLeaf", COMMON | LEAF),
diff --git a/layout/generic/ScrollAnchorContainer.cpp b/layout/generic/ScrollAnchorContainer.cpp
index 5e1d8aa56d..93336480f7 100644
--- a/layout/generic/ScrollAnchorContainer.cpp
+++ b/layout/generic/ScrollAnchorContainer.cpp
@@ -539,11 +539,8 @@ void ScrollAnchorContainer::ApplyAdjustments() {
MOZ_RELEASE_ASSERT(!mApplyingAnchorAdjustment);
// We should use AutoRestore here, but that doesn't work with bitfields
mApplyingAnchorAdjustment = true;
- Frame()->ScrollToInternal(
- Frame()->GetScrollPosition() + physicalAdjustment, ScrollMode::Instant,
- StaticPrefs::layout_css_scroll_anchoring_absolute_update()
- ? ScrollOrigin::AnchorAdjustment
- : ScrollOrigin::Relative);
+ Frame()->ScrollToInternal(Frame()->GetScrollPosition() + physicalAdjustment,
+ ScrollMode::Instant, ScrollOrigin::Relative);
mApplyingAnchorAdjustment = false;
if (Frame()->mIsRoot) {
diff --git a/layout/generic/ScrollAnimationMSDPhysics.cpp b/layout/generic/ScrollAnimationMSDPhysics.cpp
index de67f9c59a..8f0ae32d3b 100644
--- a/layout/generic/ScrollAnimationMSDPhysics.cpp
+++ b/layout/generic/ScrollAnimationMSDPhysics.cpp
@@ -5,7 +5,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ScrollAnimationMSDPhysics.h"
+#include "mozilla/Logging.h"
#include "mozilla/StaticPrefs_general.h"
+#include "mozilla/ToString.h"
+
+static mozilla::LazyLogModule sApzMsdLog("apz.msd");
+#define MSD_LOG(...) MOZ_LOG(sApzMsdLog, LogLevel::Debug, (__VA_ARGS__))
using namespace mozilla;
@@ -108,13 +113,17 @@ double ScrollAnimationMSDPhysics::ComputeSpringConstant(
}
void ScrollAnimationMSDPhysics::SimulateUntil(const TimeStamp& aTime) {
- if (!mLastSimulatedTime || aTime < mLastSimulatedTime) {
+ if (!mLastSimulatedTime || aTime <= mLastSimulatedTime) {
return;
}
TimeDuration delta = aTime - mLastSimulatedTime;
mModelX.Simulate(delta);
mModelY.Simulate(delta);
mLastSimulatedTime = aTime;
+ MSD_LOG("Simulated for duration %f, finished %d position %s velocity %s\n",
+ delta.ToMilliseconds(), IsFinished(aTime),
+ ToString(CSSPoint::FromAppUnits(PositionAt(aTime))).c_str(),
+ ToString(CSSPoint::FromAppUnits(VelocityAt(aTime))).c_str());
}
nsPoint ScrollAnimationMSDPhysics::PositionAt(const TimeStamp& aTime) {
@@ -152,6 +161,9 @@ ScrollAnimationMSDPhysics::NonOscillatingAxisPhysicsMSDModel::
ClampVelocityToMaximum(aInitialVelocity, aInitialPosition,
aInitialDestination, aSpringConstant),
aSpringConstant, aDampingRatio) {
+ MSD_LOG("Constructing axis physics model with parameters %f %f %f %f %f\n",
+ aInitialPosition, aInitialDestination, aInitialVelocity,
+ aSpringConstant, aDampingRatio);
MOZ_ASSERT(aDampingRatio >= 1.0,
"Damping ratio must be >= 1.0 to avoid oscillation");
}
diff --git a/layout/generic/ScrollOrigin.h b/layout/generic/ScrollOrigin.h
index f1ad0e3367..edffa2d4f6 100644
--- a/layout/generic/ScrollOrigin.h
+++ b/layout/generic/ScrollOrigin.h
@@ -33,8 +33,6 @@ enum class ScrollOrigin : uint8_t {
// The scroll came from an attempt by the main thread to re-clamp the scroll
// position after a reflow.
Clamp,
- // The scroll came from a scroll adjustment triggered by scroll anchoring.
- AnchorAdjustment,
// The following scroll origins also are associated with prefs of the form
// general.smoothScroll.<origin>(.*)
diff --git a/layout/generic/ScrollPositionUpdate.cpp b/layout/generic/ScrollPositionUpdate.cpp
index 9607d2d18a..a680768525 100644
--- a/layout/generic/ScrollPositionUpdate.cpp
+++ b/layout/generic/ScrollPositionUpdate.cpp
@@ -93,20 +93,6 @@ ScrollPositionUpdate ScrollPositionUpdate::NewPureRelativeScroll(
return ret;
}
-/*static*/
-ScrollPositionUpdate ScrollPositionUpdate::NewMergeableScroll(
- ScrollOrigin aOrigin, nsPoint aDestination) {
- MOZ_ASSERT(aOrigin == ScrollOrigin::AnchorAdjustment);
-
- ScrollPositionUpdate ret;
- ret.mScrollGeneration = sGenerationCounter.NewMainThreadGeneration();
- ret.mType = ScrollUpdateType::MergeableAbsolute;
- ret.mScrollMode = ScrollMode::Instant;
- ret.mScrollOrigin = aOrigin;
- ret.mDestination = CSSPoint::FromAppUnits(aDestination);
- return ret;
-}
-
bool ScrollPositionUpdate::operator==(
const ScrollPositionUpdate& aOther) const {
// instances are immutable, and all the fields are set when the generation
@@ -126,7 +112,6 @@ ScrollOrigin ScrollPositionUpdate::GetOrigin() const { return mScrollOrigin; }
CSSPoint ScrollPositionUpdate::GetDestination() const {
MOZ_ASSERT(mType == ScrollUpdateType::Absolute ||
- mType == ScrollUpdateType::MergeableAbsolute ||
mType == ScrollUpdateType::Relative);
return mDestination;
}
diff --git a/layout/generic/ScrollPositionUpdate.h b/layout/generic/ScrollPositionUpdate.h
index 0e8dc020c1..ca22da8af0 100644
--- a/layout/generic/ScrollPositionUpdate.h
+++ b/layout/generic/ScrollPositionUpdate.h
@@ -34,9 +34,6 @@ enum class ScrollUpdateType {
// The delta should be applied to whatever the current scroll position is
// on the receiver side.
PureRelative,
- // Similar to |Absolute|, but even if there's an active async scroll animation
- // the position update will NOT cancel the async scroll animation.
- MergeableAbsolute,
};
enum class ScrollTriggeredByScript : bool { No, Yes };
@@ -86,9 +83,6 @@ class ScrollPositionUpdate {
ScrollMode aMode,
const nsPoint& aDelta);
- static ScrollPositionUpdate NewMergeableScroll(ScrollOrigin aOrigin,
- nsPoint aDestination);
-
bool operator==(const ScrollPositionUpdate& aOther) const;
MainThreadScrollGeneration GetGeneration() const;
diff --git a/layout/generic/StickyScrollContainer.cpp b/layout/generic/StickyScrollContainer.cpp
index 2e9d32ab5f..416bbbf4c4 100644
--- a/layout/generic/StickyScrollContainer.cpp
+++ b/layout/generic/StickyScrollContainer.cpp
@@ -186,12 +186,17 @@ void StickyScrollContainer::ComputeStickyLimits(nsIFrame* aFrame,
// Containing block limits for the position of aFrame relative to its parent.
// The margin box of the sticky element stays within the content box of the
- // contaning-block element.
+ // containing-block element.
if (cbFrame == scrolledFrame) {
// cbFrame is the scrolledFrame, and it won't have continuations. Unlike the
- // else clause, we consider scrollable overflow rect because and the union
- // of its in-flow rects doesn't include the scrollable overflow area.
+ // else clause, we consider scrollable overflow rect because the union of
+ // its in-flow rects doesn't include the scrollable overflow area. We need
+ // to subtract the padding however, which _is_ included in the scrollable
+ // area, since we want the content box.
+ MOZ_ASSERT(cbFrame->GetUsedBorder() == nsMargin(),
+ "How did the ::-moz-scrolled-frame end up with border?");
*aContain = cbFrame->ScrollableOverflowRectRelativeToSelf();
+ aContain->Deflate(cbFrame->GetUsedPadding());
nsLayoutUtils::TransformRect(cbFrame, aFrame->GetParent(), *aContain);
} else {
*aContain = nsLayoutUtils::GetAllInFlowRectsUnion(
diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp
index f529a2268d..758b61a99b 100644
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -29,8 +29,7 @@
using mozilla::layout::TextDrawTarget;
-namespace mozilla {
-namespace css {
+namespace mozilla::css {
class LazyReferenceRenderingDrawTargetGetterFromFrame final
: public gfxFontGroup::LazyReferenceDrawTargetGetter {
@@ -165,8 +164,7 @@ class nsDisplayTextOverflowMarker final : public nsPaintedDisplayItem {
virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
bool* aSnap) const override {
*aSnap = false;
- nsRect shadowRect = nsLayoutUtils::GetTextShadowRectsUnion(mRect, mFrame);
- return mRect.Union(shadowRect);
+ return nsLayoutUtils::GetTextShadowRectsUnion(mRect, mFrame);
}
virtual nsRect GetComponentAlphaBounds(
@@ -835,9 +833,10 @@ bool TextOverflow::CanHaveOverflowMarkers(nsBlockFrame* aBlockFrame,
return false;
}
- // Skip ComboboxControlFrame because it would clip the drop-down arrow.
- // Its anon block inherits 'text-overflow' and does what is expected.
- if (aBlockFrame->IsComboboxControlFrame()) {
+ // Skip the combobox anonymous block because it would clip the drop-down
+ // arrow. The inner label inherits 'text-overflow' and does the right thing.
+ if (aBlockFrame->GetParent() &&
+ aBlockFrame->GetParent()->IsComboboxControlFrame()) {
return false;
}
@@ -932,5 +931,4 @@ void TextOverflow::Marker::SetupString(nsIFrame* aFrame) {
mInitialized = true;
}
-} // namespace css
-} // namespace mozilla
+} // namespace mozilla::css
diff --git a/layout/generic/ViewportFrame.cpp b/layout/generic/ViewportFrame.cpp
index 1837441e86..812aaa8e33 100644
--- a/layout/generic/ViewportFrame.cpp
+++ b/layout/generic/ViewportFrame.cpp
@@ -21,7 +21,6 @@
#include "nsCanvasFrame.h"
#include "nsLayoutUtils.h"
#include "nsSubDocumentFrame.h"
-#include "nsIMozBrowserFrame.h"
#include "nsPlaceholderFrame.h"
#include "MobileViewportManager.h"
diff --git a/layout/generic/WritingModes.h b/layout/generic/WritingModes.h
index 2f28b73775..e84c5e276d 100644
--- a/layout/generic/WritingModes.h
+++ b/layout/generic/WritingModes.h
@@ -62,11 +62,11 @@ constexpr auto AllLogicalSides() {
eLogicalSideIEnd);
}
-enum LogicalCorner {
- eLogicalCornerBStartIStart = 0,
- eLogicalCornerBStartIEnd = 1,
- eLogicalCornerBEndIEnd = 2,
- eLogicalCornerBEndIStart = 3
+enum class LogicalCorner : uint8_t {
+ BStartIStart,
+ BStartIEnd,
+ BEndIEnd,
+ BEndIStart,
};
// Physical axis constants.
diff --git a/layout/generic/crashtests/1140268-1.html b/layout/generic/crashtests/1140268-1.html
deleted file mode 100644
index 5e5510ba7f..0000000000
--- a/layout/generic/crashtests/1140268-1.html
+++ /dev/null
@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset=utf-8>
-<script>
-function boom()
-{
- var e = document.getElementsByTagName("mo")[0];
- e.setAttribute("style", "position: absolute; top: 0px;");
- document.documentElement.offsetHeight;
- e.setAttribute("style", "position: absolute; top: 100px;");
-}
-</script>
-</head>
-<body onload="boom();">
-<math><mo>boom!</mo></math>
-</body>
-</html>
diff --git a/layout/generic/crashtests/364686-1.xhtml b/layout/generic/crashtests/364686-1.xhtml
deleted file mode 100644
index 93a1eeaa4b..0000000000
--- a/layout/generic/crashtests/364686-1.xhtml
+++ /dev/null
@@ -1,12 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:math="http://www.w3.org/1998/Math/MathML">
-
-<body>
-
-<math:merror>
- <img/>
-</math:merror>
-
-</body>
-</html>
-
diff --git a/layout/generic/crashtests/368461-1.xhtml b/layout/generic/crashtests/368461-1.xhtml
deleted file mode 100644
index d5baccf523..0000000000
--- a/layout/generic/crashtests/368461-1.xhtml
+++ /dev/null
@@ -1,11 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
-
-<head>
-</head>
-
-<body>
-
-<p><math:msubsup><span>Foo bar baz<td></td></span></math:msubsup></p>
-
-</body>
-</html>
diff --git a/layout/generic/crashtests/370884-1.xhtml b/layout/generic/crashtests/370884-1.xhtml
deleted file mode 100644
index 3959d4b178..0000000000
--- a/layout/generic/crashtests/370884-1.xhtml
+++ /dev/null
@@ -1,14 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
-<head>
-</head>
-
-<body>
-
-<math:mroot>
- <div>
- <div style="position: fixed;">Y</div>
- </div>
-</math:mroot>
-
-</body>
-</html>
diff --git a/layout/generic/crashtests/382208-1.xhtml b/layout/generic/crashtests/382208-1.xhtml
deleted file mode 100644
index 5264b8845d..0000000000
--- a/layout/generic/crashtests/382208-1.xhtml
+++ /dev/null
@@ -1,7 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
-<body>
-
-<div><math:mfrac><math:mmultiscripts/><math:mi/></math:mfrac></div>
-
-</body>
-</html>
diff --git a/layout/generic/crashtests/382396-1.xhtml b/layout/generic/crashtests/382396-1.xhtml
deleted file mode 100644
index f334bbfdf5..0000000000
--- a/layout/generic/crashtests/382396-1.xhtml
+++ /dev/null
@@ -1,7 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
-<body>
-
-<p style="text-indent: 0%">a<math:ms/></p>
-
-</body>
-</html>
diff --git a/layout/generic/crashtests/385265-1.xhtml b/layout/generic/crashtests/385265-1.xhtml
deleted file mode 100644
index 7994653ffa..0000000000
--- a/layout/generic/crashtests/385265-1.xhtml
+++ /dev/null
@@ -1,13 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml">
-<body>
-
-<math xmlns="http://www.w3.org/1998/Math/MathML" display="block">
- <mtable>
- <mtr>
- <mtd><mi>x</mi></mtd>
- </mtr>
- </mtable>
-</math>
-
-</body>
-</html> \ No newline at end of file
diff --git a/layout/generic/crashtests/395450-1.xhtml b/layout/generic/crashtests/395450-1.xhtml
deleted file mode 100644
index 79510267ba..0000000000
--- a/layout/generic/crashtests/395450-1.xhtml
+++ /dev/null
@@ -1,28 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml" xmlns:math="http://www.w3.org/1998/Math/MathML">
-
-<head>
-<style>
-
-/*
- This testcase uses [class~="foo"] instead of .foo to work around bug 276267
- (see bug 379178 comment 78)
-*/
-
-[class~="abs"] { position: absolute; }
-[class~="marg"] { margin: 1em; }
-[class="noheight"] { height: 0; }
-
-</style>
-</head>
-
-<body>
-
-<math:mrow class="noheight">
- <span class="abs">
- <math:mroot class="abs marg" />
- <span class="abs" />
- </span>
-</math:mrow>
-
-</body>
-</html>
diff --git a/layout/generic/crashtests/467914-1.html b/layout/generic/crashtests/467914-1.html
deleted file mode 100644
index 4f518f09df..0000000000
--- a/layout/generic/crashtests/467914-1.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:mathml="http://www.w3.org/1998/Math/MathML">
-<mathml:munder style="transform: translate(50px);clip-path: url(#h);"/>
-</window>
diff --git a/layout/generic/crashtests/547843-1.xhtml b/layout/generic/crashtests/547843-1.xhtml
deleted file mode 100644
index 0ad086d90c..0000000000
--- a/layout/generic/crashtests/547843-1.xhtml
+++ /dev/null
@@ -1 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml"><body><math xmlns="http://www.w3.org/1998/Math/MathML" style="display: table;"/><div style="position: fixed;"></div></body></html>
diff --git a/layout/generic/crashtests/700031.xhtml b/layout/generic/crashtests/700031.xhtml
deleted file mode 100644
index 70f924279e..0000000000
--- a/layout/generic/crashtests/700031.xhtml
+++ /dev/null
@@ -1,9 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml"><body>
-
-<div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>
-
-<math xmlns="http://www.w3.org/1998/Math/MathML"><mover>abcdef</mover></math>
-
-</div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
-
-</body></html>
diff --git a/layout/generic/crashtests/crashtests.list b/layout/generic/crashtests/crashtests.list
index 51589c9aba..1c184739d7 100644
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -63,14 +63,12 @@ load 363722-1.html
load 363722-2.html
load 364220.html
load 364407-1.html
-load 364686-1.xhtml
load 366021-1.xhtml
load 366667-1.html
load 366952-1.html
load 367246-1.html
load 367360.html
load 368330-1.html
-load 368461-1.xhtml
load 368568.html
load 368752.html
load 368860-1.html
@@ -86,7 +84,6 @@ load 370174-2.html
load 370174-3.html
load 370699-1.html
load 370794-1.html
-load 370884-1.xhtml
load 371348-1.xhtml
load 371561-1.html
load 371566-1.xhtml
@@ -105,11 +102,8 @@ load 381152-1.html
load 382129-1.xhtml
load 382131-1.html
load 382199-1.html
-load 382208-1.xhtml
load 382262-1.html
-load 382396-1.xhtml
load 383089-1.html
-load 385265-1.xhtml
load 385295-1.xhtml
load 385344-1.html
load 385344-2.html
@@ -158,7 +152,6 @@ load 394818-1.html
load 394818-2.html
load 394820-1.html
load 395316-1.html
-load 395450-1.xhtml
load 397007-1.html
load 397187-1.html
load 397844-1.xhtml
@@ -316,7 +309,6 @@ load 467487-1.html
load 467493-1.html
load 467493-2.html
load 467875-1.xhtml
-load 467914-1.html
asserts-if(winWidget,0-2) load 468207-1.html # bug 1647811
load 468771-1.xhtml
load 468771-2.xhtml
@@ -391,7 +383,6 @@ load 541714-1.html
load 541714-2.html
load 542136-1.html
load 545571-1.html
-load 547843-1.xhtml
load 551635-1.html
load 553504-1.xhtml
load 564368-1.xhtml
@@ -457,7 +448,6 @@ load 683712.html
load 688996-1.html
load 688996-2.html
load 691210.html
-load 700031.xhtml
load 709398-1.html
load 718516.html
load 723108.html
@@ -553,7 +543,7 @@ load 942794-1.html
load 943509-1.html
asserts(2-3) load 944909-1.html # bogus sizes
load 946167-1.html
-skip-if(Android&&browserIsRemote) load 947158.html # bug 1507207
+skip-if(Android) load 947158.html # bug 1507207
load 949932.html
load 963878.html
load 964078.html
@@ -587,7 +577,6 @@ load 1137723-2.html
asserts(1) load 1140043-1.html
asserts(1) load 1140043-2.html
asserts(1) load 1140043-3.html
-load 1140268-1.html
load 1145768.html
load 1145931.html
load 1145950-1.html
@@ -631,7 +620,7 @@ load first-letter-638937-1.html
load first-letter-638937-2.html
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||OSX,0-2) load outline-on-frameset.xhtml # bug 762332, bug 1594135
+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
@@ -672,7 +661,7 @@ load 1343552-2.html
load 1346454-1.html
load 1346454-2.html
load 1349650.html
-asserts-if(browserIsRemote,0-5) load 1349816-1.html # bug 1350352
+asserts(0-5) load 1349816-1.html # bug 1350352
load 1350372.html
load 1364361-1.html
load 1367413-1.html
diff --git a/layout/generic/nsBlockFrame.cpp b/layout/generic/nsBlockFrame.cpp
index 54976ecc47..a25e4e996e 100644
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -41,7 +41,6 @@
#include "nsPresContextInlines.h"
#include "nsHTMLParts.h"
#include "nsGkAtoms.h"
-#include "nsAttrValueInlines.h"
#include "mozilla/Sprintf.h"
#include "nsFloatManager.h"
#include "prenv.h"
@@ -50,22 +49,15 @@
#include <algorithm>
#include "nsLayoutUtils.h"
#include "nsDisplayList.h"
-#include "nsCSSAnonBoxes.h"
#include "nsCSSFrameConstructor.h"
#include "TextOverflow.h"
#include "nsIFrameInlines.h"
#include "CounterStyleManager.h"
-#include "mozilla/dom/HTMLDetailsElement.h"
-#include "mozilla/dom/HTMLSummaryElement.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/PresShell.h"
#include "mozilla/RestyleManager.h"
#include "mozilla/ServoStyleSet.h"
-#include "mozilla/Telemetry.h"
#include "nsFlexContainerFrame.h"
-#include "nsFileControlFrame.h"
-#include "nsMathMLContainerFrame.h"
-#include "nsSelectsAreaFrame.h"
#include "nsBidiPresUtils.h"
@@ -95,7 +87,7 @@ static void MarkAllDescendantLinesDirty(nsBlockFrame* aBlock) {
static void MarkSameFloatManagerLinesDirty(nsBlockFrame* aBlock) {
nsBlockFrame* blockWithFloatMgr = aBlock;
- while (!blockWithFloatMgr->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
+ while (!blockWithFloatMgr->HasAnyStateBits(NS_BLOCK_BFC)) {
nsBlockFrame* bf = do_QueryFrame(blockWithFloatMgr->GetParent());
if (!bf) {
break;
@@ -130,47 +122,37 @@ static bool BlockHasAnyFloats(nsIFrame* aFrame) {
return false;
}
-/**
- * Determines whether the given frame is visible or has
- * visible children that participate in the same line. Frames
- * that are not line participants do not have their
- * children checked.
- */
-static bool FrameHasVisibleInlineContent(nsIFrame* aFrame) {
+// Determines whether the given frame is visible text or has visible text that
+// participate in the same line. Frames that are not line participants do not
+// have their children checked.
+static bool FrameHasVisibleInlineText(nsIFrame* aFrame) {
MOZ_ASSERT(aFrame, "Frame argument cannot be null");
-
- if (aFrame->StyleVisibility()->IsVisible()) {
- return true;
+ if (!aFrame->IsLineParticipant()) {
+ return false;
}
-
- if (aFrame->IsLineParticipant()) {
- for (nsIFrame* kid : aFrame->PrincipalChildList()) {
- if (kid->StyleVisibility()->IsVisible() ||
- FrameHasVisibleInlineContent(kid)) {
- return true;
- }
+ if (aFrame->IsTextFrame()) {
+ return aFrame->StyleVisibility()->IsVisible() &&
+ NS_GET_A(aFrame->StyleText()->mWebkitTextFillColor.CalcColor(
+ aFrame)) != 0;
+ }
+ for (nsIFrame* kid : aFrame->PrincipalChildList()) {
+ if (FrameHasVisibleInlineText(kid)) {
+ return true;
}
}
return false;
}
-/**
- * Determines whether any of the frames descended from the
- * given line have inline content with 'visibility: visible'.
- * This function calls FrameHasVisibleInlineContent to process
- * each frame in the line's child list.
- */
-static bool LineHasVisibleInlineContent(nsLineBox* aLine) {
+// Determines whether any of the frames from the given line have visible text.
+static bool LineHasVisibleInlineText(nsLineBox* aLine) {
nsIFrame* kid = aLine->mFirstChild;
int32_t n = aLine->GetChildCount();
while (n-- > 0) {
- if (FrameHasVisibleInlineContent(kid)) {
+ if (FrameHasVisibleInlineText(kid)) {
return true;
}
-
kid = kid->GetNextSibling();
}
-
return false;
}
@@ -446,13 +428,6 @@ nsBlockFrame* NS_NewBlockFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
return new (aPresShell) nsBlockFrame(aStyle, aPresShell->GetPresContext());
}
-nsBlockFrame* NS_NewBlockFormattingContext(PresShell* aPresShell,
- ComputedStyle* aComputedStyle) {
- nsBlockFrame* blockFrame = NS_NewBlockFrame(aPresShell, aComputedStyle);
- blockFrame->AddStateBits(NS_BLOCK_STATIC_BFC);
- return blockFrame;
-}
-
NS_IMPL_FRAMEARENA_HELPERS(nsBlockFrame)
nsBlockFrame::~nsBlockFrame() = default;
@@ -1194,7 +1169,7 @@ static LogicalSize CalculateContainingBlockSizeForAbsolutes(
*/
static const nsBlockFrame* GetAsLineClampDescendant(const nsIFrame* aFrame) {
if (const nsBlockFrame* block = do_QueryFrame(aFrame)) {
- if (!block->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
+ if (!block->HasAnyStateBits(NS_BLOCK_BFC)) {
return block;
}
}
@@ -1211,7 +1186,7 @@ static bool IsLineClampRoot(const nsBlockFrame* aFrame) {
return false;
}
- if (!aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
+ if (!aFrame->HasAnyStateBits(NS_BLOCK_BFC)) {
return false;
}
@@ -2023,6 +1998,9 @@ nsReflowStatus nsBlockFrame::TrialReflow(nsPresContext* aPresContext,
ComputeFinalSize(aReflowInput, state, aMetrics);
aTrialState.mContainerWidth = state.ContainerSize().width;
+ // Align content
+ AlignContent(state, aMetrics, aTrialState.mBlockEndEdgeOfChildren);
+
return state.mReflowStatus;
}
@@ -2191,6 +2169,11 @@ nscoord nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput,
aState.ClearFloats(blockEndEdgeOfChildren, StyleClear::Both);
}
+ // undo cached alignment shift for sizing purposes
+ // (we used shifted positions because the float manager uses them)
+ blockEndEdgeOfChildren -= aState.mAlignContentShift;
+ aState.UndoAlignContentShift();
+
if (NS_UNCONSTRAINEDSIZE != aReflowInput.ComputedBSize()) {
// Note: We don't use blockEndEdgeOfChildren because it includes the
// previous margin.
@@ -2221,97 +2204,83 @@ nscoord nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput,
// calculated from aspect-ratio. i.e. Don't carry out block margin-end if it
// is replaced by the block size from aspect-ratio and inline size.
aMetrics.mCarriedOutBEndMargin.Zero();
- } else {
- Maybe<nscoord> containBSize = ContainIntrinsicBSize(
- IsComboboxControlFrame() ? NS_UNCONSTRAINEDSIZE : 0);
- if (containBSize && *containBSize != NS_UNCONSTRAINEDSIZE) {
- // If we're size-containing in block axis and we don't have a specified
- // block size, then our final size should actually be computed from only
- // our border, padding and contain-intrinsic-block-size, ignoring the
- // actual contents. Hence this case is a simplified version of the case
- // below.
- //
- // NOTE: We exempt the nsComboboxControlFrame subclass from taking this
- // special case when it has 'contain-intrinsic-block-size: none', because
- // comboboxes implicitly honors the size-containment behavior on its
- // nsComboboxDisplayFrame child (which it shrinkwraps) rather than on the
- // nsComboboxControlFrame. (Moreover, the DisplayFrame child doesn't even
- // need any special content-size-ignoring behavior in its reflow method,
- // because that method just resolves "auto" BSize values to one
- // line-height rather than by measuring its contents' BSize.)
- nscoord contentBSize = *containBSize;
- nscoord autoBSize =
- aReflowInput.ApplyMinMaxBSize(contentBSize, aState.mConsumedBSize);
+ } else if (Maybe<nscoord> containBSize = ContainIntrinsicBSize()) {
+ // If we're size-containing in block axis and we don't have a specified
+ // block size, then our final size should actually be computed from only
+ // our border, padding and contain-intrinsic-block-size, ignoring the
+ // actual contents. Hence this case is a simplified version of the case
+ // below.
+ nscoord contentBSize = *containBSize;
+ nscoord autoBSize =
+ aReflowInput.ApplyMinMaxBSize(contentBSize, aState.mConsumedBSize);
+ aMetrics.mCarriedOutBEndMargin.Zero();
+ autoBSize += borderPadding.BStartEnd(wm);
+ finalSize.BSize(wm) = autoBSize;
+ } else if (aState.mReflowStatus.IsInlineBreakBefore()) {
+ // Our parent is expected to push this frame to the next page/column so
+ // what size we set here doesn't really matter.
+ finalSize.BSize(wm) = aReflowInput.AvailableBSize();
+ } else if (aState.mReflowStatus.IsComplete()) {
+ const nscoord lineClampedContentBlockEndEdge =
+ ApplyLineClamp(aReflowInput, this, blockEndEdgeOfChildren);
+
+ const nscoord bpBStart = borderPadding.BStart(wm);
+ const nscoord contentBSize = blockEndEdgeOfChildren - bpBStart;
+ const nscoord lineClampedContentBSize =
+ lineClampedContentBlockEndEdge - bpBStart;
+
+ const nscoord autoBSize = aReflowInput.ApplyMinMaxBSize(
+ lineClampedContentBSize, aState.mConsumedBSize);
+ if (autoBSize != contentBSize) {
+ // Our min-block-size, max-block-size, or -webkit-line-clamp value made
+ // our bsize change. Don't carry out our kids' block-end margins.
aMetrics.mCarriedOutBEndMargin.Zero();
- autoBSize += borderPadding.BStartEnd(wm);
- finalSize.BSize(wm) = autoBSize;
- } else if (aState.mReflowStatus.IsInlineBreakBefore()) {
- // Our parent is expected to push this frame to the next page/column so
- // what size we set here doesn't really matter.
- finalSize.BSize(wm) = aReflowInput.AvailableBSize();
- } else if (aState.mReflowStatus.IsComplete()) {
- const nscoord lineClampedContentBlockEndEdge =
- ApplyLineClamp(aReflowInput, this, blockEndEdgeOfChildren);
-
- const nscoord bpBStart = borderPadding.BStart(wm);
- const nscoord contentBSize = blockEndEdgeOfChildren - bpBStart;
- const nscoord lineClampedContentBSize =
- lineClampedContentBlockEndEdge - bpBStart;
-
- const nscoord autoBSize = aReflowInput.ApplyMinMaxBSize(
- lineClampedContentBSize, aState.mConsumedBSize);
- if (autoBSize != contentBSize) {
- // Our min-block-size, max-block-size, or -webkit-line-clamp value made
- // our bsize change. Don't carry out our kids' block-end margins.
- aMetrics.mCarriedOutBEndMargin.Zero();
- }
- nscoord bSize = autoBSize + borderPadding.BStartEnd(wm);
- if (MOZ_UNLIKELY(autoBSize > contentBSize &&
- bSize > aReflowInput.AvailableBSize() &&
- aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE)) {
- // Applying `min-size` made us overflow our available size.
- // Clamp it and report that we're Incomplete, or BreakBefore if we have
- // 'break-inside: avoid' that is applicable.
- bSize = aReflowInput.AvailableBSize();
- if (ShouldAvoidBreakInside(aReflowInput)) {
- aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
- } else {
- aState.mReflowStatus.SetIncomplete();
- }
+ }
+ nscoord bSize = autoBSize + borderPadding.BStartEnd(wm);
+ if (MOZ_UNLIKELY(autoBSize > contentBSize &&
+ bSize > aReflowInput.AvailableBSize() &&
+ aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE)) {
+ // Applying `min-size` made us overflow our available size.
+ // Clamp it and report that we're Incomplete, or BreakBefore if we have
+ // 'break-inside: avoid' that is applicable.
+ bSize = aReflowInput.AvailableBSize();
+ if (ShouldAvoidBreakInside(aReflowInput)) {
+ aState.mReflowStatus.SetInlineLineBreakBeforeAndReset();
+ } else {
+ aState.mReflowStatus.SetIncomplete();
}
- finalSize.BSize(wm) = bSize;
- } else {
- NS_ASSERTION(
- aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE,
- "Shouldn't be incomplete if availableBSize is UNCONSTRAINED.");
- nscoord bSize = std::max(aState.mBCoord, aReflowInput.AvailableBSize());
- if (aReflowInput.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
- // This should never happen, but it does. See bug 414255
- bSize = aState.mBCoord;
- }
- const nscoord maxBSize = aReflowInput.ComputedMaxBSize();
- if (maxBSize != NS_UNCONSTRAINEDSIZE &&
- aState.mConsumedBSize + bSize - borderPadding.BStart(wm) > maxBSize) {
- // Compute this fragment's block-size, with the max-block-size
- // constraint taken into consideration.
- const nscoord clampedBSizeWithoutEndBP =
- std::max(0, maxBSize - aState.mConsumedBSize) +
- borderPadding.BStart(wm);
- const nscoord clampedBSize =
- clampedBSizeWithoutEndBP + borderPadding.BEnd(wm);
- if (clampedBSize <= aReflowInput.AvailableBSize()) {
- // We actually fit after applying `max-size` so we should be
- // Overflow-Incomplete instead.
- bSize = clampedBSize;
- aState.mReflowStatus.SetOverflowIncomplete();
- } else {
- // We cannot fit after applying `max-size` with our block-end BP, so
- // we should draw it in our next continuation.
- bSize = clampedBSizeWithoutEndBP;
- }
+ }
+ finalSize.BSize(wm) = bSize;
+ } else {
+ NS_ASSERTION(aReflowInput.AvailableBSize() != NS_UNCONSTRAINEDSIZE,
+ "Shouldn't be incomplete if availableBSize is UNCONSTRAINED.");
+ nscoord bSize = std::max(aState.mBCoord, aReflowInput.AvailableBSize());
+ if (aReflowInput.AvailableBSize() == NS_UNCONSTRAINEDSIZE) {
+ // This should never happen, but it does. See bug 414255
+ bSize = aState.mBCoord;
+ }
+ const nscoord maxBSize = aReflowInput.ComputedMaxBSize();
+ if (maxBSize != NS_UNCONSTRAINEDSIZE &&
+ aState.mConsumedBSize + bSize - borderPadding.BStart(wm) > maxBSize) {
+ // Compute this fragment's block-size, with the max-block-size
+ // constraint taken into consideration.
+ const nscoord clampedBSizeWithoutEndBP =
+ std::max(0, maxBSize - aState.mConsumedBSize) +
+ borderPadding.BStart(wm);
+ const nscoord clampedBSize =
+ clampedBSizeWithoutEndBP + borderPadding.BEnd(wm);
+ if (clampedBSize <= aReflowInput.AvailableBSize()) {
+ // We actually fit after applying `max-size` so we should be
+ // Overflow-Incomplete instead.
+ bSize = clampedBSize;
+ aState.mReflowStatus.SetOverflowIncomplete();
+ } else {
+ // We cannot fit after applying `max-size` with our block-end BP, so
+ // we should draw it in our next continuation.
+ bSize = clampedBSizeWithoutEndBP;
}
- finalSize.BSize(wm) = bSize;
}
+ finalSize.BSize(wm) = bSize;
}
if (IsTrueOverflowContainer()) {
@@ -2381,6 +2350,77 @@ nscoord nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput,
return blockEndEdgeOfChildren;
}
+void nsBlockFrame::AlignContent(BlockReflowState& aState,
+ ReflowOutput& aMetrics,
+ nscoord aBEndEdgeOfChildren) {
+ if (!StaticPrefs::layout_css_align_content_blocks_enabled()) {
+ return;
+ }
+
+ StyleAlignFlags alignment = StylePosition()->mAlignContent.primary;
+ alignment &= ~StyleAlignFlags::FLAG_BITS;
+
+ // Short circuit
+ const bool isCentered = alignment == StyleAlignFlags::CENTER ||
+ alignment == StyleAlignFlags::SPACE_AROUND ||
+ alignment == StyleAlignFlags::SPACE_EVENLY;
+ const bool isEndAlign = alignment == StyleAlignFlags::END ||
+ alignment == StyleAlignFlags::FLEX_END ||
+ alignment == StyleAlignFlags::LAST_BASELINE;
+ if (!isEndAlign && !isCentered && !aState.mAlignContentShift) {
+ // desired shift = 0, no cached shift to undo
+ return;
+ }
+
+ // NOTE: ComputeFinalSize already called aState.UndoAlignContentShift(),
+ // so metrics no longer include cached shift.
+ // NOTE: Content is currently positioned at cached shift
+ // NOTE: Content has been fragmented against 0-shift assumption.
+
+ // Calculate shift
+ nscoord shift = 0;
+ WritingMode wm = aState.mReflowInput.GetWritingMode();
+ if ((isCentered || isEndAlign) && !mLines.empty() &&
+ aState.mReflowStatus.IsFullyComplete() && !GetPrevInFlow()) {
+ nscoord availB = aState.mReflowInput.AvailableBSize();
+ nscoord endB = aMetrics.BSize(wm) - aState.BorderPadding().BEnd(wm);
+ shift = std::min(availB, endB) - aBEndEdgeOfChildren;
+
+ // note: these measures all include start BP, so it subtracts out
+ if (!(StylePosition()->mAlignContent.primary & StyleAlignFlags::UNSAFE)) {
+ shift = std::max(0, shift);
+ }
+ if (isCentered) {
+ shift = shift / 2;
+ }
+ }
+ // else: zero shift if start-aligned or if fragmented
+
+ nscoord delta = shift - aState.mAlignContentShift;
+ if (delta) {
+ // Shift children
+ LogicalPoint translation(wm, 0, delta);
+ for (nsLineBox& line : Lines()) {
+ SlideLine(aState, &line, delta);
+ }
+ for (nsIFrame* kid : GetChildList(FrameChildListID::Float)) {
+ kid->MovePositionBy(wm, translation);
+ nsContainerFrame::PlaceFrameView(kid);
+ }
+ if (HasOutsideMarker() && !mLines.empty()) {
+ nsIFrame* marker = GetOutsideMarker();
+ marker->MovePositionBy(wm, translation);
+ }
+ }
+
+ if (shift) {
+ // Cache shift
+ SetProperty(AlignContentShift(), shift);
+ } else {
+ RemoveProperty(AlignContentShift());
+ }
+}
+
void nsBlockFrame::ConsiderBlockEndEdgeOfChildren(
OverflowAreas& aOverflowAreas, nscoord aBEndEdgeOfChildren,
const nsStyleDisplay* aDisplay) const {
@@ -3153,9 +3193,12 @@ bool nsBlockFrame::ReflowDirtyLines(BlockReflowState& aState) {
// Immediately fragment for page-name. It is possible we could break
// out of the loop right here, but this should make it more similar to
// what happens when reflow causes fragmentation.
- PushTruncatedLine(aState, line, &keepGoing);
+ // Set the page name, so that PushTruncatedLine does not need to
+ // recalculate the new page name.
PresShell()->FrameConstructor()->SetNextPageContentFramePageName(
nextPageName ? nextPageName : GetAutoPageValue());
+ PushTruncatedLine(aState, line, &keepGoing,
+ ComputeNewPageNameIfNeeded::No);
} else {
// Reflow the dirty line. If it's an incremental reflow, then force
// it to invalidate the dirty area if necessary
@@ -3867,7 +3910,7 @@ bool nsBlockFrame::IsSelfEmpty() {
// Blocks which are margin-roots (including inline-blocks) cannot be treated
// as empty for margin-collapsing and other purposes. They're more like
// replaced elements.
- if (HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
+ if (HasAnyStateBits(NS_BLOCK_BFC)) {
return false;
}
@@ -4730,11 +4773,25 @@ void nsBlockFrame::SetBreakBeforeStatusBeforeLine(BlockReflowState& aState,
*aKeepReflowGoing = false;
}
-void nsBlockFrame::PushTruncatedLine(BlockReflowState& aState,
- LineIterator aLine,
- bool* aKeepReflowGoing) {
+void nsBlockFrame::PushTruncatedLine(
+ BlockReflowState& aState, LineIterator aLine, bool* aKeepReflowGoing,
+ ComputeNewPageNameIfNeeded aComputeNewPageName) {
PushLines(aState, aLine.prev());
*aKeepReflowGoing = false;
+
+ if (aComputeNewPageName == ComputeNewPageNameIfNeeded::Yes) {
+ // mCanHaveClassABreakpoints can only be true during paginated reflow, and
+ // we expect this function to only be called when the available bsize is
+ // constrained.
+ const WritingMode wm = GetWritingMode();
+ const bool canBreakForPageNames =
+ aState.mReflowInput.mFlags.mCanHaveClassABreakpoints &&
+ !PresShell()->GetRootFrame()->GetWritingMode().IsOrthogonalTo(wm);
+ if (canBreakForPageNames) {
+ PresShell()->FrameConstructor()->MaybeSetNextPageContentFramePageName(
+ aLine->mFirstChild);
+ }
+ }
aState.mReflowStatus.SetIncomplete();
}
@@ -5177,7 +5234,7 @@ void nsBlockFrame::SplitFloat(BlockReflowState& aState, nsIFrame* aFloat,
}
aState.AppendPushedFloatChain(nextInFlow);
- if (MOZ_LIKELY(!HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) ||
+ if (MOZ_LIKELY(!HasAnyStateBits(NS_BLOCK_BFC)) ||
MOZ_UNLIKELY(IsTrueOverflowContainer())) {
aState.mReflowStatus.SetOverflowIncomplete();
} else {
@@ -6290,7 +6347,7 @@ nsContainerFrame* nsBlockFrame::GetRubyContentPseudoFrame() {
auto* firstChild = PrincipalChildList().FirstChild();
if (firstChild && firstChild->IsRubyFrame() &&
firstChild->Style()->GetPseudoType() ==
- mozilla::PseudoStyleType::blockRubyContent) {
+ PseudoStyleType::blockRubyContent) {
return static_cast<nsContainerFrame*>(firstChild);
}
return nullptr;
@@ -6425,15 +6482,80 @@ nsBlockInFlowLineIterator::nsBlockInFlowLineIterator(nsBlockFrame* aFrame,
*aFoundValidLine = FindValidLine();
}
+static bool AnonymousBoxIsBFC(const ComputedStyle* aStyle) {
+ switch (aStyle->GetPseudoType()) {
+ case PseudoStyleType::fieldsetContent:
+ case PseudoStyleType::columnContent:
+ case PseudoStyleType::buttonContent:
+ case PseudoStyleType::cellContent:
+ case PseudoStyleType::scrolledContent:
+ case PseudoStyleType::anonymousItem:
+ return true;
+ default:
+ return false;
+ }
+}
+
static bool StyleEstablishesBFC(const ComputedStyle* aStyle) {
// paint/layout containment boxes and multi-column containers establish an
// independent formatting context.
// https://drafts.csswg.org/css-contain/#containment-paint
// https://drafts.csswg.org/css-contain/#containment-layout
+ // https://drafts.csswg.org/css-align/#distribution-block
// https://drafts.csswg.org/css-multicol/#columns
- return aStyle->StyleDisplay()->IsContainPaint() ||
- aStyle->StyleDisplay()->IsContainLayout() ||
- aStyle->GetPseudoType() == PseudoStyleType::columnContent;
+ const auto* disp = aStyle->StyleDisplay();
+ return disp->IsContainPaint() || disp->IsContainLayout() ||
+ disp->DisplayInside() == StyleDisplayInside::FlowRoot ||
+ disp->IsAbsolutelyPositionedStyle() || disp->IsFloatingStyle() ||
+ aStyle->StylePosition()->mAlignContent.primary !=
+ StyleAlignFlags::NORMAL ||
+ aStyle->IsRootElementStyle() || AnonymousBoxIsBFC(aStyle);
+}
+
+static bool EstablishesBFC(const nsBlockFrame* aFrame) {
+ if (aFrame->HasAnyClassFlag(LayoutFrameClassFlags::BlockFormattingContext)) {
+ return true;
+ }
+
+ if (nsIFrame* parent = aFrame->GetParent()) {
+ if (parent->IsFieldSetFrame()) {
+ // A rendered legend always establishes a new formatting context, and so
+ // does the fieldset content frame, so we can just return true here.
+ // https://html.spec.whatwg.org/#rendered-legend
+ return true;
+ }
+
+ const auto wm = aFrame->GetWritingMode();
+ const auto parentWM = parent->GetWritingMode();
+ if (wm.GetBlockDir() != parentWM.GetBlockDir() ||
+ wm.IsVerticalSideways() != parentWM.IsVerticalSideways()) {
+ // If a box has a different writing-mode value than its containing block
+ // [...] if the box is a block container, then it establishes a new block
+ // formatting context.
+ // https://drafts.csswg.org/css-writing-modes/#block-flow
+ return true;
+ }
+ }
+
+ if (aFrame->IsColumnSpan()) {
+ return true;
+ }
+
+ if (aFrame->IsSuppressedScrollableBlockForPrint()) {
+ return true;
+ }
+
+ const auto* style = aFrame->Style();
+ if (style->GetPseudoType() == PseudoStyleType::marker) {
+ if (aFrame->GetParent() &&
+ aFrame->GetParent()->StyleList()->mListStylePosition ==
+ StyleListStylePosition::Outside) {
+ // An outside ::marker needs to be an independent formatting context
+ // to avoid being influenced by the float manager etc.
+ return true;
+ }
+ }
+ return StyleEstablishesBFC(style);
}
void nsBlockFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
@@ -6442,24 +6564,16 @@ void nsBlockFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
return;
}
- // If NS_BLOCK_STATIC_BFC flag was set when the frame was initialized, it
- // remains set during the lifetime of the frame and always forces it to be
- // treated as a BFC, independently of the value of NS_BLOCK_DYNAMIC_BFC.
- // Consequently, we don't bother invalidating or updating that latter flag.
- if (HasAnyStateBits(NS_BLOCK_STATIC_BFC)) {
- return;
- }
-
- bool isBFC = StyleEstablishesBFC(Style());
- if (StyleEstablishesBFC(aOldStyle) != isBFC) {
+ const bool isBFC = EstablishesBFC(this);
+ if (HasAnyStateBits(NS_BLOCK_BFC) != isBFC) {
if (MaybeHasFloats()) {
// If the frame contains floats, this update may change their float
// manager. Be safe by dirtying all descendant lines of the nearest
// ancestor's float manager.
- RemoveStateBits(NS_BLOCK_DYNAMIC_BFC);
+ RemoveStateBits(NS_BLOCK_BFC);
MarkSameFloatManagerLinesDirty(this);
}
- AddOrRemoveStateBits(NS_BLOCK_DYNAMIC_BFC, isBFC);
+ AddOrRemoveStateBits(NS_BLOCK_BFC, isBFC);
}
}
@@ -7469,11 +7583,11 @@ void nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// We'll try to draw an accessibility backplate behind text (to ensure it's
// readable over any possible background-images), if all of the following
// hold:
- // (A) the backplate feature is preffed on
- // (B) we are not honoring the document colors
+ // (A) we are not honoring the document colors
+ // (B) the backplate feature is preffed on
// (C) the force color adjust property is set to auto
- if (StaticPrefs::browser_display_permit_backplate() &&
- PresContext()->ForcingColors() && !IsComboboxControlFrame() &&
+ if (PresContext()->ForcingColors() &&
+ StaticPrefs::browser_display_permit_backplate() &&
StyleText()->mForcedColorAdjust != StyleForcedColorAdjust::None) {
backplateColor.emplace(GetBackplateColor(this));
}
@@ -7565,7 +7679,7 @@ void nsBlockFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
}
lastY = lineArea.y;
lastYMost = lineArea.YMost();
- if (lineInLine && backplateColor && LineHasVisibleInlineContent(line)) {
+ if (lineInLine && backplateColor && LineHasVisibleInlineText(line)) {
nsRect lineBackplate = GetLineTextArea(line, aBuilder) +
aBuilder->ToReferenceFrame(this);
if (curBackplateArea.IsEmpty()) {
@@ -7762,35 +7876,15 @@ void nsBlockFrame::ChildIsDirty(nsIFrame* aChild) {
nsContainerFrame::ChildIsDirty(aChild);
}
-static bool AlwaysEstablishesBFC(const nsBlockFrame* aFrame) {
- switch (aFrame->Type()) {
- case LayoutFrameType::ColumnSetWrapper:
- // CSS Multi-column level 1 section 2: A multi-column container
- // establishes a new block formatting context, as per CSS 2.1 section
- // 9.4.1.
- case LayoutFrameType::ComboboxControl:
- return true;
- case LayoutFrameType::Block:
- return static_cast<const nsFileControlFrame*>(do_QueryFrame(aFrame)) ||
- // Ensure that the options inside the select aren't expanded by
- // right floats outside the select.
- static_cast<const nsSelectsAreaFrame*>(do_QueryFrame(aFrame)) ||
- // See bug 1373767 and bug 353894.
- static_cast<const nsMathMLmathBlockFrame*>(do_QueryFrame(aFrame));
- default:
- return false;
- }
-}
-
void nsBlockFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
nsIFrame* aPrevInFlow) {
// These are all the block specific frame bits, they are copied from
// the prev-in-flow to a newly created next-in-flow, except for the
// NS_BLOCK_FLAGS_NON_INHERITED_MASK bits below.
constexpr nsFrameState NS_BLOCK_FLAGS_MASK =
- NS_BLOCK_BFC_STATE_BITS | NS_BLOCK_CLIP_PAGINATED_OVERFLOW |
- NS_BLOCK_HAS_FIRST_LETTER_STYLE | NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER |
- NS_BLOCK_HAS_FIRST_LETTER_CHILD | NS_BLOCK_FRAME_HAS_INSIDE_MARKER;
+ NS_BLOCK_BFC | NS_BLOCK_HAS_FIRST_LETTER_STYLE |
+ NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER | NS_BLOCK_HAS_FIRST_LETTER_CHILD |
+ NS_BLOCK_FRAME_HAS_INSIDE_MARKER;
// This is the subset of NS_BLOCK_FLAGS_MASK that is NOT inherited
// by default. They should only be set on the first-in-flow.
@@ -7812,37 +7906,12 @@ void nsBlockFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
AddStateBits(NS_BLOCK_NEEDS_BIDI_RESOLUTION);
}
- // A display:flow-root box establishes a block formatting context.
- //
- // If a box has a different writing-mode value than its containing block:
- // ...
- // If the box is a block container, then it establishes a new block
- // formatting context.
- // (https://drafts.csswg.org/css-writing-modes/#block-flow)
- //
- // If the box has contain: paint or contain:layout (or contain:strict),
- // then it should also establish a formatting context.
- //
- // Per spec, a column-span always establishes a new block formatting context.
- //
- // Other more specific frame types also always establish a BFC.
- //
- if (StyleDisplay()->mDisplay == mozilla::StyleDisplay::FlowRoot ||
- (GetParent() &&
- (GetWritingMode().GetBlockDir() !=
- GetParent()->GetWritingMode().GetBlockDir() ||
- GetWritingMode().IsVerticalSideways() !=
- GetParent()->GetWritingMode().IsVerticalSideways())) ||
- IsColumnSpan() || AlwaysEstablishesBFC(this)) {
- AddStateBits(NS_BLOCK_STATIC_BFC);
- }
-
- if (StyleEstablishesBFC(Style())) {
- AddStateBits(NS_BLOCK_DYNAMIC_BFC);
+ if (EstablishesBFC(this)) {
+ AddStateBits(NS_BLOCK_BFC);
}
if (HasAnyStateBits(NS_FRAME_FONT_INFLATION_CONTAINER) &&
- HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
+ HasAnyStateBits(NS_BLOCK_BFC)) {
AddStateBits(NS_FRAME_FONT_INFLATION_FLOW_ROOT);
}
}
@@ -7866,13 +7935,13 @@ void nsBlockFrame::SetInitialChildList(ChildListID aListID,
(pseudo == PseudoStyleType::cellContent &&
!GetParent()->Style()->IsPseudoOrAnonBox()) ||
pseudo == PseudoStyleType::fieldsetContent ||
- pseudo == PseudoStyleType::buttonContent ||
+ (pseudo == PseudoStyleType::buttonContent &&
+ !GetParent()->IsComboboxControlFrame()) ||
pseudo == PseudoStyleType::columnContent ||
(pseudo == PseudoStyleType::scrolledContent &&
!GetParent()->IsListControlFrame()) ||
pseudo == PseudoStyleType::mozSVGText) &&
- !IsComboboxControlFrame() && !IsMathMLFrame() &&
- !IsColumnSetWrapperFrame() &&
+ !IsMathMLFrame() && !IsColumnSetWrapperFrame() &&
RefPtr<ComputedStyle>(GetFirstLetterStyle(PresContext())) != nullptr;
NS_ASSERTION(haveFirstLetterStyle ==
HasAnyStateBits(NS_BLOCK_HAS_FIRST_LETTER_STYLE),
@@ -7895,11 +7964,6 @@ void nsBlockFrame::SetMarkerFrameForListItem(nsIFrame* aMarkerFrame) {
SetProperty(InsideMarkerProperty(), aMarkerFrame);
AddStateBits(NS_BLOCK_FRAME_HAS_INSIDE_MARKER);
} else {
- if (nsBlockFrame* marker = do_QueryFrame(aMarkerFrame)) {
- // An outside ::marker needs to be an independent formatting context
- // to avoid being influenced by the float manager etc.
- marker->AddStateBits(NS_BLOCK_STATIC_BFC);
- }
SetProperty(OutsideMarkerProperty(),
new (PresShell()) nsFrameList(aMarkerFrame, aMarkerFrame));
AddStateBits(NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER);
@@ -8100,7 +8164,7 @@ void nsBlockFrame::CheckFloats(BlockReflowState& aState) {
void nsBlockFrame::IsMarginRoot(bool* aBStartMarginRoot,
bool* aBEndMarginRoot) {
nsIFrame* parent = GetParent();
- if (!HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
+ if (!HasAnyStateBits(NS_BLOCK_BFC)) {
if (!parent || parent->IsFloatContainingBlock()) {
*aBStartMarginRoot = false;
*aBEndMarginRoot = false;
@@ -8127,14 +8191,14 @@ bool nsBlockFrame::BlockNeedsFloatManager(nsIFrame* aBlock) {
NS_ASSERTION(aBlock->IsBlockFrameOrSubclass(), "aBlock must be a block");
nsIFrame* parent = aBlock->GetParent();
- return aBlock->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS) ||
+ return aBlock->HasAnyStateBits(NS_BLOCK_BFC) ||
(parent && !parent->IsFloatContainingBlock());
}
/* static */
bool nsBlockFrame::BlockCanIntersectFloats(nsIFrame* aFrame) {
return aFrame->IsBlockFrameOrSubclass() && !aFrame->IsReplaced() &&
- !aFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS);
+ !aFrame->HasAnyStateBits(NS_BLOCK_BFC);
}
// Note that this width can vary based on the vertical position.
diff --git a/layout/generic/nsBlockFrame.h b/layout/generic/nsBlockFrame.h
index 15dd4c3278..9fb909430c 100644
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -492,6 +492,14 @@ class nsBlockFrame : public nsContainerFrame {
BlockReflowState& aState, ReflowOutput& aMetrics);
/**
+ * Calculates the necessary shift to honor 'align-content' and applies it.
+ */
+ void AlignContent(BlockReflowState& aState, ReflowOutput& aMetrics,
+ nscoord aBEndEdgeOfChildren);
+ // Stash the effective align-content shift value between reflows
+ NS_DECLARE_FRAME_PROPERTY_SMALL_VALUE(AlignContentShift, nscoord)
+
+ /**
* Helper method for Reflow(). Computes the overflow areas created by our
* children, and includes them into aOverflowAreas.
*/
@@ -540,6 +548,16 @@ class nsBlockFrame : public nsContainerFrame {
*/
bool IsVisualFormControl(nsPresContext* aPresContext);
+ /** Whether this block has an effective align-content property */
+ bool IsAligned() const {
+ return StylePosition()->mAlignContent.primary !=
+ mozilla::StyleAlignFlags::NORMAL;
+ }
+
+ nscoord GetAlignContentShift() const {
+ return IsAligned() ? GetProperty(AlignContentShift()) : 0;
+ }
+
/**
* For text-wrap:balance, we iteratively try reflowing with adjusted inline
* size to find the "best" result (the tightest size that can be applied
@@ -849,12 +867,23 @@ class nsBlockFrame : public nsContainerFrame {
bool* aKeepReflowGoing);
/**
+ * Indicates if we need to compute a page name for the next page when pushing
+ * a truncated line.
+ *
+ * Using a value of No saves work when a new page name has already been set
+ * with nsCSSFrameConstructor::SetNextPageContentFramePageName.
+ */
+ enum class ComputeNewPageNameIfNeeded : uint8_t { Yes, No };
+
+ /**
* Push aLine (and any after it), since it cannot be placed on this
* page/column. Set aKeepReflowGoing to false and set
* flag aState.mReflowStatus as incomplete.
*/
void PushTruncatedLine(BlockReflowState& aState, LineIterator aLine,
- bool* aKeepReflowGoing);
+ bool* aKeepReflowGoing,
+ ComputeNewPageNameIfNeeded aComputeNewPageName =
+ ComputeNewPageNameIfNeeded::Yes);
void SplitLine(BlockReflowState& aState, nsLineLayout& aLineLayout,
LineIterator aLine, nsIFrame* aFrame,
diff --git a/layout/generic/nsBlockReflowContext.cpp b/layout/generic/nsBlockReflowContext.cpp
index ceae9f4849..23f3b83645 100644
--- a/layout/generic/nsBlockReflowContext.cpp
+++ b/layout/generic/nsBlockReflowContext.cpp
@@ -275,7 +275,7 @@ void nsBlockReflowContext::ReflowBlock(const LogicalRect& aSpace,
tI = space.LineLeft(mWritingMode, mContainerSize);
tB = mBCoord;
- if (!mFrame->HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
+ if (!mFrame->HasAnyStateBits(NS_BLOCK_BFC)) {
aFrameRI.mBlockDelta =
mOuterReflowInput.mBlockDelta + mBCoord - aLine->BStart();
}
diff --git a/layout/generic/nsContainerFrame.cpp b/layout/generic/nsContainerFrame.cpp
index 9629905968..2577a7a00d 100644
--- a/layout/generic/nsContainerFrame.cpp
+++ b/layout/generic/nsContainerFrame.cpp
@@ -1124,7 +1124,6 @@ void nsContainerFrame::ReflowOverflowContainerChildren(
// isn't dirty.
if (shouldReflowAllKids || frame->IsSubtreeDirty() ||
ScrollableOverflowExceedsAvailableBSize(frame)) {
- // Get prev-in-flow
nsIFrame* prevInFlow = frame->GetPrevInFlow();
NS_ASSERTION(prevInFlow,
"overflow container frame must have a prev-in-flow");
@@ -1132,38 +1131,45 @@ void nsContainerFrame::ReflowOverflowContainerChildren(
frame->HasAnyStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER),
"overflow container frame must have overflow container bit set");
WritingMode wm = frame->GetWritingMode();
- nsSize containerSize =
- aContainerSize ? *aContainerSize
- : aReflowInput.AvailableSize(wm).GetPhysicalSize(wm);
- LogicalRect prevRect = prevInFlow->GetLogicalRect(wm, containerSize);
-
- // Initialize reflow params
- LogicalSize availSpace(wm, prevRect.ISize(wm),
- aReflowInput.AvailableSize(wm).BSize(wm));
- ReflowOutput desiredSize(aReflowInput);
+ // Note: aReflowInput's available inline-size is technically wrong for us
+ // to hand off to children here, because it doesn't account for the space
+ // that's been used for the container's margin/border/padding (and some
+ // other space that a concrete container type, e.g. fieldset and grid [1],
+ // might reserve before setting up the available space for their
+ // children). Since we don't have a way to query the specific available
+ // inline-size each container type used, nor do we know how the container
+ // computes its non-overflow-container children's inline-size, we just
+ // unconditionally override the frame's inline-size, so that the available
+ // inline-size for the children doesn't really matter anyway.
+ //
+ // [1] For example, fieldset uses its computed inline-size with padding as
+ // the available inline-size to reflow its inner child frame.
+ // https://searchfox.org/mozilla-central/rev/04f7743d94691fa24212fb43099f9d84c3bfc890/layout/forms/nsFieldSetFrame.cpp#535-536
+ const LogicalSize availSpace = aReflowInput.AvailableSize(wm);
StyleSizeOverrides sizeOverride;
- if (frame->IsFlexItem()) {
- // A flex item's size is determined by the flex algorithm, not solely by
- // its style. Thus, the following overrides are necessary.
- //
- // Use the overflow container flex item's prev-in-flow inline-size since
- // this continuation's inline-size is the same.
- sizeOverride.mStyleISize.emplace(
- StyleSize::LengthPercentage(LengthPercentage::FromAppUnits(
- frame->StylePosition()->mBoxSizing == StyleBoxSizing::Border
- ? prevRect.ISize(wm)
- : prevInFlow->ContentISize(wm))));
+ // We override current continuation's inline-size by using the
+ // prev-in-flow's inline-size since both should be the same.
+ sizeOverride.mStyleISize.emplace(
+ StyleSize::LengthPercentage(LengthPercentage::FromAppUnits(
+ frame->StylePosition()->mBoxSizing == StyleBoxSizing::Border
+ ? prevInFlow->ISize(wm)
+ : prevInFlow->ContentISize(wm))));
+ if (frame->IsFlexItem()) {
// An overflow container's block-size must be 0.
sizeOverride.mStyleBSize.emplace(
StyleSize::LengthPercentage(LengthPercentage::FromAppUnits(0)));
}
+ ReflowOutput desiredSize(wm);
ReflowInput reflowInput(aPresContext, aReflowInput, frame, availSpace,
Nothing(), {}, sizeOverride);
-
- LogicalPoint pos(wm, prevRect.IStart(wm), 0);
+ const nsSize containerSize =
+ aContainerSize ? *aContainerSize
+ : aReflowInput.AvailableSize(wm).GetPhysicalSize(wm);
+ const LogicalPoint pos(wm, prevInFlow->IStart(wm, containerSize), 0);
nsReflowStatus frameStatus;
+
ReflowChild(frame, aPresContext, desiredSize, reflowInput, wm, pos,
containerSize, aFlags, frameStatus, &tracker);
FinishReflowChild(frame, aPresContext, desiredSize, &reflowInput, wm, pos,
diff --git a/layout/generic/nsFloatManager.h b/layout/generic/nsFloatManager.h
index f947567383..eb12d44e1d 100644
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -70,8 +70,8 @@ struct nsFlowAreaRect {
/**
* nsFloatManager is responsible for implementing CSS's rules for
* positioning floats. An nsFloatManager object is created during reflow for
- * any block with NS_BLOCK_BFC_STATE_BITS. During reflow, the float manager for
- * the nearest such ancestor block is found in ReflowInput::mFloatManager.
+ * any block with NS_BLOCK_BFC. During reflow, the float manager for the nearest
+ * such ancestor block is found in ReflowInput::mFloatManager.
*
* According to the line-relative mappings in CSS Writing Modes spec [1],
* line-right and line-left are calculated with respect to the writing mode
diff --git a/layout/generic/nsFrameSelection.cpp b/layout/generic/nsFrameSelection.cpp
index 002d26c4fa..f1a8c7e27c 100644
--- a/layout/generic/nsFrameSelection.cpp
+++ b/layout/generic/nsFrameSelection.cpp
@@ -31,7 +31,6 @@
#include "nsFrameTraversal.h"
#include "nsString.h"
#include "nsISelectionListener.h"
-#include "nsContentCID.h"
#include "nsDeviceContext.h"
#include "nsIContent.h"
#include "nsRange.h"
@@ -48,7 +47,6 @@
#include "nsGkAtoms.h"
#include "nsLayoutUtils.h"
-#include "nsLayoutCID.h"
#include "nsBidiPresUtils.h"
#include "nsTextFrame.h"
diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h
index a9a1700737..db00deab95 100644
--- a/layout/generic/nsFrameStateBits.h
+++ b/layout/generic/nsFrameStateBits.h
@@ -541,41 +541,30 @@ FRAME_STATE_BIT(Block, 21, NS_BLOCK_HAS_PUSHED_FLOATS)
// 2. This indicates that a block frame should create its own float manager.
// This is required by each block frame that can contain floats. The float
// manager is used to reserve space for the floated frames.
-FRAME_STATE_BIT(Block, 22, NS_BLOCK_STATIC_BFC)
+FRAME_STATE_BIT(Block, 22, NS_BLOCK_BFC)
-// This is the same as NS_BLOCK_STATIC_BFC but can be updated dynamically after
-// the frame construction (e.g. paint/layout containment).
-// FIXME(bug 1874823): Try and merge this and NS_BLOCK_STATIC_BFC.
-FRAME_STATE_BIT(Block, 23, NS_BLOCK_DYNAMIC_BFC)
+FRAME_STATE_BIT(Block, 23, NS_BLOCK_HAS_LINE_CURSOR)
-// For testing the relevant bits on a block formatting context:
-#define NS_BLOCK_BFC_STATE_BITS (NS_BLOCK_STATIC_BFC | NS_BLOCK_DYNAMIC_BFC)
+FRAME_STATE_BIT(Block, 24, NS_BLOCK_HAS_OVERFLOW_LINES)
-FRAME_STATE_BIT(Block, 24, NS_BLOCK_HAS_LINE_CURSOR)
-
-FRAME_STATE_BIT(Block, 25, NS_BLOCK_HAS_OVERFLOW_LINES)
-
-FRAME_STATE_BIT(Block, 26, NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS)
+FRAME_STATE_BIT(Block, 25, NS_BLOCK_HAS_OVERFLOW_OUT_OF_FLOWS)
// Set on any block that has descendant frames in the normal
// flow with 'clear' set to something other than 'none'
// (including <BR CLEAR="..."> frames)
-FRAME_STATE_BIT(Block, 27, NS_BLOCK_HAS_CLEAR_CHILDREN)
-
-// NS_BLOCK_CLIP_PAGINATED_OVERFLOW is only set in paginated prescontexts, on
-// blocks which were forced to not have scrollframes but still need to clip
-// the display of their kids.
-FRAME_STATE_BIT(Block, 28, NS_BLOCK_CLIP_PAGINATED_OVERFLOW)
+FRAME_STATE_BIT(Block, 26, NS_BLOCK_HAS_CLEAR_CHILDREN)
// NS_BLOCK_HAS_FIRST_LETTER_STYLE means that the block has first-letter style,
// even if it has no actual first-letter frame among its descendants.
-FRAME_STATE_BIT(Block, 29, NS_BLOCK_HAS_FIRST_LETTER_STYLE)
+FRAME_STATE_BIT(Block, 27, NS_BLOCK_HAS_FIRST_LETTER_STYLE)
// NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER and NS_BLOCK_FRAME_HAS_INSIDE_MARKER
// means the block has an associated ::marker frame, they are mutually
// exclusive.
-FRAME_STATE_BIT(Block, 30, NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER)
-FRAME_STATE_BIT(Block, 31, NS_BLOCK_FRAME_HAS_INSIDE_MARKER)
+FRAME_STATE_BIT(Block, 28, NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER)
+FRAME_STATE_BIT(Block, 29, NS_BLOCK_FRAME_HAS_INSIDE_MARKER)
+
+// bits 30 and 31 free.
// NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS indicates that exactly one line in this
// block has the LineClampEllipsis flag set, and that such a line must be found
diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp
index b51f3eccb7..361847b753 100644
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -1172,10 +1172,16 @@ void nsHTMLScrollFrame::PlaceScrollArea(ScrollReflowInput& aState,
scrolledArea, ReflowChildFlags::Default);
}
-nscoord nsHTMLScrollFrame::IntrinsicScrollbarGutterSizeAtInlineEdges() {
- const bool isVerticalWM = GetWritingMode().IsVertical();
+nscoord nsHTMLScrollFrame::IntrinsicScrollbarGutterSizeAtInlineEdges() const {
+ const auto wm = GetWritingMode();
+ const LogicalMargin gutter(wm, IntrinsicScrollbarGutterSize());
+ return gutter.IStartEnd(wm);
+}
+
+nsMargin nsHTMLScrollFrame::IntrinsicScrollbarGutterSize() const {
if (PresContext()->UseOverlayScrollbars()) {
- return 0;
+ // Overlay scrollbars do not consume space per spec.
+ return {};
}
const auto* styleForScrollbar = nsLayoutUtils::StyleForScrollbar(this);
@@ -1183,28 +1189,30 @@ nscoord nsHTMLScrollFrame::IntrinsicScrollbarGutterSizeAtInlineEdges() {
styleForScrollbar->StyleUIReset()->ScrollbarWidth();
if (styleScrollbarWidth == StyleScrollbarWidth::None) {
// Scrollbar shouldn't appear at all with "scrollbar-width: none".
- return 0;
+ return {};
}
const auto& styleScrollbarGutter =
styleForScrollbar->StyleDisplay()->mScrollbarGutter;
- ScrollStyles ss = GetScrollStyles();
- const StyleOverflow& inlineEndStyleOverflow =
- isVerticalWM ? ss.mHorizontal : ss.mVertical;
-
- // Return the scrollbar-gutter size only if we have "overflow:scroll" or
- // non-auto "scrollbar-gutter", so early-return here if the conditions aren't
- // satisfied.
- if (inlineEndStyleOverflow != StyleOverflow::Scroll &&
- styleScrollbarGutter == StyleScrollbarGutter::AUTO) {
- return 0;
+ nsMargin gutter =
+ ComputeStableScrollbarGutter(styleScrollbarWidth, styleScrollbarGutter);
+ if (gutter.LeftRight() == 0 || gutter.TopBottom() == 0) {
+ // If there is no stable scrollbar-gutter at vertical or horizontal
+ // dimension, check if a scrollbar is always shown at that dimension.
+ ScrollStyles scrollStyles = GetScrollStyles();
+ const nscoord scrollbarSize =
+ GetNonOverlayScrollbarSize(PresContext(), styleScrollbarWidth);
+ if (gutter.LeftRight() == 0 &&
+ scrollStyles.mVertical == StyleOverflow::Scroll) {
+ (IsScrollbarOnRight() ? gutter.right : gutter.left) = scrollbarSize;
+ }
+ if (gutter.TopBottom() == 0 &&
+ scrollStyles.mHorizontal == StyleOverflow::Scroll) {
+ // The horizontal scrollbar is always at the bottom side.
+ gutter.bottom = scrollbarSize;
+ }
}
-
- const nscoord scrollbarSize =
- GetNonOverlayScrollbarSize(PresContext(), styleScrollbarWidth);
- const auto bothEdges =
- bool(styleScrollbarGutter & StyleScrollbarGutter::BOTH_EDGES);
- return bothEdges ? scrollbarSize * 2 : scrollbarSize;
+ return gutter;
}
nsMargin nsHTMLScrollFrame::ComputeStableScrollbarGutter(
@@ -2040,8 +2048,13 @@ class nsHTMLScrollFrame::AsyncSmoothMSDScroll final
* Should be used at most once during the lifetime of this object.
*/
void SetRefreshObserver(nsHTMLScrollFrame* aCallee) {
- NS_ASSERTION(aCallee && !mCallee,
- "AsyncSmoothMSDScroll::SetRefreshObserver - Invalid usage.");
+ MOZ_ASSERT(aCallee,
+ "AsyncSmoothMSDScroll::SetRefreshObserver needs "
+ "a non-null aCallee in order to get a refresh driver");
+ MOZ_RELEASE_ASSERT(!mCallee,
+ "AsyncSmoothMSDScroll::SetRefreshObserver "
+ "shouldn't be called if we're already registered with "
+ "a refresh driver, via a preexisting mCallee");
RefreshDriver(aCallee)->AddRefreshObserver(this, FlushType::Style,
"Smooth scroll (MSD) animation");
@@ -2168,8 +2181,13 @@ class nsHTMLScrollFrame::AsyncScroll final : public nsARefreshObserver {
* Should be used at most once during the lifetime of this object.
*/
void SetRefreshObserver(nsHTMLScrollFrame* aCallee) {
- NS_ASSERTION(aCallee && !mCallee,
- "AsyncScroll::SetRefreshObserver - Invalid usage.");
+ MOZ_ASSERT(aCallee,
+ "AsyncScroll::SetRefreshObserver needs "
+ "a non-null aCallee in order to get a refresh driver");
+ MOZ_RELEASE_ASSERT(!mCallee,
+ "AsyncScroll::SetRefreshObserver "
+ "shouldn't be called if we're already registered with "
+ "a refresh driver, via a preexisting mCallee");
RefreshDriver(aCallee)->AddRefreshObserver(this, FlushType::Style,
"Smooth scroll animation");
@@ -2235,12 +2253,7 @@ void nsHTMLScrollFrame::AsyncScroll::InitSmoothScroll(
case ScrollOrigin::Apz:
// Likewise we should never get APZ-triggered scrolls here, and if that
// changes something is likely broken somewhere.
- MOZ_ASSERT_UNREACHABLE(
- "APZ scroll position updates should never be smooth");
- break;
- case ScrollOrigin::AnchorAdjustment:
- MOZ_ASSERT_UNREACHABLE(
- "scroll anchor adjustments should never be smooth");
+ MOZ_ASSERT(false);
break;
default:
break;
@@ -3016,7 +3029,6 @@ void nsHTMLScrollFrame::ScrollToImpl(
(mLastScrollOrigin != ScrollOrigin::None &&
mLastScrollOrigin != ScrollOrigin::NotSpecified &&
mLastScrollOrigin != ScrollOrigin::Relative &&
- mLastScrollOrigin != ScrollOrigin::AnchorAdjustment &&
mLastScrollOrigin != ScrollOrigin::Apz)) {
aOrigin = ScrollOrigin::Other;
}
@@ -3069,10 +3081,8 @@ void nsHTMLScrollFrame::ScrollToImpl(
// may simplify this a bit and should be fine from the APZ side.
if (mApzSmoothScrollDestination && aOrigin != ScrollOrigin::Clamp) {
if (aOrigin == ScrollOrigin::Relative) {
- AppendScrollUpdate(ScrollPositionUpdate::NewRelativeScroll(
- // Clamp |mApzScrollPos| here. See the comment for this clamping
- // reason below NewRelativeScroll call.
- GetLayoutScrollRange().ClampPoint(mApzScrollPos), pt));
+ AppendScrollUpdate(
+ ScrollPositionUpdate::NewRelativeScroll(mApzScrollPos, pt));
mApzScrollPos = pt;
} else if (aOrigin != ScrollOrigin::Apz) {
ScrollOrigin origin =
@@ -3159,15 +3169,8 @@ void nsHTMLScrollFrame::ScrollToImpl(
if (aOrigin == ScrollOrigin::Relative) {
MOZ_ASSERT(!isScrollOriginDowngrade);
MOZ_ASSERT(mLastScrollOrigin == ScrollOrigin::Relative);
- AppendScrollUpdate(ScrollPositionUpdate::NewRelativeScroll(
- // It's possible that |mApzScrollPos| is no longer within the scroll
- // range, we need to clamp it to the current scroll range, otherwise
- // calculating a relative scroll distance from the outside point will
- // result a point far from the desired point.
- GetLayoutScrollRange().ClampPoint(mApzScrollPos), pt));
- mApzScrollPos = pt;
- } else if (aOrigin == ScrollOrigin::AnchorAdjustment) {
- AppendScrollUpdate(ScrollPositionUpdate::NewMergeableScroll(aOrigin, pt));
+ AppendScrollUpdate(
+ ScrollPositionUpdate::NewRelativeScroll(mApzScrollPos, pt));
mApzScrollPos = pt;
} else if (aOrigin != ScrollOrigin::Apz) {
AppendScrollUpdate(ScrollPositionUpdate::NewScroll(mLastScrollOrigin, pt));
diff --git a/layout/generic/nsGfxScrollFrame.h b/layout/generic/nsGfxScrollFrame.h
index e05a2a077b..ce2a75a3df 100644
--- a/layout/generic/nsGfxScrollFrame.h
+++ b/layout/generic/nsGfxScrollFrame.h
@@ -110,7 +110,13 @@ class nsHTMLScrollFrame : public nsContainerFrame,
// Return the sum of inline-size of the scrollbar gutters (if any) at the
// inline-start and inline-end edges of the scroll frame (for a potential
// scrollbar that scrolls in the block axis).
- nscoord IntrinsicScrollbarGutterSizeAtInlineEdges();
+ nscoord IntrinsicScrollbarGutterSizeAtInlineEdges() const;
+
+ // Return the size of space created by scrollbar-gutter or actual scrollbars,
+ // assuming that the content is *not* overflowing the container. In other
+ // words, this space is created by stable scrollbar-gutter or by scrollbars
+ // due to "overflow: scroll".
+ nsMargin IntrinsicScrollbarGutterSize() const;
// Compute stable scrollbar-gutter from scrollbar-width and scrollbar-gutter
// properties.
diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp
index 97d8549cb0..5eb9cde7da 100644
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -28,6 +28,7 @@
#include "nsCSSFrameConstructor.h"
#include "nsDisplayList.h"
#include "nsFieldSetFrame.h"
+#include "nsGfxScrollFrame.h"
#include "nsHashKeys.h"
#include "nsIFrameInlines.h" // for nsIFrame::GetLogicalNormalPosition (don't remove)
#include "nsLayoutUtils.h"
@@ -3685,7 +3686,8 @@ static Subgrid* SubgridComputeMarginBorderPadding(
sz.ComputedLogicalMargin(cbWM) + sz.ComputedLogicalBorderPadding(cbWM);
if (aGridItem.mFrame != subgridFrame) {
- nsIScrollableFrame* scrollFrame = aGridItem.mFrame->GetScrollTargetFrame();
+ nsHTMLScrollFrame* scrollFrame =
+ do_QueryFrame(aGridItem.mFrame->GetScrollTargetFrame());
if (scrollFrame) {
MOZ_ASSERT(
sz.ComputedLogicalMargin(cbWM) == LogicalMargin(cbWM) &&
@@ -3699,7 +3701,7 @@ static Subgrid* SubgridComputeMarginBorderPadding(
szScrollFrame.ComputedLogicalMargin(cbWM) +
szScrollFrame.ComputedLogicalBorder(cbWM);
- nsMargin ssz = scrollFrame->GetActualScrollbarSizes();
+ nsMargin ssz = scrollFrame->IntrinsicScrollbarGutterSize();
subgrid->mMarginBorderPadding += LogicalMargin(cbWM, ssz);
}
@@ -4032,16 +4034,6 @@ static void AlignSelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
aAlignSelf == StyleAlignFlags::LAST_BASELINE) {
aAlignSelf = aGridItem.GetSelfBaseline(aAlignSelf, eLogicalAxisBlock,
&baselineAdjust);
- // Adjust the baseline alignment value if the baseline affects the opposite
- // side of what AlignJustifySelf expects.
- auto state = aGridItem.mState[eLogicalAxisBlock];
- if (aAlignSelf == StyleAlignFlags::LAST_BASELINE &&
- !GridItemInfo::BaselineAlignmentAffectsEndSide(state)) {
- aAlignSelf = StyleAlignFlags::BASELINE;
- } else if (aAlignSelf == StyleAlignFlags::BASELINE &&
- GridItemInfo::BaselineAlignmentAffectsEndSide(state)) {
- aAlignSelf = StyleAlignFlags::LAST_BASELINE;
- }
}
bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
@@ -4083,16 +4075,6 @@ static void JustifySelf(const nsGridContainerFrame::GridItemInfo& aGridItem,
aJustifySelf == StyleAlignFlags::LAST_BASELINE) {
aJustifySelf = aGridItem.GetSelfBaseline(aJustifySelf, eLogicalAxisInline,
&baselineAdjust);
- // Adjust the baseline alignment value if the baseline affects the opposite
- // side of what AlignJustifySelf expects.
- auto state = aGridItem.mState[eLogicalAxisInline];
- if (aJustifySelf == StyleAlignFlags::LAST_BASELINE &&
- !GridItemInfo::BaselineAlignmentAffectsEndSide(state)) {
- aJustifySelf = StyleAlignFlags::BASELINE;
- } else if (aJustifySelf == StyleAlignFlags::BASELINE &&
- GridItemInfo::BaselineAlignmentAffectsEndSide(state)) {
- aJustifySelf = StyleAlignFlags::LAST_BASELINE;
- }
}
bool isOrthogonal = aCBWM.IsOrthogonalTo(childWM);
@@ -6006,6 +5988,12 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines(
const WritingMode containerWM = aState.mWM;
ComputedStyle* containerStyle = aState.mFrame->Style();
+ // The physical side of the container's block start side. We use it to match
+ // against the physical block start side of the child to determine its
+ // baseline sharing group.
+ auto containerBlockStartSide =
+ containerWM.PhysicalSide(MakeLogicalSide(mAxis, eLogicalEdgeStart));
+
for (GridItemInfo& gridItem : aGridItems) {
if (gridItem.IsSubgrid(mAxis)) {
// A subgrid itself is never baseline-aligned.
@@ -6101,6 +6089,27 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines(
}
if (state & ItemState::eIsBaselineAligned) {
+ // The item is baseline aligned, so calculate the baseline sharing group.
+ // <https://drafts.csswg.org/css-align-3/#baseline-terms>
+ BaselineSharingGroup baselineAlignment =
+ (state & ItemState::eFirstBaseline) ? BaselineSharingGroup::First
+ : BaselineSharingGroup::Last;
+
+ BaselineSharingGroup baselineSharingGroup = [&]() {
+ {
+ auto childAxis = isOrthogonal ? GetOrthogonalAxis(mAxis) : mAxis;
+ auto childBlockStartSide = childWM.PhysicalSide(
+ MakeLogicalSide(childAxis, eLogicalEdgeStart));
+ bool isFirstBaseline = (state & ItemState::eFirstBaseline) != 0;
+ const bool containerAndChildHasEqualBaselineSide =
+ containerBlockStartSide == childBlockStartSide;
+
+ return isFirstBaseline == containerAndChildHasEqualBaselineSide
+ ? BaselineSharingGroup::First
+ : BaselineSharingGroup::Last;
+ }
+ }();
+
// XXXmats if |child| is a descendant of a subgrid then the metrics
// below needs to account for the accumulated MPB somehow...
@@ -6128,16 +6137,13 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines(
: margin.BStartEnd(containerWM));
Maybe<nscoord> baseline;
- auto baselineSharingGroup = state & ItemState::eFirstBaseline
- ? BaselineSharingGroup::First
- : BaselineSharingGroup::Last;
if (grid) {
baseline.emplace((isOrthogonal == isInlineAxis)
- ? grid->GetBBaseline(baselineSharingGroup)
- : grid->GetIBaseline(baselineSharingGroup));
+ ? grid->GetBBaseline(baselineAlignment)
+ : grid->GetIBaseline(baselineAlignment));
} else {
baseline = child->GetNaturalBaselineBOffset(
- childWM, baselineSharingGroup, BaselineExportContext::Other);
+ childWM, baselineAlignment, BaselineExportContext::Other);
if (!baseline) {
// If baseline alignment is specified on a grid item whose size in
@@ -6162,7 +6168,7 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines(
if (!isTrackAutoSize ||
!gridItem.IsBSizeDependentOnContainerSize(containerWM)) {
baseline.emplace(Baseline::SynthesizeBOffsetFromBorderBox(
- child, containerWM, baselineSharingGroup));
+ child, containerWM, baselineAlignment));
}
}
}
@@ -6172,15 +6178,19 @@ void nsGridContainerFrame::Tracks::InitializeItemBaselines(
NS_ASSERTION(finalBaseline != NS_INTRINSIC_ISIZE_UNKNOWN,
"about to use an unknown baseline");
+ nscoord marginAdjust = 0;
if (baselineSharingGroup == BaselineSharingGroup::First) {
- finalBaseline += isInlineAxis ? margin.IStart(containerWM)
- : margin.BStart(containerWM);
-
+ marginAdjust = isInlineAxis ? margin.IStart(containerWM)
+ : margin.BStart(containerWM);
} else {
- finalBaseline += isInlineAxis ? margin.IEnd(containerWM)
- : margin.BEnd(containerWM);
- state |= ItemState::eEndSideBaseline;
+ marginAdjust = isInlineAxis ? margin.IEnd(containerWM)
+ : margin.BEnd(containerWM);
+
+ // This flag is used in ::AlignSelf(...) to check whether the item is
+ // last baseline aligned, but this flag should go away.
+ state |= GridItemInfo::eEndSideBaseline;
}
+ finalBaseline += marginAdjust;
auto& baselineItems =
(baselineSharingGroup == BaselineSharingGroup::First)
@@ -7602,7 +7612,12 @@ void nsGridContainerFrame::ReflowInFlowChild(
// This happens when the subtree overflows its track.
// XXX spec issue? it's unclear how to handle this.
baselineAdjust = nscoord(0);
- } else if (GridItemInfo::BaselineAlignmentAffectsEndSide(state)) {
+ } else if (state & ItemState::eLastBaseline) {
+ // FIXME: We're not setting the ItemState::eEndSideBaseline flag any
+ // more as the new baseline sharing group calculation handles most of
+ // the cases we need. For non-masonry grids this flag was always set
+ // for LAST_BASELINE items, so we're just mimicking that behavior here.
+ // That said, masonry grids might not work 100% any more..
baselineAdjust = -baselineAdjust;
}
if (baselineAdjust != nscoord(0)) {
diff --git a/layout/generic/nsGridContainerFrame.h b/layout/generic/nsGridContainerFrame.h
index d785d65a50..cf3a3b5776 100644
--- a/layout/generic/nsGridContainerFrame.h
+++ b/layout/generic/nsGridContainerFrame.h
@@ -106,12 +106,10 @@ class nsGridContainerFrame final : public nsContainerFrame,
using NamedArea = mozilla::StyleNamedArea;
template <typename T>
- using PerBaseline = mozilla::EnumeratedArray<BaselineSharingGroup,
- BaselineSharingGroup(2), T>;
+ using PerBaseline = mozilla::EnumeratedArray<BaselineSharingGroup, T, 2>;
template <typename T>
- using PerLogicalAxis =
- mozilla::EnumeratedArray<LogicalAxis, LogicalAxis(2), T>;
+ using PerLogicalAxis = mozilla::EnumeratedArray<LogicalAxis, T, 2>;
// nsIFrame overrides
void Reflow(nsPresContext* aPresContext, ReflowOutput& aDesiredSize,
diff --git a/layout/generic/nsHTMLParts.h b/layout/generic/nsHTMLParts.h
index e1d7ef4d2d..e3cab48343 100644
--- a/layout/generic/nsHTMLParts.h
+++ b/layout/generic/nsHTMLParts.h
@@ -57,10 +57,6 @@ nsresult NS_NewAttributeContent(nsNodeInfoManager* aNodeInfoManager,
nsContainerFrame* NS_NewSelectsAreaFrame(mozilla::PresShell* aPresShell,
mozilla::ComputedStyle* aStyle);
-// Create a block formatting context blockframe
-nsBlockFrame* NS_NewBlockFormattingContext(mozilla::PresShell* aPresShell,
- mozilla::ComputedStyle* aStyle);
-
nsIFrame* NS_NewBRFrame(mozilla::PresShell* aPresShell,
mozilla::ComputedStyle* aStyle);
diff --git a/layout/generic/nsIFrame.cpp b/layout/generic/nsIFrame.cpp
index 81109151ff..479c26d18b 100644
--- a/layout/generic/nsIFrame.cpp
+++ b/layout/generic/nsIFrame.cpp
@@ -2117,8 +2117,8 @@ nsIFrame::CaretBlockAxisMetrics nsIFrame::GetCaretBlockAxisMetrics(
return CaretBlockAxisMetrics{.mOffset = baseline - ascent, .mExtent = height};
}
-const nsAtom* nsIFrame::ComputePageValue() const {
- const nsAtom* value = nsGkAtoms::_empty;
+const nsAtom* nsIFrame::ComputePageValue(const nsAtom* aAutoValue) const {
+ const nsAtom* value = aAutoValue ? aAutoValue : nsGkAtoms::_empty;
const nsIFrame* frame = this;
// Find what CSS page name value this frame's subtree has, if any.
// Starting with this frame, check if a page name other than auto is present,
@@ -2484,7 +2484,7 @@ bool nsIFrame::CanBeDynamicReflowRoot() const {
// If we participate in a container's block reflow context, or margins
// can collapse through us, we can't be a dynamic reflow root.
- if (IsBlockFrameOrSubclass() && !HasAnyStateBits(NS_BLOCK_BFC_STATE_BITS)) {
+ if (IsBlockFrameOrSubclass() && !HasAnyStateBits(NS_BLOCK_BFC)) {
return false;
}
@@ -3409,6 +3409,9 @@ void nsIFrame::BuildDisplayListForStackingContext(
ApplyClipProp(transformedCssClip);
}
+ uint32_t numActiveScrollframesEncounteredBefore =
+ aBuilder->GetNumActiveScrollframesEncountered();
+
nsDisplayListCollection set(aBuilder);
Maybe<nsRect> clipForMask;
{
@@ -3692,17 +3695,22 @@ void nsIFrame::BuildDisplayListForStackingContext(
if (transformItem) {
resultList.AppendToTop(transformItem);
createdContainer = true;
- }
- if (hasPerspective) {
- transformItem->MarkWithAssociatedPerspective();
+ if (numActiveScrollframesEncounteredBefore !=
+ aBuilder->GetNumActiveScrollframesEncountered()) {
+ transformItem->SetContainsASRs(true);
+ }
+
+ if (hasPerspective) {
+ transformItem->MarkWithAssociatedPerspective();
- if (clipCapturedBy == ContainerItemType::Perspective) {
- clipState.Restore();
+ if (clipCapturedBy == ContainerItemType::Perspective) {
+ clipState.Restore();
+ }
+ resultList.AppendNewToTop<nsDisplayPerspective>(aBuilder, this,
+ &resultList);
+ createdContainer = true;
}
- resultList.AppendNewToTop<nsDisplayPerspective>(aBuilder, this,
- &resultList);
- createdContainer = true;
}
}
@@ -5413,7 +5421,15 @@ static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame,
const nsPoint& aPoint,
uint32_t aFlags);
-static bool SelfIsSelectable(nsIFrame* aFrame, uint32_t aFlags) {
+static bool SelfIsSelectable(nsIFrame* aFrame, nsIFrame* aParentFrame,
+ uint32_t aFlags) {
+ // We should not move selection into a native anonymous subtree when handling
+ // selection outside it.
+ if ((aFlags & nsIFrame::IGNORE_NATIVE_ANONYMOUS_SUBTREE) &&
+ aParentFrame->GetClosestNativeAnonymousSubtreeRoot() !=
+ aFrame->GetClosestNativeAnonymousSubtreeRoot()) {
+ return false;
+ }
if ((aFlags & nsIFrame::SKIP_HIDDEN) &&
!aFrame->StyleVisibility()->IsVisible()) {
return false;
@@ -5476,21 +5492,28 @@ static FrameTarget DrillDownToSelectionFrame(nsIFrame* aFrame, bool aEndFrame,
nsIFrame* result = nullptr;
nsIFrame* frame = aFrame->PrincipalChildList().FirstChild();
if (!aEndFrame) {
- while (frame && (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty()))
+ while (frame &&
+ (!SelfIsSelectable(frame, aFrame, aFlags) || frame->IsEmpty())) {
frame = frame->GetNextSibling();
- if (frame) result = frame;
+ }
+ if (frame) {
+ result = frame;
+ }
} else {
// Because the frame tree is singly linked, to find the last frame,
// we have to iterate through all the frames
// XXX I have a feeling this could be slow for long blocks, although
// I can't find any slowdowns
while (frame) {
- if (!frame->IsEmpty() && SelfIsSelectable(frame, aFlags))
+ if (!frame->IsEmpty() && SelfIsSelectable(frame, aFrame, aFlags)) {
result = frame;
+ }
frame = frame->GetNextSibling();
}
}
- if (result) return DrillDownToSelectionFrame(result, aEndFrame, aFlags);
+ if (result) {
+ return DrillDownToSelectionFrame(result, aEndFrame, aFlags);
+ }
}
// If the current frame has no targetable children, target the current frame
return FrameTarget{aFrame, true, aEndFrame};
@@ -5502,8 +5525,9 @@ static FrameTarget GetSelectionClosestFrameForLine(
nsBlockFrame* aParent, nsBlockFrame::LineIterator aLine,
const nsPoint& aPoint, uint32_t aFlags) {
// Account for end of lines (any iterator from the block is valid)
- if (aLine == aParent->LinesEnd())
+ if (aLine == aParent->LinesEnd()) {
return DrillDownToSelectionFrame(aParent, true, aFlags);
+ }
nsIFrame* frame = aLine->mFirstChild;
nsIFrame* closestFromIStart = nullptr;
nsIFrame* closestFromIEnd = nullptr;
@@ -5519,7 +5543,7 @@ static FrameTarget GetSelectionClosestFrameForLine(
// the previous thing had a different editableness than us, since then we
// may end up not being able to select after it if the br is the last thing
// on the line.
- if (!SelfIsSelectable(frame, aFlags) || frame->IsEmpty() ||
+ if (!SelfIsSelectable(frame, aParent, aFlags) || frame->IsEmpty() ||
(canSkipBr && frame->IsBrFrame() &&
lastFrameWasEditable == frame->GetContent()->IsEditable())) {
continue;
@@ -5699,7 +5723,7 @@ static FrameTarget GetSelectionClosestFrame(nsIFrame* aFrame,
// Go through all the child frames to find the closest one
nsIFrame::FrameWithDistance closest = {nullptr, nscoord_MAX, nscoord_MAX};
for (; kid; kid = kid->GetNextSibling()) {
- if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty()) {
+ if (!SelfIsSelectable(kid, aFrame, aFlags) || kid->IsEmpty()) {
continue;
}
@@ -9368,7 +9392,8 @@ nsresult nsIFrame::PeekOffsetForLineEdge(PeekOffsetStruct* aPos) {
}
}
}
- FrameTarget targetFrame = DrillDownToSelectionFrame(baseFrame, endOfLine, 0);
+ FrameTarget targetFrame = DrillDownToSelectionFrame(
+ baseFrame, endOfLine, nsIFrame::IGNORE_NATIVE_ANONYMOUS_SUBTREE);
SetPeekResultFromFrame(*aPos, targetFrame.frame, endOfLine ? -1 : 0,
OffsetIsAtLineEdge::Yes);
if (endOfLine && targetFrame.frame->HasSignificantTerminalNewline()) {
@@ -11538,11 +11563,44 @@ nsIFrame::PhysicalAxes nsIFrame::ShouldApplyOverflowClipping(
return PhysicalAxes::None;
}
- // If we're paginated and a block, and have NS_BLOCK_CLIP_PAGINATED_OVERFLOW
- // set, then we want to clip our overflow.
- bool clip = HasAnyStateBits(NS_BLOCK_CLIP_PAGINATED_OVERFLOW) &&
- PresContext()->IsPaginated() && IsBlockFrame();
- return clip ? PhysicalAxes::Both : PhysicalAxes::None;
+ return IsSuppressedScrollableBlockForPrint() ? PhysicalAxes::Both
+ : PhysicalAxes::None;
+}
+
+bool nsIFrame::IsSuppressedScrollableBlockForPrint() const {
+ // This condition needs to match the suppressScrollFrame logic in the frame
+ // constructor.
+ if (!PresContext()->IsPaginated() || !IsBlockFrame() ||
+ !StyleDisplay()->IsScrollableOverflow() ||
+ !StyleDisplay()->IsBlockOutsideStyle() ||
+ mContent->IsInNativeAnonymousSubtree()) {
+ return false;
+ }
+ if (auto* element = Element::FromNode(mContent);
+ element && PresContext()->ElementWouldPropagateScrollStyles(*element)) {
+ return false;
+ }
+ return true;
+}
+
+bool nsIFrame::HasUnreflowedContainerQueryAncestor() const {
+ // If this frame has done the first reflow, its ancestors are guaranteed to
+ // have as well.
+ if (!HasAnyStateBits(NS_FRAME_FIRST_REFLOW) ||
+ !PresContext()->HasContainerQueryFrames()) {
+ return false;
+ }
+ for (nsIFrame* cur = GetInFlowParent(); cur; cur = cur->GetInFlowParent()) {
+ if (!cur->HasAnyStateBits(NS_FRAME_FIRST_REFLOW)) {
+ // Done first reflow from this ancestor up, including query containers.
+ return false;
+ }
+ if (cur->StyleDisplay()->IsQueryContainer()) {
+ return true;
+ }
+ }
+ // No query container from this frame up to root.
+ return false;
}
#ifdef DEBUG
diff --git a/layout/generic/nsIFrame.h b/layout/generic/nsIFrame.h
index a29786488f..16f3d17d64 100644
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -562,6 +562,8 @@ enum class LayoutFrameClassFlags : uint16_t {
SupportsContainLayoutAndPaint = 1 << 13,
// Whether this frame class supports the `aspect-ratio` property.
SupportsAspectRatio = 1 << 14,
+ // Whether this frame class is always a BFC.
+ BlockFormattingContext = 1 << 15,
};
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(LayoutFrameClassFlags)
@@ -1380,6 +1382,8 @@ class nsIFrame : public nsQueryFrame {
return nullptr;
}
+ bool HasUnreflowedContainerQueryAncestor() const;
+
private:
// The value that the CSS page-name "auto" keyword resolves to for children
// of this frame.
@@ -1643,7 +1647,13 @@ class nsIFrame : public nsQueryFrame {
// This is intended to be used either on the root frame to find the first
// page's page-name, or on a newly created continuation to find what the new
// page's page-name will be.
- const nsAtom* ComputePageValue() const MOZ_NONNULL_RETURN;
+ //
+ // The auto page value can be set by the caller. This is useful when trying
+ // to compute a page value in the middle of a frame tree. In that case the
+ // auto value can be found from the AutoPageValue frame property of the
+ // parent frame. A null auto value is interpreted as the empty-string atom.
+ const nsAtom* ComputePageValue(const nsAtom* aAutoValue = nullptr) const
+ MOZ_NONNULL_RETURN;
///////////////////////////////////////////////////////////////////////////////
// The public visibility API.
@@ -3027,6 +3037,9 @@ class nsIFrame : public nsQueryFrame {
nsSize OverflowClipMargin(PhysicalAxes aClipAxes) const;
// Returns the axes on which this frame should apply overflow clipping.
PhysicalAxes ShouldApplyOverflowClipping(const nsStyleDisplay* aDisp) const;
+ // Returns whether this frame is a block that was supposed to be a
+ // scrollframe, but that was suppressed for print.
+ bool IsSuppressedScrollableBlockForPrint() const;
/**
* Helper method used by block reflow to identify runs of text so
diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp
index e0a6243ed2..c1e69df6c9 100644
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -18,6 +18,7 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/Encoding.h"
#include "mozilla/HTMLEditor.h"
+#include "mozilla/dom/FetchPriority.h"
#include "mozilla/dom/ImageTracker.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Helpers.h"
@@ -268,7 +269,7 @@ BrokenImageIcon::BrokenImageIcon(const nsImageFrame& aFrame) {
loadFlags, nullptr, contentPolicyType, u""_ns,
false, /* aUseUrgentStartForChannel */
false, /* aLinkPreload */
- 0, getter_AddRefs(mImage));
+ 0, FetchPriority::Auto, getter_AddRefs(mImage));
Unused << NS_WARN_IF(NS_FAILED(rv));
}
@@ -554,15 +555,16 @@ void nsImageFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
//
// TODO(emilio): We might want to do the same for regular list-style-image or
// even simple content: url() changes.
- if (mKind == Kind::XULImage) {
- if (!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms::src) && aOldStyle &&
+ if (mKind == Kind::XULImage && aOldStyle) {
+ if (!mContent->AsElement()->HasNonEmptyAttr(nsGkAtoms::src) &&
aOldStyle->StyleList()->mListStyleImage !=
StyleList()->mListStyleImage) {
UpdateXULImage();
}
- if (!mOwnedRequest && aOldStyle &&
- aOldStyle->StyleDisplay()->EffectiveAppearance() !=
- StyleDisplay()->EffectiveAppearance()) {
+ // If we have no image our intrinsic size might be themed. We need to
+ // update the size even if the effective appearance hasn't changed to
+ // deal correctly with theme changes.
+ if (!mOwnedRequest) {
UpdateIntrinsicSize();
}
}
diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp
index 03aa6e87b3..ab6924faa4 100644
--- a/layout/generic/nsLineLayout.cpp
+++ b/layout/generic/nsLineLayout.cpp
@@ -430,7 +430,7 @@ void nsLineLayout::BeginSpan(nsIFrame* aFrame,
psd->mIStart = aIStart;
psd->mICoord = aIStart;
psd->mIEnd = aIEnd;
- psd->mInset = mCurrentSpan->mInset;
+ psd->mInset = 0; // inset applies only to the root span
psd->mBaseline = aBaseline;
nsIFrame* frame = aSpanReflowInput->mFrame;
@@ -735,8 +735,7 @@ static bool IsPercentageAware(const nsIFrame* aFrame, WritingMode aWM) {
disp->DisplayInside() == StyleDisplayInside::Table)) ||
fType == LayoutFrameType::HTMLButtonControl ||
fType == LayoutFrameType::GfxButtonControl ||
- fType == LayoutFrameType::FieldSet ||
- fType == LayoutFrameType::ComboboxDisplay) {
+ fType == LayoutFrameType::FieldSet) {
return true;
}
diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp
index 369722fe8d..9afefc5c28 100644
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -226,6 +226,7 @@ struct nsTextFrame::DrawTextRunParams {
float textStrokeWidth = 0.0f;
bool drawSoftHyphen = false;
bool hasTextShadow = false;
+ bool paintingShadows = false;
DrawTextRunParams(gfxContext* aContext,
mozilla::gfx::PaletteCache& aPaletteCache)
: context(aContext), paletteCache(aPaletteCache) {}
@@ -276,6 +277,7 @@ struct nsTextFrame::PaintShadowParams {
Point framePt;
Point textBaselinePt;
gfxContext* context;
+ DrawPathCallbacks* callbacks = nullptr;
nscolor foregroundColor = NS_RGBA(0, 0, 0, 0);
const ClipEdges* clipEdges = nullptr;
PropertyProvider* provider = nullptr;
@@ -5374,9 +5376,8 @@ void nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
// Text-shadow overflows
if (aIncludeShadows) {
- nsRect shadowRect =
+ *aInkOverflowRect =
nsLayoutUtils::GetTextShadowRectsUnion(*aInkOverflowRect, this);
- aInkOverflowRect->UnionRect(*aInkOverflowRect, shadowRect);
}
// When this frame is not selected, the text-decoration area must be in
@@ -5460,6 +5461,7 @@ struct nsTextFrame::PaintDecorationLineParams
gfxFloat baselineOffset = 0.0f;
DecorationType decorationType = DecorationType::Normal;
DrawPathCallbacks* callbacks = nullptr;
+ bool paintingShadows = false;
};
void nsTextFrame::PaintDecorationLine(
@@ -5474,9 +5476,11 @@ void nsTextFrame::PaintDecorationLine(
if (aParams.callbacks) {
Rect path = nsCSSRendering::DecorationLineToPath(params);
if (aParams.decorationType == DecorationType::Normal) {
- aParams.callbacks->PaintDecorationLine(path, params.color);
+ aParams.callbacks->PaintDecorationLine(path, aParams.paintingShadows,
+ params.color);
} else {
- aParams.callbacks->PaintSelectionDecorationLine(path, params.color);
+ aParams.callbacks->PaintSelectionDecorationLine(
+ path, aParams.paintingShadows, params.color);
}
} else {
nsCSSRendering::PaintDecorationLine(this, *aParams.context->GetDrawTarget(),
@@ -5938,6 +5942,7 @@ void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
gfxFloat advanceWidth;
nsTextPaintStyle textPaintStyle(this);
DrawTextParams params(shadowContext, PresContext()->FontPaletteCache());
+ params.paintingShadows = true;
params.advanceWidth = &advanceWidth;
params.dirtyRect = aParams.dirtyRect;
params.framePt = aParams.framePt + shadowGfxOffset;
@@ -5945,9 +5950,10 @@ void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
params.textStyle = &textPaintStyle;
params.textColor =
aParams.context == shadowContext ? shadowColor : NS_RGB(0, 0, 0);
+ params.callbacks = aParams.callbacks;
params.clipEdges = aParams.clipEdges;
params.drawSoftHyphen = HasAnyStateBits(TEXT_HYPHEN_BREAK);
- // Multi-color shadow is not allowed, so we use the same color of the text
+ // Multi-color shadow is not allowed, so we use the same color as the text
// color.
params.decorationOverrideColor = &params.textColor;
params.fontPalette = StyleFont()->GetFontPaletteAtom();
@@ -6253,6 +6259,7 @@ bool nsTextFrame::PaintTextWithSelectionColors(
PaintShadowParams shadowParams(aParams);
shadowParams.provider = aParams.provider;
+ shadowParams.callbacks = aParams.callbacks;
shadowParams.clipEdges = &aClipEdges;
// Draw text
@@ -6815,6 +6822,7 @@ void nsTextFrame::PaintText(const PaintTextParams& aParams,
shadowParams.textBaselinePt = textBaselinePt;
shadowParams.leftSideOffset = snappedStartEdge;
shadowParams.provider = &provider;
+ shadowParams.callbacks = aParams.callbacks;
shadowParams.foregroundColor = foregroundColor;
shadowParams.clipEdges = &clipEdges;
PaintShadows(textStyle->mTextShadow.AsSpan(), shadowParams);
@@ -6854,7 +6862,8 @@ static void DrawTextRun(const gfxTextRun* aTextRun,
params.callbacks = aParams.callbacks;
params.hasTextShadow = aParams.hasTextShadow;
if (aParams.callbacks) {
- aParams.callbacks->NotifyBeforeText(aParams.textColor);
+ aParams.callbacks->NotifyBeforeText(aParams.paintingShadows,
+ aParams.textColor);
params.drawMode = DrawMode::GLYPH_PATH;
aTextRun->Draw(aRange, aTextBaselinePt, params);
aParams.callbacks->NotifyAfterText();
@@ -6995,6 +7004,7 @@ void nsTextFrame::DrawTextRunAndDecorations(
params.callbacks = aParams.callbacks;
params.glyphRange = aParams.glyphRange;
params.provider = aParams.provider;
+ params.paintingShadows = aParams.paintingShadows;
// pt is the physical point where the decoration is to be drawn,
// relative to the frame; one of its coordinates will be updated below.
params.pt = Point(x / app, y / app);
diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h
index 568d3333c2..707d39dba2 100644
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -513,20 +513,22 @@ class nsTextFrame : public nsIFrame {
* Called before (for under/over-line) or after (for line-through) the text
* is drawn to have a text decoration line drawn.
*/
- virtual void PaintDecorationLine(Rect aPath, nscolor aColor) {}
+ virtual void PaintDecorationLine(Rect aPath, bool aPaintingShadows,
+ nscolor aColor) {}
/**
* Called after selected text is drawn to have a decoration line drawn over
* the text. (All types of text decoration are drawn after the text when
* text is selected.)
*/
- virtual void PaintSelectionDecorationLine(Rect aPath, nscolor aColor) {}
+ virtual void PaintSelectionDecorationLine(Rect aPath, bool aPaintingShadows,
+ nscolor aColor) {}
/**
* Called just before any paths have been emitted to the gfxContext
* for the glyphs of the frame's text.
*/
- virtual void NotifyBeforeText(nscolor aColor) {}
+ virtual void NotifyBeforeText(bool aPaintingShadows, nscolor aColor) {}
/**
* Called just after all the paths have been emitted to the gfxContext
diff --git a/layout/generic/nsTextPaintStyle.cpp b/layout/generic/nsTextPaintStyle.cpp
index 0eff737602..e97a059b07 100644
--- a/layout/generic/nsTextPaintStyle.cpp
+++ b/layout/generic/nsTextPaintStyle.cpp
@@ -417,8 +417,8 @@ struct StyleIDs {
LookAndFeel::IntID mLineStyle;
LookAndFeel::FloatID mLineRelativeSize;
};
-EnumeratedArray<nsTextPaintStyle::SelectionStyleIndex,
- nsTextPaintStyle::SelectionStyleIndex::Count, StyleIDs>
+EnumeratedArray<nsTextPaintStyle::SelectionStyleIndex, StyleIDs,
+ size_t(nsTextPaintStyle::SelectionStyleIndex::Count)>
SelectionStyleIDs = {
StyleIDs{LookAndFeel::ColorID::IMERawInputForeground,
LookAndFeel::ColorID::IMERawInputBackground,
diff --git a/layout/generic/nsTextPaintStyle.h b/layout/generic/nsTextPaintStyle.h
index a99ee9fd46..adf28fdad8 100644
--- a/layout/generic/nsTextPaintStyle.h
+++ b/layout/generic/nsTextPaintStyle.h
@@ -144,8 +144,9 @@ class MOZ_STACK_CLASS nsTextPaintStyle {
StyleTextDecorationStyle mUnderlineStyle;
float mUnderlineRelativeSize;
};
- mozilla::EnumeratedArray<SelectionStyleIndex, SelectionStyleIndex::Count,
- mozilla::Maybe<nsSelectionStyle>>
+ mozilla::EnumeratedArray<SelectionStyleIndex,
+ mozilla::Maybe<nsSelectionStyle>,
+ size_t(SelectionStyleIndex::Count)>
mSelectionStyle;
// Color initializations