Backed out changeset c8f96b912b44 (bug 1897783) for causing reftest failures CLOSED...
[gecko.git] / layout / style / ServoStyleConstsInlines.h
blob50893f5112926677db54b8b7a464978a601c8e6c
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<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>;
60 template <typename T>
61 inline void StyleOwnedSlice<T>::Clear() {
62 if (!len) {
63 return;
65 for (size_t i : IntegerRange(len)) {
66 ptr[i].~T();
68 free(ptr);
69 ptr = (T*)alignof(T);
70 len = 0;
73 template <typename T>
74 inline void StyleOwnedSlice<T>::CopyFrom(const StyleOwnedSlice& aOther) {
75 Clear();
76 len = aOther.len;
77 if (!len) {
78 ptr = (T*)alignof(T);
79 } else {
80 ptr = (T*)malloc(len * sizeof(T));
81 size_t i = 0;
82 for (const T& elem : aOther.AsSpan()) {
83 new (ptr + i++) T(elem);
88 template <typename T>
89 inline void StyleOwnedSlice<T>::SwapElements(StyleOwnedSlice& aOther) {
90 std::swap(ptr, aOther.ptr);
91 std::swap(len, aOther.len);
94 template <typename T>
95 inline StyleOwnedSlice<T>::StyleOwnedSlice(const StyleOwnedSlice& aOther)
96 : StyleOwnedSlice() {
97 CopyFrom(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()) {
110 return;
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();
118 MOZ_ASSERT(ptr,
119 "How did extractRawBuffer return null if we're not using inline "
120 "capacity?");
123 template <typename T>
124 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=(
125 const StyleOwnedSlice& aOther) {
126 CopyFrom(aOther);
127 return *this;
130 template <typename T>
131 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=(
132 StyleOwnedSlice&& aOther) {
133 Clear();
134 SwapElements(aOther);
135 return *this;
138 template <typename T>
139 inline StyleOwnedSlice<T>::~StyleOwnedSlice() {
140 Clear();
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)) {
155 ::abort();
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) {
164 return false;
166 if (count.fetch_sub(1, std::memory_order_release) != 1) {
167 return false;
169 #ifdef MOZ_TSAN
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);
174 #else
175 std::atomic_thread_fence(std::memory_order_acquire);
176 #endif
177 MOZ_LOG_DTOR(this, "ServoArc", 8);
178 return true;
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)) {
196 elem.~T();
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())) {
215 ASSERT_CANARY
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);
223 ASSERT_CANARY
226 template <typename T>
227 inline size_t StyleArcSlice<T>::Length() const {
228 ASSERT_CANARY
229 return _0->Length();
232 template <typename T>
233 inline bool StyleArcSlice<T>::IsEmpty() const {
234 ASSERT_CANARY
235 return _0->IsEmpty();
238 template <typename T>
239 inline Span<const T> StyleArcSlice<T>::AsSpan() const {
240 ASSERT_CANARY
241 return _0->AsSpan();
244 #undef ASSERT_CANARY
246 template <typename T>
247 inline StyleArc<T>::StyleArc(const StyleArc& aOther) : p(aOther.p) {
248 p->IncrementRef();
251 template <typename T>
252 inline void StyleArc<T>::Release() {
253 if (MOZ_LIKELY(!p->DecrementRef())) {
254 return;
256 p->data.~T();
257 free(p);
260 template <typename T>
261 inline StyleArc<T>& StyleArc<T>::operator=(const StyleArc& aOther) {
262 if (p != aOther.p) {
263 Release();
264 p = aOther.p;
265 p->IncrementRef();
267 return *this;
270 template <typename T>
271 inline StyleArc<T>& StyleArc<T>::operator=(StyleArc&& aOther) {
272 std::swap(p, aOther.p);
273 return *this;
276 template <typename T>
277 inline StyleArc<T>::~StyleArc() {
278 Release();
281 inline bool StyleAtom::IsStatic() const { return !!(_0 & 1); }
283 inline nsAtom* StyleAtom::AsAtom() const {
284 if (IsStatic()) {
285 return const_cast<nsStaticAtom*>(&detail::gGkAtoms.mAtoms[_0 >> 1]);
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 size_t index = atom->AsStatic() - &detail::gGkAtoms.mAtoms[0];
306 _0 = (index << 1) | 1;
307 } else {
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) {
318 AddRef();
321 inline StyleAtom& StyleAtom::operator=(const StyleAtom& aOther) {
322 if (MOZ_LIKELY(this != &aOther)) {
323 Release();
324 _0 = aOther._0;
325 AddRef();
327 return *this;
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()),
337 s.Length());
340 template <typename T>
341 inline Span<const T> StyleGenericTransform<T>::Operations() const {
342 return _0.AsSpan();
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() {
361 if (!IsShared()) {
362 reinterpret_cast<URLExtraData*>(_0)->Release();
366 inline const URLExtraData& StyleUrlExtraData::get() const {
367 if (IsShared()) {
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 {
433 if (IsLocalRef()) {
434 return true;
436 if (nsIURI* uri = GetURI()) {
437 bool hasRef = false;
438 return NS_SUCCEEDED(uri->GetHasRef(&hasRef)) && hasRef;
440 return false;
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;
452 template <>
453 inline bool StyleGradient::Repeating() const {
454 if (IsLinear()) {
455 return bool(AsLinear().flags & StyleGradientFlags::REPEATING);
457 if (IsRadial()) {
458 return bool(AsRadial().flags & StyleGradientFlags::REPEATING);
460 return bool(AsConic().flags & StyleGradientFlags::REPEATING);
463 template <>
464 bool StyleGradient::IsOpaque() const;
466 template <>
467 inline const StyleColorInterpolationMethod&
468 StyleGradient::ColorInterpolationMethod() const {
469 if (IsLinear()) {
470 return AsLinear().color_interpolation_method;
472 if (IsRadial()) {
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) {}
482 template <>
483 inline nsAtom* StyleGridLine::LineName() const {
484 return ident.AsAtom();
487 template <>
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);
513 namespace detail {
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)) {
523 return nscoord_MAX;
525 if (length <= float(nscoord_MIN)) {
526 return nscoord_MIN;
528 return NSToIntRound(length);
530 } // namespace detail
532 nscoord StyleCSSPixelLength::ToAppUnits() const {
533 if (IsZero()) {
534 // Avoid the expensive FP math below.
535 return 0;
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.
574 #ifdef SERVO_32_BITS
575 return *calc.ptr;
576 #else
577 return *reinterpret_cast<StyleCalcLengthPercentage*>(
578 NativeEndian::swapFromLittleEndian(calc.ptr));
579 #endif
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()};
591 } else {
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
595 // tag.
596 calc = {
597 #ifdef SERVO_32_BITS
598 TAG_CALC,
599 ptr,
600 #else
601 NativeEndian::swapToLittleEndian(reinterpret_cast<uintptr_t>(ptr)),
602 #endif
605 MOZ_ASSERT(Tag() == aOther.Tag());
608 StyleLengthPercentageUnion::~StyleLengthPercentageUnion() {
609 if (IsCalc()) {
610 delete &AsCalc();
614 LengthPercentage& LengthPercentage::operator=(const LengthPercentage& aOther) {
615 if (this != &aOther) {
616 this->~LengthPercentage();
617 new (this) LengthPercentage(aOther);
619 return *this;
622 bool LengthPercentage::operator==(const LengthPercentage& aOther) const {
623 if (Tag() != aOther.Tag()) {
624 return false;
626 if (IsLength()) {
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) {
642 LengthPercentage l;
643 MOZ_ASSERT(l.IsLength());
644 l.length.length = {aCoord};
645 return l;
648 LengthPercentage LengthPercentage::FromAppUnits(nscoord aCoord) {
649 return FromPixels(CSSPixel::FromAppUnits(aCoord));
652 LengthPercentage LengthPercentage::FromPercentage(float aPercentage) {
653 LengthPercentage l;
654 l.percentage = {TAG_PERCENTAGE, {aPercentage}};
655 return l;
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 {
680 if (!IsCalc()) {
681 return false;
683 MOZ_ASSERT(!ConvertsToLength() && !ConvertsToPercentage(),
684 "Should've been simplified earlier");
685 return true;
688 bool LengthPercentage::IsDefinitelyZero() const {
689 if (IsLength()) {
690 return AsLength().IsZero();
692 if (IsPercentage()) {
693 return AsPercentage()._0 == 0.0f;
695 // calc() should've been simplified to a percentage.
696 return false;
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());
711 template <>
712 void StyleCalcNode::ScaleLengthsBy(float);
714 CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const {
715 if (IsLength()) {
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()) {
738 return ToLength();
740 if (IsPercentage() && AsPercentage()._0 == 0.0f) {
741 return 0;
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) {
767 if (IsLength()) {
768 AsLength().ScaleBy(aScale);
770 if (IsCalc()) {
771 AsCalc().node.ScaleLengthsBy(aScale);
775 #define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \
776 template <> \
777 inline bool ty_::HasPercent() const { \
778 return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \
780 template <> \
781 inline bool ty_::ConvertsToLength() const { \
782 return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \
784 template <> \
785 inline bool ty_::HasLengthAndPercentage() const { \
786 return IsLengthPercentage() && \
787 AsLengthPercentage().HasLengthAndPercentage(); \
789 template <> \
790 inline nscoord ty_::ToLength() const { \
791 MOZ_ASSERT(ConvertsToLength()); \
792 return AsLengthPercentage().ToLength(); \
794 template <> \
795 inline bool ty_::ConvertsToPercentage() const { \
796 return IsLengthPercentage() && \
797 AsLengthPercentage().ConvertsToPercentage(); \
799 template <> \
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)
809 template <>
810 inline bool LengthOrAuto::IsLength() const {
811 return IsLengthPercentage();
814 template <>
815 inline const Length& LengthOrAuto::AsLength() const {
816 return AsLengthPercentage();
819 template <>
820 inline nscoord LengthOrAuto::ToLength() const {
821 return AsLength().ToAppUnits();
824 template <>
825 inline bool StyleFlexBasis::IsAuto() const {
826 return IsSize() && AsSize().IsAuto();
829 template <>
830 inline bool StyleSize::BehavesLikeInitialValueOnBlockAxis() const {
831 return IsAuto() || !IsLengthPercentage();
834 template <>
835 inline bool StyleMaxSize::BehavesLikeInitialValueOnBlockAxis() const {
836 return IsNone() || !IsLengthPercentage();
839 template <>
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);
869 template <>
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];
877 template <>
878 inline bool StyleTrackBreadth::HasPercent() const {
879 return IsBreadth() && AsBreadth().HasPercent();
882 // Implemented in nsStyleStructs.cpp
883 template <>
884 bool StyleTransform::HasPercent() const;
886 template <>
887 inline bool StyleTransformOrigin::HasPercent() const {
888 // NOTE(emilio): `depth` is just a `<length>` so doesn't have a percentage at
889 // all.
890 return horizontal.HasPercent() || vertical.HasPercent();
893 template <>
894 inline Maybe<size_t> StyleGridTemplateComponent::RepeatAutoIndex() const {
895 if (!IsTrackList()) {
896 return Nothing();
898 const auto& list = *AsTrackList();
899 return list.auto_repeat_index < list.values.Length()
900 ? Some(list.auto_repeat_index)
901 : Nothing();
904 template <>
905 inline bool StyleGridTemplateComponent::HasRepeatAuto() const {
906 return RepeatAutoIndex().isSome();
909 template <>
910 inline Span<const StyleGenericTrackListValue<LengthPercentage, StyleInteger>>
911 StyleGridTemplateComponent::TrackListValues() const {
912 if (IsTrackList()) {
913 return AsTrackList()->values.AsSpan();
915 return {};
918 template <>
919 inline const StyleGenericTrackRepeat<LengthPercentage, StyleInteger>*
920 StyleGridTemplateComponent::GetRepeatAutoValue() const {
921 auto index = RepeatAutoIndex();
922 if (!index) {
923 return nullptr;
925 return &TrackListValues()[*index].AsTrackRepeat();
928 constexpr const auto kPaintOrderShift = StylePAINT_ORDER_SHIFT;
929 constexpr const auto kPaintOrderMask = StylePAINT_ORDER_MASK;
931 template <>
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))) {
957 return false;
959 return bool(*this & (RESTYLE_SELF | RECASCADE_SELF));
962 template <>
963 ImageResolution StyleImage::GetResolution(const ComputedStyle&) const;
965 template <>
966 inline const StyleImage& StyleImage::FinalImage() const {
967 if (!IsImageSet()) {
968 return *this;
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();
976 return sNone;
979 template <>
980 inline bool StyleImage::IsImageRequestType() const {
981 const auto& finalImage = FinalImage();
982 return finalImage.IsUrl();
985 template <>
986 inline const StyleComputedImageUrl* StyleImage::GetImageRequestURLValue()
987 const {
988 const auto& finalImage = FinalImage();
989 if (finalImage.IsUrl()) {
990 return &finalImage.AsUrl();
992 return nullptr;
995 template <>
996 inline imgRequestProxy* StyleImage::GetImageRequest() const {
997 const auto* url = GetImageRequestURLValue();
998 return url ? url->GetImage() : nullptr;
1001 template <>
1002 inline bool StyleImage::IsResolved() const {
1003 const auto* url = GetImageRequestURLValue();
1004 return !url || url->IsImageResolved();
1007 template <>
1008 bool StyleImage::IsOpaque() const;
1009 template <>
1010 bool StyleImage::IsSizeAvailable() const;
1011 template <>
1012 bool StyleImage::IsComplete() const;
1013 template <>
1014 void StyleImage::ResolveImage(dom::Document&, const StyleImage*);
1016 template <>
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);
1025 template <>
1026 inline AspectRatio StyleAspectRatio::ToLayoutRatio() const {
1027 return HasRatio() ? ratio.AsRatio().ToLayoutRatio(auto_ ? UseBoxSizing::No
1028 : UseBoxSizing::Yes)
1029 : AspectRatio();
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());
1054 return ToFloat();
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;
1065 template <>
1066 inline double StyleComputedTimingFunction::At(double aPortion,
1067 bool aBeforeFlag) const {
1068 return Servo_EasingFunctionAt(
1069 this, aPortion,
1070 aBeforeFlag ? StyleEasingBeforeFlag::Set : StyleEasingBeforeFlag::Unset);
1073 template <>
1074 inline void StyleComputedTimingFunction::AppendToString(
1075 nsACString& aOut) const {
1076 return Servo_SerializeEasing(this, &aOut);
1079 template <>
1080 inline double StyleComputedTimingFunction::GetPortion(
1081 const Maybe<StyleComputedTimingFunction>& aFn, double aPortion,
1082 bool aBeforeFlag) {
1083 return aFn ? aFn->At(aPortion, aBeforeFlag) : aPortion;
1086 /* static */
1087 template <>
1088 inline LengthPercentageOrAuto LengthPercentageOrAuto::Zero() {
1089 return LengthPercentage(LengthPercentage::Zero());
1092 template <>
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 {
1137 if (*this == ONE) {
1138 return aValue;
1140 return ToFloat() * aValue;
1143 inline float StyleZoom::Unzoom(float aValue) const {
1144 if (*this == ONE) {
1145 return aValue;
1147 return aValue / ToFloat();
1150 inline nscoord StyleZoom::ZoomCoord(nscoord aValue) const {
1151 if (*this == ONE) {
1152 return aValue;
1154 return NSToCoordRoundWithClamp(Zoom(float(aValue)));
1157 inline nscoord StyleZoom::UnzoomCoord(nscoord aValue) const {
1158 if (*this == ONE) {
1159 return aValue;
1161 return NSToCoordRoundWithClamp(Unzoom(float(aValue)));
1164 inline nsSize StyleZoom::Zoom(const nsSize& aValue) const {
1165 if (*this == ONE) {
1166 return aValue;
1168 return nsSize(ZoomCoord(aValue.Width()), ZoomCoord(aValue.Height()));
1171 inline nsSize StyleZoom::Unzoom(const nsSize& aValue) const {
1172 if (*this == ONE) {
1173 return aValue;
1175 return nsSize(UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height()));
1178 inline nsPoint StyleZoom::Zoom(const nsPoint& aValue) const {
1179 if (*this == ONE) {
1180 return aValue;
1182 return nsPoint(ZoomCoord(aValue.X()), ZoomCoord(aValue.Y()));
1185 inline nsPoint StyleZoom::Unzoom(const nsPoint& aValue) const {
1186 if (*this == ONE) {
1187 return aValue;
1189 return nsPoint(UnzoomCoord(aValue.X()), UnzoomCoord(aValue.Y()));
1192 inline nsRect StyleZoom::Zoom(const nsRect& aValue) const {
1193 if (*this == ONE) {
1194 return aValue;
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 {
1201 if (*this == ONE) {
1202 return aValue;
1204 return nsRect(UnzoomCoord(aValue.X()), UnzoomCoord(aValue.Y()),
1205 UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height()));
1208 template <>
1209 inline gfx::Point StyleCoordinatePair<StyleCSSFloat>::ToGfxPoint(
1210 const CSSSize* aBasis) const {
1211 return gfx::Point(x, y);
1214 template <>
1215 inline gfx::Point StyleCoordinatePair<LengthPercentage>::ToGfxPoint(
1216 const CSSSize* aBasis) const {
1217 MOZ_ASSERT(aBasis);
1218 return gfx::Point(x.ResolveToCSSPixels(aBasis->Width()),
1219 y.ResolveToCSSPixels(aBasis->Height()));
1222 } // namespace mozilla
1224 #endif