Wed, 31 Dec 2014 07:16:47 +0100
Revert simplistic fix pending revisit of Mozilla integration attempt.
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"
29 #include "mozilla/Likely.h"
30 #include "nsIURI.h"
31 #include "nsIDocument.h"
32 #include <algorithm>
34 static_assert((((1 << nsStyleStructID_Length) - 1) &
35 ~(NS_STYLE_INHERIT_MASK)) == 0,
36 "Not enough bits in NS_STYLE_INHERIT_MASK");
38 inline bool IsFixedUnit(const nsStyleCoord& aCoord, bool aEnumOK)
39 {
40 return aCoord.ConvertsToLength() ||
41 (aEnumOK && aCoord.GetUnit() == eStyleUnit_Enumerated);
42 }
44 static bool EqualURIs(nsIURI *aURI1, nsIURI *aURI2)
45 {
46 bool eq;
47 return aURI1 == aURI2 || // handle null==null, and optimize
48 (aURI1 && aURI2 &&
49 NS_SUCCEEDED(aURI1->Equals(aURI2, &eq)) && // not equal on fail
50 eq);
51 }
53 static bool EqualURIs(mozilla::css::URLValue *aURI1, mozilla::css::URLValue *aURI2)
54 {
55 return aURI1 == aURI2 || // handle null==null, and optimize
56 (aURI1 && aURI2 && aURI1->URIEquals(*aURI2));
57 }
59 static bool EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
60 {
61 if (aImage1 == aImage2) {
62 return true;
63 }
65 if (!aImage1 || !aImage2) {
66 return false;
67 }
69 nsCOMPtr<nsIURI> uri1, uri2;
70 aImage1->GetURI(getter_AddRefs(uri1));
71 aImage2->GetURI(getter_AddRefs(uri2));
72 return EqualURIs(uri1, uri2);
73 }
75 // A nullsafe wrapper for strcmp. We depend on null-safety.
76 static int safe_strcmp(const char16_t* a, const char16_t* b)
77 {
78 if (!a || !b) {
79 return (int)(a - b);
80 }
81 return NS_strcmp(a, b);
82 }
84 static nsChangeHint CalcShadowDifference(nsCSSShadowArray* lhs,
85 nsCSSShadowArray* rhs);
87 // --------------------
88 // nsStyleFont
89 //
90 nsStyleFont::nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext)
91 : mFont(aFont)
92 , mGenericID(kGenericFont_NONE)
93 , mExplicitLanguage(false)
94 {
95 MOZ_COUNT_CTOR(nsStyleFont);
96 Init(aPresContext);
97 }
99 nsStyleFont::nsStyleFont(const nsStyleFont& aSrc)
100 : mFont(aSrc.mFont)
101 , mSize(aSrc.mSize)
102 , mGenericID(aSrc.mGenericID)
103 , mScriptLevel(aSrc.mScriptLevel)
104 , mMathVariant(aSrc.mMathVariant)
105 , mMathDisplay(aSrc.mMathDisplay)
106 , mExplicitLanguage(aSrc.mExplicitLanguage)
107 , mAllowZoom(aSrc.mAllowZoom)
108 , mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize)
109 , mScriptMinSize(aSrc.mScriptMinSize)
110 , mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier)
111 , mLanguage(aSrc.mLanguage)
112 {
113 MOZ_COUNT_CTOR(nsStyleFont);
114 }
116 nsStyleFont::nsStyleFont(nsPresContext* aPresContext)
117 // passing nullptr to GetDefaultFont make it use the doc language
118 : mFont(*(aPresContext->GetDefaultFont(kPresContext_DefaultVariableFont_ID,
119 nullptr)))
120 , mGenericID(kGenericFont_NONE)
121 , mExplicitLanguage(false)
122 {
123 MOZ_COUNT_CTOR(nsStyleFont);
124 Init(aPresContext);
125 }
127 void
128 nsStyleFont::Init(nsPresContext* aPresContext)
129 {
130 mSize = mFont.size = nsStyleFont::ZoomText(aPresContext, mFont.size);
131 mScriptUnconstrainedSize = mSize;
132 mScriptMinSize = aPresContext->CSSTwipsToAppUnits(
133 NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT));
134 mScriptLevel = 0;
135 mScriptSizeMultiplier = NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER;
136 mMathVariant = NS_MATHML_MATHVARIANT_NONE;
137 mMathDisplay = NS_MATHML_DISPLAYSTYLE_INLINE;
138 mAllowZoom = true;
140 nsAutoString language;
141 aPresContext->Document()->GetContentLanguage(language);
142 language.StripWhitespace();
144 // Content-Language may be a comma-separated list of language codes,
145 // in which case the HTML5 spec says to treat it as unknown
146 if (!language.IsEmpty() &&
147 language.FindChar(char16_t(',')) == kNotFound) {
148 mLanguage = do_GetAtom(language);
149 // NOTE: This does *not* count as an explicit language; in other
150 // words, it doesn't trigger language-specific hyphenation.
151 } else {
152 // we didn't find a (usable) Content-Language, so we fall back
153 // to whatever the presContext guessed from the charset
154 mLanguage = aPresContext->GetLanguageFromCharset();
155 }
156 }
158 void*
159 nsStyleFont::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
160 void* result = aContext->AllocateFromShell(sz);
161 if (result)
162 memset(result, 0, sz);
163 return result;
164 }
166 void
167 nsStyleFont::Destroy(nsPresContext* aContext) {
168 this->~nsStyleFont();
169 aContext->FreeToShell(sizeof(nsStyleFont), this);
170 }
172 void
173 nsStyleFont::EnableZoom(nsPresContext* aContext, bool aEnable)
174 {
175 if (mAllowZoom == aEnable) {
176 return;
177 }
178 mAllowZoom = aEnable;
179 if (mAllowZoom) {
180 mSize = nsStyleFont::ZoomText(aContext, mSize);
181 mFont.size = nsStyleFont::ZoomText(aContext, mFont.size);
182 mScriptUnconstrainedSize =
183 nsStyleFont::ZoomText(aContext, mScriptUnconstrainedSize);
184 } else {
185 mSize = nsStyleFont::UnZoomText(aContext, mSize);
186 mFont.size = nsStyleFont::UnZoomText(aContext, mFont.size);
187 mScriptUnconstrainedSize =
188 nsStyleFont::UnZoomText(aContext, mScriptUnconstrainedSize);
189 }
190 }
192 nsChangeHint nsStyleFont::CalcDifference(const nsStyleFont& aOther) const
193 {
194 MOZ_ASSERT(mAllowZoom == aOther.mAllowZoom,
195 "expected mAllowZoom to be the same on both nsStyleFonts");
196 if (mSize != aOther.mSize ||
197 mLanguage != aOther.mLanguage ||
198 mExplicitLanguage != aOther.mExplicitLanguage ||
199 mMathVariant != aOther.mMathVariant ||
200 mMathDisplay != aOther.mMathDisplay) {
201 return NS_STYLE_HINT_REFLOW;
202 }
203 return CalcFontDifference(mFont, aOther.mFont);
204 }
206 /* static */ nscoord
207 nsStyleFont::ZoomText(nsPresContext *aPresContext, nscoord aSize)
208 {
209 return nscoord(float(aSize) * aPresContext->TextZoom());
210 }
212 /* static */ nscoord
213 nsStyleFont::UnZoomText(nsPresContext *aPresContext, nscoord aSize)
214 {
215 return nscoord(float(aSize) / aPresContext->TextZoom());
216 }
218 nsChangeHint nsStyleFont::CalcFontDifference(const nsFont& aFont1, const nsFont& aFont2)
219 {
220 if ((aFont1.size == aFont2.size) &&
221 (aFont1.sizeAdjust == aFont2.sizeAdjust) &&
222 (aFont1.style == aFont2.style) &&
223 (aFont1.variant == aFont2.variant) &&
224 (aFont1.weight == aFont2.weight) &&
225 (aFont1.stretch == aFont2.stretch) &&
226 (aFont1.smoothing == aFont2.smoothing) &&
227 (aFont1.name == aFont2.name) &&
228 (aFont1.kerning == aFont2.kerning) &&
229 (aFont1.synthesis == aFont2.synthesis) &&
230 (aFont1.variantAlternates == aFont2.variantAlternates) &&
231 (aFont1.alternateValues == aFont2.alternateValues) &&
232 (aFont1.featureValueLookup == aFont2.featureValueLookup) &&
233 (aFont1.variantCaps == aFont2.variantCaps) &&
234 (aFont1.variantEastAsian == aFont2.variantEastAsian) &&
235 (aFont1.variantLigatures == aFont2.variantLigatures) &&
236 (aFont1.variantNumeric == aFont2.variantNumeric) &&
237 (aFont1.variantPosition == aFont2.variantPosition) &&
238 (aFont1.fontFeatureSettings == aFont2.fontFeatureSettings) &&
239 (aFont1.languageOverride == aFont2.languageOverride) &&
240 (aFont1.systemFont == aFont2.systemFont)) {
241 if ((aFont1.decorations == aFont2.decorations)) {
242 return NS_STYLE_HINT_NONE;
243 }
244 return NS_STYLE_HINT_VISUAL;
245 }
246 return NS_STYLE_HINT_REFLOW;
247 }
249 static bool IsFixedData(const nsStyleSides& aSides, bool aEnumOK)
250 {
251 NS_FOR_CSS_SIDES(side) {
252 if (!IsFixedUnit(aSides.Get(side), aEnumOK))
253 return false;
254 }
255 return true;
256 }
258 static nscoord CalcCoord(const nsStyleCoord& aCoord,
259 const nscoord* aEnumTable,
260 int32_t aNumEnums)
261 {
262 if (aCoord.GetUnit() == eStyleUnit_Enumerated) {
263 NS_ABORT_IF_FALSE(aEnumTable, "must have enum table");
264 int32_t value = aCoord.GetIntValue();
265 if (0 <= value && value < aNumEnums) {
266 return aEnumTable[aCoord.GetIntValue()];
267 }
268 NS_NOTREACHED("unexpected enum value");
269 return 0;
270 }
271 NS_ABORT_IF_FALSE(aCoord.ConvertsToLength(), "unexpected unit");
272 return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
273 }
275 nsStyleMargin::nsStyleMargin() {
276 MOZ_COUNT_CTOR(nsStyleMargin);
277 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
278 NS_FOR_CSS_SIDES(side) {
279 mMargin.Set(side, zero);
280 }
281 mHasCachedMargin = false;
282 }
284 nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc) {
285 MOZ_COUNT_CTOR(nsStyleMargin);
286 mMargin = aSrc.mMargin;
287 mHasCachedMargin = false;
288 }
290 void*
291 nsStyleMargin::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
292 void* result = aContext->AllocateFromShell(sz);
293 if (result)
294 memset(result, 0, sz);
295 return result;
296 }
298 void
299 nsStyleMargin::Destroy(nsPresContext* aContext) {
300 this->~nsStyleMargin();
301 aContext->FreeToShell(sizeof(nsStyleMargin), this);
302 }
305 void nsStyleMargin::RecalcData()
306 {
307 if (IsFixedData(mMargin, false)) {
308 NS_FOR_CSS_SIDES(side) {
309 mCachedMargin.Side(side) = CalcCoord(mMargin.Get(side), nullptr, 0);
310 }
311 mHasCachedMargin = true;
312 }
313 else
314 mHasCachedMargin = false;
315 }
317 nsChangeHint nsStyleMargin::CalcDifference(const nsStyleMargin& aOther) const
318 {
319 if (mMargin == aOther.mMargin) {
320 return NS_STYLE_HINT_NONE;
321 }
322 // Margin differences can't affect descendant intrinsic sizes and
323 // don't need to force children to reflow.
324 return NS_CombineHint(nsChangeHint_NeedReflow,
325 nsChangeHint_ClearAncestorIntrinsics);
326 }
328 nsStylePadding::nsStylePadding() {
329 MOZ_COUNT_CTOR(nsStylePadding);
330 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
331 NS_FOR_CSS_SIDES(side) {
332 mPadding.Set(side, zero);
333 }
334 mHasCachedPadding = false;
335 }
337 nsStylePadding::nsStylePadding(const nsStylePadding& aSrc) {
338 MOZ_COUNT_CTOR(nsStylePadding);
339 mPadding = aSrc.mPadding;
340 mHasCachedPadding = false;
341 }
343 void*
344 nsStylePadding::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
345 void* result = aContext->AllocateFromShell(sz);
346 if (result)
347 memset(result, 0, sz);
348 return result;
349 }
351 void
352 nsStylePadding::Destroy(nsPresContext* aContext) {
353 this->~nsStylePadding();
354 aContext->FreeToShell(sizeof(nsStylePadding), this);
355 }
357 void nsStylePadding::RecalcData()
358 {
359 if (IsFixedData(mPadding, false)) {
360 NS_FOR_CSS_SIDES(side) {
361 // Clamp negative calc() to 0.
362 mCachedPadding.Side(side) =
363 std::max(CalcCoord(mPadding.Get(side), nullptr, 0), 0);
364 }
365 mHasCachedPadding = true;
366 }
367 else
368 mHasCachedPadding = false;
369 }
371 nsChangeHint nsStylePadding::CalcDifference(const nsStylePadding& aOther) const
372 {
373 if (mPadding == aOther.mPadding) {
374 return NS_STYLE_HINT_NONE;
375 }
376 // Padding differences can't affect descendant intrinsic sizes, but do need
377 // to force children to reflow so that we can reposition them, since their
378 // offsets are from our frame bounds but our content rect's position within
379 // those bounds is moving.
380 return NS_SubtractHint(NS_STYLE_HINT_REFLOW,
381 nsChangeHint_ClearDescendantIntrinsics);
382 }
384 nsStyleBorder::nsStyleBorder(nsPresContext* aPresContext)
385 : mBorderColors(nullptr),
386 mBoxShadow(nullptr),
387 mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL),
388 mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
389 mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH),
390 mFloatEdge(NS_STYLE_FLOAT_EDGE_CONTENT),
391 mComputedBorder(0, 0, 0, 0)
392 {
393 MOZ_COUNT_CTOR(nsStyleBorder);
395 NS_FOR_CSS_HALF_CORNERS (corner) {
396 mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
397 }
399 nscoord medium =
400 (aPresContext->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
401 NS_FOR_CSS_SIDES(side) {
402 mBorderImageSlice.Set(side, nsStyleCoord(1.0f, eStyleUnit_Percent));
403 mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor));
404 mBorderImageOutset.Set(side, nsStyleCoord(0.0f, eStyleUnit_Factor));
406 mBorder.Side(side) = medium;
407 mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE | BORDER_COLOR_FOREGROUND;
408 mBorderColor[side] = NS_RGB(0, 0, 0);
409 }
411 mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
412 }
414 nsBorderColors::~nsBorderColors()
415 {
416 NS_CSS_DELETE_LIST_MEMBER(nsBorderColors, this, mNext);
417 }
419 nsBorderColors*
420 nsBorderColors::Clone(bool aDeep) const
421 {
422 nsBorderColors* result = new nsBorderColors(mColor);
423 if (MOZ_UNLIKELY(!result))
424 return result;
425 if (aDeep)
426 NS_CSS_CLONE_LIST_MEMBER(nsBorderColors, this, mNext, result, (false));
427 return result;
428 }
430 nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
431 : mBorderColors(nullptr),
432 mBoxShadow(aSrc.mBoxShadow),
433 mBorderRadius(aSrc.mBorderRadius),
434 mBorderImageSource(aSrc.mBorderImageSource),
435 mBorderImageSlice(aSrc.mBorderImageSlice),
436 mBorderImageWidth(aSrc.mBorderImageWidth),
437 mBorderImageOutset(aSrc.mBorderImageOutset),
438 mBorderImageFill(aSrc.mBorderImageFill),
439 mBorderImageRepeatH(aSrc.mBorderImageRepeatH),
440 mBorderImageRepeatV(aSrc.mBorderImageRepeatV),
441 mFloatEdge(aSrc.mFloatEdge),
442 mComputedBorder(aSrc.mComputedBorder),
443 mBorder(aSrc.mBorder),
444 mTwipsPerPixel(aSrc.mTwipsPerPixel)
445 {
446 MOZ_COUNT_CTOR(nsStyleBorder);
447 if (aSrc.mBorderColors) {
448 EnsureBorderColors();
449 for (int32_t i = 0; i < 4; i++)
450 if (aSrc.mBorderColors[i])
451 mBorderColors[i] = aSrc.mBorderColors[i]->Clone();
452 else
453 mBorderColors[i] = nullptr;
454 }
456 NS_FOR_CSS_SIDES(side) {
457 mBorderStyle[side] = aSrc.mBorderStyle[side];
458 mBorderColor[side] = aSrc.mBorderColor[side];
459 }
460 }
462 nsStyleBorder::~nsStyleBorder()
463 {
464 MOZ_COUNT_DTOR(nsStyleBorder);
465 if (mBorderColors) {
466 for (int32_t i = 0; i < 4; i++)
467 delete mBorderColors[i];
468 delete [] mBorderColors;
469 }
470 }
472 void*
473 nsStyleBorder::operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
474 void* result = aContext->AllocateFromShell(sz);
475 if (result)
476 memset(result, 0, sz);
477 return result;
478 }
480 nsMargin
481 nsStyleBorder::GetImageOutset() const
482 {
483 // We don't check whether there is a border-image (which is OK since
484 // the initial values yields 0 outset) so that we don't have to
485 // reflow to update overflow areas when an image loads.
486 nsMargin outset;
487 NS_FOR_CSS_SIDES(s) {
488 nsStyleCoord coord = mBorderImageOutset.Get(s);
489 nscoord value;
490 switch (coord.GetUnit()) {
491 case eStyleUnit_Coord:
492 value = coord.GetCoordValue();
493 break;
494 case eStyleUnit_Factor:
495 value = coord.GetFactorValue() * mComputedBorder.Side(s);
496 break;
497 default:
498 NS_NOTREACHED("unexpected CSS unit for image outset");
499 value = 0;
500 break;
501 }
502 outset.Side(s) = value;
503 }
504 return outset;
505 }
507 void
508 nsStyleBorder::Destroy(nsPresContext* aContext) {
509 UntrackImage(aContext);
510 this->~nsStyleBorder();
511 aContext->FreeToShell(sizeof(nsStyleBorder), this);
512 }
514 nsChangeHint nsStyleBorder::CalcDifference(const nsStyleBorder& aOther) const
515 {
516 nsChangeHint shadowDifference =
517 CalcShadowDifference(mBoxShadow, aOther.mBoxShadow);
518 NS_ABORT_IF_FALSE(shadowDifference == unsigned(NS_STYLE_HINT_REFLOW) ||
519 shadowDifference == unsigned(NS_STYLE_HINT_VISUAL) ||
520 shadowDifference == unsigned(NS_STYLE_HINT_NONE),
521 "should do more with shadowDifference");
523 // Note that differences in mBorder don't affect rendering (which should only
524 // use mComputedBorder), so don't need to be tested for here.
525 // XXXbz we should be able to return a more specific change hint for
526 // at least GetComputedBorder() differences...
527 if (mTwipsPerPixel != aOther.mTwipsPerPixel ||
528 GetComputedBorder() != aOther.GetComputedBorder() ||
529 mFloatEdge != aOther.mFloatEdge ||
530 mBorderImageOutset != aOther.mBorderImageOutset ||
531 (shadowDifference & nsChangeHint_NeedReflow))
532 return NS_STYLE_HINT_REFLOW;
534 NS_FOR_CSS_SIDES(ix) {
535 // See the explanation in nsChangeHint.h of
536 // nsChangeHint_BorderStyleNoneChange .
537 // Furthermore, even though we know *this* side is 0 width, just
538 // assume a visual hint for some other change rather than bother
539 // tracking this result through the rest of the function.
540 if (HasVisibleStyle(ix) != aOther.HasVisibleStyle(ix)) {
541 return NS_CombineHint(NS_STYLE_HINT_VISUAL,
542 nsChangeHint_BorderStyleNoneChange);
543 }
544 }
546 // Note that mBorderStyle stores not only the border style but also
547 // color-related flags. Given that we've already done an mComputedBorder
548 // comparison, border-style differences can only lead to a VISUAL hint. So
549 // it's OK to just compare the values directly -- if either the actual
550 // style or the color flags differ we want to repaint.
551 NS_FOR_CSS_SIDES(ix) {
552 if (mBorderStyle[ix] != aOther.mBorderStyle[ix] ||
553 mBorderColor[ix] != aOther.mBorderColor[ix])
554 return NS_STYLE_HINT_VISUAL;
555 }
557 if (mBorderRadius != aOther.mBorderRadius ||
558 !mBorderColors != !aOther.mBorderColors)
559 return NS_STYLE_HINT_VISUAL;
561 if (IsBorderImageLoaded() || aOther.IsBorderImageLoaded()) {
562 if (mBorderImageSource != aOther.mBorderImageSource ||
563 mBorderImageRepeatH != aOther.mBorderImageRepeatH ||
564 mBorderImageRepeatV != aOther.mBorderImageRepeatV ||
565 mBorderImageSlice != aOther.mBorderImageSlice ||
566 mBorderImageFill != aOther.mBorderImageFill ||
567 mBorderImageWidth != aOther.mBorderImageWidth ||
568 mBorderImageOutset != aOther.mBorderImageOutset)
569 return NS_STYLE_HINT_VISUAL;
570 }
572 // Note that at this point if mBorderColors is non-null so is
573 // aOther.mBorderColors
574 if (mBorderColors) {
575 NS_FOR_CSS_SIDES(ix) {
576 if (!nsBorderColors::Equal(mBorderColors[ix],
577 aOther.mBorderColors[ix]))
578 return NS_STYLE_HINT_VISUAL;
579 }
580 }
582 return shadowDifference;
583 }
585 nsStyleOutline::nsStyleOutline(nsPresContext* aPresContext)
586 {
587 MOZ_COUNT_CTOR(nsStyleOutline);
588 // spacing values not inherited
589 nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
590 NS_FOR_CSS_HALF_CORNERS(corner) {
591 mOutlineRadius.Set(corner, zero);
592 }
594 mOutlineOffset = 0;
596 mOutlineWidth = nsStyleCoord(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated);
597 mOutlineStyle = NS_STYLE_BORDER_STYLE_NONE;
598 mOutlineColor = NS_RGB(0, 0, 0);
600 mHasCachedOutline = false;
601 mTwipsPerPixel = aPresContext->DevPixelsToAppUnits(1);
602 }
604 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc) {
605 MOZ_COUNT_CTOR(nsStyleOutline);
606 memcpy((nsStyleOutline*)this, &aSrc, sizeof(nsStyleOutline));
607 }
609 void
610 nsStyleOutline::RecalcData(nsPresContext* aContext)
611 {
612 if (NS_STYLE_BORDER_STYLE_NONE == GetOutlineStyle()) {
613 mCachedOutlineWidth = 0;
614 mHasCachedOutline = true;
615 } else if (IsFixedUnit(mOutlineWidth, true)) {
616 // Clamp negative calc() to 0.
617 mCachedOutlineWidth =
618 std::max(CalcCoord(mOutlineWidth, aContext->GetBorderWidthTable(), 3), 0);
619 mCachedOutlineWidth =
620 NS_ROUND_BORDER_TO_PIXELS(mCachedOutlineWidth, mTwipsPerPixel);
621 mHasCachedOutline = true;
622 }
623 else
624 mHasCachedOutline = false;
625 }
627 nsChangeHint nsStyleOutline::CalcDifference(const nsStyleOutline& aOther) const
628 {
629 bool outlineWasVisible =
630 mCachedOutlineWidth > 0 && mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
631 bool outlineIsVisible =
632 aOther.mCachedOutlineWidth > 0 && aOther.mOutlineStyle != NS_STYLE_BORDER_STYLE_NONE;
633 if (outlineWasVisible != outlineIsVisible ||
634 (outlineIsVisible && (mOutlineOffset != aOther.mOutlineOffset ||
635 mOutlineWidth != aOther.mOutlineWidth ||
636 mTwipsPerPixel != aOther.mTwipsPerPixel))) {
637 return NS_CombineHint(nsChangeHint_AllReflowHints,
638 nsChangeHint_RepaintFrame);
639 }
640 if ((mOutlineStyle != aOther.mOutlineStyle) ||
641 (mOutlineColor != aOther.mOutlineColor) ||
642 (mOutlineRadius != aOther.mOutlineRadius)) {
643 return nsChangeHint_RepaintFrame;
644 }
645 return NS_STYLE_HINT_NONE;
646 }
648 // --------------------
649 // nsStyleList
650 //
651 nsStyleList::nsStyleList()
652 : mListStyleType(NS_STYLE_LIST_STYLE_DISC),
653 mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE)
654 {
655 MOZ_COUNT_CTOR(nsStyleList);
656 }
658 nsStyleList::~nsStyleList()
659 {
660 MOZ_COUNT_DTOR(nsStyleList);
661 }
663 nsStyleList::nsStyleList(const nsStyleList& aSource)
664 : mListStyleType(aSource.mListStyleType),
665 mListStylePosition(aSource.mListStylePosition),
666 mImageRegion(aSource.mImageRegion)
667 {
668 SetListStyleImage(aSource.GetListStyleImage());
669 MOZ_COUNT_CTOR(nsStyleList);
670 }
672 nsChangeHint nsStyleList::CalcDifference(const nsStyleList& aOther) const
673 {
674 if (mListStylePosition != aOther.mListStylePosition)
675 return NS_STYLE_HINT_FRAMECHANGE;
676 if (EqualImages(mListStyleImage, aOther.mListStyleImage) &&
677 mListStyleType == aOther.mListStyleType) {
678 if (mImageRegion.IsEqualInterior(aOther.mImageRegion))
679 return NS_STYLE_HINT_NONE;
680 if (mImageRegion.width == aOther.mImageRegion.width &&
681 mImageRegion.height == aOther.mImageRegion.height)
682 return NS_STYLE_HINT_VISUAL;
683 }
684 return NS_STYLE_HINT_REFLOW;
685 }
687 // --------------------
688 // nsStyleXUL
689 //
690 nsStyleXUL::nsStyleXUL()
691 {
692 MOZ_COUNT_CTOR(nsStyleXUL);
693 mBoxAlign = NS_STYLE_BOX_ALIGN_STRETCH;
694 mBoxDirection = NS_STYLE_BOX_DIRECTION_NORMAL;
695 mBoxFlex = 0.0f;
696 mBoxOrient = NS_STYLE_BOX_ORIENT_HORIZONTAL;
697 mBoxPack = NS_STYLE_BOX_PACK_START;
698 mBoxOrdinal = 1;
699 mStretchStack = true;
700 }
702 nsStyleXUL::~nsStyleXUL()
703 {
704 MOZ_COUNT_DTOR(nsStyleXUL);
705 }
707 nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource)
708 {
709 MOZ_COUNT_CTOR(nsStyleXUL);
710 memcpy((nsStyleXUL*)this, &aSource, sizeof(nsStyleXUL));
711 }
713 nsChangeHint nsStyleXUL::CalcDifference(const nsStyleXUL& aOther) const
714 {
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;
726 }
728 // --------------------
729 // nsStyleColumn
730 //
731 /* static */ const uint32_t nsStyleColumn::kMaxColumnCount = 1000;
733 nsStyleColumn::nsStyleColumn(nsPresContext* aPresContext)
734 {
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();
747 }
749 nsStyleColumn::~nsStyleColumn()
750 {
751 MOZ_COUNT_DTOR(nsStyleColumn);
752 }
754 nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
755 {
756 MOZ_COUNT_CTOR(nsStyleColumn);
757 memcpy((nsStyleColumn*)this, &aSource, sizeof(nsStyleColumn));
758 }
760 nsChangeHint nsStyleColumn::CalcDifference(const nsStyleColumn& aOther) const
761 {
762 if ((mColumnWidth.GetUnit() == eStyleUnit_Auto)
763 != (aOther.mColumnWidth.GetUnit() == eStyleUnit_Auto) ||
764 mColumnCount != aOther.mColumnCount)
765 // We force column count changes to do a reframe, because it's tricky to handle
766 // some edge cases where the column count gets smaller and content overflows.
767 // XXX not ideal
768 return NS_STYLE_HINT_FRAMECHANGE;
770 if (mColumnWidth != aOther.mColumnWidth ||
771 mColumnGap != aOther.mColumnGap ||
772 mColumnFill != aOther.mColumnFill)
773 return NS_STYLE_HINT_REFLOW;
775 if (GetComputedColumnRuleWidth() != aOther.GetComputedColumnRuleWidth() ||
776 mColumnRuleStyle != aOther.mColumnRuleStyle ||
777 mColumnRuleColor != aOther.mColumnRuleColor ||
778 mColumnRuleColorIsForeground != aOther.mColumnRuleColorIsForeground)
779 return NS_STYLE_HINT_VISUAL;
781 return NS_STYLE_HINT_NONE;
782 }
784 // --------------------
785 // nsStyleSVG
786 //
787 nsStyleSVG::nsStyleSVG()
788 {
789 MOZ_COUNT_CTOR(nsStyleSVG);
790 mFill.mType = eStyleSVGPaintType_Color;
791 mFill.mPaint.mColor = NS_RGB(0,0,0);
792 mFill.mFallbackColor = NS_RGB(0,0,0);
793 mStroke.mType = eStyleSVGPaintType_None;
794 mStroke.mPaint.mColor = NS_RGB(0,0,0);
795 mStroke.mFallbackColor = NS_RGB(0,0,0);
796 mStrokeDasharray = nullptr;
798 mStrokeDashoffset.SetCoordValue(0);
799 mStrokeWidth.SetCoordValue(nsPresContext::CSSPixelsToAppUnits(1));
801 mFillOpacity = 1.0f;
802 mStrokeMiterlimit = 4.0f;
803 mStrokeOpacity = 1.0f;
805 mStrokeDasharrayLength = 0;
806 mClipRule = NS_STYLE_FILL_RULE_NONZERO;
807 mColorInterpolation = NS_STYLE_COLOR_INTERPOLATION_SRGB;
808 mColorInterpolationFilters = NS_STYLE_COLOR_INTERPOLATION_LINEARRGB;
809 mFillRule = NS_STYLE_FILL_RULE_NONZERO;
810 mImageRendering = NS_STYLE_IMAGE_RENDERING_AUTO;
811 mPaintOrder = NS_STYLE_PAINT_ORDER_NORMAL;
812 mShapeRendering = NS_STYLE_SHAPE_RENDERING_AUTO;
813 mStrokeLinecap = NS_STYLE_STROKE_LINECAP_BUTT;
814 mStrokeLinejoin = NS_STYLE_STROKE_LINEJOIN_MITER;
815 mTextAnchor = NS_STYLE_TEXT_ANCHOR_START;
816 mTextRendering = NS_STYLE_TEXT_RENDERING_AUTO;
817 mFillOpacitySource = eStyleSVGOpacitySource_Normal;
818 mStrokeOpacitySource = eStyleSVGOpacitySource_Normal;
819 mStrokeDasharrayFromObject = false;
820 mStrokeDashoffsetFromObject = false;
821 mStrokeWidthFromObject = false;
822 }
824 nsStyleSVG::~nsStyleSVG()
825 {
826 MOZ_COUNT_DTOR(nsStyleSVG);
827 delete [] mStrokeDasharray;
828 }
830 nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
831 {
832 MOZ_COUNT_CTOR(nsStyleSVG);
833 mFill = aSource.mFill;
834 mStroke = aSource.mStroke;
836 mMarkerEnd = aSource.mMarkerEnd;
837 mMarkerMid = aSource.mMarkerMid;
838 mMarkerStart = aSource.mMarkerStart;
840 mStrokeDasharrayLength = aSource.mStrokeDasharrayLength;
841 if (aSource.mStrokeDasharray) {
842 mStrokeDasharray = new nsStyleCoord[mStrokeDasharrayLength];
843 if (mStrokeDasharray)
844 memcpy(mStrokeDasharray,
845 aSource.mStrokeDasharray,
846 mStrokeDasharrayLength * sizeof(nsStyleCoord));
847 else
848 mStrokeDasharrayLength = 0;
849 } else {
850 mStrokeDasharray = nullptr;
851 }
853 mStrokeDashoffset = aSource.mStrokeDashoffset;
854 mStrokeWidth = aSource.mStrokeWidth;
856 mFillOpacity = aSource.mFillOpacity;
857 mStrokeMiterlimit = aSource.mStrokeMiterlimit;
858 mStrokeOpacity = aSource.mStrokeOpacity;
860 mClipRule = aSource.mClipRule;
861 mColorInterpolation = aSource.mColorInterpolation;
862 mColorInterpolationFilters = aSource.mColorInterpolationFilters;
863 mFillRule = aSource.mFillRule;
864 mImageRendering = aSource.mImageRendering;
865 mPaintOrder = aSource.mPaintOrder;
866 mShapeRendering = aSource.mShapeRendering;
867 mStrokeLinecap = aSource.mStrokeLinecap;
868 mStrokeLinejoin = aSource.mStrokeLinejoin;
869 mTextAnchor = aSource.mTextAnchor;
870 mTextRendering = aSource.mTextRendering;
871 mFillOpacitySource = aSource.mFillOpacitySource;
872 mStrokeOpacitySource = aSource.mStrokeOpacitySource;
873 mStrokeDasharrayFromObject = aSource.mStrokeDasharrayFromObject;
874 mStrokeDashoffsetFromObject = aSource.mStrokeDashoffsetFromObject;
875 mStrokeWidthFromObject = aSource.mStrokeWidthFromObject;
876 }
878 static bool PaintURIChanged(const nsStyleSVGPaint& aPaint1,
879 const nsStyleSVGPaint& aPaint2)
880 {
881 if (aPaint1.mType != aPaint2.mType) {
882 return aPaint1.mType == eStyleSVGPaintType_Server ||
883 aPaint2.mType == eStyleSVGPaintType_Server;
884 }
885 return aPaint1.mType == eStyleSVGPaintType_Server &&
886 !EqualURIs(aPaint1.mPaint.mPaintServer, aPaint2.mPaint.mPaintServer);
887 }
889 nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aOther) const
890 {
891 nsChangeHint hint = nsChangeHint(0);
893 if (!EqualURIs(mMarkerEnd, aOther.mMarkerEnd) ||
894 !EqualURIs(mMarkerMid, aOther.mMarkerMid) ||
895 !EqualURIs(mMarkerStart, aOther.mMarkerStart)) {
896 // Markers currently contribute to nsSVGPathGeometryFrame::mRect,
897 // so we need a reflow as well as a repaint. No intrinsic sizes need
898 // to change, so nsChangeHint_NeedReflow is sufficient.
899 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
900 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
901 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
902 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
903 return hint;
904 }
906 if (mFill != aOther.mFill ||
907 mStroke != aOther.mStroke ||
908 mFillOpacity != aOther.mFillOpacity ||
909 mStrokeOpacity != aOther.mStrokeOpacity) {
910 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
911 if (HasStroke() != aOther.HasStroke() ||
912 (!HasStroke() && HasFill() != aOther.HasFill())) {
913 // Frame bounds and overflow rects depend on whether we "have" fill or
914 // stroke. Whether we have stroke or not just changed, or else we have no
915 // stroke (in which case whether we have fill or not is significant to frame
916 // bounds) and whether we have fill or not just changed. In either case we
917 // need to reflow so the frame rect is updated.
918 // XXXperf this is a waste on non nsSVGPathGeometryFrames.
919 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
920 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
921 }
922 if (PaintURIChanged(mFill, aOther.mFill) ||
923 PaintURIChanged(mStroke, aOther.mStroke)) {
924 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
925 }
926 }
928 // Stroke currently contributes to nsSVGPathGeometryFrame::mRect, so
929 // we need a reflow here. No intrinsic sizes need to change, so
930 // nsChangeHint_NeedReflow is sufficient.
931 // Note that stroke-dashoffset does not affect nsSVGPathGeometryFrame::mRect.
932 // text-anchor and text-rendering changes also require a reflow since they
933 // change frames' rects.
934 if (mStrokeWidth != aOther.mStrokeWidth ||
935 mStrokeMiterlimit != aOther.mStrokeMiterlimit ||
936 mStrokeLinecap != aOther.mStrokeLinecap ||
937 mStrokeLinejoin != aOther.mStrokeLinejoin ||
938 mTextAnchor != aOther.mTextAnchor ||
939 mTextRendering != aOther.mTextRendering) {
940 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
941 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
942 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
943 return hint;
944 }
946 if (hint & nsChangeHint_RepaintFrame) {
947 return hint; // we don't add anything else below
948 }
950 if ( mStrokeDashoffset != aOther.mStrokeDashoffset ||
951 mClipRule != aOther.mClipRule ||
952 mColorInterpolation != aOther.mColorInterpolation ||
953 mColorInterpolationFilters != aOther.mColorInterpolationFilters ||
954 mFillRule != aOther.mFillRule ||
955 mImageRendering != aOther.mImageRendering ||
956 mPaintOrder != aOther.mPaintOrder ||
957 mShapeRendering != aOther.mShapeRendering ||
958 mStrokeDasharrayLength != aOther.mStrokeDasharrayLength ||
959 mFillOpacitySource != aOther.mFillOpacitySource ||
960 mStrokeOpacitySource != aOther.mStrokeOpacitySource ||
961 mStrokeDasharrayFromObject != aOther.mStrokeDasharrayFromObject ||
962 mStrokeDashoffsetFromObject != aOther.mStrokeDashoffsetFromObject ||
963 mStrokeWidthFromObject != aOther.mStrokeWidthFromObject) {
964 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
965 return hint;
966 }
968 // length of stroke dasharrays are the same (tested above) - check entries
969 for (uint32_t i=0; i<mStrokeDasharrayLength; i++)
970 if (mStrokeDasharray[i] != aOther.mStrokeDasharray[i]) {
971 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
972 return hint;
973 }
975 return hint;
976 }
978 // --------------------
979 // nsStyleFilter
980 //
981 nsStyleFilter::nsStyleFilter()
982 : mType(NS_STYLE_FILTER_NONE)
983 , mDropShadow(nullptr)
984 {
985 MOZ_COUNT_CTOR(nsStyleFilter);
986 }
988 nsStyleFilter::nsStyleFilter(const nsStyleFilter& aSource)
989 : mType(NS_STYLE_FILTER_NONE)
990 , mDropShadow(nullptr)
991 {
992 MOZ_COUNT_CTOR(nsStyleFilter);
993 if (aSource.mType == NS_STYLE_FILTER_URL) {
994 SetURL(aSource.mURL);
995 } else if (aSource.mType == NS_STYLE_FILTER_DROP_SHADOW) {
996 SetDropShadow(aSource.mDropShadow);
997 } else if (aSource.mType != NS_STYLE_FILTER_NONE) {
998 SetFilterParameter(aSource.mFilterParameter, aSource.mType);
999 }
1000 }
1002 nsStyleFilter::~nsStyleFilter()
1003 {
1004 ReleaseRef();
1005 MOZ_COUNT_DTOR(nsStyleFilter);
1006 }
1008 nsStyleFilter&
1009 nsStyleFilter::operator=(const nsStyleFilter& aOther)
1010 {
1011 if (this == &aOther)
1012 return *this;
1014 if (aOther.mType == NS_STYLE_FILTER_URL) {
1015 SetURL(aOther.mURL);
1016 } else if (aOther.mType == NS_STYLE_FILTER_DROP_SHADOW) {
1017 SetDropShadow(aOther.mDropShadow);
1018 } else if (aOther.mType != NS_STYLE_FILTER_NONE) {
1019 SetFilterParameter(aOther.mFilterParameter, aOther.mType);
1020 }
1021 return *this;
1022 }
1025 bool
1026 nsStyleFilter::operator==(const nsStyleFilter& aOther) const
1027 {
1028 if (mType != aOther.mType) {
1029 return false;
1030 }
1032 if (mType == NS_STYLE_FILTER_URL) {
1033 return EqualURIs(mURL, aOther.mURL);
1034 } else if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
1035 return *mDropShadow == *aOther.mDropShadow;
1036 } else if (mType != NS_STYLE_FILTER_NONE) {
1037 return mFilterParameter == aOther.mFilterParameter;
1038 }
1040 return true;
1041 }
1043 void
1044 nsStyleFilter::ReleaseRef()
1045 {
1046 if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
1047 NS_ASSERTION(mDropShadow, "expected pointer");
1048 mDropShadow->Release();
1049 } else if (mType == NS_STYLE_FILTER_URL) {
1050 NS_ASSERTION(mURL, "expected pointer");
1051 mURL->Release();
1052 }
1053 }
1055 void
1056 nsStyleFilter::SetFilterParameter(const nsStyleCoord& aFilterParameter,
1057 int32_t aType)
1058 {
1059 ReleaseRef();
1060 mFilterParameter = aFilterParameter;
1061 mType = aType;
1062 }
1064 void
1065 nsStyleFilter::SetURL(nsIURI* aURL)
1066 {
1067 NS_ASSERTION(aURL, "expected pointer");
1068 ReleaseRef();
1069 mURL = aURL;
1070 mURL->AddRef();
1071 mType = NS_STYLE_FILTER_URL;
1072 }
1074 void
1075 nsStyleFilter::SetDropShadow(nsCSSShadowArray* aDropShadow)
1076 {
1077 NS_ASSERTION(aDropShadow, "expected pointer");
1078 ReleaseRef();
1079 mDropShadow = aDropShadow;
1080 mDropShadow->AddRef();
1081 mType = NS_STYLE_FILTER_DROP_SHADOW;
1082 }
1084 // --------------------
1085 // nsStyleSVGReset
1086 //
1087 nsStyleSVGReset::nsStyleSVGReset()
1088 {
1089 MOZ_COUNT_CTOR(nsStyleSVGReset);
1090 mStopColor = NS_RGB(0,0,0);
1091 mFloodColor = NS_RGB(0,0,0);
1092 mLightingColor = NS_RGB(255,255,255);
1093 mClipPath = nullptr;
1094 mMask = nullptr;
1095 mStopOpacity = 1.0f;
1096 mFloodOpacity = 1.0f;
1097 mDominantBaseline = NS_STYLE_DOMINANT_BASELINE_AUTO;
1098 mVectorEffect = NS_STYLE_VECTOR_EFFECT_NONE;
1099 mMaskType = NS_STYLE_MASK_TYPE_LUMINANCE;
1100 }
1102 nsStyleSVGReset::~nsStyleSVGReset()
1103 {
1104 MOZ_COUNT_DTOR(nsStyleSVGReset);
1105 }
1107 nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
1108 {
1109 MOZ_COUNT_CTOR(nsStyleSVGReset);
1110 mStopColor = aSource.mStopColor;
1111 mFloodColor = aSource.mFloodColor;
1112 mLightingColor = aSource.mLightingColor;
1113 mClipPath = aSource.mClipPath;
1114 mFilters = aSource.mFilters;
1115 mMask = aSource.mMask;
1116 mStopOpacity = aSource.mStopOpacity;
1117 mFloodOpacity = aSource.mFloodOpacity;
1118 mDominantBaseline = aSource.mDominantBaseline;
1119 mVectorEffect = aSource.mVectorEffect;
1120 mMaskType = aSource.mMaskType;
1121 }
1123 nsChangeHint nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aOther) const
1124 {
1125 nsChangeHint hint = nsChangeHint(0);
1127 bool equalFilters = (mFilters == aOther.mFilters);
1129 if (!equalFilters) {
1130 NS_UpdateHint(hint, nsChangeHint_UpdateOverflow);
1131 }
1133 if (!EqualURIs(mClipPath, aOther.mClipPath) ||
1134 !EqualURIs(mMask, aOther.mMask) ||
1135 !equalFilters) {
1136 NS_UpdateHint(hint, nsChangeHint_UpdateEffects);
1137 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
1138 }
1140 if (mDominantBaseline != aOther.mDominantBaseline) {
1141 // XXXjwatt: why NS_STYLE_HINT_REFLOW? Isn't that excessive?
1142 NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
1143 } else if (mVectorEffect != aOther.mVectorEffect) {
1144 // Stroke currently affects nsSVGPathGeometryFrame::mRect, and
1145 // vector-effect affect stroke. As a result we need to reflow if
1146 // vector-effect changes in order to have nsSVGPathGeometryFrame::
1147 // ReflowSVG called to update its mRect. No intrinsic sizes need
1148 // to change so nsChangeHint_NeedReflow is sufficient.
1149 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
1150 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
1151 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
1152 } else if (mStopColor != aOther.mStopColor ||
1153 mFloodColor != aOther.mFloodColor ||
1154 mLightingColor != aOther.mLightingColor ||
1155 mStopOpacity != aOther.mStopOpacity ||
1156 mFloodOpacity != aOther.mFloodOpacity ||
1157 mMaskType != aOther.mMaskType) {
1158 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
1159 }
1161 return hint;
1162 }
1164 // nsStyleSVGPaint implementation
1165 nsStyleSVGPaint::~nsStyleSVGPaint()
1166 {
1167 if (mType == eStyleSVGPaintType_Server) {
1168 NS_IF_RELEASE(mPaint.mPaintServer);
1169 }
1170 }
1172 void
1173 nsStyleSVGPaint::SetType(nsStyleSVGPaintType aType)
1174 {
1175 if (mType == eStyleSVGPaintType_Server) {
1176 this->~nsStyleSVGPaint();
1177 new (this) nsStyleSVGPaint();
1178 }
1179 mType = aType;
1180 }
1182 nsStyleSVGPaint& nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther)
1183 {
1184 if (this == &aOther)
1185 return *this;
1187 SetType(aOther.mType);
1189 mFallbackColor = aOther.mFallbackColor;
1190 if (mType == eStyleSVGPaintType_Server) {
1191 mPaint.mPaintServer = aOther.mPaint.mPaintServer;
1192 NS_IF_ADDREF(mPaint.mPaintServer);
1193 } else {
1194 mPaint.mColor = aOther.mPaint.mColor;
1195 }
1196 return *this;
1197 }
1199 bool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const
1200 {
1201 if (mType != aOther.mType)
1202 return false;
1203 if (mType == eStyleSVGPaintType_Server)
1204 return EqualURIs(mPaint.mPaintServer, aOther.mPaint.mPaintServer) &&
1205 mFallbackColor == aOther.mFallbackColor;
1206 if (mType == eStyleSVGPaintType_Color)
1207 return mPaint.mColor == aOther.mPaint.mColor;
1208 return true;
1209 }
1212 // --------------------
1213 // nsStylePosition
1214 //
1215 nsStylePosition::nsStylePosition(void)
1216 {
1217 MOZ_COUNT_CTOR(nsStylePosition);
1218 // positioning values not inherited
1219 nsStyleCoord autoCoord(eStyleUnit_Auto);
1220 mOffset.SetLeft(autoCoord);
1221 mOffset.SetTop(autoCoord);
1222 mOffset.SetRight(autoCoord);
1223 mOffset.SetBottom(autoCoord);
1224 mWidth.SetAutoValue();
1225 mMinWidth.SetCoordValue(0);
1226 mMaxWidth.SetNoneValue();
1227 mHeight.SetAutoValue();
1228 mMinHeight.SetCoordValue(0);
1229 mMaxHeight.SetNoneValue();
1230 mFlexBasis.SetAutoValue();
1232 // The initial value of grid-auto-columns and grid-auto-rows is 'auto',
1233 // which computes to 'minmax(min-content, max-content)'.
1234 mGridAutoColumnsMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
1235 eStyleUnit_Enumerated);
1236 mGridAutoColumnsMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
1237 eStyleUnit_Enumerated);
1238 mGridAutoRowsMin.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MIN_CONTENT,
1239 eStyleUnit_Enumerated);
1240 mGridAutoRowsMax.SetIntValue(NS_STYLE_GRID_TRACK_BREADTH_MAX_CONTENT,
1241 eStyleUnit_Enumerated);
1243 mGridAutoFlow = NS_STYLE_GRID_AUTO_FLOW_NONE;
1244 mBoxSizing = NS_STYLE_BOX_SIZING_CONTENT;
1245 mAlignContent = NS_STYLE_ALIGN_CONTENT_STRETCH;
1246 mAlignItems = NS_STYLE_ALIGN_ITEMS_INITIAL_VALUE;
1247 mAlignSelf = NS_STYLE_ALIGN_SELF_AUTO;
1248 mFlexDirection = NS_STYLE_FLEX_DIRECTION_ROW;
1249 mFlexWrap = NS_STYLE_FLEX_WRAP_NOWRAP;
1250 mJustifyContent = NS_STYLE_JUSTIFY_CONTENT_FLEX_START;
1251 mOrder = NS_STYLE_ORDER_INITIAL;
1252 mFlexGrow = 0.0f;
1253 mFlexShrink = 1.0f;
1254 mZIndex.SetAutoValue();
1255 mGridAutoPositionColumn.SetToInteger(1);
1256 mGridAutoPositionRow.SetToInteger(1);
1257 // Other members get their default constructors
1258 // which initialize them to representations of their respective initial value.
1259 // mGridTemplateAreas: nullptr for 'none'
1260 // mGridTemplate{Rows,Columns}: false and empty arrays for 'none'
1261 // mGrid{Column,Row}{Start,End}: false/0/empty values for 'auto'
1262 }
1264 nsStylePosition::~nsStylePosition(void)
1265 {
1266 MOZ_COUNT_DTOR(nsStylePosition);
1267 }
1269 nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
1270 : mGridTemplateColumns(aSource.mGridTemplateColumns)
1271 , mGridTemplateRows(aSource.mGridTemplateRows)
1272 , mGridTemplateAreas(aSource.mGridTemplateAreas)
1273 , mGridAutoPositionColumn(aSource.mGridAutoPositionColumn)
1274 , mGridAutoPositionRow(aSource.mGridAutoPositionRow)
1275 , mGridColumnStart(aSource.mGridColumnStart)
1276 , mGridColumnEnd(aSource.mGridColumnEnd)
1277 , mGridRowStart(aSource.mGridRowStart)
1278 , mGridRowEnd(aSource.mGridRowEnd)
1279 {
1280 MOZ_COUNT_CTOR(nsStylePosition);
1281 // If you add any memcpy'able member vars,
1282 // they should be declared before mGridTemplateColumns.
1283 // If you add any non-memcpy'able member vars,
1284 // they should be declared after mGridTemplateColumns,
1285 // and you should invoke their copy constructor in the init list above
1286 // and update this static-assert to include their "sizeof()"
1287 static_assert(sizeof(nsStylePosition) ==
1288 offsetof(nsStylePosition, mGridTemplateColumns) +
1289 sizeof(mGridTemplateColumns) +
1290 sizeof(mGridTemplateRows) +
1291 sizeof(mGridTemplateAreas) +
1292 sizeof(mGridAutoPositionColumn) +
1293 sizeof(mGridAutoPositionRow) +
1294 sizeof(mGridColumnStart) +
1295 sizeof(mGridColumnEnd) +
1296 sizeof(mGridRowStart) +
1297 sizeof(mGridRowEnd),
1298 "Unexpected size or offset in nsStylePosition");
1299 memcpy((nsStylePosition*) this,
1300 &aSource,
1301 offsetof(nsStylePosition, mGridTemplateColumns));
1302 }
1304 static bool
1305 IsAutonessEqual(const nsStyleSides& aSides1, const nsStyleSides& aSides2)
1306 {
1307 NS_FOR_CSS_SIDES(side) {
1308 if ((aSides1.GetUnit(side) == eStyleUnit_Auto) !=
1309 (aSides2.GetUnit(side) == eStyleUnit_Auto)) {
1310 return false;
1311 }
1312 }
1313 return true;
1314 }
1316 nsChangeHint nsStylePosition::CalcDifference(const nsStylePosition& aOther) const
1317 {
1318 nsChangeHint hint =
1319 (mZIndex == aOther.mZIndex) ? NS_STYLE_HINT_NONE : nsChangeHint_RepaintFrame;
1321 if (mBoxSizing != aOther.mBoxSizing) {
1322 // Can affect both widths and heights; just a bad scene.
1323 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1324 }
1326 // Properties that apply to flex items:
1327 // NOTE: Changes to "order" on a flex item may trigger some repositioning.
1328 // If we're in a multi-line flex container, it also may affect our size
1329 // (and that of our container & siblings) by shuffling items between lines.
1330 if (mAlignSelf != aOther.mAlignSelf ||
1331 mFlexBasis != aOther.mFlexBasis ||
1332 mFlexGrow != aOther.mFlexGrow ||
1333 mFlexShrink != aOther.mFlexShrink ||
1334 mOrder != aOther.mOrder) {
1335 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1336 }
1338 // Properties that apply to flex containers:
1339 // - flex-direction can swap a flex container between vertical & horizontal.
1340 // - align-items can change the sizing of a flex container & the positioning
1341 // of its children.
1342 // - flex-wrap changes whether a flex container's children are wrapped, which
1343 // impacts their sizing/positioning and hence impacts the container's size.
1344 if (mAlignItems != aOther.mAlignItems ||
1345 mFlexDirection != aOther.mFlexDirection ||
1346 mFlexWrap != aOther.mFlexWrap) {
1347 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1348 }
1350 // Properties that apply to grid containers:
1351 // FIXME: only for grid containers
1352 // (ie. 'display: grid' or 'display: inline-grid')
1353 if (mGridTemplateColumns != aOther.mGridTemplateColumns ||
1354 mGridTemplateRows != aOther.mGridTemplateRows ||
1355 mGridTemplateAreas != aOther.mGridTemplateAreas ||
1356 mGridAutoColumnsMin != aOther.mGridAutoColumnsMin ||
1357 mGridAutoColumnsMax != aOther.mGridAutoColumnsMax ||
1358 mGridAutoRowsMin != aOther.mGridAutoRowsMin ||
1359 mGridAutoRowsMax != aOther.mGridAutoRowsMax ||
1360 mGridAutoFlow != aOther.mGridAutoFlow) {
1361 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1362 }
1364 // Properties that apply to grid items:
1365 // FIXME: only for grid items
1366 // (ie. parent frame is 'display: grid' or 'display: inline-grid')
1367 if (mGridColumnStart != aOther.mGridColumnStart ||
1368 mGridColumnEnd != aOther.mGridColumnEnd ||
1369 mGridRowStart != aOther.mGridRowStart ||
1370 mGridRowEnd != aOther.mGridRowEnd) {
1371 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1372 }
1374 // Changing justify-content on a flexbox might affect the positioning of its
1375 // children, but it won't affect any sizing.
1376 if (mJustifyContent != aOther.mJustifyContent) {
1377 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
1378 }
1380 // Properties that apply only to multi-line flex containers:
1381 // 'align-content' can change the positioning & sizing of a multi-line flex
1382 // container's children when there's extra space in the cross axis, but it
1383 // shouldn't affect the container's own sizing.
1384 //
1385 // NOTE: If we get here, we know that mFlexWrap == aOther.mFlexWrap
1386 // (otherwise, we would've returned earlier). So it doesn't matter which one
1387 // of those we check to see if we're multi-line.
1388 if (mFlexWrap != NS_STYLE_FLEX_WRAP_NOWRAP &&
1389 mAlignContent != aOther.mAlignContent) {
1390 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
1391 }
1393 if (mHeight != aOther.mHeight ||
1394 mMinHeight != aOther.mMinHeight ||
1395 mMaxHeight != aOther.mMaxHeight) {
1396 // Height changes can affect descendant intrinsic sizes due to replaced
1397 // elements with percentage heights in descendants which also have
1398 // percentage heights. And due to our not-so-great computation of mVResize
1399 // in nsHTMLReflowState, they do need to force reflow of the whole subtree.
1400 // XXXbz due to XUL caching heights as well, height changes also need to
1401 // clear ancestor intrinsics!
1402 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1403 }
1405 if (mWidth != aOther.mWidth ||
1406 mMinWidth != aOther.mMinWidth ||
1407 mMaxWidth != aOther.mMaxWidth) {
1408 // None of our width differences can affect descendant intrinsic
1409 // sizes and none of them need to force children to reflow.
1410 return
1411 NS_CombineHint(hint,
1412 NS_SubtractHint(nsChangeHint_AllReflowHints,
1413 NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
1414 nsChangeHint_NeedDirtyReflow)));
1415 }
1417 // If width and height have not changed, but any of the offsets have changed,
1418 // then return the respective hints so that we would hopefully be able to
1419 // avoid reflowing.
1420 // Note that it is possible that we'll need to reflow when processing
1421 // restyles, but we don't have enough information to make a good decision
1422 // right now.
1423 // Don't try to handle changes between "auto" and non-auto efficiently;
1424 // that's tricky to do and will hardly ever be able to avoid a reflow.
1425 if (mOffset != aOther.mOffset) {
1426 if (IsAutonessEqual(mOffset, aOther.mOffset)) {
1427 NS_UpdateHint(hint, nsChangeHint(nsChangeHint_RecomputePosition |
1428 nsChangeHint_UpdateOverflow));
1429 } else {
1430 return NS_CombineHint(hint, nsChangeHint_AllReflowHints);
1431 }
1432 }
1433 return hint;
1434 }
1436 /* static */ bool
1437 nsStylePosition::WidthCoordDependsOnContainer(const nsStyleCoord &aCoord)
1438 {
1439 return aCoord.GetUnit() == eStyleUnit_Auto ||
1440 aCoord.HasPercent() ||
1441 (aCoord.GetUnit() == eStyleUnit_Enumerated &&
1442 (aCoord.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT ||
1443 aCoord.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE));
1444 }
1446 // --------------------
1447 // nsStyleTable
1448 //
1450 nsStyleTable::nsStyleTable()
1451 {
1452 MOZ_COUNT_CTOR(nsStyleTable);
1453 // values not inherited
1454 mLayoutStrategy = NS_STYLE_TABLE_LAYOUT_AUTO;
1455 mFrame = NS_STYLE_TABLE_FRAME_NONE;
1456 mRules = NS_STYLE_TABLE_RULES_NONE;
1457 mSpan = 1;
1458 }
1460 nsStyleTable::~nsStyleTable(void)
1461 {
1462 MOZ_COUNT_DTOR(nsStyleTable);
1463 }
1465 nsStyleTable::nsStyleTable(const nsStyleTable& aSource)
1466 {
1467 MOZ_COUNT_CTOR(nsStyleTable);
1468 memcpy((nsStyleTable*)this, &aSource, sizeof(nsStyleTable));
1469 }
1471 nsChangeHint nsStyleTable::CalcDifference(const nsStyleTable& aOther) const
1472 {
1473 // Changes in mRules may require reframing (if border-collapse stuff changes, for example).
1474 if (mRules != aOther.mRules || mSpan != aOther.mSpan ||
1475 mLayoutStrategy != aOther.mLayoutStrategy)
1476 return NS_STYLE_HINT_FRAMECHANGE;
1477 if (mFrame != aOther.mFrame)
1478 return NS_STYLE_HINT_REFLOW;
1479 return NS_STYLE_HINT_NONE;
1480 }
1482 // -----------------------
1483 // nsStyleTableBorder
1485 nsStyleTableBorder::nsStyleTableBorder(nsPresContext* aPresContext)
1486 {
1487 MOZ_COUNT_CTOR(nsStyleTableBorder);
1488 mBorderCollapse = NS_STYLE_BORDER_SEPARATE;
1490 nsCompatibility compatMode = eCompatibility_FullStandards;
1491 if (aPresContext)
1492 compatMode = aPresContext->CompatibilityMode();
1493 mEmptyCells = (compatMode == eCompatibility_NavQuirks)
1494 ? NS_STYLE_TABLE_EMPTY_CELLS_SHOW_BACKGROUND
1495 : NS_STYLE_TABLE_EMPTY_CELLS_SHOW;
1496 mCaptionSide = NS_STYLE_CAPTION_SIDE_TOP;
1497 mBorderSpacingX = 0;
1498 mBorderSpacingY = 0;
1499 }
1501 nsStyleTableBorder::~nsStyleTableBorder(void)
1502 {
1503 MOZ_COUNT_DTOR(nsStyleTableBorder);
1504 }
1506 nsStyleTableBorder::nsStyleTableBorder(const nsStyleTableBorder& aSource)
1507 {
1508 MOZ_COUNT_CTOR(nsStyleTableBorder);
1509 memcpy((nsStyleTableBorder*)this, &aSource, sizeof(nsStyleTableBorder));
1510 }
1512 nsChangeHint nsStyleTableBorder::CalcDifference(const nsStyleTableBorder& aOther) const
1513 {
1514 // Border-collapse changes need a reframe, because we use a different frame
1515 // class for table cells in the collapsed border model. This is used to
1516 // conserve memory when using the separated border model (collapsed borders
1517 // require extra state to be stored).
1518 if (mBorderCollapse != aOther.mBorderCollapse) {
1519 return NS_STYLE_HINT_FRAMECHANGE;
1520 }
1522 if ((mCaptionSide == aOther.mCaptionSide) &&
1523 (mBorderSpacingX == aOther.mBorderSpacingX) &&
1524 (mBorderSpacingY == aOther.mBorderSpacingY)) {
1525 if (mEmptyCells == aOther.mEmptyCells)
1526 return NS_STYLE_HINT_NONE;
1527 return NS_STYLE_HINT_VISUAL;
1528 }
1529 else
1530 return NS_STYLE_HINT_REFLOW;
1531 }
1533 // --------------------
1534 // nsStyleColor
1535 //
1537 nsStyleColor::nsStyleColor(nsPresContext* aPresContext)
1538 {
1539 MOZ_COUNT_CTOR(nsStyleColor);
1540 mColor = aPresContext->DefaultColor();
1541 }
1543 nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
1544 {
1545 MOZ_COUNT_CTOR(nsStyleColor);
1546 mColor = aSource.mColor;
1547 }
1549 nsChangeHint nsStyleColor::CalcDifference(const nsStyleColor& aOther) const
1550 {
1551 if (mColor == aOther.mColor)
1552 return NS_STYLE_HINT_NONE;
1553 return NS_STYLE_HINT_VISUAL;
1554 }
1556 // --------------------
1557 // nsStyleGradient
1558 //
1559 bool
1560 nsStyleGradient::operator==(const nsStyleGradient& aOther) const
1561 {
1562 NS_ABORT_IF_FALSE(mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
1563 mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1564 "incorrect combination of shape and size");
1565 NS_ABORT_IF_FALSE(aOther.mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
1566 aOther.mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1567 "incorrect combination of shape and size");
1569 if (mShape != aOther.mShape ||
1570 mSize != aOther.mSize ||
1571 mRepeating != aOther.mRepeating ||
1572 mLegacySyntax != aOther.mLegacySyntax ||
1573 mBgPosX != aOther.mBgPosX ||
1574 mBgPosY != aOther.mBgPosY ||
1575 mAngle != aOther.mAngle ||
1576 mRadiusX != aOther.mRadiusX ||
1577 mRadiusY != aOther.mRadiusY)
1578 return false;
1580 if (mStops.Length() != aOther.mStops.Length())
1581 return false;
1583 for (uint32_t i = 0; i < mStops.Length(); i++) {
1584 if (mStops[i].mLocation != aOther.mStops[i].mLocation ||
1585 mStops[i].mColor != aOther.mStops[i].mColor)
1586 return false;
1587 }
1589 return true;
1590 }
1592 nsStyleGradient::nsStyleGradient(void)
1593 : mShape(NS_STYLE_GRADIENT_SHAPE_LINEAR)
1594 , mSize(NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)
1595 , mRepeating(false)
1596 , mLegacySyntax(false)
1597 {
1598 }
1600 bool
1601 nsStyleGradient::IsOpaque()
1602 {
1603 for (uint32_t i = 0; i < mStops.Length(); i++) {
1604 if (NS_GET_A(mStops[i].mColor) < 255)
1605 return false;
1606 }
1607 return true;
1608 }
1610 bool
1611 nsStyleGradient::HasCalc()
1612 {
1613 for (uint32_t i = 0; i < mStops.Length(); i++) {
1614 if (mStops[i].mLocation.IsCalcUnit())
1615 return true;
1616 }
1617 return mBgPosX.IsCalcUnit() || mBgPosY.IsCalcUnit() || mAngle.IsCalcUnit() ||
1618 mRadiusX.IsCalcUnit() || mRadiusY.IsCalcUnit();
1619 }
1621 // --------------------
1622 // nsStyleImage
1623 //
1625 nsStyleImage::nsStyleImage()
1626 : mType(eStyleImageType_Null)
1627 , mCropRect(nullptr)
1628 #ifdef DEBUG
1629 , mImageTracked(false)
1630 #endif
1631 {
1632 MOZ_COUNT_CTOR(nsStyleImage);
1633 }
1635 nsStyleImage::~nsStyleImage()
1636 {
1637 MOZ_COUNT_DTOR(nsStyleImage);
1638 if (mType != eStyleImageType_Null)
1639 SetNull();
1640 }
1642 nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
1643 : mType(eStyleImageType_Null)
1644 , mCropRect(nullptr)
1645 #ifdef DEBUG
1646 , mImageTracked(false)
1647 #endif
1648 {
1649 // We need our own copy constructor because we don't want
1650 // to copy the reference count
1651 MOZ_COUNT_CTOR(nsStyleImage);
1652 DoCopy(aOther);
1653 }
1655 nsStyleImage&
1656 nsStyleImage::operator=(const nsStyleImage& aOther)
1657 {
1658 if (this != &aOther)
1659 DoCopy(aOther);
1661 return *this;
1662 }
1664 void
1665 nsStyleImage::DoCopy(const nsStyleImage& aOther)
1666 {
1667 SetNull();
1669 if (aOther.mType == eStyleImageType_Image)
1670 SetImageData(aOther.mImage);
1671 else if (aOther.mType == eStyleImageType_Gradient)
1672 SetGradientData(aOther.mGradient);
1673 else if (aOther.mType == eStyleImageType_Element)
1674 SetElementId(aOther.mElementId);
1676 SetCropRect(aOther.mCropRect);
1677 }
1679 void
1680 nsStyleImage::SetNull()
1681 {
1682 NS_ABORT_IF_FALSE(!mImageTracked,
1683 "Calling SetNull() with image tracked!");
1685 if (mType == eStyleImageType_Gradient)
1686 mGradient->Release();
1687 else if (mType == eStyleImageType_Image)
1688 NS_RELEASE(mImage);
1689 else if (mType == eStyleImageType_Element)
1690 NS_Free(mElementId);
1692 mType = eStyleImageType_Null;
1693 mCropRect = nullptr;
1694 }
1696 void
1697 nsStyleImage::SetImageData(imgIRequest* aImage)
1698 {
1699 NS_ABORT_IF_FALSE(!mImageTracked,
1700 "Setting a new image without untracking the old one!");
1702 NS_IF_ADDREF(aImage);
1704 if (mType != eStyleImageType_Null)
1705 SetNull();
1707 if (aImage) {
1708 mImage = aImage;
1709 mType = eStyleImageType_Image;
1710 }
1711 mSubImages.Clear();
1712 }
1714 void
1715 nsStyleImage::TrackImage(nsPresContext* aContext)
1716 {
1717 // Sanity
1718 NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
1719 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image,
1720 "Can't track image when there isn't one!");
1722 // Register the image with the document
1723 nsIDocument* doc = aContext->Document();
1724 if (doc)
1725 doc->AddImage(mImage);
1727 // Mark state
1728 #ifdef DEBUG
1729 mImageTracked = true;
1730 #endif
1731 }
1733 void
1734 nsStyleImage::UntrackImage(nsPresContext* aContext)
1735 {
1736 // Sanity
1737 NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
1738 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image,
1739 "Can't untrack image when there isn't one!");
1741 // Unregister the image with the document
1742 nsIDocument* doc = aContext->Document();
1743 if (doc)
1744 doc->RemoveImage(mImage, nsIDocument::REQUEST_DISCARD);
1746 // Mark state
1747 #ifdef DEBUG
1748 mImageTracked = false;
1749 #endif
1750 }
1752 void
1753 nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
1754 {
1755 if (aGradient)
1756 aGradient->AddRef();
1758 if (mType != eStyleImageType_Null)
1759 SetNull();
1761 if (aGradient) {
1762 mGradient = aGradient;
1763 mType = eStyleImageType_Gradient;
1764 }
1765 }
1767 void
1768 nsStyleImage::SetElementId(const char16_t* aElementId)
1769 {
1770 if (mType != eStyleImageType_Null)
1771 SetNull();
1773 if (aElementId) {
1774 mElementId = NS_strdup(aElementId);
1775 mType = eStyleImageType_Element;
1776 }
1777 }
1779 void
1780 nsStyleImage::SetCropRect(nsStyleSides* aCropRect)
1781 {
1782 if (aCropRect) {
1783 mCropRect = new nsStyleSides(*aCropRect);
1784 // There is really not much we can do if 'new' fails
1785 } else {
1786 mCropRect = nullptr;
1787 }
1788 }
1790 static int32_t
1791 ConvertToPixelCoord(const nsStyleCoord& aCoord, int32_t aPercentScale)
1792 {
1793 double pixelValue;
1794 switch (aCoord.GetUnit()) {
1795 case eStyleUnit_Percent:
1796 pixelValue = aCoord.GetPercentValue() * aPercentScale;
1797 break;
1798 case eStyleUnit_Factor:
1799 pixelValue = aCoord.GetFactorValue();
1800 break;
1801 default:
1802 NS_NOTREACHED("unexpected unit for image crop rect");
1803 return 0;
1804 }
1805 NS_ABORT_IF_FALSE(pixelValue >= 0, "we ensured non-negative while parsing");
1806 pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow
1807 return NS_lround(pixelValue);
1808 }
1810 bool
1811 nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
1812 bool* aIsEntireImage) const
1813 {
1814 if (mType != eStyleImageType_Image)
1815 return false;
1817 nsCOMPtr<imgIContainer> imageContainer;
1818 mImage->GetImage(getter_AddRefs(imageContainer));
1819 if (!imageContainer)
1820 return false;
1822 nsIntSize imageSize;
1823 imageContainer->GetWidth(&imageSize.width);
1824 imageContainer->GetHeight(&imageSize.height);
1825 if (imageSize.width <= 0 || imageSize.height <= 0)
1826 return false;
1828 int32_t left = ConvertToPixelCoord(mCropRect->GetLeft(), imageSize.width);
1829 int32_t top = ConvertToPixelCoord(mCropRect->GetTop(), imageSize.height);
1830 int32_t right = ConvertToPixelCoord(mCropRect->GetRight(), imageSize.width);
1831 int32_t bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height);
1833 // IntersectRect() returns an empty rect if we get negative width or height
1834 nsIntRect cropRect(left, top, right - left, bottom - top);
1835 nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
1836 aActualCropRect.IntersectRect(imageRect, cropRect);
1838 if (aIsEntireImage)
1839 *aIsEntireImage = aActualCropRect.IsEqualInterior(imageRect);
1840 return true;
1841 }
1843 nsresult
1844 nsStyleImage::StartDecoding() const
1845 {
1846 if ((mType == eStyleImageType_Image) && mImage)
1847 return mImage->StartDecoding();
1848 return NS_OK;
1849 }
1851 bool
1852 nsStyleImage::IsOpaque() const
1853 {
1854 if (!IsComplete())
1855 return false;
1857 if (mType == eStyleImageType_Gradient)
1858 return mGradient->IsOpaque();
1860 if (mType == eStyleImageType_Element)
1861 return false;
1863 NS_ABORT_IF_FALSE(mType == eStyleImageType_Image, "unexpected image type");
1865 nsCOMPtr<imgIContainer> imageContainer;
1866 mImage->GetImage(getter_AddRefs(imageContainer));
1867 NS_ABORT_IF_FALSE(imageContainer, "IsComplete() said image container is ready");
1869 // Check if the crop region of the current image frame is opaque.
1870 if (imageContainer->FrameIsOpaque(imgIContainer::FRAME_CURRENT)) {
1871 if (!mCropRect)
1872 return true;
1874 // Must make sure if mCropRect contains at least a pixel.
1875 // XXX Is this optimization worth it? Maybe I should just return false.
1876 nsIntRect actualCropRect;
1877 bool rv = ComputeActualCropRect(actualCropRect);
1878 NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
1879 return rv && !actualCropRect.IsEmpty();
1880 }
1882 return false;
1883 }
1885 bool
1886 nsStyleImage::IsComplete() const
1887 {
1888 switch (mType) {
1889 case eStyleImageType_Null:
1890 return false;
1891 case eStyleImageType_Gradient:
1892 case eStyleImageType_Element:
1893 return true;
1894 case eStyleImageType_Image:
1895 {
1896 uint32_t status = imgIRequest::STATUS_ERROR;
1897 return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
1898 (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
1899 (status & imgIRequest::STATUS_FRAME_COMPLETE);
1900 }
1901 default:
1902 NS_NOTREACHED("unexpected image type");
1903 return false;
1904 }
1905 }
1907 bool
1908 nsStyleImage::IsLoaded() const
1909 {
1910 switch (mType) {
1911 case eStyleImageType_Null:
1912 return false;
1913 case eStyleImageType_Gradient:
1914 case eStyleImageType_Element:
1915 return true;
1916 case eStyleImageType_Image:
1917 {
1918 uint32_t status = imgIRequest::STATUS_ERROR;
1919 return NS_SUCCEEDED(mImage->GetImageStatus(&status)) &&
1920 !(status & imgIRequest::STATUS_ERROR) &&
1921 (status & imgIRequest::STATUS_LOAD_COMPLETE);
1922 }
1923 default:
1924 NS_NOTREACHED("unexpected image type");
1925 return false;
1926 }
1927 }
1929 static inline bool
1930 EqualRects(const nsStyleSides* aRect1, const nsStyleSides* aRect2)
1931 {
1932 return aRect1 == aRect2 || /* handles null== null, and optimize */
1933 (aRect1 && aRect2 && *aRect1 == *aRect2);
1934 }
1936 bool
1937 nsStyleImage::operator==(const nsStyleImage& aOther) const
1938 {
1939 if (mType != aOther.mType)
1940 return false;
1942 if (!EqualRects(mCropRect, aOther.mCropRect))
1943 return false;
1945 if (mType == eStyleImageType_Image)
1946 return EqualImages(mImage, aOther.mImage);
1948 if (mType == eStyleImageType_Gradient)
1949 return *mGradient == *aOther.mGradient;
1951 if (mType == eStyleImageType_Element)
1952 return NS_strcmp(mElementId, aOther.mElementId) == 0;
1954 return true;
1955 }
1957 // --------------------
1958 // nsStyleBackground
1959 //
1961 nsStyleBackground::nsStyleBackground()
1962 : mAttachmentCount(1)
1963 , mClipCount(1)
1964 , mOriginCount(1)
1965 , mRepeatCount(1)
1966 , mPositionCount(1)
1967 , mImageCount(1)
1968 , mSizeCount(1)
1969 , mBlendModeCount(1)
1970 , mBackgroundColor(NS_RGBA(0, 0, 0, 0))
1971 , mBackgroundInlinePolicy(NS_STYLE_BG_INLINE_POLICY_CONTINUOUS)
1972 {
1973 MOZ_COUNT_CTOR(nsStyleBackground);
1974 Layer *onlyLayer = mLayers.AppendElement();
1975 NS_ASSERTION(onlyLayer, "auto array must have room for 1 element");
1976 onlyLayer->SetInitialValues();
1977 }
1979 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
1980 : mAttachmentCount(aSource.mAttachmentCount)
1981 , mClipCount(aSource.mClipCount)
1982 , mOriginCount(aSource.mOriginCount)
1983 , mRepeatCount(aSource.mRepeatCount)
1984 , mPositionCount(aSource.mPositionCount)
1985 , mImageCount(aSource.mImageCount)
1986 , mSizeCount(aSource.mSizeCount)
1987 , mBlendModeCount(aSource.mBlendModeCount)
1988 , mLayers(aSource.mLayers) // deep copy
1989 , mBackgroundColor(aSource.mBackgroundColor)
1990 , mBackgroundInlinePolicy(aSource.mBackgroundInlinePolicy)
1991 {
1992 MOZ_COUNT_CTOR(nsStyleBackground);
1993 // If the deep copy of mLayers failed, truncate the counts.
1994 uint32_t count = mLayers.Length();
1995 if (count != aSource.mLayers.Length()) {
1996 NS_WARNING("truncating counts due to out-of-memory");
1997 mAttachmentCount = std::max(mAttachmentCount, count);
1998 mClipCount = std::max(mClipCount, count);
1999 mOriginCount = std::max(mOriginCount, count);
2000 mRepeatCount = std::max(mRepeatCount, count);
2001 mPositionCount = std::max(mPositionCount, count);
2002 mImageCount = std::max(mImageCount, count);
2003 mSizeCount = std::max(mSizeCount, count);
2004 mBlendModeCount = std::max(mSizeCount, count);
2005 }
2006 }
2008 nsStyleBackground::~nsStyleBackground()
2009 {
2010 MOZ_COUNT_DTOR(nsStyleBackground);
2011 }
2013 void
2014 nsStyleBackground::Destroy(nsPresContext* aContext)
2015 {
2016 // Untrack all the images stored in our layers
2017 for (uint32_t i = 0; i < mImageCount; ++i)
2018 mLayers[i].UntrackImages(aContext);
2020 this->~nsStyleBackground();
2021 aContext->FreeToShell(sizeof(nsStyleBackground), this);
2022 }
2024 nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther) const
2025 {
2026 const nsStyleBackground* moreLayers =
2027 mImageCount > aOther.mImageCount ? this : &aOther;
2028 const nsStyleBackground* lessLayers =
2029 mImageCount > aOther.mImageCount ? &aOther : this;
2031 bool hasVisualDifference = false;
2033 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, moreLayers) {
2034 if (i < lessLayers->mImageCount) {
2035 if (moreLayers->mLayers[i] != lessLayers->mLayers[i]) {
2036 if ((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) ||
2037 (lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element))
2038 return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
2039 hasVisualDifference = true;
2040 }
2041 } else {
2042 if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)
2043 return NS_CombineHint(nsChangeHint_UpdateEffects, NS_STYLE_HINT_VISUAL);
2044 hasVisualDifference = true;
2045 }
2046 }
2048 if (hasVisualDifference ||
2049 mBackgroundColor != aOther.mBackgroundColor ||
2050 mBackgroundInlinePolicy != aOther.mBackgroundInlinePolicy)
2051 return NS_STYLE_HINT_VISUAL;
2053 return NS_STYLE_HINT_NONE;
2054 }
2056 bool nsStyleBackground::HasFixedBackground() const
2057 {
2058 NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, this) {
2059 const Layer &layer = mLayers[i];
2060 if (layer.mAttachment == NS_STYLE_BG_ATTACHMENT_FIXED &&
2061 !layer.mImage.IsEmpty()) {
2062 return true;
2063 }
2064 }
2065 return false;
2066 }
2068 bool nsStyleBackground::IsTransparent() const
2069 {
2070 return BottomLayer().mImage.IsEmpty() &&
2071 mImageCount == 1 &&
2072 NS_GET_A(mBackgroundColor) == 0;
2073 }
2075 void
2076 nsStyleBackground::Position::SetInitialValues()
2077 {
2078 // Initial value is "0% 0%"
2079 mXPosition.mPercent = 0.0f;
2080 mXPosition.mLength = 0;
2081 mXPosition.mHasPercent = true;
2082 mYPosition.mPercent = 0.0f;
2083 mYPosition.mLength = 0;
2084 mYPosition.mHasPercent = true;
2085 }
2087 bool
2088 nsStyleBackground::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImage) const
2089 {
2090 NS_ABORT_IF_FALSE(aImage.GetType() != eStyleImageType_Null,
2091 "caller should have handled this");
2093 // If either dimension contains a non-zero percentage, rendering for that
2094 // dimension straightforwardly depends on frame size.
2095 if ((mWidthType == eLengthPercentage && mWidth.mPercent != 0.0f) ||
2096 (mHeightType == eLengthPercentage && mHeight.mPercent != 0.0f)) {
2097 return true;
2098 }
2100 // So too for contain and cover.
2101 if (mWidthType == eContain || mWidthType == eCover) {
2102 return true;
2103 }
2105 // If both dimensions are fixed lengths, there's no dependency.
2106 if (mWidthType == eLengthPercentage && mHeightType == eLengthPercentage) {
2107 return false;
2108 }
2110 NS_ABORT_IF_FALSE((mWidthType == eLengthPercentage && mHeightType == eAuto) ||
2111 (mWidthType == eAuto && mHeightType == eLengthPercentage) ||
2112 (mWidthType == eAuto && mHeightType == eAuto),
2113 "logic error");
2115 nsStyleImageType type = aImage.GetType();
2117 // Gradient rendering depends on frame size when auto is involved because
2118 // gradients have no intrinsic ratio or dimensions, and therefore the relevant
2119 // dimension is "treat[ed] as 100%".
2120 if (type == eStyleImageType_Gradient) {
2121 return true;
2122 }
2124 // XXX Element rendering for auto or fixed length doesn't depend on frame size
2125 // according to the spec. However, we don't implement the spec yet, so
2126 // for now we bail and say element() plus auto affects ultimate size.
2127 if (type == eStyleImageType_Element) {
2128 return true;
2129 }
2131 if (type == eStyleImageType_Image) {
2132 nsCOMPtr<imgIContainer> imgContainer;
2133 aImage.GetImageData()->GetImage(getter_AddRefs(imgContainer));
2134 if (imgContainer) {
2135 nsIntSize imageSize;
2136 nsSize imageRatio;
2137 bool hasWidth, hasHeight;
2138 nsLayoutUtils::ComputeSizeForDrawing(imgContainer, imageSize, imageRatio,
2139 hasWidth, hasHeight);
2141 // If the image has a fixed width and height, rendering never depends on
2142 // the frame size.
2143 if (hasWidth && hasHeight) {
2144 return false;
2145 }
2147 // If the image has an intrinsic ratio, rendering will depend on frame
2148 // size when background-size is all auto.
2149 if (imageRatio != nsSize(0, 0)) {
2150 return mWidthType == mHeightType;
2151 }
2153 // Otherwise, rendering depends on frame size when the image dimensions
2154 // and background-size don't complement each other.
2155 return !(hasWidth && mHeightType == eLengthPercentage) &&
2156 !(hasHeight && mWidthType == eLengthPercentage);
2157 }
2158 } else {
2159 NS_NOTREACHED("missed an enum value");
2160 }
2162 // Passed the gauntlet: no dependency.
2163 return false;
2164 }
2166 void
2167 nsStyleBackground::Size::SetInitialValues()
2168 {
2169 mWidthType = mHeightType = eAuto;
2170 }
2172 bool
2173 nsStyleBackground::Size::operator==(const Size& aOther) const
2174 {
2175 NS_ABORT_IF_FALSE(mWidthType < eDimensionType_COUNT,
2176 "bad mWidthType for this");
2177 NS_ABORT_IF_FALSE(mHeightType < eDimensionType_COUNT,
2178 "bad mHeightType for this");
2179 NS_ABORT_IF_FALSE(aOther.mWidthType < eDimensionType_COUNT,
2180 "bad mWidthType for aOther");
2181 NS_ABORT_IF_FALSE(aOther.mHeightType < eDimensionType_COUNT,
2182 "bad mHeightType for aOther");
2184 return mWidthType == aOther.mWidthType &&
2185 mHeightType == aOther.mHeightType &&
2186 (mWidthType != eLengthPercentage || mWidth == aOther.mWidth) &&
2187 (mHeightType != eLengthPercentage || mHeight == aOther.mHeight);
2188 }
2190 void
2191 nsStyleBackground::Repeat::SetInitialValues()
2192 {
2193 mXRepeat = NS_STYLE_BG_REPEAT_REPEAT;
2194 mYRepeat = NS_STYLE_BG_REPEAT_REPEAT;
2195 }
2197 nsStyleBackground::Layer::Layer()
2198 {
2199 }
2201 nsStyleBackground::Layer::~Layer()
2202 {
2203 }
2205 void
2206 nsStyleBackground::Layer::SetInitialValues()
2207 {
2208 mAttachment = NS_STYLE_BG_ATTACHMENT_SCROLL;
2209 mClip = NS_STYLE_BG_CLIP_BORDER;
2210 mOrigin = NS_STYLE_BG_ORIGIN_PADDING;
2211 mRepeat.SetInitialValues();
2212 mBlendMode = NS_STYLE_BLEND_NORMAL;
2213 mPosition.SetInitialValues();
2214 mSize.SetInitialValues();
2215 mImage.SetNull();
2216 }
2218 bool
2219 nsStyleBackground::Layer::RenderingMightDependOnPositioningAreaSizeChange() const
2220 {
2221 // Do we even have an image?
2222 if (mImage.IsEmpty()) {
2223 return false;
2224 }
2226 return mPosition.DependsOnPositioningAreaSize() ||
2227 mSize.DependsOnPositioningAreaSize(mImage);
2228 }
2230 bool
2231 nsStyleBackground::Layer::operator==(const Layer& aOther) const
2232 {
2233 return mAttachment == aOther.mAttachment &&
2234 mClip == aOther.mClip &&
2235 mOrigin == aOther.mOrigin &&
2236 mRepeat == aOther.mRepeat &&
2237 mBlendMode == aOther.mBlendMode &&
2238 mPosition == aOther.mPosition &&
2239 mSize == aOther.mSize &&
2240 mImage == aOther.mImage;
2241 }
2243 // --------------------
2244 // nsStyleDisplay
2245 //
2246 void nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
2247 {
2248 switch (aTimingFunctionType) {
2249 case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
2250 mType = StepStart;
2251 mSteps = 1;
2252 return;
2253 case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END:
2254 mType = StepEnd;
2255 mSteps = 1;
2256 return;
2257 default:
2258 mType = Function;
2259 break;
2260 }
2262 static_assert(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE == 0 &&
2263 NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR == 1 &&
2264 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN == 2 &&
2265 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT == 3 &&
2266 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT == 4,
2267 "transition timing function constants not as expected");
2269 static const float timingFunctionValues[5][4] = {
2270 { 0.25f, 0.10f, 0.25f, 1.00f }, // ease
2271 { 0.00f, 0.00f, 1.00f, 1.00f }, // linear
2272 { 0.42f, 0.00f, 1.00f, 1.00f }, // ease-in
2273 { 0.00f, 0.00f, 0.58f, 1.00f }, // ease-out
2274 { 0.42f, 0.00f, 0.58f, 1.00f } // ease-in-out
2275 };
2277 NS_ABORT_IF_FALSE(0 <= aTimingFunctionType && aTimingFunctionType < 5,
2278 "keyword out of range");
2279 mFunc.mX1 = timingFunctionValues[aTimingFunctionType][0];
2280 mFunc.mY1 = timingFunctionValues[aTimingFunctionType][1];
2281 mFunc.mX2 = timingFunctionValues[aTimingFunctionType][2];
2282 mFunc.mY2 = timingFunctionValues[aTimingFunctionType][3];
2283 }
2285 nsTransition::nsTransition(const nsTransition& aCopy)
2286 : mTimingFunction(aCopy.mTimingFunction)
2287 , mDuration(aCopy.mDuration)
2288 , mDelay(aCopy.mDelay)
2289 , mProperty(aCopy.mProperty)
2290 , mUnknownProperty(aCopy.mUnknownProperty)
2291 {
2292 }
2294 void nsTransition::SetInitialValues()
2295 {
2296 mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
2297 mDuration = 0.0;
2298 mDelay = 0.0;
2299 mProperty = eCSSPropertyExtra_all_properties;
2300 }
2302 void nsTransition::SetUnknownProperty(const nsAString& aUnknownProperty)
2303 {
2304 NS_ASSERTION(nsCSSProps::LookupProperty(aUnknownProperty,
2305 nsCSSProps::eEnabledForAllContent) ==
2306 eCSSProperty_UNKNOWN,
2307 "should be unknown property");
2308 mProperty = eCSSProperty_UNKNOWN;
2309 mUnknownProperty = do_GetAtom(aUnknownProperty);
2310 }
2312 nsAnimation::nsAnimation(const nsAnimation& aCopy)
2313 : mTimingFunction(aCopy.mTimingFunction)
2314 , mDuration(aCopy.mDuration)
2315 , mDelay(aCopy.mDelay)
2316 , mName(aCopy.mName)
2317 , mDirection(aCopy.mDirection)
2318 , mFillMode(aCopy.mFillMode)
2319 , mPlayState(aCopy.mPlayState)
2320 , mIterationCount(aCopy.mIterationCount)
2321 {
2322 }
2324 void
2325 nsAnimation::SetInitialValues()
2326 {
2327 mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
2328 mDuration = 0.0;
2329 mDelay = 0.0;
2330 mName = EmptyString();
2331 mDirection = NS_STYLE_ANIMATION_DIRECTION_NORMAL;
2332 mFillMode = NS_STYLE_ANIMATION_FILL_MODE_NONE;
2333 mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING;
2334 mIterationCount = 1.0f;
2335 }
2337 nsStyleDisplay::nsStyleDisplay()
2338 : mWillChangeBitField(0)
2339 {
2340 MOZ_COUNT_CTOR(nsStyleDisplay);
2341 mAppearance = NS_THEME_NONE;
2342 mDisplay = NS_STYLE_DISPLAY_INLINE;
2343 mOriginalDisplay = mDisplay;
2344 mPosition = NS_STYLE_POSITION_STATIC;
2345 mFloats = NS_STYLE_FLOAT_NONE;
2346 mOriginalFloats = mFloats;
2347 mBreakType = NS_STYLE_CLEAR_NONE;
2348 mBreakInside = NS_STYLE_PAGE_BREAK_AUTO;
2349 mBreakBefore = false;
2350 mBreakAfter = false;
2351 mOverflowX = NS_STYLE_OVERFLOW_VISIBLE;
2352 mOverflowY = NS_STYLE_OVERFLOW_VISIBLE;
2353 mOverflowClipBox = NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX;
2354 mResize = NS_STYLE_RESIZE_NONE;
2355 mClipFlags = NS_STYLE_CLIP_AUTO;
2356 mClip.SetRect(0,0,0,0);
2357 mOpacity = 1.0f;
2358 mSpecifiedTransform = nullptr;
2359 mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
2360 mTransformOrigin[1].SetPercentValue(0.5f);
2361 mTransformOrigin[2].SetCoordValue(0);
2362 mPerspectiveOrigin[0].SetPercentValue(0.5f);
2363 mPerspectiveOrigin[1].SetPercentValue(0.5f);
2364 mChildPerspective.SetNoneValue();
2365 mBackfaceVisibility = NS_STYLE_BACKFACE_VISIBILITY_VISIBLE;
2366 mTransformStyle = NS_STYLE_TRANSFORM_STYLE_FLAT;
2367 mOrient = NS_STYLE_ORIENT_AUTO;
2368 mMixBlendMode = NS_STYLE_BLEND_NORMAL;
2369 mTouchAction = NS_STYLE_TOUCH_ACTION_AUTO;
2371 mTransitions.AppendElement();
2372 NS_ABORT_IF_FALSE(mTransitions.Length() == 1,
2373 "appending within auto buffer should never fail");
2374 mTransitions[0].SetInitialValues();
2375 mTransitionTimingFunctionCount = 1;
2376 mTransitionDurationCount = 1;
2377 mTransitionDelayCount = 1;
2378 mTransitionPropertyCount = 1;
2380 mAnimations.AppendElement();
2381 NS_ABORT_IF_FALSE(mAnimations.Length() == 1,
2382 "appending within auto buffer should never fail");
2383 mAnimations[0].SetInitialValues();
2384 mAnimationTimingFunctionCount = 1;
2385 mAnimationDurationCount = 1;
2386 mAnimationDelayCount = 1;
2387 mAnimationNameCount = 1;
2388 mAnimationDirectionCount = 1;
2389 mAnimationFillModeCount = 1;
2390 mAnimationPlayStateCount = 1;
2391 mAnimationIterationCountCount = 1;
2392 }
2394 nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
2395 : mBinding(aSource.mBinding)
2396 , mClip(aSource.mClip)
2397 , mOpacity(aSource.mOpacity)
2398 , mDisplay(aSource.mDisplay)
2399 , mOriginalDisplay(aSource.mOriginalDisplay)
2400 , mAppearance(aSource.mAppearance)
2401 , mPosition(aSource.mPosition)
2402 , mFloats(aSource.mFloats)
2403 , mOriginalFloats(aSource.mOriginalFloats)
2404 , mBreakType(aSource.mBreakType)
2405 , mBreakInside(aSource.mBreakInside)
2406 , mBreakBefore(aSource.mBreakBefore)
2407 , mBreakAfter(aSource.mBreakAfter)
2408 , mOverflowX(aSource.mOverflowX)
2409 , mOverflowY(aSource.mOverflowY)
2410 , mOverflowClipBox(aSource.mOverflowClipBox)
2411 , mResize(aSource.mResize)
2412 , mClipFlags(aSource.mClipFlags)
2413 , mOrient(aSource.mOrient)
2414 , mMixBlendMode(aSource.mMixBlendMode)
2415 , mWillChangeBitField(aSource.mWillChangeBitField)
2416 , mWillChange(aSource.mWillChange)
2417 , mTouchAction(aSource.mTouchAction)
2418 , mBackfaceVisibility(aSource.mBackfaceVisibility)
2419 , mTransformStyle(aSource.mTransformStyle)
2420 , mSpecifiedTransform(aSource.mSpecifiedTransform)
2421 , mChildPerspective(aSource.mChildPerspective)
2422 , mTransitions(aSource.mTransitions)
2423 , mTransitionTimingFunctionCount(aSource.mTransitionTimingFunctionCount)
2424 , mTransitionDurationCount(aSource.mTransitionDurationCount)
2425 , mTransitionDelayCount(aSource.mTransitionDelayCount)
2426 , mTransitionPropertyCount(aSource.mTransitionPropertyCount)
2427 , mAnimations(aSource.mAnimations)
2428 , mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount)
2429 , mAnimationDurationCount(aSource.mAnimationDurationCount)
2430 , mAnimationDelayCount(aSource.mAnimationDelayCount)
2431 , mAnimationNameCount(aSource.mAnimationNameCount)
2432 , mAnimationDirectionCount(aSource.mAnimationDirectionCount)
2433 , mAnimationFillModeCount(aSource.mAnimationFillModeCount)
2434 , mAnimationPlayStateCount(aSource.mAnimationPlayStateCount)
2435 , mAnimationIterationCountCount(aSource.mAnimationIterationCountCount)
2436 {
2437 MOZ_COUNT_CTOR(nsStyleDisplay);
2439 /* Copy over transform origin. */
2440 mTransformOrigin[0] = aSource.mTransformOrigin[0];
2441 mTransformOrigin[1] = aSource.mTransformOrigin[1];
2442 mTransformOrigin[2] = aSource.mTransformOrigin[2];
2443 mPerspectiveOrigin[0] = aSource.mPerspectiveOrigin[0];
2444 mPerspectiveOrigin[1] = aSource.mPerspectiveOrigin[1];
2445 }
2447 nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
2448 {
2449 nsChangeHint hint = nsChangeHint(0);
2451 if (!EqualURIs(mBinding, aOther.mBinding)
2452 || mPosition != aOther.mPosition
2453 || mDisplay != aOther.mDisplay
2454 || (mFloats == NS_STYLE_FLOAT_NONE) != (aOther.mFloats == NS_STYLE_FLOAT_NONE)
2455 || mOverflowX != aOther.mOverflowX
2456 || mOverflowY != aOther.mOverflowY
2457 || mResize != aOther.mResize)
2458 NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
2460 if ((mAppearance == NS_THEME_TEXTFIELD &&
2461 aOther.mAppearance != NS_THEME_TEXTFIELD) ||
2462 (mAppearance != NS_THEME_TEXTFIELD &&
2463 aOther.mAppearance == NS_THEME_TEXTFIELD)) {
2464 // This is for <input type=number> where we allow authors to specify a
2465 // |-moz-appearance:textfield| to get a control without a spinner. (The
2466 // spinner is present for |-moz-appearance:number-input| but also other
2467 // values such as 'none'.) We need to reframe since we want to use
2468 // nsTextControlFrame instead of nsNumberControlFrame if the author
2469 // specifies 'textfield'.
2470 return nsChangeHint_ReconstructFrame;
2471 }
2473 if (mFloats != aOther.mFloats) {
2474 // Changing which side we float on doesn't affect descendants directly
2475 NS_UpdateHint(hint,
2476 NS_SubtractHint(nsChangeHint_AllReflowHints,
2477 NS_CombineHint(nsChangeHint_ClearDescendantIntrinsics,
2478 nsChangeHint_NeedDirtyReflow)));
2479 }
2481 // XXX the following is conservative, for now: changing float breaking shouldn't
2482 // necessarily require a repaint, reflow should suffice.
2483 if (mBreakType != aOther.mBreakType
2484 || mBreakInside != aOther.mBreakInside
2485 || mBreakBefore != aOther.mBreakBefore
2486 || mBreakAfter != aOther.mBreakAfter
2487 || mAppearance != aOther.mAppearance
2488 || mOrient != aOther.mOrient
2489 || mOverflowClipBox != aOther.mOverflowClipBox
2490 || mClipFlags != aOther.mClipFlags || !mClip.IsEqualInterior(aOther.mClip))
2491 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints,
2492 nsChangeHint_RepaintFrame));
2494 if (mOpacity != aOther.mOpacity) {
2495 // If we're going from the optimized >=0.99 opacity value to 1.0 or back, then
2496 // repaint the frame because DLBI will not catch the invalidation. Otherwise,
2497 // just update the opacity layer.
2498 if ((mOpacity >= 0.99f && mOpacity < 1.0f && aOther.mOpacity == 1.0f) ||
2499 (aOther.mOpacity >= 0.99f && aOther.mOpacity < 1.0f && mOpacity == 1.0f)) {
2500 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
2501 } else {
2502 NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
2503 }
2504 }
2506 /* If we've added or removed the transform property, we need to reconstruct the frame to add
2507 * or remove the view object, and also to handle abs-pos and fixed-pos containers.
2508 */
2509 if (HasTransformStyle() != aOther.HasTransformStyle()) {
2510 // We do not need to apply nsChangeHint_UpdateTransformLayer since
2511 // nsChangeHint_RepaintFrame will forcibly invalidate the frame area and
2512 // ensure layers are rebuilt (or removed).
2513 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AddOrRemoveTransform,
2514 NS_CombineHint(nsChangeHint_UpdateOverflow,
2515 nsChangeHint_RepaintFrame)));
2516 }
2517 else if (HasTransformStyle()) {
2518 /* Otherwise, if we've kept the property lying around and we already had a
2519 * transform, we need to see whether or not we've changed the transform.
2520 * If so, we need to recompute its overflow rect (which probably changed
2521 * if the transform changed) and to redraw within the bounds of that new
2522 * overflow rect.
2523 */
2524 if (!mSpecifiedTransform != !aOther.mSpecifiedTransform ||
2525 (mSpecifiedTransform &&
2526 *mSpecifiedTransform != *aOther.mSpecifiedTransform)) {
2527 NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_UpdatePostTransformOverflow,
2528 nsChangeHint_UpdateTransformLayer));
2529 }
2531 const nsChangeHint kUpdateOverflowAndRepaintHint =
2532 NS_CombineHint(nsChangeHint_UpdateOverflow, nsChangeHint_RepaintFrame);
2533 for (uint8_t index = 0; index < 3; ++index)
2534 if (mTransformOrigin[index] != aOther.mTransformOrigin[index]) {
2535 NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
2536 break;
2537 }
2539 for (uint8_t index = 0; index < 2; ++index)
2540 if (mPerspectiveOrigin[index] != aOther.mPerspectiveOrigin[index]) {
2541 NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
2542 break;
2543 }
2545 if (mChildPerspective != aOther.mChildPerspective ||
2546 mTransformStyle != aOther.mTransformStyle)
2547 NS_UpdateHint(hint, kUpdateOverflowAndRepaintHint);
2549 if (mBackfaceVisibility != aOther.mBackfaceVisibility)
2550 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
2551 }
2553 uint8_t willChangeBitsChanged =
2554 mWillChangeBitField ^ aOther.mWillChangeBitField;
2555 if (willChangeBitsChanged & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) {
2556 NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
2557 }
2558 if (willChangeBitsChanged & ~uint8_t(NS_STYLE_WILL_CHANGE_STACKING_CONTEXT)) {
2559 // FIXME (Bug 974125): Don't reconstruct the frame
2560 NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
2561 }
2563 // Note: Our current behavior for handling changes to the
2564 // transition-duration, transition-delay, and transition-timing-function
2565 // properties is to do nothing. In other words, the transition
2566 // property that matters is what it is when the transition begins, and
2567 // we don't stop a transition later because the transition property
2568 // changed.
2569 // We do handle changes to transition-property, but we don't need to
2570 // bother with anything here, since the transition manager is notified
2571 // of any style context change anyway.
2573 // Note: Likewise, for animation-*, the animation manager gets
2574 // notified about every new style context constructed, and it uses
2575 // that opportunity to handle dynamic changes appropriately.
2577 return hint;
2578 }
2580 // --------------------
2581 // nsStyleVisibility
2582 //
2584 nsStyleVisibility::nsStyleVisibility(nsPresContext* aPresContext)
2585 {
2586 MOZ_COUNT_CTOR(nsStyleVisibility);
2587 uint32_t bidiOptions = aPresContext->GetBidi();
2588 if (GET_BIDI_OPTION_DIRECTION(bidiOptions) == IBMBIDI_TEXTDIRECTION_RTL)
2589 mDirection = NS_STYLE_DIRECTION_RTL;
2590 else
2591 mDirection = NS_STYLE_DIRECTION_LTR;
2593 mVisible = NS_STYLE_VISIBILITY_VISIBLE;
2594 mPointerEvents = NS_STYLE_POINTER_EVENTS_AUTO;
2595 mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
2596 }
2598 nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource)
2599 {
2600 MOZ_COUNT_CTOR(nsStyleVisibility);
2601 mImageOrientation = aSource.mImageOrientation;
2602 mDirection = aSource.mDirection;
2603 mVisible = aSource.mVisible;
2604 mPointerEvents = aSource.mPointerEvents;
2605 mWritingMode = aSource.mWritingMode;
2606 }
2608 nsChangeHint nsStyleVisibility::CalcDifference(const nsStyleVisibility& aOther) const
2609 {
2610 nsChangeHint hint = nsChangeHint(0);
2612 if (mDirection != aOther.mDirection || mWritingMode != aOther.mWritingMode) {
2613 NS_UpdateHint(hint, nsChangeHint_ReconstructFrame);
2614 } else {
2615 if ((mImageOrientation != aOther.mImageOrientation)) {
2616 NS_UpdateHint(hint, nsChangeHint_AllReflowHints);
2617 }
2618 if (mVisible != aOther.mVisible) {
2619 if ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) ||
2620 (NS_STYLE_VISIBILITY_COLLAPSE == aOther.mVisible)) {
2621 NS_UpdateHint(hint, NS_STYLE_HINT_REFLOW);
2622 } else {
2623 NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
2624 }
2625 }
2626 if (mPointerEvents != aOther.mPointerEvents) {
2627 // nsSVGPathGeometryFrame's mRect depends on stroke _and_ on the value
2628 // of pointer-events. See nsSVGPathGeometryFrame::ReflowSVG's use of
2629 // GetHitTestFlags. (Only a reflow, no visual change.)
2630 NS_UpdateHint(hint, nsChangeHint_NeedReflow);
2631 NS_UpdateHint(hint, nsChangeHint_NeedDirtyReflow); // XXX remove me: bug 876085
2632 }
2633 }
2634 return hint;
2635 }
2637 nsStyleContentData::~nsStyleContentData()
2638 {
2639 NS_ABORT_IF_FALSE(!mImageTracked,
2640 "nsStyleContentData being destroyed while still tracking image!");
2641 if (mType == eStyleContentType_Image) {
2642 NS_IF_RELEASE(mContent.mImage);
2643 } else if (mType == eStyleContentType_Counter ||
2644 mType == eStyleContentType_Counters) {
2645 mContent.mCounters->Release();
2646 } else if (mContent.mString) {
2647 NS_Free(mContent.mString);
2648 }
2649 }
2651 nsStyleContentData& nsStyleContentData::operator=(const nsStyleContentData& aOther)
2652 {
2653 if (this == &aOther)
2654 return *this;
2655 this->~nsStyleContentData();
2656 new (this) nsStyleContentData();
2658 mType = aOther.mType;
2659 if (mType == eStyleContentType_Image) {
2660 mContent.mImage = aOther.mContent.mImage;
2661 NS_IF_ADDREF(mContent.mImage);
2662 } else if (mType == eStyleContentType_Counter ||
2663 mType == eStyleContentType_Counters) {
2664 mContent.mCounters = aOther.mContent.mCounters;
2665 mContent.mCounters->AddRef();
2666 } else if (aOther.mContent.mString) {
2667 mContent.mString = NS_strdup(aOther.mContent.mString);
2668 } else {
2669 mContent.mString = nullptr;
2670 }
2671 return *this;
2672 }
2674 bool nsStyleContentData::operator==(const nsStyleContentData& aOther) const
2675 {
2676 if (mType != aOther.mType)
2677 return false;
2678 if (mType == eStyleContentType_Image) {
2679 if (!mContent.mImage || !aOther.mContent.mImage)
2680 return mContent.mImage == aOther.mContent.mImage;
2681 bool eq;
2682 nsCOMPtr<nsIURI> thisURI, otherURI;
2683 mContent.mImage->GetURI(getter_AddRefs(thisURI));
2684 aOther.mContent.mImage->GetURI(getter_AddRefs(otherURI));
2685 return thisURI == otherURI || // handles null==null
2686 (thisURI && otherURI &&
2687 NS_SUCCEEDED(thisURI->Equals(otherURI, &eq)) &&
2688 eq);
2689 }
2690 if (mType == eStyleContentType_Counter ||
2691 mType == eStyleContentType_Counters)
2692 return *mContent.mCounters == *aOther.mContent.mCounters;
2693 return safe_strcmp(mContent.mString, aOther.mContent.mString) == 0;
2694 }
2696 void
2697 nsStyleContentData::TrackImage(nsPresContext* aContext)
2698 {
2699 // Sanity
2700 NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
2701 NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
2702 "Trying to do image tracking on non-image!");
2703 NS_ABORT_IF_FALSE(mContent.mImage,
2704 "Can't track image when there isn't one!");
2706 // Register the image with the document
2707 nsIDocument* doc = aContext->Document();
2708 if (doc)
2709 doc->AddImage(mContent.mImage);
2711 // Mark state
2712 #ifdef DEBUG
2713 mImageTracked = true;
2714 #endif
2715 }
2717 void
2718 nsStyleContentData::UntrackImage(nsPresContext* aContext)
2719 {
2720 // Sanity
2721 NS_ABORT_IF_FALSE(mImageTracked, "Image not tracked!");
2722 NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
2723 "Trying to do image tracking on non-image!");
2724 NS_ABORT_IF_FALSE(mContent.mImage,
2725 "Can't untrack image when there isn't one!");
2727 // Unregister the image with the document
2728 nsIDocument* doc = aContext->Document();
2729 if (doc)
2730 doc->RemoveImage(mContent.mImage, nsIDocument::REQUEST_DISCARD);
2732 // Mark state
2733 #ifdef DEBUG
2734 mImageTracked = false;
2735 #endif
2736 }
2739 //-----------------------
2740 // nsStyleContent
2741 //
2743 nsStyleContent::nsStyleContent(void)
2744 : mMarkerOffset(),
2745 mContents(nullptr),
2746 mIncrements(nullptr),
2747 mResets(nullptr),
2748 mContentCount(0),
2749 mIncrementCount(0),
2750 mResetCount(0)
2751 {
2752 MOZ_COUNT_CTOR(nsStyleContent);
2753 mMarkerOffset.SetAutoValue();
2754 }
2756 nsStyleContent::~nsStyleContent(void)
2757 {
2758 MOZ_COUNT_DTOR(nsStyleContent);
2759 DELETE_ARRAY_IF(mContents);
2760 DELETE_ARRAY_IF(mIncrements);
2761 DELETE_ARRAY_IF(mResets);
2762 }
2764 void
2765 nsStyleContent::Destroy(nsPresContext* aContext)
2766 {
2767 // Unregister any images we might have with the document.
2768 for (uint32_t i = 0; i < mContentCount; ++i) {
2769 if ((mContents[i].mType == eStyleContentType_Image) &&
2770 mContents[i].mContent.mImage) {
2771 mContents[i].UntrackImage(aContext);
2772 }
2773 }
2775 this->~nsStyleContent();
2776 aContext->FreeToShell(sizeof(nsStyleContent), this);
2777 }
2779 nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
2780 :mMarkerOffset(),
2781 mContents(nullptr),
2782 mIncrements(nullptr),
2783 mResets(nullptr),
2784 mContentCount(0),
2785 mIncrementCount(0),
2786 mResetCount(0)
2788 {
2789 MOZ_COUNT_CTOR(nsStyleContent);
2790 mMarkerOffset = aSource.mMarkerOffset;
2792 uint32_t index;
2793 if (NS_SUCCEEDED(AllocateContents(aSource.ContentCount()))) {
2794 for (index = 0; index < mContentCount; index++) {
2795 ContentAt(index) = aSource.ContentAt(index);
2796 }
2797 }
2799 if (NS_SUCCEEDED(AllocateCounterIncrements(aSource.CounterIncrementCount()))) {
2800 for (index = 0; index < mIncrementCount; index++) {
2801 const nsStyleCounterData *data = aSource.GetCounterIncrementAt(index);
2802 mIncrements[index].mCounter = data->mCounter;
2803 mIncrements[index].mValue = data->mValue;
2804 }
2805 }
2807 if (NS_SUCCEEDED(AllocateCounterResets(aSource.CounterResetCount()))) {
2808 for (index = 0; index < mResetCount; index++) {
2809 const nsStyleCounterData *data = aSource.GetCounterResetAt(index);
2810 mResets[index].mCounter = data->mCounter;
2811 mResets[index].mValue = data->mValue;
2812 }
2813 }
2814 }
2816 nsChangeHint nsStyleContent::CalcDifference(const nsStyleContent& aOther) const
2817 {
2818 // In ReResolveStyleContext we assume that if there's no existing
2819 // ::before or ::after and we don't have to restyle children of the
2820 // node then we can't end up with a ::before or ::after due to the
2821 // restyle of the node itself. That's not quite true, but the only
2822 // exception to the above is when the 'content' property of the node
2823 // changes and the pseudo-element inherits the changed value. Since
2824 // the code here triggers a frame change on the node in that case,
2825 // the optimization in ReResolveStyleContext is ok. But if we ever
2826 // change this code to not reconstruct frames on changes to the
2827 // 'content' property, then we will need to revisit the optimization
2828 // in ReResolveStyleContext.
2830 if (mContentCount != aOther.mContentCount ||
2831 mIncrementCount != aOther.mIncrementCount ||
2832 mResetCount != aOther.mResetCount) {
2833 return NS_STYLE_HINT_FRAMECHANGE;
2834 }
2836 uint32_t ix = mContentCount;
2837 while (0 < ix--) {
2838 if (mContents[ix] != aOther.mContents[ix]) {
2839 // Unfortunately we need to reframe here; a simple reflow
2840 // will not pick up different text or different image URLs,
2841 // since we set all that up in the CSSFrameConstructor
2842 return NS_STYLE_HINT_FRAMECHANGE;
2843 }
2844 }
2845 ix = mIncrementCount;
2846 while (0 < ix--) {
2847 if ((mIncrements[ix].mValue != aOther.mIncrements[ix].mValue) ||
2848 (mIncrements[ix].mCounter != aOther.mIncrements[ix].mCounter)) {
2849 return NS_STYLE_HINT_FRAMECHANGE;
2850 }
2851 }
2852 ix = mResetCount;
2853 while (0 < ix--) {
2854 if ((mResets[ix].mValue != aOther.mResets[ix].mValue) ||
2855 (mResets[ix].mCounter != aOther.mResets[ix].mCounter)) {
2856 return NS_STYLE_HINT_FRAMECHANGE;
2857 }
2858 }
2859 if (mMarkerOffset != aOther.mMarkerOffset) {
2860 return NS_STYLE_HINT_REFLOW;
2861 }
2862 return NS_STYLE_HINT_NONE;
2863 }
2865 nsresult nsStyleContent::AllocateContents(uint32_t aCount)
2866 {
2867 // We need to run the destructors of the elements of mContents, so we
2868 // delete and reallocate even if aCount == mContentCount. (If
2869 // nsStyleContentData had its members private and managed their
2870 // ownership on setting, we wouldn't need this, but that seems
2871 // unnecessary at this point.)
2872 DELETE_ARRAY_IF(mContents);
2873 if (aCount) {
2874 mContents = new nsStyleContentData[aCount];
2875 if (! mContents) {
2876 mContentCount = 0;
2877 return NS_ERROR_OUT_OF_MEMORY;
2878 }
2879 }
2880 mContentCount = aCount;
2881 return NS_OK;
2882 }
2884 // ---------------------
2885 // nsStyleQuotes
2886 //
2888 nsStyleQuotes::nsStyleQuotes(void)
2889 : mQuotesCount(0),
2890 mQuotes(nullptr)
2891 {
2892 MOZ_COUNT_CTOR(nsStyleQuotes);
2893 SetInitial();
2894 }
2896 nsStyleQuotes::~nsStyleQuotes(void)
2897 {
2898 MOZ_COUNT_DTOR(nsStyleQuotes);
2899 DELETE_ARRAY_IF(mQuotes);
2900 }
2902 nsStyleQuotes::nsStyleQuotes(const nsStyleQuotes& aSource)
2903 : mQuotesCount(0),
2904 mQuotes(nullptr)
2905 {
2906 MOZ_COUNT_CTOR(nsStyleQuotes);
2907 CopyFrom(aSource);
2908 }
2910 void
2911 nsStyleQuotes::SetInitial()
2912 {
2913 // The initial value for quotes is the en-US typographic convention:
2914 // outermost are LEFT and RIGHT DOUBLE QUOTATION MARK, alternating
2915 // with LEFT and RIGHT SINGLE QUOTATION MARK.
2916 static const char16_t initialQuotes[8] = {
2917 0x201C, 0, 0x201D, 0, 0x2018, 0, 0x2019, 0
2918 };
2920 if (NS_SUCCEEDED(AllocateQuotes(2))) {
2921 SetQuotesAt(0,
2922 nsDependentString(&initialQuotes[0], 1),
2923 nsDependentString(&initialQuotes[2], 1));
2924 SetQuotesAt(1,
2925 nsDependentString(&initialQuotes[4], 1),
2926 nsDependentString(&initialQuotes[6], 1));
2927 }
2928 }
2930 void
2931 nsStyleQuotes::CopyFrom(const nsStyleQuotes& aSource)
2932 {
2933 if (NS_SUCCEEDED(AllocateQuotes(aSource.QuotesCount()))) {
2934 uint32_t count = (mQuotesCount * 2);
2935 for (uint32_t index = 0; index < count; index += 2) {
2936 aSource.GetQuotesAt(index, mQuotes[index], mQuotes[index + 1]);
2937 }
2938 }
2939 }
2941 nsChangeHint nsStyleQuotes::CalcDifference(const nsStyleQuotes& aOther) const
2942 {
2943 // If the quotes implementation is ever going to change we might not need
2944 // a framechange here and a reflow should be sufficient. See bug 35768.
2945 if (mQuotesCount == aOther.mQuotesCount) {
2946 uint32_t ix = (mQuotesCount * 2);
2947 while (0 < ix--) {
2948 if (mQuotes[ix] != aOther.mQuotes[ix]) {
2949 return NS_STYLE_HINT_FRAMECHANGE;
2950 }
2951 }
2953 return NS_STYLE_HINT_NONE;
2954 }
2955 return NS_STYLE_HINT_FRAMECHANGE;
2956 }
2958 // --------------------
2959 // nsStyleTextReset
2960 //
2962 nsStyleTextReset::nsStyleTextReset(void)
2963 {
2964 MOZ_COUNT_CTOR(nsStyleTextReset);
2965 mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated);
2966 mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
2967 mTextDecorationColor = NS_RGB(0,0,0);
2968 mTextDecorationStyle =
2969 NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND;
2970 mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL;
2971 }
2973 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
2974 {
2975 MOZ_COUNT_CTOR(nsStyleTextReset);
2976 *this = aSource;
2977 }
2979 nsStyleTextReset::~nsStyleTextReset(void)
2980 {
2981 MOZ_COUNT_DTOR(nsStyleTextReset);
2982 }
2984 nsChangeHint nsStyleTextReset::CalcDifference(const nsStyleTextReset& aOther) const
2985 {
2986 if (mVerticalAlign == aOther.mVerticalAlign
2987 && mUnicodeBidi == aOther.mUnicodeBidi) {
2988 uint8_t lineStyle = GetDecorationStyle();
2989 uint8_t otherLineStyle = aOther.GetDecorationStyle();
2990 if (mTextDecorationLine != aOther.mTextDecorationLine ||
2991 lineStyle != otherLineStyle) {
2992 // Reflow for decoration line style changes only to or from double or
2993 // wave because that may cause overflow area changes
2994 if (lineStyle == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE ||
2995 lineStyle == NS_STYLE_TEXT_DECORATION_STYLE_WAVY ||
2996 otherLineStyle == NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE ||
2997 otherLineStyle == NS_STYLE_TEXT_DECORATION_STYLE_WAVY) {
2998 return NS_STYLE_HINT_REFLOW;
2999 }
3000 // Repaint for other style decoration lines because they must be in
3001 // default overflow rect
3002 return NS_STYLE_HINT_VISUAL;
3003 }
3005 // Repaint for decoration color changes
3006 nscolor decColor, otherDecColor;
3007 bool isFG, otherIsFG;
3008 GetDecorationColor(decColor, isFG);
3009 aOther.GetDecorationColor(otherDecColor, otherIsFG);
3010 if (isFG != otherIsFG || (!isFG && decColor != otherDecColor)) {
3011 return NS_STYLE_HINT_VISUAL;
3012 }
3014 if (mTextOverflow != aOther.mTextOverflow) {
3015 return NS_STYLE_HINT_VISUAL;
3016 }
3017 return NS_STYLE_HINT_NONE;
3018 }
3019 return NS_STYLE_HINT_REFLOW;
3020 }
3022 // Allowed to return one of NS_STYLE_HINT_NONE, NS_STYLE_HINT_REFLOW
3023 // or NS_STYLE_HINT_VISUAL. Currently we just return NONE or REFLOW, though.
3024 // XXXbz can this not return a more specific hint? If that's ever
3025 // changed, nsStyleBorder::CalcDifference will need changing too.
3026 static nsChangeHint
3027 CalcShadowDifference(nsCSSShadowArray* lhs,
3028 nsCSSShadowArray* rhs)
3029 {
3030 if (lhs == rhs)
3031 return NS_STYLE_HINT_NONE;
3033 if (!lhs || !rhs || lhs->Length() != rhs->Length())
3034 return NS_STYLE_HINT_REFLOW;
3036 for (uint32_t i = 0; i < lhs->Length(); ++i) {
3037 if (*lhs->ShadowAt(i) != *rhs->ShadowAt(i))
3038 return NS_STYLE_HINT_REFLOW;
3039 }
3040 return NS_STYLE_HINT_NONE;
3041 }
3043 // --------------------
3044 // nsStyleText
3045 //
3047 nsStyleText::nsStyleText(void)
3048 {
3049 MOZ_COUNT_CTOR(nsStyleText);
3050 mTextAlign = NS_STYLE_TEXT_ALIGN_DEFAULT;
3051 mTextAlignLast = NS_STYLE_TEXT_ALIGN_AUTO;
3052 mTextAlignTrue = false;
3053 mTextAlignLastTrue = false;
3054 mTextTransform = NS_STYLE_TEXT_TRANSFORM_NONE;
3055 mWhiteSpace = NS_STYLE_WHITESPACE_NORMAL;
3056 mWordBreak = NS_STYLE_WORDBREAK_NORMAL;
3057 mWordWrap = NS_STYLE_WORDWRAP_NORMAL;
3058 mHyphens = NS_STYLE_HYPHENS_MANUAL;
3059 mTextSizeAdjust = NS_STYLE_TEXT_SIZE_ADJUST_AUTO;
3060 mTextOrientation = NS_STYLE_TEXT_ORIENTATION_AUTO;
3061 mTextCombineUpright = NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE;
3062 mControlCharacterVisibility = NS_STYLE_CONTROL_CHARACTER_VISIBILITY_HIDDEN;
3064 mLetterSpacing.SetNormalValue();
3065 mLineHeight.SetNormalValue();
3066 mTextIndent.SetCoordValue(0);
3067 mWordSpacing = 0;
3069 mTextShadow = nullptr;
3070 mTabSize = NS_STYLE_TABSIZE_INITIAL;
3071 }
3073 nsStyleText::nsStyleText(const nsStyleText& aSource)
3074 : mTextAlign(aSource.mTextAlign),
3075 mTextAlignLast(aSource.mTextAlignLast),
3076 mTextAlignTrue(false),
3077 mTextAlignLastTrue(false),
3078 mTextTransform(aSource.mTextTransform),
3079 mWhiteSpace(aSource.mWhiteSpace),
3080 mWordBreak(aSource.mWordBreak),
3081 mWordWrap(aSource.mWordWrap),
3082 mHyphens(aSource.mHyphens),
3083 mTextSizeAdjust(aSource.mTextSizeAdjust),
3084 mTextOrientation(aSource.mTextOrientation),
3085 mTextCombineUpright(aSource.mTextCombineUpright),
3086 mControlCharacterVisibility(aSource.mControlCharacterVisibility),
3087 mTabSize(aSource.mTabSize),
3088 mWordSpacing(aSource.mWordSpacing),
3089 mLetterSpacing(aSource.mLetterSpacing),
3090 mLineHeight(aSource.mLineHeight),
3091 mTextIndent(aSource.mTextIndent),
3092 mTextShadow(aSource.mTextShadow)
3093 {
3094 MOZ_COUNT_CTOR(nsStyleText);
3095 }
3097 nsStyleText::~nsStyleText(void)
3098 {
3099 MOZ_COUNT_DTOR(nsStyleText);
3100 }
3102 nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aOther) const
3103 {
3104 if (WhiteSpaceOrNewlineIsSignificant() !=
3105 aOther.WhiteSpaceOrNewlineIsSignificant()) {
3106 // This may require construction of suppressed text frames
3107 return NS_STYLE_HINT_FRAMECHANGE;
3108 }
3110 if (mTextCombineUpright != aOther.mTextCombineUpright ||
3111 mControlCharacterVisibility != aOther.mControlCharacterVisibility) {
3112 return nsChangeHint_ReconstructFrame;
3113 }
3115 if ((mTextAlign != aOther.mTextAlign) ||
3116 (mTextAlignLast != aOther.mTextAlignLast) ||
3117 (mTextAlignTrue != aOther.mTextAlignTrue) ||
3118 (mTextAlignLastTrue != aOther.mTextAlignLastTrue) ||
3119 (mTextTransform != aOther.mTextTransform) ||
3120 (mWhiteSpace != aOther.mWhiteSpace) ||
3121 (mWordBreak != aOther.mWordBreak) ||
3122 (mWordWrap != aOther.mWordWrap) ||
3123 (mHyphens != aOther.mHyphens) ||
3124 (mTextSizeAdjust != aOther.mTextSizeAdjust) ||
3125 (mTextOrientation != aOther.mTextOrientation) ||
3126 (mLetterSpacing != aOther.mLetterSpacing) ||
3127 (mLineHeight != aOther.mLineHeight) ||
3128 (mTextIndent != aOther.mTextIndent) ||
3129 (mWordSpacing != aOther.mWordSpacing) ||
3130 (mTabSize != aOther.mTabSize))
3131 return NS_STYLE_HINT_REFLOW;
3133 return CalcShadowDifference(mTextShadow, aOther.mTextShadow);
3134 }
3136 //-----------------------
3137 // nsStyleUserInterface
3138 //
3140 nsCursorImage::nsCursorImage()
3141 : mHaveHotspot(false)
3142 , mHotspotX(0.0f)
3143 , mHotspotY(0.0f)
3144 {
3145 }
3147 nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
3148 : mHaveHotspot(aOther.mHaveHotspot)
3149 , mHotspotX(aOther.mHotspotX)
3150 , mHotspotY(aOther.mHotspotY)
3151 {
3152 SetImage(aOther.GetImage());
3153 }
3155 nsCursorImage::~nsCursorImage()
3156 {
3157 SetImage(nullptr);
3158 }
3160 nsCursorImage&
3161 nsCursorImage::operator=(const nsCursorImage& aOther)
3162 {
3163 if (this != &aOther) {
3164 mHaveHotspot = aOther.mHaveHotspot;
3165 mHotspotX = aOther.mHotspotX;
3166 mHotspotY = aOther.mHotspotY;
3167 SetImage(aOther.GetImage());
3168 }
3170 return *this;
3171 }
3173 nsStyleUserInterface::nsStyleUserInterface(void)
3174 {
3175 MOZ_COUNT_CTOR(nsStyleUserInterface);
3176 mUserInput = NS_STYLE_USER_INPUT_AUTO;
3177 mUserModify = NS_STYLE_USER_MODIFY_READ_ONLY;
3178 mUserFocus = NS_STYLE_USER_FOCUS_NONE;
3180 mCursor = NS_STYLE_CURSOR_AUTO; // fix for bugzilla bug 51113
3182 mCursorArrayLength = 0;
3183 mCursorArray = nullptr;
3184 }
3186 nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource) :
3187 mUserInput(aSource.mUserInput),
3188 mUserModify(aSource.mUserModify),
3189 mUserFocus(aSource.mUserFocus),
3190 mCursor(aSource.mCursor)
3191 {
3192 MOZ_COUNT_CTOR(nsStyleUserInterface);
3193 CopyCursorArrayFrom(aSource);
3194 }
3196 nsStyleUserInterface::~nsStyleUserInterface(void)
3197 {
3198 MOZ_COUNT_DTOR(nsStyleUserInterface);
3199 delete [] mCursorArray;
3200 }
3202 nsChangeHint nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aOther) const
3203 {
3204 nsChangeHint hint = nsChangeHint(0);
3205 if (mCursor != aOther.mCursor)
3206 NS_UpdateHint(hint, nsChangeHint_UpdateCursor);
3208 // We could do better. But it wouldn't be worth it, URL-specified cursors are
3209 // rare.
3210 if (mCursorArrayLength > 0 || aOther.mCursorArrayLength > 0)
3211 NS_UpdateHint(hint, nsChangeHint_UpdateCursor);
3213 if (mUserModify != aOther.mUserModify)
3214 NS_UpdateHint(hint, NS_STYLE_HINT_VISUAL);
3216 if ((mUserInput != aOther.mUserInput) &&
3217 ((NS_STYLE_USER_INPUT_NONE == mUserInput) ||
3218 (NS_STYLE_USER_INPUT_NONE == aOther.mUserInput))) {
3219 NS_UpdateHint(hint, NS_STYLE_HINT_FRAMECHANGE);
3220 }
3222 // ignore mUserFocus
3224 return hint;
3225 }
3227 void
3228 nsStyleUserInterface::CopyCursorArrayFrom(const nsStyleUserInterface& aSource)
3229 {
3230 mCursorArray = nullptr;
3231 mCursorArrayLength = 0;
3232 if (aSource.mCursorArrayLength) {
3233 mCursorArray = new nsCursorImage[aSource.mCursorArrayLength];
3234 if (mCursorArray) {
3235 mCursorArrayLength = aSource.mCursorArrayLength;
3236 for (uint32_t i = 0; i < mCursorArrayLength; ++i)
3237 mCursorArray[i] = aSource.mCursorArray[i];
3238 }
3239 }
3240 }
3242 //-----------------------
3243 // nsStyleUIReset
3244 //
3246 nsStyleUIReset::nsStyleUIReset(void)
3247 {
3248 MOZ_COUNT_CTOR(nsStyleUIReset);
3249 mUserSelect = NS_STYLE_USER_SELECT_AUTO;
3250 mForceBrokenImageIcon = 0;
3251 mIMEMode = NS_STYLE_IME_MODE_AUTO;
3252 mWindowShadow = NS_STYLE_WINDOW_SHADOW_DEFAULT;
3253 }
3255 nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
3256 {
3257 MOZ_COUNT_CTOR(nsStyleUIReset);
3258 mUserSelect = aSource.mUserSelect;
3259 mForceBrokenImageIcon = aSource.mForceBrokenImageIcon;
3260 mIMEMode = aSource.mIMEMode;
3261 mWindowShadow = aSource.mWindowShadow;
3262 }
3264 nsStyleUIReset::~nsStyleUIReset(void)
3265 {
3266 MOZ_COUNT_DTOR(nsStyleUIReset);
3267 }
3269 nsChangeHint nsStyleUIReset::CalcDifference(const nsStyleUIReset& aOther) const
3270 {
3271 // ignore mIMEMode
3272 if (mForceBrokenImageIcon != aOther.mForceBrokenImageIcon)
3273 return NS_STYLE_HINT_FRAMECHANGE;
3274 if (mWindowShadow != aOther.mWindowShadow) {
3275 // We really need just an nsChangeHint_SyncFrameView, except
3276 // on an ancestor of the frame, so we get that by doing a
3277 // reflow.
3278 return NS_STYLE_HINT_REFLOW;
3279 }
3280 if (mUserSelect != aOther.mUserSelect)
3281 return NS_STYLE_HINT_VISUAL;
3282 return NS_STYLE_HINT_NONE;
3283 }
3285 //-----------------------
3286 // nsStyleVariables
3287 //
3289 nsStyleVariables::nsStyleVariables()
3290 {
3291 MOZ_COUNT_CTOR(nsStyleVariables);
3292 }
3294 nsStyleVariables::nsStyleVariables(const nsStyleVariables& aSource)
3295 {
3296 MOZ_COUNT_CTOR(nsStyleVariables);
3297 }
3299 nsStyleVariables::~nsStyleVariables(void)
3300 {
3301 MOZ_COUNT_DTOR(nsStyleVariables);
3302 }
3304 nsChangeHint
3305 nsStyleVariables::CalcDifference(const nsStyleVariables& aOther) const
3306 {
3307 return nsChangeHint(0);
3308 }