Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  InspectorUtils.cpp

  Sprache: C
 

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "mozilla/dom/InspectorUtils.h"

#include "AnchorPositioningUtils.h"
#include "ChildIterator.h"
#include "Units.h"
#include "gfxTextRun.h"
#include "inLayoutUtils.h"
#include "mozilla/DeclarationBlock.h"
#include "mozilla/EventStateManager.h"
#include "mozilla/PresShell.h"
#include "mozilla/PresShellInlines.h"
#include "mozilla/RefPtr.h"
#include "mozilla/RelativeLuminanceUtils.h"
#include "mozilla/ScrollContainerFrame.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoCSSParser.h"
#include "mozilla/ServoStyleRuleMap.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/StaticPrefs_layout.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/dom/BrowserParent.h"
#include "mozilla/dom/CSSBinding.h"
#include "mozilla/dom/CSSKeyframesRule.h"
#include "mozilla/dom/CSSStylePropertiesBinding.h"
#include "mozilla/dom/CSSStyleRule.h"
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/CharacterData.h"
#include "mozilla/dom/ContentList.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/HTMLSlotElement.h"
#include "mozilla/dom/HTMLTemplateElement.h"
#include "mozilla/dom/Highlight.h"
#include "mozilla/dom/HighlightRegistry.h"
#include "mozilla/dom/InspectorFontFace.h"
#include "mozilla/dom/InspectorUtilsBinding.h"
#include "mozilla/dom/LinkStyle.h"
#include "mozilla/dom/ToJSValue.h"
#include "mozilla/gfx/Matrix.h"
#include "nsArray.h"
#include "nsAtom.h"
#include "nsBlockFrame.h"
#include "nsCSSProps.h"
#include "nsCSSValue.h"
#include "nsColor.h"
#include "nsComputedDOMStyle.h"
#include "nsFieldSetFrame.h"
#include "nsGlobalWindowInner.h"
#include "nsGridContainerFrame.h"
#include "nsIContentInlines.h"
#include "nsIFrameInlines.h"
#include "nsLayoutUtils.h"
#include "nsNameSpaceManager.h"
#include "nsPresContext.h"
#include "nsQueryObject.h"
#include "nsRange.h"
#include "nsString.h"
#include "nsStyleUtil.h"

using namespace mozilla;
using namespace mozilla::css;
using namespace mozilla::dom;

namespace mozilla::dom {

static nsPresContext* EnsureSafeToHandOutRules(Element& aElement) {
  Document* doc = aElement.GetComposedDoc();
  if (!doc) {
    return nullptr;
  }
  const PresShell* presShell = doc->GetPresShell();
  if (!presShell) {
    return nullptr;
  }
  nsPresContext* presContext = presShell->GetPresContext();
  if (!presContext) {
    return nullptr;
  }
  presContext->EnsureSafeToHandOutCSSRules();
  return presContext;
}

static already_AddRefed<const ComputedStyle> GetCleanComputedStyleForElement(
    dom::Element* aElement, const PseudoStyleRequest& aPseudo) {
  MOZ_ASSERT(aElement);
  nsPresContext* pc = EnsureSafeToHandOutRules(*aElement);
  if (!pc) {
    return nullptr;
  }
  return nsComputedDOMStyle::GetComputedStyle(aElement, aPseudo);
}

/* static */
void InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject,
                                       Document& aDocument, bool aDocumentOnly,
                                       nsTArray<RefPtr<StyleSheet>>& aResult) {
  // Get the agent, then user and finally xbl sheets in the style set.
  PresShell* presShell = aDocument.GetPresShell();
  nsTHashSet<StyleSheet*> sheetSet;

  if (presShell) {
    ServoStyleSet* styleSet = presShell->StyleSet();

    if (!aDocumentOnly) {
      const StyleOrigin kOrigins[] = {StyleOrigin::UserAgent,
                                      StyleOrigin::User};
      for (const auto origin : kOrigins) {
        for (size_t i = 0, count = styleSet->SheetCount(origin); i < count;
             i++) {
          aResult.AppendElement(styleSet->SheetAt(origin, i));
        }
      }
    }

    AutoTArray<StyleSheet*, 32> nonDocumentSheets;
    styleSet->AppendAllNonDocumentAuthorSheets(nonDocumentSheets);

    // The non-document stylesheet array can have duplicates due to adopted
    // stylesheets.
    nsTHashSet<StyleSheet*> sheetSet;
    for (StyleSheet* sheet : nonDocumentSheets) {
      if (sheetSet.EnsureInserted(sheet)) {
        aResult.AppendElement(sheet);
      }
    }
  }

  // Get the document sheets.
  for (size_t i = 0; i < aDocument.SheetCount(); i++) {
    aResult.AppendElement(aDocument.SheetAt(i));
  }

  for (auto& sheet : aDocument.AdoptedStyleSheets()) {
    if (sheetSet.EnsureInserted(sheet)) {
      aResult.AppendElement(sheet);
    }
  }
}

bool InspectorUtils::IsIgnorableWhitespace(CharacterData& aDataNode) {
  if (!aDataNode.TextIsOnlyWhitespace()) {
    return false;
  }

  // Okay.  We have only white space.  Let's check the white-space
  // property now and make sure that this isn't preformatted text...
  if (nsIFrame* frame = aDataNode.GetPrimaryFrame()) {
    return !frame->StyleText()->WhiteSpaceIsSignificant();
  }

  // empty inter-tag text node without frame, e.g., in between <table>\n<tr>
  return true;
}

/* static */
nsINode* InspectorUtils::GetParentForNode(nsINode& aNode,
                                          bool aShowingAnonymousContent) {
  if (nsINode* parent = aNode.GetParentNode()) {
    return parent;
  }
  if (aNode.IsDocument()) {
    return inLayoutUtils::GetContainerFor(*aNode.AsDocument());
  }
  if (aShowingAnonymousContent) {
    if (auto* frag = DocumentFragment::FromNode(aNode)) {
      // This deals with shadow roots and HTMLTemplateElement.content.
      return frag->GetHost();
    }
  }
  return nullptr;
}

/* static */
void InspectorUtils::GetChildrenForNode(nsINode& aNode,
                                        bool aShowingAnonymousContent,
                                        bool aIncludeAssignedNodes,
                                        bool aIncludeSubdocuments,
                                        nsTArray<RefPtr<nsINode>>& aResult) {
  if (aIncludeSubdocuments) {
    if (auto* doc = inLayoutUtils::GetSubDocumentFor(&aNode)) {
      aResult.AppendElement(doc);
      // XXX Do we really want to early-return?
      return;
    }
  }

  if (!aShowingAnonymousContent || !aNode.IsContent()) {
    for (nsINode* child = aNode.GetFirstChild(); child;
         child = child->GetNextSibling()) {
      aResult.AppendElement(child);
    }
    return;
  }

  if (auto* tmpl = HTMLTemplateElement::FromNode(aNode)) {
    aResult.AppendElement(tmpl->Content());
    // XXX Do we really want to early-return?
    return;
  }

  if (auto* element = Element::FromNode(aNode)) {
    if (auto* shadow = element->GetShadowRoot()) {
      aResult.AppendElement(shadow);
    }
  }
  nsIContent* parent = aNode.AsContent();
  if (auto* node = nsLayoutUtils::GetBackdropPseudo(parent)) {
    aResult.AppendElement(node);
  }
  if (auto* node = nsLayoutUtils::GetMarkerPseudo(parent)) {
    aResult.AppendElement(node);
  }
  if (auto* node = nsLayoutUtils::GetCheckmarkPseudo(parent)) {
    aResult.AppendElement(node);
  }
  if (auto* node = nsLayoutUtils::GetBeforePseudo(parent)) {
    aResult.AppendElement(node);
  }
  if (aIncludeAssignedNodes) {
    if (auto* slot = HTMLSlotElement::FromNode(aNode)) {
      for (nsINode* node : slot->AssignedNodes()) {
        aResult.AppendElement(node);
      }
    }
  }
  for (nsIContent* node = parent->GetFirstChild(); node;
       node = node->GetNextSibling()) {
    aResult.AppendElement(node);
  }
  AutoTArray<nsIContent*, 4> anonKids;
  nsContentUtils::AppendNativeAnonymousChildren(parent, anonKids,
                                                nsIContent::eAllChildren);
  for (nsIContent* node : anonKids) {
    aResult.AppendElement(node);
  }
  if (auto* node = nsLayoutUtils::GetAfterPseudo(parent)) {
    aResult.AppendElement(node);
  }
}

class ReadOnlyInspectorDeclaration final : public nsDOMCSSDeclaration {
 public:
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
  NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(ReadOnlyInspectorDeclaration)

  explicit ReadOnlyInspectorDeclaration(const StyleLockedDeclarationBlock* aRaw)
      : mRaw(aRaw) {}

  nsINode* GetAssociatedNode() const final { return nullptr; }
  nsISupports* GetParentObject() const final { return nullptr; }
  void GetPropertyValue(const nsACString& aPropName, nsACString& aValue) final {
    Servo_DeclarationBlock_GetPropertyValue(mRaw, &aPropName, &aValue);
  }
  void GetPropertyValue(NonCustomCSSPropertyId aId, nsACString& aValue) final {
    Servo_DeclarationBlock_GetPropertyValueByNonCustomId(mRaw, aId, &aValue);
  }
  bool HasLonghandProperty(const nsACString& aPropName) final {
    return Servo_DeclarationBlock_HasLonghandProperty(mRaw, &aPropName);
  }
  void IndexedGetter(uint32_t aIndex, bool& aFound,
                     nsACString& aPropName) final {
    aFound = Servo_DeclarationBlock_GetNthProperty(mRaw, aIndex, &aPropName);
  }
  void RemoveProperty(const nsACString& aPropertyName, nsACString& aValue,
                      ErrorResult& aRv) final {
    aRv.ThrowInvalidModificationError("Can't mutate this declaration");
  }
  void SetProperty(const nsACString& aPropertyName, const nsACString& aValue,
                   const nsACString& aPriority, nsIPrincipal* aSubjectPrincipal,
                   ErrorResult& aRv) final {
    aRv.ThrowInvalidModificationError("Can't mutate this declaration");
  }
  void SetPropertyValue(NonCustomCSSPropertyId aId, const nsACString& aValue,
                        nsIPrincipal* aSubjectPrincipal,
                        ErrorResult& aRv) final {
    aRv.ThrowInvalidModificationError("Can't mutate this declaration");
  }
  void SetCssText(const nsACString& aString, nsIPrincipal* aSubjectPrincipal,
                  ErrorResult& aRv) final {
    aRv.ThrowInvalidModificationError("Can't mutate this declaration");
  }
  void GetCssText(nsACString& aString) final {
    Servo_DeclarationBlock_GetCssText(mRaw, &aString);
  }
  uint32_t Length() final { return Servo_DeclarationBlock_Count(mRaw); }
  void GetPropertyPriority(const nsACString& aPropName,
                           nsACString& aPriority) final {
    if (Servo_DeclarationBlock_GetPropertyIsImportant(mRaw, &aPropName)) {
      aPriority.AssignLiteral("important");
    }
  }
  css::Rule* GetParentRule() final { return nullptr; }
  JSObject* WrapObject(JSContext* aCx,
                       JS::Handle<JSObject*> aGivenProto) final {
    return CSSStyleProperties_Binding::Wrap(aCx, this, aGivenProto);
  }
  // These ones are a bit sad, but matches e.g. nsComputedDOMStyle.
  nsresult SetCSSDeclaration(Block* aDecl, MutationClosureData*) final {
    MOZ_CRASH("called ReadOnlyInspectorDeclaration::SetCSSDeclaration");
  }
  Block* GetOrCreateCSSDeclaration(Operation, Block**) override {
    MOZ_CRASH("called ReadOnlyInspectorDeclaration::GetOrCreateCSSDeclaration");
  }
  ParsingEnvironment GetParsingEnvironment(nsIPrincipal*) const final {
    MOZ_CRASH("called ReadOnlyInspectorDeclaration::GetParsingEnvironment");
  }

 private:
  ~ReadOnlyInspectorDeclaration() = default;

  RefPtr<const StyleLockedDeclarationBlock> mRaw;
};

NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ReadOnlyInspectorDeclaration)
  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  NS_INTERFACE_MAP_ENTRY(nsICSSDeclaration)
  NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END

NS_IMPL_CYCLE_COLLECTING_ADDREF(ReadOnlyInspectorDeclaration)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ReadOnlyInspectorDeclaration)
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(ReadOnlyInspectorDeclaration)

static void GetCSSRulesFromComputedValues(
    Element& aElement, const ComputedStyle* aComputedStyle,
    bool aWithStartingStyle,
    nsTArray<OwningCSSRuleOrInspectorDeclaration>& aResult) {
  const PresShell* presShell = aElement.OwnerDoc()->GetPresShell();
  if (!presShell) {
    return;
  }

  AutoTArray<StyleMatchingDeclarationBlock, 8> rawDecls;
  Servo_ComputedValues_GetMatchingDeclarations(aComputedStyle,
                                               aWithStartingStyle, &rawDecls);

  AutoTArray<ServoStyleRuleMap*, 8> maps;
  {
    ServoStyleSet* styleSet = presShell->StyleSet();
    ServoStyleRuleMap* map = styleSet->StyleRuleMap();
    maps.AppendElement(map);
  }

  // Now shadow DOM stuff...
  if (auto* shadow = aElement.GetShadowRoot()) {
    maps.AppendElement(&shadow->ServoStyleRuleMap());
  }

  // Now NAC:
  for (auto* el = aElement.GetClosestNativeAnonymousSubtreeRootParentOrHost();
       el; el = el->GetClosestNativeAnonymousSubtreeRootParentOrHost()) {
    if (auto* shadow = el->GetShadowRoot()) {
      maps.AppendElement(&shadow->ServoStyleRuleMap());
    }
  }

  for (auto* shadow = aElement.GetContainingShadow(); shadow;
       shadow = shadow->Host()->GetContainingShadow()) {
    maps.AppendElement(&shadow->ServoStyleRuleMap());
  }

  // Rules from the assigned slot.
  for (auto* slot = aElement.GetAssignedSlot(); slot;
       slot = slot->GetAssignedSlot()) {
    if (auto* shadow = slot->GetContainingShadow()) {
      maps.AppendElement(&shadow->ServoStyleRuleMap());
    }
  }

  // Find matching rules in the table.
  for (const StyleMatchingDeclarationBlock& block : Reversed(rawDecls)) {
    bool found = false;
    for (ServoStyleRuleMap* map : maps) {
      if (css::Rule* rule = map->Lookup(block.block)) {
        aResult.AppendElement()->SetAsCSSRule() = rule;
        found = true;
        break;
      }
    }
    if (!found) {
      auto& declaration = aResult.AppendElement()->SetAsInspectorDeclaration();
      declaration.mStyle = OwningNonNull<ReadOnlyInspectorDeclaration>(
          *new ReadOnlyInspectorDeclaration(block.block));
      declaration.mDeclarationOrigin = [&] {
        switch (block.origin) {
          case StyleMatchingDeclarationBlockOrigin::Author:
            return DeclarationOrigin::Style_attribute;
          case StyleMatchingDeclarationBlockOrigin::User:
            MOZ_ASSERT_UNREACHABLE(
                "Where did this user agent declaration come from?");
            return DeclarationOrigin::User;
          case StyleMatchingDeclarationBlockOrigin::UserAgent:
            return DeclarationOrigin::User_agent;
          case StyleMatchingDeclarationBlockOrigin::PositionFallback:
            return DeclarationOrigin::Position_fallback;
          case StyleMatchingDeclarationBlockOrigin::Animations:
            return DeclarationOrigin::Animations;
          case StyleMatchingDeclarationBlockOrigin::Transitions:
            return DeclarationOrigin::Transitions;
          case StyleMatchingDeclarationBlockOrigin::SMIL:
            return DeclarationOrigin::Smil;
          case StyleMatchingDeclarationBlockOrigin::PresHints:
            return DeclarationOrigin::Pres_hints;
        }
        MOZ_ASSERT_UNREACHABLE("Unkown origin?");
        return DeclarationOrigin::Pres_hints;
      }();
    }
  }
}

/* static */
void InspectorUtils::GetMatchingCSSRules(
    GlobalObject& aGlobalObject, Element& aElement, const nsAString& aPseudo,
    bool aIncludeVisitedStyle, bool aWithStartingStyle,
    nsTArray<OwningCSSRuleOrInspectorDeclaration>& aResult) {
  auto pseudo = PseudoStyleRequest::Parse(
      aPseudo, aElement.OwnerDoc()->DefaultStyleAttrURLData());
  if (!pseudo) {
    return;
  }

  RefPtr<const ComputedStyle> computedStyle =
      GetCleanComputedStyleForElement(&aElement, *pseudo);
  if (!computedStyle) {
    // This can fail for elements that are not in the document or
    // if the document they're in doesn't have a presshell.  Bail out.
    return;
  }

  if (aIncludeVisitedStyle) {
    if (const auto* styleIfVisited = computedStyle->GetStyleIfVisited()) {
      computedStyle = styleIfVisited;
    }
  }

  GetCSSRulesFromComputedValues(aElement, computedStyle, aWithStartingStyle,
                                aResult);
}

/* static */
uint32_t InspectorUtils::GetRuleLine(GlobalObject& aGlobal, css::Rule& aRule) {
  uint32_t line = aRule.GetLineNumber();
  if (StyleSheet* sheet = aRule.GetStyleSheet()) {
    if (auto* link = LinkStyle::FromNodeOrNull(sheet->GetOwnerNode())) {
      line += link->GetLineNumber();
    }
  }
  return line;
}

/* static */
uint32_t InspectorUtils::GetRuleColumn(GlobalObject& aGlobal,
                                       css::Rule& aRule) {
  return aRule.GetColumnNumber();
}

/* static */
uint32_t InspectorUtils::GetRelativeRuleLine(GlobalObject& aGlobal,
                                             css::Rule& aRule) {
  // Rule lines are 0-based, but inspector wants 1-based.
  return aRule.GetLineNumber() + 1;
}

void InspectorUtils::GetRuleIndex(GlobalObject& aGlobal, css::Rule& aRule,
                                  nsTArray<uint32_t>& aResult) {
  css::Rule* currentRule = &aRule;

  do {
    css::Rule* parentRule = currentRule->GetParentRule();
    dom::CSSRuleList* ruleList = nullptr;

    if (parentRule) {
      if (parentRule->IsGroupRule()) {
        ruleList = static_cast<css::GroupRule*>(parentRule)->CssRules();
      } else if (parentRule->Type() == StyleCssRuleType::Keyframes) {
        ruleList = static_cast<CSSKeyframesRule*>(parentRule)->CssRules();
      } else {
        MOZ_ASSERT_UNREACHABLE("Unknown parent rule type?");
      }
    } else if (StyleSheet* sheet = currentRule->GetStyleSheet()) {
      ruleList = sheet->GetCssRulesInternal();
    }

    if (!ruleList) {
      return;
    }

    bool found = false;
    for (uint32_t i = 0, len = ruleList->Length(); i < len; ++i) {
      css::Rule* rule = ruleList->Item(i);
      if (currentRule == rule) {
        found = true;
        aResult.InsertElementAt(0, i);
        break;
      }
    }

    if (!found) {
      return;
    }

    currentRule = parentRule;
  } while (currentRule);
}

/* static */
bool InspectorUtils::HasRulesModifiedByCSSOM(GlobalObject& aGlobal,
                                             StyleSheet& aSheet) {
  return aSheet.HasModifiedRulesForDevtools();
}

static uint32_t CollectAtRules(ServoCSSRuleList& aRuleList,
                               Sequence<OwningNonNull<css::Rule>>& aResult) {
  uint32_t len = aRuleList.Length();
  uint32_t ruleCount = len;
  for (uint32_t i = 0; i < len; ++i) {
    css::Rule* rule = aRuleList.GetRule(i);
    // This collect rules we want to display in Devtools Style Editor toolbar.
    // When adding a new StyleCssRuleType, put it in the "default" list, and
    // file a new bug with
    // https://bugzilla.mozilla.org/enter_bug.cgi?product=DevTools&component=Style%20Editor&short_desc=Consider%20displaying%20new%20XXX%20rule%20type%20in%20at-rules%20sidebar
    // so the DevTools team gets notified and can decide if it should be
    // displayed.
    switch (rule->Type()) {
      case StyleCssRuleType::CustomMedia:
      case StyleCssRuleType::Media:
      case StyleCssRuleType::Supports:
      case StyleCssRuleType::LayerBlock:
      case StyleCssRuleType::PositionTry:
      case StyleCssRuleType::Property:
      case StyleCssRuleType::Container: {
        (void)aResult.AppendElement(OwningNonNull(*rule), fallible);
        break;
      }
      case StyleCssRuleType::Style:
      case StyleCssRuleType::Import:
      case StyleCssRuleType::Document:
      case StyleCssRuleType::LayerStatement:
      case StyleCssRuleType::FontFace:
      case StyleCssRuleType::Page:
      case StyleCssRuleType::Keyframes:
      case StyleCssRuleType::Keyframe:
      case StyleCssRuleType::Margin:
      case StyleCssRuleType::Namespace:
      case StyleCssRuleType::CounterStyle:
      case StyleCssRuleType::FontFeatureValues:
      case StyleCssRuleType::FontPaletteValues:
      case StyleCssRuleType::Scope:
      case StyleCssRuleType::StartingStyle:
      case StyleCssRuleType::NestedDeclarations:
      case StyleCssRuleType::AppearanceBase:
      case StyleCssRuleType::ViewTransition:
        break;
    }

    if (rule->IsGroupRule()) {
      ruleCount += CollectAtRules(
          *static_cast<css::GroupRule*>(rule)->CssRules(), aResult);
    }
  }
  return ruleCount;
}

void InspectorUtils::GetStyleSheetRuleCountAndAtRules(
    GlobalObject& aGlobal, StyleSheet& aSheet,
    InspectorStyleSheetRuleCountAndAtRulesResult& aResult) {
  aResult.mRuleCount =
      CollectAtRules(*aSheet.GetCssRulesInternal(), aResult.mAtRules);
}

/* static */
bool InspectorUtils::IsInheritedProperty(GlobalObject& aGlobalObject,
                                         Document& aDocument,
                                         const nsACString& aPropertyName) {
  return Servo_Property_IsInherited(aDocument.EnsureStyleSet().RawData(),
                                    &aPropertyName);
}

/* static */
void InspectorUtils::GetCSSPropertyNames(GlobalObject& aGlobalObject,
                                         const PropertyNamesOptions& aOptions,
                                         nsTArray<nsString>& aResult) {
  CSSEnabledState enabledState = aOptions.mIncludeExperimentals
                                     ? CSSEnabledState::IgnoreEnabledState
                                     : CSSEnabledState::ForAllContent;

  auto appendProperty = [enabledState, &aResult](uint32_t prop) {
    NonCustomCSSPropertyId cssProp = NonCustomCSSPropertyId(prop);
    if (nsCSSProps::IsEnabled(cssProp, enabledState)) {
      aResult.AppendElement(
          NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(cssProp)));
    }
  };

  uint32_t prop = 0;
  for (; prop < eCSSProperty_COUNT_no_shorthands; ++prop) {
    if (!nsCSSProps::PropHasFlags(NonCustomCSSPropertyId(prop),
                                  CSSPropFlags::Inaccessible)) {
      appendProperty(prop);
    }
  }

  if (aOptions.mIncludeShorthands) {
    for (; prop < eCSSProperty_COUNT; ++prop) {
      appendProperty(prop);
    }
  }

  if (aOptions.mIncludeAliases) {
    for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases;
         ++prop) {
      appendProperty(prop);
    }
  }
}

/* static */
void InspectorUtils::GetCSSPropertyPrefs(GlobalObject& aGlobalObject,
                                         nsTArray<PropertyPref>& aResult) {
  for (const auto* src = nsCSSProps::kPropertyPrefTable;
       src->mPropId != eCSSProperty_UNKNOWN; src++) {
    PropertyPref& dest = *aResult.AppendElement();
    dest.mName.Assign(
        NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(src->mPropId)));
    dest.mPref.AssignASCII(src->mPref);
  }
}

/* static */
void InspectorUtils::GetSubpropertiesForCSSProperty(GlobalObject& aGlobal,
                                                    const nsACString& aProperty,
                                                    nsTArray<nsString>& aResult,
                                                    ErrorResult& aRv) {
  NonCustomCSSPropertyId propertyId = nsCSSProps::LookupProperty(aProperty);

  if (propertyId == eCSSProperty_UNKNOWN) {
    aRv.Throw(NS_ERROR_FAILURE);
    return;
  }

  if (propertyId == eCSSPropertyExtra_variable) {
    aResult.AppendElement(NS_ConvertUTF8toUTF16(aProperty));
    return;
  }

  if (!nsCSSProps::IsShorthand(propertyId)) {
    nsString* name = aResult.AppendElement();
    CopyASCIItoUTF16(nsCSSProps::GetStringValue(propertyId), *name);
    return;
  }

  for (const NonCustomCSSPropertyId* props =
           nsCSSProps::SubpropertyEntryFor(propertyId);
       *props != eCSSProperty_UNKNOWN; ++props) {
    nsString* name = aResult.AppendElement();
    CopyASCIItoUTF16(nsCSSProps::GetStringValue(*props), *name);
  }
}

/* static */
bool InspectorUtils::CssPropertyIsShorthand(GlobalObject& aGlobalObject,
                                            const nsACString& aProperty,
                                            ErrorResult& aRv) {
  bool found;
  bool isShorthand = Servo_Property_IsShorthand(&aProperty, &found);
  if (!found) {
    aRv.Throw(NS_ERROR_FAILURE);
  }
  return isShorthand;
}

// This should match the constants in specified_value_info.rs
//
// Once we can use bitflags in consts, we can also cbindgen that and use them
// here instead.
static uint8_t ToServoCssType(InspectorPropertyType aType) {
  switch (aType) {
    case InspectorPropertyType::Color:
      return 1;
    case InspectorPropertyType::Gradient:
      return 1 << 1;
    case InspectorPropertyType::Timing_function:
      return 1 << 2;
    default:
      MOZ_ASSERT_UNREACHABLE("Unknown property type?");
      return 0;
  }
}

bool InspectorUtils::Supports(GlobalObject&, const nsACString& aDeclaration,
                              const SupportsOptions& aOptions) {
  StyleCssSupportsParams params{
      .origin =
          aOptions.mUserAgent ? StyleOrigin::UserAgent : StyleOrigin::Author,
      .url_context = aOptions.mChrome ? StyleCssSupportsUrlContext::Chrome
                                      : StyleCssSupportsUrlContext::Default,
      .quirks = aOptions.mQuirks
                    ? nsCompatibility::eCompatibility_NavQuirks
                    : nsCompatibility::eCompatibility_FullStandards,
  };
  return Servo_CSSSupports(&aDeclaration, ¶ms,
                           /* aUrlData = */ nullptr);
}

bool InspectorUtils::CssPropertySupportsType(GlobalObject& aGlobalObject,
                                             const nsACString& aProperty,
                                             InspectorPropertyType aType,
                                             ErrorResult& aRv) {
  bool found;
  bool result =
      Servo_Property_SupportsType(&aProperty, ToServoCssType(aType), &found);
  if (!found) {
    aRv.Throw(NS_ERROR_FAILURE);
    return false;
  }
  return result;
}

/* static */
void InspectorUtils::GetCSSValuesForProperty(GlobalObject& aGlobalObject,
                                             const nsACString& aProperty,
                                             nsTArray<nsString>& aResult,
                                             ErrorResult& aRv) {
  bool found;
  Servo_Property_GetCSSValuesForProperty(&aProperty, &found, &aResult);
  if (!found) {
    aRv.Throw(NS_ERROR_FAILURE);
  }
}

/* static */
void InspectorUtils::GetCSSWideKeywords(GlobalObject& aGlobalObject,
                                        nsTArray<nsString>& aResult) {
  Servo_Property_GetCSSWideKeywords(&aResult);
}

/* static */
void InspectorUtils::RgbToColorName(GlobalObject&, uint8_t aR, uint8_t aG,
                                    uint8_t aB, nsACString& aColorName) {
  Servo_SlowRgbToColorName(aR, aG, aB, &aColorName);
}

void InspectorUtils::RgbToNearestColorName(GlobalObject&, float aR, float aG,
                                           float aB,
                                           InspectorNearestColor& aResult) {
  bool exact = Servo_SlowRgbToNearestColorName(
      aR, aG, aB, StyleColorSpace::Srgb, &aResult.mColorName);
  aResult.mExact = exact;
}

/* static */
void InspectorUtils::RgbToHsv(GlobalObject&, float aR, float aG, float aB,
                              nsTArray<float>& aResult) {
  StyleAbsoluteColor input{
      .components = StyleColorComponents{aR, aG, aB},
      .alpha = 1.0,
      .color_space = StyleColorSpace::Srgb,
  };
  StyleAbsoluteColor result = input.ToColorSpace(StyleColorSpace::Hwb);
  float h = result.components._0 / 360.0f;
  float v = 1 - result.components._2 / 100.0f;
  float s = 0;
  if (v != 0.0) {
    s = 1 - (result.components._1 / 100.0f) / v;
  }
  aResult = {h, s, v};
}

/* static */
void InspectorUtils::HsvToRgb(GlobalObject&, float aH, float aS, float aV,
                              nsTArray<float>& aResult) {
  float h = aH * 360;
  float w = aV * (1 - aS) * 100;
  float b = (1 - aV) * 100;
  StyleAbsoluteColor input{
      .components = StyleColorComponents{h, w, b},
      .alpha = 1.0,
      .color_space = StyleColorSpace::Hwb,
  };
  StyleAbsoluteColor result = input.ToColorSpace(StyleColorSpace::Srgb);
  aResult = {result.components._0, result.components._1, result.components._2};
}

/* static */
float InspectorUtils::RelativeLuminance(GlobalObject&, float aR, float aG,
                                        float aB) {
  return RelativeLuminanceUtils::Compute(aR, aG, aB);
}

/* static */
void InspectorUtils::ColorToRGBA(GlobalObject& aGlobal,
                                 const nsACString& aColorString,
                                 Nullable<InspectorRGBATuple>& aResult) {
  const auto* styleData = [&]() -> const StylePerDocumentStyleData* {
    nsCOMPtr<nsIGlobalObject> global =
        do_QueryInterface(aGlobal.GetAsSupports());
    if (!global) {
      return nullptr;
    }
    auto* win = global->GetAsInnerWindow();
    if (!win) {
      return nullptr;
    }
    Document* doc = win->GetExtantDoc();
    if (!doc) {
      return nullptr;
    }
    PresShell* ps = doc->GetPresShell();
    if (!ps) {
      return nullptr;
    }
    return ps->StyleSet()->RawData();
  }();

  nscolor color = NS_RGB(000);
  if (!ServoCSSParser::ComputeColor(styleData, NS_RGB(000), aColorString,
                                    &color)) {
    aResult.SetNull();
    return;
  }

  InspectorRGBATuple& tuple = aResult.SetValue();
  tuple.mR = NS_GET_R(color);
  tuple.mG = NS_GET_G(color);
  tuple.mB = NS_GET_B(color);
  tuple.mA = nsStyleUtil::ColorComponentToFloat(NS_GET_A(color));
}

/* static */
void InspectorUtils::ColorTo(GlobalObject&, const nsACString& aFromColor,
                             const nsACString& aToColorSpace,
                             Nullable<InspectorColorToResult>& aResult) {
  nsCString resultColor;
  nsTArray<float> resultComponents;
  bool resultAdjusted = false;

  if (!ServoCSSParser::ColorTo(aFromColor, aToColorSpace, &resultColor,
                               &resultComponents, &resultAdjusted)) {
    aResult.SetNull();
    return;
  }

  auto& result = aResult.SetValue();
  result.mColor.AssignASCII(resultColor);
  result.mComponents = std::move(resultComponents);
  result.mAdjusted = resultAdjusted;
}

/* static */
bool InspectorUtils::IsValidCSSColor(GlobalObject& aGlobalObject,
                                     const nsACString& aColorString) {
  return ServoCSSParser::IsValidCSSColor(aColorString);
}

/* static */
bool InspectorUtils::IsValidCSSImage(GlobalObject& aGlobalObject,
                                     const nsACString& aImageString) {
  return ServoCSSParser::IsValidCSSImage(aImageString);
}

/* static */
bool InspectorUtils::SetContentState(GlobalObject& aGlobalObject,
                                     Element& aElement, uint64_t aState,
                                     ErrorResult& aRv) {
  RefPtr<EventStateManager> esm =
      inLayoutUtils::GetEventStateManagerFor(aElement);
  ElementState state(aState);
  if (!esm || !EventStateManager::ManagesState(state)) {
    aRv.Throw(NS_ERROR_INVALID_ARG);
    return false;
  }
  return esm->SetContentState(&aElement, state);
}

/* static */
bool InspectorUtils::RemoveContentState(GlobalObject& aGlobalObject,
                                        Element& aElement, uint64_t aState,
                                        bool aClearActiveDocument,
                                        ErrorResult& aRv) {
  RefPtr<EventStateManager> esm =
      inLayoutUtils::GetEventStateManagerFor(aElement);
  ElementState state(aState);
  if (!esm || !EventStateManager::ManagesState(state)) {
    aRv.Throw(NS_ERROR_INVALID_ARG);
    return false;
  }

  bool result = esm->SetContentState(nullptr, state);

  if (aClearActiveDocument && state == ElementState::ACTIVE) {
    EventStateManager* activeESM = static_cast<EventStateManager*>(
        EventStateManager::GetActiveEventStateManager());
    if (activeESM == esm) {
      EventStateManager::ClearGlobalActiveContent(nullptr);
    }
  }

  return result;
}

/* static */
uint64_t InspectorUtils::GetContentState(GlobalObject& aGlobalObject,
                                         Element& aElement) {
  // NOTE: if this method is removed,
  // please remove GetInternalValue from ElementState
  return aElement.State().GetInternalValue();
}

/* static */
void InspectorUtils::GetUsedFontFaces(GlobalObject& aGlobalObject,
                                      nsRange& aRange, uint32_t aMaxRanges,
                                      bool aSkipCollapsedWhitespace,
                                      nsLayoutUtils::UsedFontFaceList& aResult,
                                      ErrorResult& aRv) {
  nsresult rv =
      aRange.GetUsedFontFaces(aResult, aMaxRanges, aSkipCollapsedWhitespace);

  if (NS_FAILED(rv)) {
    aRv.Throw(rv);
  }
}

static ElementState GetStatesForPseudoClass(const nsAString& aStatePseudo) {
  if (aStatePseudo.IsEmpty() || aStatePseudo[0] != u':') {
    return ElementState();
  }
  NS_ConvertUTF16toUTF8 statePseudo(Substring(aStatePseudo, 1));
  return ElementState(Servo_PseudoClass_GetStates(&statePseudo));
}

/* static */
void InspectorUtils::GetCSSPseudoElementNames(GlobalObject& aGlobalObject,
                                              nsTArray<nsString>& aResult) {
  const auto kPseudoCount = static_cast<size_t>(PseudoStyleType::MAX);
  for (size_t i = 0; i < kPseudoCount; ++i) {
    PseudoStyleType type = static_cast<PseudoStyleType>(i);
    if (type == PseudoStyleType::NotPseudo ||
        !Servo_PseudoStyleType_EnabledForAllContent(type)) {
      continue;
    }
    auto& string = *aResult.AppendElement();
    // Use two semi-colons (though internally we use one).
    string.Append(u':');
    const nsStaticAtom* atom = PseudoStyle::GetAtom(type);
    string.Append(nsDependentAtomString(atom));
  }
}

/* static */
void InspectorUtils::AddPseudoClassLock(GlobalObject& aGlobalObject,
                                        Element& aElement,
                                        const nsAString& aPseudoClass,
                                        bool aEnabled) {
  ElementState state = GetStatesForPseudoClass(aPseudoClass);
  if (state.IsEmpty()) {
    return;
  }

  aElement.LockStyleStates(state, aEnabled);
}

/* static */
void InspectorUtils::RemovePseudoClassLock(GlobalObject& aGlobal,
                                           Element& aElement,
                                           const nsAString& aPseudoClass) {
  ElementState state = GetStatesForPseudoClass(aPseudoClass);
  if (state.IsEmpty()) {
    return;
  }

  aElement.UnlockStyleStates(state);
}

/* static */
bool InspectorUtils::HasPseudoClassLock(GlobalObject& aGlobalObject,
                                        Element& aElement,
                                        const nsAString& aPseudoClass) {
  ElementState state = GetStatesForPseudoClass(aPseudoClass);
  if (state.IsEmpty()) {
    return false;
  }

  ElementState locks = aElement.LockedStyleStates().mLocks;
  return locks.HasAllStates(state);
}

/* static */
void InspectorUtils::ClearPseudoClassLocks(GlobalObject& aGlobalObject,
                                           Element& aElement) {
  aElement.ClearStyleStateLocks();
}

/* static */
void InspectorUtils::ParseStyleSheet(GlobalObject& aGlobalObject,
                                     StyleSheet& aSheet,
                                     const nsACString& aInput,
                                     ErrorResult& aRv) {
  aSheet.ReparseSheet(aInput, aRv);
}

bool InspectorUtils::IsCustomElementName(GlobalObject&, const nsAString& aName,
                                         const nsAString& aNamespaceURI) {
  if (aName.IsEmpty()) {
    return false;
  }

  int32_t namespaceID;
  nsNameSpaceManager::GetInstance()->RegisterNameSpace(aNamespaceURI,
                                                       namespaceID);

  RefPtr<nsAtom> nameElt = NS_Atomize(aName);
  return nsContentUtils::IsCustomElementName(nameElt, namespaceID);
}

bool InspectorUtils::IsElementThemed(GlobalObject&, Element& aElement) {
  // IsThemed will check if the native theme supports the widget using
  // ThemeSupportsWidget which in turn will check that the widget is not
  // already styled by content through nsNativeTheme::IsWidgetStyled. We
  // assume that if the native theme styles the widget and the author did not
  // override the appropriate styles, the theme will provide focus styling.
  nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames);
  return frame && frame->IsThemed();
}

bool InspectorUtils::IsUsedColorSchemeDark(GlobalObject&, Element& aElement) {
  nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames);
  return frame && LookAndFeel::ColorSchemeForFrame(frame) == ColorScheme::Dark;
}

Element* InspectorUtils::ContainingBlockOf(GlobalObject&, Element& aElement) {
  nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames);
  if (!frame) {
    return nullptr;
  }
  nsIFrame* cb = frame->GetContainingBlock();
  if (!cb) {
    return nullptr;
  }
  return Element::FromNodeOrNull(cb->GetContent());
}

bool InspectorUtils::IsBlockContainer(GlobalObject&, Element& aElement) {
  nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames);
  if (!frame) {
    return false;
  }
  if (frame->IsBlockFrameOrSubclass()) {
    return true;
  }
  // ScrollContainerFrame::GetContentInsertionFrame() jumps across the block and
  // returns the ruby inside (because it calls GetContentInsertionFrame on its
  // own). So we have to account for that here.
  if (auto* sc = frame->GetScrollTargetFrame()) {
    if (sc->GetScrolledFrame()->IsBlockFrameOrSubclass()) {
      return true;
    }
  }
  if (nsIFrame* inner = frame->GetContentInsertionFrame()) {
    if (inner->IsBlockFrameOrSubclass()) {
      return true;
    }
  }
  return false;
}

void InspectorUtils::GetBlockLineCounts(GlobalObject& aGlobal,
                                        Element& aElement,
                                        Nullable<nsTArray<uint32_t>>& aResult) {
  nsBlockFrame* block =
      do_QueryFrame(aElement.GetPrimaryFrame(FlushType::Layout));
  if (!block) {
    aResult.SetNull();
    return;
  }

  // If CSS columns were specified on the actual block element (rather than an
  // ancestor block, GetPrimaryFrame will return its ColumnSetWrapperFrame, and
  // we need to drill down to the actual block that contains the lines.
  if (block->IsColumnSetWrapperFrame()) {
    nsIFrame* firstChild = block->PrincipalChildList().FirstChild();
    if (!firstChild->IsColumnSetFrame()) {
      aResult.SetNull();
      return;
    }
    block = do_QueryFrame(firstChild->PrincipalChildList().FirstChild());
    if (!block || block->GetContent() != &aElement) {
      aResult.SetNull();
      return;
    }
  }

  nsTArray<uint32_t> result;
  do {
    result.AppendElement(block->Lines().size());
    block = static_cast<nsBlockFrame*>(block->GetNextInFlow());
  } while (block);

  aResult.SetValue(std::move(result));
}

static bool FrameHasSpecifiedSize(const nsIFrame* aFrame) {
  auto wm = aFrame->GetWritingMode();

  const nsStylePosition* stylePos = aFrame->StylePosition();
  const auto anchorResolutionParams = AnchorPosResolutionParams::From(aFrame);

  return stylePos->ISize(wm, anchorResolutionParams)->IsLengthPercentage() ||
         stylePos->BSize(wm, anchorResolutionParams)->IsLengthPercentage();
}

static bool IsFrameOutsideOfAncestor(const nsIFrame* aFrame,
                                     const nsIFrame* aAncestorFrame,
                                     const nsRect& aAncestorRect) {
  nsRect frameRectInAncestorSpace = nsLayoutUtils::TransformFrameRectToAncestor(
      aFrame, aFrame->ScrollableOverflowRect(), RelativeTo{aAncestorFrame},
      nullptr, nullptr, false, nullptr);

  // We use nsRect::SaturatingUnionEdges because it correctly handles the case
  // of a zero-width or zero-height frame, which we still want to consider as
  // contributing to the union.
  nsRect unionizedRect =
      frameRectInAncestorSpace.SaturatingUnionEdges(aAncestorRect);

  // If frameRectInAncestorSpace is inside aAncestorRect then union of
  // frameRectInAncestorSpace and aAncestorRect should be equal to aAncestorRect
  // hence if it is equal, then false should be returned.

  return !(unionizedRect == aAncestorRect);
}

static void AddOverflowingChildrenOfElement(const nsIFrame* aFrame,
                                            const nsIFrame* aAncestorFrame,
                                            const nsRect& aRect,
                                            SimpleContentList& aList) {
  MOZ_ASSERT(aFrame, "we assume the passed-in frame is non-null");
  for (const auto& childList : aFrame->ChildLists()) {
    for (const nsIFrame* child : childList.mList) {
      // We want to identify if the child or any of its children have a
      // frame that is outside of aAncestorFrame. Ideally, child would have
      // a frame rect that encompasses all of its children, but this is not
      // guaranteed by the frame tree. So instead we first check other
      // conditions that indicate child is an interesting frame:
      //
      // 1) child has a specified size
      // 2) none of child's children are implicated
      //
      // If either of these conditions are true, we *then* check if child's
      // frame is outside of aAncestorFrame, and if so, we add child's content
      // to aList.

      if (FrameHasSpecifiedSize(child) &&
          IsFrameOutsideOfAncestor(child, aAncestorFrame, aRect)) {
        aList.MaybeAppendElement(child->GetContent());
        continue;
      }

      uint32_t currListLength = aList.Length();
      AddOverflowingChildrenOfElement(child, aAncestorFrame, aRect, aList);

      // If child is a leaf node, length of aList should remain same after
      // calling AddOverflowingChildrenOfElement on it.
      if (currListLength == aList.Length() &&
          IsFrameOutsideOfAncestor(child, aAncestorFrame, aRect)) {
        aList.MaybeAppendElement(child->GetContent());
      }
    }
  }
}

already_AddRefed<dom::NodeList> InspectorUtils::GetOverflowingChildrenOfElement(
    GlobalObject& aGlobal, Element& aElement) {
  auto list = MakeRefPtr<SimpleContentList>(&aElement);
  const ScrollContainerFrame* scrollContainerFrame =
      aElement.GetScrollContainerFrame();
  // Element must be a ScrollContainerFrame.
  if (!scrollContainerFrame) {
    return list.forget();
  }

  auto scrollPortRect = scrollContainerFrame->GetScrollPortRect();
  const nsIFrame* scrolledFrame = scrollContainerFrame->GetScrolledFrame();
  AddOverflowingChildrenOfElement(scrolledFrame, scrollContainerFrame,
                                  scrollPortRect, *list);
  return list.forget();
}

/* static */
void InspectorUtils::GetRegisteredCssHighlights(GlobalObject& aGlobalObject,
                                                Document& aDocument,
                                                bool aActiveOnly,
                                                nsTArray<nsString>& aResult) {
  for (auto const& iter : aDocument.HighlightRegistry().HighlightsOrdered()) {
    const RefPtr<nsAtom>& highlightName = iter.first();
    const RefPtr<Highlight>& highlight = iter.second();
    if (!aActiveOnly || highlight->Size() > 0) {
      aResult.AppendElement(highlightName->GetUTF16String());
    }
  }
}

/* static */
void InspectorUtils::GetCSSRegisteredProperties(
    GlobalObject& aGlobalObject, Document& aDocument,
    nsTArray<InspectorCSSPropertyDefinition>& aResult) {
  nsTArray<StylePropDef> result;

  ServoStyleSet& styleSet = aDocument.EnsureStyleSet();
  // Update the rules before looking up @property rules.
  styleSet.UpdateStylistIfNeeded();

  Servo_GetRegisteredCustomProperties(styleSet.RawData(), &result);
  for (const auto& propDef : result) {
    InspectorCSSPropertyDefinition& property = *aResult.AppendElement();

    // Servo does not include the "--" prefix in the property definition name.
    // Add it back as it's easier for DevTools to handle them _with_ "--".
    property.mName.AssignLiteral("--");
    property.mName.Append(nsAtomCString(propDef.name.AsAtom()));
    property.mSyntax.Append(propDef.syntax);
    property.mInherits = propDef.inherits;
    if (propDef.has_initial_value) {
      property.mInitialValue.Append(propDef.initial_value);
    } else {
      property.mInitialValue.SetIsVoid(true);
    }
    property.mFromJS = propDef.from_js;
  }
}

/* static */
void InspectorUtils::GetCSSRegisteredProperty(
    GlobalObject& aGlobalObject, Document& aDocument, const nsACString& aName,
    Nullable<InspectorCSSPropertyDefinition>& aResult) {
  StylePropDef result{StyleAtom(NS_Atomize(aName))};

  // Update the rules before looking up @property rules.
  ServoStyleSet& styleSet = aDocument.EnsureStyleSet();
  styleSet.UpdateStylistIfNeeded();

  if (!Servo_GetRegisteredCustomProperty(styleSet.RawData(), &aName, &result)) {
    aResult.SetNull();
    return;
  }

  InspectorCSSPropertyDefinition& propDef = aResult.SetValue();

  // Servo does not include the "--" prefix in the property definition name.
  // Add it back as it's easier for DevTools to handle them _with_ "--".
  propDef.mName.AssignLiteral("--");
  propDef.mName.Append(nsAtomCString(result.name.AsAtom()));
  propDef.mSyntax.Append(result.syntax);
  propDef.mInherits = result.inherits;
  if (result.has_initial_value) {
    propDef.mInitialValue.Append(result.initial_value);
  } else {
    propDef.mInitialValue.SetIsVoid(true);
  }
  propDef.mFromJS = result.from_js;
}

/* static */
bool InspectorUtils::ValueMatchesSyntax(GlobalObject&, Document& aDocument,
                                        const nsACString& aValue,
                                        const nsACString& aSyntax) {
  return Servo_Value_Matches_Syntax(&aValue, &aSyntax,
                                    aDocument.DefaultStyleAttrURLData());
}

/* static */
void InspectorUtils::GetRuleBodyText(GlobalObject&,
                                     const nsACString& aInitialText,
                                     nsACString& aBodyText) {
  Servo_GetRuleBodyText(&aInitialText, &aBodyText);
}

/* static */
void InspectorUtils::ReplaceBlockRuleBodyTextInStylesheet(
    GlobalObject&, const nsACString& aStyleSheetText, uint32_t aLine,
    uint32_t aColumn, const nsACString& aNewBodyText,
    nsACString& aNewStyleSheetText) {
  Servo_ReplaceBlockRuleBodyTextInStylesheetText(
      &aStyleSheetText, aLine, aColumn, &aNewBodyText, &aNewStyleSheetText);
}

void InspectorUtils::SetVerticalClipping(GlobalObject&,
                                         BrowsingContext* aContext,
                                         mozilla::CSSCoord aOffset) {
  MOZ_ASSERT(XRE_IsParentProcess());
  if (!aContext) {
    return;
  }

  CanonicalBrowsingContext* canonical = aContext->Canonical();
  if (!canonical) {
    return;
  }

  BrowserParent* parent = canonical->GetBrowserParent();
  if (!parent) {
    return;
  }
  const LayoutDeviceToCSSScale scale = parent->GetLayoutDeviceToCSSScale();
  const mozilla::LayoutDeviceCoord layoutOffset = aOffset / scale;
  const mozilla::ScreenCoord screenOffset = ViewAs<ScreenPixel>(
      layoutOffset, PixelCastJustification::LayoutDeviceIsScreenForBounds);
  const mozilla::ScreenIntCoord offset = screenOffset.Rounded();
  parent->DynamicToolbarOffsetChanged(offset);

  RefPtr<nsIWidget> widget = canonical->GetParentProcessWidgetContaining();
  if (!widget) {
    return;
  }
  widget->DynamicToolbarOffsetChanged(offset);
}

void InspectorUtils::SetDynamicToolbarMaxHeight(GlobalObject&,
                                                BrowsingContext* aContext,
                                                mozilla::CSSCoord aHeight) {
  MOZ_ASSERT(XRE_IsParentProcess());
  if (!aContext) {
    return;
  }

  CanonicalBrowsingContext* canonical = aContext->Canonical();
  if (!canonical) {
    return;
  }

  BrowserParent* parent = canonical->GetBrowserParent();
  if (!parent) {
    return;
  }

  const LayoutDeviceToCSSScale scale = parent->GetLayoutDeviceToCSSScale();
  const mozilla::LayoutDeviceCoord layoutOffset = aHeight / scale;
  const mozilla::ScreenCoord screenOffset = ViewAs<ScreenPixel>(
      layoutOffset, PixelCastJustification::LayoutDeviceIsScreenForBounds);
  const mozilla::ScreenIntCoord height = screenOffset.Rounded();
  parent->DynamicToolbarMaxHeightChanged(height);
}

uint16_t InspectorUtils::GetGridContainerType(GlobalObject&,
                                              Element& aElement) {
  auto* f = nsGridContainerFrame::GetGridContainerFrame(
      aElement.GetPrimaryFrame(FlushType::Frames));
  if (!f) {
    return InspectorUtils_Binding::GRID_NONE;
  }
  uint16_t result = InspectorUtils_Binding::GRID_CONTAINER;
  if (f->IsRowSubgrid()) {
    result |= InspectorUtils_Binding::GRID_SUBGRID_ROW;
  }
  if (f->IsColSubgrid()) {
    result |= InspectorUtils_Binding::GRID_SUBGRID_COL;
  }
  return result;
}

void InspectorUtils::GetAnchorFor(GlobalObject&, Element& aElement,
                                  const nsAString& aName,
                                  Nullable<InspectorAnchorElement>& aResult) {
  auto* frame = aElement.GetPrimaryFrame(FlushType::Frames);
  if (!frame || !frame->IsAbsolutelyPositioned()) {
    return;
  }

  nsIFrame* anchor = nullptr;
  RefPtr<nsAtom> name;
  ScopedNameRef scopedName{nullptr, StyleCascadeLevel::Default()};
  InspectorAnchorType type = InspectorAnchorType::Explicit;
  if (aName.IsEmpty()) {
    // Anchor name, otherwise implicit anchor.
    const auto& positionAnchor = frame->StylePosition()->mPositionAnchor;
    if (positionAnchor.value.IsIdent()) {
      scopedName = {positionAnchor.value.AsIdent().AsAtom(),
                    positionAnchor.scope};
    } else {
      auto implicit = AnchorPositioningUtils::GetAnchorPosImplicitAnchor(frame);
      anchor = implicit.mAnchorFrame;
      if (!anchor) {
        return;
      }
      switch (implicit.mKind) {
        case AnchorPositioningUtils::ImplicitAnchorKind::None:
          break;
        case AnchorPositioningUtils::ImplicitAnchorKind::Popover:
          type = InspectorAnchorType::Popover;
          break;
        case AnchorPositioningUtils::ImplicitAnchorKind::PseudoElement:
          type = InspectorAnchorType::Pseudo_element;
          break;
      }
      auto& result = aResult.SetValue();
      result.mElement = *anchor->GetContent()->AsElement();
      result.mType = type;
      return;
    }
  } else {
    // TODO(emilio): Allow looking up names from other trees.
    name = NS_Atomize(aName);
    scopedName = {name, StyleCascadeLevel::Default()};
  }
  anchor = frame->PresShell()->GetAnchorPosAnchor(scopedName, frame);
  if (!anchor) {
    return;
  }
  auto& result = aResult.SetValue();
  result.mElement = *anchor->GetContent()->AsElement();
  result.mType = type;
}

/* static */
void InspectorUtils::GetAnchorNamesFor(GlobalObject& aGlobalObject,
                                       Element& aElement,
                                       nsTArray<nsString>& aResult) {
  auto* frame = aElement.GetPrimaryFrame(FlushType::Frames);
  if (!frame || !frame->IsAbsolutelyPositioned()) {
    return;
  }

  frame->PresShell()->CollectAnchorNames(frame, aResult);
}

/* static */
void InspectorUtils::GetComputationStepsSupportedCSSFunctions(
    GlobalObject& aGlobalObject, nsTArray<nsCString>& aResult) {
  Servo_GetComputationStepsSupportedCSSFunctions(&aResult);
}

/* static */
void InspectorUtils::GetComputationSteps(GlobalObject& aGlobalObject,
                                         const nsAString& aExpression,
                                         Element& aElement,
                                         const nsAString& aPseudo,
                                         nsTArray<nsString>& aResult) {
  Document* doc = aElement.GetComposedDoc();
  if (!doc) {
    return;
  }

  auto pseudo = PseudoStyleRequest::Parse(
      aPseudo, aElement.OwnerDoc()->DefaultStyleAttrURLData());
  if (!pseudo) {
    return;
  }

  RefPtr<const ComputedStyle> computedStyle =
      GetCleanComputedStyleForElement(&aElement, *pseudo);
  if (!computedStyle) {
    // This can fail for elements that are not in the document or
    // if the document they're in doesn't have a presshell.  Bail out.
    return;
  }

  Servo_GetComputationSteps(&aExpression, &aElement, pseudo->mType,
                            computedStyle, doc->EnsureStyleSet().RawData(),
                            &aResult);
}

}  // namespace mozilla::dom

Messung V0.5 in Prozent
C=91 H=96 G=93

¤ Dauer der Verarbeitung: 0.23 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002