Bug 1890793: Assert CallArgs::newTarget is not gray. r=spidermonkey-reviewers,sfink...
[gecko.git] / layout / style / ServoStyleConstsInlines.h
blobf1cfa8565a55d7e4799de2f8580040dbbe73c18d
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>;
56 template struct StyleStrong<StyleScopeRule>;
57 template struct StyleStrong<StyleStartingStyleRule>;
59 template <typename T>
60 inline void StyleOwnedSlice<T>::Clear() {
61 if (!len) {
62 return;
64 for (size_t i : IntegerRange(len)) {
65 ptr[i].~T();
67 free(ptr);
68 ptr = (T*)alignof(T);
69 len = 0;
72 template <typename T>
73 inline void StyleOwnedSlice<T>::CopyFrom(const StyleOwnedSlice& aOther) {
74 Clear();
75 len = aOther.len;
76 if (!len) {
77 ptr = (T*)alignof(T);
78 } else {
79 ptr = (T*)malloc(len * sizeof(T));
80 size_t i = 0;
81 for (const T& elem : aOther.AsSpan()) {
82 new (ptr + i++) T(elem);
87 template <typename T>
88 inline void StyleOwnedSlice<T>::SwapElements(StyleOwnedSlice& aOther) {
89 std::swap(ptr, aOther.ptr);
90 std::swap(len, aOther.len);
93 template <typename T>
94 inline StyleOwnedSlice<T>::StyleOwnedSlice(const StyleOwnedSlice& aOther)
95 : StyleOwnedSlice() {
96 CopyFrom(aOther);
99 template <typename T>
100 inline StyleOwnedSlice<T>::StyleOwnedSlice(StyleOwnedSlice&& aOther)
101 : StyleOwnedSlice() {
102 SwapElements(aOther);
105 template <typename T>
106 inline StyleOwnedSlice<T>::StyleOwnedSlice(Vector<T>&& aVector)
107 : StyleOwnedSlice() {
108 if (!aVector.length()) {
109 return;
112 // We could handle this if Vector provided the relevant APIs, see bug 1610702.
113 MOZ_DIAGNOSTIC_ASSERT(aVector.length() == aVector.capacity(),
114 "Shouldn't over-allocate");
115 len = aVector.length();
116 ptr = aVector.extractRawBuffer();
117 MOZ_ASSERT(ptr,
118 "How did extractRawBuffer return null if we're not using inline "
119 "capacity?");
122 template <typename T>
123 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=(
124 const StyleOwnedSlice& aOther) {
125 CopyFrom(aOther);
126 return *this;
129 template <typename T>
130 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=(
131 StyleOwnedSlice&& aOther) {
132 Clear();
133 SwapElements(aOther);
134 return *this;
137 template <typename T>
138 inline StyleOwnedSlice<T>::~StyleOwnedSlice() {
139 Clear();
142 // This code is basically a C++ port of the Arc::clone() implementation in
143 // servo/components/servo_arc/lib.rs.
144 static constexpr const size_t kStaticRefcount =
145 std::numeric_limits<size_t>::max();
146 static constexpr const size_t kMaxRefcount =
147 std::numeric_limits<intptr_t>::max();
149 template <typename T>
150 inline void StyleArcInner<T>::IncrementRef() {
151 if (count.load(std::memory_order_relaxed) != kStaticRefcount) {
152 auto old_size = count.fetch_add(1, std::memory_order_relaxed);
153 if (MOZ_UNLIKELY(old_size > kMaxRefcount)) {
154 ::abort();
159 // This is a C++ port-ish of Arc::drop().
160 template <typename T>
161 inline bool StyleArcInner<T>::DecrementRef() {
162 if (count.load(std::memory_order_relaxed) == kStaticRefcount) {
163 return false;
165 if (count.fetch_sub(1, std::memory_order_release) != 1) {
166 return false;
168 #ifdef MOZ_TSAN
169 // TSan doesn't understand std::atomic_thread_fence, so in order
170 // to avoid a false positive for every time a refcounted object
171 // is deleted, we replace the fence with an atomic operation.
172 count.load(std::memory_order_acquire);
173 #else
174 std::atomic_thread_fence(std::memory_order_acquire);
175 #endif
176 MOZ_LOG_DTOR(this, "ServoArc", 8);
177 return true;
180 template <typename H, typename T>
181 inline bool StyleHeaderSlice<H, T>::operator==(
182 const StyleHeaderSlice& aOther) const {
183 return header == aOther.header && AsSpan() == aOther.AsSpan();
186 template <typename H, typename T>
187 inline bool StyleHeaderSlice<H, T>::operator!=(
188 const StyleHeaderSlice& aOther) const {
189 return !(*this == aOther);
192 template <typename H, typename T>
193 inline StyleHeaderSlice<H, T>::~StyleHeaderSlice() {
194 for (T& elem : Span(data, len)) {
195 elem.~T();
199 template <typename H, typename T>
200 inline Span<const T> StyleHeaderSlice<H, T>::AsSpan() const {
201 // Explicitly specify template argument here to avoid instantiating Span<T>
202 // first and then implicitly converting to Span<const T>
203 return Span<const T>{data, len};
206 static constexpr const uint64_t kArcSliceCanary = 0xf3f3f3f3f3f3f3f3;
208 #define ASSERT_CANARY \
209 MOZ_DIAGNOSTIC_ASSERT(_0.p->data.header == kArcSliceCanary, "Uh?");
211 template <typename T>
212 inline StyleArcSlice<T>::StyleArcSlice()
213 : _0(reinterpret_cast<decltype(_0.p)>(Servo_StyleArcSlice_EmptyPtr())) {
214 ASSERT_CANARY
217 template <typename T>
218 inline StyleArcSlice<T>::StyleArcSlice(
219 const StyleForgottenArcSlicePtr<T>& aPtr) {
220 // See the forget() implementation to see why reinterpret_cast() is ok.
221 _0.p = reinterpret_cast<decltype(_0.p)>(aPtr._0);
222 ASSERT_CANARY
225 template <typename T>
226 inline size_t StyleArcSlice<T>::Length() const {
227 ASSERT_CANARY
228 return _0->Length();
231 template <typename T>
232 inline bool StyleArcSlice<T>::IsEmpty() const {
233 ASSERT_CANARY
234 return _0->IsEmpty();
237 template <typename T>
238 inline Span<const T> StyleArcSlice<T>::AsSpan() const {
239 ASSERT_CANARY
240 return _0->AsSpan();
243 #undef ASSERT_CANARY
245 template <typename T>
246 inline StyleArc<T>::StyleArc(const StyleArc& aOther) : p(aOther.p) {
247 p->IncrementRef();
250 template <typename T>
251 inline void StyleArc<T>::Release() {
252 if (MOZ_LIKELY(!p->DecrementRef())) {
253 return;
255 p->data.~T();
256 free(p);
259 template <typename T>
260 inline StyleArc<T>& StyleArc<T>::operator=(const StyleArc& aOther) {
261 if (p != aOther.p) {
262 Release();
263 p = aOther.p;
264 p->IncrementRef();
266 return *this;
269 template <typename T>
270 inline StyleArc<T>& StyleArc<T>::operator=(StyleArc&& aOther) {
271 std::swap(p, aOther.p);
272 return *this;
275 template <typename T>
276 inline StyleArc<T>::~StyleArc() {
277 Release();
280 inline bool StyleAtom::IsStatic() const { return !!(_0 & 1); }
282 inline nsAtom* StyleAtom::AsAtom() const {
283 if (IsStatic()) {
284 return const_cast<nsStaticAtom*>(&detail::gGkAtoms.mAtoms[_0 >> 1]);
286 return reinterpret_cast<nsAtom*>(_0);
289 inline void StyleAtom::AddRef() {
290 if (!IsStatic()) {
291 AsAtom()->AddRef();
295 inline void StyleAtom::Release() {
296 if (!IsStatic()) {
297 AsAtom()->Release();
301 inline StyleAtom::StyleAtom(already_AddRefed<nsAtom> aAtom) {
302 nsAtom* atom = aAtom.take();
303 if (atom->IsStatic()) {
304 size_t index = atom->AsStatic() - &detail::gGkAtoms.mAtoms[0];
305 _0 = (index << 1) | 1;
306 } else {
307 _0 = reinterpret_cast<uintptr_t>(atom);
309 MOZ_ASSERT(IsStatic() == atom->IsStatic());
310 MOZ_ASSERT(AsAtom() == atom);
313 inline StyleAtom::StyleAtom(nsStaticAtom* aAtom)
314 : StyleAtom(do_AddRef(static_cast<nsAtom*>(aAtom))) {}
316 inline StyleAtom::StyleAtom(const StyleAtom& aOther) : _0(aOther._0) {
317 AddRef();
320 inline StyleAtom& StyleAtom::operator=(const StyleAtom& aOther) {
321 if (MOZ_LIKELY(this != &aOther)) {
322 Release();
323 _0 = aOther._0;
324 AddRef();
326 return *this;
329 inline StyleAtom::~StyleAtom() { Release(); }
331 inline nsAtom* StyleCustomIdent::AsAtom() const { return _0.AsAtom(); }
333 inline nsDependentCSubstring StyleOwnedStr::AsString() const {
334 Span<const uint8_t> s = _0.AsSpan();
335 return nsDependentCSubstring(reinterpret_cast<const char*>(s.Elements()),
336 s.Length());
339 template <typename T>
340 inline Span<const T> StyleGenericTransform<T>::Operations() const {
341 return _0.AsSpan();
344 template <typename T>
345 inline bool StyleGenericTransform<T>::IsNone() const {
346 return Operations().IsEmpty();
349 inline StyleAngle StyleAngle::Zero() { return {0.0f}; }
351 inline float StyleAngle::ToDegrees() const { return _0; }
353 inline double StyleAngle::ToRadians() const {
354 return double(ToDegrees()) * M_PI / 180.0;
357 inline bool StyleUrlExtraData::IsShared() const { return !!(_0 & 1); }
359 inline StyleUrlExtraData::~StyleUrlExtraData() {
360 if (!IsShared()) {
361 reinterpret_cast<URLExtraData*>(_0)->Release();
365 inline const URLExtraData& StyleUrlExtraData::get() const {
366 if (IsShared()) {
367 return *URLExtraData::sShared[_0 >> 1];
369 return *reinterpret_cast<const URLExtraData*>(_0);
372 inline nsDependentCSubstring StyleCssUrl::SpecifiedSerialization() const {
373 return _0->serialization.AsString();
376 inline const URLExtraData& StyleCssUrl::ExtraData() const {
377 return _0->extra_data.get();
380 inline StyleLoadData& StyleCssUrl::LoadData() const {
381 if (MOZ_LIKELY(_0->load_data.tag == StyleLoadDataSource::Tag::Owned)) {
382 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread() ||
383 dom::IsCurrentThreadRunningWorker());
384 return const_cast<StyleLoadData&>(_0->load_data.owned._0);
386 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread(),
387 "Lazy load datas should come from user-agent sheets, "
388 "which don't make sense on workers");
389 return const_cast<StyleLoadData&>(*Servo_LoadData_GetLazy(&_0->load_data));
392 inline nsIURI* StyleCssUrl::GetURI() const {
393 auto& loadData = LoadData();
394 if (!(loadData.flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_URI)) {
395 loadData.flags |= StyleLoadDataFlags::TRIED_TO_RESOLVE_URI;
396 nsDependentCSubstring serialization = SpecifiedSerialization();
397 // https://drafts.csswg.org/css-values-4/#url-empty:
399 // If the value of the url() is the empty string (like url("") or
400 // url()), the url must resolve to an invalid resource (similar to what
401 // the url about:invalid does).
403 if (!serialization.IsEmpty()) {
404 RefPtr<nsIURI> resolved;
405 NS_NewURI(getter_AddRefs(resolved), serialization, nullptr,
406 ExtraData().BaseURI());
407 loadData.resolved_uri = resolved.forget().take();
410 return loadData.resolved_uri;
413 inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const {
414 return _0.SpecifiedSerialization();
416 inline const URLExtraData& StyleComputedUrl::ExtraData() const {
417 return _0.ExtraData();
419 inline StyleLoadData& StyleComputedUrl::LoadData() const {
420 return _0.LoadData();
422 inline StyleCorsMode StyleComputedUrl::CorsMode() const {
423 return _0._0->cors_mode;
425 inline nsIURI* StyleComputedUrl::GetURI() const { return _0.GetURI(); }
427 inline bool StyleComputedUrl::IsLocalRef() const {
428 return Servo_CssUrl_IsLocalRef(&_0);
431 inline bool StyleComputedUrl::HasRef() const {
432 if (IsLocalRef()) {
433 return true;
435 if (nsIURI* uri = GetURI()) {
436 bool hasRef = false;
437 return NS_SUCCEEDED(uri->GetHasRef(&hasRef)) && hasRef;
439 return false;
442 inline bool StyleComputedImageUrl::IsImageResolved() const {
443 return bool(LoadData().flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE);
446 inline imgRequestProxy* StyleComputedImageUrl::GetImage() const {
447 MOZ_ASSERT(IsImageResolved());
448 return LoadData().resolved_image;
451 template <>
452 inline bool StyleGradient::Repeating() const {
453 if (IsLinear()) {
454 return bool(AsLinear().flags & StyleGradientFlags::REPEATING);
456 if (IsRadial()) {
457 return bool(AsRadial().flags & StyleGradientFlags::REPEATING);
459 return bool(AsConic().flags & StyleGradientFlags::REPEATING);
462 template <>
463 bool StyleGradient::IsOpaque() const;
465 template <>
466 inline const StyleColorInterpolationMethod&
467 StyleGradient::ColorInterpolationMethod() const {
468 if (IsLinear()) {
469 return AsLinear().color_interpolation_method;
471 if (IsRadial()) {
472 return AsRadial().color_interpolation_method;
474 return AsConic().color_interpolation_method;
477 template <typename Integer>
478 inline StyleGenericGridLine<Integer>::StyleGenericGridLine()
479 : ident{StyleAtom(nsGkAtoms::_empty)}, line_num(0), is_span(false) {}
481 template <>
482 inline nsAtom* StyleGridLine::LineName() const {
483 return ident.AsAtom();
486 template <>
487 inline bool StyleGridLine::IsAuto() const {
488 return LineName()->IsEmpty() && line_num == 0 && !is_span;
491 using LengthPercentage = StyleLengthPercentage;
492 using LengthPercentageOrAuto = StyleLengthPercentageOrAuto;
493 using NonNegativeLengthPercentage = StyleNonNegativeLengthPercentage;
494 using NonNegativeLengthPercentageOrAuto =
495 StyleNonNegativeLengthPercentageOrAuto;
496 using NonNegativeLengthPercentageOrNormal =
497 StyleNonNegativeLengthPercentageOrNormal;
498 using Length = StyleLength;
499 using LengthOrAuto = StyleLengthOrAuto;
500 using NonNegativeLength = StyleNonNegativeLength;
501 using NonNegativeLengthOrAuto = StyleNonNegativeLengthOrAuto;
502 using BorderRadius = StyleBorderRadius;
504 bool StyleCSSPixelLength::IsZero() const { return _0 == 0.0f; }
506 void StyleCSSPixelLength::ScaleBy(float aScale) { _0 *= aScale; }
508 StyleCSSPixelLength StyleCSSPixelLength::ScaledBy(float aScale) const {
509 return FromPixels(ToCSSPixels() * aScale);
512 namespace detail {
513 static inline nscoord DefaultPercentLengthToAppUnits(float aPixelLength) {
514 return NSToCoordTruncClamped(aPixelLength);
517 static inline nscoord DefaultLengthToAppUnits(float aPixelLength) {
518 // We want to round lengths rounding 0.5 away from zero, instead of the
519 // default behavior of NSToCoordRound{,WithClamp} which do floor(x + 0.5).
520 float length = aPixelLength * float(mozilla::AppUnitsPerCSSPixel());
521 if (length >= float(nscoord_MAX)) {
522 return nscoord_MAX;
524 if (length <= float(nscoord_MIN)) {
525 return nscoord_MIN;
527 return NSToIntRound(length);
529 } // namespace detail
531 nscoord StyleCSSPixelLength::ToAppUnits() const {
532 if (IsZero()) {
533 // Avoid the expensive FP math below.
534 return 0;
536 return detail::DefaultLengthToAppUnits(_0);
539 bool LengthPercentage::IsLength() const { return Tag() == TAG_LENGTH; }
541 StyleLengthPercentageUnion::StyleLengthPercentageUnion() {
542 length = {TAG_LENGTH, {0.0f}};
543 MOZ_ASSERT(IsLength());
546 static_assert(sizeof(LengthPercentage) == sizeof(uint64_t), "");
548 Length& LengthPercentage::AsLength() {
549 MOZ_ASSERT(IsLength());
550 return length.length;
553 const Length& LengthPercentage::AsLength() const {
554 return const_cast<LengthPercentage*>(this)->AsLength();
557 bool LengthPercentage::IsPercentage() const { return Tag() == TAG_PERCENTAGE; }
559 StylePercentage& LengthPercentage::AsPercentage() {
560 MOZ_ASSERT(IsPercentage());
561 return percentage.percentage;
564 const StylePercentage& LengthPercentage::AsPercentage() const {
565 return const_cast<LengthPercentage*>(this)->AsPercentage();
568 bool LengthPercentage::IsCalc() const { return Tag() == TAG_CALC; }
570 StyleCalcLengthPercentage& LengthPercentage::AsCalc() {
571 MOZ_ASSERT(IsCalc());
572 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the tag.
573 #ifdef SERVO_32_BITS
574 return *calc.ptr;
575 #else
576 return *reinterpret_cast<StyleCalcLengthPercentage*>(
577 NativeEndian::swapFromLittleEndian(calc.ptr));
578 #endif
581 const StyleCalcLengthPercentage& LengthPercentage::AsCalc() const {
582 return const_cast<LengthPercentage*>(this)->AsCalc();
585 StyleLengthPercentageUnion::StyleLengthPercentageUnion(const Self& aOther) {
586 if (aOther.IsLength()) {
587 length = {TAG_LENGTH, aOther.AsLength()};
588 } else if (aOther.IsPercentage()) {
589 percentage = {TAG_PERCENTAGE, aOther.AsPercentage()};
590 } else {
591 MOZ_ASSERT(aOther.IsCalc());
592 auto* ptr = new StyleCalcLengthPercentage(aOther.AsCalc());
593 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the
594 // tag.
595 calc = {
596 #ifdef SERVO_32_BITS
597 TAG_CALC,
598 ptr,
599 #else
600 NativeEndian::swapToLittleEndian(reinterpret_cast<uintptr_t>(ptr)),
601 #endif
604 MOZ_ASSERT(Tag() == aOther.Tag());
607 StyleLengthPercentageUnion::~StyleLengthPercentageUnion() {
608 if (IsCalc()) {
609 delete &AsCalc();
613 LengthPercentage& LengthPercentage::operator=(const LengthPercentage& aOther) {
614 if (this != &aOther) {
615 this->~LengthPercentage();
616 new (this) LengthPercentage(aOther);
618 return *this;
621 bool LengthPercentage::operator==(const LengthPercentage& aOther) const {
622 if (Tag() != aOther.Tag()) {
623 return false;
625 if (IsLength()) {
626 return AsLength() == aOther.AsLength();
628 if (IsPercentage()) {
629 return AsPercentage() == aOther.AsPercentage();
631 return AsCalc() == aOther.AsCalc();
634 bool LengthPercentage::operator!=(const LengthPercentage& aOther) const {
635 return !(*this == aOther);
638 LengthPercentage LengthPercentage::Zero() { return {}; }
640 LengthPercentage LengthPercentage::FromPixels(CSSCoord aCoord) {
641 LengthPercentage l;
642 MOZ_ASSERT(l.IsLength());
643 l.length.length = {aCoord};
644 return l;
647 LengthPercentage LengthPercentage::FromAppUnits(nscoord aCoord) {
648 return FromPixels(CSSPixel::FromAppUnits(aCoord));
651 LengthPercentage LengthPercentage::FromPercentage(float aPercentage) {
652 LengthPercentage l;
653 l.percentage = {TAG_PERCENTAGE, {aPercentage}};
654 return l;
657 bool LengthPercentage::HasPercent() const { return IsPercentage() || IsCalc(); }
659 bool LengthPercentage::ConvertsToLength() const { return IsLength(); }
661 nscoord LengthPercentage::ToLength() const {
662 MOZ_ASSERT(ConvertsToLength());
663 return AsLength().ToAppUnits();
666 CSSCoord LengthPercentage::ToLengthInCSSPixels() const {
667 MOZ_ASSERT(ConvertsToLength());
668 return AsLength().ToCSSPixels();
671 bool LengthPercentage::ConvertsToPercentage() const { return IsPercentage(); }
673 float LengthPercentage::ToPercentage() const {
674 MOZ_ASSERT(ConvertsToPercentage());
675 return AsPercentage()._0;
678 bool LengthPercentage::HasLengthAndPercentage() const {
679 if (!IsCalc()) {
680 return false;
682 MOZ_ASSERT(!ConvertsToLength() && !ConvertsToPercentage(),
683 "Should've been simplified earlier");
684 return true;
687 bool LengthPercentage::IsDefinitelyZero() const {
688 if (IsLength()) {
689 return AsLength().IsZero();
691 if (IsPercentage()) {
692 return AsPercentage()._0 == 0.0f;
694 // calc() should've been simplified to a percentage.
695 return false;
698 CSSCoord StyleCalcLengthPercentage::ResolveToCSSPixels(CSSCoord aBasis) const {
699 return Servo_ResolveCalcLengthPercentage(this, aBasis);
702 nscoord StyleCalcLengthPercentage::Resolve(nscoord aBasis) const {
703 return detail::DefaultLengthToAppUnits(
704 ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis)));
707 template <>
708 void StyleCalcNode::ScaleLengthsBy(float);
710 CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const {
711 if (IsLength()) {
712 return AsLength().ToCSSPixels();
714 if (IsPercentage()) {
715 return AsPercentage()._0 * aPercentageBasis;
717 return AsCalc().ResolveToCSSPixels(aPercentageBasis);
720 template <typename T>
721 CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const {
722 static_assert(std::is_same_v<decltype(aPercentageGetter()), CSSCoord>);
723 if (ConvertsToLength()) {
724 return ToLengthInCSSPixels();
726 return ResolveToCSSPixels(aPercentageGetter());
729 template <typename T, typename PercentRounder>
730 nscoord LengthPercentage::Resolve(T aPercentageGetter,
731 PercentRounder aPercentRounder) const {
732 static_assert(std::is_same_v<decltype(aPercentageGetter()), nscoord>);
733 static_assert(std::is_same_v<decltype(aPercentRounder(1.0f)), nscoord>);
734 if (ConvertsToLength()) {
735 return ToLength();
737 if (IsPercentage() && AsPercentage()._0 == 0.0f) {
738 return 0;
740 nscoord basis = aPercentageGetter();
741 if (IsPercentage()) {
742 return aPercentRounder(basis * AsPercentage()._0);
744 return AsCalc().Resolve(basis);
747 nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const {
748 return Resolve([=] { return aPercentageBasis; },
749 detail::DefaultPercentLengthToAppUnits);
752 template <typename T>
753 nscoord LengthPercentage::Resolve(T aPercentageGetter) const {
754 return Resolve(aPercentageGetter, detail::DefaultPercentLengthToAppUnits);
757 template <typename PercentRounder>
758 nscoord LengthPercentage::Resolve(nscoord aPercentageBasis,
759 PercentRounder aPercentRounder) const {
760 return Resolve([aPercentageBasis] { return aPercentageBasis; },
761 aPercentRounder);
764 void LengthPercentage::ScaleLengthsBy(float aScale) {
765 if (IsLength()) {
766 AsLength().ScaleBy(aScale);
768 if (IsCalc()) {
769 AsCalc().node.ScaleLengthsBy(aScale);
773 #define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \
774 template <> \
775 inline bool ty_::HasPercent() const { \
776 return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \
778 template <> \
779 inline bool ty_::ConvertsToLength() const { \
780 return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \
782 template <> \
783 inline bool ty_::HasLengthAndPercentage() const { \
784 return IsLengthPercentage() && \
785 AsLengthPercentage().HasLengthAndPercentage(); \
787 template <> \
788 inline nscoord ty_::ToLength() const { \
789 MOZ_ASSERT(ConvertsToLength()); \
790 return AsLengthPercentage().ToLength(); \
792 template <> \
793 inline bool ty_::ConvertsToPercentage() const { \
794 return IsLengthPercentage() && \
795 AsLengthPercentage().ConvertsToPercentage(); \
797 template <> \
798 inline float ty_::ToPercentage() const { \
799 MOZ_ASSERT(ConvertsToPercentage()); \
800 return AsLengthPercentage().ToPercentage(); \
803 IMPL_LENGTHPERCENTAGE_FORWARDS(LengthPercentageOrAuto)
804 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleSize)
805 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMaxSize)
807 template <>
808 inline bool LengthOrAuto::IsLength() const {
809 return IsLengthPercentage();
812 template <>
813 inline const Length& LengthOrAuto::AsLength() const {
814 return AsLengthPercentage();
817 template <>
818 inline nscoord LengthOrAuto::ToLength() const {
819 return AsLength().ToAppUnits();
822 template <>
823 inline bool StyleFlexBasis::IsAuto() const {
824 return IsSize() && AsSize().IsAuto();
827 template <>
828 inline bool StyleSize::BehavesLikeInitialValueOnBlockAxis() const {
829 return IsAuto() || !IsLengthPercentage();
832 template <>
833 inline bool StyleMaxSize::BehavesLikeInitialValueOnBlockAxis() const {
834 return IsNone() || !IsLengthPercentage();
837 template <>
838 inline bool StyleBackgroundSize::IsInitialValue() const {
839 return IsExplicitSize() && explicit_size.width.IsAuto() &&
840 explicit_size.height.IsAuto();
843 template <typename T>
844 const T& StyleRect<T>::Get(mozilla::Side aSide) const {
845 static_assert(sizeof(StyleRect<T>) == sizeof(T) * 4, "");
846 static_assert(alignof(StyleRect<T>) == alignof(T), "");
847 return reinterpret_cast<const T*>(this)[aSide];
850 template <typename T>
851 T& StyleRect<T>::Get(mozilla::Side aSide) {
852 return const_cast<T&>(static_cast<const StyleRect&>(*this).Get(aSide));
855 template <typename T>
856 template <typename Predicate>
857 bool StyleRect<T>::All(Predicate aPredicate) const {
858 return aPredicate(_0) && aPredicate(_1) && aPredicate(_2) && aPredicate(_3);
861 template <typename T>
862 template <typename Predicate>
863 bool StyleRect<T>::Any(Predicate aPredicate) const {
864 return aPredicate(_0) || aPredicate(_1) || aPredicate(_2) || aPredicate(_3);
867 template <>
868 inline const LengthPercentage& BorderRadius::Get(HalfCorner aCorner) const {
869 static_assert(sizeof(BorderRadius) == sizeof(LengthPercentage) * 8, "");
870 static_assert(alignof(BorderRadius) == alignof(LengthPercentage), "");
871 const auto* self = reinterpret_cast<const LengthPercentage*>(this);
872 return self[aCorner];
875 template <>
876 inline bool StyleTrackBreadth::HasPercent() const {
877 return IsBreadth() && AsBreadth().HasPercent();
880 // Implemented in nsStyleStructs.cpp
881 template <>
882 bool StyleTransform::HasPercent() const;
884 template <>
885 inline bool StyleTransformOrigin::HasPercent() const {
886 // NOTE(emilio): `depth` is just a `<length>` so doesn't have a percentage at
887 // all.
888 return horizontal.HasPercent() || vertical.HasPercent();
891 template <>
892 inline Maybe<size_t> StyleGridTemplateComponent::RepeatAutoIndex() const {
893 if (!IsTrackList()) {
894 return Nothing();
896 const auto& list = *AsTrackList();
897 return list.auto_repeat_index < list.values.Length()
898 ? Some(list.auto_repeat_index)
899 : Nothing();
902 template <>
903 inline bool StyleGridTemplateComponent::HasRepeatAuto() const {
904 return RepeatAutoIndex().isSome();
907 template <>
908 inline Span<const StyleGenericTrackListValue<LengthPercentage, StyleInteger>>
909 StyleGridTemplateComponent::TrackListValues() const {
910 if (IsTrackList()) {
911 return AsTrackList()->values.AsSpan();
913 return {};
916 template <>
917 inline const StyleGenericTrackRepeat<LengthPercentage, StyleInteger>*
918 StyleGridTemplateComponent::GetRepeatAutoValue() const {
919 auto index = RepeatAutoIndex();
920 if (!index) {
921 return nullptr;
923 return &TrackListValues()[*index].AsTrackRepeat();
926 constexpr const auto kPaintOrderShift = StylePAINT_ORDER_SHIFT;
927 constexpr const auto kPaintOrderMask = StylePAINT_ORDER_MASK;
929 template <>
930 inline nsRect StyleGenericClipRect<LengthOrAuto>::ToLayoutRect(
931 nscoord aAutoSize) const {
932 nscoord x = left.IsLength() ? left.ToLength() : 0;
933 nscoord y = top.IsLength() ? top.ToLength() : 0;
934 nscoord width = right.IsLength() ? right.ToLength() - x : aAutoSize;
935 nscoord height = bottom.IsLength() ? bottom.ToLength() - y : aAutoSize;
936 return nsRect(x, y, width, height);
939 using RestyleHint = StyleRestyleHint;
941 inline RestyleHint RestyleHint::RestyleSubtree() {
942 return RESTYLE_SELF | RESTYLE_DESCENDANTS;
945 inline RestyleHint RestyleHint::RecascadeSubtree() {
946 return RECASCADE_SELF | RECASCADE_DESCENDANTS;
949 inline RestyleHint RestyleHint::ForAnimations() {
950 return RESTYLE_CSS_TRANSITIONS | RESTYLE_CSS_ANIMATIONS | RESTYLE_SMIL;
953 inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const {
954 if (!(*this & (RECASCADE_DESCENDANTS | RESTYLE_DESCENDANTS))) {
955 return false;
957 return bool(*this & (RESTYLE_SELF | RECASCADE_SELF));
960 template <>
961 ImageResolution StyleImage::GetResolution(const ComputedStyle&) const;
963 template <>
964 inline const StyleImage& StyleImage::FinalImage() const {
965 if (!IsImageSet()) {
966 return *this;
968 const auto& set = *AsImageSet();
969 auto items = set.items.AsSpan();
970 if (MOZ_LIKELY(set.selected_index < items.Length())) {
971 return items[set.selected_index].image.FinalImage();
973 static auto sNone = StyleImage::None();
974 return sNone;
977 template <>
978 inline bool StyleImage::IsImageRequestType() const {
979 const auto& finalImage = FinalImage();
980 return finalImage.IsUrl();
983 template <>
984 inline const StyleComputedImageUrl* StyleImage::GetImageRequestURLValue()
985 const {
986 const auto& finalImage = FinalImage();
987 if (finalImage.IsUrl()) {
988 return &finalImage.AsUrl();
990 return nullptr;
993 template <>
994 inline imgRequestProxy* StyleImage::GetImageRequest() const {
995 const auto* url = GetImageRequestURLValue();
996 return url ? url->GetImage() : nullptr;
999 template <>
1000 inline bool StyleImage::IsResolved() const {
1001 const auto* url = GetImageRequestURLValue();
1002 return !url || url->IsImageResolved();
1005 template <>
1006 bool StyleImage::IsOpaque() const;
1007 template <>
1008 bool StyleImage::IsSizeAvailable() const;
1009 template <>
1010 bool StyleImage::IsComplete() const;
1011 template <>
1012 void StyleImage::ResolveImage(dom::Document&, const StyleImage*);
1014 template <>
1015 inline AspectRatio StyleRatio<StyleNonNegativeNumber>::ToLayoutRatio(
1016 UseBoxSizing aUseBoxSizing) const {
1017 // 0/1, 1/0, and 0/0 are all degenerate ratios (which behave as auto), and we
1018 // always return 0.0f.
1019 // https://drafts.csswg.org/css-values-4/#degenerate-ratio
1020 return AspectRatio::FromSize(_0, _1, aUseBoxSizing);
1023 template <>
1024 inline AspectRatio StyleAspectRatio::ToLayoutRatio() const {
1025 return HasRatio() ? ratio.AsRatio().ToLayoutRatio(auto_ ? UseBoxSizing::No
1026 : UseBoxSizing::Yes)
1027 : AspectRatio();
1030 inline void StyleFontWeight::ToString(nsACString& aString) const {
1031 Servo_FontWeight_ToCss(this, &aString);
1034 inline void StyleFontStretch::ToString(nsACString& aString) const {
1035 Servo_FontStretch_ToCss(this, &aString);
1038 inline void StyleFontStyle::ToString(nsACString& aString) const {
1039 Servo_FontStyle_ToCss(this, &aString);
1042 inline bool StyleFontWeight::IsBold() const { return *this >= BOLD_THRESHOLD; }
1044 inline bool StyleFontStyle::IsItalic() const { return *this == ITALIC; }
1046 inline bool StyleFontStyle::IsOblique() const {
1047 return !IsItalic() && !IsNormal();
1050 inline float StyleFontStyle::ObliqueAngle() const {
1051 MOZ_ASSERT(IsOblique());
1052 return ToFloat();
1055 inline float StyleFontStyle::SlantAngle() const {
1056 return IsNormal() ? 0 : IsItalic() ? DEFAULT_OBLIQUE_DEGREES : ObliqueAngle();
1059 using FontStretch = StyleFontStretch;
1060 using FontSlantStyle = StyleFontStyle;
1061 using FontWeight = StyleFontWeight;
1063 template <>
1064 inline double StyleComputedTimingFunction::At(double aPortion,
1065 bool aBeforeFlag) const {
1066 return Servo_EasingFunctionAt(
1067 this, aPortion,
1068 aBeforeFlag ? StyleEasingBeforeFlag::Set : StyleEasingBeforeFlag::Unset);
1071 template <>
1072 inline void StyleComputedTimingFunction::AppendToString(
1073 nsACString& aOut) const {
1074 return Servo_SerializeEasing(this, &aOut);
1077 template <>
1078 inline double StyleComputedTimingFunction::GetPortion(
1079 const Maybe<StyleComputedTimingFunction>& aFn, double aPortion,
1080 bool aBeforeFlag) {
1081 return aFn ? aFn->At(aPortion, aBeforeFlag) : aPortion;
1084 /* static */
1085 template <>
1086 inline LengthPercentageOrAuto LengthPercentageOrAuto::Zero() {
1087 return LengthPercentage(LengthPercentage::Zero());
1090 template <>
1091 inline StyleViewTimelineInset::StyleGenericViewTimelineInset()
1092 : start(LengthPercentageOrAuto::Auto()),
1093 end(LengthPercentageOrAuto::Auto()) {}
1095 inline StyleDisplayOutside StyleDisplay::Outside() const {
1096 return StyleDisplayOutside((_0 & OUTSIDE_MASK) >> OUTSIDE_SHIFT);
1099 inline StyleDisplayInside StyleDisplay::Inside() const {
1100 return StyleDisplayInside(_0 & INSIDE_MASK);
1103 inline bool StyleDisplay::IsListItem() const { return _0 & LIST_ITEM_MASK; }
1105 inline bool StyleDisplay::IsInternalTable() const {
1106 return Outside() == StyleDisplayOutside::InternalTable;
1109 inline bool StyleDisplay::IsInternalTableExceptCell() const {
1110 return IsInternalTable() && *this != TableCell;
1113 inline bool StyleDisplay::IsInternalRuby() const {
1114 return Outside() == StyleDisplayOutside::InternalRuby;
1117 inline bool StyleDisplay::IsRuby() const {
1118 return Inside() == StyleDisplayInside::Ruby || IsInternalRuby();
1121 inline bool StyleDisplay::IsInlineFlow() const {
1122 return Outside() == StyleDisplayOutside::Inline &&
1123 Inside() == StyleDisplayInside::Flow;
1126 inline bool StyleDisplay::IsInlineInside() const {
1127 return IsInlineFlow() || IsRuby();
1130 inline bool StyleDisplay::IsInlineOutside() const {
1131 return Outside() == StyleDisplayOutside::Inline || IsInternalRuby();
1134 inline float StyleZoom::Zoom(float aValue) const {
1135 if (*this == ONE) {
1136 return aValue;
1138 return ToFloat() * aValue;
1141 inline float StyleZoom::Unzoom(float aValue) const {
1142 if (*this == ONE) {
1143 return aValue;
1145 return aValue / ToFloat();
1148 inline nscoord StyleZoom::ZoomCoord(nscoord aValue) const {
1149 if (*this == ONE) {
1150 return aValue;
1152 return NSToCoordRoundWithClamp(Zoom(float(aValue)));
1155 inline nscoord StyleZoom::UnzoomCoord(nscoord aValue) const {
1156 if (*this == ONE) {
1157 return aValue;
1159 return NSToCoordRoundWithClamp(Unzoom(float(aValue)));
1162 inline nsSize StyleZoom::Zoom(const nsSize& aValue) const {
1163 if (*this == ONE) {
1164 return aValue;
1166 return nsSize(ZoomCoord(aValue.Width()), ZoomCoord(aValue.Height()));
1169 inline nsSize StyleZoom::Unzoom(const nsSize& aValue) const {
1170 if (*this == ONE) {
1171 return aValue;
1173 return nsSize(UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height()));
1176 inline nsPoint StyleZoom::Zoom(const nsPoint& aValue) const {
1177 if (*this == ONE) {
1178 return aValue;
1180 return nsPoint(ZoomCoord(aValue.X()), ZoomCoord(aValue.Y()));
1183 inline nsPoint StyleZoom::Unzoom(const nsPoint& aValue) const {
1184 if (*this == ONE) {
1185 return aValue;
1187 return nsPoint(UnzoomCoord(aValue.X()), UnzoomCoord(aValue.Y()));
1190 inline nsRect StyleZoom::Zoom(const nsRect& aValue) const {
1191 if (*this == ONE) {
1192 return aValue;
1194 return nsRect(ZoomCoord(aValue.X()), ZoomCoord(aValue.Y()),
1195 ZoomCoord(aValue.Width()), ZoomCoord(aValue.Height()));
1198 inline nsRect StyleZoom::Unzoom(const nsRect& aValue) const {
1199 if (*this == ONE) {
1200 return aValue;
1202 return nsRect(UnzoomCoord(aValue.X()), UnzoomCoord(aValue.Y()),
1203 UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height()));
1206 template <>
1207 inline gfx::Point StyleCoordinatePair<StyleCSSFloat>::ToGfxPoint(
1208 const CSSSize* aBasis) const {
1209 return gfx::Point(x, y);
1212 template <>
1213 inline gfx::Point StyleCoordinatePair<LengthPercentage>::ToGfxPoint(
1214 const CSSSize* aBasis) const {
1215 MOZ_ASSERT(aBasis);
1216 return gfx::Point(x.ResolveToCSSPixels(aBasis->Width()),
1217 y.ResolveToCSSPixels(aBasis->Height()));
1220 } // namespace mozilla
1222 #endif