Bug 1839526 [wpt PR 40658] - Update wpt metadata, a=testonly
[gecko.git] / layout / style / nsStyleStruct.cpp
blobbb0c8d3939c305228c1199a403e0e4df417960be
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/. */
7 /*
8 * structs that contain the data provided by ComputedStyle, the
9 * internal API for computed style data for an element
12 #include "nsStyleStruct.h"
13 #include "nsStyleStructInlines.h"
14 #include "nsStyleConsts.h"
15 #include "nsString.h"
16 #include "nsPresContext.h"
17 #include "nsIWidget.h"
18 #include "nsCRTGlue.h"
19 #include "nsCSSProps.h"
20 #include "nsDeviceContext.h"
21 #include "nsStyleUtil.h"
22 #include "nsIURIMutator.h"
24 #include "nsCOMPtr.h"
26 #include "nsBidiUtils.h"
27 #include "nsLayoutUtils.h"
29 #include "imgIRequest.h"
30 #include "imgIContainer.h"
31 #include "CounterStyleManager.h"
33 #include "mozilla/dom/AnimationEffectBinding.h" // for PlaybackDirection
34 #include "mozilla/dom/BaseKeyframeTypesBinding.h" // for CompositeOperation
35 #include "mozilla/dom/DocGroup.h"
36 #include "mozilla/dom/ImageTracker.h"
37 #include "mozilla/CORSMode.h"
38 #include "mozilla/ClearOnShutdown.h"
39 #include "mozilla/GeckoBindings.h"
40 #include "mozilla/PreferenceSheet.h"
41 #include "mozilla/SchedulerGroup.h"
42 #include "mozilla/StaticPresData.h"
43 #include "mozilla/Likely.h"
44 #include "nsIURI.h"
45 #include "mozilla/dom/Document.h"
46 #include "mozilla/dom/DocumentInlines.h"
47 #include <algorithm>
48 #include "ImageLoader.h"
49 #include "mozilla/StaticPrefs_layout.h"
51 using namespace mozilla;
52 using namespace mozilla::dom;
54 static const nscoord kMediumBorderWidth = nsPresContext::CSSPixelsToAppUnits(3);
56 // We set the size limit of style structs to 504 bytes so that when they
57 // are allocated by Servo side with Arc, the total size doesn't exceed
58 // 512 bytes, which minimizes allocator slop.
59 static constexpr size_t kStyleStructSizeLimit = 504;
61 template <typename Struct, size_t Actual, size_t Limit>
62 struct AssertSizeIsLessThan {
63 static_assert(Actual == sizeof(Struct), "Bogus invocation");
64 static_assert(Actual <= Limit,
65 "Style struct became larger than the size limit");
66 static constexpr bool instantiate = true;
69 #define STYLE_STRUCT(name_) \
70 static_assert(AssertSizeIsLessThan<nsStyle##name_, sizeof(nsStyle##name_), \
71 kStyleStructSizeLimit>::instantiate, \
72 "");
73 #include "nsStyleStructList.h"
74 #undef STYLE_STRUCT
76 bool StyleCssUrlData::operator==(const StyleCssUrlData& aOther) const {
77 // This very intentionally avoids comparing LoadData and such.
78 const auto& extra = extra_data.get();
79 const auto& otherExtra = aOther.extra_data.get();
80 if (extra.BaseURI() != otherExtra.BaseURI() ||
81 extra.Principal() != otherExtra.Principal() ||
82 cors_mode != aOther.cors_mode) {
83 // NOTE(emilio): This does pointer comparison, but it's what URLValue used
84 // to do. That's ok though since this is only used for style struct diffing.
85 return false;
87 return serialization == aOther.serialization;
90 StyleLoadData::~StyleLoadData() { Gecko_LoadData_Drop(this); }
92 already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(nsIURI* aURI) const {
93 nsCOMPtr<nsIURI> result = GetURI();
94 if (result && IsLocalRef()) {
95 nsCString ref;
96 result->GetRef(ref);
98 nsresult rv = NS_MutateURI(aURI).SetRef(ref).Finalize(result);
100 if (NS_FAILED(rv)) {
101 // If setting the ref failed, just return the original URI.
102 result = aURI;
105 return result.forget();
108 already_AddRefed<nsIURI> StyleComputedUrl::ResolveLocalRef(
109 const nsIContent* aContent) const {
110 return ResolveLocalRef(aContent->GetBaseURI());
113 void StyleComputedUrl::ResolveImage(Document& aDocument,
114 const StyleComputedUrl* aOldImage) {
115 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
117 StyleLoadData& data = LoadData();
119 MOZ_ASSERT(!(data.flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE));
121 data.flags |= StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE;
123 MOZ_ASSERT(NS_IsMainThread());
125 // TODO(emilio, bug 1440442): This is a hackaround to avoid flickering due the
126 // lack of non-http image caching in imagelib (bug 1406134), which causes
127 // stuff like bug 1439285. Cleanest fix if that doesn't get fixed is bug
128 // 1440305, but that seems too risky, and a lot of work to do before 60.
130 // Once that's fixed, the "old style" argument to TriggerImageLoads can go
131 // away, and same for mSharedCount in the image loader and so on.
132 const bool reuseProxy = nsContentUtils::IsChromeDoc(&aDocument) &&
133 aOldImage && aOldImage->IsImageResolved() &&
134 *this == *aOldImage;
136 RefPtr<imgRequestProxy> request;
137 if (reuseProxy) {
138 request = aOldImage->LoadData().resolved_image;
139 if (request) {
140 css::ImageLoader::NoteSharedLoad(request);
142 } else {
143 request = css::ImageLoader::LoadImage(*this, aDocument);
146 if (!request) {
147 return;
150 data.resolved_image = request.forget().take();
152 // Boost priority now that we know the image is present in the ComputedStyle
153 // of some frame.
154 data.resolved_image->BoostPriority(imgIRequest::CATEGORY_FRAME_STYLE);
158 * Runnable to release the image request's mRequestProxy
159 * and mImageTracker on the main thread, and to perform
160 * any necessary unlocking and untracking of the image.
162 class StyleImageRequestCleanupTask final : public mozilla::Runnable {
163 public:
164 explicit StyleImageRequestCleanupTask(StyleLoadData& aData)
165 : mozilla::Runnable("StyleImageRequestCleanupTask"),
166 mRequestProxy(dont_AddRef(aData.resolved_image)) {
167 MOZ_ASSERT(mRequestProxy);
168 aData.resolved_image = nullptr;
171 NS_IMETHOD Run() final {
172 MOZ_ASSERT(NS_IsMainThread());
173 css::ImageLoader::UnloadImage(mRequestProxy);
174 return NS_OK;
177 protected:
178 virtual ~StyleImageRequestCleanupTask() {
179 MOZ_ASSERT(!mRequestProxy || NS_IsMainThread(),
180 "mRequestProxy destructor need to run on the main thread!");
183 private:
184 // Since we always dispatch this runnable to the main thread, these will be
185 // released on the main thread when the runnable itself is released.
186 RefPtr<imgRequestProxy> mRequestProxy;
189 // This is defined here for parallelism with LoadURI.
190 void Gecko_LoadData_Drop(StyleLoadData* aData) {
191 if (aData->resolved_image) {
192 // We want to dispatch this async to prevent reentrancy issues, as
193 // imgRequestProxy going away can destroy documents, etc, see bug 1677555.
194 auto task = MakeRefPtr<StyleImageRequestCleanupTask>(*aData);
195 SchedulerGroup::Dispatch(TaskCategory::Other, task.forget());
198 // URIs are safe to refcount from any thread.
199 NS_IF_RELEASE(aData->resolved_uri);
202 // --------------------
203 // nsStyleFont
205 nsStyleFont::nsStyleFont(const nsStyleFont& aSrc)
206 : mFont(aSrc.mFont),
207 mSize(aSrc.mSize),
208 mFontSizeFactor(aSrc.mFontSizeFactor),
209 mFontSizeOffset(aSrc.mFontSizeOffset),
210 mFontSizeKeyword(aSrc.mFontSizeKeyword),
211 mFontPalette(aSrc.mFontPalette),
212 mMathDepth(aSrc.mMathDepth),
213 mMathVariant(aSrc.mMathVariant),
214 mMathStyle(aSrc.mMathStyle),
215 mMinFontSizeRatio(aSrc.mMinFontSizeRatio),
216 mExplicitLanguage(aSrc.mExplicitLanguage),
217 mXTextScale(aSrc.mXTextScale),
218 mScriptUnconstrainedSize(aSrc.mScriptUnconstrainedSize),
219 mScriptMinSize(aSrc.mScriptMinSize),
220 mScriptSizeMultiplier(aSrc.mScriptSizeMultiplier),
221 mLanguage(aSrc.mLanguage) {
222 MOZ_COUNT_CTOR(nsStyleFont);
225 static StyleXTextScale InitialTextScale(const Document& aDoc) {
226 if (nsContentUtils::IsChromeDoc(&aDoc) ||
227 nsContentUtils::IsPDFJS(aDoc.NodePrincipal())) {
228 return StyleXTextScale::ZoomOnly;
230 return StyleXTextScale::All;
233 nsStyleFont::nsStyleFont(const Document& aDocument)
234 : mFont(*aDocument.GetFontPrefsForLang(nullptr)->GetDefaultFont(
235 StyleGenericFontFamily::None)),
236 mSize(ZoomText(aDocument, mFont.size)),
237 mFontSizeFactor(1.0),
238 mFontSizeOffset{0},
239 mFontSizeKeyword(StyleFontSizeKeyword::Medium),
240 mFontPalette(StyleFontPalette::Normal()),
241 mMathDepth(0),
242 mMathVariant(StyleMathVariant::None),
243 mMathStyle(StyleMathStyle::Normal),
244 mXTextScale(InitialTextScale(aDocument)),
245 mScriptUnconstrainedSize(mSize),
246 mScriptMinSize(Length::FromPixels(
247 CSSPixel::FromPoints(kMathMLDefaultScriptMinSizePt))),
248 mScriptSizeMultiplier(kMathMLDefaultScriptSizeMultiplier),
249 mLanguage(aDocument.GetLanguageForStyle()) {
250 MOZ_COUNT_CTOR(nsStyleFont);
251 MOZ_ASSERT(NS_IsMainThread());
252 mFont.family.is_initial = true;
253 mFont.size = mSize;
254 if (MinFontSizeEnabled()) {
255 const Length minimumFontSize =
256 aDocument.GetFontPrefsForLang(mLanguage)->mMinimumFontSize;
257 mFont.size = Length::FromPixels(
258 std::max(mSize.ToCSSPixels(), minimumFontSize.ToCSSPixels()));
262 nsChangeHint nsStyleFont::CalcDifference(const nsStyleFont& aNewData) const {
263 MOZ_ASSERT(mXTextScale == aNewData.mXTextScale,
264 "expected -x-text-scale to be the same on both nsStyleFonts");
265 if (mSize != aNewData.mSize || mLanguage != aNewData.mLanguage ||
266 mExplicitLanguage != aNewData.mExplicitLanguage ||
267 mMathVariant != aNewData.mMathVariant ||
268 mMathStyle != aNewData.mMathStyle ||
269 mMinFontSizeRatio != aNewData.mMinFontSizeRatio) {
270 return NS_STYLE_HINT_REFLOW;
273 switch (mFont.CalcDifference(aNewData.mFont)) {
274 case nsFont::MaxDifference::eLayoutAffecting:
275 return NS_STYLE_HINT_REFLOW;
277 case nsFont::MaxDifference::eVisual:
278 return NS_STYLE_HINT_VISUAL;
280 case nsFont::MaxDifference::eNone:
281 break;
284 if (mFontPalette != aNewData.mFontPalette) {
285 return NS_STYLE_HINT_VISUAL;
288 // XXX Should any of these cause a non-nsChangeHint_NeutralChange change?
289 if (mMathDepth != aNewData.mMathDepth ||
290 mScriptUnconstrainedSize != aNewData.mScriptUnconstrainedSize ||
291 mScriptMinSize != aNewData.mScriptMinSize ||
292 mScriptSizeMultiplier != aNewData.mScriptSizeMultiplier) {
293 return nsChangeHint_NeutralChange;
296 return nsChangeHint(0);
299 Length nsStyleFont::ZoomText(const Document& aDocument, Length aSize) {
300 if (auto* pc = aDocument.GetPresContext()) {
301 aSize.ScaleBy(pc->TextZoom());
303 return aSize;
306 template <typename T>
307 static StyleRect<T> StyleRectWithAllSides(const T& aSide) {
308 return {aSide, aSide, aSide, aSide};
311 nsStyleMargin::nsStyleMargin(const Document& aDocument)
312 : mMargin(StyleRectWithAllSides(
313 LengthPercentageOrAuto::LengthPercentage(LengthPercentage::Zero()))),
314 mScrollMargin(StyleRectWithAllSides(StyleLength{0.})),
315 mOverflowClipMargin(StyleLength::Zero()) {
316 MOZ_COUNT_CTOR(nsStyleMargin);
319 nsStyleMargin::nsStyleMargin(const nsStyleMargin& aSrc)
320 : mMargin(aSrc.mMargin),
321 mScrollMargin(aSrc.mScrollMargin),
322 mOverflowClipMargin(aSrc.mOverflowClipMargin) {
323 MOZ_COUNT_CTOR(nsStyleMargin);
326 nsChangeHint nsStyleMargin::CalcDifference(
327 const nsStyleMargin& aNewData) const {
328 nsChangeHint hint = nsChangeHint(0);
330 if (mMargin != aNewData.mMargin) {
331 // Margin differences can't affect descendant intrinsic sizes and
332 // don't need to force children to reflow.
333 hint |= nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition |
334 nsChangeHint_ClearAncestorIntrinsics;
337 if (mScrollMargin != aNewData.mScrollMargin) {
338 // FIXME: Bug 1530253 Support re-snapping when scroll-margin changes.
339 hint |= nsChangeHint_NeutralChange;
342 if (mOverflowClipMargin != aNewData.mOverflowClipMargin) {
343 hint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
346 return hint;
349 nsStylePadding::nsStylePadding(const Document& aDocument)
350 : mPadding(StyleRectWithAllSides(LengthPercentage::Zero())),
351 mScrollPadding(StyleRectWithAllSides(LengthPercentageOrAuto::Auto())) {
352 MOZ_COUNT_CTOR(nsStylePadding);
355 nsStylePadding::nsStylePadding(const nsStylePadding& aSrc)
356 : mPadding(aSrc.mPadding), mScrollPadding(aSrc.mScrollPadding) {
357 MOZ_COUNT_CTOR(nsStylePadding);
360 nsChangeHint nsStylePadding::CalcDifference(
361 const nsStylePadding& aNewData) const {
362 nsChangeHint hint = nsChangeHint(0);
364 if (mPadding != aNewData.mPadding) {
365 // Padding differences can't affect descendant intrinsic sizes, but do need
366 // to force children to reflow so that we can reposition them, since their
367 // offsets are from our frame bounds but our content rect's position within
368 // those bounds is moving.
369 // FIXME: It would be good to return a weaker hint here that doesn't
370 // force reflow of all descendants, but the hint would need to force
371 // reflow of the frame's children (see how
372 // ReflowInput::InitResizeFlags initializes the inline-resize flag).
373 hint |= NS_STYLE_HINT_REFLOW & ~nsChangeHint_ClearDescendantIntrinsics;
376 if (mScrollPadding != aNewData.mScrollPadding) {
377 // FIXME: Bug 1530253 Support re-snapping when scroll-padding changes.
378 hint |= nsChangeHint_NeutralChange;
381 return hint;
384 static inline BorderRadius ZeroBorderRadius() {
385 auto zero = LengthPercentage::Zero();
386 return {{{zero, zero}}, {{zero, zero}}, {{zero, zero}}, {{zero, zero}}};
389 nsStyleBorder::nsStyleBorder(const Document& aDocument)
390 : mBorderRadius(ZeroBorderRadius()),
391 mBorderImageSource(StyleImage::None()),
392 mBorderImageWidth(
393 StyleRectWithAllSides(StyleBorderImageSideWidth::Number(1.))),
394 mBorderImageOutset(
395 StyleRectWithAllSides(StyleNonNegativeLengthOrNumber::Number(0.))),
396 mBorderImageSlice(
397 {StyleRectWithAllSides(StyleNumberOrPercentage::Percentage({1.})),
398 false}),
399 mBorderImageRepeatH(StyleBorderImageRepeat::Stretch),
400 mBorderImageRepeatV(StyleBorderImageRepeat::Stretch),
401 mFloatEdge(StyleFloatEdge::ContentBox),
402 mBoxDecorationBreak(StyleBoxDecorationBreak::Slice),
403 mBorderTopColor(StyleColor::CurrentColor()),
404 mBorderRightColor(StyleColor::CurrentColor()),
405 mBorderBottomColor(StyleColor::CurrentColor()),
406 mBorderLeftColor(StyleColor::CurrentColor()),
407 mComputedBorder(0, 0, 0, 0) {
408 MOZ_COUNT_CTOR(nsStyleBorder);
410 nscoord medium = kMediumBorderWidth;
411 for (const auto side : mozilla::AllPhysicalSides()) {
412 mBorder.Side(side) = medium;
413 mBorderStyle[side] = StyleBorderStyle::None;
417 nsStyleBorder::nsStyleBorder(const nsStyleBorder& aSrc)
418 : mBorderRadius(aSrc.mBorderRadius),
419 mBorderImageSource(aSrc.mBorderImageSource),
420 mBorderImageWidth(aSrc.mBorderImageWidth),
421 mBorderImageOutset(aSrc.mBorderImageOutset),
422 mBorderImageSlice(aSrc.mBorderImageSlice),
423 mBorderImageRepeatH(aSrc.mBorderImageRepeatH),
424 mBorderImageRepeatV(aSrc.mBorderImageRepeatV),
425 mFloatEdge(aSrc.mFloatEdge),
426 mBoxDecorationBreak(aSrc.mBoxDecorationBreak),
427 mBorderTopColor(aSrc.mBorderTopColor),
428 mBorderRightColor(aSrc.mBorderRightColor),
429 mBorderBottomColor(aSrc.mBorderBottomColor),
430 mBorderLeftColor(aSrc.mBorderLeftColor),
431 mComputedBorder(aSrc.mComputedBorder),
432 mBorder(aSrc.mBorder) {
433 MOZ_COUNT_CTOR(nsStyleBorder);
434 for (const auto side : mozilla::AllPhysicalSides()) {
435 mBorderStyle[side] = aSrc.mBorderStyle[side];
439 nsStyleBorder::~nsStyleBorder() { MOZ_COUNT_DTOR(nsStyleBorder); }
441 void nsStyleBorder::TriggerImageLoads(Document& aDocument,
442 const nsStyleBorder* aOldStyle) {
443 MOZ_ASSERT(NS_IsMainThread());
445 mBorderImageSource.ResolveImage(
446 aDocument, aOldStyle ? &aOldStyle->mBorderImageSource : nullptr);
449 nsMargin nsStyleBorder::GetImageOutset() const {
450 // We don't check whether there is a border-image (which is OK since
451 // the initial values yields 0 outset) so that we don't have to
452 // reflow to update overflow areas when an image loads.
453 nsMargin outset;
454 for (const auto s : mozilla::AllPhysicalSides()) {
455 const auto& coord = mBorderImageOutset.Get(s);
456 nscoord value;
457 if (coord.IsLength()) {
458 value = coord.AsLength().ToAppUnits();
459 } else {
460 MOZ_ASSERT(coord.IsNumber());
461 value = coord.AsNumber() * mComputedBorder.Side(s);
463 outset.Side(s) = value;
465 return outset;
468 nsChangeHint nsStyleBorder::CalcDifference(
469 const nsStyleBorder& aNewData) const {
470 // FIXME: XXXbz: As in nsStylePadding::CalcDifference, many of these
471 // differences should not need to clear descendant intrinsics.
472 // FIXME: It would be good to return a weaker hint for the
473 // GetComputedBorder() differences (and perhaps others) that doesn't
474 // force reflow of all descendants, but the hint would need to force
475 // reflow of the frame's children (see how
476 // ReflowInput::InitResizeFlags initializes the inline-resize flag).
477 if (GetComputedBorder() != aNewData.GetComputedBorder() ||
478 mFloatEdge != aNewData.mFloatEdge ||
479 mBorderImageOutset != aNewData.mBorderImageOutset ||
480 mBoxDecorationBreak != aNewData.mBoxDecorationBreak) {
481 return NS_STYLE_HINT_REFLOW;
484 for (const auto ix : mozilla::AllPhysicalSides()) {
485 // See the explanation in nsChangeHint.h of
486 // nsChangeHint_BorderStyleNoneChange .
487 // Furthermore, even though we know *this* side is 0 width, just
488 // assume a repaint hint for some other change rather than bother
489 // tracking this result through the rest of the function.
490 if (HasVisibleStyle(ix) != aNewData.HasVisibleStyle(ix)) {
491 return nsChangeHint_RepaintFrame | nsChangeHint_BorderStyleNoneChange;
495 // Note that mBorderStyle stores not only the border style but also
496 // color-related flags. Given that we've already done an mComputedBorder
497 // comparison, border-style differences can only lead to a repaint hint. So
498 // it's OK to just compare the values directly -- if either the actual
499 // style or the color flags differ we want to repaint.
500 for (const auto ix : mozilla::AllPhysicalSides()) {
501 if (mBorderStyle[ix] != aNewData.mBorderStyle[ix] ||
502 BorderColorFor(ix) != aNewData.BorderColorFor(ix)) {
503 return nsChangeHint_RepaintFrame;
507 // Note that border radius also controls the outline radius if the
508 // layout.css.outline-follows-border-radius.enabled pref is set. Any
509 // optimizations here should apply to both.
510 if (mBorderRadius != aNewData.mBorderRadius) {
511 return nsChangeHint_RepaintFrame;
514 // Loading status of the border image can be accessed in main thread only
515 // while CalcDifference might be executed on a background thread. As a
516 // result, we have to check mBorderImage* fields even before border image was
517 // actually loaded.
518 if (!mBorderImageSource.IsNone() || !aNewData.mBorderImageSource.IsNone()) {
519 if (mBorderImageSource != aNewData.mBorderImageSource ||
520 mBorderImageRepeatH != aNewData.mBorderImageRepeatH ||
521 mBorderImageRepeatV != aNewData.mBorderImageRepeatV ||
522 mBorderImageSlice != aNewData.mBorderImageSlice ||
523 mBorderImageWidth != aNewData.mBorderImageWidth) {
524 return nsChangeHint_RepaintFrame;
528 // mBorder is the specified border value. Changes to this don't
529 // need any change processing, since we operate on the computed
530 // border values instead.
531 if (mBorder != aNewData.mBorder) {
532 return nsChangeHint_NeutralChange;
535 // mBorderImage* fields are checked only when border-image is not 'none'.
536 if (mBorderImageSource != aNewData.mBorderImageSource ||
537 mBorderImageRepeatH != aNewData.mBorderImageRepeatH ||
538 mBorderImageRepeatV != aNewData.mBorderImageRepeatV ||
539 mBorderImageSlice != aNewData.mBorderImageSlice ||
540 mBorderImageWidth != aNewData.mBorderImageWidth) {
541 return nsChangeHint_NeutralChange;
544 return nsChangeHint(0);
547 nsStyleOutline::nsStyleOutline(const Document& aDocument)
548 : mOutlineWidth(kMediumBorderWidth),
549 mOutlineOffset({0.0f}),
550 mOutlineColor(StyleColor::CurrentColor()),
551 mOutlineStyle(StyleOutlineStyle::BorderStyle(StyleBorderStyle::None)),
552 mActualOutlineWidth(0) {
553 MOZ_COUNT_CTOR(nsStyleOutline);
556 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc)
557 : mOutlineWidth(aSrc.mOutlineWidth),
558 mOutlineOffset(aSrc.mOutlineOffset),
559 mOutlineColor(aSrc.mOutlineColor),
560 mOutlineStyle(aSrc.mOutlineStyle),
561 mActualOutlineWidth(aSrc.mActualOutlineWidth) {
562 MOZ_COUNT_CTOR(nsStyleOutline);
565 nsChangeHint nsStyleOutline::CalcDifference(
566 const nsStyleOutline& aNewData) const {
567 const bool shouldPaintOutline = ShouldPaintOutline();
568 // We need the explicit 'outline-style: auto' check because
569 // 'outline-style: auto' effectively also changes 'outline-width'.
570 if (shouldPaintOutline != aNewData.ShouldPaintOutline() ||
571 mActualOutlineWidth != aNewData.mActualOutlineWidth ||
572 mOutlineStyle.IsAuto() != aNewData.mOutlineStyle.IsAuto() ||
573 (shouldPaintOutline && mOutlineOffset != aNewData.mOutlineOffset)) {
574 return nsChangeHint_UpdateOverflow | nsChangeHint_SchedulePaint |
575 nsChangeHint_RepaintFrame;
578 if (mOutlineStyle != aNewData.mOutlineStyle ||
579 mOutlineColor != aNewData.mOutlineColor) {
580 return shouldPaintOutline ? nsChangeHint_RepaintFrame
581 : nsChangeHint_NeutralChange;
584 if (mOutlineWidth != aNewData.mOutlineWidth ||
585 mOutlineOffset != aNewData.mOutlineOffset) {
586 return nsChangeHint_NeutralChange;
589 return nsChangeHint(0);
592 // --------------------
593 // nsStyleList
595 nsStyleList::nsStyleList(const Document& aDocument)
596 : mListStylePosition(StyleListStylePosition::Outside),
597 mQuotes(StyleQuotes::Auto()),
598 mListStyleImage(StyleImage::None()) {
599 MOZ_COUNT_CTOR(nsStyleList);
600 MOZ_ASSERT(NS_IsMainThread());
602 mCounterStyle = nsGkAtoms::disc;
605 nsStyleList::~nsStyleList() { MOZ_COUNT_DTOR(nsStyleList); }
607 nsStyleList::nsStyleList(const nsStyleList& aSource)
608 : mListStylePosition(aSource.mListStylePosition),
609 mCounterStyle(aSource.mCounterStyle),
610 mQuotes(aSource.mQuotes),
611 mListStyleImage(aSource.mListStyleImage) {
612 MOZ_COUNT_CTOR(nsStyleList);
615 void nsStyleList::TriggerImageLoads(Document& aDocument,
616 const nsStyleList* aOldStyle) {
617 MOZ_ASSERT(NS_IsMainThread());
618 mListStyleImage.ResolveImage(
619 aDocument, aOldStyle ? &aOldStyle->mListStyleImage : nullptr);
622 nsChangeHint nsStyleList::CalcDifference(
623 const nsStyleList& aNewData, const nsStyleDisplay& aOldDisplay) const {
624 // If the quotes implementation is ever going to change we might not need
625 // a framechange here and a reflow should be sufficient. See bug 35768.
626 if (mQuotes != aNewData.mQuotes) {
627 return nsChangeHint_ReconstructFrame;
629 nsChangeHint hint = nsChangeHint(0);
630 // Only elements whose display value is list-item can be affected by
631 // list-style-position and list-style-type. If the old display struct
632 // doesn't exist, assume it isn't affected by display value at all,
633 // and thus these properties should not affect it either. This also
634 // relies on that when the display value changes from something else
635 // to list-item, that change itself would cause ReconstructFrame.
636 if (aOldDisplay.IsListItem()) {
637 if (mListStylePosition != aNewData.mListStylePosition ||
638 mCounterStyle != aNewData.mCounterStyle ||
639 mListStyleImage != aNewData.mListStyleImage) {
640 return nsChangeHint_ReconstructFrame;
642 } else if (mListStylePosition != aNewData.mListStylePosition ||
643 mCounterStyle != aNewData.mCounterStyle) {
644 hint = nsChangeHint_NeutralChange;
646 // list-style-image and -moz-image-region may affect some XUL elements
647 // regardless of display value, so we still need to check them.
648 if (mListStyleImage != aNewData.mListStyleImage) {
649 return NS_STYLE_HINT_REFLOW;
651 return hint;
654 already_AddRefed<nsIURI> nsStyleList::GetListStyleImageURI() const {
655 if (!mListStyleImage.IsUrl()) {
656 return nullptr;
659 return do_AddRef(mListStyleImage.AsUrl().GetURI());
662 // --------------------
663 // nsStyleXUL
665 nsStyleXUL::nsStyleXUL(const Document& aDocument)
666 : mBoxFlex(0.0f),
667 mBoxOrdinal(1),
668 mBoxAlign(StyleBoxAlign::Stretch),
669 mBoxDirection(StyleBoxDirection::Normal),
670 mBoxOrient(StyleBoxOrient::Horizontal),
671 mBoxPack(StyleBoxPack::Start) {
672 MOZ_COUNT_CTOR(nsStyleXUL);
675 nsStyleXUL::~nsStyleXUL() { MOZ_COUNT_DTOR(nsStyleXUL); }
677 nsStyleXUL::nsStyleXUL(const nsStyleXUL& aSource)
678 : mBoxFlex(aSource.mBoxFlex),
679 mBoxOrdinal(aSource.mBoxOrdinal),
680 mBoxAlign(aSource.mBoxAlign),
681 mBoxDirection(aSource.mBoxDirection),
682 mBoxOrient(aSource.mBoxOrient),
683 mBoxPack(aSource.mBoxPack) {
684 MOZ_COUNT_CTOR(nsStyleXUL);
687 nsChangeHint nsStyleXUL::CalcDifference(const nsStyleXUL& aNewData) const {
688 if (mBoxAlign == aNewData.mBoxAlign &&
689 mBoxDirection == aNewData.mBoxDirection &&
690 mBoxFlex == aNewData.mBoxFlex && mBoxOrient == aNewData.mBoxOrient &&
691 mBoxPack == aNewData.mBoxPack && mBoxOrdinal == aNewData.mBoxOrdinal) {
692 return nsChangeHint(0);
694 if (mBoxOrdinal != aNewData.mBoxOrdinal) {
695 return nsChangeHint_ReconstructFrame;
697 return NS_STYLE_HINT_REFLOW;
700 // --------------------
701 // nsStyleColumn
703 /* static */ const uint32_t nsStyleColumn::kMaxColumnCount;
704 /* static */ const uint32_t nsStyleColumn::kColumnCountAuto;
706 nsStyleColumn::nsStyleColumn(const Document& aDocument)
707 : mColumnWidth(LengthOrAuto::Auto()),
708 mColumnRuleColor(StyleColor::CurrentColor()),
709 mColumnRuleStyle(StyleBorderStyle::None),
710 mColumnRuleWidth(kMediumBorderWidth),
711 mActualColumnRuleWidth(0) {
712 MOZ_COUNT_CTOR(nsStyleColumn);
715 nsStyleColumn::~nsStyleColumn() { MOZ_COUNT_DTOR(nsStyleColumn); }
717 nsStyleColumn::nsStyleColumn(const nsStyleColumn& aSource)
718 : mColumnCount(aSource.mColumnCount),
719 mColumnWidth(aSource.mColumnWidth),
720 mColumnRuleColor(aSource.mColumnRuleColor),
721 mColumnRuleStyle(aSource.mColumnRuleStyle),
722 mColumnFill(aSource.mColumnFill),
723 mColumnSpan(aSource.mColumnSpan),
724 mColumnRuleWidth(aSource.mColumnRuleWidth),
725 mActualColumnRuleWidth(aSource.mActualColumnRuleWidth) {
726 MOZ_COUNT_CTOR(nsStyleColumn);
729 nsChangeHint nsStyleColumn::CalcDifference(
730 const nsStyleColumn& aNewData) const {
731 if (mColumnWidth.IsAuto() != aNewData.mColumnWidth.IsAuto() ||
732 mColumnCount != aNewData.mColumnCount ||
733 mColumnSpan != aNewData.mColumnSpan) {
734 // We force column count changes to do a reframe, because it's tricky to
735 // handle some edge cases where the column count gets smaller and content
736 // overflows.
737 // XXX not ideal
738 return nsChangeHint_ReconstructFrame;
741 if (mColumnWidth != aNewData.mColumnWidth ||
742 mColumnFill != aNewData.mColumnFill) {
743 return NS_STYLE_HINT_REFLOW;
746 if (mActualColumnRuleWidth != aNewData.mActualColumnRuleWidth ||
747 mColumnRuleStyle != aNewData.mColumnRuleStyle ||
748 mColumnRuleColor != aNewData.mColumnRuleColor) {
749 return NS_STYLE_HINT_VISUAL;
752 if (mColumnRuleWidth != aNewData.mColumnRuleWidth) {
753 return nsChangeHint_NeutralChange;
756 return nsChangeHint(0);
759 using SVGPaintFallback = StyleGenericSVGPaintFallback<StyleColor>;
761 // --------------------
762 // nsStyleSVG
764 nsStyleSVG::nsStyleSVG(const Document& aDocument)
765 : mFill{StyleSVGPaintKind::Color(StyleColor::Black()),
766 SVGPaintFallback::Unset()},
767 mStroke{StyleSVGPaintKind::None(), SVGPaintFallback::Unset()},
768 mMarkerEnd(StyleUrlOrNone::None()),
769 mMarkerMid(StyleUrlOrNone::None()),
770 mMarkerStart(StyleUrlOrNone::None()),
771 mMozContextProperties{{}, {0}},
772 mStrokeDasharray(StyleSVGStrokeDashArray::Values({})),
773 mStrokeDashoffset(
774 StyleSVGLength::LengthPercentage(LengthPercentage::Zero())),
775 mStrokeWidth(
776 StyleSVGWidth::LengthPercentage(LengthPercentage::FromPixels(1.0f))),
777 mFillOpacity(StyleSVGOpacity::Opacity(1.0f)),
778 mStrokeMiterlimit(4.0f),
779 mStrokeOpacity(StyleSVGOpacity::Opacity(1.0f)),
780 mClipRule(StyleFillRule::Nonzero),
781 mColorInterpolation(StyleColorInterpolation::Srgb),
782 mColorInterpolationFilters(StyleColorInterpolation::Linearrgb),
783 mFillRule(StyleFillRule::Nonzero),
784 mPaintOrder(0),
785 mShapeRendering(StyleShapeRendering::Auto),
786 mStrokeLinecap(StyleStrokeLinecap::Butt),
787 mStrokeLinejoin(StyleStrokeLinejoin::Miter),
788 mDominantBaseline(StyleDominantBaseline::Auto),
789 mTextAnchor(StyleTextAnchor::Start) {
790 MOZ_COUNT_CTOR(nsStyleSVG);
793 nsStyleSVG::~nsStyleSVG() { MOZ_COUNT_DTOR(nsStyleSVG); }
795 nsStyleSVG::nsStyleSVG(const nsStyleSVG& aSource)
796 : mFill(aSource.mFill),
797 mStroke(aSource.mStroke),
798 mMarkerEnd(aSource.mMarkerEnd),
799 mMarkerMid(aSource.mMarkerMid),
800 mMarkerStart(aSource.mMarkerStart),
801 mMozContextProperties(aSource.mMozContextProperties),
802 mStrokeDasharray(aSource.mStrokeDasharray),
803 mStrokeDashoffset(aSource.mStrokeDashoffset),
804 mStrokeWidth(aSource.mStrokeWidth),
805 mFillOpacity(aSource.mFillOpacity),
806 mStrokeMiterlimit(aSource.mStrokeMiterlimit),
807 mStrokeOpacity(aSource.mStrokeOpacity),
808 mClipRule(aSource.mClipRule),
809 mColorInterpolation(aSource.mColorInterpolation),
810 mColorInterpolationFilters(aSource.mColorInterpolationFilters),
811 mFillRule(aSource.mFillRule),
812 mPaintOrder(aSource.mPaintOrder),
813 mShapeRendering(aSource.mShapeRendering),
814 mStrokeLinecap(aSource.mStrokeLinecap),
815 mStrokeLinejoin(aSource.mStrokeLinejoin),
816 mDominantBaseline(aSource.mDominantBaseline),
817 mTextAnchor(aSource.mTextAnchor) {
818 MOZ_COUNT_CTOR(nsStyleSVG);
821 static bool PaintURIChanged(const StyleSVGPaint& aPaint1,
822 const StyleSVGPaint& aPaint2) {
823 if (aPaint1.kind.IsPaintServer() != aPaint2.kind.IsPaintServer()) {
824 return true;
826 return aPaint1.kind.IsPaintServer() &&
827 aPaint1.kind.AsPaintServer() != aPaint2.kind.AsPaintServer();
830 nsChangeHint nsStyleSVG::CalcDifference(const nsStyleSVG& aNewData) const {
831 nsChangeHint hint = nsChangeHint(0);
833 if (mMarkerEnd != aNewData.mMarkerEnd || mMarkerMid != aNewData.mMarkerMid ||
834 mMarkerStart != aNewData.mMarkerStart) {
835 // Markers currently contribute to SVGGeometryFrame::mRect,
836 // so we need a reflow as well as a repaint. No intrinsic sizes need
837 // to change, so nsChangeHint_NeedReflow is sufficient.
838 return nsChangeHint_UpdateEffects | nsChangeHint_NeedReflow |
839 nsChangeHint_RepaintFrame;
842 if (mFill != aNewData.mFill || mStroke != aNewData.mStroke ||
843 mFillOpacity != aNewData.mFillOpacity ||
844 mStrokeOpacity != aNewData.mStrokeOpacity) {
845 hint |= nsChangeHint_RepaintFrame;
846 if (HasStroke() != aNewData.HasStroke() ||
847 (!HasStroke() && HasFill() != aNewData.HasFill())) {
848 // Frame bounds and overflow rects depend on whether we "have" fill or
849 // stroke. Whether we have stroke or not just changed, or else we have no
850 // stroke (in which case whether we have fill or not is significant to
851 // frame bounds) and whether we have fill or not just changed. In either
852 // case we need to reflow so the frame rect is updated.
853 // XXXperf this is a waste on non SVGGeometryFrames.
854 hint |= nsChangeHint_NeedReflow;
856 if (PaintURIChanged(mFill, aNewData.mFill) ||
857 PaintURIChanged(mStroke, aNewData.mStroke)) {
858 hint |= nsChangeHint_UpdateEffects;
862 // Stroke currently contributes to SVGGeometryFrame::mRect, so
863 // we need a reflow here. No intrinsic sizes need to change, so
864 // nsChangeHint_NeedReflow is sufficient.
865 // Note that stroke-dashoffset does not affect SVGGeometryFrame::mRect.
866 // text-anchor and dominant-baseline changes also require a reflow since
867 // they change frames' rects.
868 if (mStrokeWidth != aNewData.mStrokeWidth ||
869 mStrokeMiterlimit != aNewData.mStrokeMiterlimit ||
870 mStrokeLinecap != aNewData.mStrokeLinecap ||
871 mStrokeLinejoin != aNewData.mStrokeLinejoin ||
872 mDominantBaseline != aNewData.mDominantBaseline ||
873 mTextAnchor != aNewData.mTextAnchor) {
874 return hint | nsChangeHint_NeedReflow | nsChangeHint_RepaintFrame;
877 if (hint & nsChangeHint_RepaintFrame) {
878 return hint; // we don't add anything else below
881 if (mStrokeDashoffset != aNewData.mStrokeDashoffset ||
882 mClipRule != aNewData.mClipRule ||
883 mColorInterpolation != aNewData.mColorInterpolation ||
884 mColorInterpolationFilters != aNewData.mColorInterpolationFilters ||
885 mFillRule != aNewData.mFillRule || mPaintOrder != aNewData.mPaintOrder ||
886 mShapeRendering != aNewData.mShapeRendering ||
887 mStrokeDasharray != aNewData.mStrokeDasharray ||
888 mMozContextProperties.bits != aNewData.mMozContextProperties.bits) {
889 return hint | nsChangeHint_RepaintFrame;
892 if (!hint) {
893 if (mMozContextProperties.idents != aNewData.mMozContextProperties.idents) {
894 hint = nsChangeHint_NeutralChange;
898 return hint;
901 // --------------------
902 // nsStyleSVGReset
904 nsStyleSVGReset::nsStyleSVGReset(const Document& aDocument)
905 : mX(LengthPercentage::Zero()),
906 mY(LengthPercentage::Zero()),
907 mCx(LengthPercentage::Zero()),
908 mCy(LengthPercentage::Zero()),
909 mRx(NonNegativeLengthPercentageOrAuto::Auto()),
910 mRy(NonNegativeLengthPercentageOrAuto::Auto()),
911 mR(NonNegativeLengthPercentage::Zero()),
912 mMask(nsStyleImageLayers::LayerType::Mask),
913 mClipPath(StyleClipPath::None()),
914 mStopColor(StyleColor::Black()),
915 mFloodColor(StyleColor::Black()),
916 mLightingColor(StyleColor::White()),
917 mStopOpacity(1.0f),
918 mFloodOpacity(1.0f),
919 mVectorEffect(StyleVectorEffect::None),
920 mMaskType(StyleMaskType::Luminance),
921 mD(StyleDProperty::None()) {
922 MOZ_COUNT_CTOR(nsStyleSVGReset);
925 nsStyleSVGReset::~nsStyleSVGReset() { MOZ_COUNT_DTOR(nsStyleSVGReset); }
927 nsStyleSVGReset::nsStyleSVGReset(const nsStyleSVGReset& aSource)
928 : mX(aSource.mX),
929 mY(aSource.mY),
930 mCx(aSource.mCx),
931 mCy(aSource.mCy),
932 mRx(aSource.mRx),
933 mRy(aSource.mRy),
934 mR(aSource.mR),
935 mMask(aSource.mMask),
936 mClipPath(aSource.mClipPath),
937 mStopColor(aSource.mStopColor),
938 mFloodColor(aSource.mFloodColor),
939 mLightingColor(aSource.mLightingColor),
940 mStopOpacity(aSource.mStopOpacity),
941 mFloodOpacity(aSource.mFloodOpacity),
942 mVectorEffect(aSource.mVectorEffect),
943 mMaskType(aSource.mMaskType),
944 mD(aSource.mD) {
945 MOZ_COUNT_CTOR(nsStyleSVGReset);
948 void nsStyleSVGReset::TriggerImageLoads(Document& aDocument,
949 const nsStyleSVGReset* aOldStyle) {
950 MOZ_ASSERT(NS_IsMainThread());
951 // NOTE(emilio): we intentionally don't call TriggerImageLoads for clip-path.
953 NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mMask) {
954 auto& image = mMask.mLayers[i].mImage;
955 if (!image.IsImageRequestType()) {
956 continue;
958 const auto* url = image.GetImageRequestURLValue();
959 // If the url is a local ref, it must be a <mask-resource>, so we don't
960 // need to resolve the style image.
961 if (url->IsLocalRef()) {
962 continue;
964 #if 0
965 // XXX The old style system also checks whether this is a reference to
966 // the current document with reference, but it doesn't seem to be a
967 // behavior mentioned anywhere, so we comment out the code for now.
968 nsIURI* docURI = aPresContext->Document()->GetDocumentURI();
969 if (url->EqualsExceptRef(docURI)) {
970 continue;
972 #endif
973 // Otherwise, we may need the image even if it has a reference, in case
974 // the referenced element isn't a valid SVG <mask> element.
975 const auto* oldImage = (aOldStyle && aOldStyle->mMask.mLayers.Length() > i)
976 ? &aOldStyle->mMask.mLayers[i].mImage
977 : nullptr;
979 image.ResolveImage(aDocument, oldImage);
983 nsChangeHint nsStyleSVGReset::CalcDifference(
984 const nsStyleSVGReset& aNewData) const {
985 nsChangeHint hint = nsChangeHint(0);
987 if (mX != aNewData.mX || mY != aNewData.mY || mCx != aNewData.mCx ||
988 mCy != aNewData.mCy || mR != aNewData.mR || mRx != aNewData.mRx ||
989 mRy != aNewData.mRy || mD != aNewData.mD) {
990 hint |= nsChangeHint_InvalidateRenderingObservers | nsChangeHint_NeedReflow;
993 if (mClipPath != aNewData.mClipPath) {
994 hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
997 if (mVectorEffect != aNewData.mVectorEffect) {
998 // Stroke currently affects SVGGeometryFrame::mRect, and
999 // vector-effect affect stroke. As a result we need to reflow if
1000 // vector-effect changes in order to have SVGGeometryFrame::
1001 // ReflowSVG called to update its mRect. No intrinsic sizes need
1002 // to change so nsChangeHint_NeedReflow is sufficient.
1003 hint |= nsChangeHint_NeedReflow | nsChangeHint_RepaintFrame;
1004 } else if (mStopColor != aNewData.mStopColor ||
1005 mFloodColor != aNewData.mFloodColor ||
1006 mLightingColor != aNewData.mLightingColor ||
1007 mStopOpacity != aNewData.mStopOpacity ||
1008 mFloodOpacity != aNewData.mFloodOpacity ||
1009 mMaskType != aNewData.mMaskType || mD != aNewData.mD) {
1010 hint |= nsChangeHint_RepaintFrame;
1013 hint |=
1014 mMask.CalcDifference(aNewData.mMask, nsStyleImageLayers::LayerType::Mask);
1016 return hint;
1019 bool nsStyleSVGReset::HasMask() const {
1020 for (uint32_t i = 0; i < mMask.mImageCount; i++) {
1021 if (!mMask.mLayers[i].mImage.IsNone()) {
1022 return true;
1026 return false;
1029 // --------------------
1030 // nsStylePage
1033 nsChangeHint nsStylePage::CalcDifference(const nsStylePage& aNewData) const {
1034 // Page rule styling only matters when printing or using print preview.
1035 if (aNewData.mSize != mSize || aNewData.mPage != mPage ||
1036 aNewData.mPageOrientation != mPageOrientation) {
1037 return nsChangeHint_NeutralChange;
1039 return nsChangeHint_Empty;
1042 // --------------------
1043 // nsStylePosition
1045 nsStylePosition::nsStylePosition(const Document& aDocument)
1046 : mObjectPosition(Position::FromPercentage(0.5f)),
1047 mOffset(StyleRectWithAllSides(LengthPercentageOrAuto::Auto())),
1048 mWidth(StyleSize::Auto()),
1049 mMinWidth(StyleSize::Auto()),
1050 mMaxWidth(StyleMaxSize::None()),
1051 mHeight(StyleSize::Auto()),
1052 mMinHeight(StyleSize::Auto()),
1053 mMaxHeight(StyleMaxSize::None()),
1054 mFlexBasis(StyleFlexBasis::Size(StyleSize::Auto())),
1055 mAspectRatio(StyleAspectRatio::Auto()),
1056 mGridAutoFlow(StyleGridAutoFlow::ROW),
1057 mMasonryAutoFlow(
1058 {StyleMasonryPlacement::Pack, StyleMasonryItemOrder::DefiniteFirst}),
1059 mAlignContent({StyleAlignFlags::NORMAL}),
1060 mAlignItems({StyleAlignFlags::NORMAL}),
1061 mAlignSelf({StyleAlignFlags::AUTO}),
1062 mJustifyContent({StyleAlignFlags::NORMAL}),
1063 mJustifyItems({{StyleAlignFlags::LEGACY}, {StyleAlignFlags::NORMAL}}),
1064 mJustifySelf({StyleAlignFlags::AUTO}),
1065 mFlexDirection(StyleFlexDirection::Row),
1066 mFlexWrap(StyleFlexWrap::Nowrap),
1067 mObjectFit(StyleObjectFit::Fill),
1068 mBoxSizing(StyleBoxSizing::Content),
1069 mOrder(0),
1070 mFlexGrow(0.0f),
1071 mFlexShrink(1.0f),
1072 mZIndex(StyleZIndex::Auto()),
1073 mGridTemplateColumns(StyleGridTemplateComponent::None()),
1074 mGridTemplateRows(StyleGridTemplateComponent::None()),
1075 mGridTemplateAreas(StyleGridTemplateAreas::None()),
1076 mColumnGap(NonNegativeLengthPercentageOrNormal::Normal()),
1077 mRowGap(NonNegativeLengthPercentageOrNormal::Normal()),
1078 mContainIntrinsicWidth(StyleContainIntrinsicSize::None()),
1079 mContainIntrinsicHeight(StyleContainIntrinsicSize::None()) {
1080 MOZ_COUNT_CTOR(nsStylePosition);
1082 // The initial value of grid-auto-columns and grid-auto-rows is 'auto',
1083 // which computes to 'minmax(auto, auto)'.
1085 // Other members get their default constructors
1086 // which initialize them to representations of their respective initial value.
1087 // mGridTemplate{Rows,Columns}: false and empty arrays for 'none'
1088 // mGrid{Column,Row}{Start,End}: false/0/empty values for 'auto'
1091 nsStylePosition::~nsStylePosition() { MOZ_COUNT_DTOR(nsStylePosition); }
1093 nsStylePosition::nsStylePosition(const nsStylePosition& aSource)
1094 : mAlignTracks(aSource.mAlignTracks),
1095 mJustifyTracks(aSource.mJustifyTracks),
1096 mObjectPosition(aSource.mObjectPosition),
1097 mOffset(aSource.mOffset),
1098 mWidth(aSource.mWidth),
1099 mMinWidth(aSource.mMinWidth),
1100 mMaxWidth(aSource.mMaxWidth),
1101 mHeight(aSource.mHeight),
1102 mMinHeight(aSource.mMinHeight),
1103 mMaxHeight(aSource.mMaxHeight),
1104 mFlexBasis(aSource.mFlexBasis),
1105 mGridAutoColumns(aSource.mGridAutoColumns),
1106 mGridAutoRows(aSource.mGridAutoRows),
1107 mAspectRatio(aSource.mAspectRatio),
1108 mGridAutoFlow(aSource.mGridAutoFlow),
1109 mMasonryAutoFlow(aSource.mMasonryAutoFlow),
1110 mAlignContent(aSource.mAlignContent),
1111 mAlignItems(aSource.mAlignItems),
1112 mAlignSelf(aSource.mAlignSelf),
1113 mJustifyContent(aSource.mJustifyContent),
1114 mJustifyItems(aSource.mJustifyItems),
1115 mJustifySelf(aSource.mJustifySelf),
1116 mFlexDirection(aSource.mFlexDirection),
1117 mFlexWrap(aSource.mFlexWrap),
1118 mObjectFit(aSource.mObjectFit),
1119 mBoxSizing(aSource.mBoxSizing),
1120 mOrder(aSource.mOrder),
1121 mFlexGrow(aSource.mFlexGrow),
1122 mFlexShrink(aSource.mFlexShrink),
1123 mZIndex(aSource.mZIndex),
1124 mGridTemplateColumns(aSource.mGridTemplateColumns),
1125 mGridTemplateRows(aSource.mGridTemplateRows),
1126 mGridTemplateAreas(aSource.mGridTemplateAreas),
1127 mGridColumnStart(aSource.mGridColumnStart),
1128 mGridColumnEnd(aSource.mGridColumnEnd),
1129 mGridRowStart(aSource.mGridRowStart),
1130 mGridRowEnd(aSource.mGridRowEnd),
1131 mColumnGap(aSource.mColumnGap),
1132 mRowGap(aSource.mRowGap),
1133 mContainIntrinsicWidth(aSource.mContainIntrinsicWidth),
1134 mContainIntrinsicHeight(aSource.mContainIntrinsicHeight) {
1135 MOZ_COUNT_CTOR(nsStylePosition);
1138 static bool IsAutonessEqual(const StyleRect<LengthPercentageOrAuto>& aSides1,
1139 const StyleRect<LengthPercentageOrAuto>& aSides2) {
1140 for (const auto side : mozilla::AllPhysicalSides()) {
1141 if (aSides1.Get(side).IsAuto() != aSides2.Get(side).IsAuto()) {
1142 return false;
1145 return true;
1148 nsChangeHint nsStylePosition::CalcDifference(
1149 const nsStylePosition& aNewData,
1150 const nsStyleVisibility& aOldStyleVisibility) const {
1151 if (mGridTemplateColumns.IsMasonry() !=
1152 aNewData.mGridTemplateColumns.IsMasonry() ||
1153 mGridTemplateRows.IsMasonry() != aNewData.mGridTemplateRows.IsMasonry()) {
1154 // XXXmats this could be optimized to AllReflowHints with a bit of work,
1155 // but I'll assume this is a very rare use case in practice. (bug 1623886)
1156 return nsChangeHint_ReconstructFrame;
1159 nsChangeHint hint = nsChangeHint(0);
1161 // Changes to "z-index" require a repaint.
1162 if (mZIndex != aNewData.mZIndex) {
1163 hint |= nsChangeHint_RepaintFrame;
1166 // Changes to "object-fit" & "object-position" require a repaint. They
1167 // may also require a reflow, if we have a nsSubDocumentFrame, so that we
1168 // can adjust the size & position of the subdocument.
1169 if (mObjectFit != aNewData.mObjectFit ||
1170 mObjectPosition != aNewData.mObjectPosition) {
1171 hint |= nsChangeHint_RepaintFrame | nsChangeHint_NeedReflow;
1174 if (mContainIntrinsicWidth != aNewData.mContainIntrinsicWidth ||
1175 mContainIntrinsicHeight != aNewData.mContainIntrinsicHeight) {
1176 hint |= NS_STYLE_HINT_REFLOW;
1179 if (mOrder != aNewData.mOrder) {
1180 // "order" impacts both layout order and stacking order, so we need both a
1181 // reflow and a repaint when it changes. (Technically, we only need a
1182 // reflow if we're in a multi-line flexbox (which we can't be sure about,
1183 // since that's determined by styling on our parent) -- there, "order" can
1184 // affect which flex line we end up on, & hence can affect our sizing by
1185 // changing the group of flex items we're competing with for space.)
1186 return hint | nsChangeHint_RepaintFrame | nsChangeHint_AllReflowHints;
1189 if (mBoxSizing != aNewData.mBoxSizing) {
1190 // Can affect both widths and heights; just a bad scene.
1191 return hint | nsChangeHint_AllReflowHints;
1194 if (mAlignItems != aNewData.mAlignItems ||
1195 mAlignSelf != aNewData.mAlignSelf ||
1196 mJustifyTracks != aNewData.mJustifyTracks ||
1197 mAlignTracks != aNewData.mAlignTracks) {
1198 return hint | nsChangeHint_AllReflowHints;
1201 // Properties that apply to flex items:
1202 // XXXdholbert These should probably be more targeted (bug 819536)
1203 if (mFlexBasis != aNewData.mFlexBasis || mFlexGrow != aNewData.mFlexGrow ||
1204 mFlexShrink != aNewData.mFlexShrink) {
1205 return hint | nsChangeHint_AllReflowHints;
1208 // Properties that apply to flex containers:
1209 // - flex-direction can swap a flex container between vertical & horizontal.
1210 // - flex-wrap changes whether a flex container's children are wrapped, which
1211 // impacts their sizing/positioning and hence impacts the container's size.
1212 if (mFlexDirection != aNewData.mFlexDirection ||
1213 mFlexWrap != aNewData.mFlexWrap) {
1214 return hint | nsChangeHint_AllReflowHints;
1217 // Properties that apply to grid containers:
1218 // FIXME: only for grid containers
1219 // (ie. 'display: grid' or 'display: inline-grid')
1220 if (mGridTemplateColumns != aNewData.mGridTemplateColumns ||
1221 mGridTemplateRows != aNewData.mGridTemplateRows ||
1222 mGridTemplateAreas != aNewData.mGridTemplateAreas ||
1223 mGridAutoColumns != aNewData.mGridAutoColumns ||
1224 mGridAutoRows != aNewData.mGridAutoRows ||
1225 mGridAutoFlow != aNewData.mGridAutoFlow ||
1226 mMasonryAutoFlow != aNewData.mMasonryAutoFlow) {
1227 return hint | nsChangeHint_AllReflowHints;
1230 // Properties that apply to grid items:
1231 // FIXME: only for grid items
1232 // (ie. parent frame is 'display: grid' or 'display: inline-grid')
1233 if (mGridColumnStart != aNewData.mGridColumnStart ||
1234 mGridColumnEnd != aNewData.mGridColumnEnd ||
1235 mGridRowStart != aNewData.mGridRowStart ||
1236 mGridRowEnd != aNewData.mGridRowEnd ||
1237 mColumnGap != aNewData.mColumnGap || mRowGap != aNewData.mRowGap) {
1238 return hint | nsChangeHint_AllReflowHints;
1241 // Changing 'justify-content/items/self' might affect the positioning,
1242 // but it won't affect any sizing.
1243 if (mJustifyContent != aNewData.mJustifyContent ||
1244 mJustifyItems.computed != aNewData.mJustifyItems.computed ||
1245 mJustifySelf != aNewData.mJustifySelf) {
1246 hint |= nsChangeHint_NeedReflow;
1249 // No need to do anything if specified justify-items changes, as long as the
1250 // computed one (tested above) is unchanged.
1251 if (mJustifyItems.specified != aNewData.mJustifyItems.specified) {
1252 hint |= nsChangeHint_NeutralChange;
1255 // 'align-content' doesn't apply to a single-line flexbox but we don't know
1256 // if we're a flex container at this point so we can't optimize for that.
1257 if (mAlignContent != aNewData.mAlignContent) {
1258 hint |= nsChangeHint_NeedReflow;
1261 bool widthChanged = mWidth != aNewData.mWidth ||
1262 mMinWidth != aNewData.mMinWidth ||
1263 mMaxWidth != aNewData.mMaxWidth;
1264 bool heightChanged = mHeight != aNewData.mHeight ||
1265 mMinHeight != aNewData.mMinHeight ||
1266 mMaxHeight != aNewData.mMaxHeight;
1268 // It doesn't matter whether we're looking at the old or new visibility
1269 // struct, since a change between vertical and horizontal writing-mode will
1270 // cause a reframe.
1271 bool isVertical = aOldStyleVisibility.mWritingMode !=
1272 StyleWritingModeProperty::HorizontalTb;
1273 if (isVertical ? widthChanged : heightChanged) {
1274 hint |= nsChangeHint_ReflowHintsForBSizeChange;
1277 if (isVertical ? heightChanged : widthChanged) {
1278 hint |= nsChangeHint_ReflowHintsForISizeChange;
1281 if (mAspectRatio != aNewData.mAspectRatio) {
1282 hint |= nsChangeHint_ReflowHintsForISizeChange |
1283 nsChangeHint_ReflowHintsForBSizeChange;
1286 // If any of the offsets have changed, then return the respective hints
1287 // so that we would hopefully be able to avoid reflowing.
1288 // Note that it is possible that we'll need to reflow when processing
1289 // restyles, but we don't have enough information to make a good decision
1290 // right now.
1291 // Don't try to handle changes between "auto" and non-auto efficiently;
1292 // that's tricky to do and will hardly ever be able to avoid a reflow.
1293 if (mOffset != aNewData.mOffset) {
1294 if (IsAutonessEqual(mOffset, aNewData.mOffset)) {
1295 hint |=
1296 nsChangeHint_RecomputePosition | nsChangeHint_UpdateParentOverflow;
1297 } else {
1298 hint |=
1299 nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition;
1302 return hint;
1305 const StyleContainIntrinsicSize& nsStylePosition::ContainIntrinsicBSize(
1306 const WritingMode& aWM) const {
1307 return aWM.IsVertical() ? mContainIntrinsicWidth : mContainIntrinsicHeight;
1310 const StyleContainIntrinsicSize& nsStylePosition::ContainIntrinsicISize(
1311 const WritingMode& aWM) const {
1312 return aWM.IsVertical() ? mContainIntrinsicHeight : mContainIntrinsicWidth;
1315 StyleAlignSelf nsStylePosition::UsedAlignSelf(
1316 const ComputedStyle* aParent) const {
1317 if (mAlignSelf._0 != StyleAlignFlags::AUTO) {
1318 return mAlignSelf;
1320 if (MOZ_LIKELY(aParent)) {
1321 auto parentAlignItems = aParent->StylePosition()->mAlignItems;
1322 MOZ_ASSERT(!(parentAlignItems._0 & StyleAlignFlags::LEGACY),
1323 "align-items can't have 'legacy'");
1324 return {parentAlignItems._0};
1326 return {StyleAlignFlags::NORMAL};
1329 StyleJustifySelf nsStylePosition::UsedJustifySelf(
1330 const ComputedStyle* aParent) const {
1331 if (mJustifySelf._0 != StyleAlignFlags::AUTO) {
1332 return mJustifySelf;
1334 if (MOZ_LIKELY(aParent)) {
1335 const auto& inheritedJustifyItems =
1336 aParent->StylePosition()->mJustifyItems.computed;
1337 return {inheritedJustifyItems._0 & ~StyleAlignFlags::LEGACY};
1339 return {StyleAlignFlags::NORMAL};
1342 // --------------------
1343 // nsStyleTable
1346 nsStyleTable::nsStyleTable(const Document& aDocument)
1347 : mLayoutStrategy(StyleTableLayout::Auto), mXSpan(1) {
1348 MOZ_COUNT_CTOR(nsStyleTable);
1351 nsStyleTable::~nsStyleTable() { MOZ_COUNT_DTOR(nsStyleTable); }
1353 nsStyleTable::nsStyleTable(const nsStyleTable& aSource)
1354 : mLayoutStrategy(aSource.mLayoutStrategy), mXSpan(aSource.mXSpan) {
1355 MOZ_COUNT_CTOR(nsStyleTable);
1358 nsChangeHint nsStyleTable::CalcDifference(const nsStyleTable& aNewData) const {
1359 if (mXSpan != aNewData.mXSpan ||
1360 mLayoutStrategy != aNewData.mLayoutStrategy) {
1361 return nsChangeHint_ReconstructFrame;
1363 return nsChangeHint(0);
1366 // -----------------------
1367 // nsStyleTableBorder
1369 nsStyleTableBorder::nsStyleTableBorder(const Document& aDocument)
1370 : mBorderSpacingCol(0),
1371 mBorderSpacingRow(0),
1372 mBorderCollapse(StyleBorderCollapse::Separate),
1373 mCaptionSide(StyleCaptionSide::Top),
1374 mEmptyCells(StyleEmptyCells::Show) {
1375 MOZ_COUNT_CTOR(nsStyleTableBorder);
1378 nsStyleTableBorder::~nsStyleTableBorder() {
1379 MOZ_COUNT_DTOR(nsStyleTableBorder);
1382 nsStyleTableBorder::nsStyleTableBorder(const nsStyleTableBorder& aSource)
1383 : mBorderSpacingCol(aSource.mBorderSpacingCol),
1384 mBorderSpacingRow(aSource.mBorderSpacingRow),
1385 mBorderCollapse(aSource.mBorderCollapse),
1386 mCaptionSide(aSource.mCaptionSide),
1387 mEmptyCells(aSource.mEmptyCells) {
1388 MOZ_COUNT_CTOR(nsStyleTableBorder);
1391 nsChangeHint nsStyleTableBorder::CalcDifference(
1392 const nsStyleTableBorder& aNewData) const {
1393 // Border-collapse changes need a reframe, because we use a different frame
1394 // class for table cells in the collapsed border model. This is used to
1395 // conserve memory when using the separated border model (collapsed borders
1396 // require extra state to be stored).
1397 if (mBorderCollapse != aNewData.mBorderCollapse) {
1398 return nsChangeHint_ReconstructFrame;
1401 if ((mCaptionSide == aNewData.mCaptionSide) &&
1402 (mBorderSpacingCol == aNewData.mBorderSpacingCol) &&
1403 (mBorderSpacingRow == aNewData.mBorderSpacingRow)) {
1404 if (mEmptyCells == aNewData.mEmptyCells) {
1405 return nsChangeHint(0);
1407 return NS_STYLE_HINT_VISUAL;
1408 } else {
1409 return NS_STYLE_HINT_REFLOW;
1413 template <typename T>
1414 static bool GradientItemsAreOpaque(
1415 Span<const StyleGenericGradientItem<StyleColor, T>> aItems) {
1416 for (auto& stop : aItems) {
1417 if (stop.IsInterpolationHint()) {
1418 continue;
1421 auto& color = stop.IsSimpleColorStop() ? stop.AsSimpleColorStop()
1422 : stop.AsComplexColorStop().color;
1423 if (color.MaybeTransparent()) {
1424 // We don't know the foreground color here, so if it's being used
1425 // we must assume it might be transparent.
1426 return false;
1430 return true;
1433 template <>
1434 bool StyleGradient::IsOpaque() const {
1435 if (IsLinear()) {
1436 return GradientItemsAreOpaque(AsLinear().items.AsSpan());
1438 if (IsRadial()) {
1439 return GradientItemsAreOpaque(AsRadial().items.AsSpan());
1441 return GradientItemsAreOpaque(AsConic().items.AsSpan());
1444 static int32_t ConvertToPixelCoord(const StyleNumberOrPercentage& aCoord,
1445 int32_t aPercentScale) {
1446 double pixelValue;
1447 if (aCoord.IsNumber()) {
1448 pixelValue = aCoord.AsNumber();
1449 } else {
1450 MOZ_ASSERT(aCoord.IsPercentage());
1451 pixelValue = aCoord.AsPercentage()._0 * aPercentScale;
1453 MOZ_ASSERT(pixelValue >= 0, "we ensured non-negative while parsing");
1454 pixelValue = std::min(pixelValue, double(INT32_MAX)); // avoid overflow
1455 return NS_lround(pixelValue);
1458 template <>
1459 Maybe<StyleImage::ActualCropRect> StyleImage::ComputeActualCropRect() const {
1460 MOZ_ASSERT(IsRect(),
1461 "This function is designed to be used only image-rect images");
1463 imgRequestProxy* req = GetImageRequest();
1464 if (!req) {
1465 return Nothing();
1468 nsCOMPtr<imgIContainer> imageContainer;
1469 req->GetImage(getter_AddRefs(imageContainer));
1470 if (!imageContainer) {
1471 return Nothing();
1474 nsIntSize imageSize;
1475 imageContainer->GetWidth(&imageSize.width);
1476 imageContainer->GetHeight(&imageSize.height);
1477 if (imageSize.width <= 0 || imageSize.height <= 0) {
1478 return Nothing();
1481 auto& rect = AsRect();
1483 int32_t left = ConvertToPixelCoord(rect->left, imageSize.width);
1484 int32_t top = ConvertToPixelCoord(rect->top, imageSize.height);
1485 int32_t right = ConvertToPixelCoord(rect->right, imageSize.width);
1486 int32_t bottom = ConvertToPixelCoord(rect->bottom, imageSize.height);
1488 // IntersectRect() returns an empty rect if we get negative width or height
1489 nsIntRect cropRect(left, top, right - left, bottom - top);
1490 nsIntRect imageRect(nsIntPoint(0, 0), imageSize);
1491 auto finalRect = imageRect.Intersect(cropRect);
1492 bool isEntireImage = finalRect.IsEqualInterior(imageRect);
1493 return Some(ActualCropRect{finalRect, isEntireImage});
1496 template <>
1497 bool StyleImage::IsOpaque() const {
1498 if (IsImageSet()) {
1499 return FinalImage().IsOpaque();
1502 if (!IsComplete()) {
1503 return false;
1506 if (IsGradient()) {
1507 return AsGradient()->IsOpaque();
1510 if (IsElement()) {
1511 return false;
1514 MOZ_ASSERT(IsImageRequestType(), "unexpected image type");
1515 MOZ_ASSERT(GetImageRequest(), "should've returned earlier above");
1517 nsCOMPtr<imgIContainer> imageContainer;
1518 GetImageRequest()->GetImage(getter_AddRefs(imageContainer));
1519 MOZ_ASSERT(imageContainer, "IsComplete() said image container is ready");
1521 // Check if the crop region of the image is opaque.
1522 if (imageContainer->WillDrawOpaqueNow()) {
1523 if (!IsRect()) {
1524 return true;
1527 // Must make sure if the crop rect contains at least a pixel.
1528 // XXX Is this optimization worth it? Maybe I should just return false.
1529 auto croprect = ComputeActualCropRect();
1530 return croprect && !croprect->mRect.IsEmpty();
1533 return false;
1536 template <>
1537 bool StyleImage::IsComplete() const {
1538 switch (tag) {
1539 case Tag::None:
1540 return false;
1541 case Tag::Gradient:
1542 case Tag::Element:
1543 return true;
1544 case Tag::Url:
1545 case Tag::Rect: {
1546 if (!IsResolved()) {
1547 return false;
1549 imgRequestProxy* req = GetImageRequest();
1550 if (!req) {
1551 return false;
1553 uint32_t status = imgIRequest::STATUS_ERROR;
1554 return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
1555 (status & imgIRequest::STATUS_SIZE_AVAILABLE) &&
1556 (status & imgIRequest::STATUS_FRAME_COMPLETE);
1558 case Tag::ImageSet:
1559 return FinalImage().IsComplete();
1560 // Bug 546052 cross-fade not yet implemented.
1561 case Tag::CrossFade:
1562 return true;
1564 MOZ_ASSERT_UNREACHABLE("unexpected image type");
1565 return false;
1568 template <>
1569 bool StyleImage::IsSizeAvailable() const {
1570 switch (tag) {
1571 case Tag::None:
1572 return false;
1573 case Tag::Gradient:
1574 case Tag::Element:
1575 return true;
1576 case Tag::Url:
1577 case Tag::Rect: {
1578 imgRequestProxy* req = GetImageRequest();
1579 if (!req) {
1580 return false;
1582 uint32_t status = imgIRequest::STATUS_ERROR;
1583 return NS_SUCCEEDED(req->GetImageStatus(&status)) &&
1584 !(status & imgIRequest::STATUS_ERROR) &&
1585 (status & imgIRequest::STATUS_SIZE_AVAILABLE);
1587 case Tag::ImageSet:
1588 return FinalImage().IsSizeAvailable();
1589 case Tag::CrossFade:
1590 // TODO: Bug 546052 cross-fade not yet implemented.
1591 return true;
1593 MOZ_ASSERT_UNREACHABLE("unexpected image type");
1594 return false;
1597 template <>
1598 void StyleImage::ResolveImage(Document& aDoc, const StyleImage* aOld) {
1599 if (IsResolved()) {
1600 return;
1602 auto* old = aOld ? aOld->GetImageRequestURLValue() : nullptr;
1603 auto* url = GetImageRequestURLValue();
1604 // We could avoid this const_cast generating more code but it's not really
1605 // worth it.
1606 const_cast<StyleComputedImageUrl*>(url)->ResolveImage(aDoc, old);
1609 template <>
1610 ImageResolution StyleImage::GetResolution() const {
1611 ImageResolution resolution;
1612 if (imgRequestProxy* request = GetImageRequest()) {
1613 RefPtr<imgIContainer> image;
1614 request->GetImage(getter_AddRefs(image));
1615 if (image) {
1616 resolution = image->GetResolution();
1619 if (IsImageSet()) {
1620 const auto& set = *AsImageSet();
1621 auto items = set.items.AsSpan();
1622 if (MOZ_LIKELY(set.selected_index < items.Length())) {
1623 float r = items[set.selected_index].resolution._0;
1624 resolution.ScaleBy(r);
1627 return resolution;
1630 template <>
1631 Maybe<CSSIntSize> StyleImage::GetIntrinsicSize() const {
1632 imgRequestProxy* request = GetImageRequest();
1633 if (!request) {
1634 return Nothing();
1636 RefPtr<imgIContainer> image;
1637 request->GetImage(getter_AddRefs(image));
1638 if (!image) {
1639 return Nothing();
1641 // FIXME(emilio): Seems like this should be smarter about unspecified width /
1642 // height, aspect ratio, etc, but this preserves the current behavior of our
1643 // only caller for now...
1644 int32_t w = 0, h = 0;
1645 image->GetWidth(&w);
1646 image->GetHeight(&h);
1647 GetResolution().ApplyTo(w, h);
1648 return Some(CSSIntSize{w, h});
1651 // --------------------
1652 // nsStyleImageLayers
1655 const nsCSSPropertyID nsStyleImageLayers::kBackgroundLayerTable[] = {
1656 eCSSProperty_background, // shorthand
1657 eCSSProperty_background_color, // color
1658 eCSSProperty_background_image, // image
1659 eCSSProperty_background_repeat, // repeat
1660 eCSSProperty_background_position_x, // positionX
1661 eCSSProperty_background_position_y, // positionY
1662 eCSSProperty_background_clip, // clip
1663 eCSSProperty_background_origin, // origin
1664 eCSSProperty_background_size, // size
1665 eCSSProperty_background_attachment, // attachment
1666 eCSSProperty_UNKNOWN, // maskMode
1667 eCSSProperty_UNKNOWN // composite
1670 const nsCSSPropertyID nsStyleImageLayers::kMaskLayerTable[] = {
1671 eCSSProperty_mask, // shorthand
1672 eCSSProperty_UNKNOWN, // color
1673 eCSSProperty_mask_image, // image
1674 eCSSProperty_mask_repeat, // repeat
1675 eCSSProperty_mask_position_x, // positionX
1676 eCSSProperty_mask_position_y, // positionY
1677 eCSSProperty_mask_clip, // clip
1678 eCSSProperty_mask_origin, // origin
1679 eCSSProperty_mask_size, // size
1680 eCSSProperty_UNKNOWN, // attachment
1681 eCSSProperty_mask_mode, // maskMode
1682 eCSSProperty_mask_composite // composite
1685 nsStyleImageLayers::nsStyleImageLayers(nsStyleImageLayers::LayerType aType)
1686 : mAttachmentCount(1),
1687 mClipCount(1),
1688 mOriginCount(1),
1689 mRepeatCount(1),
1690 mPositionXCount(1),
1691 mPositionYCount(1),
1692 mImageCount(1),
1693 mSizeCount(1),
1694 mMaskModeCount(1),
1695 mBlendModeCount(1),
1696 mCompositeCount(1),
1697 mLayers(nsStyleAutoArray<Layer>::WITH_SINGLE_INITIAL_ELEMENT) {
1698 MOZ_COUNT_CTOR(nsStyleImageLayers);
1700 // Ensure first layer is initialized as specified layer type
1701 mLayers[0].Initialize(aType);
1704 nsStyleImageLayers::nsStyleImageLayers(const nsStyleImageLayers& aSource)
1705 : mAttachmentCount(aSource.mAttachmentCount),
1706 mClipCount(aSource.mClipCount),
1707 mOriginCount(aSource.mOriginCount),
1708 mRepeatCount(aSource.mRepeatCount),
1709 mPositionXCount(aSource.mPositionXCount),
1710 mPositionYCount(aSource.mPositionYCount),
1711 mImageCount(aSource.mImageCount),
1712 mSizeCount(aSource.mSizeCount),
1713 mMaskModeCount(aSource.mMaskModeCount),
1714 mBlendModeCount(aSource.mBlendModeCount),
1715 mCompositeCount(aSource.mCompositeCount),
1716 mLayers(aSource.mLayers.Clone()) {
1717 MOZ_COUNT_CTOR(nsStyleImageLayers);
1720 static bool AnyLayerIsElementImage(const nsStyleImageLayers& aLayers) {
1721 NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, aLayers) {
1722 if (aLayers.mLayers[i].mImage.FinalImage().IsElement()) {
1723 return true;
1726 return false;
1729 nsChangeHint nsStyleImageLayers::CalcDifference(
1730 const nsStyleImageLayers& aNewLayers, LayerType aType) const {
1731 nsChangeHint hint = nsChangeHint(0);
1733 // If the number of visible images changes, then it's easy-peasy.
1734 if (mImageCount != aNewLayers.mImageCount) {
1735 hint |= nsChangeHint_RepaintFrame;
1736 if (aType == nsStyleImageLayers::LayerType::Mask ||
1737 AnyLayerIsElementImage(*this) || AnyLayerIsElementImage(aNewLayers)) {
1738 hint |= nsChangeHint_UpdateEffects;
1740 return hint;
1743 const nsStyleImageLayers& moreLayers =
1744 mLayers.Length() > aNewLayers.mLayers.Length() ? *this : aNewLayers;
1745 const nsStyleImageLayers& lessLayers =
1746 mLayers.Length() > aNewLayers.mLayers.Length() ? aNewLayers : *this;
1748 for (size_t i = 0; i < moreLayers.mLayers.Length(); ++i) {
1749 const Layer& moreLayersLayer = moreLayers.mLayers[i];
1750 if (i < moreLayers.mImageCount) {
1751 // This is a visible image we're diffing, we may need to repaint.
1752 const Layer& lessLayersLayer = lessLayers.mLayers[i];
1753 nsChangeHint layerDifference =
1754 moreLayersLayer.CalcDifference(lessLayersLayer);
1755 if (layerDifference &&
1756 (moreLayersLayer.mImage.FinalImage().IsElement() ||
1757 lessLayersLayer.mImage.FinalImage().IsElement())) {
1758 layerDifference |=
1759 nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
1761 hint |= layerDifference;
1762 continue;
1764 if (hint) {
1765 // If they're different by now, we're done.
1766 return hint;
1768 if (i >= lessLayers.mLayers.Length()) {
1769 // The layer count differs, we know some property has changed, but if we
1770 // got here we know it won't affect rendering.
1771 return nsChangeHint_NeutralChange;
1774 const Layer& lessLayersLayer = lessLayers.mLayers[i];
1775 MOZ_ASSERT(moreLayersLayer.mImage.IsNone());
1776 MOZ_ASSERT(lessLayersLayer.mImage.IsNone());
1777 if (moreLayersLayer.CalcDifference(lessLayersLayer)) {
1778 // We don't care about the difference returned, we know it's not visible,
1779 // but if something changed, then we need to return the neutral change.
1780 return nsChangeHint_NeutralChange;
1784 if (hint) {
1785 // If they're different by now, we're done.
1786 return hint;
1789 // We could have same layers and values, but different count still.
1790 if (mAttachmentCount != aNewLayers.mAttachmentCount ||
1791 mBlendModeCount != aNewLayers.mBlendModeCount ||
1792 mClipCount != aNewLayers.mClipCount ||
1793 mCompositeCount != aNewLayers.mCompositeCount ||
1794 mMaskModeCount != aNewLayers.mMaskModeCount ||
1795 mOriginCount != aNewLayers.mOriginCount ||
1796 mRepeatCount != aNewLayers.mRepeatCount ||
1797 mPositionXCount != aNewLayers.mPositionXCount ||
1798 mPositionYCount != aNewLayers.mPositionYCount ||
1799 mSizeCount != aNewLayers.mSizeCount) {
1800 hint |= nsChangeHint_NeutralChange;
1803 return hint;
1806 nsStyleImageLayers& nsStyleImageLayers::operator=(
1807 const nsStyleImageLayers& aOther) {
1808 mAttachmentCount = aOther.mAttachmentCount;
1809 mClipCount = aOther.mClipCount;
1810 mOriginCount = aOther.mOriginCount;
1811 mRepeatCount = aOther.mRepeatCount;
1812 mPositionXCount = aOther.mPositionXCount;
1813 mPositionYCount = aOther.mPositionYCount;
1814 mImageCount = aOther.mImageCount;
1815 mSizeCount = aOther.mSizeCount;
1816 mMaskModeCount = aOther.mMaskModeCount;
1817 mBlendModeCount = aOther.mBlendModeCount;
1818 mCompositeCount = aOther.mCompositeCount;
1819 mLayers = aOther.mLayers.Clone();
1821 return *this;
1824 bool nsStyleImageLayers::operator==(const nsStyleImageLayers& aOther) const {
1825 if (mAttachmentCount != aOther.mAttachmentCount ||
1826 mClipCount != aOther.mClipCount || mOriginCount != aOther.mOriginCount ||
1827 mRepeatCount != aOther.mRepeatCount ||
1828 mPositionXCount != aOther.mPositionXCount ||
1829 mPositionYCount != aOther.mPositionYCount ||
1830 mImageCount != aOther.mImageCount || mSizeCount != aOther.mSizeCount ||
1831 mMaskModeCount != aOther.mMaskModeCount ||
1832 mBlendModeCount != aOther.mBlendModeCount) {
1833 return false;
1836 if (mLayers.Length() != aOther.mLayers.Length()) {
1837 return false;
1840 for (uint32_t i = 0; i < mLayers.Length(); i++) {
1841 if (mLayers[i].mPosition != aOther.mLayers[i].mPosition ||
1842 mLayers[i].mImage != aOther.mLayers[i].mImage ||
1843 mLayers[i].mSize != aOther.mLayers[i].mSize ||
1844 mLayers[i].mClip != aOther.mLayers[i].mClip ||
1845 mLayers[i].mOrigin != aOther.mLayers[i].mOrigin ||
1846 mLayers[i].mAttachment != aOther.mLayers[i].mAttachment ||
1847 mLayers[i].mBlendMode != aOther.mLayers[i].mBlendMode ||
1848 mLayers[i].mComposite != aOther.mLayers[i].mComposite ||
1849 mLayers[i].mMaskMode != aOther.mLayers[i].mMaskMode ||
1850 mLayers[i].mRepeat != aOther.mLayers[i].mRepeat) {
1851 return false;
1855 return true;
1858 static bool SizeDependsOnPositioningAreaSize(const StyleBackgroundSize& aSize,
1859 const StyleImage& aImage) {
1860 MOZ_ASSERT(!aImage.IsNone(), "caller should have handled this");
1861 MOZ_ASSERT(!aImage.IsImageSet(), "caller should have handled this");
1863 // Contain and cover straightforwardly depend on frame size.
1864 if (aSize.IsCover() || aSize.IsContain()) {
1865 return true;
1868 MOZ_ASSERT(aSize.IsExplicitSize());
1869 auto& size = aSize.explicit_size;
1871 // If either dimension contains a non-zero percentage, rendering for that
1872 // dimension straightforwardly depends on frame size.
1873 if (size.width.HasPercent() || size.height.HasPercent()) {
1874 return true;
1877 // If both dimensions are fixed lengths, there's no dependency.
1878 if (!size.width.IsAuto() && !size.height.IsAuto()) {
1879 return false;
1882 // Gradient rendering depends on frame size when auto is involved because
1883 // gradients have no intrinsic ratio or dimensions, and therefore the relevant
1884 // dimension is "treat[ed] as 100%".
1885 if (aImage.IsGradient()) {
1886 return true;
1889 // XXX Element rendering for auto or fixed length doesn't depend on frame size
1890 // according to the spec. However, we don't implement the spec yet, so
1891 // for now we bail and say element() plus auto affects ultimate size.
1892 if (aImage.IsElement()) {
1893 return true;
1896 MOZ_ASSERT(aImage.IsImageRequestType(), "Missed some image");
1897 if (auto* request = aImage.GetImageRequest()) {
1898 nsCOMPtr<imgIContainer> imgContainer;
1899 request->GetImage(getter_AddRefs(imgContainer));
1900 if (imgContainer) {
1901 CSSIntSize imageSize;
1902 AspectRatio imageRatio;
1903 bool hasWidth, hasHeight;
1904 // We could bother getting the right resolution here but it doesn't matter
1905 // since we ignore `imageSize`.
1906 nsLayoutUtils::ComputeSizeForDrawing(imgContainer, ImageResolution(),
1907 imageSize, imageRatio, hasWidth,
1908 hasHeight);
1910 // If the image has a fixed width and height, rendering never depends on
1911 // the frame size.
1912 if (hasWidth && hasHeight) {
1913 return false;
1916 // If the image has an intrinsic ratio, rendering will depend on frame
1917 // size when background-size is all auto.
1918 if (imageRatio) {
1919 return size.width.IsAuto() == size.height.IsAuto();
1922 // Otherwise, rendering depends on frame size when the image dimensions
1923 // and background-size don't complement each other.
1924 return !(hasWidth && size.width.IsLengthPercentage()) &&
1925 !(hasHeight && size.height.IsLengthPercentage());
1929 // Passed the gauntlet: no dependency.
1930 return false;
1933 nsStyleImageLayers::Layer::Layer()
1934 : mImage(StyleImage::None()),
1935 mSize(StyleBackgroundSize::ExplicitSize(LengthPercentageOrAuto::Auto(),
1936 LengthPercentageOrAuto::Auto())),
1938 mClip(StyleGeometryBox::BorderBox),
1939 mAttachment(StyleImageLayerAttachment::Scroll),
1940 mBlendMode(StyleBlend::Normal),
1941 mComposite(StyleMaskComposite::Add),
1942 mMaskMode(StyleMaskMode::MatchSource) {}
1944 nsStyleImageLayers::Layer::~Layer() = default;
1946 void nsStyleImageLayers::Layer::Initialize(
1947 nsStyleImageLayers::LayerType aType) {
1948 mRepeat.SetInitialValues();
1950 mPosition = Position::FromPercentage(0.);
1952 if (aType == LayerType::Background) {
1953 mOrigin = StyleGeometryBox::PaddingBox;
1954 } else {
1955 MOZ_ASSERT(aType == LayerType::Mask, "unsupported layer type.");
1956 mOrigin = StyleGeometryBox::BorderBox;
1960 bool nsStyleImageLayers::Layer::
1961 RenderingMightDependOnPositioningAreaSizeChange() const {
1962 // Do we even have an image?
1963 if (mImage.IsNone()) {
1964 return false;
1967 return mPosition.DependsOnPositioningAreaSize() ||
1968 SizeDependsOnPositioningAreaSize(mSize, mImage.FinalImage()) ||
1969 mRepeat.DependsOnPositioningAreaSize();
1972 bool nsStyleImageLayers::Layer::operator==(const Layer& aOther) const {
1973 return mAttachment == aOther.mAttachment && mClip == aOther.mClip &&
1974 mOrigin == aOther.mOrigin && mRepeat == aOther.mRepeat &&
1975 mBlendMode == aOther.mBlendMode && mPosition == aOther.mPosition &&
1976 mSize == aOther.mSize && mImage == aOther.mImage &&
1977 mMaskMode == aOther.mMaskMode && mComposite == aOther.mComposite;
1980 template <class ComputedValueItem>
1981 static void FillImageLayerList(
1982 nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
1983 ComputedValueItem nsStyleImageLayers::Layer::*aResultLocation,
1984 uint32_t aItemCount, uint32_t aFillCount) {
1985 MOZ_ASSERT(aFillCount <= aLayers.Length(), "unexpected array length");
1986 for (uint32_t sourceLayer = 0, destLayer = aItemCount; destLayer < aFillCount;
1987 ++sourceLayer, ++destLayer) {
1988 aLayers[destLayer].*aResultLocation = aLayers[sourceLayer].*aResultLocation;
1992 // The same as FillImageLayerList, but for values stored in
1993 // layer.mPosition.*aResultLocation instead of layer.*aResultLocation.
1994 static void FillImageLayerPositionCoordList(
1995 nsStyleAutoArray<nsStyleImageLayers::Layer>& aLayers,
1996 LengthPercentage Position::*aResultLocation, uint32_t aItemCount,
1997 uint32_t aFillCount) {
1998 MOZ_ASSERT(aFillCount <= aLayers.Length(), "unexpected array length");
1999 for (uint32_t sourceLayer = 0, destLayer = aItemCount; destLayer < aFillCount;
2000 ++sourceLayer, ++destLayer) {
2001 aLayers[destLayer].mPosition.*aResultLocation =
2002 aLayers[sourceLayer].mPosition.*aResultLocation;
2006 void nsStyleImageLayers::FillAllLayers(uint32_t aMaxItemCount) {
2007 // Delete any extra items. We need to keep layers in which any
2008 // property was specified.
2009 mLayers.TruncateLengthNonZero(aMaxItemCount);
2011 uint32_t fillCount = mImageCount;
2012 FillImageLayerList(mLayers, &Layer::mImage, mImageCount, fillCount);
2013 FillImageLayerList(mLayers, &Layer::mRepeat, mRepeatCount, fillCount);
2014 FillImageLayerList(mLayers, &Layer::mAttachment, mAttachmentCount, fillCount);
2015 FillImageLayerList(mLayers, &Layer::mClip, mClipCount, fillCount);
2016 FillImageLayerList(mLayers, &Layer::mBlendMode, mBlendModeCount, fillCount);
2017 FillImageLayerList(mLayers, &Layer::mOrigin, mOriginCount, fillCount);
2018 FillImageLayerPositionCoordList(mLayers, &Position::horizontal,
2019 mPositionXCount, fillCount);
2020 FillImageLayerPositionCoordList(mLayers, &Position::vertical, mPositionYCount,
2021 fillCount);
2022 FillImageLayerList(mLayers, &Layer::mSize, mSizeCount, fillCount);
2023 FillImageLayerList(mLayers, &Layer::mMaskMode, mMaskModeCount, fillCount);
2024 FillImageLayerList(mLayers, &Layer::mComposite, mCompositeCount, fillCount);
2027 static bool UrlValuesEqual(const StyleImage& aImage,
2028 const StyleImage& aOtherImage) {
2029 auto* url = aImage.GetImageRequestURLValue();
2030 auto* other = aOtherImage.GetImageRequestURLValue();
2031 return url == other || (url && other && *url == *other);
2034 nsChangeHint nsStyleImageLayers::Layer::CalcDifference(
2035 const nsStyleImageLayers::Layer& aNewLayer) const {
2036 nsChangeHint hint = nsChangeHint(0);
2037 if (!UrlValuesEqual(mImage, aNewLayer.mImage)) {
2038 hint |= nsChangeHint_RepaintFrame | nsChangeHint_UpdateEffects;
2039 } else if (mAttachment != aNewLayer.mAttachment || mClip != aNewLayer.mClip ||
2040 mOrigin != aNewLayer.mOrigin || mRepeat != aNewLayer.mRepeat ||
2041 mBlendMode != aNewLayer.mBlendMode || mSize != aNewLayer.mSize ||
2042 mImage != aNewLayer.mImage || mMaskMode != aNewLayer.mMaskMode ||
2043 mComposite != aNewLayer.mComposite) {
2044 hint |= nsChangeHint_RepaintFrame;
2047 if (mPosition != aNewLayer.mPosition) {
2048 hint |= nsChangeHint_UpdateBackgroundPosition;
2051 return hint;
2054 // --------------------
2055 // nsStyleBackground
2058 nsStyleBackground::nsStyleBackground(const Document& aDocument)
2059 : mImage(nsStyleImageLayers::LayerType::Background),
2060 mBackgroundColor(StyleColor::Transparent()) {
2061 MOZ_COUNT_CTOR(nsStyleBackground);
2064 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
2065 : mImage(aSource.mImage), mBackgroundColor(aSource.mBackgroundColor) {
2066 MOZ_COUNT_CTOR(nsStyleBackground);
2069 nsStyleBackground::~nsStyleBackground() { MOZ_COUNT_DTOR(nsStyleBackground); }
2071 void nsStyleBackground::TriggerImageLoads(Document& aDocument,
2072 const nsStyleBackground* aOldStyle) {
2073 MOZ_ASSERT(NS_IsMainThread());
2074 mImage.ResolveImages(aDocument, aOldStyle ? &aOldStyle->mImage : nullptr);
2077 nsChangeHint nsStyleBackground::CalcDifference(
2078 const nsStyleBackground& aNewData) const {
2079 nsChangeHint hint = nsChangeHint(0);
2080 if (mBackgroundColor != aNewData.mBackgroundColor) {
2081 hint |= nsChangeHint_RepaintFrame;
2084 hint |= mImage.CalcDifference(aNewData.mImage,
2085 nsStyleImageLayers::LayerType::Background);
2087 return hint;
2090 bool nsStyleBackground::HasFixedBackground(nsIFrame* aFrame) const {
2091 NS_FOR_VISIBLE_IMAGE_LAYERS_BACK_TO_FRONT(i, mImage) {
2092 const nsStyleImageLayers::Layer& layer = mImage.mLayers[i];
2093 if (layer.mAttachment == StyleImageLayerAttachment::Fixed &&
2094 !layer.mImage.IsNone() && !nsLayoutUtils::IsTransformed(aFrame)) {
2095 return true;
2098 return false;
2101 nscolor nsStyleBackground::BackgroundColor(const nsIFrame* aFrame) const {
2102 return mBackgroundColor.CalcColor(aFrame);
2105 nscolor nsStyleBackground::BackgroundColor(const ComputedStyle* aStyle) const {
2106 return mBackgroundColor.CalcColor(*aStyle);
2109 bool nsStyleBackground::IsTransparent(const nsIFrame* aFrame) const {
2110 return IsTransparent(aFrame->Style());
2113 bool nsStyleBackground::IsTransparent(const ComputedStyle* aStyle) const {
2114 return BottomLayer().mImage.IsNone() && mImage.mImageCount == 1 &&
2115 NS_GET_A(BackgroundColor(aStyle)) == 0;
2118 StyleTransition::StyleTransition(const StyleTransition& aCopy) = default;
2120 void StyleTransition::SetInitialValues() {
2121 mTimingFunction =
2122 StyleComputedTimingFunction::Keyword(StyleTimingKeyword::Ease);
2123 mDuration = {0.0};
2124 mDelay = {0.0};
2125 mProperty = eCSSPropertyExtra_all_properties;
2128 bool StyleTransition::operator==(const StyleTransition& aOther) const {
2129 return mTimingFunction == aOther.mTimingFunction &&
2130 mDuration == aOther.mDuration && mDelay == aOther.mDelay &&
2131 mProperty == aOther.mProperty &&
2132 (mProperty != eCSSProperty_UNKNOWN ||
2133 mUnknownProperty == aOther.mUnknownProperty);
2136 StyleAnimation::StyleAnimation(const StyleAnimation& aCopy) = default;
2138 void StyleAnimation::SetInitialValues() {
2139 mTimingFunction =
2140 StyleComputedTimingFunction::Keyword(StyleTimingKeyword::Ease);
2141 mDuration = {0.0};
2142 mDelay = {0.0};
2143 mName = nsGkAtoms::_empty;
2144 mDirection = dom::PlaybackDirection::Normal;
2145 mFillMode = dom::FillMode::None;
2146 mPlayState = StyleAnimationPlayState::Running;
2147 mIterationCount = {1.0f};
2148 mComposition = dom::CompositeOperation::Replace;
2149 mTimeline = StyleAnimationTimeline::Auto();
2152 bool StyleAnimation::operator==(const StyleAnimation& aOther) const {
2153 return mTimingFunction == aOther.mTimingFunction &&
2154 mDuration == aOther.mDuration && mDelay == aOther.mDelay &&
2155 mName == aOther.mName && mDirection == aOther.mDirection &&
2156 mFillMode == aOther.mFillMode && mPlayState == aOther.mPlayState &&
2157 mIterationCount == aOther.mIterationCount &&
2158 mComposition == aOther.mComposition && mTimeline == aOther.mTimeline;
2161 // --------------------
2162 // nsStyleDisplay
2164 nsStyleDisplay::nsStyleDisplay(const Document& aDocument)
2165 : mDisplay(StyleDisplay::Inline),
2166 mOriginalDisplay(StyleDisplay::Inline),
2167 mContentVisibility(StyleContentVisibility::Visible),
2168 mContainerType(StyleContainerType::Normal),
2169 mAppearance(StyleAppearance::None),
2170 mContain(StyleContain::NONE),
2171 mEffectiveContainment(StyleContain::NONE),
2172 mDefaultAppearance(StyleAppearance::None),
2173 mPosition(StylePositionProperty::Static),
2174 mFloat(StyleFloat::None),
2175 mClear(StyleClear::None),
2176 mBreakInside(StyleBreakWithin::Auto),
2177 mBreakBefore(StyleBreakBetween::Auto),
2178 mBreakAfter(StyleBreakBetween::Auto),
2179 mOverflowX(StyleOverflow::Visible),
2180 mOverflowY(StyleOverflow::Visible),
2181 mOverflowClipBoxBlock(StyleOverflowClipBox::PaddingBox),
2182 mOverflowClipBoxInline(StyleOverflowClipBox::PaddingBox),
2183 mScrollbarGutter(StyleScrollbarGutter::AUTO),
2184 mResize(StyleResize::None),
2185 mOrient(StyleOrient::Inline),
2186 mIsolation(StyleIsolation::Auto),
2187 mTopLayer(StyleTopLayer::None),
2188 mTouchAction(StyleTouchAction::AUTO),
2189 mScrollBehavior(StyleScrollBehavior::Auto),
2190 mOverscrollBehaviorX(StyleOverscrollBehavior::Auto),
2191 mOverscrollBehaviorY(StyleOverscrollBehavior::Auto),
2192 mOverflowAnchor(StyleOverflowAnchor::Auto),
2193 mScrollSnapAlign{StyleScrollSnapAlignKeyword::None,
2194 StyleScrollSnapAlignKeyword::None},
2195 mScrollSnapType{StyleScrollSnapAxis::Both,
2196 StyleScrollSnapStrictness::None},
2197 mBackfaceVisibility(StyleBackfaceVisibility::Visible),
2198 mTransformStyle(StyleTransformStyle::Flat),
2199 mTransformBox(StyleGeometryBox::BorderBox),
2200 mRotate(StyleRotate::None()),
2201 mTranslate(StyleTranslate::None()),
2202 mScale(StyleScale::None()),
2203 mWillChange{{}, {0}},
2204 mOffsetPath(StyleOffsetPath::None()),
2205 mOffsetDistance(LengthPercentage::Zero()),
2206 mOffsetRotate{true, StyleAngle{0.0}},
2207 mOffsetAnchor(StylePositionOrAuto::Auto()),
2208 mOffsetPosition(StyleOffsetPosition::Auto()),
2209 mTransformOrigin{LengthPercentage::FromPercentage(0.5),
2210 LengthPercentage::FromPercentage(0.5),
2211 {0.}},
2212 mChildPerspective(StylePerspective::None()),
2213 mPerspectiveOrigin(Position::FromPercentage(0.5f)),
2214 mVerticalAlign(
2215 StyleVerticalAlign::Keyword(StyleVerticalAlignKeyword::Baseline)),
2216 mBaselineSource(StyleBaselineSource::Auto),
2217 mWebkitLineClamp(0),
2218 mShapeMargin(LengthPercentage::Zero()),
2219 mShapeOutside(StyleShapeOutside::None()) {
2220 MOZ_COUNT_CTOR(nsStyleDisplay);
2223 nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
2224 : mDisplay(aSource.mDisplay),
2225 mOriginalDisplay(aSource.mOriginalDisplay),
2226 mContentVisibility(aSource.mContentVisibility),
2227 mContainerType(aSource.mContainerType),
2228 mAppearance(aSource.mAppearance),
2229 mContain(aSource.mContain),
2230 mEffectiveContainment(aSource.mEffectiveContainment),
2231 mDefaultAppearance(aSource.mDefaultAppearance),
2232 mPosition(aSource.mPosition),
2233 mFloat(aSource.mFloat),
2234 mClear(aSource.mClear),
2235 mBreakInside(aSource.mBreakInside),
2236 mBreakBefore(aSource.mBreakBefore),
2237 mBreakAfter(aSource.mBreakAfter),
2238 mOverflowX(aSource.mOverflowX),
2239 mOverflowY(aSource.mOverflowY),
2240 mOverflowClipBoxBlock(aSource.mOverflowClipBoxBlock),
2241 mOverflowClipBoxInline(aSource.mOverflowClipBoxInline),
2242 mScrollbarGutter(aSource.mScrollbarGutter),
2243 mResize(aSource.mResize),
2244 mOrient(aSource.mOrient),
2245 mIsolation(aSource.mIsolation),
2246 mTopLayer(aSource.mTopLayer),
2247 mTouchAction(aSource.mTouchAction),
2248 mScrollBehavior(aSource.mScrollBehavior),
2249 mOverscrollBehaviorX(aSource.mOverscrollBehaviorX),
2250 mOverscrollBehaviorY(aSource.mOverscrollBehaviorY),
2251 mOverflowAnchor(aSource.mOverflowAnchor),
2252 mScrollSnapAlign(aSource.mScrollSnapAlign),
2253 mScrollSnapType(aSource.mScrollSnapType),
2254 mBackfaceVisibility(aSource.mBackfaceVisibility),
2255 mTransformStyle(aSource.mTransformStyle),
2256 mTransformBox(aSource.mTransformBox),
2257 mTransform(aSource.mTransform),
2258 mRotate(aSource.mRotate),
2259 mTranslate(aSource.mTranslate),
2260 mScale(aSource.mScale),
2261 mContainerName(aSource.mContainerName),
2262 mWillChange(aSource.mWillChange),
2263 mOffsetPath(aSource.mOffsetPath),
2264 mOffsetDistance(aSource.mOffsetDistance),
2265 mOffsetRotate(aSource.mOffsetRotate),
2266 mOffsetAnchor(aSource.mOffsetAnchor),
2267 mOffsetPosition(aSource.mOffsetPosition),
2268 mTransformOrigin(aSource.mTransformOrigin),
2269 mChildPerspective(aSource.mChildPerspective),
2270 mPerspectiveOrigin(aSource.mPerspectiveOrigin),
2271 mVerticalAlign(aSource.mVerticalAlign),
2272 mBaselineSource(aSource.mBaselineSource),
2273 mWebkitLineClamp(aSource.mWebkitLineClamp),
2274 mShapeImageThreshold(aSource.mShapeImageThreshold),
2275 mShapeMargin(aSource.mShapeMargin),
2276 mShapeOutside(aSource.mShapeOutside) {
2277 MOZ_COUNT_CTOR(nsStyleDisplay);
2280 nsStyleDisplay::~nsStyleDisplay() { MOZ_COUNT_DTOR(nsStyleDisplay); }
2282 void nsStyleDisplay::TriggerImageLoads(Document& aDocument,
2283 const nsStyleDisplay* aOldStyle) {
2284 MOZ_ASSERT(NS_IsMainThread());
2286 if (mShapeOutside.IsImage()) {
2287 auto* old = aOldStyle && aOldStyle->mShapeOutside.IsImage()
2288 ? &aOldStyle->mShapeOutside.AsImage()
2289 : nullptr;
2290 // Const-cast is ugly but legit, we could avoid it by generating mut-casts
2291 // with cbindgen.
2292 const_cast<StyleImage&>(mShapeOutside.AsImage())
2293 .ResolveImage(aDocument, old);
2297 template <typename TransformLike>
2298 static inline nsChangeHint CompareTransformValues(
2299 const TransformLike& aOldTransform, const TransformLike& aNewTransform) {
2300 nsChangeHint result = nsChangeHint(0);
2302 // Note: If we add a new change hint for transform changes here, we have to
2303 // modify KeyframeEffect::CalculateCumulativeChangeHint too!
2304 if (aOldTransform != aNewTransform) {
2305 result |= nsChangeHint_UpdateTransformLayer;
2306 if (!aOldTransform.IsNone() && !aNewTransform.IsNone()) {
2307 result |= nsChangeHint_UpdatePostTransformOverflow;
2308 } else {
2309 result |= nsChangeHint_UpdateOverflow;
2313 return result;
2316 static inline nsChangeHint CompareMotionValues(
2317 const nsStyleDisplay& aDisplay, const nsStyleDisplay& aNewDisplay) {
2318 if (aDisplay.mOffsetPath == aNewDisplay.mOffsetPath) {
2319 if (aDisplay.mOffsetDistance == aNewDisplay.mOffsetDistance &&
2320 aDisplay.mOffsetRotate == aNewDisplay.mOffsetRotate &&
2321 aDisplay.mOffsetAnchor == aNewDisplay.mOffsetAnchor &&
2322 aDisplay.mOffsetPosition == aNewDisplay.mOffsetPosition) {
2323 return nsChangeHint(0);
2326 // No motion path transform is applied.
2327 if (aDisplay.mOffsetPath.IsNone()) {
2328 return nsChangeHint_NeutralChange;
2332 // TODO: Bug 1482737: This probably doesn't need to UpdateOverflow
2333 // (or UpdateTransformLayer) if there's already a transform.
2334 // Set the same hints as what we use for transform because motion path is
2335 // a kind of transform and will be combined with other transforms.
2336 nsChangeHint result = nsChangeHint_UpdateTransformLayer;
2337 if (!aDisplay.mOffsetPath.IsNone() && !aNewDisplay.mOffsetPath.IsNone()) {
2338 result |= nsChangeHint_UpdatePostTransformOverflow;
2339 } else {
2340 result |= nsChangeHint_UpdateOverflow;
2342 return result;
2345 static bool ScrollbarGenerationChanged(const nsStyleDisplay& aOld,
2346 const nsStyleDisplay& aNew) {
2347 auto changed = [](StyleOverflow aOld, StyleOverflow aNew) {
2348 return aOld != aNew &&
2349 (aOld == StyleOverflow::Hidden || aNew == StyleOverflow::Hidden);
2351 return changed(aOld.mOverflowX, aNew.mOverflowX) ||
2352 changed(aOld.mOverflowY, aNew.mOverflowY);
2355 static bool AppearanceValueAffectsFrames(StyleAppearance aAppearance,
2356 StyleAppearance aDefaultAppearance) {
2357 switch (aAppearance) {
2358 case StyleAppearance::Textfield:
2359 // This is for <input type=number/search> where we allow authors to
2360 // specify a |-moz-appearance:textfield| to get a control without buttons.
2361 // We need to reframe since this affects the spinbox creation in
2362 // nsNumber/SearchControlFrame::CreateAnonymousContent.
2363 return aDefaultAppearance == StyleAppearance::NumberInput ||
2364 aDefaultAppearance == StyleAppearance::Searchfield;
2365 case StyleAppearance::Menulist:
2366 // This affects the menulist button creation.
2367 return aDefaultAppearance == StyleAppearance::Menulist;
2368 default:
2369 return false;
2373 nsChangeHint nsStyleDisplay::CalcDifference(
2374 const nsStyleDisplay& aNewData, const nsStylePosition& aOldPosition) const {
2375 if (mDisplay != aNewData.mDisplay || mContain != aNewData.mContain ||
2376 (mFloat == StyleFloat::None) != (aNewData.mFloat == StyleFloat::None) ||
2377 mTopLayer != aNewData.mTopLayer || mResize != aNewData.mResize) {
2378 return nsChangeHint_ReconstructFrame;
2381 // `content-visibility` can impact whether or not this frame has containment,
2382 // so we reconstruct the frame like we do above.
2383 // TODO: We should avoid reconstruction here, per bug 1765615.
2384 if (mContentVisibility != aNewData.mContentVisibility) {
2385 return nsChangeHint_ReconstructFrame;
2388 // Same issue as above for now.
2389 if (mContainerType != aNewData.mContainerType) {
2390 return nsChangeHint_ReconstructFrame;
2393 auto oldAppearance = EffectiveAppearance();
2394 auto newAppearance = aNewData.EffectiveAppearance();
2395 if (oldAppearance != newAppearance) {
2396 // Changes to the relevant default appearance changes in
2397 // AppearanceValueRequiresFrameReconstruction require reconstruction on
2398 // their own, so we can just pick either the new or the old.
2399 if (AppearanceValueAffectsFrames(oldAppearance, mDefaultAppearance) ||
2400 AppearanceValueAffectsFrames(newAppearance, mDefaultAppearance)) {
2401 return nsChangeHint_ReconstructFrame;
2405 auto hint = nsChangeHint(0);
2406 if (mPosition != aNewData.mPosition) {
2407 if (IsAbsolutelyPositionedStyle() ||
2408 aNewData.IsAbsolutelyPositionedStyle()) {
2409 // This changes our parent relationship on the frame tree and / or needs
2410 // to create a placeholder, so gotta reframe. There are some cases (when
2411 // switching from fixed to absolute or viceversa, if our containing block
2412 // happens to remain the same, i.e., if it has a transform or such) where
2413 // this wouldn't really be needed (though we'd still need to move the
2414 // frame from one child list to another). In any case we don't have a hand
2415 // to that information from here, and it doesn't seem like a case worth
2416 // optimizing for.
2417 return nsChangeHint_ReconstructFrame;
2419 // We start or stop being a containing block for abspos descendants. This
2420 // also causes painting to change, as we'd become a pseudo-stacking context.
2421 if (IsRelativelyOrStickyPositionedStyle() !=
2422 aNewData.IsRelativelyOrStickyPositionedStyle()) {
2423 hint |= nsChangeHint_UpdateContainingBlock | nsChangeHint_RepaintFrame;
2425 if (IsPositionForcingStackingContext() !=
2426 aNewData.IsPositionForcingStackingContext()) {
2427 hint |= nsChangeHint_RepaintFrame;
2429 // On top of that: if the above ends up not reframing, we need a reflow to
2430 // compute our relative, static or sticky position.
2431 hint |= nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition;
2434 if (mScrollSnapAlign != aNewData.mScrollSnapAlign ||
2435 mScrollSnapType != aNewData.mScrollSnapType ||
2436 mScrollSnapStop != aNewData.mScrollSnapStop) {
2437 hint |= nsChangeHint_RepaintFrame;
2439 if (mScrollBehavior != aNewData.mScrollBehavior) {
2440 hint |= nsChangeHint_NeutralChange;
2443 if (mOverflowX != aNewData.mOverflowX || mOverflowY != aNewData.mOverflowY) {
2444 const bool isScrollable = IsScrollableOverflow();
2445 if (isScrollable != aNewData.IsScrollableOverflow()) {
2446 // We may need to construct or destroy a scroll frame as a result of this
2447 // change.
2448 hint |= nsChangeHint_ScrollbarChange;
2449 } else if (isScrollable) {
2450 if (ScrollbarGenerationChanged(*this, aNewData)) {
2451 // We might need to reframe in the case of hidden -> non-hidden case
2452 // though, since nsHTMLScrollFrame::CreateAnonymousContent avoids
2453 // creating scrollbars altogether for overflow: hidden. That seems it
2454 // could create some interesting perf cliffs...
2455 hint |= nsChangeHint_ScrollbarChange;
2456 } else {
2457 // Otherwise, for changes where both overflow values are scrollable,
2458 // means that scrollbars may appear or disappear. We need to reflow,
2459 // since reflow is what determines which scrollbars if any are visible.
2460 hint |= nsChangeHint_ReflowHintsForScrollbarChange;
2462 } else {
2463 // Otherwise this is a change between 'visible' and 'clip'.
2464 // Here only whether we have a 'clip' changes, so just repaint and
2465 // update our overflow areas in that case.
2466 hint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
2470 if (mScrollbarGutter != aNewData.mScrollbarGutter) {
2471 if (IsScrollableOverflow()) {
2472 // Changing scrollbar-gutter affects available inline-size of a inner
2473 // scrolled frame, so we need a reflow for scrollbar change.
2474 hint |= nsChangeHint_ReflowHintsForScrollbarChange;
2475 } else {
2476 // scrollbar-gutter only applies to the scroll containers.
2477 hint |= nsChangeHint_NeutralChange;
2481 if (mFloat != aNewData.mFloat) {
2482 // Changing which side we're floating on (float:none was handled above).
2483 hint |= nsChangeHint_ReflowHintsForFloatAreaChange;
2486 if (mShapeOutside != aNewData.mShapeOutside ||
2487 mShapeMargin != aNewData.mShapeMargin ||
2488 mShapeImageThreshold != aNewData.mShapeImageThreshold) {
2489 if (aNewData.mFloat != StyleFloat::None) {
2490 // If we are floating, and our shape-outside, shape-margin, or
2491 // shape-image-threshold are changed, our descendants are not impacted,
2492 // but our ancestor and siblings are.
2493 hint |= nsChangeHint_ReflowHintsForFloatAreaChange;
2494 } else {
2495 // shape-outside or shape-margin or shape-image-threshold changed,
2496 // but we don't need to reflow because we're not floating.
2497 hint |= nsChangeHint_NeutralChange;
2501 if (mWebkitLineClamp != aNewData.mWebkitLineClamp ||
2502 mVerticalAlign != aNewData.mVerticalAlign ||
2503 mBaselineSource != aNewData.mBaselineSource) {
2504 // XXX Can this just be AllReflowHints + RepaintFrame, and be included in
2505 // the block below?
2506 hint |= NS_STYLE_HINT_REFLOW;
2509 // XXX the following is conservative, for now: changing float breaking
2510 // shouldn't necessarily require a repaint, reflow should suffice.
2512 // FIXME(emilio): We definitely change the frame tree in nsCSSFrameConstructor
2513 // based on break-before / break-after... Shouldn't that reframe?
2514 if (mClear != aNewData.mClear || mBreakInside != aNewData.mBreakInside ||
2515 mBreakBefore != aNewData.mBreakBefore ||
2516 mBreakAfter != aNewData.mBreakAfter ||
2517 mAppearance != aNewData.mAppearance ||
2518 mDefaultAppearance != aNewData.mDefaultAppearance ||
2519 mOrient != aNewData.mOrient ||
2520 mOverflowClipBoxBlock != aNewData.mOverflowClipBoxBlock ||
2521 mOverflowClipBoxInline != aNewData.mOverflowClipBoxInline) {
2522 hint |= nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
2525 if (mIsolation != aNewData.mIsolation) {
2526 hint |= nsChangeHint_RepaintFrame;
2529 /* If we've added or removed the transform property, we need to reconstruct
2530 * the frame to add or remove the view object, and also to handle abs-pos and
2531 * fixed-pos containers.
2533 if (HasTransformStyle() != aNewData.HasTransformStyle()) {
2534 hint |= nsChangeHint_ComprehensiveAddOrRemoveTransform;
2535 } else {
2536 /* Otherwise, if we've kept the property lying around and we already had a
2537 * transform, we need to see whether or not we've changed the transform.
2538 * If so, we need to recompute its overflow rect (which probably changed
2539 * if the transform changed) and to redraw within the bounds of that new
2540 * overflow rect.
2542 * If the property isn't present in either style struct, we still do the
2543 * comparisons but turn all the resulting change hints into
2544 * nsChangeHint_NeutralChange.
2546 nsChangeHint transformHint = CalcTransformPropertyDifference(aNewData);
2548 if (transformHint) {
2549 if (HasTransformStyle()) {
2550 hint |= transformHint;
2551 } else {
2552 hint |= nsChangeHint_NeutralChange;
2557 if (HasPerspectiveStyle() != aNewData.HasPerspectiveStyle()) {
2558 // A change from/to being a containing block for position:fixed.
2559 hint |= nsChangeHint_UpdateContainingBlock | nsChangeHint_UpdateOverflow |
2560 nsChangeHint_RepaintFrame;
2561 } else if (mChildPerspective != aNewData.mChildPerspective) {
2562 hint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
2565 // Note that the HasTransformStyle() != aNewData.HasTransformStyle()
2566 // test above handles relevant changes in the StyleWillChangeBit_TRANSFORM
2567 // bit, which in turn handles frame reconstruction for changes in the
2568 // containing block of fixed-positioned elements.
2569 auto willChangeBitsChanged = mWillChange.bits ^ aNewData.mWillChange.bits;
2571 if (willChangeBitsChanged &
2572 (StyleWillChangeBits::STACKING_CONTEXT_UNCONDITIONAL |
2573 StyleWillChangeBits::SCROLL | StyleWillChangeBits::OPACITY |
2574 StyleWillChangeBits::PERSPECTIVE | StyleWillChangeBits::TRANSFORM |
2575 StyleWillChangeBits::Z_INDEX)) {
2576 hint |= nsChangeHint_RepaintFrame;
2579 if (willChangeBitsChanged &
2580 (StyleWillChangeBits::FIXPOS_CB_NON_SVG | StyleWillChangeBits::TRANSFORM |
2581 StyleWillChangeBits::PERSPECTIVE | StyleWillChangeBits::POSITION |
2582 StyleWillChangeBits::CONTAIN)) {
2583 hint |= nsChangeHint_UpdateContainingBlock;
2586 // If touch-action is changed, we need to regenerate the event regions on
2587 // the layers and send it over to the compositor for APZ to handle.
2588 if (mTouchAction != aNewData.mTouchAction) {
2589 hint |= nsChangeHint_RepaintFrame;
2592 // If overscroll-behavior has changed, the changes are picked up
2593 // during a repaint.
2594 if (mOverscrollBehaviorX != aNewData.mOverscrollBehaviorX ||
2595 mOverscrollBehaviorY != aNewData.mOverscrollBehaviorY) {
2596 hint |= nsChangeHint_SchedulePaint;
2599 if (mOriginalDisplay != aNewData.mOriginalDisplay) {
2600 // Our hypothetical box position may have changed.
2602 // Note that it doesn't matter if we look at the old or the new struct,
2603 // since a change on whether we need a hypothetical position would trigger
2604 // reflow anyway.
2605 if (IsAbsolutelyPositionedStyle() &&
2606 aOldPosition.NeedsHypotheticalPositionIfAbsPos()) {
2607 hint |=
2608 nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition;
2609 } else {
2610 hint |= nsChangeHint_NeutralChange;
2614 // Note: Our current behavior for handling changes to the
2615 // transition-duration, transition-delay, and transition-timing-function
2616 // properties is to do nothing. In other words, the transition
2617 // property that matters is what it is when the transition begins, and
2618 // we don't stop a transition later because the transition property
2619 // changed.
2620 // We do handle changes to transition-property, but we don't need to
2621 // bother with anything here, since the transition manager is notified
2622 // of any ComputedStyle change anyway.
2624 // Note: Likewise, for animation-*, the animation manager gets
2625 // notified about every new ComputedStyle constructed, and it uses
2626 // that opportunity to handle dynamic changes appropriately.
2628 // But we still need to return nsChangeHint_NeutralChange for these
2629 // properties, since some data did change in the style struct.
2631 // TODO(emilio): Figure out change hints for container-name, maybe it needs to
2632 // be handled by the style system as a special-case (since it changes
2633 // container-query selection on descendants).
2634 if (!hint && (mWillChange != aNewData.mWillChange ||
2635 mOverflowAnchor != aNewData.mOverflowAnchor ||
2636 mContainerName != aNewData.mContainerName)) {
2637 hint |= nsChangeHint_NeutralChange;
2640 return hint;
2643 nsChangeHint nsStyleDisplay::CalcTransformPropertyDifference(
2644 const nsStyleDisplay& aNewData) const {
2645 nsChangeHint transformHint = nsChangeHint(0);
2647 transformHint |= CompareTransformValues(mTransform, aNewData.mTransform);
2648 transformHint |= CompareTransformValues(mRotate, aNewData.mRotate);
2649 transformHint |= CompareTransformValues(mTranslate, aNewData.mTranslate);
2650 transformHint |= CompareTransformValues(mScale, aNewData.mScale);
2651 transformHint |= CompareMotionValues(*this, aNewData);
2653 if (mTransformOrigin != aNewData.mTransformOrigin) {
2654 transformHint |= nsChangeHint_UpdateTransformLayer |
2655 nsChangeHint_UpdatePostTransformOverflow;
2658 if (mPerspectiveOrigin != aNewData.mPerspectiveOrigin ||
2659 mTransformStyle != aNewData.mTransformStyle ||
2660 mTransformBox != aNewData.mTransformBox) {
2661 transformHint |= nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame;
2664 if (mBackfaceVisibility != aNewData.mBackfaceVisibility) {
2665 transformHint |= nsChangeHint_RepaintFrame;
2668 return transformHint;
2671 // --------------------
2672 // nsStyleVisibility
2675 nsStyleVisibility::nsStyleVisibility(const Document& aDocument)
2676 : mDirection(aDocument.GetBidiOptions() == IBMBIDI_TEXTDIRECTION_RTL
2677 ? StyleDirection::Rtl
2678 : StyleDirection::Ltr),
2679 mVisible(StyleVisibility::Visible),
2680 mImageRendering(StyleImageRendering::Auto),
2681 mWritingMode(StyleWritingModeProperty::HorizontalTb),
2682 mTextOrientation(StyleTextOrientation::Mixed),
2683 mMozBoxCollapse(StyleMozBoxCollapse::Flex),
2684 mPrintColorAdjust(StylePrintColorAdjust::Economy),
2685 mImageOrientation(StyleImageOrientation::FromImage) {
2686 MOZ_COUNT_CTOR(nsStyleVisibility);
2689 nsStyleVisibility::nsStyleVisibility(const nsStyleVisibility& aSource)
2690 : mDirection(aSource.mDirection),
2691 mVisible(aSource.mVisible),
2692 mImageRendering(aSource.mImageRendering),
2693 mWritingMode(aSource.mWritingMode),
2694 mTextOrientation(aSource.mTextOrientation),
2695 mMozBoxCollapse(aSource.mMozBoxCollapse),
2696 mPrintColorAdjust(aSource.mPrintColorAdjust),
2697 mImageOrientation(aSource.mImageOrientation) {
2698 MOZ_COUNT_CTOR(nsStyleVisibility);
2701 nsChangeHint nsStyleVisibility::CalcDifference(
2702 const nsStyleVisibility& aNewData) const {
2703 nsChangeHint hint = nsChangeHint(0);
2705 if (mDirection != aNewData.mDirection ||
2706 mWritingMode != aNewData.mWritingMode) {
2707 // It's important that a change in mWritingMode results in frame
2708 // reconstruction, because it may affect intrinsic size (see
2709 // nsSubDocumentFrame::GetIntrinsicISize/BSize).
2710 // Also, the used writing-mode value is now a field on nsIFrame and some
2711 // classes (e.g. table rows/cells) copy their value from an ancestor.
2712 return nsChangeHint_ReconstructFrame;
2714 if (mImageOrientation != aNewData.mImageOrientation) {
2715 hint |= nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
2717 if (mVisible != aNewData.mVisible) {
2718 if (mVisible == StyleVisibility::Visible ||
2719 aNewData.mVisible == StyleVisibility::Visible) {
2720 hint |= nsChangeHint_VisibilityChange;
2722 if (mVisible == StyleVisibility::Collapse ||
2723 aNewData.mVisible == StyleVisibility::Collapse) {
2724 hint |= NS_STYLE_HINT_REFLOW;
2725 } else {
2726 hint |= NS_STYLE_HINT_VISUAL;
2729 if (mTextOrientation != aNewData.mTextOrientation ||
2730 mMozBoxCollapse != aNewData.mMozBoxCollapse) {
2731 hint |= NS_STYLE_HINT_REFLOW;
2733 if (mImageRendering != aNewData.mImageRendering) {
2734 hint |= nsChangeHint_RepaintFrame;
2736 if (mPrintColorAdjust != aNewData.mPrintColorAdjust) {
2737 // color-adjust only affects media where dynamic changes can't happen.
2738 hint |= nsChangeHint_NeutralChange;
2740 return hint;
2743 StyleImageOrientation nsStyleVisibility::UsedImageOrientation(
2744 imgIRequest* aRequest, StyleImageOrientation aOrientation) {
2745 if (aOrientation == StyleImageOrientation::FromImage || !aRequest) {
2746 return aOrientation;
2749 nsCOMPtr<nsIPrincipal> triggeringPrincipal =
2750 aRequest->GetTriggeringPrincipal();
2752 // If the request was for a blob, the request may not have a triggering
2753 // principal and we should use the input orientation.
2754 if (!triggeringPrincipal) {
2755 return aOrientation;
2758 nsCOMPtr<nsIURI> uri = aRequest->GetURI();
2759 // If the image request is a data uri, then treat the request as a
2760 // same origin request.
2761 bool isSameOrigin =
2762 uri->SchemeIs("data") || triggeringPrincipal->IsSameOrigin(uri);
2764 // If the image request is a cross-origin request that does not use CORS,
2765 // do not enforce the image orientation found in the style. Use the image
2766 // orientation found in the exif data.
2767 if (!isSameOrigin && !nsLayoutUtils::ImageRequestUsesCORS(aRequest)) {
2768 return StyleImageOrientation::FromImage;
2771 return aOrientation;
2774 //-----------------------
2775 // nsStyleContent
2778 nsStyleContent::nsStyleContent(const Document& aDocument)
2779 : mContent(StyleContent::Normal()) {
2780 MOZ_COUNT_CTOR(nsStyleContent);
2783 nsStyleContent::~nsStyleContent() { MOZ_COUNT_DTOR(nsStyleContent); }
2785 nsStyleContent::nsStyleContent(const nsStyleContent& aSource)
2786 : mContent(aSource.mContent),
2787 mCounterIncrement(aSource.mCounterIncrement),
2788 mCounterReset(aSource.mCounterReset),
2789 mCounterSet(aSource.mCounterSet) {
2790 MOZ_COUNT_CTOR(nsStyleContent);
2793 nsChangeHint nsStyleContent::CalcDifference(
2794 const nsStyleContent& aNewData) const {
2795 // Unfortunately we need to reframe even if the content lengths are the same;
2796 // a simple reflow will not pick up different text or different image URLs,
2797 // since we set all that up in the CSSFrameConstructor
2798 if (mContent != aNewData.mContent ||
2799 mCounterIncrement != aNewData.mCounterIncrement ||
2800 mCounterReset != aNewData.mCounterReset ||
2801 mCounterSet != aNewData.mCounterSet) {
2802 return nsChangeHint_ReconstructFrame;
2805 return nsChangeHint(0);
2808 void nsStyleContent::TriggerImageLoads(Document& aDoc,
2809 const nsStyleContent* aOld) {
2810 if (!mContent.IsItems()) {
2811 return;
2814 Span<const StyleContentItem> oldItems;
2815 if (aOld && aOld->mContent.IsItems()) {
2816 oldItems = aOld->mContent.AsItems().AsSpan();
2819 auto items = mContent.AsItems().AsSpan();
2821 for (size_t i = 0; i < items.Length(); ++i) {
2822 auto& item = items[i];
2823 if (!item.IsImage()) {
2824 continue;
2826 auto& image = item.AsImage();
2827 auto* oldImage = i < oldItems.Length() && oldItems[i].IsImage()
2828 ? &oldItems[i].AsImage()
2829 : nullptr;
2830 const_cast<StyleImage&>(image).ResolveImage(aDoc, oldImage);
2834 // --------------------
2835 // nsStyleTextReset
2838 nsStyleTextReset::nsStyleTextReset(const Document& aDocument)
2839 : mTextOverflow(),
2840 mTextDecorationLine(StyleTextDecorationLine::NONE),
2841 mTextDecorationStyle(StyleTextDecorationStyle::Solid),
2842 mUnicodeBidi(StyleUnicodeBidi::Normal),
2843 mInitialLetterSink(0),
2844 mInitialLetterSize(0.0f),
2845 mTextDecorationColor(StyleColor::CurrentColor()),
2846 mTextDecorationThickness(StyleTextDecorationLength::Auto()) {
2847 MOZ_COUNT_CTOR(nsStyleTextReset);
2850 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
2851 : mTextOverflow(aSource.mTextOverflow),
2852 mTextDecorationLine(aSource.mTextDecorationLine),
2853 mTextDecorationStyle(aSource.mTextDecorationStyle),
2854 mUnicodeBidi(aSource.mUnicodeBidi),
2855 mInitialLetterSink(aSource.mInitialLetterSink),
2856 mInitialLetterSize(aSource.mInitialLetterSize),
2857 mTextDecorationColor(aSource.mTextDecorationColor),
2858 mTextDecorationThickness(aSource.mTextDecorationThickness) {
2859 MOZ_COUNT_CTOR(nsStyleTextReset);
2862 nsStyleTextReset::~nsStyleTextReset() { MOZ_COUNT_DTOR(nsStyleTextReset); }
2864 nsChangeHint nsStyleTextReset::CalcDifference(
2865 const nsStyleTextReset& aNewData) const {
2866 if (mUnicodeBidi != aNewData.mUnicodeBidi ||
2867 mInitialLetterSink != aNewData.mInitialLetterSink ||
2868 mInitialLetterSize != aNewData.mInitialLetterSize) {
2869 return NS_STYLE_HINT_REFLOW;
2872 if (mTextDecorationLine != aNewData.mTextDecorationLine ||
2873 mTextDecorationStyle != aNewData.mTextDecorationStyle ||
2874 mTextDecorationThickness != aNewData.mTextDecorationThickness) {
2875 // Changes to our text-decoration line can impact our overflow area &
2876 // also our descendants' overflow areas (particularly for text-frame
2877 // descendants). So, we update those areas & trigger a repaint.
2878 return nsChangeHint_RepaintFrame | nsChangeHint_UpdateSubtreeOverflow |
2879 nsChangeHint_SchedulePaint;
2882 // Repaint for decoration color changes
2883 if (mTextDecorationColor != aNewData.mTextDecorationColor) {
2884 return nsChangeHint_RepaintFrame;
2887 if (mTextOverflow != aNewData.mTextOverflow) {
2888 return nsChangeHint_RepaintFrame;
2891 return nsChangeHint(0);
2894 // --------------------
2895 // nsStyleText
2898 static StyleAbsoluteColor DefaultColor(const Document& aDocument) {
2899 return StyleAbsoluteColor::FromColor(
2900 PreferenceSheet::PrefsFor(aDocument)
2901 .ColorsFor(aDocument.DefaultColorScheme())
2902 .mDefault);
2905 nsStyleText::nsStyleText(const Document& aDocument)
2906 : mColor(DefaultColor(aDocument)),
2907 mForcedColorAdjust(StyleForcedColorAdjust::Auto),
2908 mTextTransform(StyleTextTransform::None()),
2909 mTextAlign(StyleTextAlign::Start),
2910 mTextAlignLast(StyleTextAlignLast::Auto),
2911 mTextJustify(StyleTextJustify::Auto),
2912 mWhiteSpace(StyleWhiteSpace::Normal),
2913 mHyphens(StyleHyphens::Manual),
2914 mRubyAlign(StyleRubyAlign::SpaceAround),
2915 mRubyPosition(StyleRubyPosition::AlternateOver),
2916 mTextSizeAdjust(StyleTextSizeAdjust::Auto),
2917 mTextCombineUpright(StyleTextCombineUpright::None),
2918 mMozControlCharacterVisibility(
2919 StaticPrefs::layout_css_control_characters_visible()
2920 ? StyleMozControlCharacterVisibility::Visible
2921 : StyleMozControlCharacterVisibility::Hidden),
2922 mTextRendering(StyleTextRendering::Auto),
2923 mTextEmphasisColor(StyleColor::CurrentColor()),
2924 mWebkitTextFillColor(StyleColor::CurrentColor()),
2925 mWebkitTextStrokeColor(StyleColor::CurrentColor()),
2926 mTabSize(StyleNonNegativeLengthOrNumber::Number(8.f)),
2927 mWordSpacing(LengthPercentage::Zero()),
2928 mLetterSpacing({0.}),
2929 mLineHeight(StyleLineHeight::Normal()),
2930 mTextIndent(LengthPercentage::Zero()),
2931 mTextUnderlineOffset(LengthPercentageOrAuto::Auto()),
2932 mTextDecorationSkipInk(StyleTextDecorationSkipInk::Auto),
2933 mTextUnderlinePosition(StyleTextUnderlinePosition::AUTO),
2934 mWebkitTextStrokeWidth(0),
2935 mTextEmphasisStyle(StyleTextEmphasisStyle::None()) {
2936 MOZ_COUNT_CTOR(nsStyleText);
2937 RefPtr<nsAtom> language = aDocument.GetContentLanguageAsAtomForStyle();
2938 mTextEmphasisPosition =
2939 language && nsStyleUtil::MatchesLanguagePrefix(language, u"zh")
2940 ? StyleTextEmphasisPosition::UNDER
2941 : StyleTextEmphasisPosition::OVER;
2944 nsStyleText::nsStyleText(const nsStyleText& aSource)
2945 : mColor(aSource.mColor),
2946 mForcedColorAdjust(aSource.mForcedColorAdjust),
2947 mTextTransform(aSource.mTextTransform),
2948 mTextAlign(aSource.mTextAlign),
2949 mTextAlignLast(aSource.mTextAlignLast),
2950 mTextJustify(aSource.mTextJustify),
2951 mWhiteSpace(aSource.mWhiteSpace),
2952 mLineBreak(aSource.mLineBreak),
2953 mWordBreak(aSource.mWordBreak),
2954 mOverflowWrap(aSource.mOverflowWrap),
2955 mHyphens(aSource.mHyphens),
2956 mRubyAlign(aSource.mRubyAlign),
2957 mRubyPosition(aSource.mRubyPosition),
2958 mTextSizeAdjust(aSource.mTextSizeAdjust),
2959 mTextCombineUpright(aSource.mTextCombineUpright),
2960 mMozControlCharacterVisibility(aSource.mMozControlCharacterVisibility),
2961 mTextEmphasisPosition(aSource.mTextEmphasisPosition),
2962 mTextRendering(aSource.mTextRendering),
2963 mTextEmphasisColor(aSource.mTextEmphasisColor),
2964 mWebkitTextFillColor(aSource.mWebkitTextFillColor),
2965 mWebkitTextStrokeColor(aSource.mWebkitTextStrokeColor),
2966 mTabSize(aSource.mTabSize),
2967 mWordSpacing(aSource.mWordSpacing),
2968 mLetterSpacing(aSource.mLetterSpacing),
2969 mLineHeight(aSource.mLineHeight),
2970 mTextIndent(aSource.mTextIndent),
2971 mTextUnderlineOffset(aSource.mTextUnderlineOffset),
2972 mTextDecorationSkipInk(aSource.mTextDecorationSkipInk),
2973 mTextUnderlinePosition(aSource.mTextUnderlinePosition),
2974 mWebkitTextStrokeWidth(aSource.mWebkitTextStrokeWidth),
2975 mTextShadow(aSource.mTextShadow),
2976 mTextEmphasisStyle(aSource.mTextEmphasisStyle),
2977 mHyphenateCharacter(aSource.mHyphenateCharacter),
2978 mWebkitTextSecurity(aSource.mWebkitTextSecurity) {
2979 MOZ_COUNT_CTOR(nsStyleText);
2982 nsStyleText::~nsStyleText() { MOZ_COUNT_DTOR(nsStyleText); }
2984 nsChangeHint nsStyleText::CalcDifference(const nsStyleText& aNewData) const {
2985 if (WhiteSpaceOrNewlineIsSignificant() !=
2986 aNewData.WhiteSpaceOrNewlineIsSignificant()) {
2987 // This may require construction of suppressed text frames
2988 return nsChangeHint_ReconstructFrame;
2991 if (mTextCombineUpright != aNewData.mTextCombineUpright ||
2992 mMozControlCharacterVisibility !=
2993 aNewData.mMozControlCharacterVisibility) {
2994 return nsChangeHint_ReconstructFrame;
2997 if ((mTextAlign != aNewData.mTextAlign) ||
2998 (mTextAlignLast != aNewData.mTextAlignLast) ||
2999 (mTextTransform != aNewData.mTextTransform) ||
3000 (mWhiteSpace != aNewData.mWhiteSpace) ||
3001 (mLineBreak != aNewData.mLineBreak) ||
3002 (mWordBreak != aNewData.mWordBreak) ||
3003 (mOverflowWrap != aNewData.mOverflowWrap) ||
3004 (mHyphens != aNewData.mHyphens) || (mRubyAlign != aNewData.mRubyAlign) ||
3005 (mRubyPosition != aNewData.mRubyPosition) ||
3006 (mTextSizeAdjust != aNewData.mTextSizeAdjust) ||
3007 (mLetterSpacing != aNewData.mLetterSpacing) ||
3008 (mLineHeight != aNewData.mLineHeight) ||
3009 (mTextIndent != aNewData.mTextIndent) ||
3010 (mTextJustify != aNewData.mTextJustify) ||
3011 (mWordSpacing != aNewData.mWordSpacing) ||
3012 (mTabSize != aNewData.mTabSize) ||
3013 (mHyphenateCharacter != aNewData.mHyphenateCharacter) ||
3014 (mWebkitTextSecurity != aNewData.mWebkitTextSecurity)) {
3015 return NS_STYLE_HINT_REFLOW;
3018 if (HasEffectiveTextEmphasis() != aNewData.HasEffectiveTextEmphasis() ||
3019 (HasEffectiveTextEmphasis() &&
3020 mTextEmphasisPosition != aNewData.mTextEmphasisPosition)) {
3021 // Text emphasis position change could affect line height calculation.
3022 return nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
3025 nsChangeHint hint = nsChangeHint(0);
3027 // text-rendering changes require a reflow since they change SVG
3028 // frames' rects.
3029 if (mTextRendering != aNewData.mTextRendering) {
3030 hint |= nsChangeHint_NeedReflow | nsChangeHint_RepaintFrame;
3033 if (mTextShadow != aNewData.mTextShadow ||
3034 mTextEmphasisStyle != aNewData.mTextEmphasisStyle ||
3035 mWebkitTextStrokeWidth != aNewData.mWebkitTextStrokeWidth ||
3036 mTextUnderlineOffset != aNewData.mTextUnderlineOffset ||
3037 mTextDecorationSkipInk != aNewData.mTextDecorationSkipInk ||
3038 mTextUnderlinePosition != aNewData.mTextUnderlinePosition) {
3039 hint |= nsChangeHint_UpdateSubtreeOverflow | nsChangeHint_SchedulePaint |
3040 nsChangeHint_RepaintFrame;
3042 // We don't add any other hints below.
3043 return hint;
3046 if (mColor != aNewData.mColor) {
3047 hint |= nsChangeHint_RepaintFrame;
3050 if (mTextEmphasisColor != aNewData.mTextEmphasisColor ||
3051 mWebkitTextFillColor != aNewData.mWebkitTextFillColor ||
3052 mWebkitTextStrokeColor != aNewData.mWebkitTextStrokeColor) {
3053 hint |= nsChangeHint_SchedulePaint | nsChangeHint_RepaintFrame;
3056 if (hint) {
3057 return hint;
3060 if (mTextEmphasisPosition != aNewData.mTextEmphasisPosition ||
3061 mForcedColorAdjust != aNewData.mForcedColorAdjust) {
3062 return nsChangeHint_NeutralChange;
3065 return nsChangeHint(0);
3068 LogicalSide nsStyleText::TextEmphasisSide(WritingMode aWM) const {
3069 bool noLeftBit = !(mTextEmphasisPosition & StyleTextEmphasisPosition::LEFT);
3070 DebugOnly<bool> noRightBit =
3071 !(mTextEmphasisPosition & StyleTextEmphasisPosition::RIGHT);
3072 bool noOverBit = !(mTextEmphasisPosition & StyleTextEmphasisPosition::OVER);
3073 DebugOnly<bool> noUnderBit =
3074 !(mTextEmphasisPosition & StyleTextEmphasisPosition::UNDER);
3076 MOZ_ASSERT((noOverBit != noUnderBit) &&
3077 ((noLeftBit != noRightBit) || noRightBit));
3078 mozilla::Side side = aWM.IsVertical() ? (noLeftBit ? eSideRight : eSideLeft)
3079 : (noOverBit ? eSideBottom : eSideTop);
3080 LogicalSide result = aWM.LogicalSideForPhysicalSide(side);
3081 MOZ_ASSERT(IsBlock(result));
3082 return result;
3085 //-----------------------
3086 // nsStyleUI
3089 nsStyleUI::nsStyleUI(const Document& aDocument)
3090 : mInert(StyleInert::None),
3091 mUserInput(StyleUserInput::Auto),
3092 mUserModify(StyleUserModify::ReadOnly),
3093 mUserFocus(StyleUserFocus::None),
3094 mPointerEvents(StylePointerEvents::Auto),
3095 mCursor{{}, StyleCursorKind::Auto},
3096 mAccentColor(StyleColorOrAuto::Auto()),
3097 mCaretColor(StyleColorOrAuto::Auto()),
3098 mScrollbarColor(StyleScrollbarColor::Auto()),
3099 mColorScheme(StyleColorScheme{{}, {}}) {
3100 MOZ_COUNT_CTOR(nsStyleUI);
3103 nsStyleUI::nsStyleUI(const nsStyleUI& aSource)
3104 : mInert(aSource.mInert),
3105 mUserInput(aSource.mUserInput),
3106 mUserModify(aSource.mUserModify),
3107 mUserFocus(aSource.mUserFocus),
3108 mPointerEvents(aSource.mPointerEvents),
3109 mCursor(aSource.mCursor),
3110 mAccentColor(aSource.mAccentColor),
3111 mCaretColor(aSource.mCaretColor),
3112 mScrollbarColor(aSource.mScrollbarColor),
3113 mColorScheme(aSource.mColorScheme) {
3114 MOZ_COUNT_CTOR(nsStyleUI);
3117 nsStyleUI::~nsStyleUI() { MOZ_COUNT_DTOR(nsStyleUI); }
3119 void nsStyleUI::TriggerImageLoads(Document& aDocument,
3120 const nsStyleUI* aOldStyle) {
3121 MOZ_ASSERT(NS_IsMainThread());
3123 auto cursorImages = mCursor.images.AsSpan();
3124 auto oldCursorImages = aOldStyle ? aOldStyle->mCursor.images.AsSpan()
3125 : Span<const StyleCursorImage>();
3126 for (size_t i = 0; i < cursorImages.Length(); ++i) {
3127 auto& cursor = cursorImages[i];
3128 const auto* oldCursorImage =
3129 oldCursorImages.Length() > i ? &oldCursorImages[i].image : nullptr;
3130 const_cast<StyleCursorImage&>(cursor).image.ResolveImage(aDocument,
3131 oldCursorImage);
3135 nsChangeHint nsStyleUI::CalcDifference(const nsStyleUI& aNewData) const {
3136 // SVGGeometryFrame's mRect depends on stroke _and_ on the value of
3137 // pointer-events. See SVGGeometryFrame::ReflowSVG's use of GetHitTestFlags.
3138 // (Only a reflow, no visual change.)
3140 // pointer-events changes can change event regions overrides on layers and
3141 // so needs a repaint.
3142 const auto kPointerEventsHint =
3143 nsChangeHint_NeedReflow | nsChangeHint_SchedulePaint;
3145 nsChangeHint hint = nsChangeHint(0);
3146 if (mCursor != aNewData.mCursor) {
3147 hint |= nsChangeHint_UpdateCursor;
3150 if (mPointerEvents != aNewData.mPointerEvents) {
3151 hint |= kPointerEventsHint;
3154 if (mUserModify != aNewData.mUserModify) {
3155 hint |= NS_STYLE_HINT_VISUAL;
3158 if (mInert != aNewData.mInert) {
3159 // inert affects pointer-events, user-modify, user-select, user-focus and
3160 // -moz-user-input, do the union of all them (minus
3161 // nsChangeHint_NeutralChange which isn't needed if there's any other hint).
3162 hint |= NS_STYLE_HINT_VISUAL | kPointerEventsHint;
3165 if (mUserFocus != aNewData.mUserFocus || mUserInput != aNewData.mUserInput) {
3166 hint |= nsChangeHint_NeutralChange;
3169 if (mCaretColor != aNewData.mCaretColor ||
3170 mAccentColor != aNewData.mAccentColor ||
3171 mScrollbarColor != aNewData.mScrollbarColor ||
3172 mColorScheme != aNewData.mColorScheme) {
3173 hint |= nsChangeHint_RepaintFrame;
3176 return hint;
3179 //-----------------------
3180 // nsStyleUIReset
3183 nsStyleUIReset::nsStyleUIReset(const Document& aDocument)
3184 : mUserSelect(StyleUserSelect::Auto),
3185 mScrollbarWidth(StyleScrollbarWidth::Auto),
3186 mMozForceBrokenImageIcon(false),
3187 mMozSubtreeHiddenOnlyVisually(false),
3188 mIMEMode(StyleImeMode::Auto),
3189 mWindowDragging(StyleWindowDragging::Default),
3190 mWindowShadow(StyleWindowShadow::Default),
3191 mWindowOpacity(1.0),
3192 mMozWindowInputRegionMargin(StyleLength::Zero()),
3193 mWindowTransformOrigin{LengthPercentage::FromPercentage(0.5),
3194 LengthPercentage::FromPercentage(0.5),
3195 {0.}},
3196 mTransitions(
3197 nsStyleAutoArray<StyleTransition>::WITH_SINGLE_INITIAL_ELEMENT),
3198 mTransitionTimingFunctionCount(1),
3199 mTransitionDurationCount(1),
3200 mTransitionDelayCount(1),
3201 mTransitionPropertyCount(1),
3202 mAnimations(
3203 nsStyleAutoArray<StyleAnimation>::WITH_SINGLE_INITIAL_ELEMENT),
3204 mAnimationTimingFunctionCount(1),
3205 mAnimationDurationCount(1),
3206 mAnimationDelayCount(1),
3207 mAnimationNameCount(1),
3208 mAnimationDirectionCount(1),
3209 mAnimationFillModeCount(1),
3210 mAnimationPlayStateCount(1),
3211 mAnimationIterationCountCount(1),
3212 mAnimationCompositionCount(1),
3213 mAnimationTimelineCount(1),
3214 mScrollTimelines(
3215 nsStyleAutoArray<StyleScrollTimeline>::WITH_SINGLE_INITIAL_ELEMENT),
3216 mScrollTimelineNameCount(1),
3217 mScrollTimelineAxisCount(1),
3218 mViewTimelines(
3219 nsStyleAutoArray<StyleViewTimeline>::WITH_SINGLE_INITIAL_ELEMENT),
3220 mViewTimelineNameCount(1),
3221 mViewTimelineAxisCount(1),
3222 mViewTimelineInsetCount(1) {
3223 MOZ_COUNT_CTOR(nsStyleUIReset);
3224 mTransitions[0].SetInitialValues();
3225 mAnimations[0].SetInitialValues();
3228 nsStyleUIReset::nsStyleUIReset(const nsStyleUIReset& aSource)
3229 : mUserSelect(aSource.mUserSelect),
3230 mScrollbarWidth(aSource.mScrollbarWidth),
3231 mMozForceBrokenImageIcon(aSource.mMozForceBrokenImageIcon),
3232 mMozSubtreeHiddenOnlyVisually(aSource.mMozSubtreeHiddenOnlyVisually),
3233 mIMEMode(aSource.mIMEMode),
3234 mWindowDragging(aSource.mWindowDragging),
3235 mWindowShadow(aSource.mWindowShadow),
3236 mWindowOpacity(aSource.mWindowOpacity),
3237 mMozWindowInputRegionMargin(aSource.mMozWindowInputRegionMargin),
3238 mMozWindowTransform(aSource.mMozWindowTransform),
3239 mWindowTransformOrigin(aSource.mWindowTransformOrigin),
3240 mTransitions(aSource.mTransitions.Clone()),
3241 mTransitionTimingFunctionCount(aSource.mTransitionTimingFunctionCount),
3242 mTransitionDurationCount(aSource.mTransitionDurationCount),
3243 mTransitionDelayCount(aSource.mTransitionDelayCount),
3244 mTransitionPropertyCount(aSource.mTransitionPropertyCount),
3245 mAnimations(aSource.mAnimations.Clone()),
3246 mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount),
3247 mAnimationDurationCount(aSource.mAnimationDurationCount),
3248 mAnimationDelayCount(aSource.mAnimationDelayCount),
3249 mAnimationNameCount(aSource.mAnimationNameCount),
3250 mAnimationDirectionCount(aSource.mAnimationDirectionCount),
3251 mAnimationFillModeCount(aSource.mAnimationFillModeCount),
3252 mAnimationPlayStateCount(aSource.mAnimationPlayStateCount),
3253 mAnimationIterationCountCount(aSource.mAnimationIterationCountCount),
3254 mAnimationCompositionCount(aSource.mAnimationCompositionCount),
3255 mAnimationTimelineCount(aSource.mAnimationTimelineCount),
3256 mScrollTimelines(aSource.mScrollTimelines.Clone()),
3257 mScrollTimelineNameCount(aSource.mScrollTimelineNameCount),
3258 mScrollTimelineAxisCount(aSource.mScrollTimelineAxisCount),
3259 mViewTimelines(aSource.mViewTimelines.Clone()),
3260 mViewTimelineNameCount(aSource.mViewTimelineNameCount),
3261 mViewTimelineAxisCount(aSource.mViewTimelineAxisCount),
3262 mViewTimelineInsetCount(aSource.mViewTimelineInsetCount) {
3263 MOZ_COUNT_CTOR(nsStyleUIReset);
3266 nsStyleUIReset::~nsStyleUIReset() { MOZ_COUNT_DTOR(nsStyleUIReset); }
3268 nsChangeHint nsStyleUIReset::CalcDifference(
3269 const nsStyleUIReset& aNewData) const {
3270 nsChangeHint hint = nsChangeHint(0);
3272 if (mMozForceBrokenImageIcon != aNewData.mMozForceBrokenImageIcon) {
3273 hint |= nsChangeHint_ReconstructFrame;
3275 if (mMozSubtreeHiddenOnlyVisually != aNewData.mMozSubtreeHiddenOnlyVisually) {
3276 hint |= nsChangeHint_RepaintFrame;
3278 if (mScrollbarWidth != aNewData.mScrollbarWidth) {
3279 // For scrollbar-width change, we need some special handling similar
3280 // to overflow properties. Specifically, we may need to reconstruct
3281 // the scrollbar or force reflow of the viewport scrollbar.
3282 hint |= nsChangeHint_ScrollbarChange;
3284 if (mWindowShadow != aNewData.mWindowShadow) {
3285 // We really need just an nsChangeHint_SyncFrameView, except
3286 // on an ancestor of the frame, so we get that by doing a
3287 // reflow.
3288 hint |= NS_STYLE_HINT_REFLOW;
3290 if (mUserSelect != aNewData.mUserSelect) {
3291 hint |= NS_STYLE_HINT_VISUAL;
3294 if (mWindowDragging != aNewData.mWindowDragging) {
3295 hint |= nsChangeHint_SchedulePaint;
3298 if (!hint &&
3299 (mTransitions != aNewData.mTransitions ||
3300 mTransitionTimingFunctionCount !=
3301 aNewData.mTransitionTimingFunctionCount ||
3302 mTransitionDurationCount != aNewData.mTransitionDurationCount ||
3303 mTransitionDelayCount != aNewData.mTransitionDelayCount ||
3304 mTransitionPropertyCount != aNewData.mTransitionPropertyCount ||
3305 mAnimations != aNewData.mAnimations ||
3306 mAnimationTimingFunctionCount !=
3307 aNewData.mAnimationTimingFunctionCount ||
3308 mAnimationDurationCount != aNewData.mAnimationDurationCount ||
3309 mAnimationDelayCount != aNewData.mAnimationDelayCount ||
3310 mAnimationNameCount != aNewData.mAnimationNameCount ||
3311 mAnimationDirectionCount != aNewData.mAnimationDirectionCount ||
3312 mAnimationFillModeCount != aNewData.mAnimationFillModeCount ||
3313 mAnimationPlayStateCount != aNewData.mAnimationPlayStateCount ||
3314 mAnimationIterationCountCount !=
3315 aNewData.mAnimationIterationCountCount ||
3316 mAnimationCompositionCount != aNewData.mAnimationCompositionCount ||
3317 mAnimationTimelineCount != aNewData.mAnimationTimelineCount ||
3318 mIMEMode != aNewData.mIMEMode ||
3319 mWindowOpacity != aNewData.mWindowOpacity ||
3320 mMozWindowInputRegionMargin != aNewData.mMozWindowInputRegionMargin ||
3321 mMozWindowTransform != aNewData.mMozWindowTransform ||
3322 mScrollTimelines != aNewData.mScrollTimelines ||
3323 mScrollTimelineNameCount != aNewData.mScrollTimelineNameCount ||
3324 mScrollTimelineAxisCount != aNewData.mScrollTimelineAxisCount ||
3325 mViewTimelines != aNewData.mViewTimelines ||
3326 mViewTimelineNameCount != aNewData.mViewTimelineNameCount ||
3327 mViewTimelineAxisCount != aNewData.mViewTimelineAxisCount ||
3328 mViewTimelineInsetCount != aNewData.mViewTimelineInsetCount)) {
3329 hint |= nsChangeHint_NeutralChange;
3332 return hint;
3335 StyleScrollbarWidth nsStyleUIReset::ScrollbarWidth() const {
3336 if (MOZ_UNLIKELY(StaticPrefs::layout_css_scrollbar_width_thin_disabled())) {
3337 if (mScrollbarWidth == StyleScrollbarWidth::Thin) {
3338 return StyleScrollbarWidth::Auto;
3341 return mScrollbarWidth;
3344 //-----------------------
3345 // nsStyleEffects
3348 nsStyleEffects::nsStyleEffects(const Document&)
3349 : mClip(StyleClipRectOrAuto::Auto()),
3350 mOpacity(1.0f),
3351 mMixBlendMode(StyleBlend::Normal) {
3352 MOZ_COUNT_CTOR(nsStyleEffects);
3355 nsStyleEffects::nsStyleEffects(const nsStyleEffects& aSource)
3356 : mFilters(aSource.mFilters),
3357 mBoxShadow(aSource.mBoxShadow),
3358 mBackdropFilters(aSource.mBackdropFilters),
3359 mClip(aSource.mClip),
3360 mOpacity(aSource.mOpacity),
3361 mMixBlendMode(aSource.mMixBlendMode) {
3362 MOZ_COUNT_CTOR(nsStyleEffects);
3365 nsStyleEffects::~nsStyleEffects() { MOZ_COUNT_DTOR(nsStyleEffects); }
3367 static bool AnyAutonessChanged(const StyleClipRectOrAuto& aOld,
3368 const StyleClipRectOrAuto& aNew) {
3369 if (aOld.IsAuto() != aNew.IsAuto()) {
3370 return true;
3372 if (aOld.IsAuto()) {
3373 return false;
3375 auto& oldRect = aOld.AsRect();
3376 auto& newRect = aNew.AsRect();
3377 return oldRect.top.IsAuto() != newRect.top.IsAuto() ||
3378 oldRect.right.IsAuto() != newRect.right.IsAuto() ||
3379 oldRect.bottom.IsAuto() != newRect.bottom.IsAuto() ||
3380 oldRect.left.IsAuto() != newRect.left.IsAuto();
3383 nsChangeHint nsStyleEffects::CalcDifference(
3384 const nsStyleEffects& aNewData) const {
3385 nsChangeHint hint = nsChangeHint(0);
3387 if (mBoxShadow != aNewData.mBoxShadow) {
3388 // Update overflow regions & trigger DLBI to be sure it's noticed.
3389 // Also request a repaint, since it's possible that only the color
3390 // of the shadow is changing (and UpdateOverflow/SchedulePaint won't
3391 // repaint for that, since they won't know what needs invalidating.)
3392 hint |= nsChangeHint_UpdateOverflow | nsChangeHint_SchedulePaint |
3393 nsChangeHint_RepaintFrame;
3396 if (AnyAutonessChanged(mClip, aNewData.mClip)) {
3397 hint |= nsChangeHint_AllReflowHints | nsChangeHint_RepaintFrame;
3398 } else if (mClip != aNewData.mClip) {
3399 // If the clip has changed, we just need to update overflow areas. DLBI
3400 // will handle the invalidation.
3401 hint |= nsChangeHint_UpdateOverflow | nsChangeHint_SchedulePaint;
3404 if (mOpacity != aNewData.mOpacity) {
3405 hint |= nsChangeHint_UpdateOpacityLayer;
3407 // If we're going from the optimized >=0.99 opacity value to 1.0 or back,
3408 // then repaint the frame because DLBI will not catch the invalidation.
3409 // Otherwise, just update the opacity layer.
3410 if ((mOpacity >= 0.99f && mOpacity < 1.0f && aNewData.mOpacity == 1.0f) ||
3411 (aNewData.mOpacity >= 0.99f && aNewData.mOpacity < 1.0f &&
3412 mOpacity == 1.0f)) {
3413 hint |= nsChangeHint_RepaintFrame;
3414 } else {
3415 if ((mOpacity == 1.0f) != (aNewData.mOpacity == 1.0f)) {
3416 hint |= nsChangeHint_UpdateUsesOpacity;
3421 if (HasFilters() != aNewData.HasFilters()) {
3422 // A change from/to being a containing block for position:fixed.
3423 hint |= nsChangeHint_UpdateContainingBlock;
3426 if (mFilters != aNewData.mFilters) {
3427 hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame |
3428 nsChangeHint_UpdateOverflow;
3431 if (mMixBlendMode != aNewData.mMixBlendMode) {
3432 hint |= nsChangeHint_RepaintFrame;
3435 if (HasBackdropFilters() != aNewData.HasBackdropFilters()) {
3436 // A change from/to being a containing block for position:fixed.
3437 hint |= nsChangeHint_UpdateContainingBlock;
3440 if (mBackdropFilters != aNewData.mBackdropFilters) {
3441 hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
3444 return hint;
3447 static bool TransformOperationHasPercent(const StyleTransformOperation& aOp) {
3448 switch (aOp.tag) {
3449 case StyleTransformOperation::Tag::TranslateX:
3450 return aOp.AsTranslateX().HasPercent();
3451 case StyleTransformOperation::Tag::TranslateY:
3452 return aOp.AsTranslateY().HasPercent();
3453 case StyleTransformOperation::Tag::TranslateZ:
3454 return false;
3455 case StyleTransformOperation::Tag::Translate3D: {
3456 auto& translate = aOp.AsTranslate3D();
3457 // NOTE(emilio): z translation is a `<length>`, so can't have percentages.
3458 return translate._0.HasPercent() || translate._1.HasPercent();
3460 case StyleTransformOperation::Tag::Translate: {
3461 auto& translate = aOp.AsTranslate();
3462 return translate._0.HasPercent() || translate._1.HasPercent();
3464 case StyleTransformOperation::Tag::AccumulateMatrix: {
3465 auto& accum = aOp.AsAccumulateMatrix();
3466 return accum.from_list.HasPercent() || accum.to_list.HasPercent();
3468 case StyleTransformOperation::Tag::InterpolateMatrix: {
3469 auto& interpolate = aOp.AsInterpolateMatrix();
3470 return interpolate.from_list.HasPercent() ||
3471 interpolate.to_list.HasPercent();
3473 case StyleTransformOperation::Tag::Perspective:
3474 case StyleTransformOperation::Tag::RotateX:
3475 case StyleTransformOperation::Tag::RotateY:
3476 case StyleTransformOperation::Tag::RotateZ:
3477 case StyleTransformOperation::Tag::Rotate:
3478 case StyleTransformOperation::Tag::Rotate3D:
3479 case StyleTransformOperation::Tag::SkewX:
3480 case StyleTransformOperation::Tag::SkewY:
3481 case StyleTransformOperation::Tag::Skew:
3482 case StyleTransformOperation::Tag::ScaleX:
3483 case StyleTransformOperation::Tag::ScaleY:
3484 case StyleTransformOperation::Tag::ScaleZ:
3485 case StyleTransformOperation::Tag::Scale:
3486 case StyleTransformOperation::Tag::Scale3D:
3487 case StyleTransformOperation::Tag::Matrix:
3488 case StyleTransformOperation::Tag::Matrix3D:
3489 return false;
3490 default:
3491 MOZ_ASSERT_UNREACHABLE("Unknown transform operation");
3492 return false;
3496 template <>
3497 bool StyleTransform::HasPercent() const {
3498 for (const auto& op : Operations()) {
3499 if (TransformOperationHasPercent(op)) {
3500 return true;
3503 return false;
3506 template <>
3507 void StyleCalcNode::ScaleLengthsBy(float aScale) {
3508 auto ScaleNode = [aScale](const StyleCalcNode& aNode) {
3509 // This const_cast could be removed by generating more mut-casts, if
3510 // needed.
3511 const_cast<StyleCalcNode&>(aNode).ScaleLengthsBy(aScale);
3514 switch (tag) {
3515 case Tag::Leaf: {
3516 auto& leaf = AsLeaf();
3517 if (leaf.IsLength()) {
3518 // This const_cast could be removed by generating more mut-casts, if
3519 // needed.
3520 const_cast<Length&>(leaf.AsLength()).ScaleBy(aScale);
3522 break;
3524 case Tag::Clamp: {
3525 auto& clamp = AsClamp();
3526 ScaleNode(*clamp.min);
3527 ScaleNode(*clamp.center);
3528 ScaleNode(*clamp.max);
3529 break;
3531 case Tag::Round: {
3532 const auto& round = AsRound();
3533 ScaleNode(*round.value);
3534 ScaleNode(*round.step);
3535 break;
3537 case Tag::ModRem: {
3538 const auto& modRem = AsModRem();
3539 ScaleNode(*modRem.dividend);
3540 ScaleNode(*modRem.divisor);
3541 break;
3543 case Tag::MinMax: {
3544 for (auto& child : AsMinMax()._0.AsSpan()) {
3545 ScaleNode(child);
3547 break;
3549 case Tag::Sum: {
3550 for (auto& child : AsSum().AsSpan()) {
3551 ScaleNode(child);
3553 break;
3555 case Tag::Negate: {
3556 const auto& negate = AsNegate();
3557 ScaleNode(*negate);
3558 break;
3560 case Tag::Hypot: {
3561 for (const auto& child : AsHypot().AsSpan()) {
3562 ScaleNode(child);
3564 break;
3566 case Tag::Abs: {
3567 const auto& abs = AsAbs();
3568 ScaleNode(*abs);
3569 break;
3574 template <>
3575 CSSCoord StyleCalcNode::ResolveInternal(CSSCoord aPercentageBasis) const {
3576 switch (tag) {
3577 case Tag::Leaf: {
3578 const auto& leaf = AsLeaf();
3579 if (leaf.IsPercentage()) {
3580 return leaf.AsPercentage()._0 * aPercentageBasis;
3582 return leaf.AsLength().ToCSSPixels();
3584 case Tag::Negate: {
3585 const auto& negate = AsNegate();
3586 auto value = negate->ResolveInternal(aPercentageBasis);
3587 return -value;
3589 case Tag::Clamp: {
3590 const auto& clamp = AsClamp();
3591 auto min = clamp.min->ResolveInternal(aPercentageBasis);
3592 auto center = clamp.center->ResolveInternal(aPercentageBasis);
3593 auto max = clamp.max->ResolveInternal(aPercentageBasis);
3594 return std::max(min, std::min(center, max));
3596 case Tag::Round: {
3597 const auto& round = AsRound();
3599 // Make sure to do the math in CSS pixels, so that floor() and ceil()
3600 // below round to an integer number of CSS pixels, not app units.
3601 const CSSCoord step = round.step->ResolveInternal(aPercentageBasis);
3602 const CSSCoord value = round.value->ResolveInternal(aPercentageBasis);
3604 const float div = value / step;
3605 const CSSCoord lowerBound = std::floor(div) * step;
3606 const CSSCoord upperBound = std::ceil(div) * step;
3607 const CSSCoord result = [&] {
3608 switch (round.strategy) {
3609 case StyleRoundingStrategy::Nearest:
3610 // In case of a tie, use the upper bound
3611 if (value - lowerBound < upperBound - value) {
3612 return lowerBound;
3614 return upperBound;
3615 case StyleRoundingStrategy::Up:
3616 return upperBound;
3617 case StyleRoundingStrategy::Down:
3618 return lowerBound;
3619 case StyleRoundingStrategy::ToZero:
3620 // In case of a tie, use the upper bound
3621 return std::abs(lowerBound) < std::abs(upperBound) ? lowerBound
3622 : upperBound;
3624 MOZ_ASSERT_UNREACHABLE("Unknown rounding strategy");
3625 return CSSCoord(0);
3626 }();
3628 return result;
3630 case Tag::ModRem: {
3631 const auto& modRem = AsModRem();
3633 CSSCoord dividend = modRem.dividend->ResolveInternal(aPercentageBasis);
3634 CSSCoord divisor = modRem.divisor->ResolveInternal(aPercentageBasis);
3636 const CSSCoord result =
3637 modRem.op == StyleModRemOp::Mod
3638 ? dividend - divisor * std::floor(dividend / divisor)
3639 : dividend - divisor * std::trunc(dividend / divisor);
3641 return result;
3643 case Tag::MinMax: {
3644 auto children = AsMinMax()._0.AsSpan();
3645 StyleMinMaxOp op = AsMinMax()._1;
3647 CSSCoord result = children[0].ResolveInternal(aPercentageBasis);
3648 for (const auto& child : children.From(1)) {
3649 CSSCoord candidate = child.ResolveInternal(aPercentageBasis);
3650 if (op == StyleMinMaxOp::Max) {
3651 result = std::max(result, candidate);
3652 } else {
3653 result = std::min(result, candidate);
3656 return result;
3658 case Tag::Sum: {
3659 CSSCoord result = 0.0f;
3660 for (const auto& child : AsSum().AsSpan()) {
3661 result += child.ResolveInternal(aPercentageBasis);
3663 return result;
3665 case Tag::Hypot: {
3666 // Doing math in CSS pixels to avoid exceeding integer range of app units
3667 CSSCoord result = 0.0f;
3668 for (const auto& child : AsHypot().AsSpan()) {
3669 CSSCoord value = child.ResolveInternal(aPercentageBasis);
3670 result += std::pow(value, 2);
3672 result = std::sqrt(result);
3674 return result;
3676 case Tag::Abs: {
3677 const auto& abs = AsAbs();
3678 auto value = abs->ResolveInternal(aPercentageBasis);
3679 if (value == 0) {
3680 return value;
3682 return std::abs(value);
3686 MOZ_ASSERT_UNREACHABLE("Unknown calc node");
3687 return 0;
3690 template <>
3691 CSSCoord StyleCalcNode::ResolveToCSSPixels(CSSCoord aBasis) const {
3692 CSSCoord result = ResolveInternal(aBasis);
3693 if (std::isnan(float(result))) {
3694 return 0.0f; // This matches style::values::normalize
3696 return result;
3699 template <>
3700 nscoord StyleCalcNode::Resolve(nscoord aBasis, CoordRounder aRounder) const {
3701 CSSCoord result = ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis));
3702 return aRounder(result * AppUnitsPerCSSPixel());
3705 bool nsStyleDisplay::PrecludesSizeContainmentOrContentVisibilityWithFrame(
3706 const nsIFrame& aFrame) const {
3707 // Note: The spec for size containment says it should have no effect on
3708 // non-atomic, inline-level boxes.
3709 bool isNonReplacedInline = aFrame.IsFrameOfType(nsIFrame::eLineParticipant) &&
3710 !aFrame.IsFrameOfType(nsIFrame::eReplaced);
3711 return isNonReplacedInline || IsInternalRubyDisplayType() ||
3712 DisplayInside() == mozilla::StyleDisplayInside::Table ||
3713 IsInnerTableStyle();
3716 ContainSizeAxes nsStyleDisplay::GetContainSizeAxes(
3717 const nsIFrame& aFrame) const {
3718 // Short circuit for no containment whatsoever
3719 if (MOZ_LIKELY(!mEffectiveContainment)) {
3720 return ContainSizeAxes(false, false);
3723 if (PrecludesSizeContainmentOrContentVisibilityWithFrame(aFrame)) {
3724 return ContainSizeAxes(false, false);
3727 // Internal SVG elements do not use the standard CSS box model, and wouldn't
3728 // be affected by size containment. By disabling it we prevent them from
3729 // becoming query containers for size features.
3730 if (aFrame.HasAnyStateBits(NS_FRAME_SVG_LAYOUT)) {
3731 return ContainSizeAxes(false, false);
3734 // https://drafts.csswg.org/css-contain-2/#content-visibility
3735 // If this content skips its content via content-visibility, it always has
3736 // size containment.
3737 if (MOZ_LIKELY(!(mEffectiveContainment & StyleContain::SIZE)) &&
3738 MOZ_UNLIKELY(aFrame.HidesContent())) {
3739 return ContainSizeAxes(true, true);
3742 return ContainSizeAxes(
3743 static_cast<bool>(mEffectiveContainment & StyleContain::INLINE_SIZE),
3744 static_cast<bool>(mEffectiveContainment & StyleContain::BLOCK_SIZE));
3747 StyleContentVisibility nsStyleDisplay::ContentVisibility(
3748 const nsIFrame& aFrame) const {
3749 if (MOZ_LIKELY(mContentVisibility == StyleContentVisibility::Visible)) {
3750 return StyleContentVisibility::Visible;
3752 if (PrecludesSizeContainmentOrContentVisibilityWithFrame(aFrame)) {
3753 return StyleContentVisibility::Visible;
3755 return mContentVisibility;
3758 static nscoord Resolve(const StyleContainIntrinsicSize& aSize,
3759 nscoord aNoneValue, const nsIFrame& aFrame,
3760 LogicalAxis aAxis) {
3761 if (aSize.IsNone()) {
3762 return aNoneValue;
3764 if (aSize.IsLength()) {
3765 return aSize.AsLength().ToAppUnits();
3767 MOZ_ASSERT(aSize.IsAutoLength());
3768 if (const auto* element = Element::FromNodeOrNull(aFrame.GetContent())) {
3769 Maybe<float> lastSize = aAxis == eLogicalAxisBlock
3770 ? element->GetLastRememberedBSize()
3771 : element->GetLastRememberedISize();
3772 if (lastSize && aFrame.HidesContent()) {
3773 return CSSPixel::ToAppUnits(*lastSize);
3776 return aSize.AsAutoLength().ToAppUnits();
3779 Maybe<nscoord> ContainSizeAxes::ContainIntrinsicBSize(
3780 const nsIFrame& aFrame, nscoord aNoneValue) const {
3781 if (!mBContained) {
3782 return Nothing();
3784 const StyleContainIntrinsicSize& bSize =
3785 aFrame.StylePosition()->ContainIntrinsicBSize(aFrame.GetWritingMode());
3786 return Some(Resolve(bSize, aNoneValue, aFrame, eLogicalAxisBlock));
3789 Maybe<nscoord> ContainSizeAxes::ContainIntrinsicISize(
3790 const nsIFrame& aFrame, nscoord aNoneValue) const {
3791 if (!mIContained) {
3792 return Nothing();
3794 const StyleContainIntrinsicSize& iSize =
3795 aFrame.StylePosition()->ContainIntrinsicISize(aFrame.GetWritingMode());
3796 return Some(Resolve(iSize, aNoneValue, aFrame, eLogicalAxisInline));
3799 nsSize ContainSizeAxes::ContainSize(const nsSize& aUncontainedSize,
3800 const nsIFrame& aFrame) const {
3801 if (!IsAny()) {
3802 return aUncontainedSize;
3804 if (aFrame.GetWritingMode().IsVertical()) {
3805 return nsSize(
3806 ContainIntrinsicBSize(aFrame).valueOr(aUncontainedSize.Width()),
3807 ContainIntrinsicISize(aFrame).valueOr(aUncontainedSize.Height()));
3809 return nsSize(
3810 ContainIntrinsicISize(aFrame).valueOr(aUncontainedSize.Width()),
3811 ContainIntrinsicBSize(aFrame).valueOr(aUncontainedSize.Height()));
3814 IntrinsicSize ContainSizeAxes::ContainIntrinsicSize(
3815 const IntrinsicSize& aUncontainedSize, const nsIFrame& aFrame) const {
3816 if (!IsAny()) {
3817 return aUncontainedSize;
3819 IntrinsicSize result(aUncontainedSize);
3820 const bool isVerticalWM = aFrame.GetWritingMode().IsVertical();
3821 if (Maybe<nscoord> containBSize = ContainIntrinsicBSize(aFrame)) {
3822 (isVerticalWM ? result.width : result.height) = containBSize;
3824 if (Maybe<nscoord> containISize = ContainIntrinsicISize(aFrame)) {
3825 (isVerticalWM ? result.height : result.width) = containISize;
3827 return result;