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 "mozilla/ServoStyleConsts.h" 13 #include "mozilla/AspectRatio.h" 14 #include "mozilla/EndianUtils.h" 15 #include "mozilla/URLExtraData.h" 16 #include "nsGkAtoms.h" 17 #include "MainThreadUtils.h" 18 #include "nsNetUtil.h" 19 #include <type_traits> 20 #include <new> 21 22 // TODO(emilio): there are quite a few other implementations scattered around 23 // that should move here. 24 25 namespace mozilla { 26 27 // We need to explicitly instantiate these so that the clang plugin can see that 28 // they're trivially copiable... 29 // 30 // https://github.com/eqrion/cbindgen/issues/402 tracks doing something like 31 // this automatically from cbindgen. 32 template struct StyleOwned<RawServoAnimationValueMap>; 33 template struct StyleOwned<RawServoAuthorStyles>; 34 template struct StyleOwned<RawServoSourceSizeList>; 35 template struct StyleOwned<StyleUseCounters>; 36 template struct StyleOwnedOrNull<StyleUseCounters>; 37 template struct StyleOwnedOrNull<RawServoSelectorList>; 38 template struct StyleStrong<ComputedStyle>; 39 template struct StyleStrong<ServoCssRules>; 40 template struct StyleStrong<RawServoAnimationValue>; 41 template struct StyleStrong<RawServoDeclarationBlock>; 42 template struct StyleStrong<RawServoStyleSheetContents>; 43 template struct StyleStrong<RawServoKeyframe>; 44 template struct StyleStrong<RawServoMediaList>; 45 template struct StyleStrong<RawServoStyleRule>; 46 template struct StyleStrong<RawServoImportRule>; 47 template struct StyleStrong<RawServoKeyframesRule>; 48 template struct StyleStrong<RawServoMediaRule>; 49 template struct StyleStrong<RawServoMozDocumentRule>; 50 template struct StyleStrong<RawServoNamespaceRule>; 51 template struct StyleStrong<RawServoPageRule>; 52 template struct StyleStrong<RawServoSupportsRule>; 53 template struct StyleStrong<RawServoFontFeatureValuesRule>; 54 template struct StyleStrong<RawServoFontFaceRule>; 55 template struct StyleStrong<RawServoCounterStyleRule>; 56 57 template <typename T> 58 inline void StyleOwnedSlice<T>::Clear() { 59 if (!len) { 60 return; 61 } 62 for (size_t i : IntegerRange(len)) { 63 ptr[i].~T(); 64 } 65 free(ptr); 66 ptr = (T*)alignof(T); 67 len = 0; 68 } 69 70 template <typename T> 71 inline void StyleOwnedSlice<T>::CopyFrom(const StyleOwnedSlice& aOther) { 72 Clear(); 73 len = aOther.len; 74 if (!len) { 75 ptr = (T*)alignof(T); 76 } else { 77 ptr = (T*)malloc(len * sizeof(T)); 78 size_t i = 0; 79 for (const T& elem : aOther.AsSpan()) { 80 new (ptr + i++) T(elem); 81 } 82 } 83 } 84 85 template <typename T> 86 inline void StyleOwnedSlice<T>::SwapElements(StyleOwnedSlice& aOther) { 87 std::swap(ptr, aOther.ptr); 88 std::swap(len, aOther.len); 89 } 90 91 template <typename T> 92 inline StyleOwnedSlice<T>::StyleOwnedSlice(const StyleOwnedSlice& aOther) 93 : StyleOwnedSlice() { 94 CopyFrom(aOther); 95 } 96 97 template <typename T> 98 inline StyleOwnedSlice<T>::StyleOwnedSlice(StyleOwnedSlice&& aOther) 99 : StyleOwnedSlice() { 100 SwapElements(aOther); 101 } 102 103 template <typename T> 104 inline StyleOwnedSlice<T>::StyleOwnedSlice(Vector<T>&& aVector) 105 : StyleOwnedSlice() { 106 if (!aVector.length()) { 107 return; 108 } 109 110 // We could handle this if Vector provided the relevant APIs, see bug 1610702. 111 MOZ_DIAGNOSTIC_ASSERT(aVector.length() == aVector.capacity(), 112 "Shouldn't over-allocate"); 113 len = aVector.length(); 114 ptr = aVector.extractRawBuffer(); 115 MOZ_ASSERT(ptr, 116 "How did extractRawBuffer return null if we're not using inline " 117 "capacity?"); 118 } 119 120 template <typename T> 121 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=( 122 const StyleOwnedSlice& aOther) { 123 CopyFrom(aOther); 124 return *this; 125 } 126 127 template <typename T> 128 inline StyleOwnedSlice<T>& StyleOwnedSlice<T>::operator=( 129 StyleOwnedSlice&& aOther) { 130 Clear(); 131 SwapElements(aOther); 132 return *this; 133 } 134 135 template <typename T> 136 inline StyleOwnedSlice<T>::~StyleOwnedSlice() { 137 Clear(); 138 } 139 140 // This code is basically a C++ port of the Arc::clone() implementation in 141 // servo/components/servo_arc/lib.rs. 142 static constexpr const size_t kStaticRefcount = 143 std::numeric_limits<size_t>::max(); 144 static constexpr const size_t kMaxRefcount = 145 std::numeric_limits<intptr_t>::max(); 146 147 template <typename T> 148 inline void StyleArcInner<T>::IncrementRef() { 149 if (count.load(std::memory_order_relaxed) != kStaticRefcount) { 150 auto old_size = count.fetch_add(1, std::memory_order_relaxed); 151 if (MOZ_UNLIKELY(old_size > kMaxRefcount)) { 152 ::abort(); 153 } 154 } 155 } 156 157 // This is a C++ port-ish of Arc::drop(). 158 template <typename T> 159 inline bool StyleArcInner<T>::DecrementRef() { 160 if (count.load(std::memory_order_relaxed) == kStaticRefcount) { 161 return false; 162 } 163 if (count.fetch_sub(1, std::memory_order_release) != 1) { 164 return false; 165 } 166 #ifdef MOZ_TSAN 167 // TSan doesn't understand std::atomic_thread_fence, so in order 168 // to avoid a false positive for every time a refcounted object 169 // is deleted, we replace the fence with an atomic operation. 170 count.load(std::memory_order_acquire); 171 #else 172 std::atomic_thread_fence(std::memory_order_acquire); 173 #endif 174 MOZ_LOG_DTOR(this, "ServoArc", 8); 175 return true; 176 } 177 178 static constexpr const uint64_t kArcSliceCanary = 0xf3f3f3f3f3f3f3f3; 179 180 #define ASSERT_CANARY \ 181 MOZ_DIAGNOSTIC_ASSERT(_0.ptr->data.header.header == kArcSliceCanary, "Uh?"); 182 183 template <typename T> 184 inline StyleArcSlice<T>::StyleArcSlice() { 185 _0.ptr = reinterpret_cast<decltype(_0.ptr)>(Servo_StyleArcSlice_EmptyPtr()); 186 ASSERT_CANARY 187 } 188 189 template <typename T> 190 inline StyleArcSlice<T>::StyleArcSlice(const StyleArcSlice& aOther) { 191 MOZ_DIAGNOSTIC_ASSERT(aOther._0.ptr); 192 _0.ptr = aOther._0.ptr; 193 _0.ptr->IncrementRef(); 194 ASSERT_CANARY 195 } 196 197 template <typename T> 198 inline StyleArcSlice<T>::StyleArcSlice( 199 const StyleForgottenArcSlicePtr<T>& aPtr) { 200 // See the forget() implementation to see why reinterpret_cast() is ok. 201 _0.ptr = reinterpret_cast<decltype(_0.ptr)>(aPtr._0); 202 ASSERT_CANARY 203 } 204 205 template <typename T> 206 inline size_t StyleArcSlice<T>::Length() const { 207 ASSERT_CANARY 208 return _0.ptr->data.header.length; 209 } 210 211 template <typename T> 212 inline bool StyleArcSlice<T>::IsEmpty() const { 213 ASSERT_CANARY 214 return Length() == 0; 215 } 216 217 template <typename T> 218 inline Span<const T> StyleArcSlice<T>::AsSpan() const { 219 ASSERT_CANARY 220 // Explicitly specify template argument here to avoid instantiating Span<T> 221 // first and then implicitly converting to Span<const T> 222 return Span<const T>{_0.ptr->data.slice, Length()}; 223 } 224 225 template <typename T> 226 inline bool StyleArcSlice<T>::operator==(const StyleArcSlice& aOther) const { 227 ASSERT_CANARY 228 return _0.ptr == aOther._0.ptr || AsSpan() == aOther.AsSpan(); 229 } 230 231 template <typename T> 232 inline bool StyleArcSlice<T>::operator!=(const StyleArcSlice& aOther) const { 233 return !(*this == aOther); 234 } 235 236 template <typename T> 237 inline void StyleArcSlice<T>::Release() { 238 ASSERT_CANARY 239 if (MOZ_LIKELY(!_0.ptr->DecrementRef())) { 240 return; 241 } 242 for (T& elem : Span(_0.ptr->data.slice, Length())) { 243 elem.~T(); 244 } 245 free(_0.ptr); // Drop the allocation now. 246 } 247 248 template <typename T> 249 inline StyleArcSlice<T>::~StyleArcSlice() { 250 Release(); 251 } 252 253 template <typename T> 254 inline StyleArcSlice<T>& StyleArcSlice<T>::operator=(StyleArcSlice&& aOther) { 255 ASSERT_CANARY 256 std::swap(_0.ptr, aOther._0.ptr); 257 ASSERT_CANARY 258 return *this; 259 } 260 261 template <typename T> 262 inline StyleArcSlice<T>& StyleArcSlice<T>::operator=( 263 const StyleArcSlice& aOther) { 264 ASSERT_CANARY 265 266 if (_0.ptr == aOther._0.ptr) { 267 return *this; 268 } 269 270 Release(); 271 272 _0.ptr = aOther._0.ptr; 273 _0.ptr->IncrementRef(); 274 275 ASSERT_CANARY 276 return *this; 277 } 278 279 #undef ASSERT_CANARY 280 281 template <typename T> 282 inline StyleArc<T>::StyleArc(const StyleArc& aOther) : p(aOther.p) { 283 p->IncrementRef(); 284 } 285 286 template <typename T> 287 inline void StyleArc<T>::Release() { 288 if (MOZ_LIKELY(!p->DecrementRef())) { 289 return; 290 } 291 p->data.~T(); 292 free(p); 293 } 294 295 template <typename T> 296 inline StyleArc<T>& StyleArc<T>::operator=(const StyleArc& aOther) { 297 if (p != aOther.p) { 298 Release(); 299 p = aOther.p; 300 p->IncrementRef(); 301 } 302 return *this; 303 } 304 305 template <typename T> 306 inline StyleArc<T>& StyleArc<T>::operator=(StyleArc&& aOther) { 307 std::swap(p, aOther.p); 308 return *this; 309 } 310 311 template <typename T> 312 inline StyleArc<T>::~StyleArc() { 313 Release(); 314 } 315 316 inline bool StyleAtom::IsStatic() const { return !!(_0 & 1); } 317 318 inline nsAtom* StyleAtom::AsAtom() const { 319 if (IsStatic()) { 320 auto* atom = reinterpret_cast<const nsStaticAtom*>( 321 reinterpret_cast<const uint8_t*>(&detail::gGkAtoms) + (_0 >> 1)); 322 MOZ_ASSERT(atom->IsStatic()); 323 return const_cast<nsStaticAtom*>(atom); 324 } 325 return reinterpret_cast<nsAtom*>(_0); 326 } 327 328 inline void StyleAtom::AddRef() { 329 if (!IsStatic()) { 330 AsAtom()->AddRef(); 331 } 332 } 333 334 inline void StyleAtom::Release() { 335 if (!IsStatic()) { 336 AsAtom()->Release(); 337 } 338 } 339 340 inline StyleAtom::StyleAtom(already_AddRefed<nsAtom> aAtom) { 341 nsAtom* atom = aAtom.take(); 342 if (atom->IsStatic()) { 343 ptrdiff_t offset = reinterpret_cast<const uint8_t*>(atom->AsStatic()) - 344 reinterpret_cast<const uint8_t*>(&detail::gGkAtoms); 345 _0 = (offset << 1) | 1; 346 } else { 347 _0 = reinterpret_cast<uintptr_t>(atom); 348 } 349 MOZ_ASSERT(IsStatic() == atom->IsStatic()); 350 MOZ_ASSERT(AsAtom() == atom); 351 } 352 353 inline StyleAtom::StyleAtom(const StyleAtom& aOther) : _0(aOther._0) { 354 AddRef(); 355 } 356 357 inline StyleAtom& StyleAtom::operator=(const StyleAtom& aOther) { 358 if (MOZ_LIKELY(this != &aOther)) { 359 Release(); 360 _0 = aOther._0; 361 AddRef(); 362 } 363 return *this; 364 } 365 366 inline StyleAtom::~StyleAtom() { Release(); } 367 368 inline nsAtom* StyleCustomIdent::AsAtom() const { return _0.AsAtom(); } 369 370 inline nsDependentCSubstring StyleOwnedStr::AsString() const { 371 Span<const uint8_t> s = _0.AsSpan(); 372 return nsDependentCSubstring(reinterpret_cast<const char*>(s.Elements()), 373 s.Length()); 374 } 375 376 template <typename T> 377 inline Span<const T> StyleGenericTransform<T>::Operations() const { 378 return _0.AsSpan(); 379 } 380 381 template <typename T> 382 inline bool StyleGenericTransform<T>::IsNone() const { 383 return Operations().IsEmpty(); 384 } 385 386 inline StyleAngle StyleAngle::Zero() { return {0.0f}; } 387 388 inline float StyleAngle::ToDegrees() const { return _0; } 389 390 inline double StyleAngle::ToRadians() const { 391 return double(ToDegrees()) * M_PI / 180.0; 392 } 393 394 inline bool StyleUrlExtraData::IsShared() const { return !!(_0 & 1); } 395 396 inline StyleUrlExtraData::~StyleUrlExtraData() { 397 if (!IsShared()) { 398 reinterpret_cast<URLExtraData*>(_0)->Release(); 399 } 400 } 401 402 inline const URLExtraData& StyleUrlExtraData::get() const { 403 if (IsShared()) { 404 return *URLExtraData::sShared[_0 >> 1].get(); 405 } 406 return *reinterpret_cast<const URLExtraData*>(_0); 407 } 408 409 inline nsDependentCSubstring StyleCssUrl::SpecifiedSerialization() const { 410 return _0->serialization.AsString(); 411 } 412 413 inline const URLExtraData& StyleCssUrl::ExtraData() const { 414 return _0->extra_data.get(); 415 } 416 417 inline StyleLoadData& StyleCssUrl::LoadData() const { 418 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); 419 if (MOZ_LIKELY(_0->load_data.tag == StyleLoadDataSource::Tag::Owned)) { 420 return const_cast<StyleLoadData&>(_0->load_data.owned._0); 421 } 422 return const_cast<StyleLoadData&>(*Servo_LoadData_GetLazy(&_0->load_data)); 423 } 424 425 inline nsIURI* StyleCssUrl::GetURI() const { 426 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); 427 auto& loadData = LoadData(); 428 if (!(loadData.flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_URI)) { 429 loadData.flags |= StyleLoadDataFlags::TRIED_TO_RESOLVE_URI; 430 nsDependentCSubstring serialization = SpecifiedSerialization(); 431 // https://drafts.csswg.org/css-values-4/#url-empty: 432 // 433 // If the value of the url() is the empty string (like url("") or 434 // url()), the url must resolve to an invalid resource (similar to what 435 // the url about:invalid does). 436 // 437 if (!serialization.IsEmpty()) { 438 RefPtr<nsIURI> resolved; 439 NS_NewURI(getter_AddRefs(resolved), serialization, nullptr, 440 ExtraData().BaseURI()); 441 loadData.resolved_uri = resolved.forget().take(); 442 } 443 } 444 return loadData.resolved_uri; 445 } 446 447 inline nsDependentCSubstring StyleComputedUrl::SpecifiedSerialization() const { 448 return _0.SpecifiedSerialization(); 449 } 450 inline const URLExtraData& StyleComputedUrl::ExtraData() const { 451 return _0.ExtraData(); 452 } 453 inline StyleLoadData& StyleComputedUrl::LoadData() const { 454 return _0.LoadData(); 455 } 456 inline StyleCorsMode StyleComputedUrl::CorsMode() const { 457 return _0._0->cors_mode; 458 } 459 inline nsIURI* StyleComputedUrl::GetURI() const { return _0.GetURI(); } 460 461 inline bool StyleComputedUrl::IsLocalRef() const { 462 return Servo_CssUrl_IsLocalRef(&_0); 463 } 464 465 inline bool StyleComputedUrl::HasRef() const { 466 if (IsLocalRef()) { 467 return true; 468 } 469 if (nsIURI* uri = GetURI()) { 470 bool hasRef = false; 471 return NS_SUCCEEDED(uri->GetHasRef(&hasRef)) && hasRef; 472 } 473 return false; 474 } 475 476 inline bool StyleComputedImageUrl::IsImageResolved() const { 477 return bool(LoadData().flags & StyleLoadDataFlags::TRIED_TO_RESOLVE_IMAGE); 478 } 479 480 inline imgRequestProxy* StyleComputedImageUrl::GetImage() const { 481 MOZ_ASSERT(IsImageResolved()); 482 return LoadData().resolved_image; 483 } 484 485 template <> 486 inline bool StyleGradient::Repeating() const { 487 if (IsLinear()) { 488 return AsLinear().repeating; 489 } 490 if (IsRadial()) { 491 return AsRadial().repeating; 492 } 493 return AsConic().repeating; 494 } 495 496 template <> 497 bool StyleGradient::IsOpaque() const; 498 499 template <typename Integer> 500 inline StyleGenericGridLine<Integer>::StyleGenericGridLine() 501 : ident(do_AddRef(static_cast<nsAtom*>(nsGkAtoms::_empty))), 502 line_num(0), 503 is_span(false) {} 504 505 template <> 506 inline nsAtom* StyleGridLine::LineName() const { 507 return ident.AsAtom(); 508 } 509 510 template <> 511 inline bool StyleGridLine::IsAuto() const { 512 return LineName()->IsEmpty() && line_num == 0 && !is_span; 513 } 514 515 using LengthPercentage = StyleLengthPercentage; 516 using LengthPercentageOrAuto = StyleLengthPercentageOrAuto; 517 using NonNegativeLengthPercentage = StyleNonNegativeLengthPercentage; 518 using NonNegativeLengthPercentageOrAuto = 519 StyleNonNegativeLengthPercentageOrAuto; 520 using NonNegativeLengthPercentageOrNormal = 521 StyleNonNegativeLengthPercentageOrNormal; 522 using Length = StyleLength; 523 using LengthOrAuto = StyleLengthOrAuto; 524 using NonNegativeLength = StyleNonNegativeLength; 525 using NonNegativeLengthOrAuto = StyleNonNegativeLengthOrAuto; 526 using BorderRadius = StyleBorderRadius; 527 528 bool StyleCSSPixelLength::IsZero() const { return _0 == 0.0f; } 529 530 void StyleCSSPixelLength::ScaleBy(float aScale) { _0 *= aScale; } 531 532 StyleCSSPixelLength StyleCSSPixelLength::ScaledBy(float aScale) const { 533 return FromPixels(ToCSSPixels() * aScale); 534 } 535 536 nscoord StyleCSSPixelLength::ToAppUnits() const { 537 // We want to resolve the length part of the calc() expression rounding 0.5 538 // away from zero, instead of the default behavior of 539 // NSToCoordRound{,WithClamp} which do floor(x + 0.5). 540 // 541 // This is what the rust code in the app_units crate does, and not doing this 542 // would regress bug 1323735, for example. 543 // 544 // FIXME(emilio, bug 1528114): Probably we should do something smarter. 545 if (IsZero()) { 546 // Avoid the expensive FP math below. 547 return 0; 548 } 549 float length = _0 * float(mozilla::AppUnitsPerCSSPixel()); 550 if (length >= float(nscoord_MAX)) { 551 return nscoord_MAX; 552 } 553 if (length <= float(nscoord_MIN)) { 554 return nscoord_MIN; 555 } 556 return NSToIntRound(length); 557 } 558 559 bool LengthPercentage::IsLength() const { return Tag() == TAG_LENGTH; } 560 561 StyleLengthPercentageUnion::StyleLengthPercentageUnion() { 562 length = {TAG_LENGTH, {0.0f}}; 563 MOZ_ASSERT(IsLength()); 564 } 565 566 static_assert(sizeof(LengthPercentage) == sizeof(uint64_t), ""); 567 568 Length& LengthPercentage::AsLength() { 569 MOZ_ASSERT(IsLength()); 570 return length.length; 571 } 572 573 const Length& LengthPercentage::AsLength() const { 574 return const_cast<LengthPercentage*>(this)->AsLength(); 575 } 576 577 bool LengthPercentage::IsPercentage() const { return Tag() == TAG_PERCENTAGE; } 578 579 StylePercentage& LengthPercentage::AsPercentage() { 580 MOZ_ASSERT(IsPercentage()); 581 return percentage.percentage; 582 } 583 584 const StylePercentage& LengthPercentage::AsPercentage() const { 585 return const_cast<LengthPercentage*>(this)->AsPercentage(); 586 } 587 588 bool LengthPercentage::IsCalc() const { return Tag() == TAG_CALC; } 589 590 StyleCalcLengthPercentage& LengthPercentage::AsCalc() { 591 MOZ_ASSERT(IsCalc()); 592 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the tag. 593 #ifdef SERVO_32_BITS 594 return *calc.ptr; 595 #else 596 return *reinterpret_cast<StyleCalcLengthPercentage*>( 597 NativeEndian::swapFromLittleEndian(calc.ptr)); 598 #endif 599 } 600 601 const StyleCalcLengthPercentage& LengthPercentage::AsCalc() const { 602 return const_cast<LengthPercentage*>(this)->AsCalc(); 603 } 604 605 StyleLengthPercentageUnion::StyleLengthPercentageUnion(const Self& aOther) { 606 if (aOther.IsLength()) { 607 length = {TAG_LENGTH, aOther.AsLength()}; 608 } else if (aOther.IsPercentage()) { 609 percentage = {TAG_PERCENTAGE, aOther.AsPercentage()}; 610 } else { 611 MOZ_ASSERT(aOther.IsCalc()); 612 auto* ptr = new StyleCalcLengthPercentage(aOther.AsCalc()); 613 // NOTE: in 32-bits, the pointer is not swapped, and goes along with the 614 // tag. 615 calc = { 616 #ifdef SERVO_32_BITS 617 TAG_CALC, 618 ptr, 619 #else 620 NativeEndian::swapToLittleEndian(reinterpret_cast<uintptr_t>(ptr)), 621 #endif 622 }; 623 } 624 MOZ_ASSERT(Tag() == aOther.Tag()); 625 } 626 627 StyleLengthPercentageUnion::~StyleLengthPercentageUnion() { 628 if (IsCalc()) { 629 delete &AsCalc(); 630 } 631 } 632 633 LengthPercentage& LengthPercentage::operator=(const LengthPercentage& aOther) { 634 if (this != &aOther) { 635 this->~LengthPercentage(); 636 new (this) LengthPercentage(aOther); 637 } 638 return *this; 639 } 640 641 bool LengthPercentage::operator==(const LengthPercentage& aOther) const { 642 if (Tag() != aOther.Tag()) { 643 return false; 644 } 645 if (IsLength()) { 646 return AsLength() == aOther.AsLength(); 647 } 648 if (IsPercentage()) { 649 return AsPercentage() == aOther.AsPercentage(); 650 } 651 return AsCalc() == aOther.AsCalc(); 652 } 653 654 bool LengthPercentage::operator!=(const LengthPercentage& aOther) const { 655 return !(*this == aOther); 656 } 657 658 LengthPercentage LengthPercentage::Zero() { return {}; } 659 660 LengthPercentage LengthPercentage::FromPixels(CSSCoord aCoord) { 661 LengthPercentage l; 662 MOZ_ASSERT(l.IsLength()); 663 l.length.length = {aCoord}; 664 return l; 665 } 666 667 LengthPercentage LengthPercentage::FromAppUnits(nscoord aCoord) { 668 return FromPixels(CSSPixel::FromAppUnits(aCoord)); 669 } 670 671 LengthPercentage LengthPercentage::FromPercentage(float aPercentage) { 672 LengthPercentage l; 673 l.percentage = {TAG_PERCENTAGE, {aPercentage}}; 674 return l; 675 } 676 677 bool LengthPercentage::HasPercent() const { return IsPercentage() || IsCalc(); } 678 679 bool LengthPercentage::ConvertsToLength() const { return IsLength(); } 680 681 nscoord LengthPercentage::ToLength() const { 682 MOZ_ASSERT(ConvertsToLength()); 683 return AsLength().ToAppUnits(); 684 } 685 686 CSSCoord LengthPercentage::ToLengthInCSSPixels() const { 687 MOZ_ASSERT(ConvertsToLength()); 688 return AsLength().ToCSSPixels(); 689 } 690 691 bool LengthPercentage::ConvertsToPercentage() const { return IsPercentage(); } 692 693 float LengthPercentage::ToPercentage() const { 694 MOZ_ASSERT(ConvertsToPercentage()); 695 return AsPercentage()._0; 696 } 697 698 bool LengthPercentage::HasLengthAndPercentage() const { 699 if (!IsCalc()) { 700 return false; 701 } 702 MOZ_ASSERT(!ConvertsToLength() && !ConvertsToPercentage(), 703 "Should've been simplified earlier"); 704 return true; 705 } 706 707 bool LengthPercentage::IsDefinitelyZero() const { 708 if (IsLength()) { 709 return AsLength().IsZero(); 710 } 711 if (IsPercentage()) { 712 return AsPercentage()._0 == 0.0f; 713 } 714 // calc() should've been simplified to a percentage. 715 return false; 716 } 717 718 template <> 719 CSSCoord StyleCalcNode::ResolveToCSSPixels(CSSCoord aPercentageBasis) const; 720 721 template <> 722 void StyleCalcNode::ScaleLengthsBy(float); 723 724 CSSCoord LengthPercentage::ResolveToCSSPixels(CSSCoord aPercentageBasis) const { 725 if (IsLength()) { 726 return AsLength().ToCSSPixels(); 727 } 728 if (IsPercentage()) { 729 return AsPercentage()._0 * aPercentageBasis; 730 } 731 return AsCalc().node.ResolveToCSSPixels(aPercentageBasis); 732 } 733 734 template <typename T> 735 CSSCoord LengthPercentage::ResolveToCSSPixelsWith(T aPercentageGetter) const { 736 static_assert(std::is_same<decltype(aPercentageGetter()), CSSCoord>::value, 737 "Should return CSS pixels"); 738 if (ConvertsToLength()) { 739 return ToLengthInCSSPixels(); 740 } 741 return ResolveToCSSPixels(aPercentageGetter()); 742 } 743 744 template <typename T, typename U> 745 nscoord LengthPercentage::Resolve(T aPercentageGetter, U aRounder) const { 746 static_assert(std::is_same<decltype(aPercentageGetter()), nscoord>::value, 747 "Should return app units"); 748 static_assert(std::is_same<decltype(aRounder(1.0f)), nscoord>::value, 749 "Should return app units"); 750 if (ConvertsToLength()) { 751 return ToLength(); 752 } 753 if (IsPercentage() && AsPercentage()._0 == 0.0f) { 754 return 0.0f; 755 } 756 nscoord basis = aPercentageGetter(); 757 if (IsPercentage()) { 758 return aRounder(basis * AsPercentage()._0); 759 } 760 return AsCalc().node.Resolve(basis, aRounder); 761 } 762 763 nscoord LengthPercentage::Resolve(nscoord aPercentageBasis) const { 764 return Resolve([=] { return aPercentageBasis; }, NSToCoordFloorClamped); 765 } 766 767 template <typename T> 768 nscoord LengthPercentage::Resolve(T aPercentageGetter) const { 769 return Resolve(aPercentageGetter, NSToCoordFloorClamped); 770 } 771 772 template <typename T> 773 nscoord LengthPercentage::Resolve(nscoord aPercentageBasis, 774 T aPercentageRounder) const { 775 return Resolve([aPercentageBasis] { return aPercentageBasis; }, 776 aPercentageRounder); 777 } 778 779 void LengthPercentage::ScaleLengthsBy(float aScale) { 780 if (IsLength()) { 781 AsLength().ScaleBy(aScale); 782 } 783 if (IsCalc()) { 784 AsCalc().node.ScaleLengthsBy(aScale); 785 } 786 } 787 788 #define IMPL_LENGTHPERCENTAGE_FORWARDS(ty_) \ 789 template <> \ 790 inline bool ty_::HasPercent() const { \ 791 return IsLengthPercentage() && AsLengthPercentage().HasPercent(); \ 792 } \ 793 template <> \ 794 inline bool ty_::ConvertsToLength() const { \ 795 return IsLengthPercentage() && AsLengthPercentage().ConvertsToLength(); \ 796 } \ 797 template <> \ 798 inline bool ty_::HasLengthAndPercentage() const { \ 799 return IsLengthPercentage() && \ 800 AsLengthPercentage().HasLengthAndPercentage(); \ 801 } \ 802 template <> \ 803 inline nscoord ty_::ToLength() const { \ 804 MOZ_ASSERT(ConvertsToLength()); \ 805 return AsLengthPercentage().ToLength(); \ 806 } \ 807 template <> \ 808 inline bool ty_::ConvertsToPercentage() const { \ 809 return IsLengthPercentage() && \ 810 AsLengthPercentage().ConvertsToPercentage(); \ 811 } \ 812 template <> \ 813 inline float ty_::ToPercentage() const { \ 814 MOZ_ASSERT(ConvertsToPercentage()); \ 815 return AsLengthPercentage().ToPercentage(); \ 816 } 817 818 IMPL_LENGTHPERCENTAGE_FORWARDS(LengthPercentageOrAuto) 819 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleSize) 820 IMPL_LENGTHPERCENTAGE_FORWARDS(StyleMaxSize) 821 822 template <> 823 inline bool LengthOrAuto::IsLength() const { 824 return IsLengthPercentage(); 825 } 826 827 template <> 828 inline const Length& LengthOrAuto::AsLength() const { 829 return AsLengthPercentage(); 830 } 831 832 template <> 833 inline nscoord LengthOrAuto::ToLength() const { 834 return AsLength().ToAppUnits(); 835 } 836 837 template <> 838 inline bool StyleFlexBasis::IsAuto() const { 839 return IsSize() && AsSize().IsAuto(); 840 } 841 842 template <> 843 inline bool StyleSize::BehavesLikeInitialValueOnBlockAxis() const { 844 return IsAuto() || !IsLengthPercentage(); 845 } 846 847 template <> 848 inline bool StyleMaxSize::BehavesLikeInitialValueOnBlockAxis() const { 849 return IsNone() || !IsLengthPercentage(); 850 } 851 852 template <> 853 inline bool StyleBackgroundSize::IsInitialValue() const { 854 return IsExplicitSize() && explicit_size.width.IsAuto() && 855 explicit_size.height.IsAuto(); 856 } 857 858 template <typename T> 859 const T& StyleRect<T>::Get(mozilla::Side aSide) const { 860 static_assert(sizeof(StyleRect<T>) == sizeof(T) * 4, ""); 861 static_assert(alignof(StyleRect<T>) == alignof(T), ""); 862 return reinterpret_cast<const T*>(this)[aSide]; 863 } 864 865 template <typename T> 866 T& StyleRect<T>::Get(mozilla::Side aSide) { 867 return const_cast<T&>(static_cast<const StyleRect&>(*this).Get(aSide)); 868 } 869 870 template <typename T> 871 template <typename Predicate> 872 bool StyleRect<T>::All(Predicate aPredicate) const { 873 return aPredicate(_0) && aPredicate(_1) && aPredicate(_2) && aPredicate(_3); 874 } 875 876 template <typename T> 877 template <typename Predicate> 878 bool StyleRect<T>::Any(Predicate aPredicate) const { 879 return aPredicate(_0) || aPredicate(_1) || aPredicate(_2) || aPredicate(_3); 880 } 881 882 template <> 883 inline const LengthPercentage& BorderRadius::Get(HalfCorner aCorner) const { 884 static_assert(sizeof(BorderRadius) == sizeof(LengthPercentage) * 8, ""); 885 static_assert(alignof(BorderRadius) == alignof(LengthPercentage), ""); 886 auto* self = reinterpret_cast<const LengthPercentage*>(this); 887 return self[aCorner]; 888 } 889 890 template <> 891 inline bool StyleTrackBreadth::HasPercent() const { 892 return IsBreadth() && AsBreadth().HasPercent(); 893 } 894 895 // Implemented in nsStyleStructs.cpp 896 template <> 897 bool StyleTransform::HasPercent() const; 898 899 template <> 900 inline bool StyleTransformOrigin::HasPercent() const { 901 // NOTE(emilio): `depth` is just a `<length>` so doesn't have a percentage at 902 // all. 903 return horizontal.HasPercent() || vertical.HasPercent(); 904 } 905 906 template <> 907 inline Maybe<size_t> StyleGridTemplateComponent::RepeatAutoIndex() const { 908 if (!IsTrackList()) { 909 return Nothing(); 910 } 911 auto& list = *AsTrackList(); 912 return list.auto_repeat_index < list.values.Length() 913 ? Some(list.auto_repeat_index) 914 : Nothing(); 915 } 916 917 template <> 918 inline bool StyleGridTemplateComponent::HasRepeatAuto() const { 919 return RepeatAutoIndex().isSome(); 920 } 921 922 template <> 923 inline Span<const StyleGenericTrackListValue<LengthPercentage, StyleInteger>> 924 StyleGridTemplateComponent::TrackListValues() const { 925 if (IsTrackList()) { 926 return AsTrackList()->values.AsSpan(); 927 } 928 return {}; 929 } 930 931 template <> 932 inline const StyleGenericTrackRepeat<LengthPercentage, StyleInteger>* 933 StyleGridTemplateComponent::GetRepeatAutoValue() const { 934 auto index = RepeatAutoIndex(); 935 if (!index) { 936 return nullptr; 937 } 938 return &TrackListValues()[*index].AsTrackRepeat(); 939 } 940 941 constexpr const auto kPaintOrderShift = StylePAINT_ORDER_SHIFT; 942 constexpr const auto kPaintOrderMask = StylePAINT_ORDER_MASK; 943 944 template <> 945 inline nsRect StyleGenericClipRect<LengthOrAuto>::ToLayoutRect( 946 nscoord aAutoSize) const { 947 nscoord x = left.IsLength() ? left.ToLength() : 0; 948 nscoord y = top.IsLength() ? top.ToLength() : 0; 949 nscoord width = right.IsLength() ? right.ToLength() - x : aAutoSize; 950 nscoord height = bottom.IsLength() ? bottom.ToLength() - y : aAutoSize; 951 return nsRect(x, y, width, height); 952 } 953 954 using RestyleHint = StyleRestyleHint; 955 956 inline RestyleHint RestyleHint::RestyleSubtree() { 957 return RESTYLE_SELF | RESTYLE_DESCENDANTS; 958 } 959 960 inline RestyleHint RestyleHint::RecascadeSubtree() { 961 return RECASCADE_SELF | RECASCADE_DESCENDANTS; 962 } 963 964 inline RestyleHint RestyleHint::ForAnimations() { 965 return RESTYLE_CSS_TRANSITIONS | RESTYLE_CSS_ANIMATIONS | RESTYLE_SMIL; 966 } 967 968 inline bool RestyleHint::DefinitelyRecascadesAllSubtree() const { 969 if (!(*this & (RECASCADE_DESCENDANTS | RESTYLE_DESCENDANTS))) { 970 return false; 971 } 972 return bool(*this & (RESTYLE_SELF | RECASCADE_SELF)); 973 } 974 975 template <> 976 ImageResolution StyleImage::GetResolution() const; 977 978 template <> 979 inline const StyleImage& StyleImage::FinalImage() const { 980 if (!IsImageSet()) { 981 return *this; 982 } 983 auto& set = AsImageSet(); 984 auto& selectedItem = set->items.AsSpan()[set->selected_index]; 985 return selectedItem.image.FinalImage(); 986 } 987 988 template <> 989 Maybe<CSSIntSize> StyleImage::GetIntrinsicSize() const; 990 991 template <> 992 inline bool StyleImage::IsImageRequestType() const { 993 auto& finalImage = FinalImage(); 994 return finalImage.IsUrl() || finalImage.IsRect(); 995 } 996 997 template <> 998 inline const StyleComputedImageUrl* StyleImage::GetImageRequestURLValue() 999 const { 1000 auto& finalImage = FinalImage(); 1001 if (finalImage.IsUrl()) { 1002 return &finalImage.AsUrl(); 1003 } 1004 if (finalImage.IsRect()) { 1005 return &finalImage.AsRect()->url; 1006 } 1007 return nullptr; 1008 } 1009 1010 template <> 1011 inline imgRequestProxy* StyleImage::GetImageRequest() const { 1012 auto* url = GetImageRequestURLValue(); 1013 return url ? url->GetImage() : nullptr; 1014 } 1015 1016 template <> 1017 inline bool StyleImage::IsResolved() const { 1018 auto* url = GetImageRequestURLValue(); 1019 return !url || url->IsImageResolved(); 1020 } 1021 1022 template <> 1023 bool StyleImage::IsOpaque() const; 1024 template <> 1025 bool StyleImage::IsSizeAvailable() const; 1026 template <> 1027 bool StyleImage::IsComplete() const; 1028 template <> 1029 Maybe<StyleImage::ActualCropRect> StyleImage::ComputeActualCropRect() const; 1030 template <> 1031 void StyleImage::ResolveImage(dom::Document&, const StyleImage*); 1032 1033 template <> 1034 inline AspectRatio StyleRatio<StyleNonNegativeNumber>::ToLayoutRatio( 1035 UseBoxSizing aUseBoxSizing) const { 1036 // 0/1, 1/0, and 0/0 are all degenerate ratios (which behave as auto), and we 1037 // always return 0.0f. 1038 // https://drafts.csswg.org/css-values-4/#degenerate-ratio 1039 return AspectRatio::FromSize(_0, _1, aUseBoxSizing); 1040 } 1041 1042 template <> 1043 inline AspectRatio StyleAspectRatio::ToLayoutRatio() const { 1044 return HasRatio() ? ratio.AsRatio().ToLayoutRatio(auto_ ? UseBoxSizing::No 1045 : UseBoxSizing::Yes) 1046 : AspectRatio(); 1047 } 1048 1049 inline bool StyleFontFamilyList::ContainsFallback() const { 1050 if (fallback == StyleGenericFontFamily::None) { 1051 return false; 1052 } 1053 for (const auto& family : list.AsSpan()) { 1054 if (family.IsGeneric() && family.AsGeneric() == fallback) { 1055 return true; 1056 } 1057 } 1058 return false; 1059 } 1060 1061 } // namespace mozilla 1062 1063 #endif 1064