1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 /*
8  * structs that contain the data provided by nsStyleContext, the
9  * internal API for computed style data for an element
10  */
11 
12 #include "nsStyleStruct.h"
13 #include "nsStyleStructInlines.h"
14 #include "nsStyleConsts.h"
15 #include "nsThemeConstants.h"
16 #include "nsString.h"
17 #include "nsPresContext.h"
18 #include "nsIAppShellService.h"
19 #include "nsIWidget.h"
20 #include "nsCRTGlue.h"
21 #include "nsCSSParser.h"
22 #include "nsCSSProps.h"
23 #include "nsDeviceContext.h"
24 #include "nsStyleUtil.h"
25 
26 #include "nsCOMPtr.h"
27 
28 #include "nsBidiUtils.h"
29 #include "nsLayoutUtils.h"
30 
31 #include "imgIRequest.h"
32 #include "imgIContainer.h"
33 #include "CounterStyleManager.h"
34 
35 #include "mozilla/dom/AnimationEffectReadOnlyBinding.h" // for PlaybackDirection
36 #include "mozilla/dom/ImageTracker.h"
37 #include "mozilla/Likely.h"
38 #include "nsIURI.h"
39 #include "nsIDocument.h"
40 #include <algorithm>
41 
42 using namespace mozilla;
43 
44 static_assert((((1 << nsStyleStructID_Length) - 1) &
45                ~(NS_STYLE_INHERIT_MASK)) == 0,
46               "Not enough bits in NS_STYLE_INHERIT_MASK");
47 
48 /* static */ const int32_t nsStyleGridLine::kMinLine;
49 /* static */ const int32_t nsStyleGridLine::kMaxLine;
50 
51 static bool
EqualURIs(nsIURI * aURI1,nsIURI * aURI2)52 EqualURIs(nsIURI *aURI1, nsIURI *aURI2)
53 {
54   bool eq;
55   return aURI1 == aURI2 ||    // handle null==null, and optimize
56          (aURI1 && aURI2 &&
57           NS_SUCCEEDED(aURI1->Equals(aURI2, &eq)) && // not equal on fail
58           eq);
59 }
60 
61 static bool
DefinitelyEqualURIs(css::URLValueData * aURI1,css::URLValueData * aURI2)62 DefinitelyEqualURIs(css::URLValueData* aURI1,
63                     css::URLValueData* aURI2)
64 {
65   return aURI1 == aURI2 ||
66          (aURI1 && aURI2 && aURI1->DefinitelyEqualURIs(*aURI2));
67 }
68 
69 static bool
DefinitelyEqualURIsAndPrincipal(css::URLValueData * aURI1,css::URLValueData * aURI2)70 DefinitelyEqualURIsAndPrincipal(css::URLValueData* aURI1,
71                                 css::URLValueData* aURI2)
72 {
73   return aURI1 == aURI2 ||
74          (aURI1 && aURI2 && aURI1->DefinitelyEqualURIsAndPrincipal(*aURI2));
75 }
76 
77 static bool
EqualImages(imgIRequest * aImage1,imgIRequest * aImage2)78 EqualImages(imgIRequest *aImage1, imgIRequest* aImage2)
79 {
80   if (aImage1 == aImage2) {
81     return true;
82   }
83 
84   if (!aImage1 || !aImage2) {
85     return false;
86   }
87 
88   nsCOMPtr<nsIURI> uri1, uri2;
89   aImage1->GetURI(getter_AddRefs(uri1));
90   aImage2->GetURI(getter_AddRefs(uri2));
91   return EqualURIs(uri1, uri2);
92 }
93 
94 static bool
DefinitelyEqualImages(nsStyleImageRequest * aRequest1,nsStyleImageRequest * aRequest2)95 DefinitelyEqualImages(nsStyleImageRequest* aRequest1,
96                       nsStyleImageRequest* aRequest2)
97 {
98   if (aRequest1 == aRequest2) {
99     return true;
100   }
101 
102   if (!aRequest1 || !aRequest2) {
103     return false;
104   }
105 
106   return aRequest1->DefinitelyEquals(*aRequest2);
107 }
108 
109 // A nullsafe wrapper for strcmp. We depend on null-safety.
110 static int
safe_strcmp(const char16_t * a,const char16_t * b)111 safe_strcmp(const char16_t* a, const char16_t* b)
112 {
113   if (!a || !b) {
114     return (int)(a - b);
115   }
116   return NS_strcmp(a, b);
117 }
118 
119 int32_t
AppUnitsPerDevPixel()120 StyleStructContext::AppUnitsPerDevPixel()
121 {
122   return DeviceContext()->AppUnitsPerDevPixel();
123 }
124 
125 nsDeviceContext*
HackilyFindSomeDeviceContext()126 StyleStructContext::HackilyFindSomeDeviceContext()
127 {
128   nsCOMPtr<nsIAppShellService> appShell(do_GetService("@mozilla.org/appshell/appShellService;1"));
129   MOZ_ASSERT(appShell);
130   nsCOMPtr<mozIDOMWindowProxy> win;
131   appShell->GetHiddenDOMWindow(getter_AddRefs(win));
132   return nsLayoutUtils::GetDeviceContextForScreenInfo(static_cast<nsPIDOMWindowOuter*>(win.get()));
133 }
134 
135 static bool AreShadowArraysEqual(nsCSSShadowArray* lhs, nsCSSShadowArray* rhs);
136 
137 // --------------------
138 // nsStyleFont
139 //
nsStyleFont(const nsFont & aFont,StyleStructContext aContext)140 nsStyleFont::nsStyleFont(const nsFont& aFont, StyleStructContext aContext)
141   : mFont(aFont)
142   , mSize(nsStyleFont::ZoomText(aContext, mFont.size))
143   , mGenericID(kGenericFont_NONE)
144   , mScriptLevel(0)
145   , mMathVariant(NS_MATHML_MATHVARIANT_NONE)
146   , mMathDisplay(NS_MATHML_DISPLAYSTYLE_INLINE)
147   , mMinFontSizeRatio(100) // 100%
148   , mExplicitLanguage(false)
149   , mAllowZoom(true)
150   , mScriptUnconstrainedSize(mSize)
151   , mScriptMinSize(nsPresContext::CSSTwipsToAppUnits(
152       NS_POINTS_TO_TWIPS(NS_MATHML_DEFAULT_SCRIPT_MIN_SIZE_PT)))
153   , mScriptSizeMultiplier(NS_MATHML_DEFAULT_SCRIPT_SIZE_MULTIPLIER)
154   , mLanguage(GetLanguage(aContext))
155 {
156   MOZ_COUNT_CTOR(nsStyleFont);
157   mFont.size = mSize;
158 }
159 
nsStyleFont(const nsStyleFont & aSrc)160 nsStyleFont::nsStyleFont(const nsStyleFont& aSrc)
161   : mFont(aSrc.mFont)
162   , mSize(aSrc.mSize)
163   , mGenericID(aSrc.mGenericID)
164   , mScriptLevel(aSrc.mScriptLevel)
165   , mMathVariant(aSrc.mMathVariant)
166   , mMathDisplay(aSrc.mMathDisplay)
167   , mMinFontSizeRatio(aSrc.mMinFontSizeRatio)
168   , mExplicitLanguage(aSrc.mExplicitLanguage)
169   , mAllowZoom(aSrc.mAllowZoom)
170   , mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize)
171   , mScriptMinSize(aSrc.mScriptMinSize)
172   , mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier)
173   , mLanguage(aSrc.mLanguage)
174 {
175   MOZ_COUNT_CTOR(nsStyleFont);
176 }
177 
nsStyleFont(StyleStructContext aContext)178 nsStyleFont::nsStyleFont(StyleStructContext aContext)
179   : nsStyleFont(*aContext.GetDefaultFont(kPresContext_DefaultVariableFont_ID),
180                 aContext)
181 {
182 }
183 
184 void
Destroy(nsPresContext * aContext)185 nsStyleFont::Destroy(nsPresContext* aContext) {
186   this->~nsStyleFont();
187   aContext->PresShell()->
188     FreeByObjectID(eArenaObjectID_nsStyleFont, this);
189 }
190 
191 void
EnableZoom(nsPresContext * aContext,bool aEnable)192 nsStyleFont::EnableZoom(nsPresContext* aContext, bool aEnable)
193 {
194   if (mAllowZoom == aEnable) {
195     return;
196   }
197   mAllowZoom = aEnable;
198   if (mAllowZoom) {
199     mSize = nsStyleFont::ZoomText(aContext, mSize);
200     mFont.size = nsStyleFont::ZoomText(aContext, mFont.size);
201     mScriptUnconstrainedSize =
202       nsStyleFont::ZoomText(aContext, mScriptUnconstrainedSize);
203   } else {
204     mSize = nsStyleFont::UnZoomText(aContext, mSize);
205     mFont.size = nsStyleFont::UnZoomText(aContext, mFont.size);
206     mScriptUnconstrainedSize =
207       nsStyleFont::UnZoomText(aContext, mScriptUnconstrainedSize);
208   }
209 }
210 
211 nsChangeHint
CalcDifference(const nsStyleFont & aNewData) const212 nsStyleFont::CalcDifference(const nsStyleFont& aNewData) const
213 {
214   MOZ_ASSERT(mAllowZoom == aNewData.mAllowZoom,
215              "expected mAllowZoom to be the same on both nsStyleFonts");
216   if (mSize != aNewData.mSize ||
217       mFont != aNewData.mFont ||
218       mLanguage != aNewData.mLanguage ||
219       mExplicitLanguage != aNewData.mExplicitLanguage ||
220       mMathVariant != aNewData.mMathVariant ||
221       mMathDisplay != aNewData.mMathDisplay ||
222       mMinFontSizeRatio != aNewData.mMinFontSizeRatio) {
223     return NS_STYLE_HINT_REFLOW;
224   }
225 
226   // XXX Should any of these cause a non-nsChangeHint_NeutralChange change?
227   if (mGenericID != aNewData.mGenericID ||
228       mScriptLevel != aNewData.mScriptLevel ||
229       mScriptUnconstrainedSize != aNewData.mScriptUnconstrainedSize ||
230       mScriptMinSize != aNewData.mScriptMinSize ||
231       mScriptSizeMultiplier != aNewData.mScriptSizeMultiplier) {
232     return nsChangeHint_NeutralChange;
233   }
234 
235   return nsChangeHint(0);
236 }
237 
238 /* static */ nscoord
ZoomText(StyleStructContext aContext,nscoord aSize)239 nsStyleFont::ZoomText(StyleStructContext aContext, nscoord aSize)
240 {
241   // aSize can be negative (e.g.: calc(-1px)) so we can't assert that here.
242   // The caller is expected deal with that.
243   return NSToCoordTruncClamped(float(aSize) * aContext.TextZoom());
244 }
245 
246 /* static */ nscoord
UnZoomText(nsPresContext * aPresContext,nscoord aSize)247 nsStyleFont::UnZoomText(nsPresContext *aPresContext, nscoord aSize)
248 {
249   // aSize can be negative (e.g.: calc(-1px)) so we can't assert that here.
250   // The caller is expected deal with that.
251   return NSToCoordTruncClamped(float(aSize) / aPresContext->TextZoom());
252 }
253 
254 /* static */ already_AddRefed<nsIAtom>
GetLanguage(StyleStructContext aContext)255 nsStyleFont::GetLanguage(StyleStructContext aContext)
256 {
257   RefPtr<nsIAtom> language = aContext.GetContentLanguage();
258   if (!language) {
259     // we didn't find a (usable) Content-Language, so we fall back
260     // to whatever the presContext guessed from the charset
261     // NOTE this should not be used elsewhere, because we want websites
262     // to use UTF-8 with proper language tag, instead of relying on
263     // deriving language from charset. See bug 1040668 comment 67.
264     language = aContext.GetLanguageFromCharset();
265   }
266   return language.forget();
267 }
268 
269 static nscoord
CalcCoord(const nsStyleCoord & aCoord,const nscoord * aEnumTable,int32_t aNumEnums)270 CalcCoord(const nsStyleCoord& aCoord, const nscoord* aEnumTable, int32_t aNumEnums)
271 {
272   if (aCoord.GetUnit() == eStyleUnit_Enumerated) {
273     MOZ_ASSERT(aEnumTable, "must have enum table");
274     int32_t value = aCoord.GetIntValue();
275     if (0 <= value && value < aNumEnums) {
276       return aEnumTable[aCoord.GetIntValue()];
277     }
278     NS_NOTREACHED("unexpected enum value");
279     return 0;
280   }
281   MOZ_ASSERT(aCoord.ConvertsToLength(), "unexpected unit");
282   return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
283 }
284 
nsStyleMargin(StyleStructContext aContext)285 nsStyleMargin::nsStyleMargin(StyleStructContext aContext)
286 {
287   MOZ_COUNT_CTOR(nsStyleMargin);
288   nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
289   NS_FOR_CSS_SIDES(side) {
290     mMargin.Set(side, zero);
291   }
292 }
293 
nsStyleMargin(const nsStyleMargin & aSrc)294 nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc)
295   : mMargin(aSrc.mMargin)
296 {
297   MOZ_COUNT_CTOR(nsStyleMargin);
298 }
299 
300 void
Destroy(nsPresContext * aContext)301 nsStyleMargin::Destroy(nsPresContext* aContext) {
302   this->~nsStyleMargin();
303   aContext->PresShell()->
304     FreeByObjectID(eArenaObjectID_nsStyleMargin, this);
305 }
306 
307 nsChangeHint
CalcDifference(const nsStyleMargin & aNewData) const308 nsStyleMargin::CalcDifference(const nsStyleMargin& aNewData) const
309 {
310   if (mMargin == aNewData.mMargin) {
311     return nsChangeHint(0);
312   }
313   // Margin differences can't affect descendant intrinsic sizes and
314   // don't need to force children to reflow.
315   return nsChangeHint_NeedReflow |
316          nsChangeHint_ReflowChangesSizeOrPosition |
317          nsChangeHint_ClearAncestorIntrinsics;
318 }
319 
nsStylePadding(StyleStructContext aContext)320 nsStylePadding::nsStylePadding(StyleStructContext aContext)
321 {
322   MOZ_COUNT_CTOR(nsStylePadding);
323   nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
324   NS_FOR_CSS_SIDES(side) {
325     mPadding.Set(side, zero);
326   }
327 }
328 
nsStylePadding(const nsStylePadding & aSrc)329 nsStylePadding::nsStylePadding(const nsStylePadding& aSrc)
330   : mPadding(aSrc.mPadding)
331 {
332   MOZ_COUNT_CTOR(nsStylePadding);
333 }
334 
335 void
Destroy(nsPresContext * aContext)336 nsStylePadding::Destroy(nsPresContext* aContext) {
337   this->~nsStylePadding();
338   aContext->PresShell()->
339     FreeByObjectID(eArenaObjectID_nsStylePadding, this);
340 }
341 
342 nsChangeHint
CalcDifference(const nsStylePadding & aNewData) const343 nsStylePadding::CalcDifference(const nsStylePadding& aNewData) const
344 {
345   if (mPadding == aNewData.mPadding) {
346     return nsChangeHint(0);
347   }
348   // Padding differences can't affect descendant intrinsic sizes, but do need
349   // to force children to reflow so that we can reposition them, since their
350   // offsets are from our frame bounds but our content rect's position within
351   // those bounds is moving.
352   // FIXME: It would be good to return a weaker hint here that doesn't
353   // force reflow of all descendants, but the hint would need to force
354   // reflow of the frame's children (see how
355   // ReflowInput::InitResizeFlags initializes the inline-resize flag).
356   return NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
357 }
358 
nsStyleBorder(StyleStructContext aContext)359 nsStyleBorder::nsStyleBorder(StyleStructContext aContext)
360   : mBorderColors(nullptr)
361   , mBorderImageFill(NS_STYLE_BORDER_IMAGE_SLICE_NOFILL)
362   , mBorderImageRepeatH(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH)
363   , mBorderImageRepeatV(NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH)
364   , mFloatEdge(StyleFloatEdge::ContentBox)
365   , mBoxDecorationBreak(StyleBoxDecorationBreak::Slice)
366   , mComputedBorder(0, 0, 0, 0)
367 {
368   MOZ_COUNT_CTOR(nsStyleBorder);
369 
370   NS_FOR_CSS_HALF_CORNERS (corner) {
371     mBorderRadius.Set(corner, nsStyleCoord(0, nsStyleCoord::CoordConstructor));
372   }
373 
374   nscoord medium =
375     (StaticPresData::Get()->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM];
376   NS_FOR_CSS_SIDES(side) {
377     mBorderImageSlice.Set(side, nsStyleCoord(1.0f, eStyleUnit_Percent));
378     mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor));
379     mBorderImageOutset.Set(side, nsStyleCoord(0.0f, eStyleUnit_Factor));
380 
381     mBorder.Side(side) = medium;
382     mBorderStyle[side] = NS_STYLE_BORDER_STYLE_NONE;
383     mBorderColor[side] = StyleComplexColor::CurrentColor();
384   }
385 
386   mTwipsPerPixel = aContext.DevPixelsToAppUnits(1);
387 }
388 
~nsBorderColors()389 nsBorderColors::~nsBorderColors()
390 {
391   NS_CSS_DELETE_LIST_MEMBER(nsBorderColors, this, mNext);
392 }
393 
394 nsBorderColors*
Clone(bool aDeep) const395 nsBorderColors::Clone(bool aDeep) const
396 {
397   nsBorderColors* result = new nsBorderColors(mColor);
398   if (MOZ_UNLIKELY(!result)) {
399     return result;
400   }
401   if (aDeep) {
402     NS_CSS_CLONE_LIST_MEMBER(nsBorderColors, this, mNext, result, (false));
403   }
404   return result;
405 }
406 
nsStyleBorder(const nsStyleBorder & aSrc)407 nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
408   : mBorderColors(nullptr)
409   , mBorderRadius(aSrc.mBorderRadius)
410   , mBorderImageSource(aSrc.mBorderImageSource)
411   , mBorderImageSlice(aSrc.mBorderImageSlice)
412   , mBorderImageWidth(aSrc.mBorderImageWidth)
413   , mBorderImageOutset(aSrc.mBorderImageOutset)
414   , mBorderImageFill(aSrc.mBorderImageFill)
415   , mBorderImageRepeatH(aSrc.mBorderImageRepeatH)
416   , mBorderImageRepeatV(aSrc.mBorderImageRepeatV)
417   , mFloatEdge(aSrc.mFloatEdge)
418   , mBoxDecorationBreak(aSrc.mBoxDecorationBreak)
419   , mComputedBorder(aSrc.mComputedBorder)
420   , mBorder(aSrc.mBorder)
421   , mTwipsPerPixel(aSrc.mTwipsPerPixel)
422 {
423   MOZ_COUNT_CTOR(nsStyleBorder);
424   if (aSrc.mBorderColors) {
425     EnsureBorderColors();
426     for (int32_t i = 0; i < 4; i++) {
427       if (aSrc.mBorderColors[i]) {
428         mBorderColors[i] = aSrc.mBorderColors[i]->Clone();
429       } else {
430         mBorderColors[i] = nullptr;
431       }
432     }
433   }
434 
435   NS_FOR_CSS_SIDES(side) {
436     mBorderStyle[side] = aSrc.mBorderStyle[side];
437     mBorderColor[side] = aSrc.mBorderColor[side];
438   }
439 }
440 
~nsStyleBorder()441 nsStyleBorder::~nsStyleBorder()
442 {
443   MOZ_COUNT_DTOR(nsStyleBorder);
444   if (mBorderColors) {
445     for (int32_t i = 0; i < 4; i++) {
446       delete mBorderColors[i];
447     }
448     delete [] mBorderColors;
449   }
450 }
451 
452 void
FinishStyle(nsPresContext * aPresContext)453 nsStyleBorder::FinishStyle(nsPresContext* aPresContext)
454 {
455   MOZ_ASSERT(NS_IsMainThread());
456   MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
457 
458   mBorderImageSource.ResolveImage(aPresContext);
459 }
460 
461 nsMargin
GetImageOutset() const462 nsStyleBorder::GetImageOutset() const
463 {
464   // We don't check whether there is a border-image (which is OK since
465   // the initial values yields 0 outset) so that we don't have to
466   // reflow to update overflow areas when an image loads.
467   nsMargin outset;
468   NS_FOR_CSS_SIDES(s) {
469     nsStyleCoord coord = mBorderImageOutset.Get(s);
470     nscoord value;
471     switch (coord.GetUnit()) {
472       case eStyleUnit_Coord:
473         value = coord.GetCoordValue();
474         break;
475       case eStyleUnit_Factor:
476         value = coord.GetFactorValue() * mComputedBorder.Side(s);
477         break;
478       default:
479         NS_NOTREACHED("unexpected CSS unit for image outset");
480         value = 0;
481         break;
482     }
483     outset.Side(s) = value;
484   }
485   return outset;
486 }
487 
488 void
Destroy(nsPresContext * aContext)489 nsStyleBorder::Destroy(nsPresContext* aContext)
490 {
491   this->~nsStyleBorder();
492   aContext->PresShell()->
493     FreeByObjectID(eArenaObjectID_nsStyleBorder, this);
494 }
495 
496 nsChangeHint
CalcDifference(const nsStyleBorder & aNewData) const497 nsStyleBorder::CalcDifference(const nsStyleBorder& aNewData) const
498 {
499   // FIXME: XXXbz: As in nsStylePadding::CalcDifference, many of these
500   // differences should not need to clear descendant intrinsics.
501   // FIXME: It would be good to return a weaker hint for the
502   // GetComputedBorder() differences (and perhaps others) that doesn't
503   // force reflow of all descendants, but the hint would need to force
504   // reflow of the frame's children (see how
505   // ReflowInput::InitResizeFlags initializes the inline-resize flag).
506   if (mTwipsPerPixel != aNewData.mTwipsPerPixel ||
507       GetComputedBorder() != aNewData.GetComputedBorder() ||
508       mFloatEdge != aNewData.mFloatEdge ||
509       mBorderImageOutset != aNewData.mBorderImageOutset ||
510       mBoxDecorationBreak != aNewData.mBoxDecorationBreak) {
511     return NS_STYLE_HINT_REFLOW;
512   }
513 
514   NS_FOR_CSS_SIDES(ix) {
515     // See the explanation in nsChangeHint.h of
516     // nsChangeHint_BorderStyleNoneChange .
517     // Furthermore, even though we know *this* side is 0 width, just
518     // assume a repaint hint for some other change rather than bother
519     // tracking this result through the rest of the function.
520     if (HasVisibleStyle(ix) != aNewData.HasVisibleStyle(ix)) {
521       return nsChangeHint_RepaintFrame |
522              nsChangeHint_BorderStyleNoneChange;
523     }
524   }
525 
526   // Note that mBorderStyle stores not only the border style but also
527   // color-related flags.  Given that we've already done an mComputedBorder
528   // comparison, border-style differences can only lead to a repaint hint.  So
529   // it's OK to just compare the values directly -- if either the actual
530   // style or the color flags differ we want to repaint.
531   NS_FOR_CSS_SIDES(ix) {
532     if (mBorderStyle[ix] != aNewData.mBorderStyle[ix] ||
533         mBorderColor[ix] != aNewData.mBorderColor[ix]) {
534       return nsChangeHint_RepaintFrame;
535     }
536   }
537 
538   if (mBorderRadius != aNewData.mBorderRadius ||
539       !mBorderColors != !aNewData.mBorderColors) {
540     return nsChangeHint_RepaintFrame;
541   }
542 
543   if (IsBorderImageLoaded() || aNewData.IsBorderImageLoaded()) {
544     if (mBorderImageSource  != aNewData.mBorderImageSource  ||
545         mBorderImageRepeatH != aNewData.mBorderImageRepeatH ||
546         mBorderImageRepeatV != aNewData.mBorderImageRepeatV ||
547         mBorderImageSlice   != aNewData.mBorderImageSlice   ||
548         mBorderImageFill    != aNewData.mBorderImageFill    ||
549         mBorderImageWidth   != aNewData.mBorderImageWidth   ||
550         mBorderImageOutset  != aNewData.mBorderImageOutset) {
551       return nsChangeHint_RepaintFrame;
552     }
553   }
554 
555   // Note that at this point if mBorderColors is non-null so is
556   // aNewData.mBorderColors
557   if (mBorderColors) {
558     NS_FOR_CSS_SIDES(ix) {
559       if (!nsBorderColors::Equal(mBorderColors[ix],
560                                  aNewData.mBorderColors[ix])) {
561         return nsChangeHint_RepaintFrame;
562       }
563     }
564   }
565 
566   // mBorder is the specified border value.  Changes to this don't
567   // need any change processing, since we operate on the computed
568   // border values instead.
569   if (mBorder != aNewData.mBorder) {
570     return nsChangeHint_NeutralChange;
571   }
572 
573   return nsChangeHint(0);
574 }
575 
nsStyleOutline(StyleStructContext aContext)576 nsStyleOutline::nsStyleOutline(StyleStructContext aContext)
577   : mOutlineWidth(NS_STYLE_BORDER_WIDTH_MEDIUM, eStyleUnit_Enumerated)
578   , mOutlineOffset(0)
579   , mOutlineColor(StyleComplexColor::CurrentColor())
580   , mOutlineStyle(NS_STYLE_BORDER_STYLE_NONE)
581   , mActualOutlineWidth(0)
582   , mTwipsPerPixel(aContext.DevPixelsToAppUnits(1))
583 {
584   MOZ_COUNT_CTOR(nsStyleOutline);
585   // spacing values not inherited
586   nsStyleCoord zero(0, nsStyleCoord::CoordConstructor);
587   NS_FOR_CSS_HALF_CORNERS(corner) {
588     mOutlineRadius.Set(corner, zero);
589   }
590 }
591 
nsStyleOutline(const nsStyleOutline & aSrc)592 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc)
593   : mOutlineRadius(aSrc.mOutlineRadius)
594   , mOutlineWidth(aSrc.mOutlineWidth)
595   , mOutlineOffset(aSrc.mOutlineOffset)
596   , mOutlineColor(aSrc.mOutlineColor)
597   , mOutlineStyle(aSrc.mOutlineStyle)
598   , mActualOutlineWidth(aSrc.mActualOutlineWidth)
599   , mTwipsPerPixel(aSrc.mTwipsPerPixel)
600 {
601   MOZ_COUNT_CTOR(nsStyleOutline);
602 }
603 
604 void
RecalcData()605 nsStyleOutline::RecalcData()
606 {
607   if (NS_STYLE_BORDER_STYLE_NONE == mOutlineStyle) {
608     mActualOutlineWidth = 0;
609   } else {
610     MOZ_ASSERT(mOutlineWidth.ConvertsToLength() ||
611                mOutlineWidth.GetUnit() == eStyleUnit_Enumerated);
612     // Clamp negative calc() to 0.
613     mActualOutlineWidth =
614       std::max(CalcCoord(mOutlineWidth,
615                          StaticPresData::Get()->GetBorderWidthTable(), 3), 0);
616     mActualOutlineWidth =
617       NS_ROUND_BORDER_TO_PIXELS(mActualOutlineWidth, mTwipsPerPixel);
618   }
619 }
620 
621 nsChangeHint
CalcDifference(const nsStyleOutline & aNewData) const622 nsStyleOutline::CalcDifference(const nsStyleOutline& aNewData) const
623 {
624   if (mActualOutlineWidth != aNewData.mActualOutlineWidth ||
625       (mActualOutlineWidth > 0 &&
626        mOutlineOffset != aNewData.mOutlineOffset)) {
627     return nsChangeHint_UpdateOverflow |
628            nsChangeHint_SchedulePaint;
629   }
630 
631   if (mOutlineStyle != aNewData.mOutlineStyle ||
632       mOutlineColor != aNewData.mOutlineColor ||
633       mOutlineRadius != aNewData.mOutlineRadius) {
634     if (mActualOutlineWidth > 0) {
635       return nsChangeHint_RepaintFrame;
636     }
637     return nsChangeHint_NeutralChange;
638   }
639 
640   if (mOutlineWidth != aNewData.mOutlineWidth ||
641       mOutlineOffset != aNewData.mOutlineOffset ||
642       mTwipsPerPixel != aNewData.mTwipsPerPixel) {
643     return nsChangeHint_NeutralChange;
644   }
645 
646   return nsChangeHint(0);
647 }
648 
649 // --------------------
650 // nsStyleList
651 //
nsStyleList(StyleStructContext aContext)652 nsStyleList::nsStyleList(StyleStructContext aContext)
653   : mListStylePosition(NS_STYLE_LIST_STYLE_POSITION_OUTSIDE)
654   , mCounterStyle(aContext.BuildCounterStyle(NS_LITERAL_STRING("disc")))
655 {
656   MOZ_COUNT_CTOR(nsStyleList);
657   SetQuotesInitial();
658 }
659 
~nsStyleList()660 nsStyleList::~nsStyleList()
661 {
662   MOZ_COUNT_DTOR(nsStyleList);
663 }
664 
nsStyleList(const nsStyleList & aSource)665 nsStyleList::nsStyleList(const nsStyleList& aSource)
666   : mListStylePosition(aSource.mListStylePosition)
667   , mListStyleImage(aSource.mListStyleImage)
668   , mCounterStyle(aSource.mCounterStyle)
669   , mQuotes(aSource.mQuotes)
670   , mImageRegion(aSource.mImageRegion)
671 {
672   MOZ_COUNT_CTOR(nsStyleList);
673 }
674 
675 void
FinishStyle(nsPresContext * aPresContext)676 nsStyleList::FinishStyle(nsPresContext* aPresContext)
677 {
678   MOZ_ASSERT(NS_IsMainThread());
679   MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
680 
681   if (mListStyleImage && !mListStyleImage->IsResolved()) {
682     mListStyleImage->Resolve(aPresContext);
683   }
684 }
685 
686 void
SetQuotesInherit(const nsStyleList * aOther)687 nsStyleList::SetQuotesInherit(const nsStyleList* aOther)
688 {
689   mQuotes = aOther->mQuotes;
690 }
691 
692 void
SetQuotesInitial()693 nsStyleList::SetQuotesInitial()
694 {
695   if (!sInitialQuotes) {
696     // The initial value for quotes is the en-US typographic convention:
697     // outermost are LEFT and RIGHT DOUBLE QUOTATION MARK, alternating
698     // with LEFT and RIGHT SINGLE QUOTATION MARK.
699     static const char16_t initialQuotes[8] = {
700       0x201C, 0, 0x201D, 0, 0x2018, 0, 0x2019, 0
701     };
702 
703     sInitialQuotes = new nsStyleQuoteValues;
704     sInitialQuotes->mQuotePairs.AppendElement(
705         std::make_pair(nsDependentString(&initialQuotes[0], 1),
706                        nsDependentString(&initialQuotes[2], 1)));
707     sInitialQuotes->mQuotePairs.AppendElement(
708         std::make_pair(nsDependentString(&initialQuotes[4], 1),
709                        nsDependentString(&initialQuotes[6], 1)));
710   }
711 
712   mQuotes = sInitialQuotes;
713 }
714 
715 void
SetQuotesNone()716 nsStyleList::SetQuotesNone()
717 {
718   if (!sNoneQuotes) {
719     sNoneQuotes = new nsStyleQuoteValues;
720   }
721   mQuotes = sNoneQuotes;
722 }
723 
724 void
SetQuotes(nsStyleQuoteValues::QuotePairArray && aValues)725 nsStyleList::SetQuotes(nsStyleQuoteValues::QuotePairArray&& aValues)
726 {
727   mQuotes = new nsStyleQuoteValues;
728   mQuotes->mQuotePairs = Move(aValues);
729 }
730 
731 const nsStyleQuoteValues::QuotePairArray&
GetQuotePairs() const732 nsStyleList::GetQuotePairs() const
733 {
734   return mQuotes->mQuotePairs;
735 }
736 
737 nsChangeHint
CalcDifference(const nsStyleList & aNewData) const738 nsStyleList::CalcDifference(const nsStyleList& aNewData) const
739 {
740   // If the quotes implementation is ever going to change we might not need
741   // a framechange here and a reflow should be sufficient.  See bug 35768.
742   if (mQuotes != aNewData.mQuotes &&
743       (mQuotes || aNewData.mQuotes) &&
744       GetQuotePairs() != aNewData.GetQuotePairs()) {
745     return nsChangeHint_ReconstructFrame;
746   }
747   if (mListStylePosition != aNewData.mListStylePosition) {
748     return nsChangeHint_ReconstructFrame;
749   }
750   if (DefinitelyEqualImages(mListStyleImage, aNewData.mListStyleImage) &&
751       mCounterStyle == aNewData.mCounterStyle) {
752     if (mImageRegion.IsEqualInterior(aNewData.mImageRegion)) {
753       return nsChangeHint(0);
754     }
755     if (mImageRegion.width == aNewData.mImageRegion.width &&
756         mImageRegion.height == aNewData.mImageRegion.height) {
757       return NS_STYLE_HINT_VISUAL;
758     }
759   }
760   return NS_STYLE_HINT_REFLOW;
761 }
762 
763 StaticRefPtr<nsStyleQuoteValues>
764 nsStyleList::sInitialQuotes;
765 
766 StaticRefPtr<nsStyleQuoteValues>
767 nsStyleList::sNoneQuotes;
768 
769 
770 // --------------------
771 // nsStyleXUL
772 //
nsStyleXUL(StyleStructContext aContext)773 nsStyleXUL::nsStyleXUL(StyleStructContext aContext)
774   : mBoxFlex(0.0f)
775   , mBoxOrdinal(1)
776   , mBoxAlign(StyleBoxAlign::Stretch)
777   , mBoxDirection(StyleBoxDirection::Normal)
778   , mBoxOrient(StyleBoxOrient::Horizontal)
779   , mBoxPack(StyleBoxPack::Start)
780   , mStretchStack(true)
781 {
782   MOZ_COUNT_CTOR(nsStyleXUL);
783 }
784 
~nsStyleXUL()785 nsStyleXUL::~nsStyleXUL()
786 {
787   MOZ_COUNT_DTOR(nsStyleXUL);
788 }
789 
nsStyleXUL(const nsStyleXUL & aSource)790 nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource)
791   : mBoxFlex(aSource.mBoxFlex)
792   , mBoxOrdinal(aSource.mBoxOrdinal)
793   , mBoxAlign(aSource.mBoxAlign)
794   , mBoxDirection(aSource.mBoxDirection)
795   , mBoxOrient(aSource.mBoxOrient)
796   , mBoxPack(aSource.mBoxPack)
797   , mStretchStack(aSource.mStretchStack)
798 {
799   MOZ_COUNT_CTOR(nsStyleXUL);
800 }
801 
802 nsChangeHint
CalcDifference(const nsStyleXUL & aNewData) const803 nsStyleXUL::CalcDifference(const nsStyleXUL& aNewData) const
804 {
805   if (mBoxAlign == aNewData.mBoxAlign &&
806       mBoxDirection == aNewData.mBoxDirection &&
807       mBoxFlex == aNewData.mBoxFlex &&
808       mBoxOrient == aNewData.mBoxOrient &&
809       mBoxPack == aNewData.mBoxPack &&
810       mBoxOrdinal == aNewData.mBoxOrdinal &&
811       mStretchStack == aNewData.mStretchStack) {
812     return nsChangeHint(0);
813   }
814   if (mBoxOrdinal != aNewData.mBoxOrdinal) {
815     return nsChangeHint_ReconstructFrame;
816   }
817   return NS_STYLE_HINT_REFLOW;
818 }
819 
820 // --------------------
821 // nsStyleColumn
822 //
823 /* static */ const uint32_t nsStyleColumn::kMaxColumnCount;
824 
nsStyleColumn(StyleStructContext aContext)825 nsStyleColumn::nsStyleColumn(StyleStructContext aContext)
826   : mColumnCount(NS_STYLE_COLUMN_COUNT_AUTO)
827   , mColumnWidth(eStyleUnit_Auto)
828   , mColumnGap(eStyleUnit_Normal)
829   , mColumnRuleColor(StyleComplexColor::CurrentColor())
830   , mColumnRuleStyle(NS_STYLE_BORDER_STYLE_NONE)
831   , mColumnFill(NS_STYLE_COLUMN_FILL_BALANCE)
832   , mColumnRuleWidth((StaticPresData::Get()
833                         ->GetBorderWidthTable())[NS_STYLE_BORDER_WIDTH_MEDIUM])
834   , mTwipsPerPixel(aContext.AppUnitsPerDevPixel())
835 {
836   MOZ_COUNT_CTOR(nsStyleColumn);
837 }
838 
~nsStyleColumn()839 nsStyleColumn::~nsStyleColumn()
840 {
841   MOZ_COUNT_DTOR(nsStyleColumn);
842 }
843 
nsStyleColumn(const nsStyleColumn & aSource)844 nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
845   : mColumnCount(aSource.mColumnCount)
846   , mColumnWidth(aSource.mColumnWidth)
847   , mColumnGap(aSource.mColumnGap)
848   , mColumnRuleColor(aSource.mColumnRuleColor)
849   , mColumnRuleStyle(aSource.mColumnRuleStyle)
850   , mColumnFill(aSource.mColumnFill)
851   , mColumnRuleWidth(aSource.mColumnRuleWidth)
852   , mTwipsPerPixel(aSource.mTwipsPerPixel)
853 {
854   MOZ_COUNT_CTOR(nsStyleColumn);
855 }
856 
857 nsChangeHint
CalcDifference(const nsStyleColumn & aNewData) const858 nsStyleColumn::CalcDifference(const nsStyleColumn& aNewData) const
859 {
860   if ((mColumnWidth.GetUnit() == eStyleUnit_Auto)
861       != (aNewData.mColumnWidth.GetUnit() == eStyleUnit_Auto) ||
862       mColumnCount != aNewData.mColumnCount) {
863     // We force column count changes to do a reframe, because it's tricky to handle
864     // some edge cases where the column count gets smaller and content overflows.
865     // XXX not ideal
866     return nsChangeHint_ReconstructFrame;
867   }
868 
869   if (mColumnWidth != aNewData.mColumnWidth ||
870       mColumnGap != aNewData.mColumnGap ||
871       mColumnFill != aNewData.mColumnFill) {
872     return NS_STYLE_HINT_REFLOW;
873   }
874 
875   if (GetComputedColumnRuleWidth() != aNewData.GetComputedColumnRuleWidth() ||
876       mColumnRuleStyle != aNewData.mColumnRuleStyle ||
877       mColumnRuleColor != aNewData.mColumnRuleColor) {
878     return NS_STYLE_HINT_VISUAL;
879   }
880 
881   // XXX Is it right that we never check mTwipsPerPixel to return a
882   // non-nsChangeHint_NeutralChange hint?
883   if (mColumnRuleWidth != aNewData.mColumnRuleWidth ||
884       mTwipsPerPixel != aNewData.mTwipsPerPixel) {
885     return nsChangeHint_NeutralChange;
886   }
887 
888   return nsChangeHint(0);
889 }
890 
891 // --------------------
892 // nsStyleSVG
893 //
nsStyleSVG(StyleStructContext aContext)894 nsStyleSVG::nsStyleSVG(StyleStructContext aContext)
895   : mFill(eStyleSVGPaintType_Color) // Will be initialized to NS_RGB(0, 0, 0)
896   , mStroke(eStyleSVGPaintType_None)
897   , mStrokeDashoffset(0, nsStyleCoord::CoordConstructor)
898   , mStrokeWidth(nsPresContext::CSSPixelsToAppUnits(1), nsStyleCoord::CoordConstructor)
899   , mFillOpacity(1.0f)
900   , mStrokeMiterlimit(4.0f)
901   , mStrokeOpacity(1.0f)
902   , mClipRule(StyleFillRule::Nonzero)
903   , mColorInterpolation(NS_STYLE_COLOR_INTERPOLATION_SRGB)
904   , mColorInterpolationFilters(NS_STYLE_COLOR_INTERPOLATION_LINEARRGB)
905   , mFillRule(StyleFillRule::Nonzero)
906   , mPaintOrder(NS_STYLE_PAINT_ORDER_NORMAL)
907   , mShapeRendering(NS_STYLE_SHAPE_RENDERING_AUTO)
908   , mStrokeLinecap(NS_STYLE_STROKE_LINECAP_BUTT)
909   , mStrokeLinejoin(NS_STYLE_STROKE_LINEJOIN_MITER)
910   , mTextAnchor(NS_STYLE_TEXT_ANCHOR_START)
911   , mContextFlags((eStyleSVGOpacitySource_Normal << FILL_OPACITY_SOURCE_SHIFT) |
912                   (eStyleSVGOpacitySource_Normal << STROKE_OPACITY_SOURCE_SHIFT))
913 {
914   MOZ_COUNT_CTOR(nsStyleSVG);
915 }
916 
~nsStyleSVG()917 nsStyleSVG::~nsStyleSVG()
918 {
919   MOZ_COUNT_DTOR(nsStyleSVG);
920 }
921 
nsStyleSVG(const nsStyleSVG & aSource)922 nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
923   : mFill(aSource.mFill)
924   , mStroke(aSource.mStroke)
925   , mMarkerEnd(aSource.mMarkerEnd)
926   , mMarkerMid(aSource.mMarkerMid)
927   , mMarkerStart(aSource.mMarkerStart)
928   , mStrokeDasharray(aSource.mStrokeDasharray)
929   , mStrokeDashoffset(aSource.mStrokeDashoffset)
930   , mStrokeWidth(aSource.mStrokeWidth)
931   , mFillOpacity(aSource.mFillOpacity)
932   , mStrokeMiterlimit(aSource.mStrokeMiterlimit)
933   , mStrokeOpacity(aSource.mStrokeOpacity)
934   , mClipRule(aSource.mClipRule)
935   , mColorInterpolation(aSource.mColorInterpolation)
936   , mColorInterpolationFilters(aSource.mColorInterpolationFilters)
937   , mFillRule(aSource.mFillRule)
938   , mPaintOrder(aSource.mPaintOrder)
939   , mShapeRendering(aSource.mShapeRendering)
940   , mStrokeLinecap(aSource.mStrokeLinecap)
941   , mStrokeLinejoin(aSource.mStrokeLinejoin)
942   , mTextAnchor(aSource.mTextAnchor)
943   , mContextFlags(aSource.mContextFlags)
944 {
945   MOZ_COUNT_CTOR(nsStyleSVG);
946 }
947 
948 static bool
PaintURIChanged(const nsStyleSVGPaint & aPaint1,const nsStyleSVGPaint & aPaint2)949 PaintURIChanged(const nsStyleSVGPaint& aPaint1, const nsStyleSVGPaint& aPaint2)
950 {
951   if (aPaint1.Type() != aPaint2.Type()) {
952     return aPaint1.Type() == eStyleSVGPaintType_Server ||
953            aPaint2.Type() == eStyleSVGPaintType_Server;
954   }
955   return aPaint1.Type() == eStyleSVGPaintType_Server &&
956          !DefinitelyEqualURIs(aPaint1.GetPaintServer(),
957                               aPaint2.GetPaintServer());
958 }
959 
960 nsChangeHint
CalcDifference(const nsStyleSVG & aNewData) const961 nsStyleSVG::CalcDifference(const nsStyleSVG& aNewData) const
962 {
963   nsChangeHint hint = nsChangeHint(0);
964 
965   if (!DefinitelyEqualURIs(mMarkerEnd, aNewData.mMarkerEnd) ||
966       !DefinitelyEqualURIs(mMarkerMid, aNewData.mMarkerMid) ||
967       !DefinitelyEqualURIs(mMarkerStart, aNewData.mMarkerStart)) {
968     // Markers currently contribute to nsSVGPathGeometryFrame::mRect,
969     // so we need a reflow as well as a repaint. No intrinsic sizes need
970     // to change, so nsChangeHint_NeedReflow is sufficient.
971     return nsChangeHint_UpdateEffects |
972            nsChangeHint_NeedReflow |
973            nsChangeHint_NeedDirtyReflow | // XXX remove me: bug 876085
974            nsChangeHint_RepaintFrame;
975   }
976 
977   if (mFill != aNewData.mFill ||
978       mStroke != aNewData.mStroke ||
979       mFillOpacity != aNewData.mFillOpacity ||
980       mStrokeOpacity != aNewData.mStrokeOpacity) {
981     hint |= nsChangeHint_RepaintFrame;
982     if (HasStroke() != aNewData.HasStroke() ||
983         (!HasStroke() && HasFill() != aNewData.HasFill())) {
984       // Frame bounds and overflow rects depend on whether we "have" fill or
985       // stroke. Whether we have stroke or not just changed, or else we have no
986       // stroke (in which case whether we have fill or not is significant to frame
987       // bounds) and whether we have fill or not just changed. In either case we
988       // need to reflow so the frame rect is updated.
989       // XXXperf this is a waste on non nsSVGPathGeometryFrames.
990       hint |= nsChangeHint_NeedReflow |
991               nsChangeHint_NeedDirtyReflow; // XXX remove me: bug 876085
992     }
993     if (PaintURIChanged(mFill, aNewData.mFill) ||
994         PaintURIChanged(mStroke, aNewData.mStroke)) {
995       hint |= nsChangeHint_UpdateEffects;
996     }
997   }
998 
999   // Stroke currently contributes to nsSVGPathGeometryFrame::mRect, so
1000   // we need a reflow here. No intrinsic sizes need to change, so
1001   // nsChangeHint_NeedReflow is sufficient.
1002   // Note that stroke-dashoffset does not affect nsSVGPathGeometryFrame::mRect.
1003   // text-anchor changes also require a reflow since it changes frames' rects.
1004   if (mStrokeWidth           != aNewData.mStrokeWidth           ||
1005       mStrokeMiterlimit      != aNewData.mStrokeMiterlimit      ||
1006       mStrokeLinecap         != aNewData.mStrokeLinecap         ||
1007       mStrokeLinejoin        != aNewData.mStrokeLinejoin        ||
1008       mTextAnchor            != aNewData.mTextAnchor) {
1009     return hint |
1010            nsChangeHint_NeedReflow |
1011            nsChangeHint_NeedDirtyReflow | // XXX remove me: bug 876085
1012            nsChangeHint_RepaintFrame;
1013   }
1014 
1015   if (hint & nsChangeHint_RepaintFrame) {
1016     return hint; // we don't add anything else below
1017   }
1018 
1019   if ( mStrokeDashoffset      != aNewData.mStrokeDashoffset      ||
1020        mClipRule              != aNewData.mClipRule              ||
1021        mColorInterpolation    != aNewData.mColorInterpolation    ||
1022        mColorInterpolationFilters != aNewData.mColorInterpolationFilters ||
1023        mFillRule              != aNewData.mFillRule              ||
1024        mPaintOrder            != aNewData.mPaintOrder            ||
1025        mShapeRendering        != aNewData.mShapeRendering        ||
1026        mStrokeDasharray       != aNewData.mStrokeDasharray       ||
1027        mContextFlags          != aNewData.mContextFlags) {
1028     return hint | nsChangeHint_RepaintFrame;
1029   }
1030 
1031   return hint;
1032 }
1033 
1034 // --------------------
1035 // StyleBasicShape
1036 
1037 nsCSSKeyword
GetShapeTypeName() const1038 StyleBasicShape::GetShapeTypeName() const
1039 {
1040   switch (mType) {
1041     case StyleBasicShapeType::Polygon:
1042       return eCSSKeyword_polygon;
1043     case StyleBasicShapeType::Circle:
1044       return eCSSKeyword_circle;
1045     case StyleBasicShapeType::Ellipse:
1046       return eCSSKeyword_ellipse;
1047     case StyleBasicShapeType::Inset:
1048       return eCSSKeyword_inset;
1049   }
1050   NS_NOTREACHED("unexpected type");
1051   return eCSSKeyword_UNKNOWN;
1052 }
1053 
1054 // --------------------
1055 // nsStyleFilter
1056 //
nsStyleFilter()1057 nsStyleFilter::nsStyleFilter()
1058   : mType(NS_STYLE_FILTER_NONE)
1059   , mDropShadow(nullptr)
1060 {
1061   MOZ_COUNT_CTOR(nsStyleFilter);
1062 }
1063 
nsStyleFilter(const nsStyleFilter & aSource)1064 nsStyleFilter::nsStyleFilter(const nsStyleFilter& aSource)
1065   : mType(NS_STYLE_FILTER_NONE)
1066   , mDropShadow(nullptr)
1067 {
1068   MOZ_COUNT_CTOR(nsStyleFilter);
1069   if (aSource.mType == NS_STYLE_FILTER_URL) {
1070     SetURL(aSource.mURL);
1071   } else if (aSource.mType == NS_STYLE_FILTER_DROP_SHADOW) {
1072     SetDropShadow(aSource.mDropShadow);
1073   } else if (aSource.mType != NS_STYLE_FILTER_NONE) {
1074     SetFilterParameter(aSource.mFilterParameter, aSource.mType);
1075   }
1076 }
1077 
~nsStyleFilter()1078 nsStyleFilter::~nsStyleFilter()
1079 {
1080   ReleaseRef();
1081   MOZ_COUNT_DTOR(nsStyleFilter);
1082 }
1083 
1084 nsStyleFilter&
operator =(const nsStyleFilter & aOther)1085 nsStyleFilter::operator=(const nsStyleFilter& aOther)
1086 {
1087   if (this == &aOther) {
1088     return *this;
1089   }
1090 
1091   if (aOther.mType == NS_STYLE_FILTER_URL) {
1092     SetURL(aOther.mURL);
1093   } else if (aOther.mType == NS_STYLE_FILTER_DROP_SHADOW) {
1094     SetDropShadow(aOther.mDropShadow);
1095   } else if (aOther.mType != NS_STYLE_FILTER_NONE) {
1096     SetFilterParameter(aOther.mFilterParameter, aOther.mType);
1097   } else {
1098     ReleaseRef();
1099     mType = NS_STYLE_FILTER_NONE;
1100   }
1101 
1102   return *this;
1103 }
1104 
1105 bool
operator ==(const nsStyleFilter & aOther) const1106 nsStyleFilter::operator==(const nsStyleFilter& aOther) const
1107 {
1108   if (mType != aOther.mType) {
1109       return false;
1110   }
1111 
1112   if (mType == NS_STYLE_FILTER_URL) {
1113     return DefinitelyEqualURIs(mURL, aOther.mURL);
1114   } else if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
1115     return *mDropShadow == *aOther.mDropShadow;
1116   } else if (mType != NS_STYLE_FILTER_NONE) {
1117     return mFilterParameter == aOther.mFilterParameter;
1118   }
1119 
1120   return true;
1121 }
1122 
1123 void
ReleaseRef()1124 nsStyleFilter::ReleaseRef()
1125 {
1126   if (mType == NS_STYLE_FILTER_DROP_SHADOW) {
1127     NS_ASSERTION(mDropShadow, "expected pointer");
1128     mDropShadow->Release();
1129   } else if (mType == NS_STYLE_FILTER_URL) {
1130     NS_ASSERTION(mURL, "expected pointer");
1131     mURL->Release();
1132   }
1133   mURL = nullptr;
1134 }
1135 
1136 void
SetFilterParameter(const nsStyleCoord & aFilterParameter,int32_t aType)1137 nsStyleFilter::SetFilterParameter(const nsStyleCoord& aFilterParameter,
1138                                   int32_t aType)
1139 {
1140   ReleaseRef();
1141   mFilterParameter = aFilterParameter;
1142   mType = aType;
1143 }
1144 
1145 bool
SetURL(css::URLValue * aURL)1146 nsStyleFilter::SetURL(css::URLValue* aURL)
1147 {
1148   ReleaseRef();
1149   mURL = aURL;
1150   mURL->AddRef();
1151   mType = NS_STYLE_FILTER_URL;
1152   return true;
1153 }
1154 
1155 void
SetDropShadow(nsCSSShadowArray * aDropShadow)1156 nsStyleFilter::SetDropShadow(nsCSSShadowArray* aDropShadow)
1157 {
1158   NS_ASSERTION(aDropShadow, "expected pointer");
1159   ReleaseRef();
1160   mDropShadow = aDropShadow;
1161   mDropShadow->AddRef();
1162   mType = NS_STYLE_FILTER_DROP_SHADOW;
1163 }
1164 
1165 // --------------------
1166 // nsStyleSVGReset
1167 //
nsStyleSVGReset(StyleStructContext aContext)1168 nsStyleSVGReset::nsStyleSVGReset(StyleStructContext aContext)
1169   : mMask(nsStyleImageLayers::LayerType::Mask)
1170   , mStopColor(NS_RGB(0, 0, 0))
1171   , mFloodColor(NS_RGB(0, 0, 0))
1172   , mLightingColor(NS_RGB(255, 255, 255))
1173   , mStopOpacity(1.0f)
1174   , mFloodOpacity(1.0f)
1175   , mDominantBaseline(NS_STYLE_DOMINANT_BASELINE_AUTO)
1176   , mVectorEffect(NS_STYLE_VECTOR_EFFECT_NONE)
1177   , mMaskType(NS_STYLE_MASK_TYPE_LUMINANCE)
1178 {
1179   MOZ_COUNT_CTOR(nsStyleSVGReset);
1180 }
1181 
~nsStyleSVGReset()1182 nsStyleSVGReset::~nsStyleSVGReset()
1183 {
1184   MOZ_COUNT_DTOR(nsStyleSVGReset);
1185 }
1186 
nsStyleSVGReset(const nsStyleSVGReset & aSource)1187 nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
1188   : mMask(aSource.mMask)
1189   , mClipPath(aSource.mClipPath)
1190   , mStopColor(aSource.mStopColor)
1191   , mFloodColor(aSource.mFloodColor)
1192   , mLightingColor(aSource.mLightingColor)
1193   , mStopOpacity(aSource.mStopOpacity)
1194   , mFloodOpacity(aSource.mFloodOpacity)
1195   , mDominantBaseline(aSource.mDominantBaseline)
1196   , mVectorEffect(aSource.mVectorEffect)
1197   , mMaskType(aSource.mMaskType)
1198 {
1199   MOZ_COUNT_CTOR(nsStyleSVGReset);
1200 }
1201 
1202 void
Destroy(nsPresContext * aContext)1203 nsStyleSVGReset::Destroy(nsPresContext* aContext)
1204 {
1205   this->~nsStyleSVGReset();
1206   aContext->PresShell()->
1207     FreeByObjectID(mozilla::eArenaObjectID_nsStyleSVGReset, this);
1208 }
1209 
1210 void
FinishStyle(nsPresContext * aPresContext)1211 nsStyleSVGReset::FinishStyle(nsPresContext* aPresContext)
1212 {
1213   MOZ_ASSERT(NS_IsMainThread());
1214   MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
1215 
1216   mMask.ResolveImages(aPresContext);
1217 }
1218 
1219 nsChangeHint
CalcDifference(const nsStyleSVGReset & aNewData) const1220 nsStyleSVGReset::CalcDifference(const nsStyleSVGReset& aNewData) const
1221 {
1222   nsChangeHint hint = nsChangeHint(0);
1223 
1224   if (mClipPath != aNewData.mClipPath) {
1225     hint |= nsChangeHint_UpdateEffects |
1226             nsChangeHint_RepaintFrame;
1227     // clip-path changes require that we update the PreEffectsBBoxProperty,
1228     // which is done during overflow computation.
1229     hint |= nsChangeHint_UpdateOverflow;
1230   }
1231 
1232   if (mDominantBaseline != aNewData.mDominantBaseline) {
1233     // XXXjwatt: why NS_STYLE_HINT_REFLOW? Isn't that excessive?
1234     hint |= NS_STYLE_HINT_REFLOW;
1235   } else if (mVectorEffect  != aNewData.mVectorEffect) {
1236     // Stroke currently affects nsSVGPathGeometryFrame::mRect, and
1237     // vector-effect affect stroke. As a result we need to reflow if
1238     // vector-effect changes in order to have nsSVGPathGeometryFrame::
1239     // ReflowSVG called to update its mRect. No intrinsic sizes need
1240     // to change so nsChangeHint_NeedReflow is sufficient.
1241     hint |= nsChangeHint_NeedReflow |
1242             nsChangeHint_NeedDirtyReflow | // XXX remove me: bug 876085
1243             nsChangeHint_RepaintFrame;
1244   } else if (mStopColor     != aNewData.mStopColor     ||
1245              mFloodColor    != aNewData.mFloodColor    ||
1246              mLightingColor != aNewData.mLightingColor ||
1247              mStopOpacity   != aNewData.mStopOpacity   ||
1248              mFloodOpacity  != aNewData.mFloodOpacity  ||
1249              mMaskType      != aNewData.mMaskType) {
1250     hint |= nsChangeHint_RepaintFrame;
1251   }
1252 
1253   hint |= mMask.CalcDifference(aNewData.mMask,
1254                                nsStyleImageLayers::LayerType::Mask);
1255 
1256   return hint;
1257 }
1258 
1259 // nsStyleSVGPaint implementation
nsStyleSVGPaint(nsStyleSVGPaintType aType)1260 nsStyleSVGPaint::nsStyleSVGPaint(nsStyleSVGPaintType aType)
1261   : mType(aType)
1262   , mFallbackColor(NS_RGB(0, 0, 0))
1263 {
1264   MOZ_ASSERT(aType == nsStyleSVGPaintType(0) ||
1265              aType == eStyleSVGPaintType_None ||
1266              aType == eStyleSVGPaintType_Color);
1267   mPaint.mColor = NS_RGB(0, 0, 0);
1268 }
1269 
nsStyleSVGPaint(const nsStyleSVGPaint & aSource)1270 nsStyleSVGPaint::nsStyleSVGPaint(const nsStyleSVGPaint& aSource)
1271   : nsStyleSVGPaint(nsStyleSVGPaintType(0))
1272 {
1273   Assign(aSource);
1274 }
1275 
~nsStyleSVGPaint()1276 nsStyleSVGPaint::~nsStyleSVGPaint()
1277 {
1278   Reset();
1279 }
1280 
1281 void
Reset()1282 nsStyleSVGPaint::Reset()
1283 {
1284   switch (mType) {
1285     case eStyleSVGPaintType_None:
1286       break;
1287     case eStyleSVGPaintType_Color:
1288       mPaint.mColor = NS_RGB(0, 0, 0);
1289       break;
1290     case eStyleSVGPaintType_Server:
1291       mPaint.mPaintServer->Release();
1292       mPaint.mPaintServer = nullptr;
1293       MOZ_FALLTHROUGH;
1294     case eStyleSVGPaintType_ContextFill:
1295     case eStyleSVGPaintType_ContextStroke:
1296       mFallbackColor = NS_RGB(0, 0, 0);
1297       break;
1298   }
1299   mType = nsStyleSVGPaintType(0);
1300 }
1301 
1302 nsStyleSVGPaint&
operator =(const nsStyleSVGPaint & aOther)1303 nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther)
1304 {
1305   if (this != &aOther) {
1306     Assign(aOther);
1307   }
1308   return *this;
1309 }
1310 
1311 void
Assign(const nsStyleSVGPaint & aOther)1312 nsStyleSVGPaint::Assign(const nsStyleSVGPaint& aOther)
1313 {
1314   MOZ_ASSERT(aOther.mType != nsStyleSVGPaintType(0),
1315              "shouldn't copy uninitialized nsStyleSVGPaint");
1316 
1317   switch (aOther.mType) {
1318     case eStyleSVGPaintType_None:
1319       SetNone();
1320       break;
1321     case eStyleSVGPaintType_Color:
1322       SetColor(aOther.mPaint.mColor);
1323       break;
1324     case eStyleSVGPaintType_Server:
1325       SetPaintServer(aOther.mPaint.mPaintServer,
1326                      aOther.mFallbackColor);
1327       break;
1328     case eStyleSVGPaintType_ContextFill:
1329     case eStyleSVGPaintType_ContextStroke:
1330       SetContextValue(aOther.mType, aOther.mFallbackColor);
1331       break;
1332   }
1333 }
1334 
1335 void
SetNone()1336 nsStyleSVGPaint::SetNone()
1337 {
1338   Reset();
1339   mType = eStyleSVGPaintType_None;
1340 }
1341 
1342 void
SetContextValue(nsStyleSVGPaintType aType,nscolor aFallbackColor)1343 nsStyleSVGPaint::SetContextValue(nsStyleSVGPaintType aType,
1344                                  nscolor aFallbackColor)
1345 {
1346   MOZ_ASSERT(aType == eStyleSVGPaintType_ContextFill ||
1347              aType == eStyleSVGPaintType_ContextStroke);
1348   Reset();
1349   mType = aType;
1350   mFallbackColor = aFallbackColor;
1351 }
1352 
1353 void
SetColor(nscolor aColor)1354 nsStyleSVGPaint::SetColor(nscolor aColor)
1355 {
1356   Reset();
1357   mType = eStyleSVGPaintType_Color;
1358   mPaint.mColor = aColor;
1359 }
1360 
1361 void
SetPaintServer(css::URLValue * aPaintServer,nscolor aFallbackColor)1362 nsStyleSVGPaint::SetPaintServer(css::URLValue* aPaintServer,
1363                                 nscolor aFallbackColor)
1364 {
1365   MOZ_ASSERT(aPaintServer);
1366   Reset();
1367   mType = eStyleSVGPaintType_Server;
1368   mPaint.mPaintServer = aPaintServer;
1369   mPaint.mPaintServer->AddRef();
1370   mFallbackColor = aFallbackColor;
1371 }
1372 
operator ==(const nsStyleSVGPaint & aOther) const1373 bool nsStyleSVGPaint::operator==(const nsStyleSVGPaint& aOther) const
1374 {
1375   if (mType != aOther.mType) {
1376     return false;
1377   }
1378   switch (mType) {
1379     case eStyleSVGPaintType_Color:
1380       return mPaint.mColor == aOther.mPaint.mColor;
1381     case eStyleSVGPaintType_Server:
1382       return DefinitelyEqualURIs(mPaint.mPaintServer,
1383                                  aOther.mPaint.mPaintServer) &&
1384              mFallbackColor == aOther.mFallbackColor;
1385     case eStyleSVGPaintType_ContextFill:
1386     case eStyleSVGPaintType_ContextStroke:
1387       return mFallbackColor == aOther.mFallbackColor;
1388     default:
1389       MOZ_ASSERT(mType == eStyleSVGPaintType_None,
1390                  "Unexpected SVG paint type");
1391       return true;
1392   }
1393 }
1394 
1395 // --------------------
1396 // nsStylePosition
1397 //
nsStylePosition(StyleStructContext aContext)1398 nsStylePosition::nsStylePosition(StyleStructContext aContext)
1399   : mWidth(eStyleUnit_Auto)
1400   , mMinWidth(eStyleUnit_Auto)
1401   , mMaxWidth(eStyleUnit_None)
1402   , mHeight(eStyleUnit_Auto)
1403   , mMinHeight(eStyleUnit_Auto)
1404   , mMaxHeight(eStyleUnit_None)
1405   , mFlexBasis(eStyleUnit_Auto)
1406   , mGridAutoColumnsMin(eStyleUnit_Auto)
1407   , mGridAutoColumnsMax(eStyleUnit_Auto)
1408   , mGridAutoRowsMin(eStyleUnit_Auto)
1409   , mGridAutoRowsMax(eStyleUnit_Auto)
1410   , mGridAutoFlow(NS_STYLE_GRID_AUTO_FLOW_ROW)
1411   , mBoxSizing(StyleBoxSizing::Content)
1412   , mAlignContent(NS_STYLE_ALIGN_NORMAL)
1413   , mAlignItems(NS_STYLE_ALIGN_NORMAL)
1414   , mAlignSelf(NS_STYLE_ALIGN_AUTO)
1415   , mJustifyContent(NS_STYLE_JUSTIFY_NORMAL)
1416   , mJustifyItems(NS_STYLE_JUSTIFY_AUTO)
1417   , mJustifySelf(NS_STYLE_JUSTIFY_AUTO)
1418   , mFlexDirection(NS_STYLE_FLEX_DIRECTION_ROW)
1419   , mFlexWrap(NS_STYLE_FLEX_WRAP_NOWRAP)
1420   , mObjectFit(NS_STYLE_OBJECT_FIT_FILL)
1421   , mOrder(NS_STYLE_ORDER_INITIAL)
1422   , mFlexGrow(0.0f)
1423   , mFlexShrink(1.0f)
1424   , mZIndex(eStyleUnit_Auto)
1425   , mGridColumnGap(nscoord(0), nsStyleCoord::CoordConstructor)
1426   , mGridRowGap(nscoord(0), nsStyleCoord::CoordConstructor)
1427 {
1428   MOZ_COUNT_CTOR(nsStylePosition);
1429 
1430   // positioning values not inherited
1431 
1432   mObjectPosition.SetInitialPercentValues(0.5f);
1433 
1434   nsStyleCoord  autoCoord(eStyleUnit_Auto);
1435   NS_FOR_CSS_SIDES(side) {
1436     mOffset.Set(side, autoCoord);
1437   }
1438 
1439   // The initial value of grid-auto-columns and grid-auto-rows is 'auto',
1440   // which computes to 'minmax(auto, auto)'.
1441 
1442   // Other members get their default constructors
1443   // which initialize them to representations of their respective initial value.
1444   // mGridTemplateAreas: nullptr for 'none'
1445   // mGridTemplate{Rows,Columns}: false and empty arrays for 'none'
1446   // mGrid{Column,Row}{Start,End}: false/0/empty values for 'auto'
1447 }
1448 
~nsStylePosition()1449 nsStylePosition::~nsStylePosition()
1450 {
1451   MOZ_COUNT_DTOR(nsStylePosition);
1452 }
1453 
nsStylePosition(const nsStylePosition & aSource)1454 nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
1455   : mObjectPosition(aSource.mObjectPosition)
1456   , mOffset(aSource.mOffset)
1457   , mWidth(aSource.mWidth)
1458   , mMinWidth(aSource.mMinWidth)
1459   , mMaxWidth(aSource.mMaxWidth)
1460   , mHeight(aSource.mHeight)
1461   , mMinHeight(aSource.mMinHeight)
1462   , mMaxHeight(aSource.mMaxHeight)
1463   , mFlexBasis(aSource.mFlexBasis)
1464   , mGridAutoColumnsMin(aSource.mGridAutoColumnsMin)
1465   , mGridAutoColumnsMax(aSource.mGridAutoColumnsMax)
1466   , mGridAutoRowsMin(aSource.mGridAutoRowsMin)
1467   , mGridAutoRowsMax(aSource.mGridAutoRowsMax)
1468   , mGridAutoFlow(aSource.mGridAutoFlow)
1469   , mBoxSizing(aSource.mBoxSizing)
1470   , mAlignContent(aSource.mAlignContent)
1471   , mAlignItems(aSource.mAlignItems)
1472   , mAlignSelf(aSource.mAlignSelf)
1473   , mJustifyContent(aSource.mJustifyContent)
1474   , mJustifyItems(aSource.mJustifyItems)
1475   , mJustifySelf(aSource.mJustifySelf)
1476   , mFlexDirection(aSource.mFlexDirection)
1477   , mFlexWrap(aSource.mFlexWrap)
1478   , mObjectFit(aSource.mObjectFit)
1479   , mOrder(aSource.mOrder)
1480   , mFlexGrow(aSource.mFlexGrow)
1481   , mFlexShrink(aSource.mFlexShrink)
1482   , mZIndex(aSource.mZIndex)
1483   , mGridTemplateColumns(aSource.mGridTemplateColumns)
1484   , mGridTemplateRows(aSource.mGridTemplateRows)
1485   , mGridTemplateAreas(aSource.mGridTemplateAreas)
1486   , mGridColumnStart(aSource.mGridColumnStart)
1487   , mGridColumnEnd(aSource.mGridColumnEnd)
1488   , mGridRowStart(aSource.mGridRowStart)
1489   , mGridRowEnd(aSource.mGridRowEnd)
1490   , mGridColumnGap(aSource.mGridColumnGap)
1491   , mGridRowGap(aSource.mGridRowGap)
1492 {
1493   MOZ_COUNT_CTOR(nsStylePosition);
1494 }
1495 
1496 static bool
IsAutonessEqual(const nsStyleSides & aSides1,const nsStyleSides & aSides2)1497 IsAutonessEqual(const nsStyleSides& aSides1, const nsStyleSides& aSides2)
1498 {
1499   NS_FOR_CSS_SIDES(side) {
1500     if ((aSides1.GetUnit(side) == eStyleUnit_Auto) !=
1501         (aSides2.GetUnit(side) == eStyleUnit_Auto)) {
1502       return false;
1503     }
1504   }
1505   return true;
1506 }
1507 
1508 nsChangeHint
CalcDifference(const nsStylePosition & aNewData,const nsStyleVisibility * aOldStyleVisibility) const1509 nsStylePosition::CalcDifference(const nsStylePosition& aNewData,
1510                                 const nsStyleVisibility* aOldStyleVisibility) const
1511 {
1512   nsChangeHint hint = nsChangeHint(0);
1513 
1514   // Changes to "z-index" require a repaint.
1515   if (mZIndex != aNewData.mZIndex) {
1516     hint |= nsChangeHint_RepaintFrame;
1517   }
1518 
1519   // Changes to "object-fit" & "object-position" require a repaint.  They
1520   // may also require a reflow, if we have a nsSubDocumentFrame, so that we
1521   // can adjust the size & position of the subdocument.
1522   if (mObjectFit != aNewData.mObjectFit ||
1523       mObjectPosition != aNewData.mObjectPosition) {
1524     hint |= nsChangeHint_RepaintFrame |
1525             nsChangeHint_NeedReflow;
1526   }
1527 
1528   if (mOrder != aNewData.mOrder) {
1529     // "order" impacts both layout order and stacking order, so we need both a
1530     // reflow and a repaint when it changes.  (Technically, we only need a
1531     // reflow if we're in a multi-line flexbox (which we can't be sure about,
1532     // since that's determined by styling on our parent) -- there, "order" can
1533     // affect which flex line we end up on, & hence can affect our sizing by
1534     // changing the group of flex items we're competing with for space.)
1535     return hint |
1536            nsChangeHint_RepaintFrame |
1537            nsChangeHint_AllReflowHints;
1538   }
1539 
1540   if (mBoxSizing != aNewData.mBoxSizing) {
1541     // Can affect both widths and heights; just a bad scene.
1542     return hint |
1543            nsChangeHint_AllReflowHints;
1544   }
1545 
1546   // Properties that apply to flex items:
1547   // XXXdholbert These should probably be more targeted (bug 819536)
1548   if (mAlignSelf != aNewData.mAlignSelf ||
1549       mFlexBasis != aNewData.mFlexBasis ||
1550       mFlexGrow != aNewData.mFlexGrow ||
1551       mFlexShrink != aNewData.mFlexShrink) {
1552     return hint |
1553            nsChangeHint_AllReflowHints;
1554   }
1555 
1556   // Properties that apply to flex containers:
1557   // - flex-direction can swap a flex container between vertical & horizontal.
1558   // - align-items can change the sizing of a flex container & the positioning
1559   //   of its children.
1560   // - flex-wrap changes whether a flex container's children are wrapped, which
1561   //   impacts their sizing/positioning and hence impacts the container's size.
1562   if (mAlignItems != aNewData.mAlignItems ||
1563       mFlexDirection != aNewData.mFlexDirection ||
1564       mFlexWrap != aNewData.mFlexWrap) {
1565     return hint |
1566            nsChangeHint_AllReflowHints;
1567   }
1568 
1569   // Properties that apply to grid containers:
1570   // FIXME: only for grid containers
1571   // (ie. 'display: grid' or 'display: inline-grid')
1572   if (mGridTemplateColumns != aNewData.mGridTemplateColumns ||
1573       mGridTemplateRows != aNewData.mGridTemplateRows ||
1574       mGridTemplateAreas != aNewData.mGridTemplateAreas ||
1575       mGridAutoColumnsMin != aNewData.mGridAutoColumnsMin ||
1576       mGridAutoColumnsMax != aNewData.mGridAutoColumnsMax ||
1577       mGridAutoRowsMin != aNewData.mGridAutoRowsMin ||
1578       mGridAutoRowsMax != aNewData.mGridAutoRowsMax ||
1579       mGridAutoFlow != aNewData.mGridAutoFlow) {
1580     return hint |
1581            nsChangeHint_AllReflowHints;
1582   }
1583 
1584   // Properties that apply to grid items:
1585   // FIXME: only for grid items
1586   // (ie. parent frame is 'display: grid' or 'display: inline-grid')
1587   if (mGridColumnStart != aNewData.mGridColumnStart ||
1588       mGridColumnEnd != aNewData.mGridColumnEnd ||
1589       mGridRowStart != aNewData.mGridRowStart ||
1590       mGridRowEnd != aNewData.mGridRowEnd ||
1591       mGridColumnGap != aNewData.mGridColumnGap ||
1592       mGridRowGap != aNewData.mGridRowGap) {
1593     return hint |
1594            nsChangeHint_AllReflowHints;
1595   }
1596 
1597   // Changing 'justify-content/items/self' might affect the positioning,
1598   // but it won't affect any sizing.
1599   if (mJustifyContent != aNewData.mJustifyContent ||
1600       mJustifyItems != aNewData.mJustifyItems ||
1601       mJustifySelf != aNewData.mJustifySelf) {
1602     hint |= nsChangeHint_NeedReflow;
1603   }
1604 
1605   // 'align-content' doesn't apply to a single-line flexbox but we don't know
1606   // if we're a flex container at this point so we can't optimize for that.
1607   if (mAlignContent != aNewData.mAlignContent) {
1608     hint |= nsChangeHint_NeedReflow;
1609   }
1610 
1611   bool widthChanged = mWidth != aNewData.mWidth ||
1612                       mMinWidth != aNewData.mMinWidth ||
1613                       mMaxWidth != aNewData.mMaxWidth;
1614   bool heightChanged = mHeight != aNewData.mHeight ||
1615                        mMinHeight != aNewData.mMinHeight ||
1616                        mMaxHeight != aNewData.mMaxHeight;
1617 
1618   // If aOldStyleVisibility is null, we don't need to bother with any of
1619   // these tests, since we know that the element never had its
1620   // nsStyleVisibility accessed, which means it couldn't have done
1621   // layout.
1622   // Note that we pass an nsStyleVisibility here because we don't want
1623   // to cause a new struct to be computed during
1624   // nsStyleContext::CalcStyleDifference, which can lead to incorrect
1625   // style data.
1626   // It doesn't matter whether we're looking at the old or new
1627   // visibility struct, since a change between vertical and horizontal
1628   // writing-mode will cause a reframe, and it's easier to pass the old.
1629   if (aOldStyleVisibility) {
1630     bool isVertical = WritingMode(aOldStyleVisibility).IsVertical();
1631     if (isVertical ? widthChanged : heightChanged) {
1632       // Block-size changes can affect descendant intrinsic sizes due to
1633       // replaced elements with percentage bsizes in descendants which
1634       // also have percentage bsizes. This is handled via
1635       // nsChangeHint_UpdateComputedBSize which clears intrinsic sizes
1636       // for frames that have such replaced elements.
1637       hint |= nsChangeHint_NeedReflow |
1638               nsChangeHint_UpdateComputedBSize |
1639               nsChangeHint_ReflowChangesSizeOrPosition;
1640     }
1641 
1642     if (isVertical ? heightChanged : widthChanged) {
1643       // None of our inline-size differences can affect descendant
1644       // intrinsic sizes and none of them need to force children to
1645       // reflow.
1646       hint |= nsChangeHint_AllReflowHints &
1647               ~(nsChangeHint_ClearDescendantIntrinsics |
1648                 nsChangeHint_NeedDirtyReflow);
1649     }
1650   } else {
1651     if (widthChanged || heightChanged) {
1652       hint |= nsChangeHint_NeutralChange;
1653     }
1654   }
1655 
1656   // If any of the offsets have changed, then return the respective hints
1657   // so that we would hopefully be able to avoid reflowing.
1658   // Note that it is possible that we'll need to reflow when processing
1659   // restyles, but we don't have enough information to make a good decision
1660   // right now.
1661   // Don't try to handle changes between "auto" and non-auto efficiently;
1662   // that's tricky to do and will hardly ever be able to avoid a reflow.
1663   if (mOffset != aNewData.mOffset) {
1664     if (IsAutonessEqual(mOffset, aNewData.mOffset)) {
1665       hint |= nsChangeHint_RecomputePosition |
1666               nsChangeHint_UpdateParentOverflow;
1667     } else {
1668       hint |= nsChangeHint_AllReflowHints;
1669     }
1670   }
1671   return hint;
1672 }
1673 
1674 /* static */ bool
WidthCoordDependsOnContainer(const nsStyleCoord & aCoord)1675 nsStylePosition::WidthCoordDependsOnContainer(const nsStyleCoord &aCoord)
1676 {
1677   return aCoord.HasPercent() ||
1678          (aCoord.GetUnit() == eStyleUnit_Enumerated &&
1679           (aCoord.GetIntValue() == NS_STYLE_WIDTH_FIT_CONTENT ||
1680            aCoord.GetIntValue() == NS_STYLE_WIDTH_AVAILABLE));
1681 }
1682 
1683 uint8_t
UsedAlignSelf(nsStyleContext * aParent) const1684 nsStylePosition::UsedAlignSelf(nsStyleContext* aParent) const
1685 {
1686   if (mAlignSelf != NS_STYLE_ALIGN_AUTO) {
1687     return mAlignSelf;
1688   }
1689   if (MOZ_LIKELY(aParent)) {
1690     auto parentAlignItems = aParent->StylePosition()->mAlignItems;
1691     MOZ_ASSERT(!(parentAlignItems & NS_STYLE_ALIGN_LEGACY),
1692                "align-items can't have 'legacy'");
1693     return parentAlignItems;
1694   }
1695   return NS_STYLE_ALIGN_NORMAL;
1696 }
1697 
1698 uint8_t
ComputedJustifyItems(nsStyleContext * aParent) const1699 nsStylePosition::ComputedJustifyItems(nsStyleContext* aParent) const
1700 {
1701   if (mJustifyItems != NS_STYLE_JUSTIFY_AUTO) {
1702     return mJustifyItems;
1703   }
1704   if (MOZ_LIKELY(aParent)) {
1705     auto inheritedJustifyItems =
1706       aParent->StylePosition()->ComputedJustifyItems(aParent->GetParent());
1707     // "If the inherited value of justify-items includes the 'legacy' keyword,
1708     // 'auto' computes to the inherited value."  Otherwise, 'normal'.
1709     if (inheritedJustifyItems & NS_STYLE_JUSTIFY_LEGACY) {
1710       return inheritedJustifyItems;
1711     }
1712   }
1713   return NS_STYLE_JUSTIFY_NORMAL;
1714 }
1715 
1716 uint8_t
UsedJustifySelf(nsStyleContext * aParent) const1717 nsStylePosition::UsedJustifySelf(nsStyleContext* aParent) const
1718 {
1719   if (mJustifySelf != NS_STYLE_JUSTIFY_AUTO) {
1720     return mJustifySelf;
1721   }
1722   if (MOZ_LIKELY(aParent)) {
1723     auto inheritedJustifyItems = aParent->StylePosition()->
1724       ComputedJustifyItems(aParent->GetParent());
1725     return inheritedJustifyItems & ~NS_STYLE_JUSTIFY_LEGACY;
1726   }
1727   return NS_STYLE_JUSTIFY_NORMAL;
1728 }
1729 
1730 // --------------------
1731 // nsStyleTable
1732 //
1733 
nsStyleTable(StyleStructContext aContext)1734 nsStyleTable::nsStyleTable(StyleStructContext aContext)
1735   : mLayoutStrategy(NS_STYLE_TABLE_LAYOUT_AUTO)
1736   , mSpan(1)
1737 {
1738   MOZ_COUNT_CTOR(nsStyleTable);
1739 }
1740 
~nsStyleTable()1741 nsStyleTable::~nsStyleTable()
1742 {
1743   MOZ_COUNT_DTOR(nsStyleTable);
1744 }
1745 
nsStyleTable(const nsStyleTable & aSource)1746 nsStyleTable::nsStyleTable(const nsStyleTable& aSource)
1747   : mLayoutStrategy(aSource.mLayoutStrategy)
1748   , mSpan(aSource.mSpan)
1749 {
1750   MOZ_COUNT_CTOR(nsStyleTable);
1751 }
1752 
1753 nsChangeHint
CalcDifference(const nsStyleTable & aNewData) const1754 nsStyleTable::CalcDifference(const nsStyleTable& aNewData) const
1755 {
1756   if (mSpan != aNewData.mSpan ||
1757       mLayoutStrategy != aNewData.mLayoutStrategy) {
1758     return nsChangeHint_ReconstructFrame;
1759   }
1760   return nsChangeHint(0);
1761 }
1762 
1763 // -----------------------
1764 // nsStyleTableBorder
1765 
nsStyleTableBorder(StyleStructContext aContext)1766 nsStyleTableBorder::nsStyleTableBorder(StyleStructContext aContext)
1767   : mBorderSpacingCol(0)
1768   , mBorderSpacingRow(0)
1769   , mBorderCollapse(NS_STYLE_BORDER_SEPARATE)
1770   , mCaptionSide(NS_STYLE_CAPTION_SIDE_TOP)
1771   , mEmptyCells(NS_STYLE_TABLE_EMPTY_CELLS_SHOW)
1772 {
1773   MOZ_COUNT_CTOR(nsStyleTableBorder);
1774 }
1775 
~nsStyleTableBorder()1776 nsStyleTableBorder::~nsStyleTableBorder()
1777 {
1778   MOZ_COUNT_DTOR(nsStyleTableBorder);
1779 }
1780 
nsStyleTableBorder(const nsStyleTableBorder & aSource)1781 nsStyleTableBorder::nsStyleTableBorder(const nsStyleTableBorder& aSource)
1782   : mBorderSpacingCol(aSource.mBorderSpacingCol)
1783   , mBorderSpacingRow(aSource.mBorderSpacingRow)
1784   , mBorderCollapse(aSource.mBorderCollapse)
1785   , mCaptionSide(aSource.mCaptionSide)
1786   , mEmptyCells(aSource.mEmptyCells)
1787 {
1788   MOZ_COUNT_CTOR(nsStyleTableBorder);
1789 }
1790 
1791 nsChangeHint
CalcDifference(const nsStyleTableBorder & aNewData) const1792 nsStyleTableBorder::CalcDifference(const nsStyleTableBorder& aNewData) const
1793 {
1794   // Border-collapse changes need a reframe, because we use a different frame
1795   // class for table cells in the collapsed border model.  This is used to
1796   // conserve memory when using the separated border model (collapsed borders
1797   // require extra state to be stored).
1798   if (mBorderCollapse != aNewData.mBorderCollapse) {
1799     return nsChangeHint_ReconstructFrame;
1800   }
1801 
1802   if ((mCaptionSide == aNewData.mCaptionSide) &&
1803       (mBorderSpacingCol == aNewData.mBorderSpacingCol) &&
1804       (mBorderSpacingRow == aNewData.mBorderSpacingRow)) {
1805     if (mEmptyCells == aNewData.mEmptyCells) {
1806       return nsChangeHint(0);
1807     }
1808     return NS_STYLE_HINT_VISUAL;
1809   } else {
1810     return NS_STYLE_HINT_REFLOW;
1811   }
1812 }
1813 
1814 // --------------------
1815 // nsStyleColor
1816 //
1817 
nsStyleColor(StyleStructContext aContext)1818 nsStyleColor::nsStyleColor(StyleStructContext aContext)
1819   : mColor(aContext.DefaultColor())
1820 {
1821   MOZ_COUNT_CTOR(nsStyleColor);
1822 }
1823 
nsStyleColor(const nsStyleColor & aSource)1824 nsStyleColor::nsStyleColor(const nsStyleColor& aSource)
1825   : mColor(aSource.mColor)
1826 {
1827   MOZ_COUNT_CTOR(nsStyleColor);
1828 }
1829 
1830 nsChangeHint
CalcDifference(const nsStyleColor & aNewData) const1831 nsStyleColor::CalcDifference(const nsStyleColor& aNewData) const
1832 {
1833   if (mColor == aNewData.mColor) {
1834     return nsChangeHint(0);
1835   }
1836   return nsChangeHint_RepaintFrame;
1837 }
1838 
1839 // --------------------
1840 // nsStyleGradient
1841 //
1842 bool
operator ==(const nsStyleGradient & aOther) const1843 nsStyleGradient::operator==(const nsStyleGradient& aOther) const
1844 {
1845   MOZ_ASSERT(mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
1846              mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1847              "incorrect combination of shape and size");
1848   MOZ_ASSERT(aOther.mSize == NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER ||
1849              aOther.mShape != NS_STYLE_GRADIENT_SHAPE_LINEAR,
1850              "incorrect combination of shape and size");
1851 
1852   if (mShape != aOther.mShape ||
1853       mSize != aOther.mSize ||
1854       mRepeating != aOther.mRepeating ||
1855       mLegacySyntax != aOther.mLegacySyntax ||
1856       mBgPosX != aOther.mBgPosX ||
1857       mBgPosY != aOther.mBgPosY ||
1858       mAngle != aOther.mAngle ||
1859       mRadiusX != aOther.mRadiusX ||
1860       mRadiusY != aOther.mRadiusY) {
1861     return false;
1862   }
1863 
1864   if (mStops.Length() != aOther.mStops.Length()) {
1865     return false;
1866   }
1867 
1868   for (uint32_t i = 0; i < mStops.Length(); i++) {
1869     const auto& stop1 = mStops[i];
1870     const auto& stop2 = aOther.mStops[i];
1871     if (stop1.mLocation != stop2.mLocation ||
1872         stop1.mIsInterpolationHint != stop2.mIsInterpolationHint ||
1873         (!stop1.mIsInterpolationHint && stop1.mColor != stop2.mColor)) {
1874       return false;
1875     }
1876   }
1877 
1878   return true;
1879 }
1880 
nsStyleGradient()1881 nsStyleGradient::nsStyleGradient()
1882   : mShape(NS_STYLE_GRADIENT_SHAPE_LINEAR)
1883   , mSize(NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER)
1884   , mRepeating(false)
1885   , mLegacySyntax(false)
1886 {
1887 }
1888 
1889 bool
IsOpaque()1890 nsStyleGradient::IsOpaque()
1891 {
1892   for (uint32_t i = 0; i < mStops.Length(); i++) {
1893     if (NS_GET_A(mStops[i].mColor) < 255) {
1894       return false;
1895     }
1896   }
1897   return true;
1898 }
1899 
1900 bool
HasCalc()1901 nsStyleGradient::HasCalc()
1902 {
1903   for (uint32_t i = 0; i < mStops.Length(); i++) {
1904     if (mStops[i].mLocation.IsCalcUnit()) {
1905       return true;
1906     }
1907   }
1908   return mBgPosX.IsCalcUnit() || mBgPosY.IsCalcUnit() || mAngle.IsCalcUnit() ||
1909          mRadiusX.IsCalcUnit() || mRadiusY.IsCalcUnit();
1910 }
1911 
1912 
1913 // --------------------
1914 // nsStyleImageRequest
1915 
1916 /**
1917  * Runnable to release the nsStyleImageRequest's mRequestProxy,
1918  * mImageValue and mImageValue on the main thread, and to perform
1919  * any necessary unlocking and untracking of the image.
1920  */
1921 class StyleImageRequestCleanupTask : public mozilla::Runnable
1922 {
1923 public:
1924   typedef nsStyleImageRequest::Mode Mode;
1925 
StyleImageRequestCleanupTask(Mode aModeFlags,already_AddRefed<imgRequestProxy> aRequestProxy,already_AddRefed<css::ImageValue> aImageValue,already_AddRefed<ImageTracker> aImageTracker)1926   StyleImageRequestCleanupTask(Mode aModeFlags,
1927                                already_AddRefed<imgRequestProxy> aRequestProxy,
1928                                already_AddRefed<css::ImageValue> aImageValue,
1929                                already_AddRefed<ImageTracker> aImageTracker)
1930     : mModeFlags(aModeFlags)
1931     , mRequestProxy(aRequestProxy)
1932     , mImageValue(aImageValue)
1933     , mImageTracker(aImageTracker)
1934   {
1935   }
1936 
Run()1937   NS_IMETHOD Run() final
1938   {
1939     MOZ_ASSERT(NS_IsMainThread());
1940 
1941     if (!mRequestProxy) {
1942       return NS_OK;
1943     }
1944 
1945     if (mModeFlags & Mode::Track) {
1946       MOZ_ASSERT(mImageTracker);
1947       mImageTracker->Remove(mRequestProxy);
1948     } else {
1949       mRequestProxy->UnlockImage();
1950     }
1951 
1952     if (mModeFlags & Mode::Discard) {
1953       mRequestProxy->RequestDiscard();
1954     }
1955 
1956     return NS_OK;
1957   }
1958 
1959 protected:
~StyleImageRequestCleanupTask()1960   virtual ~StyleImageRequestCleanupTask() { MOZ_ASSERT(NS_IsMainThread()); }
1961 
1962 private:
1963   Mode mModeFlags;
1964   // Since we always dispatch this runnable to the main thread, these will be
1965   // released on the main thread when the runnable itself is released.
1966   RefPtr<imgRequestProxy> mRequestProxy;
1967   RefPtr<css::ImageValue> mImageValue;
1968   RefPtr<ImageTracker> mImageTracker;
1969 };
1970 
nsStyleImageRequest(Mode aModeFlags,imgRequestProxy * aRequestProxy,css::ImageValue * aImageValue,ImageTracker * aImageTracker)1971 nsStyleImageRequest::nsStyleImageRequest(Mode aModeFlags,
1972                                          imgRequestProxy* aRequestProxy,
1973                                          css::ImageValue* aImageValue,
1974                                          ImageTracker* aImageTracker)
1975   : mRequestProxy(aRequestProxy)
1976   , mImageValue(aImageValue)
1977   , mImageTracker(aImageTracker)
1978   , mModeFlags(aModeFlags)
1979   , mResolved(true)
1980 {
1981   MOZ_ASSERT(NS_IsMainThread());
1982   MOZ_ASSERT(aRequestProxy);
1983   MOZ_ASSERT(aImageValue);
1984   MOZ_ASSERT(!!(aModeFlags & Mode::Track) == !!aImageTracker);
1985 
1986   MaybeTrackAndLock();
1987 }
1988 
nsStyleImageRequest(Mode aModeFlags,nsStringBuffer * aURLBuffer,already_AddRefed<PtrHolder<nsIURI>> aBaseURI,already_AddRefed<PtrHolder<nsIURI>> aReferrer,already_AddRefed<PtrHolder<nsIPrincipal>> aPrincipal)1989 nsStyleImageRequest::nsStyleImageRequest(
1990     Mode aModeFlags,
1991     nsStringBuffer* aURLBuffer,
1992     already_AddRefed<PtrHolder<nsIURI>> aBaseURI,
1993     already_AddRefed<PtrHolder<nsIURI>> aReferrer,
1994     already_AddRefed<PtrHolder<nsIPrincipal>> aPrincipal)
1995   : mModeFlags(aModeFlags)
1996   , mResolved(false)
1997 {
1998   mImageValue = new css::ImageValue(aURLBuffer, Move(aBaseURI),
1999                                     Move(aReferrer), Move(aPrincipal));
2000 }
2001 
~nsStyleImageRequest()2002 nsStyleImageRequest::~nsStyleImageRequest()
2003 {
2004   // We may or may not be being destroyed on the main thread.  To clean
2005   // up, we must untrack and unlock the image (depending on mModeFlags),
2006   // and release mRequestProxy and mImageValue, all on the main thread.
2007   {
2008     RefPtr<StyleImageRequestCleanupTask> task =
2009         new StyleImageRequestCleanupTask(mModeFlags,
2010                                          mRequestProxy.forget(),
2011                                          mImageValue.forget(),
2012                                          mImageTracker.forget());
2013     if (NS_IsMainThread()) {
2014       task->Run();
2015     } else {
2016       NS_DispatchToMainThread(task.forget());
2017     }
2018   }
2019 
2020   MOZ_ASSERT(!mRequestProxy);
2021   MOZ_ASSERT(!mImageValue);
2022   MOZ_ASSERT(!mImageTracker);
2023 }
2024 
2025 bool
Resolve(nsPresContext * aPresContext)2026 nsStyleImageRequest::Resolve(nsPresContext* aPresContext)
2027 {
2028   MOZ_ASSERT(NS_IsMainThread());
2029   MOZ_ASSERT(!IsResolved(), "already resolved");
2030 
2031   mResolved = true;
2032 
2033   // For now, just have unique nsCSSValue/ImageValue objects.  We should
2034   // really store the ImageValue on the Servo specified value, so that we can
2035   // share imgRequestProxys that come from the same rule in the same
2036   // document.
2037   mImageValue->Initialize(aPresContext->Document());
2038 
2039   nsCSSValue value;
2040   value.SetImageValue(mImageValue);
2041   mRequestProxy = value.GetPossiblyStaticImageValue(aPresContext->Document(),
2042                                                     aPresContext);
2043 
2044   if (!mRequestProxy) {
2045     // The URL resolution or image load failed.
2046     return false;
2047   }
2048 
2049   if (mModeFlags & Mode::Track) {
2050     mImageTracker = aPresContext->Document()->ImageTracker();
2051   }
2052 
2053   MaybeTrackAndLock();
2054   return true;
2055 }
2056 
2057 void
MaybeTrackAndLock()2058 nsStyleImageRequest::MaybeTrackAndLock()
2059 {
2060   MOZ_ASSERT(NS_IsMainThread());
2061   MOZ_ASSERT(IsResolved());
2062   MOZ_ASSERT(mRequestProxy);
2063 
2064   if (mModeFlags & Mode::Track) {
2065     MOZ_ASSERT(mImageTracker);
2066     mImageTracker->Add(mRequestProxy);
2067   } else {
2068     MOZ_ASSERT(!mImageTracker);
2069     mRequestProxy->LockImage();
2070   }
2071 }
2072 
2073 bool
DefinitelyEquals(const nsStyleImageRequest & aOther) const2074 nsStyleImageRequest::DefinitelyEquals(const nsStyleImageRequest& aOther) const
2075 {
2076   return DefinitelyEqualURIs(mImageValue, aOther.mImageValue);
2077 }
2078 
2079 // --------------------
2080 // CachedBorderImageData
2081 //
2082 void
SetCachedSVGViewportSize(const mozilla::Maybe<nsSize> & aSVGViewportSize)2083 CachedBorderImageData::SetCachedSVGViewportSize(
2084   const mozilla::Maybe<nsSize>& aSVGViewportSize)
2085 {
2086   mCachedSVGViewportSize = aSVGViewportSize;
2087 }
2088 
2089 const mozilla::Maybe<nsSize>&
GetCachedSVGViewportSize()2090 CachedBorderImageData::GetCachedSVGViewportSize()
2091 {
2092   return mCachedSVGViewportSize;
2093 }
2094 
2095 void
PurgeCachedImages()2096 CachedBorderImageData::PurgeCachedImages()
2097 {
2098   mSubImages.Clear();
2099 }
2100 
2101 void
SetSubImage(uint8_t aIndex,imgIContainer * aSubImage)2102 CachedBorderImageData::SetSubImage(uint8_t aIndex, imgIContainer* aSubImage)
2103 {
2104   mSubImages.ReplaceObjectAt(aSubImage, aIndex);
2105 }
2106 
2107 imgIContainer*
GetSubImage(uint8_t aIndex)2108 CachedBorderImageData::GetSubImage(uint8_t aIndex)
2109 {
2110   imgIContainer* subImage = nullptr;
2111   if (aIndex < mSubImages.Count())
2112     subImage = mSubImages[aIndex];
2113   return subImage;
2114 }
2115 
2116 // --------------------
2117 // nsStyleImage
2118 //
2119 
nsStyleImage()2120 nsStyleImage::nsStyleImage()
2121   : mType(eStyleImageType_Null)
2122   , mCropRect(nullptr)
2123 {
2124   MOZ_COUNT_CTOR(nsStyleImage);
2125 }
2126 
~nsStyleImage()2127 nsStyleImage::~nsStyleImage()
2128 {
2129   MOZ_COUNT_DTOR(nsStyleImage);
2130   if (mType != eStyleImageType_Null) {
2131     SetNull();
2132   }
2133 }
2134 
nsStyleImage(const nsStyleImage & aOther)2135 nsStyleImage::nsStyleImage(const nsStyleImage& aOther)
2136   : mType(eStyleImageType_Null)
2137   , mCropRect(nullptr)
2138 {
2139   // We need our own copy constructor because we don't want
2140   // to copy the reference count
2141   MOZ_COUNT_CTOR(nsStyleImage);
2142   DoCopy(aOther);
2143 }
2144 
2145 nsStyleImage&
operator =(const nsStyleImage & aOther)2146 nsStyleImage::operator=(const nsStyleImage& aOther)
2147 {
2148   if (this != &aOther) {
2149     DoCopy(aOther);
2150   }
2151 
2152   return *this;
2153 }
2154 
2155 void
DoCopy(const nsStyleImage & aOther)2156 nsStyleImage::DoCopy(const nsStyleImage& aOther)
2157 {
2158   SetNull();
2159 
2160   if (aOther.mType == eStyleImageType_Image) {
2161     SetImageRequest(do_AddRef(aOther.mImage));
2162   } else if (aOther.mType == eStyleImageType_Gradient) {
2163     SetGradientData(aOther.mGradient);
2164   } else if (aOther.mType == eStyleImageType_Element) {
2165     SetElementId(aOther.mElementId);
2166   }
2167 
2168   UniquePtr<nsStyleSides> cropRectCopy;
2169   if (aOther.mCropRect) {
2170     cropRectCopy = MakeUnique<nsStyleSides>(*aOther.mCropRect.get());
2171   }
2172   SetCropRect(Move(cropRectCopy));
2173 }
2174 
2175 void
SetNull()2176 nsStyleImage::SetNull()
2177 {
2178   if (mType == eStyleImageType_Gradient) {
2179     mGradient->Release();
2180   } else if (mType == eStyleImageType_Image) {
2181     NS_RELEASE(mImage);
2182   } else if (mType == eStyleImageType_Element) {
2183     free(mElementId);
2184   }
2185 
2186   mType = eStyleImageType_Null;
2187   mCropRect = nullptr;
2188 }
2189 
2190 void
SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage)2191 nsStyleImage::SetImageRequest(already_AddRefed<nsStyleImageRequest> aImage)
2192 {
2193   RefPtr<nsStyleImageRequest> image = aImage;
2194 
2195   if (mType != eStyleImageType_Null) {
2196     SetNull();
2197   }
2198 
2199   if (image) {
2200     mImage = image.forget().take();
2201     mType = eStyleImageType_Image;
2202   }
2203   if (mCachedBIData) {
2204     mCachedBIData->PurgeCachedImages();
2205   }
2206 }
2207 
2208 void
SetGradientData(nsStyleGradient * aGradient)2209 nsStyleImage::SetGradientData(nsStyleGradient* aGradient)
2210 {
2211   if (aGradient) {
2212     aGradient->AddRef();
2213   }
2214 
2215   if (mType != eStyleImageType_Null) {
2216     SetNull();
2217   }
2218 
2219   if (aGradient) {
2220     mGradient = aGradient;
2221     mType = eStyleImageType_Gradient;
2222   }
2223 }
2224 
2225 void
SetElementId(const char16_t * aElementId)2226 nsStyleImage::SetElementId(const char16_t* aElementId)
2227 {
2228   if (mType != eStyleImageType_Null) {
2229     SetNull();
2230   }
2231 
2232   if (aElementId) {
2233     mElementId = NS_strdup(aElementId);
2234     mType = eStyleImageType_Element;
2235   }
2236 }
2237 
2238 void
SetCropRect(UniquePtr<nsStyleSides> aCropRect)2239 nsStyleImage::SetCropRect(UniquePtr<nsStyleSides> aCropRect)
2240 {
2241     mCropRect = Move(aCropRect);
2242 }
2243 
2244 static int32_t
ConvertToPixelCoord(const nsStyleCoord & aCoord,int32_t aPercentScale)2245 ConvertToPixelCoord(const nsStyleCoord& aCoord, int32_t aPercentScale)
2246 {
2247   double pixelValue;
2248   switch (aCoord.GetUnit()) {
2249     case eStyleUnit_Percent:
2250       pixelValue = aCoord.GetPercentValue() * aPercentScale;
2251       break;
2252     case eStyleUnit_Factor:
2253       pixelValue = aCoord.GetFactorValue();
2254       break;
2255     default:
2256       NS_NOTREACHED("unexpected unit for image crop rect");
2257       return 0;
2258   }
2259   MOZ_ASSERT(pixelValue >= 0, "we ensured non-negative while parsing");
2260   pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow
2261   return NS_lround(pixelValue);
2262 }
2263 
2264 bool
ComputeActualCropRect(nsIntRect & aActualCropRect,bool * aIsEntireImage) const2265 nsStyleImage::ComputeActualCropRect(nsIntRect& aActualCropRect,
2266                                     bool* aIsEntireImage) const
2267 {
2268   if (mType != eStyleImageType_Image) {
2269     return false;
2270   }
2271 
2272   imgRequestProxy* req = GetImageData();
2273   if (!req) {
2274     return false;
2275   }
2276 
2277   nsCOMPtr<imgIContainer> imageContainer;
2278   req->GetImage(getter_AddRefs(imageContainer));
2279   if (!imageContainer) {
2280     return false;
2281   }
2282 
2283   nsIntSize imageSize;
2284   imageContainer->GetWidth(&imageSize.width);
2285   imageContainer->GetHeight(&imageSize.height);
2286   if (imageSize.width <= 0 || imageSize.height <= 0) {
2287     return false;
2288   }
2289 
2290   int32_t left   = ConvertToPixelCoord(mCropRect->GetLeft(),   imageSize.width);
2291   int32_t top    = ConvertToPixelCoord(mCropRect->GetTop(),    imageSize.height);
2292   int32_t right  = ConvertToPixelCoord(mCropRect->GetRight(),  imageSize.width);
2293   int32_t bottom = ConvertToPixelCoord(mCropRect->GetBottom(), imageSize.height);
2294 
2295   // IntersectRect() returns an empty rect if we get negative width or height
2296   nsIntRect cropRect(left, top, right - left, bottom - top);
2297   nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
2298   aActualCropRect.IntersectRect(imageRect, cropRect);
2299 
2300   if (aIsEntireImage) {
2301     *aIsEntireImage = aActualCropRect.IsEqualInterior(imageRect);
2302   }
2303   return true;
2304 }
2305 
2306 nsresult
StartDecoding() const2307 nsStyleImage::StartDecoding() const
2308 {
2309   if (mType == eStyleImageType_Image) {
2310     imgRequestProxy* req = GetImageData();
2311     if (!req) {
2312       return NS_ERROR_FAILURE;
2313     }
2314     return req->StartDecoding();
2315   }
2316   return NS_OK;
2317 }
2318 
2319 bool
IsOpaque() const2320 nsStyleImage::IsOpaque() const
2321 {
2322   if (!IsComplete()) {
2323     return false;
2324   }
2325 
2326   if (mType == eStyleImageType_Gradient) {
2327     return mGradient->IsOpaque();
2328   }
2329 
2330   if (mType == eStyleImageType_Element) {
2331     return false;
2332   }
2333 
2334   MOZ_ASSERT(mType == eStyleImageType_Image, "unexpected image type");
2335   MOZ_ASSERT(GetImageData(), "should've returned earlier above");
2336 
2337   nsCOMPtr<imgIContainer> imageContainer;
2338   GetImageData()->GetImage(getter_AddRefs(imageContainer));
2339   MOZ_ASSERT(imageContainer, "IsComplete() said image container is ready");
2340 
2341   // Check if the crop region of the image is opaque.
2342   if (imageContainer->WillDrawOpaqueNow()) {
2343     if (!mCropRect) {
2344       return true;
2345     }
2346 
2347     // Must make sure if mCropRect contains at least a pixel.
2348     // XXX Is this optimization worth it? Maybe I should just return false.
2349     nsIntRect actualCropRect;
2350     bool rv = ComputeActualCropRect(actualCropRect);
2351     NS_ASSERTION(rv, "ComputeActualCropRect() can not fail here");
2352     return rv && !actualCropRect.IsEmpty();
2353   }
2354 
2355   return false;
2356 }
2357 
2358 bool
IsComplete() const2359 nsStyleImage::IsComplete() const
2360 {
2361   switch (mType) {
2362     case eStyleImageType_Null:
2363       return false;
2364     case eStyleImageType_Gradient:
2365     case eStyleImageType_Element:
2366       return true;
2367     case eStyleImageType_Image: {
2368       imgRequestProxy* req = GetImageData();
2369       if (!req) {
2370         return false;
2371       }
2372       uint32_t status = imgIRequest::STATUS_ERROR;
2373       return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
2374              (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
2375              (status & imgIRequest::STATUS_FRAME_COMPLETE);
2376     }
2377     default:
2378       NS_NOTREACHED("unexpected image type");
2379       return false;
2380   }
2381 }
2382 
2383 bool
IsLoaded() const2384 nsStyleImage::IsLoaded() const
2385 {
2386   switch (mType) {
2387     case eStyleImageType_Null:
2388       return false;
2389     case eStyleImageType_Gradient:
2390     case eStyleImageType_Element:
2391       return true;
2392     case eStyleImageType_Image: {
2393       imgRequestProxy* req = GetImageData();
2394       if (!req) {
2395         return false;
2396       }
2397       uint32_t status = imgIRequest::STATUS_ERROR;
2398       return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
2399              !(status & imgIRequest::STATUS_ERROR) &&
2400              (status & imgIRequest::STATUS_LOAD_COMPLETE);
2401     }
2402     default:
2403       NS_NOTREACHED("unexpected image type");
2404       return false;
2405   }
2406 }
2407 
2408 static inline bool
EqualRects(const UniquePtr<nsStyleSides> & aRect1,const UniquePtr<nsStyleSides> & aRect2)2409 EqualRects(const UniquePtr<nsStyleSides>& aRect1, const UniquePtr<nsStyleSides>& aRect2)
2410 {
2411   return aRect1 == aRect2 || /* handles null== null, and optimize */
2412          (aRect1 && aRect2 && *aRect1 == *aRect2);
2413 }
2414 
2415 bool
operator ==(const nsStyleImage & aOther) const2416 nsStyleImage::operator==(const nsStyleImage& aOther) const
2417 {
2418   if (mType != aOther.mType) {
2419     return false;
2420   }
2421 
2422   if (!EqualRects(mCropRect, aOther.mCropRect)) {
2423     return false;
2424   }
2425 
2426   if (mType == eStyleImageType_Image) {
2427     return DefinitelyEqualImages(mImage, aOther.mImage);
2428   }
2429 
2430   if (mType == eStyleImageType_Gradient) {
2431     return *mGradient == *aOther.mGradient;
2432   }
2433 
2434   if (mType == eStyleImageType_Element) {
2435     return NS_strcmp(mElementId, aOther.mElementId) == 0;
2436   }
2437 
2438   return true;
2439 }
2440 
2441 void
PurgeCacheForViewportChange(const mozilla::Maybe<nsSize> & aSVGViewportSize,const bool aHasIntrinsicRatio) const2442 nsStyleImage::PurgeCacheForViewportChange(
2443   const mozilla::Maybe<nsSize>& aSVGViewportSize,
2444   const bool aHasIntrinsicRatio) const
2445 {
2446   EnsureCachedBIData();
2447 
2448   // If we're redrawing with a different viewport-size than we used for our
2449   // cached subimages, then we can't trust that our subimages are valid;
2450   // any percent sizes/positions in our SVG doc may be different now. Purge!
2451   // (We don't have to purge if the SVG document has an intrinsic ratio,
2452   // though, because the actual size of elements in SVG documant's coordinate
2453   // axis are fixed in this case.)
2454   if (aSVGViewportSize != mCachedBIData->GetCachedSVGViewportSize() &&
2455       !aHasIntrinsicRatio) {
2456     mCachedBIData->PurgeCachedImages();
2457     mCachedBIData->SetCachedSVGViewportSize(aSVGViewportSize);
2458   }
2459 }
2460 
2461 // --------------------
2462 // nsStyleImageLayers
2463 //
2464 
2465 const nsCSSPropertyID nsStyleImageLayers::kBackgroundLayerTable[] = {
2466   eCSSProperty_background,                // shorthand
2467   eCSSProperty_background_color,          // color
2468   eCSSProperty_background_image,          // image
2469   eCSSProperty_background_repeat,         // repeat
2470   eCSSProperty_background_position_x,     // positionX
2471   eCSSProperty_background_position_y,     // positionY
2472   eCSSProperty_background_clip,           // clip
2473   eCSSProperty_background_origin,         // origin
2474   eCSSProperty_background_size,           // size
2475   eCSSProperty_background_attachment,     // attachment
2476   eCSSProperty_UNKNOWN,                   // maskMode
2477   eCSSProperty_UNKNOWN                    // composite
2478 };
2479 
2480 #ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
2481 const nsCSSPropertyID nsStyleImageLayers::kMaskLayerTable[] = {
2482   eCSSProperty_mask,                      // shorthand
2483   eCSSProperty_UNKNOWN,                   // color
2484   eCSSProperty_mask_image,                // image
2485   eCSSProperty_mask_repeat,               // repeat
2486   eCSSProperty_mask_position_x,           // positionX
2487   eCSSProperty_mask_position_y,           // positionY
2488   eCSSProperty_mask_clip,                 // clip
2489   eCSSProperty_mask_origin,               // origin
2490   eCSSProperty_mask_size,                 // size
2491   eCSSProperty_UNKNOWN,                   // attachment
2492   eCSSProperty_mask_mode,                 // maskMode
2493   eCSSProperty_mask_composite             // composite
2494 };
2495 #endif
2496 
nsStyleImageLayers(nsStyleImageLayers::LayerType aType)2497 nsStyleImageLayers::nsStyleImageLayers(nsStyleImageLayers::LayerType aType)
2498   : mAttachmentCount(1)
2499   , mClipCount(1)
2500   , mOriginCount(1)
2501   , mRepeatCount(1)
2502   , mPositionXCount(1)
2503   , mPositionYCount(1)
2504   , mImageCount(1)
2505   , mSizeCount(1)
2506   , mMaskModeCount(1)
2507   , mBlendModeCount(1)
2508   , mCompositeCount(1)
2509   , mLayers(nsStyleAutoArray<Layer>::WITH_SINGLE_INITIAL_ELEMENT)
2510 {
2511   MOZ_COUNT_CTOR(nsStyleImageLayers);
2512 
2513   // Ensure first layer is initialized as specified layer type
2514   mLayers[0].Initialize(aType);
2515 }
2516 
nsStyleImageLayers(const nsStyleImageLayers & aSource)2517 nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers &aSource)
2518   : mAttachmentCount(aSource.mAttachmentCount)
2519   , mClipCount(aSource.mClipCount)
2520   , mOriginCount(aSource.mOriginCount)
2521   , mRepeatCount(aSource.mRepeatCount)
2522   , mPositionXCount(aSource.mPositionXCount)
2523   , mPositionYCount(aSource.mPositionYCount)
2524   , mImageCount(aSource.mImageCount)
2525   , mSizeCount(aSource.mSizeCount)
2526   , mMaskModeCount(aSource.mMaskModeCount)
2527   , mBlendModeCount(aSource.mBlendModeCount)
2528   , mCompositeCount(aSource.mCompositeCount)
2529   , mLayers(aSource.mLayers) // deep copy
2530 {
2531   MOZ_COUNT_CTOR(nsStyleImageLayers);
2532   // If the deep copy of mLayers failed, truncate the counts.
2533   uint32_t count = mLayers.Length();
2534   if (count != aSource.mLayers.Length()) {
2535     NS_WARNING("truncating counts due to out-of-memory");
2536     mAttachmentCount = std::max(mAttachmentCount, count);
2537     mClipCount = std::max(mClipCount, count);
2538     mOriginCount = std::max(mOriginCount, count);
2539     mRepeatCount = std::max(mRepeatCount, count);
2540     mPositionXCount = std::max(mPositionXCount, count);
2541     mPositionYCount = std::max(mPositionYCount, count);
2542     mImageCount = std::max(mImageCount, count);
2543     mSizeCount = std::max(mSizeCount, count);
2544     mMaskModeCount = std::max(mMaskModeCount, count);
2545     mBlendModeCount = std::max(mBlendModeCount, count);
2546     mCompositeCount = std::max(mCompositeCount, count);
2547   }
2548 }
2549 
2550 nsChangeHint
CalcDifference(const nsStyleImageLayers & aNewLayers,nsStyleImageLayers::LayerType aType) const2551 nsStyleImageLayers::CalcDifference(const nsStyleImageLayers& aNewLayers,
2552                                    nsStyleImageLayers::LayerType aType) const
2553 {
2554   nsChangeHint hint = nsChangeHint(0);
2555 
2556   const nsStyleImageLayers& moreLayers =
2557     mImageCount > aNewLayers.mImageCount ?
2558       *this : aNewLayers;
2559   const nsStyleImageLayers& lessLayers =
2560     mImageCount > aNewLayers.mImageCount ?
2561       aNewLayers : *this;
2562 
2563   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, moreLayers) {
2564     if (i < lessLayers.mImageCount) {
2565       nsChangeHint layerDifference =
2566         moreLayers.mLayers[i].CalcDifference(lessLayers.mLayers[i]);
2567       hint |= layerDifference;
2568       if (layerDifference &&
2569           ((moreLayers.mLayers[i].mImage.GetType() == eStyleImageType_Element) ||
2570            (lessLayers.mLayers[i].mImage.GetType() == eStyleImageType_Element))) {
2571         hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
2572       }
2573     } else {
2574       hint |= nsChangeHint_RepaintFrame;
2575       if (moreLayers.mLayers[i].mImage.GetType() == eStyleImageType_Element) {
2576         hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
2577       }
2578     }
2579   }
2580 
2581   if (aType == nsStyleImageLayers::LayerType::Mask &&
2582       mImageCount != aNewLayers.mImageCount) {
2583     hint |= nsChangeHint_UpdateEffects;
2584   }
2585 
2586   if (hint) {
2587     return hint;
2588   }
2589 
2590   if (mAttachmentCount != aNewLayers.mAttachmentCount ||
2591       mBlendModeCount != aNewLayers.mBlendModeCount ||
2592       mClipCount != aNewLayers.mClipCount ||
2593       mCompositeCount != aNewLayers.mCompositeCount ||
2594       mMaskModeCount != aNewLayers.mMaskModeCount ||
2595       mOriginCount != aNewLayers.mOriginCount ||
2596       mRepeatCount != aNewLayers.mRepeatCount ||
2597       mPositionXCount != aNewLayers.mPositionXCount ||
2598       mPositionYCount != aNewLayers.mPositionYCount ||
2599       mSizeCount != aNewLayers.mSizeCount) {
2600     hint |= nsChangeHint_NeutralChange;
2601   }
2602 
2603   return hint;
2604 }
2605 
2606 bool
HasLayerWithImage() const2607 nsStyleImageLayers::HasLayerWithImage() const
2608 {
2609   for (uint32_t i = 0; i < mImageCount; i++) {
2610     // mLayers[i].mSourceURI can be nullptr if mask-image prop value is
2611     // <element-reference> or <gradient>
2612     // mLayers[i].mImage can be empty if mask-image prop value is a reference
2613     // to SVG mask element.
2614     // So we need to test both mSourceURI and mImage.
2615     if ((mLayers[i].mSourceURI && mLayers[i].mSourceURI->GetURI()) ||
2616         !mLayers[i].mImage.IsEmpty()) {
2617       return true;
2618     }
2619   }
2620 
2621   return false;
2622 }
2623 
2624 nsStyleImageLayers&
operator =(const nsStyleImageLayers & aOther)2625 nsStyleImageLayers::operator=(const nsStyleImageLayers& aOther)
2626 {
2627   mAttachmentCount = aOther.mAttachmentCount;
2628   mClipCount = aOther.mClipCount;
2629   mOriginCount = aOther.mOriginCount;
2630   mRepeatCount = aOther.mRepeatCount;
2631   mPositionXCount = aOther.mPositionXCount;
2632   mPositionYCount = aOther.mPositionYCount;
2633   mImageCount = aOther.mImageCount;
2634   mSizeCount = aOther.mSizeCount;
2635   mMaskModeCount = aOther.mMaskModeCount;
2636   mBlendModeCount = aOther.mBlendModeCount;
2637   mCompositeCount = aOther.mCompositeCount;
2638   mLayers = aOther.mLayers;
2639 
2640   uint32_t count = mLayers.Length();
2641   if (count != aOther.mLayers.Length()) {
2642     NS_WARNING("truncating counts due to out-of-memory");
2643     mAttachmentCount = std::max(mAttachmentCount, count);
2644     mClipCount = std::max(mClipCount, count);
2645     mOriginCount = std::max(mOriginCount, count);
2646     mRepeatCount = std::max(mRepeatCount, count);
2647     mPositionXCount = std::max(mPositionXCount, count);
2648     mPositionYCount = std::max(mPositionYCount, count);
2649     mImageCount = std::max(mImageCount, count);
2650     mSizeCount = std::max(mSizeCount, count);
2651     mMaskModeCount = std::max(mMaskModeCount, count);
2652     mBlendModeCount = std::max(mBlendModeCount, count);
2653     mCompositeCount = std::max(mCompositeCount, count);
2654   }
2655 
2656   return *this;
2657 }
2658 
2659 bool
IsInitialPositionForLayerType(Position aPosition,LayerType aType)2660 nsStyleImageLayers::IsInitialPositionForLayerType(Position aPosition, LayerType aType)
2661 {
2662   if (aPosition.mXPosition.mPercent == 0.0f &&
2663       aPosition.mXPosition.mLength == 0 &&
2664       aPosition.mXPosition.mHasPercent &&
2665       aPosition.mYPosition.mPercent == 0.0f &&
2666       aPosition.mYPosition.mLength == 0 &&
2667       aPosition.mYPosition.mHasPercent) {
2668     return true;
2669   }
2670 
2671   return false;
2672 }
2673 
2674 void
SetInitialPercentValues(float aPercentVal)2675 Position::SetInitialPercentValues(float aPercentVal)
2676 {
2677   mXPosition.mPercent = aPercentVal;
2678   mXPosition.mLength = 0;
2679   mXPosition.mHasPercent = true;
2680   mYPosition.mPercent = aPercentVal;
2681   mYPosition.mLength = 0;
2682   mYPosition.mHasPercent = true;
2683 }
2684 
2685 void
SetInitialZeroValues()2686 Position::SetInitialZeroValues()
2687 {
2688   mXPosition.mPercent = 0;
2689   mXPosition.mLength = 0;
2690   mXPosition.mHasPercent = false;
2691   mYPosition.mPercent = 0;
2692   mYPosition.mLength = 0;
2693   mYPosition.mHasPercent = false;
2694 }
2695 
2696 bool
DependsOnPositioningAreaSize(const nsStyleImage & aImage) const2697 nsStyleImageLayers::Size::DependsOnPositioningAreaSize(const nsStyleImage& aImage) const
2698 {
2699   MOZ_ASSERT(aImage.GetType() != eStyleImageType_Null,
2700              "caller should have handled this");
2701 
2702   // If either dimension contains a non-zero percentage, rendering for that
2703   // dimension straightforwardly depends on frame size.
2704   if ((mWidthType == eLengthPercentage && mWidth.mPercent != 0.0f) ||
2705       (mHeightType == eLengthPercentage && mHeight.mPercent != 0.0f)) {
2706     return true;
2707   }
2708 
2709   // So too for contain and cover.
2710   if (mWidthType == eContain || mWidthType == eCover) {
2711     return true;
2712   }
2713 
2714   // If both dimensions are fixed lengths, there's no dependency.
2715   if (mWidthType == eLengthPercentage && mHeightType == eLengthPercentage) {
2716     return false;
2717   }
2718 
2719   MOZ_ASSERT((mWidthType == eLengthPercentage && mHeightType == eAuto) ||
2720              (mWidthType == eAuto && mHeightType == eLengthPercentage) ||
2721              (mWidthType == eAuto && mHeightType == eAuto),
2722              "logic error");
2723 
2724   nsStyleImageType type = aImage.GetType();
2725 
2726   // Gradient rendering depends on frame size when auto is involved because
2727   // gradients have no intrinsic ratio or dimensions, and therefore the relevant
2728   // dimension is "treat[ed] as 100%".
2729   if (type == eStyleImageType_Gradient) {
2730     return true;
2731   }
2732 
2733   // XXX Element rendering for auto or fixed length doesn't depend on frame size
2734   //     according to the spec.  However, we don't implement the spec yet, so
2735   //     for now we bail and say element() plus auto affects ultimate size.
2736   if (type == eStyleImageType_Element) {
2737     return true;
2738   }
2739 
2740   if (type == eStyleImageType_Image) {
2741     nsCOMPtr<imgIContainer> imgContainer;
2742     if (imgRequestProxy* req = aImage.GetImageData()) {
2743       req->GetImage(getter_AddRefs(imgContainer));
2744     }
2745     if (imgContainer) {
2746       CSSIntSize imageSize;
2747       nsSize imageRatio;
2748       bool hasWidth, hasHeight;
2749       nsLayoutUtils::ComputeSizeForDrawing(imgContainer, imageSize, imageRatio,
2750                                            hasWidth, hasHeight);
2751 
2752       // If the image has a fixed width and height, rendering never depends on
2753       // the frame size.
2754       if (hasWidth && hasHeight) {
2755         return false;
2756       }
2757 
2758       // If the image has an intrinsic ratio, rendering will depend on frame
2759       // size when background-size is all auto.
2760       if (imageRatio != nsSize(0, 0)) {
2761         return mWidthType == mHeightType;
2762       }
2763 
2764       // Otherwise, rendering depends on frame size when the image dimensions
2765       // and background-size don't complement each other.
2766       return !(hasWidth && mHeightType == eLengthPercentage) &&
2767              !(hasHeight && mWidthType == eLengthPercentage);
2768     }
2769   } else {
2770     NS_NOTREACHED("missed an enum value");
2771   }
2772 
2773   // Passed the gauntlet: no dependency.
2774   return false;
2775 }
2776 
2777 void
SetInitialValues()2778 nsStyleImageLayers::Size::SetInitialValues()
2779 {
2780   mWidthType = mHeightType = eAuto;
2781 }
2782 
2783 bool
operator ==(const Size & aOther) const2784 nsStyleImageLayers::Size::operator==(const Size& aOther) const
2785 {
2786   MOZ_ASSERT(mWidthType < eDimensionType_COUNT,
2787              "bad mWidthType for this");
2788   MOZ_ASSERT(mHeightType < eDimensionType_COUNT,
2789              "bad mHeightType for this");
2790   MOZ_ASSERT(aOther.mWidthType < eDimensionType_COUNT,
2791              "bad mWidthType for aOther");
2792   MOZ_ASSERT(aOther.mHeightType < eDimensionType_COUNT,
2793              "bad mHeightType for aOther");
2794 
2795   return mWidthType == aOther.mWidthType &&
2796          mHeightType == aOther.mHeightType &&
2797          (mWidthType != eLengthPercentage || mWidth == aOther.mWidth) &&
2798          (mHeightType != eLengthPercentage || mHeight == aOther.mHeight);
2799 }
2800 
Layer()2801 nsStyleImageLayers::Layer::Layer()
2802   : mClip(NS_STYLE_IMAGELAYER_CLIP_BORDER)
2803   , mAttachment(NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL)
2804   , mBlendMode(NS_STYLE_BLEND_NORMAL)
2805   , mComposite(NS_STYLE_MASK_COMPOSITE_ADD)
2806   , mMaskMode(NS_STYLE_MASK_MODE_MATCH_SOURCE)
2807 {
2808   mImage.SetNull();
2809   mSize.SetInitialValues();
2810 }
2811 
~Layer()2812 nsStyleImageLayers::Layer::~Layer()
2813 {
2814 }
2815 
2816 void
Initialize(nsStyleImageLayers::LayerType aType)2817 nsStyleImageLayers::Layer::Initialize(nsStyleImageLayers::LayerType aType)
2818 {
2819   mRepeat.SetInitialValues();
2820 
2821   mPosition.SetInitialPercentValues(0.0f);
2822 
2823   if (aType == LayerType::Background) {
2824     mOrigin = NS_STYLE_IMAGELAYER_ORIGIN_PADDING;
2825   } else {
2826     MOZ_ASSERT(aType == LayerType::Mask, "unsupported layer type.");
2827     mOrigin = NS_STYLE_IMAGELAYER_ORIGIN_BORDER;
2828   }
2829 }
2830 
2831 bool
RenderingMightDependOnPositioningAreaSizeChange() const2832 nsStyleImageLayers::Layer::RenderingMightDependOnPositioningAreaSizeChange() const
2833 {
2834   // Do we even have an image?
2835   if (mImage.IsEmpty()) {
2836     return false;
2837   }
2838 
2839   return mPosition.DependsOnPositioningAreaSize() ||
2840       mSize.DependsOnPositioningAreaSize(mImage) ||
2841       mRepeat.DependsOnPositioningAreaSize();
2842 }
2843 
2844 bool
operator ==(const Layer & aOther) const2845 nsStyleImageLayers::Layer::operator==(const Layer& aOther) const
2846 {
2847   return mAttachment == aOther.mAttachment &&
2848          mClip == aOther.mClip &&
2849          mOrigin == aOther.mOrigin &&
2850          mRepeat == aOther.mRepeat &&
2851          mBlendMode == aOther.mBlendMode &&
2852          mPosition == aOther.mPosition &&
2853          mSize == aOther.mSize &&
2854          mImage == aOther.mImage &&
2855          mMaskMode == aOther.mMaskMode &&
2856          mComposite == aOther.mComposite &&
2857          DefinitelyEqualURIs(mSourceURI, aOther.mSourceURI);
2858 }
2859 
2860 nsChangeHint
CalcDifference(const nsStyleImageLayers::Layer & aNewLayer) const2861 nsStyleImageLayers::Layer::CalcDifference(const nsStyleImageLayers::Layer& aNewLayer) const
2862 {
2863   nsChangeHint hint = nsChangeHint(0);
2864   if (!DefinitelyEqualURIs(mSourceURI, aNewLayer.mSourceURI)) {
2865     hint |= nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects;
2866 
2867     // If Layer::mSourceURI links to a SVG mask, it has a fragment. Not vice
2868     // versa. Here are examples of URI contains a fragment, two of them link
2869     // to a SVG mask:
2870     //   mask:url(a.svg#maskID); // The fragment of this URI is an ID of a mask
2871     //                           // element in a.svg.
2872     //   mask:url(#localMaskID); // The fragment of this URI is an ID of a mask
2873     //                           // element in local document.
2874     //   mask:url(b.svg#viewBoxID); // The fragment of this URI is an ID of a
2875     //                              // viewbox defined in b.svg.
2876     // That is, if mSourceURI has a fragment, it may link to a SVG mask; If
2877     // not, it "must" not link to a SVG mask.
2878     bool maybeSVGMask = false;
2879     if (mSourceURI) {
2880       if (mSourceURI->IsLocalRef()) {
2881         maybeSVGMask = true;
2882       } else if (mSourceURI->GetURI()) {
2883         mSourceURI->GetURI()->GetHasRef(&maybeSVGMask);
2884       }
2885     }
2886 
2887     if (!maybeSVGMask) {
2888       if (aNewLayer.mSourceURI) {
2889         if (aNewLayer.mSourceURI->IsLocalRef()) {
2890           maybeSVGMask = true;
2891         } else if (aNewLayer.mSourceURI->GetURI()) {
2892           aNewLayer.mSourceURI->GetURI()->GetHasRef(&maybeSVGMask);
2893         }
2894       }
2895     }
2896 
2897     // Return nsChangeHint_UpdateOverflow if either URI might link to an SVG
2898     // mask.
2899     if (maybeSVGMask) {
2900       // Mask changes require that we update the PreEffectsBBoxProperty,
2901       // which is done during overflow computation.
2902       hint |= nsChangeHint_UpdateOverflow;
2903     }
2904   } else if (mAttachment != aNewLayer.mAttachment ||
2905              mClip != aNewLayer.mClip ||
2906              mOrigin != aNewLayer.mOrigin ||
2907              mRepeat != aNewLayer.mRepeat ||
2908              mBlendMode != aNewLayer.mBlendMode ||
2909              mSize != aNewLayer.mSize ||
2910              mImage != aNewLayer.mImage ||
2911              mMaskMode != aNewLayer.mMaskMode ||
2912              mComposite != aNewLayer.mComposite) {
2913     hint |= nsChangeHint_RepaintFrame;
2914   }
2915 
2916   if (mPosition != aNewLayer.mPosition) {
2917     hint |= nsChangeHint_UpdateBackgroundPosition;
2918   }
2919 
2920   return hint;
2921 }
2922 
2923 // --------------------
2924 // nsStyleBackground
2925 //
2926 
nsStyleBackground(StyleStructContext aContext)2927 nsStyleBackground::nsStyleBackground(StyleStructContext aContext)
2928   : mImage(nsStyleImageLayers::LayerType::Background)
2929   , mBackgroundColor(NS_RGBA(0, 0, 0, 0))
2930 {
2931   MOZ_COUNT_CTOR(nsStyleBackground);
2932 }
2933 
nsStyleBackground(const nsStyleBackground & aSource)2934 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
2935   : mImage(aSource.mImage)
2936   , mBackgroundColor(aSource.mBackgroundColor)
2937 {
2938   MOZ_COUNT_CTOR(nsStyleBackground);
2939 }
2940 
~nsStyleBackground()2941 nsStyleBackground::~nsStyleBackground()
2942 {
2943   MOZ_COUNT_DTOR(nsStyleBackground);
2944 }
2945 
2946 void
Destroy(nsPresContext * aContext)2947 nsStyleBackground::Destroy(nsPresContext* aContext)
2948 {
2949   this->~nsStyleBackground();
2950   aContext->PresShell()->
2951     FreeByObjectID(eArenaObjectID_nsStyleBackground, this);
2952 }
2953 
2954 void
FinishStyle(nsPresContext * aPresContext)2955 nsStyleBackground::FinishStyle(nsPresContext* aPresContext)
2956 {
2957   MOZ_ASSERT(NS_IsMainThread());
2958   MOZ_ASSERT(aPresContext->StyleSet()->IsServo());
2959 
2960   mImage.ResolveImages(aPresContext);
2961 }
2962 
2963 nsChangeHint
CalcDifference(const nsStyleBackground & aNewData) const2964 nsStyleBackground::CalcDifference(const nsStyleBackground& aNewData) const
2965 {
2966   nsChangeHint hint = nsChangeHint(0);
2967   if (mBackgroundColor != aNewData.mBackgroundColor) {
2968     hint |= nsChangeHint_RepaintFrame;
2969   }
2970 
2971   hint |= mImage.CalcDifference(aNewData.mImage,
2972                                 nsStyleImageLayers::LayerType::Background);
2973 
2974   return hint;
2975 }
2976 
2977 bool
HasFixedBackground(nsIFrame * aFrame) const2978 nsStyleBackground::HasFixedBackground(nsIFrame* aFrame) const
2979 {
2980   NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mImage) {
2981     const nsStyleImageLayers::Layer &layer = mImage.mLayers[i];
2982     if (layer.mAttachment == NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED &&
2983         !layer.mImage.IsEmpty() &&
2984         !nsLayoutUtils::IsTransformed(aFrame)) {
2985       return true;
2986     }
2987   }
2988   return false;
2989 }
2990 
2991 bool
IsTransparent() const2992 nsStyleBackground::IsTransparent() const
2993 {
2994   return BottomLayer().mImage.IsEmpty() &&
2995          mImage.mImageCount == 1 &&
2996          NS_GET_A(mBackgroundColor) == 0;
2997 }
2998 
2999 void
AssignFromKeyword(int32_t aTimingFunctionType)3000 nsTimingFunction::AssignFromKeyword(int32_t aTimingFunctionType)
3001 {
3002   switch (aTimingFunctionType) {
3003     case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_START:
3004       mType = Type::StepStart;
3005       mSteps = 1;
3006       return;
3007     default:
3008       MOZ_FALLTHROUGH_ASSERT("aTimingFunctionType must be a keyword value");
3009     case NS_STYLE_TRANSITION_TIMING_FUNCTION_STEP_END:
3010       mType = Type::StepEnd;
3011       mSteps = 1;
3012       return;
3013     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE:
3014     case NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR:
3015     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN:
3016     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT:
3017     case NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT:
3018       mType = static_cast<Type>(aTimingFunctionType);
3019       break;
3020   }
3021 
3022   static_assert(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE == 0 &&
3023                 NS_STYLE_TRANSITION_TIMING_FUNCTION_LINEAR == 1 &&
3024                 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN == 2 &&
3025                 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_OUT == 3 &&
3026                 NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE_IN_OUT == 4,
3027                 "transition timing function constants not as expected");
3028 
3029   static const float timingFunctionValues[5][4] = {
3030     { 0.25f, 0.10f, 0.25f, 1.00f }, // ease
3031     { 0.00f, 0.00f, 1.00f, 1.00f }, // linear
3032     { 0.42f, 0.00f, 1.00f, 1.00f }, // ease-in
3033     { 0.00f, 0.00f, 0.58f, 1.00f }, // ease-out
3034     { 0.42f, 0.00f, 0.58f, 1.00f }  // ease-in-out
3035   };
3036 
3037   MOZ_ASSERT(0 <= aTimingFunctionType && aTimingFunctionType < 5,
3038              "keyword out of range");
3039   mFunc.mX1 = timingFunctionValues[aTimingFunctionType][0];
3040   mFunc.mY1 = timingFunctionValues[aTimingFunctionType][1];
3041   mFunc.mX2 = timingFunctionValues[aTimingFunctionType][2];
3042   mFunc.mY2 = timingFunctionValues[aTimingFunctionType][3];
3043 }
3044 
StyleTransition(const StyleTransition & aCopy)3045 StyleTransition::StyleTransition(const StyleTransition& aCopy)
3046   : mTimingFunction(aCopy.mTimingFunction)
3047   , mDuration(aCopy.mDuration)
3048   , mDelay(aCopy.mDelay)
3049   , mProperty(aCopy.mProperty)
3050   , mUnknownProperty(aCopy.mUnknownProperty)
3051 {
3052 }
3053 
3054 void
SetInitialValues()3055 StyleTransition::SetInitialValues()
3056 {
3057   mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
3058   mDuration = 0.0;
3059   mDelay = 0.0;
3060   mProperty = eCSSPropertyExtra_all_properties;
3061 }
3062 
3063 void
SetUnknownProperty(nsCSSPropertyID aProperty,const nsAString & aPropertyString)3064 StyleTransition::SetUnknownProperty(nsCSSPropertyID aProperty,
3065                                              const nsAString& aPropertyString)
3066 {
3067   MOZ_ASSERT(nsCSSProps::LookupProperty(aPropertyString,
3068                                         CSSEnabledState::eForAllContent) ==
3069                aProperty,
3070              "property and property string should match");
3071   MOZ_ASSERT(aProperty == eCSSProperty_UNKNOWN ||
3072              aProperty == eCSSPropertyExtra_variable,
3073              "should be either unknown or custom property");
3074   mProperty = aProperty;
3075   mUnknownProperty = NS_Atomize(aPropertyString);
3076 }
3077 
3078 bool
operator ==(const StyleTransition & aOther) const3079 StyleTransition::operator==(const StyleTransition& aOther) const
3080 {
3081   return mTimingFunction == aOther.mTimingFunction &&
3082          mDuration == aOther.mDuration &&
3083          mDelay == aOther.mDelay &&
3084          mProperty == aOther.mProperty &&
3085          (mProperty != eCSSProperty_UNKNOWN ||
3086           mUnknownProperty == aOther.mUnknownProperty);
3087 }
3088 
StyleAnimation(const StyleAnimation & aCopy)3089 StyleAnimation::StyleAnimation(const StyleAnimation& aCopy)
3090   : mTimingFunction(aCopy.mTimingFunction)
3091   , mDuration(aCopy.mDuration)
3092   , mDelay(aCopy.mDelay)
3093   , mName(aCopy.mName)
3094   , mDirection(aCopy.mDirection)
3095   , mFillMode(aCopy.mFillMode)
3096   , mPlayState(aCopy.mPlayState)
3097   , mIterationCount(aCopy.mIterationCount)
3098 {
3099 }
3100 
3101 void
SetInitialValues()3102 StyleAnimation::SetInitialValues()
3103 {
3104   mTimingFunction = nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE);
3105   mDuration = 0.0;
3106   mDelay = 0.0;
3107   mName = EmptyString();
3108   mDirection = dom::PlaybackDirection::Normal;
3109   mFillMode = dom::FillMode::None;
3110   mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING;
3111   mIterationCount = 1.0f;
3112 }
3113 
3114 bool
operator ==(const StyleAnimation & aOther) const3115 StyleAnimation::operator==(const StyleAnimation& aOther) const
3116 {
3117   return mTimingFunction == aOther.mTimingFunction &&
3118          mDuration == aOther.mDuration &&
3119          mDelay == aOther.mDelay &&
3120          mName == aOther.mName &&
3121          mDirection == aOther.mDirection &&
3122          mFillMode == aOther.mFillMode &&
3123          mPlayState == aOther.mPlayState &&
3124          mIterationCount == aOther.mIterationCount;
3125 }
3126 
3127 // --------------------
3128 // nsStyleDisplay
3129 //
nsStyleDisplay(StyleStructContext aContext)3130 nsStyleDisplay::nsStyleDisplay(StyleStructContext aContext)
3131   : mDisplay(StyleDisplay::Inline)
3132   , mOriginalDisplay(StyleDisplay::Inline)
3133   , mContain(NS_STYLE_CONTAIN_NONE)
3134   , mAppearance(NS_THEME_NONE)
3135   , mPosition(NS_STYLE_POSITION_STATIC)
3136   , mFloat(StyleFloat::None)
3137   , mOriginalFloat(StyleFloat::None)
3138   , mBreakType(StyleClear::None)
3139   , mBreakInside(NS_STYLE_PAGE_BREAK_AUTO)
3140   , mBreakBefore(false)
3141   , mBreakAfter(false)
3142   , mOverflowX(NS_STYLE_OVERFLOW_VISIBLE)
3143   , mOverflowY(NS_STYLE_OVERFLOW_VISIBLE)
3144   , mOverflowClipBox(NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX)
3145   , mResize(NS_STYLE_RESIZE_NONE)
3146   , mOrient(StyleOrient::Inline)
3147   , mIsolation(NS_STYLE_ISOLATION_AUTO)
3148   , mTopLayer(NS_STYLE_TOP_LAYER_NONE)
3149   , mWillChangeBitField(0)
3150   , mTouchAction(NS_STYLE_TOUCH_ACTION_AUTO)
3151   , mScrollBehavior(NS_STYLE_SCROLL_BEHAVIOR_AUTO)
3152   , mScrollSnapTypeX(NS_STYLE_SCROLL_SNAP_TYPE_NONE)
3153   , mScrollSnapTypeY(NS_STYLE_SCROLL_SNAP_TYPE_NONE)
3154   , mScrollSnapPointsX(eStyleUnit_None)
3155   , mScrollSnapPointsY(eStyleUnit_None)
3156   , mBackfaceVisibility(NS_STYLE_BACKFACE_VISIBILITY_VISIBLE)
3157   , mTransformStyle(NS_STYLE_TRANSFORM_STYLE_FLAT)
3158   , mTransformBox(NS_STYLE_TRANSFORM_BOX_BORDER_BOX)
3159   , mSpecifiedTransform(nullptr)
3160   , mTransformOrigin{ {0.5f, eStyleUnit_Percent}, // Transform is centered on origin
3161                       {0.5f, eStyleUnit_Percent},
3162                       {0, nsStyleCoord::CoordConstructor} }
3163   , mChildPerspective(eStyleUnit_None)
3164   , mPerspectiveOrigin{ {0.5f, eStyleUnit_Percent},
3165                         {0.5f, eStyleUnit_Percent} }
3166   , mVerticalAlign(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated)
3167   , mTransitions(nsStyleAutoArray<StyleTransition>::WITH_SINGLE_INITIAL_ELEMENT)
3168   , mTransitionTimingFunctionCount(1)
3169   , mTransitionDurationCount(1)
3170   , mTransitionDelayCount(1)
3171   , mTransitionPropertyCount(1)
3172   , mAnimations(nsStyleAutoArray<StyleAnimation>::WITH_SINGLE_INITIAL_ELEMENT)
3173   , mAnimationTimingFunctionCount(1)
3174   , mAnimationDurationCount(1)
3175   , mAnimationDelayCount(1)
3176   , mAnimationNameCount(1)
3177   , mAnimationDirectionCount(1)
3178   , mAnimationFillModeCount(1)
3179   , mAnimationPlayStateCount(1)
3180   , mAnimationIterationCountCount(1)
3181 {
3182   MOZ_COUNT_CTOR(nsStyleDisplay);
3183 
3184   // Initial value for mScrollSnapDestination is "0px 0px"
3185   mScrollSnapDestination.SetInitialZeroValues();
3186 
3187   mTransitions[0].SetInitialValues();
3188   mAnimations[0].SetInitialValues();
3189 }
3190 
nsStyleDisplay(const nsStyleDisplay & aSource)3191 nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
3192   : mBinding(aSource.mBinding)
3193   , mDisplay(aSource.mDisplay)
3194   , mOriginalDisplay(aSource.mOriginalDisplay)
3195   , mContain(aSource.mContain)
3196   , mAppearance(aSource.mAppearance)
3197   , mPosition(aSource.mPosition)
3198   , mFloat(aSource.mFloat)
3199   , mOriginalFloat(aSource.mOriginalFloat)
3200   , mBreakType(aSource.mBreakType)
3201   , mBreakInside(aSource.mBreakInside)
3202   , mBreakBefore(aSource.mBreakBefore)
3203   , mBreakAfter(aSource.mBreakAfter)
3204   , mOverflowX(aSource.mOverflowX)
3205   , mOverflowY(aSource.mOverflowY)
3206   , mOverflowClipBox(aSource.mOverflowClipBox)
3207   , mResize(aSource.mResize)
3208   , mOrient(aSource.mOrient)
3209   , mIsolation(aSource.mIsolation)
3210   , mTopLayer(aSource.mTopLayer)
3211   , mWillChangeBitField(aSource.mWillChangeBitField)
3212   , mWillChange(aSource.mWillChange)
3213   , mTouchAction(aSource.mTouchAction)
3214   , mScrollBehavior(aSource.mScrollBehavior)
3215   , mScrollSnapTypeX(aSource.mScrollSnapTypeX)
3216   , mScrollSnapTypeY(aSource.mScrollSnapTypeY)
3217   , mScrollSnapPointsX(aSource.mScrollSnapPointsX)
3218   , mScrollSnapPointsY(aSource.mScrollSnapPointsY)
3219   , mScrollSnapDestination(aSource.mScrollSnapDestination)
3220   , mScrollSnapCoordinate(aSource.mScrollSnapCoordinate)
3221   , mBackfaceVisibility(aSource.mBackfaceVisibility)
3222   , mTransformStyle(aSource.mTransformStyle)
3223   , mTransformBox(aSource.mTransformBox)
3224   , mSpecifiedTransform(aSource.mSpecifiedTransform)
3225   , mTransformOrigin{ aSource.mTransformOrigin[0],
3226                       aSource.mTransformOrigin[1],
3227                       aSource.mTransformOrigin[2] }
3228   , mChildPerspective(aSource.mChildPerspective)
3229   , mPerspectiveOrigin{ aSource.mPerspectiveOrigin[0],
3230                         aSource.mPerspectiveOrigin[1] }
3231   , mVerticalAlign(aSource.mVerticalAlign)
3232   , mTransitions(aSource.mTransitions)
3233   , mTransitionTimingFunctionCount(aSource.mTransitionTimingFunctionCount)
3234   , mTransitionDurationCount(aSource.mTransitionDurationCount)
3235   , mTransitionDelayCount(aSource.mTransitionDelayCount)
3236   , mTransitionPropertyCount(aSource.mTransitionPropertyCount)
3237   , mAnimations(aSource.mAnimations)
3238   , mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount)
3239   , mAnimationDurationCount(aSource.mAnimationDurationCount)
3240   , mAnimationDelayCount(aSource.mAnimationDelayCount)
3241   , mAnimationNameCount(aSource.mAnimationNameCount)
3242   , mAnimationDirectionCount(aSource.mAnimationDirectionCount)
3243   , mAnimationFillModeCount(aSource.mAnimationFillModeCount)
3244   , mAnimationPlayStateCount(aSource.mAnimationPlayStateCount)
3245   , mAnimationIterationCountCount(aSource.mAnimationIterationCountCount)
3246   , mShapeOutside(aSource.mShapeOutside)
3247 {
3248   MOZ_COUNT_CTOR(nsStyleDisplay);
3249 }
3250 
3251 nsChangeHint
CalcDifference(const nsStyleDisplay & aNewData) const3252 nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const
3253 {
3254   nsChangeHint hint = nsChangeHint(0);
3255 
3256   if (!DefinitelyEqualURIsAndPrincipal(mBinding, aNewData.mBinding)
3257       || mPosition != aNewData.mPosition
3258       || mDisplay != aNewData.mDisplay
3259       || mContain != aNewData.mContain
3260       || (mFloat == StyleFloat::None) != (aNewData.mFloat == StyleFloat::None)
3261       || mOverflowX != aNewData.mOverflowX
3262       || mOverflowY != aNewData.mOverflowY
3263       || mScrollBehavior != aNewData.mScrollBehavior
3264       || mScrollSnapTypeX != aNewData.mScrollSnapTypeX
3265       || mScrollSnapTypeY != aNewData.mScrollSnapTypeY
3266       || mScrollSnapPointsX != aNewData.mScrollSnapPointsX
3267       || mScrollSnapPointsY != aNewData.mScrollSnapPointsY
3268       || mScrollSnapDestination != aNewData.mScrollSnapDestination
3269       || mTopLayer != aNewData.mTopLayer
3270       || mResize != aNewData.mResize) {
3271     hint |= nsChangeHint_ReconstructFrame;
3272   }
3273 
3274   /* Note: When mScrollBehavior, mScrollSnapTypeX, mScrollSnapTypeY,
3275    * mScrollSnapPointsX, mScrollSnapPointsY, or mScrollSnapDestination are
3276    * changed, nsChangeHint_NeutralChange is not sufficient to enter
3277    * nsCSSFrameConstructor::PropagateScrollToViewport. By using the same hint
3278    * as used when the overflow css property changes,
3279    * nsChangeHint_ReconstructFrame, PropagateScrollToViewport will be called.
3280    *
3281    * The scroll-behavior css property is not expected to change often (the
3282    * CSSOM-View DOM methods are likely to be used in those cases); however,
3283    * if this does become common perhaps a faster-path might be worth while.
3284    */
3285 
3286   if ((mAppearance == NS_THEME_TEXTFIELD &&
3287        aNewData.mAppearance != NS_THEME_TEXTFIELD) ||
3288       (mAppearance != NS_THEME_TEXTFIELD &&
3289        aNewData.mAppearance == NS_THEME_TEXTFIELD)) {
3290     // This is for <input type=number> where we allow authors to specify a
3291     // |-moz-appearance:textfield| to get a control without a spinner. (The
3292     // spinner is present for |-moz-appearance:number-input| but also other
3293     // values such as 'none'.) We need to reframe since we want to use
3294     // nsTextControlFrame instead of nsNumberControlFrame if the author
3295     // specifies 'textfield'.
3296     return nsChangeHint_ReconstructFrame;
3297   }
3298 
3299   if (mFloat != aNewData.mFloat) {
3300     // Changing which side we float on doesn't affect descendants directly
3301     hint |= nsChangeHint_AllReflowHints &
3302             ~(nsChangeHint_ClearDescendantIntrinsics |
3303               nsChangeHint_NeedDirtyReflow);
3304   }
3305 
3306   if (mVerticalAlign != aNewData.mVerticalAlign) {
3307     // XXX Can this just be AllReflowHints + RepaintFrame, and be included in
3308     // the block below?
3309     hint |= NS_STYLE_HINT_REFLOW;
3310   }
3311 
3312   // XXX the following is conservative, for now: changing float breaking shouldn't
3313   // necessarily require a repaint, reflow should suffice.
3314   if (mBreakType != aNewData.mBreakType
3315       || mBreakInside != aNewData.mBreakInside
3316       || mBreakBefore != aNewData.mBreakBefore
3317       || mBreakAfter != aNewData.mBreakAfter
3318       || mAppearance != aNewData.mAppearance
3319       || mOrient != aNewData.mOrient
3320       || mOverflowClipBox != aNewData.mOverflowClipBox) {
3321     hint |= nsChangeHint_AllReflowHints |
3322             nsChangeHint_RepaintFrame;
3323   }
3324 
3325   if (mIsolation != aNewData.mIsolation) {
3326     hint |= nsChangeHint_RepaintFrame;
3327   }
3328 
3329   /* If we've added or removed the transform property, we need to reconstruct the frame to add
3330    * or remove the view object, and also to handle abs-pos and fixed-pos containers.
3331    */
3332   if (HasTransformStyle() != aNewData.HasTransformStyle()) {
3333     // We do not need to apply nsChangeHint_UpdateTransformLayer since
3334     // nsChangeHint_RepaintFrame will forcibly invalidate the frame area and
3335     // ensure layers are rebuilt (or removed).
3336     hint |= nsChangeHint_UpdateContainingBlock |
3337             nsChangeHint_AddOrRemoveTransform |
3338             nsChangeHint_UpdateOverflow |
3339             nsChangeHint_RepaintFrame;
3340   } else {
3341     /* Otherwise, if we've kept the property lying around and we already had a
3342      * transform, we need to see whether or not we've changed the transform.
3343      * If so, we need to recompute its overflow rect (which probably changed
3344      * if the transform changed) and to redraw within the bounds of that new
3345      * overflow rect.
3346      *
3347      * If the property isn't present in either style struct, we still do the
3348      * comparisons but turn all the resulting change hints into
3349      * nsChangeHint_NeutralChange.
3350      */
3351     nsChangeHint transformHint = nsChangeHint(0);
3352 
3353     if (!mSpecifiedTransform != !aNewData.mSpecifiedTransform ||
3354         (mSpecifiedTransform &&
3355          *mSpecifiedTransform != *aNewData.mSpecifiedTransform)) {
3356       transformHint |= nsChangeHint_UpdateTransformLayer;
3357 
3358       if (mSpecifiedTransform &&
3359           aNewData.mSpecifiedTransform) {
3360         transformHint |= nsChangeHint_UpdatePostTransformOverflow;
3361       } else {
3362         transformHint |= nsChangeHint_UpdateOverflow;
3363       }
3364     }
3365 
3366     const nsChangeHint kUpdateOverflowAndRepaintHint =
3367       nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
3368     for (uint8_t index = 0; index < 3; ++index) {
3369       if (mTransformOrigin[index] != aNewData.mTransformOrigin[index]) {
3370         transformHint |= nsChangeHint_UpdateTransformLayer |
3371                          nsChangeHint_UpdatePostTransformOverflow;
3372         break;
3373       }
3374     }
3375 
3376     for (uint8_t index = 0; index < 2; ++index) {
3377       if (mPerspectiveOrigin[index] != aNewData.mPerspectiveOrigin[index]) {
3378         transformHint |= kUpdateOverflowAndRepaintHint;
3379         break;
3380       }
3381     }
3382 
3383     if (HasPerspectiveStyle() != aNewData.HasPerspectiveStyle()) {
3384       // A change from/to being a containing block for position:fixed.
3385       hint |= nsChangeHint_UpdateContainingBlock;
3386     }
3387 
3388     if (mChildPerspective != aNewData.mChildPerspective ||
3389         mTransformStyle != aNewData.mTransformStyle ||
3390         mTransformBox != aNewData.mTransformBox) {
3391       transformHint |= kUpdateOverflowAndRepaintHint;
3392     }
3393 
3394     if (mBackfaceVisibility != aNewData.mBackfaceVisibility) {
3395       transformHint |= nsChangeHint_RepaintFrame;
3396     }
3397 
3398     if (transformHint) {
3399       if (HasTransformStyle()) {
3400         hint |= transformHint;
3401       } else {
3402         hint |= nsChangeHint_NeutralChange;
3403       }
3404     }
3405   }
3406 
3407   // Note that the HasTransformStyle() != aNewData.HasTransformStyle()
3408   // test above handles relevant changes in the
3409   // NS_STYLE_WILL_CHANGE_TRANSFORM bit, which in turn handles frame
3410   // reconstruction for changes in the containing block of
3411   // fixed-positioned elements.
3412   uint8_t willChangeBitsChanged =
3413     mWillChangeBitField ^ aNewData.mWillChangeBitField;
3414   if (willChangeBitsChanged & (NS_STYLE_WILL_CHANGE_STACKING_CONTEXT |
3415                                NS_STYLE_WILL_CHANGE_SCROLL |
3416                                NS_STYLE_WILL_CHANGE_OPACITY)) {
3417     hint |= nsChangeHint_RepaintFrame;
3418   }
3419 
3420   if (willChangeBitsChanged & NS_STYLE_WILL_CHANGE_FIXPOS_CB) {
3421     hint |= nsChangeHint_UpdateContainingBlock;
3422   }
3423 
3424   // If touch-action is changed, we need to regenerate the event regions on
3425   // the layers and send it over to the compositor for APZ to handle.
3426   if (mTouchAction != aNewData.mTouchAction) {
3427     hint |= nsChangeHint_RepaintFrame;
3428   }
3429 
3430   // Note:  Our current behavior for handling changes to the
3431   // transition-duration, transition-delay, and transition-timing-function
3432   // properties is to do nothing.  In other words, the transition
3433   // property that matters is what it is when the transition begins, and
3434   // we don't stop a transition later because the transition property
3435   // changed.
3436   // We do handle changes to transition-property, but we don't need to
3437   // bother with anything here, since the transition manager is notified
3438   // of any style context change anyway.
3439 
3440   // Note: Likewise, for animation-*, the animation manager gets
3441   // notified about every new style context constructed, and it uses
3442   // that opportunity to handle dynamic changes appropriately.
3443 
3444   // But we still need to return nsChangeHint_NeutralChange for these
3445   // properties, since some data did change in the style struct.
3446 
3447   if (!hint &&
3448       (mOriginalDisplay != aNewData.mOriginalDisplay ||
3449        mOriginalFloat != aNewData.mOriginalFloat ||
3450        mTransitions != aNewData.mTransitions ||
3451        mTransitionTimingFunctionCount !=
3452          aNewData.mTransitionTimingFunctionCount ||
3453        mTransitionDurationCount != aNewData.mTransitionDurationCount ||
3454        mTransitionDelayCount != aNewData.mTransitionDelayCount ||
3455        mTransitionPropertyCount != aNewData.mTransitionPropertyCount ||
3456        mAnimations != aNewData.mAnimations ||
3457        mAnimationTimingFunctionCount != aNewData.mAnimationTimingFunctionCount ||
3458        mAnimationDurationCount != aNewData.mAnimationDurationCount ||
3459        mAnimationDelayCount != aNewData.mAnimationDelayCount ||
3460        mAnimationNameCount != aNewData.mAnimationNameCount ||
3461        mAnimationDirectionCount != aNewData.mAnimationDirectionCount ||
3462        mAnimationFillModeCount != aNewData.mAnimationFillModeCount ||
3463        mAnimationPlayStateCount != aNewData.mAnimationPlayStateCount ||
3464        mAnimationIterationCountCount != aNewData.mAnimationIterationCountCount ||
3465        mScrollSnapCoordinate != aNewData.mScrollSnapCoordinate ||
3466        mShapeOutside != aNewData.mShapeOutside)) {
3467     hint |= nsChangeHint_NeutralChange;
3468   }
3469 
3470   return hint;
3471 }
3472 
3473 // --------------------
3474 // nsStyleVisibility
3475 //
3476 
nsStyleVisibility(StyleStructContext aContext)3477 nsStyleVisibility::nsStyleVisibility(StyleStructContext aContext)
3478   : mDirection(aContext.GetBidi() == IBMBIDI_TEXTDIRECTION_RTL
3479                  ? NS_STYLE_DIRECTION_RTL
3480                  : NS_STYLE_DIRECTION_LTR)
3481   , mVisible(NS_STYLE_VISIBILITY_VISIBLE)
3482   , mImageRendering(NS_STYLE_IMAGE_RENDERING_AUTO)
3483   , mWritingMode(NS_STYLE_WRITING_MODE_HORIZONTAL_TB)
3484   , mTextOrientation(NS_STYLE_TEXT_ORIENTATION_MIXED)
3485   , mColorAdjust(NS_STYLE_COLOR_ADJUST_ECONOMY)
3486 {
3487   MOZ_COUNT_CTOR(nsStyleVisibility);
3488 }
3489 
nsStyleVisibility(const nsStyleVisibility & aSource)3490 nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource)
3491   : mImageOrientation(aSource.mImageOrientation)
3492   , mDirection(aSource.mDirection)
3493   , mVisible(aSource.mVisible)
3494   , mImageRendering(aSource.mImageRendering)
3495   , mWritingMode(aSource.mWritingMode)
3496   , mTextOrientation(aSource.mTextOrientation)
3497   , mColorAdjust(aSource.mColorAdjust)
3498 {
3499   MOZ_COUNT_CTOR(nsStyleVisibility);
3500 }
3501 
3502 nsChangeHint
CalcDifference(const nsStyleVisibility & aNewData) const3503 nsStyleVisibility::CalcDifference(const nsStyleVisibility& aNewData) const
3504 {
3505   nsChangeHint hint = nsChangeHint(0);
3506 
3507   if (mDirection != aNewData.mDirection || mWritingMode != aNewData.mWritingMode) {
3508     // It's important that a change in mWritingMode results in frame
3509     // reconstruction, because it may affect intrinsic size (see
3510     // nsSubDocumentFrame::GetIntrinsicISize/BSize).
3511     hint |= nsChangeHint_ReconstructFrame;
3512   } else {
3513     if ((mImageOrientation != aNewData.mImageOrientation)) {
3514       hint |= nsChangeHint_AllReflowHints |
3515               nsChangeHint_RepaintFrame;
3516     }
3517     if (mVisible != aNewData.mVisible) {
3518       if ((NS_STYLE_VISIBILITY_COLLAPSE == mVisible) ||
3519           (NS_STYLE_VISIBILITY_COLLAPSE == aNewData.mVisible)) {
3520         hint |= NS_STYLE_HINT_REFLOW;
3521       } else {
3522         hint |= NS_STYLE_HINT_VISUAL;
3523       }
3524     }
3525     if (mTextOrientation != aNewData.mTextOrientation) {
3526       hint |= NS_STYLE_HINT_REFLOW;
3527     }
3528     if (mImageRendering != aNewData.mImageRendering) {
3529       hint |= nsChangeHint_RepaintFrame;
3530     }
3531     if (mColorAdjust != aNewData.mColorAdjust) {
3532       // color-adjust only affects media where dynamic changes can't happen.
3533       hint |= nsChangeHint_NeutralChange;
3534     }
3535   }
3536   return hint;
3537 }
3538 
~nsStyleContentData()3539 nsStyleContentData::~nsStyleContentData()
3540 {
3541   MOZ_COUNT_DTOR(nsStyleContentData);
3542   MOZ_ASSERT(!mImageTracked,
3543              "nsStyleContentData being destroyed while still tracking image!");
3544   if (mType == eStyleContentType_Image) {
3545     NS_IF_RELEASE(mContent.mImage);
3546   } else if (mType == eStyleContentType_Counter ||
3547              mType == eStyleContentType_Counters) {
3548     mContent.mCounters->Release();
3549   } else if (mContent.mString) {
3550     free(mContent.mString);
3551   }
3552 }
3553 
nsStyleContentData(const nsStyleContentData & aOther)3554 nsStyleContentData::nsStyleContentData(const nsStyleContentData& aOther)
3555   : mType(aOther.mType)
3556 #ifdef DEBUG
3557   , mImageTracked(false)
3558 #endif
3559 {
3560   MOZ_COUNT_CTOR(nsStyleContentData);
3561   if (mType == eStyleContentType_Image) {
3562     mContent.mImage = aOther.mContent.mImage;
3563     NS_IF_ADDREF(mContent.mImage);
3564   } else if (mType == eStyleContentType_Counter ||
3565              mType == eStyleContentType_Counters) {
3566     mContent.mCounters = aOther.mContent.mCounters;
3567     mContent.mCounters->AddRef();
3568   } else if (aOther.mContent.mString) {
3569     mContent.mString = NS_strdup(aOther.mContent.mString);
3570   } else {
3571     mContent.mString = nullptr;
3572   }
3573 }
3574 
3575 nsStyleContentData&
operator =(const nsStyleContentData & aOther)3576 nsStyleContentData::operator=(const nsStyleContentData& aOther)
3577 {
3578   if (this == &aOther) {
3579     return *this;
3580   }
3581   this->~nsStyleContentData();
3582   new (this) nsStyleContentData(aOther);
3583 
3584   return *this;
3585 }
3586 
3587 bool
operator ==(const nsStyleContentData & aOther) const3588 nsStyleContentData::operator==(const nsStyleContentData& aOther) const
3589 {
3590   if (mType != aOther.mType) {
3591     return false;
3592   }
3593   if (mType == eStyleContentType_Image) {
3594     if (!mContent.mImage || !aOther.mContent.mImage) {
3595       return mContent.mImage == aOther.mContent.mImage;
3596     }
3597     bool eq;
3598     nsCOMPtr<nsIURI> thisURI, otherURI;
3599     mContent.mImage->GetURI(getter_AddRefs(thisURI));
3600     aOther.mContent.mImage->GetURI(getter_AddRefs(otherURI));
3601     return thisURI == otherURI ||  // handles null==null
3602            (thisURI && otherURI &&
3603             NS_SUCCEEDED(thisURI->Equals(otherURI, &eq)) &&
3604             eq);
3605   }
3606   if (mType == eStyleContentType_Counter ||
3607       mType == eStyleContentType_Counters) {
3608     return *mContent.mCounters == *aOther.mContent.mCounters;
3609   }
3610   return safe_strcmp(mContent.mString, aOther.mContent.mString) == 0;
3611 }
3612 
3613 void
TrackImage(ImageTracker * aImageTracker)3614 nsStyleContentData::TrackImage(ImageTracker* aImageTracker)
3615 {
3616   // Sanity
3617   MOZ_ASSERT(!mImageTracked, "Already tracking image!");
3618   MOZ_ASSERT(mType == eStyleContentType_Image,
3619              "Trying to do image tracking on non-image!");
3620   MOZ_ASSERT(mContent.mImage,
3621              "Can't track image when there isn't one!");
3622 
3623   aImageTracker->Add(mContent.mImage);
3624 
3625   // Mark state
3626 #ifdef DEBUG
3627   mImageTracked = true;
3628 #endif
3629 }
3630 
3631 void
UntrackImage(ImageTracker * aImageTracker)3632 nsStyleContentData::UntrackImage(ImageTracker* aImageTracker)
3633 {
3634   // Sanity
3635   MOZ_ASSERT(mImageTracked, "Image not tracked!");
3636   MOZ_ASSERT(mType == eStyleContentType_Image,
3637              "Trying to do image tracking on non-image!");
3638   MOZ_ASSERT(mContent.mImage,
3639              "Can't untrack image when there isn't one!");
3640 
3641   aImageTracker->Remove(mContent.mImage);
3642 
3643   // Mark state
3644 #ifdef DEBUG
3645   mImageTracked = false;
3646 #endif
3647 }
3648 
3649 
3650 //-----------------------
3651 // nsStyleContent
3652 //
3653 
nsStyleContent(StyleStructContext aContext)3654 nsStyleContent::nsStyleContent(StyleStructContext aContext)
3655 {
3656   MOZ_COUNT_CTOR(nsStyleContent);
3657 }
3658 
~nsStyleContent()3659 nsStyleContent::~nsStyleContent()
3660 {
3661   MOZ_COUNT_DTOR(nsStyleContent);
3662 }
3663 
3664 void
Destroy(nsPresContext * aContext)3665 nsStyleContent::Destroy(nsPresContext* aContext)
3666 {
3667   // Unregister any images we might have with the document.
3668   for (auto& content : mContents) {
3669     if (content.mType == eStyleContentType_Image && content.mContent.mImage) {
3670       content.UntrackImage(aContext->Document()->ImageTracker());
3671     }
3672   }
3673 
3674   this->~nsStyleContent();
3675   aContext->PresShell()->FreeByObjectID(eArenaObjectID_nsStyleContent, this);
3676 }
3677 
nsStyleContent(const nsStyleContent & aSource)3678 nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
3679   : mContents(aSource.mContents)
3680   , mIncrements(aSource.mIncrements)
3681   , mResets(aSource.mResets)
3682 {
3683   MOZ_COUNT_CTOR(nsStyleContent);
3684 }
3685 
3686 nsChangeHint
CalcDifference(const nsStyleContent & aNewData) const3687 nsStyleContent::CalcDifference(const nsStyleContent& aNewData) const
3688 {
3689   // In ElementRestyler::Restyle we assume that if there's no existing
3690   // ::before or ::after and we don't have to restyle children of the
3691   // node then we can't end up with a ::before or ::after due to the
3692   // restyle of the node itself.  That's not quite true, but the only
3693   // exception to the above is when the 'content' property of the node
3694   // changes and the pseudo-element inherits the changed value.  Since
3695   // the code here triggers a frame change on the node in that case,
3696   // the optimization in ElementRestyler::Restyle is ok.  But if we ever
3697   // change this code to not reconstruct frames on changes to the
3698   // 'content' property, then we will need to revisit the optimization
3699   // in ElementRestyler::Restyle.
3700 
3701   // Unfortunately we need to reframe even if the content lengths are the same;
3702   // a simple reflow will not pick up different text or different image URLs,
3703   // since we set all that up in the CSSFrameConstructor
3704   if (mContents != aNewData.mContents ||
3705       mIncrements != aNewData.mIncrements ||
3706       mResets != aNewData.mResets) {
3707     return nsChangeHint_ReconstructFrame;
3708   }
3709 
3710   return nsChangeHint(0);
3711 }
3712 
3713 // --------------------
3714 // nsStyleTextReset
3715 //
3716 
nsStyleTextReset(StyleStructContext aContext)3717 nsStyleTextReset::nsStyleTextReset(StyleStructContext aContext)
3718   : mTextDecorationLine(NS_STYLE_TEXT_DECORATION_LINE_NONE)
3719   , mTextDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID)
3720   , mUnicodeBidi(NS_STYLE_UNICODE_BIDI_NORMAL)
3721   , mInitialLetterSink(0)
3722   , mInitialLetterSize(0.0f)
3723   , mTextDecorationColor(StyleComplexColor::CurrentColor())
3724 {
3725   MOZ_COUNT_CTOR(nsStyleTextReset);
3726 }
3727 
nsStyleTextReset(const nsStyleTextReset & aSource)3728 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
3729 {
3730   MOZ_COUNT_CTOR(nsStyleTextReset);
3731   *this = aSource;
3732 }
3733 
~nsStyleTextReset()3734 nsStyleTextReset::~nsStyleTextReset()
3735 {
3736   MOZ_COUNT_DTOR(nsStyleTextReset);
3737 }
3738 
3739 nsChangeHint
CalcDifference(const nsStyleTextReset & aNewData) const3740 nsStyleTextReset::CalcDifference(const nsStyleTextReset& aNewData) const
3741 {
3742   if (mUnicodeBidi != aNewData.mUnicodeBidi ||
3743       mInitialLetterSink != aNewData.mInitialLetterSink ||
3744       mInitialLetterSize != aNewData.mInitialLetterSize) {
3745     return NS_STYLE_HINT_REFLOW;
3746   }
3747 
3748   if (mTextDecorationLine != aNewData.mTextDecorationLine ||
3749       mTextDecorationStyle != aNewData.mTextDecorationStyle) {
3750     // Changes to our text-decoration line can impact our overflow area &
3751     // also our descendants' overflow areas (particularly for text-frame
3752     // descendants).  So, we update those areas & trigger a repaint.
3753     return nsChangeHint_RepaintFrame |
3754            nsChangeHint_UpdateSubtreeOverflow |
3755            nsChangeHint_SchedulePaint;
3756   }
3757 
3758   // Repaint for decoration color changes
3759   if (mTextDecorationColor != aNewData.mTextDecorationColor) {
3760     return nsChangeHint_RepaintFrame;
3761   }
3762 
3763   if (mTextOverflow != aNewData.mTextOverflow) {
3764     return nsChangeHint_RepaintFrame;
3765   }
3766 
3767   return nsChangeHint(0);
3768 }
3769 
3770 // Returns true if the given shadow-arrays are equal.
3771 static bool
AreShadowArraysEqual(nsCSSShadowArray * lhs,nsCSSShadowArray * rhs)3772 AreShadowArraysEqual(nsCSSShadowArray* lhs,
3773                      nsCSSShadowArray* rhs)
3774 {
3775   if (lhs == rhs) {
3776     return true;
3777   }
3778 
3779   if (!lhs || !rhs || lhs->Length() != rhs->Length()) {
3780     return false;
3781   }
3782 
3783   for (uint32_t i = 0; i < lhs->Length(); ++i) {
3784     if (*lhs->ShadowAt(i) != *rhs->ShadowAt(i)) {
3785       return false;
3786     }
3787   }
3788   return true;
3789 }
3790 
3791 // --------------------
3792 // nsStyleText
3793 //
3794 
nsStyleText(StyleStructContext aContext)3795 nsStyleText::nsStyleText(StyleStructContext aContext)
3796   : mTextAlign(NS_STYLE_TEXT_ALIGN_START)
3797   , mTextAlignLast(NS_STYLE_TEXT_ALIGN_AUTO)
3798   , mTextAlignTrue(false)
3799   , mTextAlignLastTrue(false)
3800   , mTextTransform(NS_STYLE_TEXT_TRANSFORM_NONE)
3801   , mWhiteSpace(NS_STYLE_WHITESPACE_NORMAL)
3802   , mWordBreak(NS_STYLE_WORDBREAK_NORMAL)
3803   , mOverflowWrap(NS_STYLE_OVERFLOWWRAP_NORMAL)
3804   , mHyphens(NS_STYLE_HYPHENS_MANUAL)
3805   , mRubyAlign(NS_STYLE_RUBY_ALIGN_SPACE_AROUND)
3806   , mRubyPosition(NS_STYLE_RUBY_POSITION_OVER)
3807   , mTextSizeAdjust(NS_STYLE_TEXT_SIZE_ADJUST_AUTO)
3808   , mTextCombineUpright(NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE)
3809   , mControlCharacterVisibility(nsCSSParser::ControlCharVisibilityDefault())
3810   , mTextEmphasisStyle(NS_STYLE_TEXT_EMPHASIS_STYLE_NONE)
3811   , mTextRendering(NS_STYLE_TEXT_RENDERING_AUTO)
3812   , mTabSize(NS_STYLE_TABSIZE_INITIAL)
3813   , mTextEmphasisColor(StyleComplexColor::CurrentColor())
3814   , mWebkitTextFillColor(StyleComplexColor::CurrentColor())
3815   , mWebkitTextStrokeColor(StyleComplexColor::CurrentColor())
3816   , mWordSpacing(0, nsStyleCoord::CoordConstructor)
3817   , mLetterSpacing(eStyleUnit_Normal)
3818   , mLineHeight(eStyleUnit_Normal)
3819   , mTextIndent(0, nsStyleCoord::CoordConstructor)
3820   , mWebkitTextStrokeWidth(0, nsStyleCoord::CoordConstructor)
3821   , mTextShadow(nullptr)
3822 {
3823   MOZ_COUNT_CTOR(nsStyleText);
3824   nsCOMPtr<nsIAtom> language = aContext.GetContentLanguage();
3825   mTextEmphasisPosition = language &&
3826     nsStyleUtil::MatchesLanguagePrefix(language, u"zh") ?
3827     NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT_ZH :
3828     NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT;
3829 }
3830 
nsStyleText(const nsStyleText & aSource)3831 nsStyleText::nsStyleText(const nsStyleText& aSource)
3832   : mTextAlign(aSource.mTextAlign)
3833   , mTextAlignLast(aSource.mTextAlignLast)
3834   , mTextAlignTrue(false)
3835   , mTextAlignLastTrue(false)
3836   , mTextTransform(aSource.mTextTransform)
3837   , mWhiteSpace(aSource.mWhiteSpace)
3838   , mWordBreak(aSource.mWordBreak)
3839   , mOverflowWrap(aSource.mOverflowWrap)
3840   , mHyphens(aSource.mHyphens)
3841   , mRubyAlign(aSource.mRubyAlign)
3842   , mRubyPosition(aSource.mRubyPosition)
3843   , mTextSizeAdjust(aSource.mTextSizeAdjust)
3844   , mTextCombineUpright(aSource.mTextCombineUpright)
3845   , mControlCharacterVisibility(aSource.mControlCharacterVisibility)
3846   , mTextEmphasisPosition(aSource.mTextEmphasisPosition)
3847   , mTextEmphasisStyle(aSource.mTextEmphasisStyle)
3848   , mTextRendering(aSource.mTextRendering)
3849   , mTabSize(aSource.mTabSize)
3850   , mTextEmphasisColor(aSource.mTextEmphasisColor)
3851   , mWebkitTextFillColor(aSource.mWebkitTextFillColor)
3852   , mWebkitTextStrokeColor(aSource.mWebkitTextStrokeColor)
3853   , mWordSpacing(aSource.mWordSpacing)
3854   , mLetterSpacing(aSource.mLetterSpacing)
3855   , mLineHeight(aSource.mLineHeight)
3856   , mTextIndent(aSource.mTextIndent)
3857   , mWebkitTextStrokeWidth(aSource.mWebkitTextStrokeWidth)
3858   , mTextShadow(aSource.mTextShadow)
3859   , mTextEmphasisStyleString(aSource.mTextEmphasisStyleString)
3860 {
3861   MOZ_COUNT_CTOR(nsStyleText);
3862 }
3863 
~nsStyleText()3864 nsStyleText::~nsStyleText()
3865 {
3866   MOZ_COUNT_DTOR(nsStyleText);
3867 }
3868 
3869 nsChangeHint
CalcDifference(const nsStyleText & aNewData) const3870 nsStyleText::CalcDifference(const nsStyleText& aNewData) const
3871 {
3872   if (WhiteSpaceOrNewlineIsSignificant() !=
3873       aNewData.WhiteSpaceOrNewlineIsSignificant()) {
3874     // This may require construction of suppressed text frames
3875     return nsChangeHint_ReconstructFrame;
3876   }
3877 
3878   if (mTextCombineUpright != aNewData.mTextCombineUpright ||
3879       mControlCharacterVisibility != aNewData.mControlCharacterVisibility) {
3880     return nsChangeHint_ReconstructFrame;
3881   }
3882 
3883   if ((mTextAlign != aNewData.mTextAlign) ||
3884       (mTextAlignLast != aNewData.mTextAlignLast) ||
3885       (mTextAlignTrue != aNewData.mTextAlignTrue) ||
3886       (mTextAlignLastTrue != aNewData.mTextAlignLastTrue) ||
3887       (mTextTransform != aNewData.mTextTransform) ||
3888       (mWhiteSpace != aNewData.mWhiteSpace) ||
3889       (mWordBreak != aNewData.mWordBreak) ||
3890       (mOverflowWrap != aNewData.mOverflowWrap) ||
3891       (mHyphens != aNewData.mHyphens) ||
3892       (mRubyAlign != aNewData.mRubyAlign) ||
3893       (mRubyPosition != aNewData.mRubyPosition) ||
3894       (mTextSizeAdjust != aNewData.mTextSizeAdjust) ||
3895       (mLetterSpacing != aNewData.mLetterSpacing) ||
3896       (mLineHeight != aNewData.mLineHeight) ||
3897       (mTextIndent != aNewData.mTextIndent) ||
3898       (mWordSpacing != aNewData.mWordSpacing) ||
3899       (mTabSize != aNewData.mTabSize)) {
3900     return NS_STYLE_HINT_REFLOW;
3901   }
3902 
3903   if (HasTextEmphasis() != aNewData.HasTextEmphasis() ||
3904       (HasTextEmphasis() &&
3905        mTextEmphasisPosition != aNewData.mTextEmphasisPosition)) {
3906     // Text emphasis position change could affect line height calculation.
3907     return nsChangeHint_AllReflowHints |
3908            nsChangeHint_RepaintFrame;
3909   }
3910 
3911   nsChangeHint hint = nsChangeHint(0);
3912 
3913   // text-rendering changes require a reflow since they change SVG
3914   // frames' rects.
3915   if (mTextRendering != aNewData.mTextRendering) {
3916     hint |= nsChangeHint_NeedReflow |
3917             nsChangeHint_NeedDirtyReflow | // XXX remove me: bug 876085
3918             nsChangeHint_RepaintFrame;
3919   }
3920 
3921   if (!AreShadowArraysEqual(mTextShadow, aNewData.mTextShadow) ||
3922       mTextEmphasisStyle != aNewData.mTextEmphasisStyle ||
3923       mTextEmphasisStyleString != aNewData.mTextEmphasisStyleString ||
3924       mWebkitTextStrokeWidth != aNewData.mWebkitTextStrokeWidth) {
3925     hint |= nsChangeHint_UpdateSubtreeOverflow |
3926             nsChangeHint_SchedulePaint |
3927             nsChangeHint_RepaintFrame;
3928 
3929     // We don't add any other hints below.
3930     return hint;
3931   }
3932 
3933   if (mTextEmphasisColor != aNewData.mTextEmphasisColor ||
3934       mWebkitTextFillColor != aNewData.mWebkitTextFillColor ||
3935       mWebkitTextStrokeColor != aNewData.mWebkitTextStrokeColor) {
3936     hint |= nsChangeHint_SchedulePaint |
3937             nsChangeHint_RepaintFrame;
3938   }
3939 
3940   if (hint) {
3941     return hint;
3942   }
3943 
3944   if (mTextEmphasisPosition != aNewData.mTextEmphasisPosition) {
3945     return nsChangeHint_NeutralChange;
3946   }
3947 
3948   return nsChangeHint(0);
3949 }
3950 
3951 LogicalSide
TextEmphasisSide(WritingMode aWM) const3952 nsStyleText::TextEmphasisSide(WritingMode aWM) const
3953 {
3954   MOZ_ASSERT(
3955     (!(mTextEmphasisPosition & NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT) !=
3956      !(mTextEmphasisPosition & NS_STYLE_TEXT_EMPHASIS_POSITION_RIGHT)) &&
3957     (!(mTextEmphasisPosition & NS_STYLE_TEXT_EMPHASIS_POSITION_OVER) !=
3958      !(mTextEmphasisPosition & NS_STYLE_TEXT_EMPHASIS_POSITION_UNDER)));
3959   mozilla::Side side = aWM.IsVertical() ?
3960     (mTextEmphasisPosition & NS_STYLE_TEXT_EMPHASIS_POSITION_LEFT
3961      ? eSideLeft : eSideRight) :
3962     (mTextEmphasisPosition & NS_STYLE_TEXT_EMPHASIS_POSITION_OVER
3963      ? eSideTop : eSideBottom);
3964   LogicalSide result = aWM.LogicalSideForPhysicalSide(side);
3965   MOZ_ASSERT(IsBlock(result));
3966   return result;
3967 }
3968 
3969 //-----------------------
3970 // nsStyleUserInterface
3971 //
3972 
nsCursorImage()3973 nsCursorImage::nsCursorImage()
3974   : mHaveHotspot(false)
3975   , mHotspotX(0.0f)
3976   , mHotspotY(0.0f)
3977 {
3978 }
3979 
nsCursorImage(const nsCursorImage & aOther)3980 nsCursorImage::nsCursorImage(const nsCursorImage& aOther)
3981   : mHaveHotspot(aOther.mHaveHotspot)
3982   , mHotspotX(aOther.mHotspotX)
3983   , mHotspotY(aOther.mHotspotY)
3984 {
3985   SetImage(aOther.GetImage());
3986 }
3987 
~nsCursorImage()3988 nsCursorImage::~nsCursorImage()
3989 {
3990   SetImage(nullptr);
3991 }
3992 
3993 nsCursorImage&
operator =(const nsCursorImage & aOther)3994 nsCursorImage::operator=(const nsCursorImage& aOther)
3995 {
3996   if (this != &aOther) {
3997     mHaveHotspot = aOther.mHaveHotspot;
3998     mHotspotX = aOther.mHotspotX;
3999     mHotspotY = aOther.mHotspotY;
4000     SetImage(aOther.GetImage());
4001   }
4002 
4003   return *this;
4004 }
4005 
4006 bool
operator ==(const nsCursorImage & aOther) const4007 nsCursorImage::operator==(const nsCursorImage& aOther) const
4008 {
4009   NS_ASSERTION(mHaveHotspot ||
4010                (mHotspotX == 0 && mHotspotY == 0),
4011                "expected mHotspot{X,Y} to be 0 when mHaveHotspot is false");
4012   NS_ASSERTION(aOther.mHaveHotspot ||
4013                (aOther.mHotspotX == 0 && aOther.mHotspotY == 0),
4014                "expected mHotspot{X,Y} to be 0 when mHaveHotspot is false");
4015   return mHaveHotspot == aOther.mHaveHotspot &&
4016          mHotspotX == aOther.mHotspotX &&
4017          mHotspotY == aOther.mHotspotY &&
4018          EqualImages(mImage, aOther.mImage);
4019 }
4020 
nsStyleUserInterface(StyleStructContext aContext)4021 nsStyleUserInterface::nsStyleUserInterface(StyleStructContext aContext)
4022   : mUserInput(StyleUserInput::Auto)
4023   , mUserModify(StyleUserModify::ReadOnly)
4024   , mUserFocus(StyleUserFocus::None)
4025   , mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO)
4026   , mCursor(NS_STYLE_CURSOR_AUTO)
4027 {
4028   MOZ_COUNT_CTOR(nsStyleUserInterface);
4029 }
4030 
nsStyleUserInterface(const nsStyleUserInterface & aSource)4031 nsStyleUserInterface::nsStyleUserInterface(const nsStyleUserInterface& aSource)
4032   : mUserInput(aSource.mUserInput)
4033   , mUserModify(aSource.mUserModify)
4034   , mUserFocus(aSource.mUserFocus)
4035   , mPointerEvents(aSource.mPointerEvents)
4036   , mCursor(aSource.mCursor)
4037   , mCursorImages(aSource.mCursorImages)
4038 {
4039   MOZ_COUNT_CTOR(nsStyleUserInterface);
4040 }
4041 
~nsStyleUserInterface()4042 nsStyleUserInterface::~nsStyleUserInterface()
4043 {
4044   MOZ_COUNT_DTOR(nsStyleUserInterface);
4045 }
4046 
4047 nsChangeHint
CalcDifference(const nsStyleUserInterface & aNewData) const4048 nsStyleUserInterface::CalcDifference(const nsStyleUserInterface& aNewData) const
4049 {
4050   nsChangeHint hint = nsChangeHint(0);
4051   if (mCursor != aNewData.mCursor) {
4052     hint |= nsChangeHint_UpdateCursor;
4053   }
4054 
4055   // We could do better. But it wouldn't be worth it, URL-specified cursors are
4056   // rare.
4057   if (mCursorImages != aNewData.mCursorImages) {
4058     hint |= nsChangeHint_UpdateCursor;
4059   }
4060 
4061   if (mPointerEvents != aNewData.mPointerEvents) {
4062     // nsSVGPathGeometryFrame's mRect depends on stroke _and_ on the value
4063     // of pointer-events. See nsSVGPathGeometryFrame::ReflowSVG's use of
4064     // GetHitTestFlags. (Only a reflow, no visual change.)
4065     hint |= nsChangeHint_NeedReflow |
4066             nsChangeHint_NeedDirtyReflow; // XXX remove me: bug 876085
4067   }
4068 
4069   if (mUserModify != aNewData.mUserModify) {
4070     hint |= NS_STYLE_HINT_VISUAL;
4071   }
4072 
4073   if (mUserInput != aNewData.mUserInput) {
4074     if (StyleUserInput::None == mUserInput ||
4075         StyleUserInput::None == aNewData.mUserInput) {
4076       hint |= nsChangeHint_ReconstructFrame;
4077     } else {
4078       hint |= nsChangeHint_NeutralChange;
4079     }
4080   }
4081 
4082   if (mUserFocus != aNewData.mUserFocus) {
4083     hint |= nsChangeHint_NeutralChange;
4084   }
4085 
4086   return hint;
4087 }
4088 
4089 //-----------------------
4090 // nsStyleUIReset
4091 //
4092 
nsStyleUIReset(StyleStructContext aContext)4093 nsStyleUIReset::nsStyleUIReset(StyleStructContext aContext)
4094   : mUserSelect(StyleUserSelect::Auto)
4095   , mForceBrokenImageIcon(0)
4096   , mIMEMode(NS_STYLE_IME_MODE_AUTO)
4097   , mWindowDragging(StyleWindowDragging::Default)
4098   , mWindowShadow(NS_STYLE_WINDOW_SHADOW_DEFAULT)
4099 {
4100   MOZ_COUNT_CTOR(nsStyleUIReset);
4101 }
4102 
nsStyleUIReset(const nsStyleUIReset & aSource)4103 nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
4104   : mUserSelect(aSource.mUserSelect)
4105   , mForceBrokenImageIcon(aSource.mForceBrokenImageIcon)
4106   , mIMEMode(aSource.mIMEMode)
4107   , mWindowDragging(aSource.mWindowDragging)
4108   , mWindowShadow(aSource.mWindowShadow)
4109 {
4110   MOZ_COUNT_CTOR(nsStyleUIReset);
4111 }
4112 
~nsStyleUIReset()4113 nsStyleUIReset::~nsStyleUIReset()
4114 {
4115   MOZ_COUNT_DTOR(nsStyleUIReset);
4116 }
4117 
4118 nsChangeHint
CalcDifference(const nsStyleUIReset & aNewData) const4119 nsStyleUIReset::CalcDifference(const nsStyleUIReset& aNewData) const
4120 {
4121   // ignore mIMEMode
4122   if (mForceBrokenImageIcon != aNewData.mForceBrokenImageIcon) {
4123     return nsChangeHint_ReconstructFrame;
4124   }
4125   if (mWindowShadow != aNewData.mWindowShadow) {
4126     // We really need just an nsChangeHint_SyncFrameView, except
4127     // on an ancestor of the frame, so we get that by doing a
4128     // reflow.
4129     return NS_STYLE_HINT_REFLOW;
4130   }
4131   if (mUserSelect != aNewData.mUserSelect) {
4132     return NS_STYLE_HINT_VISUAL;
4133   }
4134 
4135   if (mWindowDragging != aNewData.mWindowDragging) {
4136     return nsChangeHint_SchedulePaint;
4137   }
4138 
4139   return nsChangeHint(0);
4140 }
4141 
4142 //-----------------------
4143 // nsStyleVariables
4144 //
4145 
nsStyleVariables(StyleStructContext aContext)4146 nsStyleVariables::nsStyleVariables(StyleStructContext aContext)
4147 {
4148   MOZ_COUNT_CTOR(nsStyleVariables);
4149 }
4150 
nsStyleVariables(const nsStyleVariables & aSource)4151 nsStyleVariables::nsStyleVariables(const nsStyleVariables& aSource)
4152   : mVariables(aSource.mVariables)
4153 {
4154   MOZ_COUNT_CTOR(nsStyleVariables);
4155 }
4156 
~nsStyleVariables()4157 nsStyleVariables::~nsStyleVariables()
4158 {
4159   MOZ_COUNT_DTOR(nsStyleVariables);
4160 }
4161 
4162 nsChangeHint
CalcDifference(const nsStyleVariables & aNewData) const4163 nsStyleVariables::CalcDifference(const nsStyleVariables& aNewData) const
4164 {
4165   return nsChangeHint(0);
4166 }
4167 
4168 //-----------------------
4169 // nsStyleEffects
4170 //
4171 
nsStyleEffects(StyleStructContext aContext)4172 nsStyleEffects::nsStyleEffects(StyleStructContext aContext)
4173   : mBoxShadow(nullptr)
4174   , mClip(0, 0, 0, 0)
4175   , mOpacity(1.0f)
4176   , mClipFlags(NS_STYLE_CLIP_AUTO)
4177   , mMixBlendMode(NS_STYLE_BLEND_NORMAL)
4178 {
4179   MOZ_COUNT_CTOR(nsStyleEffects);
4180 }
4181 
nsStyleEffects(const nsStyleEffects & aSource)4182 nsStyleEffects::nsStyleEffects(const nsStyleEffects& aSource)
4183   : mFilters(aSource.mFilters)
4184   , mBoxShadow(aSource.mBoxShadow)
4185   , mClip(aSource.mClip)
4186   , mOpacity(aSource.mOpacity)
4187   , mClipFlags(aSource.mClipFlags)
4188   , mMixBlendMode(aSource.mMixBlendMode)
4189 {
4190   MOZ_COUNT_CTOR(nsStyleEffects);
4191 }
4192 
~nsStyleEffects()4193 nsStyleEffects::~nsStyleEffects()
4194 {
4195   MOZ_COUNT_DTOR(nsStyleEffects);
4196 }
4197 
4198 nsChangeHint
CalcDifference(const nsStyleEffects & aNewData) const4199 nsStyleEffects::CalcDifference(const nsStyleEffects& aNewData) const
4200 {
4201   nsChangeHint hint = nsChangeHint(0);
4202 
4203   if (!AreShadowArraysEqual(mBoxShadow, aNewData.mBoxShadow)) {
4204     // Update overflow regions & trigger DLBI to be sure it's noticed.
4205     // Also request a repaint, since it's possible that only the color
4206     // of the shadow is changing (and UpdateOverflow/SchedulePaint won't
4207     // repaint for that, since they won't know what needs invalidating.)
4208     hint |= nsChangeHint_UpdateOverflow |
4209             nsChangeHint_SchedulePaint |
4210             nsChangeHint_RepaintFrame;
4211   }
4212 
4213   if (mClipFlags != aNewData.mClipFlags) {
4214     hint |= nsChangeHint_AllReflowHints |
4215             nsChangeHint_RepaintFrame;
4216   }
4217 
4218   if (!mClip.IsEqualInterior(aNewData.mClip)) {
4219     // If the clip has changed, we just need to update overflow areas. DLBI
4220     // will handle the invalidation.
4221     hint |= nsChangeHint_UpdateOverflow |
4222             nsChangeHint_SchedulePaint;
4223   }
4224 
4225   if (mOpacity != aNewData.mOpacity) {
4226     // If we're going from the optimized >=0.99 opacity value to 1.0 or back, then
4227     // repaint the frame because DLBI will not catch the invalidation.  Otherwise,
4228     // just update the opacity layer.
4229     if ((mOpacity >= 0.99f && mOpacity < 1.0f && aNewData.mOpacity == 1.0f) ||
4230         (aNewData.mOpacity >= 0.99f && aNewData.mOpacity < 1.0f && mOpacity == 1.0f)) {
4231       hint |= nsChangeHint_RepaintFrame;
4232     } else {
4233       hint |= nsChangeHint_UpdateOpacityLayer;
4234       if ((mOpacity == 1.0f) != (aNewData.mOpacity == 1.0f)) {
4235         hint |= nsChangeHint_UpdateUsesOpacity;
4236       }
4237     }
4238   }
4239 
4240   if (HasFilters() != aNewData.HasFilters()) {
4241     // A change from/to being a containing block for position:fixed.
4242     hint |= nsChangeHint_UpdateContainingBlock;
4243   }
4244 
4245   if (mFilters != aNewData.mFilters) {
4246     hint |= nsChangeHint_UpdateEffects |
4247             nsChangeHint_RepaintFrame |
4248             nsChangeHint_UpdateOverflow;
4249   }
4250 
4251   if (mMixBlendMode != aNewData.mMixBlendMode) {
4252     hint |= nsChangeHint_RepaintFrame;
4253   }
4254 
4255   if (!hint &&
4256       !mClip.IsEqualEdges(aNewData.mClip)) {
4257     hint |= nsChangeHint_NeutralChange;
4258   }
4259 
4260   return hint;
4261 }
4262