ServoStyleConstsInlines.h (45098B)
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/. */ 6 7 /* Some inline functions declared in cbindgen.toml */ 8 9 #ifndef mozilla_ServoStyleConstsInlines_h 10 #define mozilla_ServoStyleConstsInlines_h 11 12 #include <new> 13 #include <type_traits> 14 15 #include "MainThreadUtils.h" 16 #include "mozilla/AspectRatio.h" 17 #include "mozilla/EndianUtils.h" 18 #include "mozilla/IntegerRange.h" 19 #include "mozilla/SVGContentUtils.h" 20 #include "mozilla/ServoStyleConsts.h" 21 #include "mozilla/URLExtraData.h" 22 #include "mozilla/dom/WorkerCommon.h" 23 #include "nsGkAtoms.h" 24 #include "nsNetUtil.h" 25 26 // TODO(emilio): there are quite a few other implementations scattered around 27 // that should move here. 28 29 namespace mozilla { 30 31 // We need to explicitly instantiate these so that the clang plugin can see that 32 // they're trivially copyable... 33 // 34 // https://github.com/eqrion/cbindgen/issues/402 tracks doing something like 35 // this automatically from cbindgen. 36 template struct StyleStrong<ComputedStyle>; 37 template struct StyleStrong<StyleLockedCssRules>; 38 template struct StyleStrong<StyleAnimationValue>; 39 template struct StyleStrong<StyleLockedDeclarationBlock>; 40 template struct StyleStrong<StyleStylesheetContents>; 41 template struct StyleStrong<StyleLockedKeyframe>; 42 template struct StyleStrong<StyleLayerBlockRule>; 43 template struct StyleStrong<StyleLayerStatementRule>; 44 template struct StyleStrong<StyleLockedMediaList>; 45 template struct StyleStrong<StyleLockedStyleRule>; 46 template struct StyleStrong<StyleLockedImportRule>; 47 template struct StyleStrong<StyleLockedKeyframesRule>; 48 template struct StyleStrong<StyleMediaRule>; 49 template struct StyleStrong<StyleCustomMediaRule>; 50 template struct StyleStrong<StyleDocumentRule>; 51 template struct StyleStrong<StyleNamespaceRule>; 52 template struct StyleStrong<StyleMarginRule>; 53 template struct StyleStrong<StyleLockedPageRule>; 54 template struct StyleStrong<StylePropertyRule>; 55 template struct StyleStrong<StyleSupportsRule>; 56 template struct StyleStrong<StyleFontFeatureValuesRule>; 57 template struct StyleStrong<StyleFontPaletteValuesRule>; 58 template struct StyleStrong<StyleLockedFontFaceRule>; 59 template struct StyleStrong<StyleLockedCounterStyleRule>; 60 template struct StyleStrong<StyleContainerRule>; 61 template struct StyleStrong<StyleScopeRule>; 62 template struct StyleStrong<StyleStartingStyleRule>; 63 template struct StyleStrong<StyleLockedPositionTryRule>; 64 template struct StyleStrong<StyleLockedNestedDeclarationsRule>; 65 66 template <typename T> 67 inline void StyleOwnedSlice<T>::Clear() { 68 if (!len) { 69 return; 70 } 71 for (size_t i : IntegerRange(len)) { 72 ptr[i].~T(); 73 } 74 free(ptr); 75 ptr = (T*)alignof(T); 76 len = 0; 77 } 78 79 template <typename T> 80 inline void StyleOwnedSlice<T>::CopyFrom(const StyleOwnedSlice& aOther) { 81 Clear(); 82 len = aOther.len; 83 if (!len) { 84 ptr = (T*)alignof(T); 85 } else { 86 ptr = (T*)malloc(len * sizeof(T)); 87 size_t i = 0; 88 for (const T& elem : aOther.AsSpan()) { 89 new (ptr + i++) T(elem); 90 } 91 } 92 } 93 94 template <typename T> 95 inline void StyleOwnedSlice<T>::SwapElements(StyleOwnedSlice& aOther) { 96 std::swap(ptr, aOther.ptr); 97 std::swap(len, aOther.len); 98 } 99 100 template <typename T> 101 inline StyleOwnedSlice<T>::StyleOwnedSlice(const StyleOwnedSlice& aOther) 102 : StyleOwnedSlice() { 103 CopyFrom(aOther); 104 } 105 106 template <typename T> 107 inline StyleOwnedSlice<T>::StyleOwnedSlice(StyleOwnedSlice&& aOther) 108 : StyleOwnedSlice() { 109 SwapElements(aOther); 110 } 111 112 template <typename T> 113 inline StyleOwnedSlice<T>::StyleOwnedSlice(Vector<T>&& aVector) 114 : StyleOwnedSlice() { 115 if (!aVector.length()) { 116 return; 117 } 118 119 // We could handle this if Vector provided the relevant APIs, see bug 1610702. 120 MOZ_DIAGNOSTIC_ASSERT(aVector.length() == aVector.capacity(), 121 "Shouldn't over-allocate"); 122 len = aVector.length(); 123 ptr = aVector.extractRawBuffer(); 124 MOZ_ASSERT(ptr, 125 "How did extractRawBuffer return null if we're not using inline " 126 "capacity?"); 127 } 128 129 template <typename T> 130 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=( 131 const StyleOwnedSlice& aOther) { 132 CopyFrom(aOther); 133 return *this; 134 } 135 136 template <typename T> 137 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=( 138 StyleOwnedSlice&& aOther) { 139 Clear(); 140 SwapElements(aOther); 141 return *this; 142 } 143 144 template <typename T> 145 inline StyleOwnedSlice<T>::~StyleOwnedSlice() { 146 Clear(); 147 } 148 149 // This code is basically a C++ port of the Arc::clone() implementation in 150 // servo/components/servo_arc/lib.rs. 151 static constexpr const size_t kStaticRefcount = 152 std::numeric_limits<size_t>::max(); 153 static constexpr const size_t kMaxRefcount = 154 std::numeric_limits<intptr_t>::max(); 155 156 template <typename T> 157 inline void StyleArcInner<T>::IncrementRef() { 158 if (count.load(std::memory_order_relaxed) != kStaticRefcount) { 159 auto old_size = count.fetch_add(1, std::memory_order_relaxed); 160 if (MOZ_UNLIKELY(old_size > kMaxRefcount)) { 161 ::abort(); 162 } 163 } 164 } 165 166 // This is a C++ port-ish of Arc::drop(). 167 template <typename T> 168 inline bool StyleArcInner<T>::DecrementRef() { 169 if (count.load(std::memory_order_relaxed) == kStaticRefcount) { 170 return false; 171 } 172 if (count.fetch_sub(1, std::memory_order_release) != 1) { 173 return false; 174 } 175 #ifdef MOZ_TSAN 176 // TSan doesn't understand std::atomic_thread_fence, so in order 177 // to avoid a false positive for every time a refcounted object 178 // is deleted, we replace the fence with an atomic operation. 179 count.load(std::memory_order_acquire); 180 #else 181 std::atomic_thread_fence(std::memory_order_acquire); 182 #endif 183 MOZ_LOG_DTOR(this, "ServoArc", 8); 184 return true; 185 } 186 187 template <typename H, typename T> 188 inline bool StyleHeaderSlice<H, T>::operator==( 189 const StyleHeaderSlice& aOther) const { 190 return header == aOther.header && AsSpan() == aOther.AsSpan(); 191 } 192 193 template <typename H, typename T> 194 inline bool StyleHeaderSlice<H, T>::operator!=( 195 const StyleHeaderSlice& aOther) const { 196 return !(*this == aOther); 197 } 198 199 template <typename H, typename T> 200 inline StyleHeaderSlice<H, T>::~StyleHeaderSlice() { 201 for (T& elem : Span(data, len)) { 202 elem.~T(); 203 } 204 } 205 206 template <typename H, typename T> 207 inline Span<const T> StyleHeaderSlice<H, T>::AsSpan() const { 208 // Explicitly specify template argument here to avoid instantiating Span<T> 209 // first and then implicitly converting to Span<const T> 210 return Span<const T>{data, len}; 211 } 212 213 static constexpr const uint64_t kArcSliceCanary = 0xf3f3f3f3f3f3f3f3; 214 215 #define ASSERT_CANARY \ 216 MOZ_DIAGNOSTIC_ASSERT(_0.p->data.header == kArcSliceCanary, "Uh?"); 217 218 template <typename T> 219 inline StyleArcSlice<T>::StyleArcSlice() 220 : _0(reinterpret_cast<decltype(_0.p)>(Servo_StyleArcSlice_EmptyPtr())) { 221 ASSERT_CANARY 222 } 223 224 template <typename T> 225 inline StyleArcSlice<T>::StyleArcSlice( 226 const StyleForgottenArcSlicePtr<T>& aPtr) { 227 // See the forget() implementation to see why reinterpret_cast() is ok. 228 _0.p = reinterpret_cast<decltype(_0.p)>(aPtr._0); 229 ASSERT_CANARY 230 } 231 232 template <typename T> 233 inline size_t StyleArcSlice<T>::Length() const { 234 ASSERT_CANARY 235 return _0->Length(); 236 } 237 238 template <typename T> 239 inline bool StyleArcSlice<T>::IsEmpty() const { 240 ASSERT_CANARY 241 return _0->IsEmpty(); 242 } 243 244 template <typename T> 245 inline Span<const T> StyleArcSlice<T>::AsSpan() const { 246 ASSERT_CANARY 247 return _0->AsSpan(); 248 } 249 250 #undef ASSERT_CANARY 251 252 template <typename T> 253 inline StyleArc<T>::StyleArc(const StyleArc& aOther) : p(aOther.p) { 254 p->IncrementRef(); 255 } 256 257 template <typename T> 258 inline void StyleArc<T>::Release() { 259 if (MOZ_LIKELY(!p->DecrementRef())) { 260 return; 261 } 262 p->data.~T(); 263 free(p); 264 } 265 266 template <typename T> 267 inline StyleArc<T>& StyleArc<T>::operator=(const StyleArc& aOther) { 268 if (p != aOther.p) { 269 Release(); 270 p = aOther.p; 271 p->IncrementRef(); 272 } 273 return *this; 274 } 275 276 template <typename T> 277 inline StyleArc<T>& StyleArc<T>::operator=(StyleArc&& aOther) { 278 std::swap(p, aOther.p); 279 return *this; 280 } 281 282 template <typename T> 283 inline StyleArc<T>::~StyleArc() { 284 Release(); 285 } 286 287 inline bool StyleAtom::IsStatic() const { return !!(_0 & 1); } 288 289 inline nsAtom* StyleAtom::AsAtom() const { 290 if (IsStatic()) { 291 return const_cast<nsStaticAtom*>(&detail::gGkAtoms.mAtoms[_0 >> 1]); 292 } 293 return reinterpret_cast<nsAtom*>(_0); 294 } 295 296 inline void StyleAtom::AddRef() { 297 if (!IsStatic()) { 298 AsAtom()->AddRef(); 299 } 300 } 301 302 inline void StyleAtom::Release() { 303 if (!IsStatic()) { 304 AsAtom()->Release(); 305 } 306 } 307 308 inline StyleAtom::StyleAtom(already_AddRefed<nsAtom> aAtom) { 309 nsAtom* atom = aAtom.take(); 310 if (atom->IsStatic()) { 311 size_t index = atom->AsStatic() - &detail::gGkAtoms.mAtoms[0]; 312 _0 = (index << 1) | 1; 313 } else { 314 _0 = reinterpret_cast<uintptr_t>(atom); 315 } 316 MOZ_ASSERT(IsStatic() == atom->IsStatic()); 317 MOZ_ASSERT(AsAtom() == atom); 318 } 319 320 inline StyleAtom::StyleAtom(nsStaticAtom* aAtom) 321 : StyleAtom(do_AddRef(static_cast<nsAtom*>(aAtom))) {} 322 323 inline StyleAtom::StyleAtom(const StyleAtom& aOther) : _0(aOther._0) { 324 AddRef(); 325 } 326 327 inline StyleAtom& StyleAtom::operator=(const StyleAtom& aOther) { 328 if (MOZ_LIKELY(this != &aOther)) { 329 Release(); 330 _0 = aOther._0; 331 AddRef(); 332 } 333 return *this; 334 } 335 336 inline StyleAtom::~StyleAtom() { Release(); } 337 338 inline nsAtom* StyleCustomIdent::AsAtom() const { return _0.AsAtom(); } 339 340 inline nsDependentCSubstring StyleOwnedStr::AsString() const { 341 Span<const uint8_t> s = _0.AsSpan(); 342 return nsDependentCSubstring(reinterpret_cast<const char*>(s.Elements()), 343 s.Length()); 344 } 345 346 template <typename T> 347 inline Span<const T> StyleGenericTransform<T>::Operations() const { 348 return _0.AsSpan(); 349 } 350 351 template <typename T> 352 inline bool StyleGenericTransform<T>::IsNone() const { 353 return Operations().IsEmpty(); 354 } 355 356 inline StyleAngle StyleAngle::Zero() { return {0.0f}; } 357 358 inline float StyleAngle::ToDegrees() const { return _0; } 359 360 inline double StyleAngle::ToRadians() const { 361 return double(ToDegrees()) * M_PI / 180.0; 362 } 363 364 inline bool StyleUrlExtraData::IsShared() const { return !!(_0 & 1); } 365 366 inline StyleUrlExtraData::~StyleUrlExtraData() { 367 if (!IsShared()) { 368 reinterpret_cast<URLExtraData*>(_0)->Release(); 369 } 370 } 371 372 inline const URLExtraData& StyleUrlExtraData::get() const { 373 if (IsShared()) { 374 return *URLExtraData::sShared[_0 >> 1]; 375 } 376 return *reinterpret_cast<const URLExtraData*>(_0); 377 } 378 379 inline nsDependentCSubstring StyleCssUrl::SpecifiedSerialization() const { 380 return _0->serialization.AsString(); 381 } 382 383 inline const URLExtraData& StyleCssUrl::ExtraData() const { 384 return _0->extra_data.get(); 385 } 386 387 inline const StyleLoadData& StyleCssUrl::LoadData() const { 388 if (MOZ_LIKELY(_0->load_data.tag == StyleLoadDataSource::Tag::Owned)) { 389 return _0->load_data.owned._0; 390 } 391 return *Servo_LoadData_GetLazy(&_0->load_data); 392 } 393 394 inline StyleLoadData& StyleCssUrl::MutLoadData() const { 395 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread() || 396 dom::IsCurrentThreadRunningWorker()); 397 return const_cast<StyleLoadData&>(LoadData()); 398 } 399 400 inline nsIURI* StyleCssUrl::GetURI() const { 401 auto& loadData = const_cast<StyleLoadData&>(LoadData()); 402 // Try to read the flags first. If it's set we can avoid entering the CAS 403 // loop. 404 auto flags = __atomic_load_n(&loadData.flags.bits, __ATOMIC_RELAXED); 405 if (!(flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_URI.bits)) { 406 nsDependentCSubstring serialization = SpecifiedSerialization(); 407 // https://drafts.csswg.org/css-values-4/#url-empty: 408 // 409 // If the value of the url() is the empty string (like url("") or 410 // url()), the url must resolve to an invalid resource (similar to what 411 // the url about:invalid does). 412 // 413 nsIURI* resolved = nullptr; 414 if (!serialization.IsEmpty()) { 415 nsIURI* old_resolved = nullptr; 416 // NOTE: This addrefs `resolved`, and `resolved` might still be null for 417 // invalid URIs. 418 NS_NewURI(&resolved, serialization, nullptr, ExtraData().BaseURI()); 419 if (!__atomic_compare_exchange_n(&loadData.resolved_uri, &old_resolved, 420 resolved, /* weak = */ false, 421 __ATOMIC_RELEASE, __ATOMIC_RELAXED)) { 422 // In the unlikely case two threads raced to write the url, avoid 423 // leaking resolved. The actual value is in `old_resolved`. 424 NS_IF_RELEASE(resolved); 425 resolved = old_resolved; 426 } 427 } 428 // The flag is effectively just an optimization so we can use relaxed 429 // ordering. 430 __atomic_fetch_or(&loadData.flags.bits, 431 StyleLoadDataFlags::TRIED_TO_RESOLVE_URI.bits, 432 __ATOMIC_RELAXED); 433 return resolved; 434 } 435 return __atomic_load_n(&loadData.resolved_uri, __ATOMIC_ACQUIRE); 436 } 437 438 inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const { 439 return _0.SpecifiedSerialization(); 440 } 441 inline const URLExtraData& StyleComputedUrl::ExtraData() const { 442 return _0.ExtraData(); 443 } 444 inline const StyleLoadData& StyleComputedUrl::LoadData() const { 445 return _0.LoadData(); 446 } 447 inline StyleLoadData& StyleComputedUrl::MutLoadData() const { 448 return _0.MutLoadData(); 449 } 450 inline StyleCorsMode StyleComputedUrl::CorsMode() const { 451 return _0._0->cors_mode; 452 } 453 inline nsIURI* StyleComputedUrl::GetURI() const { return _0.GetURI(); } 454 455 inline bool StyleComputedUrl::IsLocalRef() const { 456 return Servo_CssUrl_IsLocalRef(&_0); 457 } 458 459 inline bool StyleComputedUrl::HasRef() const { 460 if (IsLocalRef()) { 461 return true; 462 } 463 if (nsIURI* uri = GetURI()) { 464 bool hasRef = false; 465 return NS_SUCCEEDED(uri->GetHasRef(&hasRef)) && hasRef; 466 } 467 return false; 468 } 469 470 inline bool StyleComputedUrl::IsImageResolved() const { 471 return bool(LoadData().flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE); 472 } 473 474 inline imgRequestProxy* StyleComputedUrl::GetImage() const { 475 MOZ_ASSERT(IsImageResolved()); 476 return LoadData().resolved_image; 477 } 478 479 template <> 480 inline bool StyleGradient::Repeating() const { 481 if (IsLinear()) { 482 return bool(AsLinear().flags & StyleGradientFlags::REPEATING); 483 } 484 if (IsRadial()) { 485 return bool(AsRadial().flags & StyleGradientFlags::REPEATING); 486 } 487 return bool(AsConic().flags & StyleGradientFlags::REPEATING); 488 } 489 490 template <> 491 bool StyleGradient::IsOpaque() const; 492 493 template <> 494 inline const StyleColorInterpolationMethod& 495 StyleGradient::ColorInterpolationMethod() const { 496 if (IsLinear()) { 497 return AsLinear().color_interpolation_method; 498 } 499 if (IsRadial()) { 500 return AsRadial().color_interpolation_method; 501 } 502 return AsConic().color_interpolation_method; 503 } 504 505 template <typename Integer> 506 inline StyleGenericGridLine<Integer>::StyleGenericGridLine() 507 : ident{StyleAtom(nsGkAtoms::_empty)}, line_num(0), is_span(false) {} 508 509 template <> 510 inline nsAtom* StyleGridLine::LineName() const { 511 return ident.AsAtom(); 512 } 513 514 template <> 515 inline bool StyleGridLine::IsAuto() const { 516 return LineName()->IsEmpty() && line_num == 0 && !is_span; 517 } 518 519 using LengthPercentage = StyleLengthPercentage; 520 using LengthPercentageOrAuto = StyleLengthPercentageOrAuto; 521 using NonNegativeLengthPercentage = StyleNonNegativeLengthPercentage; 522 using NonNegativeLengthPercentageOrAuto = 523 StyleNonNegativeLengthPercentageOrAuto; 524 using NonNegativeLengthPercentageOrNormal = 525 StyleNonNegativeLengthPercentageOrNormal; 526 using Length = StyleLength; 527 using LengthOrAuto = StyleLengthOrAuto; 528 using NonNegativeLength = StyleNonNegativeLength; 529 using NonNegativeLengthOrAuto = StyleNonNegativeLengthOrAuto; 530 using BorderRadius = StyleBorderRadius; 531 532 bool StyleCSSPixelLength::IsZero() const { return _0 == 0.0f; } 533 534 void StyleCSSPixelLength::ScaleBy(float aScale) { _0 *= aScale; } 535 536 StyleCSSPixelLength StyleCSSPixelLength::ScaledBy(float aScale) const { 537 return FromPixels(ToCSSPixels() * aScale); 538 } 539 540 namespace detail { 541 static inline nscoord DefaultPercentLengthToAppUnits(float aPixelLength) { 542 return NSToCoordTruncClamped(aPixelLength); 543 } 544 545 static inline nscoord DefaultLengthToAppUnits(float aPixelLength) { 546 // We want to round lengths rounding 0.5 away from zero, instead of the 547 // default behavior of NSToCoordRound{,WithClamp} which do floor(x + 0.5). 548 float length = aPixelLength * float(mozilla::AppUnitsPerCSSPixel()); 549 if (length >= float(nscoord_MAX)) { 550 return nscoord_MAX; 551 } 552 if (length <= float(nscoord_MIN)) { 553 return nscoord_MIN; 554 } 555 return NSToIntRound(length); 556 } 557 } // namespace detail 558 559 nscoord StyleCSSPixelLength::ToAppUnits() const { 560 if (IsZero()) { 561 // Avoid the expensive FP math below. 562 return 0; 563 } 564 return detail::DefaultLengthToAppUnits(_0); 565 } 566 567 bool LengthPercentage::IsLength() const { return Tag() == TAG_LENGTH; } 568 569 StyleLengthPercentageUnion::StyleLengthPercentageUnion() { 570 length = {TAG_LENGTH, {0.0f}}; 571 MOZ_ASSERT(IsLength()); 572 } 573 574 static_assert(sizeof(LengthPercentage) == sizeof(uint64_t), ""); 575 576 Length& LengthPercentage::AsLength() { 577 MOZ_ASSERT(IsLength()); 578 return length.length; 579 } 580 581 const Length& LengthPercentage::AsLength() const { 582 return const_cast<LengthPercentage*>(this)->AsLength(); 583 } 584 585 bool LengthPercentage::IsPercentage() const { return Tag() == TAG_PERCENTAGE; } 586 587 StylePercentage& LengthPercentage::AsPercentage() { 588 MOZ_ASSERT(IsPercentage()); 589 return percentage.percentage; 590 } 591 592 const StylePercentage& LengthPercentage::AsPercentage() const { 593 return const_cast<LengthPercentage*>(this)->AsPercentage(); 594 } 595 596 bool LengthPercentage::IsCalc() const { return Tag() == TAG_CALC; } 597 598 StyleCalcLengthPercentage& LengthPercentage::AsCalc() { 599 MOZ_ASSERT(IsCalc()); 600 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the tag. 601 #ifdef SERVO_32_BITS 602 return *reinterpret_cast<StyleCalcLengthPercentage*>(calc.ptr); 603 #else 604 return *reinterpret_cast<StyleCalcLengthPercentage*>( 605 NativeEndian::swapFromLittleEndian(calc.ptr)); 606 #endif 607 } 608 609 const StyleCalcLengthPercentage& LengthPercentage::AsCalc() const { 610 return const_cast<LengthPercentage*>(this)->AsCalc(); 611 } 612 613 StyleLengthPercentageUnion::StyleLengthPercentageUnion(const Self& aOther) { 614 if (aOther.IsLength()) { 615 length = {TAG_LENGTH, aOther.AsLength()}; 616 } else if (aOther.IsPercentage()) { 617 percentage = {TAG_PERCENTAGE, aOther.AsPercentage()}; 618 } else { 619 MOZ_ASSERT(aOther.IsCalc()); 620 auto* ptr = new StyleCalcLengthPercentage(aOther.AsCalc()); 621 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the 622 // tag. 623 calc = { 624 #ifdef SERVO_32_BITS 625 TAG_CALC, 626 ptr, 627 #else 628 NativeEndian::swapToLittleEndian(reinterpret_cast<uintptr_t>(ptr)), 629 #endif 630 }; 631 } 632 MOZ_ASSERT(Tag() == aOther.Tag()); 633 } 634 635 StyleLengthPercentageUnion::~StyleLengthPercentageUnion() { 636 if (IsCalc()) { 637 delete &AsCalc(); 638 } 639 } 640 641 LengthPercentage& LengthPercentage::operator=(const LengthPercentage& aOther) { 642 if (this != &aOther) { 643 this->~LengthPercentage(); 644 new (this) LengthPercentage(aOther); 645 } 646 return *this; 647 } 648 649 bool LengthPercentage::operator==(const LengthPercentage& aOther) const { 650 if (Tag() != aOther.Tag()) { 651 return false; 652 } 653 if (IsLength()) { 654 return AsLength() == aOther.AsLength(); 655 } 656 if (IsPercentage()) { 657 return AsPercentage() == aOther.AsPercentage(); 658 } 659 return AsCalc() == aOther.AsCalc(); 660 } 661 662 bool LengthPercentage::operator!=(const LengthPercentage& aOther) const { 663 return !(*this == aOther); 664 } 665 666 LengthPercentage LengthPercentage::Zero() { return {}; } 667 668 LengthPercentage LengthPercentage::FromPixels(CSSCoord aCoord) { 669 LengthPercentage l; 670 MOZ_ASSERT(l.IsLength()); 671 l.length.length = {aCoord}; 672 return l; 673 } 674 675 LengthPercentage LengthPercentage::FromAppUnits(nscoord aCoord) { 676 return FromPixels(CSSPixel::FromAppUnits(aCoord)); 677 } 678 679 LengthPercentage LengthPercentage::FromPercentage(float aPercentage) { 680 LengthPercentage l; 681 l.percentage = {TAG_PERCENTAGE, {aPercentage}}; 682 return l; 683 } 684 685 bool LengthPercentage::HasPercent() const { return IsPercentage() || IsCalc(); } 686 687 bool LengthPercentage::ConvertsToLength() const { return IsLength(); } 688 689 nscoord LengthPercentage::ToLength() const { 690 MOZ_ASSERT(ConvertsToLength()); 691 return AsLength().ToAppUnits(); 692 } 693 694 CSSCoord LengthPercentage::ToLengthInCSSPixels() const { 695 MOZ_ASSERT(ConvertsToLength()); 696 return AsLength().ToCSSPixels(); 697 } 698 699 bool LengthPercentage::ConvertsToPercentage() const { return IsPercentage(); } 700 701 float LengthPercentage::ToPercentage() const { 702 MOZ_ASSERT(ConvertsToPercentage()); 703 return AsPercentage()._0; 704 } 705 706 bool LengthPercentage::HasLengthAndPercentage() const { 707 if (!IsCalc()) { 708 return false; 709 } 710 MOZ_ASSERT(!ConvertsToLength() && !ConvertsToPercentage(), 711 "Should've been simplified earlier"); 712 return true; 713 } 714 715 bool LengthPercentage::IsDefinitelyZero() const { 716 if (IsLength()) { 717 return AsLength().IsZero(); 718 } 719 if (IsPercentage()) { 720 return AsPercentage()._0 == 0.0f; 721 } 722 // calc() should've been simplified to a percentage. 723 return false; 724 } 725 726 CSSCoord StyleCalcLengthPercentage::ResolveToCSSPixels(CSSCoord aBasis) const { 727 return Servo_ResolveCalcLengthPercentage(this, aBasis); 728 } 729 730 template <typename Rounder> 731 nscoord StyleCalcLengthPercentage::Resolve(nscoord aBasis, 732 Rounder aRounder) const { 733 static_assert(std::is_same_v<decltype(aRounder(1.0f)), nscoord>); 734 CSSCoord result = ResolveToCSSPixels(CSSPixel::FromAppUnits(aBasis)); 735 return aRounder(result * AppUnitsPerCSSPixel()); 736 } 737 738 template <> 739 void StyleCalcNode::ScaleLengthsBy(float); 740 741 CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const { 742 if (IsLength()) { 743 return AsLength().ToCSSPixels(); 744 } 745 if (IsPercentage()) { 746 return AsPercentage()._0 * aPercentageBasis; 747 } 748 return AsCalc().ResolveToCSSPixels(aPercentageBasis); 749 } 750 751 template <typename T> 752 CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const { 753 static_assert(std::is_same_v<decltype(aPercentageGetter()), CSSCoord>); 754 if (ConvertsToLength()) { 755 return ToLengthInCSSPixels(); 756 } 757 return ResolveToCSSPixels(aPercentageGetter()); 758 } 759 760 template <typename T, typename Rounder> 761 nscoord LengthPercentage::Resolve(T aPercentageGetter, Rounder aRounder) const { 762 static_assert(std::is_same_v<decltype(aPercentageGetter()), nscoord>); 763 static_assert(std::is_same_v<decltype(aRounder(1.0f)), nscoord>); 764 if (ConvertsToLength()) { 765 return ToLength(); 766 } 767 if (IsPercentage() && AsPercentage()._0 == 0.0f) { 768 return 0; 769 } 770 nscoord basis = aPercentageGetter(); 771 if (IsPercentage()) { 772 return aRounder(basis * AsPercentage()._0); 773 } 774 return AsCalc().Resolve(basis, aRounder); 775 } 776 777 nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const { 778 return Resolve([=] { return aPercentageBasis; }, 779 detail::DefaultPercentLengthToAppUnits); 780 } 781 782 template <typename T> 783 nscoord LengthPercentage::Resolve(T aPercentageGetter) const { 784 return Resolve(aPercentageGetter, detail::DefaultPercentLengthToAppUnits); 785 } 786 787 template <typename Rounder> 788 nscoord LengthPercentage::Resolve(nscoord aPercentageBasis, 789 Rounder aRounder) const { 790 return Resolve([aPercentageBasis] { return aPercentageBasis; }, aRounder); 791 } 792 793 void LengthPercentage::ScaleLengthsBy(float aScale) { 794 if (IsLength()) { 795 AsLength().ScaleBy(aScale); 796 } 797 if (IsCalc()) { 798 AsCalc().node.ScaleLengthsBy(aScale); 799 } 800 } 801 802 #define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \ 803 template <> \ 804 inline bool ty_::HasPercent() const { \ 805 return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \ 806 } \ 807 template <> \ 808 inline bool ty_::ConvertsToLength() const { \ 809 return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \ 810 } \ 811 template <> \ 812 inline bool ty_::HasLengthAndPercentage() const { \ 813 return IsLengthPercentage() && \ 814 AsLengthPercentage().HasLengthAndPercentage(); \ 815 } \ 816 template <> \ 817 inline nscoord ty_::ToLength() const { \ 818 MOZ_ASSERT(ConvertsToLength()); \ 819 return AsLengthPercentage().ToLength(); \ 820 } \ 821 template <> \ 822 inline bool ty_::ConvertsToPercentage() const { \ 823 return IsLengthPercentage() && \ 824 AsLengthPercentage().ConvertsToPercentage(); \ 825 } \ 826 template <> \ 827 inline float ty_::ToPercentage() const { \ 828 MOZ_ASSERT(ConvertsToPercentage()); \ 829 return AsLengthPercentage().ToPercentage(); \ 830 } 831 832 IMPL_LENGTHPERCENTAGE_FORWARDS(LengthPercentageOrAuto) 833 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleSize) 834 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMaxSize) 835 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleInset) 836 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMargin) 837 838 template <> 839 inline bool StyleInset::HasAnchorPositioningFunction() const { 840 return IsAnchorFunction() || IsAnchorSizeFunction() || 841 IsAnchorContainingCalcFunction(); 842 } 843 844 template <> 845 inline bool StyleMargin::HasAnchorPositioningFunction() const { 846 return IsAnchorSizeFunction() || IsAnchorContainingCalcFunction(); 847 } 848 849 template <> 850 inline bool StyleSize::HasAnchorPositioningFunction() const { 851 return IsAnchorSizeFunction() || IsAnchorContainingCalcFunction(); 852 } 853 854 template <> 855 inline bool StyleMaxSize::HasAnchorPositioningFunction() const { 856 return IsAnchorSizeFunction() || IsAnchorContainingCalcFunction(); 857 } 858 859 #undef IMPL_LENGTHPERCENTAGE_FORWARDS 860 861 template <> 862 inline bool LengthOrAuto::IsLength() const { 863 return IsLengthPercentage(); 864 } 865 866 template <> 867 inline const Length& LengthOrAuto::AsLength() const { 868 return AsLengthPercentage(); 869 } 870 871 template <> 872 inline nscoord LengthOrAuto::ToLength() const { 873 return AsLength().ToAppUnits(); 874 } 875 876 template <> 877 inline bool StyleFlexBasis::IsAuto() const { 878 return IsSize() && AsSize().IsAuto(); 879 } 880 881 #define IMPL_BEHAVES_LIKE_SIZE_METHODS(ty_, isInitialValMethod_) \ 882 template <> \ 883 inline bool ty_::BehavesLikeStretchOnInlineAxis() const { \ 884 return IsStretch() || IsMozAvailable() || IsWebkitFillAvailable(); \ 885 } \ 886 template <> \ 887 inline bool ty_::BehavesLikeStretchOnBlockAxis() const { \ 888 /* TODO(dholbert): Add "|| IsMozAvailable()" in bug 527285. */ \ 889 return IsStretch() || IsWebkitFillAvailable(); \ 890 } \ 891 template <> \ 892 inline bool ty_::BehavesLikeInitialValueOnBlockAxis() const { \ 893 return isInitialValMethod_() || \ 894 (!BehavesLikeStretchOnBlockAxis() && !IsLengthPercentage()); \ 895 } 896 897 IMPL_BEHAVES_LIKE_SIZE_METHODS(StyleSize, IsAuto) 898 IMPL_BEHAVES_LIKE_SIZE_METHODS(StyleMaxSize, IsNone) 899 900 #undef IMPL_BEHAVES_LIKE_SIZE_METHODS 901 902 template <> 903 inline bool StyleBackgroundSize::IsInitialValue() const { 904 return IsExplicitSize() && explicit_size.width.IsAuto() && 905 explicit_size.height.IsAuto(); 906 } 907 908 template <typename T> 909 const T& StyleRect<T>::Get(mozilla::Side aSide) const { 910 static_assert(sizeof(StyleRect<T>) == sizeof(T) * 4, ""); 911 static_assert(alignof(StyleRect<T>) == alignof(T), ""); 912 return reinterpret_cast<const T*>(this)[aSide]; 913 } 914 915 template <typename T> 916 T& StyleRect<T>::Get(mozilla::Side aSide) { 917 return const_cast<T&>(static_cast<const StyleRect&>(*this).Get(aSide)); 918 } 919 920 template <typename T> 921 template <typename Predicate> 922 bool StyleRect<T>::All(Predicate aPredicate) const { 923 return aPredicate(_0) && aPredicate(_1) && aPredicate(_2) && aPredicate(_3); 924 } 925 926 template <typename T> 927 template <typename Predicate> 928 bool StyleRect<T>::Any(Predicate aPredicate) const { 929 return aPredicate(_0) || aPredicate(_1) || aPredicate(_2) || aPredicate(_3); 930 } 931 932 template <> 933 inline const LengthPercentage& BorderRadius::Get(HalfCorner aCorner) const { 934 static_assert(sizeof(BorderRadius) == sizeof(LengthPercentage) * 8, ""); 935 static_assert(alignof(BorderRadius) == alignof(LengthPercentage), ""); 936 const auto* self = reinterpret_cast<const LengthPercentage*>(this); 937 return self[aCorner]; 938 } 939 940 template <> 941 inline bool StyleTrackBreadth::HasPercent() const { 942 return IsBreadth() && AsBreadth().HasPercent(); 943 } 944 945 // Implemented in nsStyleStructs.cpp 946 template <> 947 bool StyleTransform::HasPercent() const; 948 949 template <> 950 inline bool StyleTransformOrigin::HasPercent() const { 951 // NOTE(emilio): `depth` is just a `<length>` so doesn't have a percentage at 952 // all. 953 return horizontal.HasPercent() || vertical.HasPercent(); 954 } 955 956 template <> 957 inline Maybe<size_t> StyleGridTemplateComponent::RepeatAutoIndex() const { 958 if (!IsTrackList()) { 959 return Nothing(); 960 } 961 const auto& list = *AsTrackList(); 962 return list.auto_repeat_index < list.values.Length() 963 ? Some(list.auto_repeat_index) 964 : Nothing(); 965 } 966 967 template <> 968 inline bool StyleGridTemplateComponent::HasRepeatAuto() const { 969 return RepeatAutoIndex().isSome(); 970 } 971 972 template <> 973 inline Span<const StyleGenericTrackListValue<LengthPercentage, StyleInteger>> 974 StyleGridTemplateComponent::TrackListValues() const { 975 if (IsTrackList()) { 976 return AsTrackList()->values.AsSpan(); 977 } 978 return {}; 979 } 980 981 template <> 982 inline const StyleGenericTrackRepeat<LengthPercentage, StyleInteger>* 983 StyleGridTemplateComponent::GetRepeatAutoValue() const { 984 auto index = RepeatAutoIndex(); 985 if (!index) { 986 return nullptr; 987 } 988 return &TrackListValues()[*index].AsTrackRepeat(); 989 } 990 991 constexpr const auto kPaintOrderShift = StylePAINT_ORDER_SHIFT; 992 constexpr const auto kPaintOrderMask = StylePAINT_ORDER_MASK; 993 994 template <> 995 inline nsRect StyleGenericClipRect<LengthOrAuto>::ToLayoutRect( 996 nscoord aAutoSize) const { 997 nscoord x = left.IsLength() ? left.ToLength() : 0; 998 nscoord y = top.IsLength() ? top.ToLength() : 0; 999 nscoord width = right.IsLength() ? right.ToLength() - x : aAutoSize; 1000 nscoord height = bottom.IsLength() ? bottom.ToLength() - y : aAutoSize; 1001 return nsRect(x, y, width, height); 1002 } 1003 1004 using RestyleHint = StyleRestyleHint; 1005 1006 inline RestyleHint RestyleHint::RestyleSubtree() { 1007 return RESTYLE_SELF | RESTYLE_DESCENDANTS; 1008 } 1009 1010 inline RestyleHint RestyleHint::RecascadeSubtree() { 1011 return RECASCADE_SELF | RECASCADE_DESCENDANTS; 1012 } 1013 1014 inline RestyleHint RestyleHint::ForAnimations() { 1015 return RESTYLE_CSS_TRANSITIONS | RESTYLE_CSS_ANIMATIONS | RESTYLE_SMIL; 1016 } 1017 1018 inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const { 1019 if (!(*this & (RECASCADE_DESCENDANTS | RESTYLE_DESCENDANTS))) { 1020 return false; 1021 } 1022 return bool(*this & (RESTYLE_SELF | RECASCADE_SELF)); 1023 } 1024 1025 template <> 1026 ImageResolution StyleImage::GetResolution(const ComputedStyle*) const; 1027 1028 template <> 1029 inline const StyleImage& StyleImage::FinalImage() const { 1030 if (!IsImageSet()) { 1031 return *this; 1032 } 1033 const auto& set = *AsImageSet(); 1034 auto items = set.items.AsSpan(); 1035 if (MOZ_LIKELY(set.selected_index < items.Length())) { 1036 return items[set.selected_index].image.FinalImage(); 1037 } 1038 static auto sNone = StyleImage::None(); 1039 return sNone; 1040 } 1041 1042 template <> 1043 inline bool StyleImage::IsImageRequestType() const { 1044 const auto& finalImage = FinalImage(); 1045 return finalImage.IsUrl(); 1046 } 1047 1048 template <> 1049 inline const StyleComputedUrl* StyleImage::GetImageRequestURLValue() const { 1050 const auto& finalImage = FinalImage(); 1051 if (finalImage.IsUrl()) { 1052 return &finalImage.AsUrl(); 1053 } 1054 return nullptr; 1055 } 1056 1057 template <> 1058 inline imgRequestProxy* StyleImage::GetImageRequest() const { 1059 const auto* url = GetImageRequestURLValue(); 1060 return url ? url->GetImage() : nullptr; 1061 } 1062 1063 template <> 1064 inline bool StyleImage::IsResolved() const { 1065 const auto* url = GetImageRequestURLValue(); 1066 return !url || url->IsImageResolved(); 1067 } 1068 1069 template <> 1070 bool StyleImage::IsOpaque() const; 1071 template <> 1072 bool StyleImage::IsSizeAvailable() const; 1073 template <> 1074 bool StyleImage::IsComplete() const; 1075 template <> 1076 void StyleImage::ResolveImage(dom::Document&, const StyleImage*); 1077 1078 template <> 1079 inline AspectRatio StyleRatio<StyleNonNegativeNumber>::ToLayoutRatio( 1080 UseBoxSizing aUseBoxSizing) const { 1081 // 0/1, 1/0, and 0/0 are all degenerate ratios (which behave as auto), and we 1082 // always return 0.0f. 1083 // https://drafts.csswg.org/css-values-4/#degenerate-ratio 1084 return AspectRatio::FromSize(_0, _1, aUseBoxSizing); 1085 } 1086 1087 template <> 1088 inline AspectRatio StyleAspectRatio::ToLayoutRatio() const { 1089 return HasRatio() ? ratio.AsRatio().ToLayoutRatio(auto_ ? UseBoxSizing::No 1090 : UseBoxSizing::Yes) 1091 : AspectRatio(); 1092 } 1093 1094 inline void StyleFontWeight::ToString(nsACString& aString) const { 1095 Servo_FontWeight_ToCss(this, &aString); 1096 } 1097 1098 inline void StyleFontStretch::ToString(nsACString& aString) const { 1099 Servo_FontStretch_ToCss(this, &aString); 1100 } 1101 1102 inline void StyleFontStyle::ToString(nsACString& aString) const { 1103 Servo_FontStyle_ToCss(this, &aString); 1104 } 1105 1106 inline bool StyleFontWeight::IsBold() const { return *this >= BOLD_THRESHOLD; } 1107 1108 inline bool StyleFontWeight::PreferBold() const { 1109 return *this > PREFER_BOLD_THRESHOLD; 1110 } 1111 1112 inline bool StyleFontStyle::IsItalic() const { return *this == ITALIC; } 1113 1114 inline float StyleFontStyle::ObliqueAngle() const { 1115 MOZ_ASSERT(!IsItalic()); 1116 return ToFloat(); 1117 } 1118 1119 inline float StyleFontStyle::SlantAngle() const { 1120 return IsNormal() ? 0 : IsItalic() ? DEFAULT_OBLIQUE_DEGREES : ObliqueAngle(); 1121 } 1122 1123 using FontStretch = StyleFontStretch; 1124 using FontSlantStyle = StyleFontStyle; 1125 using FontWeight = StyleFontWeight; 1126 1127 template <> 1128 inline double StyleComputedTimingFunction::At(double aPortion, 1129 bool aBeforeFlag) const { 1130 return Servo_EasingFunctionAt( 1131 this, aPortion, 1132 aBeforeFlag ? StyleEasingBeforeFlag::Set : StyleEasingBeforeFlag::Unset); 1133 } 1134 1135 template <> 1136 inline void StyleComputedTimingFunction::AppendToString( 1137 nsACString& aOut) const { 1138 return Servo_SerializeEasing(this, &aOut); 1139 } 1140 1141 template <> 1142 inline double StyleComputedTimingFunction::GetPortion( 1143 const Maybe<StyleComputedTimingFunction>& aFn, double aPortion, 1144 bool aBeforeFlag) { 1145 return aFn ? aFn->At(aPortion, aBeforeFlag) : aPortion; 1146 } 1147 1148 /* static */ 1149 template <> 1150 inline LengthPercentageOrAuto LengthPercentageOrAuto::Zero() { 1151 return LengthPercentage(LengthPercentage::Zero()); 1152 } 1153 1154 template <> 1155 inline StyleViewTimelineInset::StyleGenericViewTimelineInset() 1156 : start(LengthPercentageOrAuto::Auto()), 1157 end(LengthPercentageOrAuto::Auto()) {} 1158 1159 inline StyleDisplayOutside StyleDisplay::Outside() const { 1160 return StyleDisplayOutside((_0 & OUTSIDE_MASK) >> OUTSIDE_SHIFT); 1161 } 1162 1163 inline StyleDisplayInside StyleDisplay::Inside() const { 1164 return StyleDisplayInside(_0 & INSIDE_MASK); 1165 } 1166 1167 inline bool StyleDisplay::IsListItem() const { return _0 & LIST_ITEM_MASK; } 1168 1169 inline bool StyleDisplay::IsInternalTable() const { 1170 return Outside() == StyleDisplayOutside::InternalTable; 1171 } 1172 1173 inline bool StyleDisplay::IsInternalTableExceptCell() const { 1174 return IsInternalTable() && *this != TableCell; 1175 } 1176 1177 inline bool StyleDisplay::IsInternalRuby() const { 1178 return Outside() == StyleDisplayOutside::InternalRuby; 1179 } 1180 1181 inline bool StyleDisplay::IsRuby() const { 1182 return Inside() == StyleDisplayInside::Ruby || IsInternalRuby(); 1183 } 1184 1185 inline bool StyleDisplay::IsInlineFlow() const { 1186 return Outside() == StyleDisplayOutside::Inline && 1187 Inside() == StyleDisplayInside::Flow; 1188 } 1189 1190 inline bool StyleDisplay::IsInlineInside() const { 1191 return IsInlineFlow() || IsRuby(); 1192 } 1193 1194 inline bool StyleDisplay::IsInlineOutside() const { 1195 return Outside() == StyleDisplayOutside::Inline || IsInternalRuby(); 1196 } 1197 1198 inline float StyleZoom::Zoom(float aValue) const { 1199 if (*this == ONE) { 1200 return aValue; 1201 } 1202 return ToFloat() * aValue; 1203 } 1204 1205 inline float StyleZoom::Unzoom(float aValue) const { 1206 if (*this == ONE) { 1207 return aValue; 1208 } 1209 return aValue / ToFloat(); 1210 } 1211 1212 inline nscoord StyleZoom::ZoomCoord(nscoord aValue) const { 1213 if (*this == ONE) { 1214 return aValue; 1215 } 1216 return NSToCoordRoundWithClamp(Zoom(float(aValue))); 1217 } 1218 1219 inline nscoord StyleZoom::UnzoomCoord(nscoord aValue) const { 1220 if (*this == ONE) { 1221 return aValue; 1222 } 1223 return NSToCoordRoundWithClamp(Unzoom(float(aValue))); 1224 } 1225 1226 inline nsSize StyleZoom::Zoom(const nsSize& aValue) const { 1227 if (*this == ONE) { 1228 return aValue; 1229 } 1230 return nsSize(ZoomCoord(aValue.Width()), ZoomCoord(aValue.Height())); 1231 } 1232 1233 inline nsSize StyleZoom::Unzoom(const nsSize& aValue) const { 1234 if (*this == ONE) { 1235 return aValue; 1236 } 1237 return nsSize(UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height())); 1238 } 1239 1240 inline nsPoint StyleZoom::Zoom(const nsPoint& aValue) const { 1241 if (*this == ONE) { 1242 return aValue; 1243 } 1244 return nsPoint(ZoomCoord(aValue.X()), ZoomCoord(aValue.Y())); 1245 } 1246 1247 inline nsPoint StyleZoom::Unzoom(const nsPoint& aValue) const { 1248 if (*this == ONE) { 1249 return aValue; 1250 } 1251 return nsPoint(UnzoomCoord(aValue.X()), UnzoomCoord(aValue.Y())); 1252 } 1253 1254 inline nsRect StyleZoom::Zoom(const nsRect& aValue) const { 1255 if (*this == ONE) { 1256 return aValue; 1257 } 1258 return nsRect(ZoomCoord(aValue.X()), ZoomCoord(aValue.Y()), 1259 ZoomCoord(aValue.Width()), ZoomCoord(aValue.Height())); 1260 } 1261 1262 inline nsRect StyleZoom::Unzoom(const nsRect& aValue) const { 1263 if (*this == ONE) { 1264 return aValue; 1265 } 1266 return nsRect(UnzoomCoord(aValue.X()), UnzoomCoord(aValue.Y()), 1267 UnzoomCoord(aValue.Width()), UnzoomCoord(aValue.Height())); 1268 } 1269 1270 template <> 1271 inline gfx::Point StyleCoordinatePair<StyleCSSFloat>::ToGfxPoint( 1272 const CSSSize* aBasis) const { 1273 return gfx::Point(x, y); 1274 } 1275 1276 template <> 1277 inline gfx::Point StyleCoordinatePair<LengthPercentage>::ToGfxPoint( 1278 const CSSSize* aBasis) const { 1279 MOZ_ASSERT(aBasis); 1280 return gfx::Point(x.ResolveToCSSPixels(aBasis->Width()), 1281 y.ResolveToCSSPixels(aBasis->Height())); 1282 } 1283 1284 template <> 1285 inline gfx::Point StyleShapePosition<StyleCSSFloat>::ToGfxPoint( 1286 const CSSSize* aBasis) const { 1287 return gfx::Point(horizontal, vertical); 1288 } 1289 1290 template <> 1291 inline gfx::Point StyleShapePosition<LengthPercentage>::ToGfxPoint( 1292 const CSSSize* aBasis) const { 1293 MOZ_ASSERT(aBasis); 1294 return gfx::Point(horizontal.ResolveToCSSPixels(aBasis->Width()), 1295 vertical.ResolveToCSSPixels(aBasis->Height())); 1296 } 1297 1298 template <> 1299 inline gfx::Point 1300 StyleCommandEndPoint<StyleShapePosition<StyleCSSFloat>, 1301 StyleCSSFloat>::ToGfxPoint(const CSSSize* aBasis) const { 1302 if (IsToPosition()) { 1303 auto& pos = AsToPosition(); 1304 return pos.ToGfxPoint(); 1305 } else { 1306 auto& coord = AsByCoordinate(); 1307 return coord.ToGfxPoint(); 1308 } 1309 } 1310 1311 template <> 1312 inline gfx::Point StyleCommandEndPoint< 1313 StyleShapePosition<LengthPercentage>, 1314 LengthPercentage>::ToGfxPoint(const CSSSize* aBasis) const { 1315 MOZ_ASSERT(aBasis); 1316 if (IsToPosition()) { 1317 auto& pos = AsToPosition(); 1318 return pos.ToGfxPoint(aBasis); 1319 } else { 1320 auto& coord = AsByCoordinate(); 1321 return coord.ToGfxPoint(aBasis); 1322 } 1323 } 1324 1325 template <> 1326 inline gfx::Coord StyleAxisEndPoint<StyleCSSFloat>::ToGfxCoord( 1327 const StyleCSSFloat* aBasis) const { 1328 if (IsToPosition()) { 1329 const auto pos = AsToPosition(); 1330 MOZ_ASSERT(pos.IsLengthPercent()); 1331 return gfx::Coord(pos.AsLengthPercent()); 1332 } 1333 return gfx::Coord(AsByCoordinate()); 1334 } 1335 1336 template <> 1337 inline gfx::Coord StyleAxisEndPoint<LengthPercentage>::ToGfxCoord( 1338 const StyleCSSFloat* aBasis) const { 1339 MOZ_ASSERT(aBasis); 1340 if (IsToPosition()) { 1341 const auto pos = AsToPosition(); 1342 MOZ_ASSERT(pos.IsLengthPercent()); 1343 return gfx::Coord(pos.AsLengthPercent().ResolveToCSSPixels(*aBasis)); 1344 } 1345 return gfx::Coord(AsByCoordinate().ResolveToCSSPixels(*aBasis)); 1346 } 1347 1348 template <> 1349 inline gfx::Point 1350 StyleControlPoint<StyleShapePosition<StyleCSSFloat>, StyleCSSFloat>::ToGfxPoint( 1351 const gfx::Point aStatePos, const gfx::Point aEndPoint, 1352 const CSSSize* aBasis) const { 1353 if (IsAbsolute()) { 1354 auto& pos = AsAbsolute(); 1355 return pos.ToGfxPoint(); 1356 } 1357 1358 // Else 1359 auto& point = AsRelative(); 1360 auto cp = point.coord.ToGfxPoint(); 1361 if (point.reference == StyleControlReference::Start) { 1362 return cp + aStatePos; 1363 } else if (point.reference == StyleControlReference::End) { 1364 return cp + aEndPoint; 1365 } else { 1366 return cp; 1367 } 1368 } 1369 1370 template <> 1371 inline gfx::Point 1372 StyleControlPoint<StyleShapePosition<LengthPercentage>, 1373 LengthPercentage>::ToGfxPoint(const gfx::Point aStatePos, 1374 const gfx::Point aEndPoint, 1375 const CSSSize* aBasis) const { 1376 MOZ_ASSERT(aBasis); 1377 if (IsAbsolute()) { 1378 auto& pos = AsAbsolute(); 1379 return pos.ToGfxPoint(aBasis); 1380 } 1381 1382 // Else 1383 auto& point = AsRelative(); 1384 auto cp = point.coord.ToGfxPoint(aBasis); 1385 if (point.reference == StyleControlReference::Start) { 1386 return cp + aStatePos; 1387 } else if (point.reference == StyleControlReference::End) { 1388 return cp + aEndPoint; 1389 } else { 1390 return cp; 1391 } 1392 } 1393 1394 template <> 1395 inline gfx::Point StyleArcRadii<StyleCSSFloat>::ToGfxPoint( 1396 const CSSSize* aBasis) const { 1397 return ry.IsSome() ? gfx::Point(rx, ry.AsSome()) : gfx::Point(rx, rx); 1398 } 1399 1400 template <> 1401 inline gfx::Point StyleArcRadii<LengthPercentage>::ToGfxPoint( 1402 const CSSSize* aBasis) const { 1403 MOZ_ASSERT(aBasis); 1404 if (ry.IsSome()) { 1405 return gfx::Point(rx.ResolveToCSSPixels(aBasis->Width()), 1406 ry.AsSome().ResolveToCSSPixels(aBasis->Height())); 1407 } 1408 1409 // Else percentages are resolved against the direction-agnostic size 1410 // of the reference box for both radiuses. 1411 // https://drafts.csswg.org/css-shapes-1/#typedef-shape-arc-command 1412 const auto directionAgnostic = SVGContentUtils::ComputeNormalizedHypotenuse( 1413 aBasis->Width(), aBasis->Height()); 1414 const auto radius = rx.ResolveToCSSPixels(directionAgnostic); 1415 return gfx::Point(radius, radius); 1416 } 1417 1418 inline StylePhysicalSide ToStylePhysicalSide(mozilla::Side aSide) { 1419 // TODO(dshin): Should look into merging these two types... 1420 static_assert(static_cast<uint8_t>(mozilla::Side::eSideLeft) == 1421 static_cast<uint8_t>(StylePhysicalSide::Left), 1422 "Left side doesn't match"); 1423 static_assert(static_cast<uint8_t>(mozilla::Side::eSideRight) == 1424 static_cast<uint8_t>(StylePhysicalSide::Right), 1425 "Left side doesn't match"); 1426 static_assert(static_cast<uint8_t>(mozilla::Side::eSideTop) == 1427 static_cast<uint8_t>(StylePhysicalSide::Top), 1428 "Left side doesn't match"); 1429 static_assert(static_cast<uint8_t>(mozilla::Side::eSideBottom) == 1430 static_cast<uint8_t>(StylePhysicalSide::Bottom), 1431 "Left side doesn't match"); 1432 return static_cast<StylePhysicalSide>(static_cast<uint8_t>(aSide)); 1433 } 1434 1435 inline StylePhysicalAxis ToStylePhysicalAxis(StylePhysicalSide aSide) { 1436 return aSide == StylePhysicalSide::Top || aSide == StylePhysicalSide::Bottom 1437 ? StylePhysicalAxis::Vertical 1438 : StylePhysicalAxis::Horizontal; 1439 } 1440 1441 inline StylePhysicalAxis ToStylePhysicalAxis(mozilla::Side aSide) { 1442 return ToStylePhysicalAxis(ToStylePhysicalSide(aSide)); 1443 } 1444 1445 inline mozilla::Side ToSide(StylePhysicalSide aSide) { 1446 return static_cast<mozilla::Side>(static_cast<uint8_t>(aSide)); 1447 } 1448 1449 #define DEFINE_LENGTH_PERCENTAGE_CTOR(ty_) \ 1450 template <> \ 1451 inline Style##ty_::StyleGeneric##ty_(const StyleLengthPercentage& aLP) \ 1452 : tag{Tag::LengthPercentage} { \ 1453 ::new (&length_percentage._0)(StyleLengthPercentage)(aLP); \ 1454 } 1455 1456 DEFINE_LENGTH_PERCENTAGE_CTOR(Inset) 1457 DEFINE_LENGTH_PERCENTAGE_CTOR(Margin) 1458 DEFINE_LENGTH_PERCENTAGE_CTOR(Size) 1459 DEFINE_LENGTH_PERCENTAGE_CTOR(MaxSize) 1460 1461 inline bool StylePositionArea::IsNone() const { 1462 return first == StylePositionAreaKeyword::None; 1463 } 1464 1465 } // namespace mozilla 1466 1467 #endif