1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /* Some inline functions declared in cbindgen.toml */
9 #ifndef mozilla_ServoStyleConstsInlines_h
10 #define mozilla_ServoStyleConstsInlines_h
12 #include "mozilla/ServoStyleConsts.h"
13 #include "mozilla/AspectRatio.h"
14 #include "mozilla/EndianUtils.h"
15 #include "mozilla/URLExtraData.h"
16 #include "mozilla/dom/WorkerCommon.h"
17 #include "nsGkAtoms.h"
18 #include "MainThreadUtils.h"
19 #include "nsNetUtil.h"
20 #include <type_traits>
23 // TODO(emilio): there are quite a few other implementations scattered around
24 // that should move here.
28 // We need to explicitly instantiate these so that the clang plugin can see that
29 // they're trivially copyable...
31 // https://github.com/eqrion/cbindgen/issues/402 tracks doing something like
32 // this automatically from cbindgen.
33 template struct StyleStrong
<ComputedStyle
>;
34 template struct StyleStrong
<StyleLockedCssRules
>;
35 template struct StyleStrong
<StyleAnimationValue
>;
36 template struct StyleStrong
<StyleLockedDeclarationBlock
>;
37 template struct StyleStrong
<StyleStylesheetContents
>;
38 template struct StyleStrong
<StyleLockedKeyframe
>;
39 template struct StyleStrong
<StyleLayerBlockRule
>;
40 template struct StyleStrong
<StyleLayerStatementRule
>;
41 template struct StyleStrong
<StyleLockedMediaList
>;
42 template struct StyleStrong
<StyleLockedStyleRule
>;
43 template struct StyleStrong
<StyleLockedImportRule
>;
44 template struct StyleStrong
<StyleLockedKeyframesRule
>;
45 template struct StyleStrong
<StyleMediaRule
>;
46 template struct StyleStrong
<StyleDocumentRule
>;
47 template struct StyleStrong
<StyleNamespaceRule
>;
48 template struct StyleStrong
<StyleMarginRule
>;
49 template struct StyleStrong
<StyleLockedPageRule
>;
50 template struct StyleStrong
<StylePropertyRule
>;
51 template struct StyleStrong
<StyleSupportsRule
>;
52 template struct StyleStrong
<StyleFontFeatureValuesRule
>;
53 template struct StyleStrong
<StyleFontPaletteValuesRule
>;
54 template struct StyleStrong
<StyleLockedFontFaceRule
>;
55 template struct StyleStrong
<StyleLockedCounterStyleRule
>;
56 template struct StyleStrong
<StyleContainerRule
>;
57 template struct StyleStrong
<StyleScopeRule
>;
58 template struct StyleStrong
<StyleStartingStyleRule
>;
61 inline void StyleOwnedSlice
<T
>::Clear() {
65 for (size_t i
: IntegerRange(len
)) {
74 inline void StyleOwnedSlice
<T
>::CopyFrom(const StyleOwnedSlice
& aOther
) {
80 ptr
= (T
*)malloc(len
* sizeof(T
));
82 for (const T
& elem
: aOther
.AsSpan()) {
83 new (ptr
+ i
++) T(elem
);
89 inline void StyleOwnedSlice
<T
>::SwapElements(StyleOwnedSlice
& aOther
) {
90 std::swap(ptr
, aOther
.ptr
);
91 std::swap(len
, aOther
.len
);
95 inline StyleOwnedSlice
<T
>::StyleOwnedSlice(const StyleOwnedSlice
& aOther
)
100 template <typename T
>
101 inline StyleOwnedSlice
<T
>::StyleOwnedSlice(StyleOwnedSlice
&& aOther
)
102 : StyleOwnedSlice() {
103 SwapElements(aOther
);
106 template <typename T
>
107 inline StyleOwnedSlice
<T
>::StyleOwnedSlice(Vector
<T
>&& aVector
)
108 : StyleOwnedSlice() {
109 if (!aVector
.length()) {
113 // We could handle this if Vector provided the relevant APIs, see bug 1610702.
114 MOZ_DIAGNOSTIC_ASSERT(aVector
.length() == aVector
.capacity(),
115 "Shouldn't over-allocate");
116 len
= aVector
.length();
117 ptr
= aVector
.extractRawBuffer();
119 "How did extractRawBuffer return null if we're not using inline "
123 template <typename T
>
124 inline StyleOwnedSlice
<T
>& StyleOwnedSlice
<T
>::operator=(
125 const StyleOwnedSlice
& aOther
) {
130 template <typename T
>
131 inline StyleOwnedSlice
<T
>& StyleOwnedSlice
<T
>::operator=(
132 StyleOwnedSlice
&& aOther
) {
134 SwapElements(aOther
);
138 template <typename T
>
139 inline StyleOwnedSlice
<T
>::~StyleOwnedSlice() {
143 // This code is basically a C++ port of the Arc::clone() implementation in
144 // servo/components/servo_arc/lib.rs.
145 static constexpr const size_t kStaticRefcount
=
146 std::numeric_limits
<size_t>::max();
147 static constexpr const size_t kMaxRefcount
=
148 std::numeric_limits
<intptr_t>::max();
150 template <typename T
>
151 inline void StyleArcInner
<T
>::IncrementRef() {
152 if (count
.load(std::memory_order_relaxed
) != kStaticRefcount
) {
153 auto old_size
= count
.fetch_add(1, std::memory_order_relaxed
);
154 if (MOZ_UNLIKELY(old_size
> kMaxRefcount
)) {
160 // This is a C++ port-ish of Arc::drop().
161 template <typename T
>
162 inline bool StyleArcInner
<T
>::DecrementRef() {
163 if (count
.load(std::memory_order_relaxed
) == kStaticRefcount
) {
166 if (count
.fetch_sub(1, std::memory_order_release
) != 1) {
170 // TSan doesn't understand std::atomic_thread_fence, so in order
171 // to avoid a false positive for every time a refcounted object
172 // is deleted, we replace the fence with an atomic operation.
173 count
.load(std::memory_order_acquire
);
175 std::atomic_thread_fence(std::memory_order_acquire
);
177 MOZ_LOG_DTOR(this, "ServoArc", 8);
181 template <typename H
, typename T
>
182 inline bool StyleHeaderSlice
<H
, T
>::operator==(
183 const StyleHeaderSlice
& aOther
) const {
184 return header
== aOther
.header
&& AsSpan() == aOther
.AsSpan();
187 template <typename H
, typename T
>
188 inline bool StyleHeaderSlice
<H
, T
>::operator!=(
189 const StyleHeaderSlice
& aOther
) const {
190 return !(*this == aOther
);
193 template <typename H
, typename T
>
194 inline StyleHeaderSlice
<H
, T
>::~StyleHeaderSlice() {
195 for (T
& elem
: Span(data
, len
)) {
200 template <typename H
, typename T
>
201 inline Span
<const T
> StyleHeaderSlice
<H
, T
>::AsSpan() const {
202 // Explicitly specify template argument here to avoid instantiating Span<T>
203 // first and then implicitly converting to Span<const T>
204 return Span
<const T
>{data
, len
};
207 static constexpr const uint64_t kArcSliceCanary
= 0xf3f3f3f3f3f3f3f3;
209 #define ASSERT_CANARY \
210 MOZ_DIAGNOSTIC_ASSERT(_0.p->data.header == kArcSliceCanary, "Uh?");
212 template <typename T
>
213 inline StyleArcSlice
<T
>::StyleArcSlice()
214 : _0(reinterpret_cast<decltype(_0
.p
)>(Servo_StyleArcSlice_EmptyPtr())) {
218 template <typename T
>
219 inline StyleArcSlice
<T
>::StyleArcSlice(
220 const StyleForgottenArcSlicePtr
<T
>& aPtr
) {
221 // See the forget() implementation to see why reinterpret_cast() is ok.
222 _0
.p
= reinterpret_cast<decltype(_0
.p
)>(aPtr
._0
);
226 template <typename T
>
227 inline size_t StyleArcSlice
<T
>::Length() const {
232 template <typename T
>
233 inline bool StyleArcSlice
<T
>::IsEmpty() const {
235 return _0
->IsEmpty();
238 template <typename T
>
239 inline Span
<const T
> StyleArcSlice
<T
>::AsSpan() const {
246 template <typename T
>
247 inline StyleArc
<T
>::StyleArc(const StyleArc
& aOther
) : p(aOther
.p
) {
251 template <typename T
>
252 inline void StyleArc
<T
>::Release() {
253 if (MOZ_LIKELY(!p
->DecrementRef())) {
260 template <typename T
>
261 inline StyleArc
<T
>& StyleArc
<T
>::operator=(const StyleArc
& aOther
) {
270 template <typename T
>
271 inline StyleArc
<T
>& StyleArc
<T
>::operator=(StyleArc
&& aOther
) {
272 std::swap(p
, aOther
.p
);
276 template <typename T
>
277 inline StyleArc
<T
>::~StyleArc() {
281 inline bool StyleAtom::IsStatic() const { return !!(_0
& 1); }
283 inline nsAtom
* StyleAtom::AsAtom() const {
285 return const_cast<nsStaticAtom
*>(&detail::gGkAtoms
.mAtoms
[_0
>> 1]);
287 return reinterpret_cast<nsAtom
*>(_0
);
290 inline void StyleAtom::AddRef() {
296 inline void StyleAtom::Release() {
302 inline StyleAtom::StyleAtom(already_AddRefed
<nsAtom
> aAtom
) {
303 nsAtom
* atom
= aAtom
.take();
304 if (atom
->IsStatic()) {
305 size_t index
= atom
->AsStatic() - &detail::gGkAtoms
.mAtoms
[0];
306 _0
= (index
<< 1) | 1;
308 _0
= reinterpret_cast<uintptr_t>(atom
);
310 MOZ_ASSERT(IsStatic() == atom
->IsStatic());
311 MOZ_ASSERT(AsAtom() == atom
);
314 inline StyleAtom::StyleAtom(nsStaticAtom
* aAtom
)
315 : StyleAtom(do_AddRef(static_cast<nsAtom
*>(aAtom
))) {}
317 inline StyleAtom::StyleAtom(const StyleAtom
& aOther
) : _0(aOther
._0
) {
321 inline StyleAtom
& StyleAtom::operator=(const StyleAtom
& aOther
) {
322 if (MOZ_LIKELY(this != &aOther
)) {
330 inline StyleAtom::~StyleAtom() { Release(); }
332 inline nsAtom
* StyleCustomIdent::AsAtom() const { return _0
.AsAtom(); }
334 inline nsDependentCSubstring
StyleOwnedStr::AsString() const {
335 Span
<const uint8_t> s
= _0
.AsSpan();
336 return nsDependentCSubstring(reinterpret_cast<const char*>(s
.Elements()),
340 template <typename T
>
341 inline Span
<const T
> StyleGenericTransform
<T
>::Operations() const {
345 template <typename T
>
346 inline bool StyleGenericTransform
<T
>::IsNone() const {
347 return Operations().IsEmpty();
350 inline StyleAngle
StyleAngle::Zero() { return {0.0f
}; }
352 inline float StyleAngle::ToDegrees() const { return _0
; }
354 inline double StyleAngle::ToRadians() const {
355 return double(ToDegrees()) * M_PI
/ 180.0;
358 inline bool StyleUrlExtraData::IsShared() const { return !!(_0
& 1); }
360 inline StyleUrlExtraData::~StyleUrlExtraData() {
362 reinterpret_cast<URLExtraData
*>(_0
)->Release();
366 inline const URLExtraData
& StyleUrlExtraData::get() const {
368 return *URLExtraData::sShared
[_0
>> 1];
370 return *reinterpret_cast<const URLExtraData
*>(_0
);
373 inline nsDependentCSubstring
StyleCssUrl::SpecifiedSerialization() const {
374 return _0
->serialization
.AsString();
377 inline const URLExtraData
& StyleCssUrl::ExtraData() const {
378 return _0
->extra_data
.get();
381 inline StyleLoadData
& StyleCssUrl::LoadData() const {
382 if (MOZ_LIKELY(_0
->load_data
.tag
== StyleLoadDataSource::Tag::Owned
)) {
383 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread() ||
384 dom::IsCurrentThreadRunningWorker());
385 return const_cast<StyleLoadData
&>(_0
->load_data
.owned
._0
);
387 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
388 "Lazy load datas should come from user-agent sheets, "
389 "which don't make sense on workers");
390 return const_cast<StyleLoadData
&>(*Servo_LoadData_GetLazy(&_0
->load_data
));
393 inline nsIURI
* StyleCssUrl::GetURI() const {
394 auto& loadData
= LoadData();
395 if (!(loadData
.flags
& StyleLoadDataFlags::TRIED_TO_RESOLVE_URI
)) {
396 loadData
.flags
|= StyleLoadDataFlags::TRIED_TO_RESOLVE_URI
;
397 nsDependentCSubstring serialization
= SpecifiedSerialization();
398 // https://drafts.csswg.org/css-values-4/#url-empty:
400 // If the value of the url() is the empty string (like url("") or
401 // url()), the url must resolve to an invalid resource (similar to what
402 // the url about:invalid does).
404 if (!serialization
.IsEmpty()) {
405 RefPtr
<nsIURI
> resolved
;
406 NS_NewURI(getter_AddRefs(resolved
), serialization
, nullptr,
407 ExtraData().BaseURI());
408 loadData
.resolved_uri
= resolved
.forget().take();
411 return loadData
.resolved_uri
;
414 inline nsDependentCSubstring
StyleComputedUrl::SpecifiedSerialization() const {
415 return _0
.SpecifiedSerialization();
417 inline const URLExtraData
& StyleComputedUrl::ExtraData() const {
418 return _0
.ExtraData();
420 inline StyleLoadData
& StyleComputedUrl::LoadData() const {
421 return _0
.LoadData();
423 inline StyleCorsMode
StyleComputedUrl::CorsMode() const {
424 return _0
._0
->cors_mode
;
426 inline nsIURI
* StyleComputedUrl::GetURI() const { return _0
.GetURI(); }
428 inline bool StyleComputedUrl::IsLocalRef() const {
429 return Servo_CssUrl_IsLocalRef(&_0
);
432 inline bool StyleComputedUrl::HasRef() const {
436 if (nsIURI
* uri
= GetURI()) {
438 return NS_SUCCEEDED(uri
->GetHasRef(&hasRef
)) && hasRef
;
443 inline bool StyleComputedImageUrl::IsImageResolved() const {
444 return bool(LoadData().flags
& StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE
);
447 inline imgRequestProxy
* StyleComputedImageUrl::GetImage() const {
448 MOZ_ASSERT(IsImageResolved());
449 return LoadData().resolved_image
;
453 inline bool StyleGradient::Repeating() const {
455 return bool(AsLinear().flags
& StyleGradientFlags::REPEATING
);
458 return bool(AsRadial().flags
& StyleGradientFlags::REPEATING
);
460 return bool(AsConic().flags
& StyleGradientFlags::REPEATING
);
464 bool StyleGradient::IsOpaque() const;
467 inline const StyleColorInterpolationMethod
&
468 StyleGradient::ColorInterpolationMethod() const {
470 return AsLinear().color_interpolation_method
;
473 return AsRadial().color_interpolation_method
;
475 return AsConic().color_interpolation_method
;
478 template <typename Integer
>
479 inline StyleGenericGridLine
<Integer
>::StyleGenericGridLine()
480 : ident
{StyleAtom(nsGkAtoms::_empty
)}, line_num(0), is_span(false) {}
483 inline nsAtom
* StyleGridLine::LineName() const {
484 return ident
.AsAtom();
488 inline bool StyleGridLine::IsAuto() const {
489 return LineName()->IsEmpty() && line_num
== 0 && !is_span
;
492 using LengthPercentage
= StyleLengthPercentage
;
493 using LengthPercentageOrAuto
= StyleLengthPercentageOrAuto
;
494 using NonNegativeLengthPercentage
= StyleNonNegativeLengthPercentage
;
495 using NonNegativeLengthPercentageOrAuto
=
496 StyleNonNegativeLengthPercentageOrAuto
;
497 using NonNegativeLengthPercentageOrNormal
=
498 StyleNonNegativeLengthPercentageOrNormal
;
499 using Length
= StyleLength
;
500 using LengthOrAuto
= StyleLengthOrAuto
;
501 using NonNegativeLength
= StyleNonNegativeLength
;
502 using NonNegativeLengthOrAuto
= StyleNonNegativeLengthOrAuto
;
503 using BorderRadius
= StyleBorderRadius
;
505 bool StyleCSSPixelLength::IsZero() const { return _0
== 0.0f
; }
507 void StyleCSSPixelLength::ScaleBy(float aScale
) { _0
*= aScale
; }
509 StyleCSSPixelLength
StyleCSSPixelLength::ScaledBy(float aScale
) const {
510 return FromPixels(ToCSSPixels() * aScale
);
514 static inline nscoord
DefaultPercentLengthToAppUnits(float aPixelLength
) {
515 return NSToCoordTruncClamped(aPixelLength
);
518 static inline nscoord
DefaultLengthToAppUnits(float aPixelLength
) {
519 // We want to round lengths rounding 0.5 away from zero, instead of the
520 // default behavior of NSToCoordRound{,WithClamp} which do floor(x + 0.5).
521 float length
= aPixelLength
* float(mozilla::AppUnitsPerCSSPixel());
522 if (length
>= float(nscoord_MAX
)) {
525 if (length
<= float(nscoord_MIN
)) {
528 return NSToIntRound(length
);
530 } // namespace detail
532 nscoord
StyleCSSPixelLength::ToAppUnits() const {
534 // Avoid the expensive FP math below.
537 return detail::DefaultLengthToAppUnits(_0
);
540 bool LengthPercentage::IsLength() const { return Tag() == TAG_LENGTH
; }
542 StyleLengthPercentageUnion::StyleLengthPercentageUnion() {
543 length
= {TAG_LENGTH
, {0.0f
}};
544 MOZ_ASSERT(IsLength());
547 static_assert(sizeof(LengthPercentage
) == sizeof(uint64_t), "");
549 Length
& LengthPercentage::AsLength() {
550 MOZ_ASSERT(IsLength());
551 return length
.length
;
554 const Length
& LengthPercentage::AsLength() const {
555 return const_cast<LengthPercentage
*>(this)->AsLength();
558 bool LengthPercentage::IsPercentage() const { return Tag() == TAG_PERCENTAGE
; }
560 StylePercentage
& LengthPercentage::AsPercentage() {
561 MOZ_ASSERT(IsPercentage());
562 return percentage
.percentage
;
565 const StylePercentage
& LengthPercentage::AsPercentage() const {
566 return const_cast<LengthPercentage
*>(this)->AsPercentage();
569 bool LengthPercentage::IsCalc() const { return Tag() == TAG_CALC
; }
571 StyleCalcLengthPercentage
& LengthPercentage::AsCalc() {
572 MOZ_ASSERT(IsCalc());
573 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the tag.
577 return *reinterpret_cast<StyleCalcLengthPercentage
*>(
578 NativeEndian::swapFromLittleEndian(calc
.ptr
));
582 const StyleCalcLengthPercentage
& LengthPercentage::AsCalc() const {
583 return const_cast<LengthPercentage
*>(this)->AsCalc();
586 StyleLengthPercentageUnion::StyleLengthPercentageUnion(const Self
& aOther
) {
587 if (aOther
.IsLength()) {
588 length
= {TAG_LENGTH
, aOther
.AsLength()};
589 } else if (aOther
.IsPercentage()) {
590 percentage
= {TAG_PERCENTAGE
, aOther
.AsPercentage()};
592 MOZ_ASSERT(aOther
.IsCalc());
593 auto* ptr
= new StyleCalcLengthPercentage(aOther
.AsCalc());
594 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the
601 NativeEndian::swapToLittleEndian(reinterpret_cast<uintptr_t>(ptr
)),
605 MOZ_ASSERT(Tag() == aOther
.Tag());
608 StyleLengthPercentageUnion::~StyleLengthPercentageUnion() {
614 LengthPercentage
& LengthPercentage::operator=(const LengthPercentage
& aOther
) {
615 if (this != &aOther
) {
616 this->~LengthPercentage();
617 new (this) LengthPercentage(aOther
);
622 bool LengthPercentage::operator==(const LengthPercentage
& aOther
) const {
623 if (Tag() != aOther
.Tag()) {
627 return AsLength() == aOther
.AsLength();
629 if (IsPercentage()) {
630 return AsPercentage() == aOther
.AsPercentage();
632 return AsCalc() == aOther
.AsCalc();
635 bool LengthPercentage::operator!=(const LengthPercentage
& aOther
) const {
636 return !(*this == aOther
);
639 LengthPercentage
LengthPercentage::Zero() { return {}; }
641 LengthPercentage
LengthPercentage::FromPixels(CSSCoord aCoord
) {
643 MOZ_ASSERT(l
.IsLength());
644 l
.length
.length
= {aCoord
};
648 LengthPercentage
LengthPercentage::FromAppUnits(nscoord aCoord
) {
649 return FromPixels(CSSPixel::FromAppUnits(aCoord
));
652 LengthPercentage
LengthPercentage::FromPercentage(float aPercentage
) {
654 l
.percentage
= {TAG_PERCENTAGE
, {aPercentage
}};
658 bool LengthPercentage::HasPercent() const { return IsPercentage() || IsCalc(); }
660 bool LengthPercentage::ConvertsToLength() const { return IsLength(); }
662 nscoord
LengthPercentage::ToLength() const {
663 MOZ_ASSERT(ConvertsToLength());
664 return AsLength().ToAppUnits();
667 CSSCoord
LengthPercentage::ToLengthInCSSPixels() const {
668 MOZ_ASSERT(ConvertsToLength());
669 return AsLength().ToCSSPixels();
672 bool LengthPercentage::ConvertsToPercentage() const { return IsPercentage(); }
674 float LengthPercentage::ToPercentage() const {
675 MOZ_ASSERT(ConvertsToPercentage());
676 return AsPercentage()._0
;
679 bool LengthPercentage::HasLengthAndPercentage() const {
683 MOZ_ASSERT(!ConvertsToLength() && !ConvertsToPercentage(),
684 "Should've been simplified earlier");
688 bool LengthPercentage::IsDefinitelyZero() const {
690 return AsLength().IsZero();
692 if (IsPercentage()) {
693 return AsPercentage()._0
== 0.0f
;
695 // calc() should've been simplified to a percentage.
699 CSSCoord
StyleCalcLengthPercentage::ResolveToCSSPixels(CSSCoord aBasis
) const {
700 return Servo_ResolveCalcLengthPercentage(this, aBasis
);
703 template <typename Rounder
>
704 nscoord
StyleCalcLengthPercentage::Resolve(nscoord aBasis
,
705 Rounder aRounder
) const {
706 static_assert(std::is_same_v
<decltype(aRounder(1.0f
)), nscoord
>);
707 CSSCoord result
= ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis
));
708 return aRounder(result
* AppUnitsPerCSSPixel());
712 void StyleCalcNode::ScaleLengthsBy(float);
714 CSSCoord
LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis
) const {
716 return AsLength().ToCSSPixels();
718 if (IsPercentage()) {
719 return AsPercentage()._0
* aPercentageBasis
;
721 return AsCalc().ResolveToCSSPixels(aPercentageBasis
);
724 template <typename T
>
725 CSSCoord
LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter
) const {
726 static_assert(std::is_same_v
<decltype(aPercentageGetter()), CSSCoord
>);
727 if (ConvertsToLength()) {
728 return ToLengthInCSSPixels();
730 return ResolveToCSSPixels(aPercentageGetter());
733 template <typename T
, typename Rounder
>
734 nscoord
LengthPercentage::Resolve(T aPercentageGetter
, Rounder aRounder
) const {
735 static_assert(std::is_same_v
<decltype(aPercentageGetter()), nscoord
>);
736 static_assert(std::is_same_v
<decltype(aRounder(1.0f
)), nscoord
>);
737 if (ConvertsToLength()) {
740 if (IsPercentage() && AsPercentage()._0
== 0.0f
) {
743 nscoord basis
= aPercentageGetter();
744 if (IsPercentage()) {
745 return aRounder(basis
* AsPercentage()._0
);
747 return AsCalc().Resolve(basis
, aRounder
);
750 nscoord
LengthPercentage::Resolve(nscoord aPercentageBasis
) const {
751 return Resolve([=] { return aPercentageBasis
; },
752 detail::DefaultPercentLengthToAppUnits
);
755 template <typename T
>
756 nscoord
LengthPercentage::Resolve(T aPercentageGetter
) const {
757 return Resolve(aPercentageGetter
, detail::DefaultPercentLengthToAppUnits
);
760 template <typename Rounder
>
761 nscoord
LengthPercentage::Resolve(nscoord aPercentageBasis
,
762 Rounder aRounder
) const {
763 return Resolve([aPercentageBasis
] { return aPercentageBasis
; }, aRounder
);
766 void LengthPercentage::ScaleLengthsBy(float aScale
) {
768 AsLength().ScaleBy(aScale
);
771 AsCalc().node
.ScaleLengthsBy(aScale
);
775 #define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \
777 inline bool ty_::HasPercent() const { \
778 return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \
781 inline bool ty_::ConvertsToLength() const { \
782 return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \
785 inline bool ty_::HasLengthAndPercentage() const { \
786 return IsLengthPercentage() && \
787 AsLengthPercentage().HasLengthAndPercentage(); \
790 inline nscoord ty_::ToLength() const { \
791 MOZ_ASSERT(ConvertsToLength()); \
792 return AsLengthPercentage().ToLength(); \
795 inline bool ty_::ConvertsToPercentage() const { \
796 return IsLengthPercentage() && \
797 AsLengthPercentage().ConvertsToPercentage(); \
800 inline float ty_::ToPercentage() const { \
801 MOZ_ASSERT(ConvertsToPercentage()); \
802 return AsLengthPercentage().ToPercentage(); \
805 IMPL_LENGTHPERCENTAGE_FORWARDS(LengthPercentageOrAuto
)
806 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleSize
)
807 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMaxSize
)
810 inline bool LengthOrAuto::IsLength() const {
811 return IsLengthPercentage();
815 inline const Length
& LengthOrAuto::AsLength() const {
816 return AsLengthPercentage();
820 inline nscoord
LengthOrAuto::ToLength() const {
821 return AsLength().ToAppUnits();
825 inline bool StyleFlexBasis::IsAuto() const {
826 return IsSize() && AsSize().IsAuto();
830 inline bool StyleSize::BehavesLikeInitialValueOnBlockAxis() const {
831 return IsAuto() || !IsLengthPercentage();
835 inline bool StyleMaxSize::BehavesLikeInitialValueOnBlockAxis() const {
836 return IsNone() || !IsLengthPercentage();
840 inline bool StyleBackgroundSize::IsInitialValue() const {
841 return IsExplicitSize() && explicit_size
.width
.IsAuto() &&
842 explicit_size
.height
.IsAuto();
845 template <typename T
>
846 const T
& StyleRect
<T
>::Get(mozilla::Side aSide
) const {
847 static_assert(sizeof(StyleRect
<T
>) == sizeof(T
) * 4, "");
848 static_assert(alignof(StyleRect
<T
>) == alignof(T
), "");
849 return reinterpret_cast<const T
*>(this)[aSide
];
852 template <typename T
>
853 T
& StyleRect
<T
>::Get(mozilla::Side aSide
) {
854 return const_cast<T
&>(static_cast<const StyleRect
&>(*this).Get(aSide
));
857 template <typename T
>
858 template <typename Predicate
>
859 bool StyleRect
<T
>::All(Predicate aPredicate
) const {
860 return aPredicate(_0
) && aPredicate(_1
) && aPredicate(_2
) && aPredicate(_3
);
863 template <typename T
>
864 template <typename Predicate
>
865 bool StyleRect
<T
>::Any(Predicate aPredicate
) const {
866 return aPredicate(_0
) || aPredicate(_1
) || aPredicate(_2
) || aPredicate(_3
);
870 inline const LengthPercentage
& BorderRadius::Get(HalfCorner aCorner
) const {
871 static_assert(sizeof(BorderRadius
) == sizeof(LengthPercentage
) * 8, "");
872 static_assert(alignof(BorderRadius
) == alignof(LengthPercentage
), "");
873 const auto* self
= reinterpret_cast<const LengthPercentage
*>(this);
874 return self
[aCorner
];
878 inline bool StyleTrackBreadth::HasPercent() const {
879 return IsBreadth() && AsBreadth().HasPercent();
882 // Implemented in nsStyleStructs.cpp
884 bool StyleTransform::HasPercent() const;
887 inline bool StyleTransformOrigin::HasPercent() const {
888 // NOTE(emilio): `depth` is just a `<length>` so doesn't have a percentage at
890 return horizontal
.HasPercent() || vertical
.HasPercent();
894 inline Maybe
<size_t> StyleGridTemplateComponent::RepeatAutoIndex() const {
895 if (!IsTrackList()) {
898 const auto& list
= *AsTrackList();
899 return list
.auto_repeat_index
< list
.values
.Length()
900 ? Some(list
.auto_repeat_index
)
905 inline bool StyleGridTemplateComponent::HasRepeatAuto() const {
906 return RepeatAutoIndex().isSome();
910 inline Span
<const StyleGenericTrackListValue
<LengthPercentage
, StyleInteger
>>
911 StyleGridTemplateComponent::TrackListValues() const {
913 return AsTrackList()->values
.AsSpan();
919 inline const StyleGenericTrackRepeat
<LengthPercentage
, StyleInteger
>*
920 StyleGridTemplateComponent::GetRepeatAutoValue() const {
921 auto index
= RepeatAutoIndex();
925 return &TrackListValues()[*index
].AsTrackRepeat();
928 constexpr const auto kPaintOrderShift
= StylePAINT_ORDER_SHIFT
;
929 constexpr const auto kPaintOrderMask
= StylePAINT_ORDER_MASK
;
932 inline nsRect StyleGenericClipRect
<LengthOrAuto
>::ToLayoutRect(
933 nscoord aAutoSize
) const {
934 nscoord x
= left
.IsLength() ? left
.ToLength() : 0;
935 nscoord y
= top
.IsLength() ? top
.ToLength() : 0;
936 nscoord width
= right
.IsLength() ? right
.ToLength() - x
: aAutoSize
;
937 nscoord height
= bottom
.IsLength() ? bottom
.ToLength() - y
: aAutoSize
;
938 return nsRect(x
, y
, width
, height
);
941 using RestyleHint
= StyleRestyleHint
;
943 inline RestyleHint
RestyleHint::RestyleSubtree() {
944 return RESTYLE_SELF
| RESTYLE_DESCENDANTS
;
947 inline RestyleHint
RestyleHint::RecascadeSubtree() {
948 return RECASCADE_SELF
| RECASCADE_DESCENDANTS
;
951 inline RestyleHint
RestyleHint::ForAnimations() {
952 return RESTYLE_CSS_TRANSITIONS
| RESTYLE_CSS_ANIMATIONS
| RESTYLE_SMIL
;
955 inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const {
956 if (!(*this & (RECASCADE_DESCENDANTS
| RESTYLE_DESCENDANTS
))) {
959 return bool(*this & (RESTYLE_SELF
| RECASCADE_SELF
));
963 ImageResolution
StyleImage::GetResolution(const ComputedStyle
&) const;
966 inline const StyleImage
& StyleImage::FinalImage() const {
970 const auto& set
= *AsImageSet();
971 auto items
= set
.items
.AsSpan();
972 if (MOZ_LIKELY(set
.selected_index
< items
.Length())) {
973 return items
[set
.selected_index
].image
.FinalImage();
975 static auto sNone
= StyleImage::None();
980 inline bool StyleImage::IsImageRequestType() const {
981 const auto& finalImage
= FinalImage();
982 return finalImage
.IsUrl();
986 inline const StyleComputedImageUrl
* StyleImage::GetImageRequestURLValue()
988 const auto& finalImage
= FinalImage();
989 if (finalImage
.IsUrl()) {
990 return &finalImage
.AsUrl();
996 inline imgRequestProxy
* StyleImage::GetImageRequest() const {
997 const auto* url
= GetImageRequestURLValue();
998 return url
? url
->GetImage() : nullptr;
1002 inline bool StyleImage::IsResolved() const {
1003 const auto* url
= GetImageRequestURLValue();
1004 return !url
|| url
->IsImageResolved();
1008 bool StyleImage::IsOpaque() const;
1010 bool StyleImage::IsSizeAvailable() const;
1012 bool StyleImage::IsComplete() const;
1014 void StyleImage::ResolveImage(dom::Document
&, const StyleImage
*);
1017 inline AspectRatio StyleRatio
<StyleNonNegativeNumber
>::ToLayoutRatio(
1018 UseBoxSizing aUseBoxSizing
) const {
1019 // 0/1, 1/0, and 0/0 are all degenerate ratios (which behave as auto), and we
1020 // always return 0.0f.
1021 // https://drafts.csswg.org/css-values-4/#degenerate-ratio
1022 return AspectRatio::FromSize(_0
, _1
, aUseBoxSizing
);
1026 inline AspectRatio
StyleAspectRatio::ToLayoutRatio() const {
1027 return HasRatio() ? ratio
.AsRatio().ToLayoutRatio(auto_
? UseBoxSizing::No
1028 : UseBoxSizing::Yes
)
1032 inline void StyleFontWeight::ToString(nsACString
& aString
) const {
1033 Servo_FontWeight_ToCss(this, &aString
);
1036 inline void StyleFontStretch::ToString(nsACString
& aString
) const {
1037 Servo_FontStretch_ToCss(this, &aString
);
1040 inline void StyleFontStyle::ToString(nsACString
& aString
) const {
1041 Servo_FontStyle_ToCss(this, &aString
);
1044 inline bool StyleFontWeight::IsBold() const { return *this >= BOLD_THRESHOLD
; }
1046 inline bool StyleFontStyle::IsItalic() const { return *this == ITALIC
; }
1048 inline bool StyleFontStyle::IsOblique() const {
1049 return !IsItalic() && !IsNormal();
1052 inline float StyleFontStyle::ObliqueAngle() const {
1053 MOZ_ASSERT(IsOblique());
1057 inline float StyleFontStyle::SlantAngle() const {
1058 return IsNormal() ? 0 : IsItalic() ? DEFAULT_OBLIQUE_DEGREES
: ObliqueAngle();
1061 using FontStretch
= StyleFontStretch
;
1062 using FontSlantStyle
= StyleFontStyle
;
1063 using FontWeight
= StyleFontWeight
;
1066 inline double StyleComputedTimingFunction::At(double aPortion
,
1067 bool aBeforeFlag
) const {
1068 return Servo_EasingFunctionAt(
1070 aBeforeFlag
? StyleEasingBeforeFlag::Set
: StyleEasingBeforeFlag::Unset
);
1074 inline void StyleComputedTimingFunction::AppendToString(
1075 nsACString
& aOut
) const {
1076 return Servo_SerializeEasing(this, &aOut
);
1080 inline double StyleComputedTimingFunction::GetPortion(
1081 const Maybe
<StyleComputedTimingFunction
>& aFn
, double aPortion
,
1083 return aFn
? aFn
->At(aPortion
, aBeforeFlag
) : aPortion
;
1088 inline LengthPercentageOrAuto
LengthPercentageOrAuto::Zero() {
1089 return LengthPercentage(LengthPercentage::Zero());
1093 inline StyleViewTimelineInset::StyleGenericViewTimelineInset()
1094 : start(LengthPercentageOrAuto::Auto()),
1095 end(LengthPercentageOrAuto::Auto()) {}
1097 inline StyleDisplayOutside
StyleDisplay::Outside() const {
1098 return StyleDisplayOutside((_0
& OUTSIDE_MASK
) >> OUTSIDE_SHIFT
);
1101 inline StyleDisplayInside
StyleDisplay::Inside() const {
1102 return StyleDisplayInside(_0
& INSIDE_MASK
);
1105 inline bool StyleDisplay::IsListItem() const { return _0
& LIST_ITEM_MASK
; }
1107 inline bool StyleDisplay::IsInternalTable() const {
1108 return Outside() == StyleDisplayOutside::InternalTable
;
1111 inline bool StyleDisplay::IsInternalTableExceptCell() const {
1112 return IsInternalTable() && *this != TableCell
;
1115 inline bool StyleDisplay::IsInternalRuby() const {
1116 return Outside() == StyleDisplayOutside::InternalRuby
;
1119 inline bool StyleDisplay::IsRuby() const {
1120 return Inside() == StyleDisplayInside::Ruby
|| IsInternalRuby();
1123 inline bool StyleDisplay::IsInlineFlow() const {
1124 return Outside() == StyleDisplayOutside::Inline
&&
1125 Inside() == StyleDisplayInside::Flow
;
1128 inline bool StyleDisplay::IsInlineInside() const {
1129 return IsInlineFlow() || IsRuby();
1132 inline bool StyleDisplay::IsInlineOutside() const {
1133 return Outside() == StyleDisplayOutside::Inline
|| IsInternalRuby();
1136 inline float StyleZoom::Zoom(float aValue
) const {
1140 return ToFloat() * aValue
;
1143 inline float StyleZoom::Unzoom(float aValue
) const {
1147 return aValue
/ ToFloat();
1150 inline nscoord
StyleZoom::ZoomCoord(nscoord aValue
) const {
1154 return NSToCoordRoundWithClamp(Zoom(float(aValue
)));
1157 inline nscoord
StyleZoom::UnzoomCoord(nscoord aValue
) const {
1161 return NSToCoordRoundWithClamp(Unzoom(float(aValue
)));
1164 inline nsSize
StyleZoom::Zoom(const nsSize
& aValue
) const {
1168 return nsSize(ZoomCoord(aValue
.Width()), ZoomCoord(aValue
.Height()));
1171 inline nsSize
StyleZoom::Unzoom(const nsSize
& aValue
) const {
1175 return nsSize(UnzoomCoord(aValue
.Width()), UnzoomCoord(aValue
.Height()));
1178 inline nsPoint
StyleZoom::Zoom(const nsPoint
& aValue
) const {
1182 return nsPoint(ZoomCoord(aValue
.X()), ZoomCoord(aValue
.Y()));
1185 inline nsPoint
StyleZoom::Unzoom(const nsPoint
& aValue
) const {
1189 return nsPoint(UnzoomCoord(aValue
.X()), UnzoomCoord(aValue
.Y()));
1192 inline nsRect
StyleZoom::Zoom(const nsRect
& aValue
) const {
1196 return nsRect(ZoomCoord(aValue
.X()), ZoomCoord(aValue
.Y()),
1197 ZoomCoord(aValue
.Width()), ZoomCoord(aValue
.Height()));
1200 inline nsRect
StyleZoom::Unzoom(const nsRect
& aValue
) const {
1204 return nsRect(UnzoomCoord(aValue
.X()), UnzoomCoord(aValue
.Y()),
1205 UnzoomCoord(aValue
.Width()), UnzoomCoord(aValue
.Height()));
1209 inline gfx::Point StyleCoordinatePair
<StyleCSSFloat
>::ToGfxPoint(
1210 const CSSSize
* aBasis
) const {
1211 return gfx::Point(x
, y
);
1215 inline gfx::Point StyleCoordinatePair
<LengthPercentage
>::ToGfxPoint(
1216 const CSSSize
* aBasis
) const {
1218 return gfx::Point(x
.ResolveToCSSPixels(aBasis
->Width()),
1219 y
.ResolveToCSSPixels(aBasis
->Height()));
1222 } // namespace mozilla