tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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