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: /* michael@0: * structs that contain the data provided by nsStyleContext, the michael@0: * internal API for computed style data for an element michael@0: */ michael@0: michael@0: #include "nsStyleStruct.h" michael@0: #include "nsStyleStructInlines.h" michael@0: #include "nsStyleConsts.h" michael@0: #include "nsThemeConstants.h" michael@0: #include "nsString.h" michael@0: #include "nsPresContext.h" michael@0: #include "nsIWidget.h" michael@0: #include "nsCRTGlue.h" michael@0: #include "nsCSSProps.h" michael@0: michael@0: #include "nsCOMPtr.h" michael@0: michael@0: #include "nsBidiUtils.h" michael@0: #include "nsLayoutUtils.h" michael@0: michael@0: #include "imgIRequest.h" michael@0: #include "imgIContainer.h" michael@0: michael@0: #include "mozilla/Likely.h" michael@0: #include "nsIURI.h" michael@0: #include "nsIDocument.h" michael@0: #include michael@0: michael@0: static_assert((((1 << nsStyleStructID_Length) - 1) & michael@0: ~(NS_STYLE_INHERIT_MASK)) == 0, michael@0: "Not enough bits in NS_STYLE_INHERIT_MASK"); michael@0: michael@0: inline bool IsFixedUnit(const nsStyleCoord& aCoord, bool aEnumOK) michael@0: { michael@0: return aCoord.ConvertsToLength() || michael@0: (aEnumOK && aCoord.GetUnit() == eStyleUnit_Enumerated); michael@0: } michael@0: michael@0: static bool EqualURIs(nsIURI *aURI1, nsIURI *aURI2) michael@0: { michael@0: bool eq; michael@0: return aURI1 == aURI2 || // handle null==null, and optimize michael@0: (aURI1 && aURI2 && michael@0: NS_SUCCEEDED(aURI1->Equals(aURI2, &eq)) && // not equal on fail michael@0: eq); michael@0: } michael@0: michael@0: static bool EqualURIs(mozilla::css::URLValue *aURI1, mozilla::css::URLValue *aURI2) michael@0: { michael@0: return aURI1 == aURI2 || // handle null==null, and optimize michael@0: (aURI1 && aURI2 && aURI1->URIEquals(*aURI2)); michael@0: } michael@0: michael@0: static bool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2) michael@0: { michael@0: if (aImage1 == aImage2) { michael@0: return true; michael@0: } michael@0: michael@0: if (!aImage1 || !aImage2) { michael@0: return false; michael@0: } michael@0: michael@0: nsCOMPtr uri1, uri2; michael@0: aImage1->GetURI(getter_AddRefs(uri1)); michael@0: aImage2->GetURI(getter_AddRefs(uri2)); michael@0: return EqualURIs(uri1, uri2); michael@0: } michael@0: michael@0: // A nullsafe wrapper for strcmp. We depend on null-safety. michael@0: static int safe_strcmp(const char16_t* a, const char16_t* b) michael@0: { michael@0: if (!a || !b) { michael@0: return (int)(a - b); michael@0: } michael@0: return NS_strcmp(a, b); michael@0: } michael@0: michael@0: static nsChangeHint CalcShadowDifference(nsCSSShadowArray* lhs, michael@0: nsCSSShadowArray* rhs); michael@0: michael@0: // -------------------- michael@0: // nsStyleFont michael@0: // michael@0: nsStyleFont::nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext) michael@0: : mFont(aFont) michael@0: , mGenericID(kGenericFont_NONE) michael@0: , mExplicitLanguage(false) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleFont); michael@0: Init(aPresContext); michael@0: } michael@0: michael@0: nsStyleFont::nsStyleFont(const nsStyleFont& aSrc) michael@0: : mFont(aSrc.mFont) michael@0: , mSize(aSrc.mSize) michael@0: , mGenericID(aSrc.mGenericID) michael@0: , mScriptLevel(aSrc.mScriptLevel) michael@0: , mMathVariant(aSrc.mMathVariant) michael@0: , mMathDisplay(aSrc.mMathDisplay) michael@0: , mExplicitLanguage(aSrc.mExplicitLanguage) michael@0: , mAllowZoom(aSrc.mAllowZoom) michael@0: , mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize) michael@0: , mScriptMinSize(aSrc.mScriptMinSize) michael@0: , mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier) michael@0: , mLanguage(aSrc.mLanguage) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleFont); michael@0: } michael@0: michael@0: nsStyleFont::nsStyleFont(nsPresContext* aPresContext) michael@0: // passing nullptr to GetDefaultFont make it use the doc language michael@0: : mFont(*(aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID, michael@0: nullptr))) michael@0: , mGenericID(kGenericFont_NONE) michael@0: , mExplicitLanguage(false) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleFont); michael@0: Init(aPresContext); michael@0: } michael@0: michael@0: void michael@0: nsStyleFont::Init(nsPresContext* aPresContext) michael@0: { michael@0: mSize = mFont.size = nsStyleFont::ZoomText(aPresContext, mFont.size); michael@0: mScriptUnconstrainedSize = mSize; michael@0: mScriptMinSize = aPresContext->CSSTwipsToAppUnits( michael@0: NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT)); michael@0: mScriptLevel = 0; michael@0: mScriptSizeMultiplier = NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER; michael@0: mMathVariant = NS_MATHML_MATHVARIANT_NONE; michael@0: mMathDisplay = NS_MATHML_DISPLAYSTYLE_INLINE; michael@0: mAllowZoom = true; michael@0: michael@0: nsAutoString language; michael@0: aPresContext->Document()->GetContentLanguage(language); michael@0: language.StripWhitespace(); michael@0: michael@0: // Content-Language may be a comma-separated list of language codes, michael@0: // in which case the HTML5 spec says to treat it as unknown michael@0: if (!language.IsEmpty() && michael@0: language.FindChar(char16_t(',')) == kNotFound) { michael@0: mLanguage = do_GetAtom(language); michael@0: // NOTE: This does *not* count as an explicit language; in other michael@0: // words, it doesn't trigger language-specific hyphenation. michael@0: } else { michael@0: // we didn't find a (usable) Content-Language, so we fall back michael@0: // to whatever the presContext guessed from the charset michael@0: mLanguage = aPresContext->GetLanguageFromCharset(); michael@0: } michael@0: } michael@0: michael@0: void* michael@0: nsStyleFont::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW { michael@0: void* result = aContext->AllocateFromShell(sz); michael@0: if (result) michael@0: memset(result, 0, sz); michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: nsStyleFont::Destroy(nsPresContext* aContext) { michael@0: this->~nsStyleFont(); michael@0: aContext->FreeToShell(sizeof(nsStyleFont), this); michael@0: } michael@0: michael@0: void michael@0: nsStyleFont::EnableZoom(nsPresContext* aContext, bool aEnable) michael@0: { michael@0: if (mAllowZoom == aEnable) { michael@0: return; michael@0: } michael@0: mAllowZoom = aEnable; michael@0: if (mAllowZoom) { michael@0: mSize = nsStyleFont::ZoomText(aContext, mSize); michael@0: mFont.size = nsStyleFont::ZoomText(aContext, mFont.size); michael@0: mScriptUnconstrainedSize = michael@0: nsStyleFont::ZoomText(aContext, mScriptUnconstrainedSize); michael@0: } else { michael@0: mSize = nsStyleFont::UnZoomText(aContext, mSize); michael@0: mFont.size = nsStyleFont::UnZoomText(aContext, mFont.size); michael@0: mScriptUnconstrainedSize = michael@0: nsStyleFont::UnZoomText(aContext, mScriptUnconstrainedSize); michael@0: } michael@0: } michael@0: michael@0: nsChangeHint nsStyleFont::CalcDifference(const nsStyleFont& aOther) const michael@0: { michael@0: MOZ_ASSERT(mAllowZoom == aOther.mAllowZoom, michael@0: "expected mAllowZoom to be the same on both nsStyleFonts"); michael@0: if (mSize != aOther.mSize || michael@0: mLanguage != aOther.mLanguage || michael@0: mExplicitLanguage != aOther.mExplicitLanguage || michael@0: mMathVariant != aOther.mMathVariant || michael@0: mMathDisplay != aOther.mMathDisplay) { michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: return CalcFontDifference(mFont, aOther.mFont); michael@0: } michael@0: michael@0: /* static */ nscoord michael@0: nsStyleFont::ZoomText(nsPresContext *aPresContext, nscoord aSize) michael@0: { michael@0: return nscoord(float(aSize) * aPresContext->TextZoom()); michael@0: } michael@0: michael@0: /* static */ nscoord michael@0: nsStyleFont::UnZoomText(nsPresContext *aPresContext, nscoord aSize) michael@0: { michael@0: return nscoord(float(aSize) / aPresContext->TextZoom()); michael@0: } michael@0: michael@0: nsChangeHint nsStyleFont::CalcFontDifference(const nsFont& aFont1, const nsFont& aFont2) michael@0: { michael@0: if ((aFont1.size == aFont2.size) && michael@0: (aFont1.sizeAdjust == aFont2.sizeAdjust) && michael@0: (aFont1.style == aFont2.style) && michael@0: (aFont1.variant == aFont2.variant) && michael@0: (aFont1.weight == aFont2.weight) && michael@0: (aFont1.stretch == aFont2.stretch) && michael@0: (aFont1.smoothing == aFont2.smoothing) && michael@0: (aFont1.name == aFont2.name) && michael@0: (aFont1.kerning == aFont2.kerning) && michael@0: (aFont1.synthesis == aFont2.synthesis) && michael@0: (aFont1.variantAlternates == aFont2.variantAlternates) && michael@0: (aFont1.alternateValues == aFont2.alternateValues) && michael@0: (aFont1.featureValueLookup == aFont2.featureValueLookup) && michael@0: (aFont1.variantCaps == aFont2.variantCaps) && michael@0: (aFont1.variantEastAsian == aFont2.variantEastAsian) && michael@0: (aFont1.variantLigatures == aFont2.variantLigatures) && michael@0: (aFont1.variantNumeric == aFont2.variantNumeric) && michael@0: (aFont1.variantPosition == aFont2.variantPosition) && michael@0: (aFont1.fontFeatureSettings == aFont2.fontFeatureSettings) && michael@0: (aFont1.languageOverride == aFont2.languageOverride) && michael@0: (aFont1.systemFont == aFont2.systemFont)) { michael@0: if ((aFont1.decorations == aFont2.decorations)) { michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: michael@0: static bool IsFixedData(const nsStyleSides& aSides, bool aEnumOK) michael@0: { michael@0: NS_FOR_CSS_SIDES(side) { michael@0: if (!IsFixedUnit(aSides.Get(side), aEnumOK)) michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: static nscoord CalcCoord(const nsStyleCoord& aCoord, michael@0: const nscoord* aEnumTable, michael@0: int32_t aNumEnums) michael@0: { michael@0: if (aCoord.GetUnit() == eStyleUnit_Enumerated) { michael@0: NS_ABORT_IF_FALSE(aEnumTable, "must have enum table"); michael@0: int32_t value = aCoord.GetIntValue(); michael@0: if (0 <= value && value < aNumEnums) { michael@0: return aEnumTable[aCoord.GetIntValue()]; michael@0: } michael@0: NS_NOTREACHED("unexpected enum value"); michael@0: return 0; michael@0: } michael@0: NS_ABORT_IF_FALSE(aCoord.ConvertsToLength(), "unexpected unit"); michael@0: return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0); michael@0: } michael@0: michael@0: nsStyleMargin::nsStyleMargin() { michael@0: MOZ_COUNT_CTOR(nsStyleMargin); michael@0: nsStyleCoord zero(0, nsStyleCoord::CoordConstructor); michael@0: NS_FOR_CSS_SIDES(side) { michael@0: mMargin.Set(side, zero); michael@0: } michael@0: mHasCachedMargin = false; michael@0: } michael@0: michael@0: nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc) { michael@0: MOZ_COUNT_CTOR(nsStyleMargin); michael@0: mMargin = aSrc.mMargin; michael@0: mHasCachedMargin = false; michael@0: } michael@0: michael@0: void* michael@0: nsStyleMargin::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW { michael@0: void* result = aContext->AllocateFromShell(sz); michael@0: if (result) michael@0: memset(result, 0, sz); michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: nsStyleMargin::Destroy(nsPresContext* aContext) { michael@0: this->~nsStyleMargin(); michael@0: aContext->FreeToShell(sizeof(nsStyleMargin), this); michael@0: } michael@0: michael@0: michael@0: void nsStyleMargin::RecalcData() michael@0: { michael@0: if (IsFixedData(mMargin, false)) { michael@0: NS_FOR_CSS_SIDES(side) { michael@0: mCachedMargin.Side(side) = CalcCoord(mMargin.Get(side), nullptr, 0); michael@0: } michael@0: mHasCachedMargin = true; michael@0: } michael@0: else michael@0: mHasCachedMargin = false; michael@0: } michael@0: michael@0: nsChangeHint nsStyleMargin::CalcDifference(const nsStyleMargin& aOther) const michael@0: { michael@0: if (mMargin == aOther.mMargin) { michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: // Margin differences can't affect descendant intrinsic sizes and michael@0: // don't need to force children to reflow. michael@0: return NS_CombineHint(nsChangeHint_NeedReflow, michael@0: nsChangeHint_ClearAncestorIntrinsics); michael@0: } michael@0: michael@0: nsStylePadding::nsStylePadding() { michael@0: MOZ_COUNT_CTOR(nsStylePadding); michael@0: nsStyleCoord zero(0, nsStyleCoord::CoordConstructor); michael@0: NS_FOR_CSS_SIDES(side) { michael@0: mPadding.Set(side, zero); michael@0: } michael@0: mHasCachedPadding = false; michael@0: } michael@0: michael@0: nsStylePadding::nsStylePadding(const nsStylePadding& aSrc) { michael@0: MOZ_COUNT_CTOR(nsStylePadding); michael@0: mPadding = aSrc.mPadding; michael@0: mHasCachedPadding = false; michael@0: } michael@0: michael@0: void* michael@0: nsStylePadding::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW { michael@0: void* result = aContext->AllocateFromShell(sz); michael@0: if (result) michael@0: memset(result, 0, sz); michael@0: return result; michael@0: } michael@0: michael@0: void michael@0: nsStylePadding::Destroy(nsPresContext* aContext) { michael@0: this->~nsStylePadding(); michael@0: aContext->FreeToShell(sizeof(nsStylePadding), this); michael@0: } michael@0: michael@0: void nsStylePadding::RecalcData() michael@0: { michael@0: if (IsFixedData(mPadding, false)) { michael@0: NS_FOR_CSS_SIDES(side) { michael@0: // Clamp negative calc() to 0. michael@0: mCachedPadding.Side(side) = michael@0: std::max(CalcCoord(mPadding.Get(side), nullptr, 0), 0); michael@0: } michael@0: mHasCachedPadding = true; michael@0: } michael@0: else michael@0: mHasCachedPadding = false; michael@0: } michael@0: michael@0: nsChangeHint nsStylePadding::CalcDifference(const nsStylePadding& aOther) const michael@0: { michael@0: if (mPadding == aOther.mPadding) { michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: // Padding differences can't affect descendant intrinsic sizes, but do need michael@0: // to force children to reflow so that we can reposition them, since their michael@0: // offsets are from our frame bounds but our content rect's position within michael@0: // those bounds is moving. michael@0: return NS_SubtractHint(NS_STYLE_HINT_REFLOW, michael@0: nsChangeHint_ClearDescendantIntrinsics); michael@0: } michael@0: michael@0: nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext) michael@0: : mBorderColors(nullptr), michael@0: mBoxShadow(nullptr), michael@0: mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL), michael@0: mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH), michael@0: mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH), michael@0: mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT), michael@0: mComputedBorder(0, 0, 0, 0) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleBorder); michael@0: michael@0: NS_FOR_CSS_HALF_CORNERS (corner) { michael@0: mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor)); michael@0: } michael@0: michael@0: nscoord medium = michael@0: (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]; michael@0: NS_FOR_CSS_SIDES(side) { michael@0: mBorderImageSlice.Set(side, nsStyleCoord(1.0f, eStyleUnit_Percent)); michael@0: mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor)); michael@0: mBorderImageOutset.Set(side, nsStyleCoord(0.0f, eStyleUnit_Factor)); michael@0: michael@0: mBorder.Side(side) = medium; michael@0: mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND; michael@0: mBorderColor[side] = NS_RGB(0, 0, 0); michael@0: } michael@0: michael@0: mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1); michael@0: } michael@0: michael@0: nsBorderColors::~nsBorderColors() michael@0: { michael@0: NS_CSS_DELETE_LIST_MEMBER(nsBorderColors, this, mNext); michael@0: } michael@0: michael@0: nsBorderColors* michael@0: nsBorderColors::Clone(bool aDeep) const michael@0: { michael@0: nsBorderColors* result = new nsBorderColors(mColor); michael@0: if (MOZ_UNLIKELY(!result)) michael@0: return result; michael@0: if (aDeep) michael@0: NS_CSS_CLONE_LIST_MEMBER(nsBorderColors, this, mNext, result, (false)); michael@0: return result; michael@0: } michael@0: michael@0: nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc) michael@0: : mBorderColors(nullptr), michael@0: mBoxShadow(aSrc.mBoxShadow), michael@0: mBorderRadius(aSrc.mBorderRadius), michael@0: mBorderImageSource(aSrc.mBorderImageSource), michael@0: mBorderImageSlice(aSrc.mBorderImageSlice), michael@0: mBorderImageWidth(aSrc.mBorderImageWidth), michael@0: mBorderImageOutset(aSrc.mBorderImageOutset), michael@0: mBorderImageFill(aSrc.mBorderImageFill), michael@0: mBorderImageRepeatH(aSrc.mBorderImageRepeatH), michael@0: mBorderImageRepeatV(aSrc.mBorderImageRepeatV), michael@0: mFloatEdge(aSrc.mFloatEdge), michael@0: mComputedBorder(aSrc.mComputedBorder), michael@0: mBorder(aSrc.mBorder), michael@0: mTwipsPerPixel(aSrc.mTwipsPerPixel) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleBorder); michael@0: if (aSrc.mBorderColors) { michael@0: EnsureBorderColors(); michael@0: for (int32_t i = 0; i < 4; i++) michael@0: if (aSrc.mBorderColors[i]) michael@0: mBorderColors[i] = aSrc.mBorderColors[i]->Clone(); michael@0: else michael@0: mBorderColors[i] = nullptr; michael@0: } michael@0: michael@0: NS_FOR_CSS_SIDES(side) { michael@0: mBorderStyle[side] = aSrc.mBorderStyle[side]; michael@0: mBorderColor[side] = aSrc.mBorderColor[side]; michael@0: } michael@0: } michael@0: michael@0: nsStyleBorder::~nsStyleBorder() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleBorder); michael@0: if (mBorderColors) { michael@0: for (int32_t i = 0; i < 4; i++) michael@0: delete mBorderColors[i]; michael@0: delete [] mBorderColors; michael@0: } michael@0: } michael@0: michael@0: void* michael@0: nsStyleBorder::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW { michael@0: void* result = aContext->AllocateFromShell(sz); michael@0: if (result) michael@0: memset(result, 0, sz); michael@0: return result; michael@0: } michael@0: michael@0: nsMargin michael@0: nsStyleBorder::GetImageOutset() const michael@0: { michael@0: // We don't check whether there is a border-image (which is OK since michael@0: // the initial values yields 0 outset) so that we don't have to michael@0: // reflow to update overflow areas when an image loads. michael@0: nsMargin outset; michael@0: NS_FOR_CSS_SIDES(s) { michael@0: nsStyleCoord coord = mBorderImageOutset.Get(s); michael@0: nscoord value; michael@0: switch (coord.GetUnit()) { michael@0: case eStyleUnit_Coord: michael@0: value = coord.GetCoordValue(); michael@0: break; michael@0: case eStyleUnit_Factor: michael@0: value = coord.GetFactorValue() * mComputedBorder.Side(s); michael@0: break; michael@0: default: michael@0: NS_NOTREACHED("unexpected CSS unit for image outset"); michael@0: value = 0; michael@0: break; michael@0: } michael@0: outset.Side(s) = value; michael@0: } michael@0: return outset; michael@0: } michael@0: michael@0: void michael@0: nsStyleBorder::Destroy(nsPresContext* aContext) { michael@0: UntrackImage(aContext); michael@0: this->~nsStyleBorder(); michael@0: aContext->FreeToShell(sizeof(nsStyleBorder), this); michael@0: } michael@0: michael@0: nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const michael@0: { michael@0: nsChangeHint shadowDifference = michael@0: CalcShadowDifference(mBoxShadow, aOther.mBoxShadow); michael@0: NS_ABORT_IF_FALSE(shadowDifference == unsigned(NS_STYLE_HINT_REFLOW) || michael@0: shadowDifference == unsigned(NS_STYLE_HINT_VISUAL) || michael@0: shadowDifference == unsigned(NS_STYLE_HINT_NONE), michael@0: "should do more with shadowDifference"); michael@0: michael@0: // Note that differences in mBorder don't affect rendering (which should only michael@0: // use mComputedBorder), so don't need to be tested for here. michael@0: // XXXbz we should be able to return a more specific change hint for michael@0: // at least GetComputedBorder() differences... michael@0: if (mTwipsPerPixel != aOther.mTwipsPerPixel || michael@0: GetComputedBorder() != aOther.GetComputedBorder() || michael@0: mFloatEdge != aOther.mFloatEdge || michael@0: mBorderImageOutset != aOther.mBorderImageOutset || michael@0: (shadowDifference & nsChangeHint_NeedReflow)) michael@0: return NS_STYLE_HINT_REFLOW; michael@0: michael@0: NS_FOR_CSS_SIDES(ix) { michael@0: // See the explanation in nsChangeHint.h of michael@0: // nsChangeHint_BorderStyleNoneChange . michael@0: // Furthermore, even though we know *this* side is 0 width, just michael@0: // assume a visual hint for some other change rather than bother michael@0: // tracking this result through the rest of the function. michael@0: if (HasVisibleStyle(ix) != aOther.HasVisibleStyle(ix)) { michael@0: return NS_CombineHint(NS_STYLE_HINT_VISUAL, michael@0: nsChangeHint_BorderStyleNoneChange); michael@0: } michael@0: } michael@0: michael@0: // Note that mBorderStyle stores not only the border style but also michael@0: // color-related flags. Given that we've already done an mComputedBorder michael@0: // comparison, border-style differences can only lead to a VISUAL hint. So michael@0: // it's OK to just compare the values directly -- if either the actual michael@0: // style or the color flags differ we want to repaint. michael@0: NS_FOR_CSS_SIDES(ix) { michael@0: if (mBorderStyle[ix] != aOther.mBorderStyle[ix] || michael@0: mBorderColor[ix] != aOther.mBorderColor[ix]) michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: michael@0: if (mBorderRadius != aOther.mBorderRadius || michael@0: !mBorderColors != !aOther.mBorderColors) michael@0: return NS_STYLE_HINT_VISUAL; michael@0: michael@0: if (IsBorderImageLoaded() || aOther.IsBorderImageLoaded()) { michael@0: if (mBorderImageSource != aOther.mBorderImageSource || michael@0: mBorderImageRepeatH != aOther.mBorderImageRepeatH || michael@0: mBorderImageRepeatV != aOther.mBorderImageRepeatV || michael@0: mBorderImageSlice != aOther.mBorderImageSlice || michael@0: mBorderImageFill != aOther.mBorderImageFill || michael@0: mBorderImageWidth != aOther.mBorderImageWidth || michael@0: mBorderImageOutset != aOther.mBorderImageOutset) michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: michael@0: // Note that at this point if mBorderColors is non-null so is michael@0: // aOther.mBorderColors michael@0: if (mBorderColors) { michael@0: NS_FOR_CSS_SIDES(ix) { michael@0: if (!nsBorderColors::Equal(mBorderColors[ix], michael@0: aOther.mBorderColors[ix])) michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: } michael@0: michael@0: return shadowDifference; michael@0: } michael@0: michael@0: nsStyleOutline::nsStyleOutline(nsPresContext* aPresContext) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleOutline); michael@0: // spacing values not inherited michael@0: nsStyleCoord zero(0, nsStyleCoord::CoordConstructor); michael@0: NS_FOR_CSS_HALF_CORNERS(corner) { michael@0: mOutlineRadius.Set(corner, zero); michael@0: } michael@0: michael@0: mOutlineOffset = 0; michael@0: michael@0: mOutlineWidth = nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated); michael@0: mOutlineStyle = NS_STYLE_BORDER_STYLE_NONE; michael@0: mOutlineColor = NS_RGB(0, 0, 0); michael@0: michael@0: mHasCachedOutline = false; michael@0: mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1); michael@0: } michael@0: michael@0: nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc) { michael@0: MOZ_COUNT_CTOR(nsStyleOutline); michael@0: memcpy((nsStyleOutline*)this, &aSrc, sizeof(nsStyleOutline)); michael@0: } michael@0: michael@0: void michael@0: nsStyleOutline::RecalcData(nsPresContext* aContext) michael@0: { michael@0: if (NS_STYLE_BORDER_STYLE_NONE == GetOutlineStyle()) { michael@0: mCachedOutlineWidth = 0; michael@0: mHasCachedOutline = true; michael@0: } else if (IsFixedUnit(mOutlineWidth, true)) { michael@0: // Clamp negative calc() to 0. michael@0: mCachedOutlineWidth = michael@0: std::max(CalcCoord(mOutlineWidth, aContext->GetBorderWidthTable(), 3), 0); michael@0: mCachedOutlineWidth = michael@0: NS_ROUND_BORDER_TO_PIXELS(mCachedOutlineWidth, mTwipsPerPixel); michael@0: mHasCachedOutline = true; michael@0: } michael@0: else michael@0: mHasCachedOutline = false; michael@0: } michael@0: michael@0: nsChangeHint nsStyleOutline::CalcDifference(const nsStyleOutline& aOther) const michael@0: { michael@0: bool outlineWasVisible = michael@0: mCachedOutlineWidth > 0 && mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE; michael@0: bool outlineIsVisible = michael@0: aOther.mCachedOutlineWidth > 0 && aOther.mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE; michael@0: if (outlineWasVisible != outlineIsVisible || michael@0: (outlineIsVisible && (mOutlineOffset != aOther.mOutlineOffset || michael@0: mOutlineWidth != aOther.mOutlineWidth || michael@0: mTwipsPerPixel != aOther.mTwipsPerPixel))) { michael@0: return NS_CombineHint(nsChangeHint_AllReflowHints, michael@0: nsChangeHint_RepaintFrame); michael@0: } michael@0: if ((mOutlineStyle != aOther.mOutlineStyle) || michael@0: (mOutlineColor != aOther.mOutlineColor) || michael@0: (mOutlineRadius != aOther.mOutlineRadius)) { michael@0: return nsChangeHint_RepaintFrame; michael@0: } michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleList michael@0: // michael@0: nsStyleList::nsStyleList() michael@0: : mListStyleType(NS_STYLE_LIST_STYLE_DISC), michael@0: mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleList); michael@0: } michael@0: michael@0: nsStyleList::~nsStyleList() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleList); michael@0: } michael@0: michael@0: nsStyleList::nsStyleList(const nsStyleList& aSource) michael@0: : mListStyleType(aSource.mListStyleType), michael@0: mListStylePosition(aSource.mListStylePosition), michael@0: mImageRegion(aSource.mImageRegion) michael@0: { michael@0: SetListStyleImage(aSource.GetListStyleImage()); michael@0: MOZ_COUNT_CTOR(nsStyleList); michael@0: } michael@0: michael@0: nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aOther) const michael@0: { michael@0: if (mListStylePosition != aOther.mListStylePosition) michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: if (EqualImages(mListStyleImage, aOther.mListStyleImage) && michael@0: mListStyleType == aOther.mListStyleType) { michael@0: if (mImageRegion.IsEqualInterior(aOther.mImageRegion)) michael@0: return NS_STYLE_HINT_NONE; michael@0: if (mImageRegion.width == aOther.mImageRegion.width && michael@0: mImageRegion.height == aOther.mImageRegion.height) michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleXUL michael@0: // michael@0: nsStyleXUL::nsStyleXUL() michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleXUL); michael@0: mBoxAlign = NS_STYLE_BOX_ALIGN_STRETCH; michael@0: mBoxDirection = NS_STYLE_BOX_DIRECTION_NORMAL; michael@0: mBoxFlex = 0.0f; michael@0: mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL; michael@0: mBoxPack = NS_STYLE_BOX_PACK_START; michael@0: mBoxOrdinal = 1; michael@0: mStretchStack = true; michael@0: } michael@0: michael@0: nsStyleXUL::~nsStyleXUL() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleXUL); michael@0: } michael@0: michael@0: nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleXUL); michael@0: memcpy((nsStyleXUL*)this, &aSource, sizeof(nsStyleXUL)); michael@0: } michael@0: michael@0: nsChangeHint nsStyleXUL::CalcDifference(const nsStyleXUL& aOther) const michael@0: { michael@0: if (mBoxAlign == aOther.mBoxAlign && michael@0: mBoxDirection == aOther.mBoxDirection && michael@0: mBoxFlex == aOther.mBoxFlex && michael@0: mBoxOrient == aOther.mBoxOrient && michael@0: mBoxPack == aOther.mBoxPack && michael@0: mBoxOrdinal == aOther.mBoxOrdinal && michael@0: mStretchStack == aOther.mStretchStack) michael@0: return NS_STYLE_HINT_NONE; michael@0: if (mBoxOrdinal != aOther.mBoxOrdinal) michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleColumn michael@0: // michael@0: /* static */ const uint32_t nsStyleColumn::kMaxColumnCount = 1000; michael@0: michael@0: nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleColumn); michael@0: mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO; michael@0: mColumnWidth.SetAutoValue(); michael@0: mColumnGap.SetNormalValue(); michael@0: mColumnFill = NS_STYLE_COLUMN_FILL_BALANCE; michael@0: michael@0: mColumnRuleWidth = (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM]; michael@0: mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE; michael@0: mColumnRuleColor = NS_RGB(0, 0, 0); michael@0: mColumnRuleColorIsForeground = true; michael@0: michael@0: mTwipsPerPixel = aPresContext->AppUnitsPerDevPixel(); michael@0: } michael@0: michael@0: nsStyleColumn::~nsStyleColumn() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleColumn); michael@0: } michael@0: michael@0: nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleColumn); michael@0: memcpy((nsStyleColumn*)this, &aSource, sizeof(nsStyleColumn)); michael@0: } michael@0: michael@0: nsChangeHint nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const michael@0: { michael@0: if ((mColumnWidth.GetUnit() == eStyleUnit_Auto) michael@0: != (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) || michael@0: mColumnCount != aOther.mColumnCount) michael@0: // We force column count changes to do a reframe, because it's tricky to handle michael@0: // some edge cases where the column count gets smaller and content overflows. michael@0: // XXX not ideal michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: michael@0: if (mColumnWidth != aOther.mColumnWidth || michael@0: mColumnGap != aOther.mColumnGap || michael@0: mColumnFill != aOther.mColumnFill) michael@0: return NS_STYLE_HINT_REFLOW; michael@0: michael@0: if (GetComputedColumnRuleWidth() != aOther.GetComputedColumnRuleWidth() || michael@0: mColumnRuleStyle != aOther.mColumnRuleStyle || michael@0: mColumnRuleColor != aOther.mColumnRuleColor || michael@0: mColumnRuleColorIsForeground != aOther.mColumnRuleColorIsForeground) michael@0: return NS_STYLE_HINT_VISUAL; michael@0: michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleSVG michael@0: // michael@0: nsStyleSVG::nsStyleSVG() michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleSVG); michael@0: mFill.mType = eStyleSVGPaintType_Color; michael@0: mFill.mPaint.mColor = NS_RGB(0,0,0); michael@0: mFill.mFallbackColor = NS_RGB(0,0,0); michael@0: mStroke.mType = eStyleSVGPaintType_None; michael@0: mStroke.mPaint.mColor = NS_RGB(0,0,0); michael@0: mStroke.mFallbackColor = NS_RGB(0,0,0); michael@0: mStrokeDasharray = nullptr; michael@0: michael@0: mStrokeDashoffset.SetCoordValue(0); michael@0: mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1)); michael@0: michael@0: mFillOpacity = 1.0f; michael@0: mStrokeMiterlimit = 4.0f; michael@0: mStrokeOpacity = 1.0f; michael@0: michael@0: mStrokeDasharrayLength = 0; michael@0: mClipRule = NS_STYLE_FILL_RULE_NONZERO; michael@0: mColorInterpolation = NS_STYLE_COLOR_INTERPOLATION_SRGB; michael@0: mColorInterpolationFilters = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB; michael@0: mFillRule = NS_STYLE_FILL_RULE_NONZERO; michael@0: mImageRendering = NS_STYLE_IMAGE_RENDERING_AUTO; michael@0: mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL; michael@0: mShapeRendering = NS_STYLE_SHAPE_RENDERING_AUTO; michael@0: mStrokeLinecap = NS_STYLE_STROKE_LINECAP_BUTT; michael@0: mStrokeLinejoin = NS_STYLE_STROKE_LINEJOIN_MITER; michael@0: mTextAnchor = NS_STYLE_TEXT_ANCHOR_START; michael@0: mTextRendering = NS_STYLE_TEXT_RENDERING_AUTO; michael@0: mFillOpacitySource = eStyleSVGOpacitySource_Normal; michael@0: mStrokeOpacitySource = eStyleSVGOpacitySource_Normal; michael@0: mStrokeDasharrayFromObject = false; michael@0: mStrokeDashoffsetFromObject = false; michael@0: mStrokeWidthFromObject = false; michael@0: } michael@0: michael@0: nsStyleSVG::~nsStyleSVG() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleSVG); michael@0: delete [] mStrokeDasharray; michael@0: } michael@0: michael@0: nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleSVG); michael@0: mFill = aSource.mFill; michael@0: mStroke = aSource.mStroke; michael@0: michael@0: mMarkerEnd = aSource.mMarkerEnd; michael@0: mMarkerMid = aSource.mMarkerMid; michael@0: mMarkerStart = aSource.mMarkerStart; michael@0: michael@0: mStrokeDasharrayLength = aSource.mStrokeDasharrayLength; michael@0: if (aSource.mStrokeDasharray) { michael@0: mStrokeDasharray = new nsStyleCoord[mStrokeDasharrayLength]; michael@0: if (mStrokeDasharray) michael@0: memcpy(mStrokeDasharray, michael@0: aSource.mStrokeDasharray, michael@0: mStrokeDasharrayLength * sizeof(nsStyleCoord)); michael@0: else michael@0: mStrokeDasharrayLength = 0; michael@0: } else { michael@0: mStrokeDasharray = nullptr; michael@0: } michael@0: michael@0: mStrokeDashoffset = aSource.mStrokeDashoffset; michael@0: mStrokeWidth = aSource.mStrokeWidth; michael@0: michael@0: mFillOpacity = aSource.mFillOpacity; michael@0: mStrokeMiterlimit = aSource.mStrokeMiterlimit; michael@0: mStrokeOpacity = aSource.mStrokeOpacity; michael@0: michael@0: mClipRule = aSource.mClipRule; michael@0: mColorInterpolation = aSource.mColorInterpolation; michael@0: mColorInterpolationFilters = aSource.mColorInterpolationFilters; michael@0: mFillRule = aSource.mFillRule; michael@0: mImageRendering = aSource.mImageRendering; michael@0: mPaintOrder = aSource.mPaintOrder; michael@0: mShapeRendering = aSource.mShapeRendering; michael@0: mStrokeLinecap = aSource.mStrokeLinecap; michael@0: mStrokeLinejoin = aSource.mStrokeLinejoin; michael@0: mTextAnchor = aSource.mTextAnchor; michael@0: mTextRendering = aSource.mTextRendering; michael@0: mFillOpacitySource = aSource.mFillOpacitySource; michael@0: mStrokeOpacitySource = aSource.mStrokeOpacitySource; michael@0: mStrokeDasharrayFromObject = aSource.mStrokeDasharrayFromObject; michael@0: mStrokeDashoffsetFromObject = aSource.mStrokeDashoffsetFromObject; michael@0: mStrokeWidthFromObject = aSource.mStrokeWidthFromObject; michael@0: } michael@0: michael@0: static bool PaintURIChanged(const nsStyleSVGPaint& aPaint1, michael@0: const nsStyleSVGPaint& aPaint2) michael@0: { michael@0: if (aPaint1.mType != aPaint2.mType) { michael@0: return aPaint1.mType == eStyleSVGPaintType_Server || michael@0: aPaint2.mType == eStyleSVGPaintType_Server; michael@0: } michael@0: return aPaint1.mType == eStyleSVGPaintType_Server && michael@0: !EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer); michael@0: } michael@0: michael@0: nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const michael@0: { michael@0: nsChangeHint hint = nsChangeHint(0); michael@0: michael@0: if (!EqualURIs(mMarkerEnd, aOther.mMarkerEnd) || michael@0: !EqualURIs(mMarkerMid, aOther.mMarkerMid) || michael@0: !EqualURIs(mMarkerStart, aOther.mMarkerStart)) { michael@0: // Markers currently contribute to nsSVGPathGeometryFrame::mRect, michael@0: // so we need a reflow as well as a repaint. No intrinsic sizes need michael@0: // to change, so nsChangeHint_NeedReflow is sufficient. michael@0: NS_UpdateHint(hint, nsChangeHint_UpdateEffects); michael@0: NS_UpdateHint(hint, nsChangeHint_NeedReflow); michael@0: NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085 michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: return hint; michael@0: } michael@0: michael@0: if (mFill != aOther.mFill || michael@0: mStroke != aOther.mStroke || michael@0: mFillOpacity != aOther.mFillOpacity || michael@0: mStrokeOpacity != aOther.mStrokeOpacity) { michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: if (HasStroke() != aOther.HasStroke() || michael@0: (!HasStroke() && HasFill() != aOther.HasFill())) { michael@0: // Frame bounds and overflow rects depend on whether we "have" fill or michael@0: // stroke. Whether we have stroke or not just changed, or else we have no michael@0: // stroke (in which case whether we have fill or not is significant to frame michael@0: // bounds) and whether we have fill or not just changed. In either case we michael@0: // need to reflow so the frame rect is updated. michael@0: // XXXperf this is a waste on non nsSVGPathGeometryFrames. michael@0: NS_UpdateHint(hint, nsChangeHint_NeedReflow); michael@0: NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085 michael@0: } michael@0: if (PaintURIChanged(mFill, aOther.mFill) || michael@0: PaintURIChanged(mStroke, aOther.mStroke)) { michael@0: NS_UpdateHint(hint, nsChangeHint_UpdateEffects); michael@0: } michael@0: } michael@0: michael@0: // Stroke currently contributes to nsSVGPathGeometryFrame::mRect, so michael@0: // we need a reflow here. No intrinsic sizes need to change, so michael@0: // nsChangeHint_NeedReflow is sufficient. michael@0: // Note that stroke-dashoffset does not affect nsSVGPathGeometryFrame::mRect. michael@0: // text-anchor and text-rendering changes also require a reflow since they michael@0: // change frames' rects. michael@0: if (mStrokeWidth != aOther.mStrokeWidth || michael@0: mStrokeMiterlimit != aOther.mStrokeMiterlimit || michael@0: mStrokeLinecap != aOther.mStrokeLinecap || michael@0: mStrokeLinejoin != aOther.mStrokeLinejoin || michael@0: mTextAnchor != aOther.mTextAnchor || michael@0: mTextRendering != aOther.mTextRendering) { michael@0: NS_UpdateHint(hint, nsChangeHint_NeedReflow); michael@0: NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085 michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: return hint; michael@0: } michael@0: michael@0: if (hint & nsChangeHint_RepaintFrame) { michael@0: return hint; // we don't add anything else below michael@0: } michael@0: michael@0: if ( mStrokeDashoffset != aOther.mStrokeDashoffset || michael@0: mClipRule != aOther.mClipRule || michael@0: mColorInterpolation != aOther.mColorInterpolation || michael@0: mColorInterpolationFilters != aOther.mColorInterpolationFilters || michael@0: mFillRule != aOther.mFillRule || michael@0: mImageRendering != aOther.mImageRendering || michael@0: mPaintOrder != aOther.mPaintOrder || michael@0: mShapeRendering != aOther.mShapeRendering || michael@0: mStrokeDasharrayLength != aOther.mStrokeDasharrayLength || michael@0: mFillOpacitySource != aOther.mFillOpacitySource || michael@0: mStrokeOpacitySource != aOther.mStrokeOpacitySource || michael@0: mStrokeDasharrayFromObject != aOther.mStrokeDasharrayFromObject || michael@0: mStrokeDashoffsetFromObject != aOther.mStrokeDashoffsetFromObject || michael@0: mStrokeWidthFromObject != aOther.mStrokeWidthFromObject) { michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: return hint; michael@0: } michael@0: michael@0: // length of stroke dasharrays are the same (tested above) - check entries michael@0: for (uint32_t i=0; iRelease(); michael@0: } else if (mType == NS_STYLE_FILTER_URL) { michael@0: NS_ASSERTION(mURL, "expected pointer"); michael@0: mURL->Release(); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsStyleFilter::SetFilterParameter(const nsStyleCoord& aFilterParameter, michael@0: int32_t aType) michael@0: { michael@0: ReleaseRef(); michael@0: mFilterParameter = aFilterParameter; michael@0: mType = aType; michael@0: } michael@0: michael@0: void michael@0: nsStyleFilter::SetURL(nsIURI* aURL) michael@0: { michael@0: NS_ASSERTION(aURL, "expected pointer"); michael@0: ReleaseRef(); michael@0: mURL = aURL; michael@0: mURL->AddRef(); michael@0: mType = NS_STYLE_FILTER_URL; michael@0: } michael@0: michael@0: void michael@0: nsStyleFilter::SetDropShadow(nsCSSShadowArray* aDropShadow) michael@0: { michael@0: NS_ASSERTION(aDropShadow, "expected pointer"); michael@0: ReleaseRef(); michael@0: mDropShadow = aDropShadow; michael@0: mDropShadow->AddRef(); michael@0: mType = NS_STYLE_FILTER_DROP_SHADOW; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleSVGReset michael@0: // michael@0: nsStyleSVGReset::nsStyleSVGReset() michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleSVGReset); michael@0: mStopColor = NS_RGB(0,0,0); michael@0: mFloodColor = NS_RGB(0,0,0); michael@0: mLightingColor = NS_RGB(255,255,255); michael@0: mClipPath = nullptr; michael@0: mMask = nullptr; michael@0: mStopOpacity = 1.0f; michael@0: mFloodOpacity = 1.0f; michael@0: mDominantBaseline = NS_STYLE_DOMINANT_BASELINE_AUTO; michael@0: mVectorEffect = NS_STYLE_VECTOR_EFFECT_NONE; michael@0: mMaskType = NS_STYLE_MASK_TYPE_LUMINANCE; michael@0: } michael@0: michael@0: nsStyleSVGReset::~nsStyleSVGReset() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleSVGReset); michael@0: } michael@0: michael@0: nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleSVGReset); michael@0: mStopColor = aSource.mStopColor; michael@0: mFloodColor = aSource.mFloodColor; michael@0: mLightingColor = aSource.mLightingColor; michael@0: mClipPath = aSource.mClipPath; michael@0: mFilters = aSource.mFilters; michael@0: mMask = aSource.mMask; michael@0: mStopOpacity = aSource.mStopOpacity; michael@0: mFloodOpacity = aSource.mFloodOpacity; michael@0: mDominantBaseline = aSource.mDominantBaseline; michael@0: mVectorEffect = aSource.mVectorEffect; michael@0: mMaskType = aSource.mMaskType; michael@0: } michael@0: michael@0: nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) const michael@0: { michael@0: nsChangeHint hint = nsChangeHint(0); michael@0: michael@0: bool equalFilters = (mFilters == aOther.mFilters); michael@0: michael@0: if (!equalFilters) { michael@0: NS_UpdateHint(hint, nsChangeHint_UpdateOverflow); michael@0: } michael@0: michael@0: if (!EqualURIs(mClipPath, aOther.mClipPath) || michael@0: !EqualURIs(mMask, aOther.mMask) || michael@0: !equalFilters) { michael@0: NS_UpdateHint(hint, nsChangeHint_UpdateEffects); michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: } michael@0: michael@0: if (mDominantBaseline != aOther.mDominantBaseline) { michael@0: // XXXjwatt: why NS_STYLE_HINT_REFLOW? Isn't that excessive? michael@0: NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW); michael@0: } else if (mVectorEffect != aOther.mVectorEffect) { michael@0: // Stroke currently affects nsSVGPathGeometryFrame::mRect, and michael@0: // vector-effect affect stroke. As a result we need to reflow if michael@0: // vector-effect changes in order to have nsSVGPathGeometryFrame:: michael@0: // ReflowSVG called to update its mRect. No intrinsic sizes need michael@0: // to change so nsChangeHint_NeedReflow is sufficient. michael@0: NS_UpdateHint(hint, nsChangeHint_NeedReflow); michael@0: NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085 michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: } else if (mStopColor != aOther.mStopColor || michael@0: mFloodColor != aOther.mFloodColor || michael@0: mLightingColor != aOther.mLightingColor || michael@0: mStopOpacity != aOther.mStopOpacity || michael@0: mFloodOpacity != aOther.mFloodOpacity || michael@0: mMaskType != aOther.mMaskType) { michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: } michael@0: michael@0: return hint; michael@0: } michael@0: michael@0: // nsStyleSVGPaint implementation michael@0: nsStyleSVGPaint::~nsStyleSVGPaint() michael@0: { michael@0: if (mType == eStyleSVGPaintType_Server) { michael@0: NS_IF_RELEASE(mPaint.mPaintServer); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsStyleSVGPaint::SetType(nsStyleSVGPaintType aType) michael@0: { michael@0: if (mType == eStyleSVGPaintType_Server) { michael@0: this->~nsStyleSVGPaint(); michael@0: new (this) nsStyleSVGPaint(); michael@0: } michael@0: mType = aType; michael@0: } michael@0: michael@0: nsStyleSVGPaint& nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther) michael@0: { michael@0: if (this == &aOther) michael@0: return *this; michael@0: michael@0: SetType(aOther.mType); michael@0: michael@0: mFallbackColor = aOther.mFallbackColor; michael@0: if (mType == eStyleSVGPaintType_Server) { michael@0: mPaint.mPaintServer = aOther.mPaint.mPaintServer; michael@0: NS_IF_ADDREF(mPaint.mPaintServer); michael@0: } else { michael@0: mPaint.mColor = aOther.mPaint.mColor; michael@0: } michael@0: return *this; michael@0: } michael@0: michael@0: bool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const michael@0: { michael@0: if (mType != aOther.mType) michael@0: return false; michael@0: if (mType == eStyleSVGPaintType_Server) michael@0: return EqualURIs(mPaint.mPaintServer, aOther.mPaint.mPaintServer) && michael@0: mFallbackColor == aOther.mFallbackColor; michael@0: if (mType == eStyleSVGPaintType_Color) michael@0: return mPaint.mColor == aOther.mPaint.mColor; michael@0: return true; michael@0: } michael@0: michael@0: michael@0: // -------------------- michael@0: // nsStylePosition michael@0: // michael@0: nsStylePosition::nsStylePosition(void) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStylePosition); michael@0: // positioning values not inherited michael@0: nsStyleCoord autoCoord(eStyleUnit_Auto); michael@0: mOffset.SetLeft(autoCoord); michael@0: mOffset.SetTop(autoCoord); michael@0: mOffset.SetRight(autoCoord); michael@0: mOffset.SetBottom(autoCoord); michael@0: mWidth.SetAutoValue(); michael@0: mMinWidth.SetCoordValue(0); michael@0: mMaxWidth.SetNoneValue(); michael@0: mHeight.SetAutoValue(); michael@0: mMinHeight.SetCoordValue(0); michael@0: mMaxHeight.SetNoneValue(); michael@0: mFlexBasis.SetAutoValue(); michael@0: michael@0: // The initial value of grid-auto-columns and grid-auto-rows is 'auto', michael@0: // which computes to 'minmax(min-content, max-content)'. michael@0: mGridAutoColumnsMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT, michael@0: eStyleUnit_Enumerated); michael@0: mGridAutoColumnsMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT, michael@0: eStyleUnit_Enumerated); michael@0: mGridAutoRowsMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT, michael@0: eStyleUnit_Enumerated); michael@0: mGridAutoRowsMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT, michael@0: eStyleUnit_Enumerated); michael@0: michael@0: mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_NONE; michael@0: mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT; michael@0: mAlignContent = NS_STYLE_ALIGN_CONTENT_STRETCH; michael@0: mAlignItems = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE; michael@0: mAlignSelf = NS_STYLE_ALIGN_SELF_AUTO; michael@0: mFlexDirection = NS_STYLE_FLEX_DIRECTION_ROW; michael@0: mFlexWrap = NS_STYLE_FLEX_WRAP_NOWRAP; michael@0: mJustifyContent = NS_STYLE_JUSTIFY_CONTENT_FLEX_START; michael@0: mOrder = NS_STYLE_ORDER_INITIAL; michael@0: mFlexGrow = 0.0f; michael@0: mFlexShrink = 1.0f; michael@0: mZIndex.SetAutoValue(); michael@0: mGridAutoPositionColumn.SetToInteger(1); michael@0: mGridAutoPositionRow.SetToInteger(1); michael@0: // Other members get their default constructors michael@0: // which initialize them to representations of their respective initial value. michael@0: // mGridTemplateAreas: nullptr for 'none' michael@0: // mGridTemplate{Rows,Columns}: false and empty arrays for 'none' michael@0: // mGrid{Column,Row}{Start,End}: false/0/empty values for 'auto' michael@0: } michael@0: michael@0: nsStylePosition::~nsStylePosition(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStylePosition); michael@0: } michael@0: michael@0: nsStylePosition::nsStylePosition(const nsStylePosition& aSource) michael@0: : mGridTemplateColumns(aSource.mGridTemplateColumns) michael@0: , mGridTemplateRows(aSource.mGridTemplateRows) michael@0: , mGridTemplateAreas(aSource.mGridTemplateAreas) michael@0: , mGridAutoPositionColumn(aSource.mGridAutoPositionColumn) michael@0: , mGridAutoPositionRow(aSource.mGridAutoPositionRow) michael@0: , mGridColumnStart(aSource.mGridColumnStart) michael@0: , mGridColumnEnd(aSource.mGridColumnEnd) michael@0: , mGridRowStart(aSource.mGridRowStart) michael@0: , mGridRowEnd(aSource.mGridRowEnd) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStylePosition); michael@0: // If you add any memcpy'able member vars, michael@0: // they should be declared before mGridTemplateColumns. michael@0: // If you add any non-memcpy'able member vars, michael@0: // they should be declared after mGridTemplateColumns, michael@0: // and you should invoke their copy constructor in the init list above michael@0: // and update this static-assert to include their "sizeof()" michael@0: static_assert(sizeof(nsStylePosition) == michael@0: offsetof(nsStylePosition, mGridTemplateColumns) + michael@0: sizeof(mGridTemplateColumns) + michael@0: sizeof(mGridTemplateRows) + michael@0: sizeof(mGridTemplateAreas) + michael@0: sizeof(mGridAutoPositionColumn) + michael@0: sizeof(mGridAutoPositionRow) + michael@0: sizeof(mGridColumnStart) + michael@0: sizeof(mGridColumnEnd) + michael@0: sizeof(mGridRowStart) + michael@0: sizeof(mGridRowEnd), michael@0: "Unexpected size or offset in nsStylePosition"); michael@0: memcpy((nsStylePosition*) this, michael@0: &aSource, michael@0: offsetof(nsStylePosition, mGridTemplateColumns)); michael@0: } michael@0: michael@0: static bool michael@0: IsAutonessEqual(const nsStyleSides& aSides1, const nsStyleSides& aSides2) michael@0: { michael@0: NS_FOR_CSS_SIDES(side) { michael@0: if ((aSides1.GetUnit(side) == eStyleUnit_Auto) != michael@0: (aSides2.GetUnit(side) == eStyleUnit_Auto)) { michael@0: return false; michael@0: } michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) const michael@0: { michael@0: nsChangeHint hint = michael@0: (mZIndex == aOther.mZIndex) ? NS_STYLE_HINT_NONE : nsChangeHint_RepaintFrame; michael@0: michael@0: if (mBoxSizing != aOther.mBoxSizing) { michael@0: // Can affect both widths and heights; just a bad scene. michael@0: return NS_CombineHint(hint, nsChangeHint_AllReflowHints); michael@0: } michael@0: michael@0: // Properties that apply to flex items: michael@0: // NOTE: Changes to "order" on a flex item may trigger some repositioning. michael@0: // If we're in a multi-line flex container, it also may affect our size michael@0: // (and that of our container & siblings) by shuffling items between lines. michael@0: if (mAlignSelf != aOther.mAlignSelf || michael@0: mFlexBasis != aOther.mFlexBasis || michael@0: mFlexGrow != aOther.mFlexGrow || michael@0: mFlexShrink != aOther.mFlexShrink || michael@0: mOrder != aOther.mOrder) { michael@0: return NS_CombineHint(hint, nsChangeHint_AllReflowHints); michael@0: } michael@0: michael@0: // Properties that apply to flex containers: michael@0: // - flex-direction can swap a flex container between vertical & horizontal. michael@0: // - align-items can change the sizing of a flex container & the positioning michael@0: // of its children. michael@0: // - flex-wrap changes whether a flex container's children are wrapped, which michael@0: // impacts their sizing/positioning and hence impacts the container's size. michael@0: if (mAlignItems != aOther.mAlignItems || michael@0: mFlexDirection != aOther.mFlexDirection || michael@0: mFlexWrap != aOther.mFlexWrap) { michael@0: return NS_CombineHint(hint, nsChangeHint_AllReflowHints); michael@0: } michael@0: michael@0: // Properties that apply to grid containers: michael@0: // FIXME: only for grid containers michael@0: // (ie. 'display: grid' or 'display: inline-grid') michael@0: if (mGridTemplateColumns != aOther.mGridTemplateColumns || michael@0: mGridTemplateRows != aOther.mGridTemplateRows || michael@0: mGridTemplateAreas != aOther.mGridTemplateAreas || michael@0: mGridAutoColumnsMin != aOther.mGridAutoColumnsMin || michael@0: mGridAutoColumnsMax != aOther.mGridAutoColumnsMax || michael@0: mGridAutoRowsMin != aOther.mGridAutoRowsMin || michael@0: mGridAutoRowsMax != aOther.mGridAutoRowsMax || michael@0: mGridAutoFlow != aOther.mGridAutoFlow) { michael@0: return NS_CombineHint(hint, nsChangeHint_AllReflowHints); michael@0: } michael@0: michael@0: // Properties that apply to grid items: michael@0: // FIXME: only for grid items michael@0: // (ie. parent frame is 'display: grid' or 'display: inline-grid') michael@0: if (mGridColumnStart != aOther.mGridColumnStart || michael@0: mGridColumnEnd != aOther.mGridColumnEnd || michael@0: mGridRowStart != aOther.mGridRowStart || michael@0: mGridRowEnd != aOther.mGridRowEnd) { michael@0: return NS_CombineHint(hint, nsChangeHint_AllReflowHints); michael@0: } michael@0: michael@0: // Changing justify-content on a flexbox might affect the positioning of its michael@0: // children, but it won't affect any sizing. michael@0: if (mJustifyContent != aOther.mJustifyContent) { michael@0: NS_UpdateHint(hint, nsChangeHint_NeedReflow); michael@0: } michael@0: michael@0: // Properties that apply only to multi-line flex containers: michael@0: // 'align-content' can change the positioning & sizing of a multi-line flex michael@0: // container's children when there's extra space in the cross axis, but it michael@0: // shouldn't affect the container's own sizing. michael@0: // michael@0: // NOTE: If we get here, we know that mFlexWrap == aOther.mFlexWrap michael@0: // (otherwise, we would've returned earlier). So it doesn't matter which one michael@0: // of those we check to see if we're multi-line. michael@0: if (mFlexWrap != NS_STYLE_FLEX_WRAP_NOWRAP && michael@0: mAlignContent != aOther.mAlignContent) { michael@0: NS_UpdateHint(hint, nsChangeHint_NeedReflow); michael@0: } michael@0: michael@0: if (mHeight != aOther.mHeight || michael@0: mMinHeight != aOther.mMinHeight || michael@0: mMaxHeight != aOther.mMaxHeight) { michael@0: // Height changes can affect descendant intrinsic sizes due to replaced michael@0: // elements with percentage heights in descendants which also have michael@0: // percentage heights. And due to our not-so-great computation of mVResize michael@0: // in nsHTMLReflowState, they do need to force reflow of the whole subtree. michael@0: // XXXbz due to XUL caching heights as well, height changes also need to michael@0: // clear ancestor intrinsics! michael@0: return NS_CombineHint(hint, nsChangeHint_AllReflowHints); michael@0: } michael@0: michael@0: if (mWidth != aOther.mWidth || michael@0: mMinWidth != aOther.mMinWidth || michael@0: mMaxWidth != aOther.mMaxWidth) { michael@0: // None of our width differences can affect descendant intrinsic michael@0: // sizes and none of them need to force children to reflow. michael@0: return michael@0: NS_CombineHint(hint, michael@0: NS_SubtractHint(nsChangeHint_AllReflowHints, michael@0: NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics, michael@0: nsChangeHint_NeedDirtyReflow))); michael@0: } michael@0: michael@0: // If width and height have not changed, but any of the offsets have changed, michael@0: // then return the respective hints so that we would hopefully be able to michael@0: // avoid reflowing. michael@0: // Note that it is possible that we'll need to reflow when processing michael@0: // restyles, but we don't have enough information to make a good decision michael@0: // right now. michael@0: // Don't try to handle changes between "auto" and non-auto efficiently; michael@0: // that's tricky to do and will hardly ever be able to avoid a reflow. michael@0: if (mOffset != aOther.mOffset) { michael@0: if (IsAutonessEqual(mOffset, aOther.mOffset)) { michael@0: NS_UpdateHint(hint, nsChangeHint(nsChangeHint_RecomputePosition | michael@0: nsChangeHint_UpdateOverflow)); michael@0: } else { michael@0: return NS_CombineHint(hint, nsChangeHint_AllReflowHints); michael@0: } michael@0: } michael@0: return hint; michael@0: } michael@0: michael@0: /* static */ bool michael@0: nsStylePosition::WidthCoordDependsOnContainer(const nsStyleCoord &aCoord) michael@0: { michael@0: return aCoord.GetUnit() == eStyleUnit_Auto || michael@0: aCoord.HasPercent() || michael@0: (aCoord.GetUnit() == eStyleUnit_Enumerated && michael@0: (aCoord.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT || michael@0: aCoord.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE)); michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleTable michael@0: // michael@0: michael@0: nsStyleTable::nsStyleTable() michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleTable); michael@0: // values not inherited michael@0: mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO; michael@0: mFrame = NS_STYLE_TABLE_FRAME_NONE; michael@0: mRules = NS_STYLE_TABLE_RULES_NONE; michael@0: mSpan = 1; michael@0: } michael@0: michael@0: nsStyleTable::~nsStyleTable(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleTable); michael@0: } michael@0: michael@0: nsStyleTable::nsStyleTable(const nsStyleTable& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleTable); michael@0: memcpy((nsStyleTable*)this, &aSource, sizeof(nsStyleTable)); michael@0: } michael@0: michael@0: nsChangeHint nsStyleTable::CalcDifference(const nsStyleTable& aOther) const michael@0: { michael@0: // Changes in mRules may require reframing (if border-collapse stuff changes, for example). michael@0: if (mRules != aOther.mRules || mSpan != aOther.mSpan || michael@0: mLayoutStrategy != aOther.mLayoutStrategy) michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: if (mFrame != aOther.mFrame) michael@0: return NS_STYLE_HINT_REFLOW; michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: michael@0: // ----------------------- michael@0: // nsStyleTableBorder michael@0: michael@0: nsStyleTableBorder::nsStyleTableBorder(nsPresContext* aPresContext) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleTableBorder); michael@0: mBorderCollapse = NS_STYLE_BORDER_SEPARATE; michael@0: michael@0: nsCompatibility compatMode = eCompatibility_FullStandards; michael@0: if (aPresContext) michael@0: compatMode = aPresContext->CompatibilityMode(); michael@0: mEmptyCells = (compatMode == eCompatibility_NavQuirks) michael@0: ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND michael@0: : NS_STYLE_TABLE_EMPTY_CELLS_SHOW; michael@0: mCaptionSide = NS_STYLE_CAPTION_SIDE_TOP; michael@0: mBorderSpacingX = 0; michael@0: mBorderSpacingY = 0; michael@0: } michael@0: michael@0: nsStyleTableBorder::~nsStyleTableBorder(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleTableBorder); michael@0: } michael@0: michael@0: nsStyleTableBorder::nsStyleTableBorder(const nsStyleTableBorder& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleTableBorder); michael@0: memcpy((nsStyleTableBorder*)this, &aSource, sizeof(nsStyleTableBorder)); michael@0: } michael@0: michael@0: nsChangeHint nsStyleTableBorder::CalcDifference(const nsStyleTableBorder& aOther) const michael@0: { michael@0: // Border-collapse changes need a reframe, because we use a different frame michael@0: // class for table cells in the collapsed border model. This is used to michael@0: // conserve memory when using the separated border model (collapsed borders michael@0: // require extra state to be stored). michael@0: if (mBorderCollapse != aOther.mBorderCollapse) { michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0: michael@0: if ((mCaptionSide == aOther.mCaptionSide) && michael@0: (mBorderSpacingX == aOther.mBorderSpacingX) && michael@0: (mBorderSpacingY == aOther.mBorderSpacingY)) { michael@0: if (mEmptyCells == aOther.mEmptyCells) michael@0: return NS_STYLE_HINT_NONE; michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: else michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleColor michael@0: // michael@0: michael@0: nsStyleColor::nsStyleColor(nsPresContext* aPresContext) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleColor); michael@0: mColor = aPresContext->DefaultColor(); michael@0: } michael@0: michael@0: nsStyleColor::nsStyleColor(const nsStyleColor& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleColor); michael@0: mColor = aSource.mColor; michael@0: } michael@0: michael@0: nsChangeHint nsStyleColor::CalcDifference(const nsStyleColor& aOther) const michael@0: { michael@0: if (mColor == aOther.mColor) michael@0: return NS_STYLE_HINT_NONE; michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleGradient michael@0: // michael@0: bool michael@0: nsStyleGradient::operator==(const nsStyleGradient& aOther) const michael@0: { michael@0: NS_ABORT_IF_FALSE(mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER || michael@0: mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR, michael@0: "incorrect combination of shape and size"); michael@0: NS_ABORT_IF_FALSE(aOther.mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER || michael@0: aOther.mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR, michael@0: "incorrect combination of shape and size"); michael@0: michael@0: if (mShape != aOther.mShape || michael@0: mSize != aOther.mSize || michael@0: mRepeating != aOther.mRepeating || michael@0: mLegacySyntax != aOther.mLegacySyntax || michael@0: mBgPosX != aOther.mBgPosX || michael@0: mBgPosY != aOther.mBgPosY || michael@0: mAngle != aOther.mAngle || michael@0: mRadiusX != aOther.mRadiusX || michael@0: mRadiusY != aOther.mRadiusY) 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].mLocation != aOther.mStops[i].mLocation || michael@0: mStops[i].mColor != aOther.mStops[i].mColor) michael@0: return false; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: nsStyleGradient::nsStyleGradient(void) michael@0: : mShape(NS_STYLE_GRADIENT_SHAPE_LINEAR) michael@0: , mSize(NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER) michael@0: , mRepeating(false) michael@0: , mLegacySyntax(false) michael@0: { michael@0: } michael@0: michael@0: bool michael@0: nsStyleGradient::IsOpaque() michael@0: { michael@0: for (uint32_t i = 0; i < mStops.Length(); i++) { michael@0: if (NS_GET_A(mStops[i].mColor) < 255) michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: bool michael@0: nsStyleGradient::HasCalc() michael@0: { michael@0: for (uint32_t i = 0; i < mStops.Length(); i++) { michael@0: if (mStops[i].mLocation.IsCalcUnit()) michael@0: return true; michael@0: } michael@0: return mBgPosX.IsCalcUnit() || mBgPosY.IsCalcUnit() || mAngle.IsCalcUnit() || michael@0: mRadiusX.IsCalcUnit() || mRadiusY.IsCalcUnit(); michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleImage michael@0: // michael@0: michael@0: nsStyleImage::nsStyleImage() michael@0: : mType(eStyleImageType_Null) michael@0: , mCropRect(nullptr) michael@0: #ifdef DEBUG michael@0: , mImageTracked(false) michael@0: #endif michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleImage); michael@0: } michael@0: michael@0: nsStyleImage::~nsStyleImage() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleImage); michael@0: if (mType != eStyleImageType_Null) michael@0: SetNull(); michael@0: } michael@0: michael@0: nsStyleImage::nsStyleImage(const nsStyleImage& aOther) michael@0: : mType(eStyleImageType_Null) michael@0: , mCropRect(nullptr) michael@0: #ifdef DEBUG michael@0: , mImageTracked(false) michael@0: #endif michael@0: { michael@0: // We need our own copy constructor because we don't want michael@0: // to copy the reference count michael@0: MOZ_COUNT_CTOR(nsStyleImage); michael@0: DoCopy(aOther); michael@0: } michael@0: michael@0: nsStyleImage& michael@0: nsStyleImage::operator=(const nsStyleImage& aOther) michael@0: { michael@0: if (this != &aOther) michael@0: DoCopy(aOther); michael@0: michael@0: return *this; michael@0: } michael@0: michael@0: void michael@0: nsStyleImage::DoCopy(const nsStyleImage& aOther) michael@0: { michael@0: SetNull(); michael@0: michael@0: if (aOther.mType == eStyleImageType_Image) michael@0: SetImageData(aOther.mImage); michael@0: else if (aOther.mType == eStyleImageType_Gradient) michael@0: SetGradientData(aOther.mGradient); michael@0: else if (aOther.mType == eStyleImageType_Element) michael@0: SetElementId(aOther.mElementId); michael@0: michael@0: SetCropRect(aOther.mCropRect); michael@0: } michael@0: michael@0: void michael@0: nsStyleImage::SetNull() michael@0: { michael@0: NS_ABORT_IF_FALSE(!mImageTracked, michael@0: "Calling SetNull() with image tracked!"); michael@0: michael@0: if (mType == eStyleImageType_Gradient) michael@0: mGradient->Release(); michael@0: else if (mType == eStyleImageType_Image) michael@0: NS_RELEASE(mImage); michael@0: else if (mType == eStyleImageType_Element) michael@0: NS_Free(mElementId); michael@0: michael@0: mType = eStyleImageType_Null; michael@0: mCropRect = nullptr; michael@0: } michael@0: michael@0: void michael@0: nsStyleImage::SetImageData(imgIRequest* aImage) michael@0: { michael@0: NS_ABORT_IF_FALSE(!mImageTracked, michael@0: "Setting a new image without untracking the old one!"); michael@0: michael@0: NS_IF_ADDREF(aImage); michael@0: michael@0: if (mType != eStyleImageType_Null) michael@0: SetNull(); michael@0: michael@0: if (aImage) { michael@0: mImage = aImage; michael@0: mType = eStyleImageType_Image; michael@0: } michael@0: mSubImages.Clear(); michael@0: } michael@0: michael@0: void michael@0: nsStyleImage::TrackImage(nsPresContext* aContext) michael@0: { michael@0: // Sanity michael@0: NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!"); michael@0: NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, michael@0: "Can't track image when there isn't one!"); michael@0: michael@0: // Register the image with the document michael@0: nsIDocument* doc = aContext->Document(); michael@0: if (doc) michael@0: doc->AddImage(mImage); michael@0: michael@0: // Mark state michael@0: #ifdef DEBUG michael@0: mImageTracked = true; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: nsStyleImage::UntrackImage(nsPresContext* aContext) michael@0: { michael@0: // Sanity michael@0: NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!"); michael@0: NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, michael@0: "Can't untrack image when there isn't one!"); michael@0: michael@0: // Unregister the image with the document michael@0: nsIDocument* doc = aContext->Document(); michael@0: if (doc) michael@0: doc->RemoveImage(mImage, nsIDocument::REQUEST_DISCARD); michael@0: michael@0: // Mark state michael@0: #ifdef DEBUG michael@0: mImageTracked = false; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: nsStyleImage::SetGradientData(nsStyleGradient* aGradient) michael@0: { michael@0: if (aGradient) michael@0: aGradient->AddRef(); michael@0: michael@0: if (mType != eStyleImageType_Null) michael@0: SetNull(); michael@0: michael@0: if (aGradient) { michael@0: mGradient = aGradient; michael@0: mType = eStyleImageType_Gradient; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsStyleImage::SetElementId(const char16_t* aElementId) michael@0: { michael@0: if (mType != eStyleImageType_Null) michael@0: SetNull(); michael@0: michael@0: if (aElementId) { michael@0: mElementId = NS_strdup(aElementId); michael@0: mType = eStyleImageType_Element; michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsStyleImage::SetCropRect(nsStyleSides* aCropRect) michael@0: { michael@0: if (aCropRect) { michael@0: mCropRect = new nsStyleSides(*aCropRect); michael@0: // There is really not much we can do if 'new' fails michael@0: } else { michael@0: mCropRect = nullptr; michael@0: } michael@0: } michael@0: michael@0: static int32_t michael@0: ConvertToPixelCoord(const nsStyleCoord& aCoord, int32_t aPercentScale) michael@0: { michael@0: double pixelValue; michael@0: switch (aCoord.GetUnit()) { michael@0: case eStyleUnit_Percent: michael@0: pixelValue = aCoord.GetPercentValue() * aPercentScale; michael@0: break; michael@0: case eStyleUnit_Factor: michael@0: pixelValue = aCoord.GetFactorValue(); michael@0: break; michael@0: default: michael@0: NS_NOTREACHED("unexpected unit for image crop rect"); michael@0: return 0; michael@0: } michael@0: NS_ABORT_IF_FALSE(pixelValue >= 0, "we ensured non-negative while parsing"); michael@0: pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow michael@0: return NS_lround(pixelValue); michael@0: } michael@0: michael@0: bool michael@0: nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect, michael@0: bool* aIsEntireImage) const michael@0: { michael@0: if (mType != eStyleImageType_Image) michael@0: return false; michael@0: michael@0: nsCOMPtr imageContainer; michael@0: mImage->GetImage(getter_AddRefs(imageContainer)); michael@0: if (!imageContainer) michael@0: return false; michael@0: michael@0: nsIntSize imageSize; michael@0: imageContainer->GetWidth(&imageSize.width); michael@0: imageContainer->GetHeight(&imageSize.height); michael@0: if (imageSize.width <= 0 || imageSize.height <= 0) michael@0: return false; michael@0: michael@0: int32_t left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width); michael@0: int32_t top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height); michael@0: int32_t right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width); michael@0: int32_t bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height); michael@0: michael@0: // IntersectRect() returns an empty rect if we get negative width or height michael@0: nsIntRect cropRect(left, top, right - left, bottom - top); michael@0: nsIntRect imageRect(nsIntPoint(0, 0), imageSize); michael@0: aActualCropRect.IntersectRect(imageRect, cropRect); michael@0: michael@0: if (aIsEntireImage) michael@0: *aIsEntireImage = aActualCropRect.IsEqualInterior(imageRect); michael@0: return true; michael@0: } michael@0: michael@0: nsresult michael@0: nsStyleImage::StartDecoding() const michael@0: { michael@0: if ((mType == eStyleImageType_Image) && mImage) michael@0: return mImage->StartDecoding(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: bool michael@0: nsStyleImage::IsOpaque() const michael@0: { michael@0: if (!IsComplete()) michael@0: return false; michael@0: michael@0: if (mType == eStyleImageType_Gradient) michael@0: return mGradient->IsOpaque(); michael@0: michael@0: if (mType == eStyleImageType_Element) michael@0: return false; michael@0: michael@0: NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, "unexpected image type"); michael@0: michael@0: nsCOMPtr imageContainer; michael@0: mImage->GetImage(getter_AddRefs(imageContainer)); michael@0: NS_ABORT_IF_FALSE(imageContainer, "IsComplete() said image container is ready"); michael@0: michael@0: // Check if the crop region of the current image frame is opaque. michael@0: if (imageContainer->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) { michael@0: if (!mCropRect) michael@0: return true; michael@0: michael@0: // Must make sure if mCropRect contains at least a pixel. michael@0: // XXX Is this optimization worth it? Maybe I should just return false. michael@0: nsIntRect actualCropRect; michael@0: bool rv = ComputeActualCropRect(actualCropRect); michael@0: NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here"); michael@0: return rv && !actualCropRect.IsEmpty(); michael@0: } michael@0: michael@0: return false; michael@0: } michael@0: michael@0: bool michael@0: nsStyleImage::IsComplete() const michael@0: { michael@0: switch (mType) { michael@0: case eStyleImageType_Null: michael@0: return false; michael@0: case eStyleImageType_Gradient: michael@0: case eStyleImageType_Element: michael@0: return true; michael@0: case eStyleImageType_Image: michael@0: { michael@0: uint32_t status = imgIRequest::STATUS_ERROR; michael@0: return NS_SUCCEEDED(mImage->GetImageStatus(&status)) && michael@0: (status & imgIRequest::STATUS_SIZE_AVAILABLE) && michael@0: (status & imgIRequest::STATUS_FRAME_COMPLETE); michael@0: } michael@0: default: michael@0: NS_NOTREACHED("unexpected image type"); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: bool michael@0: nsStyleImage::IsLoaded() const michael@0: { michael@0: switch (mType) { michael@0: case eStyleImageType_Null: michael@0: return false; michael@0: case eStyleImageType_Gradient: michael@0: case eStyleImageType_Element: michael@0: return true; michael@0: case eStyleImageType_Image: michael@0: { michael@0: uint32_t status = imgIRequest::STATUS_ERROR; michael@0: return NS_SUCCEEDED(mImage->GetImageStatus(&status)) && michael@0: !(status & imgIRequest::STATUS_ERROR) && michael@0: (status & imgIRequest::STATUS_LOAD_COMPLETE); michael@0: } michael@0: default: michael@0: NS_NOTREACHED("unexpected image type"); michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: static inline bool michael@0: EqualRects(const nsStyleSides* aRect1, const nsStyleSides* aRect2) michael@0: { michael@0: return aRect1 == aRect2 || /* handles null== null, and optimize */ michael@0: (aRect1 && aRect2 && *aRect1 == *aRect2); michael@0: } michael@0: michael@0: bool michael@0: nsStyleImage::operator==(const nsStyleImage& aOther) const michael@0: { michael@0: if (mType != aOther.mType) michael@0: return false; michael@0: michael@0: if (!EqualRects(mCropRect, aOther.mCropRect)) michael@0: return false; michael@0: michael@0: if (mType == eStyleImageType_Image) michael@0: return EqualImages(mImage, aOther.mImage); michael@0: michael@0: if (mType == eStyleImageType_Gradient) michael@0: return *mGradient == *aOther.mGradient; michael@0: michael@0: if (mType == eStyleImageType_Element) michael@0: return NS_strcmp(mElementId, aOther.mElementId) == 0; michael@0: michael@0: return true; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleBackground michael@0: // michael@0: michael@0: nsStyleBackground::nsStyleBackground() michael@0: : mAttachmentCount(1) michael@0: , mClipCount(1) michael@0: , mOriginCount(1) michael@0: , mRepeatCount(1) michael@0: , mPositionCount(1) michael@0: , mImageCount(1) michael@0: , mSizeCount(1) michael@0: , mBlendModeCount(1) michael@0: , mBackgroundColor(NS_RGBA(0, 0, 0, 0)) michael@0: , mBackgroundInlinePolicy(NS_STYLE_BG_INLINE_POLICY_CONTINUOUS) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleBackground); michael@0: Layer *onlyLayer = mLayers.AppendElement(); michael@0: NS_ASSERTION(onlyLayer, "auto array must have room for 1 element"); michael@0: onlyLayer->SetInitialValues(); michael@0: } michael@0: michael@0: nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource) michael@0: : mAttachmentCount(aSource.mAttachmentCount) michael@0: , mClipCount(aSource.mClipCount) michael@0: , mOriginCount(aSource.mOriginCount) michael@0: , mRepeatCount(aSource.mRepeatCount) michael@0: , mPositionCount(aSource.mPositionCount) michael@0: , mImageCount(aSource.mImageCount) michael@0: , mSizeCount(aSource.mSizeCount) michael@0: , mBlendModeCount(aSource.mBlendModeCount) michael@0: , mLayers(aSource.mLayers) // deep copy michael@0: , mBackgroundColor(aSource.mBackgroundColor) michael@0: , mBackgroundInlinePolicy(aSource.mBackgroundInlinePolicy) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleBackground); michael@0: // If the deep copy of mLayers failed, truncate the counts. michael@0: uint32_t count = mLayers.Length(); michael@0: if (count != aSource.mLayers.Length()) { michael@0: NS_WARNING("truncating counts due to out-of-memory"); michael@0: mAttachmentCount = std::max(mAttachmentCount, count); michael@0: mClipCount = std::max(mClipCount, count); michael@0: mOriginCount = std::max(mOriginCount, count); michael@0: mRepeatCount = std::max(mRepeatCount, count); michael@0: mPositionCount = std::max(mPositionCount, count); michael@0: mImageCount = std::max(mImageCount, count); michael@0: mSizeCount = std::max(mSizeCount, count); michael@0: mBlendModeCount = std::max(mSizeCount, count); michael@0: } michael@0: } michael@0: michael@0: nsStyleBackground::~nsStyleBackground() michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleBackground); michael@0: } michael@0: michael@0: void michael@0: nsStyleBackground::Destroy(nsPresContext* aContext) michael@0: { michael@0: // Untrack all the images stored in our layers michael@0: for (uint32_t i = 0; i < mImageCount; ++i) michael@0: mLayers[i].UntrackImages(aContext); michael@0: michael@0: this->~nsStyleBackground(); michael@0: aContext->FreeToShell(sizeof(nsStyleBackground), this); michael@0: } michael@0: michael@0: nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const michael@0: { michael@0: const nsStyleBackground* moreLayers = michael@0: mImageCount > aOther.mImageCount ? this : &aOther; michael@0: const nsStyleBackground* lessLayers = michael@0: mImageCount > aOther.mImageCount ? &aOther : this; michael@0: michael@0: bool hasVisualDifference = false; michael@0: michael@0: NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, moreLayers) { michael@0: if (i < lessLayers->mImageCount) { michael@0: if (moreLayers->mLayers[i] != lessLayers->mLayers[i]) { michael@0: if ((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) || michael@0: (lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)) michael@0: return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL); michael@0: hasVisualDifference = true; michael@0: } michael@0: } else { michael@0: if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) michael@0: return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL); michael@0: hasVisualDifference = true; michael@0: } michael@0: } michael@0: michael@0: if (hasVisualDifference || michael@0: mBackgroundColor != aOther.mBackgroundColor || michael@0: mBackgroundInlinePolicy != aOther.mBackgroundInlinePolicy) michael@0: return NS_STYLE_HINT_VISUAL; michael@0: michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: michael@0: bool nsStyleBackground::HasFixedBackground() const michael@0: { michael@0: NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, this) { michael@0: const Layer &layer = mLayers[i]; michael@0: if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED && michael@0: !layer.mImage.IsEmpty()) { michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool nsStyleBackground::IsTransparent() const michael@0: { michael@0: return BottomLayer().mImage.IsEmpty() && michael@0: mImageCount == 1 && michael@0: NS_GET_A(mBackgroundColor) == 0; michael@0: } michael@0: michael@0: void michael@0: nsStyleBackground::Position::SetInitialValues() michael@0: { michael@0: // Initial value is "0% 0%" michael@0: mXPosition.mPercent = 0.0f; michael@0: mXPosition.mLength = 0; michael@0: mXPosition.mHasPercent = true; michael@0: mYPosition.mPercent = 0.0f; michael@0: mYPosition.mLength = 0; michael@0: mYPosition.mHasPercent = true; michael@0: } michael@0: michael@0: bool michael@0: nsStyleBackground::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImage) const michael@0: { michael@0: NS_ABORT_IF_FALSE(aImage.GetType() != eStyleImageType_Null, michael@0: "caller should have handled this"); michael@0: michael@0: // If either dimension contains a non-zero percentage, rendering for that michael@0: // dimension straightforwardly depends on frame size. michael@0: if ((mWidthType == eLengthPercentage && mWidth.mPercent != 0.0f) || michael@0: (mHeightType == eLengthPercentage && mHeight.mPercent != 0.0f)) { michael@0: return true; michael@0: } michael@0: michael@0: // So too for contain and cover. michael@0: if (mWidthType == eContain || mWidthType == eCover) { michael@0: return true; michael@0: } michael@0: michael@0: // If both dimensions are fixed lengths, there's no dependency. michael@0: if (mWidthType == eLengthPercentage && mHeightType == eLengthPercentage) { michael@0: return false; michael@0: } michael@0: michael@0: NS_ABORT_IF_FALSE((mWidthType == eLengthPercentage && mHeightType == eAuto) || michael@0: (mWidthType == eAuto && mHeightType == eLengthPercentage) || michael@0: (mWidthType == eAuto && mHeightType == eAuto), michael@0: "logic error"); michael@0: michael@0: nsStyleImageType type = aImage.GetType(); michael@0: michael@0: // Gradient rendering depends on frame size when auto is involved because michael@0: // gradients have no intrinsic ratio or dimensions, and therefore the relevant michael@0: // dimension is "treat[ed] as 100%". michael@0: if (type == eStyleImageType_Gradient) { michael@0: return true; michael@0: } michael@0: michael@0: // XXX Element rendering for auto or fixed length doesn't depend on frame size michael@0: // according to the spec. However, we don't implement the spec yet, so michael@0: // for now we bail and say element() plus auto affects ultimate size. michael@0: if (type == eStyleImageType_Element) { michael@0: return true; michael@0: } michael@0: michael@0: if (type == eStyleImageType_Image) { michael@0: nsCOMPtr imgContainer; michael@0: aImage.GetImageData()->GetImage(getter_AddRefs(imgContainer)); michael@0: if (imgContainer) { michael@0: nsIntSize imageSize; michael@0: nsSize imageRatio; michael@0: bool hasWidth, hasHeight; michael@0: nsLayoutUtils::ComputeSizeForDrawing(imgContainer, imageSize, imageRatio, michael@0: hasWidth, hasHeight); michael@0: michael@0: // If the image has a fixed width and height, rendering never depends on michael@0: // the frame size. michael@0: if (hasWidth && hasHeight) { michael@0: return false; michael@0: } michael@0: michael@0: // If the image has an intrinsic ratio, rendering will depend on frame michael@0: // size when background-size is all auto. michael@0: if (imageRatio != nsSize(0, 0)) { michael@0: return mWidthType == mHeightType; michael@0: } michael@0: michael@0: // Otherwise, rendering depends on frame size when the image dimensions michael@0: // and background-size don't complement each other. michael@0: return !(hasWidth && mHeightType == eLengthPercentage) && michael@0: !(hasHeight && mWidthType == eLengthPercentage); michael@0: } michael@0: } else { michael@0: NS_NOTREACHED("missed an enum value"); michael@0: } michael@0: michael@0: // Passed the gauntlet: no dependency. michael@0: return false; michael@0: } michael@0: michael@0: void michael@0: nsStyleBackground::Size::SetInitialValues() michael@0: { michael@0: mWidthType = mHeightType = eAuto; michael@0: } michael@0: michael@0: bool michael@0: nsStyleBackground::Size::operator==(const Size& aOther) const michael@0: { michael@0: NS_ABORT_IF_FALSE(mWidthType < eDimensionType_COUNT, michael@0: "bad mWidthType for this"); michael@0: NS_ABORT_IF_FALSE(mHeightType < eDimensionType_COUNT, michael@0: "bad mHeightType for this"); michael@0: NS_ABORT_IF_FALSE(aOther.mWidthType < eDimensionType_COUNT, michael@0: "bad mWidthType for aOther"); michael@0: NS_ABORT_IF_FALSE(aOther.mHeightType < eDimensionType_COUNT, michael@0: "bad mHeightType for aOther"); michael@0: michael@0: return mWidthType == aOther.mWidthType && michael@0: mHeightType == aOther.mHeightType && michael@0: (mWidthType != eLengthPercentage || mWidth == aOther.mWidth) && michael@0: (mHeightType != eLengthPercentage || mHeight == aOther.mHeight); michael@0: } michael@0: michael@0: void michael@0: nsStyleBackground::Repeat::SetInitialValues() michael@0: { michael@0: mXRepeat = NS_STYLE_BG_REPEAT_REPEAT; michael@0: mYRepeat = NS_STYLE_BG_REPEAT_REPEAT; michael@0: } michael@0: michael@0: nsStyleBackground::Layer::Layer() michael@0: { michael@0: } michael@0: michael@0: nsStyleBackground::Layer::~Layer() michael@0: { michael@0: } michael@0: michael@0: void michael@0: nsStyleBackground::Layer::SetInitialValues() michael@0: { michael@0: mAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL; michael@0: mClip = NS_STYLE_BG_CLIP_BORDER; michael@0: mOrigin = NS_STYLE_BG_ORIGIN_PADDING; michael@0: mRepeat.SetInitialValues(); michael@0: mBlendMode = NS_STYLE_BLEND_NORMAL; michael@0: mPosition.SetInitialValues(); michael@0: mSize.SetInitialValues(); michael@0: mImage.SetNull(); michael@0: } michael@0: michael@0: bool michael@0: nsStyleBackground::Layer::RenderingMightDependOnPositioningAreaSizeChange() const michael@0: { michael@0: // Do we even have an image? michael@0: if (mImage.IsEmpty()) { michael@0: return false; michael@0: } michael@0: michael@0: return mPosition.DependsOnPositioningAreaSize() || michael@0: mSize.DependsOnPositioningAreaSize(mImage); michael@0: } michael@0: michael@0: bool michael@0: nsStyleBackground::Layer::operator==(const Layer& aOther) const michael@0: { michael@0: return mAttachment == aOther.mAttachment && michael@0: mClip == aOther.mClip && michael@0: mOrigin == aOther.mOrigin && michael@0: mRepeat == aOther.mRepeat && michael@0: mBlendMode == aOther.mBlendMode && michael@0: mPosition == aOther.mPosition && michael@0: mSize == aOther.mSize && michael@0: mImage == aOther.mImage; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleDisplay michael@0: // michael@0: void nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType) michael@0: { michael@0: switch (aTimingFunctionType) { michael@0: case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START: michael@0: mType = StepStart; michael@0: mSteps = 1; michael@0: return; michael@0: case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END: michael@0: mType = StepEnd; michael@0: mSteps = 1; michael@0: return; michael@0: default: michael@0: mType = Function; michael@0: break; michael@0: } michael@0: michael@0: static_assert(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE == 0 && michael@0: NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR == 1 && michael@0: NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN == 2 && michael@0: NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT == 3 && michael@0: NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT == 4, michael@0: "transition timing function constants not as expected"); michael@0: michael@0: static const float timingFunctionValues[5][4] = { michael@0: { 0.25f, 0.10f, 0.25f, 1.00f }, // ease michael@0: { 0.00f, 0.00f, 1.00f, 1.00f }, // linear michael@0: { 0.42f, 0.00f, 1.00f, 1.00f }, // ease-in michael@0: { 0.00f, 0.00f, 0.58f, 1.00f }, // ease-out michael@0: { 0.42f, 0.00f, 0.58f, 1.00f } // ease-in-out michael@0: }; michael@0: michael@0: NS_ABORT_IF_FALSE(0 <= aTimingFunctionType && aTimingFunctionType < 5, michael@0: "keyword out of range"); michael@0: mFunc.mX1 = timingFunctionValues[aTimingFunctionType][0]; michael@0: mFunc.mY1 = timingFunctionValues[aTimingFunctionType][1]; michael@0: mFunc.mX2 = timingFunctionValues[aTimingFunctionType][2]; michael@0: mFunc.mY2 = timingFunctionValues[aTimingFunctionType][3]; michael@0: } michael@0: michael@0: nsTransition::nsTransition(const nsTransition& aCopy) michael@0: : mTimingFunction(aCopy.mTimingFunction) michael@0: , mDuration(aCopy.mDuration) michael@0: , mDelay(aCopy.mDelay) michael@0: , mProperty(aCopy.mProperty) michael@0: , mUnknownProperty(aCopy.mUnknownProperty) michael@0: { michael@0: } michael@0: michael@0: void nsTransition::SetInitialValues() michael@0: { michael@0: mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE); michael@0: mDuration = 0.0; michael@0: mDelay = 0.0; michael@0: mProperty = eCSSPropertyExtra_all_properties; michael@0: } michael@0: michael@0: void nsTransition::SetUnknownProperty(const nsAString& aUnknownProperty) michael@0: { michael@0: NS_ASSERTION(nsCSSProps::LookupProperty(aUnknownProperty, michael@0: nsCSSProps::eEnabledForAllContent) == michael@0: eCSSProperty_UNKNOWN, michael@0: "should be unknown property"); michael@0: mProperty = eCSSProperty_UNKNOWN; michael@0: mUnknownProperty = do_GetAtom(aUnknownProperty); michael@0: } michael@0: michael@0: nsAnimation::nsAnimation(const nsAnimation& aCopy) michael@0: : mTimingFunction(aCopy.mTimingFunction) michael@0: , mDuration(aCopy.mDuration) michael@0: , mDelay(aCopy.mDelay) michael@0: , mName(aCopy.mName) michael@0: , mDirection(aCopy.mDirection) michael@0: , mFillMode(aCopy.mFillMode) michael@0: , mPlayState(aCopy.mPlayState) michael@0: , mIterationCount(aCopy.mIterationCount) michael@0: { michael@0: } michael@0: michael@0: void michael@0: nsAnimation::SetInitialValues() michael@0: { michael@0: mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE); michael@0: mDuration = 0.0; michael@0: mDelay = 0.0; michael@0: mName = EmptyString(); michael@0: mDirection = NS_STYLE_ANIMATION_DIRECTION_NORMAL; michael@0: mFillMode = NS_STYLE_ANIMATION_FILL_MODE_NONE; michael@0: mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING; michael@0: mIterationCount = 1.0f; michael@0: } michael@0: michael@0: nsStyleDisplay::nsStyleDisplay() michael@0: : mWillChangeBitField(0) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleDisplay); michael@0: mAppearance = NS_THEME_NONE; michael@0: mDisplay = NS_STYLE_DISPLAY_INLINE; michael@0: mOriginalDisplay = mDisplay; michael@0: mPosition = NS_STYLE_POSITION_STATIC; michael@0: mFloats = NS_STYLE_FLOAT_NONE; michael@0: mOriginalFloats = mFloats; michael@0: mBreakType = NS_STYLE_CLEAR_NONE; michael@0: mBreakInside = NS_STYLE_PAGE_BREAK_AUTO; michael@0: mBreakBefore = false; michael@0: mBreakAfter = false; michael@0: mOverflowX = NS_STYLE_OVERFLOW_VISIBLE; michael@0: mOverflowY = NS_STYLE_OVERFLOW_VISIBLE; michael@0: mOverflowClipBox = NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX; michael@0: mResize = NS_STYLE_RESIZE_NONE; michael@0: mClipFlags = NS_STYLE_CLIP_AUTO; michael@0: mClip.SetRect(0,0,0,0); michael@0: mOpacity = 1.0f; michael@0: mSpecifiedTransform = nullptr; michael@0: mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin michael@0: mTransformOrigin[1].SetPercentValue(0.5f); michael@0: mTransformOrigin[2].SetCoordValue(0); michael@0: mPerspectiveOrigin[0].SetPercentValue(0.5f); michael@0: mPerspectiveOrigin[1].SetPercentValue(0.5f); michael@0: mChildPerspective.SetNoneValue(); michael@0: mBackfaceVisibility = NS_STYLE_BACKFACE_VISIBILITY_VISIBLE; michael@0: mTransformStyle = NS_STYLE_TRANSFORM_STYLE_FLAT; michael@0: mOrient = NS_STYLE_ORIENT_AUTO; michael@0: mMixBlendMode = NS_STYLE_BLEND_NORMAL; michael@0: mTouchAction = NS_STYLE_TOUCH_ACTION_AUTO; michael@0: michael@0: mTransitions.AppendElement(); michael@0: NS_ABORT_IF_FALSE(mTransitions.Length() == 1, michael@0: "appending within auto buffer should never fail"); michael@0: mTransitions[0].SetInitialValues(); michael@0: mTransitionTimingFunctionCount = 1; michael@0: mTransitionDurationCount = 1; michael@0: mTransitionDelayCount = 1; michael@0: mTransitionPropertyCount = 1; michael@0: michael@0: mAnimations.AppendElement(); michael@0: NS_ABORT_IF_FALSE(mAnimations.Length() == 1, michael@0: "appending within auto buffer should never fail"); michael@0: mAnimations[0].SetInitialValues(); michael@0: mAnimationTimingFunctionCount = 1; michael@0: mAnimationDurationCount = 1; michael@0: mAnimationDelayCount = 1; michael@0: mAnimationNameCount = 1; michael@0: mAnimationDirectionCount = 1; michael@0: mAnimationFillModeCount = 1; michael@0: mAnimationPlayStateCount = 1; michael@0: mAnimationIterationCountCount = 1; michael@0: } michael@0: michael@0: nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource) michael@0: : mBinding(aSource.mBinding) michael@0: , mClip(aSource.mClip) michael@0: , mOpacity(aSource.mOpacity) michael@0: , mDisplay(aSource.mDisplay) michael@0: , mOriginalDisplay(aSource.mOriginalDisplay) michael@0: , mAppearance(aSource.mAppearance) michael@0: , mPosition(aSource.mPosition) michael@0: , mFloats(aSource.mFloats) michael@0: , mOriginalFloats(aSource.mOriginalFloats) michael@0: , mBreakType(aSource.mBreakType) michael@0: , mBreakInside(aSource.mBreakInside) michael@0: , mBreakBefore(aSource.mBreakBefore) michael@0: , mBreakAfter(aSource.mBreakAfter) michael@0: , mOverflowX(aSource.mOverflowX) michael@0: , mOverflowY(aSource.mOverflowY) michael@0: , mOverflowClipBox(aSource.mOverflowClipBox) michael@0: , mResize(aSource.mResize) michael@0: , mClipFlags(aSource.mClipFlags) michael@0: , mOrient(aSource.mOrient) michael@0: , mMixBlendMode(aSource.mMixBlendMode) michael@0: , mWillChangeBitField(aSource.mWillChangeBitField) michael@0: , mWillChange(aSource.mWillChange) michael@0: , mTouchAction(aSource.mTouchAction) michael@0: , mBackfaceVisibility(aSource.mBackfaceVisibility) michael@0: , mTransformStyle(aSource.mTransformStyle) michael@0: , mSpecifiedTransform(aSource.mSpecifiedTransform) michael@0: , mChildPerspective(aSource.mChildPerspective) michael@0: , mTransitions(aSource.mTransitions) michael@0: , mTransitionTimingFunctionCount(aSource.mTransitionTimingFunctionCount) michael@0: , mTransitionDurationCount(aSource.mTransitionDurationCount) michael@0: , mTransitionDelayCount(aSource.mTransitionDelayCount) michael@0: , mTransitionPropertyCount(aSource.mTransitionPropertyCount) michael@0: , mAnimations(aSource.mAnimations) michael@0: , mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount) michael@0: , mAnimationDurationCount(aSource.mAnimationDurationCount) michael@0: , mAnimationDelayCount(aSource.mAnimationDelayCount) michael@0: , mAnimationNameCount(aSource.mAnimationNameCount) michael@0: , mAnimationDirectionCount(aSource.mAnimationDirectionCount) michael@0: , mAnimationFillModeCount(aSource.mAnimationFillModeCount) michael@0: , mAnimationPlayStateCount(aSource.mAnimationPlayStateCount) michael@0: , mAnimationIterationCountCount(aSource.mAnimationIterationCountCount) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleDisplay); michael@0: michael@0: /* Copy over transform origin. */ michael@0: mTransformOrigin[0] = aSource.mTransformOrigin[0]; michael@0: mTransformOrigin[1] = aSource.mTransformOrigin[1]; michael@0: mTransformOrigin[2] = aSource.mTransformOrigin[2]; michael@0: mPerspectiveOrigin[0] = aSource.mPerspectiveOrigin[0]; michael@0: mPerspectiveOrigin[1] = aSource.mPerspectiveOrigin[1]; michael@0: } michael@0: michael@0: nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const michael@0: { michael@0: nsChangeHint hint = nsChangeHint(0); michael@0: michael@0: if (!EqualURIs(mBinding, aOther.mBinding) michael@0: || mPosition != aOther.mPosition michael@0: || mDisplay != aOther.mDisplay michael@0: || (mFloats == NS_STYLE_FLOAT_NONE) != (aOther.mFloats == NS_STYLE_FLOAT_NONE) michael@0: || mOverflowX != aOther.mOverflowX michael@0: || mOverflowY != aOther.mOverflowY michael@0: || mResize != aOther.mResize) michael@0: NS_UpdateHint(hint, nsChangeHint_ReconstructFrame); michael@0: michael@0: if ((mAppearance == NS_THEME_TEXTFIELD && michael@0: aOther.mAppearance != NS_THEME_TEXTFIELD) || michael@0: (mAppearance != NS_THEME_TEXTFIELD && michael@0: aOther.mAppearance == NS_THEME_TEXTFIELD)) { michael@0: // This is for where we allow authors to specify a michael@0: // |-moz-appearance:textfield| to get a control without a spinner. (The michael@0: // spinner is present for |-moz-appearance:number-input| but also other michael@0: // values such as 'none'.) We need to reframe since we want to use michael@0: // nsTextControlFrame instead of nsNumberControlFrame if the author michael@0: // specifies 'textfield'. michael@0: return nsChangeHint_ReconstructFrame; michael@0: } michael@0: michael@0: if (mFloats != aOther.mFloats) { michael@0: // Changing which side we float on doesn't affect descendants directly michael@0: NS_UpdateHint(hint, michael@0: NS_SubtractHint(nsChangeHint_AllReflowHints, michael@0: NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics, michael@0: nsChangeHint_NeedDirtyReflow))); michael@0: } michael@0: michael@0: // XXX the following is conservative, for now: changing float breaking shouldn't michael@0: // necessarily require a repaint, reflow should suffice. michael@0: if (mBreakType != aOther.mBreakType michael@0: || mBreakInside != aOther.mBreakInside michael@0: || mBreakBefore != aOther.mBreakBefore michael@0: || mBreakAfter != aOther.mBreakAfter michael@0: || mAppearance != aOther.mAppearance michael@0: || mOrient != aOther.mOrient michael@0: || mOverflowClipBox != aOther.mOverflowClipBox michael@0: || mClipFlags != aOther.mClipFlags || !mClip.IsEqualInterior(aOther.mClip)) michael@0: NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints, michael@0: nsChangeHint_RepaintFrame)); michael@0: michael@0: if (mOpacity != aOther.mOpacity) { michael@0: // If we're going from the optimized >=0.99 opacity value to 1.0 or back, then michael@0: // repaint the frame because DLBI will not catch the invalidation. Otherwise, michael@0: // just update the opacity layer. michael@0: if ((mOpacity >= 0.99f && mOpacity < 1.0f && aOther.mOpacity == 1.0f) || michael@0: (aOther.mOpacity >= 0.99f && aOther.mOpacity < 1.0f && mOpacity == 1.0f)) { michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: } else { michael@0: NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer); michael@0: } michael@0: } michael@0: michael@0: /* If we've added or removed the transform property, we need to reconstruct the frame to add michael@0: * or remove the view object, and also to handle abs-pos and fixed-pos containers. michael@0: */ michael@0: if (HasTransformStyle() != aOther.HasTransformStyle()) { michael@0: // We do not need to apply nsChangeHint_UpdateTransformLayer since michael@0: // nsChangeHint_RepaintFrame will forcibly invalidate the frame area and michael@0: // ensure layers are rebuilt (or removed). michael@0: NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AddOrRemoveTransform, michael@0: NS_CombineHint(nsChangeHint_UpdateOverflow, michael@0: nsChangeHint_RepaintFrame))); michael@0: } michael@0: else if (HasTransformStyle()) { michael@0: /* Otherwise, if we've kept the property lying around and we already had a michael@0: * transform, we need to see whether or not we've changed the transform. michael@0: * If so, we need to recompute its overflow rect (which probably changed michael@0: * if the transform changed) and to redraw within the bounds of that new michael@0: * overflow rect. michael@0: */ michael@0: if (!mSpecifiedTransform != !aOther.mSpecifiedTransform || michael@0: (mSpecifiedTransform && michael@0: *mSpecifiedTransform != *aOther.mSpecifiedTransform)) { michael@0: NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_UpdatePostTransformOverflow, michael@0: nsChangeHint_UpdateTransformLayer)); michael@0: } michael@0: michael@0: const nsChangeHint kUpdateOverflowAndRepaintHint = michael@0: NS_CombineHint(nsChangeHint_UpdateOverflow, nsChangeHint_RepaintFrame); michael@0: for (uint8_t index = 0; index < 3; ++index) michael@0: if (mTransformOrigin[index] != aOther.mTransformOrigin[index]) { michael@0: NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint); michael@0: break; michael@0: } michael@0: michael@0: for (uint8_t index = 0; index < 2; ++index) michael@0: if (mPerspectiveOrigin[index] != aOther.mPerspectiveOrigin[index]) { michael@0: NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint); michael@0: break; michael@0: } michael@0: michael@0: if (mChildPerspective != aOther.mChildPerspective || michael@0: mTransformStyle != aOther.mTransformStyle) michael@0: NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint); michael@0: michael@0: if (mBackfaceVisibility != aOther.mBackfaceVisibility) michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: } michael@0: michael@0: uint8_t willChangeBitsChanged = michael@0: mWillChangeBitField ^ aOther.mWillChangeBitField; michael@0: if (willChangeBitsChanged & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) { michael@0: NS_UpdateHint(hint, nsChangeHint_RepaintFrame); michael@0: } michael@0: if (willChangeBitsChanged & ~uint8_t(NS_STYLE_WILL_CHANGE_STACKING_CONTEXT)) { michael@0: // FIXME (Bug 974125): Don't reconstruct the frame michael@0: NS_UpdateHint(hint, nsChangeHint_ReconstructFrame); michael@0: } michael@0: michael@0: // Note: Our current behavior for handling changes to the michael@0: // transition-duration, transition-delay, and transition-timing-function michael@0: // properties is to do nothing. In other words, the transition michael@0: // property that matters is what it is when the transition begins, and michael@0: // we don't stop a transition later because the transition property michael@0: // changed. michael@0: // We do handle changes to transition-property, but we don't need to michael@0: // bother with anything here, since the transition manager is notified michael@0: // of any style context change anyway. michael@0: michael@0: // Note: Likewise, for animation-*, the animation manager gets michael@0: // notified about every new style context constructed, and it uses michael@0: // that opportunity to handle dynamic changes appropriately. michael@0: michael@0: return hint; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleVisibility michael@0: // michael@0: michael@0: nsStyleVisibility::nsStyleVisibility(nsPresContext* aPresContext) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleVisibility); michael@0: uint32_t bidiOptions = aPresContext->GetBidi(); michael@0: if (GET_BIDI_OPTION_DIRECTION(bidiOptions) == IBMBIDI_TEXTDIRECTION_RTL) michael@0: mDirection = NS_STYLE_DIRECTION_RTL; michael@0: else michael@0: mDirection = NS_STYLE_DIRECTION_LTR; michael@0: michael@0: mVisible = NS_STYLE_VISIBILITY_VISIBLE; michael@0: mPointerEvents = NS_STYLE_POINTER_EVENTS_AUTO; michael@0: mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB; michael@0: } michael@0: michael@0: nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleVisibility); michael@0: mImageOrientation = aSource.mImageOrientation; michael@0: mDirection = aSource.mDirection; michael@0: mVisible = aSource.mVisible; michael@0: mPointerEvents = aSource.mPointerEvents; michael@0: mWritingMode = aSource.mWritingMode; michael@0: } michael@0: michael@0: nsChangeHint nsStyleVisibility::CalcDifference(const nsStyleVisibility& aOther) const michael@0: { michael@0: nsChangeHint hint = nsChangeHint(0); michael@0: michael@0: if (mDirection != aOther.mDirection || mWritingMode != aOther.mWritingMode) { michael@0: NS_UpdateHint(hint, nsChangeHint_ReconstructFrame); michael@0: } else { michael@0: if ((mImageOrientation != aOther.mImageOrientation)) { michael@0: NS_UpdateHint(hint, nsChangeHint_AllReflowHints); michael@0: } michael@0: if (mVisible != aOther.mVisible) { michael@0: if ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) || michael@0: (NS_STYLE_VISIBILITY_COLLAPSE == aOther.mVisible)) { michael@0: NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW); michael@0: } else { michael@0: NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL); michael@0: } michael@0: } michael@0: if (mPointerEvents != aOther.mPointerEvents) { michael@0: // nsSVGPathGeometryFrame's mRect depends on stroke _and_ on the value michael@0: // of pointer-events. See nsSVGPathGeometryFrame::ReflowSVG's use of michael@0: // GetHitTestFlags. (Only a reflow, no visual change.) michael@0: NS_UpdateHint(hint, nsChangeHint_NeedReflow); michael@0: NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085 michael@0: } michael@0: } michael@0: return hint; michael@0: } michael@0: michael@0: nsStyleContentData::~nsStyleContentData() michael@0: { michael@0: NS_ABORT_IF_FALSE(!mImageTracked, michael@0: "nsStyleContentData being destroyed while still tracking image!"); michael@0: if (mType == eStyleContentType_Image) { michael@0: NS_IF_RELEASE(mContent.mImage); michael@0: } else if (mType == eStyleContentType_Counter || michael@0: mType == eStyleContentType_Counters) { michael@0: mContent.mCounters->Release(); michael@0: } else if (mContent.mString) { michael@0: NS_Free(mContent.mString); michael@0: } michael@0: } michael@0: michael@0: nsStyleContentData& nsStyleContentData::operator=(const nsStyleContentData& aOther) michael@0: { michael@0: if (this == &aOther) michael@0: return *this; michael@0: this->~nsStyleContentData(); michael@0: new (this) nsStyleContentData(); michael@0: michael@0: mType = aOther.mType; michael@0: if (mType == eStyleContentType_Image) { michael@0: mContent.mImage = aOther.mContent.mImage; michael@0: NS_IF_ADDREF(mContent.mImage); michael@0: } else if (mType == eStyleContentType_Counter || michael@0: mType == eStyleContentType_Counters) { michael@0: mContent.mCounters = aOther.mContent.mCounters; michael@0: mContent.mCounters->AddRef(); michael@0: } else if (aOther.mContent.mString) { michael@0: mContent.mString = NS_strdup(aOther.mContent.mString); michael@0: } else { michael@0: mContent.mString = nullptr; michael@0: } michael@0: return *this; michael@0: } michael@0: michael@0: bool nsStyleContentData::operator==(const nsStyleContentData& aOther) const michael@0: { michael@0: if (mType != aOther.mType) michael@0: return false; michael@0: if (mType == eStyleContentType_Image) { michael@0: if (!mContent.mImage || !aOther.mContent.mImage) michael@0: return mContent.mImage == aOther.mContent.mImage; michael@0: bool eq; michael@0: nsCOMPtr thisURI, otherURI; michael@0: mContent.mImage->GetURI(getter_AddRefs(thisURI)); michael@0: aOther.mContent.mImage->GetURI(getter_AddRefs(otherURI)); michael@0: return thisURI == otherURI || // handles null==null michael@0: (thisURI && otherURI && michael@0: NS_SUCCEEDED(thisURI->Equals(otherURI, &eq)) && michael@0: eq); michael@0: } michael@0: if (mType == eStyleContentType_Counter || michael@0: mType == eStyleContentType_Counters) michael@0: return *mContent.mCounters == *aOther.mContent.mCounters; michael@0: return safe_strcmp(mContent.mString, aOther.mContent.mString) == 0; michael@0: } michael@0: michael@0: void michael@0: nsStyleContentData::TrackImage(nsPresContext* aContext) michael@0: { michael@0: // Sanity michael@0: NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!"); michael@0: NS_ABORT_IF_FALSE(mType == eStyleContentType_Image, michael@0: "Trying to do image tracking on non-image!"); michael@0: NS_ABORT_IF_FALSE(mContent.mImage, michael@0: "Can't track image when there isn't one!"); michael@0: michael@0: // Register the image with the document michael@0: nsIDocument* doc = aContext->Document(); michael@0: if (doc) michael@0: doc->AddImage(mContent.mImage); michael@0: michael@0: // Mark state michael@0: #ifdef DEBUG michael@0: mImageTracked = true; michael@0: #endif michael@0: } michael@0: michael@0: void michael@0: nsStyleContentData::UntrackImage(nsPresContext* aContext) michael@0: { michael@0: // Sanity michael@0: NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!"); michael@0: NS_ABORT_IF_FALSE(mType == eStyleContentType_Image, michael@0: "Trying to do image tracking on non-image!"); michael@0: NS_ABORT_IF_FALSE(mContent.mImage, michael@0: "Can't untrack image when there isn't one!"); michael@0: michael@0: // Unregister the image with the document michael@0: nsIDocument* doc = aContext->Document(); michael@0: if (doc) michael@0: doc->RemoveImage(mContent.mImage, nsIDocument::REQUEST_DISCARD); michael@0: michael@0: // Mark state michael@0: #ifdef DEBUG michael@0: mImageTracked = false; michael@0: #endif michael@0: } michael@0: michael@0: michael@0: //----------------------- michael@0: // nsStyleContent michael@0: // michael@0: michael@0: nsStyleContent::nsStyleContent(void) michael@0: : mMarkerOffset(), michael@0: mContents(nullptr), michael@0: mIncrements(nullptr), michael@0: mResets(nullptr), michael@0: mContentCount(0), michael@0: mIncrementCount(0), michael@0: mResetCount(0) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleContent); michael@0: mMarkerOffset.SetAutoValue(); michael@0: } michael@0: michael@0: nsStyleContent::~nsStyleContent(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleContent); michael@0: DELETE_ARRAY_IF(mContents); michael@0: DELETE_ARRAY_IF(mIncrements); michael@0: DELETE_ARRAY_IF(mResets); michael@0: } michael@0: michael@0: void michael@0: nsStyleContent::Destroy(nsPresContext* aContext) michael@0: { michael@0: // Unregister any images we might have with the document. michael@0: for (uint32_t i = 0; i < mContentCount; ++i) { michael@0: if ((mContents[i].mType == eStyleContentType_Image) && michael@0: mContents[i].mContent.mImage) { michael@0: mContents[i].UntrackImage(aContext); michael@0: } michael@0: } michael@0: michael@0: this->~nsStyleContent(); michael@0: aContext->FreeToShell(sizeof(nsStyleContent), this); michael@0: } michael@0: michael@0: nsStyleContent::nsStyleContent(const nsStyleContent& aSource) michael@0: :mMarkerOffset(), michael@0: mContents(nullptr), michael@0: mIncrements(nullptr), michael@0: mResets(nullptr), michael@0: mContentCount(0), michael@0: mIncrementCount(0), michael@0: mResetCount(0) michael@0: michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleContent); michael@0: mMarkerOffset = aSource.mMarkerOffset; michael@0: michael@0: uint32_t index; michael@0: if (NS_SUCCEEDED(AllocateContents(aSource.ContentCount()))) { michael@0: for (index = 0; index < mContentCount; index++) { michael@0: ContentAt(index) = aSource.ContentAt(index); michael@0: } michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(AllocateCounterIncrements(aSource.CounterIncrementCount()))) { michael@0: for (index = 0; index < mIncrementCount; index++) { michael@0: const nsStyleCounterData *data = aSource.GetCounterIncrementAt(index); michael@0: mIncrements[index].mCounter = data->mCounter; michael@0: mIncrements[index].mValue = data->mValue; michael@0: } michael@0: } michael@0: michael@0: if (NS_SUCCEEDED(AllocateCounterResets(aSource.CounterResetCount()))) { michael@0: for (index = 0; index < mResetCount; index++) { michael@0: const nsStyleCounterData *data = aSource.GetCounterResetAt(index); michael@0: mResets[index].mCounter = data->mCounter; michael@0: mResets[index].mValue = data->mValue; michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsChangeHint nsStyleContent::CalcDifference(const nsStyleContent& aOther) const michael@0: { michael@0: // In ReResolveStyleContext we assume that if there's no existing michael@0: // ::before or ::after and we don't have to restyle children of the michael@0: // node then we can't end up with a ::before or ::after due to the michael@0: // restyle of the node itself. That's not quite true, but the only michael@0: // exception to the above is when the 'content' property of the node michael@0: // changes and the pseudo-element inherits the changed value. Since michael@0: // the code here triggers a frame change on the node in that case, michael@0: // the optimization in ReResolveStyleContext is ok. But if we ever michael@0: // change this code to not reconstruct frames on changes to the michael@0: // 'content' property, then we will need to revisit the optimization michael@0: // in ReResolveStyleContext. michael@0: michael@0: if (mContentCount != aOther.mContentCount || michael@0: mIncrementCount != aOther.mIncrementCount || michael@0: mResetCount != aOther.mResetCount) { michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0: michael@0: uint32_t ix = mContentCount; michael@0: while (0 < ix--) { michael@0: if (mContents[ix] != aOther.mContents[ix]) { michael@0: // Unfortunately we need to reframe here; a simple reflow michael@0: // will not pick up different text or different image URLs, michael@0: // since we set all that up in the CSSFrameConstructor michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0: } michael@0: ix = mIncrementCount; michael@0: while (0 < ix--) { michael@0: if ((mIncrements[ix].mValue != aOther.mIncrements[ix].mValue) || michael@0: (mIncrements[ix].mCounter != aOther.mIncrements[ix].mCounter)) { michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0: } michael@0: ix = mResetCount; michael@0: while (0 < ix--) { michael@0: if ((mResets[ix].mValue != aOther.mResets[ix].mValue) || michael@0: (mResets[ix].mCounter != aOther.mResets[ix].mCounter)) { michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0: } michael@0: if (mMarkerOffset != aOther.mMarkerOffset) { michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: michael@0: nsresult nsStyleContent::AllocateContents(uint32_t aCount) michael@0: { michael@0: // We need to run the destructors of the elements of mContents, so we michael@0: // delete and reallocate even if aCount == mContentCount. (If michael@0: // nsStyleContentData had its members private and managed their michael@0: // ownership on setting, we wouldn't need this, but that seems michael@0: // unnecessary at this point.) michael@0: DELETE_ARRAY_IF(mContents); michael@0: if (aCount) { michael@0: mContents = new nsStyleContentData[aCount]; michael@0: if (! mContents) { michael@0: mContentCount = 0; michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: } michael@0: } michael@0: mContentCount = aCount; michael@0: return NS_OK; michael@0: } michael@0: michael@0: // --------------------- michael@0: // nsStyleQuotes michael@0: // michael@0: michael@0: nsStyleQuotes::nsStyleQuotes(void) michael@0: : mQuotesCount(0), michael@0: mQuotes(nullptr) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleQuotes); michael@0: SetInitial(); michael@0: } michael@0: michael@0: nsStyleQuotes::~nsStyleQuotes(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleQuotes); michael@0: DELETE_ARRAY_IF(mQuotes); michael@0: } michael@0: michael@0: nsStyleQuotes::nsStyleQuotes(const nsStyleQuotes& aSource) michael@0: : mQuotesCount(0), michael@0: mQuotes(nullptr) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleQuotes); michael@0: CopyFrom(aSource); michael@0: } michael@0: michael@0: void michael@0: nsStyleQuotes::SetInitial() michael@0: { michael@0: // The initial value for quotes is the en-US typographic convention: michael@0: // outermost are LEFT and RIGHT DOUBLE QUOTATION MARK, alternating michael@0: // with LEFT and RIGHT SINGLE QUOTATION MARK. michael@0: static const char16_t initialQuotes[8] = { michael@0: 0x201C, 0, 0x201D, 0, 0x2018, 0, 0x2019, 0 michael@0: }; michael@0: michael@0: if (NS_SUCCEEDED(AllocateQuotes(2))) { michael@0: SetQuotesAt(0, michael@0: nsDependentString(&initialQuotes[0], 1), michael@0: nsDependentString(&initialQuotes[2], 1)); michael@0: SetQuotesAt(1, michael@0: nsDependentString(&initialQuotes[4], 1), michael@0: nsDependentString(&initialQuotes[6], 1)); michael@0: } michael@0: } michael@0: michael@0: void michael@0: nsStyleQuotes::CopyFrom(const nsStyleQuotes& aSource) michael@0: { michael@0: if (NS_SUCCEEDED(AllocateQuotes(aSource.QuotesCount()))) { michael@0: uint32_t count = (mQuotesCount * 2); michael@0: for (uint32_t index = 0; index < count; index += 2) { michael@0: aSource.GetQuotesAt(index, mQuotes[index], mQuotes[index + 1]); michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsChangeHint nsStyleQuotes::CalcDifference(const nsStyleQuotes& aOther) const michael@0: { michael@0: // If the quotes implementation is ever going to change we might not need michael@0: // a framechange here and a reflow should be sufficient. See bug 35768. michael@0: if (mQuotesCount == aOther.mQuotesCount) { michael@0: uint32_t ix = (mQuotesCount * 2); michael@0: while (0 < ix--) { michael@0: if (mQuotes[ix] != aOther.mQuotes[ix]) { michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0: } michael@0: michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleTextReset michael@0: // michael@0: michael@0: nsStyleTextReset::nsStyleTextReset(void) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleTextReset); michael@0: mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated); michael@0: mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE; michael@0: mTextDecorationColor = NS_RGB(0,0,0); michael@0: mTextDecorationStyle = michael@0: NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND; michael@0: mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL; michael@0: } michael@0: michael@0: nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleTextReset); michael@0: *this = aSource; michael@0: } michael@0: michael@0: nsStyleTextReset::~nsStyleTextReset(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleTextReset); michael@0: } michael@0: michael@0: nsChangeHint nsStyleTextReset::CalcDifference(const nsStyleTextReset& aOther) const michael@0: { michael@0: if (mVerticalAlign == aOther.mVerticalAlign michael@0: && mUnicodeBidi == aOther.mUnicodeBidi) { michael@0: uint8_t lineStyle = GetDecorationStyle(); michael@0: uint8_t otherLineStyle = aOther.GetDecorationStyle(); michael@0: if (mTextDecorationLine != aOther.mTextDecorationLine || michael@0: lineStyle != otherLineStyle) { michael@0: // Reflow for decoration line style changes only to or from double or michael@0: // wave because that may cause overflow area changes michael@0: if (lineStyle == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE || michael@0: lineStyle == NS_STYLE_TEXT_DECORATION_STYLE_WAVY || michael@0: otherLineStyle == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE || michael@0: otherLineStyle == NS_STYLE_TEXT_DECORATION_STYLE_WAVY) { michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: // Repaint for other style decoration lines because they must be in michael@0: // default overflow rect michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: michael@0: // Repaint for decoration color changes michael@0: nscolor decColor, otherDecColor; michael@0: bool isFG, otherIsFG; michael@0: GetDecorationColor(decColor, isFG); michael@0: aOther.GetDecorationColor(otherDecColor, otherIsFG); michael@0: if (isFG != otherIsFG || (!isFG && decColor != otherDecColor)) { michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: michael@0: if (mTextOverflow != aOther.mTextOverflow) { michael@0: return NS_STYLE_HINT_VISUAL; michael@0: } michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: michael@0: // Allowed to return one of NS_STYLE_HINT_NONE, NS_STYLE_HINT_REFLOW michael@0: // or NS_STYLE_HINT_VISUAL. Currently we just return NONE or REFLOW, though. michael@0: // XXXbz can this not return a more specific hint? If that's ever michael@0: // changed, nsStyleBorder::CalcDifference will need changing too. michael@0: static nsChangeHint michael@0: CalcShadowDifference(nsCSSShadowArray* lhs, michael@0: nsCSSShadowArray* rhs) michael@0: { michael@0: if (lhs == rhs) michael@0: return NS_STYLE_HINT_NONE; michael@0: michael@0: if (!lhs || !rhs || lhs->Length() != rhs->Length()) michael@0: return NS_STYLE_HINT_REFLOW; michael@0: michael@0: for (uint32_t i = 0; i < lhs->Length(); ++i) { michael@0: if (*lhs->ShadowAt(i) != *rhs->ShadowAt(i)) michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: michael@0: // -------------------- michael@0: // nsStyleText michael@0: // michael@0: michael@0: nsStyleText::nsStyleText(void) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleText); michael@0: mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT; michael@0: mTextAlignLast = NS_STYLE_TEXT_ALIGN_AUTO; michael@0: mTextAlignTrue = false; michael@0: mTextAlignLastTrue = false; michael@0: mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE; michael@0: mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL; michael@0: mWordBreak = NS_STYLE_WORDBREAK_NORMAL; michael@0: mWordWrap = NS_STYLE_WORDWRAP_NORMAL; michael@0: mHyphens = NS_STYLE_HYPHENS_MANUAL; michael@0: mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO; michael@0: mTextOrientation = NS_STYLE_TEXT_ORIENTATION_AUTO; michael@0: mTextCombineUpright = NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE; michael@0: mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN; michael@0: michael@0: mLetterSpacing.SetNormalValue(); michael@0: mLineHeight.SetNormalValue(); michael@0: mTextIndent.SetCoordValue(0); michael@0: mWordSpacing = 0; michael@0: michael@0: mTextShadow = nullptr; michael@0: mTabSize = NS_STYLE_TABSIZE_INITIAL; michael@0: } michael@0: michael@0: nsStyleText::nsStyleText(const nsStyleText& aSource) michael@0: : mTextAlign(aSource.mTextAlign), michael@0: mTextAlignLast(aSource.mTextAlignLast), michael@0: mTextAlignTrue(false), michael@0: mTextAlignLastTrue(false), michael@0: mTextTransform(aSource.mTextTransform), michael@0: mWhiteSpace(aSource.mWhiteSpace), michael@0: mWordBreak(aSource.mWordBreak), michael@0: mWordWrap(aSource.mWordWrap), michael@0: mHyphens(aSource.mHyphens), michael@0: mTextSizeAdjust(aSource.mTextSizeAdjust), michael@0: mTextOrientation(aSource.mTextOrientation), michael@0: mTextCombineUpright(aSource.mTextCombineUpright), michael@0: mControlCharacterVisibility(aSource.mControlCharacterVisibility), michael@0: mTabSize(aSource.mTabSize), michael@0: mWordSpacing(aSource.mWordSpacing), michael@0: mLetterSpacing(aSource.mLetterSpacing), michael@0: mLineHeight(aSource.mLineHeight), michael@0: mTextIndent(aSource.mTextIndent), michael@0: mTextShadow(aSource.mTextShadow) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleText); michael@0: } michael@0: michael@0: nsStyleText::~nsStyleText(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleText); michael@0: } michael@0: michael@0: nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const michael@0: { michael@0: if (WhiteSpaceOrNewlineIsSignificant() != michael@0: aOther.WhiteSpaceOrNewlineIsSignificant()) { michael@0: // This may require construction of suppressed text frames michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: } michael@0: michael@0: if (mTextCombineUpright != aOther.mTextCombineUpright || michael@0: mControlCharacterVisibility != aOther.mControlCharacterVisibility) { michael@0: return nsChangeHint_ReconstructFrame; michael@0: } michael@0: michael@0: if ((mTextAlign != aOther.mTextAlign) || michael@0: (mTextAlignLast != aOther.mTextAlignLast) || michael@0: (mTextAlignTrue != aOther.mTextAlignTrue) || michael@0: (mTextAlignLastTrue != aOther.mTextAlignLastTrue) || michael@0: (mTextTransform != aOther.mTextTransform) || michael@0: (mWhiteSpace != aOther.mWhiteSpace) || michael@0: (mWordBreak != aOther.mWordBreak) || michael@0: (mWordWrap != aOther.mWordWrap) || michael@0: (mHyphens != aOther.mHyphens) || michael@0: (mTextSizeAdjust != aOther.mTextSizeAdjust) || michael@0: (mTextOrientation != aOther.mTextOrientation) || michael@0: (mLetterSpacing != aOther.mLetterSpacing) || michael@0: (mLineHeight != aOther.mLineHeight) || michael@0: (mTextIndent != aOther.mTextIndent) || michael@0: (mWordSpacing != aOther.mWordSpacing) || michael@0: (mTabSize != aOther.mTabSize)) michael@0: return NS_STYLE_HINT_REFLOW; michael@0: michael@0: return CalcShadowDifference(mTextShadow, aOther.mTextShadow); michael@0: } michael@0: michael@0: //----------------------- michael@0: // nsStyleUserInterface michael@0: // michael@0: michael@0: nsCursorImage::nsCursorImage() michael@0: : mHaveHotspot(false) michael@0: , mHotspotX(0.0f) michael@0: , mHotspotY(0.0f) michael@0: { michael@0: } michael@0: michael@0: nsCursorImage::nsCursorImage(const nsCursorImage& aOther) michael@0: : mHaveHotspot(aOther.mHaveHotspot) michael@0: , mHotspotX(aOther.mHotspotX) michael@0: , mHotspotY(aOther.mHotspotY) michael@0: { michael@0: SetImage(aOther.GetImage()); michael@0: } michael@0: michael@0: nsCursorImage::~nsCursorImage() michael@0: { michael@0: SetImage(nullptr); michael@0: } michael@0: michael@0: nsCursorImage& michael@0: nsCursorImage::operator=(const nsCursorImage& aOther) michael@0: { michael@0: if (this != &aOther) { michael@0: mHaveHotspot = aOther.mHaveHotspot; michael@0: mHotspotX = aOther.mHotspotX; michael@0: mHotspotY = aOther.mHotspotY; michael@0: SetImage(aOther.GetImage()); michael@0: } michael@0: michael@0: return *this; michael@0: } michael@0: michael@0: nsStyleUserInterface::nsStyleUserInterface(void) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleUserInterface); michael@0: mUserInput = NS_STYLE_USER_INPUT_AUTO; michael@0: mUserModify = NS_STYLE_USER_MODIFY_READ_ONLY; michael@0: mUserFocus = NS_STYLE_USER_FOCUS_NONE; michael@0: michael@0: mCursor = NS_STYLE_CURSOR_AUTO; // fix for bugzilla bug 51113 michael@0: michael@0: mCursorArrayLength = 0; michael@0: mCursorArray = nullptr; michael@0: } michael@0: michael@0: nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource) : michael@0: mUserInput(aSource.mUserInput), michael@0: mUserModify(aSource.mUserModify), michael@0: mUserFocus(aSource.mUserFocus), michael@0: mCursor(aSource.mCursor) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleUserInterface); michael@0: CopyCursorArrayFrom(aSource); michael@0: } michael@0: michael@0: nsStyleUserInterface::~nsStyleUserInterface(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleUserInterface); michael@0: delete [] mCursorArray; michael@0: } michael@0: michael@0: nsChangeHint nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aOther) const michael@0: { michael@0: nsChangeHint hint = nsChangeHint(0); michael@0: if (mCursor != aOther.mCursor) michael@0: NS_UpdateHint(hint, nsChangeHint_UpdateCursor); michael@0: michael@0: // We could do better. But it wouldn't be worth it, URL-specified cursors are michael@0: // rare. michael@0: if (mCursorArrayLength > 0 || aOther.mCursorArrayLength > 0) michael@0: NS_UpdateHint(hint, nsChangeHint_UpdateCursor); michael@0: michael@0: if (mUserModify != aOther.mUserModify) michael@0: NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL); michael@0: michael@0: if ((mUserInput != aOther.mUserInput) && michael@0: ((NS_STYLE_USER_INPUT_NONE == mUserInput) || michael@0: (NS_STYLE_USER_INPUT_NONE == aOther.mUserInput))) { michael@0: NS_UpdateHint(hint, NS_STYLE_HINT_FRAMECHANGE); michael@0: } michael@0: michael@0: // ignore mUserFocus michael@0: michael@0: return hint; michael@0: } michael@0: michael@0: void michael@0: nsStyleUserInterface::CopyCursorArrayFrom(const nsStyleUserInterface& aSource) michael@0: { michael@0: mCursorArray = nullptr; michael@0: mCursorArrayLength = 0; michael@0: if (aSource.mCursorArrayLength) { michael@0: mCursorArray = new nsCursorImage[aSource.mCursorArrayLength]; michael@0: if (mCursorArray) { michael@0: mCursorArrayLength = aSource.mCursorArrayLength; michael@0: for (uint32_t i = 0; i < mCursorArrayLength; ++i) michael@0: mCursorArray[i] = aSource.mCursorArray[i]; michael@0: } michael@0: } michael@0: } michael@0: michael@0: //----------------------- michael@0: // nsStyleUIReset michael@0: // michael@0: michael@0: nsStyleUIReset::nsStyleUIReset(void) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleUIReset); michael@0: mUserSelect = NS_STYLE_USER_SELECT_AUTO; michael@0: mForceBrokenImageIcon = 0; michael@0: mIMEMode = NS_STYLE_IME_MODE_AUTO; michael@0: mWindowShadow = NS_STYLE_WINDOW_SHADOW_DEFAULT; michael@0: } michael@0: michael@0: nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleUIReset); michael@0: mUserSelect = aSource.mUserSelect; michael@0: mForceBrokenImageIcon = aSource.mForceBrokenImageIcon; michael@0: mIMEMode = aSource.mIMEMode; michael@0: mWindowShadow = aSource.mWindowShadow; michael@0: } michael@0: michael@0: nsStyleUIReset::~nsStyleUIReset(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleUIReset); michael@0: } michael@0: michael@0: nsChangeHint nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const michael@0: { michael@0: // ignore mIMEMode michael@0: if (mForceBrokenImageIcon != aOther.mForceBrokenImageIcon) michael@0: return NS_STYLE_HINT_FRAMECHANGE; michael@0: if (mWindowShadow != aOther.mWindowShadow) { michael@0: // We really need just an nsChangeHint_SyncFrameView, except michael@0: // on an ancestor of the frame, so we get that by doing a michael@0: // reflow. michael@0: return NS_STYLE_HINT_REFLOW; michael@0: } michael@0: if (mUserSelect != aOther.mUserSelect) michael@0: return NS_STYLE_HINT_VISUAL; michael@0: return NS_STYLE_HINT_NONE; michael@0: } michael@0: michael@0: //----------------------- michael@0: // nsStyleVariables michael@0: // michael@0: michael@0: nsStyleVariables::nsStyleVariables() michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleVariables); michael@0: } michael@0: michael@0: nsStyleVariables::nsStyleVariables(const nsStyleVariables& aSource) michael@0: { michael@0: MOZ_COUNT_CTOR(nsStyleVariables); michael@0: } michael@0: michael@0: nsStyleVariables::~nsStyleVariables(void) michael@0: { michael@0: MOZ_COUNT_DTOR(nsStyleVariables); michael@0: } michael@0: michael@0: nsChangeHint michael@0: nsStyleVariables::CalcDifference(const nsStyleVariables& aOther) const michael@0: { michael@0: return nsChangeHint(0); michael@0: }