Bug 1839315: part 4) Link from `SheetLoadData::mWasAlternate` to spec. r=emilio DONTBUILD
[gecko.git] / layout / style / ServoStyleConstsInlines.h
blobe357a4f46262f8b59631531169b85a92b64d11f1
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>
21 #include <new>
23 // TODO(emilio): there are quite a few other implementations scattered around
24 // that should move here.
26 namespace mozilla {
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>;
57 template <typename T>
58 inline void StyleOwnedSlice<T>::Clear() {
59 if (!len) {
60 return;
62 for (size_t i : IntegerRange(len)) {
63 ptr[i].~T();
65 free(ptr);
66 ptr = (T*)alignof(T);
67 len = 0;
70 template <typename T>
71 inline void StyleOwnedSlice<T>::CopyFrom(const StyleOwnedSlice& aOther) {
72 Clear();
73 len = aOther.len;
74 if (!len) {
75 ptr = (T*)alignof(T);
76 } else {
77 ptr = (T*)malloc(len * sizeof(T));
78 size_t i = 0;
79 for (const T& elem : aOther.AsSpan()) {
80 new (ptr + i++) T(elem);
85 template <typename T>
86 inline void StyleOwnedSlice<T>::SwapElements(StyleOwnedSlice& aOther) {
87 std::swap(ptr, aOther.ptr);
88 std::swap(len, aOther.len);
91 template <typename T>
92 inline StyleOwnedSlice<T>::StyleOwnedSlice(const StyleOwnedSlice& aOther)
93 : StyleOwnedSlice() {
94 CopyFrom(aOther);
97 template <typename T>
98 inline StyleOwnedSlice<T>::StyleOwnedSlice(StyleOwnedSlice&& aOther)
99 : StyleOwnedSlice() {
100 SwapElements(aOther);
103 template <typename T>
104 inline StyleOwnedSlice<T>::StyleOwnedSlice(Vector<T>&& aVector)
105 : StyleOwnedSlice() {
106 if (!aVector.length()) {
107 return;
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();
115 MOZ_ASSERT(ptr,
116 "How did extractRawBuffer return null if we're not using inline "
117 "capacity?");
120 template <typename T>
121 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=(
122 const StyleOwnedSlice& aOther) {
123 CopyFrom(aOther);
124 return *this;
127 template <typename T>
128 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=(
129 StyleOwnedSlice&& aOther) {
130 Clear();
131 SwapElements(aOther);
132 return *this;
135 template <typename T>
136 inline StyleOwnedSlice<T>::~StyleOwnedSlice() {
137 Clear();
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)) {
152 ::abort();
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) {
161 return false;
163 if (count.fetch_sub(1, std::memory_order_release) != 1) {
164 return false;
166 #ifdef MOZ_TSAN
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);
171 #else
172 std::atomic_thread_fence(std::memory_order_acquire);
173 #endif
174 MOZ_LOG_DTOR(this, "ServoArc", 8);
175 return true;
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)) {
193 elem.~T();
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())) {
212 ASSERT_CANARY
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);
220 ASSERT_CANARY
223 template <typename T>
224 inline size_t StyleArcSlice<T>::Length() const {
225 ASSERT_CANARY
226 return _0->Length();
229 template <typename T>
230 inline bool StyleArcSlice<T>::IsEmpty() const {
231 ASSERT_CANARY
232 return _0->IsEmpty();
235 template <typename T>
236 inline Span<const T> StyleArcSlice<T>::AsSpan() const {
237 ASSERT_CANARY
238 return _0->AsSpan();
241 #undef ASSERT_CANARY
243 template <typename T>
244 inline StyleArc<T>::StyleArc(const StyleArc& aOther) : p(aOther.p) {
245 p->IncrementRef();
248 template <typename T>
249 inline void StyleArc<T>::Release() {
250 if (MOZ_LIKELY(!p->DecrementRef())) {
251 return;
253 p->data.~T();
254 free(p);
257 template <typename T>
258 inline StyleArc<T>& StyleArc<T>::operator=(const StyleArc& aOther) {
259 if (p != aOther.p) {
260 Release();
261 p = aOther.p;
262 p->IncrementRef();
264 return *this;
267 template <typename T>
268 inline StyleArc<T>& StyleArc<T>::operator=(StyleArc&& aOther) {
269 std::swap(p, aOther.p);
270 return *this;
273 template <typename T>
274 inline StyleArc<T>::~StyleArc() {
275 Release();
278 inline bool StyleAtom::IsStatic() const { return !!(_0 & 1); }
280 inline nsAtom* StyleAtom::AsAtom() const {
281 if (IsStatic()) {
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() {
291 if (!IsStatic()) {
292 AsAtom()->AddRef();
296 inline void StyleAtom::Release() {
297 if (!IsStatic()) {
298 AsAtom()->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;
308 } else {
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) {
316 AddRef();
319 inline StyleAtom& StyleAtom::operator=(const StyleAtom& aOther) {
320 if (MOZ_LIKELY(this != &aOther)) {
321 Release();
322 _0 = aOther._0;
323 AddRef();
325 return *this;
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()),
335 s.Length());
338 template <typename T>
339 inline Span<const T> StyleGenericTransform<T>::Operations() const {
340 return _0.AsSpan();
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() {
359 if (!IsShared()) {
360 reinterpret_cast<URLExtraData*>(_0)->Release();
364 inline const URLExtraData& StyleUrlExtraData::get() const {
365 if (IsShared()) {
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 {
431 if (IsLocalRef()) {
432 return true;
434 if (nsIURI* uri = GetURI()) {
435 bool hasRef = false;
436 return NS_SUCCEEDED(uri->GetHasRef(&hasRef)) && hasRef;
438 return false;
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;
450 template <>
451 inline bool StyleGradient::Repeating() const {
452 if (IsLinear()) {
453 return bool(AsLinear().flags & StyleGradientFlags::REPEATING);
455 if (IsRadial()) {
456 return bool(AsRadial().flags & StyleGradientFlags::REPEATING);
458 return bool(AsConic().flags & StyleGradientFlags::REPEATING);
461 template <>
462 bool StyleGradient::IsOpaque() const;
464 template <typename Integer>
465 inline StyleGenericGridLine<Integer>::StyleGenericGridLine()
466 : ident(do_AddRef(static_cast<nsAtom*>(nsGkAtoms::_empty))),
467 line_num(0),
468 is_span(false) {}
470 template <>
471 inline nsAtom* StyleGridLine::LineName() const {
472 return ident.AsAtom();
475 template <>
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.
510 if (IsZero()) {
511 // Avoid the expensive FP math below.
512 return 0;
514 float length = _0 * float(mozilla::AppUnitsPerCSSPixel());
515 if (length >= float(nscoord_MAX)) {
516 return nscoord_MAX;
518 if (length <= float(nscoord_MIN)) {
519 return 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.
558 #ifdef SERVO_32_BITS
559 return *calc.ptr;
560 #else
561 return *reinterpret_cast<StyleCalcLengthPercentage*>(
562 NativeEndian::swapFromLittleEndian(calc.ptr));
563 #endif
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()};
575 } else {
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
579 // tag.
580 calc = {
581 #ifdef SERVO_32_BITS
582 TAG_CALC,
583 ptr,
584 #else
585 NativeEndian::swapToLittleEndian(reinterpret_cast<uintptr_t>(ptr)),
586 #endif
589 MOZ_ASSERT(Tag() == aOther.Tag());
592 StyleLengthPercentageUnion::~StyleLengthPercentageUnion() {
593 if (IsCalc()) {
594 delete &AsCalc();
598 LengthPercentage& LengthPercentage::operator=(const LengthPercentage& aOther) {
599 if (this != &aOther) {
600 this->~LengthPercentage();
601 new (this) LengthPercentage(aOther);
603 return *this;
606 bool LengthPercentage::operator==(const LengthPercentage& aOther) const {
607 if (Tag() != aOther.Tag()) {
608 return false;
610 if (IsLength()) {
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) {
626 LengthPercentage l;
627 MOZ_ASSERT(l.IsLength());
628 l.length.length = {aCoord};
629 return l;
632 LengthPercentage LengthPercentage::FromAppUnits(nscoord aCoord) {
633 return FromPixels(CSSPixel::FromAppUnits(aCoord));
636 LengthPercentage LengthPercentage::FromPercentage(float aPercentage) {
637 LengthPercentage l;
638 l.percentage = {TAG_PERCENTAGE, {aPercentage}};
639 return l;
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 {
664 if (!IsCalc()) {
665 return false;
667 MOZ_ASSERT(!ConvertsToLength() && !ConvertsToPercentage(),
668 "Should've been simplified earlier");
669 return true;
672 bool LengthPercentage::IsDefinitelyZero() const {
673 if (IsLength()) {
674 return AsLength().IsZero();
676 if (IsPercentage()) {
677 return AsPercentage()._0 == 0.0f;
679 // calc() should've been simplified to a percentage.
680 return false;
683 CSSCoord StyleCalcLengthPercentage::ResolveToCSSPixels(CSSCoord aBasis) const {
684 return Servo_ResolveCalcLengthPercentage(this, aBasis);
687 template <>
688 void StyleCalcNode::ScaleLengthsBy(float);
690 CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const {
691 if (IsLength()) {
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()) {
717 return ToLength();
719 if (IsPercentage() && AsPercentage()._0 == 0.0f) {
720 return 0;
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; },
746 aPercentageRounder);
749 void LengthPercentage::ScaleLengthsBy(float aScale) {
750 if (IsLength()) {
751 AsLength().ScaleBy(aScale);
753 if (IsCalc()) {
754 AsCalc().node.ScaleLengthsBy(aScale);
758 #define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \
759 template <> \
760 inline bool ty_::HasPercent() const { \
761 return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \
763 template <> \
764 inline bool ty_::ConvertsToLength() const { \
765 return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \
767 template <> \
768 inline bool ty_::HasLengthAndPercentage() const { \
769 return IsLengthPercentage() && \
770 AsLengthPercentage().HasLengthAndPercentage(); \
772 template <> \
773 inline nscoord ty_::ToLength() const { \
774 MOZ_ASSERT(ConvertsToLength()); \
775 return AsLengthPercentage().ToLength(); \
777 template <> \
778 inline bool ty_::ConvertsToPercentage() const { \
779 return IsLengthPercentage() && \
780 AsLengthPercentage().ConvertsToPercentage(); \
782 template <> \
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)
792 template <>
793 inline bool LengthOrAuto::IsLength() const {
794 return IsLengthPercentage();
797 template <>
798 inline const Length& LengthOrAuto::AsLength() const {
799 return AsLengthPercentage();
802 template <>
803 inline nscoord LengthOrAuto::ToLength() const {
804 return AsLength().ToAppUnits();
807 template <>
808 inline bool StyleFlexBasis::IsAuto() const {
809 return IsSize() && AsSize().IsAuto();
812 template <>
813 inline bool StyleSize::BehavesLikeInitialValueOnBlockAxis() const {
814 return IsAuto() || !IsLengthPercentage();
817 template <>
818 inline bool StyleMaxSize::BehavesLikeInitialValueOnBlockAxis() const {
819 return IsNone() || !IsLengthPercentage();
822 template <>
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);
852 template <>
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];
860 template <>
861 inline bool StyleTrackBreadth::HasPercent() const {
862 return IsBreadth() && AsBreadth().HasPercent();
865 // Implemented in nsStyleStructs.cpp
866 template <>
867 bool StyleTransform::HasPercent() const;
869 template <>
870 inline bool StyleTransformOrigin::HasPercent() const {
871 // NOTE(emilio): `depth` is just a `<length>` so doesn't have a percentage at
872 // all.
873 return horizontal.HasPercent() || vertical.HasPercent();
876 template <>
877 inline Maybe<size_t> StyleGridTemplateComponent::RepeatAutoIndex() const {
878 if (!IsTrackList()) {
879 return Nothing();
881 const auto& list = *AsTrackList();
882 return list.auto_repeat_index < list.values.Length()
883 ? Some(list.auto_repeat_index)
884 : Nothing();
887 template <>
888 inline bool StyleGridTemplateComponent::HasRepeatAuto() const {
889 return RepeatAutoIndex().isSome();
892 template <>
893 inline Span<const StyleGenericTrackListValue<LengthPercentage, StyleInteger>>
894 StyleGridTemplateComponent::TrackListValues() const {
895 if (IsTrackList()) {
896 return AsTrackList()->values.AsSpan();
898 return {};
901 template <>
902 inline const StyleGenericTrackRepeat<LengthPercentage, StyleInteger>*
903 StyleGridTemplateComponent::GetRepeatAutoValue() const {
904 auto index = RepeatAutoIndex();
905 if (!index) {
906 return nullptr;
908 return &TrackListValues()[*index].AsTrackRepeat();
911 constexpr const auto kPaintOrderShift = StylePAINT_ORDER_SHIFT;
912 constexpr const auto kPaintOrderMask = StylePAINT_ORDER_MASK;
914 template <>
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))) {
940 return false;
942 return bool(*this & (RESTYLE_SELF | RECASCADE_SELF));
945 template <>
946 ImageResolution StyleImage::GetResolution() const;
948 template <>
949 inline const StyleImage& StyleImage::FinalImage() const {
950 if (!IsImageSet()) {
951 return *this;
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();
959 return sNone;
962 template <>
963 Maybe<CSSIntSize> StyleImage::GetIntrinsicSize() const;
965 template <>
966 inline bool StyleImage::IsImageRequestType() const {
967 const auto& finalImage = FinalImage();
968 return finalImage.IsUrl();
971 template <>
972 inline const StyleComputedImageUrl* StyleImage::GetImageRequestURLValue()
973 const {
974 const auto& finalImage = FinalImage();
975 if (finalImage.IsUrl()) {
976 return &finalImage.AsUrl();
978 return nullptr;
981 template <>
982 inline imgRequestProxy* StyleImage::GetImageRequest() const {
983 const auto* url = GetImageRequestURLValue();
984 return url ? url->GetImage() : nullptr;
987 template <>
988 inline bool StyleImage::IsResolved() const {
989 const auto* url = GetImageRequestURLValue();
990 return !url || url->IsImageResolved();
993 template <>
994 bool StyleImage::IsOpaque() const;
995 template <>
996 bool StyleImage::IsSizeAvailable() const;
997 template <>
998 bool StyleImage::IsComplete() const;
999 template <>
1000 void StyleImage::ResolveImage(dom::Document&, const StyleImage*);
1002 template <>
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);
1011 template <>
1012 inline AspectRatio StyleAspectRatio::ToLayoutRatio() const {
1013 return HasRatio() ? ratio.AsRatio().ToLayoutRatio(auto_ ? UseBoxSizing::No
1014 : UseBoxSizing::Yes)
1015 : AspectRatio();
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());
1040 return ToFloat();
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;
1051 template <>
1052 inline double StyleComputedTimingFunction::At(double aPortion,
1053 bool aBeforeFlag) const {
1054 return Servo_EasingFunctionAt(
1055 this, aPortion,
1056 aBeforeFlag ? StyleEasingBeforeFlag::Set : StyleEasingBeforeFlag::Unset);
1059 template <>
1060 inline void StyleComputedTimingFunction::AppendToString(
1061 nsACString& aOut) const {
1062 return Servo_SerializeEasing(this, &aOut);
1065 template <>
1066 inline double StyleComputedTimingFunction::GetPortion(
1067 const Maybe<StyleComputedTimingFunction>& aFn, double aPortion,
1068 bool aBeforeFlag) {
1069 return aFn ? aFn->At(aPortion, aBeforeFlag) : aPortion;
1072 /* static */
1073 template <>
1074 inline LengthPercentageOrAuto LengthPercentageOrAuto::Zero() {
1075 return LengthPercentage(LengthPercentage::Zero());
1078 template <>
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
1124 #endif