diff options
Diffstat (limited to 'layout/style/nsStyleStruct.h')
-rw-r--r-- | layout/style/nsStyleStruct.h | 2066 |
1 files changed, 2066 insertions, 0 deletions
diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h new file mode 100644 index 0000000000..88b88e7312 --- /dev/null +++ b/layout/style/nsStyleStruct.h @@ -0,0 +1,2066 @@ +/* -*- 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/. */ + +/* + * structs that contain the data provided by ComputedStyle, the + * internal API for computed style data for an element + */ + +#ifndef nsStyleStruct_h___ +#define nsStyleStruct_h___ + +#include "mozilla/Attributes.h" +#include "mozilla/Maybe.h" +#include "mozilla/ServoStyleConstsInlines.h" +#include "mozilla/StaticPrefs_layout.h" +#include "mozilla/UniquePtr.h" +#include "nsColor.h" +#include "nsCoord.h" +#include "nsMargin.h" +#include "nsFont.h" +#include "nsStyleAutoArray.h" +#include "nsStyleConsts.h" +#include "nsChangeHint.h" +#include "nsTimingFunction.h" +#include "nsTArray.h" +#include "imgIContainer.h" +#include "imgRequestProxy.h" +#include "CounterStyleManager.h" +#include <cstddef> // offsetof() +#include "X11UndefineNone.h" + +class nsIFrame; +class nsIURI; +class nsTextFrame; +struct nsStyleDisplay; +struct nsStyleVisibility; +namespace mozilla { +class ComputedStyle; + +} // namespace mozilla + +namespace mozilla { + +using Position = StylePosition; + +template <> +inline bool StylePosition::HasPercent() const { + return horizontal.HasPercent() || vertical.HasPercent(); +} + +/** + * True if the effective background image position described by this depends on + * the size of the corresponding frame. + */ +template <> +inline bool StylePosition::DependsOnPositioningAreaSize() const { + return HasPercent(); +} + +template <> +inline Position Position::FromPercentage(float aPercent) { + return {LengthPercentage::FromPercentage(aPercent), + LengthPercentage::FromPercentage(aPercent)}; +} + +} // namespace mozilla + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleFont { + nsStyleFont(const nsStyleFont& aStyleFont); + explicit nsStyleFont(const mozilla::dom::Document&); + MOZ_COUNTED_DTOR(nsStyleFont) + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleFont& aNewData) const; + + /** + * Return a given size multiplied by the current text zoom factor (in + * aPresContext). + * + * The size is allowed to be negative, but the caller is expected to deal with + * negative results. + */ + static mozilla::Length ZoomText(const mozilla::dom::Document&, + mozilla::Length); + + nsFont mFont; + + // Our "computed size". Can be different from mFont.size which is our "actual + // size" and is enforced to be >= the user's preferred min-size. mFont.size + // should be used for display purposes while mSize is the value to return in + // getComputedStyle() for example. + mozilla::NonNegativeLength mSize; + + // In stylo these three track whether the size is keyword-derived + // and if so if it has been modified by a factor/offset + float mFontSizeFactor; + mozilla::Length mFontSizeOffset; + mozilla::StyleFontSizeKeyword mFontSizeKeyword; + + mozilla::StyleGenericFontFamily mGenericID; + + // math-depth support (used for MathML scriptlevel) + int8_t mMathDepth; + // MathML mathvariant support + uint8_t mMathVariant; + // math-style support (used for MathML displaystyle) + uint8_t mMathStyle; + + // allow different min font-size for certain cases + uint8_t mMinFontSizeRatio; // percent * 100 + + // was mLanguage set based on a lang attribute in the document? + bool mExplicitLanguage; + + // should calls to ZoomText() and UnZoomText() be made to the font + // size on this nsStyleFont? Also used to prevent SVG text from being + // affected by minimum font size pref. + bool mAllowZoomAndMinSize; + + // The value mSize would have had if scriptminsize had never been applied + mozilla::NonNegativeLength mScriptUnconstrainedSize; + mozilla::Length mScriptMinSize; + float mScriptSizeMultiplier; + RefPtr<nsAtom> mLanguage; +}; + +// TODO(emilio, bug 1564526): Evaluate whether this is still needed. +struct CachedBorderImageData { + ~CachedBorderImageData() { PurgeCachedImages(); } + + // Caller are expected to ensure that the value of aSize is different from the + // cached one since the method won't do the check. + void SetCachedSVGViewportSize(const mozilla::Maybe<nsSize>& aSize) { + mCachedSVGViewportSize = aSize; + } + + const mozilla::Maybe<nsSize>& GetCachedSVGViewportSize() const { + return mCachedSVGViewportSize; + } + + void PurgeCachedImages(); + + void SetSubImage(uint8_t aIndex, imgIContainer* aSubImage) { + mSubImages.EnsureLengthAtLeast(aIndex + 1); + mSubImages[aIndex] = aSubImage; + } + imgIContainer* GetSubImage(uint8_t aIndex) { + return mSubImages.SafeElementAt(aIndex); + } + + // These methods are used for the caller to caches the sub images created + // during a border-image paint operation + void PurgeCacheForViewportChange( + const mozilla::Maybe<nsSize>& aSVGViewportSize, + const bool aHasIntrinsicRatio); + + private: + // If this is a SVG border-image, we save the size of the SVG viewport that + // we used when rasterizing any cached border-image subimages. (The viewport + // size matters for percent-valued sizes & positions in inner SVG doc). + mozilla::Maybe<nsSize> mCachedSVGViewportSize; + nsTArray<RefPtr<imgIContainer>> mSubImages; +}; + +struct nsStyleImageLayers { + enum class LayerType : uint8_t { Background = 0, Mask }; + + explicit nsStyleImageLayers(LayerType aType); + nsStyleImageLayers(const nsStyleImageLayers& aSource); + MOZ_COUNTED_DTOR(nsStyleImageLayers) + + struct Repeat { + mozilla::StyleImageLayerRepeat mXRepeat, mYRepeat; + + // Initialize nothing + Repeat() = default; + + bool IsInitialValue() const { + return mXRepeat == mozilla::StyleImageLayerRepeat::Repeat && + mYRepeat == mozilla::StyleImageLayerRepeat::Repeat; + } + + bool DependsOnPositioningAreaSize() const { + return mXRepeat == mozilla::StyleImageLayerRepeat::Space || + mYRepeat == mozilla::StyleImageLayerRepeat::Space; + } + + // Initialize to initial values + void SetInitialValues() { + mXRepeat = mozilla::StyleImageLayerRepeat::Repeat; + mYRepeat = mozilla::StyleImageLayerRepeat::Repeat; + } + + bool operator==(const Repeat& aOther) const { + return mXRepeat == aOther.mXRepeat && mYRepeat == aOther.mYRepeat; + } + bool operator!=(const Repeat& aOther) const { return !(*this == aOther); } + }; + + struct Layer { + typedef mozilla::StyleGeometryBox StyleGeometryBox; + typedef mozilla::StyleImageLayerAttachment StyleImageLayerAttachment; + typedef mozilla::StyleBackgroundSize StyleBackgroundSize; + + mozilla::StyleImage mImage; + mozilla::Position mPosition; + StyleBackgroundSize mSize; + StyleGeometryBox mClip; + MOZ_INIT_OUTSIDE_CTOR StyleGeometryBox mOrigin; + + // This property is used for background layer only. + // For a mask layer, it should always be the initial value, which is + // StyleImageLayerAttachment::Scroll. + StyleImageLayerAttachment mAttachment; + + // This property is used for background layer only. + // For a mask layer, it should always be the initial value, which is + // StyleBlend::Normal. + mozilla::StyleBlend mBlendMode; + + // This property is used for mask layer only. + // For a background layer, it should always be the initial value, which is + // StyleMaskComposite::Add. + mozilla::StyleMaskComposite mComposite; + + // mask-only property. This property is used for mask layer only. For a + // background layer, it should always be the initial value, which is + // StyleMaskMode::MatchSource. + mozilla::StyleMaskMode mMaskMode; + + Repeat mRepeat; + + // This constructor does not initialize mRepeat or mOrigin and Initialize() + // must be called to do that. + Layer(); + ~Layer(); + + // Initialize mRepeat and mOrigin by specified layer type + void Initialize(LayerType aType); + + void ResolveImage(mozilla::dom::Document& aDocument, + const Layer* aOldLayer) { + mImage.ResolveImage(aDocument, aOldLayer ? &aOldLayer->mImage : nullptr); + } + + // True if the rendering of this layer might change when the size + // of the background positioning area changes. This is true for any + // non-solid-color background whose position or size depends on + // the size of the positioning area. It's also true for SVG images + // whose root <svg> node has a viewBox. + bool RenderingMightDependOnPositioningAreaSizeChange() const; + + // Compute the change hint required by changes in just this layer. + nsChangeHint CalcDifference(const Layer& aNewLayer) const; + + // An equality operator that compares the images using URL-equality + // rather than pointer-equality. + bool operator==(const Layer& aOther) const; + bool operator!=(const Layer& aOther) const { return !(*this == aOther); } + }; + + // The (positive) number of computed values of each property, since + // the lengths of the lists are independent. + uint32_t mAttachmentCount; + uint32_t mClipCount; + uint32_t mOriginCount; + uint32_t mRepeatCount; + uint32_t mPositionXCount; + uint32_t mPositionYCount; + uint32_t mImageCount; + uint32_t mSizeCount; + uint32_t mMaskModeCount; + uint32_t mBlendModeCount; + uint32_t mCompositeCount; + + // Layers are stored in an array, matching the top-to-bottom order in + // which they are specified in CSS. The number of layers to be used + // should come from the background-image property. We create + // additional |Layer| objects for *any* property, not just + // background-image. This means that the bottommost layer that + // callers in layout care about (which is also the one whose + // background-clip applies to the background-color) may not be last + // layer. In layers below the bottom layer, properties will be + // uninitialized unless their count, above, indicates that they are + // present. + nsStyleAutoArray<Layer> mLayers; + + const Layer& BottomLayer() const { return mLayers[mImageCount - 1]; } + + void ResolveImages(mozilla::dom::Document& aDocument, + const nsStyleImageLayers* aOldLayers) { + for (uint32_t i = 0; i < mImageCount; ++i) { + const Layer* oldLayer = (aOldLayers && aOldLayers->mLayers.Length() > i) + ? &aOldLayers->mLayers[i] + : nullptr; + mLayers[i].ResolveImage(aDocument, oldLayer); + } + } + + // Fill unspecified layers by cycling through their values + // till they all are of length aMaxItemCount + void FillAllLayers(uint32_t aMaxItemCount); + + nsChangeHint CalcDifference(const nsStyleImageLayers& aNewLayers, + nsStyleImageLayers::LayerType aType) const; + + nsStyleImageLayers& operator=(const nsStyleImageLayers& aOther); + nsStyleImageLayers& operator=(nsStyleImageLayers&& aOther) = default; + bool operator==(const nsStyleImageLayers& aOther) const; + + static const nsCSSPropertyID kBackgroundLayerTable[]; + static const nsCSSPropertyID kMaskLayerTable[]; + +#define NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(var_, layers_) \ + for (uint32_t var_ = (layers_).mImageCount; var_-- != 0;) +#define NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT_WITH_RANGE(var_, layers_, \ + start_, count_) \ + NS_ASSERTION( \ + (int32_t)(start_) >= 0 && (uint32_t)(start_) < (layers_).mImageCount, \ + "Invalid layer start!"); \ + NS_ASSERTION((count_) > 0 && (count_) <= (start_) + 1, \ + "Invalid layer range!"); \ + for (uint32_t var_ = (start_) + 1; \ + var_-- != (uint32_t)((start_) + 1 - (count_));) +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBackground { + explicit nsStyleBackground(const mozilla::dom::Document&); + nsStyleBackground(const nsStyleBackground& aOther); + ~nsStyleBackground(); + + // Resolves and tracks the images in mImage. Only called with a Servo-backed + // style system, where those images must be resolved later than the OMT + // nsStyleBackground constructor call. + void TriggerImageLoads(mozilla::dom::Document&, const nsStyleBackground*); + static constexpr bool kHasTriggerImageLoads = true; + + nsChangeHint CalcDifference(const nsStyleBackground& aNewData) const; + + // Return the background color as nscolor. + nscolor BackgroundColor(const nsIFrame* aFrame) const; + nscolor BackgroundColor(mozilla::ComputedStyle* aStyle) const; + + // True if this background is completely transparent. + bool IsTransparent(const nsIFrame* aFrame) const; + bool IsTransparent(mozilla::ComputedStyle* aStyle) const; + + // We have to take slower codepaths for fixed background attachment, + // but we don't want to do that when there's no image. + // Not inline because it uses an nsCOMPtr<imgIRequest> + // FIXME: Should be in nsStyleStructInlines.h. + bool HasFixedBackground(nsIFrame* aFrame) const; + + // Checks to see if this has a non-empty image with "local" attachment. + // This is defined in nsStyleStructInlines.h. + inline bool HasLocalBackground() const; + + const nsStyleImageLayers::Layer& BottomLayer() const { + return mImage.BottomLayer(); + } + + nsStyleImageLayers mImage; + mozilla::StyleColor mBackgroundColor; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleMargin { + explicit nsStyleMargin(const mozilla::dom::Document&); + nsStyleMargin(const nsStyleMargin& aMargin); + MOZ_COUNTED_DTOR(nsStyleMargin) + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleMargin& aNewData) const; + + bool GetMargin(nsMargin& aMargin) const { + bool convertsToLength = mMargin.All( + [](const auto& aLength) { return aLength.ConvertsToLength(); }); + + if (!convertsToLength) { + return false; + } + + for (const auto side : mozilla::AllPhysicalSides()) { + aMargin.Side(side) = mMargin.Get(side).AsLengthPercentage().ToLength(); + } + return true; + } + + nsMargin GetScrollMargin() const { + return nsMargin(mScrollMargin.Get(mozilla::eSideTop).ToAppUnits(), + mScrollMargin.Get(mozilla::eSideRight).ToAppUnits(), + mScrollMargin.Get(mozilla::eSideBottom).ToAppUnits(), + mScrollMargin.Get(mozilla::eSideLeft).ToAppUnits()); + } + + // Return true if either the start or end side in the axis is 'auto'. + // (defined in WritingModes.h since we need the full WritingMode type) + inline bool HasBlockAxisAuto(mozilla::WritingMode aWM) const; + inline bool HasInlineAxisAuto(mozilla::WritingMode aWM) const; + inline bool HasAuto(mozilla::LogicalAxis, mozilla::WritingMode) const; + + mozilla::StyleRect<mozilla::LengthPercentageOrAuto> mMargin; + mozilla::StyleRect<mozilla::StyleLength> mScrollMargin; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePadding { + explicit nsStylePadding(const mozilla::dom::Document&); + nsStylePadding(const nsStylePadding& aPadding); + MOZ_COUNTED_DTOR(nsStylePadding) + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStylePadding& aNewData) const; + + mozilla::StyleRect<mozilla::NonNegativeLengthPercentage> mPadding; + mozilla::StyleRect<mozilla::NonNegativeLengthPercentageOrAuto> mScrollPadding; + + inline bool IsWidthDependent() const { + return !mPadding.All( + [](const auto& aLength) { return aLength.ConvertsToLength(); }); + } + + bool GetPadding(nsMargin& aPadding) const { + if (IsWidthDependent()) { + return false; + } + + for (const auto side : mozilla::AllPhysicalSides()) { + // Clamp negative calc() to 0. + aPadding.Side(side) = std::max(mPadding.Get(side).ToLength(), 0); + } + return true; + } +}; + +// Border widths are rounded to the nearest-below integer number of pixels, +// but values between zero and one device pixels are always rounded up to +// one device pixel. +#define NS_ROUND_BORDER_TO_PIXELS(l, tpp) \ + ((l) == 0) ? 0 : std::max((tpp), (l) / (tpp) * (tpp)) + +// Returns if the given border style type is visible or not +static bool IsVisibleBorderStyle(mozilla::StyleBorderStyle aStyle) { + return (aStyle != mozilla::StyleBorderStyle::None && + aStyle != mozilla::StyleBorderStyle::Hidden); +} + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleBorder { + explicit nsStyleBorder(const mozilla::dom::Document&); + nsStyleBorder(const nsStyleBorder& aBorder); + ~nsStyleBorder(); + + // Resolves and tracks mBorderImageSource. Only called with a Servo-backed + // style system, where those images must be resolved later than the OMT + // nsStyleBorder constructor call. + void TriggerImageLoads(mozilla::dom::Document&, const nsStyleBorder*); + static constexpr bool kHasTriggerImageLoads = true; + + nsChangeHint CalcDifference(const nsStyleBorder& aNewData) const; + + // Return whether aStyle is a visible style. Invisible styles cause + // the relevant computed border width to be 0. + // Note that this does *not* consider the effects of 'border-image': + // if border-style is none, but there is a loaded border image, + // HasVisibleStyle will be false even though there *is* a border. + bool HasVisibleStyle(mozilla::Side aSide) const { + return IsVisibleBorderStyle(mBorderStyle[aSide]); + } + + // aBorderWidth is in twips + void SetBorderWidth(mozilla::Side aSide, nscoord aBorderWidth) { + nscoord roundedWidth = + NS_ROUND_BORDER_TO_PIXELS(aBorderWidth, mTwipsPerPixel); + mBorder.Side(aSide) = roundedWidth; + if (HasVisibleStyle(aSide)) { + mComputedBorder.Side(aSide) = roundedWidth; + } + } + + // Get the computed border (plus rounding). This does consider the + // effects of 'border-style: none', but does not consider + // 'border-image'. + const nsMargin& GetComputedBorder() const { return mComputedBorder; } + + bool HasBorder() const { + return mComputedBorder != nsMargin(0, 0, 0, 0) || + !mBorderImageSource.IsNone(); + } + + // Get the actual border width for a particular side, in appunits. Note that + // this is zero if and only if there is no border to be painted for this + // side. That is, this value takes into account the border style and the + // value is rounded to the nearest device pixel by NS_ROUND_BORDER_TO_PIXELS. + nscoord GetComputedBorderWidth(mozilla::Side aSide) const { + return GetComputedBorder().Side(aSide); + } + + mozilla::StyleBorderStyle GetBorderStyle(mozilla::Side aSide) const { + NS_ASSERTION(aSide <= mozilla::eSideLeft, "bad side"); + return mBorderStyle[aSide]; + } + + void SetBorderStyle(mozilla::Side aSide, mozilla::StyleBorderStyle aStyle) { + NS_ASSERTION(aSide <= mozilla::eSideLeft, "bad side"); + mBorderStyle[aSide] = aStyle; + mComputedBorder.Side(aSide) = + (HasVisibleStyle(aSide) ? mBorder.Side(aSide) : 0); + } + + inline bool IsBorderImageSizeAvailable() const { + return mBorderImageSource.IsSizeAvailable(); + } + + nsMargin GetImageOutset() const; + + imgIRequest* GetBorderImageRequest() const { + return mBorderImageSource.GetImageRequest(); + } + + public: + mozilla::StyleBorderRadius mBorderRadius; // coord, percent + mozilla::StyleImage mBorderImageSource; + mozilla::StyleBorderImageWidth mBorderImageWidth; + mozilla::StyleNonNegativeLengthOrNumberRect mBorderImageOutset; + mozilla::StyleBorderImageSlice mBorderImageSlice; // factor, percent + mozilla::StyleBorderImageRepeat mBorderImageRepeatH; + mozilla::StyleBorderImageRepeat mBorderImageRepeatV; + mozilla::StyleFloatEdge mFloatEdge; + mozilla::StyleBoxDecorationBreak mBoxDecorationBreak; + + protected: + mozilla::StyleBorderStyle mBorderStyle[4]; // StyleBorderStyle::* + + public: + // the colors to use for a simple border. + // not used for -moz-border-colors + mozilla::StyleColor mBorderTopColor; + mozilla::StyleColor mBorderRightColor; + mozilla::StyleColor mBorderBottomColor; + mozilla::StyleColor mBorderLeftColor; + + mozilla::StyleColor& BorderColorFor(mozilla::Side aSide) { + switch (aSide) { + case mozilla::eSideTop: + return mBorderTopColor; + case mozilla::eSideRight: + return mBorderRightColor; + case mozilla::eSideBottom: + return mBorderBottomColor; + case mozilla::eSideLeft: + return mBorderLeftColor; + } + MOZ_ASSERT_UNREACHABLE("Unknown side"); + return mBorderTopColor; + } + + const mozilla::StyleColor& BorderColorFor(mozilla::Side aSide) const { + switch (aSide) { + case mozilla::eSideTop: + return mBorderTopColor; + case mozilla::eSideRight: + return mBorderRightColor; + case mozilla::eSideBottom: + return mBorderBottomColor; + case mozilla::eSideLeft: + return mBorderLeftColor; + } + MOZ_ASSERT_UNREACHABLE("Unknown side"); + return mBorderTopColor; + } + + static mozilla::StyleColor nsStyleBorder::*BorderColorFieldFor( + mozilla::Side aSide) { + switch (aSide) { + case mozilla::eSideTop: + return &nsStyleBorder::mBorderTopColor; + case mozilla::eSideRight: + return &nsStyleBorder::mBorderRightColor; + case mozilla::eSideBottom: + return &nsStyleBorder::mBorderBottomColor; + case mozilla::eSideLeft: + return &nsStyleBorder::mBorderLeftColor; + } + MOZ_ASSERT_UNREACHABLE("Unknown side"); + return nullptr; + } + + protected: + // mComputedBorder holds the CSS2.1 computed border-width values. + // In particular, these widths take into account the border-style + // for the relevant side, and the values are rounded to the nearest + // device pixel (which is not part of the definition of computed + // values). The presence or absence of a border-image does not + // affect border-width values. + nsMargin mComputedBorder; + + // mBorder holds the nscoord values for the border widths as they + // would be if all the border-style values were visible (not hidden + // or none). This member exists so that when we create structs + // using the copy constructor during style resolution the new + // structs will know what the specified values of the border were in + // case they have more specific rules setting the border style. + // + // Note that this isn't quite the CSS specified value, since this + // has had the enumerated border widths converted to lengths, and + // all lengths converted to twips. But it's not quite the computed + // value either. The values are rounded to the nearest device pixel. + nsMargin mBorder; + + private: + nscoord mTwipsPerPixel; + + nsStyleBorder& operator=(const nsStyleBorder& aOther) = delete; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleOutline { + explicit nsStyleOutline(const mozilla::dom::Document&); + nsStyleOutline(const nsStyleOutline& aOutline); + MOZ_COUNTED_DTOR(nsStyleOutline) + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleOutline& aNewData) const; + + mozilla::StyleBorderRadius mOutlineRadius; + + // This is the specified value of outline-width, but with length values + // computed to absolute. mActualOutlineWidth stores the outline-width + // value used by layout. (We must store mOutlineWidth for the same + // style struct resolution reasons that we do nsStyleBorder::mBorder; + // see that field's comment.) + nscoord mOutlineWidth; + mozilla::Length mOutlineOffset; + mozilla::StyleColor mOutlineColor; + mozilla::StyleOutlineStyle mOutlineStyle; + + nscoord GetOutlineWidth() const { return mActualOutlineWidth; } + + bool ShouldPaintOutline() const { + if (mOutlineStyle.IsAuto()) { + return true; + } + if (GetOutlineWidth() > 0) { + MOZ_ASSERT( + mOutlineStyle.AsBorderStyle() != mozilla::StyleBorderStyle::None, + "outline-style: none implies outline-width of zero"); + return true; + } + return false; + } + + protected: + // The actual value of outline-width is the computed value (an absolute + // length, forced to zero when outline-style is none) rounded to device + // pixels. This is the value used by layout. + nscoord mActualOutlineWidth; + nscoord mTwipsPerPixel; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleList { + explicit nsStyleList(const mozilla::dom::Document&); + nsStyleList(const nsStyleList& aStyleList); + ~nsStyleList(); + + private: + nsStyleList& operator=(const nsStyleList& aOther) = delete; + + public: + void TriggerImageLoads(mozilla::dom::Document&, const nsStyleList*); + static constexpr bool kHasTriggerImageLoads = true; + + nsChangeHint CalcDifference(const nsStyleList& aNewData, + const nsStyleDisplay& aOldDisplay) const; + + imgRequestProxy* GetListStyleImage() const { + return mListStyleImage.IsUrl() ? mListStyleImage.AsUrl().GetImage() + : nullptr; + } + + nsRect GetImageRegion() const { + if (!mImageRegion.IsRect()) { + return nsRect(); + } + return mImageRegion.AsRect().ToLayoutRect(0); + } + + already_AddRefed<nsIURI> GetListStyleImageURI() const; + + uint8_t mListStylePosition; + + mozilla::CounterStylePtr mCounterStyle; + mozilla::StyleQuotes mQuotes; + mozilla::StyleImageUrlOrNone mListStyleImage; + + // the rect to use within an image. + mozilla::StyleClipRectOrAuto mImageRegion; + // true in an <ol reversed> scope. + mozilla::StyleMozListReversed mMozListReversed; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition { + using LengthPercentageOrAuto = mozilla::LengthPercentageOrAuto; + using Position = mozilla::Position; + template <typename T> + using StyleRect = mozilla::StyleRect<T>; + using StyleSize = mozilla::StyleSize; + using StyleMaxSize = mozilla::StyleMaxSize; + using WritingMode = mozilla::WritingMode; + using LogicalAxis = mozilla::LogicalAxis; + using StyleImplicitGridTracks = mozilla::StyleImplicitGridTracks; + using ComputedStyle = mozilla::ComputedStyle; + using StyleAlignSelf = mozilla::StyleAlignSelf; + using StyleJustifySelf = mozilla::StyleJustifySelf; + + explicit nsStylePosition(const mozilla::dom::Document&); + nsStylePosition(const nsStylePosition& aOther); + ~nsStylePosition(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference( + const nsStylePosition& aNewData, + const nsStyleVisibility& aOldStyleVisibility) const; + + // Returns whether we need to compute an hypothetical position if we were + // absolutely positioned. + bool NeedsHypotheticalPositionIfAbsPos() const { + return (mOffset.Get(mozilla::eSideRight).IsAuto() && + mOffset.Get(mozilla::eSideLeft).IsAuto()) || + (mOffset.Get(mozilla::eSideTop).IsAuto() && + mOffset.Get(mozilla::eSideBottom).IsAuto()); + } + + /** + * Return the used value for 'align-self' given our parent ComputedStyle + * (or null for the root). + */ + StyleAlignSelf UsedAlignSelf(const ComputedStyle*) const; + + /** + * Return the used value for 'justify-self' given our parent ComputedStyle + * aParent (or null for the root). + */ + StyleJustifySelf UsedJustifySelf(const ComputedStyle*) const; + + /** + * Return the used value for 'justify/align-self' in aAxis given our parent + * ComputedStyle aParent (or null for the root). + * (defined in WritingModes.h since we need the full WritingMode type) + */ + inline mozilla::StyleAlignFlags UsedSelfAlignment( + LogicalAxis aAxis, const mozilla::ComputedStyle* aParent) const; + + /** + * Return the used value for 'justify/align-content' in aAxis. + * (defined in WritingModes.h since we need the full WritingMode type) + */ + inline mozilla::StyleContentDistribution UsedContentAlignment( + LogicalAxis aAxis) const; + + /** + * Return the used value for 'align-tracks'/'justify-tracks' for a track + * in the given axis. + * (defined in WritingModes.h since we need the full LogicalAxis type) + */ + inline mozilla::StyleContentDistribution UsedTracksAlignment( + LogicalAxis aAxis, uint32_t aIndex) const; + + // Each entry has the same encoding as *-content, see below. + mozilla::StyleAlignTracks mAlignTracks; + mozilla::StyleJustifyTracks mJustifyTracks; + + Position mObjectPosition; + StyleRect<LengthPercentageOrAuto> mOffset; + StyleSize mWidth; + StyleSize mMinWidth; + StyleMaxSize mMaxWidth; + StyleSize mHeight; + StyleSize mMinHeight; + StyleMaxSize mMaxHeight; + mozilla::StyleFlexBasis mFlexBasis; + StyleImplicitGridTracks mGridAutoColumns; + StyleImplicitGridTracks mGridAutoRows; + mozilla::StyleAspectRatio mAspectRatio; + mozilla::StyleGridAutoFlow mGridAutoFlow; + uint8_t mMasonryAutoFlow; // NS_STYLE_MASONRY_* + + mozilla::StyleAlignContent mAlignContent; + mozilla::StyleAlignItems mAlignItems; + mozilla::StyleAlignSelf mAlignSelf; + mozilla::StyleJustifyContent mJustifyContent; + mozilla::StyleComputedJustifyItems mJustifyItems; + mozilla::StyleJustifySelf mJustifySelf; + mozilla::StyleFlexDirection mFlexDirection; + mozilla::StyleFlexWrap mFlexWrap; + mozilla::StyleObjectFit mObjectFit; + mozilla::StyleBoxSizing mBoxSizing; + int32_t mOrder; + float mFlexGrow; + float mFlexShrink; + mozilla::StyleZIndex mZIndex; + + mozilla::StyleGridTemplateComponent mGridTemplateColumns; + mozilla::StyleGridTemplateComponent mGridTemplateRows; + mozilla::StyleGridTemplateAreas mGridTemplateAreas; + + mozilla::StyleGridLine mGridColumnStart; + mozilla::StyleGridLine mGridColumnEnd; + mozilla::StyleGridLine mGridRowStart; + mozilla::StyleGridLine mGridRowEnd; + mozilla::NonNegativeLengthPercentageOrNormal mColumnGap; + mozilla::NonNegativeLengthPercentageOrNormal mRowGap; + + // Logical-coordinate accessors for width and height properties, + // given a WritingMode value. The definitions of these methods are + // found in WritingModes.h (after the WritingMode class is fully + // declared). + inline const StyleSize& ISize(WritingMode) const; + inline const StyleSize& MinISize(WritingMode) const; + inline const StyleMaxSize& MaxISize(WritingMode) const; + inline const StyleSize& BSize(WritingMode) const; + inline const StyleSize& MinBSize(WritingMode) const; + inline const StyleMaxSize& MaxBSize(WritingMode) const; + inline const StyleSize& Size(LogicalAxis, WritingMode) const; + inline const StyleSize& MinSize(LogicalAxis, WritingMode) const; + inline const StyleMaxSize& MaxSize(LogicalAxis, WritingMode) const; + inline bool ISizeDependsOnContainer(WritingMode) const; + inline bool MinISizeDependsOnContainer(WritingMode) const; + inline bool MaxISizeDependsOnContainer(WritingMode) const; + inline bool BSizeDependsOnContainer(WritingMode) const; + inline bool MinBSizeDependsOnContainer(WritingMode) const; + inline bool MaxBSizeDependsOnContainer(WritingMode) const; + + private: + template <typename SizeOrMaxSize> + static bool ISizeCoordDependsOnContainer(const SizeOrMaxSize& aCoord) { + if (aCoord.IsLengthPercentage()) { + return aCoord.AsLengthPercentage().HasPercent(); + } + + if (!aCoord.IsExtremumLength()) { + return false; + } + + auto keyword = aCoord.AsExtremumLength(); + return keyword == mozilla::StyleExtremumLength::MozFitContent || + keyword == mozilla::StyleExtremumLength::MozAvailable; + } + + template <typename SizeOrMaxSize> + static bool BSizeCoordDependsOnContainer(const SizeOrMaxSize& aCoord) { + return aCoord.IsLengthPercentage() && + aCoord.AsLengthPercentage().HasPercent(); + } +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTextReset { + explicit nsStyleTextReset(const mozilla::dom::Document&); + nsStyleTextReset(const nsStyleTextReset& aOther); + ~nsStyleTextReset(); + static constexpr bool kHasTriggerImageLoads = false; + + // Note the difference between this and + // ComputedStyle::HasTextDecorationLines. + bool HasTextDecorationLines() const { + return mTextDecorationLine != mozilla::StyleTextDecorationLine::NONE && + mTextDecorationLine != + mozilla::StyleTextDecorationLine::COLOR_OVERRIDE; + } + + nsChangeHint CalcDifference(const nsStyleTextReset& aNewData) const; + + mozilla::StyleTextOverflow mTextOverflow; + + mozilla::StyleTextDecorationLine mTextDecorationLine; + uint8_t mTextDecorationStyle; // NS_STYLE_TEXT_DECORATION_STYLE_* + uint8_t mUnicodeBidi; // NS_STYLE_UNICODE_BIDI_* + nscoord mInitialLetterSink; // 0 means normal + float mInitialLetterSize; // 0.0f means normal + mozilla::StyleColor mTextDecorationColor; + mozilla::StyleTextDecorationLength mTextDecorationThickness; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText { + explicit nsStyleText(const mozilla::dom::Document&); + nsStyleText(const nsStyleText& aOther); + ~nsStyleText(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleText& aNewData) const; + + mozilla::StyleRGBA mColor; + mozilla::StyleTextTransform mTextTransform; + mozilla::StyleTextAlign mTextAlign; + mozilla::StyleTextAlignLast mTextAlignLast; + mozilla::StyleTextJustify mTextJustify; + mozilla::StyleWhiteSpace mWhiteSpace; + mozilla::StyleLineBreak mLineBreak = mozilla::StyleLineBreak::Auto; + + private: + mozilla::StyleWordBreak mWordBreak = mozilla::StyleWordBreak::Normal; + mozilla::StyleOverflowWrap mOverflowWrap = mozilla::StyleOverflowWrap::Normal; + + public: + mozilla::StyleHyphens mHyphens; + mozilla::StyleRubyAlign mRubyAlign; + mozilla::StyleRubyPosition mRubyPosition; + mozilla::StyleTextSizeAdjust mTextSizeAdjust; + uint8_t mTextCombineUpright; // NS_STYLE_TEXT_COMBINE_UPRIGHT_* + mozilla::StyleControlCharacterVisibility mControlCharacterVisibility; + uint8_t mTextEmphasisPosition; // NS_STYLE_TEXT_EMPHASIS_POSITION_* + mozilla::StyleTextRendering mTextRendering; + mozilla::StyleColor mTextEmphasisColor; + mozilla::StyleColor mWebkitTextFillColor; + mozilla::StyleColor mWebkitTextStrokeColor; + + mozilla::StyleNonNegativeLengthOrNumber mMozTabSize; + mozilla::LengthPercentage mWordSpacing; + mozilla::StyleLetterSpacing mLetterSpacing; + mozilla::StyleLineHeight mLineHeight; + mozilla::LengthPercentage mTextIndent; + + mozilla::LengthPercentageOrAuto mTextUnderlineOffset; + mozilla::StyleTextDecorationSkipInk mTextDecorationSkipInk; + mozilla::StyleTextUnderlinePosition mTextUnderlinePosition; + + nscoord mWebkitTextStrokeWidth; // coord + + mozilla::StyleArcSlice<mozilla::StyleSimpleShadow> mTextShadow; + mozilla::StyleTextEmphasisStyle mTextEmphasisStyle; + + mozilla::StyleWordBreak EffectiveWordBreak() const { + if (mWordBreak == mozilla::StyleWordBreak::BreakWord) { + return mozilla::StyleWordBreak::Normal; + } + return mWordBreak; + } + + mozilla::StyleOverflowWrap EffectiveOverflowWrap() const { + if (mWordBreak == mozilla::StyleWordBreak::BreakWord) { + return mozilla::StyleOverflowWrap::Anywhere; + } + return mOverflowWrap; + } + + bool WhiteSpaceIsSignificant() const { + return mWhiteSpace == mozilla::StyleWhiteSpace::Pre || + mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap || + mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces || + mWhiteSpace == mozilla::StyleWhiteSpace::PreSpace; + } + + bool WhiteSpaceCanHangOrVisuallyCollapse() const { + // This was originally expressed in nsTextFrame in terms of: + // mWhiteSpace != StyleWhiteSpace::BreakSpaces && + // WhiteSpaceCanWrapStyle() && + // WhiteSpaceIsSignificant() + // which simplifies to: + return mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap; + } + + bool NewlineIsSignificantStyle() const { + return mWhiteSpace == mozilla::StyleWhiteSpace::Pre || + mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap || + mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces || + mWhiteSpace == mozilla::StyleWhiteSpace::PreLine; + } + + bool WhiteSpaceOrNewlineIsSignificant() const { + return mWhiteSpace == mozilla::StyleWhiteSpace::Pre || + mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap || + mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces || + mWhiteSpace == mozilla::StyleWhiteSpace::PreLine || + mWhiteSpace == mozilla::StyleWhiteSpace::PreSpace; + } + + bool TabIsSignificant() const { + return mWhiteSpace == mozilla::StyleWhiteSpace::Pre || + mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap || + mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces; + } + + bool WhiteSpaceCanWrapStyle() const { + return mWhiteSpace == mozilla::StyleWhiteSpace::Normal || + mWhiteSpace == mozilla::StyleWhiteSpace::PreWrap || + mWhiteSpace == mozilla::StyleWhiteSpace::BreakSpaces || + mWhiteSpace == mozilla::StyleWhiteSpace::PreLine; + } + + bool WordCanWrapStyle() const { + if (!WhiteSpaceCanWrapStyle()) { + return false; + } + auto owrap = EffectiveOverflowWrap(); + return owrap == mozilla::StyleOverflowWrap::BreakWord || + owrap == mozilla::StyleOverflowWrap::Anywhere; + } + + bool HasEffectiveTextEmphasis() const { + if (mTextEmphasisStyle.IsNone()) { + return false; + } + if (mTextEmphasisStyle.IsString() && + mTextEmphasisStyle.AsString().AsString().IsEmpty()) { + return false; + } + return true; + } + + mozilla::StyleTextAlign TextAlignForLastLine() const { + switch (mTextAlignLast) { + case mozilla::StyleTextAlignLast::Auto: + // 'text-align-last: auto' is equivalent to the value of the + // 'text-align' property except when 'text-align' is set to 'justify', + // in which case it is 'justify' when 'text-justify' is 'distribute' and + // 'start' otherwise. + // + // XXX: the code below will have to change when we implement + // text-justify + if (mTextAlign == mozilla::StyleTextAlign::Justify) { + return mozilla::StyleTextAlign::Start; + } + return mTextAlign; + case mozilla::StyleTextAlignLast::Center: + return mozilla::StyleTextAlign::Center; + case mozilla::StyleTextAlignLast::Start: + return mozilla::StyleTextAlign::Start; + case mozilla::StyleTextAlignLast::End: + return mozilla::StyleTextAlign::End; + case mozilla::StyleTextAlignLast::Left: + return mozilla::StyleTextAlign::Left; + case mozilla::StyleTextAlignLast::Right: + return mozilla::StyleTextAlign::Right; + case mozilla::StyleTextAlignLast::Justify: + return mozilla::StyleTextAlign::Justify; + } + return mozilla::StyleTextAlign::Start; + } + + bool HasWebkitTextStroke() const { return mWebkitTextStrokeWidth > 0; } + + bool HasTextShadow() const { return !mTextShadow.IsEmpty(); } + + // The aContextFrame argument on each of these is the frame this + // style struct is for. If the frame is for SVG text or inside ruby, + // the return value will be massaged to be something that makes sense + // for those cases. + inline bool NewlineIsSignificant(const nsTextFrame* aContextFrame) const; + inline bool WhiteSpaceCanWrap(const nsIFrame* aContextFrame) const; + inline bool WordCanWrap(const nsIFrame* aContextFrame) const; + + mozilla::LogicalSide TextEmphasisSide(mozilla::WritingMode aWM) const; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleVisibility { + explicit nsStyleVisibility(const mozilla::dom::Document&); + nsStyleVisibility(const nsStyleVisibility& aVisibility); + MOZ_COUNTED_DTOR(nsStyleVisibility) + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleVisibility& aNewData) const; + + mozilla::StyleImageOrientation mImageOrientation; + mozilla::StyleDirection mDirection; + mozilla::StyleVisibility mVisible; + mozilla::StyleImageRendering mImageRendering; + mozilla::StyleWritingModeProperty mWritingMode; + mozilla::StyleTextOrientation mTextOrientation; + mozilla::StyleColorAdjust mColorAdjust; + + bool IsVisible() const { + return mVisible == mozilla::StyleVisibility::Visible; + } + + bool IsVisibleOrCollapsed() const { + return mVisible == mozilla::StyleVisibility::Visible || + mVisible == mozilla::StyleVisibility::Collapse; + } +}; + +namespace mozilla { + +inline StyleTextTransform StyleTextTransform::None() { + return StyleTextTransform{StyleTextTransformCase::None, + StyleTextTransformOther()}; +} + +inline bool StyleTextTransform::IsNone() const { return *this == None(); } + +// Note that IsAuto() does not exclude the possibility that `left` or `right` +// is set; it refers only to behavior in horizontal typographic mode. +inline bool StyleTextUnderlinePosition::IsAuto() const { + return !(*this & (StyleTextUnderlinePosition::FROM_FONT | + StyleTextUnderlinePosition::UNDER)); +} +inline bool StyleTextUnderlinePosition::IsFromFont() const { + return bool(*this & StyleTextUnderlinePosition::FROM_FONT); +} +inline bool StyleTextUnderlinePosition::IsUnder() const { + return bool(*this & StyleTextUnderlinePosition::UNDER); +} +inline bool StyleTextUnderlinePosition::IsLeft() const { + return bool(*this & StyleTextUnderlinePosition::LEFT); +} +inline bool StyleTextUnderlinePosition::IsRight() const { + return bool(*this & StyleTextUnderlinePosition::RIGHT); +} + +struct StyleTransition { + StyleTransition() { /* leaves uninitialized; see also SetInitialValues */ + } + explicit StyleTransition(const StyleTransition& aCopy); + + void SetInitialValues(); + + // Delay and Duration are in milliseconds + + const nsTimingFunction& GetTimingFunction() const { return mTimingFunction; } + float GetDelay() const { return mDelay; } + float GetDuration() const { return mDuration; } + nsCSSPropertyID GetProperty() const { return mProperty; } + nsAtom* GetUnknownProperty() const { return mUnknownProperty; } + + bool operator==(const StyleTransition& aOther) const; + bool operator!=(const StyleTransition& aOther) const { + return !(*this == aOther); + } + + private: + nsTimingFunction mTimingFunction; + float mDuration; + float mDelay; + nsCSSPropertyID mProperty; + RefPtr<nsAtom> mUnknownProperty; // used when mProperty is + // eCSSProperty_UNKNOWN or + // eCSSPropertyExtra_variable +}; + +struct StyleAnimation { + StyleAnimation() { /* leaves uninitialized; see also SetInitialValues */ + } + explicit StyleAnimation(const StyleAnimation& aCopy); + + void SetInitialValues(); + + // Delay and Duration are in milliseconds + + const nsTimingFunction& GetTimingFunction() const { return mTimingFunction; } + float GetDelay() const { return mDelay; } + float GetDuration() const { return mDuration; } + nsAtom* GetName() const { return mName; } + dom::PlaybackDirection GetDirection() const { return mDirection; } + dom::FillMode GetFillMode() const { return mFillMode; } + StyleAnimationPlayState GetPlayState() const { return mPlayState; } + float GetIterationCount() const { return mIterationCount; } + + void SetName(already_AddRefed<nsAtom> aName) { mName = aName; } + void SetName(nsAtom* aName) { mName = aName; } + + bool operator==(const StyleAnimation& aOther) const; + bool operator!=(const StyleAnimation& aOther) const { + return !(*this == aOther); + } + + private: + nsTimingFunction mTimingFunction; + float mDuration; + float mDelay; + RefPtr<nsAtom> mName; // nsGkAtoms::_empty for 'none' + dom::PlaybackDirection mDirection; + dom::FillMode mFillMode; + StyleAnimationPlayState mPlayState; + float mIterationCount; // mozilla::PositiveInfinity<float>() means infinite +}; + +} // namespace mozilla + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay { + typedef mozilla::StyleGeometryBox StyleGeometryBox; + + explicit nsStyleDisplay(const mozilla::dom::Document&); + nsStyleDisplay(const nsStyleDisplay& aOther); + ~nsStyleDisplay(); + + void TriggerImageLoads(mozilla::dom::Document&, const nsStyleDisplay*); + static constexpr bool kHasTriggerImageLoads = true; + + nsChangeHint CalcDifference(const nsStyleDisplay& aNewData, + const nsStylePosition& aOldPosition) const; + + nsStyleAutoArray<mozilla::StyleTransition> mTransitions; + // The number of elements in mTransitions that are not from repeating + // a list due to another property being longer. + uint32_t mTransitionTimingFunctionCount; + uint32_t mTransitionDurationCount; + uint32_t mTransitionDelayCount; + uint32_t mTransitionPropertyCount; + nsStyleAutoArray<mozilla::StyleAnimation> mAnimations; + // The number of elements in mAnimations that are not from repeating + // a list due to another property being longer. + uint32_t mAnimationTimingFunctionCount; + uint32_t mAnimationDurationCount; + uint32_t mAnimationDelayCount; + uint32_t mAnimationNameCount; + uint32_t mAnimationDirectionCount; + uint32_t mAnimationFillModeCount; + uint32_t mAnimationPlayStateCount; + uint32_t mAnimationIterationCountCount; + + mozilla::StyleWillChange mWillChange; + mozilla::StyleDisplay mDisplay; + mozilla::StyleDisplay mOriginalDisplay; // saved mDisplay for + // position:absolute/fixed + // and float:left/right; + // otherwise equal to + // mDisplay + mozilla::StyleContain mContain; + + private: + mozilla::StyleAppearance mAppearance; + + public: + mozilla::StyleAppearance mDefaultAppearance; + mozilla::StylePositionProperty mPosition; + + mozilla::StyleFloat mFloat; + mozilla::StyleClear mBreakType; + mozilla::StyleBreakWithin mBreakInside; + mozilla::StyleBreakBetween mBreakBefore; + mozilla::StyleBreakBetween mBreakAfter; + mozilla::StyleOverflow mOverflowX; + mozilla::StyleOverflow mOverflowY; + mozilla::StyleOverflowClipBox mOverflowClipBoxBlock; + mozilla::StyleOverflowClipBox mOverflowClipBoxInline; + mozilla::StyleResize mResize; + mozilla::StyleOrient mOrient; + mozilla::StyleIsolation mIsolation; + mozilla::StyleTopLayer mTopLayer; + + mozilla::StyleTouchAction mTouchAction; + mozilla::StyleScrollBehavior mScrollBehavior; + mozilla::StyleOverscrollBehavior mOverscrollBehaviorX; + mozilla::StyleOverscrollBehavior mOverscrollBehaviorY; + mozilla::StyleOverflowAnchor mOverflowAnchor; + mozilla::StyleScrollSnapAlign mScrollSnapAlign; + mozilla::StyleScrollSnapType mScrollSnapType; + uint32_t mLineClamp; + + mozilla::StyleTransform mTransform; + mozilla::StyleRotate mRotate; + mozilla::StyleTranslate mTranslate; + mozilla::StyleScale mScale; + + mozilla::StyleBackfaceVisibility mBackfaceVisibility; + mozilla::StyleTransformStyle mTransformStyle; + StyleGeometryBox mTransformBox; + + mozilla::StyleOffsetPath mOffsetPath; + mozilla::LengthPercentage mOffsetDistance; + mozilla::StyleOffsetRotate mOffsetRotate; + mozilla::StylePositionOrAuto mOffsetAnchor; + + mozilla::StyleTransformOrigin mTransformOrigin; + mozilla::StylePerspective mChildPerspective; + mozilla::Position mPerspectiveOrigin; + + mozilla::StyleVerticalAlign mVerticalAlign; + + nsCSSPropertyID GetTransitionProperty(uint32_t aIndex) const { + return mTransitions[aIndex % mTransitionPropertyCount].GetProperty(); + } + float GetTransitionDelay(uint32_t aIndex) const { + return mTransitions[aIndex % mTransitionDelayCount].GetDelay(); + } + float GetTransitionDuration(uint32_t aIndex) const { + return mTransitions[aIndex % mTransitionDurationCount].GetDuration(); + } + const nsTimingFunction& GetTransitionTimingFunction(uint32_t aIndex) const { + return mTransitions[aIndex % mTransitionTimingFunctionCount] + .GetTimingFunction(); + } + float GetTransitionCombinedDuration(uint32_t aIndex) const { + // https://drafts.csswg.org/css-transitions/#transition-combined-duration + return std::max( + mTransitions[aIndex % mTransitionDurationCount].GetDuration(), + 0.0f) + + mTransitions[aIndex % mTransitionDelayCount].GetDelay(); + } + + nsAtom* GetAnimationName(uint32_t aIndex) const { + return mAnimations[aIndex % mAnimationNameCount].GetName(); + } + float GetAnimationDelay(uint32_t aIndex) const { + return mAnimations[aIndex % mAnimationDelayCount].GetDelay(); + } + float GetAnimationDuration(uint32_t aIndex) const { + return mAnimations[aIndex % mAnimationDurationCount].GetDuration(); + } + mozilla::dom::PlaybackDirection GetAnimationDirection(uint32_t aIndex) const { + return mAnimations[aIndex % mAnimationDirectionCount].GetDirection(); + } + mozilla::dom::FillMode GetAnimationFillMode(uint32_t aIndex) const { + return mAnimations[aIndex % mAnimationFillModeCount].GetFillMode(); + } + mozilla::StyleAnimationPlayState GetAnimationPlayState( + uint32_t aIndex) const { + return mAnimations[aIndex % mAnimationPlayStateCount].GetPlayState(); + } + float GetAnimationIterationCount(uint32_t aIndex) const { + return mAnimations[aIndex % mAnimationIterationCountCount] + .GetIterationCount(); + } + const nsTimingFunction& GetAnimationTimingFunction(uint32_t aIndex) const { + return mAnimations[aIndex % mAnimationTimingFunctionCount] + .GetTimingFunction(); + } + + // The threshold used for extracting a shape from shape-outside: <image>. + float mShapeImageThreshold = 0.0f; + + // The margin around a shape-outside: <image>. + mozilla::NonNegativeLengthPercentage mShapeMargin; + + mozilla::StyleShapeOutside mShapeOutside; + + bool HasAppearance() const { + return EffectiveAppearance() != mozilla::StyleAppearance::None; + } + + mozilla::StyleAppearance EffectiveAppearance() const { + switch (mAppearance) { + case mozilla::StyleAppearance::Auto: + case mozilla::StyleAppearance::Button: + case mozilla::StyleAppearance::Searchfield: + case mozilla::StyleAppearance::Textarea: + case mozilla::StyleAppearance::Checkbox: + case mozilla::StyleAppearance::Radio: + case mozilla::StyleAppearance::Menulist: + case mozilla::StyleAppearance::Listbox: + case mozilla::StyleAppearance::Meter: + case mozilla::StyleAppearance::ProgressBar: + // These are all the values that behave like `auto`. + return mDefaultAppearance; + case mozilla::StyleAppearance::Textfield: + // `appearance: textfield` should behave like `auto` on all elements + // except <input type=search> elements, which we identify using the + // internal -moz-default-appearance property. (In the browser chrome + // we have some other elements that set `-moz-default-appearance: + // searchfield`, but not in content documents.) + if (mDefaultAppearance == mozilla::StyleAppearance::Searchfield) { + return mAppearance; + } + // We also need to support `appearance: textfield` on <input + // type=number>, since that is the only way in Gecko to disable the + // spinners. + if (mDefaultAppearance == mozilla::StyleAppearance::NumberInput) { + return mAppearance; + } + return mDefaultAppearance; + case mozilla::StyleAppearance::MenulistButton: + // `appearance: menulist-button` should behave like `auto` on all + // elements except for drop down selects, but since we have very little + // difference between menulist and menulist-button handling, we don't + // bother. + return mDefaultAppearance; + default: + return mAppearance; + } + } + + static mozilla::StyleDisplayOutside DisplayOutside( + mozilla::StyleDisplay aDisplay) { + return mozilla::StyleDisplayOutside( + (uint16_t(aDisplay) >> mozilla::STYLE_DISPLAY_INSIDE_BITS) & + uint16_t(((1 << mozilla::STYLE_DISPLAY_OUTSIDE_BITS) - 1))); + } + mozilla::StyleDisplayOutside DisplayOutside() const { + return DisplayOutside(mDisplay); + } + + static mozilla::StyleDisplayInside DisplayInside( + mozilla::StyleDisplay aDisplay) { + return mozilla::StyleDisplayInside( + uint16_t(aDisplay) & + uint16_t(((1 << mozilla::STYLE_DISPLAY_INSIDE_BITS) - 1))); + } + mozilla::StyleDisplayInside DisplayInside() const { + return DisplayInside(mDisplay); + } + + static bool IsListItem(mozilla::StyleDisplay aDisplay) { + return !!(uint16_t(aDisplay) & mozilla::STYLE_DISPLAY_LIST_ITEM_BIT); + } + bool IsListItem() const { return IsListItem(mDisplay); } + + // Whether display is `inline` or `inline list-item`. + static bool IsInlineFlow(mozilla::StyleDisplay aDisplay) { + return DisplayOutside(aDisplay) == mozilla::StyleDisplayOutside::Inline && + DisplayInside(aDisplay) == mozilla::StyleDisplayInside::Flow; + } + + bool IsInlineFlow() const { return IsInlineFlow(mDisplay); } + + bool IsInlineInsideStyle() const { + auto inside = DisplayInside(); + return IsInlineFlow() || inside == mozilla::StyleDisplayInside::Ruby || + inside == mozilla::StyleDisplayInside::RubyBase || + inside == mozilla::StyleDisplayInside::RubyBaseContainer || + inside == mozilla::StyleDisplayInside::RubyText || + inside == mozilla::StyleDisplayInside::RubyTextContainer; + } + + bool IsBlockOutsideStyle() const { + return DisplayOutside() == mozilla::StyleDisplayOutside::Block; + } + + static bool IsDisplayTypeInlineOutside(mozilla::StyleDisplay aDisplay) { + auto outside = DisplayOutside(aDisplay); + if (outside == mozilla::StyleDisplayOutside::Inline) { + return true; + } + // just an optimization for the common case: + if (outside == mozilla::StyleDisplayOutside::Block) { + return false; + } + return mozilla::StyleDisplay::MozInlineBox == aDisplay || + mozilla::StyleDisplay::RubyBase == aDisplay || + mozilla::StyleDisplay::RubyBaseContainer == aDisplay || + mozilla::StyleDisplay::RubyText == aDisplay || + mozilla::StyleDisplay::RubyTextContainer == aDisplay; + } + + bool IsInlineOutsideStyle() const { + return IsDisplayTypeInlineOutside(mDisplay); + } + + bool IsOriginalDisplayInlineOutside() const { + return IsDisplayTypeInlineOutside(mOriginalDisplay); + } + + bool IsInnerTableStyle() const { + return DisplayOutside() == mozilla::StyleDisplayOutside::InternalTable; + } + + bool IsInternalTableStyleExceptCell() const { + return IsInnerTableStyle() && mozilla::StyleDisplay::TableCell != mDisplay; + } + + bool IsXULDisplayStyle() const { + // -moz-{inline-}box is XUL, unless we're emulating it with flexbox. + if (!mozilla::StaticPrefs::layout_css_emulate_moz_box_with_flex() && + DisplayInside() == mozilla::StyleDisplayInside::MozBox) { + return true; + } + +#ifdef MOZ_XUL + return DisplayOutside() == mozilla::StyleDisplayOutside::XUL; +#else + return false; +#endif + } + + bool IsFloatingStyle() const { return mozilla::StyleFloat::None != mFloat; } + + bool IsPositionedStyle() const { + return mPosition != mozilla::StylePositionProperty::Static || + (mWillChange.bits & mozilla::StyleWillChangeBits::ABSPOS_CB); + } + + bool IsAbsolutelyPositionedStyle() const { + return mozilla::StylePositionProperty::Absolute == mPosition || + mozilla::StylePositionProperty::Fixed == mPosition; + } + + bool IsRelativelyPositionedStyle() const { + return mozilla::StylePositionProperty::Relative == mPosition || + mozilla::StylePositionProperty::Sticky == mPosition; + } + bool IsStickyPositionedStyle() const { + return mozilla::StylePositionProperty::Sticky == mPosition; + } + bool IsPositionForcingStackingContext() const { + return mozilla::StylePositionProperty::Sticky == mPosition || + mozilla::StylePositionProperty::Fixed == mPosition; + } + + static bool IsRubyDisplayType(mozilla::StyleDisplay aDisplay) { + return DisplayInside(aDisplay) == mozilla::StyleDisplayInside::Ruby || + IsInternalRubyDisplayType(aDisplay); + } + + static bool IsInternalRubyDisplayType(mozilla::StyleDisplay aDisplay) { + return mozilla::StyleDisplay::RubyBase == aDisplay || + mozilla::StyleDisplay::RubyBaseContainer == aDisplay || + mozilla::StyleDisplay::RubyText == aDisplay || + mozilla::StyleDisplay::RubyTextContainer == aDisplay; + } + + bool IsRubyDisplayType() const { return IsRubyDisplayType(mDisplay); } + + bool IsInternalRubyDisplayType() const { + return IsInternalRubyDisplayType(mDisplay); + } + + bool IsOutOfFlowStyle() const { + return (IsAbsolutelyPositionedStyle() || IsFloatingStyle()); + } + + bool IsScrollableOverflow() const { + // Visible and Clip can be combined but not with other values, + // so checking mOverflowX is enough. + return mOverflowX != mozilla::StyleOverflow::Visible && + mOverflowX != mozilla::StyleOverflow::Clip; + } + + bool OverflowIsVisibleInBothAxis() const { + return mOverflowX == mozilla::StyleOverflow::Visible && + mOverflowY == mozilla::StyleOverflow::Visible; + } + + bool IsContainPaint() const { + return (mContain & mozilla::StyleContain::PAINT) && + !IsInternalRubyDisplayType() && !IsInternalTableStyleExceptCell(); + } + + bool IsContainLayout() const { + // Note: The spec for layout containment says it should + // have no effect on non-atomic, inline-level boxes. We + // don't check for these here because we don't know + // what type of element is involved. Callers are + // responsible for checking if the box in question is + // non-atomic and inline-level, and creating an + // exemption as necessary. + return (mContain & mozilla::StyleContain::LAYOUT) && + !IsInternalRubyDisplayType() && !IsInternalTableStyleExceptCell(); + } + + bool IsContainSize() const { + // Note: The spec for size containment says it should + // have no effect on non-atomic, inline-level boxes. We + // don't check for these here because we don't know + // what type of element is involved. Callers are + // responsible for checking if the box in question is + // non-atomic and inline-level, and creating an + // exemption as necessary. + return (mContain & mozilla::StyleContain::SIZE) && + !IsInternalRubyDisplayType() && + DisplayInside() != mozilla::StyleDisplayInside::Table && + !IsInnerTableStyle(); + } + + /* Returns whether the element has the transform property or a related + * property. */ + bool HasTransformStyle() const { + return HasTransformProperty() || HasIndividualTransform() || + mTransformStyle == mozilla::StyleTransformStyle::Preserve3d || + (mWillChange.bits & mozilla::StyleWillChangeBits::TRANSFORM) || + !mOffsetPath.IsNone(); + } + + bool HasTransformProperty() const { return !mTransform._0.IsEmpty(); } + + bool HasIndividualTransform() const { + return !mRotate.IsNone() || !mTranslate.IsNone() || !mScale.IsNone(); + } + + bool HasPerspectiveStyle() const { return !mChildPerspective.IsNone(); } + + bool BackfaceIsHidden() const { + return mBackfaceVisibility == mozilla::StyleBackfaceVisibility::Hidden; + } + + // FIXME(emilio): This should be more fine-grained on each caller to + // BreakBefore() / BreakAfter(). + static bool ShouldBreak(mozilla::StyleBreakBetween aBreak) { + switch (aBreak) { + case mozilla::StyleBreakBetween::Left: + case mozilla::StyleBreakBetween::Right: + case mozilla::StyleBreakBetween::Page: + case mozilla::StyleBreakBetween::Always: + return true; + case mozilla::StyleBreakBetween::Auto: + case mozilla::StyleBreakBetween::Avoid: + return false; + default: + MOZ_ASSERT_UNREACHABLE("Unknown break kind"); + return false; + } + } + + bool BreakBefore() const { return ShouldBreak(mBreakBefore); } + + bool BreakAfter() const { return ShouldBreak(mBreakAfter); } + + // These are defined in nsStyleStructInlines.h. + + // The aContextFrame argument on each of these is the frame this + // style struct is for. If the frame is for SVG text, the return + // value will be massaged to be something that makes sense for + // SVG text. + inline bool IsBlockOutside(const nsIFrame* aContextFrame) const; + inline bool IsInlineOutside(const nsIFrame* aContextFrame) const; + inline mozilla::StyleDisplay GetDisplay(const nsIFrame* aContextFrame) const; + inline bool IsFloating(const nsIFrame* aContextFrame) const; + inline bool IsRelativelyPositioned(const nsIFrame* aContextFrame) const; + inline bool IsStickyPositioned(const nsIFrame* aContextFrame) const; + inline bool IsAbsolutelyPositioned(const nsIFrame* aContextFrame) const; + + // These methods are defined in nsStyleStructInlines.h. + + /** + * Returns true when the element has the transform property + * or a related property, and supports CSS transforms. + * aContextFrame is the frame for which this is the nsStyleDisplay. + */ + inline bool HasTransform(const nsIFrame* aContextFrame) const; + + /** + * Returns true when the element has the perspective property, + * and supports CSS transforms. aContextFrame is the frame for + * which this is the nsStyleDisplay. + */ + inline bool HasPerspective(const nsIFrame* aContextFrame) const; + + /** + * Returns whether the element is a containing block for its + * absolutely positioned descendants. + * aContextFrame is the frame for which this is the nsStyleDisplay. + */ + inline bool IsAbsPosContainingBlock(const nsIFrame* aContextFrame) const; + + /** + * Returns true when the element is a containing block for its fixed-pos + * descendants. + * aContextFrame is the frame for which this is the nsStyleDisplay. + */ + inline bool IsFixedPosContainingBlock(const nsIFrame* aContextFrame) const; + + /** + * Tests for only the sub-parts of IsFixedPosContainingBlock that apply + * to: + * - nearly all frames, except those that are SVG text frames. + * - frames that support CSS contain:layout and contain:paint and are not + * SVG text frames. + * - frames that support CSS transforms and are not SVG text frames. + * + * This should be used only when the caller has the style but not the + * frame (i.e., when calculating style changes). + */ + inline bool IsFixedPosContainingBlockForNonSVGTextFrames( + const mozilla::ComputedStyle&) const; + inline bool + IsFixedPosContainingBlockForContainLayoutAndPaintSupportingFrames() const; + inline bool IsFixedPosContainingBlockForTransformSupportingFrames() const; + + void GenerateCombinedIndividualTransform(); +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTable { + explicit nsStyleTable(const mozilla::dom::Document&); + nsStyleTable(const nsStyleTable& aOther); + ~nsStyleTable(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleTable& aNewData) const; + + mozilla::StyleTableLayout mLayoutStrategy; + int32_t mXSpan; // The number of columns spanned by a colgroup or col +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleTableBorder { + explicit nsStyleTableBorder(const mozilla::dom::Document&); + nsStyleTableBorder(const nsStyleTableBorder& aOther); + ~nsStyleTableBorder(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleTableBorder& aNewData) const; + + nscoord mBorderSpacingCol; + nscoord mBorderSpacingRow; + mozilla::StyleBorderCollapse mBorderCollapse; + uint8_t mCaptionSide; + mozilla::StyleEmptyCells mEmptyCells; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleContent { + using CounterPair = mozilla::StyleGenericCounterPair<int32_t>; + + explicit nsStyleContent(const mozilla::dom::Document&); + nsStyleContent(const nsStyleContent& aContent); + ~nsStyleContent(); + + void TriggerImageLoads(mozilla::dom::Document&, const nsStyleContent*); + static constexpr bool kHasTriggerImageLoads = true; + + size_t ContentCount() const { + return mContent.IsItems() ? mContent.AsItems().Length() : 0; + } + + const mozilla::StyleContentItem& ContentAt(size_t aIndex) const { + return mContent.AsItems().AsSpan()[aIndex]; + } + + nsChangeHint CalcDifference(const nsStyleContent& aNewData) const; + + mozilla::StyleContent mContent; + mozilla::StyleCounterIncrement mCounterIncrement; + mozilla::StyleCounterSetOrReset mCounterReset; + mozilla::StyleCounterSetOrReset mCounterSet; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUIReset { + explicit nsStyleUIReset(const mozilla::dom::Document&); + nsStyleUIReset(const nsStyleUIReset& aOther); + ~nsStyleUIReset(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleUIReset& aNewData) const; + + mozilla::StyleUserSelect mUserSelect; // [reset](selection-style) + mozilla::StyleScrollbarWidth mScrollbarWidth; + uint8_t mMozForceBrokenImageIcon; // (0 if not forcing, otherwise forcing) + mozilla::StyleImeMode mIMEMode; + mozilla::StyleWindowDragging mWindowDragging; + mozilla::StyleWindowShadow mWindowShadow; + float mWindowOpacity; + mozilla::StyleTransform mMozWindowTransform; + mozilla::StyleTransformOrigin mWindowTransformOrigin; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUI { + explicit nsStyleUI(const mozilla::dom::Document&); + nsStyleUI(const nsStyleUI& aOther); + ~nsStyleUI(); + + void TriggerImageLoads(mozilla::dom::Document&, const nsStyleUI*); + static constexpr bool kHasTriggerImageLoads = true; + + nsChangeHint CalcDifference(const nsStyleUI& aNewData) const; + + mozilla::StyleInert mInert; + mozilla::StyleUserInput mUserInput; + mozilla::StyleUserModify mUserModify; // (modify-content) + mozilla::StyleUserFocus mUserFocus; // (auto-select) + mozilla::StylePointerEvents mPointerEvents; + + mozilla::StyleCursor mCursor; + + mozilla::StyleColorOrAuto mCaretColor; + mozilla::StyleScrollbarColor mScrollbarColor; + + inline mozilla::StylePointerEvents GetEffectivePointerEvents( + nsIFrame* aFrame) const; + + bool HasCustomScrollbars() const { return !mScrollbarColor.IsAuto(); } +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleXUL { + explicit nsStyleXUL(const mozilla::dom::Document&); + nsStyleXUL(const nsStyleXUL& aSource); + ~nsStyleXUL(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleXUL& aNewData) const; + + float mBoxFlex; + int32_t mBoxOrdinal; + mozilla::StyleBoxAlign mBoxAlign; + mozilla::StyleBoxDirection mBoxDirection; + mozilla::StyleBoxOrient mBoxOrient; + mozilla::StyleBoxPack mBoxPack; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleColumn { + explicit nsStyleColumn(const mozilla::dom::Document&); + nsStyleColumn(const nsStyleColumn& aSource); + ~nsStyleColumn(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleColumn& aNewData) const; + + // This is the maximum number of columns we can process. It's used in + // nsColumnSetFrame. + static const uint32_t kMaxColumnCount = 1000; + + // This represents the value of column-count: auto. + static const uint32_t kColumnCountAuto = 0; + + uint32_t mColumnCount = kColumnCountAuto; + mozilla::NonNegativeLengthOrAuto mColumnWidth; + + mozilla::StyleColor mColumnRuleColor; + mozilla::StyleBorderStyle mColumnRuleStyle; // StyleborderStyle::* + mozilla::StyleColumnFill mColumnFill = mozilla::StyleColumnFill::Balance; + mozilla::StyleColumnSpan mColumnSpan = mozilla::StyleColumnSpan::None; + + nscoord GetComputedColumnRuleWidth() const { + return (IsVisibleBorderStyle(mColumnRuleStyle) ? mColumnRuleWidth : 0); + } + + bool IsColumnContainerStyle() const { + return mColumnCount != kColumnCountAuto || !mColumnWidth.IsAuto(); + } + + bool IsColumnSpanStyle() const { + return mColumnSpan == mozilla::StyleColumnSpan::All; + } + + protected: + nscoord mColumnRuleWidth; // coord + nscoord mTwipsPerPixel; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG { + explicit nsStyleSVG(const mozilla::dom::Document&); + nsStyleSVG(const nsStyleSVG& aSource); + ~nsStyleSVG(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleSVG& aNewData) const; + + mozilla::StyleSVGPaint mFill; + mozilla::StyleSVGPaint mStroke; + mozilla::StyleUrlOrNone mMarkerEnd; + mozilla::StyleUrlOrNone mMarkerMid; + mozilla::StyleUrlOrNone mMarkerStart; + mozilla::StyleMozContextProperties mMozContextProperties; + + mozilla::StyleSVGStrokeDashArray mStrokeDasharray; + mozilla::StyleSVGLength mStrokeDashoffset; + mozilla::StyleSVGWidth mStrokeWidth; + + mozilla::StyleSVGOpacity mFillOpacity; + float mStrokeMiterlimit; + mozilla::StyleSVGOpacity mStrokeOpacity; + + mozilla::StyleFillRule mClipRule; + mozilla::StyleColorInterpolation mColorInterpolation; + mozilla::StyleColorInterpolation mColorInterpolationFilters; + mozilla::StyleFillRule mFillRule; + mozilla::StyleSVGPaintOrder mPaintOrder; + mozilla::StyleShapeRendering mShapeRendering; + mozilla::StyleStrokeLinecap mStrokeLinecap; + mozilla::StyleStrokeLinejoin mStrokeLinejoin; + mozilla::StyleDominantBaseline mDominantBaseline; + mozilla::StyleTextAnchor mTextAnchor; + + /// Returns true if style has been set to expose the computed values of + /// certain properties (such as 'fill') to the contents of any linked images. + bool ExposesContextProperties() const { + return bool(mMozContextProperties.bits); + } + + bool HasMarker() const { + return mMarkerStart.IsUrl() || mMarkerMid.IsUrl() || mMarkerEnd.IsUrl(); + } + + /** + * Returns true if the stroke is not "none" and the stroke-opacity is greater + * than zero (or a context-dependent value). + * + * This ignores stroke-widths as that depends on the context. + */ + bool HasStroke() const { + if (mStroke.kind.IsNone()) { + return false; + } + return !mStrokeOpacity.IsOpacity() || mStrokeOpacity.AsOpacity() > 0; + } + + /** + * Returns true if the fill is not "none" and the fill-opacity is greater + * than zero (or a context-dependent value). + */ + bool HasFill() const { + if (mFill.kind.IsNone()) { + return false; + } + return !mFillOpacity.IsOpacity() || mFillOpacity.AsOpacity() > 0; + } +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVGReset { + explicit nsStyleSVGReset(const mozilla::dom::Document&); + nsStyleSVGReset(const nsStyleSVGReset& aSource); + ~nsStyleSVGReset(); + + // Resolves and tracks the images in mMask. Only called with a Servo-backed + // style system, where those images must be resolved later than the OMT + // nsStyleSVGReset constructor call. + void TriggerImageLoads(mozilla::dom::Document&, const nsStyleSVGReset*); + static constexpr bool kHasTriggerImageLoads = true; + + nsChangeHint CalcDifference(const nsStyleSVGReset& aNewData) const; + + bool HasClipPath() const { return !mClipPath.IsNone(); } + + bool HasMask() const; + + bool HasNonScalingStroke() const { + return mVectorEffect == mozilla::StyleVectorEffect::NonScalingStroke; + } + + // geometry properties + mozilla::LengthPercentage mX; + mozilla::LengthPercentage mY; + mozilla::LengthPercentage mCx; + mozilla::LengthPercentage mCy; + mozilla::NonNegativeLengthPercentageOrAuto mRx; + mozilla::NonNegativeLengthPercentageOrAuto mRy; + mozilla::NonNegativeLengthPercentage mR; + + nsStyleImageLayers mMask; + mozilla::StyleClipPath mClipPath; + mozilla::StyleColor mStopColor; + mozilla::StyleColor mFloodColor; + mozilla::StyleColor mLightingColor; + + float mStopOpacity; + float mFloodOpacity; + + mozilla::StyleVectorEffect mVectorEffect; + mozilla::StyleMaskType mMaskType; +}; + +struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleEffects { + explicit nsStyleEffects(const mozilla::dom::Document&); + nsStyleEffects(const nsStyleEffects& aSource); + ~nsStyleEffects(); + static constexpr bool kHasTriggerImageLoads = false; + + nsChangeHint CalcDifference(const nsStyleEffects& aNewData) const; + + bool HasFilters() const { return !mFilters.IsEmpty(); } + + bool HasBackdropFilters() const { return !mBackdropFilters.IsEmpty(); } + + bool HasBoxShadowWithInset(bool aInset) const { + for (auto& shadow : mBoxShadow.AsSpan()) { + if (shadow.inset == aInset) { + return true; + } + } + return false; + } + + bool HasMixBlendMode() const { + return mMixBlendMode != mozilla::StyleBlend::Normal; + } + + mozilla::StyleOwnedSlice<mozilla::StyleFilter> mFilters; + mozilla::StyleOwnedSlice<mozilla::StyleBoxShadow> mBoxShadow; + mozilla::StyleOwnedSlice<mozilla::StyleFilter> mBackdropFilters; + mozilla::StyleClipRectOrAuto mClip; // offsets from UL border edge + float mOpacity; + mozilla::StyleBlend mMixBlendMode; +}; + +#define STATIC_ASSERT_TYPE_LAYOUTS_MATCH(T1, T2) \ + static_assert(sizeof(T1) == sizeof(T2), \ + "Size mismatch between " #T1 " and " #T2); \ + static_assert(alignof(T1) == alignof(T2), \ + "Align mismatch between " #T1 " and " #T2); + +#define STATIC_ASSERT_FIELD_OFFSET_MATCHES(T1, T2, field) \ + static_assert(offsetof(T1, field) == offsetof(T2, field), \ + "Field offset mismatch of " #field " between " #T1 \ + " and " #T2); + +/** + * These *_Simple types are used to map Gecko types to layout-equivalent but + * simpler Rust types, to aid Rust binding generation. + * + * If something in this types or the assertions below needs to change, ask + * bholley, heycam or emilio before! + * + * <div rustbindgen="true" replaces="nsPoint"> + */ +struct nsPoint_Simple { + nscoord x, y; +}; + +STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsPoint, nsPoint_Simple); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsPoint, nsPoint_Simple, x); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsPoint, nsPoint_Simple, y); + +/** + * <div rustbindgen="true" replaces="nsMargin"> + */ +struct nsMargin_Simple { + nscoord top, right, bottom, left; +}; + +STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsMargin, nsMargin_Simple); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsMargin, nsMargin_Simple, top); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsMargin, nsMargin_Simple, right); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsMargin, nsMargin_Simple, bottom); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsMargin, nsMargin_Simple, left); + +/** + * <div rustbindgen="true" replaces="nsRect"> + */ +struct nsRect_Simple { + nscoord x, y, width, height; +}; + +STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsRect, nsRect_Simple); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsRect, nsRect_Simple, x); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsRect, nsRect_Simple, y); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsRect, nsRect_Simple, width); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsRect, nsRect_Simple, height); + +/** + * <div rustbindgen="true" replaces="nsSize"> + */ +struct nsSize_Simple { + nscoord width, height; +}; + +STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsSize, nsSize_Simple); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsSize, nsSize_Simple, width); +STATIC_ASSERT_FIELD_OFFSET_MATCHES(nsSize, nsSize_Simple, height); + +/** + * <div rustbindgen="true" replaces="mozilla::UniquePtr"> + * + * TODO(Emilio): This is a workaround and we should be able to get rid of this + * one. + */ +template <typename T> +struct UniquePtr_Simple { + T* mPtr; +}; + +STATIC_ASSERT_TYPE_LAYOUTS_MATCH(mozilla::UniquePtr<int>, + UniquePtr_Simple<int>); + +/** + * <div rustbindgen replaces="nsTArray"></div> + */ +template <typename T> +class nsTArray_Simple { + protected: + T* mBuffer; + + public: + ~nsTArray_Simple() { + // The existence of a user-provided, and therefore non-trivial, destructor + // here prevents bindgen from deriving the Clone trait via a simple memory + // copy. + } +}; + +/** + * <div rustbindgen replaces="CopyableTArray"></div> + */ +template <typename T> +class CopyableTArray_Simple : public nsTArray_Simple<T> {}; + +STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<nsStyleImageLayers::Layer>, + nsTArray_Simple<nsStyleImageLayers::Layer>); +STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<mozilla::StyleTransition>, + nsTArray_Simple<mozilla::StyleTransition>); +STATIC_ASSERT_TYPE_LAYOUTS_MATCH(nsTArray<mozilla::StyleAnimation>, + nsTArray_Simple<mozilla::StyleAnimation>); + +#endif /* nsStyleStruct_h___ */ |