layout/inspector/InspectorUtils.cpp
author Xianzhu Wang <wangxianzhu@chromium.org>
Tue, 05 Mar 2019 12:18:01 +0000
changeset 464575 4325ba7b38576495a78289c2a8f4dff391922e66
parent 463546 aa539ea8ce2790a991b512b1aea46ab260d9c0f5
child 464858 8b9c4b28f0332517cd189d475cc02a493e61737b
permissions -rw-r--r--
Bug 1529059 [wpt PR 15420] - [BlinkGenPropertyTrees] Initiailize double_sided of synthetic effect, a=testonly Automatic update from web-platform-tests [BlinkGenPropertyTrees] Initiailize double_sided of synthetic effect Previously synthetic effects always had double_sided==false, causing the layer disappear when the backface was facing forward. Bug: 928190 Change-Id: I35534b40346d5c5918bc99c00a4ca6b4e3b68796 Reviewed-on: https://chromium-review.googlesource.com/c/1475815 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org> Cr-Commit-Position: refs/heads/master@{#632764} -- wpt-commits: a89467050deaf1dcbd9140a2f0670b1b85e518ee wpt-pr: 15420

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/ArrayUtils.h"
#include "mozilla/EventStates.h"

#include "inLayoutUtils.h"

#include "gfxTextRun.h"
#include "nsArray.h"
#include "nsAutoPtr.h"
#include "nsIServiceManager.h"
#include "nsString.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsIContentInlines.h"
#include "mozilla/dom/Document.h"
#include "nsIPresShell.h"
#include "nsIDOMWindow.h"
#include "nsXBLBinding.h"
#include "nsXBLPrototypeBinding.h"
#include "nsIMutableArray.h"
#include "nsBindingManager.h"
#include "ChildIterator.h"
#include "nsComputedDOMStyle.h"
#include "mozilla/EventStateManager.h"
#include "nsAtom.h"
#include "nsRange.h"
#include "mozilla/StyleSheetInlines.h"
#include "mozilla/dom/CharacterData.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/CSSStyleRule.h"
#include "mozilla/dom/InspectorUtilsBinding.h"
#include "mozilla/dom/ToJSValue.h"
#include "nsCSSProps.h"
#include "nsCSSValue.h"
#include "nsColor.h"
#include "mozilla/ServoStyleSet.h"
#include "nsStyleUtil.h"
#include "nsQueryObject.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoStyleRuleMap.h"
#include "mozilla/ServoCSSParser.h"
#include "mozilla/dom/InspectorUtils.h"
#include "mozilla/dom/InspectorFontFace.h"

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

namespace mozilla {
namespace dom {

/* 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.
  nsIPresShell* presShell = aDocument.GetShell();

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

    if (!aDocumentOnly) {
      SheetType sheetType = SheetType::Agent;
      for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
        aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
      }
      sheetType = SheetType::User;
      for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
        aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i));
      }
    }

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

    // The XBL stylesheet array will quite often be full of duplicates. Cope:
    //
    // FIXME(emilio, bug 1454467): I think this is not true since bug 1452525.
    nsTHashtable<nsPtrHashKey<StyleSheet>> sheetSet;
    for (StyleSheet* sheet : xblSheetArray) {
      if (!sheetSet.Contains(sheet)) {
        sheetSet.PutEntry(sheet);
        aResult.AppendElement(sheet);
      }
    }
  }

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

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) {
  // First do the special cases -- document nodes and anonymous content
  nsINode* parent = nullptr;

  if (aNode.IsDocument()) {
    parent = inLayoutUtils::GetContainerFor(*aNode.AsDocument());
  } else if (aShowingAnonymousContent) {
    if (aNode.IsContent()) {
      parent = aNode.AsContent()->GetFlattenedTreeParent();
    }
  }

  if (!parent) {
    // Ok, just get the normal DOM parent node
    return aNode.GetParentNode();
  }

  return parent;
}

/* static */
already_AddRefed<nsINodeList> InspectorUtils::GetChildrenForNode(
    nsINode& aNode, bool aShowingAnonymousContent) {
  nsCOMPtr<nsINodeList> kids;

  if (aShowingAnonymousContent) {
    if (aNode.IsContent()) {
      kids = aNode.AsContent()->GetChildren(nsIContent::eAllChildren);
    }
  }

  if (!kids) {
    kids = aNode.ChildNodes();
  }

  return kids.forget();
}

/* static */
void InspectorUtils::GetCSSStyleRules(
    GlobalObject& aGlobalObject, Element& aElement, const nsAString& aPseudo,
    nsTArray<RefPtr<BindingStyleRule>>& aResult) {
  RefPtr<nsAtom> pseudoElt;
  if (!aPseudo.IsEmpty()) {
    pseudoElt = NS_Atomize(aPseudo);
  }

  RefPtr<ComputedStyle> computedStyle =
      GetCleanComputedStyleForElement(&aElement, pseudoElt);
  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;
  }

  Document* doc = aElement.OwnerDoc();
  nsIPresShell* shell = doc->GetShell();
  if (!shell) {
    return;
  }

  nsTArray<const RawServoStyleRule*> rawRuleList;
  Servo_ComputedValues_GetStyleRuleList(computedStyle, &rawRuleList);

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

  // Collect style rule maps for bindings.
  for (nsIContent* bindingContent = &aElement; bindingContent;
       bindingContent = bindingContent->GetBindingParent()) {
    for (nsXBLBinding* binding = bindingContent->GetXBLBinding(); binding;
         binding = binding->GetBaseBinding()) {
      if (auto* map = binding->PrototypeBinding()->GetServoStyleRuleMap()) {
        maps.AppendElement(map);
      }
    }
    // Note that we intentionally don't cut off here, unlike when we
    // do styling, because even if style rules from parent binding
    // do not apply to the element directly in those cases, their
    // rules may still show up in the list we get above due to the
    // inheritance in cascading.
  }

  // Now shadow DOM stuff...
  if (auto* shadow = aElement.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 RawServoStyleRule* rawRule : Reversed(rawRuleList)) {
    CSSStyleRule* rule = nullptr;
    for (ServoStyleRuleMap* map : maps) {
      rule = map->Lookup(rawRule);
      if (rule) {
        break;
      }
    }
    if (rule) {
      aResult.AppendElement(rule);
    } else {
#ifdef DEBUG
      nsAutoCString str;
      fprintf(stderr, "%s\n", str.get());
      Servo_StyleRule_Debug(rawRule, &str);
      MOZ_CRASH_UNSAFE_PRINTF(
          "We should be able to map a raw rule to a rule: %s\n", str.get());
#endif
    }
  }
}

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

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

/* static */
uint32_t InspectorUtils::GetRelativeRuleLine(GlobalObject& aGlobal,
                                             css::Rule& aRule) {
  uint32_t lineNumber = aRule.GetLineNumber();

  // If aRule was parsed along with its stylesheet, then it will
  // have an absolute lineNumber that we need to remap to its
  // containing node. But if aRule was added via CSSOM after parsing,
  // then it has a sort-of relative line number already:
  // Gecko gives all rules a 0 lineNumber.
  // Servo gives the first line of a rule a 0 lineNumber, and then
  //   counts up from there.

  // The Servo behavior is arguably more correct, but harder to
  // interpret for purposes of deciding whether a lineNumber is
  // relative or absolute.

  // Since most of the time, inserted rules are single line and
  // therefore have 0 lineNumbers in both Gecko and Servo, we use
  // that to detect that a lineNumber is already relative.

  // There is one ugly edge case that we avoid: if an inserted rule
  // is multi-line, then Servo will give it 0+ lineNumbers. If we
  // do relative number mapping on those line numbers, we could get
  // negative underflow. So we check for underflow and instead report
  // a 0 lineNumber.
  StyleSheet* sheet = aRule.GetStyleSheet();
  if (sheet && lineNumber != 0) {
    nsINode* owningNode = sheet->GetOwnerNode();
    if (owningNode) {
      nsCOMPtr<nsIStyleSheetLinkingElement> link =
          do_QueryInterface(owningNode);
      if (link) {
        // Check for underflow, which is one indication that we're
        // trying to remap an already relative lineNumber.
        uint32_t linkLineIndex0 = link->GetLineNumber() - 1;
        if (linkLineIndex0 > lineNumber) {
          lineNumber = 0;
        } else {
          lineNumber -= linkLineIndex0;
        }
      }
    }
  }

  return lineNumber;
}

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

/* static */
uint32_t InspectorUtils::GetSelectorCount(GlobalObject& aGlobal,
                                          BindingStyleRule& aRule) {
  return aRule.GetSelectorCount();
}

/* static */
void InspectorUtils::GetSelectorText(GlobalObject& aGlobal,
                                     BindingStyleRule& aRule,
                                     uint32_t aSelectorIndex, nsString& aText,
                                     ErrorResult& aRv) {
  aRv = aRule.GetSelectorText(aSelectorIndex, aText);
}

/* static */
uint64_t InspectorUtils::GetSpecificity(GlobalObject& aGlobal,
                                        BindingStyleRule& aRule,
                                        uint32_t aSelectorIndex,
                                        ErrorResult& aRv) {
  uint64_t s;
  aRv = aRule.GetSpecificity(aSelectorIndex, &s);
  return s;
}

/* static */
bool InspectorUtils::SelectorMatchesElement(
    GlobalObject& aGlobalObject, Element& aElement, BindingStyleRule& aRule,
    uint32_t aSelectorIndex, const nsAString& aPseudo, ErrorResult& aRv) {
  bool result = false;
  aRv =
      aRule.SelectorMatchesElement(&aElement, aSelectorIndex, aPseudo, &result);
  return result;
}

/* static */
bool InspectorUtils::IsInheritedProperty(GlobalObject& aGlobalObject,
                                         const nsAString& aPropertyName) {
  NS_ConvertUTF16toUTF8 propName(aPropertyName);
  return Servo_Property_IsInherited(&propName);
}

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

  auto appendProperty = [enabledState, &aResult](uint32_t prop) {
    nsCSSPropertyID cssProp = nsCSSPropertyID(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(nsCSSPropertyID(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 nsAString& aProperty,
                                                    nsTArray<nsString>& aResult,
                                                    ErrorResult& aRv) {
  nsCSSPropertyID propertyID = nsCSSProps::LookupProperty(aProperty);

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

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

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

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

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

bool InspectorUtils::CssPropertySupportsType(GlobalObject& aGlobalObject,
                                             const nsAString& aProperty,
                                             uint32_t aType, ErrorResult& aRv) {
  NS_ConvertUTF16toUTF8 property(aProperty);
  if (!aType || aType > InspectorUtils_Binding::TYPE_TIMING_FUNCTION) {
    aRv.Throw(NS_ERROR_INVALID_ARG);
    return false;
  }
  bool found;
  bool result = Servo_Property_SupportsType(&property, aType, &found);
  if (!found) {
    aRv.Throw(NS_ERROR_FAILURE);
    return false;
  }
  return result;
}

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

/* static */
void InspectorUtils::RgbToColorName(GlobalObject& aGlobalObject, uint8_t aR,
                                    uint8_t aG, uint8_t aB,
                                    nsAString& aColorName, ErrorResult& aRv) {
  const char* color = NS_RGBToColorName(NS_RGB(aR, aG, aB));
  if (!color) {
    aColorName.Truncate();
    aRv.Throw(NS_ERROR_INVALID_ARG);
    return;
  }

  aColorName.AssignASCII(color);
}

/* static */
void InspectorUtils::ColorToRGBA(GlobalObject& aGlobalObject,
                                 const nsAString& aColorString,
                                 Nullable<InspectorRGBATuple>& aResult) {
  nscolor color = NS_RGB(0, 0, 0);

  if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), 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 */
bool InspectorUtils::IsValidCSSColor(GlobalObject& aGlobalObject,
                                     const nsAString& aColorString) {
  return ServoCSSParser::IsValidCSSColor(aColorString);
}

void InspectorUtils::GetBindingURLs(GlobalObject& aGlobalObject,
                                    Element& aElement,
                                    nsTArray<nsString>& aResult) {
  nsXBLBinding* binding = aElement.GetXBLBinding();

  while (binding) {
    nsCString spec;
    nsCOMPtr<nsIURI> bindingURI = binding->PrototypeBinding()->BindingURI();
    bindingURI->GetSpec(spec);
    nsString* resultURI = aResult.AppendElement();
    CopyASCIItoUTF16(spec, *resultURI);
    binding = binding->GetBaseBinding();
  }
}

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

  return esm->SetContentState(&aElement, EventStates(aState));
}

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

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

  if (aClearActiveDocument && EventStates(aState) == NS_EVENT_STATE_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 EventStates
  return aElement.State().GetInternalValue();
}

/* static */
already_AddRefed<ComputedStyle> InspectorUtils::GetCleanComputedStyleForElement(
    dom::Element* aElement, nsAtom* aPseudo) {
  MOZ_ASSERT(aElement);

  Document* doc = aElement->GetComposedDoc();
  if (!doc) {
    return nullptr;
  }

  nsIPresShell* presShell = doc->GetShell();
  if (!presShell) {
    return nullptr;
  }

  nsPresContext* presContext = presShell->GetPresContext();
  if (!presContext) {
    return nullptr;
  }

  presContext->EnsureSafeToHandOutCSSRules();

  return nsComputedDOMStyle::GetComputedStyle(aElement, aPseudo);
}

/* static */
void InspectorUtils::GetUsedFontFaces(
    GlobalObject& aGlobalObject, nsRange& aRange, uint32_t aMaxRanges,
    bool aSkipCollapsedWhitespace,
    nsTArray<nsAutoPtr<InspectorFontFace>>& aResult, ErrorResult& aRv) {
  nsresult rv =
      aRange.GetUsedFontFaces(aResult, aMaxRanges, aSkipCollapsedWhitespace);
  if (NS_FAILED(rv)) {
    aRv.Throw(rv);
  }
}

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

/* static */
void InspectorUtils::GetCSSPseudoElementNames(GlobalObject& aGlobalObject,
                                              nsTArray<nsString>& aResult) {
  const auto kPseudoCount =
      static_cast<size_t>(PseudoStyleType::CSSPseudoElementsEnd);
  for (size_t i = 0; i < kPseudoCount; ++i) {
    PseudoStyleType type = static_cast<PseudoStyleType>(i);
    if (nsCSSPseudoElements::IsEnabled(type, CSSEnabledState::eForAllContent)) {
      nsAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type);
      aResult.AppendElement(nsDependentAtomString(atom));
    }
  }
}

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

  aElement.LockStyleStates(state, aEnabled);
}

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

  aElement.UnlockStyleStates(state);
}

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

  EventStates 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 nsAString& aInput,
                                     ErrorResult& aRv) {
  aRv = aSheet.ReparseSheet(aInput);
}

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

  int32_t namespaceID;
  nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
                                                        namespaceID);

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

}  // namespace dom
}  // namespace mozilla