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/. */
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"
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"
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"
45 #include "mozilla/dom/Document.h"
46 #include "mozilla/dom/DocumentInlines.h"
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, \
73 #include "nsStyleStructList.h"
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.
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()) {
98 nsresult rv
= NS_MutateURI(aURI
).SetRef(ref
).Finalize(result
);
101 // If setting the ref failed, just return the original URI.
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() &&
136 RefPtr
<imgRequestProxy
> request
;
138 request
= aOldImage
->LoadData().resolved_image
;
140 css::ImageLoader::NoteSharedLoad(request
);
143 request
= css::ImageLoader::LoadImage(*this, aDocument
);
150 data
.resolved_image
= request
.forget().take();
152 // Boost priority now that we know the image is present in the ComputedStyle
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
{
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
);
178 virtual ~StyleImageRequestCleanupTask() {
179 MOZ_ASSERT(!mRequestProxy
|| NS_IsMainThread(),
180 "mRequestProxy destructor need to run on the main thread!");
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 // --------------------
205 nsStyleFont::nsStyleFont(const nsStyleFont
& aSrc
)
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),
239 mFontSizeKeyword(StyleFontSizeKeyword::Medium
),
240 mFontPalette(StyleFontPalette::Normal()),
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;
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
:
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());
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
;
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
;
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()),
393 StyleRectWithAllSides(StyleBorderImageSideWidth::Number(1.))),
395 StyleRectWithAllSides(StyleNonNegativeLengthOrNumber::Number(0.))),
397 {StyleRectWithAllSides(StyleNumberOrPercentage::Percentage({1.})),
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.
454 for (const auto s
: mozilla::AllPhysicalSides()) {
455 const auto& coord
= mBorderImageOutset
.Get(s
);
457 if (coord
.IsLength()) {
458 value
= coord
.AsLength().ToAppUnits();
460 MOZ_ASSERT(coord
.IsNumber());
461 value
= coord
.AsNumber() * mComputedBorder
.Side(s
);
463 outset
.Side(s
) = value
;
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
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 // --------------------
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
;
654 already_AddRefed
<nsIURI
> nsStyleList::GetListStyleImageURI() const {
655 if (!mListStyleImage
.IsUrl()) {
659 return do_AddRef(mListStyleImage
.AsUrl().GetURI());
662 // --------------------
665 nsStyleXUL::nsStyleXUL(const Document
& aDocument
)
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 // --------------------
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
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 // --------------------
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({})),
774 StyleSVGLength::LengthPercentage(LengthPercentage::Zero())),
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
),
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()) {
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
;
893 if (mMozContextProperties
.idents
!= aNewData
.mMozContextProperties
.idents
) {
894 hint
= nsChangeHint_NeutralChange
;
901 // --------------------
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()),
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
)
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
),
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()) {
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()) {
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
)) {
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
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
;
1014 mMask
.CalcDifference(aNewData
.mMask
, nsStyleImageLayers::LayerType::Mask
);
1019 bool nsStyleSVGReset::HasMask() const {
1020 for (uint32_t i
= 0; i
< mMask
.mImageCount
; i
++) {
1021 if (!mMask
.mLayers
[i
].mImage
.IsNone()) {
1029 // --------------------
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 // --------------------
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
),
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
),
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()) {
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
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
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
)) {
1296 nsChangeHint_RecomputePosition
| nsChangeHint_UpdateParentOverflow
;
1299 nsChangeHint_NeedReflow
| nsChangeHint_ReflowChangesSizeOrPosition
;
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
) {
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 // --------------------
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
;
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()) {
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.
1434 bool StyleGradient::IsOpaque() const {
1436 return GradientItemsAreOpaque(AsLinear().items
.AsSpan());
1439 return GradientItemsAreOpaque(AsRadial().items
.AsSpan());
1441 return GradientItemsAreOpaque(AsConic().items
.AsSpan());
1444 static int32_t ConvertToPixelCoord(const StyleNumberOrPercentage
& aCoord
,
1445 int32_t aPercentScale
) {
1447 if (aCoord
.IsNumber()) {
1448 pixelValue
= aCoord
.AsNumber();
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
);
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();
1468 nsCOMPtr
<imgIContainer
> imageContainer
;
1469 req
->GetImage(getter_AddRefs(imageContainer
));
1470 if (!imageContainer
) {
1474 nsIntSize imageSize
;
1475 imageContainer
->GetWidth(&imageSize
.width
);
1476 imageContainer
->GetHeight(&imageSize
.height
);
1477 if (imageSize
.width
<= 0 || imageSize
.height
<= 0) {
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
});
1497 bool StyleImage::IsOpaque() const {
1499 return FinalImage().IsOpaque();
1502 if (!IsComplete()) {
1507 return AsGradient()->IsOpaque();
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()) {
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();
1537 bool StyleImage::IsComplete() const {
1546 if (!IsResolved()) {
1549 imgRequestProxy
* req
= GetImageRequest();
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
);
1559 return FinalImage().IsComplete();
1560 // Bug 546052 cross-fade not yet implemented.
1561 case Tag::CrossFade
:
1564 MOZ_ASSERT_UNREACHABLE("unexpected image type");
1569 bool StyleImage::IsSizeAvailable() const {
1578 imgRequestProxy
* req
= GetImageRequest();
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
);
1588 return FinalImage().IsSizeAvailable();
1589 case Tag::CrossFade
:
1590 // TODO: Bug 546052 cross-fade not yet implemented.
1593 MOZ_ASSERT_UNREACHABLE("unexpected image type");
1598 void StyleImage::ResolveImage(Document
& aDoc
, const StyleImage
* aOld
) {
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
1606 const_cast<StyleComputedImageUrl
*>(url
)->ResolveImage(aDoc
, old
);
1610 ImageResolution
StyleImage::GetResolution() const {
1611 ImageResolution resolution
;
1612 if (imgRequestProxy
* request
= GetImageRequest()) {
1613 RefPtr
<imgIContainer
> image
;
1614 request
->GetImage(getter_AddRefs(image
));
1616 resolution
= image
->GetResolution();
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
);
1631 Maybe
<CSSIntSize
> StyleImage::GetIntrinsicSize() const {
1632 imgRequestProxy
* request
= GetImageRequest();
1636 RefPtr
<imgIContainer
> image
;
1637 request
->GetImage(getter_AddRefs(image
));
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),
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()) {
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
;
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())) {
1759 nsChangeHint_UpdateEffects
| nsChangeHint_RepaintFrame
;
1761 hint
|= layerDifference
;
1765 // If they're different by now, we're done.
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
;
1785 // If they're different by now, we're done.
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
;
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();
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
) {
1836 if (mLayers
.Length() != aOther
.mLayers
.Length()) {
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
) {
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()) {
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()) {
1877 // If both dimensions are fixed lengths, there's no dependency.
1878 if (!size
.width
.IsAuto() && !size
.height
.IsAuto()) {
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()) {
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()) {
1896 MOZ_ASSERT(aImage
.IsImageRequestType(), "Missed some image");
1897 if (auto* request
= aImage
.GetImageRequest()) {
1898 nsCOMPtr
<imgIContainer
> imgContainer
;
1899 request
->GetImage(getter_AddRefs(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
,
1910 // If the image has a fixed width and height, rendering never depends on
1912 if (hasWidth
&& hasHeight
) {
1916 // If the image has an intrinsic ratio, rendering will depend on frame
1917 // size when background-size is all auto.
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.
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
;
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()) {
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
,
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
;
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
);
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
)) {
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() {
2122 StyleComputedTimingFunction::Keyword(StyleTimingKeyword::Ease
);
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() {
2140 StyleComputedTimingFunction::Keyword(StyleTimingKeyword::Ease
);
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 // --------------------
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),
2212 mChildPerspective(StylePerspective::None()),
2213 mPerspectiveOrigin(Position::FromPercentage(0.5f
)),
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()
2290 // Const-cast is ugly but legit, we could avoid it by generating mut-casts
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
;
2309 result
|= nsChangeHint_UpdateOverflow
;
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
;
2340 result
|= nsChangeHint_UpdateOverflow
;
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
;
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
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
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
;
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
;
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
;
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
;
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
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
;
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
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
;
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
2605 if (IsAbsolutelyPositionedStyle() &&
2606 aOldPosition
.NeedsHypotheticalPositionIfAbsPos()) {
2608 nsChangeHint_NeedReflow
| nsChangeHint_ReflowChangesSizeOrPosition
;
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
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
;
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
;
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
;
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.
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 //-----------------------
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()) {
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()) {
2826 auto& image
= item
.AsImage();
2827 auto* oldImage
= i
< oldItems
.Length() && oldItems
[i
].IsImage()
2828 ? &oldItems
[i
].AsImage()
2830 const_cast<StyleImage
&>(image
).ResolveImage(aDoc
, oldImage
);
2834 // --------------------
2838 nsStyleTextReset::nsStyleTextReset(const Document
& aDocument
)
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 // --------------------
2898 static StyleAbsoluteColor
DefaultColor(const Document
& aDocument
) {
2899 return StyleAbsoluteColor::FromColor(
2900 PreferenceSheet::PrefsFor(aDocument
)
2901 .ColorsFor(aDocument
.DefaultColorScheme())
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
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.
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
;
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
));
3085 //-----------------------
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
,
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
;
3179 //-----------------------
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),
3197 nsStyleAutoArray
<StyleTransition
>::WITH_SINGLE_INITIAL_ELEMENT
),
3198 mTransitionTimingFunctionCount(1),
3199 mTransitionDurationCount(1),
3200 mTransitionDelayCount(1),
3201 mTransitionPropertyCount(1),
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),
3215 nsStyleAutoArray
<StyleScrollTimeline
>::WITH_SINGLE_INITIAL_ELEMENT
),
3216 mScrollTimelineNameCount(1),
3217 mScrollTimelineAxisCount(1),
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
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
;
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
;
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 //-----------------------
3348 nsStyleEffects::nsStyleEffects(const Document
&)
3349 : mClip(StyleClipRectOrAuto::Auto()),
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()) {
3372 if (aOld
.IsAuto()) {
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
;
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
;
3447 static bool TransformOperationHasPercent(const StyleTransformOperation
& aOp
) {
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
:
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
:
3491 MOZ_ASSERT_UNREACHABLE("Unknown transform operation");
3497 bool StyleTransform::HasPercent() const {
3498 for (const auto& op
: Operations()) {
3499 if (TransformOperationHasPercent(op
)) {
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
3511 const_cast<StyleCalcNode
&>(aNode
).ScaleLengthsBy(aScale
);
3516 auto& leaf
= AsLeaf();
3517 if (leaf
.IsLength()) {
3518 // This const_cast could be removed by generating more mut-casts, if
3520 const_cast<Length
&>(leaf
.AsLength()).ScaleBy(aScale
);
3525 auto& clamp
= AsClamp();
3526 ScaleNode(*clamp
.min
);
3527 ScaleNode(*clamp
.center
);
3528 ScaleNode(*clamp
.max
);
3532 const auto& round
= AsRound();
3533 ScaleNode(*round
.value
);
3534 ScaleNode(*round
.step
);
3538 const auto& modRem
= AsModRem();
3539 ScaleNode(*modRem
.dividend
);
3540 ScaleNode(*modRem
.divisor
);
3544 for (auto& child
: AsMinMax()._0
.AsSpan()) {
3550 for (auto& child
: AsSum().AsSpan()) {
3556 const auto& negate
= AsNegate();
3561 for (const auto& child
: AsHypot().AsSpan()) {
3567 const auto& abs
= AsAbs();
3575 CSSCoord
StyleCalcNode::ResolveInternal(CSSCoord aPercentageBasis
) const {
3578 const auto& leaf
= AsLeaf();
3579 if (leaf
.IsPercentage()) {
3580 return leaf
.AsPercentage()._0
* aPercentageBasis
;
3582 return leaf
.AsLength().ToCSSPixels();
3585 const auto& negate
= AsNegate();
3586 auto value
= negate
->ResolveInternal(aPercentageBasis
);
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
));
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
) {
3615 case StyleRoundingStrategy::Up
:
3617 case StyleRoundingStrategy::Down
:
3619 case StyleRoundingStrategy::ToZero
:
3620 // In case of a tie, use the upper bound
3621 return std::abs(lowerBound
) < std::abs(upperBound
) ? lowerBound
3624 MOZ_ASSERT_UNREACHABLE("Unknown rounding strategy");
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
);
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
);
3653 result
= std::min(result
, candidate
);
3659 CSSCoord result
= 0.0f
;
3660 for (const auto& child
: AsSum().AsSpan()) {
3661 result
+= child
.ResolveInternal(aPercentageBasis
);
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
);
3677 const auto& abs
= AsAbs();
3678 auto value
= abs
->ResolveInternal(aPercentageBasis
);
3682 return std::abs(value
);
3686 MOZ_ASSERT_UNREACHABLE("Unknown calc node");
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
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()) {
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 {
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 {
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 {
3802 return aUncontainedSize
;
3804 if (aFrame
.GetWritingMode().IsVertical()) {
3806 ContainIntrinsicBSize(aFrame
).valueOr(aUncontainedSize
.Width()),
3807 ContainIntrinsicISize(aFrame
).valueOr(aUncontainedSize
.Height()));
3810 ContainIntrinsicISize(aFrame
).valueOr(aUncontainedSize
.Width()),
3811 ContainIntrinsicBSize(aFrame
).valueOr(aUncontainedSize
.Height()));
3814 IntrinsicSize
ContainSizeAxes::ContainIntrinsicSize(
3815 const IntrinsicSize
& aUncontainedSize
, const nsIFrame
& aFrame
) const {
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
;