Bumping manifests a=b2g-bump
[gecko.git] / layout / style / nsStyleStruct.cpp
blobdf9b219dd496a398468c4420a7e801ede3efd717
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /*
7 * structs that contain the data provided by nsStyleContext, the
8 * internal API for computed style data for an element
9 */
11 #include "nsStyleStruct.h"
12 #include "nsStyleStructInlines.h"
13 #include "nsStyleConsts.h"
14 #include "nsThemeConstants.h"
15 #include "nsString.h"
16 #include "nsPresContext.h"
17 #include "nsIWidget.h"
18 #include "nsCRTGlue.h"
19 #include "nsCSSProps.h"
21 #include "nsCOMPtr.h"
23 #include "nsBidiUtils.h"
24 #include "nsLayoutUtils.h"
26 #include "imgIRequest.h"
27 #include "imgIContainer.h"
28 #include "CounterStyleManager.h"
30 #include "mozilla/Likely.h"
31 #include "nsIURI.h"
32 #include "nsIDocument.h"
33 #include <algorithm>
35 static_assert((((1 << nsStyleStructID_Length) - 1) &
36 ~(NS_STYLE_INHERIT_MASK)) == 0,
37 "Not enough bits in NS_STYLE_INHERIT_MASK");
39 inline bool IsFixedUnit(const nsStyleCoord& aCoord, bool aEnumOK)
41 return aCoord.ConvertsToLength() ||
42 (aEnumOK && aCoord.GetUnit() == eStyleUnit_Enumerated);
45 static bool EqualURIs(nsIURI *aURI1, nsIURI *aURI2)
47 bool eq;
48 return aURI1 == aURI2 || // handle null==null, and optimize
49 (aURI1 && aURI2 &&
50 NS_SUCCEEDED(aURI1->Equals(aURI2, &eq)) && // not equal on fail
51 eq);
54 static bool EqualURIs(mozilla::css::URLValue *aURI1, mozilla::css::URLValue *aURI2)
56 return aURI1 == aURI2 || // handle null==null, and optimize
57 (aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
60 static bool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
62 if (aImage1 == aImage2) {
63 return true;
66 if (!aImage1 || !aImage2) {
67 return false;
70 nsCOMPtr<nsIURI> uri1, uri2;
71 aImage1->GetURI(getter_AddRefs(uri1));
72 aImage2->GetURI(getter_AddRefs(uri2));
73 return EqualURIs(uri1, uri2);
76 // A nullsafe wrapper for strcmp. We depend on null-safety.
77 static int safe_strcmp(const char16_t* a, const char16_t* b)
79 if (!a || !b) {
80 return (int)(a - b);
82 return NS_strcmp(a, b);
85 static nsChangeHint CalcShadowDifference(nsCSSShadowArray* lhs,
86 nsCSSShadowArray* rhs);
88 // --------------------
89 // nsStyleFont
91 nsStyleFont::nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext)
92 : mFont(aFont)
93 , mGenericID(kGenericFont_NONE)
94 , mExplicitLanguage(false)
96 MOZ_COUNT_CTOR(nsStyleFont);
97 Init(aPresContext);
100 nsStyleFont::nsStyleFont(const nsStyleFont& aSrc)
101 : mFont(aSrc.mFont)
102 , mSize(aSrc.mSize)
103 , mGenericID(aSrc.mGenericID)
104 , mScriptLevel(aSrc.mScriptLevel)
105 , mMathVariant(aSrc.mMathVariant)
106 , mMathDisplay(aSrc.mMathDisplay)
107 , mExplicitLanguage(aSrc.mExplicitLanguage)
108 , mAllowZoom(aSrc.mAllowZoom)
109 , mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize)
110 , mScriptMinSize(aSrc.mScriptMinSize)
111 , mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier)
112 , mLanguage(aSrc.mLanguage)
114 MOZ_COUNT_CTOR(nsStyleFont);
117 nsStyleFont::nsStyleFont(nsPresContext* aPresContext)
118 // passing nullptr to GetDefaultFont make it use the doc language
119 : mFont(*(aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
120 nullptr)))
121 , mGenericID(kGenericFont_NONE)
122 , mExplicitLanguage(false)
124 MOZ_COUNT_CTOR(nsStyleFont);
125 Init(aPresContext);
128 void
129 nsStyleFont::Init(nsPresContext* aPresContext)
131 mSize = mFont.size = nsStyleFont::ZoomText(aPresContext, mFont.size);
132 mScriptUnconstrainedSize = mSize;
133 mScriptMinSize = aPresContext->CSSTwipsToAppUnits(
134 NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT));
135 mScriptLevel = 0;
136 mScriptSizeMultiplier = NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER;
137 mMathVariant = NS_MATHML_MATHVARIANT_NONE;
138 mMathDisplay = NS_MATHML_DISPLAYSTYLE_INLINE;
139 mAllowZoom = true;
141 nsAutoString language;
142 aPresContext->Document()->GetContentLanguage(language);
143 language.StripWhitespace();
145 // Content-Language may be a comma-separated list of language codes,
146 // in which case the HTML5 spec says to treat it as unknown
147 if (!language.IsEmpty() &&
148 language.FindChar(char16_t(',')) == kNotFound) {
149 mLanguage = do_GetAtom(language);
150 // NOTE: This does *not* count as an explicit language; in other
151 // words, it doesn't trigger language-specific hyphenation.
152 } else {
153 // we didn't find a (usable) Content-Language, so we fall back
154 // to whatever the presContext guessed from the charset
155 mLanguage = aPresContext->GetLanguageFromCharset();
159 void
160 nsStyleFont::Destroy(nsPresContext* aContext) {
161 this->~nsStyleFont();
162 aContext->PresShell()->
163 FreeByObjectID(nsPresArena::nsStyleFont_id, this);
166 void
167 nsStyleFont::EnableZoom(nsPresContext* aContext, bool aEnable)
169 if (mAllowZoom == aEnable) {
170 return;
172 mAllowZoom = aEnable;
173 if (mAllowZoom) {
174 mSize = nsStyleFont::ZoomText(aContext, mSize);
175 mFont.size = nsStyleFont::ZoomText(aContext, mFont.size);
176 mScriptUnconstrainedSize =
177 nsStyleFont::ZoomText(aContext, mScriptUnconstrainedSize);
178 } else {
179 mSize = nsStyleFont::UnZoomText(aContext, mSize);
180 mFont.size = nsStyleFont::UnZoomText(aContext, mFont.size);
181 mScriptUnconstrainedSize =
182 nsStyleFont::UnZoomText(aContext, mScriptUnconstrainedSize);
186 nsChangeHint nsStyleFont::CalcDifference(const nsStyleFont& aOther) const
188 MOZ_ASSERT(mAllowZoom == aOther.mAllowZoom,
189 "expected mAllowZoom to be the same on both nsStyleFonts");
190 if (mSize != aOther.mSize ||
191 mLanguage != aOther.mLanguage ||
192 mExplicitLanguage != aOther.mExplicitLanguage ||
193 mMathVariant != aOther.mMathVariant ||
194 mMathDisplay != aOther.mMathDisplay) {
195 return NS_STYLE_HINT_REFLOW;
197 return CalcFontDifference(mFont, aOther.mFont);
200 /* static */ nscoord
201 nsStyleFont::ZoomText(nsPresContext *aPresContext, nscoord aSize)
203 return nscoord(float(aSize) * aPresContext->TextZoom());
206 /* static */ nscoord
207 nsStyleFont::UnZoomText(nsPresContext *aPresContext, nscoord aSize)
209 return nscoord(float(aSize) / aPresContext->TextZoom());
212 nsChangeHint nsStyleFont::CalcFontDifference(const nsFont& aFont1, const nsFont& aFont2)
214 if ((aFont1.size == aFont2.size) &&
215 (aFont1.sizeAdjust == aFont2.sizeAdjust) &&
216 (aFont1.style == aFont2.style) &&
217 (aFont1.weight == aFont2.weight) &&
218 (aFont1.stretch == aFont2.stretch) &&
219 (aFont1.smoothing == aFont2.smoothing) &&
220 (aFont1.fontlist == aFont2.fontlist) &&
221 (aFont1.kerning == aFont2.kerning) &&
222 (aFont1.synthesis == aFont2.synthesis) &&
223 (aFont1.variantAlternates == aFont2.variantAlternates) &&
224 (aFont1.alternateValues == aFont2.alternateValues) &&
225 (aFont1.featureValueLookup == aFont2.featureValueLookup) &&
226 (aFont1.variantCaps == aFont2.variantCaps) &&
227 (aFont1.variantEastAsian == aFont2.variantEastAsian) &&
228 (aFont1.variantLigatures == aFont2.variantLigatures) &&
229 (aFont1.variantNumeric == aFont2.variantNumeric) &&
230 (aFont1.variantPosition == aFont2.variantPosition) &&
231 (aFont1.fontFeatureSettings == aFont2.fontFeatureSettings) &&
232 (aFont1.languageOverride == aFont2.languageOverride) &&
233 (aFont1.systemFont == aFont2.systemFont)) {
234 if ((aFont1.decorations == aFont2.decorations)) {
235 return NS_STYLE_HINT_NONE;
237 return NS_STYLE_HINT_VISUAL;
239 return NS_STYLE_HINT_REFLOW;
242 static bool IsFixedData(const nsStyleSides& aSides, bool aEnumOK)
244 NS_FOR_CSS_SIDES(side) {
245 if (!IsFixedUnit(aSides.Get(side), aEnumOK))
246 return false;
248 return true;
251 static nscoord CalcCoord(const nsStyleCoord& aCoord,
252 const nscoord* aEnumTable,
253 int32_t aNumEnums)
255 if (aCoord.GetUnit() == eStyleUnit_Enumerated) {
256 NS_ABORT_IF_FALSE(aEnumTable, "must have enum table");
257 int32_t value = aCoord.GetIntValue();
258 if (0 <= value && value < aNumEnums) {
259 return aEnumTable[aCoord.GetIntValue()];
261 NS_NOTREACHED("unexpected enum value");
262 return 0;
264 NS_ABORT_IF_FALSE(aCoord.ConvertsToLength(), "unexpected unit");
265 return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
268 nsStyleMargin::nsStyleMargin()
269 : mHasCachedMargin(false)
270 , mCachedMargin(0, 0, 0, 0)
272 MOZ_COUNT_CTOR(nsStyleMargin);
273 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
274 NS_FOR_CSS_SIDES(side) {
275 mMargin.Set(side, zero);
279 nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc)
280 : mMargin(aSrc.mMargin)
281 , mHasCachedMargin(false)
282 , mCachedMargin(0, 0, 0, 0)
284 MOZ_COUNT_CTOR(nsStyleMargin);
287 void
288 nsStyleMargin::Destroy(nsPresContext* aContext) {
289 this->~nsStyleMargin();
290 aContext->PresShell()->
291 FreeByObjectID(nsPresArena::nsStyleMargin_id, this);
295 void nsStyleMargin::RecalcData()
297 if (IsFixedData(mMargin, false)) {
298 NS_FOR_CSS_SIDES(side) {
299 mCachedMargin.Side(side) = CalcCoord(mMargin.Get(side), nullptr, 0);
301 mHasCachedMargin = true;
303 else
304 mHasCachedMargin = false;
307 nsChangeHint nsStyleMargin::CalcDifference(const nsStyleMargin& aOther) const
309 if (mMargin == aOther.mMargin) {
310 return NS_STYLE_HINT_NONE;
312 // Margin differences can't affect descendant intrinsic sizes and
313 // don't need to force children to reflow.
314 return NS_CombineHint(nsChangeHint_NeedReflow,
315 nsChangeHint_ClearAncestorIntrinsics);
318 nsStylePadding::nsStylePadding()
319 : mHasCachedPadding(false)
320 , mCachedPadding(0, 0, 0, 0)
322 MOZ_COUNT_CTOR(nsStylePadding);
323 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
324 NS_FOR_CSS_SIDES(side) {
325 mPadding.Set(side, zero);
329 nsStylePadding::nsStylePadding(const nsStylePadding& aSrc)
330 : mPadding(aSrc.mPadding)
331 , mHasCachedPadding(false)
332 , mCachedPadding(0, 0, 0, 0)
334 MOZ_COUNT_CTOR(nsStylePadding);
337 void
338 nsStylePadding::Destroy(nsPresContext* aContext) {
339 this->~nsStylePadding();
340 aContext->PresShell()->
341 FreeByObjectID(nsPresArena::nsStylePadding_id, this);
344 void nsStylePadding::RecalcData()
346 if (IsFixedData(mPadding, false)) {
347 NS_FOR_CSS_SIDES(side) {
348 // Clamp negative calc() to 0.
349 mCachedPadding.Side(side) =
350 std::max(CalcCoord(mPadding.Get(side), nullptr, 0), 0);
352 mHasCachedPadding = true;
354 else
355 mHasCachedPadding = false;
358 nsChangeHint nsStylePadding::CalcDifference(const nsStylePadding& aOther) const
360 if (mPadding == aOther.mPadding) {
361 return NS_STYLE_HINT_NONE;
363 // Padding differences can't affect descendant intrinsic sizes, but do need
364 // to force children to reflow so that we can reposition them, since their
365 // offsets are from our frame bounds but our content rect's position within
366 // those bounds is moving.
367 return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
368 nsChangeHint_ClearDescendantIntrinsics);
371 nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
372 : mBorderColors(nullptr),
373 mBoxShadow(nullptr),
374 mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL),
375 mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
376 mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
377 mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT),
378 mBoxDecorationBreak(NS_STYLE_BOX_DECORATION_BREAK_SLICE),
379 mComputedBorder(0, 0, 0, 0)
381 MOZ_COUNT_CTOR(nsStyleBorder);
383 NS_FOR_CSS_HALF_CORNERS (corner) {
384 mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
387 nscoord medium =
388 (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
389 NS_FOR_CSS_SIDES(side) {
390 mBorderImageSlice.Set(side, nsStyleCoord(1.0f, eStyleUnit_Percent));
391 mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor));
392 mBorderImageOutset.Set(side, nsStyleCoord(0.0f, eStyleUnit_Factor));
394 mBorder.Side(side) = medium;
395 mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND;
396 mBorderColor[side] = NS_RGB(0, 0, 0);
399 mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
402 nsBorderColors::~nsBorderColors()
404 NS_CSS_DELETE_LIST_MEMBER(nsBorderColors, this, mNext);
407 nsBorderColors*
408 nsBorderColors::Clone(bool aDeep) const
410 nsBorderColors* result = new nsBorderColors(mColor);
411 if (MOZ_UNLIKELY(!result))
412 return result;
413 if (aDeep)
414 NS_CSS_CLONE_LIST_MEMBER(nsBorderColors, this, mNext, result, (false));
415 return result;
418 nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
419 : mBorderColors(nullptr),
420 mBoxShadow(aSrc.mBoxShadow),
421 mBorderRadius(aSrc.mBorderRadius),
422 mBorderImageSource(aSrc.mBorderImageSource),
423 mBorderImageSlice(aSrc.mBorderImageSlice),
424 mBorderImageWidth(aSrc.mBorderImageWidth),
425 mBorderImageOutset(aSrc.mBorderImageOutset),
426 mBorderImageFill(aSrc.mBorderImageFill),
427 mBorderImageRepeatH(aSrc.mBorderImageRepeatH),
428 mBorderImageRepeatV(aSrc.mBorderImageRepeatV),
429 mFloatEdge(aSrc.mFloatEdge),
430 mBoxDecorationBreak(aSrc.mBoxDecorationBreak),
431 mComputedBorder(aSrc.mComputedBorder),
432 mBorder(aSrc.mBorder),
433 mTwipsPerPixel(aSrc.mTwipsPerPixel)
435 MOZ_COUNT_CTOR(nsStyleBorder);
436 if (aSrc.mBorderColors) {
437 EnsureBorderColors();
438 for (int32_t i = 0; i < 4; i++)
439 if (aSrc.mBorderColors[i])
440 mBorderColors[i] = aSrc.mBorderColors[i]->Clone();
441 else
442 mBorderColors[i] = nullptr;
445 NS_FOR_CSS_SIDES(side) {
446 mBorderStyle[side] = aSrc.mBorderStyle[side];
447 mBorderColor[side] = aSrc.mBorderColor[side];
451 nsStyleBorder::~nsStyleBorder()
453 MOZ_COUNT_DTOR(nsStyleBorder);
454 if (mBorderColors) {
455 for (int32_t i = 0; i < 4; i++)
456 delete mBorderColors[i];
457 delete [] mBorderColors;
461 nsMargin
462 nsStyleBorder::GetImageOutset() const
464 // We don't check whether there is a border-image (which is OK since
465 // the initial values yields 0 outset) so that we don't have to
466 // reflow to update overflow areas when an image loads.
467 nsMargin outset;
468 NS_FOR_CSS_SIDES(s) {
469 nsStyleCoord coord = mBorderImageOutset.Get(s);
470 nscoord value;
471 switch (coord.GetUnit()) {
472 case eStyleUnit_Coord:
473 value = coord.GetCoordValue();
474 break;
475 case eStyleUnit_Factor:
476 value = coord.GetFactorValue() * mComputedBorder.Side(s);
477 break;
478 default:
479 NS_NOTREACHED("unexpected CSS unit for image outset");
480 value = 0;
481 break;
483 outset.Side(s) = value;
485 return outset;
488 void
489 nsStyleBorder::Destroy(nsPresContext* aContext) {
490 UntrackImage(aContext);
491 this->~nsStyleBorder();
492 aContext->PresShell()->
493 FreeByObjectID(nsPresArena::nsStyleBorder_id, this);
496 nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
498 nsChangeHint shadowDifference =
499 CalcShadowDifference(mBoxShadow, aOther.mBoxShadow);
500 NS_ABORT_IF_FALSE(shadowDifference == unsigned(NS_STYLE_HINT_REFLOW) ||
501 shadowDifference == unsigned(NS_STYLE_HINT_VISUAL) ||
502 shadowDifference == unsigned(NS_STYLE_HINT_NONE),
503 "should do more with shadowDifference");
505 // Note that differences in mBorder don't affect rendering (which should only
506 // use mComputedBorder), so don't need to be tested for here.
507 // XXXbz we should be able to return a more specific change hint for
508 // at least GetComputedBorder() differences...
509 if (mTwipsPerPixel != aOther.mTwipsPerPixel ||
510 GetComputedBorder() != aOther.GetComputedBorder() ||
511 mFloatEdge != aOther.mFloatEdge ||
512 mBorderImageOutset != aOther.mBorderImageOutset ||
513 (shadowDifference & nsChangeHint_NeedReflow) ||
514 mBoxDecorationBreak != aOther.mBoxDecorationBreak)
515 return NS_STYLE_HINT_REFLOW;
517 NS_FOR_CSS_SIDES(ix) {
518 // See the explanation in nsChangeHint.h of
519 // nsChangeHint_BorderStyleNoneChange .
520 // Furthermore, even though we know *this* side is 0 width, just
521 // assume a visual hint for some other change rather than bother
522 // tracking this result through the rest of the function.
523 if (HasVisibleStyle(ix) != aOther.HasVisibleStyle(ix)) {
524 return NS_CombineHint(NS_STYLE_HINT_VISUAL,
525 nsChangeHint_BorderStyleNoneChange);
529 // Note that mBorderStyle stores not only the border style but also
530 // color-related flags. Given that we've already done an mComputedBorder
531 // comparison, border-style differences can only lead to a VISUAL hint. So
532 // it's OK to just compare the values directly -- if either the actual
533 // style or the color flags differ we want to repaint.
534 NS_FOR_CSS_SIDES(ix) {
535 if (mBorderStyle[ix] != aOther.mBorderStyle[ix] ||
536 mBorderColor[ix] != aOther.mBorderColor[ix])
537 return NS_STYLE_HINT_VISUAL;
540 if (mBorderRadius != aOther.mBorderRadius ||
541 !mBorderColors != !aOther.mBorderColors)
542 return NS_STYLE_HINT_VISUAL;
544 if (IsBorderImageLoaded() || aOther.IsBorderImageLoaded()) {
545 if (mBorderImageSource != aOther.mBorderImageSource ||
546 mBorderImageRepeatH != aOther.mBorderImageRepeatH ||
547 mBorderImageRepeatV != aOther.mBorderImageRepeatV ||
548 mBorderImageSlice != aOther.mBorderImageSlice ||
549 mBorderImageFill != aOther.mBorderImageFill ||
550 mBorderImageWidth != aOther.mBorderImageWidth ||
551 mBorderImageOutset != aOther.mBorderImageOutset)
552 return NS_STYLE_HINT_VISUAL;
555 // Note that at this point if mBorderColors is non-null so is
556 // aOther.mBorderColors
557 if (mBorderColors) {
558 NS_FOR_CSS_SIDES(ix) {
559 if (!nsBorderColors::Equal(mBorderColors[ix],
560 aOther.mBorderColors[ix]))
561 return NS_STYLE_HINT_VISUAL;
565 return shadowDifference;
568 nsStyleOutline::nsStyleOutline(nsPresContext* aPresContext)
570 MOZ_COUNT_CTOR(nsStyleOutline);
571 // spacing values not inherited
572 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
573 NS_FOR_CSS_HALF_CORNERS(corner) {
574 mOutlineRadius.Set(corner, zero);
577 mOutlineOffset = 0;
579 mOutlineWidth = nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
580 mOutlineStyle = NS_STYLE_BORDER_STYLE_NONE;
581 mOutlineColor = NS_RGB(0, 0, 0);
583 mHasCachedOutline = false;
584 mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
587 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc)
588 : mOutlineRadius(aSrc.mOutlineRadius)
589 , mOutlineWidth(aSrc.mOutlineWidth)
590 , mOutlineOffset(aSrc.mOutlineOffset)
591 , mCachedOutlineWidth(aSrc.mCachedOutlineWidth)
592 , mOutlineColor(aSrc.mOutlineColor)
593 , mHasCachedOutline(aSrc.mHasCachedOutline)
594 , mOutlineStyle(aSrc.mOutlineStyle)
595 , mTwipsPerPixel(aSrc.mTwipsPerPixel)
597 MOZ_COUNT_CTOR(nsStyleOutline);
600 void
601 nsStyleOutline::RecalcData(nsPresContext* aContext)
603 if (NS_STYLE_BORDER_STYLE_NONE == GetOutlineStyle()) {
604 mCachedOutlineWidth = 0;
605 mHasCachedOutline = true;
606 } else if (IsFixedUnit(mOutlineWidth, true)) {
607 // Clamp negative calc() to 0.
608 mCachedOutlineWidth =
609 std::max(CalcCoord(mOutlineWidth, aContext->GetBorderWidthTable(), 3), 0);
610 mCachedOutlineWidth =
611 NS_ROUND_BORDER_TO_PIXELS(mCachedOutlineWidth, mTwipsPerPixel);
612 mHasCachedOutline = true;
614 else
615 mHasCachedOutline = false;
618 nsChangeHint nsStyleOutline::CalcDifference(const nsStyleOutline& aOther) const
620 bool outlineWasVisible =
621 mCachedOutlineWidth > 0 && mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
622 bool outlineIsVisible =
623 aOther.mCachedOutlineWidth > 0 && aOther.mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
624 if (outlineWasVisible != outlineIsVisible ||
625 (outlineIsVisible && (mOutlineOffset != aOther.mOutlineOffset ||
626 mOutlineWidth != aOther.mOutlineWidth ||
627 mTwipsPerPixel != aOther.mTwipsPerPixel))) {
628 return NS_CombineHint(nsChangeHint_AllReflowHints,
629 nsChangeHint_RepaintFrame);
631 if ((mOutlineStyle != aOther.mOutlineStyle) ||
632 (mOutlineColor != aOther.mOutlineColor) ||
633 (mOutlineRadius != aOther.mOutlineRadius)) {
634 return nsChangeHint_RepaintFrame;
636 return NS_STYLE_HINT_NONE;
639 // --------------------
640 // nsStyleList
642 nsStyleList::nsStyleList(nsPresContext* aPresContext)
643 : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE),
644 mListStyleType(NS_LITERAL_STRING("disc")),
645 mCounterStyle(aPresContext->CounterStyleManager()->
646 BuildCounterStyle(mListStyleType))
648 MOZ_COUNT_CTOR(nsStyleList);
651 nsStyleList::~nsStyleList()
653 MOZ_COUNT_DTOR(nsStyleList);
656 nsStyleList::nsStyleList(const nsStyleList& aSource)
657 : mListStylePosition(aSource.mListStylePosition),
658 mListStyleType(aSource.mListStyleType),
659 mCounterStyle(aSource.mCounterStyle),
660 mImageRegion(aSource.mImageRegion)
662 SetListStyleImage(aSource.GetListStyleImage());
663 MOZ_COUNT_CTOR(nsStyleList);
666 nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aOther) const
668 if (mListStylePosition != aOther.mListStylePosition)
669 return NS_STYLE_HINT_FRAMECHANGE;
670 if (EqualImages(mListStyleImage, aOther.mListStyleImage) &&
671 mListStyleType == aOther.mListStyleType) {
672 if (mImageRegion.IsEqualInterior(aOther.mImageRegion))
673 return NS_STYLE_HINT_NONE;
674 if (mImageRegion.width == aOther.mImageRegion.width &&
675 mImageRegion.height == aOther.mImageRegion.height)
676 return NS_STYLE_HINT_VISUAL;
678 return NS_STYLE_HINT_REFLOW;
681 // --------------------
682 // nsStyleXUL
684 nsStyleXUL::nsStyleXUL()
686 MOZ_COUNT_CTOR(nsStyleXUL);
687 mBoxAlign = NS_STYLE_BOX_ALIGN_STRETCH;
688 mBoxDirection = NS_STYLE_BOX_DIRECTION_NORMAL;
689 mBoxFlex = 0.0f;
690 mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL;
691 mBoxPack = NS_STYLE_BOX_PACK_START;
692 mBoxOrdinal = 1;
693 mStretchStack = true;
696 nsStyleXUL::~nsStyleXUL()
698 MOZ_COUNT_DTOR(nsStyleXUL);
701 nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource)
702 : mBoxFlex(aSource.mBoxFlex)
703 , mBoxOrdinal(aSource.mBoxOrdinal)
704 , mBoxAlign(aSource.mBoxAlign)
705 , mBoxDirection(aSource.mBoxDirection)
706 , mBoxOrient(aSource.mBoxOrient)
707 , mBoxPack(aSource.mBoxPack)
708 , mStretchStack(aSource.mStretchStack)
710 MOZ_COUNT_CTOR(nsStyleXUL);
713 nsChangeHint nsStyleXUL::CalcDifference(const nsStyleXUL& aOther) const
715 if (mBoxAlign == aOther.mBoxAlign &&
716 mBoxDirection == aOther.mBoxDirection &&
717 mBoxFlex == aOther.mBoxFlex &&
718 mBoxOrient == aOther.mBoxOrient &&
719 mBoxPack == aOther.mBoxPack &&
720 mBoxOrdinal == aOther.mBoxOrdinal &&
721 mStretchStack == aOther.mStretchStack)
722 return NS_STYLE_HINT_NONE;
723 if (mBoxOrdinal != aOther.mBoxOrdinal)
724 return NS_STYLE_HINT_FRAMECHANGE;
725 return NS_STYLE_HINT_REFLOW;
728 // --------------------
729 // nsStyleColumn
731 /* static */ const uint32_t nsStyleColumn::kMaxColumnCount = 1000;
733 nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext)
735 MOZ_COUNT_CTOR(nsStyleColumn);
736 mColumnCount = NS_STYLE_COLUMN_COUNT_AUTO;
737 mColumnWidth.SetAutoValue();
738 mColumnGap.SetNormalValue();
739 mColumnFill = NS_STYLE_COLUMN_FILL_BALANCE;
741 mColumnRuleWidth = (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
742 mColumnRuleStyle = NS_STYLE_BORDER_STYLE_NONE;
743 mColumnRuleColor = NS_RGB(0, 0, 0);
744 mColumnRuleColorIsForeground = true;
746 mTwipsPerPixel = aPresContext->AppUnitsPerDevPixel();
749 nsStyleColumn::~nsStyleColumn()
751 MOZ_COUNT_DTOR(nsStyleColumn);
754 nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
755 : mColumnCount(aSource.mColumnCount)
756 , mColumnWidth(aSource.mColumnWidth)
757 , mColumnGap(aSource.mColumnGap)
758 , mColumnRuleColor(aSource.mColumnRuleColor)
759 , mColumnRuleStyle(aSource.mColumnRuleStyle)
760 , mColumnFill(aSource.mColumnFill)
761 , mColumnRuleColorIsForeground(aSource.mColumnRuleColorIsForeground)
762 , mColumnRuleWidth(aSource.mColumnRuleWidth)
763 , mTwipsPerPixel(aSource.mTwipsPerPixel)
765 MOZ_COUNT_CTOR(nsStyleColumn);
768 nsChangeHint nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const
770 if ((mColumnWidth.GetUnit() == eStyleUnit_Auto)
771 != (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) ||
772 mColumnCount != aOther.mColumnCount)
773 // We force column count changes to do a reframe, because it's tricky to handle
774 // some edge cases where the column count gets smaller and content overflows.
775 // XXX not ideal
776 return NS_STYLE_HINT_FRAMECHANGE;
778 if (mColumnWidth != aOther.mColumnWidth ||
779 mColumnGap != aOther.mColumnGap ||
780 mColumnFill != aOther.mColumnFill)
781 return NS_STYLE_HINT_REFLOW;
783 if (GetComputedColumnRuleWidth() != aOther.GetComputedColumnRuleWidth() ||
784 mColumnRuleStyle != aOther.mColumnRuleStyle ||
785 mColumnRuleColor != aOther.mColumnRuleColor ||
786 mColumnRuleColorIsForeground != aOther.mColumnRuleColorIsForeground)
787 return NS_STYLE_HINT_VISUAL;
789 return NS_STYLE_HINT_NONE;
792 // --------------------
793 // nsStyleSVG
795 nsStyleSVG::nsStyleSVG()
797 MOZ_COUNT_CTOR(nsStyleSVG);
798 mFill.mType = eStyleSVGPaintType_Color;
799 mFill.mPaint.mColor = NS_RGB(0,0,0);
800 mFill.mFallbackColor = NS_RGB(0,0,0);
801 mStroke.mType = eStyleSVGPaintType_None;
802 mStroke.mPaint.mColor = NS_RGB(0,0,0);
803 mStroke.mFallbackColor = NS_RGB(0,0,0);
804 mStrokeDasharray = nullptr;
806 mStrokeDashoffset.SetCoordValue(0);
807 mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
809 mFillOpacity = 1.0f;
810 mStrokeMiterlimit = 4.0f;
811 mStrokeOpacity = 1.0f;
813 mStrokeDasharrayLength = 0;
814 mClipRule = NS_STYLE_FILL_RULE_NONZERO;
815 mColorInterpolation = NS_STYLE_COLOR_INTERPOLATION_SRGB;
816 mColorInterpolationFilters = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
817 mFillRule = NS_STYLE_FILL_RULE_NONZERO;
818 mImageRendering = NS_STYLE_IMAGE_RENDERING_AUTO;
819 mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
820 mShapeRendering = NS_STYLE_SHAPE_RENDERING_AUTO;
821 mStrokeLinecap = NS_STYLE_STROKE_LINECAP_BUTT;
822 mStrokeLinejoin = NS_STYLE_STROKE_LINEJOIN_MITER;
823 mTextAnchor = NS_STYLE_TEXT_ANCHOR_START;
824 mTextRendering = NS_STYLE_TEXT_RENDERING_AUTO;
825 mFillOpacitySource = eStyleSVGOpacitySource_Normal;
826 mStrokeOpacitySource = eStyleSVGOpacitySource_Normal;
827 mStrokeDasharrayFromObject = false;
828 mStrokeDashoffsetFromObject = false;
829 mStrokeWidthFromObject = false;
832 nsStyleSVG::~nsStyleSVG()
834 MOZ_COUNT_DTOR(nsStyleSVG);
835 delete [] mStrokeDasharray;
838 nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
840 MOZ_COUNT_CTOR(nsStyleSVG);
841 mFill = aSource.mFill;
842 mStroke = aSource.mStroke;
844 mMarkerEnd = aSource.mMarkerEnd;
845 mMarkerMid = aSource.mMarkerMid;
846 mMarkerStart = aSource.mMarkerStart;
848 mStrokeDasharrayLength = aSource.mStrokeDasharrayLength;
849 if (aSource.mStrokeDasharray) {
850 mStrokeDasharray = new nsStyleCoord[mStrokeDasharrayLength];
851 if (mStrokeDasharray) {
852 for (size_t i = 0; i < mStrokeDasharrayLength; i++) {
853 mStrokeDasharray[i] = aSource.mStrokeDasharray[i];
855 } else {
856 mStrokeDasharrayLength = 0;
858 } else {
859 mStrokeDasharray = nullptr;
862 mStrokeDashoffset = aSource.mStrokeDashoffset;
863 mStrokeWidth = aSource.mStrokeWidth;
865 mFillOpacity = aSource.mFillOpacity;
866 mStrokeMiterlimit = aSource.mStrokeMiterlimit;
867 mStrokeOpacity = aSource.mStrokeOpacity;
869 mClipRule = aSource.mClipRule;
870 mColorInterpolation = aSource.mColorInterpolation;
871 mColorInterpolationFilters = aSource.mColorInterpolationFilters;
872 mFillRule = aSource.mFillRule;
873 mImageRendering = aSource.mImageRendering;
874 mPaintOrder = aSource.mPaintOrder;
875 mShapeRendering = aSource.mShapeRendering;
876 mStrokeLinecap = aSource.mStrokeLinecap;
877 mStrokeLinejoin = aSource.mStrokeLinejoin;
878 mTextAnchor = aSource.mTextAnchor;
879 mTextRendering = aSource.mTextRendering;
880 mFillOpacitySource = aSource.mFillOpacitySource;
881 mStrokeOpacitySource = aSource.mStrokeOpacitySource;
882 mStrokeDasharrayFromObject = aSource.mStrokeDasharrayFromObject;
883 mStrokeDashoffsetFromObject = aSource.mStrokeDashoffsetFromObject;
884 mStrokeWidthFromObject = aSource.mStrokeWidthFromObject;
887 static bool PaintURIChanged(const nsStyleSVGPaint& aPaint1,
888 const nsStyleSVGPaint& aPaint2)
890 if (aPaint1.mType != aPaint2.mType) {
891 return aPaint1.mType == eStyleSVGPaintType_Server ||
892 aPaint2.mType == eStyleSVGPaintType_Server;
894 return aPaint1.mType == eStyleSVGPaintType_Server &&
895 !EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
898 nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
900 nsChangeHint hint = nsChangeHint(0);
902 if (!EqualURIs(mMarkerEnd, aOther.mMarkerEnd) ||
903 !EqualURIs(mMarkerMid, aOther.mMarkerMid) ||
904 !EqualURIs(mMarkerStart, aOther.mMarkerStart)) {
905 // Markers currently contribute to nsSVGPathGeometryFrame::mRect,
906 // so we need a reflow as well as a repaint. No intrinsic sizes need
907 // to change, so nsChangeHint_NeedReflow is sufficient.
908 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
909 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
910 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
911 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
912 return hint;
915 if (mFill != aOther.mFill ||
916 mStroke != aOther.mStroke ||
917 mFillOpacity != aOther.mFillOpacity ||
918 mStrokeOpacity != aOther.mStrokeOpacity) {
919 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
920 if (HasStroke() != aOther.HasStroke() ||
921 (!HasStroke() && HasFill() != aOther.HasFill())) {
922 // Frame bounds and overflow rects depend on whether we "have" fill or
923 // stroke. Whether we have stroke or not just changed, or else we have no
924 // stroke (in which case whether we have fill or not is significant to frame
925 // bounds) and whether we have fill or not just changed. In either case we
926 // need to reflow so the frame rect is updated.
927 // XXXperf this is a waste on non nsSVGPathGeometryFrames.
928 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
929 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
931 if (PaintURIChanged(mFill, aOther.mFill) ||
932 PaintURIChanged(mStroke, aOther.mStroke)) {
933 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
937 // Stroke currently contributes to nsSVGPathGeometryFrame::mRect, so
938 // we need a reflow here. No intrinsic sizes need to change, so
939 // nsChangeHint_NeedReflow is sufficient.
940 // Note that stroke-dashoffset does not affect nsSVGPathGeometryFrame::mRect.
941 // text-anchor and text-rendering changes also require a reflow since they
942 // change frames' rects.
943 if (mStrokeWidth != aOther.mStrokeWidth ||
944 mStrokeMiterlimit != aOther.mStrokeMiterlimit ||
945 mStrokeLinecap != aOther.mStrokeLinecap ||
946 mStrokeLinejoin != aOther.mStrokeLinejoin ||
947 mTextAnchor != aOther.mTextAnchor ||
948 mTextRendering != aOther.mTextRendering) {
949 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
950 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
951 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
952 return hint;
955 if (hint & nsChangeHint_RepaintFrame) {
956 return hint; // we don't add anything else below
959 if ( mStrokeDashoffset != aOther.mStrokeDashoffset ||
960 mClipRule != aOther.mClipRule ||
961 mColorInterpolation != aOther.mColorInterpolation ||
962 mColorInterpolationFilters != aOther.mColorInterpolationFilters ||
963 mFillRule != aOther.mFillRule ||
964 mImageRendering != aOther.mImageRendering ||
965 mPaintOrder != aOther.mPaintOrder ||
966 mShapeRendering != aOther.mShapeRendering ||
967 mStrokeDasharrayLength != aOther.mStrokeDasharrayLength ||
968 mFillOpacitySource != aOther.mFillOpacitySource ||
969 mStrokeOpacitySource != aOther.mStrokeOpacitySource ||
970 mStrokeDasharrayFromObject != aOther.mStrokeDasharrayFromObject ||
971 mStrokeDashoffsetFromObject != aOther.mStrokeDashoffsetFromObject ||
972 mStrokeWidthFromObject != aOther.mStrokeWidthFromObject) {
973 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
974 return hint;
977 // length of stroke dasharrays are the same (tested above) - check entries
978 for (uint32_t i=0; i<mStrokeDasharrayLength; i++)
979 if (mStrokeDasharray[i] != aOther.mStrokeDasharray[i]) {
980 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
981 return hint;
984 return hint;
987 // --------------------
988 // nsStyleFilter
990 nsStyleFilter::nsStyleFilter()
991 : mType(NS_STYLE_FILTER_NONE)
992 , mDropShadow(nullptr)
994 MOZ_COUNT_CTOR(nsStyleFilter);
997 nsStyleFilter::nsStyleFilter(const nsStyleFilter& aSource)
998 : mType(NS_STYLE_FILTER_NONE)
999 , mDropShadow(nullptr)
1001 MOZ_COUNT_CTOR(nsStyleFilter);
1002 if (aSource.mType == NS_STYLE_FILTER_URL) {
1003 SetURL(aSource.mURL);
1004 } else if (aSource.mType == NS_STYLE_FILTER_DROP_SHADOW) {
1005 SetDropShadow(aSource.mDropShadow);
1006 } else if (aSource.mType != NS_STYLE_FILTER_NONE) {
1007 SetFilterParameter(aSource.mFilterParameter, aSource.mType);
1011 nsStyleFilter::~nsStyleFilter()
1013 ReleaseRef();
1014 MOZ_COUNT_DTOR(nsStyleFilter);
1017 nsStyleFilter&
1018 nsStyleFilter::operator=(const nsStyleFilter& aOther)
1020 if (this == &aOther)
1021 return *this;
1023 if (aOther.mType == NS_STYLE_FILTER_URL) {
1024 SetURL(aOther.mURL);
1025 } else if (aOther.mType == NS_STYLE_FILTER_DROP_SHADOW) {
1026 SetDropShadow(aOther.mDropShadow);
1027 } else if (aOther.mType != NS_STYLE_FILTER_NONE) {
1028 SetFilterParameter(aOther.mFilterParameter, aOther.mType);
1030 return *this;
1034 bool
1035 nsStyleFilter::operator==(const nsStyleFilter& aOther) const
1037 if (mType != aOther.mType) {
1038 return false;
1041 if (mType == NS_STYLE_FILTER_URL) {
1042 return EqualURIs(mURL, aOther.mURL);
1043 } else if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
1044 return *mDropShadow == *aOther.mDropShadow;
1045 } else if (mType != NS_STYLE_FILTER_NONE) {
1046 return mFilterParameter == aOther.mFilterParameter;
1049 return true;
1052 void
1053 nsStyleFilter::ReleaseRef()
1055 if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
1056 NS_ASSERTION(mDropShadow, "expected pointer");
1057 mDropShadow->Release();
1058 } else if (mType == NS_STYLE_FILTER_URL) {
1059 NS_ASSERTION(mURL, "expected pointer");
1060 mURL->Release();
1064 void
1065 nsStyleFilter::SetFilterParameter(const nsStyleCoord& aFilterParameter,
1066 int32_t aType)
1068 ReleaseRef();
1069 mFilterParameter = aFilterParameter;
1070 mType = aType;
1073 void
1074 nsStyleFilter::SetURL(nsIURI* aURL)
1076 NS_ASSERTION(aURL, "expected pointer");
1077 ReleaseRef();
1078 mURL = aURL;
1079 mURL->AddRef();
1080 mType = NS_STYLE_FILTER_URL;
1083 void
1084 nsStyleFilter::SetDropShadow(nsCSSShadowArray* aDropShadow)
1086 NS_ASSERTION(aDropShadow, "expected pointer");
1087 ReleaseRef();
1088 mDropShadow = aDropShadow;
1089 mDropShadow->AddRef();
1090 mType = NS_STYLE_FILTER_DROP_SHADOW;
1093 // --------------------
1094 // nsStyleSVGReset
1096 nsStyleSVGReset::nsStyleSVGReset()
1098 MOZ_COUNT_CTOR(nsStyleSVGReset);
1099 mStopColor = NS_RGB(0,0,0);
1100 mFloodColor = NS_RGB(0,0,0);
1101 mLightingColor = NS_RGB(255,255,255);
1102 mClipPath = nullptr;
1103 mMask = nullptr;
1104 mStopOpacity = 1.0f;
1105 mFloodOpacity = 1.0f;
1106 mDominantBaseline = NS_STYLE_DOMINANT_BASELINE_AUTO;
1107 mVectorEffect = NS_STYLE_VECTOR_EFFECT_NONE;
1108 mMaskType = NS_STYLE_MASK_TYPE_LUMINANCE;
1111 nsStyleSVGReset::~nsStyleSVGReset()
1113 MOZ_COUNT_DTOR(nsStyleSVGReset);
1116 nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
1118 MOZ_COUNT_CTOR(nsStyleSVGReset);
1119 mStopColor = aSource.mStopColor;
1120 mFloodColor = aSource.mFloodColor;
1121 mLightingColor = aSource.mLightingColor;
1122 mClipPath = aSource.mClipPath;
1123 mFilters = aSource.mFilters;
1124 mMask = aSource.mMask;
1125 mStopOpacity = aSource.mStopOpacity;
1126 mFloodOpacity = aSource.mFloodOpacity;
1127 mDominantBaseline = aSource.mDominantBaseline;
1128 mVectorEffect = aSource.mVectorEffect;
1129 mMaskType = aSource.mMaskType;
1132 nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) const
1134 nsChangeHint hint = nsChangeHint(0);
1136 if (!EqualURIs(mClipPath, aOther.mClipPath) ||
1137 !EqualURIs(mMask, aOther.mMask) ||
1138 mFilters != aOther.mFilters) {
1139 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
1140 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
1141 // We only actually need to update the overflow area for filter
1142 // changes. However, mask and clip-path changes require that we
1143 // update the PreEffectsBBoxProperty, which is done during overflow
1144 // computation.
1145 NS_UpdateHint(hint, nsChangeHint_UpdateOverflow);
1148 if (mDominantBaseline != aOther.mDominantBaseline) {
1149 // XXXjwatt: why NS_STYLE_HINT_REFLOW? Isn't that excessive?
1150 NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
1151 } else if (mVectorEffect != aOther.mVectorEffect) {
1152 // Stroke currently affects nsSVGPathGeometryFrame::mRect, and
1153 // vector-effect affect stroke. As a result we need to reflow if
1154 // vector-effect changes in order to have nsSVGPathGeometryFrame::
1155 // ReflowSVG called to update its mRect. No intrinsic sizes need
1156 // to change so nsChangeHint_NeedReflow is sufficient.
1157 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
1158 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
1159 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
1160 } else if (mStopColor != aOther.mStopColor ||
1161 mFloodColor != aOther.mFloodColor ||
1162 mLightingColor != aOther.mLightingColor ||
1163 mStopOpacity != aOther.mStopOpacity ||
1164 mFloodOpacity != aOther.mFloodOpacity ||
1165 mMaskType != aOther.mMaskType) {
1166 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
1169 return hint;
1172 // nsStyleSVGPaint implementation
1173 nsStyleSVGPaint::~nsStyleSVGPaint()
1175 if (mType == eStyleSVGPaintType_Server) {
1176 NS_IF_RELEASE(mPaint.mPaintServer);
1180 void
1181 nsStyleSVGPaint::SetType(nsStyleSVGPaintType aType)
1183 if (mType == eStyleSVGPaintType_Server) {
1184 this->~nsStyleSVGPaint();
1185 new (this) nsStyleSVGPaint();
1187 mType = aType;
1190 nsStyleSVGPaint& nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther)
1192 if (this == &aOther)
1193 return *this;
1195 SetType(aOther.mType);
1197 mFallbackColor = aOther.mFallbackColor;
1198 if (mType == eStyleSVGPaintType_Server) {
1199 mPaint.mPaintServer = aOther.mPaint.mPaintServer;
1200 NS_IF_ADDREF(mPaint.mPaintServer);
1201 } else {
1202 mPaint.mColor = aOther.mPaint.mColor;
1204 return *this;
1207 bool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const
1209 if (mType != aOther.mType)
1210 return false;
1211 if (mType == eStyleSVGPaintType_Server)
1212 return EqualURIs(mPaint.mPaintServer, aOther.mPaint.mPaintServer) &&
1213 mFallbackColor == aOther.mFallbackColor;
1214 if (mType == eStyleSVGPaintType_Color)
1215 return mPaint.mColor == aOther.mPaint.mColor;
1216 return true;
1220 // --------------------
1221 // nsStylePosition
1223 nsStylePosition::nsStylePosition(void)
1225 MOZ_COUNT_CTOR(nsStylePosition);
1226 // positioning values not inherited
1227 nsStyleCoord autoCoord(eStyleUnit_Auto);
1228 mOffset.SetLeft(autoCoord);
1229 mOffset.SetTop(autoCoord);
1230 mOffset.SetRight(autoCoord);
1231 mOffset.SetBottom(autoCoord);
1232 mWidth.SetAutoValue();
1233 mMinWidth.SetAutoValue();
1234 mMaxWidth.SetNoneValue();
1235 mHeight.SetAutoValue();
1236 mMinHeight.SetAutoValue();
1237 mMaxHeight.SetNoneValue();
1238 mFlexBasis.SetAutoValue();
1240 // The initial value of grid-auto-columns and grid-auto-rows is 'auto',
1241 // which computes to 'minmax(min-content, max-content)'.
1242 mGridAutoColumnsMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
1243 eStyleUnit_Enumerated);
1244 mGridAutoColumnsMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
1245 eStyleUnit_Enumerated);
1246 mGridAutoRowsMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
1247 eStyleUnit_Enumerated);
1248 mGridAutoRowsMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
1249 eStyleUnit_Enumerated);
1251 mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_ROW;
1252 mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT;
1253 mAlignContent = NS_STYLE_ALIGN_CONTENT_STRETCH;
1254 mAlignItems = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
1255 mAlignSelf = NS_STYLE_ALIGN_SELF_AUTO;
1256 mFlexDirection = NS_STYLE_FLEX_DIRECTION_ROW;
1257 mFlexWrap = NS_STYLE_FLEX_WRAP_NOWRAP;
1258 mJustifyContent = NS_STYLE_JUSTIFY_CONTENT_FLEX_START;
1259 mOrder = NS_STYLE_ORDER_INITIAL;
1260 mFlexGrow = 0.0f;
1261 mFlexShrink = 1.0f;
1262 mZIndex.SetAutoValue();
1263 // Other members get their default constructors
1264 // which initialize them to representations of their respective initial value.
1265 // mGridTemplateAreas: nullptr for 'none'
1266 // mGridTemplate{Rows,Columns}: false and empty arrays for 'none'
1267 // mGrid{Column,Row}{Start,End}: false/0/empty values for 'auto'
1270 nsStylePosition::~nsStylePosition(void)
1272 MOZ_COUNT_DTOR(nsStylePosition);
1275 nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
1276 : mOffset(aSource.mOffset)
1277 , mWidth(aSource.mWidth)
1278 , mMinWidth(aSource.mMinWidth)
1279 , mMaxWidth(aSource.mMaxWidth)
1280 , mHeight(aSource.mHeight)
1281 , mMinHeight(aSource.mMinHeight)
1282 , mMaxHeight(aSource.mMaxHeight)
1283 , mFlexBasis(aSource.mFlexBasis)
1284 , mGridAutoColumnsMin(aSource.mGridAutoColumnsMin)
1285 , mGridAutoColumnsMax(aSource.mGridAutoColumnsMax)
1286 , mGridAutoRowsMin(aSource.mGridAutoRowsMin)
1287 , mGridAutoRowsMax(aSource.mGridAutoRowsMax)
1288 , mGridAutoFlow(aSource.mGridAutoFlow)
1289 , mBoxSizing(aSource.mBoxSizing)
1290 , mAlignContent(aSource.mAlignContent)
1291 , mAlignItems(aSource.mAlignItems)
1292 , mAlignSelf(aSource.mAlignSelf)
1293 , mFlexDirection(aSource.mFlexDirection)
1294 , mFlexWrap(aSource.mFlexWrap)
1295 , mJustifyContent(aSource.mJustifyContent)
1296 , mOrder(aSource.mOrder)
1297 , mFlexGrow(aSource.mFlexGrow)
1298 , mFlexShrink(aSource.mFlexShrink)
1299 , mZIndex(aSource.mZIndex)
1300 , mGridTemplateColumns(aSource.mGridTemplateColumns)
1301 , mGridTemplateRows(aSource.mGridTemplateRows)
1302 , mGridTemplateAreas(aSource.mGridTemplateAreas)
1303 , mGridColumnStart(aSource.mGridColumnStart)
1304 , mGridColumnEnd(aSource.mGridColumnEnd)
1305 , mGridRowStart(aSource.mGridRowStart)
1306 , mGridRowEnd(aSource.mGridRowEnd)
1308 MOZ_COUNT_CTOR(nsStylePosition);
1311 static bool
1312 IsAutonessEqual(const nsStyleSides& aSides1, const nsStyleSides& aSides2)
1314 NS_FOR_CSS_SIDES(side) {
1315 if ((aSides1.GetUnit(side) == eStyleUnit_Auto) !=
1316 (aSides2.GetUnit(side) == eStyleUnit_Auto)) {
1317 return false;
1320 return true;
1323 nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) const
1325 nsChangeHint hint =
1326 (mZIndex == aOther.mZIndex) ? NS_STYLE_HINT_NONE : nsChangeHint_RepaintFrame;
1328 if (mOrder != aOther.mOrder) {
1329 // "order" impacts both layout order and stacking order, so we need both a
1330 // reflow and a repaint when it changes. (Technically, we only need a
1331 // reflow if we're in a multi-line flexbox (which we can't be sure about,
1332 // since that's determined by styling on our parent) -- there, "order" can
1333 // affect which flex line we end up on, & hence can affect our sizing by
1334 // changing the group of flex items we're competing with for space.)
1335 return NS_CombineHint(hint, NS_CombineHint(nsChangeHint_RepaintFrame,
1336 nsChangeHint_AllReflowHints));
1339 if (mBoxSizing != aOther.mBoxSizing) {
1340 // Can affect both widths and heights; just a bad scene.
1341 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1344 // Properties that apply to flex items:
1345 // XXXdholbert These should probably be more targeted (bug 819536)
1346 if (mAlignSelf != aOther.mAlignSelf ||
1347 mFlexBasis != aOther.mFlexBasis ||
1348 mFlexGrow != aOther.mFlexGrow ||
1349 mFlexShrink != aOther.mFlexShrink) {
1350 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1353 // Properties that apply to flex containers:
1354 // - flex-direction can swap a flex container between vertical & horizontal.
1355 // - align-items can change the sizing of a flex container & the positioning
1356 // of its children.
1357 // - flex-wrap changes whether a flex container's children are wrapped, which
1358 // impacts their sizing/positioning and hence impacts the container's size.
1359 if (mAlignItems != aOther.mAlignItems ||
1360 mFlexDirection != aOther.mFlexDirection ||
1361 mFlexWrap != aOther.mFlexWrap) {
1362 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1365 // Properties that apply to grid containers:
1366 // FIXME: only for grid containers
1367 // (ie. 'display: grid' or 'display: inline-grid')
1368 if (mGridTemplateColumns != aOther.mGridTemplateColumns ||
1369 mGridTemplateRows != aOther.mGridTemplateRows ||
1370 mGridTemplateAreas != aOther.mGridTemplateAreas ||
1371 mGridAutoColumnsMin != aOther.mGridAutoColumnsMin ||
1372 mGridAutoColumnsMax != aOther.mGridAutoColumnsMax ||
1373 mGridAutoRowsMin != aOther.mGridAutoRowsMin ||
1374 mGridAutoRowsMax != aOther.mGridAutoRowsMax ||
1375 mGridAutoFlow != aOther.mGridAutoFlow) {
1376 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1379 // Properties that apply to grid items:
1380 // FIXME: only for grid items
1381 // (ie. parent frame is 'display: grid' or 'display: inline-grid')
1382 if (mGridColumnStart != aOther.mGridColumnStart ||
1383 mGridColumnEnd != aOther.mGridColumnEnd ||
1384 mGridRowStart != aOther.mGridRowStart ||
1385 mGridRowEnd != aOther.mGridRowEnd) {
1386 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1389 // Changing justify-content on a flexbox might affect the positioning of its
1390 // children, but it won't affect any sizing.
1391 if (mJustifyContent != aOther.mJustifyContent) {
1392 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
1395 // Properties that apply only to multi-line flex containers:
1396 // 'align-content' can change the positioning & sizing of a multi-line flex
1397 // container's children when there's extra space in the cross axis, but it
1398 // shouldn't affect the container's own sizing.
1400 // NOTE: If we get here, we know that mFlexWrap == aOther.mFlexWrap
1401 // (otherwise, we would've returned earlier). So it doesn't matter which one
1402 // of those we check to see if we're multi-line.
1403 if (mFlexWrap != NS_STYLE_FLEX_WRAP_NOWRAP &&
1404 mAlignContent != aOther.mAlignContent) {
1405 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
1408 if (mHeight != aOther.mHeight ||
1409 mMinHeight != aOther.mMinHeight ||
1410 mMaxHeight != aOther.mMaxHeight) {
1411 // Height changes can affect descendant intrinsic sizes due to replaced
1412 // elements with percentage heights in descendants which also have
1413 // percentage heights. And due to our not-so-great computation of mVResize
1414 // in nsHTMLReflowState, they do need to force reflow of the whole subtree.
1415 // XXXbz due to XUL caching heights as well, height changes also need to
1416 // clear ancestor intrinsics!
1417 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1420 if (mWidth != aOther.mWidth ||
1421 mMinWidth != aOther.mMinWidth ||
1422 mMaxWidth != aOther.mMaxWidth) {
1423 // None of our width differences can affect descendant intrinsic
1424 // sizes and none of them need to force children to reflow.
1425 return
1426 NS_CombineHint(hint,
1427 NS_SubtractHint(nsChangeHint_AllReflowHints,
1428 NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
1429 nsChangeHint_NeedDirtyReflow)));
1432 // If width and height have not changed, but any of the offsets have changed,
1433 // then return the respective hints so that we would hopefully be able to
1434 // avoid reflowing.
1435 // Note that it is possible that we'll need to reflow when processing
1436 // restyles, but we don't have enough information to make a good decision
1437 // right now.
1438 // Don't try to handle changes between "auto" and non-auto efficiently;
1439 // that's tricky to do and will hardly ever be able to avoid a reflow.
1440 if (mOffset != aOther.mOffset) {
1441 if (IsAutonessEqual(mOffset, aOther.mOffset)) {
1442 NS_UpdateHint(hint, nsChangeHint(nsChangeHint_RecomputePosition |
1443 nsChangeHint_UpdateOverflow));
1444 } else {
1445 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1448 return hint;
1451 /* static */ bool
1452 nsStylePosition::WidthCoordDependsOnContainer(const nsStyleCoord &aCoord)
1454 return aCoord.HasPercent() ||
1455 (aCoord.GetUnit() == eStyleUnit_Enumerated &&
1456 (aCoord.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT ||
1457 aCoord.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE));
1460 // --------------------
1461 // nsStyleTable
1464 nsStyleTable::nsStyleTable()
1466 MOZ_COUNT_CTOR(nsStyleTable);
1467 // values not inherited
1468 mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
1469 mSpan = 1;
1472 nsStyleTable::~nsStyleTable(void)
1474 MOZ_COUNT_DTOR(nsStyleTable);
1477 nsStyleTable::nsStyleTable(const nsStyleTable& aSource)
1478 : mLayoutStrategy(aSource.mLayoutStrategy)
1479 , mSpan(aSource.mSpan)
1481 MOZ_COUNT_CTOR(nsStyleTable);
1484 nsChangeHint nsStyleTable::CalcDifference(const nsStyleTable& aOther) const
1486 if (mSpan != aOther.mSpan ||
1487 mLayoutStrategy != aOther.mLayoutStrategy)
1488 return NS_STYLE_HINT_FRAMECHANGE;
1489 return NS_STYLE_HINT_NONE;
1492 // -----------------------
1493 // nsStyleTableBorder
1495 nsStyleTableBorder::nsStyleTableBorder(nsPresContext* aPresContext)
1497 MOZ_COUNT_CTOR(nsStyleTableBorder);
1498 mBorderCollapse = NS_STYLE_BORDER_SEPARATE;
1500 nsCompatibility compatMode = eCompatibility_FullStandards;
1501 if (aPresContext)
1502 compatMode = aPresContext->CompatibilityMode();
1503 mEmptyCells = (compatMode == eCompatibility_NavQuirks)
1504 ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
1505 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
1506 mCaptionSide = NS_STYLE_CAPTION_SIDE_TOP;
1507 mBorderSpacingX = 0;
1508 mBorderSpacingY = 0;
1511 nsStyleTableBorder::~nsStyleTableBorder(void)
1513 MOZ_COUNT_DTOR(nsStyleTableBorder);
1516 nsStyleTableBorder::nsStyleTableBorder(const nsStyleTableBorder& aSource)
1517 : mBorderSpacingX(aSource.mBorderSpacingX)
1518 , mBorderSpacingY(aSource.mBorderSpacingY)
1519 , mBorderCollapse(aSource.mBorderCollapse)
1520 , mCaptionSide(aSource.mCaptionSide)
1521 , mEmptyCells(aSource.mEmptyCells)
1523 MOZ_COUNT_CTOR(nsStyleTableBorder);
1526 nsChangeHint nsStyleTableBorder::CalcDifference(const nsStyleTableBorder& aOther) const
1528 // Border-collapse changes need a reframe, because we use a different frame
1529 // class for table cells in the collapsed border model. This is used to
1530 // conserve memory when using the separated border model (collapsed borders
1531 // require extra state to be stored).
1532 if (mBorderCollapse != aOther.mBorderCollapse) {
1533 return NS_STYLE_HINT_FRAMECHANGE;
1536 if ((mCaptionSide == aOther.mCaptionSide) &&
1537 (mBorderSpacingX == aOther.mBorderSpacingX) &&
1538 (mBorderSpacingY == aOther.mBorderSpacingY)) {
1539 if (mEmptyCells == aOther.mEmptyCells)
1540 return NS_STYLE_HINT_NONE;
1541 return NS_STYLE_HINT_VISUAL;
1543 else
1544 return NS_STYLE_HINT_REFLOW;
1547 // --------------------
1548 // nsStyleColor
1551 nsStyleColor::nsStyleColor(nsPresContext* aPresContext)
1553 MOZ_COUNT_CTOR(nsStyleColor);
1554 mColor = aPresContext->DefaultColor();
1557 nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
1559 MOZ_COUNT_CTOR(nsStyleColor);
1560 mColor = aSource.mColor;
1563 nsChangeHint nsStyleColor::CalcDifference(const nsStyleColor& aOther) const
1565 if (mColor == aOther.mColor)
1566 return NS_STYLE_HINT_NONE;
1567 return NS_STYLE_HINT_VISUAL;
1570 // --------------------
1571 // nsStyleGradient
1573 bool
1574 nsStyleGradient::operator==(const nsStyleGradient& aOther) const
1576 NS_ABORT_IF_FALSE(mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
1577 mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1578 "incorrect combination of shape and size");
1579 NS_ABORT_IF_FALSE(aOther.mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
1580 aOther.mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1581 "incorrect combination of shape and size");
1583 if (mShape != aOther.mShape ||
1584 mSize != aOther.mSize ||
1585 mRepeating != aOther.mRepeating ||
1586 mLegacySyntax != aOther.mLegacySyntax ||
1587 mBgPosX != aOther.mBgPosX ||
1588 mBgPosY != aOther.mBgPosY ||
1589 mAngle != aOther.mAngle ||
1590 mRadiusX != aOther.mRadiusX ||
1591 mRadiusY != aOther.mRadiusY)
1592 return false;
1594 if (mStops.Length() != aOther.mStops.Length())
1595 return false;
1597 for (uint32_t i = 0; i < mStops.Length(); i++) {
1598 if (mStops[i].mLocation != aOther.mStops[i].mLocation ||
1599 mStops[i].mColor != aOther.mStops[i].mColor)
1600 return false;
1603 return true;
1606 nsStyleGradient::nsStyleGradient(void)
1607 : mShape(NS_STYLE_GRADIENT_SHAPE_LINEAR)
1608 , mSize(NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)
1609 , mRepeating(false)
1610 , mLegacySyntax(false)
1614 bool
1615 nsStyleGradient::IsOpaque()
1617 for (uint32_t i = 0; i < mStops.Length(); i++) {
1618 if (NS_GET_A(mStops[i].mColor) < 255)
1619 return false;
1621 return true;
1624 bool
1625 nsStyleGradient::HasCalc()
1627 for (uint32_t i = 0; i < mStops.Length(); i++) {
1628 if (mStops[i].mLocation.IsCalcUnit())
1629 return true;
1631 return mBgPosX.IsCalcUnit() || mBgPosY.IsCalcUnit() || mAngle.IsCalcUnit() ||
1632 mRadiusX.IsCalcUnit() || mRadiusY.IsCalcUnit();
1635 // --------------------
1636 // nsStyleImage
1639 nsStyleImage::nsStyleImage()
1640 : mType(eStyleImageType_Null)
1641 , mCropRect(nullptr)
1642 #ifdef DEBUG
1643 , mImageTracked(false)
1644 #endif
1646 MOZ_COUNT_CTOR(nsStyleImage);
1649 nsStyleImage::~nsStyleImage()
1651 MOZ_COUNT_DTOR(nsStyleImage);
1652 if (mType != eStyleImageType_Null)
1653 SetNull();
1656 nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
1657 : mType(eStyleImageType_Null)
1658 , mCropRect(nullptr)
1659 #ifdef DEBUG
1660 , mImageTracked(false)
1661 #endif
1663 // We need our own copy constructor because we don't want
1664 // to copy the reference count
1665 MOZ_COUNT_CTOR(nsStyleImage);
1666 DoCopy(aOther);
1669 nsStyleImage&
1670 nsStyleImage::operator=(const nsStyleImage& aOther)
1672 if (this != &aOther)
1673 DoCopy(aOther);
1675 return *this;
1678 void
1679 nsStyleImage::DoCopy(const nsStyleImage& aOther)
1681 SetNull();
1683 if (aOther.mType == eStyleImageType_Image)
1684 SetImageData(aOther.mImage);
1685 else if (aOther.mType == eStyleImageType_Gradient)
1686 SetGradientData(aOther.mGradient);
1687 else if (aOther.mType == eStyleImageType_Element)
1688 SetElementId(aOther.mElementId);
1690 SetCropRect(aOther.mCropRect);
1693 void
1694 nsStyleImage::SetNull()
1696 NS_ABORT_IF_FALSE(!mImageTracked,
1697 "Calling SetNull() with image tracked!");
1699 if (mType == eStyleImageType_Gradient)
1700 mGradient->Release();
1701 else if (mType == eStyleImageType_Image)
1702 NS_RELEASE(mImage);
1703 else if (mType == eStyleImageType_Element)
1704 NS_Free(mElementId);
1706 mType = eStyleImageType_Null;
1707 mCropRect = nullptr;
1710 void
1711 nsStyleImage::SetImageData(imgRequestProxy* aImage)
1713 NS_ABORT_IF_FALSE(!mImageTracked,
1714 "Setting a new image without untracking the old one!");
1716 NS_IF_ADDREF(aImage);
1718 if (mType != eStyleImageType_Null)
1719 SetNull();
1721 if (aImage) {
1722 mImage = aImage;
1723 mType = eStyleImageType_Image;
1725 mSubImages.Clear();
1728 void
1729 nsStyleImage::TrackImage(nsPresContext* aContext)
1731 // Sanity
1732 NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
1733 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image,
1734 "Can't track image when there isn't one!");
1736 // Register the image with the document
1737 nsIDocument* doc = aContext->Document();
1738 if (doc)
1739 doc->AddImage(mImage);
1741 // Mark state
1742 #ifdef DEBUG
1743 mImageTracked = true;
1744 #endif
1747 void
1748 nsStyleImage::UntrackImage(nsPresContext* aContext)
1750 // Sanity
1751 NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
1752 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image,
1753 "Can't untrack image when there isn't one!");
1755 // Unregister the image with the document
1756 nsIDocument* doc = aContext->Document();
1757 if (doc)
1758 doc->RemoveImage(mImage, nsIDocument::REQUEST_DISCARD);
1760 // Mark state
1761 #ifdef DEBUG
1762 mImageTracked = false;
1763 #endif
1766 void
1767 nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
1769 if (aGradient)
1770 aGradient->AddRef();
1772 if (mType != eStyleImageType_Null)
1773 SetNull();
1775 if (aGradient) {
1776 mGradient = aGradient;
1777 mType = eStyleImageType_Gradient;
1781 void
1782 nsStyleImage::SetElementId(const char16_t* aElementId)
1784 if (mType != eStyleImageType_Null)
1785 SetNull();
1787 if (aElementId) {
1788 mElementId = NS_strdup(aElementId);
1789 mType = eStyleImageType_Element;
1793 void
1794 nsStyleImage::SetCropRect(nsStyleSides* aCropRect)
1796 if (aCropRect) {
1797 mCropRect = new nsStyleSides(*aCropRect);
1798 // There is really not much we can do if 'new' fails
1799 } else {
1800 mCropRect = nullptr;
1804 static int32_t
1805 ConvertToPixelCoord(const nsStyleCoord& aCoord, int32_t aPercentScale)
1807 double pixelValue;
1808 switch (aCoord.GetUnit()) {
1809 case eStyleUnit_Percent:
1810 pixelValue = aCoord.GetPercentValue() * aPercentScale;
1811 break;
1812 case eStyleUnit_Factor:
1813 pixelValue = aCoord.GetFactorValue();
1814 break;
1815 default:
1816 NS_NOTREACHED("unexpected unit for image crop rect");
1817 return 0;
1819 NS_ABORT_IF_FALSE(pixelValue >= 0, "we ensured non-negative while parsing");
1820 pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow
1821 return NS_lround(pixelValue);
1824 bool
1825 nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
1826 bool* aIsEntireImage) const
1828 if (mType != eStyleImageType_Image)
1829 return false;
1831 nsCOMPtr<imgIContainer> imageContainer;
1832 mImage->GetImage(getter_AddRefs(imageContainer));
1833 if (!imageContainer)
1834 return false;
1836 nsIntSize imageSize;
1837 imageContainer->GetWidth(&imageSize.width);
1838 imageContainer->GetHeight(&imageSize.height);
1839 if (imageSize.width <= 0 || imageSize.height <= 0)
1840 return false;
1842 int32_t left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width);
1843 int32_t top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height);
1844 int32_t right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width);
1845 int32_t bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height);
1847 // IntersectRect() returns an empty rect if we get negative width or height
1848 nsIntRect cropRect(left, top, right - left, bottom - top);
1849 nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
1850 aActualCropRect.IntersectRect(imageRect, cropRect);
1852 if (aIsEntireImage)
1853 *aIsEntireImage = aActualCropRect.IsEqualInterior(imageRect);
1854 return true;
1857 nsresult
1858 nsStyleImage::StartDecoding() const
1860 if ((mType == eStyleImageType_Image) && mImage)
1861 return mImage->StartDecoding();
1862 return NS_OK;
1865 bool
1866 nsStyleImage::IsOpaque() const
1868 if (!IsComplete())
1869 return false;
1871 if (mType == eStyleImageType_Gradient)
1872 return mGradient->IsOpaque();
1874 if (mType == eStyleImageType_Element)
1875 return false;
1877 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, "unexpected image type");
1879 nsCOMPtr<imgIContainer> imageContainer;
1880 mImage->GetImage(getter_AddRefs(imageContainer));
1881 NS_ABORT_IF_FALSE(imageContainer, "IsComplete() said image container is ready");
1883 // Check if the crop region of the current image frame is opaque.
1884 if (imageContainer->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) {
1885 if (!mCropRect)
1886 return true;
1888 // Must make sure if mCropRect contains at least a pixel.
1889 // XXX Is this optimization worth it? Maybe I should just return false.
1890 nsIntRect actualCropRect;
1891 bool rv = ComputeActualCropRect(actualCropRect);
1892 NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
1893 return rv && !actualCropRect.IsEmpty();
1896 return false;
1899 bool
1900 nsStyleImage::IsComplete() const
1902 switch (mType) {
1903 case eStyleImageType_Null:
1904 return false;
1905 case eStyleImageType_Gradient:
1906 case eStyleImageType_Element:
1907 return true;
1908 case eStyleImageType_Image:
1910 uint32_t status = imgIRequest::STATUS_ERROR;
1911 return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
1912 (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
1913 (status & imgIRequest::STATUS_FRAME_COMPLETE);
1915 default:
1916 NS_NOTREACHED("unexpected image type");
1917 return false;
1921 bool
1922 nsStyleImage::IsLoaded() const
1924 switch (mType) {
1925 case eStyleImageType_Null:
1926 return false;
1927 case eStyleImageType_Gradient:
1928 case eStyleImageType_Element:
1929 return true;
1930 case eStyleImageType_Image:
1932 uint32_t status = imgIRequest::STATUS_ERROR;
1933 return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
1934 !(status & imgIRequest::STATUS_ERROR) &&
1935 (status & imgIRequest::STATUS_LOAD_COMPLETE);
1937 default:
1938 NS_NOTREACHED("unexpected image type");
1939 return false;
1943 static inline bool
1944 EqualRects(const nsStyleSides* aRect1, const nsStyleSides* aRect2)
1946 return aRect1 == aRect2 || /* handles null== null, and optimize */
1947 (aRect1 && aRect2 && *aRect1 == *aRect2);
1950 bool
1951 nsStyleImage::operator==(const nsStyleImage& aOther) const
1953 if (mType != aOther.mType)
1954 return false;
1956 if (!EqualRects(mCropRect, aOther.mCropRect))
1957 return false;
1959 if (mType == eStyleImageType_Image)
1960 return EqualImages(mImage, aOther.mImage);
1962 if (mType == eStyleImageType_Gradient)
1963 return *mGradient == *aOther.mGradient;
1965 if (mType == eStyleImageType_Element)
1966 return NS_strcmp(mElementId, aOther.mElementId) == 0;
1968 return true;
1971 // --------------------
1972 // nsStyleBackground
1975 nsStyleBackground::nsStyleBackground()
1976 : mAttachmentCount(1)
1977 , mClipCount(1)
1978 , mOriginCount(1)
1979 , mRepeatCount(1)
1980 , mPositionCount(1)
1981 , mImageCount(1)
1982 , mSizeCount(1)
1983 , mBlendModeCount(1)
1984 , mBackgroundColor(NS_RGBA(0, 0, 0, 0))
1986 MOZ_COUNT_CTOR(nsStyleBackground);
1987 Layer *onlyLayer = mLayers.AppendElement();
1988 NS_ASSERTION(onlyLayer, "auto array must have room for 1 element");
1989 onlyLayer->SetInitialValues();
1992 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
1993 : mAttachmentCount(aSource.mAttachmentCount)
1994 , mClipCount(aSource.mClipCount)
1995 , mOriginCount(aSource.mOriginCount)
1996 , mRepeatCount(aSource.mRepeatCount)
1997 , mPositionCount(aSource.mPositionCount)
1998 , mImageCount(aSource.mImageCount)
1999 , mSizeCount(aSource.mSizeCount)
2000 , mBlendModeCount(aSource.mBlendModeCount)
2001 , mLayers(aSource.mLayers) // deep copy
2002 , mBackgroundColor(aSource.mBackgroundColor)
2004 MOZ_COUNT_CTOR(nsStyleBackground);
2005 // If the deep copy of mLayers failed, truncate the counts.
2006 uint32_t count = mLayers.Length();
2007 if (count != aSource.mLayers.Length()) {
2008 NS_WARNING("truncating counts due to out-of-memory");
2009 mAttachmentCount = std::max(mAttachmentCount, count);
2010 mClipCount = std::max(mClipCount, count);
2011 mOriginCount = std::max(mOriginCount, count);
2012 mRepeatCount = std::max(mRepeatCount, count);
2013 mPositionCount = std::max(mPositionCount, count);
2014 mImageCount = std::max(mImageCount, count);
2015 mSizeCount = std::max(mSizeCount, count);
2016 mBlendModeCount = std::max(mSizeCount, count);
2020 nsStyleBackground::~nsStyleBackground()
2022 MOZ_COUNT_DTOR(nsStyleBackground);
2025 void
2026 nsStyleBackground::Destroy(nsPresContext* aContext)
2028 // Untrack all the images stored in our layers
2029 for (uint32_t i = 0; i < mImageCount; ++i)
2030 mLayers[i].UntrackImages(aContext);
2032 this->~nsStyleBackground();
2033 aContext->PresShell()->
2034 FreeByObjectID(nsPresArena::nsStyleBackground_id, this);
2037 nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const
2039 const nsStyleBackground* moreLayers =
2040 mImageCount > aOther.mImageCount ? this : &aOther;
2041 const nsStyleBackground* lessLayers =
2042 mImageCount > aOther.mImageCount ? &aOther : this;
2044 bool hasVisualDifference = false;
2046 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, moreLayers) {
2047 if (i < lessLayers->mImageCount) {
2048 if (moreLayers->mLayers[i] != lessLayers->mLayers[i]) {
2049 if ((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) ||
2050 (lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element))
2051 return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
2052 hasVisualDifference = true;
2054 } else {
2055 if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)
2056 return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
2057 hasVisualDifference = true;
2061 if (hasVisualDifference || mBackgroundColor != aOther.mBackgroundColor)
2062 return NS_STYLE_HINT_VISUAL;
2064 return NS_STYLE_HINT_NONE;
2067 bool nsStyleBackground::HasFixedBackground() const
2069 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, this) {
2070 const Layer &layer = mLayers[i];
2071 if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
2072 !layer.mImage.IsEmpty()) {
2073 return true;
2076 return false;
2079 bool nsStyleBackground::IsTransparent() const
2081 return BottomLayer().mImage.IsEmpty() &&
2082 mImageCount == 1 &&
2083 NS_GET_A(mBackgroundColor) == 0;
2086 void
2087 nsStyleBackground::Position::SetInitialValues()
2089 // Initial value is "0% 0%"
2090 mXPosition.mPercent = 0.0f;
2091 mXPosition.mLength = 0;
2092 mXPosition.mHasPercent = true;
2093 mYPosition.mPercent = 0.0f;
2094 mYPosition.mLength = 0;
2095 mYPosition.mHasPercent = true;
2098 bool
2099 nsStyleBackground::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImage) const
2101 NS_ABORT_IF_FALSE(aImage.GetType() != eStyleImageType_Null,
2102 "caller should have handled this");
2104 // If either dimension contains a non-zero percentage, rendering for that
2105 // dimension straightforwardly depends on frame size.
2106 if ((mWidthType == eLengthPercentage && mWidth.mPercent != 0.0f) ||
2107 (mHeightType == eLengthPercentage && mHeight.mPercent != 0.0f)) {
2108 return true;
2111 // So too for contain and cover.
2112 if (mWidthType == eContain || mWidthType == eCover) {
2113 return true;
2116 // If both dimensions are fixed lengths, there's no dependency.
2117 if (mWidthType == eLengthPercentage && mHeightType == eLengthPercentage) {
2118 return false;
2121 NS_ABORT_IF_FALSE((mWidthType == eLengthPercentage && mHeightType == eAuto) ||
2122 (mWidthType == eAuto && mHeightType == eLengthPercentage) ||
2123 (mWidthType == eAuto && mHeightType == eAuto),
2124 "logic error");
2126 nsStyleImageType type = aImage.GetType();
2128 // Gradient rendering depends on frame size when auto is involved because
2129 // gradients have no intrinsic ratio or dimensions, and therefore the relevant
2130 // dimension is "treat[ed] as 100%".
2131 if (type == eStyleImageType_Gradient) {
2132 return true;
2135 // XXX Element rendering for auto or fixed length doesn't depend on frame size
2136 // according to the spec. However, we don't implement the spec yet, so
2137 // for now we bail and say element() plus auto affects ultimate size.
2138 if (type == eStyleImageType_Element) {
2139 return true;
2142 if (type == eStyleImageType_Image) {
2143 nsCOMPtr<imgIContainer> imgContainer;
2144 aImage.GetImageData()->GetImage(getter_AddRefs(imgContainer));
2145 if (imgContainer) {
2146 nsIntSize imageSize;
2147 nsSize imageRatio;
2148 bool hasWidth, hasHeight;
2149 nsLayoutUtils::ComputeSizeForDrawing(imgContainer, imageSize, imageRatio,
2150 hasWidth, hasHeight);
2152 // If the image has a fixed width and height, rendering never depends on
2153 // the frame size.
2154 if (hasWidth && hasHeight) {
2155 return false;
2158 // If the image has an intrinsic ratio, rendering will depend on frame
2159 // size when background-size is all auto.
2160 if (imageRatio != nsSize(0, 0)) {
2161 return mWidthType == mHeightType;
2164 // Otherwise, rendering depends on frame size when the image dimensions
2165 // and background-size don't complement each other.
2166 return !(hasWidth && mHeightType == eLengthPercentage) &&
2167 !(hasHeight && mWidthType == eLengthPercentage);
2169 } else {
2170 NS_NOTREACHED("missed an enum value");
2173 // Passed the gauntlet: no dependency.
2174 return false;
2177 void
2178 nsStyleBackground::Size::SetInitialValues()
2180 mWidthType = mHeightType = eAuto;
2183 bool
2184 nsStyleBackground::Size::operator==(const Size& aOther) const
2186 NS_ABORT_IF_FALSE(mWidthType < eDimensionType_COUNT,
2187 "bad mWidthType for this");
2188 NS_ABORT_IF_FALSE(mHeightType < eDimensionType_COUNT,
2189 "bad mHeightType for this");
2190 NS_ABORT_IF_FALSE(aOther.mWidthType < eDimensionType_COUNT,
2191 "bad mWidthType for aOther");
2192 NS_ABORT_IF_FALSE(aOther.mHeightType < eDimensionType_COUNT,
2193 "bad mHeightType for aOther");
2195 return mWidthType == aOther.mWidthType &&
2196 mHeightType == aOther.mHeightType &&
2197 (mWidthType != eLengthPercentage || mWidth == aOther.mWidth) &&
2198 (mHeightType != eLengthPercentage || mHeight == aOther.mHeight);
2201 void
2202 nsStyleBackground::Repeat::SetInitialValues()
2204 mXRepeat = NS_STYLE_BG_REPEAT_REPEAT;
2205 mYRepeat = NS_STYLE_BG_REPEAT_REPEAT;
2208 nsStyleBackground::Layer::Layer()
2212 nsStyleBackground::Layer::~Layer()
2216 void
2217 nsStyleBackground::Layer::SetInitialValues()
2219 mAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL;
2220 mClip = NS_STYLE_BG_CLIP_BORDER;
2221 mOrigin = NS_STYLE_BG_ORIGIN_PADDING;
2222 mRepeat.SetInitialValues();
2223 mBlendMode = NS_STYLE_BLEND_NORMAL;
2224 mPosition.SetInitialValues();
2225 mSize.SetInitialValues();
2226 mImage.SetNull();
2229 bool
2230 nsStyleBackground::Layer::RenderingMightDependOnPositioningAreaSizeChange() const
2232 // Do we even have an image?
2233 if (mImage.IsEmpty()) {
2234 return false;
2237 return mPosition.DependsOnPositioningAreaSize() ||
2238 mSize.DependsOnPositioningAreaSize(mImage);
2241 bool
2242 nsStyleBackground::Layer::operator==(const Layer& aOther) const
2244 return mAttachment == aOther.mAttachment &&
2245 mClip == aOther.mClip &&
2246 mOrigin == aOther.mOrigin &&
2247 mRepeat == aOther.mRepeat &&
2248 mBlendMode == aOther.mBlendMode &&
2249 mPosition == aOther.mPosition &&
2250 mSize == aOther.mSize &&
2251 mImage == aOther.mImage;
2254 // --------------------
2255 // nsStyleDisplay
2257 void nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
2259 switch (aTimingFunctionType) {
2260 case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
2261 mType = StepStart;
2262 mSteps = 1;
2263 return;
2264 case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END:
2265 mType = StepEnd;
2266 mSteps = 1;
2267 return;
2268 default:
2269 mType = Function;
2270 break;
2273 static_assert(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE == 0 &&
2274 NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR == 1 &&
2275 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN == 2 &&
2276 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT == 3 &&
2277 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT == 4,
2278 "transition timing function constants not as expected");
2280 static const float timingFunctionValues[5][4] = {
2281 { 0.25f, 0.10f, 0.25f, 1.00f }, // ease
2282 { 0.00f, 0.00f, 1.00f, 1.00f }, // linear
2283 { 0.42f, 0.00f, 1.00f, 1.00f }, // ease-in
2284 { 0.00f, 0.00f, 0.58f, 1.00f }, // ease-out
2285 { 0.42f, 0.00f, 0.58f, 1.00f } // ease-in-out
2288 NS_ABORT_IF_FALSE(0 <= aTimingFunctionType && aTimingFunctionType < 5,
2289 "keyword out of range");
2290 mFunc.mX1 = timingFunctionValues[aTimingFunctionType][0];
2291 mFunc.mY1 = timingFunctionValues[aTimingFunctionType][1];
2292 mFunc.mX2 = timingFunctionValues[aTimingFunctionType][2];
2293 mFunc.mY2 = timingFunctionValues[aTimingFunctionType][3];
2296 mozilla::StyleTransition::StyleTransition(const StyleTransition& aCopy)
2297 : mTimingFunction(aCopy.mTimingFunction)
2298 , mDuration(aCopy.mDuration)
2299 , mDelay(aCopy.mDelay)
2300 , mProperty(aCopy.mProperty)
2301 , mUnknownProperty(aCopy.mUnknownProperty)
2305 void
2306 mozilla::StyleTransition::SetInitialValues()
2308 mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
2309 mDuration = 0.0;
2310 mDelay = 0.0;
2311 mProperty = eCSSPropertyExtra_all_properties;
2314 void
2315 mozilla::StyleTransition::SetUnknownProperty(const nsAString& aUnknownProperty)
2317 NS_ASSERTION(nsCSSProps::LookupProperty(aUnknownProperty,
2318 nsCSSProps::eEnabledForAllContent) ==
2319 eCSSProperty_UNKNOWN,
2320 "should be unknown property");
2321 mProperty = eCSSProperty_UNKNOWN;
2322 mUnknownProperty = do_GetAtom(aUnknownProperty);
2325 mozilla::StyleAnimation::StyleAnimation(const mozilla::StyleAnimation& aCopy)
2326 : mTimingFunction(aCopy.mTimingFunction)
2327 , mDuration(aCopy.mDuration)
2328 , mDelay(aCopy.mDelay)
2329 , mName(aCopy.mName)
2330 , mDirection(aCopy.mDirection)
2331 , mFillMode(aCopy.mFillMode)
2332 , mPlayState(aCopy.mPlayState)
2333 , mIterationCount(aCopy.mIterationCount)
2337 void
2338 mozilla::StyleAnimation::SetInitialValues()
2340 mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
2341 mDuration = 0.0;
2342 mDelay = 0.0;
2343 mName = EmptyString();
2344 mDirection = NS_STYLE_ANIMATION_DIRECTION_NORMAL;
2345 mFillMode = NS_STYLE_ANIMATION_FILL_MODE_NONE;
2346 mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING;
2347 mIterationCount = 1.0f;
2350 nsStyleDisplay::nsStyleDisplay()
2351 : mWillChangeBitField(0)
2353 MOZ_COUNT_CTOR(nsStyleDisplay);
2354 mAppearance = NS_THEME_NONE;
2355 mDisplay = NS_STYLE_DISPLAY_INLINE;
2356 mOriginalDisplay = mDisplay;
2357 mPosition = NS_STYLE_POSITION_STATIC;
2358 mFloats = NS_STYLE_FLOAT_NONE;
2359 mOriginalFloats = mFloats;
2360 mBreakType = NS_STYLE_CLEAR_NONE;
2361 mBreakInside = NS_STYLE_PAGE_BREAK_AUTO;
2362 mBreakBefore = false;
2363 mBreakAfter = false;
2364 mOverflowX = NS_STYLE_OVERFLOW_VISIBLE;
2365 mOverflowY = NS_STYLE_OVERFLOW_VISIBLE;
2366 mOverflowClipBox = NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX;
2367 mResize = NS_STYLE_RESIZE_NONE;
2368 mClipFlags = NS_STYLE_CLIP_AUTO;
2369 mClip.SetRect(0,0,0,0);
2370 mOpacity = 1.0f;
2371 mSpecifiedTransform = nullptr;
2372 mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
2373 mTransformOrigin[1].SetPercentValue(0.5f);
2374 mTransformOrigin[2].SetCoordValue(0);
2375 mPerspectiveOrigin[0].SetPercentValue(0.5f);
2376 mPerspectiveOrigin[1].SetPercentValue(0.5f);
2377 mChildPerspective.SetNoneValue();
2378 mBackfaceVisibility = NS_STYLE_BACKFACE_VISIBILITY_VISIBLE;
2379 mTransformStyle = NS_STYLE_TRANSFORM_STYLE_FLAT;
2380 mOrient = NS_STYLE_ORIENT_AUTO;
2381 mMixBlendMode = NS_STYLE_BLEND_NORMAL;
2382 mTouchAction = NS_STYLE_TOUCH_ACTION_AUTO;
2384 mTransitions.AppendElement();
2385 NS_ABORT_IF_FALSE(mTransitions.Length() == 1,
2386 "appending within auto buffer should never fail");
2387 mTransitions[0].SetInitialValues();
2388 mTransitionTimingFunctionCount = 1;
2389 mTransitionDurationCount = 1;
2390 mTransitionDelayCount = 1;
2391 mTransitionPropertyCount = 1;
2393 mAnimations.AppendElement();
2394 NS_ABORT_IF_FALSE(mAnimations.Length() == 1,
2395 "appending within auto buffer should never fail");
2396 mAnimations[0].SetInitialValues();
2397 mAnimationTimingFunctionCount = 1;
2398 mAnimationDurationCount = 1;
2399 mAnimationDelayCount = 1;
2400 mAnimationNameCount = 1;
2401 mAnimationDirectionCount = 1;
2402 mAnimationFillModeCount = 1;
2403 mAnimationPlayStateCount = 1;
2404 mAnimationIterationCountCount = 1;
2407 nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
2408 : mBinding(aSource.mBinding)
2409 , mClip(aSource.mClip)
2410 , mOpacity(aSource.mOpacity)
2411 , mDisplay(aSource.mDisplay)
2412 , mOriginalDisplay(aSource.mOriginalDisplay)
2413 , mAppearance(aSource.mAppearance)
2414 , mPosition(aSource.mPosition)
2415 , mFloats(aSource.mFloats)
2416 , mOriginalFloats(aSource.mOriginalFloats)
2417 , mBreakType(aSource.mBreakType)
2418 , mBreakInside(aSource.mBreakInside)
2419 , mBreakBefore(aSource.mBreakBefore)
2420 , mBreakAfter(aSource.mBreakAfter)
2421 , mOverflowX(aSource.mOverflowX)
2422 , mOverflowY(aSource.mOverflowY)
2423 , mOverflowClipBox(aSource.mOverflowClipBox)
2424 , mResize(aSource.mResize)
2425 , mClipFlags(aSource.mClipFlags)
2426 , mOrient(aSource.mOrient)
2427 , mMixBlendMode(aSource.mMixBlendMode)
2428 , mWillChangeBitField(aSource.mWillChangeBitField)
2429 , mWillChange(aSource.mWillChange)
2430 , mTouchAction(aSource.mTouchAction)
2431 , mBackfaceVisibility(aSource.mBackfaceVisibility)
2432 , mTransformStyle(aSource.mTransformStyle)
2433 , mSpecifiedTransform(aSource.mSpecifiedTransform)
2434 , mChildPerspective(aSource.mChildPerspective)
2435 , mTransitions(aSource.mTransitions)
2436 , mTransitionTimingFunctionCount(aSource.mTransitionTimingFunctionCount)
2437 , mTransitionDurationCount(aSource.mTransitionDurationCount)
2438 , mTransitionDelayCount(aSource.mTransitionDelayCount)
2439 , mTransitionPropertyCount(aSource.mTransitionPropertyCount)
2440 , mAnimations(aSource.mAnimations)
2441 , mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount)
2442 , mAnimationDurationCount(aSource.mAnimationDurationCount)
2443 , mAnimationDelayCount(aSource.mAnimationDelayCount)
2444 , mAnimationNameCount(aSource.mAnimationNameCount)
2445 , mAnimationDirectionCount(aSource.mAnimationDirectionCount)
2446 , mAnimationFillModeCount(aSource.mAnimationFillModeCount)
2447 , mAnimationPlayStateCount(aSource.mAnimationPlayStateCount)
2448 , mAnimationIterationCountCount(aSource.mAnimationIterationCountCount)
2450 MOZ_COUNT_CTOR(nsStyleDisplay);
2452 /* Copy over transform origin. */
2453 mTransformOrigin[0] = aSource.mTransformOrigin[0];
2454 mTransformOrigin[1] = aSource.mTransformOrigin[1];
2455 mTransformOrigin[2] = aSource.mTransformOrigin[2];
2456 mPerspectiveOrigin[0] = aSource.mPerspectiveOrigin[0];
2457 mPerspectiveOrigin[1] = aSource.mPerspectiveOrigin[1];
2460 nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
2462 nsChangeHint hint = nsChangeHint(0);
2464 if (!EqualURIs(mBinding, aOther.mBinding)
2465 || mPosition != aOther.mPosition
2466 || mDisplay != aOther.mDisplay
2467 || (mFloats == NS_STYLE_FLOAT_NONE) != (aOther.mFloats == NS_STYLE_FLOAT_NONE)
2468 || mOverflowX != aOther.mOverflowX
2469 || mOverflowY != aOther.mOverflowY
2470 || mResize != aOther.mResize)
2471 NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
2473 if ((mAppearance == NS_THEME_TEXTFIELD &&
2474 aOther.mAppearance != NS_THEME_TEXTFIELD) ||
2475 (mAppearance != NS_THEME_TEXTFIELD &&
2476 aOther.mAppearance == NS_THEME_TEXTFIELD)) {
2477 // This is for <input type=number> where we allow authors to specify a
2478 // |-moz-appearance:textfield| to get a control without a spinner. (The
2479 // spinner is present for |-moz-appearance:number-input| but also other
2480 // values such as 'none'.) We need to reframe since we want to use
2481 // nsTextControlFrame instead of nsNumberControlFrame if the author
2482 // specifies 'textfield'.
2483 return nsChangeHint_ReconstructFrame;
2486 if (mFloats != aOther.mFloats) {
2487 // Changing which side we float on doesn't affect descendants directly
2488 NS_UpdateHint(hint,
2489 NS_SubtractHint(nsChangeHint_AllReflowHints,
2490 NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
2491 nsChangeHint_NeedDirtyReflow)));
2494 // XXX the following is conservative, for now: changing float breaking shouldn't
2495 // necessarily require a repaint, reflow should suffice.
2496 if (mBreakType != aOther.mBreakType
2497 || mBreakInside != aOther.mBreakInside
2498 || mBreakBefore != aOther.mBreakBefore
2499 || mBreakAfter != aOther.mBreakAfter
2500 || mAppearance != aOther.mAppearance
2501 || mOrient != aOther.mOrient
2502 || mOverflowClipBox != aOther.mOverflowClipBox
2503 || mClipFlags != aOther.mClipFlags)
2504 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints,
2505 nsChangeHint_RepaintFrame));
2507 if (!mClip.IsEqualInterior(aOther.mClip)) {
2508 // If the clip has changed, we just need to update overflow areas. DLBI
2509 // will handle the invalidation.
2510 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_UpdateOverflow,
2511 nsChangeHint_SchedulePaint));
2514 if (mOpacity != aOther.mOpacity) {
2515 // If we're going from the optimized >=0.99 opacity value to 1.0 or back, then
2516 // repaint the frame because DLBI will not catch the invalidation. Otherwise,
2517 // just update the opacity layer.
2518 if ((mOpacity >= 0.99f && mOpacity < 1.0f && aOther.mOpacity == 1.0f) ||
2519 (aOther.mOpacity >= 0.99f && aOther.mOpacity < 1.0f && mOpacity == 1.0f)) {
2520 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
2521 } else {
2522 NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
2526 if (mMixBlendMode != aOther.mMixBlendMode) {
2527 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
2530 /* If we've added or removed the transform property, we need to reconstruct the frame to add
2531 * or remove the view object, and also to handle abs-pos and fixed-pos containers.
2533 if (HasTransformStyle() != aOther.HasTransformStyle()) {
2534 // We do not need to apply nsChangeHint_UpdateTransformLayer since
2535 // nsChangeHint_RepaintFrame will forcibly invalidate the frame area and
2536 // ensure layers are rebuilt (or removed).
2537 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AddOrRemoveTransform,
2538 NS_CombineHint(nsChangeHint_UpdateOverflow,
2539 nsChangeHint_RepaintFrame)));
2541 else if (HasTransformStyle()) {
2542 /* Otherwise, if we've kept the property lying around and we already had a
2543 * transform, we need to see whether or not we've changed the transform.
2544 * If so, we need to recompute its overflow rect (which probably changed
2545 * if the transform changed) and to redraw within the bounds of that new
2546 * overflow rect.
2548 if (!mSpecifiedTransform != !aOther.mSpecifiedTransform ||
2549 (mSpecifiedTransform &&
2550 *mSpecifiedTransform != *aOther.mSpecifiedTransform)) {
2551 NS_UpdateHint(hint, nsChangeHint_UpdateTransformLayer);
2553 if (mSpecifiedTransform &&
2554 aOther.mSpecifiedTransform) {
2555 NS_UpdateHint(hint, nsChangeHint_UpdatePostTransformOverflow);
2556 } else {
2557 NS_UpdateHint(hint, nsChangeHint_UpdateOverflow);
2561 const nsChangeHint kUpdateOverflowAndRepaintHint =
2562 NS_CombineHint(nsChangeHint_UpdateOverflow, nsChangeHint_RepaintFrame);
2563 for (uint8_t index = 0; index < 3; ++index)
2564 if (mTransformOrigin[index] != aOther.mTransformOrigin[index]) {
2565 NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
2566 break;
2569 for (uint8_t index = 0; index < 2; ++index)
2570 if (mPerspectiveOrigin[index] != aOther.mPerspectiveOrigin[index]) {
2571 NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
2572 break;
2575 if (mChildPerspective != aOther.mChildPerspective ||
2576 mTransformStyle != aOther.mTransformStyle)
2577 NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
2579 if (mBackfaceVisibility != aOther.mBackfaceVisibility)
2580 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
2583 // Note that the HasTransformStyle() != aOther.HasTransformStyle()
2584 // test above handles relevant changes in the
2585 // NS_STYLE_WILL_CHANGE_TRANSFORM bit, which in turn handles frame
2586 // reconstruction for changes in the containing block of
2587 // fixed-positioned elements. Other than that, all changes to
2588 // 'will-change' can be handled by a repaint.
2589 uint8_t willChangeBitsChanged =
2590 mWillChangeBitField ^ aOther.mWillChangeBitField;
2591 if (willChangeBitsChanged) {
2592 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
2595 // Note: Our current behavior for handling changes to the
2596 // transition-duration, transition-delay, and transition-timing-function
2597 // properties is to do nothing. In other words, the transition
2598 // property that matters is what it is when the transition begins, and
2599 // we don't stop a transition later because the transition property
2600 // changed.
2601 // We do handle changes to transition-property, but we don't need to
2602 // bother with anything here, since the transition manager is notified
2603 // of any style context change anyway.
2605 // Note: Likewise, for animation-*, the animation manager gets
2606 // notified about every new style context constructed, and it uses
2607 // that opportunity to handle dynamic changes appropriately.
2609 return hint;
2612 // --------------------
2613 // nsStyleVisibility
2616 nsStyleVisibility::nsStyleVisibility(nsPresContext* aPresContext)
2618 MOZ_COUNT_CTOR(nsStyleVisibility);
2619 uint32_t bidiOptions = aPresContext->GetBidi();
2620 if (GET_BIDI_OPTION_DIRECTION(bidiOptions) == IBMBIDI_TEXTDIRECTION_RTL)
2621 mDirection = NS_STYLE_DIRECTION_RTL;
2622 else
2623 mDirection = NS_STYLE_DIRECTION_LTR;
2625 mVisible = NS_STYLE_VISIBILITY_VISIBLE;
2626 mPointerEvents = NS_STYLE_POINTER_EVENTS_AUTO;
2627 mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
2630 nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource)
2632 MOZ_COUNT_CTOR(nsStyleVisibility);
2633 mImageOrientation = aSource.mImageOrientation;
2634 mDirection = aSource.mDirection;
2635 mVisible = aSource.mVisible;
2636 mPointerEvents = aSource.mPointerEvents;
2637 mWritingMode = aSource.mWritingMode;
2640 nsChangeHint nsStyleVisibility::CalcDifference(const nsStyleVisibility& aOther) const
2642 nsChangeHint hint = nsChangeHint(0);
2644 if (mDirection != aOther.mDirection || mWritingMode != aOther.mWritingMode) {
2645 NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
2646 } else {
2647 if ((mImageOrientation != aOther.mImageOrientation)) {
2648 NS_UpdateHint(hint, nsChangeHint_AllReflowHints);
2649 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
2651 if (mVisible != aOther.mVisible) {
2652 if ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) ||
2653 (NS_STYLE_VISIBILITY_COLLAPSE == aOther.mVisible)) {
2654 NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
2655 } else {
2656 NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
2659 if (mPointerEvents != aOther.mPointerEvents) {
2660 // nsSVGPathGeometryFrame's mRect depends on stroke _and_ on the value
2661 // of pointer-events. See nsSVGPathGeometryFrame::ReflowSVG's use of
2662 // GetHitTestFlags. (Only a reflow, no visual change.)
2663 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
2664 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
2667 return hint;
2670 nsStyleContentData::~nsStyleContentData()
2672 NS_ABORT_IF_FALSE(!mImageTracked,
2673 "nsStyleContentData being destroyed while still tracking image!");
2674 if (mType == eStyleContentType_Image) {
2675 NS_IF_RELEASE(mContent.mImage);
2676 } else if (mType == eStyleContentType_Counter ||
2677 mType == eStyleContentType_Counters) {
2678 mContent.mCounters->Release();
2679 } else if (mContent.mString) {
2680 NS_Free(mContent.mString);
2684 nsStyleContentData& nsStyleContentData::operator=(const nsStyleContentData& aOther)
2686 if (this == &aOther)
2687 return *this;
2688 this->~nsStyleContentData();
2689 new (this) nsStyleContentData();
2691 mType = aOther.mType;
2692 if (mType == eStyleContentType_Image) {
2693 mContent.mImage = aOther.mContent.mImage;
2694 NS_IF_ADDREF(mContent.mImage);
2695 } else if (mType == eStyleContentType_Counter ||
2696 mType == eStyleContentType_Counters) {
2697 mContent.mCounters = aOther.mContent.mCounters;
2698 mContent.mCounters->AddRef();
2699 } else if (aOther.mContent.mString) {
2700 mContent.mString = NS_strdup(aOther.mContent.mString);
2701 } else {
2702 mContent.mString = nullptr;
2704 return *this;
2707 bool nsStyleContentData::operator==(const nsStyleContentData& aOther) const
2709 if (mType != aOther.mType)
2710 return false;
2711 if (mType == eStyleContentType_Image) {
2712 if (!mContent.mImage || !aOther.mContent.mImage)
2713 return mContent.mImage == aOther.mContent.mImage;
2714 bool eq;
2715 nsCOMPtr<nsIURI> thisURI, otherURI;
2716 mContent.mImage->GetURI(getter_AddRefs(thisURI));
2717 aOther.mContent.mImage->GetURI(getter_AddRefs(otherURI));
2718 return thisURI == otherURI || // handles null==null
2719 (thisURI && otherURI &&
2720 NS_SUCCEEDED(thisURI->Equals(otherURI, &eq)) &&
2721 eq);
2723 if (mType == eStyleContentType_Counter ||
2724 mType == eStyleContentType_Counters)
2725 return *mContent.mCounters == *aOther.mContent.mCounters;
2726 return safe_strcmp(mContent.mString, aOther.mContent.mString) == 0;
2729 void
2730 nsStyleContentData::TrackImage(nsPresContext* aContext)
2732 // Sanity
2733 NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
2734 NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
2735 "Trying to do image tracking on non-image!");
2736 NS_ABORT_IF_FALSE(mContent.mImage,
2737 "Can't track image when there isn't one!");
2739 // Register the image with the document
2740 nsIDocument* doc = aContext->Document();
2741 if (doc)
2742 doc->AddImage(mContent.mImage);
2744 // Mark state
2745 #ifdef DEBUG
2746 mImageTracked = true;
2747 #endif
2750 void
2751 nsStyleContentData::UntrackImage(nsPresContext* aContext)
2753 // Sanity
2754 NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
2755 NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
2756 "Trying to do image tracking on non-image!");
2757 NS_ABORT_IF_FALSE(mContent.mImage,
2758 "Can't untrack image when there isn't one!");
2760 // Unregister the image with the document
2761 nsIDocument* doc = aContext->Document();
2762 if (doc)
2763 doc->RemoveImage(mContent.mImage, nsIDocument::REQUEST_DISCARD);
2765 // Mark state
2766 #ifdef DEBUG
2767 mImageTracked = false;
2768 #endif
2772 //-----------------------
2773 // nsStyleContent
2776 nsStyleContent::nsStyleContent(void)
2777 : mMarkerOffset(),
2778 mContents(nullptr),
2779 mIncrements(nullptr),
2780 mResets(nullptr),
2781 mContentCount(0),
2782 mIncrementCount(0),
2783 mResetCount(0)
2785 MOZ_COUNT_CTOR(nsStyleContent);
2786 mMarkerOffset.SetAutoValue();
2789 nsStyleContent::~nsStyleContent(void)
2791 MOZ_COUNT_DTOR(nsStyleContent);
2792 DELETE_ARRAY_IF(mContents);
2793 DELETE_ARRAY_IF(mIncrements);
2794 DELETE_ARRAY_IF(mResets);
2797 void
2798 nsStyleContent::Destroy(nsPresContext* aContext)
2800 // Unregister any images we might have with the document.
2801 for (uint32_t i = 0; i < mContentCount; ++i) {
2802 if ((mContents[i].mType == eStyleContentType_Image) &&
2803 mContents[i].mContent.mImage) {
2804 mContents[i].UntrackImage(aContext);
2808 this->~nsStyleContent();
2809 aContext->PresShell()->
2810 FreeByObjectID(nsPresArena::nsStyleContent_id, this);
2813 nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
2814 :mMarkerOffset(),
2815 mContents(nullptr),
2816 mIncrements(nullptr),
2817 mResets(nullptr),
2818 mContentCount(0),
2819 mIncrementCount(0),
2820 mResetCount(0)
2823 MOZ_COUNT_CTOR(nsStyleContent);
2824 mMarkerOffset = aSource.mMarkerOffset;
2826 uint32_t index;
2827 if (NS_SUCCEEDED(AllocateContents(aSource.ContentCount()))) {
2828 for (index = 0; index < mContentCount; index++) {
2829 ContentAt(index) = aSource.ContentAt(index);
2833 if (NS_SUCCEEDED(AllocateCounterIncrements(aSource.CounterIncrementCount()))) {
2834 for (index = 0; index < mIncrementCount; index++) {
2835 const nsStyleCounterData *data = aSource.GetCounterIncrementAt(index);
2836 mIncrements[index].mCounter = data->mCounter;
2837 mIncrements[index].mValue = data->mValue;
2841 if (NS_SUCCEEDED(AllocateCounterResets(aSource.CounterResetCount()))) {
2842 for (index = 0; index < mResetCount; index++) {
2843 const nsStyleCounterData *data = aSource.GetCounterResetAt(index);
2844 mResets[index].mCounter = data->mCounter;
2845 mResets[index].mValue = data->mValue;
2850 nsChangeHint nsStyleContent::CalcDifference(const nsStyleContent& aOther) const
2852 // In ReResolveStyleContext we assume that if there's no existing
2853 // ::before or ::after and we don't have to restyle children of the
2854 // node then we can't end up with a ::before or ::after due to the
2855 // restyle of the node itself. That's not quite true, but the only
2856 // exception to the above is when the 'content' property of the node
2857 // changes and the pseudo-element inherits the changed value. Since
2858 // the code here triggers a frame change on the node in that case,
2859 // the optimization in ReResolveStyleContext is ok. But if we ever
2860 // change this code to not reconstruct frames on changes to the
2861 // 'content' property, then we will need to revisit the optimization
2862 // in ReResolveStyleContext.
2864 if (mContentCount != aOther.mContentCount ||
2865 mIncrementCount != aOther.mIncrementCount ||
2866 mResetCount != aOther.mResetCount) {
2867 return NS_STYLE_HINT_FRAMECHANGE;
2870 uint32_t ix = mContentCount;
2871 while (0 < ix--) {
2872 if (mContents[ix] != aOther.mContents[ix]) {
2873 // Unfortunately we need to reframe here; a simple reflow
2874 // will not pick up different text or different image URLs,
2875 // since we set all that up in the CSSFrameConstructor
2876 return NS_STYLE_HINT_FRAMECHANGE;
2879 ix = mIncrementCount;
2880 while (0 < ix--) {
2881 if ((mIncrements[ix].mValue != aOther.mIncrements[ix].mValue) ||
2882 (mIncrements[ix].mCounter != aOther.mIncrements[ix].mCounter)) {
2883 return NS_STYLE_HINT_FRAMECHANGE;
2886 ix = mResetCount;
2887 while (0 < ix--) {
2888 if ((mResets[ix].mValue != aOther.mResets[ix].mValue) ||
2889 (mResets[ix].mCounter != aOther.mResets[ix].mCounter)) {
2890 return NS_STYLE_HINT_FRAMECHANGE;
2893 if (mMarkerOffset != aOther.mMarkerOffset) {
2894 return NS_STYLE_HINT_REFLOW;
2896 return NS_STYLE_HINT_NONE;
2899 nsresult nsStyleContent::AllocateContents(uint32_t aCount)
2901 // We need to run the destructors of the elements of mContents, so we
2902 // delete and reallocate even if aCount == mContentCount. (If
2903 // nsStyleContentData had its members private and managed their
2904 // ownership on setting, we wouldn't need this, but that seems
2905 // unnecessary at this point.)
2906 DELETE_ARRAY_IF(mContents);
2907 if (aCount) {
2908 mContents = new nsStyleContentData[aCount];
2909 if (! mContents) {
2910 mContentCount = 0;
2911 return NS_ERROR_OUT_OF_MEMORY;
2914 mContentCount = aCount;
2915 return NS_OK;
2918 // ---------------------
2919 // nsStyleQuotes
2922 nsStyleQuotes::nsStyleQuotes(void)
2923 : mQuotesCount(0),
2924 mQuotes(nullptr)
2926 MOZ_COUNT_CTOR(nsStyleQuotes);
2927 SetInitial();
2930 nsStyleQuotes::~nsStyleQuotes(void)
2932 MOZ_COUNT_DTOR(nsStyleQuotes);
2933 DELETE_ARRAY_IF(mQuotes);
2936 nsStyleQuotes::nsStyleQuotes(const nsStyleQuotes& aSource)
2937 : mQuotesCount(0),
2938 mQuotes(nullptr)
2940 MOZ_COUNT_CTOR(nsStyleQuotes);
2941 CopyFrom(aSource);
2944 void
2945 nsStyleQuotes::SetInitial()
2947 // The initial value for quotes is the en-US typographic convention:
2948 // outermost are LEFT and RIGHT DOUBLE QUOTATION MARK, alternating
2949 // with LEFT and RIGHT SINGLE QUOTATION MARK.
2950 static const char16_t initialQuotes[8] = {
2951 0x201C, 0, 0x201D, 0, 0x2018, 0, 0x2019, 0
2954 if (NS_SUCCEEDED(AllocateQuotes(2))) {
2955 SetQuotesAt(0,
2956 nsDependentString(&initialQuotes[0], 1),
2957 nsDependentString(&initialQuotes[2], 1));
2958 SetQuotesAt(1,
2959 nsDependentString(&initialQuotes[4], 1),
2960 nsDependentString(&initialQuotes[6], 1));
2964 void
2965 nsStyleQuotes::CopyFrom(const nsStyleQuotes& aSource)
2967 if (NS_SUCCEEDED(AllocateQuotes(aSource.QuotesCount()))) {
2968 uint32_t count = (mQuotesCount * 2);
2969 for (uint32_t index = 0; index < count; index += 2) {
2970 aSource.GetQuotesAt(index, mQuotes[index], mQuotes[index + 1]);
2975 nsChangeHint nsStyleQuotes::CalcDifference(const nsStyleQuotes& aOther) const
2977 // If the quotes implementation is ever going to change we might not need
2978 // a framechange here and a reflow should be sufficient. See bug 35768.
2979 if (mQuotesCount == aOther.mQuotesCount) {
2980 uint32_t ix = (mQuotesCount * 2);
2981 while (0 < ix--) {
2982 if (mQuotes[ix] != aOther.mQuotes[ix]) {
2983 return NS_STYLE_HINT_FRAMECHANGE;
2987 return NS_STYLE_HINT_NONE;
2989 return NS_STYLE_HINT_FRAMECHANGE;
2992 // --------------------
2993 // nsStyleTextReset
2996 nsStyleTextReset::nsStyleTextReset(void)
2998 MOZ_COUNT_CTOR(nsStyleTextReset);
2999 mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated);
3000 mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
3001 mTextDecorationColor = NS_RGB(0,0,0);
3002 mTextDecorationStyle =
3003 NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND;
3004 mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL;
3007 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
3009 MOZ_COUNT_CTOR(nsStyleTextReset);
3010 *this = aSource;
3013 nsStyleTextReset::~nsStyleTextReset(void)
3015 MOZ_COUNT_DTOR(nsStyleTextReset);
3018 nsChangeHint nsStyleTextReset::CalcDifference(const nsStyleTextReset& aOther) const
3020 if (mVerticalAlign == aOther.mVerticalAlign
3021 && mUnicodeBidi == aOther.mUnicodeBidi) {
3022 uint8_t lineStyle = GetDecorationStyle();
3023 uint8_t otherLineStyle = aOther.GetDecorationStyle();
3024 if (mTextDecorationLine != aOther.mTextDecorationLine ||
3025 lineStyle != otherLineStyle) {
3026 // Repaint for other style decoration lines because they must be in
3027 // default overflow rect
3028 nsChangeHint hint = NS_STYLE_HINT_VISUAL;
3029 NS_UpdateHint(hint, nsChangeHint_UpdateSubtreeOverflow);
3030 return hint;
3033 // Repaint for decoration color changes
3034 nscolor decColor, otherDecColor;
3035 bool isFG, otherIsFG;
3036 GetDecorationColor(decColor, isFG);
3037 aOther.GetDecorationColor(otherDecColor, otherIsFG);
3038 if (isFG != otherIsFG || (!isFG && decColor != otherDecColor)) {
3039 return NS_STYLE_HINT_VISUAL;
3042 if (mTextOverflow != aOther.mTextOverflow) {
3043 return NS_STYLE_HINT_VISUAL;
3045 return NS_STYLE_HINT_NONE;
3047 return NS_STYLE_HINT_REFLOW;
3050 // Allowed to return one of NS_STYLE_HINT_NONE, NS_STYLE_HINT_REFLOW
3051 // or NS_STYLE_HINT_VISUAL. Currently we just return NONE or REFLOW, though.
3052 // XXXbz can this not return a more specific hint? If that's ever
3053 // changed, nsStyleBorder::CalcDifference will need changing too.
3054 static nsChangeHint
3055 CalcShadowDifference(nsCSSShadowArray* lhs,
3056 nsCSSShadowArray* rhs)
3058 if (lhs == rhs)
3059 return NS_STYLE_HINT_NONE;
3061 if (!lhs || !rhs || lhs->Length() != rhs->Length())
3062 return NS_STYLE_HINT_REFLOW;
3064 for (uint32_t i = 0; i < lhs->Length(); ++i) {
3065 if (*lhs->ShadowAt(i) != *rhs->ShadowAt(i))
3066 return NS_STYLE_HINT_REFLOW;
3068 return NS_STYLE_HINT_NONE;
3071 // --------------------
3072 // nsStyleText
3075 nsStyleText::nsStyleText(void)
3077 MOZ_COUNT_CTOR(nsStyleText);
3078 mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
3079 mTextAlignLast = NS_STYLE_TEXT_ALIGN_AUTO;
3080 mTextAlignTrue = false;
3081 mTextAlignLastTrue = false;
3082 mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
3083 mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
3084 mWordBreak = NS_STYLE_WORDBREAK_NORMAL;
3085 mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
3086 mHyphens = NS_STYLE_HYPHENS_MANUAL;
3087 mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO;
3088 mTextOrientation = NS_STYLE_TEXT_ORIENTATION_AUTO;
3089 mTextCombineUpright = NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE;
3090 mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN;
3092 mLetterSpacing.SetNormalValue();
3093 mLineHeight.SetNormalValue();
3094 mTextIndent.SetCoordValue(0);
3095 mWordSpacing = 0;
3097 mTextShadow = nullptr;
3098 mTabSize = NS_STYLE_TABSIZE_INITIAL;
3101 nsStyleText::nsStyleText(const nsStyleText& aSource)
3102 : mTextAlign(aSource.mTextAlign),
3103 mTextAlignLast(aSource.mTextAlignLast),
3104 mTextAlignTrue(false),
3105 mTextAlignLastTrue(false),
3106 mTextTransform(aSource.mTextTransform),
3107 mWhiteSpace(aSource.mWhiteSpace),
3108 mWordBreak(aSource.mWordBreak),
3109 mWordWrap(aSource.mWordWrap),
3110 mHyphens(aSource.mHyphens),
3111 mTextSizeAdjust(aSource.mTextSizeAdjust),
3112 mTextOrientation(aSource.mTextOrientation),
3113 mTextCombineUpright(aSource.mTextCombineUpright),
3114 mControlCharacterVisibility(aSource.mControlCharacterVisibility),
3115 mTabSize(aSource.mTabSize),
3116 mWordSpacing(aSource.mWordSpacing),
3117 mLetterSpacing(aSource.mLetterSpacing),
3118 mLineHeight(aSource.mLineHeight),
3119 mTextIndent(aSource.mTextIndent),
3120 mTextShadow(aSource.mTextShadow)
3122 MOZ_COUNT_CTOR(nsStyleText);
3125 nsStyleText::~nsStyleText(void)
3127 MOZ_COUNT_DTOR(nsStyleText);
3130 nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
3132 if (WhiteSpaceOrNewlineIsSignificant() !=
3133 aOther.WhiteSpaceOrNewlineIsSignificant()) {
3134 // This may require construction of suppressed text frames
3135 return NS_STYLE_HINT_FRAMECHANGE;
3138 if (mTextCombineUpright != aOther.mTextCombineUpright ||
3139 mControlCharacterVisibility != aOther.mControlCharacterVisibility) {
3140 return nsChangeHint_ReconstructFrame;
3143 if ((mTextAlign != aOther.mTextAlign) ||
3144 (mTextAlignLast != aOther.mTextAlignLast) ||
3145 (mTextAlignTrue != aOther.mTextAlignTrue) ||
3146 (mTextAlignLastTrue != aOther.mTextAlignLastTrue) ||
3147 (mTextTransform != aOther.mTextTransform) ||
3148 (mWhiteSpace != aOther.mWhiteSpace) ||
3149 (mWordBreak != aOther.mWordBreak) ||
3150 (mWordWrap != aOther.mWordWrap) ||
3151 (mHyphens != aOther.mHyphens) ||
3152 (mTextSizeAdjust != aOther.mTextSizeAdjust) ||
3153 (mTextOrientation != aOther.mTextOrientation) ||
3154 (mLetterSpacing != aOther.mLetterSpacing) ||
3155 (mLineHeight != aOther.mLineHeight) ||
3156 (mTextIndent != aOther.mTextIndent) ||
3157 (mWordSpacing != aOther.mWordSpacing) ||
3158 (mTabSize != aOther.mTabSize))
3159 return NS_STYLE_HINT_REFLOW;
3161 return CalcShadowDifference(mTextShadow, aOther.mTextShadow);
3164 //-----------------------
3165 // nsStyleUserInterface
3168 nsCursorImage::nsCursorImage()
3169 : mHaveHotspot(false)
3170 , mHotspotX(0.0f)
3171 , mHotspotY(0.0f)
3175 nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
3176 : mHaveHotspot(aOther.mHaveHotspot)
3177 , mHotspotX(aOther.mHotspotX)
3178 , mHotspotY(aOther.mHotspotY)
3180 SetImage(aOther.GetImage());
3183 nsCursorImage::~nsCursorImage()
3185 SetImage(nullptr);
3188 nsCursorImage&
3189 nsCursorImage::operator=(const nsCursorImage& aOther)
3191 if (this != &aOther) {
3192 mHaveHotspot = aOther.mHaveHotspot;
3193 mHotspotX = aOther.mHotspotX;
3194 mHotspotY = aOther.mHotspotY;
3195 SetImage(aOther.GetImage());
3198 return *this;
3201 nsStyleUserInterface::nsStyleUserInterface(void)
3203 MOZ_COUNT_CTOR(nsStyleUserInterface);
3204 mUserInput = NS_STYLE_USER_INPUT_AUTO;
3205 mUserModify = NS_STYLE_USER_MODIFY_READ_ONLY;
3206 mUserFocus = NS_STYLE_USER_FOCUS_NONE;
3208 mCursor = NS_STYLE_CURSOR_AUTO; // fix for bugzilla bug 51113
3210 mCursorArrayLength = 0;
3211 mCursorArray = nullptr;
3214 nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource) :
3215 mUserInput(aSource.mUserInput),
3216 mUserModify(aSource.mUserModify),
3217 mUserFocus(aSource.mUserFocus),
3218 mCursor(aSource.mCursor)
3220 MOZ_COUNT_CTOR(nsStyleUserInterface);
3221 CopyCursorArrayFrom(aSource);
3224 nsStyleUserInterface::~nsStyleUserInterface(void)
3226 MOZ_COUNT_DTOR(nsStyleUserInterface);
3227 delete [] mCursorArray;
3230 nsChangeHint nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aOther) const
3232 nsChangeHint hint = nsChangeHint(0);
3233 if (mCursor != aOther.mCursor)
3234 NS_UpdateHint(hint, nsChangeHint_UpdateCursor);
3236 // We could do better. But it wouldn't be worth it, URL-specified cursors are
3237 // rare.
3238 if (mCursorArrayLength > 0 || aOther.mCursorArrayLength > 0)
3239 NS_UpdateHint(hint, nsChangeHint_UpdateCursor);
3241 if (mUserModify != aOther.mUserModify)
3242 NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
3244 if ((mUserInput != aOther.mUserInput) &&
3245 ((NS_STYLE_USER_INPUT_NONE == mUserInput) ||
3246 (NS_STYLE_USER_INPUT_NONE == aOther.mUserInput))) {
3247 NS_UpdateHint(hint, NS_STYLE_HINT_FRAMECHANGE);
3250 // ignore mUserFocus
3252 return hint;
3255 void
3256 nsStyleUserInterface::CopyCursorArrayFrom(const nsStyleUserInterface& aSource)
3258 mCursorArray = nullptr;
3259 mCursorArrayLength = 0;
3260 if (aSource.mCursorArrayLength) {
3261 mCursorArray = new nsCursorImage[aSource.mCursorArrayLength];
3262 if (mCursorArray) {
3263 mCursorArrayLength = aSource.mCursorArrayLength;
3264 for (uint32_t i = 0; i < mCursorArrayLength; ++i)
3265 mCursorArray[i] = aSource.mCursorArray[i];
3270 //-----------------------
3271 // nsStyleUIReset
3274 nsStyleUIReset::nsStyleUIReset(void)
3276 MOZ_COUNT_CTOR(nsStyleUIReset);
3277 mUserSelect = NS_STYLE_USER_SELECT_AUTO;
3278 mForceBrokenImageIcon = 0;
3279 mIMEMode = NS_STYLE_IME_MODE_AUTO;
3280 mWindowShadow = NS_STYLE_WINDOW_SHADOW_DEFAULT;
3283 nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
3285 MOZ_COUNT_CTOR(nsStyleUIReset);
3286 mUserSelect = aSource.mUserSelect;
3287 mForceBrokenImageIcon = aSource.mForceBrokenImageIcon;
3288 mIMEMode = aSource.mIMEMode;
3289 mWindowShadow = aSource.mWindowShadow;
3292 nsStyleUIReset::~nsStyleUIReset(void)
3294 MOZ_COUNT_DTOR(nsStyleUIReset);
3297 nsChangeHint nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const
3299 // ignore mIMEMode
3300 if (mForceBrokenImageIcon != aOther.mForceBrokenImageIcon)
3301 return NS_STYLE_HINT_FRAMECHANGE;
3302 if (mWindowShadow != aOther.mWindowShadow) {
3303 // We really need just an nsChangeHint_SyncFrameView, except
3304 // on an ancestor of the frame, so we get that by doing a
3305 // reflow.
3306 return NS_STYLE_HINT_REFLOW;
3308 if (mUserSelect != aOther.mUserSelect)
3309 return NS_STYLE_HINT_VISUAL;
3310 return NS_STYLE_HINT_NONE;
3313 //-----------------------
3314 // nsStyleVariables
3317 nsStyleVariables::nsStyleVariables()
3319 MOZ_COUNT_CTOR(nsStyleVariables);
3322 nsStyleVariables::nsStyleVariables(const nsStyleVariables& aSource)
3324 MOZ_COUNT_CTOR(nsStyleVariables);
3327 nsStyleVariables::~nsStyleVariables(void)
3329 MOZ_COUNT_DTOR(nsStyleVariables);
3332 nsChangeHint
3333 nsStyleVariables::CalcDifference(const nsStyleVariables& aOther) const
3335 return nsChangeHint(0);