diff options
Diffstat (limited to 'layout/style/nsCSSValue.h')
-rw-r--r-- | layout/style/nsCSSValue.h | 1943 |
1 files changed, 1943 insertions, 0 deletions
diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h new file mode 100644 index 000000000..1721cc8ee --- /dev/null +++ b/layout/style/nsCSSValue.h @@ -0,0 +1,1943 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 simple property values within CSS declarations */ + +#ifndef nsCSSValue_h___ +#define nsCSSValue_h___ + +#include <type_traits> + +#include "mozilla/Attributes.h" +#include "mozilla/MemoryReporting.h" +#include "mozilla/SheetType.h" +#include "mozilla/StyleComplexColor.h" +#include "mozilla/UniquePtr.h" + +#include "nsIPrincipal.h" +#include "nsIURI.h" +#include "nsCOMPtr.h" +#include "nsCSSKeywords.h" +#include "nsCSSPropertyID.h" +#include "nsCSSProps.h" +#include "nsColor.h" +#include "nsCoord.h" +#include "nsProxyRelease.h" +#include "nsRefPtrHashtable.h" +#include "nsString.h" +#include "nsStringBuffer.h" +#include "nsTArray.h" +#include "nsStyleConsts.h" +#include "nsStyleCoord.h" +#include "gfxFontFamilyList.h" + +class imgRequestProxy; +class nsIContent; +class nsIDocument; +class nsIPrincipal; +class nsIURI; +class nsPresContext; +template <class T> +class nsPtrHashKey; + +namespace mozilla { +class CSSStyleSheet; +} // namespace mozilla + +// Deletes a linked list iteratively to avoid blowing up the stack (bug 456196). +#define NS_CSS_DELETE_LIST_MEMBER(type_, ptr_, member_) \ + { \ + type_ *cur = (ptr_)->member_; \ + (ptr_)->member_ = nullptr; \ + while (cur) { \ + type_ *dlm_next = cur->member_; \ + cur->member_ = nullptr; \ + delete cur; \ + cur = dlm_next; \ + } \ + } +// Ditto, but use NS_RELEASE instead of 'delete' (bug 1221902). +#define NS_CSS_NS_RELEASE_LIST_MEMBER(type_, ptr_, member_) \ + { \ + type_ *cur = (ptr_)->member_; \ + (ptr_)->member_ = nullptr; \ + while (cur) { \ + type_ *dlm_next = cur->member_; \ + cur->member_ = nullptr; \ + NS_RELEASE(cur); \ + cur = dlm_next; \ + } \ + } + +// Clones a linked list iteratively to avoid blowing up the stack. +// If it fails to clone the entire list then 'to_' is deleted and +// we return null. +#define NS_CSS_CLONE_LIST_MEMBER(type_, from_, member_, to_, args_) \ + { \ + type_ *dest = (to_); \ + (to_)->member_ = nullptr; \ + for (const type_ *src = (from_)->member_; src; src = src->member_) { \ + type_ *clm_clone = src->Clone args_; \ + if (!clm_clone) { \ + delete (to_); \ + return nullptr; \ + } \ + dest->member_ = clm_clone; \ + dest = clm_clone; \ + } \ + } + +namespace mozilla { +namespace css { + +struct URLValueData +{ +protected: + // Methods are not inline because using an nsIPrincipal means requiring + // caps, which leads to REQUIRES hell, since this header is included all + // over. + + // For both constructors aString must not be null. + // For both constructors aOriginPrincipal must not be null. + // Construct with a base URI; this will create the actual URI lazily from + // aString and aBaseURI. + URLValueData(nsStringBuffer* aString, + already_AddRefed<PtrHolder<nsIURI>> aBaseURI, + already_AddRefed<PtrHolder<nsIURI>> aReferrer, + already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPricinpal); + // Construct with the actual URI. + URLValueData(already_AddRefed<PtrHolder<nsIURI>> aURI, + nsStringBuffer* aString, + already_AddRefed<PtrHolder<nsIURI>> aBaseURI, + already_AddRefed<PtrHolder<nsIURI>> aReferrer, + already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPrincipal); + +public: + // Returns true iff all fields of the two URLValueData objects are equal. + // + // Only safe to call on the main thread, since this will call Equals on the + // nsIURI and nsIPrincipal objects stored on the URLValueData objects. + bool Equals(const URLValueData& aOther) const; + + // Returns true iff we know for sure, by comparing the mBaseURI pointer, + // the specified url() value mString, and the mIsLocalRef, that these + // two URLValueData objects represent the same computed url() value. + // + // Doesn't look at mReferrer or mOriginPrincipal. + // + // Safe to call from any thread. + bool DefinitelyEqualURIs(const URLValueData& aOther) const; + + // Smae as DefinitelyEqualURIs but additionally compares the nsIPrincipal + // pointers of the two URLValueData objects. + bool DefinitelyEqualURIsAndPrincipal(const URLValueData& aOther) const; + + nsIURI* GetURI() const; + + bool IsLocalRef() const { return mIsLocalRef; } + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(URLValueData) + + // When matching a url with mIsLocalRef set, resolve it against aURI; + // Otherwise, ignore aURL and return mURL directly. + already_AddRefed<nsIURI> ResolveLocalRef(nsIURI* aURI) const; + already_AddRefed<nsIURI> ResolveLocalRef(nsIContent* aContent) const; + + // Serializes mURI as a computed URI value, taking into account mIsLocalRef + // and serializing just the fragment if true. + void GetSourceString(nsString& aRef) const; + + bool EqualsExceptRef(nsIURI* aURI) const; + +private: + // mURI stores the lazily resolved URI. This may be null if the URI is + // invalid, even once resolved. + mutable PtrHandle<nsIURI> mURI; +public: + PtrHandle<nsIURI> mBaseURI; + RefPtr<nsStringBuffer> mString; + PtrHandle<nsIURI> mReferrer; + PtrHandle<nsIPrincipal> mOriginPrincipal; +private: + mutable bool mURIResolved; + // mIsLocalRef is set when url starts with a U+0023 number sign(#) character. + bool mIsLocalRef; + +protected: + virtual ~URLValueData() = default; + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +private: + URLValueData(const URLValueData& aOther) = delete; + URLValueData& operator=(const URLValueData& aOther) = delete; +}; + +struct URLValue final : public URLValueData +{ + // These two constructors are safe to call only on the main thread. + URLValue(nsStringBuffer* aString, nsIURI* aBaseURI, nsIURI* aReferrer, + nsIPrincipal* aOriginPrincipal); + URLValue(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aBaseURI, + nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal); + + // This constructor is safe to call from any thread. + URLValue(nsStringBuffer* aString, + already_AddRefed<PtrHolder<nsIURI>> aBaseURI, + already_AddRefed<PtrHolder<nsIURI>> aReferrer, + already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPrincipal) + : URLValueData(aString, Move(aBaseURI), Move(aReferrer), + Move(aOriginPrincipal)) {} + + URLValue(const URLValue&) = delete; + URLValue& operator=(const URLValue&) = delete; + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; +}; + +struct ImageValue final : public URLValueData +{ + // Not making the constructor and destructor inline because that would + // force us to include imgIRequest.h, which leads to REQUIRES hell, since + // this header is included all over. + // aString must not be null. + // + // This constructor is only safe to call from the main thread. + ImageValue(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aBaseURI, + nsIURI* aReferrer, nsIPrincipal* aOriginPrincipal, + nsIDocument* aDocument); + + // This constructor is safe to call from any thread, but Initialize + // must be called later for the object to be useful. + ImageValue(nsStringBuffer* aString, + already_AddRefed<PtrHolder<nsIURI>> aBaseURI, + already_AddRefed<PtrHolder<nsIURI>> aReferrer, + already_AddRefed<PtrHolder<nsIPrincipal>> aOriginPrincipal); + + ImageValue(const ImageValue&) = delete; + ImageValue& operator=(const ImageValue&) = delete; + + void Initialize(nsIDocument* aDocument); + + // XXXheycam We should have our own SizeOfIncludingThis method. + +protected: + ~ImageValue(); + +public: + // Inherit Equals from URLValueData + + nsRefPtrHashtable<nsPtrHashKey<nsIDocument>, imgRequestProxy> mRequests; + +private: +#ifdef DEBUG + bool mInitialized = false; +#endif +}; + +struct GridNamedArea { + nsString mName; + uint32_t mColumnStart; + uint32_t mColumnEnd; + uint32_t mRowStart; + uint32_t mRowEnd; +}; + +struct GridTemplateAreasValue final { + // Parsed value + nsTArray<GridNamedArea> mNamedAreas; + + // Original <string> values. Length gives the number of rows, + // content makes serialization easier. + nsTArray<nsString> mTemplates; + + // How many columns grid-template-areas contributes to the explicit grid. + // http://dev.w3.org/csswg/css-grid/#explicit-grid + uint32_t mNColumns; + + // How many rows grid-template-areas contributes to the explicit grid. + // http://dev.w3.org/csswg/css-grid/#explicit-grid + uint32_t NRows() const { + return mTemplates.Length(); + } + + GridTemplateAreasValue() + : mNColumns(0) + // Default constructors for mNamedAreas and mTemplates: empty arrays. + { + } + + bool operator==(const GridTemplateAreasValue& aOther) const + { + return mTemplates == aOther.mTemplates; + } + + bool operator!=(const GridTemplateAreasValue& aOther) const + { + return !(*this == aOther); + } + + NS_INLINE_DECL_REFCOUNTING(GridTemplateAreasValue) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +private: + // Private destructor to make sure this isn't used as a stack variable + // or member variable. + ~GridTemplateAreasValue() + { + } + + GridTemplateAreasValue(const GridTemplateAreasValue& aOther) = delete; + GridTemplateAreasValue& + operator=(const GridTemplateAreasValue& aOther) = delete; +}; + +class FontFamilyListRefCnt final : public FontFamilyList { +public: + FontFamilyListRefCnt() + : FontFamilyList() + { + MOZ_COUNT_CTOR(FontFamilyListRefCnt); + } + + explicit FontFamilyListRefCnt(FontFamilyType aGenericType) + : FontFamilyList(aGenericType) + { + MOZ_COUNT_CTOR(FontFamilyListRefCnt); + } + + FontFamilyListRefCnt(const nsAString& aFamilyName, + QuotedName aQuoted) + : FontFamilyList(aFamilyName, aQuoted) + { + MOZ_COUNT_CTOR(FontFamilyListRefCnt); + } + + FontFamilyListRefCnt(const FontFamilyListRefCnt& aOther) + : FontFamilyList(aOther) + { + MOZ_COUNT_CTOR(FontFamilyListRefCnt); + } + + NS_INLINE_DECL_REFCOUNTING(FontFamilyListRefCnt); + +private: + ~FontFamilyListRefCnt() { + MOZ_COUNT_DTOR(FontFamilyListRefCnt); + } +}; + +struct RGBAColorData +{ + // 1.0 means 100% for all components, but the value may fall outside + // the range of [0.0, 1.0], so it is necessary to clamp them when + // converting to nscolor. + float mR; + float mG; + float mB; + float mA; + + RGBAColorData() = default; + MOZ_IMPLICIT RGBAColorData(nscolor aColor) + : mR(NS_GET_R(aColor) * (1.0f / 255.0f)) + , mG(NS_GET_G(aColor) * (1.0f / 255.0f)) + , mB(NS_GET_B(aColor) * (1.0f / 255.0f)) + , mA(NS_GET_A(aColor) * (1.0f / 255.0f)) + {} + RGBAColorData(float aR, float aG, float aB, float aA) + : mR(aR), mG(aG), mB(aB), mA(aA) {} + + bool operator==(const RGBAColorData& aOther) const + { + return mR == aOther.mR && mG == aOther.mG && + mB == aOther.mB && mA == aOther.mA; + } + bool operator!=(const RGBAColorData& aOther) const + { + return !(*this == aOther); + } + + nscolor ToColor() const + { + return NS_RGBA(ClampColor(mR * 255.0f), + ClampColor(mG * 255.0f), + ClampColor(mB * 255.0f), + ClampColor(mA * 255.0f)); + } + + RGBAColorData WithAlpha(float aAlpha) const + { + RGBAColorData result = *this; + result.mA = aAlpha; + return result; + } +}; + +struct ComplexColorData +{ + RGBAColorData mColor; + float mForegroundRatio; + + ComplexColorData() = default; + ComplexColorData(const RGBAColorData& aColor, float aForegroundRatio) + : mColor(aColor), mForegroundRatio(aForegroundRatio) {} + ComplexColorData(nscolor aColor, float aForegroundRatio) + : mColor(aColor), mForegroundRatio(aForegroundRatio) {} + explicit ComplexColorData(const StyleComplexColor& aColor) + : mColor(aColor.mColor) + , mForegroundRatio(aColor.mForegroundRatio * (1.0f / 255.0f)) {} + + bool operator==(const ComplexColorData& aOther) const + { + return mForegroundRatio == aOther.mForegroundRatio && + (IsCurrentColor() || mColor == aOther.mColor); + } + bool operator!=(const ComplexColorData& aOther) const + { + return !(*this == aOther); + } + + bool IsCurrentColor() const { return mForegroundRatio >= 1.0f; } + bool IsNumericColor() const { return mForegroundRatio <= 0.0f; } + + StyleComplexColor ToComplexColor() const + { + return {mColor.ToColor(), ClampColor(mForegroundRatio * 255.0f)}; + } +}; + +struct ComplexColorValue final : public ComplexColorData +{ + // Just redirect any parameter to the data struct. + template<typename... Args> + explicit ComplexColorValue(Args&&... aArgs) + : ComplexColorData(Forward<Args>(aArgs)...) {} + ComplexColorValue(const ComplexColorValue&) = delete; + + NS_INLINE_DECL_REFCOUNTING(ComplexColorValue) + + size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const; + +private: + ~ComplexColorValue() {} +}; + +} // namespace css +} // namespace mozilla + +enum nsCSSUnit { + eCSSUnit_Null = 0, // (n/a) null unit, value is not specified + eCSSUnit_Auto = 1, // (n/a) value is algorithmic + eCSSUnit_Inherit = 2, // (n/a) value is inherited + eCSSUnit_Initial = 3, // (n/a) value is default UA value + eCSSUnit_Unset = 4, // (n/a) value equivalent to 'initial' if on a reset property, 'inherit' otherwise + eCSSUnit_None = 5, // (n/a) value is none + eCSSUnit_Normal = 6, // (n/a) value is normal (algorithmic, different than auto) + eCSSUnit_System_Font = 7, // (n/a) value is -moz-use-system-font + eCSSUnit_All = 8, // (n/a) value is all + eCSSUnit_Dummy = 9, // (n/a) a fake but specified value, used + // only in temporary values + eCSSUnit_DummyInherit = 10, // (n/a) a fake but specified value, used + // only in temporary values + + eCSSUnit_String = 11, // (char16_t*) a string value + eCSSUnit_Ident = 12, // (char16_t*) a string value + eCSSUnit_Attr = 14, // (char16_t*) a attr(string) value + eCSSUnit_Local_Font = 15, // (char16_t*) a local font name + eCSSUnit_Font_Format = 16, // (char16_t*) a font format name + eCSSUnit_Element = 17, // (char16_t*) an element id + + eCSSUnit_Array = 20, // (nsCSSValue::Array*) a list of values + eCSSUnit_Counter = 21, // (nsCSSValue::Array*) a counter(string,[string]) value + eCSSUnit_Counters = 22, // (nsCSSValue::Array*) a counters(string,string[,string]) value + eCSSUnit_Cubic_Bezier = 23, // (nsCSSValue::Array*) a list of float values + eCSSUnit_Steps = 24, // (nsCSSValue::Array*) a list of (integer, enumerated) + eCSSUnit_Symbols = 25, // (nsCSSValue::Array*) a symbols(enumerated, symbols) value + eCSSUnit_Function = 26, // (nsCSSValue::Array*) a function with + // parameters. First elem of array is name, + // an nsCSSKeyword as eCSSUnit_Enumerated, + // the rest of the values are arguments. + + // The top level of a calc() expression is eCSSUnit_Calc. All + // remaining eCSSUnit_Calc_* units only occur inside these toplevel + // calc values. + + // eCSSUnit_Calc has an array with exactly 1 element. eCSSUnit_Calc + // exists so we can distinguish calc(2em) from 2em as specified values + // (but we drop this distinction for nsStyleCoord when we store + // computed values). + eCSSUnit_Calc = 30, // (nsCSSValue::Array*) calc() value + // Plus, Minus, Times_* and Divided have arrays with exactly 2 + // elements. a + b + c + d is grouped as ((a + b) + c) + d + eCSSUnit_Calc_Plus = 31, // (nsCSSValue::Array*) + node within calc() + eCSSUnit_Calc_Minus = 32, // (nsCSSValue::Array*) - within calc + eCSSUnit_Calc_Times_L = 33, // (nsCSSValue::Array*) num * val within calc + eCSSUnit_Calc_Times_R = 34, // (nsCSSValue::Array*) val * num within calc + eCSSUnit_Calc_Divided = 35, // (nsCSSValue::Array*) / within calc + + eCSSUnit_URL = 40, // (nsCSSValue::URL*) value + eCSSUnit_Image = 41, // (nsCSSValue::Image*) value + eCSSUnit_Gradient = 42, // (nsCSSValueGradient*) value + eCSSUnit_TokenStream = 43, // (nsCSSValueTokenStream*) value + eCSSUnit_GridTemplateAreas = 44, // (GridTemplateAreasValue*) + // for grid-template-areas + + eCSSUnit_Pair = 50, // (nsCSSValuePair*) pair of values + eCSSUnit_Triplet = 51, // (nsCSSValueTriplet*) triplet of values + eCSSUnit_Rect = 52, // (nsCSSRect*) rectangle (four values) + eCSSUnit_List = 53, // (nsCSSValueList*) list of values + eCSSUnit_ListDep = 54, // (nsCSSValueList*) same as List + // but does not own the list + eCSSUnit_SharedList = 55, // (nsCSSValueSharedList*) same as list + // but reference counted and shared + eCSSUnit_PairList = 56, // (nsCSSValuePairList*) list of value pairs + eCSSUnit_PairListDep = 57, // (nsCSSValuePairList*) same as PairList + // but does not own the list + + eCSSUnit_FontFamilyList = 58, // (FontFamilyList*) value + + eCSSUnit_Integer = 70, // (int) simple value + eCSSUnit_Enumerated = 71, // (int) value has enumerated meaning + + eCSSUnit_EnumColor = 80, // (int) enumerated color (kColorKTable) + eCSSUnit_RGBColor = 81, // (nscolor) an opaque RGBA value specified as rgb() + eCSSUnit_RGBAColor = 82, // (nscolor) an RGBA value specified as rgba() + eCSSUnit_HexColor = 83, // (nscolor) an opaque RGBA value specified as #rrggbb + eCSSUnit_ShortHexColor = 84, // (nscolor) an opaque RGBA value specified as #rgb + eCSSUnit_HexColorAlpha = 85, // (nscolor) an opaque RGBA value specified as #rrggbbaa + eCSSUnit_ShortHexColorAlpha = 86, // (nscolor) an opaque RGBA value specified as #rgba + eCSSUnit_PercentageRGBColor = 87, // (nsCSSValueFloatColor*) an opaque + // RGBA value specified as rgb() with + // percentage components. Values over + // 100% are allowed. + eCSSUnit_PercentageRGBAColor = 88, // (nsCSSValueFloatColor*) an RGBA value + // specified as rgba() with percentage + // components. Values over 100% are + // allowed. + eCSSUnit_HSLColor = 89, // (nsCSSValueFloatColor*) + eCSSUnit_HSLAColor = 90, // (nsCSSValueFloatColor*) + eCSSUnit_ComplexColor = 91, // (ComplexColorValue*) + + eCSSUnit_Percent = 100, // (float) 1.0 == 100%) value is percentage of something + eCSSUnit_Number = 101, // (float) value is numeric (usually multiplier, different behavior than percent) + + // Physical length units + eCSSUnit_PhysicalMillimeter = 200, // (float) 1/25.4 inch + + // Length units - relative + // Viewport relative measure + eCSSUnit_ViewportWidth = 700, // (float) 1% of the width of the initial containing block + eCSSUnit_ViewportHeight = 701, // (float) 1% of the height of the initial containing block + eCSSUnit_ViewportMin = 702, // (float) smaller of ViewportWidth and ViewportHeight + eCSSUnit_ViewportMax = 703, // (float) larger of ViewportWidth and ViewportHeight + + // Font relative measure + eCSSUnit_EM = 800, // (float) == current font size + eCSSUnit_XHeight = 801, // (float) distance from top of lower case x to baseline + eCSSUnit_Char = 802, // (float) number of characters, used for width with monospace font + eCSSUnit_RootEM = 803, // (float) == root element font size + + // Screen relative measure + eCSSUnit_Point = 900, // (float) 4/3 of a CSS pixel + eCSSUnit_Inch = 901, // (float) 96 CSS pixels + eCSSUnit_Millimeter = 902, // (float) 96/25.4 CSS pixels + eCSSUnit_Centimeter = 903, // (float) 96/2.54 CSS pixels + eCSSUnit_Pica = 904, // (float) 12 points == 16 CSS pixls + eCSSUnit_Quarter = 905, // (float) 96/101.6 CSS pixels + eCSSUnit_Pixel = 906, // (float) CSS pixel unit + + // Angular units + eCSSUnit_Degree = 1000, // (float) 360 per circle + eCSSUnit_Grad = 1001, // (float) 400 per circle + eCSSUnit_Radian = 1002, // (float) 2*pi per circle + eCSSUnit_Turn = 1003, // (float) 1 per circle + + // Frequency units + eCSSUnit_Hertz = 2000, // (float) 1/seconds + eCSSUnit_Kilohertz = 2001, // (float) 1000 Hertz + + // Time units + eCSSUnit_Seconds = 3000, // (float) Standard time + eCSSUnit_Milliseconds = 3001, // (float) 1/1000 second + + // Flexible fraction (CSS Grid) + eCSSUnit_FlexFraction = 4000 // (float) Fraction of free space +}; + +struct nsCSSValueGradient; +struct nsCSSValuePair; +struct nsCSSValuePair_heap; +struct nsCSSValueTokenStream; +struct nsCSSRect; +struct nsCSSRect_heap; +struct nsCSSValueList; +struct nsCSSValueList_heap; +struct nsCSSValueSharedList; +struct nsCSSValuePairList; +struct nsCSSValuePairList_heap; +struct nsCSSValueTriplet; +struct nsCSSValueTriplet_heap; +class nsCSSValueFloatColor; + +class nsCSSValue { +public: + struct Array; + friend struct Array; + + friend struct mozilla::css::URLValueData; + + friend struct mozilla::css::ImageValue; + + // for valueless units only (null, auto, inherit, none, all, normal) + explicit nsCSSValue(nsCSSUnit aUnit = eCSSUnit_Null) + : mUnit(aUnit) + { + MOZ_ASSERT(aUnit <= eCSSUnit_DummyInherit, "not a valueless unit"); + } + + nsCSSValue(int32_t aValue, nsCSSUnit aUnit); + nsCSSValue(float aValue, nsCSSUnit aUnit); + nsCSSValue(const nsString& aValue, nsCSSUnit aUnit); + nsCSSValue(Array* aArray, nsCSSUnit aUnit); + explicit nsCSSValue(mozilla::css::URLValue* aValue); + explicit nsCSSValue(mozilla::css::ImageValue* aValue); + explicit nsCSSValue(nsCSSValueGradient* aValue); + explicit nsCSSValue(nsCSSValueTokenStream* aValue); + explicit nsCSSValue(mozilla::css::GridTemplateAreasValue* aValue); + explicit nsCSSValue(mozilla::css::FontFamilyListRefCnt* aValue); + nsCSSValue(const nsCSSValue& aCopy); + nsCSSValue(nsCSSValue&& aOther) + : mUnit(aOther.mUnit) + , mValue(aOther.mValue) + { + aOther.mUnit = eCSSUnit_Null; + } + ~nsCSSValue() { Reset(); } + + nsCSSValue& operator=(const nsCSSValue& aCopy); + nsCSSValue& operator=(nsCSSValue&& aCopy); + bool operator==(const nsCSSValue& aOther) const; + + bool operator!=(const nsCSSValue& aOther) const + { + return !(*this == aOther); + } + + // Enum for AppendToString's aValueSerialization argument. + enum Serialization { eNormalized, eAuthorSpecified }; + + /** + * Serialize |this| as a specified value for |aProperty| and append + * it to |aResult|. + */ + void AppendToString(nsCSSPropertyID aProperty, nsAString& aResult, + Serialization aValueSerialization) const; + + nsCSSUnit GetUnit() const { return mUnit; } + bool IsLengthUnit() const + { return eCSSUnit_PhysicalMillimeter <= mUnit && mUnit <= eCSSUnit_Pixel; } + bool IsLengthPercentCalcUnit() const + { return IsLengthUnit() || mUnit == eCSSUnit_Percent || IsCalcUnit(); } + /** + * A "fixed" length unit is one that means a specific physical length + * which we try to match based on the physical characteristics of an + * output device. + */ + bool IsFixedLengthUnit() const + { return mUnit == eCSSUnit_PhysicalMillimeter; } + /** + * What the spec calls relative length units is, for us, split + * between relative length units and pixel length units. + * + * A "relative" length unit is a multiple of some derived metric, + * such as a font em-size, which itself was controlled by an input CSS + * length. Relative length units should not be scaled by zooming, since + * the underlying CSS length would already have been scaled. + */ + bool IsRelativeLengthUnit() const + { return eCSSUnit_EM <= mUnit && mUnit <= eCSSUnit_RootEM; } + /** + * A "pixel" length unit is a some multiple of CSS pixels. + */ + static bool IsPixelLengthUnit(nsCSSUnit aUnit) + { return eCSSUnit_Point <= aUnit && aUnit <= eCSSUnit_Pixel; } + bool IsPixelLengthUnit() const + { return IsPixelLengthUnit(mUnit); } + static bool IsPercentLengthUnit(nsCSSUnit aUnit) + { return aUnit == eCSSUnit_Percent; } + bool IsPercentLengthUnit() + { return IsPercentLengthUnit(mUnit); } + static bool IsFloatUnit(nsCSSUnit aUnit) + { return eCSSUnit_Number <= aUnit; } + bool IsAngularUnit() const + { return eCSSUnit_Degree <= mUnit && mUnit <= eCSSUnit_Turn; } + bool IsFrequencyUnit() const + { return eCSSUnit_Hertz <= mUnit && mUnit <= eCSSUnit_Kilohertz; } + bool IsTimeUnit() const + { return eCSSUnit_Seconds <= mUnit && mUnit <= eCSSUnit_Milliseconds; } + bool IsCalcUnit() const + { return eCSSUnit_Calc <= mUnit && mUnit <= eCSSUnit_Calc_Divided; } + + bool UnitHasStringValue() const + { return eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Element; } + bool UnitHasArrayValue() const + { return eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Calc_Divided; } + + // Checks for the nsCSSValue being of a particular type of color unit: + // + // - IsIntegerColorUnit returns true for: + // eCSSUnit_RGBColor -- rgb(int,int,int) + // eCSSUnit_RGBAColor -- rgba(int,int,int,float) + // eCSSUnit_HexColor -- #rrggbb + // eCSSUnit_ShortHexColor -- #rgb + // eCSSUnit_HexColorAlpha -- #rrggbbaa + // eCSSUnit_ShortHexColorAlpha -- #rgba + // + // - IsFloatColorUnit returns true for: + // eCSSUnit_PercentageRGBColor -- rgb(%,%,%) + // eCSSUnit_PercentageRGBAColor -- rgba(%,%,%,float) + // eCSSUnit_HSLColor -- hsl(float,%,%) + // eCSSUnit_HSLAColor -- hsla(float,%,%,float) + // + // - IsNumericColorUnit returns true for any of the above units. + // + // Note that color keywords and system colors are represented by + // eCSSUnit_EnumColor and eCSSUnit_Ident. + bool IsIntegerColorUnit() const { return IsIntegerColorUnit(mUnit); } + bool IsFloatColorUnit() const { return IsFloatColorUnit(mUnit); } + bool IsNumericColorUnit() const { return IsNumericColorUnit(mUnit); } + static bool IsIntegerColorUnit(nsCSSUnit aUnit) + { return eCSSUnit_RGBColor <= aUnit && aUnit <= eCSSUnit_ShortHexColorAlpha; } + static bool IsFloatColorUnit(nsCSSUnit aUnit) + { return eCSSUnit_PercentageRGBColor <= aUnit && + aUnit <= eCSSUnit_HSLAColor; } + static bool IsNumericColorUnit(nsCSSUnit aUnit) + { return IsIntegerColorUnit(aUnit) || IsFloatColorUnit(aUnit); } + + int32_t GetIntValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_Integer || + mUnit == eCSSUnit_Enumerated || + mUnit == eCSSUnit_EnumColor, + "not an int value"); + return mValue.mInt; + } + + nsCSSKeyword GetKeywordValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_Enumerated, "not a keyword value"); + return static_cast<nsCSSKeyword>(mValue.mInt); + } + + float GetPercentValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_Percent, "not a percent value"); + return mValue.mFloat; + } + + float GetFloatValue() const + { + MOZ_ASSERT(eCSSUnit_Number <= mUnit, "not a float value"); + MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat)); + return mValue.mFloat; + } + + float GetAngleValue() const + { + MOZ_ASSERT(eCSSUnit_Degree <= mUnit && mUnit <= eCSSUnit_Turn, + "not an angle value"); + return mValue.mFloat; + } + + // Converts any angle to radians. + double GetAngleValueInRadians() const; + + // Converts any angle to degrees. + double GetAngleValueInDegrees() const; + + nsAString& GetStringValue(nsAString& aBuffer) const + { + MOZ_ASSERT(UnitHasStringValue(), "not a string value"); + aBuffer.Truncate(); + uint32_t len = NS_strlen(GetBufferValue(mValue.mString)); + mValue.mString->ToString(len, aBuffer); + return aBuffer; + } + + const char16_t* GetStringBufferValue() const + { + MOZ_ASSERT(UnitHasStringValue(), "not a string value"); + return GetBufferValue(mValue.mString); + } + + nscolor GetColorValue() const; + bool IsNonTransparentColor() const; + mozilla::StyleComplexColor GetStyleComplexColorValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_ComplexColor); + return mValue.mComplexColor->ToComplexColor(); + } + + Array* GetArrayValue() const + { + MOZ_ASSERT(UnitHasArrayValue(), "not an array value"); + return mValue.mArray; + } + + nsIURI* GetURLValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, + "not a URL value"); + return mUnit == eCSSUnit_URL ? + mValue.mURL->GetURI() : mValue.mImage->GetURI(); + } + + nsCSSValueGradient* GetGradientValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_Gradient, "not a gradient value"); + return mValue.mGradient; + } + + nsCSSValueTokenStream* GetTokenStreamValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_TokenStream, "not a token stream value"); + return mValue.mTokenStream; + } + + nsCSSValueSharedList* GetSharedListValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_SharedList, "not a shared list value"); + return mValue.mSharedList; + } + + mozilla::FontFamilyList* GetFontFamilyListValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_FontFamilyList, + "not a font family list value"); + NS_ASSERTION(mValue.mFontFamilyList != nullptr, + "font family list value should never be null"); + return mValue.mFontFamilyList; + } + + // bodies of these are below + inline nsCSSValuePair& GetPairValue(); + inline const nsCSSValuePair& GetPairValue() const; + + inline nsCSSRect& GetRectValue(); + inline const nsCSSRect& GetRectValue() const; + + inline nsCSSValueList* GetListValue(); + inline const nsCSSValueList* GetListValue() const; + + inline nsCSSValuePairList* GetPairListValue(); + inline const nsCSSValuePairList* GetPairListValue() const; + + inline nsCSSValueTriplet& GetTripletValue(); + inline const nsCSSValueTriplet& GetTripletValue() const; + + + mozilla::css::URLValue* GetURLStructValue() const + { + // Not allowing this for Image values, because if the caller takes + // a ref to them they won't be able to delete them properly. + MOZ_ASSERT(mUnit == eCSSUnit_URL, "not a URL value"); + return mValue.mURL; + } + + mozilla::css::ImageValue* GetImageStructValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_Image, "not an Image value"); + return mValue.mImage; + } + + mozilla::css::GridTemplateAreasValue* GetGridTemplateAreas() const + { + MOZ_ASSERT(mUnit == eCSSUnit_GridTemplateAreas, + "not a grid-template-areas value"); + return mValue.mGridTemplateAreas; + } + + const char16_t* GetOriginalURLValue() const + { + MOZ_ASSERT(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, + "not a URL value"); + return GetBufferValue(mUnit == eCSSUnit_URL ? + mValue.mURL->mString : + mValue.mImage->mString); + } + + // Not making this inline because that would force us to include + // imgIRequest.h, which leads to REQUIRES hell, since this header is included + // all over. + imgRequestProxy* GetImageValue(nsIDocument* aDocument) const; + + // Like GetImageValue, but additionally will pass the imgRequestProxy + // through nsContentUtils::GetStaticRequest if aPresContent is static. + already_AddRefed<imgRequestProxy> GetPossiblyStaticImageValue( + nsIDocument* aDocument, nsPresContext* aPresContext) const; + + nscoord GetFixedLength(nsPresContext* aPresContext) const; + nscoord GetPixelLength() const; + + nsCSSValueFloatColor* GetFloatColorValue() const + { + MOZ_ASSERT(IsFloatColorUnit(), "not a float color value"); + return mValue.mFloatColor; + } + + void Reset() // sets to null + { + if (mUnit != eCSSUnit_Null) + DoReset(); + } +private: + void DoReset(); + +public: + void SetIntValue(int32_t aValue, nsCSSUnit aUnit); + template<typename T, + typename = typename std::enable_if<std::is_enum<T>::value>::type> + void SetIntValue(T aValue, nsCSSUnit aUnit) + { + static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value, + "aValue must be an enum that fits within mValue.mInt"); + SetIntValue(static_cast<int32_t>(aValue), aUnit); + } + void SetPercentValue(float aValue); + void SetFloatValue(float aValue, nsCSSUnit aUnit); + void SetStringValue(const nsString& aValue, nsCSSUnit aUnit); + void SetColorValue(nscolor aValue); + void SetIntegerColorValue(nscolor aValue, nsCSSUnit aUnit); + // converts the nscoord to pixels + void SetIntegerCoordValue(nscoord aCoord); + void SetFloatColorValue(float aComponent1, + float aComponent2, + float aComponent3, + float aAlpha, nsCSSUnit aUnit); + void SetRGBAColorValue(const mozilla::css::RGBAColorData& aValue); + void SetComplexColorValue( + already_AddRefed<mozilla::css::ComplexColorValue> aValue); + void SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit); + void SetURLValue(mozilla::css::URLValue* aURI); + void SetImageValue(mozilla::css::ImageValue* aImage); + void SetGradientValue(nsCSSValueGradient* aGradient); + void SetTokenStreamValue(nsCSSValueTokenStream* aTokenStream); + void SetGridTemplateAreas(mozilla::css::GridTemplateAreasValue* aValue); + void SetFontFamilyListValue(mozilla::css::FontFamilyListRefCnt* aFontListValue); + void SetPairValue(const nsCSSValuePair* aPair); + void SetPairValue(const nsCSSValue& xValue, const nsCSSValue& yValue); + void SetSharedListValue(nsCSSValueSharedList* aList); + void SetDependentListValue(nsCSSValueList* aList); + void SetDependentPairListValue(nsCSSValuePairList* aList); + void SetTripletValue(const nsCSSValueTriplet* aTriplet); + void SetTripletValue(const nsCSSValue& xValue, const nsCSSValue& yValue, const nsCSSValue& zValue); + void SetAutoValue(); + void SetInheritValue(); + void SetInitialValue(); + void SetUnsetValue(); + void SetNoneValue(); + void SetAllValue(); + void SetNormalValue(); + void SetSystemFontValue(); + void SetDummyValue(); + void SetDummyInheritValue(); + + // Converts an nsStyleCoord::CalcValue back into a CSSValue + void SetCalcValue(const nsStyleCoord::CalcValue* aCalc); + + // These are a little different - they allocate storage for you and + // return a handle. + nsCSSRect& SetRectValue(); + nsCSSValueList* SetListValue(); + nsCSSValuePairList* SetPairListValue(); + + // These take ownership of the passed-in resource. + void AdoptListValue(mozilla::UniquePtr<nsCSSValueList> aValue); + void AdoptPairListValue(mozilla::UniquePtr<nsCSSValuePairList> aValue); + + void StartImageLoad(nsIDocument* aDocument) const; // Only pretend const + + // Initializes as a function value with the specified function id. + Array* InitFunction(nsCSSKeyword aFunctionId, uint32_t aNumArgs); + // Checks if this is a function value with the specified function id. + bool EqualsFunction(nsCSSKeyword aFunctionId) const; + + // Returns an already addrefed buffer. Guaranteed to return non-null. + // (Will abort on allocation failure.) + static already_AddRefed<nsStringBuffer> + BufferFromString(const nsString& aValue); + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + static void + AppendSidesShorthandToString(const nsCSSPropertyID aProperties[], + const nsCSSValue* aValues[], + nsAString& aString, + Serialization aSerialization); + static void + AppendBasicShapeRadiusToString(const nsCSSPropertyID aProperties[], + const nsCSSValue* aValues[], + nsAString& aResult, + Serialization aValueSerialization); + static void + AppendAlignJustifyValueToString(int32_t aValue, nsAString& aResult); + +private: + static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) { + return static_cast<char16_t*>(aBuffer->Data()); + } + + void AppendPolygonToString(nsCSSPropertyID aProperty, nsAString& aResult, + Serialization aValueSerialization) const; + void AppendPositionCoordinateToString(const nsCSSValue& aValue, + nsCSSPropertyID aProperty, + nsAString& aResult, + Serialization aSerialization) const; + void AppendCircleOrEllipseToString( + nsCSSKeyword aFunctionId, + nsCSSPropertyID aProperty, nsAString& aResult, + Serialization aValueSerialization) const; + void AppendBasicShapePositionToString( + nsAString& aResult, + Serialization aValueSerialization) const; + void AppendInsetToString(nsCSSPropertyID aProperty, nsAString& aResult, + Serialization aValueSerialization) const; +protected: + nsCSSUnit mUnit; + union { + int32_t mInt; + float mFloat; + // Note: the capacity of the buffer may exceed the length of the string. + // If we're of a string type, mString is not null. + nsStringBuffer* MOZ_OWNING_REF mString; + nscolor mColor; + Array* MOZ_OWNING_REF mArray; + mozilla::css::URLValue* MOZ_OWNING_REF mURL; + mozilla::css::ImageValue* MOZ_OWNING_REF mImage; + mozilla::css::GridTemplateAreasValue* MOZ_OWNING_REF mGridTemplateAreas; + nsCSSValueGradient* MOZ_OWNING_REF mGradient; + nsCSSValueTokenStream* MOZ_OWNING_REF mTokenStream; + nsCSSValuePair_heap* MOZ_OWNING_REF mPair; + nsCSSRect_heap* MOZ_OWNING_REF mRect; + nsCSSValueTriplet_heap* MOZ_OWNING_REF mTriplet; + nsCSSValueList_heap* MOZ_OWNING_REF mList; + nsCSSValueList* mListDependent; + nsCSSValueSharedList* MOZ_OWNING_REF mSharedList; + nsCSSValuePairList_heap* MOZ_OWNING_REF mPairList; + nsCSSValuePairList* mPairListDependent; + nsCSSValueFloatColor* MOZ_OWNING_REF mFloatColor; + mozilla::css::FontFamilyListRefCnt* MOZ_OWNING_REF mFontFamilyList; + mozilla::css::ComplexColorValue* MOZ_OWNING_REF mComplexColor; + } mValue; +}; + +struct nsCSSValue::Array final { + + // return |Array| with reference count of zero + static Array* Create(size_t aItemCount) { + return new (aItemCount) Array(aItemCount); + } + + nsCSSValue& operator[](size_t aIndex) { + MOZ_ASSERT(aIndex < mCount, "out of range"); + return mArray[aIndex]; + } + + const nsCSSValue& operator[](size_t aIndex) const { + MOZ_ASSERT(aIndex < mCount, "out of range"); + return mArray[aIndex]; + } + + nsCSSValue& Item(size_t aIndex) { return (*this)[aIndex]; } + const nsCSSValue& Item(size_t aIndex) const { return (*this)[aIndex]; } + + size_t Count() const { return mCount; } + + // callers depend on the items being contiguous + nsCSSValue* ItemStorage() { + return this->First(); + } + + bool operator==(const Array& aOther) const + { + if (mCount != aOther.mCount) + return false; + for (size_t i = 0; i < mCount; ++i) + if ((*this)[i] != aOther[i]) + return false; + return true; + } + + // XXXdholbert This uses a size_t ref count. Should we use a variant + // of NS_INLINE_DECL_REFCOUNTING that takes a type as an argument? + void AddRef() { + if (mRefCnt == size_t(-1)) { // really want SIZE_MAX + NS_WARNING("refcount overflow, leaking nsCSSValue::Array"); + return; + } + ++mRefCnt; + NS_LOG_ADDREF(this, mRefCnt, "nsCSSValue::Array", sizeof(*this)); + } + void Release() { + if (mRefCnt == size_t(-1)) { // really want SIZE_MAX + NS_WARNING("refcount overflow, leaking nsCSSValue::Array"); + return; + } + --mRefCnt; + NS_LOG_RELEASE(this, mRefCnt, "nsCSSValue::Array"); + if (mRefCnt == 0) + delete this; + } + +private: + + size_t mRefCnt; + const size_t mCount; + // This must be the last sub-object, since we extend this array to + // be of size mCount; it needs to be a sub-object so it gets proper + // alignment. + nsCSSValue mArray[1]; + + void* operator new(size_t aSelfSize, size_t aItemCount) CPP_THROW_NEW { + MOZ_ASSERT(aItemCount > 0, "cannot have a 0 item count"); + return ::operator new(aSelfSize + sizeof(nsCSSValue) * (aItemCount - 1)); + } + + void operator delete(void* aPtr) { ::operator delete(aPtr); } + + nsCSSValue* First() { return mArray; } + + const nsCSSValue* First() const { return mArray; } + +#define CSSVALUE_LIST_FOR_EXTRA_VALUES(var) \ + for (nsCSSValue *var = First() + 1, *var##_end = First() + mCount; \ + var != var##_end; ++var) + + explicit Array(size_t aItemCount) + : mRefCnt(0) + , mCount(aItemCount) + { + MOZ_COUNT_CTOR(nsCSSValue::Array); + CSSVALUE_LIST_FOR_EXTRA_VALUES(val) { + new (val) nsCSSValue(); + } + } + + ~Array() + { + MOZ_COUNT_DTOR(nsCSSValue::Array); + CSSVALUE_LIST_FOR_EXTRA_VALUES(val) { + val->~nsCSSValue(); + } + } + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +#undef CSSVALUE_LIST_FOR_EXTRA_VALUES + +private: + Array(const Array& aOther) = delete; + Array& operator=(const Array& aOther) = delete; +}; + +// Prefer nsCSSValue::Array for lists of fixed size. +struct nsCSSValueList { + nsCSSValueList() : mNext(nullptr) { MOZ_COUNT_CTOR(nsCSSValueList); } + ~nsCSSValueList(); + + nsCSSValueList* Clone() const; // makes a deep copy. Infallible. + void CloneInto(nsCSSValueList* aList) const; // makes a deep copy into aList + void AppendToString(nsCSSPropertyID aProperty, nsAString& aResult, + nsCSSValue::Serialization aValueSerialization) const; + + static bool Equal(const nsCSSValueList* aList1, + const nsCSSValueList* aList2); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + nsCSSValue mValue; + nsCSSValueList* mNext; + +private: + nsCSSValueList(const nsCSSValueList& aCopy) // makes a shallow copy + : mValue(aCopy.mValue), mNext(nullptr) + { + MOZ_COUNT_CTOR(nsCSSValueList); + } + + // We don't want operator== or operator!= because they wouldn't be + // null-safe, which is generally what we need. Use |Equal| method + // above instead. + bool operator==(nsCSSValueList const& aOther) const = delete; + bool operator!=(const nsCSSValueList& aOther) const = delete; +}; + +// nsCSSValueList_heap differs from nsCSSValueList only in being +// refcounted. It should not be necessary to use this class directly; +// it's an implementation detail of nsCSSValue. +struct nsCSSValueList_heap final : public nsCSSValueList { + NS_INLINE_DECL_REFCOUNTING(nsCSSValueList_heap) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSValueList_heap() + { + } +}; + +// This is a reference counted list value. Note that the object is +// a wrapper for the reference count and a pointer to the head of the +// list, whereas the other list types (such as nsCSSValueList) do +// not have such a wrapper. +struct nsCSSValueSharedList final { + nsCSSValueSharedList() + : mHead(nullptr) + { + MOZ_COUNT_CTOR(nsCSSValueSharedList); + } + + // Takes ownership of aList. + explicit nsCSSValueSharedList(nsCSSValueList* aList) + : mHead(aList) + { + MOZ_COUNT_CTOR(nsCSSValueSharedList); + } + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSValueSharedList(); + +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsCSSValueSharedList) + + void AppendToString(nsCSSPropertyID aProperty, nsAString& aResult, + nsCSSValue::Serialization aValueSerialization) const; + + bool operator==(nsCSSValueSharedList const& aOther) const; + bool operator!=(const nsCSSValueSharedList& aOther) const + { return !(*this == aOther); } + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + nsCSSValueList* mHead; +}; + +// This has to be here so that the relationship between nsCSSValueList +// and nsCSSValueList_heap is visible. +inline nsCSSValueList* +nsCSSValue::GetListValue() +{ + if (mUnit == eCSSUnit_List) + return mValue.mList; + else { + MOZ_ASSERT(mUnit == eCSSUnit_ListDep, "not a list value"); + return mValue.mListDependent; + } +} + +inline const nsCSSValueList* +nsCSSValue::GetListValue() const +{ + if (mUnit == eCSSUnit_List) + return mValue.mList; + else { + MOZ_ASSERT(mUnit == eCSSUnit_ListDep, "not a list value"); + return mValue.mListDependent; + } +} + +struct nsCSSRect { + nsCSSRect(void); + nsCSSRect(const nsCSSRect& aCopy); + ~nsCSSRect(); + + void AppendToString(nsCSSPropertyID aProperty, nsAString& aResult, + nsCSSValue::Serialization aValueSerialization) const; + + bool operator==(const nsCSSRect& aOther) const { + return mTop == aOther.mTop && + mRight == aOther.mRight && + mBottom == aOther.mBottom && + mLeft == aOther.mLeft; + } + + bool operator!=(const nsCSSRect& aOther) const { + return mTop != aOther.mTop || + mRight != aOther.mRight || + mBottom != aOther.mBottom || + mLeft != aOther.mLeft; + } + + void SetAllSidesTo(const nsCSSValue& aValue); + + bool AllSidesEqualTo(const nsCSSValue& aValue) const { + return mTop == aValue && + mRight == aValue && + mBottom == aValue && + mLeft == aValue; + } + + void Reset() { + mTop.Reset(); + mRight.Reset(); + mBottom.Reset(); + mLeft.Reset(); + } + + bool HasValue() const { + return + mTop.GetUnit() != eCSSUnit_Null || + mRight.GetUnit() != eCSSUnit_Null || + mBottom.GetUnit() != eCSSUnit_Null || + mLeft.GetUnit() != eCSSUnit_Null; + } + + nsCSSValue mTop; + nsCSSValue mRight; + nsCSSValue mBottom; + nsCSSValue mLeft; + + typedef nsCSSValue nsCSSRect::*side_type; + static const side_type sides[4]; +}; + +// nsCSSRect_heap differs from nsCSSRect only in being +// refcounted. It should not be necessary to use this class directly; +// it's an implementation detail of nsCSSValue. +struct nsCSSRect_heap final : public nsCSSRect { + NS_INLINE_DECL_REFCOUNTING(nsCSSRect_heap) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSRect_heap() + { + } +}; + +// This has to be here so that the relationship between nsCSSRect +// and nsCSSRect_heap is visible. +inline nsCSSRect& +nsCSSValue::GetRectValue() +{ + MOZ_ASSERT(mUnit == eCSSUnit_Rect, "not a rect value"); + return *mValue.mRect; +} + +inline const nsCSSRect& +nsCSSValue::GetRectValue() const +{ + MOZ_ASSERT(mUnit == eCSSUnit_Rect, "not a rect value"); + return *mValue.mRect; +} + +struct nsCSSValuePair { + nsCSSValuePair() + { + MOZ_COUNT_CTOR(nsCSSValuePair); + } + explicit nsCSSValuePair(nsCSSUnit aUnit) + : mXValue(aUnit), mYValue(aUnit) + { + MOZ_COUNT_CTOR(nsCSSValuePair); + } + nsCSSValuePair(const nsCSSValue& aXValue, const nsCSSValue& aYValue) + : mXValue(aXValue), mYValue(aYValue) + { + MOZ_COUNT_CTOR(nsCSSValuePair); + } + nsCSSValuePair(const nsCSSValuePair& aCopy) + : mXValue(aCopy.mXValue), mYValue(aCopy.mYValue) + { + MOZ_COUNT_CTOR(nsCSSValuePair); + } + ~nsCSSValuePair() + { + MOZ_COUNT_DTOR(nsCSSValuePair); + } + + nsCSSValuePair& operator=(const nsCSSValuePair& aOther) { + mXValue = aOther.mXValue; + mYValue = aOther.mYValue; + return *this; + } + + bool operator==(const nsCSSValuePair& aOther) const { + return mXValue == aOther.mXValue && + mYValue == aOther.mYValue; + } + + bool operator!=(const nsCSSValuePair& aOther) const { + return mXValue != aOther.mXValue || + mYValue != aOther.mYValue; + } + + bool BothValuesEqualTo(const nsCSSValue& aValue) const { + return mXValue == aValue && + mYValue == aValue; + } + + void SetBothValuesTo(const nsCSSValue& aValue) { + mXValue = aValue; + mYValue = aValue; + } + + void Reset() { + mXValue.Reset(); + mYValue.Reset(); + } + + bool HasValue() const { + return mXValue.GetUnit() != eCSSUnit_Null || + mYValue.GetUnit() != eCSSUnit_Null; + } + + void AppendToString(nsCSSPropertyID aProperty, nsAString& aResult, + nsCSSValue::Serialization aValueSerialization) const; + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + nsCSSValue mXValue; + nsCSSValue mYValue; +}; + +// nsCSSValuePair_heap differs from nsCSSValuePair only in being +// refcounted. It should not be necessary to use this class directly; +// it's an implementation detail of nsCSSValue. +struct nsCSSValuePair_heap final : public nsCSSValuePair { + // forward constructor + nsCSSValuePair_heap(const nsCSSValue& aXValue, const nsCSSValue& aYValue) + : nsCSSValuePair(aXValue, aYValue) + {} + + NS_INLINE_DECL_REFCOUNTING(nsCSSValuePair_heap) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSValuePair_heap() + { + } +}; + +struct nsCSSValueTriplet { + nsCSSValueTriplet() + { + MOZ_COUNT_CTOR(nsCSSValueTriplet); + } + explicit nsCSSValueTriplet(nsCSSUnit aUnit) + : mXValue(aUnit), mYValue(aUnit), mZValue(aUnit) + { + MOZ_COUNT_CTOR(nsCSSValueTriplet); + } + nsCSSValueTriplet(const nsCSSValue& aXValue, + const nsCSSValue& aYValue, + const nsCSSValue& aZValue) + : mXValue(aXValue), mYValue(aYValue), mZValue(aZValue) + { + MOZ_COUNT_CTOR(nsCSSValueTriplet); + } + nsCSSValueTriplet(const nsCSSValueTriplet& aCopy) + : mXValue(aCopy.mXValue), mYValue(aCopy.mYValue), mZValue(aCopy.mZValue) + { + MOZ_COUNT_CTOR(nsCSSValueTriplet); + } + ~nsCSSValueTriplet() + { + MOZ_COUNT_DTOR(nsCSSValueTriplet); + } + + bool operator==(const nsCSSValueTriplet& aOther) const { + return mXValue == aOther.mXValue && + mYValue == aOther.mYValue && + mZValue == aOther.mZValue; + } + + bool operator!=(const nsCSSValueTriplet& aOther) const { + return mXValue != aOther.mXValue || + mYValue != aOther.mYValue || + mZValue != aOther.mZValue; + } + + bool AllValuesEqualTo(const nsCSSValue& aValue) const { + return mXValue == aValue && + mYValue == aValue && + mZValue == aValue; + } + + void SetAllValuesTo(const nsCSSValue& aValue) { + mXValue = aValue; + mYValue = aValue; + mZValue = aValue; + } + + void Reset() { + mXValue.Reset(); + mYValue.Reset(); + mZValue.Reset(); + } + + bool HasValue() const { + return mXValue.GetUnit() != eCSSUnit_Null || + mYValue.GetUnit() != eCSSUnit_Null || + mZValue.GetUnit() != eCSSUnit_Null; + } + + void AppendToString(nsCSSPropertyID aProperty, nsAString& aResult, + nsCSSValue::Serialization aValueSerialization) const; + + nsCSSValue mXValue; + nsCSSValue mYValue; + nsCSSValue mZValue; +}; + +// nsCSSValueTriplet_heap differs from nsCSSValueTriplet only in being +// refcounted. It should not be necessary to use this class directly; +// it's an implementation detail of nsCSSValue. +struct nsCSSValueTriplet_heap final : public nsCSSValueTriplet { + // forward constructor + nsCSSValueTriplet_heap(const nsCSSValue& aXValue, const nsCSSValue& aYValue, const nsCSSValue& aZValue) + : nsCSSValueTriplet(aXValue, aYValue, aZValue) + {} + + NS_INLINE_DECL_REFCOUNTING(nsCSSValueTriplet_heap) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSValueTriplet_heap() + { + } +}; + +// This has to be here so that the relationship between nsCSSValuePair +// and nsCSSValuePair_heap is visible. +inline nsCSSValuePair& +nsCSSValue::GetPairValue() +{ + MOZ_ASSERT(mUnit == eCSSUnit_Pair, "not a pair value"); + return *mValue.mPair; +} + +inline const nsCSSValuePair& +nsCSSValue::GetPairValue() const +{ + MOZ_ASSERT(mUnit == eCSSUnit_Pair, "not a pair value"); + return *mValue.mPair; +} + +inline nsCSSValueTriplet& +nsCSSValue::GetTripletValue() +{ + MOZ_ASSERT(mUnit == eCSSUnit_Triplet, "not a triplet value"); + return *mValue.mTriplet; +} + +inline const nsCSSValueTriplet& +nsCSSValue::GetTripletValue() const +{ + MOZ_ASSERT(mUnit == eCSSUnit_Triplet, "not a triplet value"); + return *mValue.mTriplet; +} + +// Maybe should be replaced with nsCSSValueList and nsCSSValue::Array? +struct nsCSSValuePairList { + nsCSSValuePairList() : mNext(nullptr) { MOZ_COUNT_CTOR(nsCSSValuePairList); } + ~nsCSSValuePairList(); + + nsCSSValuePairList* Clone() const; // makes a deep copy. Infallible. + void AppendToString(nsCSSPropertyID aProperty, nsAString& aResult, + nsCSSValue::Serialization aValueSerialization) const; + + static bool Equal(const nsCSSValuePairList* aList1, + const nsCSSValuePairList* aList2); + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + nsCSSValue mXValue; + nsCSSValue mYValue; + nsCSSValuePairList* mNext; + +private: + nsCSSValuePairList(const nsCSSValuePairList& aCopy) // makes a shallow copy + : mXValue(aCopy.mXValue), mYValue(aCopy.mYValue), mNext(nullptr) + { + MOZ_COUNT_CTOR(nsCSSValuePairList); + } + + // We don't want operator== or operator!= because they wouldn't be + // null-safe, which is generally what we need. Use |Equal| method + // above instead. + bool operator==(const nsCSSValuePairList& aOther) const = delete; + bool operator!=(const nsCSSValuePairList& aOther) const = delete; +}; + +// nsCSSValuePairList_heap differs from nsCSSValuePairList only in being +// refcounted. It should not be necessary to use this class directly; +// it's an implementation detail of nsCSSValue. +struct nsCSSValuePairList_heap final : public nsCSSValuePairList { + NS_INLINE_DECL_REFCOUNTING(nsCSSValuePairList_heap) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSValuePairList_heap() + { + } +}; + +// This has to be here so that the relationship between nsCSSValuePairList +// and nsCSSValuePairList_heap is visible. +inline nsCSSValuePairList* +nsCSSValue::GetPairListValue() +{ + if (mUnit == eCSSUnit_PairList) + return mValue.mPairList; + else { + MOZ_ASSERT (mUnit == eCSSUnit_PairListDep, "not a pairlist value"); + return mValue.mPairListDependent; + } +} + +inline const nsCSSValuePairList* +nsCSSValue::GetPairListValue() const +{ + if (mUnit == eCSSUnit_PairList) + return mValue.mPairList; + else { + MOZ_ASSERT (mUnit == eCSSUnit_PairListDep, "not a pairlist value"); + return mValue.mPairListDependent; + } +} + +struct nsCSSValueGradientStop { +public: + nsCSSValueGradientStop(); + // needed to keep bloat logs happy when we use the TArray + // in nsCSSValueGradient + nsCSSValueGradientStop(const nsCSSValueGradientStop& aOther); + ~nsCSSValueGradientStop(); + + nsCSSValue mLocation; + nsCSSValue mColor; + // If mIsInterpolationHint is true, there is no color, just + // a location. + bool mIsInterpolationHint; + + bool operator==(const nsCSSValueGradientStop& aOther) const + { + return (mLocation == aOther.mLocation && + mIsInterpolationHint == aOther.mIsInterpolationHint && + (mIsInterpolationHint || mColor == aOther.mColor)); + } + + bool operator!=(const nsCSSValueGradientStop& aOther) const + { + return !(*this == aOther); + } + + size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; +}; + +struct nsCSSValueGradient final { + nsCSSValueGradient(bool aIsRadial, bool aIsRepeating); + + // true if gradient is radial, false if it is linear + bool mIsRadial; + bool mIsRepeating; + bool mIsLegacySyntax; + bool mIsExplicitSize; + // line position and angle + nsCSSValuePair mBgPos; + nsCSSValue mAngle; + + // Only meaningful if mIsRadial is true +private: + nsCSSValue mRadialValues[2]; +public: + nsCSSValue& GetRadialShape() + { + MOZ_ASSERT(!mIsExplicitSize); + return mRadialValues[0]; + } + const nsCSSValue& GetRadialShape() const + { + MOZ_ASSERT(!mIsExplicitSize); + return mRadialValues[0]; + } + nsCSSValue& GetRadialSize() + { + MOZ_ASSERT(!mIsExplicitSize); + return mRadialValues[1]; + } + const nsCSSValue& GetRadialSize() const + { + MOZ_ASSERT(!mIsExplicitSize); + return mRadialValues[1]; + } + nsCSSValue& GetRadiusX() + { + MOZ_ASSERT(mIsExplicitSize); + return mRadialValues[0]; + } + const nsCSSValue& GetRadiusX() const + { + MOZ_ASSERT(mIsExplicitSize); + return mRadialValues[0]; + } + nsCSSValue& GetRadiusY() + { + MOZ_ASSERT(mIsExplicitSize); + return mRadialValues[1]; + } + const nsCSSValue& GetRadiusY() const + { + MOZ_ASSERT(mIsExplicitSize); + return mRadialValues[1]; + } + + InfallibleTArray<nsCSSValueGradientStop> mStops; + + bool operator==(const nsCSSValueGradient& aOther) const + { + if (mIsRadial != aOther.mIsRadial || + mIsRepeating != aOther.mIsRepeating || + mIsLegacySyntax != aOther.mIsLegacySyntax || + mIsExplicitSize != aOther.mIsExplicitSize || + mBgPos != aOther.mBgPos || + mAngle != aOther.mAngle || + mRadialValues[0] != aOther.mRadialValues[0] || + mRadialValues[1] != aOther.mRadialValues[1]) + return false; + + if (mStops.Length() != aOther.mStops.Length()) + return false; + + for (uint32_t i = 0; i < mStops.Length(); i++) { + if (mStops[i] != aOther.mStops[i]) + return false; + } + + return true; + } + + bool operator!=(const nsCSSValueGradient& aOther) const + { + return !(*this == aOther); + } + + NS_INLINE_DECL_REFCOUNTING(nsCSSValueGradient) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSValueGradient() + { + } + + nsCSSValueGradient(const nsCSSValueGradient& aOther) = delete; + nsCSSValueGradient& operator=(const nsCSSValueGradient& aOther) = delete; +}; + +// A string value used primarily to represent variable references. +// +// Animation code, specifically the KeyframeUtils class, also uses this +// type as a container for various string values including: +// +// * Shorthand property values +// * Shorthand sentinel values used for testing failure conditions +// * Invalid longhand property values +// +// For the most part, the above values are not passed to functions that +// manipulate nsCSSValue objects in a generic fashion. Instead KeyframeUtils +// extracts the string from the nsCSSValueTokenStream and passes that around +// instead. The single exception is nsCSSValue::AppendToString which we use +// to serialize the string contained in the nsCSSValueTokenStream by ensuring +// the mShorthandPropertyID is set to eCSSProperty_UNKNOWN. +struct nsCSSValueTokenStream final { + nsCSSValueTokenStream(); + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSValueTokenStream(); + +public: + bool operator==(const nsCSSValueTokenStream& aOther) const + { + bool eq; + return mPropertyID == aOther.mPropertyID && + mShorthandPropertyID == aOther.mShorthandPropertyID && + mTokenStream.Equals(aOther.mTokenStream) && + mLevel == aOther.mLevel && + (mBaseURI == aOther.mBaseURI || + (mBaseURI && aOther.mBaseURI && + NS_SUCCEEDED(mBaseURI->Equals(aOther.mBaseURI, &eq)) && + eq)) && + (mSheetURI == aOther.mSheetURI || + (mSheetURI && aOther.mSheetURI && + NS_SUCCEEDED(mSheetURI->Equals(aOther.mSheetURI, &eq)) && + eq)) && + (mSheetPrincipal == aOther.mSheetPrincipal || + (mSheetPrincipal && aOther.mSheetPrincipal && + NS_SUCCEEDED(mSheetPrincipal->Equals(aOther.mSheetPrincipal, + &eq)) && + eq)); + } + + bool operator!=(const nsCSSValueTokenStream& aOther) const + { + return !(*this == aOther); + } + + NS_INLINE_DECL_REFCOUNTING(nsCSSValueTokenStream) + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + // The property that has mTokenStream as its unparsed specified value. + // When a variable reference is used in a shorthand property, a + // TokenStream value is stored as the specified value for each of its + // component longhand properties. + nsCSSPropertyID mPropertyID; + + // The shorthand property that had a value with a variable reference, + // which caused the longhand property identified by mPropertyID to have + // a TokenStream value. + nsCSSPropertyID mShorthandPropertyID; + + // The unparsed CSS corresponding to the specified value of the property. + // When the value of a shorthand property has a variable reference, the + // same mTokenStream value is used on each of the nsCSSValueTokenStream + // objects that will be set by parsing the shorthand. + nsString mTokenStream; + + nsCOMPtr<nsIURI> mBaseURI; + nsCOMPtr<nsIURI> mSheetURI; + nsCOMPtr<nsIPrincipal> mSheetPrincipal; + // XXX Should store sheet here (see Bug 952338) + // mozilla::CSSStyleSheet* mSheet; + uint32_t mLineNumber; + uint32_t mLineOffset; + mozilla::SheetType mLevel; + +private: + nsCSSValueTokenStream(const nsCSSValueTokenStream& aOther) = delete; + nsCSSValueTokenStream& operator=(const nsCSSValueTokenStream& aOther) = delete; +}; + +class nsCSSValueFloatColor final { +public: + nsCSSValueFloatColor(float aComponent1, float aComponent2, float aComponent3, + float aAlpha) + : mComponent1(aComponent1) + , mComponent2(aComponent2) + , mComponent3(aComponent3) + , mAlpha(aAlpha) + { + MOZ_COUNT_CTOR(nsCSSValueFloatColor); + } + +private: + // Private destructor, to discourage deletion outside of Release(): + ~nsCSSValueFloatColor() + { + MOZ_COUNT_DTOR(nsCSSValueFloatColor); + } + +public: + bool operator==(nsCSSValueFloatColor& aOther) const; + + nscolor GetColorValue(nsCSSUnit aUnit) const; + float Comp1() const { return mComponent1; } + float Comp2() const { return mComponent2; } + float Comp3() const { return mComponent3; } + float Alpha() const { return mAlpha; } + bool IsNonTransparentColor() const; + + void AppendToString(nsCSSUnit aUnit, nsAString& aResult) const; + + size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; + + NS_INLINE_DECL_REFCOUNTING(nsCSSValueFloatColor) + +private: + // The range of each component is. + // [0, 1] for HSLColor and HSLAColor. mComponent1 for hue, mComponent2 for + // saturation, mComponent3 for lightness. + // [0, 1] for saturation and lightness + // represents [0%, 100%]. + // [0, 1] for hue represents + // [0deg, 360deg]. + // + // [-float::max(), float::max()] for PercentageRGBColor, PercentageRGBAColor. + // 1.0 means 100%. + float mComponent1; + float mComponent2; + float mComponent3; + float mAlpha; + + nsCSSValueFloatColor(const nsCSSValueFloatColor& aOther) = delete; + nsCSSValueFloatColor& operator=(const nsCSSValueFloatColor& aOther) + = delete; +}; + +struct nsCSSCornerSizes { + nsCSSCornerSizes(void); + nsCSSCornerSizes(const nsCSSCornerSizes& aCopy); + ~nsCSSCornerSizes(); + + // argument is a "full corner" constant from nsStyleConsts.h + nsCSSValue const & GetCorner(uint32_t aCorner) const { + return this->*corners[aCorner]; + } + nsCSSValue & GetCorner(uint32_t aCorner) { + return this->*corners[aCorner]; + } + + bool operator==(const nsCSSCornerSizes& aOther) const { + NS_FOR_CSS_FULL_CORNERS(corner) { + if (this->GetCorner(corner) != aOther.GetCorner(corner)) + return false; + } + return true; + } + + bool operator!=(const nsCSSCornerSizes& aOther) const { + NS_FOR_CSS_FULL_CORNERS(corner) { + if (this->GetCorner(corner) != aOther.GetCorner(corner)) + return true; + } + return false; + } + + bool HasValue() const { + NS_FOR_CSS_FULL_CORNERS(corner) { + if (this->GetCorner(corner).GetUnit() != eCSSUnit_Null) + return true; + } + return false; + } + + void Reset(); + + nsCSSValue mTopLeft; + nsCSSValue mTopRight; + nsCSSValue mBottomRight; + nsCSSValue mBottomLeft; + +protected: + typedef nsCSSValue nsCSSCornerSizes::*corner_type; + static const corner_type corners[4]; +}; + +#endif /* nsCSSValue_h___ */ + |