InspectorUtils.cpp (49377B)
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 #include "mozilla/dom/InspectorUtils.h" 8 9 #include "ChildIterator.h" 10 #include "Units.h" 11 #include "gfxTextRun.h" 12 #include "inLayoutUtils.h" 13 #include "mozilla/DeclarationBlock.h" 14 #include "mozilla/EventStateManager.h" 15 #include "mozilla/PresShell.h" 16 #include "mozilla/PresShellInlines.h" 17 #include "mozilla/RefPtr.h" 18 #include "mozilla/RelativeLuminanceUtils.h" 19 #include "mozilla/ScrollContainerFrame.h" 20 #include "mozilla/ServoBindings.h" 21 #include "mozilla/ServoCSSParser.h" 22 #include "mozilla/ServoStyleRuleMap.h" 23 #include "mozilla/ServoStyleSet.h" 24 #include "mozilla/StaticPrefs_layout.h" 25 #include "mozilla/StyleSheetInlines.h" 26 #include "mozilla/dom/BrowserParent.h" 27 #include "mozilla/dom/CSSBinding.h" 28 #include "mozilla/dom/CSSKeyframesRule.h" 29 #include "mozilla/dom/CSSStylePropertiesBinding.h" 30 #include "mozilla/dom/CSSStyleRule.h" 31 #include "mozilla/dom/CanonicalBrowsingContext.h" 32 #include "mozilla/dom/CharacterData.h" 33 #include "mozilla/dom/Document.h" 34 #include "mozilla/dom/DocumentInlines.h" 35 #include "mozilla/dom/Element.h" 36 #include "mozilla/dom/HTMLSlotElement.h" 37 #include "mozilla/dom/HTMLTemplateElement.h" 38 #include "mozilla/dom/Highlight.h" 39 #include "mozilla/dom/HighlightRegistry.h" 40 #include "mozilla/dom/InspectorFontFace.h" 41 #include "mozilla/dom/InspectorUtilsBinding.h" 42 #include "mozilla/dom/LinkStyle.h" 43 #include "mozilla/dom/ToJSValue.h" 44 #include "mozilla/gfx/Matrix.h" 45 #include "nsArray.h" 46 #include "nsAtom.h" 47 #include "nsBlockFrame.h" 48 #include "nsCSSProps.h" 49 #include "nsCSSValue.h" 50 #include "nsColor.h" 51 #include "nsComputedDOMStyle.h" 52 #include "nsContentList.h" 53 #include "nsFieldSetFrame.h" 54 #include "nsGlobalWindowInner.h" 55 #include "nsGridContainerFrame.h" 56 #include "nsIContentInlines.h" 57 #include "nsLayoutUtils.h" 58 #include "nsNameSpaceManager.h" 59 #include "nsPresContext.h" 60 #include "nsQueryObject.h" 61 #include "nsRange.h" 62 #include "nsString.h" 63 #include "nsStyleUtil.h" 64 65 using namespace mozilla; 66 using namespace mozilla::css; 67 using namespace mozilla::dom; 68 69 namespace mozilla::dom { 70 71 static nsPresContext* EnsureSafeToHandOutRules(Element& aElement) { 72 Document* doc = aElement.GetComposedDoc(); 73 if (!doc) { 74 return nullptr; 75 } 76 const PresShell* presShell = doc->GetPresShell(); 77 if (!presShell) { 78 return nullptr; 79 } 80 nsPresContext* presContext = presShell->GetPresContext(); 81 if (!presContext) { 82 return nullptr; 83 } 84 presContext->EnsureSafeToHandOutCSSRules(); 85 return presContext; 86 } 87 88 static already_AddRefed<const ComputedStyle> GetStartingStyle( 89 Element& aElement, const PseudoStyleRequest& aPseudo) { 90 Element* elementOrPseudoElement = aElement.GetPseudoElement(aPseudo); 91 if (!elementOrPseudoElement) { 92 // For the pseudo elements which doesn't support animations or transitions, 93 // this returns nullptr. This is probably fine because @starting-style 94 // doesn't work on these pseudo elements neither. 95 // 96 // FIXME: If we still want to retrieve the @starting-style rules for those 97 // pseudo-elements which don't support animations, we may have to rework 98 // Servo_ResolveStartingStyle() because now @starting-style doesn't work on 99 // eagerly-cascaded pseudo-elements, and the above function, 100 // GetPseudoElement(), only works on the pseudo-elements which support 101 // animations. 102 return nullptr; 103 } 104 // If this element is unstyled, or it doesn't have matched rules in 105 // @starting-style, we return. 106 if (!Servo_Element_MayHaveStartingStyle(elementOrPseudoElement)) { 107 return nullptr; 108 } 109 if (!EnsureSafeToHandOutRules(aElement)) { 110 return nullptr; 111 } 112 RefPtr<Document> doc = aElement.GetComposedDoc(); 113 if (!doc) { 114 return nullptr; 115 } 116 doc->FlushPendingNotifications(FlushType::Style); 117 RefPtr<PresShell> ps = doc->GetPresShell(); 118 if (!ps) { 119 return nullptr; 120 } 121 return ps->StyleSet()->ResolveStartingStyle(*elementOrPseudoElement); 122 } 123 124 static already_AddRefed<const ComputedStyle> GetCleanComputedStyleForElement( 125 dom::Element* aElement, const PseudoStyleRequest& aPseudo) { 126 MOZ_ASSERT(aElement); 127 nsPresContext* pc = EnsureSafeToHandOutRules(*aElement); 128 if (!pc) { 129 return nullptr; 130 } 131 return nsComputedDOMStyle::GetComputedStyle(aElement, aPseudo); 132 } 133 134 /* static */ 135 void InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject, 136 Document& aDocument, bool aDocumentOnly, 137 nsTArray<RefPtr<StyleSheet>>& aResult) { 138 // Get the agent, then user and finally xbl sheets in the style set. 139 PresShell* presShell = aDocument.GetPresShell(); 140 nsTHashSet<StyleSheet*> sheetSet; 141 142 if (presShell) { 143 ServoStyleSet* styleSet = presShell->StyleSet(); 144 145 if (!aDocumentOnly) { 146 const StyleOrigin kOrigins[] = {StyleOrigin::UserAgent, 147 StyleOrigin::User}; 148 for (const auto origin : kOrigins) { 149 for (size_t i = 0, count = styleSet->SheetCount(origin); i < count; 150 i++) { 151 aResult.AppendElement(styleSet->SheetAt(origin, i)); 152 } 153 } 154 } 155 156 AutoTArray<StyleSheet*, 32> nonDocumentSheets; 157 styleSet->AppendAllNonDocumentAuthorSheets(nonDocumentSheets); 158 159 // The non-document stylesheet array can have duplicates due to adopted 160 // stylesheets. 161 nsTHashSet<StyleSheet*> sheetSet; 162 for (StyleSheet* sheet : nonDocumentSheets) { 163 if (sheetSet.EnsureInserted(sheet)) { 164 aResult.AppendElement(sheet); 165 } 166 } 167 } 168 169 // Get the document sheets. 170 for (size_t i = 0; i < aDocument.SheetCount(); i++) { 171 aResult.AppendElement(aDocument.SheetAt(i)); 172 } 173 174 for (auto& sheet : aDocument.AdoptedStyleSheets()) { 175 if (sheetSet.EnsureInserted(sheet)) { 176 aResult.AppendElement(sheet); 177 } 178 } 179 } 180 181 bool InspectorUtils::IsIgnorableWhitespace(CharacterData& aDataNode) { 182 if (!aDataNode.TextIsOnlyWhitespace()) { 183 return false; 184 } 185 186 // Okay. We have only white space. Let's check the white-space 187 // property now and make sure that this isn't preformatted text... 188 if (nsIFrame* frame = aDataNode.GetPrimaryFrame()) { 189 return !frame->StyleText()->WhiteSpaceIsSignificant(); 190 } 191 192 // empty inter-tag text node without frame, e.g., in between <table>\n<tr> 193 return true; 194 } 195 196 /* static */ 197 nsINode* InspectorUtils::GetParentForNode(nsINode& aNode, 198 bool aShowingAnonymousContent) { 199 if (nsINode* parent = aNode.GetParentNode()) { 200 return parent; 201 } 202 if (aNode.IsDocument()) { 203 return inLayoutUtils::GetContainerFor(*aNode.AsDocument()); 204 } 205 if (aShowingAnonymousContent) { 206 if (auto* frag = DocumentFragment::FromNode(aNode)) { 207 // This deals with shadow roots and HTMLTemplateElement.content. 208 return frag->GetHost(); 209 } 210 } 211 return nullptr; 212 } 213 214 /* static */ 215 void InspectorUtils::GetChildrenForNode(nsINode& aNode, 216 bool aShowingAnonymousContent, 217 bool aIncludeAssignedNodes, 218 bool aIncludeSubdocuments, 219 nsTArray<RefPtr<nsINode>>& aResult) { 220 if (aIncludeSubdocuments) { 221 if (auto* doc = inLayoutUtils::GetSubDocumentFor(&aNode)) { 222 aResult.AppendElement(doc); 223 // XXX Do we really want to early-return? 224 return; 225 } 226 } 227 228 if (!aShowingAnonymousContent || !aNode.IsContent()) { 229 for (nsINode* child = aNode.GetFirstChild(); child; 230 child = child->GetNextSibling()) { 231 aResult.AppendElement(child); 232 } 233 return; 234 } 235 236 if (auto* tmpl = HTMLTemplateElement::FromNode(aNode)) { 237 aResult.AppendElement(tmpl->Content()); 238 // XXX Do we really want to early-return? 239 return; 240 } 241 242 if (auto* element = Element::FromNode(aNode)) { 243 if (auto* shadow = element->GetShadowRoot()) { 244 aResult.AppendElement(shadow); 245 } 246 } 247 nsIContent* parent = aNode.AsContent(); 248 if (auto* node = nsLayoutUtils::GetBackdropPseudo(parent)) { 249 aResult.AppendElement(node); 250 } 251 if (auto* node = nsLayoutUtils::GetMarkerPseudo(parent)) { 252 aResult.AppendElement(node); 253 } 254 if (auto* node = nsLayoutUtils::GetBeforePseudo(parent)) { 255 aResult.AppendElement(node); 256 } 257 if (aIncludeAssignedNodes) { 258 if (auto* slot = HTMLSlotElement::FromNode(aNode)) { 259 for (nsINode* node : slot->AssignedNodes()) { 260 aResult.AppendElement(node); 261 } 262 } 263 } 264 for (nsIContent* node = parent->GetFirstChild(); node; 265 node = node->GetNextSibling()) { 266 aResult.AppendElement(node); 267 } 268 AutoTArray<nsIContent*, 4> anonKids; 269 nsContentUtils::AppendNativeAnonymousChildren(parent, anonKids, 270 nsIContent::eAllChildren); 271 for (nsIContent* node : anonKids) { 272 aResult.AppendElement(node); 273 } 274 if (auto* node = nsLayoutUtils::GetAfterPseudo(parent)) { 275 aResult.AppendElement(node); 276 } 277 } 278 279 class ReadOnlyInspectorDeclaration final : public nsDOMCSSDeclaration { 280 public: 281 NS_DECL_CYCLE_COLLECTING_ISUPPORTS 282 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ReadOnlyInspectorDeclaration) 283 284 explicit ReadOnlyInspectorDeclaration(const StyleLockedDeclarationBlock* aRaw) 285 : mRaw(aRaw) {} 286 287 nsINode* GetAssociatedNode() const final { return nullptr; } 288 nsISupports* GetParentObject() const final { return nullptr; } 289 void GetPropertyValue(const nsACString& aPropName, nsACString& aValue) final { 290 Servo_DeclarationBlock_GetPropertyValue(mRaw, &aPropName, &aValue); 291 } 292 void GetPropertyValue(NonCustomCSSPropertyId aId, nsACString& aValue) final { 293 Servo_DeclarationBlock_GetPropertyValueByNonCustomId(mRaw, aId, &aValue); 294 } 295 bool HasLonghandProperty(const nsACString& aPropName) final { 296 return Servo_DeclarationBlock_HasLonghandProperty(mRaw, &aPropName); 297 } 298 void IndexedGetter(uint32_t aIndex, bool& aFound, 299 nsACString& aPropName) final { 300 aFound = Servo_DeclarationBlock_GetNthProperty(mRaw, aIndex, &aPropName); 301 } 302 void RemoveProperty(const nsACString& aPropertyName, nsACString& aValue, 303 ErrorResult& aRv) final { 304 aRv.ThrowInvalidModificationError("Can't mutate this declaration"); 305 } 306 void SetProperty(const nsACString& aPropertyName, const nsACString& aValue, 307 const nsACString& aPriority, nsIPrincipal* aSubjectPrincipal, 308 ErrorResult& aRv) final { 309 aRv.ThrowInvalidModificationError("Can't mutate this declaration"); 310 } 311 void SetPropertyValue(NonCustomCSSPropertyId aId, const nsACString& aValue, 312 nsIPrincipal* aSubjectPrincipal, 313 ErrorResult& aRv) final { 314 aRv.ThrowInvalidModificationError("Can't mutate this declaration"); 315 } 316 void SetCssText(const nsACString& aString, nsIPrincipal* aSubjectPrincipal, 317 ErrorResult& aRv) final { 318 aRv.ThrowInvalidModificationError("Can't mutate this declaration"); 319 } 320 void GetCssText(nsACString& aString) final { 321 Servo_DeclarationBlock_GetCssText(mRaw, &aString); 322 } 323 uint32_t Length() final { return Servo_DeclarationBlock_Count(mRaw); } 324 void GetPropertyPriority(const nsACString& aPropName, 325 nsACString& aPriority) final { 326 if (Servo_DeclarationBlock_GetPropertyIsImportant(mRaw, &aPropName)) { 327 aPriority.AssignLiteral("important"); 328 } 329 } 330 css::Rule* GetParentRule() final { return nullptr; } 331 JSObject* WrapObject(JSContext* aCx, 332 JS::Handle<JSObject*> aGivenProto) final { 333 return CSSStyleProperties_Binding::Wrap(aCx, this, aGivenProto); 334 } 335 // These ones are a bit sad, but matches e.g. nsComputedDOMStyle. 336 nsresult SetCSSDeclaration(DeclarationBlock* aDecl, 337 MutationClosureData*) final { 338 MOZ_CRASH("called ReadOnlyInspectorDeclaration::SetCSSDeclaration"); 339 } 340 DeclarationBlock* GetOrCreateCSSDeclaration(Operation, 341 DeclarationBlock**) override { 342 MOZ_CRASH("called ReadOnlyInspectorDeclaration::GetOrCreateCSSDeclaration"); 343 } 344 ParsingEnvironment GetParsingEnvironment(nsIPrincipal*) const final { 345 MOZ_CRASH("called ReadOnlyInspectorDeclaration::GetParsingEnvironment"); 346 } 347 348 private: 349 ~ReadOnlyInspectorDeclaration() = default; 350 351 RefPtr<const StyleLockedDeclarationBlock> mRaw; 352 }; 353 354 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadOnlyInspectorDeclaration) 355 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 356 NS_INTERFACE_MAP_ENTRY(nsICSSDeclaration) 357 NS_INTERFACE_MAP_ENTRY(nsISupports) 358 NS_INTERFACE_MAP_END 359 360 NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadOnlyInspectorDeclaration) 361 NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadOnlyInspectorDeclaration) 362 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(ReadOnlyInspectorDeclaration) 363 364 static void GetCSSRulesFromComputedValues( 365 Element& aElement, const ComputedStyle* aComputedStyle, 366 nsTArray<OwningCSSRuleOrInspectorDeclaration>& aResult) { 367 const PresShell* presShell = aElement.OwnerDoc()->GetPresShell(); 368 if (!presShell) { 369 return; 370 } 371 372 AutoTArray<StyleMatchingDeclarationBlock, 8> rawDecls; 373 Servo_ComputedValues_GetMatchingDeclarations(aComputedStyle, &rawDecls); 374 375 AutoTArray<ServoStyleRuleMap*, 8> maps; 376 { 377 ServoStyleSet* styleSet = presShell->StyleSet(); 378 ServoStyleRuleMap* map = styleSet->StyleRuleMap(); 379 maps.AppendElement(map); 380 } 381 382 // Now shadow DOM stuff... 383 if (auto* shadow = aElement.GetShadowRoot()) { 384 maps.AppendElement(&shadow->ServoStyleRuleMap()); 385 } 386 387 // Now NAC: 388 for (auto* el = aElement.GetClosestNativeAnonymousSubtreeRootParentOrHost(); 389 el; el = el->GetClosestNativeAnonymousSubtreeRootParentOrHost()) { 390 if (auto* shadow = el->GetShadowRoot()) { 391 maps.AppendElement(&shadow->ServoStyleRuleMap()); 392 } 393 } 394 395 for (auto* shadow = aElement.GetContainingShadow(); shadow; 396 shadow = shadow->Host()->GetContainingShadow()) { 397 maps.AppendElement(&shadow->ServoStyleRuleMap()); 398 } 399 400 // Rules from the assigned slot. 401 for (auto* slot = aElement.GetAssignedSlot(); slot; 402 slot = slot->GetAssignedSlot()) { 403 if (auto* shadow = slot->GetContainingShadow()) { 404 maps.AppendElement(&shadow->ServoStyleRuleMap()); 405 } 406 } 407 408 // Find matching rules in the table. 409 for (const StyleMatchingDeclarationBlock& block : Reversed(rawDecls)) { 410 bool found = false; 411 for (ServoStyleRuleMap* map : maps) { 412 if (css::Rule* rule = map->Lookup(block.block)) { 413 aResult.AppendElement()->SetAsCSSRule() = rule; 414 found = true; 415 break; 416 } 417 } 418 if (!found) { 419 auto& declaration = aResult.AppendElement()->SetAsInspectorDeclaration(); 420 declaration.mStyle = OwningNonNull<ReadOnlyInspectorDeclaration>( 421 *new ReadOnlyInspectorDeclaration(block.block)); 422 declaration.mDeclarationOrigin = [&] { 423 switch (block.origin) { 424 case StyleMatchingDeclarationBlockOrigin::Author: 425 return DeclarationOrigin::Style_attribute; 426 case StyleMatchingDeclarationBlockOrigin::User: 427 MOZ_ASSERT_UNREACHABLE( 428 "Where did this user agent declaration come from?"); 429 return DeclarationOrigin::User; 430 case StyleMatchingDeclarationBlockOrigin::UserAgent: 431 return DeclarationOrigin::User_agent; 432 case StyleMatchingDeclarationBlockOrigin::PositionFallback: 433 return DeclarationOrigin::Position_fallback; 434 case StyleMatchingDeclarationBlockOrigin::Animations: 435 return DeclarationOrigin::Animations; 436 case StyleMatchingDeclarationBlockOrigin::Transitions: 437 return DeclarationOrigin::Transitions; 438 case StyleMatchingDeclarationBlockOrigin::SMIL: 439 return DeclarationOrigin::Smil; 440 case StyleMatchingDeclarationBlockOrigin::PresHints: 441 return DeclarationOrigin::Pres_hints; 442 } 443 MOZ_ASSERT_UNREACHABLE("Unkown origin?"); 444 return DeclarationOrigin::Pres_hints; 445 }(); 446 } 447 } 448 } 449 450 /* static */ 451 void InspectorUtils::GetMatchingCSSRules( 452 GlobalObject& aGlobalObject, Element& aElement, const nsAString& aPseudo, 453 bool aIncludeVisitedStyle, bool aWithStartingStyle, 454 nsTArray<OwningCSSRuleOrInspectorDeclaration>& aResult) { 455 auto pseudo = nsCSSPseudoElements::ParsePseudoElement( 456 aPseudo, CSSEnabledState::ForAllContent); 457 if (!pseudo) { 458 return; 459 } 460 461 RefPtr<const ComputedStyle> computedStyle; 462 if (aWithStartingStyle) { 463 computedStyle = GetStartingStyle(aElement, *pseudo); 464 } 465 466 // Note: GetStartingStyle() return nullptr if this element doesn't have rules 467 // inside @starting-style, or the pseudo-element doesn't support animations or 468 // transitions. For this case, we would like to return the primay rules of 469 // this element. 470 if (!computedStyle) { 471 computedStyle = GetCleanComputedStyleForElement(&aElement, *pseudo); 472 } 473 474 if (!computedStyle) { 475 // This can fail for elements that are not in the document or 476 // if the document they're in doesn't have a presshell. Bail out. 477 return; 478 } 479 480 if (aIncludeVisitedStyle) { 481 if (const auto* styleIfVisited = computedStyle->GetStyleIfVisited()) { 482 computedStyle = styleIfVisited; 483 } 484 } 485 486 GetCSSRulesFromComputedValues(aElement, computedStyle, aResult); 487 } 488 489 /* static */ 490 uint32_t InspectorUtils::GetRuleLine(GlobalObject& aGlobal, css::Rule& aRule) { 491 uint32_t line = aRule.GetLineNumber(); 492 if (StyleSheet* sheet = aRule.GetStyleSheet()) { 493 if (auto* link = LinkStyle::FromNodeOrNull(sheet->GetOwnerNode())) { 494 line += link->GetLineNumber(); 495 } 496 } 497 return line; 498 } 499 500 /* static */ 501 uint32_t InspectorUtils::GetRuleColumn(GlobalObject& aGlobal, 502 css::Rule& aRule) { 503 return aRule.GetColumnNumber(); 504 } 505 506 /* static */ 507 uint32_t InspectorUtils::GetRelativeRuleLine(GlobalObject& aGlobal, 508 css::Rule& aRule) { 509 // Rule lines are 0-based, but inspector wants 1-based. 510 return aRule.GetLineNumber() + 1; 511 } 512 513 void InspectorUtils::GetRuleIndex(GlobalObject& aGlobal, css::Rule& aRule, 514 nsTArray<uint32_t>& aResult) { 515 css::Rule* currentRule = &aRule; 516 517 do { 518 css::Rule* parentRule = currentRule->GetParentRule(); 519 dom::CSSRuleList* ruleList = nullptr; 520 521 if (parentRule) { 522 if (parentRule->IsGroupRule()) { 523 ruleList = static_cast<css::GroupRule*>(parentRule)->CssRules(); 524 } else if (parentRule->Type() == StyleCssRuleType::Keyframes) { 525 ruleList = static_cast<CSSKeyframesRule*>(parentRule)->CssRules(); 526 } else { 527 MOZ_ASSERT_UNREACHABLE("Unknown parent rule type?"); 528 } 529 } else if (StyleSheet* sheet = currentRule->GetStyleSheet()) { 530 ruleList = sheet->GetCssRulesInternal(); 531 } 532 533 if (!ruleList) { 534 return; 535 } 536 537 bool found = false; 538 for (uint32_t i = 0, len = ruleList->Length(); i < len; ++i) { 539 css::Rule* rule = ruleList->Item(i); 540 if (currentRule == rule) { 541 found = true; 542 aResult.InsertElementAt(0, i); 543 break; 544 } 545 } 546 547 if (!found) { 548 return; 549 } 550 551 currentRule = parentRule; 552 } while (currentRule); 553 } 554 555 /* static */ 556 bool InspectorUtils::HasRulesModifiedByCSSOM(GlobalObject& aGlobal, 557 StyleSheet& aSheet) { 558 return aSheet.HasModifiedRulesForDevtools(); 559 } 560 561 static uint32_t CollectAtRules(ServoCSSRuleList& aRuleList, 562 Sequence<OwningNonNull<css::Rule>>& aResult) { 563 uint32_t len = aRuleList.Length(); 564 uint32_t ruleCount = len; 565 for (uint32_t i = 0; i < len; ++i) { 566 css::Rule* rule = aRuleList.GetRule(i); 567 // This collect rules we want to display in Devtools Style Editor toolbar. 568 // When adding a new StyleCssRuleType, put it in the "default" list, and 569 // file a new bug with 570 // https://bugzilla.mozilla.org/enter_bug.cgi?product=DevTools&component=Style%20Editor&short_desc=Consider%20displaying%20new%20XXX%20rule%20type%20in%20at-rules%20sidebar 571 // so the DevTools team gets notified and can decide if it should be 572 // displayed. 573 switch (rule->Type()) { 574 case StyleCssRuleType::CustomMedia: 575 case StyleCssRuleType::Media: 576 case StyleCssRuleType::Supports: 577 case StyleCssRuleType::LayerBlock: 578 case StyleCssRuleType::PositionTry: 579 case StyleCssRuleType::Property: 580 case StyleCssRuleType::Container: { 581 (void)aResult.AppendElement(OwningNonNull(*rule), fallible); 582 break; 583 } 584 case StyleCssRuleType::Style: 585 case StyleCssRuleType::Import: 586 case StyleCssRuleType::Document: 587 case StyleCssRuleType::LayerStatement: 588 case StyleCssRuleType::FontFace: 589 case StyleCssRuleType::Page: 590 case StyleCssRuleType::Keyframes: 591 case StyleCssRuleType::Keyframe: 592 case StyleCssRuleType::Margin: 593 case StyleCssRuleType::Namespace: 594 case StyleCssRuleType::CounterStyle: 595 case StyleCssRuleType::FontFeatureValues: 596 case StyleCssRuleType::FontPaletteValues: 597 case StyleCssRuleType::Scope: 598 case StyleCssRuleType::StartingStyle: 599 case StyleCssRuleType::NestedDeclarations: 600 break; 601 } 602 603 if (rule->IsGroupRule()) { 604 ruleCount += CollectAtRules( 605 *static_cast<css::GroupRule*>(rule)->CssRules(), aResult); 606 } 607 } 608 return ruleCount; 609 } 610 611 void InspectorUtils::GetStyleSheetRuleCountAndAtRules( 612 GlobalObject& aGlobal, StyleSheet& aSheet, 613 InspectorStyleSheetRuleCountAndAtRulesResult& aResult) { 614 aResult.mRuleCount = 615 CollectAtRules(*aSheet.GetCssRulesInternal(), aResult.mAtRules); 616 } 617 618 /* static */ 619 bool InspectorUtils::IsInheritedProperty(GlobalObject& aGlobalObject, 620 Document& aDocument, 621 const nsACString& aPropertyName) { 622 return Servo_Property_IsInherited(aDocument.EnsureStyleSet().RawData(), 623 &aPropertyName); 624 } 625 626 /* static */ 627 void InspectorUtils::GetCSSPropertyNames(GlobalObject& aGlobalObject, 628 const PropertyNamesOptions& aOptions, 629 nsTArray<nsString>& aResult) { 630 CSSEnabledState enabledState = aOptions.mIncludeExperimentals 631 ? CSSEnabledState::IgnoreEnabledState 632 : CSSEnabledState::ForAllContent; 633 634 auto appendProperty = [enabledState, &aResult](uint32_t prop) { 635 NonCustomCSSPropertyId cssProp = NonCustomCSSPropertyId(prop); 636 if (nsCSSProps::IsEnabled(cssProp, enabledState)) { 637 aResult.AppendElement( 638 NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(cssProp))); 639 } 640 }; 641 642 uint32_t prop = 0; 643 for (; prop < eCSSProperty_COUNT_no_shorthands; ++prop) { 644 if (!nsCSSProps::PropHasFlags(NonCustomCSSPropertyId(prop), 645 CSSPropFlags::Inaccessible)) { 646 appendProperty(prop); 647 } 648 } 649 650 if (aOptions.mIncludeShorthands) { 651 for (; prop < eCSSProperty_COUNT; ++prop) { 652 appendProperty(prop); 653 } 654 } 655 656 if (aOptions.mIncludeAliases) { 657 for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; 658 ++prop) { 659 appendProperty(prop); 660 } 661 } 662 } 663 664 /* static */ 665 void InspectorUtils::GetCSSPropertyPrefs(GlobalObject& aGlobalObject, 666 nsTArray<PropertyPref>& aResult) { 667 for (const auto* src = nsCSSProps::kPropertyPrefTable; 668 src->mPropId != eCSSProperty_UNKNOWN; src++) { 669 PropertyPref& dest = *aResult.AppendElement(); 670 dest.mName.Assign( 671 NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(src->mPropId))); 672 dest.mPref.AssignASCII(src->mPref); 673 } 674 } 675 676 /* static */ 677 void InspectorUtils::GetSubpropertiesForCSSProperty(GlobalObject& aGlobal, 678 const nsACString& aProperty, 679 nsTArray<nsString>& aResult, 680 ErrorResult& aRv) { 681 NonCustomCSSPropertyId propertyId = nsCSSProps::LookupProperty(aProperty); 682 683 if (propertyId == eCSSProperty_UNKNOWN) { 684 aRv.Throw(NS_ERROR_FAILURE); 685 return; 686 } 687 688 if (propertyId == eCSSPropertyExtra_variable) { 689 aResult.AppendElement(NS_ConvertUTF8toUTF16(aProperty)); 690 return; 691 } 692 693 if (!nsCSSProps::IsShorthand(propertyId)) { 694 nsString* name = aResult.AppendElement(); 695 CopyASCIItoUTF16(nsCSSProps::GetStringValue(propertyId), *name); 696 return; 697 } 698 699 for (const NonCustomCSSPropertyId* props = 700 nsCSSProps::SubpropertyEntryFor(propertyId); 701 *props != eCSSProperty_UNKNOWN; ++props) { 702 nsString* name = aResult.AppendElement(); 703 CopyASCIItoUTF16(nsCSSProps::GetStringValue(*props), *name); 704 } 705 } 706 707 /* static */ 708 bool InspectorUtils::CssPropertyIsShorthand(GlobalObject& aGlobalObject, 709 const nsACString& aProperty, 710 ErrorResult& aRv) { 711 bool found; 712 bool isShorthand = Servo_Property_IsShorthand(&aProperty, &found); 713 if (!found) { 714 aRv.Throw(NS_ERROR_FAILURE); 715 } 716 return isShorthand; 717 } 718 719 // This should match the constants in specified_value_info.rs 720 // 721 // Once we can use bitflags in consts, we can also cbindgen that and use them 722 // here instead. 723 static uint8_t ToServoCssType(InspectorPropertyType aType) { 724 switch (aType) { 725 case InspectorPropertyType::Color: 726 return 1; 727 case InspectorPropertyType::Gradient: 728 return 1 << 1; 729 case InspectorPropertyType::Timing_function: 730 return 1 << 2; 731 default: 732 MOZ_ASSERT_UNREACHABLE("Unknown property type?"); 733 return 0; 734 } 735 } 736 737 bool InspectorUtils::Supports(GlobalObject&, const nsACString& aDeclaration, 738 const SupportsOptions& aOptions) { 739 return Servo_CSSSupports(&aDeclaration, aOptions.mUserAgent, aOptions.mChrome, 740 aOptions.mQuirks); 741 } 742 743 bool InspectorUtils::CssPropertySupportsType(GlobalObject& aGlobalObject, 744 const nsACString& aProperty, 745 InspectorPropertyType aType, 746 ErrorResult& aRv) { 747 bool found; 748 bool result = 749 Servo_Property_SupportsType(&aProperty, ToServoCssType(aType), &found); 750 if (!found) { 751 aRv.Throw(NS_ERROR_FAILURE); 752 return false; 753 } 754 return result; 755 } 756 757 /* static */ 758 void InspectorUtils::GetCSSValuesForProperty(GlobalObject& aGlobalObject, 759 const nsACString& aProperty, 760 nsTArray<nsString>& aResult, 761 ErrorResult& aRv) { 762 bool found; 763 Servo_Property_GetCSSValuesForProperty(&aProperty, &found, &aResult); 764 if (!found) { 765 aRv.Throw(NS_ERROR_FAILURE); 766 } 767 } 768 769 /* static */ 770 void InspectorUtils::RgbToColorName(GlobalObject&, uint8_t aR, uint8_t aG, 771 uint8_t aB, nsACString& aColorName) { 772 Servo_SlowRgbToColorName(aR, aG, aB, &aColorName); 773 } 774 775 void InspectorUtils::RgbToNearestColorName(GlobalObject&, float aR, float aG, 776 float aB, 777 InspectorNearestColor& aResult) { 778 bool exact = Servo_SlowRgbToNearestColorName( 779 aR, aG, aB, StyleColorSpace::Srgb, &aResult.mColorName); 780 aResult.mExact = exact; 781 } 782 783 /* static */ 784 void InspectorUtils::RgbToHsv(GlobalObject&, float aR, float aG, float aB, 785 nsTArray<float>& aResult) { 786 StyleAbsoluteColor input{ 787 .components = StyleColorComponents{aR, aG, aB}, 788 .alpha = 1.0, 789 .color_space = StyleColorSpace::Srgb, 790 }; 791 StyleAbsoluteColor result = input.ToColorSpace(StyleColorSpace::Hwb); 792 float h = result.components._0 / 360.0f; 793 float v = 1 - result.components._2 / 100.0f; 794 float s = 0; 795 if (v != 0.0) { 796 s = 1 - (result.components._1 / 100.0f) / v; 797 } 798 aResult = {h, s, v}; 799 } 800 801 /* static */ 802 void InspectorUtils::HsvToRgb(GlobalObject&, float aH, float aS, float aV, 803 nsTArray<float>& aResult) { 804 float h = aH * 360; 805 float w = aV * (1 - aS) * 100; 806 float b = (1 - aV) * 100; 807 StyleAbsoluteColor input{ 808 .components = StyleColorComponents{h, w, b}, 809 .alpha = 1.0, 810 .color_space = StyleColorSpace::Hwb, 811 }; 812 StyleAbsoluteColor result = input.ToColorSpace(StyleColorSpace::Srgb); 813 aResult = {result.components._0, result.components._1, result.components._2}; 814 } 815 816 /* static */ 817 float InspectorUtils::RelativeLuminance(GlobalObject&, float aR, float aG, 818 float aB) { 819 return RelativeLuminanceUtils::Compute(aR, aG, aB); 820 } 821 822 /* static */ 823 void InspectorUtils::ColorToRGBA(GlobalObject& aGlobal, 824 const nsACString& aColorString, 825 Nullable<InspectorRGBATuple>& aResult) { 826 const auto* styleData = [&]() -> const StylePerDocumentStyleData* { 827 nsCOMPtr<nsIGlobalObject> global = 828 do_QueryInterface(aGlobal.GetAsSupports()); 829 if (!global) { 830 return nullptr; 831 } 832 auto* win = global->GetAsInnerWindow(); 833 if (!win) { 834 return nullptr; 835 } 836 Document* doc = win->GetExtantDoc(); 837 if (!doc) { 838 return nullptr; 839 } 840 PresShell* ps = doc->GetPresShell(); 841 if (!ps) { 842 return nullptr; 843 } 844 return ps->StyleSet()->RawData(); 845 }(); 846 847 nscolor color = NS_RGB(0, 0, 0); 848 if (!ServoCSSParser::ComputeColor(styleData, NS_RGB(0, 0, 0), aColorString, 849 &color)) { 850 aResult.SetNull(); 851 return; 852 } 853 854 InspectorRGBATuple& tuple = aResult.SetValue(); 855 tuple.mR = NS_GET_R(color); 856 tuple.mG = NS_GET_G(color); 857 tuple.mB = NS_GET_B(color); 858 tuple.mA = nsStyleUtil::ColorComponentToFloat(NS_GET_A(color)); 859 } 860 861 /* static */ 862 void InspectorUtils::ColorTo(GlobalObject&, const nsACString& aFromColor, 863 const nsACString& aToColorSpace, 864 Nullable<InspectorColorToResult>& aResult) { 865 nsCString resultColor; 866 nsTArray<float> resultComponents; 867 bool resultAdjusted = false; 868 869 if (!ServoCSSParser::ColorTo(aFromColor, aToColorSpace, &resultColor, 870 &resultComponents, &resultAdjusted)) { 871 aResult.SetNull(); 872 return; 873 } 874 875 auto& result = aResult.SetValue(); 876 result.mColor.AssignASCII(resultColor); 877 result.mComponents = std::move(resultComponents); 878 result.mAdjusted = resultAdjusted; 879 } 880 881 /* static */ 882 bool InspectorUtils::IsValidCSSColor(GlobalObject& aGlobalObject, 883 const nsACString& aColorString) { 884 return ServoCSSParser::IsValidCSSColor(aColorString); 885 } 886 887 /* static */ 888 bool InspectorUtils::SetContentState(GlobalObject& aGlobalObject, 889 Element& aElement, uint64_t aState, 890 ErrorResult& aRv) { 891 RefPtr<EventStateManager> esm = 892 inLayoutUtils::GetEventStateManagerFor(aElement); 893 ElementState state(aState); 894 if (!esm || !EventStateManager::ManagesState(state)) { 895 aRv.Throw(NS_ERROR_INVALID_ARG); 896 return false; 897 } 898 return esm->SetContentState(&aElement, state); 899 } 900 901 /* static */ 902 bool InspectorUtils::RemoveContentState(GlobalObject& aGlobalObject, 903 Element& aElement, uint64_t aState, 904 bool aClearActiveDocument, 905 ErrorResult& aRv) { 906 RefPtr<EventStateManager> esm = 907 inLayoutUtils::GetEventStateManagerFor(aElement); 908 ElementState state(aState); 909 if (!esm || !EventStateManager::ManagesState(state)) { 910 aRv.Throw(NS_ERROR_INVALID_ARG); 911 return false; 912 } 913 914 bool result = esm->SetContentState(nullptr, state); 915 916 if (aClearActiveDocument && state == ElementState::ACTIVE) { 917 EventStateManager* activeESM = static_cast<EventStateManager*>( 918 EventStateManager::GetActiveEventStateManager()); 919 if (activeESM == esm) { 920 EventStateManager::ClearGlobalActiveContent(nullptr); 921 } 922 } 923 924 return result; 925 } 926 927 /* static */ 928 uint64_t InspectorUtils::GetContentState(GlobalObject& aGlobalObject, 929 Element& aElement) { 930 // NOTE: if this method is removed, 931 // please remove GetInternalValue from ElementState 932 return aElement.State().GetInternalValue(); 933 } 934 935 /* static */ 936 void InspectorUtils::GetUsedFontFaces(GlobalObject& aGlobalObject, 937 nsRange& aRange, uint32_t aMaxRanges, 938 bool aSkipCollapsedWhitespace, 939 nsLayoutUtils::UsedFontFaceList& aResult, 940 ErrorResult& aRv) { 941 nsresult rv = 942 aRange.GetUsedFontFaces(aResult, aMaxRanges, aSkipCollapsedWhitespace); 943 944 if (NS_FAILED(rv)) { 945 aRv.Throw(rv); 946 } 947 } 948 949 static ElementState GetStatesForPseudoClass(const nsAString& aStatePseudo) { 950 if (aStatePseudo.IsEmpty() || aStatePseudo[0] != u':') { 951 return ElementState(); 952 } 953 NS_ConvertUTF16toUTF8 statePseudo(Substring(aStatePseudo, 1)); 954 return ElementState(Servo_PseudoClass_GetStates(&statePseudo)); 955 } 956 957 /* static */ 958 void InspectorUtils::GetCSSPseudoElementNames(GlobalObject& aGlobalObject, 959 nsTArray<nsString>& aResult) { 960 const auto kPseudoCount = 961 static_cast<size_t>(PseudoStyleType::CSSPseudoElementsEnd); 962 for (size_t i = 0; i < kPseudoCount; ++i) { 963 PseudoStyleType type = static_cast<PseudoStyleType>(i); 964 if (!nsCSSPseudoElements::IsEnabled(type, CSSEnabledState::ForAllContent)) { 965 continue; 966 } 967 auto& string = *aResult.AppendElement(); 968 // Use two semi-colons (though internally we use one). 969 string.Append(u':'); 970 nsAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type); 971 string.Append(nsDependentAtomString(atom)); 972 } 973 } 974 975 /* static */ 976 void InspectorUtils::AddPseudoClassLock(GlobalObject& aGlobalObject, 977 Element& aElement, 978 const nsAString& aPseudoClass, 979 bool aEnabled) { 980 ElementState state = GetStatesForPseudoClass(aPseudoClass); 981 if (state.IsEmpty()) { 982 return; 983 } 984 985 aElement.LockStyleStates(state, aEnabled); 986 } 987 988 /* static */ 989 void InspectorUtils::RemovePseudoClassLock(GlobalObject& aGlobal, 990 Element& aElement, 991 const nsAString& aPseudoClass) { 992 ElementState state = GetStatesForPseudoClass(aPseudoClass); 993 if (state.IsEmpty()) { 994 return; 995 } 996 997 aElement.UnlockStyleStates(state); 998 } 999 1000 /* static */ 1001 bool InspectorUtils::HasPseudoClassLock(GlobalObject& aGlobalObject, 1002 Element& aElement, 1003 const nsAString& aPseudoClass) { 1004 ElementState state = GetStatesForPseudoClass(aPseudoClass); 1005 if (state.IsEmpty()) { 1006 return false; 1007 } 1008 1009 ElementState locks = aElement.LockedStyleStates().mLocks; 1010 return locks.HasAllStates(state); 1011 } 1012 1013 /* static */ 1014 void InspectorUtils::ClearPseudoClassLocks(GlobalObject& aGlobalObject, 1015 Element& aElement) { 1016 aElement.ClearStyleStateLocks(); 1017 } 1018 1019 /* static */ 1020 void InspectorUtils::ParseStyleSheet(GlobalObject& aGlobalObject, 1021 StyleSheet& aSheet, 1022 const nsACString& aInput, 1023 ErrorResult& aRv) { 1024 aSheet.ReparseSheet(aInput, aRv); 1025 } 1026 1027 bool InspectorUtils::IsCustomElementName(GlobalObject&, const nsAString& aName, 1028 const nsAString& aNamespaceURI) { 1029 if (aName.IsEmpty()) { 1030 return false; 1031 } 1032 1033 int32_t namespaceID; 1034 nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI, 1035 namespaceID); 1036 1037 RefPtr<nsAtom> nameElt = NS_Atomize(aName); 1038 return nsContentUtils::IsCustomElementName(nameElt, namespaceID); 1039 } 1040 1041 bool InspectorUtils::IsElementThemed(GlobalObject&, Element& aElement) { 1042 // IsThemed will check if the native theme supports the widget using 1043 // ThemeSupportsWidget which in turn will check that the widget is not 1044 // already styled by content through nsNativeTheme::IsWidgetStyled. We 1045 // assume that if the native theme styles the widget and the author did not 1046 // override the appropriate styles, the theme will provide focus styling. 1047 nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames); 1048 return frame && frame->IsThemed(); 1049 } 1050 1051 bool InspectorUtils::IsUsedColorSchemeDark(GlobalObject&, Element& aElement) { 1052 nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames); 1053 return frame && LookAndFeel::ColorSchemeForFrame(frame) == ColorScheme::Dark; 1054 } 1055 1056 Element* InspectorUtils::ContainingBlockOf(GlobalObject&, Element& aElement) { 1057 nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames); 1058 if (!frame) { 1059 return nullptr; 1060 } 1061 nsIFrame* cb = frame->GetContainingBlock(); 1062 if (!cb) { 1063 return nullptr; 1064 } 1065 return Element::FromNodeOrNull(cb->GetContent()); 1066 } 1067 1068 bool InspectorUtils::IsBlockContainer(GlobalObject&, Element& aElement) { 1069 nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames); 1070 if (!frame) { 1071 return false; 1072 } 1073 if (frame->IsBlockFrameOrSubclass()) { 1074 return true; 1075 } 1076 // ScrollContainerFrame::GetContentInsertionFrame() jumps across the block and 1077 // returns the ruby inside (because it calls GetContentInsertionFrame on its 1078 // own). So we have to account for that here. 1079 if (auto* sc = frame->GetScrollTargetFrame()) { 1080 if (sc->GetScrolledFrame()->IsBlockFrameOrSubclass()) { 1081 return true; 1082 } 1083 } 1084 if (nsIFrame* inner = frame->GetContentInsertionFrame()) { 1085 if (inner->IsBlockFrameOrSubclass()) { 1086 return true; 1087 } 1088 } 1089 return false; 1090 } 1091 1092 void InspectorUtils::GetBlockLineCounts(GlobalObject& aGlobal, 1093 Element& aElement, 1094 Nullable<nsTArray<uint32_t>>& aResult) { 1095 nsBlockFrame* block = 1096 do_QueryFrame(aElement.GetPrimaryFrame(FlushType::Layout)); 1097 if (!block) { 1098 aResult.SetNull(); 1099 return; 1100 } 1101 1102 // If CSS columns were specified on the actual block element (rather than an 1103 // ancestor block, GetPrimaryFrame will return its ColumnSetWrapperFrame, and 1104 // we need to drill down to the actual block that contains the lines. 1105 if (block->IsColumnSetWrapperFrame()) { 1106 nsIFrame* firstChild = block->PrincipalChildList().FirstChild(); 1107 if (!firstChild->IsColumnSetFrame()) { 1108 aResult.SetNull(); 1109 return; 1110 } 1111 block = do_QueryFrame(firstChild->PrincipalChildList().FirstChild()); 1112 if (!block || block->GetContent() != &aElement) { 1113 aResult.SetNull(); 1114 return; 1115 } 1116 } 1117 1118 nsTArray<uint32_t> result; 1119 do { 1120 result.AppendElement(block->Lines().size()); 1121 block = static_cast<nsBlockFrame*>(block->GetNextInFlow()); 1122 } while (block); 1123 1124 aResult.SetValue(std::move(result)); 1125 } 1126 1127 static bool FrameHasSpecifiedSize(const nsIFrame* aFrame) { 1128 auto wm = aFrame->GetWritingMode(); 1129 1130 const nsStylePosition* stylePos = aFrame->StylePosition(); 1131 const auto anchorResolutionParams = AnchorPosResolutionParams::From(aFrame); 1132 1133 return stylePos->ISize(wm, anchorResolutionParams)->IsLengthPercentage() || 1134 stylePos->BSize(wm, anchorResolutionParams)->IsLengthPercentage(); 1135 } 1136 1137 static bool IsFrameOutsideOfAncestor(const nsIFrame* aFrame, 1138 const nsIFrame* aAncestorFrame, 1139 const nsRect& aAncestorRect) { 1140 nsRect frameRectInAncestorSpace = nsLayoutUtils::TransformFrameRectToAncestor( 1141 aFrame, aFrame->ScrollableOverflowRect(), RelativeTo{aAncestorFrame}, 1142 nullptr, nullptr, false, nullptr); 1143 1144 // We use nsRect::SaturatingUnionEdges because it correctly handles the case 1145 // of a zero-width or zero-height frame, which we still want to consider as 1146 // contributing to the union. 1147 nsRect unionizedRect = 1148 frameRectInAncestorSpace.SaturatingUnionEdges(aAncestorRect); 1149 1150 // If frameRectInAncestorSpace is inside aAncestorRect then union of 1151 // frameRectInAncestorSpace and aAncestorRect should be equal to aAncestorRect 1152 // hence if it is equal, then false should be returned. 1153 1154 return !(unionizedRect == aAncestorRect); 1155 } 1156 1157 static void AddOverflowingChildrenOfElement(const nsIFrame* aFrame, 1158 const nsIFrame* aAncestorFrame, 1159 const nsRect& aRect, 1160 nsSimpleContentList& aList) { 1161 MOZ_ASSERT(aFrame, "we assume the passed-in frame is non-null"); 1162 for (const auto& childList : aFrame->ChildLists()) { 1163 for (const nsIFrame* child : childList.mList) { 1164 // We want to identify if the child or any of its children have a 1165 // frame that is outside of aAncestorFrame. Ideally, child would have 1166 // a frame rect that encompasses all of its children, but this is not 1167 // guaranteed by the frame tree. So instead we first check other 1168 // conditions that indicate child is an interesting frame: 1169 // 1170 // 1) child has a specified size 1171 // 2) none of child's children are implicated 1172 // 1173 // If either of these conditions are true, we *then* check if child's 1174 // frame is outside of aAncestorFrame, and if so, we add child's content 1175 // to aList. 1176 1177 if (FrameHasSpecifiedSize(child) && 1178 IsFrameOutsideOfAncestor(child, aAncestorFrame, aRect)) { 1179 aList.MaybeAppendElement(child->GetContent()); 1180 continue; 1181 } 1182 1183 uint32_t currListLength = aList.Length(); 1184 AddOverflowingChildrenOfElement(child, aAncestorFrame, aRect, aList); 1185 1186 // If child is a leaf node, length of aList should remain same after 1187 // calling AddOverflowingChildrenOfElement on it. 1188 if (currListLength == aList.Length() && 1189 IsFrameOutsideOfAncestor(child, aAncestorFrame, aRect)) { 1190 aList.MaybeAppendElement(child->GetContent()); 1191 } 1192 } 1193 } 1194 } 1195 1196 already_AddRefed<nsINodeList> InspectorUtils::GetOverflowingChildrenOfElement( 1197 GlobalObject& aGlobal, Element& aElement) { 1198 auto list = MakeRefPtr<nsSimpleContentList>(&aElement); 1199 const ScrollContainerFrame* scrollContainerFrame = 1200 aElement.GetScrollContainerFrame(); 1201 // Element must be a ScrollContainerFrame. 1202 if (!scrollContainerFrame) { 1203 return list.forget(); 1204 } 1205 1206 auto scrollPortRect = scrollContainerFrame->GetScrollPortRect(); 1207 const nsIFrame* scrolledFrame = scrollContainerFrame->GetScrolledFrame(); 1208 AddOverflowingChildrenOfElement(scrolledFrame, scrollContainerFrame, 1209 scrollPortRect, *list); 1210 return list.forget(); 1211 } 1212 1213 /* static */ 1214 void InspectorUtils::GetRegisteredCssHighlights(GlobalObject& aGlobalObject, 1215 Document& aDocument, 1216 bool aActiveOnly, 1217 nsTArray<nsString>& aResult) { 1218 for (auto const& iter : aDocument.HighlightRegistry().HighlightsOrdered()) { 1219 const RefPtr<nsAtom>& highlightName = iter.first(); 1220 const RefPtr<Highlight>& highlight = iter.second(); 1221 if (!aActiveOnly || highlight->Size() > 0) { 1222 aResult.AppendElement(highlightName->GetUTF16String()); 1223 } 1224 } 1225 } 1226 1227 /* static */ 1228 void InspectorUtils::GetCSSRegisteredProperties( 1229 GlobalObject& aGlobalObject, Document& aDocument, 1230 nsTArray<InspectorCSSPropertyDefinition>& aResult) { 1231 nsTArray<StylePropDef> result; 1232 1233 ServoStyleSet& styleSet = aDocument.EnsureStyleSet(); 1234 // Update the rules before looking up @property rules. 1235 styleSet.UpdateStylistIfNeeded(); 1236 1237 Servo_GetRegisteredCustomProperties(styleSet.RawData(), &result); 1238 for (const auto& propDef : result) { 1239 InspectorCSSPropertyDefinition& property = *aResult.AppendElement(); 1240 1241 // Servo does not include the "--" prefix in the property definition name. 1242 // Add it back as it's easier for DevTools to handle them _with_ "--". 1243 property.mName.AssignLiteral("--"); 1244 property.mName.Append(nsAtomCString(propDef.name.AsAtom())); 1245 property.mSyntax.Append(propDef.syntax); 1246 property.mInherits = propDef.inherits; 1247 if (propDef.has_initial_value) { 1248 property.mInitialValue.Append(propDef.initial_value); 1249 } else { 1250 property.mInitialValue.SetIsVoid(true); 1251 } 1252 property.mFromJS = propDef.from_js; 1253 } 1254 } 1255 1256 /* static */ 1257 void InspectorUtils::GetCSSRegisteredProperty( 1258 GlobalObject& aGlobalObject, Document& aDocument, const nsACString& aName, 1259 Nullable<InspectorCSSPropertyDefinition>& aResult) { 1260 StylePropDef result{StyleAtom(NS_Atomize(aName))}; 1261 1262 // Update the rules before looking up @property rules. 1263 ServoStyleSet& styleSet = aDocument.EnsureStyleSet(); 1264 styleSet.UpdateStylistIfNeeded(); 1265 1266 if (!Servo_GetRegisteredCustomProperty(styleSet.RawData(), &aName, &result)) { 1267 aResult.SetNull(); 1268 return; 1269 } 1270 1271 InspectorCSSPropertyDefinition& propDef = aResult.SetValue(); 1272 1273 // Servo does not include the "--" prefix in the property definition name. 1274 // Add it back as it's easier for DevTools to handle them _with_ "--". 1275 propDef.mName.AssignLiteral("--"); 1276 propDef.mName.Append(nsAtomCString(result.name.AsAtom())); 1277 propDef.mSyntax.Append(result.syntax); 1278 propDef.mInherits = result.inherits; 1279 if (result.has_initial_value) { 1280 propDef.mInitialValue.Append(result.initial_value); 1281 } else { 1282 propDef.mInitialValue.SetIsVoid(true); 1283 } 1284 propDef.mFromJS = result.from_js; 1285 } 1286 1287 /* static */ 1288 bool InspectorUtils::ValueMatchesSyntax(GlobalObject&, Document& aDocument, 1289 const nsACString& aValue, 1290 const nsACString& aSyntax) { 1291 return Servo_Value_Matches_Syntax(&aValue, &aSyntax, 1292 aDocument.DefaultStyleAttrURLData()); 1293 } 1294 1295 /* static */ 1296 void InspectorUtils::GetRuleBodyText(GlobalObject&, 1297 const nsACString& aInitialText, 1298 nsACString& aBodyText) { 1299 Servo_GetRuleBodyText(&aInitialText, &aBodyText); 1300 } 1301 1302 /* static */ 1303 void InspectorUtils::ReplaceBlockRuleBodyTextInStylesheet( 1304 GlobalObject&, const nsACString& aStyleSheetText, uint32_t aLine, 1305 uint32_t aColumn, const nsACString& aNewBodyText, 1306 nsACString& aNewStyleSheetText) { 1307 Servo_ReplaceBlockRuleBodyTextInStylesheetText( 1308 &aStyleSheetText, aLine, aColumn, &aNewBodyText, &aNewStyleSheetText); 1309 } 1310 1311 void InspectorUtils::SetVerticalClipping(GlobalObject&, 1312 BrowsingContext* aContext, 1313 mozilla::CSSCoord aOffset) { 1314 MOZ_ASSERT(XRE_IsParentProcess()); 1315 if (!aContext) { 1316 return; 1317 } 1318 1319 CanonicalBrowsingContext* canonical = aContext->Canonical(); 1320 if (!canonical) { 1321 return; 1322 } 1323 1324 BrowserParent* parent = canonical->GetBrowserParent(); 1325 if (!parent) { 1326 return; 1327 } 1328 const LayoutDeviceToCSSScale scale = parent->GetLayoutDeviceToCSSScale(); 1329 const mozilla::LayoutDeviceCoord layoutOffset = aOffset / scale; 1330 const mozilla::ScreenCoord screenOffset = ViewAs<ScreenPixel>( 1331 layoutOffset, PixelCastJustification::LayoutDeviceIsScreenForBounds); 1332 const mozilla::ScreenIntCoord offset = screenOffset.Rounded(); 1333 parent->DynamicToolbarOffsetChanged(offset); 1334 1335 RefPtr<nsIWidget> widget = canonical->GetParentProcessWidgetContaining(); 1336 if (!widget) { 1337 return; 1338 } 1339 widget->DynamicToolbarOffsetChanged(offset); 1340 } 1341 1342 void InspectorUtils::SetDynamicToolbarMaxHeight(GlobalObject&, 1343 BrowsingContext* aContext, 1344 mozilla::CSSCoord aHeight) { 1345 MOZ_ASSERT(XRE_IsParentProcess()); 1346 if (!aContext) { 1347 return; 1348 } 1349 1350 CanonicalBrowsingContext* canonical = aContext->Canonical(); 1351 if (!canonical) { 1352 return; 1353 } 1354 1355 BrowserParent* parent = canonical->GetBrowserParent(); 1356 if (!parent) { 1357 return; 1358 } 1359 1360 const LayoutDeviceToCSSScale scale = parent->GetLayoutDeviceToCSSScale(); 1361 const mozilla::LayoutDeviceCoord layoutOffset = aHeight / scale; 1362 const mozilla::ScreenCoord screenOffset = ViewAs<ScreenPixel>( 1363 layoutOffset, PixelCastJustification::LayoutDeviceIsScreenForBounds); 1364 const mozilla::ScreenIntCoord height = screenOffset.Rounded(); 1365 parent->DynamicToolbarMaxHeightChanged(height); 1366 } 1367 1368 uint16_t InspectorUtils::GetGridContainerType(GlobalObject&, 1369 Element& aElement) { 1370 auto* f = nsGridContainerFrame::GetGridContainerFrame( 1371 aElement.GetPrimaryFrame(FlushType::Frames)); 1372 if (!f) { 1373 return InspectorUtils_Binding::GRID_NONE; 1374 } 1375 uint16_t result = InspectorUtils_Binding::GRID_CONTAINER; 1376 if (f->IsRowSubgrid()) { 1377 result |= InspectorUtils_Binding::GRID_SUBGRID_ROW; 1378 } 1379 if (f->IsColSubgrid()) { 1380 result |= InspectorUtils_Binding::GRID_SUBGRID_COL; 1381 } 1382 return result; 1383 } 1384 1385 } // namespace mozilla::dom