diff --git a/docshell/base/nsDocShellTreeOwner.cpp b/docshell/base/nsDocShellTreeOwner.cpp index be2081c36714..a80424ce4268 100644 --- a/docshell/base/nsDocShellTreeOwner.cpp +++ b/docshell/base/nsDocShellTreeOwner.cpp @@ -10,6 +10,7 @@ // Helper Classes #include "nsContentUtils.h" +#include "nsStyleCoord.h" #include "nsSize.h" #include "mozilla/ReflowInput.h" #include "nsIServiceManager.h" diff --git a/dom/base/DOMIntersectionObserver.h b/dom/base/DOMIntersectionObserver.h index 1774f80085fc..5378faf6c3a9 100644 --- a/dom/base/DOMIntersectionObserver.h +++ b/dom/base/DOMIntersectionObserver.h @@ -9,7 +9,7 @@ #include "mozilla/Attributes.h" #include "mozilla/dom/IntersectionObserverBinding.h" -#include "mozilla/ServoStyleConsts.h" +#include "nsStyleCoord.h" #include "nsTArray.h" using mozilla::dom::DOMRect; diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index 98e2a4ffde26..433c396017e1 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -36,6 +36,7 @@ #include "nsIObserverService.h" #include "nsIObjectFrame.h" #include "nsBindingManager.h" +#include "nsStyleCoord.h" #include "BrowserChild.h" #include "nsFrameLoader.h" #include "nsHTMLDocument.h" diff --git a/dom/svg/SVGContentUtils.h b/dom/svg/SVGContentUtils.h index d3f83e8d65ba..5558029a9015 100644 --- a/dom/svg/SVGContentUtils.h +++ b/dom/svg/SVGContentUtils.h @@ -13,7 +13,7 @@ #include "mozilla/gfx/2D.h" // for StrokeOptions #include "mozilla/gfx/Matrix.h" #include "mozilla/RangedPtr.h" -#include "mozilla/ServoStyleConsts.h" +#include "nsStyleCoord.h" #include "nsError.h" #include "nsStringFwd.h" #include "gfx2DGlue.h" @@ -318,7 +318,7 @@ class SVGContentUtils { static bool ParseInteger(const nsAString& aString, int32_t& aValue); /** - * Converts a LengthPercentage into a userspace value, resolving percentage + * Converts an nsStyleCoord into a userspace value, resolving percentage * values relative to aContent's SVG viewport. */ static float CoordToFloat(dom::SVGElement* aContent, const LengthPercentage&); diff --git a/gfx/2d/Types.h b/gfx/2d/Types.h index 54e6cf1d6403..98aea5ef805f 100644 --- a/gfx/2d/Types.h +++ b/gfx/2d/Types.h @@ -560,7 +560,7 @@ static inline HalfCorner operator++(HalfCorner& aHalfCorner) { } // The result of these conversion functions are exhaustively checked in -// nsFrame.cpp, which also serves as usage examples. +// nsStyleCoord.cpp, which also serves as usage examples. constexpr bool HalfCornerIsX(HalfCorner aHalfCorner) { return !(aHalfCorner % 2); diff --git a/gfx/layers/FrameMetrics.h b/gfx/layers/FrameMetrics.h index 6deac644c182..1f41fead19cf 100644 --- a/gfx/layers/FrameMetrics.h +++ b/gfx/layers/FrameMetrics.h @@ -22,7 +22,7 @@ #include "mozilla/StaticPtr.h" // for StaticAutoPtr #include "mozilla/TimeStamp.h" // for TimeStamp #include "nsString.h" -#include "mozilla/ServoStyleConsts.h" +#include "nsStyleCoord.h" // for nsStyleCoord #include "PLDHashTable.h" // for PLDHashNumber struct nsStyleDisplay; @@ -759,7 +759,7 @@ struct ScrollSnapInfo { Maybe mScrollSnapIntervalY; // The scroll frame's scroll-snap-destination, in cooked form (to avoid - // shipping the raw style value over IPC). + // shipping the raw nsStyleCoord::CalcValue over IPC). nsPoint mScrollSnapDestination; // The scroll-snap-coordinates of any descendant frames of the scroll frame, diff --git a/layout/base/ScrollStyles.h b/layout/base/ScrollStyles.h index 1833747cac17..bf57075a0ebf 100644 --- a/layout/base/ScrollStyles.h +++ b/layout/base/ScrollStyles.h @@ -9,6 +9,7 @@ #include #include "nsStyleConsts.h" +#include "nsStyleCoord.h" // for nsStyleCoord #include "mozilla/dom/WindowBinding.h" // Forward declarations diff --git a/layout/base/ShapeUtils.cpp b/layout/base/ShapeUtils.cpp index 0397fb70ec7c..d1092d75f61a 100644 --- a/layout/base/ShapeUtils.cpp +++ b/layout/base/ShapeUtils.cpp @@ -10,6 +10,7 @@ #include "nsCSSRendering.h" #include "nsMargin.h" +#include "nsStyleCoord.h" #include "nsStyleStruct.h" #include "SVGContentUtils.h" diff --git a/layout/base/ShapeUtils.h b/layout/base/ShapeUtils.h index edb77e8fcc0d..f15b44466024 100644 --- a/layout/base/ShapeUtils.h +++ b/layout/base/ShapeUtils.h @@ -10,6 +10,7 @@ #include "nsCoord.h" #include "nsSize.h" #include "nsStyleConsts.h" +#include "nsStyleCoord.h" #include "nsTArray.h" struct nsPoint; diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index a6e98e42aac1..e5ea31d926f3 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -19,6 +19,7 @@ #include "mozilla/layers/ScrollableLayerGuid.h" #include "nsThreadUtils.h" #include "nsCSSPropertyIDSet.h" +#include "nsStyleCoord.h" #include "nsStyleConsts.h" #include "nsGkAtoms.h" #include "mozilla/gfx/2D.h" @@ -54,6 +55,7 @@ class nsBlockFrame; class nsContainerFrame; class nsView; class nsIFrame; +class nsStyleCoord; class nsPIDOMWindowOuter; class imgIRequest; struct nsStyleFont; diff --git a/layout/generic/ColumnUtils.h b/layout/generic/ColumnUtils.h index 15fa0efca51e..b730e0effb89 100644 --- a/layout/generic/ColumnUtils.h +++ b/layout/generic/ColumnUtils.h @@ -9,8 +9,7 @@ #ifndef mozilla_ColumnUtils_h #define mozilla_ColumnUtils_h -#include "nsCoord.h" -#include "nsStyleConsts.h" +#include "nsStyleCoord.h" class nsContainerFrame; diff --git a/layout/generic/ReflowInput.h b/layout/generic/ReflowInput.h index 7aa0eb083542..f5ed0fe64726 100644 --- a/layout/generic/ReflowInput.h +++ b/layout/generic/ReflowInput.h @@ -10,7 +10,7 @@ #define mozilla_ReflowInput_h #include "nsMargin.h" -#include "nsStyleConsts.h" +#include "nsStyleCoord.h" #include "nsIFrame.h" #include "mozilla/Assertions.h" #include "mozilla/Maybe.h" @@ -334,10 +334,10 @@ struct SizeComputationInput { const nsStyleDisplay* aDisplay = nullptr); /* - * Convert StyleSize or StyleMaxSize to nscoord when percentages depend on the - * inline size of the containing block, and enumerated values are for inline - * size, min-inline-size, or max-inline-size. Does not handle auto inline - * sizes. + * Convert nsStyleCoord to nscoord when percentages depend on the + * inline size of the containing block, and enumerated values are for + * inline size, min-inline-size, or max-inline-size. Does not handle + * auto inline sizes. */ template inline nscoord ComputeISizeValue(nscoord aContainingBlockISize, diff --git a/layout/generic/WritingModes.h b/layout/generic/WritingModes.h index 86cd6cadec7b..fcdf22d878a4 100644 --- a/layout/generic/WritingModes.h +++ b/layout/generic/WritingModes.h @@ -1919,6 +1919,59 @@ const T& StyleRect::GetBEnd(mozilla::WritingMode aWM) const { } // namespace mozilla +// Definitions of inline methods for nsStyleSides, declared in nsStyleCoord.h +// but not defined there because they need WritingMode. +inline nsStyleUnit nsStyleSides::GetUnit(mozilla::WritingMode aWM, + mozilla::LogicalSide aSide) const { + return GetUnit(aWM.PhysicalSide(aSide)); +} + +inline nsStyleUnit nsStyleSides::GetIStartUnit(mozilla::WritingMode aWM) const { + return GetUnit(aWM, mozilla::eLogicalSideIStart); +} + +inline nsStyleUnit nsStyleSides::GetBStartUnit(mozilla::WritingMode aWM) const { + return GetUnit(aWM, mozilla::eLogicalSideBStart); +} + +inline nsStyleUnit nsStyleSides::GetIEndUnit(mozilla::WritingMode aWM) const { + return GetUnit(aWM, mozilla::eLogicalSideIEnd); +} + +inline nsStyleUnit nsStyleSides::GetBEndUnit(mozilla::WritingMode aWM) const { + return GetUnit(aWM, mozilla::eLogicalSideBEnd); +} + +inline bool nsStyleSides::HasBlockAxisAuto(mozilla::WritingMode aWM) const { + return GetBStartUnit(aWM) == eStyleUnit_Auto || + GetBEndUnit(aWM) == eStyleUnit_Auto; +} + +inline bool nsStyleSides::HasInlineAxisAuto(mozilla::WritingMode aWM) const { + return GetIStartUnit(aWM) == eStyleUnit_Auto || + GetIEndUnit(aWM) == eStyleUnit_Auto; +} + +inline nsStyleCoord nsStyleSides::Get(mozilla::WritingMode aWM, + mozilla::LogicalSide aSide) const { + return Get(aWM.PhysicalSide(aSide)); +} + +inline nsStyleCoord nsStyleSides::GetIStart(mozilla::WritingMode aWM) const { + return Get(aWM, mozilla::eLogicalSideIStart); +} + +inline nsStyleCoord nsStyleSides::GetBStart(mozilla::WritingMode aWM) const { + return Get(aWM, mozilla::eLogicalSideBStart); +} + +inline nsStyleCoord nsStyleSides::GetIEnd(mozilla::WritingMode aWM) const { + return Get(aWM, mozilla::eLogicalSideIEnd); +} + +inline nsStyleCoord nsStyleSides::GetBEnd(mozilla::WritingMode aWM) const { + return Get(aWM, mozilla::eLogicalSideBEnd); +} // Definitions of inline methods for nsStylePosition, declared in // nsStyleStruct.h but not defined there because they need WritingMode. diff --git a/layout/generic/nsFlexContainerFrame.h b/layout/generic/nsFlexContainerFrame.h index 6f7e0a79b256..66541a252476 100644 --- a/layout/generic/nsFlexContainerFrame.h +++ b/layout/generic/nsFlexContainerFrame.h @@ -13,6 +13,8 @@ #include "mozilla/UniquePtr.h" #include "mozilla/dom/FlexBinding.h" +class nsStyleCoord; + namespace mozilla { template class LinkedList; diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index b32719b3b15e..5da0d0905198 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -12321,97 +12321,4 @@ void ReflowInput::DisplayInitFrameTypeExit(nsIFrame* aFrame, # endif // End Display Reflow -// Validation of SideIsVertical. -#define CASE(side, result) \ - static_assert(SideIsVertical(side) == result, "SideIsVertical is wrong") -CASE(eSideTop, false); -CASE(eSideRight, true); -CASE(eSideBottom, false); -CASE(eSideLeft, true); -#undef CASE - -// Validation of HalfCornerIsX. -#define CASE(corner, result) \ - static_assert(HalfCornerIsX(corner) == result, "HalfCornerIsX is wrong") -CASE(eCornerTopLeftX, true); -CASE(eCornerTopLeftY, false); -CASE(eCornerTopRightX, true); -CASE(eCornerTopRightY, false); -CASE(eCornerBottomRightX, true); -CASE(eCornerBottomRightY, false); -CASE(eCornerBottomLeftX, true); -CASE(eCornerBottomLeftY, false); -#undef CASE - -// Validation of HalfToFullCorner. -#define CASE(corner, result) \ - static_assert(HalfToFullCorner(corner) == result, \ - "HalfToFullCorner is " \ - "wrong") -CASE(eCornerTopLeftX, eCornerTopLeft); -CASE(eCornerTopLeftY, eCornerTopLeft); -CASE(eCornerTopRightX, eCornerTopRight); -CASE(eCornerTopRightY, eCornerTopRight); -CASE(eCornerBottomRightX, eCornerBottomRight); -CASE(eCornerBottomRightY, eCornerBottomRight); -CASE(eCornerBottomLeftX, eCornerBottomLeft); -CASE(eCornerBottomLeftY, eCornerBottomLeft); -#undef CASE - -// Validation of FullToHalfCorner. -#define CASE(corner, vert, result) \ - static_assert(FullToHalfCorner(corner, vert) == result, \ - "FullToHalfCorner is wrong") -CASE(eCornerTopLeft, false, eCornerTopLeftX); -CASE(eCornerTopLeft, true, eCornerTopLeftY); -CASE(eCornerTopRight, false, eCornerTopRightX); -CASE(eCornerTopRight, true, eCornerTopRightY); -CASE(eCornerBottomRight, false, eCornerBottomRightX); -CASE(eCornerBottomRight, true, eCornerBottomRightY); -CASE(eCornerBottomLeft, false, eCornerBottomLeftX); -CASE(eCornerBottomLeft, true, eCornerBottomLeftY); -#undef CASE - -// Validation of SideToFullCorner. -#define CASE(side, second, result) \ - static_assert(SideToFullCorner(side, second) == result, \ - "SideToFullCorner is wrong") -CASE(eSideTop, false, eCornerTopLeft); -CASE(eSideTop, true, eCornerTopRight); - -CASE(eSideRight, false, eCornerTopRight); -CASE(eSideRight, true, eCornerBottomRight); - -CASE(eSideBottom, false, eCornerBottomRight); -CASE(eSideBottom, true, eCornerBottomLeft); - -CASE(eSideLeft, false, eCornerBottomLeft); -CASE(eSideLeft, true, eCornerTopLeft); -#undef CASE - -// Validation of SideToHalfCorner. -#define CASE(side, second, parallel, result) \ - static_assert(SideToHalfCorner(side, second, parallel) == result, \ - "SideToHalfCorner is wrong") -CASE(eSideTop, false, true, eCornerTopLeftX); -CASE(eSideTop, false, false, eCornerTopLeftY); -CASE(eSideTop, true, true, eCornerTopRightX); -CASE(eSideTop, true, false, eCornerTopRightY); - -CASE(eSideRight, false, false, eCornerTopRightX); -CASE(eSideRight, false, true, eCornerTopRightY); -CASE(eSideRight, true, false, eCornerBottomRightX); -CASE(eSideRight, true, true, eCornerBottomRightY); - -CASE(eSideBottom, false, true, eCornerBottomRightX); -CASE(eSideBottom, false, false, eCornerBottomRightY); -CASE(eSideBottom, true, true, eCornerBottomLeftX); -CASE(eSideBottom, true, false, eCornerBottomLeftY); - -CASE(eSideLeft, false, false, eCornerBottomLeftX); -CASE(eSideLeft, false, true, eCornerBottomLeftY); -CASE(eSideLeft, true, false, eCornerTopLeftX); -CASE(eSideLeft, true, true, eCornerTopLeftY); -#undef CASE - #endif diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp index e04a62334d31..a65bee28ee97 100644 --- a/layout/generic/nsGridContainerFrame.cpp +++ b/layout/generic/nsGridContainerFrame.cpp @@ -59,32 +59,6 @@ enum class SizingConstraint { NoConstraint // no constraint, used during Reflow }; -template <> -inline const StyleTrackBreadth& StyleTrackSize::GetMax() const { - if (IsBreadth()) { - return AsBreadth(); - } - if (IsMinmax()) { - return AsMinmax()._1; - } - MOZ_ASSERT(IsFitContent()); - return AsFitContent(); -} - -template <> -inline const StyleTrackBreadth& StyleTrackSize::GetMin() const { - static const StyleTrackBreadth kAuto = StyleTrackBreadth::Auto(); - if (IsBreadth()) { - // behaves like minmax(auto, ) - return AsBreadth().IsFr() ? kAuto : AsBreadth(); - } - if (IsMinmax()) { - return AsMinmax()._0; - } - MOZ_ASSERT(IsFitContent()); - return kAuto; -} - static void ReparentFrame(nsIFrame* aFrame, nsContainerFrame* aOldParent, nsContainerFrame* aNewParent) { NS_ASSERTION(aOldParent == aFrame->GetParent(), @@ -142,13 +116,13 @@ static bool IsPercentOfIndefiniteSize(const Size& aCoord, return aPercentBasis == NS_UNCONSTRAINEDSIZE && aCoord.HasPercent(); } -static nscoord ResolveToDefiniteSize(const StyleTrackBreadth& aBreadth, +static nscoord ResolveToDefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis) { - MOZ_ASSERT(aBreadth.IsBreadth()); - if (::IsPercentOfIndefiniteSize(aBreadth.AsBreadth(), aPercentBasis)) { + MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit()); + if (::IsPercentOfIndefiniteSize(aCoord, aPercentBasis)) { return nscoord(0); } - return std::max(nscoord(0), aBreadth.AsBreadth().Resolve(aPercentBasis)); + return std::max(nscoord(0), aCoord.ComputeCoordPercentCalc(aPercentBasis)); } // Synthesize a baseline from a border box. For an alphabetical baseline @@ -233,12 +207,18 @@ struct nsGridContainerFrame::TrackSize { // clang-format on }; - StateBits Initialize(nscoord aPercentageBasis, const StyleTrackSize&); + StateBits Initialize(nscoord aPercentageBasis, const nsStyleCoord& aMinCoord, + const nsStyleCoord& aMaxCoord); bool IsFrozen() const { return mState & eFrozen; } #ifdef DEBUG void Dump() const; #endif + static bool IsMinContent(const nsStyleCoord& aCoord) { + return aCoord.GetUnit() == eStyleUnit_Enumerated && + aCoord.GetEnumValue() == + StyleGridTrackBreadth::MinContent; + } static bool IsDefiniteMaxSizing(StateBits aStateBits) { return (aStateBits & (eIntrinsicMaxSizing | eFlexMaxSizing)) == 0; } @@ -260,72 +240,66 @@ struct IsPod : TrueType {}; } // namespace mozilla TrackSize::StateBits nsGridContainerFrame::TrackSize::Initialize( - nscoord aPercentageBasis, const StyleTrackSize& aSize) { - using Tag = StyleTrackBreadth::Tag; - + nscoord aPercentageBasis, const nsStyleCoord& aMinCoord, + const nsStyleCoord& aMaxCoord) { MOZ_ASSERT(mBase == 0 && mLimit == 0 && mState == 0, "track size data is expected to be initialized to zero"); - mBaselineSubtreeSize[BaselineSharingGroup::First] = nscoord(0); - mBaselineSubtreeSize[BaselineSharingGroup::Last] = nscoord(0); - - auto& min = aSize.GetMin(); - auto& max = aSize.GetMax(); - - Tag minSizeTag = min.tag; - Tag maxSizeTag = max.tag; - if (aSize.IsFitContent()) { - // In layout, fit-content(size) behaves as minmax(auto, max-content), with - // 'size' as an additional upper-bound. + auto minSizeUnit = aMinCoord.GetUnit(); + auto maxSizeUnit = aMaxCoord.GetUnit(); + if (minSizeUnit == eStyleUnit_None) { + // This track is sized using fit-content(size) (represented in style system + // with minCoord=None,maxCoord=size). In layout, fit-content(size) behaves + // as minmax(auto, max-content), with 'size' as an additional upper-bound. mState = eFitContent; - minSizeTag = Tag::Auto; - maxSizeTag = Tag::MaxContent; + minSizeUnit = eStyleUnit_Auto; + maxSizeUnit = eStyleUnit_Enumerated; // triggers max-content sizing below } - if (::IsPercentOfIndefiniteSize(min, aPercentageBasis)) { + if (::IsPercentOfIndefiniteSize(aMinCoord, aPercentageBasis)) { // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-percentage // "If the inline or block size of the grid container is indefinite, // values relative to that size are treated as 'auto'." - minSizeTag = Tag::Auto; + minSizeUnit = eStyleUnit_Auto; } - if (::IsPercentOfIndefiniteSize(max, aPercentageBasis)) { - maxSizeTag = Tag::Auto; + if (::IsPercentOfIndefiniteSize(aMaxCoord, aPercentageBasis)) { + maxSizeUnit = eStyleUnit_Auto; } - // http://dev.w3.org/csswg/css-grid/#algo-init - switch (minSizeTag) { - case Tag::Auto: + switch (minSizeUnit) { + case eStyleUnit_Auto: mState |= eAutoMinSizing; break; - case Tag::MinContent: - mState |= eMinContentMinSizing; - break; - case Tag::MaxContent: - mState |= eMaxContentMinSizing; + case eStyleUnit_Enumerated: + mState |= + IsMinContent(aMinCoord) ? eMinContentMinSizing : eMaxContentMinSizing; break; default: - MOZ_ASSERT(!min.IsFr(), " min-sizing is invalid as a track size"); - mBase = ::ResolveToDefiniteSize(min, aPercentageBasis); + MOZ_ASSERT(minSizeUnit != eStyleUnit_FlexFraction, + " min-sizing is invalid as a track size"); + mBase = ::ResolveToDefiniteSize(aMinCoord, aPercentageBasis); } - switch (maxSizeTag) { - case Tag::Auto: + switch (maxSizeUnit) { + case eStyleUnit_Auto: mState |= eAutoMaxSizing; mLimit = NS_UNCONSTRAINEDSIZE; break; - case Tag::MinContent: - case Tag::MaxContent: - mState |= maxSizeTag == Tag::MinContent ? eMinContentMaxSizing - : eMaxContentMaxSizing; + case eStyleUnit_Enumerated: + mState |= + IsMinContent(aMaxCoord) ? eMinContentMaxSizing : eMaxContentMaxSizing; mLimit = NS_UNCONSTRAINEDSIZE; break; - case Tag::Fr: + case eStyleUnit_FlexFraction: mState |= eFlexMaxSizing; mLimit = mBase; break; default: - mLimit = ::ResolveToDefiniteSize(max, aPercentageBasis); + mLimit = ::ResolveToDefiniteSize(aMaxCoord, aPercentageBasis); if (mLimit < mBase) { mLimit = mBase; } } + + mBaselineSubtreeSize[BaselineSharingGroup::First] = nscoord(0); + mBaselineSubtreeSize[BaselineSharingGroup::Last] = nscoord(0); return mState; } @@ -1266,29 +1240,37 @@ class MOZ_STACK_CLASS nsGridContainerFrame::LineNameMap { * Encapsulates CSS track-sizing functions. */ struct nsGridContainerFrame::TrackSizingFunctions { - TrackSizingFunctions(const nsTArray& aSizingFunctions, - const StyleTrackSize& aAutoSizing, bool aHasRepeatAuto, + TrackSizingFunctions(const nsTArray& aMinSizingFunctions, + const nsTArray& aMaxSizingFunctions, + const nsStyleCoord& aAutoMinSizing, + const nsStyleCoord& aAutoMaxSizing, bool aHasRepeatAuto, int32_t aRepeatAutoIndex) - : mSizingFunctions(aSizingFunctions), - mAutoSizing(aAutoSizing), + : mMinSizingFunctions(aMinSizingFunctions), + mMaxSizingFunctions(aMaxSizingFunctions), + mAutoMinSizing(aAutoMinSizing), + mAutoMaxSizing(aAutoMaxSizing), mExplicitGridOffset(0), mRepeatAutoStart(aHasRepeatAuto ? aRepeatAutoIndex : 0), mRepeatAutoEnd(mRepeatAutoStart), mRepeatEndDelta(0), mHasRepeatAuto(aHasRepeatAuto) { + MOZ_ASSERT(mMinSizingFunctions.Length() == mMaxSizingFunctions.Length()); MOZ_ASSERT(!mHasRepeatAuto || - (mSizingFunctions.Length() >= 1 && - mRepeatAutoStart < mSizingFunctions.Length())); + (mMinSizingFunctions.Length() >= 1 && + mRepeatAutoStart < mMinSizingFunctions.Length())); } TrackSizingFunctions(const nsStyleGridTemplate& aGridTemplate, - const StyleTrackSize& aAutoSizing) + const nsStyleCoord& aAutoMinSizing, + const nsStyleCoord& aAutoMaxSizing) // Note: if mIsSubgrid is true below then the HasRepeatAuto bit is for // the mLineNameList, so we suppress that so that we can use this struct // also when it's true. This can happen when a specified 'subgrid' has // no grid parent, which will behave as 'none'. : TrackSizingFunctions( - aGridTemplate.mTrackSizingFunctions, aAutoSizing, + aGridTemplate.mMinTrackSizingFunctions, + aGridTemplate.mMaxTrackSizingFunctions, aAutoMinSizing, + aAutoMaxSizing, !aGridTemplate.mIsSubgrid && aGridTemplate.HasRepeatAuto(), aGridTemplate.mRepeatAutoIndex) {} @@ -1316,7 +1298,7 @@ struct nsGridContainerFrame::TrackSizingFunctions { return 0; } // Spec quotes are from https://drafts.csswg.org/css-grid/#repeat-notation - const uint32_t numTracks = mSizingFunctions.Length(); + const uint32_t numTracks = mMinSizingFunctions.Length(); MOZ_ASSERT(numTracks >= 1, "expected at least the repeat() track"); nscoord maxFill = aSize != NS_UNCONSTRAINEDSIZE ? aSize : aMaxSize; if (maxFill == NS_UNCONSTRAINEDSIZE && aMinSize == 0) { @@ -1331,11 +1313,11 @@ struct nsGridContainerFrame::TrackSizingFunctions { // "treating each track as its max track sizing function if that is // definite or as its minimum track sizing function otherwise" // https://drafts.csswg.org/css-grid/#valdef-repeat-auto-fill - const auto& maxCoord = mSizingFunctions[i].GetMax(); + const auto& maxCoord = mMaxSizingFunctions[i]; const auto* coord = &maxCoord; - if (!coord->IsBreadth()) { - coord = &mSizingFunctions[i].GetMin(); - if (!coord->IsBreadth()) { + if (!coord->IsCoordPercentCalcUnit()) { + coord = &mMinSizingFunctions[i]; + if (!coord->IsCoordPercentCalcUnit()) { return 1; } } @@ -1388,28 +1370,36 @@ struct nsGridContainerFrame::TrackSizingFunctions { return end; } - const StyleTrackSize& SizingFor(uint32_t aTrackIndex) const { + const nsStyleCoord& MinSizingFor(uint32_t aTrackIndex) const { if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)) { - return mAutoSizing; + return mAutoMinSizing; } uint32_t index = aTrackIndex - mExplicitGridOffset; if (index >= mRepeatAutoStart) { if (index < mRepeatAutoEnd) { - return mSizingFunctions[mRepeatAutoStart]; + return mMinSizingFunctions[mRepeatAutoStart]; } index -= mRepeatEndDelta; } - return index < mSizingFunctions.Length() ? mSizingFunctions[index] - : mAutoSizing; + return index < mMinSizingFunctions.Length() ? mMinSizingFunctions[index] + : mAutoMinSizing; } - const StyleTrackBreadth& MaxSizingFor(uint32_t aTrackIndex) const { - return SizingFor(aTrackIndex).GetMax(); - } - const StyleTrackBreadth& MinSizingFor(uint32_t aTrackIndex) const { - return SizingFor(aTrackIndex).GetMin(); + const nsStyleCoord& MaxSizingFor(uint32_t aTrackIndex) const { + if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)) { + return mAutoMaxSizing; + } + uint32_t index = aTrackIndex - mExplicitGridOffset; + if (index >= mRepeatAutoStart) { + if (index < mRepeatAutoEnd) { + return mMaxSizingFunctions[mRepeatAutoStart]; + } + index -= mRepeatEndDelta; + } + return index < mMaxSizingFunctions.Length() ? mMaxSizingFunctions[index] + : mAutoMaxSizing; } uint32_t NumExplicitTracks() const { - return mSizingFunctions.Length() + mRepeatEndDelta; + return mMinSizingFunctions.Length() + mRepeatEndDelta; } uint32_t NumRepeatTracks() const { return mRepeatAutoEnd - mRepeatAutoStart; } void SetNumRepeatTracks(uint32_t aNumRepeatTracks) { @@ -1419,8 +1409,10 @@ struct nsGridContainerFrame::TrackSizingFunctions { } // Some style data references, for easy access. - const nsTArray& mSizingFunctions; - const StyleTrackSize& mAutoSizing; + const nsTArray& mMinSizingFunctions; + const nsTArray& mMaxSizingFunctions; + const nsStyleCoord& mAutoMinSizing; + const nsStyleCoord& mAutoMaxSizing; // Offset from the start of the implicit grid to the first explicit track. uint32_t mExplicitGridOffset; // The index of the repeat(auto-fill/fit) track, or zero if there is none. @@ -1428,7 +1420,7 @@ struct nsGridContainerFrame::TrackSizingFunctions { const uint32_t mRepeatAutoStart; // The (hypothetical) index of the last such repeat() track. uint32_t mRepeatAutoEnd; - // The difference between mExplicitGridEnd and mSizingFunctions.Length(). + // The difference between mExplicitGridEnd and mMinSizingFunctions.Length(). int32_t mRepeatEndDelta; // True if there is a specified repeat(auto-fill/fit) track. const bool mHasRepeatAuto; @@ -1490,14 +1482,22 @@ struct MOZ_STACK_CLASS const auto isInlineAxis = parentAxis == eLogicalAxisInline; const auto& szf = isInlineAxis ? pos->GridTemplateColumns() : pos->GridTemplateRows(); - mAutoSizing = isInlineAxis ? &pos->mGridAutoColumns : &pos->mGridAutoRows; - TrackSizingFunctions tsf(szf, *mAutoSizing); + const auto& minAuto = + isInlineAxis ? pos->mGridAutoColumnsMin : pos->mGridAutoRowsMin; + const auto& maxAuto = + isInlineAxis ? pos->mGridAutoColumnsMax : pos->mGridAutoRowsMax; + TrackSizingFunctions tsf(szf, minAuto, maxAuto); for (auto i : range.Range()) { - mSizingFunctions.AppendElement(tsf.SizingFor(i)); + mMinSizingFunctions.AppendElement(tsf.MinSizingFor(i)); + mMaxSizingFunctions.AppendElement(tsf.MaxSizingFor(i)); } + mAutoMinSizing = &minAuto; + mAutoMaxSizing = &maxAuto; } - nsTArray mSizingFunctions; - const StyleTrackSize* mAutoSizing; + nsTArray mMinSizingFunctions; + nsTArray mMaxSizingFunctions; + const nsStyleCoord* mAutoMinSizing; + const nsStyleCoord* mAutoMaxSizing; uint32_t mRepeatAutoIndex = 0; bool mHasRepeatAuto = false; }; @@ -2486,9 +2486,11 @@ struct MOZ_STACK_CLASS nsGridContainerFrame::GridReflowInput { mCols(eLogicalAxisInline), mRows(eLogicalAxisBlock), mColFunctions(mGridStyle->GridTemplateColumns(), - mGridStyle->mGridAutoColumns), + mGridStyle->mGridAutoColumnsMin, + mGridStyle->mGridAutoColumnsMax), mRowFunctions(mGridStyle->GridTemplateRows(), - mGridStyle->mGridAutoRows), + mGridStyle->mGridAutoRowsMin, + mGridStyle->mGridAutoRowsMax), mReflowInput(aReflowInput), mRenderingContext(aRenderingContext), mFrame(aFrame), @@ -3060,8 +3062,10 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis( } else { fallbackTrackSizing.emplace(mFrame, subgrid, parent, parentAxis); tracks.Initialize( - TrackSizingFunctions(fallbackTrackSizing->mSizingFunctions, - *fallbackTrackSizing->mAutoSizing, + TrackSizingFunctions(fallbackTrackSizing->mMinSizingFunctions, + fallbackTrackSizing->mMaxSizingFunctions, + *fallbackTrackSizing->mAutoMinSizing, + *fallbackTrackSizing->mAutoMaxSizing, fallbackTrackSizing->mHasRepeatAuto, fallbackTrackSizing->mRepeatAutoIndex), gapStyle, gridEnd, aContentBoxSize); @@ -3078,8 +3082,10 @@ void nsGridContainerFrame::GridReflowInput::CalculateTrackSizesForAxis( tracks.CalculateSizes( *this, mGridItems, fallbackTrackSizing.isSome() - ? TrackSizingFunctions(fallbackTrackSizing->mSizingFunctions, - *fallbackTrackSizing->mAutoSizing, + ? TrackSizingFunctions(fallbackTrackSizing->mMinSizingFunctions, + fallbackTrackSizing->mMaxSizingFunctions, + *fallbackTrackSizing->mAutoMinSizing, + *fallbackTrackSizing->mAutoMaxSizing, fallbackTrackSizing->mHasRepeatAuto, fallbackTrackSizing->mRepeatAutoIndex) : sizingFunctions, @@ -4319,7 +4325,8 @@ void nsGridContainerFrame::Tracks::Initialize( PodZero(mSizes.Elements(), mSizes.Length()); for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) { mStateUnion |= - mSizes[i].Initialize(aContentBoxSize, aFunctions.SizingFor(i)); + mSizes[i].Initialize(aContentBoxSize, aFunctions.MinSizingFor(i), + aFunctions.MaxSizingFor(i)); } mGridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aContentBoxSize); mContentBoxSize = aContentBoxSize; @@ -4799,9 +4806,9 @@ bool nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1( aGridItem.mState[mAxis] |= ItemState::eApplyAutoMinSize; // Clamp it if it's spanning a definite track max-sizing function. if (TrackSize::IsDefiniteMaxSizing(sz.mState)) { - cache.mMinSizeClamp = aFunctions.MaxSizingFor(aRange.mStart) - .AsBreadth() - .Resolve(aPercentageBasis); + auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart); + cache.mMinSizeClamp = + maxCoord.ComputeCoordPercentCalc(aPercentageBasis); aGridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize; } if (aConstraint != SizingConstraint::MaxContent) { @@ -4838,10 +4845,9 @@ bool nsGridContainerFrame::Tracks::ResolveIntrinsicSizeStep1( } if (MOZ_UNLIKELY(sz.mState & TrackSize::eFitContent)) { // Clamp mLimit to the fit-content() size, for ยง12.5.1. - nscoord fitContentClamp = aFunctions.SizingFor(aRange.mStart) - .AsFitContent() - .AsBreadth() - .Resolve(aPercentageBasis); + auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart); + nscoord fitContentClamp = + maxCoord.ComputeCoordPercentCalc(aPercentageBasis); sz.mLimit = std::min(sz.mLimit, fitContentClamp); } } @@ -5287,8 +5293,8 @@ void nsGridContainerFrame::Tracks::ResolveIntrinsicSize( (gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize)) { nscoord minSizeClamp = 0; for (auto i : lineRange.Range()) { - minSizeClamp += aFunctions.MaxSizingFor(i).AsBreadth().Resolve( - aPercentageBasis); + auto maxCoord = aFunctions.MaxSizingFor(i); + minSizeClamp += maxCoord.ComputeCoordPercentCalc(aPercentageBasis); } minSizeClamp += mGridGap * (span - 1); cache.mMinSizeClamp = minSizeClamp; @@ -5427,7 +5433,7 @@ float nsGridContainerFrame::Tracks::FindFrUnitSize( for (auto i : aRange.Range()) { const TrackSize& sz = mSizes[i]; if (sz.mState & TrackSize::eFlexMaxSizing) { - flexFactorSum += aFunctions.MaxSizingFor(i).AsFr(); + flexFactorSum += aFunctions.MaxSizingFor(i).GetFlexFractionValue(); } else { leftOverSpace -= sz.mBase; if (leftOverSpace <= 0) { @@ -5447,7 +5453,7 @@ float nsGridContainerFrame::Tracks::FindFrUnitSize( if (track == kAutoLine) { continue; // Track marked as inflexible in a prev. iter of this loop. } - float flexFactor = aFunctions.MaxSizingFor(track).AsFr(); + float flexFactor = aFunctions.MaxSizingFor(track).GetFlexFractionValue(); const nscoord base = mSizes[track].mBase; if (flexFactor * hypotheticalFrSize < base) { // 12.7.1.4: Treat this track as inflexible. @@ -5481,7 +5487,7 @@ float nsGridContainerFrame::Tracks::FindUsedFlexFraction( // floored at 1). float fr = 0.0f; for (uint32_t track : aFlexTracks) { - float flexFactor = aFunctions.MaxSizingFor(track).AsFr(); + float flexFactor = aFunctions.MaxSizingFor(track).GetFlexFractionValue(); float possiblyDividedBaseSize = (flexFactor > 1.0f) ? mSizes[track].mBase / flexFactor : mSizes[track].mBase; @@ -5556,7 +5562,7 @@ void nsGridContainerFrame::Tracks::StretchFlexibleTracks( aAvailableSize); if (fr != 0.0f) { for (uint32_t i : flexTracks) { - float flexFactor = aFunctions.MaxSizingFor(i).AsFr(); + float flexFactor = aFunctions.MaxSizingFor(i).GetFlexFractionValue(); nscoord flexLength = NSToCoordRound(flexFactor * fr); nscoord& base = mSizes[i].mBase; if (flexLength > base) { diff --git a/layout/generic/nsImageFrame.cpp b/layout/generic/nsImageFrame.cpp index 77079b9177e2..c5174d9a98eb 100644 --- a/layout/generic/nsImageFrame.cpp +++ b/layout/generic/nsImageFrame.cpp @@ -43,6 +43,7 @@ #include "nsContentUtils.h" #include "nsCSSAnonBoxes.h" #include "nsStyleConsts.h" +#include "nsStyleCoord.h" #include "nsStyleUtil.h" #include "nsTransform2D.h" #include "nsImageMap.h" diff --git a/layout/style/GeckoBindings.cpp b/layout/style/GeckoBindings.cpp index 4fb4da094ce0..bde8b9c0d9c8 100644 --- a/layout/style/GeckoBindings.cpp +++ b/layout/style/GeckoBindings.cpp @@ -1170,7 +1170,7 @@ void Gecko_CopyImageValueFrom(nsStyleImage* aImage, void Gecko_InitializeImageCropRect(nsStyleImage* aImage) { MOZ_ASSERT(aImage); - aImage->SetCropRect(MakeUnique()); + aImage->SetCropRect(MakeUnique()); } void Gecko_SetCursorArrayLength(nsStyleUI* aStyleUI, size_t aLen) { @@ -1270,12 +1270,8 @@ void Gecko_SetStyleGridTemplate(UniquePtr* aGridTemplate, nsStyleGridTemplate* Gecko_CreateStyleGridTemplate(uint32_t aTrackSizes, uint32_t aNameSize) { nsStyleGridTemplate* result = new nsStyleGridTemplate; - result->mTrackSizingFunctions.SetCapacity(aTrackSizes); - auto auto_ = StyleTrackSize::Breadth(StyleTrackBreadth::Auto()); - for (auto i : IntegerRange(aTrackSizes)) { - Unused << i; - result->mTrackSizingFunctions.AppendElement(auto_); - } + result->mMinTrackSizingFunctions.SetLength(aTrackSizes); + result->mMaxTrackSizingFunctions.SetLength(aTrackSizes); result->mLineNameLists.SetLength(aNameSize); return result; } @@ -1473,6 +1469,23 @@ PropertyValuePair* Gecko_AppendPropertyValuePair( return aProperties->AppendElement(PropertyValuePair{aProperty}); } +void Gecko_ResetStyleCoord(nsStyleUnit* aUnit, nsStyleUnion* aValue) { + nsStyleCoord::Reset(*aUnit, *aValue); +} + +void Gecko_SetStyleCoordCalcValue(nsStyleUnit* aUnit, nsStyleUnion* aValue, + nsStyleCoord::CalcValue aCalc) { + // Calc units should be cleaned up first + MOZ_ASSERT(*aUnit != nsStyleUnit::eStyleUnit_Calc); + nsStyleCoord::Calc* calcRef = new nsStyleCoord::Calc(); + calcRef->mLength = aCalc.mLength; + calcRef->mPercent = aCalc.mPercent; + calcRef->mHasPercent = aCalc.mHasPercent; + *aUnit = nsStyleUnit::eStyleUnit_Calc; + aValue->mPointer = calcRef; + calcRef->AddRef(); +} + void Gecko_CopyShapeSourceFrom(StyleShapeSource* aDst, const StyleShapeSource* aSrc) { MOZ_ASSERT(aDst); @@ -1592,6 +1605,8 @@ void Gecko_Snapshot_DebugListAttributes(const ServoElementSnapshot* aSnapshot, NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData); +NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc); + void Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsAtom* aAtom) { aFont->mLanguage = dont_AddRef(aAtom); aFont->mExplicitLanguage = true; diff --git a/layout/style/GeckoBindings.h b/layout/style/GeckoBindings.h index f7a443a222a1..fe83adf5b5fa 100644 --- a/layout/style/GeckoBindings.h +++ b/layout/style/GeckoBindings.h @@ -504,6 +504,13 @@ mozilla::Keyframe* Gecko_GetOrCreateFinalKeyframe( mozilla::PropertyValuePair* Gecko_AppendPropertyValuePair( nsTArray*, nsCSSPropertyID aProperty); +// Clean up pointer-based coordinates +void Gecko_ResetStyleCoord(nsStyleUnit* unit, nsStyleUnion* value); + +// Set an nsStyleCoord to a computed `calc()` value +void Gecko_SetStyleCoordCalcValue(nsStyleUnit* unit, nsStyleUnion* value, + nsStyleCoord::CalcValue calc); + void Gecko_CopyShapeSourceFrom(mozilla::StyleShapeSource* dst, const mozilla::StyleShapeSource* src); @@ -549,6 +556,8 @@ NS_DECL_THREADSAFE_FFI_REFCOUNTING(mozilla::URLExtraData, URLExtraData); void Gecko_FillAllImageLayers(nsStyleImageLayers* layers, uint32_t max_len); +NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc); + float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch); void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch, diff --git a/layout/style/ServoBindings.toml b/layout/style/ServoBindings.toml index b8bd789fbee0..2ebb218c8816 100644 --- a/layout/style/ServoBindings.toml +++ b/layout/style/ServoBindings.toml @@ -71,6 +71,7 @@ rusty-enums = [ "mozilla::css::SheetParsingMode", "mozilla::StyleContentType", "nsStyleSVGOpacitySource", + "nsStyleUnit", "nsCSSKeyword", "mozilla::dom::Document_DocumentTheme", "mozilla::dom::Document_Type", @@ -274,6 +275,7 @@ whitelist-types = [ "nsStyleContent", "nsStyleContentData", "ComputedStyle", + "nsStyleCoord", "nsStyleCounterData", "nsStyleDisplay", "nsStyleEffects", @@ -299,6 +301,7 @@ whitelist-types = [ "nsStyleTextReset", "nsStyleUIReset", "nsStyleUnion", + "nsStyleUnit", "nsStyleUI", "nsStyleVisibility", "nsStyleXUL", @@ -513,9 +516,6 @@ cbindgen-types = [ { gecko = "StyleLineDirection", servo = "values::computed::image::LineDirection" }, { gecko = "StyleGridTemplateAreas", servo = "values::computed::position::GridTemplateAreas" }, { gecko = "StyleGenericGridLine", servo = "values::generics::grid::GridLine" }, - { gecko = "StyleGenericTrackSize", servo = "values::generics::grid::TrackSize" }, - { gecko = "StyleGenericTrackBreadth", servo = "values::generics::grid::TrackBreadth" }, - { gecko = "StyleNumberOrPercentage", servo = "values::computed::NumberOrPercentage" }, ] mapped-generic-types = [ diff --git a/layout/style/ServoStyleConstsInlines.h b/layout/style/ServoStyleConstsInlines.h index a410f809579f..472e065c1597 100644 --- a/layout/style/ServoStyleConstsInlines.h +++ b/layout/style/ServoStyleConstsInlines.h @@ -400,248 +400,6 @@ inline bool StyleGridLine::IsAuto() const { return LineName()->IsEmpty() && line_num == 0 && !is_span; } -class WritingMode; - -// Logical axis, edge, side and corner constants for use in various places. -enum LogicalAxis { eLogicalAxisBlock = 0x0, eLogicalAxisInline = 0x1 }; -enum LogicalEdge { eLogicalEdgeStart = 0x0, eLogicalEdgeEnd = 0x1 }; -enum LogicalSide : uint8_t { - eLogicalSideBStart = (eLogicalAxisBlock << 1) | eLogicalEdgeStart, // 0x0 - eLogicalSideBEnd = (eLogicalAxisBlock << 1) | eLogicalEdgeEnd, // 0x1 - eLogicalSideIStart = (eLogicalAxisInline << 1) | eLogicalEdgeStart, // 0x2 - eLogicalSideIEnd = (eLogicalAxisInline << 1) | eLogicalEdgeEnd // 0x3 -}; - -enum LogicalCorner { - eLogicalCornerBStartIStart = 0, - eLogicalCornerBStartIEnd = 1, - eLogicalCornerBEndIEnd = 2, - eLogicalCornerBEndIStart = 3 -}; - -using LengthPercentage = StyleLengthPercentage; -using LengthPercentageOrAuto = StyleLengthPercentageOrAuto; -using NonNegativeLengthPercentage = StyleNonNegativeLengthPercentage; -using NonNegativeLengthPercentageOrAuto = - StyleNonNegativeLengthPercentageOrAuto; -using NonNegativeLengthPercentageOrNormal = - StyleNonNegativeLengthPercentageOrNormal; -using Length = StyleLength; -using LengthOrAuto = StyleLengthOrAuto; -using NonNegativeLength = StyleNonNegativeLength; -using NonNegativeLengthOrAuto = StyleNonNegativeLengthOrAuto; -using BorderRadius = StyleBorderRadius; - -bool StyleCSSPixelLength::IsZero() const { return _0 == 0.0f; } - -nscoord StyleCSSPixelLength::ToAppUnits() const { - // We want to resolve the length part of the calc() expression rounding 0.5 - // away from zero, instead of the default behavior of - // NSToCoordRound{,WithClamp} which do floor(x + 0.5). - // - // This is what the rust code in the app_units crate does, and not doing this - // would regress bug 1323735, for example. - // - // FIXME(emilio, bug 1528114): Probably we should do something smarter. - float length = _0 * float(mozilla::AppUnitsPerCSSPixel()); - if (length >= nscoord_MAX) { - return nscoord_MAX; - } - if (length <= nscoord_MIN) { - return nscoord_MIN; - } - return NSToIntRound(length); -} - -constexpr LengthPercentage LengthPercentage::Zero() { - return {{0.}, {0.}, StyleAllowedNumericType::All, false, false}; -} - -LengthPercentage LengthPercentage::FromPixels(CSSCoord aCoord) { - return {{aCoord}, {0.}, StyleAllowedNumericType::All, false, false}; -} - -LengthPercentage LengthPercentage::FromAppUnits(nscoord aCoord) { - return LengthPercentage::FromPixels(CSSPixel::FromAppUnits(aCoord)); -} - -LengthPercentage LengthPercentage::FromPercentage(float aPercentage) { - return {{0.}, {aPercentage}, StyleAllowedNumericType::All, true, false}; -} - -CSSCoord LengthPercentage::LengthInCSSPixels() const { return length._0; } - -float LengthPercentage::Percentage() const { return percentage._0; } - -bool LengthPercentage::HasPercent() const { return has_percentage; } - -bool LengthPercentage::ConvertsToLength() const { return !HasPercent(); } - -nscoord LengthPercentage::ToLength() const { - MOZ_ASSERT(ConvertsToLength()); - return length.ToAppUnits(); -} - -bool LengthPercentage::ConvertsToPercentage() const { - return has_percentage && length.IsZero(); -} - -float LengthPercentage::ToPercentage() const { - MOZ_ASSERT(ConvertsToPercentage()); - return Percentage(); -} - -bool LengthPercentage::HasLengthAndPercentage() const { - return !ConvertsToLength() && !ConvertsToPercentage(); -} - -bool LengthPercentage::IsDefinitelyZero() const { - return length.IsZero() && Percentage() == 0.0f; -} - -CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const { - return LengthInCSSPixels() + Percentage() * aPercentageBasis; -} - -template -CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const { - static_assert(std::is_same::value, - "Should return CSS pixels"); - if (ConvertsToLength()) { - return LengthInCSSPixels(); - } - return ResolveToCSSPixels(aPercentageGetter()); -} - -template -nscoord LengthPercentage::Resolve(T aPercentageGetter, - U aPercentageRounder) const { - static_assert(std::is_same::value, - "Should return app units"); - static_assert( - std::is_same::value, - "Should return app units"); - if (ConvertsToLength()) { - return ToLength(); - } - nscoord basis = aPercentageGetter(); - return length.ToAppUnits() + aPercentageRounder(basis * Percentage()); -} - -nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const { - return Resolve([=] { return aPercentageBasis; }, NSToCoordFloorClamped); -} - -template -nscoord LengthPercentage::Resolve(T aPercentageGetter) const { - static_assert(std::is_same::value, - "Should return app units"); - return Resolve(aPercentageGetter, NSToCoordFloorClamped); -} - -template -nscoord LengthPercentage::Resolve(nscoord aPercentageBasis, - T aPercentageRounder) const { - return Resolve([=] { return aPercentageBasis; }, aPercentageRounder); -} - -#define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \ - template <> \ - inline bool ty_::HasPercent() const { \ - return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \ - } \ - template <> \ - inline bool ty_::ConvertsToLength() const { \ - return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \ - } \ - template <> \ - inline bool ty_::HasLengthAndPercentage() const { \ - return IsLengthPercentage() && \ - AsLengthPercentage().HasLengthAndPercentage(); \ - } \ - template <> \ - inline nscoord ty_::ToLength() const { \ - MOZ_ASSERT(ConvertsToLength()); \ - return AsLengthPercentage().ToLength(); \ - } \ - template <> \ - inline bool ty_::ConvertsToPercentage() const { \ - return IsLengthPercentage() && \ - AsLengthPercentage().ConvertsToPercentage(); \ - } \ - template <> \ - inline float ty_::ToPercentage() const { \ - MOZ_ASSERT(ConvertsToPercentage()); \ - return AsLengthPercentage().ToPercentage(); \ - } - -IMPL_LENGTHPERCENTAGE_FORWARDS(LengthPercentageOrAuto) -IMPL_LENGTHPERCENTAGE_FORWARDS(StyleSize) -IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMaxSize) - -template <> -inline bool LengthOrAuto::IsLength() const { - return IsLengthPercentage(); -} - -template <> -inline const Length& LengthOrAuto::AsLength() const { - return AsLengthPercentage(); -} - -template <> -inline bool StyleFlexBasis::IsAuto() const { - return IsSize() && AsSize().IsAuto(); -} - -template <> -inline bool StyleSize::BehavesLikeInitialValueOnBlockAxis() const { - return IsAuto() || IsExtremumLength(); -} - -template <> -inline bool StyleMaxSize::BehavesLikeInitialValueOnBlockAxis() const { - return IsNone() || IsExtremumLength(); -} - -template <> -inline bool StyleBackgroundSize::IsInitialValue() const { - return IsExplicitSize() && explicit_size.width.IsAuto() && - explicit_size.height.IsAuto(); -} - -template -const T& StyleRect::Get(mozilla::Side aSide) const { - static_assert(sizeof(StyleRect) == sizeof(T) * 4, ""); - static_assert(alignof(StyleRect) == alignof(T), ""); - return reinterpret_cast(this)[aSide]; -} - -template -template -bool StyleRect::All(Predicate aPredicate) const { - return aPredicate(_0) && aPredicate(_1) && aPredicate(_2) && aPredicate(_3); -} - -template -template -bool StyleRect::Any(Predicate aPredicate) const { - return aPredicate(_0) || aPredicate(_1) || aPredicate(_2) || aPredicate(_3); -} - -template <> -inline const LengthPercentage& BorderRadius::Get(HalfCorner aCorner) const { - static_assert(sizeof(BorderRadius) == sizeof(LengthPercentage) * 8, ""); - static_assert(alignof(BorderRadius) == alignof(LengthPercentage), ""); - auto* self = reinterpret_cast(this); - return self[aCorner]; -} - -template <> -inline bool StyleTrackBreadth::HasPercent() const { - return IsBreadth() && AsBreadth().HasPercent(); -} - } // namespace mozilla #endif diff --git a/layout/style/StyleAnimationValue.h b/layout/style/StyleAnimationValue.h index e7c3d920d7ee..3a2069c8db69 100644 --- a/layout/style/StyleAnimationValue.h +++ b/layout/style/StyleAnimationValue.h @@ -21,7 +21,7 @@ #include "nsColor.h" #include "nsCSSPropertyID.h" #include "nsCSSValue.h" -#include "nsStyleConsts.h" +#include "nsStyleCoord.h" #include "nsStyleTransformMatrix.h" class nsIFrame; diff --git a/layout/style/moz.build b/layout/style/moz.build index c57eb39db1f3..b1a1a8b8f33c 100644 --- a/layout/style/moz.build +++ b/layout/style/moz.build @@ -60,6 +60,7 @@ EXPORTS += [ 'nsMediaFeatures.h', 'nsStyleAutoArray.h', 'nsStyleConsts.h', + 'nsStyleCoord.h', 'nsStyleStruct.h', 'nsStyleStructFwd.h', 'nsStyleStructInlines.h', @@ -204,6 +205,7 @@ UNIFIED_SOURCES += [ 'nsLayoutStylesheetCache.cpp', 'nsMediaFeatures.cpp', 'nsROCSSPrimitiveValue.cpp', + 'nsStyleCoord.cpp', 'nsStyleStruct.cpp', 'nsStyleTransformMatrix.cpp', 'nsStyleUtil.cpp', diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index 47a43ee08f6f..c4e7875c4eb2 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -11,7 +11,6 @@ #include "mozilla/Attributes.h" #include "mozilla/CORSMode.h" -#include "mozilla/EnumTypeTraits.h" #include "mozilla/FontPropertyTypes.h" #include "mozilla/MemoryReporting.h" #include "mozilla/ServoBindingTypes.h" @@ -27,6 +26,7 @@ #include "nsStringBuffer.h" #include "nsTArray.h" #include "nsStyleConsts.h" +#include "nsStyleCoord.h" #include "gfxFontFamilyList.h" #include diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp index 7545ede00ac9..6e444414dad2 100644 --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -46,6 +46,7 @@ #include "imgIRequest.h" #include "nsLayoutUtils.h" #include "nsCSSKeywords.h" +#include "nsStyleCoord.h" #include "nsDisplayList.h" #include "nsDOMCSSDeclaration.h" #include "nsStyleTransformMatrix.h" @@ -1164,6 +1165,30 @@ already_AddRefed nsComputedDOMStyle::DoGetOsxFontSmoothing() { return val.forget(); } +static void SetValueToCalc(const nsStyleCoord::CalcValue* aCalc, + nsROCSSPrimitiveValue* aValue) { + RefPtr val = new nsROCSSPrimitiveValue; + nsAutoString tmp, result; + + result.AppendLiteral("calc("); + + val->SetAppUnits(aCalc->mLength); + val->GetCssText(tmp); + result.Append(tmp); + + if (aCalc->mHasPercent) { + result.AppendLiteral(" + "); + + val->SetPercent(aCalc->mPercent); + val->GetCssText(tmp); + result.Append(tmp); + } + + result.Append(')'); + + aValue->SetString(result); // not really SetString +} + already_AddRefed nsComputedDOMStyle::DoGetImageLayerPosition( const nsStyleImageLayers& aLayers) { if (aLayers.mPositionXCount != aLayers.mPositionYCount) { @@ -1273,48 +1298,16 @@ void nsComputedDOMStyle::AppendGridLineNames( aValueList->AppendCSSValue(val.forget()); } -void nsComputedDOMStyle::SetValueToTrackBreadth( - nsROCSSPrimitiveValue* aValue, - const StyleTrackBreadth& aBreadth) { - using Tag = StyleTrackBreadth::Tag; - switch (aBreadth.tag) { - case Tag::MinContent: - return aValue->SetIdent(eCSSKeyword_min_content); - case Tag::MaxContent: - return aValue->SetIdent(eCSSKeyword_max_content); - case Tag::Auto: - return aValue->SetIdent(eCSSKeyword_auto); - case Tag::Breadth: - return SetValueToLengthPercentage(aValue, aBreadth.AsBreadth(), true); - case Tag::Fr: { - nsAutoString tmpStr; - nsStyleUtil::AppendCSSNumber(aBreadth.AsFr(), tmpStr); - tmpStr.AppendLiteral("fr"); - return aValue->SetString(tmpStr); - } - default: - MOZ_ASSERT_UNREACHABLE("Unknown breadth value"); - return; - } -} - -already_AddRefed nsComputedDOMStyle::GetGridTrackBreadth( - const StyleTrackBreadth& aBreadth) { - RefPtr val = new nsROCSSPrimitiveValue; - SetValueToTrackBreadth(val, aBreadth); - return val.forget(); -} - -already_AddRefed nsComputedDOMStyle::GetGridTrackSize( - const StyleTrackSize& aTrackSize) { - if (aTrackSize.IsFitContent()) { +already_AddRefed nsComputedDOMStyle::GetGridTrackSize( + const nsStyleCoord& aMinValue, const nsStyleCoord& aMaxValue) { + if (aMinValue.GetUnit() == eStyleUnit_None) { // A fit-content() function. RefPtr val = new nsROCSSPrimitiveValue; nsAutoString argumentStr, fitContentStr; fitContentStr.AppendLiteral("fit-content("); - MOZ_ASSERT(aTrackSize.AsFitContent().IsBreadth(), + MOZ_ASSERT(aMaxValue.IsCoordPercentCalcUnit(), "unexpected unit for fit-content() argument value"); - SetValueToLengthPercentage(val, aTrackSize.AsFitContent().AsBreadth(), true); + SetValueToCoord(val, aMaxValue, true); val->GetCssText(argumentStr); fitContentStr.Append(argumentStr); fitContentStr.Append(char16_t(')')); @@ -1322,43 +1315,39 @@ already_AddRefed nsComputedDOMStyle::GetGridTrackSize( return val.forget(); } - if (aTrackSize.IsBreadth()) { - return GetGridTrackBreadth(aTrackSize.AsBreadth()); - } - - MOZ_ASSERT(aTrackSize.IsMinmax()); - auto& min = aTrackSize.AsMinmax()._0; - auto& max = aTrackSize.AsMinmax()._1; - if (min == max) { - return GetGridTrackBreadth(min); + if (aMinValue == aMaxValue) { + RefPtr val = new nsROCSSPrimitiveValue; + SetValueToCoord(val, aMinValue, true, nullptr, + nsCSSProps::kGridTrackBreadthKTable); + return val.forget(); } // minmax(auto, ) is equivalent to (and is our internal representation // of) , and both compute to - if (min.IsAuto() && max.IsFr()) { - return GetGridTrackBreadth(max); + if (aMinValue.GetUnit() == eStyleUnit_Auto && + aMaxValue.GetUnit() == eStyleUnit_FlexFraction) { + RefPtr val = new nsROCSSPrimitiveValue; + SetValueToCoord(val, aMaxValue, true); + return val.forget(); } + RefPtr val = new nsROCSSPrimitiveValue; nsAutoString argumentStr, minmaxStr; minmaxStr.AppendLiteral("minmax("); - { - RefPtr argValue = GetGridTrackBreadth(min); - argValue->GetCssText(argumentStr); - minmaxStr.Append(argumentStr); - argumentStr.Truncate(); - } + SetValueToCoord(val, aMinValue, true, nullptr, + nsCSSProps::kGridTrackBreadthKTable); + val->GetCssText(argumentStr); + minmaxStr.Append(argumentStr); minmaxStr.AppendLiteral(", "); - { - RefPtr argValue = GetGridTrackBreadth(max); - argValue->GetCssText(argumentStr); - minmaxStr.Append(argumentStr); - } + SetValueToCoord(val, aMaxValue, true, nullptr, + nsCSSProps::kGridTrackBreadthKTable); + val->GetCssText(argumentStr); + minmaxStr.Append(argumentStr); minmaxStr.Append(char16_t(')')); - RefPtr val = new nsROCSSPrimitiveValue; val->SetString(minmaxStr); return val.forget(); } @@ -1368,7 +1357,8 @@ already_AddRefed nsComputedDOMStyle::GetGridTemplateColumnsRows( const ComputedGridTrackInfo* aTrackInfo) { if (aTrackList.mIsSubgrid) { // XXX TODO: add support for repeat(auto-fill) for 'subgrid' (bug 1234311) - NS_ASSERTION(aTrackList.mTrackSizingFunctions.IsEmpty(), + NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() && + aTrackList.mMaxTrackSizingFunctions.IsEmpty(), "Unexpected sizing functions with subgrid"); RefPtr valueList = GetROCSSValueList(false); @@ -1399,7 +1389,9 @@ already_AddRefed nsComputedDOMStyle::GetGridTemplateColumnsRows( return valueList.forget(); } - uint32_t numSizes = aTrackList.mTrackSizingFunctions.Length(); + uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length(); + MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes, + "Different number of min and max track sizing functions"); if (aTrackInfo) { DebugOnly isAutoFill = aTrackList.HasRepeatAuto() && aTrackList.mIsAutoFill; @@ -1570,7 +1562,8 @@ already_AddRefed nsComputedDOMStyle::GetGridTemplateColumnsRows( } valueList->AppendCSSValue( - GetGridTrackSize(aTrackList.mTrackSizingFunctions[i])); + GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i], + aTrackList.mMaxTrackSizingFunctions[i])); if (!aTrackList.mRepeatAutoLineNameListAfter.IsEmpty()) { AppendGridLineNames(valueList, aTrackList.mRepeatAutoLineNameListAfter); @@ -1580,7 +1573,8 @@ already_AddRefed nsComputedDOMStyle::GetGridTemplateColumnsRows( valueList->AppendCSSValue(end.forget()); } else { valueList->AppendCSSValue( - GetGridTrackSize(aTrackList.mTrackSizingFunctions[i])); + GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i], + aTrackList.mMaxTrackSizingFunctions[i])); } } } @@ -1589,11 +1583,13 @@ already_AddRefed nsComputedDOMStyle::GetGridTemplateColumnsRows( } already_AddRefed nsComputedDOMStyle::DoGetGridAutoColumns() { - return GetGridTrackSize(StylePosition()->mGridAutoColumns); + return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin, + StylePosition()->mGridAutoColumnsMax); } already_AddRefed nsComputedDOMStyle::DoGetGridAutoRows() { - return GetGridTrackSize(StylePosition()->mGridAutoRows); + return GetGridTrackSize(StylePosition()->mGridAutoRowsMin, + StylePosition()->mGridAutoRowsMax); } already_AddRefed nsComputedDOMStyle::DoGetGridTemplateColumns() { @@ -1761,6 +1757,32 @@ already_AddRefed nsComputedDOMStyle::DoGetTextDecorationStyle() { return val.forget(); } +/* Border image properties */ + +void nsComputedDOMStyle::AppendFourSideCoordValues( + nsDOMCSSValueList* aList, const nsStyleSides& aValues) { + const nsStyleCoord& top = aValues.Get(eSideTop); + const nsStyleCoord& right = aValues.Get(eSideRight); + const nsStyleCoord& bottom = aValues.Get(eSideBottom); + const nsStyleCoord& left = aValues.Get(eSideLeft); + + auto appendValue = [this, aList](const nsStyleCoord& value) { + RefPtr val = new nsROCSSPrimitiveValue; + SetValueToCoord(val, value, true); + aList->AppendCSSValue(val.forget()); + }; + appendValue(top); + if (top != right || top != bottom || top != left) { + appendValue(right); + if (top != bottom || right != left) { + appendValue(bottom); + if (right != left) { + appendValue(left); + } + } + } +} + already_AddRefed nsComputedDOMStyle::DoGetHeight() { RefPtr val = new nsROCSSPrimitiveValue; @@ -2217,6 +2239,97 @@ void nsComputedDOMStyle::SetValueToLengthPercentage( aValue->SetString(result); } +void nsComputedDOMStyle::SetValueToCoord( + nsROCSSPrimitiveValue* aValue, const nsStyleCoord& aCoord, + bool aClampNegativeCalc, PercentageBaseGetter aPercentageBaseGetter, + const KTableEntry aTable[]) { + MOZ_ASSERT(aValue, "Must have a value to work with"); + + switch (aCoord.GetUnit()) { + case eStyleUnit_Normal: + aValue->SetIdent(eCSSKeyword_normal); + break; + + case eStyleUnit_Auto: + aValue->SetIdent(eCSSKeyword_auto); + break; + + case eStyleUnit_Percent: { + nscoord percentageBase; + if (aPercentageBaseGetter && + (this->*aPercentageBaseGetter)(percentageBase)) { + nscoord val = + NSCoordSaturatingMultiply(percentageBase, aCoord.GetPercentValue()); + aValue->SetAppUnits(val); + } else { + aValue->SetPercent(aCoord.GetPercentValue()); + } + } break; + + case eStyleUnit_Factor: + aValue->SetNumber(aCoord.GetFactorValue()); + break; + + case eStyleUnit_Coord: { + nscoord val = aCoord.GetCoordValue(); + aValue->SetAppUnits(val); + } break; + + case eStyleUnit_Integer: + aValue->SetNumber(aCoord.GetIntValue()); + break; + + case eStyleUnit_Enumerated: + NS_ASSERTION(aTable, "Must have table to handle this case"); + aValue->SetIdent( + nsCSSProps::ValueToKeywordEnum(aCoord.GetIntValue(), aTable)); + break; + + case eStyleUnit_None: + aValue->SetIdent(eCSSKeyword_none); + break; + + case eStyleUnit_Calc: + nscoord percentageBase; + if (!aCoord.CalcHasPercent()) { + nscoord val = aCoord.ComputeCoordPercentCalc(0); + if (aClampNegativeCalc && val < 0) { + MOZ_ASSERT(aCoord.IsCalcUnit(), "parser should have rejected value"); + val = 0; + } + aValue->SetAppUnits(val); + } else if (aPercentageBaseGetter && + (this->*aPercentageBaseGetter)(percentageBase)) { + nscoord val = aCoord.ComputeCoordPercentCalc(percentageBase); + if (aClampNegativeCalc && val < 0) { + MOZ_ASSERT(aCoord.IsCalcUnit(), "parser should have rejected value"); + val = 0; + } + aValue->SetAppUnits(val); + } else { + nsStyleCoord::Calc* calc = aCoord.GetCalcValue(); + SetValueToCalc(calc, aValue); + } + break; + + case eStyleUnit_Degree: + aValue->SetDegree(aCoord.GetAngleValue()); + break; + + case eStyleUnit_FlexFraction: { + nsAutoString tmpStr; + nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr); + tmpStr.AppendLiteral("fr"); + aValue->SetString(tmpStr); + break; + } + + default: + NS_ERROR("Can't handle this unit"); + break; + } +} + nscoord nsComputedDOMStyle::StyleCoordToNSCoord( const LengthPercentage& aCoord, PercentageBaseGetter aPercentageBaseGetter, nscoord aDefaultValue, bool aClampNegativeCalc) { @@ -2394,6 +2507,14 @@ already_AddRefed nsComputedDOMStyle::GetTransformValue( return MatrixToCSSValue(matrix); } +void nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText, + const nsStyleCoord& aCoord, + bool aClampNegativeCalc) { + RefPtr value = new nsROCSSPrimitiveValue; + SetValueToCoord(value, aCoord, aClampNegativeCalc); + value->GetCssText(aCssText); +} + already_AddRefed nsComputedDOMStyle::DoGetMask() { const nsStyleSVGReset* svg = StyleSVGReset(); const nsStyleImageLayers::Layer& firstLayer = svg->mMask.mLayers[0]; diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h index 83301cb47c13..036a5d6a6552 100644 --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -40,8 +40,10 @@ class nsIFrame; class nsDOMCSSValueList; struct nsMargin; class nsROCSSPrimitiveValue; +class nsStyleCoord; class nsStyleGradient; struct nsStyleImage; +class nsStyleSides; class nsComputedDOMStyle final : public nsDOMCSSDeclaration, public nsStubMutationObserver { @@ -199,9 +201,8 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration, void AppendGridLineNames(nsDOMCSSValueList* aValueList, const nsTArray>& aLineNames1, const nsTArray>& aLineNames2); - already_AddRefed GetGridTrackSize(const mozilla::StyleTrackSize&); - already_AddRefed GetGridTrackBreadth(const mozilla::StyleTrackBreadth&); - void SetValueToTrackBreadth(nsROCSSPrimitiveValue*, const mozilla::StyleTrackBreadth&); + already_AddRefed GetGridTrackSize(const nsStyleCoord& aMinSize, + const nsStyleCoord& aMaxSize); already_AddRefed GetGridTemplateColumnsRows( const nsStyleGridTemplate& aTrackList, const mozilla::ComputedGridTrackInfo* aTrackInfo); @@ -306,6 +307,25 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration, void SetValueToExtremumLength(nsROCSSPrimitiveValue* aValue, StyleExtremumLength); + /** + * Method to set aValue to aCoord. If aCoord is a percentage value and + * aPercentageBaseGetter is not null, aPercentageBaseGetter is called. If it + * returns true, the percentage base it outputs in its out param is used + * to compute an nscoord value. If the getter is null or returns false, + * the percent value of aCoord is set as a percent value on aValue. aTable, + * if not null, is the keyword table to handle eStyleUnit_Enumerated. When + * calling SetAppUnits on aValue (for coord or percent values), the value + * passed in will be clamped to be no less than aMinAppUnits and no more than + * aMaxAppUnits. + * + * XXXbz should caller pass in some sort of bitfield indicating which units + * can be expected or something? + */ + void SetValueToCoord(nsROCSSPrimitiveValue* aValue, + const nsStyleCoord& aCoord, bool aClampNegativeCalc, + PercentageBaseGetter aPercentageBaseGetter = nullptr, + const KTableEntry aTable[] = nullptr); + /** * If aCoord is a eStyleUnit_Coord returns the nscoord. If it's * eStyleUnit_Percent, attempts to resolve the percentage base and returns @@ -327,6 +347,12 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration, return aDefaultValue; } + /** + * Append coord values from four sides. It omits values when possible. + */ + void AppendFourSideCoordValues(nsDOMCSSValueList* aList, + const nsStyleSides& aValues); + bool GetCBContentWidth(nscoord& aWidth); bool GetCBContentHeight(nscoord& aHeight); bool GetCBPaddingRectWidth(nscoord& aWidth); @@ -336,6 +362,10 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration, bool GetFrameBorderRectWidth(nscoord& aWidth); bool GetFrameBorderRectHeight(nscoord& aHeight); + /* Helper functions for computing and serializing a nsStyleCoord. */ + void SetCssTextToCoord(nsAString& aCssText, const nsStyleCoord& aCoord, + bool aClampNegativeCalc); + // Find out if we can safely skip flushing (i.e. pending restyles do not // affect mElement). bool NeedsToFlush() const; diff --git a/layout/style/nsStyleCoord.cpp b/layout/style/nsStyleCoord.cpp new file mode 100644 index 000000000000..88ac55166043 --- /dev/null +++ b/layout/style/nsStyleCoord.cpp @@ -0,0 +1,297 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* representation of length values in computed style data */ + +#include "mozilla/HashFunctions.h" +#include "mozilla/PodOperations.h" + +// nsStyleCoord.h must not be the first header in a unified source file, +// otherwise it may not build with MSVC due to a bug in our STL wrapper. +// See bug 1331102. +#include "nsStyleCoord.h" + +using namespace mozilla; + +nsStyleCoord::nsStyleCoord(nsStyleUnit aUnit) : mUnit(aUnit) { + NS_ASSERTION(aUnit < eStyleUnit_Percent, "not a valueless unit"); + if (aUnit >= eStyleUnit_Percent) { + mUnit = eStyleUnit_Null; + } + mValue.mInt = 0; +} + +nsStyleCoord::nsStyleCoord(int32_t aValue, nsStyleUnit aUnit) : mUnit(aUnit) { + // if you want to pass in eStyleUnit_Coord, don't. instead, use the + // constructor just above this one... MMP + NS_ASSERTION( + (aUnit == eStyleUnit_Enumerated) || (aUnit == eStyleUnit_Integer), + "not an int value"); + if ((aUnit == eStyleUnit_Enumerated) || (aUnit == eStyleUnit_Integer)) { + mValue.mInt = aValue; + } else { + mUnit = eStyleUnit_Null; + mValue.mInt = 0; + } +} + +nsStyleCoord::nsStyleCoord(float aValue, nsStyleUnit aUnit) : mUnit(aUnit) { + if (aUnit < eStyleUnit_Percent || aUnit >= eStyleUnit_Coord) { + MOZ_ASSERT_UNREACHABLE("not a float value"); + mUnit = eStyleUnit_Null; + mValue.mInt = 0; + } else { + mValue.mFloat = aValue; + } +} + +bool nsStyleCoord::operator==(const nsStyleCoord& aOther) const { + if (mUnit != aOther.mUnit) { + return false; + } + switch (mUnit) { + case eStyleUnit_Null: + case eStyleUnit_Normal: + case eStyleUnit_Auto: + case eStyleUnit_None: + return true; + case eStyleUnit_Percent: + case eStyleUnit_Factor: + case eStyleUnit_Degree: + case eStyleUnit_FlexFraction: + return mValue.mFloat == aOther.mValue.mFloat; + case eStyleUnit_Coord: + case eStyleUnit_Integer: + case eStyleUnit_Enumerated: + return mValue.mInt == aOther.mValue.mInt; + case eStyleUnit_Calc: + return *this->GetCalcValue() == *aOther.GetCalcValue(); + } + MOZ_ASSERT(false, "unexpected unit"); + return false; +} + +void nsStyleCoord::Reset() { Reset(mUnit, mValue); } + +void nsStyleCoord::SetCoordValue(nscoord aValue) { + Reset(); + mUnit = eStyleUnit_Coord; + mValue.mInt = aValue; +} + +void nsStyleCoord::SetIntValue(int32_t aValue, nsStyleUnit aUnit) { + NS_ASSERTION( + (aUnit == eStyleUnit_Enumerated) || (aUnit == eStyleUnit_Integer), + "not an int value"); + Reset(); + if ((aUnit == eStyleUnit_Enumerated) || (aUnit == eStyleUnit_Integer)) { + mUnit = aUnit; + mValue.mInt = aValue; + } +} + +void nsStyleCoord::SetPercentValue(float aValue) { + Reset(); + mUnit = eStyleUnit_Percent; + mValue.mFloat = aValue; +} + +void nsStyleCoord::SetFactorValue(float aValue) { + Reset(); + mUnit = eStyleUnit_Factor; + mValue.mFloat = aValue; +} + +void nsStyleCoord::SetFlexFractionValue(float aValue) { + Reset(); + mUnit = eStyleUnit_FlexFraction; + mValue.mFloat = aValue; +} + +void nsStyleCoord::SetCalcValue(Calc* aValue) { + Reset(); + mUnit = eStyleUnit_Calc; + mValue.mPointer = aValue; + aValue->AddRef(); +} + +void nsStyleCoord::SetNormalValue() { + Reset(); + mUnit = eStyleUnit_Normal; + mValue.mInt = 0; +} + +void nsStyleCoord::SetAutoValue() { + Reset(); + mUnit = eStyleUnit_Auto; + mValue.mInt = 0; +} + +void nsStyleCoord::SetNoneValue() { + Reset(); + mUnit = eStyleUnit_None; + mValue.mInt = 0; +} + +// accessors that are not inlined + +double nsStyleCoord::GetAngleValueInDegrees() const { + // Note that this extends the value from float to double. + return GetAngleValue(); +} + +double nsStyleCoord::GetAngleValueInRadians() const { + return GetAngleValueInDegrees() * M_PI / 180.0; +} + +nscoord nsStyleCoord::ComputeComputedCalc(nscoord aPercentageBasis) const { + Calc* calc = GetCalcValue(); + return calc->mLength + + NSToCoordFloorClamped(aPercentageBasis * calc->mPercent); +} + +nscoord nsStyleCoord::ComputeCoordPercentCalc(nscoord aPercentageBasis) const { + switch (GetUnit()) { + case eStyleUnit_Coord: + return GetCoordValue(); + case eStyleUnit_Percent: + return NSToCoordFloorClamped(aPercentageBasis * GetPercentValue()); + case eStyleUnit_Calc: + return ComputeComputedCalc(aPercentageBasis); + default: + MOZ_ASSERT_UNREACHABLE("Unexpected unit!"); + return 0; + } +} + +nsStyleSides::nsStyleSides() { + NS_FOR_CSS_SIDES(i) { mUnits[i] = eStyleUnit_Null; } + mozilla::PodArrayZero(mValues); +} + +nsStyleSides::nsStyleSides(const nsStyleSides& aOther) { + NS_FOR_CSS_SIDES(i) { mUnits[i] = eStyleUnit_Null; } + *this = aOther; +} + +nsStyleSides::~nsStyleSides() { Reset(); } + +nsStyleSides& nsStyleSides::operator=(const nsStyleSides& aCopy) { + if (this != &aCopy) { + NS_FOR_CSS_SIDES(i) { + nsStyleCoord::SetValue(mUnits[i], mValues[i], aCopy.mUnits[i], + aCopy.mValues[i]); + } + } + return *this; +} + +bool nsStyleSides::operator==(const nsStyleSides& aOther) const { + NS_FOR_CSS_SIDES(i) { + if (nsStyleCoord(mValues[i], (nsStyleUnit)mUnits[i]) != + nsStyleCoord(aOther.mValues[i], (nsStyleUnit)aOther.mUnits[i])) { + return false; + } + } + return true; +} + +void nsStyleSides::Reset() { + NS_FOR_CSS_SIDES(i) { nsStyleCoord::Reset(mUnits[i], mValues[i]); } +} + +// Validation of SideIsVertical. +#define CASE(side, result) \ + static_assert(SideIsVertical(side) == result, "SideIsVertical is wrong") +CASE(eSideTop, false); +CASE(eSideRight, true); +CASE(eSideBottom, false); +CASE(eSideLeft, true); +#undef CASE + +// Validation of HalfCornerIsX. +#define CASE(corner, result) \ + static_assert(HalfCornerIsX(corner) == result, "HalfCornerIsX is wrong") +CASE(eCornerTopLeftX, true); +CASE(eCornerTopLeftY, false); +CASE(eCornerTopRightX, true); +CASE(eCornerTopRightY, false); +CASE(eCornerBottomRightX, true); +CASE(eCornerBottomRightY, false); +CASE(eCornerBottomLeftX, true); +CASE(eCornerBottomLeftY, false); +#undef CASE + +// Validation of HalfToFullCorner. +#define CASE(corner, result) \ + static_assert(HalfToFullCorner(corner) == result, \ + "HalfToFullCorner is " \ + "wrong") +CASE(eCornerTopLeftX, eCornerTopLeft); +CASE(eCornerTopLeftY, eCornerTopLeft); +CASE(eCornerTopRightX, eCornerTopRight); +CASE(eCornerTopRightY, eCornerTopRight); +CASE(eCornerBottomRightX, eCornerBottomRight); +CASE(eCornerBottomRightY, eCornerBottomRight); +CASE(eCornerBottomLeftX, eCornerBottomLeft); +CASE(eCornerBottomLeftY, eCornerBottomLeft); +#undef CASE + +// Validation of FullToHalfCorner. +#define CASE(corner, vert, result) \ + static_assert(FullToHalfCorner(corner, vert) == result, \ + "FullToHalfCorner is wrong") +CASE(eCornerTopLeft, false, eCornerTopLeftX); +CASE(eCornerTopLeft, true, eCornerTopLeftY); +CASE(eCornerTopRight, false, eCornerTopRightX); +CASE(eCornerTopRight, true, eCornerTopRightY); +CASE(eCornerBottomRight, false, eCornerBottomRightX); +CASE(eCornerBottomRight, true, eCornerBottomRightY); +CASE(eCornerBottomLeft, false, eCornerBottomLeftX); +CASE(eCornerBottomLeft, true, eCornerBottomLeftY); +#undef CASE + +// Validation of SideToFullCorner. +#define CASE(side, second, result) \ + static_assert(SideToFullCorner(side, second) == result, \ + "SideToFullCorner is wrong") +CASE(eSideTop, false, eCornerTopLeft); +CASE(eSideTop, true, eCornerTopRight); + +CASE(eSideRight, false, eCornerTopRight); +CASE(eSideRight, true, eCornerBottomRight); + +CASE(eSideBottom, false, eCornerBottomRight); +CASE(eSideBottom, true, eCornerBottomLeft); + +CASE(eSideLeft, false, eCornerBottomLeft); +CASE(eSideLeft, true, eCornerTopLeft); +#undef CASE + +// Validation of SideToHalfCorner. +#define CASE(side, second, parallel, result) \ + static_assert(SideToHalfCorner(side, second, parallel) == result, \ + "SideToHalfCorner is wrong") +CASE(eSideTop, false, true, eCornerTopLeftX); +CASE(eSideTop, false, false, eCornerTopLeftY); +CASE(eSideTop, true, true, eCornerTopRightX); +CASE(eSideTop, true, false, eCornerTopRightY); + +CASE(eSideRight, false, false, eCornerTopRightX); +CASE(eSideRight, false, true, eCornerTopRightY); +CASE(eSideRight, true, false, eCornerBottomRightX); +CASE(eSideRight, true, true, eCornerBottomRightY); + +CASE(eSideBottom, false, true, eCornerBottomRightX); +CASE(eSideBottom, false, false, eCornerBottomRightY); +CASE(eSideBottom, true, true, eCornerBottomLeftX); +CASE(eSideBottom, true, false, eCornerBottomLeftY); + +CASE(eSideLeft, false, false, eCornerBottomLeftX); +CASE(eSideLeft, false, true, eCornerBottomLeftY); +CASE(eSideLeft, true, false, eCornerTopLeftX); +CASE(eSideLeft, true, true, eCornerTopLeftY); +#undef CASE diff --git a/layout/style/nsStyleCoord.h b/layout/style/nsStyleCoord.h new file mode 100644 index 000000000000..6a8c8b9744c4 --- /dev/null +++ b/layout/style/nsStyleCoord.h @@ -0,0 +1,800 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* representation of length values in computed style data */ + +#ifndef nsStyleCoord_h___ +#define nsStyleCoord_h___ + +#include + +#include "mozilla/EnumTypeTraits.h" +#include "mozilla/gfx/Types.h" +#include "Units.h" +#include "nsCoord.h" +#include "nsISupportsImpl.h" +#include "nsStyleConsts.h" + +namespace mozilla { + +class WritingMode; + +// Logical axis, edge, side and corner constants for use in various places. +enum LogicalAxis { eLogicalAxisBlock = 0x0, eLogicalAxisInline = 0x1 }; +enum LogicalEdge { eLogicalEdgeStart = 0x0, eLogicalEdgeEnd = 0x1 }; +enum LogicalSide : uint8_t { + eLogicalSideBStart = (eLogicalAxisBlock << 1) | eLogicalEdgeStart, // 0x0 + eLogicalSideBEnd = (eLogicalAxisBlock << 1) | eLogicalEdgeEnd, // 0x1 + eLogicalSideIStart = (eLogicalAxisInline << 1) | eLogicalEdgeStart, // 0x2 + eLogicalSideIEnd = (eLogicalAxisInline << 1) | eLogicalEdgeEnd // 0x3 +}; + +enum LogicalCorner { + eLogicalCornerBStartIStart = 0, + eLogicalCornerBStartIEnd = 1, + eLogicalCornerBEndIEnd = 2, + eLogicalCornerBEndIStart = 3 +}; + +using LengthPercentage = StyleLengthPercentage; +using LengthPercentageOrAuto = StyleLengthPercentageOrAuto; +using NonNegativeLengthPercentage = StyleNonNegativeLengthPercentage; +using NonNegativeLengthPercentageOrAuto = + StyleNonNegativeLengthPercentageOrAuto; +using NonNegativeLengthPercentageOrNormal = + StyleNonNegativeLengthPercentageOrNormal; +using Length = StyleLength; +using LengthOrAuto = StyleLengthOrAuto; +using NonNegativeLength = StyleNonNegativeLength; +using NonNegativeLengthOrAuto = StyleNonNegativeLengthOrAuto; +using BorderRadius = StyleBorderRadius; + +bool StyleCSSPixelLength::IsZero() const { return _0 == 0.0f; } + +nscoord StyleCSSPixelLength::ToAppUnits() const { + // We want to resolve the length part of the calc() expression rounding 0.5 + // away from zero, instead of the default behavior of + // NSToCoordRound{,WithClamp} which do floor(x + 0.5). + // + // This is what the rust code in the app_units crate does, and not doing this + // would regress bug 1323735, for example. + // + // FIXME(emilio, bug 1528114): Probably we should do something smarter. + float length = _0 * float(mozilla::AppUnitsPerCSSPixel()); + if (length >= nscoord_MAX) { + return nscoord_MAX; + } + if (length <= nscoord_MIN) { + return nscoord_MIN; + } + return NSToIntRound(length); +} + +constexpr LengthPercentage LengthPercentage::Zero() { + return {{0.}, {0.}, StyleAllowedNumericType::All, false, false}; +} + +LengthPercentage LengthPercentage::FromPixels(CSSCoord aCoord) { + return {{aCoord}, {0.}, StyleAllowedNumericType::All, false, false}; +} + +LengthPercentage LengthPercentage::FromAppUnits(nscoord aCoord) { + return LengthPercentage::FromPixels(CSSPixel::FromAppUnits(aCoord)); +} + +LengthPercentage LengthPercentage::FromPercentage(float aPercentage) { + return {{0.}, {aPercentage}, StyleAllowedNumericType::All, true, false}; +} + +CSSCoord LengthPercentage::LengthInCSSPixels() const { return length._0; } + +float LengthPercentage::Percentage() const { return percentage._0; } + +bool LengthPercentage::HasPercent() const { return has_percentage; } + +bool LengthPercentage::ConvertsToLength() const { return !HasPercent(); } + +nscoord LengthPercentage::ToLength() const { + MOZ_ASSERT(ConvertsToLength()); + return length.ToAppUnits(); +} + +bool LengthPercentage::ConvertsToPercentage() const { + return has_percentage && length.IsZero(); +} + +float LengthPercentage::ToPercentage() const { + MOZ_ASSERT(ConvertsToPercentage()); + return Percentage(); +} + +bool LengthPercentage::HasLengthAndPercentage() const { + return !ConvertsToLength() && !ConvertsToPercentage(); +} + +bool LengthPercentage::IsDefinitelyZero() const { + return length.IsZero() && Percentage() == 0.0f; +} + +CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const { + return LengthInCSSPixels() + Percentage() * aPercentageBasis; +} + +template +CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const { + static_assert(std::is_same::value, + "Should return CSS pixels"); + if (ConvertsToLength()) { + return LengthInCSSPixels(); + } + return ResolveToCSSPixels(aPercentageGetter()); +} + +template +nscoord LengthPercentage::Resolve(T aPercentageGetter, + U aPercentageRounder) const { + static_assert(std::is_same::value, + "Should return app units"); + static_assert( + std::is_same::value, + "Should return app units"); + if (ConvertsToLength()) { + return ToLength(); + } + nscoord basis = aPercentageGetter(); + return length.ToAppUnits() + aPercentageRounder(basis * Percentage()); +} + +nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const { + return Resolve([=] { return aPercentageBasis; }, NSToCoordFloorClamped); +} + +template +nscoord LengthPercentage::Resolve(T aPercentageGetter) const { + static_assert(std::is_same::value, + "Should return app units"); + return Resolve(aPercentageGetter, NSToCoordFloorClamped); +} + +template +nscoord LengthPercentage::Resolve(nscoord aPercentageBasis, + T aPercentageRounder) const { + return Resolve([=] { return aPercentageBasis; }, aPercentageRounder); +} + +#define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \ + template <> \ + inline bool ty_::HasPercent() const { \ + return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \ + } \ + template <> \ + inline bool ty_::ConvertsToLength() const { \ + return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \ + } \ + template <> \ + inline bool ty_::HasLengthAndPercentage() const { \ + return IsLengthPercentage() && \ + AsLengthPercentage().HasLengthAndPercentage(); \ + } \ + template <> \ + inline nscoord ty_::ToLength() const { \ + MOZ_ASSERT(ConvertsToLength()); \ + return AsLengthPercentage().ToLength(); \ + } \ + template <> \ + inline bool ty_::ConvertsToPercentage() const { \ + return IsLengthPercentage() && \ + AsLengthPercentage().ConvertsToPercentage(); \ + } \ + template <> \ + inline float ty_::ToPercentage() const { \ + MOZ_ASSERT(ConvertsToPercentage()); \ + return AsLengthPercentage().ToPercentage(); \ + } + +IMPL_LENGTHPERCENTAGE_FORWARDS(LengthPercentageOrAuto) +IMPL_LENGTHPERCENTAGE_FORWARDS(StyleSize) +IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMaxSize) + +template <> +inline bool LengthOrAuto::IsLength() const { + return IsLengthPercentage(); +} + +template <> +inline const Length& LengthOrAuto::AsLength() const { + return AsLengthPercentage(); +} + +template <> +inline bool StyleFlexBasis::IsAuto() const { + return IsSize() && AsSize().IsAuto(); +} + +template <> +inline bool StyleSize::BehavesLikeInitialValueOnBlockAxis() const { + return IsAuto() || IsExtremumLength(); +} + +template <> +inline bool StyleMaxSize::BehavesLikeInitialValueOnBlockAxis() const { + return IsNone() || IsExtremumLength(); +} + +template <> +inline bool StyleBackgroundSize::IsInitialValue() const { + return IsExplicitSize() && explicit_size.width.IsAuto() && + explicit_size.height.IsAuto(); +} + +template +const T& StyleRect::Get(mozilla::Side aSide) const { + static_assert(sizeof(StyleRect) == sizeof(T) * 4, ""); + static_assert(alignof(StyleRect) == alignof(T), ""); + return reinterpret_cast(this)[aSide]; +} + +template +template +bool StyleRect::All(Predicate aPredicate) const { + return aPredicate(_0) && aPredicate(_1) && aPredicate(_2) && aPredicate(_3); +} + +template +template +bool StyleRect::Any(Predicate aPredicate) const { + return aPredicate(_0) || aPredicate(_1) || aPredicate(_2) || aPredicate(_3); +} + +template <> +inline const LengthPercentage& BorderRadius::Get(HalfCorner aCorner) const { + static_assert(sizeof(BorderRadius) == sizeof(LengthPercentage) * 8, ""); + static_assert(alignof(BorderRadius) == alignof(LengthPercentage), ""); + auto* self = reinterpret_cast(this); + return self[aCorner]; +} + +} // namespace mozilla + +enum nsStyleUnit : uint8_t { + eStyleUnit_Null = 0, // (no value) value is not specified + eStyleUnit_Normal = 1, // (no value) + eStyleUnit_Auto = 2, // (no value) + eStyleUnit_None = 3, // (no value) + eStyleUnit_Percent = 10, // (float) 1.0 == 100% + eStyleUnit_Factor = 11, // (float) a multiplier + eStyleUnit_Degree = 12, // (float) angle in degrees + eStyleUnit_FlexFraction = 16, // (float) in fr units + eStyleUnit_Coord = 20, // (nscoord) value is twips + eStyleUnit_Integer = 30, // (int) value is simple integer + eStyleUnit_Enumerated = 32, // (int) value has enumerated meaning + + // The following are reference counted allocated types. + eStyleUnit_Calc = 40, // (Calc*) calc() toplevel; always present + // to distinguish 50% from calc(50%), etc. + + eStyleUnit_MAX = 40 // highest valid nsStyleUnit value +}; + +typedef union { + int32_t mInt; // nscoord is a int32_t for now + float mFloat; + // An mPointer is a reference counted pointer. Currently this can only + // ever be an nsStyleCoord::Calc*. + void* mPointer; +} nsStyleUnion; + +/** + * Class that hold a single size specification used by the style + * system. The size specification consists of two parts -- a number + * and a unit. The number is an integer, a floating point value, an + * nscoord, or undefined, and the unit is an nsStyleUnit. Checking + * the unit is a must before asking for the value in any particular + * form. + */ +/**
*/ +class nsStyleCoord { + public: + // Non-reference counted calc() value. See nsStyleStruct.h for some uses + // of this. + struct CalcValue { + // Every calc() expression evaluates to a length plus a percentage. + nscoord mLength; + float mPercent; + bool mHasPercent; // whether there was any % syntax, even if 0 + + bool operator==(const CalcValue& aOther) const { + return mLength == aOther.mLength && mPercent == aOther.mPercent && + mHasPercent == aOther.mHasPercent; + } + bool operator!=(const CalcValue& aOther) const { + return !(*this == aOther); + } + + nscoord ToLength() const { + MOZ_ASSERT(!mHasPercent); + return mLength; + } + + // If this returns true the value is definitely zero. It it returns false + // it might be zero. So it's best used for conservative optimization. + bool IsDefinitelyZero() const { return mLength == 0 && mPercent == 0; } + }; + + // Reference counted calc() value. This is the type that is used to store + // the calc() value in nsStyleCoord. + struct Calc final : public CalcValue { + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Calc) + Calc() {} + + private: + Calc(const Calc&) = delete; + ~Calc() {} + Calc& operator=(const Calc&) = delete; + }; + + explicit nsStyleCoord(nsStyleUnit aUnit = eStyleUnit_Null); + enum CoordConstructorType { CoordConstructor }; + inline nsStyleCoord(nscoord aValue, CoordConstructorType); + nsStyleCoord(int32_t aValue, nsStyleUnit aUnit); + nsStyleCoord(float aValue, nsStyleUnit aUnit); + inline nsStyleCoord(const nsStyleCoord& aCopy); + inline nsStyleCoord(const nsStyleUnion& aValue, nsStyleUnit aUnit); + ~nsStyleCoord() { Reset(); } + + nsStyleCoord& operator=(const nsStyleCoord& aOther) { + if (this != &aOther) { + SetValue(mUnit, mValue, aOther); + } + return *this; + } + bool operator==(const nsStyleCoord& aOther) const; + bool operator!=(const nsStyleCoord& aOther) const; + + nsStyleUnit GetUnit() const { + NS_ASSERTION(mUnit != eStyleUnit_Null, "reading uninitialized value"); + return mUnit; + } + + // This is especially useful to check if it is the property's initial value + // or keyword for sizing properties. + bool IsAutoOrEnum() const { + // The initial value of width/height and min-width/min-height is `auto`. + // The initial value of max-width/max-height is `none`. + return mUnit == eStyleUnit_Auto || mUnit == eStyleUnit_None || + mUnit == eStyleUnit_Enumerated; + } + + bool IsAngleValue() const { return eStyleUnit_Degree == mUnit; } + + static bool IsCalcUnit(nsStyleUnit aUnit) { return aUnit == eStyleUnit_Calc; } + + static bool IsPointerUnit(nsStyleUnit aUnit) { return IsCalcUnit(aUnit); } + + bool IsCalcUnit() const { return IsCalcUnit(mUnit); } + + bool IsPointerValue() const { return IsPointerUnit(mUnit); } + + bool IsCoordPercentCalcUnit() const { + return mUnit == eStyleUnit_Coord || mUnit == eStyleUnit_Percent || + IsCalcUnit(); + } + + // Does this calc() expression have any percentages inside it? Can be + // called only when IsCalcUnit() is true. + bool CalcHasPercent() const { return GetCalcValue()->mHasPercent; } + + bool HasPercent() const { + return mUnit == eStyleUnit_Percent || (IsCalcUnit() && CalcHasPercent()); + } + + static bool ConvertsToPercent(const nsStyleUnit aUnit, + const nsStyleUnion aValue) { + if (aUnit == eStyleUnit_Percent) { + return true; + } + if (!IsCalcUnit(aUnit)) { + return false; + } + auto* calc = AsCalcValue(aValue); + return calc->mLength == 0 && calc->mHasPercent; + } + + bool ConvertsToPercent() const { return ConvertsToPercent(mUnit, mValue); } + + float ToPercent() const { + MOZ_ASSERT(ConvertsToPercent()); + if (IsCalcUnit()) { + MOZ_ASSERT(CalcHasPercent() && GetCalcValue()->mLength == 0); + return GetCalcValue()->mPercent; + } + return mValue.mFloat; + } + + static bool ConvertsToLength(const nsStyleUnit aUnit, + const nsStyleUnion aValue) { + return aUnit == eStyleUnit_Coord || + (IsCalcUnit(aUnit) && !AsCalcValue(aValue)->mHasPercent); + } + + bool ConvertsToLength() const { return ConvertsToLength(mUnit, mValue); } + + static nscoord ToLength(nsStyleUnit aUnit, nsStyleUnion aValue) { + MOZ_ASSERT(ConvertsToLength(aUnit, aValue)); + if (IsCalcUnit(aUnit)) { + // Note: ToLength asserts !mHasPercent + return AsCalcValue(aValue)->ToLength(); + } + MOZ_ASSERT(aUnit == eStyleUnit_Coord); + return aValue.mInt; + } + + nscoord ToLength() const { return ToLength(GetUnit(), mValue); } + + // Callers must verify IsCalcUnit before calling this function. + static Calc* AsCalcValue(nsStyleUnion aValue) { + return static_cast(aValue.mPointer); + } + + // Compute the value that IsCalcUnit(). + // @note the caller is expected to handle percentage of an indefinite size + // and NOT call this method with aPercentageBasis == NS_UNCONSTRAINEDSIZE. + // @note the return value may be negative, e.g. for "calc(a - b%)" + nscoord ComputeComputedCalc(nscoord aPercentageBasis) const; + + // Compute the value that is either a coord, a percent, or a calc expression. + // @note the caller is expected to handle percentage of an indefinite size + // and NOT call this method with aPercentageBasis == NS_UNCONSTRAINEDSIZE. + // @note the return value may be negative, e.g. for "calc(a - b%)" + nscoord ComputeCoordPercentCalc(nscoord aPercentageBasis) const; + + nscoord GetCoordValue() const; + int32_t GetIntValue() const; + float GetPercentValue() const; + float GetFactorValue() const; + float GetFactorOrPercentValue() const; + float GetAngleValue() const; + double GetAngleValueInDegrees() const; + double GetAngleValueInRadians() const; + float GetFlexFractionValue() const; + Calc* GetCalcValue() const; + template ::value>::type> + T GetEnumValue() const { + MOZ_ASSERT(GetUnit() == eStyleUnit_Enumerated, + "The unit must be eStyleUnit_Enumerated!"); + return static_cast(GetIntValue()); + } + + // Sets to null and releases any refcounted objects. Only use this if the + // object is initialized (i.e. don't use it in nsStyleCoord constructors). + void Reset(); + + void SetCoordValue(nscoord aValue); + void SetIntValue(int32_t aValue, nsStyleUnit aUnit); + void SetPercentValue(float aValue); + void SetFactorValue(float aValue); + void SetFlexFractionValue(float aValue); + void SetNormalValue(); + void SetAutoValue(); + void SetNoneValue(); + void SetCalcValue(Calc* aValue); + template ::value>::type> + void SetEnumValue(T aValue) { + static_assert(mozilla::EnumTypeFitsWithin::value, + "aValue must be an enum that fits within mValue.mInt!"); + SetIntValue(static_cast(aValue), eStyleUnit_Enumerated); + } + + // Resets a coord represented by a unit/value pair. + static inline void Reset(nsStyleUnit& aUnit, nsStyleUnion& aValue); + + // Sets a coord represented by a unit/value pair from a second + // unit/value pair. + static inline void SetValue(nsStyleUnit& aUnit, nsStyleUnion& aValue, + nsStyleUnit aOtherUnit, + const nsStyleUnion& aOtherValue); + + // Sets a coord represented by a unit/value pair from an nsStyleCoord. + static inline void SetValue(nsStyleUnit& aUnit, nsStyleUnion& aValue, + const nsStyleCoord& aOther); + + // Like the above, but do not reset before setting. + static inline void InitWithValue(nsStyleUnit& aUnit, nsStyleUnion& aValue, + nsStyleUnit aOtherUnit, + const nsStyleUnion& aOtherValue); + + static inline void InitWithValue(nsStyleUnit& aUnit, nsStyleUnion& aValue, + const nsStyleCoord& aOther); + + private: + nsStyleUnit mUnit; + nsStyleUnion mValue; +}; + +/** + * Class that represents a set of top/right/bottom/left nsStyleCoords. + * This is commonly used to hold the widths of the borders, margins, + * or paddings of a box. + */ +/**
*/ +class nsStyleSides { + public: + nsStyleSides(); + nsStyleSides(const nsStyleSides&); + ~nsStyleSides(); + + nsStyleSides& operator=(const nsStyleSides& aCopy); + bool operator==(const nsStyleSides& aOther) const; + bool operator!=(const nsStyleSides& aOther) const; + + inline nsStyleUnit GetUnit(mozilla::Side aSide) const; + inline nsStyleUnit GetLeftUnit() const; + inline nsStyleUnit GetTopUnit() const; + inline nsStyleUnit GetRightUnit() const; + inline nsStyleUnit GetBottomUnit() const; + + inline nsStyleCoord Get(mozilla::Side aSide) const; + inline nsStyleCoord GetLeft() const; + inline nsStyleCoord GetTop() const; + inline nsStyleCoord GetRight() const; + inline nsStyleCoord GetBottom() const; + + // Methods to access the units and values in terms of logical sides + // for a given writing mode. + // NOTE: The definitions are in WritingModes.h (after we have the full + // declaration of WritingMode available). + inline nsStyleUnit GetUnit(mozilla::WritingMode aWritingMode, + mozilla::LogicalSide aSide) const; + inline nsStyleUnit GetIStartUnit(mozilla::WritingMode aWritingMode) const; + inline nsStyleUnit GetBStartUnit(mozilla::WritingMode aWritingMode) const; + inline nsStyleUnit GetIEndUnit(mozilla::WritingMode aWritingMode) const; + inline nsStyleUnit GetBEndUnit(mozilla::WritingMode aWritingMode) const; + + // Return true if either the start or end side in the axis is 'auto'. + inline bool HasBlockAxisAuto(mozilla::WritingMode aWritingMode) const; + inline bool HasInlineAxisAuto(mozilla::WritingMode aWritingMode) const; + + inline nsStyleCoord Get(mozilla::WritingMode aWritingMode, + mozilla::LogicalSide aSide) const; + inline nsStyleCoord GetIStart(mozilla::WritingMode aWritingMode) const; + inline nsStyleCoord GetBStart(mozilla::WritingMode aWritingMode) const; + inline nsStyleCoord GetIEnd(mozilla::WritingMode aWritingMode) const; + inline nsStyleCoord GetBEnd(mozilla::WritingMode aWritingMode) const; + + // Sets each side to null and releases any refcounted objects. Only use this + // if the object is initialized (i.e. don't use it in nsStyleSides + // constructors). + void Reset(); + + inline void Set(mozilla::Side aSide, const nsStyleCoord& aCoord); + inline void SetLeft(const nsStyleCoord& aCoord); + inline void SetTop(const nsStyleCoord& aCoord); + inline void SetRight(const nsStyleCoord& aCoord); + inline void SetBottom(const nsStyleCoord& aCoord); + + nscoord ToLength(mozilla::Side aSide) const { + return nsStyleCoord::ToLength(mUnits[aSide], mValues[aSide]); + } + + bool ConvertsToLength() const { + NS_FOR_CSS_SIDES(side) { + if (!nsStyleCoord::ConvertsToLength(mUnits[side], mValues[side])) { + return false; + } + } + return true; + } + + protected: + nsStyleUnit mUnits[4]; + nsStyleUnion mValues[4]; +}; + +// ------------------------- +// nsStyleCoord inlines +// +inline nsStyleCoord::nsStyleCoord(nscoord aValue, CoordConstructorType) + : mUnit(eStyleUnit_Coord) { + mValue.mInt = aValue; +} + +inline nsStyleCoord::nsStyleCoord(const nsStyleCoord& aCopy) + : mUnit(eStyleUnit_Null) { + InitWithValue(mUnit, mValue, aCopy); +} + +inline nsStyleCoord::nsStyleCoord(const nsStyleUnion& aValue, nsStyleUnit aUnit) + : mUnit(eStyleUnit_Null) { + InitWithValue(mUnit, mValue, aUnit, aValue); +} + +inline bool nsStyleCoord::operator!=(const nsStyleCoord& aOther) const { + return !((*this) == aOther); +} + +inline nscoord nsStyleCoord::GetCoordValue() const { + NS_ASSERTION((mUnit == eStyleUnit_Coord), "not a coord value"); + if (mUnit == eStyleUnit_Coord) { + return mValue.mInt; + } + return 0; +} + +inline int32_t nsStyleCoord::GetIntValue() const { + NS_ASSERTION( + (mUnit == eStyleUnit_Enumerated) || (mUnit == eStyleUnit_Integer), + "not an int value"); + if ((mUnit == eStyleUnit_Enumerated) || (mUnit == eStyleUnit_Integer)) { + return mValue.mInt; + } + return 0; +} + +inline float nsStyleCoord::GetPercentValue() const { + NS_ASSERTION(mUnit == eStyleUnit_Percent, "not a percent value"); + if (mUnit == eStyleUnit_Percent) { + return mValue.mFloat; + } + return 0.0f; +} + +inline float nsStyleCoord::GetFactorValue() const { + NS_ASSERTION(mUnit == eStyleUnit_Factor, "not a factor value"); + if (mUnit == eStyleUnit_Factor) { + return mValue.mFloat; + } + return 0.0f; +} + +inline float nsStyleCoord::GetFactorOrPercentValue() const { + NS_ASSERTION(mUnit == eStyleUnit_Factor || mUnit == eStyleUnit_Percent, + "not a percent or factor value"); + if (mUnit == eStyleUnit_Factor || mUnit == eStyleUnit_Percent) { + return mValue.mFloat; + } + return 0.0f; +} + +inline float nsStyleCoord::GetAngleValue() const { + MOZ_ASSERT(mUnit == eStyleUnit_Degree); + return mValue.mFloat; +} + +inline float nsStyleCoord::GetFlexFractionValue() const { + NS_ASSERTION(mUnit == eStyleUnit_FlexFraction, "not a fr value"); + if (mUnit == eStyleUnit_FlexFraction) { + return mValue.mFloat; + } + return 0.0f; +} + +inline nsStyleCoord::Calc* nsStyleCoord::GetCalcValue() const { + NS_ASSERTION(IsCalcUnit(), "not a pointer value"); + if (IsCalcUnit()) { + return AsCalcValue(mValue); + } + return nullptr; +} + +/* static */ inline void nsStyleCoord::Reset(nsStyleUnit& aUnit, + nsStyleUnion& aValue) { + MOZ_ASSERT(aUnit <= eStyleUnit_MAX, + "calling Reset on uninitialized nsStyleCoord?"); + + switch (aUnit) { + case eStyleUnit_Calc: + static_cast(aValue.mPointer)->Release(); + break; + default: + MOZ_ASSERT(!IsPointerUnit(aUnit), "check pointer refcounting logic"); + } + + aUnit = eStyleUnit_Null; + aValue.mInt = 0; +} + +/* static */ inline void nsStyleCoord::SetValue( + nsStyleUnit& aUnit, nsStyleUnion& aValue, nsStyleUnit aOtherUnit, + const nsStyleUnion& aOtherValue) { + Reset(aUnit, aValue); + InitWithValue(aUnit, aValue, aOtherUnit, aOtherValue); +} + +/* static */ inline void nsStyleCoord::InitWithValue( + nsStyleUnit& aUnit, nsStyleUnion& aValue, nsStyleUnit aOtherUnit, + const nsStyleUnion& aOtherValue) { + aUnit = aOtherUnit; + aValue = aOtherValue; + + switch (aUnit) { + case eStyleUnit_Calc: + static_cast(aValue.mPointer)->AddRef(); + break; + default: + MOZ_ASSERT(!IsPointerUnit(aUnit), "check pointer refcounting logic"); + } +} + +/* static */ inline void nsStyleCoord::SetValue(nsStyleUnit& aUnit, + nsStyleUnion& aValue, + const nsStyleCoord& aOther) { + SetValue(aUnit, aValue, aOther.mUnit, aOther.mValue); +} + +/* static */ inline void nsStyleCoord::InitWithValue( + nsStyleUnit& aUnit, nsStyleUnion& aValue, const nsStyleCoord& aOther) { + InitWithValue(aUnit, aValue, aOther.mUnit, aOther.mValue); +} + +// ------------------------- +// nsStyleSides inlines +// +inline bool nsStyleSides::operator!=(const nsStyleSides& aOther) const { + return !((*this) == aOther); +} + +inline nsStyleUnit nsStyleSides::GetUnit(mozilla::Side aSide) const { + return (nsStyleUnit)mUnits[aSide]; +} + +inline nsStyleUnit nsStyleSides::GetLeftUnit() const { + return GetUnit(mozilla::eSideLeft); +} + +inline nsStyleUnit nsStyleSides::GetTopUnit() const { + return GetUnit(mozilla::eSideTop); +} + +inline nsStyleUnit nsStyleSides::GetRightUnit() const { + return GetUnit(mozilla::eSideRight); +} + +inline nsStyleUnit nsStyleSides::GetBottomUnit() const { + return GetUnit(mozilla::eSideBottom); +} + +inline nsStyleCoord nsStyleSides::Get(mozilla::Side aSide) const { + return nsStyleCoord(mValues[aSide], nsStyleUnit(mUnits[aSide])); +} + +inline nsStyleCoord nsStyleSides::GetLeft() const { + return Get(mozilla::eSideLeft); +} + +inline nsStyleCoord nsStyleSides::GetTop() const { + return Get(mozilla::eSideTop); +} + +inline nsStyleCoord nsStyleSides::GetRight() const { + return Get(mozilla::eSideRight); +} + +inline nsStyleCoord nsStyleSides::GetBottom() const { + return Get(mozilla::eSideBottom); +} + +inline void nsStyleSides::Set(mozilla::Side aSide, const nsStyleCoord& aCoord) { + nsStyleCoord::SetValue(mUnits[aSide], mValues[aSide], aCoord); +} + +inline void nsStyleSides::SetLeft(const nsStyleCoord& aCoord) { + Set(mozilla::eSideLeft, aCoord); +} + +inline void nsStyleSides::SetTop(const nsStyleCoord& aCoord) { + Set(mozilla::eSideTop, aCoord); +} + +inline void nsStyleSides::SetRight(const nsStyleCoord& aCoord) { + Set(mozilla::eSideRight, aCoord); +} + +inline void nsStyleSides::SetBottom(const nsStyleCoord& aCoord) { + Set(mozilla::eSideBottom, aCoord); +} +#endif /* nsStyleCoord_h___ */ diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 20c3013ccc80..400e1bf389bd 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1273,8 +1273,10 @@ nsStylePosition::nsStylePosition(const Document& aDocument) mMinHeight(StyleSize::Auto()), mMaxHeight(StyleMaxSize::None()), mFlexBasis(StyleFlexBasis::Size(StyleSize::Auto())), - mGridAutoColumns(StyleTrackSize::Breadth(StyleTrackBreadth::Auto())), - mGridAutoRows(StyleTrackSize::Breadth(StyleTrackBreadth::Auto())), + mGridAutoColumnsMin(eStyleUnit_Auto), + mGridAutoColumnsMax(eStyleUnit_Auto), + mGridAutoRowsMin(eStyleUnit_Auto), + mGridAutoRowsMax(eStyleUnit_Auto), mAspectRatio(0.0f), mGridAutoFlow(NS_STYLE_GRID_AUTO_FLOW_ROW), mBoxSizing(StyleBoxSizing::Content), @@ -1318,8 +1320,10 @@ nsStylePosition::nsStylePosition(const nsStylePosition& aSource) mMinHeight(aSource.mMinHeight), mMaxHeight(aSource.mMaxHeight), mFlexBasis(aSource.mFlexBasis), - mGridAutoColumns(aSource.mGridAutoColumns), - mGridAutoRows(aSource.mGridAutoRows), + mGridAutoColumnsMin(aSource.mGridAutoColumnsMin), + mGridAutoColumnsMax(aSource.mGridAutoColumnsMax), + mGridAutoRowsMin(aSource.mGridAutoRowsMin), + mGridAutoRowsMax(aSource.mGridAutoRowsMax), mAspectRatio(aSource.mAspectRatio), mGridAutoFlow(aSource.mGridAutoFlow), mBoxSizing(aSource.mBoxSizing), @@ -1437,8 +1441,10 @@ nsChangeHint nsStylePosition::CalcDifference( aNewData.mGridTemplateColumns) || !IsGridTemplateEqual(mGridTemplateRows, aNewData.mGridTemplateRows) || mGridTemplateAreas != aNewData.mGridTemplateAreas || - mGridAutoColumns != aNewData.mGridAutoColumns || - mGridAutoRows != aNewData.mGridAutoRows || + mGridAutoColumnsMin != aNewData.mGridAutoColumnsMin || + mGridAutoColumnsMax != aNewData.mGridAutoColumnsMax || + mGridAutoRowsMin != aNewData.mGridAutoRowsMin || + mGridAutoRowsMax != aNewData.mGridAutoRowsMax || mGridAutoFlow != aNewData.mGridAutoFlow) { return hint | nsChangeHint_AllReflowHints; } @@ -1906,9 +1912,9 @@ void nsStyleImage::DoCopy(const nsStyleImage& aOther) { SetElementId(do_AddRef(aOther.mElementId)); } - UniquePtr cropRectCopy; + UniquePtr cropRectCopy; if (aOther.mCropRect) { - cropRectCopy = MakeUnique(*aOther.mCropRect.get()); + cropRectCopy = MakeUnique(*aOther.mCropRect.get()); } SetCropRect(std::move(cropRectCopy)); } @@ -1966,18 +1972,23 @@ void nsStyleImage::SetElementId(already_AddRefed aElementId) { } } -void nsStyleImage::SetCropRect(UniquePtr aCropRect) { +void nsStyleImage::SetCropRect(UniquePtr aCropRect) { mCropRect = std::move(aCropRect); } -static int32_t ConvertToPixelCoord(const StyleNumberOrPercentage& aCoord, +static int32_t ConvertToPixelCoord(const nsStyleCoord& aCoord, int32_t aPercentScale) { double pixelValue; - if (aCoord.IsNumber()) { - pixelValue = aCoord.AsNumber(); - } else { - MOZ_ASSERT(aCoord.IsPercentage()); - pixelValue = aCoord.AsPercentage()._0 * aPercentScale; + switch (aCoord.GetUnit()) { + case eStyleUnit_Percent: + pixelValue = aCoord.GetPercentValue() * aPercentScale; + break; + case eStyleUnit_Factor: + pixelValue = aCoord.GetFactorValue(); + break; + default: + MOZ_ASSERT_UNREACHABLE("unexpected unit for image crop rect"); + return 0; } MOZ_ASSERT(pixelValue >= 0, "we ensured non-negative while parsing"); pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow @@ -2024,13 +2035,11 @@ bool nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect, return false; } - int32_t left = - ConvertToPixelCoord(mCropRect->Get(eSideLeft), imageSize.width); - int32_t top = ConvertToPixelCoord(mCropRect->Get(eSideTop), imageSize.height); - int32_t right = - ConvertToPixelCoord(mCropRect->Get(eSideRight), imageSize.width); + int32_t left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width); + int32_t top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height); + int32_t right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width); int32_t bottom = - ConvertToPixelCoord(mCropRect->Get(eSideBottom), imageSize.height); + ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height); // IntersectRect() returns an empty rect if we get negative width or height nsIntRect cropRect(left, top, right - left, bottom - top); @@ -2140,8 +2149,8 @@ bool nsStyleImage::IsLoaded() const { } } -static inline bool EqualRects(const nsStyleImage::CropRect* aRect1, - const nsStyleImage::CropRect* aRect2) { +static inline bool EqualRects(const UniquePtr& aRect1, + const UniquePtr& aRect2) { return aRect1 == aRect2 || /* handles null== null, and optimize */ (aRect1 && aRect2 && *aRect1 == *aRect2); } @@ -2151,7 +2160,7 @@ bool nsStyleImage::operator==(const nsStyleImage& aOther) const { return false; } - if (!EqualRects(mCropRect.get(), aOther.mCropRect.get())) { + if (!EqualRects(mCropRect, aOther.mCropRect)) { return false; } diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index 48bb582b3df5..ab56def39d8b 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -22,6 +22,7 @@ #include "nsMargin.h" #include "nsFont.h" #include "nsStyleAutoArray.h" +#include "nsStyleCoord.h" #include "nsStyleConsts.h" #include "nsChangeHint.h" #include "nsTimingFunction.h" @@ -256,8 +257,6 @@ struct CachedBorderImageData { * image of type (1)). */ struct nsStyleImage { - using CropRect = mozilla::StyleRect; - nsStyleImage(); ~nsStyleImage(); nsStyleImage(const nsStyleImage& aOther); @@ -267,7 +266,7 @@ struct nsStyleImage { void SetImageRequest(already_AddRefed aImage); void SetGradientData(mozilla::UniquePtr); void SetElementId(already_AddRefed aElementId); - void SetCropRect(mozilla::UniquePtr aCropRect); + void SetCropRect(mozilla::UniquePtr aCropRect); void ResolveImage(mozilla::dom::Document& aDocument, const nsStyleImage* aOldImage) { @@ -299,10 +298,10 @@ struct nsStyleImage { NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!"); return mElementId; } - const CropRect* GetCropRect() const { + const mozilla::UniquePtr& GetCropRect() const { NS_ASSERTION(mType == eStyleImageType_Image, "Only image data can have a crop rect"); - return mCropRect.get(); + return mCropRect; } already_AddRefed GetImageURI() const; @@ -395,7 +394,7 @@ struct nsStyleImage { }; // This is _currently_ used only in conjunction with eStyleImageType_Image. - mozilla::UniquePtr mCropRect; + mozilla::UniquePtr mCropRect; }; struct nsStyleImageLayers { @@ -955,7 +954,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList { // mIsSubgrid is false, all three arrays are empty // * : // mIsSubgrid is false, -// mTrackSizingFunctions is of non-zero size, +// mMinTrackSizingFunctions and mMaxTrackSizingFunctions +// are of identical non-zero size, // and mLineNameLists is one element longer than that. // (Delimiting N columns requires N+1 lines: // one before each track, plus one at the very end.) @@ -968,10 +968,15 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList { // A 'fit-content(size)' is represented as eStyleUnit_None // in the min sizing function and 'size' in the max sizing function. // +// The units for nsStyleCoord are: +// * eStyleUnit_Percent represents a +// * eStyleUnit_FlexFraction represents a flexible fraction +// * eStyleUnit_Coord represents a +// * eStyleUnit_Enumerated represents min-content or max-content // * subgrid ?: // mIsSubgrid is true, // mLineNameLists may or may not be empty, -// mTrackSizingFunctions is empty. +// mMinTrackSizingFunctions and mMaxTrackSizingFunctions are empty. // // If mRepeatAutoIndex != -1 then that index is an and // mIsAutoFill == true means it's an 'auto-fill', otherwise 'auto-fit'. @@ -982,7 +987,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList { // names and mRepeatAutoLineNameListAfter is empty. struct nsStyleGridTemplate { nsTArray>> mLineNameLists; - nsTArray mTrackSizingFunctions; + nsTArray mMinTrackSizingFunctions; + nsTArray mMaxTrackSizingFunctions; nsTArray> mRepeatAutoLineNameListBefore; nsTArray> mRepeatAutoLineNameListAfter; int16_t mRepeatAutoIndex; // -1 or the track index for an auto-fill/fit track @@ -995,7 +1001,8 @@ struct nsStyleGridTemplate { inline bool operator==(const nsStyleGridTemplate& aOther) const { return mIsSubgrid == aOther.mIsSubgrid && mLineNameLists == aOther.mLineNameLists && - mTrackSizingFunctions == aOther.mTrackSizingFunctions && + mMinTrackSizingFunctions == aOther.mMinTrackSizingFunctions && + mMaxTrackSizingFunctions == aOther.mMaxTrackSizingFunctions && mIsAutoFill == aOther.mIsAutoFill && mRepeatAutoIndex == aOther.mRepeatAutoIndex && mRepeatAutoLineNameListBefore == @@ -1020,7 +1027,6 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition { using StyleMaxSize = mozilla::StyleMaxSize; using StyleFlexBasis = mozilla::StyleFlexBasis; using WritingMode = mozilla::WritingMode; - using StyleTrackSize = mozilla::StyleTrackSize; explicit nsStylePosition(const mozilla::dom::Document&); nsStylePosition(const nsStylePosition& aOther); @@ -1062,8 +1068,10 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition { StyleSize mMinHeight; StyleMaxSize mMaxHeight; StyleFlexBasis mFlexBasis; - StyleTrackSize mGridAutoColumns; - StyleTrackSize mGridAutoRows; + nsStyleCoord mGridAutoColumnsMin; // coord, percent, enum, calc, flex + nsStyleCoord mGridAutoColumnsMax; // coord, percent, enum, calc, flex + nsStyleCoord mGridAutoRowsMin; // coord, percent, enum, calc, flex + nsStyleCoord mGridAutoRowsMax; // coord, percent, enum, calc, flex float mAspectRatio; uint8_t mGridAutoFlow; // NS_STYLE_GRID_AUTO_FLOW_* mozilla::StyleBoxSizing mBoxSizing; diff --git a/layout/style/nsStyleUtil.cpp b/layout/style/nsStyleUtil.cpp index b9aeb4ea2893..d453726215e0 100644 --- a/layout/style/nsStyleUtil.cpp +++ b/layout/style/nsStyleUtil.cpp @@ -185,6 +185,24 @@ void nsStyleUtil::AppendBitmaskCSSValue(const nsCSSKTableEntry aTable[], MOZ_ASSERT(aMaskedValue == 0, "unexpected bit remaining in bitfield"); } +/* static */ +void nsStyleUtil::AppendAngleValue(const nsStyleCoord& aAngle, + nsAString& aResult) { + MOZ_ASSERT(aAngle.IsAngleValue(), "Should have angle value"); + + // Append number. + AppendCSSNumber(aAngle.GetAngleValue(), aResult); + + // Append unit. + switch (aAngle.GetUnit()) { + case eStyleUnit_Degree: + aResult.AppendLiteral("deg"); + break; + default: + MOZ_ASSERT_UNREACHABLE("unrecognized angle unit"); + } +} + /* static */ void nsStyleUtil::AppendPaintOrderValue(uint8_t aValue, nsAString& aResult) { static_assert( @@ -410,8 +428,7 @@ void nsStyleUtil::AppendFontSlantStyle(const FontSlantStyle& aStyle, auto angle = aStyle.ObliqueAngle(); if (angle != FontSlantStyle::kDefaultAngle) { aOut.AppendLiteral(" "); - AppendCSSNumber(angle, aOut); - aOut.AppendLiteral("deg"); + AppendAngleValue(nsStyleCoord(angle, eStyleUnit_Degree), aOut); } } } diff --git a/layout/style/nsStyleUtil.h b/layout/style/nsStyleUtil.h index 430f69c2cc71..ceb1aaf8ade7 100644 --- a/layout/style/nsStyleUtil.h +++ b/layout/style/nsStyleUtil.h @@ -15,6 +15,7 @@ #include "nsCRT.h" class nsCSSValue; +class nsStyleCoord; class nsIContent; class nsIPrincipal; class nsIURI; @@ -64,6 +65,8 @@ class nsStyleUtil { int32_t aMaskedValue, int32_t aFirstMask, int32_t aLastMask, nsAString& aResult); + static void AppendAngleValue(const nsStyleCoord& aValue, nsAString& aResult); + static void AppendPaintOrderValue(uint8_t aValue, nsAString& aResult); static void AppendCSSNumber(float aNumber, nsAString& aResult) { diff --git a/layout/svg/nsSVGUtils.cpp b/layout/svg/nsSVGUtils.cpp index 6dc3d7a3a605..32b379ce1ee4 100644 --- a/layout/svg/nsSVGUtils.cpp +++ b/layout/svg/nsSVGUtils.cpp @@ -26,6 +26,7 @@ #include "nsIFrame.h" #include "nsLayoutUtils.h" #include "nsPresContext.h" +#include "nsStyleCoord.h" #include "nsStyleStruct.h" #include "nsStyleTransformMatrix.h" #include "SVGAnimatedLength.h" diff --git a/layout/tables/nsTableFrame.h b/layout/tables/nsTableFrame.h index 02ef9888d07f..b95adb8e2e20 100644 --- a/layout/tables/nsTableFrame.h +++ b/layout/tables/nsTableFrame.h @@ -10,6 +10,7 @@ #include "imgIContainer.h" #include "nscore.h" #include "nsContainerFrame.h" +#include "nsStyleCoord.h" #include "nsStyleConsts.h" #include "nsCellMap.h" #include "nsGkAtoms.h" diff --git a/servo/components/style/gecko/conversions.rs b/servo/components/style/gecko/conversions.rs index 26159c5681cf..bf1b93422f0c 100644 --- a/servo/components/style/gecko/conversions.rs +++ b/servo/components/style/gecko/conversions.rs @@ -10,15 +10,57 @@ #![allow(unsafe_code)] +use crate::gecko::values::GeckoStyleCoordConvertible; use crate::gecko_bindings::bindings; -use crate::gecko_bindings::structs::{self, Matrix4x4Components}; +use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue, Matrix4x4Components}; use crate::gecko_bindings::structs::{nsStyleImage, nsresult}; +use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; use crate::stylesheets::RulesMutateError; use crate::values::computed::transform::Matrix3D; use crate::values::computed::url::ComputedImageUrl; -use crate::values::computed::{Gradient, Image, TextAlign}; +use crate::values::computed::{Angle, Gradient, Image}; +use crate::values::computed::{Integer, LengthPercentage}; +use crate::values::computed::{Length, Percentage, TextAlign}; +use crate::values::generics::grid::{TrackListValue, TrackSize}; use crate::values::generics::image::GenericImage; use crate::values::generics::rect::Rect; +use crate::Zero; +use app_units::Au; +use style_traits::values::specified::AllowedNumericType; + +impl From for nsStyleCoord_CalcValue { + fn from(other: LengthPercentage) -> nsStyleCoord_CalcValue { + debug_assert!( + other.was_calc || !other.has_percentage || other.unclamped_length() == Length::zero() + ); + nsStyleCoord_CalcValue { + mLength: other.unclamped_length().to_i32_au(), + mPercent: other.percentage(), + mHasPercent: other.has_percentage, + } + } +} + +impl From for LengthPercentage { + fn from(other: nsStyleCoord_CalcValue) -> LengthPercentage { + let percentage = if other.mHasPercent { + Some(Percentage(other.mPercent)) + } else { + None + }; + Self::with_clamping_mode( + Au(other.mLength).into(), + percentage, + AllowedNumericType::All, + /* was_calc = */ true, + ) + } +} +impl From for CoordDataValue { + fn from(reference: Angle) -> Self { + CoordDataValue::Degree(reference.degrees()) + } +} impl nsStyleImage { /// Set a given Servo `Image` value into this `nsStyleImage`. @@ -35,7 +77,18 @@ impl nsStyleImage { // Set CropRect let ref mut rect = *self.mCropRect.mPtr; - *rect = Rect(image_rect.top, image_rect.right, image_rect.bottom, image_rect.left); + image_rect + .top + .to_gecko_style_coord(&mut rect.data_at_mut(0)); + image_rect + .right + .to_gecko_style_coord(&mut rect.data_at_mut(1)); + image_rect + .bottom + .to_gecko_style_coord(&mut rect.data_at_mut(2)); + image_rect + .left + .to_gecko_style_coord(&mut rect.data_at_mut(3)); } }, GenericImage::Element(ref element) => unsafe { @@ -53,7 +106,7 @@ impl nsStyleImage { /// Converts into Image. pub unsafe fn into_image(self: &nsStyleImage) -> Option { use crate::gecko_bindings::structs::nsStyleImageType; - use crate::values::computed::MozImageRect; + use crate::values::computed::{MozImageRect, NumberOrPercentage}; match self.mType { nsStyleImageType::eStyleImageType_Null => None, @@ -62,14 +115,30 @@ impl nsStyleImage { if self.mCropRect.mPtr.is_null() { Some(GenericImage::Url(url)) } else { - let rect = &*self.mCropRect.mPtr; - Some(GenericImage::Rect(Box::new(MozImageRect { - url, - top: rect.0, - right: rect.1, - bottom: rect.2, - left: rect.3, - }))) + let ref rect = *self.mCropRect.mPtr; + match ( + NumberOrPercentage::from_gecko_style_coord(&rect.data_at(0)), + NumberOrPercentage::from_gecko_style_coord(&rect.data_at(1)), + NumberOrPercentage::from_gecko_style_coord(&rect.data_at(2)), + NumberOrPercentage::from_gecko_style_coord(&rect.data_at(3)), + ) { + (Some(top), Some(right), Some(bottom), Some(left)) => { + Some(GenericImage::Rect(Box::new(MozImageRect { + url, + top, + right, + bottom, + left, + }))) + }, + _ => { + debug_assert!( + false, + "mCropRect could not convert to NumberOrPercentage" + ); + None + }, + } } }, nsStyleImageType::eStyleImageType_Gradient => { @@ -262,6 +331,98 @@ impl From for nsresult { } } +impl TrackSize { + /// Return TrackSize from given two nsStyleCoord + pub fn from_gecko_style_coords(gecko_min: &T, gecko_max: &T) -> Self { + use crate::gecko_bindings::structs::root::nsStyleUnit; + use crate::values::generics::grid::TrackBreadth; + + if gecko_min.unit() == nsStyleUnit::eStyleUnit_None { + debug_assert!( + gecko_max.unit() == nsStyleUnit::eStyleUnit_Coord || + gecko_max.unit() == nsStyleUnit::eStyleUnit_Percent || + gecko_max.unit() == nsStyleUnit::eStyleUnit_Calc + ); + return TrackSize::FitContent( + LengthPercentage::from_gecko_style_coord(gecko_max) + .expect("gecko_max could not convert to LengthPercentage"), + ); + } + + let min = TrackBreadth::from_gecko_style_coord(gecko_min) + .expect("gecko_min could not convert to TrackBreadth"); + let max = TrackBreadth::from_gecko_style_coord(gecko_max) + .expect("gecko_max could not convert to TrackBreadth"); + if min == max { + TrackSize::Breadth(max) + } else { + TrackSize::Minmax(min, max) + } + } + + /// Save TrackSize to given gecko fields. + pub fn to_gecko_style_coords(&self, gecko_min: &mut T, gecko_max: &mut T) { + match *self { + TrackSize::FitContent(ref lop) => { + // Gecko sets min value to None and max value to the actual value in fit-content + // https://searchfox.org/mozilla-central/rev/c05d9d61188d32b8/layout/style/nsRuleNode.cpp#7910 + gecko_min.set_value(CoordDataValue::None); + lop.to_gecko_style_coord(gecko_max); + }, + TrackSize::Breadth(ref breadth) => { + // Set the value to both fields if there's one breadth value + // https://searchfox.org/mozilla-central/rev/c05d9d61188d32b8/layout/style/nsRuleNode.cpp#7919 + breadth.to_gecko_style_coord(gecko_min); + breadth.to_gecko_style_coord(gecko_max); + }, + TrackSize::Minmax(ref min, ref max) => { + min.to_gecko_style_coord(gecko_min); + max.to_gecko_style_coord(gecko_max); + }, + } + } +} + +impl TrackListValue { + /// Return TrackSize from given two nsStyleCoord + pub fn from_gecko_style_coords(gecko_min: &T, gecko_max: &T) -> Self { + TrackListValue::TrackSize(TrackSize::from_gecko_style_coords(gecko_min, gecko_max)) + } + + /// Save TrackSize to given gecko fields. + pub fn to_gecko_style_coords(&self, gecko_min: &mut T, gecko_max: &mut T) { + match *self { + TrackListValue::TrackSize(ref size) => size.to_gecko_style_coords(gecko_min, gecko_max), + _ => unreachable!("Should only transform from track-size computed values"), + } + } +} + +impl Rect +where + T: GeckoStyleCoordConvertible, +{ + /// Convert this generic Rect to given Gecko fields. + pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) { + self.0.to_gecko_style_coord(&mut sides.data_at_mut(0)); + self.1.to_gecko_style_coord(&mut sides.data_at_mut(1)); + self.2.to_gecko_style_coord(&mut sides.data_at_mut(2)); + self.3.to_gecko_style_coord(&mut sides.data_at_mut(3)); + } + + /// Convert from given Gecko data to generic Rect. + pub fn from_gecko_rect( + sides: &crate::gecko_bindings::structs::nsStyleSides, + ) -> Option> { + Some(Rect::new( + T::from_gecko_style_coord(&sides.data_at(0)).expect("coord[0] cound not convert"), + T::from_gecko_style_coord(&sides.data_at(1)).expect("coord[1] cound not convert"), + T::from_gecko_style_coord(&sides.data_at(2)).expect("coord[2] cound not convert"), + T::from_gecko_style_coord(&sides.data_at(3)).expect("coord[3] cound not convert"), + )) + } +} + impl TextAlign { /// Obtain a specified value from a Gecko keyword value /// diff --git a/servo/components/style/gecko/values.rs b/servo/components/style/gecko/values.rs index f0c998f8f081..8df85339265a 100644 --- a/servo/components/style/gecko/values.rs +++ b/servo/components/style/gecko/values.rs @@ -7,15 +7,215 @@ //! Different kind of helpers to interact with Gecko values. use crate::counter_style::{Symbol, Symbols}; -use crate::gecko_bindings::structs::CounterStylePtr; -use crate::values::generics::CounterStyleOrNone; +use crate::gecko_bindings::structs::StyleGridTrackBreadth; +use crate::gecko_bindings::structs::{nsStyleCoord, CounterStylePtr}; +use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; +use crate::values::computed::{Angle, Length, LengthPercentage}; +use crate::values::computed::{Number, NumberOrPercentage, Percentage}; +use crate::values::generics::grid::{TrackBreadth, TrackKeyword}; +use crate::values::generics::length::LengthPercentageOrAuto; +use crate::values::generics::{CounterStyleOrNone, NonNegative}; use crate::values::Either; -use crate::Atom; +use crate::{Atom, Zero}; use app_units::Au; use cssparser::RGBA; use nsstring::{nsACString, nsCStr}; use std::cmp::max; +/// A trait that defines an interface to convert from and to `nsStyleCoord`s. +/// +/// TODO(emilio): Almost everything that is in this file should be somehow +/// switched to cbindgen. +pub trait GeckoStyleCoordConvertible: Sized { + /// Convert this to a `nsStyleCoord`. + fn to_gecko_style_coord(&self, coord: &mut T); + /// Given a `nsStyleCoord`, try to get a value of this type.. + fn from_gecko_style_coord(coord: &T) -> Option; +} + +impl nsStyleCoord { + #[inline] + /// Set this `nsStyleCoord` value to `val`. + pub fn set(&mut self, val: T) { + val.to_gecko_style_coord(self); + } +} + +impl GeckoStyleCoordConvertible for NonNegative +where + Inner: GeckoStyleCoordConvertible, +{ + fn to_gecko_style_coord(&self, coord: &mut T) { + self.0.to_gecko_style_coord(coord) + } + + fn from_gecko_style_coord(coord: &T) -> Option { + Some(NonNegative(Inner::from_gecko_style_coord(coord)?)) + } +} + +impl GeckoStyleCoordConvertible for Number { + fn to_gecko_style_coord(&self, coord: &mut T) { + coord.set_value(CoordDataValue::Factor(*self)); + } + + fn from_gecko_style_coord(coord: &T) -> Option { + match coord.as_value() { + CoordDataValue::Factor(f) => Some(f), + _ => None, + } + } +} + +impl GeckoStyleCoordConvertible for Percentage { + fn to_gecko_style_coord(&self, coord: &mut T) { + coord.set_value(CoordDataValue::Percent(self.0)); + } + + fn from_gecko_style_coord(coord: &T) -> Option { + match coord.as_value() { + CoordDataValue::Percent(p) => Some(Percentage(p)), + _ => None, + } + } +} + +impl GeckoStyleCoordConvertible for NumberOrPercentage { + fn to_gecko_style_coord(&self, coord: &mut T) { + match *self { + NumberOrPercentage::Number(ref n) => n.to_gecko_style_coord(coord), + NumberOrPercentage::Percentage(ref p) => p.to_gecko_style_coord(coord), + } + } + + fn from_gecko_style_coord(coord: &T) -> Option { + match coord.as_value() { + CoordDataValue::Factor(f) => Some(NumberOrPercentage::Number(f)), + CoordDataValue::Percent(p) => Some(NumberOrPercentage::Percentage(Percentage(p))), + _ => None, + } + } +} + +impl GeckoStyleCoordConvertible for LengthPercentage { + fn to_gecko_style_coord(&self, coord: &mut T) { + if self.was_calc { + return coord.set_value(CoordDataValue::Calc((*self).into())); + } + debug_assert!(!self.has_percentage || self.unclamped_length() == Length::zero()); + if self.has_percentage { + return coord.set_value(CoordDataValue::Percent(self.percentage())); + } + coord.set_value(CoordDataValue::Coord(self.unclamped_length().to_i32_au())) + } + + fn from_gecko_style_coord(coord: &T) -> Option { + match coord.as_value() { + CoordDataValue::Coord(coord) => Some(LengthPercentage::new(Au(coord).into(), None)), + CoordDataValue::Percent(p) => { + Some(LengthPercentage::new(Au(0).into(), Some(Percentage(p)))) + }, + CoordDataValue::Calc(calc) => Some(calc.into()), + _ => None, + } + } +} + +impl GeckoStyleCoordConvertible for Length { + fn to_gecko_style_coord(&self, coord: &mut T) { + coord.set_value(CoordDataValue::Coord(self.to_i32_au())); + } + + fn from_gecko_style_coord(coord: &T) -> Option { + match coord.as_value() { + CoordDataValue::Coord(coord) => Some(Au(coord).into()), + _ => None, + } + } +} + +impl GeckoStyleCoordConvertible for LengthPercentageOrAuto +where + LengthPercentage: GeckoStyleCoordConvertible, +{ + fn to_gecko_style_coord(&self, coord: &mut T) { + match *self { + LengthPercentageOrAuto::Auto => coord.set_value(CoordDataValue::Auto), + LengthPercentageOrAuto::LengthPercentage(ref lp) => lp.to_gecko_style_coord(coord), + } + } + + fn from_gecko_style_coord(coord: &T) -> Option { + match coord.as_value() { + CoordDataValue::Auto => Some(LengthPercentageOrAuto::Auto), + _ => LengthPercentage::from_gecko_style_coord(coord) + .map(LengthPercentageOrAuto::LengthPercentage), + } + } +} + +impl GeckoStyleCoordConvertible for TrackBreadth { + fn to_gecko_style_coord(&self, coord: &mut T) { + match *self { + TrackBreadth::Breadth(ref lp) => lp.to_gecko_style_coord(coord), + TrackBreadth::Fr(fr) => coord.set_value(CoordDataValue::FlexFraction(fr)), + TrackBreadth::Keyword(TrackKeyword::Auto) => coord.set_value(CoordDataValue::Auto), + TrackBreadth::Keyword(TrackKeyword::MinContent) => coord.set_value( + CoordDataValue::Enumerated(StyleGridTrackBreadth::MinContent as u32), + ), + TrackBreadth::Keyword(TrackKeyword::MaxContent) => coord.set_value( + CoordDataValue::Enumerated(StyleGridTrackBreadth::MaxContent as u32), + ), + } + } + + fn from_gecko_style_coord(coord: &T) -> Option { + L::from_gecko_style_coord(coord) + .map(TrackBreadth::Breadth) + .or_else(|| match coord.as_value() { + CoordDataValue::Enumerated(v) => { + if v == StyleGridTrackBreadth::MinContent as u32 { + Some(TrackBreadth::Keyword(TrackKeyword::MinContent)) + } else if v == StyleGridTrackBreadth::MaxContent as u32 { + Some(TrackBreadth::Keyword(TrackKeyword::MaxContent)) + } else { + None + } + }, + CoordDataValue::FlexFraction(fr) => Some(TrackBreadth::Fr(fr)), + CoordDataValue::Auto => Some(TrackBreadth::Keyword(TrackKeyword::Auto)), + _ => L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth), + }) + } +} + +impl GeckoStyleCoordConvertible for Option { + fn to_gecko_style_coord(&self, coord: &mut U) { + if let Some(ref me) = *self { + me.to_gecko_style_coord(coord); + } else { + coord.set_value(CoordDataValue::None); + } + } + + fn from_gecko_style_coord(coord: &U) -> Option { + Some(T::from_gecko_style_coord(coord)) + } +} + +impl GeckoStyleCoordConvertible for Angle { + fn to_gecko_style_coord(&self, coord: &mut T) { + coord.set_value(CoordDataValue::from(*self)); + } + + fn from_gecko_style_coord(coord: &T) -> Option { + match coord.as_value() { + CoordDataValue::Degree(val) => Some(Angle::from_degrees(val)), + _ => None, + } + } +} + /// Convert a given RGBA value to `nscolor`. pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 { ((rgba.alpha as u32) << 24) | diff --git a/servo/components/style/gecko_bindings/sugar/mod.rs b/servo/components/style/gecko_bindings/sugar/mod.rs index 00faf63ba663..338236c175ae 100644 --- a/servo/components/style/gecko_bindings/sugar/mod.rs +++ b/servo/components/style/gecko_bindings/sugar/mod.rs @@ -7,6 +7,7 @@ mod ns_com_ptr; mod ns_compatibility; mod ns_style_auto_array; +pub mod ns_style_coord; mod ns_t_array; pub mod origin_flags; pub mod ownership; diff --git a/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs b/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs new file mode 100644 index 000000000000..7c6612f35efe --- /dev/null +++ b/servo/components/style/gecko_bindings/sugar/ns_style_coord.rs @@ -0,0 +1,369 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +//! Rust helpers for Gecko's `nsStyleCoord`. + +use crate::gecko_bindings::bindings; +use crate::gecko_bindings::structs::nsStyleSides; +use crate::gecko_bindings::structs::{nsStyleCoord, nsStyleCoord_Calc, nsStyleCoord_CalcValue}; +use crate::gecko_bindings::structs::{nsStyleUnion, nsStyleUnit, nscoord}; +use std::mem; + +impl nsStyleCoord { + #[inline] + /// Get a `null` nsStyleCoord. + pub fn null() -> Self { + // Can't construct directly because it has private fields + let mut coord: Self = unsafe { mem::zeroed() }; + coord.leaky_set_null(); + coord + } +} + +unsafe impl CoordData for nsStyleCoord { + #[inline] + fn unit(&self) -> nsStyleUnit { + unsafe { *self.get_mUnit() } + } + #[inline] + fn union(&self) -> nsStyleUnion { + unsafe { *self.get_mValue() } + } +} + +unsafe impl CoordDataMut for nsStyleCoord { + unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) { + let unit = self.get_mUnit_mut() as *mut _; + let value = self.get_mValue_mut() as *mut _; + (&mut *unit, &mut *value) + } +} + +impl nsStyleCoord_CalcValue { + /// Create an "empty" CalcValue (whose value is `0`). + pub fn new() -> Self { + nsStyleCoord_CalcValue { + mLength: 0, + mPercent: 0.0, + mHasPercent: false, + } + } +} + +impl PartialEq for nsStyleCoord_CalcValue { + fn eq(&self, other: &Self) -> bool { + self.mLength == other.mLength && + self.mPercent == other.mPercent && + self.mHasPercent == other.mHasPercent + } +} + +impl nsStyleSides { + /// Immutably get the `nsStyleCoord`-like object representing the side at + /// index `index`. + #[inline] + pub fn data_at(&self, index: usize) -> SidesData { + SidesData { + sides: self, + index: index, + } + } + + /// Mutably get the `nsStyleCoord`-like object representing the side at + /// index `index`. + #[inline] + pub fn data_at_mut(&mut self, index: usize) -> SidesDataMut { + SidesDataMut { + sides: self, + index: index, + } + } +} + +/// A `nsStyleCoord`-like object on top of an immutable reference to +/// `nsStyleSides`. +pub struct SidesData<'a> { + sides: &'a nsStyleSides, + index: usize, +} + +/// A `nsStyleCoord`-like object on top of an mutable reference to +/// `nsStyleSides`. +pub struct SidesDataMut<'a> { + sides: &'a mut nsStyleSides, + index: usize, +} + +unsafe impl<'a> CoordData for SidesData<'a> { + #[inline] + fn unit(&self) -> nsStyleUnit { + unsafe { self.sides.get_mUnits()[self.index] } + } + #[inline] + fn union(&self) -> nsStyleUnion { + unsafe { self.sides.get_mValues()[self.index] } + } +} +unsafe impl<'a> CoordData for SidesDataMut<'a> { + #[inline] + fn unit(&self) -> nsStyleUnit { + unsafe { self.sides.get_mUnits()[self.index] } + } + #[inline] + fn union(&self) -> nsStyleUnion { + unsafe { self.sides.get_mValues()[self.index] } + } +} +unsafe impl<'a> CoordDataMut for SidesDataMut<'a> { + unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion) { + let unit = &mut self.sides.get_mUnits_mut()[self.index] as *mut _; + let value = &mut self.sides.get_mValues_mut()[self.index] as *mut _; + (&mut *unit, &mut *value) + } +} + +/// Enum representing the tagged union that is CoordData. +/// +/// In release mode this should never actually exist in the code, and will be +/// optimized out by threading matches and inlining. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum CoordDataValue { + /// eStyleUnit_Null + Null, + /// eStyleUnit_Normal + Normal, + /// eStyleUnit_Auto + Auto, + /// eStyleUnit_None + None, + /// eStyleUnit_Percent + Percent(f32), + /// eStyleUnit_Factor + Factor(f32), + /// eStyleUnit_Degree + Degree(f32), + /// eStyleUnit_FlexFraction + FlexFraction(f32), + /// eStyleUnit_Coord + Coord(nscoord), + /// eStyleUnit_Integer + Integer(i32), + /// eStyleUnit_Enumerated + Enumerated(u32), + /// eStyleUnit_Calc + Calc(nsStyleCoord_CalcValue), +} + +/// A trait to abstract on top of a mutable `nsStyleCoord`-like object. +pub unsafe trait CoordDataMut: CoordData { + /// Get mutably the unit and the union. + /// + /// This is unsafe since it's possible to modify the unit without changing + /// the union. + /// + /// NB: This can't be two methods since we can't mutably borrow twice + unsafe fn values_mut(&mut self) -> (&mut nsStyleUnit, &mut nsStyleUnion); + + /// Clean up any resources used by the union. + /// + /// Currently, this only happens if the nsStyleUnit is a Calc. + #[inline] + fn reset(&mut self) { + unsafe { + if self.unit() == nsStyleUnit::eStyleUnit_Calc { + let (unit, union) = self.values_mut(); + bindings::Gecko_ResetStyleCoord(unit, union); + } + } + } + + #[inline] + /// Copies the unit and value from another `CoordData` type. + fn copy_from(&mut self, other: &T) { + unsafe { + self.reset(); + self.copy_from_unchecked(other); + self.addref_if_calc(); + } + } + + #[inline] + /// Moves the unit and value from another `CoordData` type. + fn move_from(&mut self, other: T) { + unsafe { + self.reset(); + self.copy_from_unchecked(&other); + } + } + + #[inline] + /// Copies the unit and value from another `CoordData` type without checking + /// the type of the value (so refcounted values like calc may leak). + unsafe fn copy_from_unchecked(&mut self, other: &T) { + let (unit, union) = self.values_mut(); + *unit = other.unit(); + *union = other.union(); + } + + /// Useful for initializing uninits, given that `set_value` may segfault on + /// uninits. + fn leaky_set_null(&mut self) { + use crate::gecko_bindings::structs::nsStyleUnit::*; + unsafe { + let (unit, union) = self.values_mut(); + *unit = eStyleUnit_Null; + *union.mInt.as_mut() = 0; + } + } + + #[inline(always)] + /// Sets the inner value. + fn set_value(&mut self, value: CoordDataValue) { + use self::CoordDataValue::*; + use crate::gecko_bindings::structs::nsStyleUnit::*; + self.reset(); + unsafe { + let (unit, union) = self.values_mut(); + match value { + Null => { + *unit = eStyleUnit_Null; + *union.mInt.as_mut() = 0; + }, + Normal => { + *unit = eStyleUnit_Normal; + *union.mInt.as_mut() = 0; + }, + Auto => { + *unit = eStyleUnit_Auto; + *union.mInt.as_mut() = 0; + }, + None => { + *unit = eStyleUnit_None; + *union.mInt.as_mut() = 0; + }, + Percent(f) => { + *unit = eStyleUnit_Percent; + *union.mFloat.as_mut() = f; + }, + Factor(f) => { + *unit = eStyleUnit_Factor; + *union.mFloat.as_mut() = f; + }, + Degree(f) => { + *unit = eStyleUnit_Degree; + *union.mFloat.as_mut() = f; + }, + FlexFraction(f) => { + *unit = eStyleUnit_FlexFraction; + *union.mFloat.as_mut() = f; + }, + Coord(coord) => { + *unit = eStyleUnit_Coord; + *union.mInt.as_mut() = coord; + }, + Integer(i) => { + *unit = eStyleUnit_Integer; + *union.mInt.as_mut() = i; + }, + Enumerated(i) => { + *unit = eStyleUnit_Enumerated; + *union.mInt.as_mut() = i as i32; + }, + Calc(calc) => { + // Gecko_SetStyleCoordCalcValue changes the unit internally + bindings::Gecko_SetStyleCoordCalcValue(unit, union, calc); + }, + } + } + } + + #[inline] + /// Gets the `Calc` value mutably, asserts in debug builds if the unit is + /// not `Calc`. + unsafe fn as_calc_mut(&mut self) -> &mut nsStyleCoord_Calc { + debug_assert_eq!(self.unit(), nsStyleUnit::eStyleUnit_Calc); + &mut *(*self.union().mPointer.as_mut() as *mut nsStyleCoord_Calc) + } + + #[inline] + /// Does what it promises, if the unit is `calc`, it bumps the reference + /// count _of the calc expression_. + fn addref_if_calc(&mut self) { + unsafe { + if self.unit() == nsStyleUnit::eStyleUnit_Calc { + bindings::Gecko_AddRefCalcArbitraryThread(self.as_calc_mut()); + } + } + } +} +/// A trait to abstract on top of a `nsStyleCoord`-like object. +pub unsafe trait CoordData { + /// Get the unit of this object. + fn unit(&self) -> nsStyleUnit; + /// Get the `nsStyleUnion` for this object. + fn union(&self) -> nsStyleUnion; + + #[inline(always)] + /// Get the appropriate value for this object. + fn as_value(&self) -> CoordDataValue { + use self::CoordDataValue::*; + use crate::gecko_bindings::structs::nsStyleUnit::*; + unsafe { + match self.unit() { + eStyleUnit_Null => Null, + eStyleUnit_Normal => Normal, + eStyleUnit_Auto => Auto, + eStyleUnit_None => None, + eStyleUnit_Percent => Percent(self.get_float()), + eStyleUnit_Factor => Factor(self.get_float()), + eStyleUnit_Degree => Degree(self.get_float()), + eStyleUnit_FlexFraction => FlexFraction(self.get_float()), + eStyleUnit_Coord => Coord(self.get_integer()), + eStyleUnit_Integer => Integer(self.get_integer()), + eStyleUnit_Enumerated => Enumerated(self.get_integer() as u32), + eStyleUnit_Calc => Calc(self.get_calc_value()), + } + } + } + + #[inline] + /// Pretend inner value is a float; obtain it. + unsafe fn get_float(&self) -> f32 { + use crate::gecko_bindings::structs::nsStyleUnit::*; + debug_assert!( + self.unit() == eStyleUnit_Percent || + self.unit() == eStyleUnit_Factor || + self.unit() == eStyleUnit_Degree || + self.unit() == eStyleUnit_FlexFraction + ); + *self.union().mFloat.as_ref() + } + + #[inline] + /// Pretend inner value is an int; obtain it. + unsafe fn get_integer(&self) -> i32 { + use crate::gecko_bindings::structs::nsStyleUnit::*; + debug_assert!( + self.unit() == eStyleUnit_Coord || + self.unit() == eStyleUnit_Integer || + self.unit() == eStyleUnit_Enumerated + ); + *self.union().mInt.as_ref() + } + + #[inline] + /// Pretend inner value is a calc; obtain it. + /// Ensure that the unit is Calc before calling this. + unsafe fn get_calc_value(&self) -> nsStyleCoord_CalcValue { + debug_assert_eq!(self.unit(), nsStyleUnit::eStyleUnit_Calc); + (*self.as_calc())._base + } + + #[inline] + /// Pretend the inner value is a calc expression, and obtain it. + unsafe fn as_calc(&self) -> &nsStyleCoord_Calc { + debug_assert_eq!(self.unit(), nsStyleUnit::eStyleUnit_Calc); + &*(*self.union().mPointer.as_ref() as *const nsStyleCoord_Calc) + } +} diff --git a/servo/components/style/properties/gecko.mako.rs b/servo/components/style/properties/gecko.mako.rs index 09082c518a6c..fce88b6f5aae 100644 --- a/servo/components/style/properties/gecko.mako.rs +++ b/servo/components/style/properties/gecko.mako.rs @@ -36,6 +36,7 @@ use crate::gecko_bindings::bindings::Gecko_SetNullImageValue; use crate::gecko_bindings::structs; use crate::gecko_bindings::structs::nsCSSPropertyID; use crate::gecko_bindings::structs::mozilla::PseudoStyleType; +use crate::gecko_bindings::sugar::ns_style_coord::CoordDataMut; use crate::gecko_bindings::sugar::refptr::RefPtr; use crate::gecko::values::round_border_to_device_pixels; use crate::logical_geometry::WritingMode; @@ -1074,6 +1075,7 @@ fn static_assert() { skip_longhands="${skip_position_longhands} order align-content justify-content align-self justify-self align-items justify-items + grid-auto-rows grid-auto-columns grid-auto-flow grid-template-rows grid-template-columns"> % for side in SIDES: @@ -1124,13 +1126,33 @@ fn static_assert() { ${impl_simple_copy('order', 'mOrder')} % for kind in ["rows", "columns"]: + pub fn set_grid_auto_${kind}(&mut self, v: longhands::grid_auto_${kind}::computed_value::T) { + let gecko = &mut *self.gecko; + v.to_gecko_style_coords(&mut gecko.mGridAuto${kind.title()}Min, + &mut gecko.mGridAuto${kind.title()}Max) + } + + pub fn copy_grid_auto_${kind}_from(&mut self, other: &Self) { + self.gecko.mGridAuto${kind.title()}Min.copy_from(&other.gecko.mGridAuto${kind.title()}Min); + self.gecko.mGridAuto${kind.title()}Max.copy_from(&other.gecko.mGridAuto${kind.title()}Max); + } + + pub fn reset_grid_auto_${kind}(&mut self, other: &Self) { + self.copy_grid_auto_${kind}_from(other) + } + + pub fn clone_grid_auto_${kind}(&self) -> longhands::grid_auto_${kind}::computed_value::T { + crate::values::generics::grid::TrackSize::from_gecko_style_coords(&self.gecko.mGridAuto${kind.title()}Min, + &self.gecko.mGridAuto${kind.title()}Max) + } + pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) { <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %> use crate::gecko_bindings::structs::nsTArray; use std::usize; use crate::values::CustomIdent; use crate::values::generics::grid::TrackListType::Auto; - use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, TrackListValue, MAX_GRID_LINE}; + use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, MAX_GRID_LINE}; #[inline] fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray>) { @@ -1189,19 +1211,20 @@ fn static_assert() { let mut line_names = track.line_names.into_iter(); let mut values_iter = track.values.into_iter(); { - for (i, track_size) in value.mTrackSizingFunctions.iter_mut().enumerate().take(max_lines) { + let min_max_iter = value.mMinTrackSizingFunctions.iter_mut() + .zip(value.mMaxTrackSizingFunctions.iter_mut()); + for (i, (gecko_min, gecko_max)) in min_max_iter.enumerate().take(max_lines) { let name_list = line_names.next().expect("expected line-names"); set_line_names(&name_list, &mut value.mLineNameLists[i]); - *track_size = if i == auto_idx { - auto_track_size.take().expect("expected for ") - } else { - match values_iter.next().expect("expected value") { - TrackListValue::TrackSize(size) => size, - // FIXME(emilio): This shouldn't be - // representable in the first place. - TrackListValue::TrackRepeat(..) => unreachable!("Shouldn't have track-repeats in computed track lists"), - } - }; + if i == auto_idx { + let track_size = auto_track_size.take() + .expect("expected for "); + track_size.to_gecko_style_coords(gecko_min, gecko_max); + continue + } + + let track_size = values_iter.next().expect("expected value"); + track_size.to_gecko_style_coords(gecko_min, gecko_max); } } @@ -1256,7 +1279,7 @@ fn static_assert() { use crate::gecko_bindings::structs::nsTArray; use crate::values::CustomIdent; use crate::values::generics::grid::{GridTemplateComponent, LineNameList, RepeatCount}; - use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat}; + use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat, TrackSize}; let value = match unsafe { ${self_grid}.mPtr.as_ref() } { None => return GridTemplateComponent::None, @@ -1298,8 +1321,13 @@ fn static_assert() { let mut auto_repeat = None; let mut list_type = TrackListType::Normal; let line_names = to_line_names_vec(&value.mLineNameLists).into_boxed_slice(); - let mut values = Vec::with_capacity(value.mTrackSizingFunctions.len()); - for (i, track_size) in value.mTrackSizingFunctions.iter().enumerate() { + let mut values = Vec::with_capacity(value.mMinTrackSizingFunctions.len()); + + let min_max_iter = value.mMinTrackSizingFunctions.iter() + .zip(value.mMaxTrackSizingFunctions.iter()); + for (i, (gecko_min, gecko_max)) in min_max_iter.enumerate() { + let track_size = TrackSize::from_gecko_style_coords(gecko_min, gecko_max); + if i == repeat_auto_index { list_type = TrackListType::Auto(repeat_auto_index as u16); @@ -1318,11 +1346,11 @@ fn static_assert() { vec.into_boxed_slice() }; - let track_sizes = vec!(track_size.clone()); + let track_sizes = vec!(track_size); auto_repeat = Some(TrackRepeat{count, line_names, track_sizes}); } else { - values.push(TrackListValue::TrackSize(track_size.clone())); + values.push(TrackListValue::TrackSize(track_size)); } } diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs index 620d4e8d2e28..6fcb4f3a4a85 100644 --- a/servo/components/style/values/computed/mod.rs +++ b/servo/components/style/values/computed/mod.rs @@ -7,8 +7,8 @@ use self::transform::DirectionVector; use super::animated::ToAnimatedValue; use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent; -use super::generics::grid::{GenericGridLine, GenericTrackBreadth}; -use super::generics::grid::{TrackList as GenericTrackList, GenericTrackSize}; +use super::generics::grid::{GenericGridLine, TrackBreadth as GenericTrackBreadth}; +use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize}; use super::generics::transform::IsParallelTo; use super::generics::{self, GreaterThanOrEqualToOne, NonNegative, ZeroToOne}; use super::specified; diff --git a/servo/components/style/values/generics/grid.rs b/servo/components/style/values/generics/grid.rs index c3e761c51962..3504278cfb86 100644 --- a/servo/components/style/values/generics/grid.rs +++ b/servo/components/style/values/generics/grid.rs @@ -7,6 +7,7 @@ use crate::{Atom, Zero}; use crate::parser::{Parse, ParserContext}; +use crate::values::computed::{Context, ToComputedValue}; use crate::values::specified; use crate::values::specified::grid::parse_line_names; use crate::values::{CSSFloat, CustomIdent}; @@ -179,12 +180,33 @@ impl Parse for GridLine { } } +#[allow(missing_docs)] +#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))] +#[derive( + Animate, + Clone, + Copy, + Debug, + Eq, + MallocSizeOf, + Parse, + PartialEq, + SpecifiedValueInfo, + ToComputedValue, + ToCss, + ToResolvedValue, + ToShmem, +)] +pub enum TrackKeyword { + Auto, + MaxContent, + MinContent, +} + /// A track breadth for explicit grid track sizing. It's generic solely to /// avoid re-implementing it for the computed type. /// /// -/// -/// cbindgen:derive-tagged-enum-copy-constructor=true #[derive( Animate, Clone, @@ -197,23 +219,16 @@ impl Parse for GridLine { ToResolvedValue, ToShmem, )] -#[repr(C, u8)] -pub enum GenericTrackBreadth { +pub enum TrackBreadth { /// The generic type is almost always a non-negative `` Breadth(L), /// A flex fraction specified in `fr` units. #[css(dimension)] Fr(CSSFloat), - /// `auto` - Auto, - /// `min-content` - MinContent, - /// `max-content` - MaxContent, + /// One of the track-sizing keywords (`auto`, `min-content`, `max-content`) + Keyword(TrackKeyword), } -pub use self::GenericTrackBreadth as TrackBreadth; - impl TrackBreadth { /// Check whether this is a `` (i.e., it only has ``) /// @@ -228,31 +243,23 @@ impl TrackBreadth { /// generic only to avoid code bloat. It only takes `` /// /// -/// -/// cbindgen:derive-tagged-enum-copy-constructor=true -#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)] -#[repr(C, u8)] -pub enum GenericTrackSize { +#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToResolvedValue, ToShmem)] +pub enum TrackSize { /// A flexible `` - Breadth(GenericTrackBreadth), + Breadth(TrackBreadth), /// A `minmax` function for a range over an inflexible `` /// and a flexible `` /// /// #[css(function)] - Minmax(GenericTrackBreadth, GenericTrackBreadth), + Minmax(TrackBreadth, TrackBreadth), /// A `fit-content` function. /// - /// This stores a TrackBreadth for convenience, but it can only be a - /// LengthPercentage. - /// /// #[css(function)] - FitContent(GenericTrackBreadth), + FitContent(L), } -pub use self::GenericTrackSize as TrackSize; - impl TrackSize { /// Check whether this is a `` /// @@ -281,7 +288,7 @@ impl TrackSize { impl Default for TrackSize { fn default() -> Self { - TrackSize::Breadth(TrackBreadth::Auto) + TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto)) } } @@ -302,7 +309,7 @@ impl ToCss for TrackSize { TrackSize::Minmax(ref min, ref max) => { // According to gecko minmax(auto, ) is equivalent to , // and both are serialized as . - if let TrackBreadth::Auto = *min { + if let TrackBreadth::Keyword(TrackKeyword::Auto) = *min { if let TrackBreadth::Fr(_) = *max { return max.to_css(dest); } @@ -323,6 +330,48 @@ impl ToCss for TrackSize { } } +impl ToComputedValue for TrackSize { + type ComputedValue = TrackSize; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + match *self { + TrackSize::Breadth(TrackBreadth::Fr(ref f)) => { + // outside `minmax()` expands to `mimmax(auto, )` + // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-flex + // FIXME(nox): This sounds false, the spec just says that + // implies `minmax(auto, )`, not that it should be changed + // into `minmax` at computed value time. + TrackSize::Minmax( + TrackBreadth::Keyword(TrackKeyword::Auto), + TrackBreadth::Fr(f.to_computed_value(context)), + ) + }, + TrackSize::Breadth(ref b) => TrackSize::Breadth(b.to_computed_value(context)), + TrackSize::Minmax(ref b1, ref b2) => { + TrackSize::Minmax(b1.to_computed_value(context), b2.to_computed_value(context)) + }, + TrackSize::FitContent(ref lp) => TrackSize::FitContent(lp.to_computed_value(context)), + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + match *computed { + TrackSize::Breadth(ref b) => { + TrackSize::Breadth(ToComputedValue::from_computed_value(b)) + }, + TrackSize::Minmax(ref b1, ref b2) => TrackSize::Minmax( + ToComputedValue::from_computed_value(b1), + ToComputedValue::from_computed_value(b2), + ), + TrackSize::FitContent(ref lp) => { + TrackSize::FitContent(ToComputedValue::from_computed_value(lp)) + }, + } + } +} + /// Helper function for serializing identifiers with a prefix and suffix, used /// for serializing (in grid). pub fn concat_serialize_idents( diff --git a/servo/components/style/values/specified/grid.rs b/servo/components/style/values/specified/grid.rs index edc570d639a1..d91ae744d632 100644 --- a/servo/components/style/values/specified/grid.rs +++ b/servo/components/style/values/specified/grid.rs @@ -8,7 +8,7 @@ use crate::parser::{Parse, ParserContext}; use crate::values::computed::{self, Context, ToComputedValue}; use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth}; -use crate::values::generics::grid::{LineNameList, TrackRepeat, TrackSize}; +use crate::values::generics::grid::{LineNameList, TrackKeyword, TrackRepeat, TrackSize}; use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue}; use crate::values::specified::{Integer, LengthPercentage}; use crate::values::{CSSFloat, CustomIdent}; @@ -27,34 +27,11 @@ pub fn parse_flex<'i, 't>(input: &mut Parser<'i, 't>) -> Result TrackBreadth { - fn parse_keyword<'i, 't>( - input: &mut Parser<'i, 't>, - ) -> Result> { - #[derive(Parse)] - enum TrackKeyword { - Auto, - MaxContent, - MinContent, - } - - Ok(match TrackKeyword::parse(input)? { - TrackKeyword::Auto => TrackBreadth::Auto, - TrackKeyword::MaxContent => TrackBreadth::MaxContent, - TrackKeyword::MinContent => TrackBreadth::MinContent, - }) - } -} - impl Parse for TrackBreadth { fn parse<'i, 't>( context: &ParserContext, input: &mut Parser<'i, 't>, ) -> Result> { - // FIXME: This and other callers in this file should use - // NonNegativeLengthPercentage instead. - // - // Though it seems these cannot be animated so it's ~ok. if let Ok(lp) = input.try(|i| LengthPercentage::parse_non_negative(context, i)) { return Ok(TrackBreadth::Breadth(lp)); } @@ -63,7 +40,7 @@ impl Parse for TrackBreadth { return Ok(TrackBreadth::Fr(f)); } - Self::parse_keyword(input) + TrackKeyword::parse(input).map(TrackBreadth::Keyword) } } @@ -81,7 +58,10 @@ impl Parse for TrackSize { let inflexible_breadth = match input.try(|i| LengthPercentage::parse_non_negative(context, i)) { Ok(lp) => TrackBreadth::Breadth(lp), - Err(..) => TrackBreadth::parse_keyword(input)?, + Err(..) => { + let keyword = TrackKeyword::parse(input)?; + TrackBreadth::Keyword(keyword) + }, }; input.expect_comma()?; @@ -94,7 +74,7 @@ impl Parse for TrackSize { input.expect_function_matching("fit-content")?; let lp = input.parse_nested_block(|i| LengthPercentage::parse_non_negative(context, i))?; - Ok(TrackSize::FitContent(TrackBreadth::Breadth(lp))) + Ok(TrackSize::FitContent(lp)) } } diff --git a/servo/ports/geckolib/cbindgen.toml b/servo/ports/geckolib/cbindgen.toml index 0ca3e7efd4d5..b2694cbfb9c2 100644 --- a/servo/ports/geckolib/cbindgen.toml +++ b/servo/ports/geckolib/cbindgen.toml @@ -158,8 +158,6 @@ include = [ "Gradient", "GridTemplateAreas", "GridLine", - "TrackSize", - "TrackBreadth", ] item_types = ["enums", "structs", "typedefs", "functions", "constants"] renaming_overrides_prefixing = true @@ -221,6 +219,7 @@ renaming_overrides_prefixing = true """ "LengthPercentage" = """ + // Defined in nsStyleCoord.h static constexpr inline StyleLengthPercentage Zero(); static inline StyleLengthPercentage FromAppUnits(nscoord); static inline StyleLengthPercentage FromPixels(CSSCoord); @@ -291,6 +290,7 @@ renaming_overrides_prefixing = true """ "Rect" = """ + // Defined in nsStyleCoord.h template inline bool All(Predicate) const; template inline bool Any(Predicate) const; @@ -607,24 +607,3 @@ renaming_overrides_prefixing = true // The line name, or nsGkAtoms::_empty if not present. inline nsAtom* LineName() const; """ - -"GenericTrackBreadth" = """ - private: - // Private default constructor without initialization so that the helper - // constructor functions still work as expected. They take care of - // initializing the fields properly. - StyleGenericTrackBreadth() {} - public: - inline bool HasPercent() const; -""" - -"GenericTrackSize" = """ - private: - // Private default constructor without initialization so that the helper - // constructor functions still work as expected. They take care of - // initializing the fields properly. - StyleGenericTrackSize() {} - public: - inline const StyleGenericTrackBreadth& GetMin() const; - inline const StyleGenericTrackBreadth& GetMax() const; -"""