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
<StyleLockedPageRule
>;
49 template struct StyleStrong
<StylePropertyRule
>;
50 template struct StyleStrong
<StyleSupportsRule
>;
51 template struct StyleStrong
<StyleFontFeatureValuesRule
>;
52 template struct StyleStrong
<StyleFontPaletteValuesRule
>;
53 template struct StyleStrong
<StyleLockedFontFaceRule
>;
54 template struct StyleStrong
<StyleLockedCounterStyleRule
>;
55 template struct StyleStrong
<StyleContainerRule
>;
58 inline void StyleOwnedSlice
<T
>::Clear() {
62 for (size_t i
: IntegerRange(len
)) {
71 inline void StyleOwnedSlice
<T
>::CopyFrom(const StyleOwnedSlice
& aOther
) {
77 ptr
= (T
*)malloc(len
* sizeof(T
));
79 for (const T
& elem
: aOther
.AsSpan()) {
80 new (ptr
+ i
++) T(elem
);
86 inline void StyleOwnedSlice
<T
>::SwapElements(StyleOwnedSlice
& aOther
) {
87 std::swap(ptr
, aOther
.ptr
);
88 std::swap(len
, aOther
.len
);
92 inline StyleOwnedSlice
<T
>::StyleOwnedSlice(const StyleOwnedSlice
& aOther
)
98 inline StyleOwnedSlice
<T
>::StyleOwnedSlice(StyleOwnedSlice
&& aOther
)
100 SwapElements(aOther
);
103 template <typename T
>
104 inline StyleOwnedSlice
<T
>::StyleOwnedSlice(Vector
<T
>&& aVector
)
105 : StyleOwnedSlice() {
106 if (!aVector
.length()) {
110 // We could handle this if Vector provided the relevant APIs, see bug 1610702.
111 MOZ_DIAGNOSTIC_ASSERT(aVector
.length() == aVector
.capacity(),
112 "Shouldn't over-allocate");
113 len
= aVector
.length();
114 ptr
= aVector
.extractRawBuffer();
116 "How did extractRawBuffer return null if we're not using inline "
120 template <typename T
>
121 inline StyleOwnedSlice
<T
>& StyleOwnedSlice
<T
>::operator=(
122 const StyleOwnedSlice
& aOther
) {
127 template <typename T
>
128 inline StyleOwnedSlice
<T
>& StyleOwnedSlice
<T
>::operator=(
129 StyleOwnedSlice
&& aOther
) {
131 SwapElements(aOther
);
135 template <typename T
>
136 inline StyleOwnedSlice
<T
>::~StyleOwnedSlice() {
140 // This code is basically a C++ port of the Arc::clone() implementation in
141 // servo/components/servo_arc/lib.rs.
142 static constexpr const size_t kStaticRefcount
=
143 std::numeric_limits
<size_t>::max();
144 static constexpr const size_t kMaxRefcount
=
145 std::numeric_limits
<intptr_t>::max();
147 template <typename T
>
148 inline void StyleArcInner
<T
>::IncrementRef() {
149 if (count
.load(std::memory_order_relaxed
) != kStaticRefcount
) {
150 auto old_size
= count
.fetch_add(1, std::memory_order_relaxed
);
151 if (MOZ_UNLIKELY(old_size
> kMaxRefcount
)) {
157 // This is a C++ port-ish of Arc::drop().
158 template <typename T
>
159 inline bool StyleArcInner
<T
>::DecrementRef() {
160 if (count
.load(std::memory_order_relaxed
) == kStaticRefcount
) {
163 if (count
.fetch_sub(1, std::memory_order_release
) != 1) {
167 // TSan doesn't understand std::atomic_thread_fence, so in order
168 // to avoid a false positive for every time a refcounted object
169 // is deleted, we replace the fence with an atomic operation.
170 count
.load(std::memory_order_acquire
);
172 std::atomic_thread_fence(std::memory_order_acquire
);
174 MOZ_LOG_DTOR(this, "ServoArc", 8);
178 template <typename H
, typename T
>
179 inline bool StyleHeaderSlice
<H
, T
>::operator==(
180 const StyleHeaderSlice
& aOther
) const {
181 return header
== aOther
.header
&& AsSpan() == aOther
.AsSpan();
184 template <typename H
, typename T
>
185 inline bool StyleHeaderSlice
<H
, T
>::operator!=(
186 const StyleHeaderSlice
& aOther
) const {
187 return !(*this == aOther
);
190 template <typename H
, typename T
>
191 inline StyleHeaderSlice
<H
, T
>::~StyleHeaderSlice() {
192 for (T
& elem
: Span(data
, len
)) {
197 template <typename H
, typename T
>
198 inline Span
<const T
> StyleHeaderSlice
<H
, T
>::AsSpan() const {
199 // Explicitly specify template argument here to avoid instantiating Span<T>
200 // first and then implicitly converting to Span<const T>
201 return Span
<const T
>{data
, len
};
204 static constexpr const uint64_t kArcSliceCanary
= 0xf3f3f3f3f3f3f3f3;
206 #define ASSERT_CANARY \
207 MOZ_DIAGNOSTIC_ASSERT(_0.p->data.header == kArcSliceCanary, "Uh?");
209 template <typename T
>
210 inline StyleArcSlice
<T
>::StyleArcSlice()
211 : _0(reinterpret_cast<decltype(_0
.p
)>(Servo_StyleArcSlice_EmptyPtr())) {
215 template <typename T
>
216 inline StyleArcSlice
<T
>::StyleArcSlice(
217 const StyleForgottenArcSlicePtr
<T
>& aPtr
) {
218 // See the forget() implementation to see why reinterpret_cast() is ok.
219 _0
.p
= reinterpret_cast<decltype(_0
.p
)>(aPtr
._0
);
223 template <typename T
>
224 inline size_t StyleArcSlice
<T
>::Length() const {
229 template <typename T
>
230 inline bool StyleArcSlice
<T
>::IsEmpty() const {
232 return _0
->IsEmpty();
235 template <typename T
>
236 inline Span
<const T
> StyleArcSlice
<T
>::AsSpan() const {
243 template <typename T
>
244 inline StyleArc
<T
>::StyleArc(const StyleArc
& aOther
) : p(aOther
.p
) {
248 template <typename T
>
249 inline void StyleArc
<T
>::Release() {
250 if (MOZ_LIKELY(!p
->DecrementRef())) {
257 template <typename T
>
258 inline StyleArc
<T
>& StyleArc
<T
>::operator=(const StyleArc
& aOther
) {
267 template <typename T
>
268 inline StyleArc
<T
>& StyleArc
<T
>::operator=(StyleArc
&& aOther
) {
269 std::swap(p
, aOther
.p
);
273 template <typename T
>
274 inline StyleArc
<T
>::~StyleArc() {
278 inline bool StyleAtom::IsStatic() const { return !!(_0
& 1); }
280 inline nsAtom
* StyleAtom::AsAtom() const {
282 auto* atom
= reinterpret_cast<const nsStaticAtom
*>(
283 reinterpret_cast<const uint8_t*>(&detail::gGkAtoms
) + (_0
>> 1));
284 MOZ_ASSERT(atom
->IsStatic());
285 return const_cast<nsStaticAtom
*>(atom
);
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 ptrdiff_t offset
= reinterpret_cast<const uint8_t*>(atom
->AsStatic()) -
306 reinterpret_cast<const uint8_t*>(&detail::gGkAtoms
);
307 _0
= (offset
<< 1) | 1;
309 _0
= reinterpret_cast<uintptr_t>(atom
);
311 MOZ_ASSERT(IsStatic() == atom
->IsStatic());
312 MOZ_ASSERT(AsAtom() == atom
);
315 inline StyleAtom::StyleAtom(const StyleAtom
& aOther
) : _0(aOther
._0
) {
319 inline StyleAtom
& StyleAtom::operator=(const StyleAtom
& aOther
) {
320 if (MOZ_LIKELY(this != &aOther
)) {
328 inline StyleAtom::~StyleAtom() { Release(); }
330 inline nsAtom
* StyleCustomIdent::AsAtom() const { return _0
.AsAtom(); }
332 inline nsDependentCSubstring
StyleOwnedStr::AsString() const {
333 Span
<const uint8_t> s
= _0
.AsSpan();
334 return nsDependentCSubstring(reinterpret_cast<const char*>(s
.Elements()),
338 template <typename T
>
339 inline Span
<const T
> StyleGenericTransform
<T
>::Operations() const {
343 template <typename T
>
344 inline bool StyleGenericTransform
<T
>::IsNone() const {
345 return Operations().IsEmpty();
348 inline StyleAngle
StyleAngle::Zero() { return {0.0f
}; }
350 inline float StyleAngle::ToDegrees() const { return _0
; }
352 inline double StyleAngle::ToRadians() const {
353 return double(ToDegrees()) * M_PI
/ 180.0;
356 inline bool StyleUrlExtraData::IsShared() const { return !!(_0
& 1); }
358 inline StyleUrlExtraData::~StyleUrlExtraData() {
360 reinterpret_cast<URLExtraData
*>(_0
)->Release();
364 inline const URLExtraData
& StyleUrlExtraData::get() const {
366 return *URLExtraData::sShared
[_0
>> 1];
368 return *reinterpret_cast<const URLExtraData
*>(_0
);
371 inline nsDependentCSubstring
StyleCssUrl::SpecifiedSerialization() const {
372 return _0
->serialization
.AsString();
375 inline const URLExtraData
& StyleCssUrl::ExtraData() const {
376 return _0
->extra_data
.get();
379 inline StyleLoadData
& StyleCssUrl::LoadData() const {
380 if (MOZ_LIKELY(_0
->load_data
.tag
== StyleLoadDataSource::Tag::Owned
)) {
381 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread() ||
382 dom::IsCurrentThreadRunningWorker());
383 return const_cast<StyleLoadData
&>(_0
->load_data
.owned
._0
);
385 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
386 "Lazy load datas should come from user-agent sheets, "
387 "which don't make sense on workers");
388 return const_cast<StyleLoadData
&>(*Servo_LoadData_GetLazy(&_0
->load_data
));
391 inline nsIURI
* StyleCssUrl::GetURI() const {
392 auto& loadData
= LoadData();
393 if (!(loadData
.flags
& StyleLoadDataFlags::TRIED_TO_RESOLVE_URI
)) {
394 loadData
.flags
|= StyleLoadDataFlags::TRIED_TO_RESOLVE_URI
;
395 nsDependentCSubstring serialization
= SpecifiedSerialization();
396 // https://drafts.csswg.org/css-values-4/#url-empty:
398 // If the value of the url() is the empty string (like url("") or
399 // url()), the url must resolve to an invalid resource (similar to what
400 // the url about:invalid does).
402 if (!serialization
.IsEmpty()) {
403 RefPtr
<nsIURI
> resolved
;
404 NS_NewURI(getter_AddRefs(resolved
), serialization
, nullptr,
405 ExtraData().BaseURI());
406 loadData
.resolved_uri
= resolved
.forget().take();
409 return loadData
.resolved_uri
;
412 inline nsDependentCSubstring
StyleComputedUrl::SpecifiedSerialization() const {
413 return _0
.SpecifiedSerialization();
415 inline const URLExtraData
& StyleComputedUrl::ExtraData() const {
416 return _0
.ExtraData();
418 inline StyleLoadData
& StyleComputedUrl::LoadData() const {
419 return _0
.LoadData();
421 inline StyleCorsMode
StyleComputedUrl::CorsMode() const {
422 return _0
._0
->cors_mode
;
424 inline nsIURI
* StyleComputedUrl::GetURI() const { return _0
.GetURI(); }
426 inline bool StyleComputedUrl::IsLocalRef() const {
427 return Servo_CssUrl_IsLocalRef(&_0
);
430 inline bool StyleComputedUrl::HasRef() const {
434 if (nsIURI
* uri
= GetURI()) {
436 return NS_SUCCEEDED(uri
->GetHasRef(&hasRef
)) && hasRef
;
441 inline bool StyleComputedImageUrl::IsImageResolved() const {
442 return bool(LoadData().flags
& StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE
);
445 inline imgRequestProxy
* StyleComputedImageUrl::GetImage() const {
446 MOZ_ASSERT(IsImageResolved());
447 return LoadData().resolved_image
;
451 inline bool StyleGradient::Repeating() const {
453 return bool(AsLinear().flags
& StyleGradientFlags::REPEATING
);
456 return bool(AsRadial().flags
& StyleGradientFlags::REPEATING
);
458 return bool(AsConic().flags
& StyleGradientFlags::REPEATING
);
462 bool StyleGradient::IsOpaque() const;
464 template <typename Integer
>
465 inline StyleGenericGridLine
<Integer
>::StyleGenericGridLine()
466 : ident(do_AddRef(static_cast<nsAtom
*>(nsGkAtoms::_empty
))),
471 inline nsAtom
* StyleGridLine::LineName() const {
472 return ident
.AsAtom();
476 inline bool StyleGridLine::IsAuto() const {
477 return LineName()->IsEmpty() && line_num
== 0 && !is_span
;
480 using LengthPercentage
= StyleLengthPercentage
;
481 using LengthPercentageOrAuto
= StyleLengthPercentageOrAuto
;
482 using NonNegativeLengthPercentage
= StyleNonNegativeLengthPercentage
;
483 using NonNegativeLengthPercentageOrAuto
=
484 StyleNonNegativeLengthPercentageOrAuto
;
485 using NonNegativeLengthPercentageOrNormal
=
486 StyleNonNegativeLengthPercentageOrNormal
;
487 using Length
= StyleLength
;
488 using LengthOrAuto
= StyleLengthOrAuto
;
489 using NonNegativeLength
= StyleNonNegativeLength
;
490 using NonNegativeLengthOrAuto
= StyleNonNegativeLengthOrAuto
;
491 using BorderRadius
= StyleBorderRadius
;
493 bool StyleCSSPixelLength::IsZero() const { return _0
== 0.0f
; }
495 void StyleCSSPixelLength::ScaleBy(float aScale
) { _0
*= aScale
; }
497 StyleCSSPixelLength
StyleCSSPixelLength::ScaledBy(float aScale
) const {
498 return FromPixels(ToCSSPixels() * aScale
);
501 nscoord
StyleCSSPixelLength::ToAppUnits() const {
502 // We want to resolve the length part of the calc() expression rounding 0.5
503 // away from zero, instead of the default behavior of
504 // NSToCoordRound{,WithClamp} which do floor(x + 0.5).
506 // This is what the rust code in the app_units crate does, and not doing this
507 // would regress bug 1323735, for example.
509 // FIXME(emilio, bug 1528114): Probably we should do something smarter.
511 // Avoid the expensive FP math below.
514 float length
= _0
* float(mozilla::AppUnitsPerCSSPixel());
515 if (length
>= float(nscoord_MAX
)) {
518 if (length
<= float(nscoord_MIN
)) {
521 return NSToIntRound(length
);
524 bool LengthPercentage::IsLength() const { return Tag() == TAG_LENGTH
; }
526 StyleLengthPercentageUnion::StyleLengthPercentageUnion() {
527 length
= {TAG_LENGTH
, {0.0f
}};
528 MOZ_ASSERT(IsLength());
531 static_assert(sizeof(LengthPercentage
) == sizeof(uint64_t), "");
533 Length
& LengthPercentage::AsLength() {
534 MOZ_ASSERT(IsLength());
535 return length
.length
;
538 const Length
& LengthPercentage::AsLength() const {
539 return const_cast<LengthPercentage
*>(this)->AsLength();
542 bool LengthPercentage::IsPercentage() const { return Tag() == TAG_PERCENTAGE
; }
544 StylePercentage
& LengthPercentage::AsPercentage() {
545 MOZ_ASSERT(IsPercentage());
546 return percentage
.percentage
;
549 const StylePercentage
& LengthPercentage::AsPercentage() const {
550 return const_cast<LengthPercentage
*>(this)->AsPercentage();
553 bool LengthPercentage::IsCalc() const { return Tag() == TAG_CALC
; }
555 StyleCalcLengthPercentage
& LengthPercentage::AsCalc() {
556 MOZ_ASSERT(IsCalc());
557 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the tag.
561 return *reinterpret_cast<StyleCalcLengthPercentage
*>(
562 NativeEndian::swapFromLittleEndian(calc
.ptr
));
566 const StyleCalcLengthPercentage
& LengthPercentage::AsCalc() const {
567 return const_cast<LengthPercentage
*>(this)->AsCalc();
570 StyleLengthPercentageUnion::StyleLengthPercentageUnion(const Self
& aOther
) {
571 if (aOther
.IsLength()) {
572 length
= {TAG_LENGTH
, aOther
.AsLength()};
573 } else if (aOther
.IsPercentage()) {
574 percentage
= {TAG_PERCENTAGE
, aOther
.AsPercentage()};
576 MOZ_ASSERT(aOther
.IsCalc());
577 auto* ptr
= new StyleCalcLengthPercentage(aOther
.AsCalc());
578 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the
585 NativeEndian::swapToLittleEndian(reinterpret_cast<uintptr_t>(ptr
)),
589 MOZ_ASSERT(Tag() == aOther
.Tag());
592 StyleLengthPercentageUnion::~StyleLengthPercentageUnion() {
598 LengthPercentage
& LengthPercentage::operator=(const LengthPercentage
& aOther
) {
599 if (this != &aOther
) {
600 this->~LengthPercentage();
601 new (this) LengthPercentage(aOther
);
606 bool LengthPercentage::operator==(const LengthPercentage
& aOther
) const {
607 if (Tag() != aOther
.Tag()) {
611 return AsLength() == aOther
.AsLength();
613 if (IsPercentage()) {
614 return AsPercentage() == aOther
.AsPercentage();
616 return AsCalc() == aOther
.AsCalc();
619 bool LengthPercentage::operator!=(const LengthPercentage
& aOther
) const {
620 return !(*this == aOther
);
623 LengthPercentage
LengthPercentage::Zero() { return {}; }
625 LengthPercentage
LengthPercentage::FromPixels(CSSCoord aCoord
) {
627 MOZ_ASSERT(l
.IsLength());
628 l
.length
.length
= {aCoord
};
632 LengthPercentage
LengthPercentage::FromAppUnits(nscoord aCoord
) {
633 return FromPixels(CSSPixel::FromAppUnits(aCoord
));
636 LengthPercentage
LengthPercentage::FromPercentage(float aPercentage
) {
638 l
.percentage
= {TAG_PERCENTAGE
, {aPercentage
}};
642 bool LengthPercentage::HasPercent() const { return IsPercentage() || IsCalc(); }
644 bool LengthPercentage::ConvertsToLength() const { return IsLength(); }
646 nscoord
LengthPercentage::ToLength() const {
647 MOZ_ASSERT(ConvertsToLength());
648 return AsLength().ToAppUnits();
651 CSSCoord
LengthPercentage::ToLengthInCSSPixels() const {
652 MOZ_ASSERT(ConvertsToLength());
653 return AsLength().ToCSSPixels();
656 bool LengthPercentage::ConvertsToPercentage() const { return IsPercentage(); }
658 float LengthPercentage::ToPercentage() const {
659 MOZ_ASSERT(ConvertsToPercentage());
660 return AsPercentage()._0
;
663 bool LengthPercentage::HasLengthAndPercentage() const {
667 MOZ_ASSERT(!ConvertsToLength() && !ConvertsToPercentage(),
668 "Should've been simplified earlier");
672 bool LengthPercentage::IsDefinitelyZero() const {
674 return AsLength().IsZero();
676 if (IsPercentage()) {
677 return AsPercentage()._0
== 0.0f
;
679 // calc() should've been simplified to a percentage.
683 CSSCoord
StyleCalcLengthPercentage::ResolveToCSSPixels(CSSCoord aBasis
) const {
684 return Servo_ResolveCalcLengthPercentage(this, aBasis
);
688 void StyleCalcNode::ScaleLengthsBy(float);
690 CSSCoord
LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis
) const {
692 return AsLength().ToCSSPixels();
694 if (IsPercentage()) {
695 return AsPercentage()._0
* aPercentageBasis
;
697 return AsCalc().ResolveToCSSPixels(aPercentageBasis
);
700 template <typename T
>
701 CSSCoord
LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter
) const {
702 static_assert(std::is_same
<decltype(aPercentageGetter()), CSSCoord
>::value
,
703 "Should return CSS pixels");
704 if (ConvertsToLength()) {
705 return ToLengthInCSSPixels();
707 return ResolveToCSSPixels(aPercentageGetter());
710 template <typename T
, typename U
>
711 nscoord
LengthPercentage::Resolve(T aPercentageGetter
, U aRounder
) const {
712 static_assert(std::is_same
<decltype(aPercentageGetter()), nscoord
>::value
,
713 "Should return app units");
714 static_assert(std::is_same
<decltype(aRounder(1.0f
)), nscoord
>::value
,
715 "Should return app units");
716 if (ConvertsToLength()) {
719 if (IsPercentage() && AsPercentage()._0
== 0.0f
) {
722 nscoord basis
= aPercentageGetter();
723 if (IsPercentage()) {
724 return aRounder(basis
* AsPercentage()._0
);
726 return AsCalc().Resolve(basis
, aRounder
);
729 // Note: the static_cast<> wrappers below are needed to disambiguate between
730 // the versions of NSToCoordTruncClamped that take float vs. double as the arg.
731 nscoord
LengthPercentage::Resolve(nscoord aPercentageBasis
) const {
732 return Resolve([=] { return aPercentageBasis
; },
733 static_cast<nscoord (*)(float)>(NSToCoordTruncClamped
));
736 template <typename T
>
737 nscoord
LengthPercentage::Resolve(T aPercentageGetter
) const {
738 return Resolve(aPercentageGetter
,
739 static_cast<nscoord (*)(float)>(NSToCoordTruncClamped
));
742 template <typename T
>
743 nscoord
LengthPercentage::Resolve(nscoord aPercentageBasis
,
744 T aPercentageRounder
) const {
745 return Resolve([aPercentageBasis
] { return aPercentageBasis
; },
749 void LengthPercentage::ScaleLengthsBy(float aScale
) {
751 AsLength().ScaleBy(aScale
);
754 AsCalc().node
.ScaleLengthsBy(aScale
);
758 #define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \
760 inline bool ty_::HasPercent() const { \
761 return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \
764 inline bool ty_::ConvertsToLength() const { \
765 return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \
768 inline bool ty_::HasLengthAndPercentage() const { \
769 return IsLengthPercentage() && \
770 AsLengthPercentage().HasLengthAndPercentage(); \
773 inline nscoord ty_::ToLength() const { \
774 MOZ_ASSERT(ConvertsToLength()); \
775 return AsLengthPercentage().ToLength(); \
778 inline bool ty_::ConvertsToPercentage() const { \
779 return IsLengthPercentage() && \
780 AsLengthPercentage().ConvertsToPercentage(); \
783 inline float ty_::ToPercentage() const { \
784 MOZ_ASSERT(ConvertsToPercentage()); \
785 return AsLengthPercentage().ToPercentage(); \
788 IMPL_LENGTHPERCENTAGE_FORWARDS(LengthPercentageOrAuto
)
789 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleSize
)
790 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMaxSize
)
793 inline bool LengthOrAuto::IsLength() const {
794 return IsLengthPercentage();
798 inline const Length
& LengthOrAuto::AsLength() const {
799 return AsLengthPercentage();
803 inline nscoord
LengthOrAuto::ToLength() const {
804 return AsLength().ToAppUnits();
808 inline bool StyleFlexBasis::IsAuto() const {
809 return IsSize() && AsSize().IsAuto();
813 inline bool StyleSize::BehavesLikeInitialValueOnBlockAxis() const {
814 return IsAuto() || !IsLengthPercentage();
818 inline bool StyleMaxSize::BehavesLikeInitialValueOnBlockAxis() const {
819 return IsNone() || !IsLengthPercentage();
823 inline bool StyleBackgroundSize::IsInitialValue() const {
824 return IsExplicitSize() && explicit_size
.width
.IsAuto() &&
825 explicit_size
.height
.IsAuto();
828 template <typename T
>
829 const T
& StyleRect
<T
>::Get(mozilla::Side aSide
) const {
830 static_assert(sizeof(StyleRect
<T
>) == sizeof(T
) * 4, "");
831 static_assert(alignof(StyleRect
<T
>) == alignof(T
), "");
832 return reinterpret_cast<const T
*>(this)[aSide
];
835 template <typename T
>
836 T
& StyleRect
<T
>::Get(mozilla::Side aSide
) {
837 return const_cast<T
&>(static_cast<const StyleRect
&>(*this).Get(aSide
));
840 template <typename T
>
841 template <typename Predicate
>
842 bool StyleRect
<T
>::All(Predicate aPredicate
) const {
843 return aPredicate(_0
) && aPredicate(_1
) && aPredicate(_2
) && aPredicate(_3
);
846 template <typename T
>
847 template <typename Predicate
>
848 bool StyleRect
<T
>::Any(Predicate aPredicate
) const {
849 return aPredicate(_0
) || aPredicate(_1
) || aPredicate(_2
) || aPredicate(_3
);
853 inline const LengthPercentage
& BorderRadius::Get(HalfCorner aCorner
) const {
854 static_assert(sizeof(BorderRadius
) == sizeof(LengthPercentage
) * 8, "");
855 static_assert(alignof(BorderRadius
) == alignof(LengthPercentage
), "");
856 const auto* self
= reinterpret_cast<const LengthPercentage
*>(this);
857 return self
[aCorner
];
861 inline bool StyleTrackBreadth::HasPercent() const {
862 return IsBreadth() && AsBreadth().HasPercent();
865 // Implemented in nsStyleStructs.cpp
867 bool StyleTransform::HasPercent() const;
870 inline bool StyleTransformOrigin::HasPercent() const {
871 // NOTE(emilio): `depth` is just a `<length>` so doesn't have a percentage at
873 return horizontal
.HasPercent() || vertical
.HasPercent();
877 inline Maybe
<size_t> StyleGridTemplateComponent::RepeatAutoIndex() const {
878 if (!IsTrackList()) {
881 const auto& list
= *AsTrackList();
882 return list
.auto_repeat_index
< list
.values
.Length()
883 ? Some(list
.auto_repeat_index
)
888 inline bool StyleGridTemplateComponent::HasRepeatAuto() const {
889 return RepeatAutoIndex().isSome();
893 inline Span
<const StyleGenericTrackListValue
<LengthPercentage
, StyleInteger
>>
894 StyleGridTemplateComponent::TrackListValues() const {
896 return AsTrackList()->values
.AsSpan();
902 inline const StyleGenericTrackRepeat
<LengthPercentage
, StyleInteger
>*
903 StyleGridTemplateComponent::GetRepeatAutoValue() const {
904 auto index
= RepeatAutoIndex();
908 return &TrackListValues()[*index
].AsTrackRepeat();
911 constexpr const auto kPaintOrderShift
= StylePAINT_ORDER_SHIFT
;
912 constexpr const auto kPaintOrderMask
= StylePAINT_ORDER_MASK
;
915 inline nsRect StyleGenericClipRect
<LengthOrAuto
>::ToLayoutRect(
916 nscoord aAutoSize
) const {
917 nscoord x
= left
.IsLength() ? left
.ToLength() : 0;
918 nscoord y
= top
.IsLength() ? top
.ToLength() : 0;
919 nscoord width
= right
.IsLength() ? right
.ToLength() - x
: aAutoSize
;
920 nscoord height
= bottom
.IsLength() ? bottom
.ToLength() - y
: aAutoSize
;
921 return nsRect(x
, y
, width
, height
);
924 using RestyleHint
= StyleRestyleHint
;
926 inline RestyleHint
RestyleHint::RestyleSubtree() {
927 return RESTYLE_SELF
| RESTYLE_DESCENDANTS
;
930 inline RestyleHint
RestyleHint::RecascadeSubtree() {
931 return RECASCADE_SELF
| RECASCADE_DESCENDANTS
;
934 inline RestyleHint
RestyleHint::ForAnimations() {
935 return RESTYLE_CSS_TRANSITIONS
| RESTYLE_CSS_ANIMATIONS
| RESTYLE_SMIL
;
938 inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const {
939 if (!(*this & (RECASCADE_DESCENDANTS
| RESTYLE_DESCENDANTS
))) {
942 return bool(*this & (RESTYLE_SELF
| RECASCADE_SELF
));
946 ImageResolution
StyleImage::GetResolution() const;
949 inline const StyleImage
& StyleImage::FinalImage() const {
953 const auto& set
= *AsImageSet();
954 auto items
= set
.items
.AsSpan();
955 if (MOZ_LIKELY(set
.selected_index
< items
.Length())) {
956 return items
[set
.selected_index
].image
.FinalImage();
958 static auto sNone
= StyleImage::None();
963 Maybe
<CSSIntSize
> StyleImage::GetIntrinsicSize() const;
966 inline bool StyleImage::IsImageRequestType() const {
967 const auto& finalImage
= FinalImage();
968 return finalImage
.IsUrl();
972 inline const StyleComputedImageUrl
* StyleImage::GetImageRequestURLValue()
974 const auto& finalImage
= FinalImage();
975 if (finalImage
.IsUrl()) {
976 return &finalImage
.AsUrl();
982 inline imgRequestProxy
* StyleImage::GetImageRequest() const {
983 const auto* url
= GetImageRequestURLValue();
984 return url
? url
->GetImage() : nullptr;
988 inline bool StyleImage::IsResolved() const {
989 const auto* url
= GetImageRequestURLValue();
990 return !url
|| url
->IsImageResolved();
994 bool StyleImage::IsOpaque() const;
996 bool StyleImage::IsSizeAvailable() const;
998 bool StyleImage::IsComplete() const;
1000 void StyleImage::ResolveImage(dom::Document
&, const StyleImage
*);
1003 inline AspectRatio StyleRatio
<StyleNonNegativeNumber
>::ToLayoutRatio(
1004 UseBoxSizing aUseBoxSizing
) const {
1005 // 0/1, 1/0, and 0/0 are all degenerate ratios (which behave as auto), and we
1006 // always return 0.0f.
1007 // https://drafts.csswg.org/css-values-4/#degenerate-ratio
1008 return AspectRatio::FromSize(_0
, _1
, aUseBoxSizing
);
1012 inline AspectRatio
StyleAspectRatio::ToLayoutRatio() const {
1013 return HasRatio() ? ratio
.AsRatio().ToLayoutRatio(auto_
? UseBoxSizing::No
1014 : UseBoxSizing::Yes
)
1018 inline void StyleFontWeight::ToString(nsACString
& aString
) const {
1019 Servo_FontWeight_ToCss(this, &aString
);
1022 inline void StyleFontStretch::ToString(nsACString
& aString
) const {
1023 Servo_FontStretch_ToCss(this, &aString
);
1026 inline void StyleFontStyle::ToString(nsACString
& aString
) const {
1027 Servo_FontStyle_ToCss(this, &aString
);
1030 inline bool StyleFontWeight::IsBold() const { return *this >= BOLD_THRESHOLD
; }
1032 inline bool StyleFontStyle::IsItalic() const { return *this == ITALIC
; }
1034 inline bool StyleFontStyle::IsOblique() const {
1035 return !IsItalic() && !IsNormal();
1038 inline float StyleFontStyle::ObliqueAngle() const {
1039 MOZ_ASSERT(IsOblique());
1043 inline float StyleFontStyle::SlantAngle() const {
1044 return IsNormal() ? 0 : IsItalic() ? DEFAULT_OBLIQUE_DEGREES
: ObliqueAngle();
1047 using FontStretch
= StyleFontStretch
;
1048 using FontSlantStyle
= StyleFontStyle
;
1049 using FontWeight
= StyleFontWeight
;
1052 inline double StyleComputedTimingFunction::At(double aPortion
,
1053 bool aBeforeFlag
) const {
1054 return Servo_EasingFunctionAt(
1056 aBeforeFlag
? StyleEasingBeforeFlag::Set
: StyleEasingBeforeFlag::Unset
);
1060 inline void StyleComputedTimingFunction::AppendToString(
1061 nsACString
& aOut
) const {
1062 return Servo_SerializeEasing(this, &aOut
);
1066 inline double StyleComputedTimingFunction::GetPortion(
1067 const Maybe
<StyleComputedTimingFunction
>& aFn
, double aPortion
,
1069 return aFn
? aFn
->At(aPortion
, aBeforeFlag
) : aPortion
;
1074 inline LengthPercentageOrAuto
LengthPercentageOrAuto::Zero() {
1075 return LengthPercentage(LengthPercentage::Zero());
1079 inline StyleViewTimelineInset::StyleGenericViewTimelineInset()
1080 : start(LengthPercentageOrAuto::Auto()),
1081 end(LengthPercentageOrAuto::Auto()) {}
1083 inline StyleDisplayOutside
StyleDisplay::Outside() const {
1084 return StyleDisplayOutside((_0
& OUTSIDE_MASK
) >> OUTSIDE_SHIFT
);
1087 inline StyleDisplayInside
StyleDisplay::Inside() const {
1088 return StyleDisplayInside(_0
& INSIDE_MASK
);
1091 inline bool StyleDisplay::IsListItem() const { return _0
& LIST_ITEM_MASK
; }
1093 inline bool StyleDisplay::IsInternalTable() const {
1094 return Outside() == StyleDisplayOutside::InternalTable
;
1097 inline bool StyleDisplay::IsInternalTableExceptCell() const {
1098 return IsInternalTable() && *this != TableCell
;
1101 inline bool StyleDisplay::IsInternalRuby() const {
1102 return Outside() == StyleDisplayOutside::InternalRuby
;
1105 inline bool StyleDisplay::IsRuby() const {
1106 return Inside() == StyleDisplayInside::Ruby
|| IsInternalRuby();
1109 inline bool StyleDisplay::IsInlineFlow() const {
1110 return Outside() == StyleDisplayOutside::Inline
&&
1111 Inside() == StyleDisplayInside::Flow
;
1114 inline bool StyleDisplay::IsInlineInside() const {
1115 return IsInlineFlow() || IsRuby();
1118 inline bool StyleDisplay::IsInlineOutside() const {
1119 return Outside() == StyleDisplayOutside::Inline
|| IsInternalRuby();
1122 } // namespace mozilla