michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* representation of simple property values within CSS declarations */ michael@0: michael@0: #ifndef nsCSSValue_h___ michael@0: #define nsCSSValue_h___ michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/FloatingPoint.h" michael@0: #include "mozilla/MemoryReporting.h" michael@0: michael@0: #include "nsIPrincipal.h" michael@0: #include "nsIURI.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsCRTGlue.h" michael@0: #include "nsCSSKeywords.h" michael@0: #include "nsCSSProperty.h" michael@0: #include "nsColor.h" michael@0: #include "nsCoord.h" michael@0: #include "nsRefPtrHashtable.h" michael@0: #include "nsString.h" michael@0: #include "nsStringBuffer.h" michael@0: #include "nsTArray.h" michael@0: #include "nsStyleConsts.h" michael@0: michael@0: class imgRequestProxy; michael@0: class nsCSSStyleSheet; michael@0: class nsIDocument; michael@0: class nsIPrincipal; michael@0: class nsIURI; michael@0: class nsPresContext; michael@0: template michael@0: class nsPtrHashKey; michael@0: michael@0: // Deletes a linked list iteratively to avoid blowing up the stack (bug 456196). michael@0: #define NS_CSS_DELETE_LIST_MEMBER(type_, ptr_, member_) \ michael@0: { \ michael@0: type_ *cur = (ptr_)->member_; \ michael@0: (ptr_)->member_ = nullptr; \ michael@0: while (cur) { \ michael@0: type_ *dlm_next = cur->member_; \ michael@0: cur->member_ = nullptr; \ michael@0: delete cur; \ michael@0: cur = dlm_next; \ michael@0: } \ michael@0: } michael@0: michael@0: // Clones a linked list iteratively to avoid blowing up the stack. michael@0: // If it fails to clone the entire list then 'to_' is deleted and michael@0: // we return null. michael@0: #define NS_CSS_CLONE_LIST_MEMBER(type_, from_, member_, to_, args_) \ michael@0: { \ michael@0: type_ *dest = (to_); \ michael@0: (to_)->member_ = nullptr; \ michael@0: for (const type_ *src = (from_)->member_; src; src = src->member_) { \ michael@0: type_ *clm_clone = src->Clone args_; \ michael@0: if (!clm_clone) { \ michael@0: delete (to_); \ michael@0: return nullptr; \ michael@0: } \ michael@0: dest->member_ = clm_clone; \ michael@0: dest = clm_clone; \ michael@0: } \ michael@0: } michael@0: michael@0: namespace mozilla { michael@0: namespace css { michael@0: michael@0: struct URLValue { michael@0: // Methods are not inline because using an nsIPrincipal means requiring michael@0: // caps, which leads to REQUIRES hell, since this header is included all michael@0: // over. michael@0: michael@0: // For both constructors aString must not be null. michael@0: // For both constructors aOriginPrincipal must not be null. michael@0: // Construct with a base URI; this will create the actual URI lazily from michael@0: // aString and aBaseURI. michael@0: URLValue(nsStringBuffer* aString, nsIURI* aBaseURI, nsIURI* aReferrer, michael@0: nsIPrincipal* aOriginPrincipal); michael@0: // Construct with the actual URI. michael@0: URLValue(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aReferrer, michael@0: nsIPrincipal* aOriginPrincipal); michael@0: michael@0: ~URLValue(); michael@0: michael@0: bool operator==(const URLValue& aOther) const; michael@0: michael@0: // URIEquals only compares URIs and principals (unlike operator==, which michael@0: // also compares the original strings). URIEquals also assumes that the michael@0: // mURI member of both URL objects is non-null. Do NOT call this method michael@0: // unless you're sure this is the case. michael@0: bool URIEquals(const URLValue& aOther) const; michael@0: michael@0: nsIURI* GetURI() const; michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: // If mURIResolved is false, mURI stores the base URI. michael@0: // If mURIResolved is true, mURI stores the URI we resolve to; this may be michael@0: // null if the URI is invalid. michael@0: mutable nsCOMPtr mURI; michael@0: public: michael@0: nsStringBuffer* mString; // Could use nsRefPtr, but it'd add useless michael@0: // null-checks; this is never null. michael@0: nsCOMPtr mReferrer; michael@0: nsCOMPtr mOriginPrincipal; michael@0: michael@0: NS_INLINE_DECL_REFCOUNTING(URLValue) michael@0: michael@0: private: michael@0: mutable bool mURIResolved; michael@0: michael@0: URLValue(const URLValue& aOther) MOZ_DELETE; michael@0: URLValue& operator=(const URLValue& aOther) MOZ_DELETE; michael@0: }; michael@0: michael@0: struct ImageValue : public URLValue { michael@0: // Not making the constructor and destructor inline because that would michael@0: // force us to include imgIRequest.h, which leads to REQUIRES hell, since michael@0: // this header is included all over. michael@0: // aString must not be null. michael@0: ImageValue(nsIURI* aURI, nsStringBuffer* aString, nsIURI* aReferrer, michael@0: nsIPrincipal* aOriginPrincipal, nsIDocument* aDocument); michael@0: ~ImageValue(); michael@0: michael@0: // Inherit operator== from URLValue michael@0: michael@0: nsRefPtrHashtable, imgRequestProxy> mRequests; michael@0: michael@0: // Override AddRef and Release to not only log ourselves correctly, but michael@0: // also so that we delete correctly without a virtual destructor michael@0: NS_INLINE_DECL_REFCOUNTING(ImageValue) michael@0: }; michael@0: michael@0: struct GridNamedArea { michael@0: nsString mName; michael@0: uint32_t mColumnStart; michael@0: uint32_t mColumnEnd; michael@0: uint32_t mRowStart; michael@0: uint32_t mRowEnd; michael@0: }; michael@0: michael@0: struct GridTemplateAreasValue MOZ_FINAL { michael@0: // Parsed value michael@0: nsTArray mNamedAreas; michael@0: michael@0: // Original values. Length gives the number of rows, michael@0: // content makes serialization easier. michael@0: nsTArray mTemplates; michael@0: michael@0: // How many columns grid-template-areas contributes to the explicit grid. michael@0: // http://dev.w3.org/csswg/css-grid/#explicit-grid michael@0: uint32_t mNColumns; michael@0: michael@0: // How many rows grid-template-areas contributes to the explicit grid. michael@0: // http://dev.w3.org/csswg/css-grid/#explicit-grid michael@0: uint32_t NRows() const { michael@0: return mTemplates.Length(); michael@0: } michael@0: michael@0: GridTemplateAreasValue() michael@0: : mNColumns(0) michael@0: // Default constructors for mNamedAreas and mTemplates: empty arrays. michael@0: { michael@0: } michael@0: michael@0: bool operator==(const GridTemplateAreasValue& aOther) const michael@0: { michael@0: return mTemplates == aOther.mTemplates; michael@0: } michael@0: michael@0: bool operator!=(const GridTemplateAreasValue& aOther) const michael@0: { michael@0: return !(*this == aOther); michael@0: } michael@0: michael@0: NS_INLINE_DECL_REFCOUNTING(GridTemplateAreasValue) michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: // Private destructor to make sure this isn't used as a stack variable michael@0: // or member variable. michael@0: ~GridTemplateAreasValue() michael@0: { michael@0: } michael@0: michael@0: GridTemplateAreasValue(const GridTemplateAreasValue& aOther) MOZ_DELETE; michael@0: GridTemplateAreasValue& michael@0: operator=(const GridTemplateAreasValue& aOther) MOZ_DELETE; michael@0: }; michael@0: michael@0: } michael@0: } michael@0: michael@0: enum nsCSSUnit { michael@0: eCSSUnit_Null = 0, // (n/a) null unit, value is not specified michael@0: eCSSUnit_Auto = 1, // (n/a) value is algorithmic michael@0: eCSSUnit_Inherit = 2, // (n/a) value is inherited michael@0: eCSSUnit_Initial = 3, // (n/a) value is default UA value michael@0: eCSSUnit_Unset = 4, // (n/a) value equivalent to 'initial' if on a reset property, 'inherit' otherwise michael@0: eCSSUnit_None = 5, // (n/a) value is none michael@0: eCSSUnit_Normal = 6, // (n/a) value is normal (algorithmic, different than auto) michael@0: eCSSUnit_System_Font = 7, // (n/a) value is -moz-use-system-font michael@0: eCSSUnit_All = 8, // (n/a) value is all michael@0: eCSSUnit_Dummy = 9, // (n/a) a fake but specified value, used michael@0: // only in temporary values michael@0: eCSSUnit_DummyInherit = 10, // (n/a) a fake but specified value, used michael@0: // only in temporary values michael@0: michael@0: eCSSUnit_String = 11, // (char16_t*) a string value michael@0: eCSSUnit_Ident = 12, // (char16_t*) a string value michael@0: eCSSUnit_Families = 13, // (char16_t*) a string value michael@0: eCSSUnit_Attr = 14, // (char16_t*) a attr(string) value michael@0: eCSSUnit_Local_Font = 15, // (char16_t*) a local font name michael@0: eCSSUnit_Font_Format = 16, // (char16_t*) a font format name michael@0: eCSSUnit_Element = 17, // (char16_t*) an element id michael@0: michael@0: eCSSUnit_Array = 20, // (nsCSSValue::Array*) a list of values michael@0: eCSSUnit_Counter = 21, // (nsCSSValue::Array*) a counter(string,[string]) value michael@0: eCSSUnit_Counters = 22, // (nsCSSValue::Array*) a counters(string,string[,string]) value michael@0: eCSSUnit_Cubic_Bezier = 23, // (nsCSSValue::Array*) a list of float values michael@0: eCSSUnit_Steps = 24, // (nsCSSValue::Array*) a list of (integer, enumerated) michael@0: eCSSUnit_Function = 25, // (nsCSSValue::Array*) a function with michael@0: // parameters. First elem of array is name, michael@0: // an nsCSSKeyword as eCSSUnit_Enumerated, michael@0: // the rest of the values are arguments. michael@0: michael@0: // The top level of a calc() expression is eCSSUnit_Calc. All michael@0: // remaining eCSSUnit_Calc_* units only occur inside these toplevel michael@0: // calc values. michael@0: michael@0: // eCSSUnit_Calc has an array with exactly 1 element. eCSSUnit_Calc michael@0: // exists so we can distinguish calc(2em) from 2em as specified values michael@0: // (but we drop this distinction for nsStyleCoord when we store michael@0: // computed values). michael@0: eCSSUnit_Calc = 30, // (nsCSSValue::Array*) calc() value michael@0: // Plus, Minus, Times_* and Divided have arrays with exactly 2 michael@0: // elements. a + b + c + d is grouped as ((a + b) + c) + d michael@0: eCSSUnit_Calc_Plus = 31, // (nsCSSValue::Array*) + node within calc() michael@0: eCSSUnit_Calc_Minus = 32, // (nsCSSValue::Array*) - within calc michael@0: eCSSUnit_Calc_Times_L = 33, // (nsCSSValue::Array*) num * val within calc michael@0: eCSSUnit_Calc_Times_R = 34, // (nsCSSValue::Array*) val * num within calc michael@0: eCSSUnit_Calc_Divided = 35, // (nsCSSValue::Array*) / within calc michael@0: michael@0: eCSSUnit_URL = 40, // (nsCSSValue::URL*) value michael@0: eCSSUnit_Image = 41, // (nsCSSValue::Image*) value michael@0: eCSSUnit_Gradient = 42, // (nsCSSValueGradient*) value michael@0: eCSSUnit_TokenStream = 43, // (nsCSSValueTokenStream*) value michael@0: eCSSUnit_GridTemplateAreas = 44, // (GridTemplateAreasValue*) michael@0: // for grid-template-areas michael@0: michael@0: eCSSUnit_Pair = 50, // (nsCSSValuePair*) pair of values michael@0: eCSSUnit_Triplet = 51, // (nsCSSValueTriplet*) triplet of values michael@0: eCSSUnit_Rect = 52, // (nsCSSRect*) rectangle (four values) michael@0: eCSSUnit_List = 53, // (nsCSSValueList*) list of values michael@0: eCSSUnit_ListDep = 54, // (nsCSSValueList*) same as List michael@0: // but does not own the list michael@0: eCSSUnit_SharedList = 55, // (nsCSSValueSharedList*) same as list michael@0: // but reference counted and shared michael@0: eCSSUnit_PairList = 56, // (nsCSSValuePairList*) list of value pairs michael@0: eCSSUnit_PairListDep = 57, // (nsCSSValuePairList*) same as PairList michael@0: // but does not own the list michael@0: michael@0: eCSSUnit_Integer = 70, // (int) simple value michael@0: eCSSUnit_Enumerated = 71, // (int) value has enumerated meaning michael@0: michael@0: eCSSUnit_EnumColor = 80, // (int) enumerated color (kColorKTable) michael@0: eCSSUnit_RGBColor = 81, // (nscolor) an opaque RGBA value specified as rgb() michael@0: eCSSUnit_RGBAColor = 82, // (nscolor) an RGBA value specified as rgba() michael@0: eCSSUnit_HexColor = 83, // (nscolor) an opaque RGBA value specified as #rrggbb michael@0: eCSSUnit_ShortHexColor = 84, // (nscolor) an opaque RGBA value specified as #rgb michael@0: eCSSUnit_PercentageRGBColor = 85, // (nsCSSValueFloatColor*) michael@0: eCSSUnit_PercentageRGBAColor = 86, // (nsCSSValueFloatColor*) michael@0: eCSSUnit_HSLColor = 87, // (nsCSSValueFloatColor*) michael@0: eCSSUnit_HSLAColor = 88, // (nsCSSValueFloatColor*) michael@0: michael@0: eCSSUnit_Percent = 90, // (float) 1.0 == 100%) value is percentage of something michael@0: eCSSUnit_Number = 91, // (float) value is numeric (usually multiplier, different behavior that percent) michael@0: michael@0: // Physical length units michael@0: eCSSUnit_PhysicalMillimeter = 200, // (float) 1/25.4 inch michael@0: michael@0: // Length units - relative michael@0: // Viewport relative measure michael@0: eCSSUnit_ViewportWidth = 700, // (float) 1% of the width of the initial containing block michael@0: eCSSUnit_ViewportHeight = 701, // (float) 1% of the height of the initial containing block michael@0: eCSSUnit_ViewportMin = 702, // (float) smaller of ViewportWidth and ViewportHeight michael@0: eCSSUnit_ViewportMax = 703, // (float) larger of ViewportWidth and ViewportHeight michael@0: michael@0: // Font relative measure michael@0: eCSSUnit_EM = 800, // (float) == current font size michael@0: eCSSUnit_XHeight = 801, // (float) distance from top of lower case x to baseline michael@0: eCSSUnit_Char = 802, // (float) number of characters, used for width with monospace font michael@0: eCSSUnit_RootEM = 803, // (float) == root element font size michael@0: michael@0: // Screen relative measure michael@0: eCSSUnit_Point = 900, // (float) 4/3 of a CSS pixel michael@0: eCSSUnit_Inch = 901, // (float) 96 CSS pixels michael@0: eCSSUnit_Millimeter = 902, // (float) 96/25.4 CSS pixels michael@0: eCSSUnit_Centimeter = 903, // (float) 96/2.54 CSS pixels michael@0: eCSSUnit_Pica = 904, // (float) 12 points == 16 CSS pixls michael@0: eCSSUnit_Pixel = 905, // (float) CSS pixel unit michael@0: michael@0: // Angular units michael@0: eCSSUnit_Degree = 1000, // (float) 360 per circle michael@0: eCSSUnit_Grad = 1001, // (float) 400 per circle michael@0: eCSSUnit_Radian = 1002, // (float) 2*pi per circle michael@0: eCSSUnit_Turn = 1003, // (float) 1 per circle michael@0: michael@0: // Frequency units michael@0: eCSSUnit_Hertz = 2000, // (float) 1/seconds michael@0: eCSSUnit_Kilohertz = 2001, // (float) 1000 Hertz michael@0: michael@0: // Time units michael@0: eCSSUnit_Seconds = 3000, // (float) Standard time michael@0: eCSSUnit_Milliseconds = 3001, // (float) 1/1000 second michael@0: michael@0: // Flexible fraction (CSS Grid) michael@0: eCSSUnit_FlexFraction = 4000 // (float) Fraction of free space michael@0: }; michael@0: michael@0: struct nsCSSValueGradient; michael@0: struct nsCSSValuePair; michael@0: struct nsCSSValuePair_heap; michael@0: struct nsCSSValueTokenStream; michael@0: struct nsCSSRect; michael@0: struct nsCSSRect_heap; michael@0: struct nsCSSValueList; michael@0: struct nsCSSValueList_heap; michael@0: struct nsCSSValueSharedList; michael@0: struct nsCSSValuePairList; michael@0: struct nsCSSValuePairList_heap; michael@0: struct nsCSSValueTriplet; michael@0: struct nsCSSValueTriplet_heap; michael@0: class nsCSSValueFloatColor; michael@0: michael@0: class nsCSSValue { michael@0: public: michael@0: struct Array; michael@0: friend struct Array; michael@0: michael@0: friend struct mozilla::css::URLValue; michael@0: michael@0: friend struct mozilla::css::ImageValue; michael@0: michael@0: // for valueless units only (null, auto, inherit, none, all, normal) michael@0: explicit nsCSSValue(nsCSSUnit aUnit = eCSSUnit_Null) michael@0: : mUnit(aUnit) michael@0: { michael@0: NS_ABORT_IF_FALSE(aUnit <= eCSSUnit_DummyInherit, "not a valueless unit"); michael@0: } michael@0: michael@0: nsCSSValue(int32_t aValue, nsCSSUnit aUnit); michael@0: nsCSSValue(float aValue, nsCSSUnit aUnit); michael@0: nsCSSValue(const nsString& aValue, nsCSSUnit aUnit); michael@0: nsCSSValue(Array* aArray, nsCSSUnit aUnit); michael@0: explicit nsCSSValue(mozilla::css::URLValue* aValue); michael@0: explicit nsCSSValue(mozilla::css::ImageValue* aValue); michael@0: explicit nsCSSValue(nsCSSValueGradient* aValue); michael@0: explicit nsCSSValue(nsCSSValueTokenStream* aValue); michael@0: explicit nsCSSValue(mozilla::css::GridTemplateAreasValue* aValue); michael@0: nsCSSValue(const nsCSSValue& aCopy); michael@0: ~nsCSSValue() { Reset(); } michael@0: michael@0: nsCSSValue& operator=(const nsCSSValue& aCopy); michael@0: bool operator==(const nsCSSValue& aOther) const; michael@0: michael@0: bool operator!=(const nsCSSValue& aOther) const michael@0: { michael@0: return !(*this == aOther); michael@0: } michael@0: michael@0: // Enum for AppendToString's aValueSerialization argument. michael@0: enum Serialization { eNormalized, eAuthorSpecified }; michael@0: michael@0: /** michael@0: * Serialize |this| as a specified value for |aProperty| and append michael@0: * it to |aResult|. michael@0: */ michael@0: void AppendToString(nsCSSProperty aProperty, nsAString& aResult, michael@0: Serialization aValueSerialization) const; michael@0: michael@0: nsCSSUnit GetUnit() const { return mUnit; } michael@0: bool IsLengthUnit() const michael@0: { return eCSSUnit_PhysicalMillimeter <= mUnit && mUnit <= eCSSUnit_Pixel; } michael@0: /** michael@0: * A "fixed" length unit is one that means a specific physical length michael@0: * which we try to match based on the physical characteristics of an michael@0: * output device. michael@0: */ michael@0: bool IsFixedLengthUnit() const michael@0: { return mUnit == eCSSUnit_PhysicalMillimeter; } michael@0: /** michael@0: * What the spec calls relative length units is, for us, split michael@0: * between relative length units and pixel length units. michael@0: * michael@0: * A "relative" length unit is a multiple of some derived metric, michael@0: * such as a font em-size, which itself was controlled by an input CSS michael@0: * length. Relative length units should not be scaled by zooming, since michael@0: * the underlying CSS length would already have been scaled. michael@0: */ michael@0: bool IsRelativeLengthUnit() const michael@0: { return eCSSUnit_EM <= mUnit && mUnit <= eCSSUnit_RootEM; } michael@0: /** michael@0: * A "pixel" length unit is a some multiple of CSS pixels. michael@0: */ michael@0: bool IsPixelLengthUnit() const michael@0: { return eCSSUnit_Point <= mUnit && mUnit <= eCSSUnit_Pixel; } michael@0: bool IsAngularUnit() const michael@0: { return eCSSUnit_Degree <= mUnit && mUnit <= eCSSUnit_Turn; } michael@0: bool IsFrequencyUnit() const michael@0: { return eCSSUnit_Hertz <= mUnit && mUnit <= eCSSUnit_Kilohertz; } michael@0: bool IsTimeUnit() const michael@0: { return eCSSUnit_Seconds <= mUnit && mUnit <= eCSSUnit_Milliseconds; } michael@0: bool IsCalcUnit() const michael@0: { return eCSSUnit_Calc <= mUnit && mUnit <= eCSSUnit_Calc_Divided; } michael@0: michael@0: bool UnitHasStringValue() const michael@0: { return eCSSUnit_String <= mUnit && mUnit <= eCSSUnit_Element; } michael@0: bool UnitHasArrayValue() const michael@0: { return eCSSUnit_Array <= mUnit && mUnit <= eCSSUnit_Calc_Divided; } michael@0: michael@0: // Checks for the nsCSSValue being of a particular type of color unit: michael@0: // michael@0: // - IsIntegerColorUnit returns true for: michael@0: // eCSSUnit_RGBColor -- rgb(int,int,int) michael@0: // eCSSUnit_RGBAColor -- rgba(int,int,int,float) michael@0: // eCSSUnit_HexColor -- #rrggbb michael@0: // eCSSUnit_ShortHexColor -- #rgb michael@0: // michael@0: // - IsFLoatColorUnit returns true for: michael@0: // eCSSUnit_PercentageRGBColor -- rgb(%,%,%) michael@0: // eCSSUnit_PercentageRGBAColor -- rgba(%,%,%,float) michael@0: // eCSSUnit_HSLColor -- hsl(float,%,%) michael@0: // eCSSUnit_HSLAColor -- hsla(float,%,%,float) michael@0: // michael@0: // - IsNumericColorUnit returns true for any of the above units. michael@0: // michael@0: // Note that color keywords and system colors are represented by michael@0: // eCSSUnit_EnumColor and eCSSUnit_Ident. michael@0: bool IsIntegerColorUnit() const { return IsIntegerColorUnit(mUnit); } michael@0: bool IsFloatColorUnit() const { return IsFloatColorUnit(mUnit); } michael@0: bool IsNumericColorUnit() const { return IsNumericColorUnit(mUnit); } michael@0: static bool IsIntegerColorUnit(nsCSSUnit aUnit) michael@0: { return eCSSUnit_RGBColor <= aUnit && aUnit <= eCSSUnit_ShortHexColor; } michael@0: static bool IsFloatColorUnit(nsCSSUnit aUnit) michael@0: { return eCSSUnit_PercentageRGBColor <= aUnit && michael@0: aUnit <= eCSSUnit_HSLAColor; } michael@0: static bool IsNumericColorUnit(nsCSSUnit aUnit) michael@0: { return IsIntegerColorUnit(aUnit) || IsFloatColorUnit(aUnit); } michael@0: michael@0: int32_t GetIntValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Integer || michael@0: mUnit == eCSSUnit_Enumerated || michael@0: mUnit == eCSSUnit_EnumColor, michael@0: "not an int value"); michael@0: return mValue.mInt; michael@0: } michael@0: michael@0: nsCSSKeyword GetKeywordValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Enumerated, "not a keyword value"); michael@0: return static_cast(mValue.mInt); michael@0: } michael@0: michael@0: float GetPercentValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Percent, "not a percent value"); michael@0: return mValue.mFloat; michael@0: } michael@0: michael@0: float GetFloatValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(eCSSUnit_Number <= mUnit, "not a float value"); michael@0: MOZ_ASSERT(!mozilla::IsNaN(mValue.mFloat)); michael@0: return mValue.mFloat; michael@0: } michael@0: michael@0: float GetAngleValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(eCSSUnit_Degree <= mUnit && michael@0: mUnit <= eCSSUnit_Turn, "not an angle value"); michael@0: return mValue.mFloat; michael@0: } michael@0: michael@0: // Converts any angle to radians. michael@0: double GetAngleValueInRadians() const; michael@0: michael@0: nsAString& GetStringValue(nsAString& aBuffer) const michael@0: { michael@0: NS_ABORT_IF_FALSE(UnitHasStringValue(), "not a string value"); michael@0: aBuffer.Truncate(); michael@0: uint32_t len = NS_strlen(GetBufferValue(mValue.mString)); michael@0: mValue.mString->ToString(len, aBuffer); michael@0: return aBuffer; michael@0: } michael@0: michael@0: const char16_t* GetStringBufferValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(UnitHasStringValue(), "not a string value"); michael@0: return GetBufferValue(mValue.mString); michael@0: } michael@0: michael@0: nscolor GetColorValue() const; michael@0: bool IsNonTransparentColor() const; michael@0: michael@0: Array* GetArrayValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(UnitHasArrayValue(), "not an array value"); michael@0: return mValue.mArray; michael@0: } michael@0: michael@0: nsIURI* GetURLValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, michael@0: "not a URL value"); michael@0: return mUnit == eCSSUnit_URL ? michael@0: mValue.mURL->GetURI() : mValue.mImage->GetURI(); michael@0: } michael@0: michael@0: nsCSSValueGradient* GetGradientValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Gradient, "not a gradient value"); michael@0: return mValue.mGradient; michael@0: } michael@0: michael@0: nsCSSValueTokenStream* GetTokenStreamValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_TokenStream, "not a token stream value"); michael@0: return mValue.mTokenStream; michael@0: } michael@0: michael@0: nsCSSValueSharedList* GetSharedListValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_SharedList, "not a shared list value"); michael@0: return mValue.mSharedList; michael@0: } michael@0: michael@0: // bodies of these are below michael@0: inline nsCSSValuePair& GetPairValue(); michael@0: inline const nsCSSValuePair& GetPairValue() const; michael@0: michael@0: inline nsCSSRect& GetRectValue(); michael@0: inline const nsCSSRect& GetRectValue() const; michael@0: michael@0: inline nsCSSValueList* GetListValue(); michael@0: inline const nsCSSValueList* GetListValue() const; michael@0: michael@0: inline nsCSSValuePairList* GetPairListValue(); michael@0: inline const nsCSSValuePairList* GetPairListValue() const; michael@0: michael@0: inline nsCSSValueTriplet& GetTripletValue(); michael@0: inline const nsCSSValueTriplet& GetTripletValue() const; michael@0: michael@0: michael@0: mozilla::css::URLValue* GetURLStructValue() const michael@0: { michael@0: // Not allowing this for Image values, because if the caller takes michael@0: // a ref to them they won't be able to delete them properly. michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_URL, "not a URL value"); michael@0: return mValue.mURL; michael@0: } michael@0: michael@0: mozilla::css::ImageValue* GetImageStructValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Image, "not an Image value"); michael@0: return mValue.mImage; michael@0: } michael@0: michael@0: mozilla::css::GridTemplateAreasValue* GetGridTemplateAreas() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_GridTemplateAreas, michael@0: "not a grid-template-areas value"); michael@0: return mValue.mGridTemplateAreas; michael@0: } michael@0: michael@0: const char16_t* GetOriginalURLValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_URL || mUnit == eCSSUnit_Image, michael@0: "not a URL value"); michael@0: return GetBufferValue(mUnit == eCSSUnit_URL ? michael@0: mValue.mURL->mString : michael@0: mValue.mImage->mString); michael@0: } michael@0: michael@0: // Not making this inline because that would force us to include michael@0: // imgIRequest.h, which leads to REQUIRES hell, since this header is included michael@0: // all over. michael@0: imgRequestProxy* GetImageValue(nsIDocument* aDocument) const; michael@0: michael@0: nscoord GetFixedLength(nsPresContext* aPresContext) const; michael@0: nscoord GetPixelLength() const; michael@0: michael@0: void Reset() // sets to null michael@0: { michael@0: if (mUnit != eCSSUnit_Null) michael@0: DoReset(); michael@0: } michael@0: private: michael@0: void DoReset(); michael@0: michael@0: public: michael@0: void SetIntValue(int32_t aValue, nsCSSUnit aUnit); michael@0: void SetPercentValue(float aValue); michael@0: void SetFloatValue(float aValue, nsCSSUnit aUnit); michael@0: void SetStringValue(const nsString& aValue, nsCSSUnit aUnit); michael@0: void SetColorValue(nscolor aValue); michael@0: void SetIntegerColorValue(nscolor aValue, nsCSSUnit aUnit); michael@0: void SetFloatColorValue(float aComponent1, michael@0: float aComponent2, michael@0: float aComponent3, michael@0: float aAlpha, nsCSSUnit aUnit); michael@0: void SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit); michael@0: void SetURLValue(mozilla::css::URLValue* aURI); michael@0: void SetImageValue(mozilla::css::ImageValue* aImage); michael@0: void SetGradientValue(nsCSSValueGradient* aGradient); michael@0: void SetTokenStreamValue(nsCSSValueTokenStream* aTokenStream); michael@0: void SetGridTemplateAreas(mozilla::css::GridTemplateAreasValue* aValue); michael@0: void SetPairValue(const nsCSSValuePair* aPair); michael@0: void SetPairValue(const nsCSSValue& xValue, const nsCSSValue& yValue); michael@0: void SetSharedListValue(nsCSSValueSharedList* aList); michael@0: void SetDependentListValue(nsCSSValueList* aList); michael@0: void SetDependentPairListValue(nsCSSValuePairList* aList); michael@0: void SetTripletValue(const nsCSSValueTriplet* aTriplet); michael@0: void SetTripletValue(const nsCSSValue& xValue, const nsCSSValue& yValue, const nsCSSValue& zValue); michael@0: void SetAutoValue(); michael@0: void SetInheritValue(); michael@0: void SetInitialValue(); michael@0: void SetUnsetValue(); michael@0: void SetNoneValue(); michael@0: void SetAllValue(); michael@0: void SetNormalValue(); michael@0: void SetSystemFontValue(); michael@0: void SetDummyValue(); michael@0: void SetDummyInheritValue(); michael@0: michael@0: // These are a little different - they allocate storage for you and michael@0: // return a handle. michael@0: nsCSSRect& SetRectValue(); michael@0: nsCSSValueList* SetListValue(); michael@0: nsCSSValuePairList* SetPairListValue(); michael@0: michael@0: void StartImageLoad(nsIDocument* aDocument) const; // Only pretend const michael@0: michael@0: // Initializes as a function value with the specified function id. michael@0: Array* InitFunction(nsCSSKeyword aFunctionId, uint32_t aNumArgs); michael@0: // Checks if this is a function value with the specified function id. michael@0: bool EqualsFunction(nsCSSKeyword aFunctionId) const; michael@0: michael@0: // Returns an already addrefed buffer. Guaranteed to return non-null. michael@0: // (Will abort on allocation failure.) michael@0: static already_AddRefed michael@0: BufferFromString(const nsString& aValue); michael@0: michael@0: size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) { michael@0: return static_cast(aBuffer->Data()); michael@0: } michael@0: michael@0: protected: michael@0: nsCSSUnit mUnit; michael@0: union { michael@0: int32_t mInt; michael@0: float mFloat; michael@0: // Note: the capacity of the buffer may exceed the length of the string. michael@0: // If we're of a string type, mString is not null. michael@0: nsStringBuffer* mString; michael@0: nscolor mColor; michael@0: Array* mArray; michael@0: mozilla::css::URLValue* mURL; michael@0: mozilla::css::ImageValue* mImage; michael@0: mozilla::css::GridTemplateAreasValue* mGridTemplateAreas; michael@0: nsCSSValueGradient* mGradient; michael@0: nsCSSValueTokenStream* mTokenStream; michael@0: nsCSSValuePair_heap* mPair; michael@0: nsCSSRect_heap* mRect; michael@0: nsCSSValueTriplet_heap* mTriplet; michael@0: nsCSSValueList_heap* mList; michael@0: nsCSSValueList* mListDependent; michael@0: nsCSSValueSharedList* mSharedList; michael@0: nsCSSValuePairList_heap* mPairList; michael@0: nsCSSValuePairList* mPairListDependent; michael@0: nsCSSValueFloatColor* mFloatColor; michael@0: } mValue; michael@0: }; michael@0: michael@0: struct nsCSSValue::Array MOZ_FINAL { michael@0: michael@0: // return |Array| with reference count of zero michael@0: static Array* Create(size_t aItemCount) { michael@0: return new (aItemCount) Array(aItemCount); michael@0: } michael@0: michael@0: nsCSSValue& operator[](size_t aIndex) { michael@0: NS_ABORT_IF_FALSE(aIndex < mCount, "out of range"); michael@0: return mArray[aIndex]; michael@0: } michael@0: michael@0: const nsCSSValue& operator[](size_t aIndex) const { michael@0: NS_ABORT_IF_FALSE(aIndex < mCount, "out of range"); michael@0: return mArray[aIndex]; michael@0: } michael@0: michael@0: nsCSSValue& Item(size_t aIndex) { return (*this)[aIndex]; } michael@0: const nsCSSValue& Item(size_t aIndex) const { return (*this)[aIndex]; } michael@0: michael@0: size_t Count() const { return mCount; } michael@0: michael@0: bool operator==(const Array& aOther) const michael@0: { michael@0: if (mCount != aOther.mCount) michael@0: return false; michael@0: for (size_t i = 0; i < mCount; ++i) michael@0: if ((*this)[i] != aOther[i]) michael@0: return false; michael@0: return true; michael@0: } michael@0: michael@0: // XXXdholbert This uses a size_t ref count. Should we use a variant michael@0: // of NS_INLINE_DECL_REFCOUNTING that takes a type as an argument? michael@0: void AddRef() { michael@0: if (mRefCnt == size_t(-1)) { // really want SIZE_MAX michael@0: NS_WARNING("refcount overflow, leaking nsCSSValue::Array"); michael@0: return; michael@0: } michael@0: ++mRefCnt; michael@0: NS_LOG_ADDREF(this, mRefCnt, "nsCSSValue::Array", sizeof(*this)); michael@0: } michael@0: void Release() { michael@0: if (mRefCnt == size_t(-1)) { // really want SIZE_MAX michael@0: NS_WARNING("refcount overflow, leaking nsCSSValue::Array"); michael@0: return; michael@0: } michael@0: --mRefCnt; michael@0: NS_LOG_RELEASE(this, mRefCnt, "nsCSSValue::Array"); michael@0: if (mRefCnt == 0) michael@0: delete this; michael@0: } michael@0: michael@0: private: michael@0: michael@0: size_t mRefCnt; michael@0: const size_t mCount; michael@0: // This must be the last sub-object, since we extend this array to michael@0: // be of size mCount; it needs to be a sub-object so it gets proper michael@0: // alignment. michael@0: nsCSSValue mArray[1]; michael@0: michael@0: void* operator new(size_t aSelfSize, size_t aItemCount) CPP_THROW_NEW { michael@0: NS_ABORT_IF_FALSE(aItemCount > 0, "cannot have a 0 item count"); michael@0: return ::operator new(aSelfSize + sizeof(nsCSSValue) * (aItemCount - 1)); michael@0: } michael@0: michael@0: void operator delete(void* aPtr) { ::operator delete(aPtr); } michael@0: michael@0: nsCSSValue* First() { return mArray; } michael@0: michael@0: const nsCSSValue* First() const { return mArray; } michael@0: michael@0: #define CSSVALUE_LIST_FOR_EXTRA_VALUES(var) \ michael@0: for (nsCSSValue *var = First() + 1, *var##_end = First() + mCount; \ michael@0: var != var##_end; ++var) michael@0: michael@0: Array(size_t aItemCount) michael@0: : mRefCnt(0) michael@0: , mCount(aItemCount) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValue::Array); michael@0: CSSVALUE_LIST_FOR_EXTRA_VALUES(val) { michael@0: new (val) nsCSSValue(); michael@0: } michael@0: } michael@0: michael@0: ~Array() michael@0: { michael@0: MOZ_COUNT_DTOR(nsCSSValue::Array); michael@0: CSSVALUE_LIST_FOR_EXTRA_VALUES(val) { michael@0: val->~nsCSSValue(); michael@0: } michael@0: } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: #undef CSSVALUE_LIST_FOR_EXTRA_VALUES michael@0: michael@0: private: michael@0: Array(const Array& aOther) MOZ_DELETE; michael@0: Array& operator=(const Array& aOther) MOZ_DELETE; michael@0: }; michael@0: michael@0: // Prefer nsCSSValue::Array for lists of fixed size. michael@0: struct nsCSSValueList { michael@0: nsCSSValueList() : mNext(nullptr) { MOZ_COUNT_CTOR(nsCSSValueList); } michael@0: ~nsCSSValueList(); michael@0: michael@0: nsCSSValueList* Clone() const; // makes a deep copy michael@0: void CloneInto(nsCSSValueList* aList) const; // makes a deep copy into aList michael@0: void AppendToString(nsCSSProperty aProperty, nsAString& aResult, michael@0: nsCSSValue::Serialization aValueSerialization) const; michael@0: michael@0: bool operator==(nsCSSValueList const& aOther) const; michael@0: bool operator!=(const nsCSSValueList& aOther) const michael@0: { return !(*this == aOther); } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: nsCSSValue mValue; michael@0: nsCSSValueList* mNext; michael@0: michael@0: private: michael@0: nsCSSValueList(const nsCSSValueList& aCopy) // makes a shallow copy michael@0: : mValue(aCopy.mValue), mNext(nullptr) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValueList); michael@0: } michael@0: }; michael@0: michael@0: // nsCSSValueList_heap differs from nsCSSValueList only in being michael@0: // refcounted. It should not be necessary to use this class directly; michael@0: // it's an implementation detail of nsCSSValue. michael@0: struct nsCSSValueList_heap MOZ_FINAL : public nsCSSValueList { michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSValueList_heap) michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSValueList_heap() michael@0: { michael@0: } michael@0: }; michael@0: michael@0: // This is a reference counted list value. Note that the object is michael@0: // a wrapper for the reference count and a pointer to the head of the michael@0: // list, whereas the other list types (such as nsCSSValueList) do michael@0: // not have such a wrapper. michael@0: struct nsCSSValueSharedList MOZ_FINAL { michael@0: nsCSSValueSharedList() michael@0: : mHead(nullptr) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValueSharedList); michael@0: } michael@0: michael@0: // Takes ownership of aList. michael@0: nsCSSValueSharedList(nsCSSValueList* aList) michael@0: : mHead(aList) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValueSharedList); michael@0: } michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSValueSharedList(); michael@0: michael@0: public: michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSValueSharedList) michael@0: michael@0: void AppendToString(nsCSSProperty aProperty, nsAString& aResult, michael@0: nsCSSValue::Serialization aValueSerialization) const; michael@0: michael@0: bool operator==(nsCSSValueSharedList const& aOther) const; michael@0: bool operator!=(const nsCSSValueSharedList& aOther) const michael@0: { return !(*this == aOther); } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: nsCSSValueList* mHead; michael@0: }; michael@0: michael@0: // This has to be here so that the relationship between nsCSSValueList michael@0: // and nsCSSValueList_heap is visible. michael@0: inline nsCSSValueList* michael@0: nsCSSValue::GetListValue() michael@0: { michael@0: if (mUnit == eCSSUnit_List) michael@0: return mValue.mList; michael@0: else { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_ListDep, "not a pairlist value"); michael@0: return mValue.mListDependent; michael@0: } michael@0: } michael@0: michael@0: inline const nsCSSValueList* michael@0: nsCSSValue::GetListValue() const michael@0: { michael@0: if (mUnit == eCSSUnit_List) michael@0: return mValue.mList; michael@0: else { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_ListDep, "not a pairlist value"); michael@0: return mValue.mListDependent; michael@0: } michael@0: } michael@0: michael@0: struct nsCSSRect { michael@0: nsCSSRect(void); michael@0: nsCSSRect(const nsCSSRect& aCopy); michael@0: ~nsCSSRect(); michael@0: michael@0: void AppendToString(nsCSSProperty aProperty, nsAString& aResult, michael@0: nsCSSValue::Serialization aValueSerialization) const; michael@0: michael@0: bool operator==(const nsCSSRect& aOther) const { michael@0: return mTop == aOther.mTop && michael@0: mRight == aOther.mRight && michael@0: mBottom == aOther.mBottom && michael@0: mLeft == aOther.mLeft; michael@0: } michael@0: michael@0: bool operator!=(const nsCSSRect& aOther) const { michael@0: return mTop != aOther.mTop || michael@0: mRight != aOther.mRight || michael@0: mBottom != aOther.mBottom || michael@0: mLeft != aOther.mLeft; michael@0: } michael@0: michael@0: void SetAllSidesTo(const nsCSSValue& aValue); michael@0: michael@0: bool AllSidesEqualTo(const nsCSSValue& aValue) const { michael@0: return mTop == aValue && michael@0: mRight == aValue && michael@0: mBottom == aValue && michael@0: mLeft == aValue; michael@0: } michael@0: michael@0: void Reset() { michael@0: mTop.Reset(); michael@0: mRight.Reset(); michael@0: mBottom.Reset(); michael@0: mLeft.Reset(); michael@0: } michael@0: michael@0: bool HasValue() const { michael@0: return michael@0: mTop.GetUnit() != eCSSUnit_Null || michael@0: mRight.GetUnit() != eCSSUnit_Null || michael@0: mBottom.GetUnit() != eCSSUnit_Null || michael@0: mLeft.GetUnit() != eCSSUnit_Null; michael@0: } michael@0: michael@0: nsCSSValue mTop; michael@0: nsCSSValue mRight; michael@0: nsCSSValue mBottom; michael@0: nsCSSValue mLeft; michael@0: michael@0: typedef nsCSSValue nsCSSRect::*side_type; michael@0: static const side_type sides[4]; michael@0: }; michael@0: michael@0: // nsCSSRect_heap differs from nsCSSRect only in being michael@0: // refcounted. It should not be necessary to use this class directly; michael@0: // it's an implementation detail of nsCSSValue. michael@0: struct nsCSSRect_heap MOZ_FINAL : public nsCSSRect { michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSRect_heap) michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSRect_heap() michael@0: { michael@0: } michael@0: }; michael@0: michael@0: // This has to be here so that the relationship between nsCSSRect michael@0: // and nsCSSRect_heap is visible. michael@0: inline nsCSSRect& michael@0: nsCSSValue::GetRectValue() michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Rect, "not a rect value"); michael@0: return *mValue.mRect; michael@0: } michael@0: michael@0: inline const nsCSSRect& michael@0: nsCSSValue::GetRectValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Rect, "not a rect value"); michael@0: return *mValue.mRect; michael@0: } michael@0: michael@0: struct nsCSSValuePair { michael@0: nsCSSValuePair() michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValuePair); michael@0: } michael@0: nsCSSValuePair(nsCSSUnit aUnit) michael@0: : mXValue(aUnit), mYValue(aUnit) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValuePair); michael@0: } michael@0: nsCSSValuePair(const nsCSSValue& aXValue, const nsCSSValue& aYValue) michael@0: : mXValue(aXValue), mYValue(aYValue) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValuePair); michael@0: } michael@0: nsCSSValuePair(const nsCSSValuePair& aCopy) michael@0: : mXValue(aCopy.mXValue), mYValue(aCopy.mYValue) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValuePair); michael@0: } michael@0: ~nsCSSValuePair() michael@0: { michael@0: MOZ_COUNT_DTOR(nsCSSValuePair); michael@0: } michael@0: michael@0: bool operator==(const nsCSSValuePair& aOther) const { michael@0: return mXValue == aOther.mXValue && michael@0: mYValue == aOther.mYValue; michael@0: } michael@0: michael@0: bool operator!=(const nsCSSValuePair& aOther) const { michael@0: return mXValue != aOther.mXValue || michael@0: mYValue != aOther.mYValue; michael@0: } michael@0: michael@0: bool BothValuesEqualTo(const nsCSSValue& aValue) const { michael@0: return mXValue == aValue && michael@0: mYValue == aValue; michael@0: } michael@0: michael@0: void SetBothValuesTo(const nsCSSValue& aValue) { michael@0: mXValue = aValue; michael@0: mYValue = aValue; michael@0: } michael@0: michael@0: void Reset() { michael@0: mXValue.Reset(); michael@0: mYValue.Reset(); michael@0: } michael@0: michael@0: bool HasValue() const { michael@0: return mXValue.GetUnit() != eCSSUnit_Null || michael@0: mYValue.GetUnit() != eCSSUnit_Null; michael@0: } michael@0: michael@0: void AppendToString(nsCSSProperty aProperty, nsAString& aResult, michael@0: nsCSSValue::Serialization aValueSerialization) const; michael@0: michael@0: size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: nsCSSValue mXValue; michael@0: nsCSSValue mYValue; michael@0: }; michael@0: michael@0: // nsCSSValuePair_heap differs from nsCSSValuePair only in being michael@0: // refcounted. It should not be necessary to use this class directly; michael@0: // it's an implementation detail of nsCSSValue. michael@0: struct nsCSSValuePair_heap MOZ_FINAL : public nsCSSValuePair { michael@0: // forward constructor michael@0: nsCSSValuePair_heap(const nsCSSValue& aXValue, const nsCSSValue& aYValue) michael@0: : nsCSSValuePair(aXValue, aYValue) michael@0: {} michael@0: michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSValuePair_heap) michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSValuePair_heap() michael@0: { michael@0: } michael@0: }; michael@0: michael@0: struct nsCSSValueTriplet { michael@0: nsCSSValueTriplet() michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValueTriplet); michael@0: } michael@0: nsCSSValueTriplet(nsCSSUnit aUnit) michael@0: : mXValue(aUnit), mYValue(aUnit), mZValue(aUnit) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValueTriplet); michael@0: } michael@0: nsCSSValueTriplet(const nsCSSValue& aXValue, michael@0: const nsCSSValue& aYValue, michael@0: const nsCSSValue& aZValue) michael@0: : mXValue(aXValue), mYValue(aYValue), mZValue(aZValue) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValueTriplet); michael@0: } michael@0: nsCSSValueTriplet(const nsCSSValueTriplet& aCopy) michael@0: : mXValue(aCopy.mXValue), mYValue(aCopy.mYValue), mZValue(aCopy.mZValue) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValueTriplet); michael@0: } michael@0: ~nsCSSValueTriplet() michael@0: { michael@0: MOZ_COUNT_DTOR(nsCSSValueTriplet); michael@0: } michael@0: michael@0: bool operator==(const nsCSSValueTriplet& aOther) const { michael@0: return mXValue == aOther.mXValue && michael@0: mYValue == aOther.mYValue && michael@0: mZValue == aOther.mZValue; michael@0: } michael@0: michael@0: bool operator!=(const nsCSSValueTriplet& aOther) const { michael@0: return mXValue != aOther.mXValue || michael@0: mYValue != aOther.mYValue || michael@0: mZValue != aOther.mZValue; michael@0: } michael@0: michael@0: bool AllValuesEqualTo(const nsCSSValue& aValue) const { michael@0: return mXValue == aValue && michael@0: mYValue == aValue && michael@0: mZValue == aValue; michael@0: } michael@0: michael@0: void SetAllValuesTo(const nsCSSValue& aValue) { michael@0: mXValue = aValue; michael@0: mYValue = aValue; michael@0: mZValue = aValue; michael@0: } michael@0: michael@0: void Reset() { michael@0: mXValue.Reset(); michael@0: mYValue.Reset(); michael@0: mZValue.Reset(); michael@0: } michael@0: michael@0: bool HasValue() const { michael@0: return mXValue.GetUnit() != eCSSUnit_Null || michael@0: mYValue.GetUnit() != eCSSUnit_Null || michael@0: mZValue.GetUnit() != eCSSUnit_Null; michael@0: } michael@0: michael@0: void AppendToString(nsCSSProperty aProperty, nsAString& aResult, michael@0: nsCSSValue::Serialization aValueSerialization) const; michael@0: michael@0: nsCSSValue mXValue; michael@0: nsCSSValue mYValue; michael@0: nsCSSValue mZValue; michael@0: }; michael@0: michael@0: // nsCSSValueTriplet_heap differs from nsCSSValueTriplet only in being michael@0: // refcounted. It should not be necessary to use this class directly; michael@0: // it's an implementation detail of nsCSSValue. michael@0: struct nsCSSValueTriplet_heap MOZ_FINAL : public nsCSSValueTriplet { michael@0: // forward constructor michael@0: nsCSSValueTriplet_heap(const nsCSSValue& aXValue, const nsCSSValue& aYValue, const nsCSSValue& aZValue) michael@0: : nsCSSValueTriplet(aXValue, aYValue, aZValue) michael@0: {} michael@0: michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSValueTriplet_heap) michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSValueTriplet_heap() michael@0: { michael@0: } michael@0: }; michael@0: michael@0: // This has to be here so that the relationship between nsCSSValuePair michael@0: // and nsCSSValuePair_heap is visible. michael@0: inline nsCSSValuePair& michael@0: nsCSSValue::GetPairValue() michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Pair, "not a pair value"); michael@0: return *mValue.mPair; michael@0: } michael@0: michael@0: inline const nsCSSValuePair& michael@0: nsCSSValue::GetPairValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Pair, "not a pair value"); michael@0: return *mValue.mPair; michael@0: } michael@0: michael@0: inline nsCSSValueTriplet& michael@0: nsCSSValue::GetTripletValue() michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Triplet, "not a triplet value"); michael@0: return *mValue.mTriplet; michael@0: } michael@0: michael@0: inline const nsCSSValueTriplet& michael@0: nsCSSValue::GetTripletValue() const michael@0: { michael@0: NS_ABORT_IF_FALSE(mUnit == eCSSUnit_Triplet, "not a triplet value"); michael@0: return *mValue.mTriplet; michael@0: } michael@0: michael@0: // Maybe should be replaced with nsCSSValueList and nsCSSValue::Array? michael@0: struct nsCSSValuePairList { michael@0: nsCSSValuePairList() : mNext(nullptr) { MOZ_COUNT_CTOR(nsCSSValuePairList); } michael@0: ~nsCSSValuePairList(); michael@0: michael@0: nsCSSValuePairList* Clone() const; // makes a deep copy michael@0: void AppendToString(nsCSSProperty aProperty, nsAString& aResult, michael@0: nsCSSValue::Serialization aValueSerialization) const; michael@0: michael@0: bool operator==(const nsCSSValuePairList& aOther) const; michael@0: bool operator!=(const nsCSSValuePairList& aOther) const michael@0: { return !(*this == aOther); } michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: nsCSSValue mXValue; michael@0: nsCSSValue mYValue; michael@0: nsCSSValuePairList* mNext; michael@0: michael@0: private: michael@0: nsCSSValuePairList(const nsCSSValuePairList& aCopy) // makes a shallow copy michael@0: : mXValue(aCopy.mXValue), mYValue(aCopy.mYValue), mNext(nullptr) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValuePairList); michael@0: } michael@0: }; michael@0: michael@0: // nsCSSValuePairList_heap differs from nsCSSValuePairList only in being michael@0: // refcounted. It should not be necessary to use this class directly; michael@0: // it's an implementation detail of nsCSSValue. michael@0: struct nsCSSValuePairList_heap MOZ_FINAL : public nsCSSValuePairList { michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSValuePairList_heap) michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSValuePairList_heap() michael@0: { michael@0: } michael@0: }; michael@0: michael@0: // This has to be here so that the relationship between nsCSSValuePairList michael@0: // and nsCSSValuePairList_heap is visible. michael@0: inline nsCSSValuePairList* michael@0: nsCSSValue::GetPairListValue() michael@0: { michael@0: if (mUnit == eCSSUnit_PairList) michael@0: return mValue.mPairList; michael@0: else { michael@0: NS_ABORT_IF_FALSE (mUnit == eCSSUnit_PairListDep, "not a pairlist value"); michael@0: return mValue.mPairListDependent; michael@0: } michael@0: } michael@0: michael@0: inline const nsCSSValuePairList* michael@0: nsCSSValue::GetPairListValue() const michael@0: { michael@0: if (mUnit == eCSSUnit_PairList) michael@0: return mValue.mPairList; michael@0: else { michael@0: NS_ABORT_IF_FALSE (mUnit == eCSSUnit_PairListDep, "not a pairlist value"); michael@0: return mValue.mPairListDependent; michael@0: } michael@0: } michael@0: michael@0: struct nsCSSValueGradientStop { michael@0: public: michael@0: nsCSSValueGradientStop(); michael@0: // needed to keep bloat logs happy when we use the TArray michael@0: // in nsCSSValueGradient michael@0: nsCSSValueGradientStop(const nsCSSValueGradientStop& aOther); michael@0: ~nsCSSValueGradientStop(); michael@0: michael@0: nsCSSValue mLocation; michael@0: nsCSSValue mColor; michael@0: michael@0: bool operator==(const nsCSSValueGradientStop& aOther) const michael@0: { michael@0: return (mLocation == aOther.mLocation && michael@0: mColor == aOther.mColor); michael@0: } michael@0: michael@0: bool operator!=(const nsCSSValueGradientStop& aOther) const michael@0: { michael@0: return !(*this == aOther); michael@0: } michael@0: michael@0: size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: }; michael@0: michael@0: struct nsCSSValueGradient MOZ_FINAL { michael@0: nsCSSValueGradient(bool aIsRadial, bool aIsRepeating); michael@0: michael@0: // true if gradient is radial, false if it is linear michael@0: bool mIsRadial; michael@0: bool mIsRepeating; michael@0: bool mIsLegacySyntax; michael@0: bool mIsExplicitSize; michael@0: // line position and angle michael@0: nsCSSValuePair mBgPos; michael@0: nsCSSValue mAngle; michael@0: michael@0: // Only meaningful if mIsRadial is true michael@0: private: michael@0: nsCSSValue mRadialValues[2]; michael@0: public: michael@0: nsCSSValue& GetRadialShape() michael@0: { michael@0: MOZ_ASSERT(!mIsExplicitSize); michael@0: return mRadialValues[0]; michael@0: } michael@0: const nsCSSValue& GetRadialShape() const michael@0: { michael@0: MOZ_ASSERT(!mIsExplicitSize); michael@0: return mRadialValues[0]; michael@0: } michael@0: nsCSSValue& GetRadialSize() michael@0: { michael@0: MOZ_ASSERT(!mIsExplicitSize); michael@0: return mRadialValues[1]; michael@0: } michael@0: const nsCSSValue& GetRadialSize() const michael@0: { michael@0: MOZ_ASSERT(!mIsExplicitSize); michael@0: return mRadialValues[1]; michael@0: } michael@0: nsCSSValue& GetRadiusX() michael@0: { michael@0: MOZ_ASSERT(mIsExplicitSize); michael@0: return mRadialValues[0]; michael@0: } michael@0: const nsCSSValue& GetRadiusX() const michael@0: { michael@0: MOZ_ASSERT(mIsExplicitSize); michael@0: return mRadialValues[0]; michael@0: } michael@0: nsCSSValue& GetRadiusY() michael@0: { michael@0: MOZ_ASSERT(mIsExplicitSize); michael@0: return mRadialValues[1]; michael@0: } michael@0: const nsCSSValue& GetRadiusY() const michael@0: { michael@0: MOZ_ASSERT(mIsExplicitSize); michael@0: return mRadialValues[1]; michael@0: } michael@0: michael@0: InfallibleTArray mStops; michael@0: michael@0: bool operator==(const nsCSSValueGradient& aOther) const michael@0: { michael@0: if (mIsRadial != aOther.mIsRadial || michael@0: mIsRepeating != aOther.mIsRepeating || michael@0: mIsLegacySyntax != aOther.mIsLegacySyntax || michael@0: mIsExplicitSize != aOther.mIsExplicitSize || michael@0: mBgPos != aOther.mBgPos || michael@0: mAngle != aOther.mAngle || michael@0: mRadialValues[0] != aOther.mRadialValues[0] || michael@0: mRadialValues[1] != aOther.mRadialValues[1]) michael@0: return false; michael@0: michael@0: if (mStops.Length() != aOther.mStops.Length()) michael@0: return false; michael@0: michael@0: for (uint32_t i = 0; i < mStops.Length(); i++) { michael@0: if (mStops[i] != aOther.mStops[i]) michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: bool operator!=(const nsCSSValueGradient& aOther) const michael@0: { michael@0: return !(*this == aOther); michael@0: } michael@0: michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSValueGradient) michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSValueGradient() michael@0: { michael@0: } michael@0: michael@0: nsCSSValueGradient(const nsCSSValueGradient& aOther) MOZ_DELETE; michael@0: nsCSSValueGradient& operator=(const nsCSSValueGradient& aOther) MOZ_DELETE; michael@0: }; michael@0: michael@0: struct nsCSSValueTokenStream MOZ_FINAL { michael@0: nsCSSValueTokenStream(); michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSValueTokenStream(); michael@0: michael@0: public: michael@0: bool operator==(const nsCSSValueTokenStream& aOther) const michael@0: { michael@0: bool eq; michael@0: return mPropertyID == aOther.mPropertyID && michael@0: mShorthandPropertyID == aOther.mShorthandPropertyID && michael@0: mTokenStream.Equals(aOther.mTokenStream) && michael@0: (mBaseURI == aOther.mBaseURI || michael@0: (mBaseURI && aOther.mBaseURI && michael@0: NS_SUCCEEDED(mBaseURI->Equals(aOther.mBaseURI, &eq)) && michael@0: eq)) && michael@0: (mSheetURI == aOther.mSheetURI || michael@0: (mSheetURI && aOther.mSheetURI && michael@0: NS_SUCCEEDED(mSheetURI->Equals(aOther.mSheetURI, &eq)) && michael@0: eq)) && michael@0: (mSheetPrincipal == aOther.mSheetPrincipal || michael@0: (mSheetPrincipal && aOther.mSheetPrincipal && michael@0: NS_SUCCEEDED(mSheetPrincipal->Equals(aOther.mSheetPrincipal, michael@0: &eq)) && michael@0: eq)); michael@0: } michael@0: michael@0: bool operator!=(const nsCSSValueTokenStream& aOther) const michael@0: { michael@0: return !(*this == aOther); michael@0: } michael@0: michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSValueTokenStream) michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: // The property that has mTokenStream as its unparsed specified value. michael@0: // When a variable reference is used in a shorthand property, a michael@0: // TokenStream value is stored as the specified value for each of its michael@0: // component longhand properties. michael@0: nsCSSProperty mPropertyID; michael@0: michael@0: // The shorthand property that had a value with a variable reference, michael@0: // which caused the longhand property identified by mPropertyID to have michael@0: // a TokenStream value. michael@0: nsCSSProperty mShorthandPropertyID; michael@0: michael@0: // The unparsed CSS corresponding to the specified value of the property. michael@0: // When the value of a shorthand property has a variable reference, the michael@0: // same mTokenStream value is used on each of the nsCSSValueTokenStream michael@0: // objects that will be set by parsing the shorthand. michael@0: nsString mTokenStream; michael@0: michael@0: nsCOMPtr mBaseURI; michael@0: nsCOMPtr mSheetURI; michael@0: nsCOMPtr mSheetPrincipal; michael@0: nsCSSStyleSheet* mSheet; michael@0: uint32_t mLineNumber; michael@0: uint32_t mLineOffset; michael@0: michael@0: // This table is used to hold a reference on to any ImageValue that results michael@0: // from re-parsing this token stream at computed value time. When properties michael@0: // like background-image contain a normal url(), the Declaration's data block michael@0: // will hold a reference to the ImageValue. When a token stream is used, michael@0: // the Declaration only holds on to this nsCSSValueTokenStream object, and michael@0: // the ImageValue would only exist for the duration of michael@0: // nsRuleNode::WalkRuleTree, in the AutoCSSValueArray. So instead when michael@0: // we re-parse a token stream and get an ImageValue, we record it in this michael@0: // table so that the Declaration can be the object that keeps holding michael@0: // a reference to it. michael@0: nsTHashtable > mImageValues; michael@0: michael@0: private: michael@0: nsCSSValueTokenStream(const nsCSSValueTokenStream& aOther) MOZ_DELETE; michael@0: nsCSSValueTokenStream& operator=(const nsCSSValueTokenStream& aOther) MOZ_DELETE; michael@0: }; michael@0: michael@0: class nsCSSValueFloatColor MOZ_FINAL { michael@0: public: michael@0: nsCSSValueFloatColor(float aComponent1, float aComponent2, float aComponent3, michael@0: float aAlpha) michael@0: : mComponent1(aComponent1) michael@0: , mComponent2(aComponent2) michael@0: , mComponent3(aComponent3) michael@0: , mAlpha(aAlpha) michael@0: { michael@0: MOZ_COUNT_CTOR(nsCSSValueFloatColor); michael@0: } michael@0: michael@0: private: michael@0: // Private destructor, to discourage deletion outside of Release(): michael@0: ~nsCSSValueFloatColor() michael@0: { michael@0: MOZ_COUNT_DTOR(nsCSSValueFloatColor); michael@0: } michael@0: michael@0: public: michael@0: bool operator==(nsCSSValueFloatColor& aOther) const; michael@0: michael@0: nscolor GetColorValue(nsCSSUnit aUnit) const; michael@0: bool IsNonTransparentColor() const; michael@0: michael@0: void AppendToString(nsCSSUnit aUnit, nsAString& aResult) const; michael@0: michael@0: size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; michael@0: michael@0: NS_INLINE_DECL_REFCOUNTING(nsCSSValueFloatColor) michael@0: michael@0: private: michael@0: // FIXME: We should not be clamping specified RGB color components. michael@0: float mComponent1; // 0..1 for RGB, 0..360 for HSL michael@0: float mComponent2; // 0..1 michael@0: float mComponent3; // 0..1 michael@0: float mAlpha; // 0..1 michael@0: michael@0: nsCSSValueFloatColor(const nsCSSValueFloatColor& aOther) MOZ_DELETE; michael@0: nsCSSValueFloatColor& operator=(const nsCSSValueFloatColor& aOther) michael@0: MOZ_DELETE; michael@0: }; michael@0: michael@0: struct nsCSSCornerSizes { michael@0: nsCSSCornerSizes(void); michael@0: nsCSSCornerSizes(const nsCSSCornerSizes& aCopy); michael@0: ~nsCSSCornerSizes(); michael@0: michael@0: // argument is a "full corner" constant from nsStyleConsts.h michael@0: nsCSSValue const & GetCorner(uint32_t aCorner) const { michael@0: return this->*corners[aCorner]; michael@0: } michael@0: nsCSSValue & GetCorner(uint32_t aCorner) { michael@0: return this->*corners[aCorner]; michael@0: } michael@0: michael@0: bool operator==(const nsCSSCornerSizes& aOther) const { michael@0: NS_FOR_CSS_FULL_CORNERS(corner) { michael@0: if (this->GetCorner(corner) != aOther.GetCorner(corner)) michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool operator!=(const nsCSSCornerSizes& aOther) const { michael@0: NS_FOR_CSS_FULL_CORNERS(corner) { michael@0: if (this->GetCorner(corner) != aOther.GetCorner(corner)) michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool HasValue() const { michael@0: NS_FOR_CSS_FULL_CORNERS(corner) { michael@0: if (this->GetCorner(corner).GetUnit() != eCSSUnit_Null) michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void Reset(); michael@0: michael@0: nsCSSValue mTopLeft; michael@0: nsCSSValue mTopRight; michael@0: nsCSSValue mBottomRight; michael@0: nsCSSValue mBottomLeft; michael@0: michael@0: protected: michael@0: typedef nsCSSValue nsCSSCornerSizes::*corner_type; michael@0: static const corner_type corners[4]; michael@0: }; michael@0: michael@0: #endif /* nsCSSValue_h___ */ michael@0: