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