text: /* -*- 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/. */
  
  /*
   * structs that contain the data provided by nsStyleContext, the
   * internal API for computed style data for an element
   */
  
  #ifndef nsStyleStruct_h___
  #define nsStyleStruct_h___
  
  #include "mozilla/Attributes.h"
  
  #include "nsColor.h"
  #include "nsCoord.h"
  #include "nsMargin.h"
  #include "nsRect.h"
  #include "nsFont.h"
  #include "nsStyleCoord.h"
  #include "nsStyleConsts.h"
  #include "nsChangeHint.h"
  #include "nsPresContext.h"
  #include "nsCOMPtr.h"
  #include "nsCOMArray.h"
  #include "nsTArray.h"
  #include "nsIAtom.h"
  #include "nsIURI.h"
  #include "nsCSSValue.h"
  #include "nsStyleTransformMatrix.h"
  #include "nsAlgorithm.h"
  #include "imgIRequest.h"
  #include "gfxRect.h"
  
  class nsIFrame;
  class imgIRequest;
  class imgIContainer;
  struct nsCSSValueList;
  
  // Includes nsStyleStructID.
  #include "nsStyleStructFwd.h"
  
  // Bits for each struct.
  // NS_STYLE_INHERIT_BIT defined in nsStyleStructFwd.h
  #define NS_STYLE_INHERIT_MASK             0x007fffff
  
  // Additional bits for nsStyleContext's mBits:
  // See nsStyleContext::HasTextDecorationLines
  #define NS_STYLE_HAS_TEXT_DECORATION_LINES 0x00800000
  // See nsStyleContext::HasPseudoElementData.
  #define NS_STYLE_HAS_PSEUDO_ELEMENT_DATA  0x01000000
  // See nsStyleContext::RelevantLinkIsVisited
  #define NS_STYLE_RELEVANT_LINK_VISITED    0x02000000
  // See nsStyleContext::IsStyleIfVisited
  #define NS_STYLE_IS_STYLE_IF_VISITED      0x04000000
  // See nsStyleContext::GetPseudoEnum
  #define NS_STYLE_CONTEXT_TYPE_MASK        0xf8000000
  #define NS_STYLE_CONTEXT_TYPE_SHIFT       27
  
  // Additional bits for nsRuleNode's mDependentBits:
  #define NS_RULE_NODE_GC_MARK              0x02000000
  #define NS_RULE_NODE_USED_DIRECTLY        0x04000000
  #define NS_RULE_NODE_IS_IMPORTANT         0x08000000
  #define NS_RULE_NODE_LEVEL_MASK           0xf0000000
  #define NS_RULE_NODE_LEVEL_SHIFT          28
  
  // The lifetime of these objects is managed by the presshell's arena.
  
  struct nsStyleFont {
    nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext);
    nsStyleFont(const nsStyleFont& aStyleFont);
    nsStyleFont(nsPresContext *aPresContext);
  private:
    void Init(nsPresContext *aPresContext);
  public:
    ~nsStyleFont(void) {
      MOZ_COUNT_DTOR(nsStyleFont);
    }
  
    nsChangeHint CalcDifference(const nsStyleFont& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_REFLOW;
    }
    static nsChangeHint CalcFontDifference(const nsFont& aFont1, const nsFont& aFont2);
  
    static nscoord ZoomText(nsPresContext* aPresContext, nscoord aSize);
    static nscoord UnZoomText(nsPresContext* aPresContext, nscoord aSize);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
    void Destroy(nsPresContext* aContext);
  
    nsFont  mFont;        // [inherited]
    nscoord mSize;        // [inherited] Our "computed size". Can be different
                          // from mFont.size which is our "actual size" and is
                          // enforced to be >= the user's preferred min-size.
                          // mFont.size should be used for display purposes
                          // while mSize is the value to return in
                          // getComputedStyle() for example.
    uint8_t mGenericID;   // [inherited] generic CSS font family, if any;
                          // value is a kGenericFont_* constant, see nsFont.h.
  
    // MathML scriptlevel support
    int8_t  mScriptLevel;          // [inherited]
  
    // was mLanguage set based on a lang attribute in the document?
    bool mExplicitLanguage;        // [inherited]
  
    // The value mSize would have had if scriptminsize had never been applied
    nscoord mScriptUnconstrainedSize;
    nscoord mScriptMinSize;        // [inherited] length
    float   mScriptSizeMultiplier; // [inherited]
    nsCOMPtr<nsIAtom> mLanguage;   // [inherited]
  };
  
  struct nsStyleGradientStop {
    nsStyleCoord mLocation; // percent, coord, calc, none
    nscolor mColor;
  };
  
  class nsStyleGradient {
  public:
    nsStyleGradient();
    uint8_t mShape;  // NS_STYLE_GRADIENT_SHAPE_*
    uint8_t mSize;   // NS_STYLE_GRADIENT_SIZE_*;
                     // not used (must be FARTHEST_CORNER) for linear shape
    bool mRepeating;
    bool mLegacySyntax;
  
    nsStyleCoord mBgPosX; // percent, coord, calc, none
    nsStyleCoord mBgPosY; // percent, coord, calc, none
    nsStyleCoord mAngle;  // none, angle
  
    nsStyleCoord mRadiusX; // percent, coord, calc, none
    nsStyleCoord mRadiusY; // percent, coord, calc, none
  
    // stops are in the order specified in the stylesheet
    nsTArray<nsStyleGradientStop> mStops;
  
    bool operator==(const nsStyleGradient& aOther) const;
    bool operator!=(const nsStyleGradient& aOther) const {
      return !(*this == aOther);
    }
  
    bool IsOpaque();
    bool HasCalc();
    uint32_t Hash(PLDHashNumber aHash);
  
    NS_INLINE_DECL_REFCOUNTING(nsStyleGradient)
  
  private:
    ~nsStyleGradient() {}
  
    nsStyleGradient(const nsStyleGradient& aOther) MOZ_DELETE;
    nsStyleGradient& operator=(const nsStyleGradient& aOther) MOZ_DELETE;
  };
  
  enum nsStyleImageType {
    eStyleImageType_Null,
    eStyleImageType_Image,
    eStyleImageType_Gradient,
    eStyleImageType_Element
  };
  
  /**
   * Represents a paintable image of one of the following types.
   * (1) A real image loaded from an external source.
   * (2) A CSS linear or radial gradient.
   * (3) An element within a document, or an <img>, <video>, or <canvas> element
   *     not in a document.
   * (*) Optionally a crop rect can be set to paint a partial (rectangular)
   * region of an image. (Currently, this feature is only supported with an
   * image of type (1)).
   *
   * This struct is currently used only for 'background-image', but it may be
   * used by other CSS properties such as 'border-image', 'list-style-image', and
   * 'content' in the future (bug 507052).
   */
  struct nsStyleImage {
    nsStyleImage();
    ~nsStyleImage();
    nsStyleImage(const nsStyleImage& aOther);
    nsStyleImage& operator=(const nsStyleImage& aOther);
  
    void SetNull();
    void SetImageData(imgIRequest* aImage);
    void TrackImage(nsPresContext* aContext);
    void UntrackImage(nsPresContext* aContext);
    void SetGradientData(nsStyleGradient* aGradient);
    void SetElementId(const PRUnichar* aElementId);
    void SetCropRect(nsStyleSides* aCropRect);
  
    nsStyleImageType GetType() const {
      return mType;
    }
    imgIRequest* GetImageData() const {
      NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, "Data is not an image!");
      NS_ABORT_IF_FALSE(mImageTracked,
                        "Should be tracking any image we're going to use!");
      return mImage;
    }
    nsStyleGradient* GetGradientData() const {
      NS_ASSERTION(mType == eStyleImageType_Gradient, "Data is not a gradient!");
      return mGradient;
    }
    const PRUnichar* GetElementId() const {
      NS_ASSERTION(mType == eStyleImageType_Element, "Data is not an element!");
      return mElementId;
    }
    nsStyleSides* GetCropRect() const {
      NS_ASSERTION(mType == eStyleImageType_Image,
                   "Only image data can have a crop rect");
      return mCropRect;
    }
  
    /**
     * Compute the actual crop rect in pixels, using the source image bounds.
     * The computation involves converting percentage unit to pixel unit and
     * clamping each side value to fit in the source image bounds.
     * @param aActualCropRect the computed actual crop rect.
     * @param aIsEntireImage true iff |aActualCropRect| is identical to the
     * source image bounds.
     * @return true iff |aActualCropRect| holds a meaningful value.
     */
    bool ComputeActualCropRect(nsIntRect& aActualCropRect,
                                 bool* aIsEntireImage = nullptr) const;
  
    /**
     * Requests a decode on the image.
     */
    nsresult RequestDecode() const;
    /**
     * @return true if the item is definitely opaque --- i.e., paints every
     * pixel within its bounds opaquely, and the bounds contains at least a pixel.
     */
    bool IsOpaque() const;
    /**
     * @return true if this image is fully loaded, and its size is calculated;
     * always returns true if |mType| is |eStyleImageType_Gradient| or
     * |eStyleImageType_Element|.
     */
    bool IsComplete() const;
    /**
     * @return true if it is 100% confident that this image contains no pixel
     * to draw.
     */
    bool IsEmpty() const {
      // There are some other cases when the image will be empty, for example
      // when the crop rect is empty. However, checking the emptiness of crop
      // rect is non-trivial since each side value can be specified with
      // percentage unit, which can not be evaluated until the source image size
      // is available. Therefore, we currently postpone the evaluation of crop
      // rect until the actual rendering time --- alternatively until GetOpaqueRegion()
      // is called.
      return mType == eStyleImageType_Null;
    }
  
    bool operator==(const nsStyleImage& aOther) const;
    bool operator!=(const nsStyleImage& aOther) const {
      return !(*this == aOther);
    }
  
  private:
    void DoCopy(const nsStyleImage& aOther);
  
    nsStyleImageType mType;
    union {
      imgIRequest* mImage;
      nsStyleGradient* mGradient;
      PRUnichar* mElementId;
    };
    // This is _currently_ used only in conjunction with eStyleImageType_Image.
    nsAutoPtr<nsStyleSides> mCropRect;
  #ifdef DEBUG
    bool mImageTracked;
  #endif
  };
  
  struct nsStyleColor {
    nsStyleColor(nsPresContext* aPresContext);
    nsStyleColor(const nsStyleColor& aOther);
    ~nsStyleColor(void) {
      MOZ_COUNT_DTOR(nsStyleColor);
    }
  
    nsChangeHint CalcDifference(const nsStyleColor& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_VISUAL;
    }
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleColor();
      aContext->FreeToShell(sizeof(nsStyleColor), this);
    }
  
    // Don't add ANY members to this struct!  We can achieve caching in the rule
    // tree (rather than the style tree) by letting color stay by itself! -dwh
    nscolor mColor;                 // [inherited]
  };
  
  struct nsStyleBackground {
    nsStyleBackground();
    nsStyleBackground(const nsStyleBackground& aOther);
    ~nsStyleBackground();
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext);
  
    nsChangeHint CalcDifference(const nsStyleBackground& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
    }
  
    struct Position;
    friend struct Position;
    struct Position {
      typedef nsStyleCoord::Calc PositionCoord;
      PositionCoord mXPosition, mYPosition;
  
      // Initialize nothing
      Position() {}
  
      // Initialize to initial values
      void SetInitialValues();
  
      // True if the effective background image position described by this depends
      // on the size of the corresponding frame.
      bool DependsOnPositioningAreaSize() const {
        return mXPosition.mPercent != 0.0f || mYPosition.mPercent != 0.0f;
      }
  
      bool operator==(const Position& aOther) const {
        return mXPosition == aOther.mXPosition &&
               mYPosition == aOther.mYPosition;
      }
      bool operator!=(const Position& aOther) const {
        return !(*this == aOther);
      }
    };
  
    struct Size;
    friend struct Size;
    struct Size {
      struct Dimension : public nsStyleCoord::Calc {
        nscoord ResolveLengthPercentage(nscoord aAvailable) const {
          double d = double(mPercent) * double(aAvailable) + double(mLength);
          if (d < 0.0)
            return 0;
          return NSToCoordRoundWithClamp(float(d));
        }
      };
      Dimension mWidth, mHeight;
  
      nscoord ResolveWidthLengthPercentage(const nsSize& aBgPositioningArea) const {
        NS_ABORT_IF_FALSE(mWidthType == eLengthPercentage,
                          "resolving non-length/percent dimension!");
        return mWidth.ResolveLengthPercentage(aBgPositioningArea.width);
      }
  
      nscoord ResolveHeightLengthPercentage(const nsSize& aBgPositioningArea) const {
        NS_ABORT_IF_FALSE(mHeightType == eLengthPercentage,
                          "resolving non-length/percent dimension!");
        return mHeight.ResolveLengthPercentage(aBgPositioningArea.height);
      }
  
      // Except for eLengthPercentage, Dimension types which might change
      // how a layer is painted when the corresponding frame's dimensions
      // change *must* precede all dimension types which are agnostic to
      // frame size; see DependsOnDependsOnPositioningAreaSizeSize.
      enum DimensionType {
        // If one of mWidth and mHeight is eContain or eCover, then both are.
        // Also, these two values must equal the corresponding values in
        // kBackgroundSizeKTable.
        eContain, eCover,
  
        eAuto,
        eLengthPercentage,
        eDimensionType_COUNT
      };
      uint8_t mWidthType, mHeightType;
  
      // True if the effective image size described by this depends on the size of
      // the corresponding frame, when aImage (which must not have null type) is
      // the background image.
      bool DependsOnPositioningAreaSize(const nsStyleImage& aImage) const;
  
      // Initialize nothing
      Size() {}
  
      // Initialize to initial values
      void SetInitialValues();
  
      bool operator==(const Size& aOther) const;
      bool operator!=(const Size& aOther) const {
        return !(*this == aOther);
      }
    };
    
    struct Repeat;
    friend struct Repeat;
    struct Repeat {
      uint8_t mXRepeat, mYRepeat;
      
      // Initialize nothing
      Repeat() {}
  
      // Initialize to initial values
      void SetInitialValues();
  
      bool operator==(const Repeat& aOther) const {
        return mXRepeat == aOther.mXRepeat &&
               mYRepeat == aOther.mYRepeat;
      }
      bool operator!=(const Repeat& aOther) const {
        return !(*this == aOther);
      }
    };
  
    struct Layer;
    friend struct Layer;
    struct Layer {
      uint8_t mAttachment;                // [reset] See nsStyleConsts.h
      uint8_t mClip;                      // [reset] See nsStyleConsts.h
      uint8_t mOrigin;                    // [reset] See nsStyleConsts.h
      Repeat mRepeat;                     // [reset] See nsStyleConsts.h
      Position mPosition;                 // [reset]
      nsStyleImage mImage;                // [reset]
      Size mSize;                         // [reset]
  
      // Initializes only mImage
      Layer();
      ~Layer();
  
      // Register/unregister images with the document. We do this only
      // after the dust has settled in ComputeBackgroundData.
      void TrackImages(nsPresContext* aContext) {
        if (mImage.GetType() == eStyleImageType_Image)
          mImage.TrackImage(aContext);
      }
      void UntrackImages(nsPresContext* aContext) {
        if (mImage.GetType() == eStyleImageType_Image)
          mImage.UntrackImage(aContext);
      }
  
      void SetInitialValues();
  
      // True if the rendering of this layer might change when the size
      // of the background positioning area changes.  This is true for any
      // non-solid-color background whose position or size depends on
      // the size of the positioning area.  It's also true for SVG images
      // whose root <svg> node has a viewBox.
      bool RenderingMightDependOnPositioningAreaSizeChange() const;
  
      // An equality operator that compares the images using URL-equality
      // rather than pointer-equality.
      bool operator==(const Layer& aOther) const;
      bool operator!=(const Layer& aOther) const {
        return !(*this == aOther);
      }
    };
  
    // The (positive) number of computed values of each property, since
    // the lengths of the lists are independent.
    uint32_t mAttachmentCount,
             mClipCount,
             mOriginCount,
             mRepeatCount,
             mPositionCount,
             mImageCount,
             mSizeCount;
    // Layers are stored in an array, matching the top-to-bottom order in
    // which they are specified in CSS.  The number of layers to be used
    // should come from the background-image property.  We create
    // additional |Layer| objects for *any* property, not just
    // background-image.  This means that the bottommost layer that
    // callers in layout care about (which is also the one whose
    // background-clip applies to the background-color) may not be last
    // layer.  In layers below the bottom layer, properties will be
    // uninitialized unless their count, above, indicates that they are
    // present.
    nsAutoTArray<Layer, 1> mLayers;
  
    const Layer& BottomLayer() const { return mLayers[mImageCount - 1]; }
  
    #define NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(var_, stylebg_) \
      for (uint32_t var_ = (stylebg_) ? (stylebg_)->mImageCount : 1; var_-- != 0; )
    #define NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT_WITH_RANGE(var_, stylebg_, start_, count_) \
      NS_ASSERTION((int32_t)(start_) >= 0 && (uint32_t)(start_) < ((stylebg_) ? (stylebg_)->mImageCount : 1), "Invalid layer start!"); \
      NS_ASSERTION((count_) > 0 && (count_) <= (start_) + 1, "Invalid layer range!"); \
      for (uint32_t var_ = (start_) + 1; var_-- != (uint32_t)((start_) + 1 - (count_)); )
  
    nscolor mBackgroundColor;       // [reset]
  
    // FIXME: This (now background-break in css3-background) should
    // probably move into a different struct so that everything in
    // nsStyleBackground is set by the background shorthand.
    uint8_t mBackgroundInlinePolicy; // [reset] See nsStyleConsts.h
  
    // True if this background is completely transparent.
    bool IsTransparent() const;
  
    // We have to take slower codepaths for fixed background attachment,
    // but we don't want to do that when there's no image.
    // Not inline because it uses an nsCOMPtr<imgIRequest>
    // FIXME: Should be in nsStyleStructInlines.h.
    bool HasFixedBackground() const;
  };
  
  // See https://bugzilla.mozilla.org/show_bug.cgi?id=271586#c43 for why
  // this is hard to replace with 'currentColor'.
  #define BORDER_COLOR_FOREGROUND   0x20
  #define OUTLINE_COLOR_INITIAL     0x80
  // FOREGROUND | INITIAL(OUTLINE)
  #define BORDER_COLOR_SPECIAL      0xA0
  #define BORDER_STYLE_MASK         0x1F
  
  #define NS_SPACING_MARGIN   0
  #define NS_SPACING_PADDING  1
  #define NS_SPACING_BORDER   2
  
  
  struct nsStyleMargin {
    nsStyleMargin(void);
    nsStyleMargin(const nsStyleMargin& aMargin);
    ~nsStyleMargin(void) {
      MOZ_COUNT_DTOR(nsStyleMargin);
    }
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
    void Destroy(nsPresContext* aContext);
  
    void RecalcData();
    nsChangeHint CalcDifference(const nsStyleMargin& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
                             NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
                                            nsChangeHint_NeedDirtyReflow));
    }
  
    nsStyleSides  mMargin;          // [reset] coord, percent, calc, auto
  
    bool IsWidthDependent() const { return !mHasCachedMargin; }
    bool GetMargin(nsMargin& aMargin) const
    {
      if (mHasCachedMargin) {
        aMargin = mCachedMargin;
        return true;
      }
      return false;
    }
  
  protected:
    bool          mHasCachedMargin;
    nsMargin      mCachedMargin;
  };
  
  
  struct nsStylePadding {
    nsStylePadding(void);
    nsStylePadding(const nsStylePadding& aPadding);
    ~nsStylePadding(void) {
      MOZ_COUNT_DTOR(nsStylePadding);
    }
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
    void Destroy(nsPresContext* aContext);
  
    void RecalcData();
    nsChangeHint CalcDifference(const nsStylePadding& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
                             nsChangeHint_ClearDescendantIntrinsics);
    }
  
    nsStyleSides  mPadding;         // [reset] coord, percent, calc
  
    bool IsWidthDependent() const { return !mHasCachedPadding; }
    bool GetPadding(nsMargin& aPadding) const
    {
      if (mHasCachedPadding) {
        aPadding = mCachedPadding;
        return true;
      }
      return false;
    }
  
  protected:
    bool          mHasCachedPadding;
    nsMargin      mCachedPadding;
  };
  
  struct nsBorderColors {
    nsBorderColors* mNext;
    nscolor mColor;
  
    nsBorderColors() : mNext(nullptr), mColor(NS_RGB(0,0,0)) {}
    nsBorderColors(const nscolor& aColor) : mNext(nullptr), mColor(aColor) {}
    ~nsBorderColors();
  
    nsBorderColors* Clone() const { return Clone(true); }
  
    static bool Equal(const nsBorderColors* c1,
                        const nsBorderColors* c2) {
      if (c1 == c2)
        return true;
      while (c1 && c2) {
        if (c1->mColor != c2->mColor)
          return false;
        c1 = c1->mNext;
        c2 = c2->mNext;
      }
      // both should be NULL if these are equal, otherwise one
      // has more colors than another
      return !c1 && !c2;
    }
  
  private:
    nsBorderColors* Clone(bool aDeep) const;
  };
  
  struct nsCSSShadowItem {
    nscoord mXOffset;
    nscoord mYOffset;
    nscoord mRadius;
    nscoord mSpread;
  
    nscolor      mColor;
    bool mHasColor; // Whether mColor should be used
    bool mInset;
  
    nsCSSShadowItem() : mHasColor(false) {
      MOZ_COUNT_CTOR(nsCSSShadowItem);
    }
    ~nsCSSShadowItem() {
      MOZ_COUNT_DTOR(nsCSSShadowItem);
    }
  
    bool operator==(const nsCSSShadowItem& aOther) {
      return (mXOffset == aOther.mXOffset &&
              mYOffset == aOther.mYOffset &&
              mRadius == aOther.mRadius &&
              mHasColor == aOther.mHasColor &&
              mSpread == aOther.mSpread &&
              mInset == aOther.mInset &&
              (!mHasColor || mColor == aOther.mColor));
    }
    bool operator!=(const nsCSSShadowItem& aOther) {
      return !(*this == aOther);
    }
  };
  
  class nsCSSShadowArray {
    public:
      void* operator new(size_t aBaseSize, uint32_t aArrayLen) {
        // We can allocate both this nsCSSShadowArray and the
        // actual array in one allocation. The amount of memory to
        // allocate is equal to the class's size + the number of bytes for all
        // but the first array item (because aBaseSize includes one
        // item, see the private declarations)
        return ::operator new(aBaseSize +
                              (aArrayLen - 1) * sizeof(nsCSSShadowItem));
      }
  
      nsCSSShadowArray(uint32_t aArrayLen) :
        mLength(aArrayLen)
      {
        MOZ_COUNT_CTOR(nsCSSShadowArray);
        for (uint32_t i = 1; i < mLength; ++i) {
          // Make sure we call the constructors of each nsCSSShadowItem
          // (the first one is called for us because we declared it under private)
          new (&mArray[i]) nsCSSShadowItem();
        }
      }
      ~nsCSSShadowArray() {
        MOZ_COUNT_DTOR(nsCSSShadowArray);
        for (uint32_t i = 1; i < mLength; ++i) {
          mArray[i].~nsCSSShadowItem();
        }
      }
  
      uint32_t Length() const { return mLength; }
      nsCSSShadowItem* ShadowAt(uint32_t i) {
        NS_ABORT_IF_FALSE(i < mLength, "Accessing too high an index in the text shadow array!");
        return &mArray[i];
      }
      const nsCSSShadowItem* ShadowAt(uint32_t i) const {
        NS_ABORT_IF_FALSE(i < mLength, "Accessing too high an index in the text shadow array!");
        return &mArray[i];
      }
  
      bool HasShadowWithInset(bool aInset) {
        for (uint32_t i = 0; i < mLength; ++i) {
          if (mArray[i].mInset == aInset)
            return true;
        }
        return false;
      }
  
      NS_INLINE_DECL_REFCOUNTING(nsCSSShadowArray)
  
    private:
      uint32_t mLength;
      nsCSSShadowItem mArray[1]; // This MUST be the last item
  };
  
  // Border widths are rounded to the nearest-below integer number of pixels,
  // but values between zero and one device pixels are always rounded up to
  // one device pixel.
  #define NS_ROUND_BORDER_TO_PIXELS(l,tpp) \
    ((l) == 0) ? 0 : NS_MAX((tpp), (l) / (tpp) * (tpp))
  // Outline offset is rounded to the nearest integer number of pixels, but values
  // between zero and one device pixels are always rounded up to one device pixel.
  // Note that the offset can be negative.
  #define NS_ROUND_OFFSET_TO_PIXELS(l,tpp) \
    (((l) == 0) ? 0 : \
      ((l) > 0) ? NS_MAX( (tpp), ((l) + ((tpp) / 2)) / (tpp) * (tpp)) : \
                  NS_MIN(-(tpp), ((l) - ((tpp) / 2)) / (tpp) * (tpp)))
  
  // Returns if the given border style type is visible or not
  static bool IsVisibleBorderStyle(uint8_t aStyle)
  {
    return (aStyle != NS_STYLE_BORDER_STYLE_NONE &&
            aStyle != NS_STYLE_BORDER_STYLE_HIDDEN);
  }
  
  struct nsStyleBorder {
    nsStyleBorder(nsPresContext* aContext);
    nsStyleBorder(const nsStyleBorder& aBorder);
    ~nsStyleBorder();
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW;
    void Destroy(nsPresContext* aContext);
  
    nsChangeHint CalcDifference(const nsStyleBorder& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_CombineHint(NS_STYLE_HINT_REFLOW,
                            nsChangeHint_BorderStyleNoneChange);
    }
  
    void EnsureBorderColors() {
      if (!mBorderColors) {
        mBorderColors = new nsBorderColors*[4];
        if (mBorderColors)
          for (int32_t i = 0; i < 4; i++)
            mBorderColors[i] = nullptr;
      }
    }
  
    void ClearBorderColors(mozilla::css::Side aSide) {
      if (mBorderColors && mBorderColors[aSide]) {
        delete mBorderColors[aSide];
        mBorderColors[aSide] = nullptr;
      }
    }
  
    // Return whether aStyle is a visible style.  Invisible styles cause
    // the relevant computed border width to be 0.
    // Note that this does *not* consider the effects of 'border-image':
    // if border-style is none, but there is a loaded border image,
    // HasVisibleStyle will be false even though there *is* a border.
    bool HasVisibleStyle(mozilla::css::Side aSide) const
    {
      return IsVisibleBorderStyle(GetBorderStyle(aSide));
    }
  
    // aBorderWidth is in twips
    void SetBorderWidth(mozilla::css::Side aSide, nscoord aBorderWidth)
    {
      nscoord roundedWidth =
        NS_ROUND_BORDER_TO_PIXELS(aBorderWidth, mTwipsPerPixel);
      mBorder.Side(aSide) = roundedWidth;
      if (HasVisibleStyle(aSide))
        mComputedBorder.Side(aSide) = roundedWidth;
    }
  
    // Get the computed border (plus rounding).  This does consider the
    // effects of 'border-style: none', but does not consider
    // 'border-image'.
    const nsMargin& GetComputedBorder() const
    {
      return mComputedBorder;
    }
  
    bool HasBorder() const
    {
      return mComputedBorder != nsMargin(0,0,0,0) || mBorderImageSource;
    }
  
    // Get the actual border width for a particular side, in appunits.  Note that
    // this is zero if and only if there is no border to be painted for this
    // side.  That is, this value takes into account the border style and the
    // value is rounded to the nearest device pixel by NS_ROUND_BORDER_TO_PIXELS.
    nscoord GetComputedBorderWidth(mozilla::css::Side aSide) const
    {
      return GetComputedBorder().Side(aSide);
    }
  
    uint8_t GetBorderStyle(mozilla::css::Side aSide) const
    {
      NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side");
      return (mBorderStyle[aSide] & BORDER_STYLE_MASK);
    }
  
    void SetBorderStyle(mozilla::css::Side aSide, uint8_t aStyle)
    {
      NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side");
      mBorderStyle[aSide] &= ~BORDER_STYLE_MASK;
      mBorderStyle[aSide] |= (aStyle & BORDER_STYLE_MASK);
      mComputedBorder.Side(aSide) =
        (HasVisibleStyle(aSide) ? mBorder.Side(aSide) : 0);
    }
  
    // Defined in nsStyleStructInlines.h
    inline bool IsBorderImageLoaded() const;
    inline nsresult RequestDecode();
  
    void GetBorderColor(mozilla::css::Side aSide, nscolor& aColor,
                        bool& aForeground) const
    {
      aForeground = false;
      NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side");
      if ((mBorderStyle[aSide] & BORDER_COLOR_SPECIAL) == 0)
        aColor = mBorderColor[aSide];
      else if (mBorderStyle[aSide] & BORDER_COLOR_FOREGROUND)
        aForeground = true;
      else
        NS_NOTREACHED("OUTLINE_COLOR_INITIAL should not be set here");
    }
  
    void SetBorderColor(mozilla::css::Side aSide, nscolor aColor)
    {
      NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side");
      mBorderColor[aSide] = aColor;
      mBorderStyle[aSide] &= ~BORDER_COLOR_SPECIAL;
    }
  
    // These are defined in nsStyleStructInlines.h
    inline void SetBorderImage(imgIRequest* aImage);
    inline imgIRequest* GetBorderImage() const;
  
    bool HasBorderImage() {return !!mBorderImageSource;}
  
    void TrackImage(nsPresContext* aContext);
    void UntrackImage(nsPresContext* aContext);
  
    nsMargin GetImageOutset() const;
  
    // These methods are used for the caller to caches the sub images created during
    // a border-image paint operation
    inline void SetSubImage(uint8_t aIndex, imgIContainer* aSubImage) const;
    inline imgIContainer* GetSubImage(uint8_t aIndex) const;
  
    void GetCompositeColors(int32_t aIndex, nsBorderColors** aColors) const
    {
      if (!mBorderColors)
        *aColors = nullptr;
      else
        *aColors = mBorderColors[aIndex];
    }
  
    void AppendBorderColor(int32_t aIndex, nscolor aColor)
    {
      NS_ASSERTION(aIndex >= 0 && aIndex <= 3, "bad side for composite border color");
      nsBorderColors* colorEntry = new nsBorderColors(aColor);
      if (!mBorderColors[aIndex])
        mBorderColors[aIndex] = colorEntry;
      else {
        nsBorderColors* last = mBorderColors[aIndex];
        while (last->mNext)
          last = last->mNext;
        last->mNext = colorEntry;
      }
      mBorderStyle[aIndex] &= ~BORDER_COLOR_SPECIAL;
    }
  
    void SetBorderToForeground(mozilla::css::Side aSide)
    {
      NS_ASSERTION(aSide <= NS_SIDE_LEFT, "bad side");
      mBorderStyle[aSide] &= ~BORDER_COLOR_SPECIAL;
      mBorderStyle[aSide] |= BORDER_COLOR_FOREGROUND;
    }
  
  public:
    nsBorderColors** mBorderColors;        // [reset] composite (stripe) colors
    nsRefPtr<nsCSSShadowArray> mBoxShadow; // [reset] NULL for 'none'
  
  #ifdef DEBUG
    bool mImageTracked;
  #endif
  
  protected:
    nsCOMPtr<imgIRequest> mBorderImageSource; // [reset]
  
  public:
    nsStyleCorners mBorderRadius;       // [reset] coord, percent
    nsStyleSides   mBorderImageSlice;   // [reset] factor, percent
    nsStyleSides   mBorderImageWidth;   // [reset] length, factor, percent, auto
    nsStyleSides   mBorderImageOutset;  // [reset] length, factor
  
    uint8_t        mBorderImageFill;    // [reset]
    uint8_t        mBorderImageRepeatH; // [reset] see nsStyleConsts.h
    uint8_t        mBorderImageRepeatV; // [reset]
    uint8_t        mFloatEdge;          // [reset]
  
  protected:
    // mComputedBorder holds the CSS2.1 computed border-width values.
    // In particular, these widths take into account the border-style
    // for the relevant side, and the values are rounded to the nearest
    // device pixel (which is not part of the definition of computed
    // values). The presence or absence of a border-image does not
    // affect border-width values.
    nsMargin      mComputedBorder;
  
    // mBorder holds the nscoord values for the border widths as they
    // would be if all the border-style values were visible (not hidden
    // or none).  This member exists so that when we create structs
    // using the copy constructor during style resolution the new
    // structs will know what the specified values of the border were in
    // case they have more specific rules setting the border style.
    //
    // Note that this isn't quite the CSS specified value, since this
    // has had the enumerated border widths converted to lengths, and
    // all lengths converted to twips.  But it's not quite the computed
    // value either. The values are rounded to the nearest device pixel.
    nsMargin      mBorder;
  
    uint8_t       mBorderStyle[4];  // [reset] See nsStyleConsts.h
    nscolor       mBorderColor[4];  // [reset] the colors to use for a simple
                                    // border.  not used for -moz-border-colors
  private:
    // Cache used by callers for border-image painting
    nsCOMArray<imgIContainer> mSubImages;
  
    nscoord       mTwipsPerPixel;
  
    nsStyleBorder& operator=(const nsStyleBorder& aOther) MOZ_DELETE;
  };
  
  
  struct nsStyleOutline {
    nsStyleOutline(nsPresContext* aPresContext);
    nsStyleOutline(const nsStyleOutline& aOutline);
    ~nsStyleOutline(void) {
      MOZ_COUNT_DTOR(nsStyleOutline);
    }
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleOutline();
      aContext->FreeToShell(sizeof(nsStyleOutline), this);
    }
  
    void RecalcData(nsPresContext* aContext);
    nsChangeHint CalcDifference(const nsStyleOutline& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_CombineHint(nsChangeHint_AllReflowHints,
                            nsChangeHint_RepaintFrame);
    }
  
    nsStyleCorners  mOutlineRadius; // [reset] coord, percent, calc
  
    // Note that this is a specified value.  You can get the actual values
    // with GetOutlineWidth.  You cannot get the computed value directly.
    nsStyleCoord  mOutlineWidth;    // [reset] coord, enum (see nsStyleConsts.h)
    nscoord       mOutlineOffset;   // [reset]
  
    bool GetOutlineWidth(nscoord& aWidth) const
    {
      if (mHasCachedOutline) {
        aWidth = mCachedOutlineWidth;
        return true;
      }
      return false;
    }
  
    uint8_t GetOutlineStyle(void) const
    {
      return (mOutlineStyle & BORDER_STYLE_MASK);
    }
  
    void SetOutlineStyle(uint8_t aStyle)
    {
      mOutlineStyle &= ~BORDER_STYLE_MASK;
      mOutlineStyle |= (aStyle & BORDER_STYLE_MASK);
    }
  
    // false means initial value
    bool GetOutlineColor(nscolor& aColor) const
    {
      if ((mOutlineStyle & BORDER_COLOR_SPECIAL) == 0) {
        aColor = mOutlineColor;
        return true;
      }
      return false;
    }
  
    void SetOutlineColor(nscolor aColor)
    {
      mOutlineColor = aColor;
      mOutlineStyle &= ~BORDER_COLOR_SPECIAL;
    }
  
    void SetOutlineInitialColor()
    {
      mOutlineStyle |= OUTLINE_COLOR_INITIAL;
    }
  
    bool GetOutlineInitialColor() const
    {
      return !!(mOutlineStyle & OUTLINE_COLOR_INITIAL);
    }
  
  protected:
    // This value is the actual value, so it's rounded to the nearest device
    // pixel.
    nscoord       mCachedOutlineWidth;
  
    nscolor       mOutlineColor;    // [reset]
  
    bool          mHasCachedOutline;
    uint8_t       mOutlineStyle;    // [reset] See nsStyleConsts.h
  
    nscoord       mTwipsPerPixel;
  };
  
  
  struct nsStyleList {
    nsStyleList(void);
    nsStyleList(const nsStyleList& aStyleList);
    ~nsStyleList(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleList();
      aContext->FreeToShell(sizeof(nsStyleList), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleList& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    imgIRequest* GetListStyleImage() const { return mListStyleImage; }
    void SetListStyleImage(imgIRequest* aReq)
    {
      if (mListStyleImage)
        mListStyleImage->UnlockImage();
      mListStyleImage = aReq;
      if (mListStyleImage)
        mListStyleImage->LockImage();
    }
  
    uint8_t   mListStyleType;             // [inherited] See nsStyleConsts.h
    uint8_t   mListStylePosition;         // [inherited]
  private:
    nsCOMPtr<imgIRequest> mListStyleImage; // [inherited]
    nsStyleList& operator=(const nsStyleList& aOther) MOZ_DELETE;
  public:
    nsRect        mImageRegion;           // [inherited] the rect to use within an image
  };
  
  struct nsStylePosition {
    nsStylePosition(void);
    nsStylePosition(const nsStylePosition& aOther);
    ~nsStylePosition(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStylePosition();
      aContext->FreeToShell(sizeof(nsStylePosition), this);
    }
  
    nsChangeHint CalcDifference(const nsStylePosition& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_REFLOW;
    }
  
    nsStyleSides  mOffset;                // [reset] coord, percent, calc, auto
    nsStyleCoord  mWidth;                 // [reset] coord, percent, enum, calc, auto
    nsStyleCoord  mMinWidth;              // [reset] coord, percent, enum, calc
    nsStyleCoord  mMaxWidth;              // [reset] coord, percent, enum, calc, none
    nsStyleCoord  mHeight;                // [reset] coord, percent, calc, auto
    nsStyleCoord  mMinHeight;             // [reset] coord, percent, calc
    nsStyleCoord  mMaxHeight;             // [reset] coord, percent, calc, none
  #ifdef MOZ_FLEXBOX
    nsStyleCoord  mFlexBasis;             // [reset] coord, percent, enum, calc, auto
  #endif // MOZ_FLEXBOX
    uint8_t       mBoxSizing;             // [reset] see nsStyleConsts.h
  #ifdef MOZ_FLEXBOX
    uint8_t       mAlignItems;            // [reset] see nsStyleConsts.h
    uint8_t       mAlignSelf;             // [reset] see nsStyleConsts.h
    uint8_t       mFlexDirection;         // [reset] see nsStyleConsts.h
    uint8_t       mJustifyContent;        // [reset] see nsStyleConsts.h
    int32_t       mOrder;                 // [reset] integer
    float         mFlexGrow;              // [reset] float
    float         mFlexShrink;            // [reset] float
  #endif // MOZ_FLEXBOX
    nsStyleCoord  mZIndex;                // [reset] integer, auto
  
    bool WidthDependsOnContainer() const
      {
        return mWidth.GetUnit() == eStyleUnit_Auto ||
          WidthCoordDependsOnContainer(mWidth);
      }
  
    // NOTE: For a flex item, "min-width:auto" is supposed to behave like
    // "min-content", which does depend on the container, so you might think we'd
    // need a special case for "flex item && min-width:auto" here.  However,
    // we don't actually need that special-case code, because flex items are
    // explicitly supposed to *ignore* their min-width (i.e. behave like it's 0)
    // until the flex container explicitly considers it.  So -- since the flex
    // container doesn't rely on this method, we don't need to worry about
    // special behavior for flex items' "min-width:auto" values here.
    bool MinWidthDependsOnContainer() const
      { return WidthCoordDependsOnContainer(mMinWidth); }
    bool MaxWidthDependsOnContainer() const
      { return WidthCoordDependsOnContainer(mMaxWidth); }
  
    // Note that these functions count 'auto' as depending on the
    // container since that's the case for absolutely positioned elements.
    // However, some callers do not care about this case and should check
    // for it, since it is the most common case.
    // FIXME: We should probably change the assumption to be the other way
    // around.
    bool HeightDependsOnContainer() const
      {
        return mHeight.GetUnit() == eStyleUnit_Auto || // CSS 2.1, 10.6.4, item (5)
          HeightCoordDependsOnContainer(mHeight);
      }
  
    // NOTE: The comment above MinWidthDependsOnContainer about flex items
    // applies here, too.
    bool MinHeightDependsOnContainer() const
      { return HeightCoordDependsOnContainer(mMinHeight); }
    bool MaxHeightDependsOnContainer() const
      { return HeightCoordDependsOnContainer(mMaxHeight); }
  
    bool OffsetHasPercent(mozilla::css::Side aSide) const
    {
      return mOffset.Get(aSide).HasPercent();
    }
  
  private:
    static bool WidthCoordDependsOnContainer(const nsStyleCoord &aCoord);
    static bool HeightCoordDependsOnContainer(const nsStyleCoord &aCoord)
      { return aCoord.HasPercent(); }
  };
  
  struct nsStyleTextOverflowSide {
    nsStyleTextOverflowSide() : mType(NS_STYLE_TEXT_OVERFLOW_CLIP) {}
  
    bool operator==(const nsStyleTextOverflowSide& aOther) const {
      return mType == aOther.mType &&
             (mType != NS_STYLE_TEXT_OVERFLOW_STRING ||
              mString == aOther.mString);
    }
    bool operator!=(const nsStyleTextOverflowSide& aOther) const {
      return !(*this == aOther);
    }
  
    nsString mString;
    uint8_t  mType;
  };
  
  struct nsStyleTextOverflow {
    nsStyleTextOverflow() : mLogicalDirections(true) {}
    bool operator==(const nsStyleTextOverflow& aOther) const {
      return mLeft == aOther.mLeft && mRight == aOther.mRight;
    }
    bool operator!=(const nsStyleTextOverflow& aOther) const {
      return !(*this == aOther);
    }
  
    // Returns the value to apply on the left side.
    const nsStyleTextOverflowSide& GetLeft(uint8_t aDirection) const {
      NS_ASSERTION(aDirection == NS_STYLE_DIRECTION_LTR ||
                   aDirection == NS_STYLE_DIRECTION_RTL, "bad direction");
      return !mLogicalDirections || aDirection == NS_STYLE_DIRECTION_LTR ?
               mLeft : mRight;
    }
  
    // Returns the value to apply on the right side.
    const nsStyleTextOverflowSide& GetRight(uint8_t aDirection) const {
      NS_ASSERTION(aDirection == NS_STYLE_DIRECTION_LTR ||
                   aDirection == NS_STYLE_DIRECTION_RTL, "bad direction");
      return !mLogicalDirections || aDirection == NS_STYLE_DIRECTION_LTR ?
               mRight : mLeft;
    }
  
    // Returns the first value that was specified.
    const nsStyleTextOverflowSide* GetFirstValue() const {
      return mLogicalDirections ? &mRight : &mLeft;
    }
  
    // Returns the second value, or null if there was only one value specified.
    const nsStyleTextOverflowSide* GetSecondValue() const {
      return mLogicalDirections ? nullptr : &mRight;
    }
  
    nsStyleTextOverflowSide mLeft;  // start side when mLogicalDirections is true
    nsStyleTextOverflowSide mRight; // end side when mLogicalDirections is true
    bool mLogicalDirections;  // true when only one value was specified
  };
  
  struct nsStyleTextReset {
    nsStyleTextReset(void);
    nsStyleTextReset(const nsStyleTextReset& aOther);
    ~nsStyleTextReset(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleTextReset();
      aContext->FreeToShell(sizeof(nsStyleTextReset), this);
    }
  
    uint8_t GetDecorationStyle() const
    {
      return (mTextDecorationStyle & BORDER_STYLE_MASK);
    }
  
    void SetDecorationStyle(uint8_t aStyle)
    {
      NS_ABORT_IF_FALSE((aStyle & BORDER_STYLE_MASK) == aStyle,
                        "style doesn't fit");
      mTextDecorationStyle &= ~BORDER_STYLE_MASK;
      mTextDecorationStyle |= (aStyle & BORDER_STYLE_MASK);
    }
  
    void GetDecorationColor(nscolor& aColor, bool& aForeground) const
    {
      aForeground = false;
      if ((mTextDecorationStyle & BORDER_COLOR_SPECIAL) == 0) {
        aColor = mTextDecorationColor;
      } else if (mTextDecorationStyle & BORDER_COLOR_FOREGROUND) {
        aForeground = true;
      } else {
        NS_NOTREACHED("OUTLINE_COLOR_INITIAL should not be set here");
      }
    }
  
    void SetDecorationColor(nscolor aColor)
    {
      mTextDecorationColor = aColor;
      mTextDecorationStyle &= ~BORDER_COLOR_SPECIAL;
    }
  
    void SetDecorationColorToForeground()
    {
      mTextDecorationStyle &= ~BORDER_COLOR_SPECIAL;
      mTextDecorationStyle |= BORDER_COLOR_FOREGROUND;
    }
  
    nsChangeHint CalcDifference(const nsStyleTextReset& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_REFLOW;
    }
  
    nsStyleCoord  mVerticalAlign;         // [reset] coord, percent, calc, enum (see nsStyleConsts.h)
    nsStyleTextOverflow mTextOverflow;    // [reset] enum, string
  
    uint8_t mTextBlink;                   // [reset] see nsStyleConsts.h
    uint8_t mTextDecorationLine;          // [reset] see nsStyleConsts.h
    uint8_t mUnicodeBidi;                 // [reset] see nsStyleConsts.h
  protected:
    uint8_t mTextDecorationStyle;         // [reset] see nsStyleConsts.h
  
    nscolor mTextDecorationColor;         // [reset] the colors to use for a decoration lines, not used at currentColor
  };
  
  struct nsStyleText {
    nsStyleText(void);
    nsStyleText(const nsStyleText& aOther);
    ~nsStyleText(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleText();
      aContext->FreeToShell(sizeof(nsStyleText), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleText& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    uint8_t mTextAlign;                   // [inherited] see nsStyleConsts.h
    uint8_t mTextAlignLast;               // [inherited] see nsStyleConsts.h
    uint8_t mTextTransform;               // [inherited] see nsStyleConsts.h
    uint8_t mWhiteSpace;                  // [inherited] see nsStyleConsts.h
    uint8_t mWordBreak;                   // [inherited] see nsStyleConsts.h
    uint8_t mWordWrap;                    // [inherited] see nsStyleConsts.h
    uint8_t mHyphens;                     // [inherited] see nsStyleConsts.h
    uint8_t mTextSizeAdjust;              // [inherited] see nsStyleConsts.h
    int32_t mTabSize;                     // [inherited] see nsStyleConsts.h
  
    nscoord mWordSpacing;                 // [inherited]
    nsStyleCoord  mLetterSpacing;         // [inherited] coord, normal
    nsStyleCoord  mLineHeight;            // [inherited] coord, factor, normal
    nsStyleCoord  mTextIndent;            // [inherited] coord, percent, calc
  
    nsRefPtr<nsCSSShadowArray> mTextShadow; // [inherited] NULL in case of a zero-length
  
    bool WhiteSpaceIsSignificant() const {
      return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES;
    }
  
    bool NewlineIsSignificant() const {
      return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_LINE;
    }
  
    bool NewlineIsDiscarded() const {
      return mWhiteSpace == NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES;
    }
  
    bool WhiteSpaceOrNewlineIsSignificant() const {
      return mWhiteSpace == NS_STYLE_WHITESPACE_PRE ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_LINE ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_DISCARD_NEWLINES;
    }
  
    bool WhiteSpaceCanWrap() const {
      return mWhiteSpace == NS_STYLE_WHITESPACE_NORMAL ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_WRAP ||
             mWhiteSpace == NS_STYLE_WHITESPACE_PRE_LINE;
    }
  
    bool WordCanWrap() const {
      return WhiteSpaceCanWrap() && mWordWrap == NS_STYLE_WORDWRAP_BREAK_WORD;
    }
  
    // These are defined in nsStyleStructInlines.h.
    inline bool HasTextShadow(const nsIFrame* aFrame) const;
    inline nsCSSShadowArray* GetTextShadow(const nsIFrame* aFrame) const;
  };
  
  struct nsStyleVisibility {
    nsStyleVisibility(nsPresContext* aPresContext);
    nsStyleVisibility(const nsStyleVisibility& aVisibility);
    ~nsStyleVisibility() {
      MOZ_COUNT_DTOR(nsStyleVisibility);
    }
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleVisibility();
      aContext->FreeToShell(sizeof(nsStyleVisibility), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleVisibility& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    uint8_t mDirection;                  // [inherited] see nsStyleConsts.h NS_STYLE_DIRECTION_*
    uint8_t mVisible;                    // [inherited]
    uint8_t mPointerEvents;              // [inherited] see nsStyleConsts.h
  
    bool IsVisible() const {
      return (mVisible == NS_STYLE_VISIBILITY_VISIBLE);
    }
  
    bool IsVisibleOrCollapsed() const {
      return ((mVisible == NS_STYLE_VISIBILITY_VISIBLE) ||
              (mVisible == NS_STYLE_VISIBILITY_COLLAPSE));
    }
  
    inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
  };
  
  struct nsTimingFunction {
    enum Type { Function, StepStart, StepEnd };
  
    explicit nsTimingFunction(int32_t aTimingFunctionType
                                = NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE)
    {
      AssignFromKeyword(aTimingFunctionType);
    }
  
    nsTimingFunction(float x1, float y1, float x2, float y2)
      : mType(Function)
    {
      mFunc.mX1 = x1;
      mFunc.mY1 = y1;
      mFunc.mX2 = x2;
      mFunc.mY2 = y2;
    }
  
    nsTimingFunction(Type aType, uint32_t aSteps)
      : mType(aType)
    {
      NS_ABORT_IF_FALSE(mType == StepStart || mType == StepEnd, "wrong type");
      mSteps = aSteps;
    }
  
    nsTimingFunction(const nsTimingFunction& aOther)
    {
      *this = aOther;
    }
  
    Type mType;
    union {
      struct {
        float mX1;
        float mY1;
        float mX2;
        float mY2;
      } mFunc;
      uint32_t mSteps;
    };
  
    nsTimingFunction&
    operator=(const nsTimingFunction& aOther)
    {
      if (&aOther == this)
        return *this;
  
      mType = aOther.mType;
  
      if (mType == Function) {
        mFunc.mX1 = aOther.mFunc.mX1;
        mFunc.mY1 = aOther.mFunc.mY1;
        mFunc.mX2 = aOther.mFunc.mX2;
        mFunc.mY2 = aOther.mFunc.mY2;
      } else {
        mSteps = aOther.mSteps;
      }
  
      return *this;
    }
  
    bool operator==(const nsTimingFunction& aOther) const
    {
      if (mType != aOther.mType) {
        return false;
      }
      if (mType == Function) {
        return mFunc.mX1 == aOther.mFunc.mX1 && mFunc.mY1 == aOther.mFunc.mY1 &&
               mFunc.mX2 == aOther.mFunc.mX2 && mFunc.mY2 == aOther.mFunc.mY2;
      }
      return mSteps == aOther.mSteps;
    }
  
    bool operator!=(const nsTimingFunction& aOther) const
    {
      return !(*this == aOther);
    }
  
  private:
    void AssignFromKeyword(int32_t aTimingFunctionType);
  };
  
  struct nsTransition {
    nsTransition() { /* leaves uninitialized; see also SetInitialValues */ }
    explicit nsTransition(const nsTransition& aCopy);
  
    void SetInitialValues();
  
    // Delay and Duration are in milliseconds
  
    const nsTimingFunction& GetTimingFunction() const { return mTimingFunction; }
    float GetDelay() const { return mDelay; }
    float GetDuration() const { return mDuration; }
    nsCSSProperty GetProperty() const { return mProperty; }
    nsIAtom* GetUnknownProperty() const { return mUnknownProperty; }
  
    void SetTimingFunction(const nsTimingFunction& aTimingFunction)
      { mTimingFunction = aTimingFunction; }
    void SetDelay(float aDelay) { mDelay = aDelay; }
    void SetDuration(float aDuration) { mDuration = aDuration; }
    void SetProperty(nsCSSProperty aProperty)
      {
        NS_ASSERTION(aProperty != eCSSProperty_UNKNOWN, "invalid property");
        mProperty = aProperty;
      }
    void SetUnknownProperty(const nsAString& aUnknownProperty);
    void CopyPropertyFrom(const nsTransition& aOther)
      {
        mProperty = aOther.mProperty;
        mUnknownProperty = aOther.mUnknownProperty;
      }
  
    nsTimingFunction& TimingFunctionSlot() { return mTimingFunction; }
  
  private:
    nsTimingFunction mTimingFunction;
    float mDuration;
    float mDelay;
    nsCSSProperty mProperty;
    nsCOMPtr<nsIAtom> mUnknownProperty; // used when mProperty is
                                        // eCSSProperty_UNKNOWN
  };
  
  struct nsAnimation {
    nsAnimation() { /* leaves uninitialized; see also SetInitialValues */ }
    explicit nsAnimation(const nsAnimation& aCopy);
  
    void SetInitialValues();
  
    // Delay and Duration are in milliseconds
  
    const nsTimingFunction& GetTimingFunction() const { return mTimingFunction; }
    float GetDelay() const { return mDelay; }
    float GetDuration() const { return mDuration; }
    const nsString& GetName() const { return mName; }
    uint8_t GetDirection() const { return mDirection; }
    uint8_t GetFillMode() const { return mFillMode; }
    uint8_t GetPlayState() const { return mPlayState; }
    float GetIterationCount() const { return mIterationCount; }
  
    void SetTimingFunction(const nsTimingFunction& aTimingFunction)
      { mTimingFunction = aTimingFunction; }
    void SetDelay(float aDelay) { mDelay = aDelay; }
    void SetDuration(float aDuration) { mDuration = aDuration; }
    void SetName(const nsSubstring& aName) { mName = aName; }
    void SetDirection(uint8_t aDirection) { mDirection = aDirection; }
    void SetFillMode(uint8_t aFillMode) { mFillMode = aFillMode; }
    void SetPlayState(uint8_t aPlayState) { mPlayState = aPlayState; }
    void SetIterationCount(float aIterationCount)
      { mIterationCount = aIterationCount; }
  
    nsTimingFunction& TimingFunctionSlot() { return mTimingFunction; }
  
  private:
    nsTimingFunction mTimingFunction;
    float mDuration;
    float mDelay;
    nsString mName; // empty string for 'none'
    uint8_t mDirection;
    uint8_t mFillMode;
    uint8_t mPlayState;
    float mIterationCount; // NS_IEEEPositiveInfinity() means infinite
  };
  
  struct nsStyleDisplay {
    nsStyleDisplay();
    nsStyleDisplay(const nsStyleDisplay& aOther);
    ~nsStyleDisplay() {
      MOZ_COUNT_DTOR(nsStyleDisplay);
    }
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleDisplay();
      aContext->FreeToShell(sizeof(nsStyleDisplay), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleDisplay& aOther) const;
    static nsChangeHint MaxDifference() {
      // All the parts of FRAMECHANGE are present in CalcDifference.
      return nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
                          nsChangeHint_UpdateOpacityLayer |
                          nsChangeHint_UpdateTransformLayer |
                          nsChangeHint_UpdateOverflow);
    }
  
    // We guarantee that if mBinding is non-null, so are mBinding->GetURI() and
    // mBinding->mOriginPrincipal.
    nsRefPtr<mozilla::css::URLValue> mBinding;    // [reset]
    nsRect  mClip;                // [reset] offsets from upper-left border edge
    float   mOpacity;             // [reset]
    uint8_t mDisplay;             // [reset] see nsStyleConsts.h NS_STYLE_DISPLAY_*
    uint8_t mOriginalDisplay;     // [reset] saved mDisplay for position:absolute/fixed
                                  //         and float:left/right; otherwise equal
                                  //         to mDisplay
    uint8_t mAppearance;          // [reset]
    uint8_t mPosition;            // [reset] see nsStyleConsts.h
    uint8_t mFloats;              // [reset] see nsStyleConsts.h NS_STYLE_FLOAT_*
    uint8_t mOriginalFloats;      // [reset] saved mFloats for position:absolute/fixed;
                                  //         otherwise equal to mFloats
    uint8_t mBreakType;           // [reset] see nsStyleConsts.h NS_STYLE_CLEAR_*
    bool mBreakBefore;    // [reset]
    bool mBreakAfter;     // [reset]
    uint8_t mOverflowX;           // [reset] see nsStyleConsts.h
    uint8_t mOverflowY;           // [reset] see nsStyleConsts.h
    uint8_t mResize;              // [reset] see nsStyleConsts.h
    uint8_t mClipFlags;           // [reset] see nsStyleConsts.h
    uint8_t mOrient;              // [reset] see nsStyleConsts.h
  
    // mSpecifiedTransform is the list of transform functions as
    // specified, or null to indicate there is no transform.  (inherit or
    // initial are replaced by an actual list of transform functions, or
    // null, as appropriate.) (owned by the style rule)
    uint8_t mBackfaceVisibility;
    uint8_t mTransformStyle;
    const nsCSSValueList *mSpecifiedTransform; // [reset]
    nsStyleCoord mTransformOrigin[3]; // [reset] percent, coord, calc, 3rd param is coord, calc only
    nsStyleCoord mChildPerspective; // [reset] coord
    nsStyleCoord mPerspectiveOrigin[2]; // [reset] percent, coord, calc
  
    nsAutoTArray<nsTransition, 1> mTransitions; // [reset]
    // The number of elements in mTransitions that are not from repeating
    // a list due to another property being longer.
    uint32_t mTransitionTimingFunctionCount,
             mTransitionDurationCount,
             mTransitionDelayCount,
             mTransitionPropertyCount;
  
    nsAutoTArray<nsAnimation, 1> mAnimations; // [reset]
    // The number of elements in mAnimations that are not from repeating
    // a list due to another property being longer.
    uint32_t mAnimationTimingFunctionCount,
             mAnimationDurationCount,
             mAnimationDelayCount,
             mAnimationNameCount,
             mAnimationDirectionCount,
             mAnimationFillModeCount,
             mAnimationPlayStateCount,
             mAnimationIterationCountCount;
  
    bool IsBlockInsideStyle() const {
      return NS_STYLE_DISPLAY_BLOCK == mDisplay ||
             NS_STYLE_DISPLAY_LIST_ITEM == mDisplay ||
             NS_STYLE_DISPLAY_INLINE_BLOCK == mDisplay;
      // Should TABLE_CELL and TABLE_CAPTION go here?  They have
      // block frames nested inside of them.
      // (But please audit all callers before changing.)
    }
  
    bool IsBlockOutsideStyle() const {
      return NS_STYLE_DISPLAY_BLOCK == mDisplay ||
  #ifdef MOZ_FLEXBOX
             NS_STYLE_DISPLAY_FLEX == mDisplay ||
  #endif // MOZ_FLEXBOX
             NS_STYLE_DISPLAY_LIST_ITEM == mDisplay ||
             NS_STYLE_DISPLAY_TABLE == mDisplay;
    }
  
    static bool IsDisplayTypeInlineOutside(uint8_t aDisplay) {
      return NS_STYLE_DISPLAY_INLINE == aDisplay ||
             NS_STYLE_DISPLAY_INLINE_BLOCK == aDisplay ||
             NS_STYLE_DISPLAY_INLINE_TABLE == aDisplay ||
             NS_STYLE_DISPLAY_INLINE_BOX == aDisplay ||
  #ifdef MOZ_FLEXBOX
             NS_STYLE_DISPLAY_INLINE_FLEX == aDisplay ||
  #endif // MOZ_FLEXBOX
             NS_STYLE_DISPLAY_INLINE_GRID == aDisplay ||
             NS_STYLE_DISPLAY_INLINE_STACK == aDisplay;
    }
  
    bool IsInlineOutsideStyle() const {
      return IsDisplayTypeInlineOutside(mDisplay);
    }
  
    bool IsOriginalDisplayInlineOutsideStyle() const {
      return IsDisplayTypeInlineOutside(mOriginalDisplay);
    }
  
    bool IsFloatingStyle() const {
      return NS_STYLE_FLOAT_NONE != mFloats;
    }
  
    bool IsAbsolutelyPositionedStyle() const {
      return NS_STYLE_POSITION_ABSOLUTE == mPosition ||
             NS_STYLE_POSITION_FIXED == mPosition;
    }
  
    /* Returns true if we're positioned or there's a transform in effect. */
    bool IsPositionedStyle() const {
      return IsAbsolutelyPositionedStyle() ||
             IsRelativelyPositionedStyle() ||
             HasTransform();
    }
  
    bool IsRelativelyPositionedStyle() const {
      return mPosition == NS_STYLE_POSITION_RELATIVE;
    }
  
    bool IsScrollableOverflow() const {
      // mOverflowX and mOverflowY always match when one of them is
      // NS_STYLE_OVERFLOW_VISIBLE or NS_STYLE_OVERFLOW_CLIP.
      return mOverflowX != NS_STYLE_OVERFLOW_VISIBLE &&
             mOverflowX != NS_STYLE_OVERFLOW_CLIP;
    }
  
    /* Returns whether the element has the -moz-transform property. */
    bool HasTransform() const {
      return mSpecifiedTransform != nullptr || 
             mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
             mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN;
    }
  
    // These are defined in nsStyleStructInlines.h.
    inline bool IsBlockInside(const nsIFrame* aFrame) const;
    inline bool IsBlockOutside(const nsIFrame* aFrame) const;
    inline bool IsInlineOutside(const nsIFrame* aFrame) const;
    inline bool IsOriginalDisplayInlineOutside(const nsIFrame* aFrame) const;
    inline uint8_t GetDisplay(const nsIFrame* aFrame) const;
    inline bool IsFloating(const nsIFrame* aFrame) const;
    inline bool IsPositioned(const nsIFrame* aFrame) const;
    inline bool IsRelativelyPositioned(const nsIFrame* aFrame) const;
    inline bool IsAbsolutelyPositioned(const nsIFrame* aFrame) const;
  };
  
  struct nsStyleTable {
    nsStyleTable(void);
    nsStyleTable(const nsStyleTable& aOther);
    ~nsStyleTable(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleTable();
      aContext->FreeToShell(sizeof(nsStyleTable), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleTable& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    uint8_t       mLayoutStrategy;// [reset] see nsStyleConsts.h NS_STYLE_TABLE_LAYOUT_*
    uint8_t       mFrame;         // [reset] see nsStyleConsts.h NS_STYLE_TABLE_FRAME_*
    uint8_t       mRules;         // [reset] see nsStyleConsts.h NS_STYLE_TABLE_RULES_*
    int32_t       mCols;          // [reset] an integer if set, or see nsStyleConsts.h NS_STYLE_TABLE_COLS_*
    int32_t       mSpan;          // [reset] the number of columns spanned by a colgroup or col
  };
  
  struct nsStyleTableBorder {
    nsStyleTableBorder(nsPresContext* aContext);
    nsStyleTableBorder(const nsStyleTableBorder& aOther);
    ~nsStyleTableBorder(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleTableBorder();
      aContext->FreeToShell(sizeof(nsStyleTableBorder), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleTableBorder& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    nscoord       mBorderSpacingX;// [inherited]
    nscoord       mBorderSpacingY;// [inherited]
    uint8_t       mBorderCollapse;// [inherited]
    uint8_t       mCaptionSide;   // [inherited]
    uint8_t       mEmptyCells;    // [inherited]
  };
  
  enum nsStyleContentType {
    eStyleContentType_String        = 1,
    eStyleContentType_Image         = 10,
    eStyleContentType_Attr          = 20,
    eStyleContentType_Counter       = 30,
    eStyleContentType_Counters      = 31,
    eStyleContentType_OpenQuote     = 40,
    eStyleContentType_CloseQuote    = 41,
    eStyleContentType_NoOpenQuote   = 42,
    eStyleContentType_NoCloseQuote  = 43,
    eStyleContentType_AltContent    = 50
  };
  
  struct nsStyleContentData {
    nsStyleContentType  mType;
    union {
      PRUnichar *mString;
      imgIRequest *mImage;
      nsCSSValue::Array* mCounters;
    } mContent;
  #ifdef DEBUG
    bool mImageTracked;
  #endif
  
    nsStyleContentData()
      : mType(nsStyleContentType(0))
  #ifdef DEBUG
      , mImageTracked(false)
  #endif
    { mContent.mString = nullptr; }
  
    ~nsStyleContentData();
    nsStyleContentData& operator=(const nsStyleContentData& aOther);
    bool operator==(const nsStyleContentData& aOther) const;
  
    bool operator!=(const nsStyleContentData& aOther) const {
      return !(*this == aOther);
    }
  
    void TrackImage(nsPresContext* aContext);
    void UntrackImage(nsPresContext* aContext);
  
    void SetImage(imgIRequest* aRequest)
    {
      NS_ABORT_IF_FALSE(!mImageTracked,
                        "Setting a new image without untracking the old one!");
      NS_ABORT_IF_FALSE(mType == eStyleContentType_Image, "Wrong type!");
      NS_IF_ADDREF(mContent.mImage = aRequest);
    }
  private:
    nsStyleContentData(const nsStyleContentData&); // not to be implemented
  };
  
  struct nsStyleCounterData {
    nsString  mCounter;
    int32_t   mValue;
  };
  
  
  #define DELETE_ARRAY_IF(array)  if (array) { delete[] array; array = nullptr; }
  
  struct nsStyleQuotes {
    nsStyleQuotes();
    nsStyleQuotes(const nsStyleQuotes& aQuotes);
    ~nsStyleQuotes();
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleQuotes();
      aContext->FreeToShell(sizeof(nsStyleQuotes), this);
    }
  
    void SetInitial();
    void CopyFrom(const nsStyleQuotes& aSource);
  
    nsChangeHint CalcDifference(const nsStyleQuotes& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    uint32_t  QuotesCount(void) const { return mQuotesCount; } // [inherited]
  
    const nsString* OpenQuoteAt(uint32_t aIndex) const
    {
      NS_ASSERTION(aIndex < mQuotesCount, "out of range");
      return mQuotes + (aIndex * 2);
    }
    const nsString* CloseQuoteAt(uint32_t aIndex) const
    {
      NS_ASSERTION(aIndex < mQuotesCount, "out of range");
      return mQuotes + (aIndex * 2 + 1);
    }
    nsresult  GetQuotesAt(uint32_t aIndex, nsString& aOpen, nsString& aClose) const {
      if (aIndex < mQuotesCount) {
        aIndex *= 2;
        aOpen = mQuotes[aIndex];
        aClose = mQuotes[++aIndex];
        return NS_OK;
      }
      return NS_ERROR_ILLEGAL_VALUE;
    }
  
    nsresult  AllocateQuotes(uint32_t aCount) {
      if (aCount != mQuotesCount) {
        DELETE_ARRAY_IF(mQuotes);
        if (aCount) {
          mQuotes = new nsString[aCount * 2];
          if (! mQuotes) {
            mQuotesCount = 0;
            return NS_ERROR_OUT_OF_MEMORY;
          }
        }
        mQuotesCount = aCount;
      }
      return NS_OK;
    }
  
    nsresult  SetQuotesAt(uint32_t aIndex, const nsString& aOpen, const nsString& aClose) {
      if (aIndex < mQuotesCount) {
        aIndex *= 2;
        mQuotes[aIndex] = aOpen;
        mQuotes[++aIndex] = aClose;
        return NS_OK;
      }
      return NS_ERROR_ILLEGAL_VALUE;
    }
  
  protected:
    uint32_t            mQuotesCount;
    nsString*           mQuotes;
  };
  
  struct nsStyleContent {
    nsStyleContent(void);
    nsStyleContent(const nsStyleContent& aContent);
    ~nsStyleContent(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext);
  
    nsChangeHint CalcDifference(const nsStyleContent& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    uint32_t  ContentCount(void) const  { return mContentCount; } // [reset]
  
    const nsStyleContentData& ContentAt(uint32_t aIndex) const {
      NS_ASSERTION(aIndex < mContentCount, "out of range");
      return mContents[aIndex];
    }
  
    nsStyleContentData& ContentAt(uint32_t aIndex) {
      NS_ASSERTION(aIndex < mContentCount, "out of range");
      return mContents[aIndex];
    }
  
    nsresult AllocateContents(uint32_t aCount);
  
    uint32_t  CounterIncrementCount(void) const { return mIncrementCount; }  // [reset]
    const nsStyleCounterData* GetCounterIncrementAt(uint32_t aIndex) const {
      NS_ASSERTION(aIndex < mIncrementCount, "out of range");
      return &mIncrements[aIndex];
    }
  
    nsresult  AllocateCounterIncrements(uint32_t aCount) {
      if (aCount != mIncrementCount) {
        DELETE_ARRAY_IF(mIncrements);
        if (aCount) {
          mIncrements = new nsStyleCounterData[aCount];
          if (! mIncrements) {
            mIncrementCount = 0;
            return NS_ERROR_OUT_OF_MEMORY;
          }
        }
        mIncrementCount = aCount;
      }
      return NS_OK;
    }
  
    nsresult  SetCounterIncrementAt(uint32_t aIndex, const nsString& aCounter, int32_t aIncrement) {
      if (aIndex < mIncrementCount) {
        mIncrements[aIndex].mCounter = aCounter;
        mIncrements[aIndex].mValue = aIncrement;
        return NS_OK;
      }
      return NS_ERROR_ILLEGAL_VALUE;
    }
  
    uint32_t  CounterResetCount(void) const { return mResetCount; }  // [reset]
    const nsStyleCounterData* GetCounterResetAt(uint32_t aIndex) const {
      NS_ASSERTION(aIndex < mResetCount, "out of range");
      return &mResets[aIndex];
    }
  
    nsresult  AllocateCounterResets(uint32_t aCount) {
      if (aCount != mResetCount) {
        DELETE_ARRAY_IF(mResets);
        if (aCount) {
          mResets = new nsStyleCounterData[aCount];
          if (! mResets) {
            mResetCount = 0;
            return NS_ERROR_OUT_OF_MEMORY;
          }
        }
        mResetCount = aCount;
      }
      return NS_OK;
    }
  
    nsresult  SetCounterResetAt(uint32_t aIndex, const nsString& aCounter, int32_t aValue) {
      if (aIndex < mResetCount) {
        mResets[aIndex].mCounter = aCounter;
        mResets[aIndex].mValue = aValue;
        return NS_OK;
      }
      return NS_ERROR_ILLEGAL_VALUE;
    }
  
    nsStyleCoord  mMarkerOffset;  // [reset] coord, auto
  
  protected:
    nsStyleContentData* mContents;
    nsStyleCounterData* mIncrements;
    nsStyleCounterData* mResets;
  
    uint32_t            mContentCount;
    uint32_t            mIncrementCount;
    uint32_t            mResetCount;
  };
  
  struct nsStyleUIReset {
    nsStyleUIReset(void);
    nsStyleUIReset(const nsStyleUIReset& aOther);
    ~nsStyleUIReset(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleUIReset();
      aContext->FreeToShell(sizeof(nsStyleUIReset), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleUIReset& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    uint8_t   mUserSelect;      // [reset] (selection-style)
    uint8_t   mForceBrokenImageIcon; // [reset]  (0 if not forcing, otherwise forcing)
    uint8_t   mIMEMode;         // [reset]
    uint8_t   mWindowShadow;    // [reset]
  };
  
  struct nsCursorImage {
    bool mHaveHotspot;
    float mHotspotX, mHotspotY;
  
    nsCursorImage();
    nsCursorImage(const nsCursorImage& aOther);
    ~nsCursorImage();
  
    nsCursorImage& operator=(const nsCursorImage& aOther);
    /*
     * We hide mImage and force access through the getter and setter so that we
     * can lock the images we use. Cursor images are likely to be small, so we
     * don't care about discarding them. See bug 512260.
     * */
    void SetImage(imgIRequest *aImage) {
      if (mImage)
        mImage->UnlockImage();
      mImage = aImage;
      if (mImage)
        mImage->LockImage();
    }
    imgIRequest* GetImage() const {
      return mImage;
    }
  
  private:
    nsCOMPtr<imgIRequest> mImage;
  };
  
  struct nsStyleUserInterface {
    nsStyleUserInterface(void);
    nsStyleUserInterface(const nsStyleUserInterface& aOther);
    ~nsStyleUserInterface(void);
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleUserInterface();
      aContext->FreeToShell(sizeof(nsStyleUserInterface), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleUserInterface& aOther) const;
    static nsChangeHint MaxDifference() {
      return nsChangeHint(nsChangeHint_UpdateCursor | NS_STYLE_HINT_FRAMECHANGE);
    }
  
    uint8_t   mUserInput;       // [inherited]
    uint8_t   mUserModify;      // [inherited] (modify-content)
    uint8_t   mUserFocus;       // [inherited] (auto-select)
  
    uint8_t   mCursor;          // [inherited] See nsStyleConsts.h
  
    uint32_t mCursorArrayLength;
    nsCursorImage *mCursorArray;// [inherited] The specified URL values
                                //   and coordinates.  Takes precedence over
                                //   mCursor.  Zero-length array is represented
                                //   by null pointer.
  
    // Does not free mCursorArray; the caller is responsible for calling
    // |delete [] mCursorArray| first if it is needed.
    void CopyCursorArrayFrom(const nsStyleUserInterface& aSource);
  };
  
  struct nsStyleXUL {
    nsStyleXUL();
    nsStyleXUL(const nsStyleXUL& aSource);
    ~nsStyleXUL();
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleXUL();
      aContext->FreeToShell(sizeof(nsStyleXUL), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleXUL& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    float         mBoxFlex;               // [reset] see nsStyleConsts.h
    uint32_t      mBoxOrdinal;            // [reset] see nsStyleConsts.h
    uint8_t       mBoxAlign;              // [reset] see nsStyleConsts.h
    uint8_t       mBoxDirection;          // [reset] see nsStyleConsts.h
    uint8_t       mBoxOrient;             // [reset] see nsStyleConsts.h
    uint8_t       mBoxPack;               // [reset] see nsStyleConsts.h
    bool          mStretchStack;          // [reset] see nsStyleConsts.h
  };
  
  struct nsStyleColumn {
    nsStyleColumn(nsPresContext* aPresContext);
    nsStyleColumn(const nsStyleColumn& aSource);
    ~nsStyleColumn();
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleColumn();
      aContext->FreeToShell(sizeof(nsStyleColumn), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleColumn& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_STYLE_HINT_FRAMECHANGE;
    }
  
    uint32_t     mColumnCount; // [reset] see nsStyleConsts.h
    nsStyleCoord mColumnWidth; // [reset] coord, auto
    nsStyleCoord mColumnGap;   // [reset] coord, normal
  
    nscolor      mColumnRuleColor;  // [reset]
    uint8_t      mColumnRuleStyle;  // [reset]
    // See https://bugzilla.mozilla.org/show_bug.cgi?id=271586#c43 for why
    // this is hard to replace with 'currentColor'.
    bool mColumnRuleColorIsForeground;
  
    void SetColumnRuleWidth(nscoord aWidth) {
      mColumnRuleWidth = NS_ROUND_BORDER_TO_PIXELS(aWidth, mTwipsPerPixel);
    }
  
    nscoord GetComputedColumnRuleWidth() const {
      return (IsVisibleBorderStyle(mColumnRuleStyle) ? mColumnRuleWidth : 0);
    }
  
  protected:
    nscoord mColumnRuleWidth;  // [reset] coord
    nscoord mTwipsPerPixel;
  };
  
  enum nsStyleSVGPaintType {
    eStyleSVGPaintType_None = 1,
    eStyleSVGPaintType_Color,
    eStyleSVGPaintType_Server,
    eStyleSVGPaintType_ObjectFill,
    eStyleSVGPaintType_ObjectStroke
  };
  
  enum nsStyleSVGOpacitySource {
    eStyleSVGOpacitySource_Normal,
    eStyleSVGOpacitySource_ObjectFillOpacity,
    eStyleSVGOpacitySource_ObjectStrokeOpacity
  };
  
  struct nsStyleSVGPaint
  {
    union {
      nscolor mColor;
      nsIURI *mPaintServer;
    } mPaint;
    nsStyleSVGPaintType mType;
    nscolor mFallbackColor;
  
    nsStyleSVGPaint() : mType(nsStyleSVGPaintType(0)) { mPaint.mPaintServer = nullptr; }
    ~nsStyleSVGPaint();
    void SetType(nsStyleSVGPaintType aType);
    nsStyleSVGPaint& operator=(const nsStyleSVGPaint& aOther);
    bool operator==(const nsStyleSVGPaint& aOther) const;
  
    bool operator!=(const nsStyleSVGPaint& aOther) const {
      return !(*this == aOther);
    }
  };
  
  struct nsStyleSVG {
    nsStyleSVG();
    nsStyleSVG(const nsStyleSVG& aSource);
    ~nsStyleSVG();
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleSVG();
      aContext->FreeToShell(sizeof(nsStyleSVG), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleSVG& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_CombineHint(NS_CombineHint(nsChangeHint_UpdateEffects,
                                           nsChangeHint_AllReflowHints),
                                           nsChangeHint_RepaintFrame);
    }
  
    nsStyleSVGPaint  mFill;             // [inherited]
    nsStyleSVGPaint  mStroke;           // [inherited]
    nsCOMPtr<nsIURI> mMarkerEnd;        // [inherited]
    nsCOMPtr<nsIURI> mMarkerMid;        // [inherited]
    nsCOMPtr<nsIURI> mMarkerStart;      // [inherited]
    nsStyleCoord    *mStrokeDasharray;  // [inherited] coord, percent, factor
  
    nsStyleCoord     mStrokeDashoffset; // [inherited] coord, percent, factor
    nsStyleCoord     mStrokeWidth;      // [inherited] coord, percent, factor
  
    float            mFillOpacity;      // [inherited]
    float            mStrokeMiterlimit; // [inherited]
    float            mStrokeOpacity;    // [inherited]
  
    uint32_t         mStrokeDasharrayLength;
    uint8_t          mClipRule;         // [inherited]
    uint8_t          mColorInterpolation; // [inherited] see nsStyleConsts.h
    uint8_t          mColorInterpolationFilters; // [inherited] see nsStyleConsts.h
    uint8_t          mFillRule;         // [inherited] see nsStyleConsts.h
    uint8_t          mImageRendering;   // [inherited] see nsStyleConsts.h
    uint8_t          mShapeRendering;   // [inherited] see nsStyleConsts.h
    uint8_t          mStrokeLinecap;    // [inherited] see nsStyleConsts.h
    uint8_t          mStrokeLinejoin;   // [inherited] see nsStyleConsts.h
    uint8_t          mTextAnchor;       // [inherited] see nsStyleConsts.h
    uint8_t          mTextRendering;    // [inherited] see nsStyleConsts.h
  
    // In SVG glyphs, whether we inherit fill or stroke opacity from the outer
    // text object.
    // Use 3 bits to avoid signedness problems in MSVC.
    nsStyleSVGOpacitySource mFillOpacitySource    : 3;
    nsStyleSVGOpacitySource mStrokeOpacitySource  : 3;
  
    // SVG glyph outer object inheritance for other properties
    bool mStrokeDasharrayFromObject   : 1;
    bool mStrokeDashoffsetFromObject  : 1;
    bool mStrokeWidthFromObject       : 1;
  };
  
  struct nsStyleSVGReset {
    nsStyleSVGReset();
    nsStyleSVGReset(const nsStyleSVGReset& aSource);
    ~nsStyleSVGReset();
  
    void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
      return aContext->AllocateFromShell(sz);
    }
    void Destroy(nsPresContext* aContext) {
      this->~nsStyleSVGReset();
      aContext->FreeToShell(sizeof(nsStyleSVGReset), this);
    }
  
    nsChangeHint CalcDifference(const nsStyleSVGReset& aOther) const;
    static nsChangeHint MaxDifference() {
      return NS_CombineHint(NS_CombineHint(nsChangeHint_UpdateEffects,
                                           nsChangeHint_AllReflowHints),
                                           nsChangeHint_RepaintFrame);
    }
  
    nsCOMPtr<nsIURI> mClipPath;         // [reset]
    nsCOMPtr<nsIURI> mFilter;           // [reset]
    nsCOMPtr<nsIURI> mMask;             // [reset]
    nscolor          mStopColor;        // [reset]
    nscolor          mFloodColor;       // [reset]
    nscolor          mLightingColor;    // [reset]
  
    float            mStopOpacity;      // [reset]
    float            mFloodOpacity;     // [reset]
  
    uint8_t          mDominantBaseline; // [reset] see nsStyleConsts.h
    uint8_t          mVectorEffect;     // [reset] see nsStyleConsts.h
  };
  
  #endif /* nsStyleStruct_h___ */
  