summaryrefslogtreecommitdiffstats
path: root/layout/inspector/inDOMUtils.cpp
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /layout/inspector/inDOMUtils.cpp
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'layout/inspector/inDOMUtils.cpp')
-rw-r--r--layout/inspector/inDOMUtils.cpp1351
1 files changed, 1351 insertions, 0 deletions
diff --git a/layout/inspector/inDOMUtils.cpp b/layout/inspector/inDOMUtils.cpp
new file mode 100644
index 000000000..9f1dcaad3
--- /dev/null
+++ b/layout/inspector/inDOMUtils.cpp
@@ -0,0 +1,1351 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "inDOMUtils.h"
+#include "inLayoutUtils.h"
+
+#include "nsArray.h"
+#include "nsAutoPtr.h"
+#include "nsIServiceManager.h"
+#include "nsString.h"
+#include "nsIStyleSheetLinkingElement.h"
+#include "nsIContentInlines.h"
+#include "nsIDOMElement.h"
+#include "nsIDocument.h"
+#include "nsIPresShell.h"
+#include "nsIDOMDocument.h"
+#include "nsIDOMCharacterData.h"
+#include "nsRuleNode.h"
+#include "nsIStyleRule.h"
+#include "mozilla/css/StyleRule.h"
+#include "nsICSSStyleRuleDOMWrapper.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 "nsIAtom.h"
+#include "nsRange.h"
+#include "nsContentList.h"
+#include "mozilla/StyleSheetInlines.h"
+#include "mozilla/dom/Element.h"
+#include "nsRuleWalker.h"
+#include "nsRuleProcessorData.h"
+#include "nsCSSPseudoClasses.h"
+#include "nsCSSRuleProcessor.h"
+#include "mozilla/dom/CSSLexer.h"
+#include "mozilla/dom/InspectorUtilsBinding.h"
+#include "mozilla/dom/ToJSValue.h"
+#include "nsCSSParser.h"
+#include "nsCSSProps.h"
+#include "nsCSSValue.h"
+#include "nsColor.h"
+#include "nsStyleSet.h"
+#include "nsStyleUtil.h"
+#include "nsQueryObject.h"
+
+using namespace mozilla;
+using namespace mozilla::css;
+using namespace mozilla::dom;
+
+///////////////////////////////////////////////////////////////////////////////
+
+inDOMUtils::inDOMUtils()
+{
+}
+
+inDOMUtils::~inDOMUtils()
+{
+}
+
+NS_IMPL_ISUPPORTS(inDOMUtils, inIDOMUtils)
+
+///////////////////////////////////////////////////////////////////////////////
+// inIDOMUtils
+
+NS_IMETHODIMP
+inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
+ nsISupports ***aSheets)
+{
+ NS_ENSURE_ARG_POINTER(aDocument);
+
+ nsTArray<RefPtr<CSSStyleSheet>> sheets;
+
+ nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument);
+ MOZ_ASSERT(document);
+
+ // Get the agent, then user and finally xbl sheets in the style set.
+ nsIPresShell* presShell = document->GetShell();
+
+ if (presShell && presShell->StyleSet()->IsServo()) {
+ // XXXheycam ServoStyleSets don't have the ability to expose their
+ // sheets in a script-accessible way yet.
+ NS_ERROR("stylo: ServoStyleSets cannot expose their sheets to script yet");
+ return NS_ERROR_FAILURE;
+ }
+
+ if (presShell) {
+ nsStyleSet* styleSet = presShell->StyleSet()->AsGecko();
+ SheetType sheetType = SheetType::Agent;
+ for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
+ sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
+ }
+ sheetType = SheetType::User;
+ for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
+ sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
+ }
+ AutoTArray<CSSStyleSheet*, 32> xblSheetArray;
+ styleSet->AppendAllXBLStyleSheets(xblSheetArray);
+
+ // The XBL stylesheet array will quite often be full of duplicates. Cope:
+ nsTHashtable<nsPtrHashKey<CSSStyleSheet>> sheetSet;
+ for (CSSStyleSheet* sheet : xblSheetArray) {
+ if (!sheetSet.Contains(sheet)) {
+ sheetSet.PutEntry(sheet);
+ sheets.AppendElement(sheet);
+ }
+ }
+ }
+
+ // Get the document sheets.
+ for (int32_t i = 0; i < document->GetNumberOfStyleSheets(); i++) {
+ // XXXheycam ServoStyleSets don't have the ability to expose their
+ // sheets in a script-accessible way yet.
+ sheets.AppendElement(document->GetStyleSheetAt(i)->AsGecko());
+ }
+
+ nsISupports** ret = static_cast<nsISupports**>(moz_xmalloc(sheets.Length() *
+ sizeof(nsISupports*)));
+
+ for (size_t i = 0; i < sheets.Length(); i++) {
+ NS_ADDREF(ret[i] = NS_ISUPPORTS_CAST(nsIDOMCSSStyleSheet*, sheets[i]));
+ }
+
+ *aLength = sheets.Length();
+ *aSheets = ret;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::IsIgnorableWhitespace(nsIDOMCharacterData *aDataNode,
+ bool *aReturn)
+{
+ NS_PRECONDITION(aReturn, "Must have an out parameter");
+
+ NS_ENSURE_ARG_POINTER(aDataNode);
+
+ *aReturn = false;
+
+ nsCOMPtr<nsIContent> content = do_QueryInterface(aDataNode);
+ NS_ASSERTION(content, "Does not implement nsIContent!");
+
+ if (!content->TextIsOnlyWhitespace()) {
+ return NS_OK;
+ }
+
+ // Okay. We have only white space. Let's check the white-space
+ // property now and make sure that this isn't preformatted text...
+ nsIFrame* frame = content->GetPrimaryFrame();
+ if (frame) {
+ const nsStyleText* text = frame->StyleText();
+ *aReturn = !text->WhiteSpaceIsSignificant();
+ }
+ else {
+ // empty inter-tag text node without frame, e.g., in between <table>\n<tr>
+ *aReturn = true;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetParentForNode(nsIDOMNode* aNode,
+ bool aShowingAnonymousContent,
+ nsIDOMNode** aParent)
+{
+ NS_ENSURE_ARG_POINTER(aNode);
+
+ // First do the special cases -- document nodes and anonymous content
+ nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode));
+ nsCOMPtr<nsIDOMNode> parent;
+
+ if (doc) {
+ parent = inLayoutUtils::GetContainerFor(*doc);
+ } else if (aShowingAnonymousContent) {
+ nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
+ if (content) {
+ nsIContent* bparent = content->GetFlattenedTreeParent();
+ parent = do_QueryInterface(bparent);
+ }
+ }
+
+ if (!parent) {
+ // Ok, just get the normal DOM parent node
+ aNode->GetParentNode(getter_AddRefs(parent));
+ }
+
+ NS_IF_ADDREF(*aParent = parent);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetChildrenForNode(nsIDOMNode* aNode,
+ bool aShowingAnonymousContent,
+ nsIDOMNodeList** aChildren)
+{
+ NS_ENSURE_ARG_POINTER(aNode);
+ NS_PRECONDITION(aChildren, "Must have an out parameter");
+
+ nsCOMPtr<nsIDOMNodeList> kids;
+
+ if (aShowingAnonymousContent) {
+ nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
+ if (content) {
+ kids = content->GetChildren(nsIContent::eAllChildren);
+ }
+ }
+
+ if (!kids) {
+ aNode->GetChildNodes(getter_AddRefs(kids));
+ }
+
+ kids.forget(aChildren);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetCSSStyleRules(nsIDOMElement *aElement,
+ const nsAString& aPseudo,
+ nsIArrayExtensions **_retval)
+{
+ NS_ENSURE_ARG_POINTER(aElement);
+
+ *_retval = nullptr;
+
+ nsCOMPtr<nsIAtom> pseudoElt;
+ if (!aPseudo.IsEmpty()) {
+ pseudoElt = NS_Atomize(aPseudo);
+ }
+
+ nsRuleNode* ruleNode = nullptr;
+ nsCOMPtr<Element> element = do_QueryInterface(aElement);
+ NS_ENSURE_STATE(element);
+ RefPtr<nsStyleContext> styleContext;
+ GetRuleNodeForElement(element, pseudoElt, getter_AddRefs(styleContext), &ruleNode);
+ if (!ruleNode) {
+ // 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 NS_OK;
+ }
+
+ AutoTArray<nsRuleNode*, 16> ruleNodes;
+ while (!ruleNode->IsRoot()) {
+ ruleNodes.AppendElement(ruleNode);
+ ruleNode = ruleNode->GetParent();
+ }
+
+ nsCOMPtr<nsIMutableArray> rules = nsArray::Create();
+ for (nsRuleNode* ruleNode : Reversed(ruleNodes)) {
+ RefPtr<Declaration> decl = do_QueryObject(ruleNode->GetRule());
+ if (decl) {
+ RefPtr<mozilla::css::StyleRule> styleRule =
+ do_QueryObject(decl->GetOwningRule());
+ if (styleRule) {
+ nsCOMPtr<nsIDOMCSSRule> domRule = styleRule->GetDOMRule();
+ if (domRule) {
+ rules->AppendElement(domRule, /*weak =*/ false);
+ }
+ }
+ }
+ }
+
+ rules.forget(_retval);
+
+ return NS_OK;
+}
+
+static already_AddRefed<StyleRule>
+GetRuleFromDOMRule(nsIDOMCSSStyleRule *aRule, ErrorResult& rv)
+{
+ nsCOMPtr<nsICSSStyleRuleDOMWrapper> rule = do_QueryInterface(aRule);
+ if (!rule) {
+ rv.Throw(NS_ERROR_INVALID_POINTER);
+ return nullptr;
+ }
+
+ RefPtr<StyleRule> cssrule;
+ rv = rule->GetCSSStyleRule(getter_AddRefs(cssrule));
+ if (rv.Failed()) {
+ return nullptr;
+ }
+
+ if (!cssrule) {
+ rv.Throw(NS_ERROR_FAILURE);
+ }
+ return cssrule.forget();
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetRuleLine(nsIDOMCSSRule* aRule, uint32_t* _retval)
+{
+ NS_ENSURE_ARG_POINTER(aRule);
+
+ Rule* rule = aRule->GetCSSRule();
+ if (!rule) {
+ return NS_ERROR_FAILURE;
+ }
+
+ *_retval = rule->GetLineNumber();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetRuleColumn(nsIDOMCSSRule* aRule, uint32_t* _retval)
+{
+ NS_ENSURE_ARG_POINTER(aRule);
+
+ Rule* rule = aRule->GetCSSRule();
+ if (!rule) {
+ return NS_ERROR_FAILURE;
+ }
+
+ *_retval = rule->GetColumnNumber();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetRelativeRuleLine(nsIDOMCSSRule* aRule, uint32_t* _retval)
+{
+ NS_ENSURE_ARG_POINTER(aRule);
+
+ Rule* rule = aRule->GetCSSRule();
+ if (!rule) {
+ return NS_ERROR_FAILURE;
+ }
+
+ uint32_t lineNumber = rule->GetLineNumber();
+ CSSStyleSheet* sheet = rule->GetStyleSheet();
+ if (sheet && lineNumber != 0) {
+ nsINode* owningNode = sheet->GetOwnerNode();
+ if (owningNode) {
+ nsCOMPtr<nsIStyleSheetLinkingElement> link =
+ do_QueryInterface(owningNode);
+ if (link) {
+ lineNumber -= link->GetLineNumber() - 1;
+ }
+ }
+ }
+
+ *_retval = lineNumber;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetCSSLexer(const nsAString& aText, JSContext* aCx,
+ JS::MutableHandleValue aResult)
+{
+ MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
+ JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
+ nsAutoPtr<CSSLexer> lexer(new CSSLexer(aText));
+ if (!WrapNewBindingNonWrapperCachedObject(aCx, scope, lexer, aResult)) {
+ return NS_ERROR_FAILURE;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetSelectorCount(nsIDOMCSSStyleRule* aRule, uint32_t *aCount)
+{
+ ErrorResult rv;
+ RefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
+ if (rv.Failed()) {
+ return rv.StealNSResult();
+ }
+
+ uint32_t count = 0;
+ for (nsCSSSelectorList* sel = rule->Selector(); sel; sel = sel->mNext) {
+ ++count;
+ }
+ *aCount = count;
+ return NS_OK;
+}
+
+static nsCSSSelectorList*
+GetSelectorAtIndex(nsIDOMCSSStyleRule* aRule, uint32_t aIndex, ErrorResult& rv)
+{
+ RefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
+ if (rv.Failed()) {
+ return nullptr;
+ }
+
+ for (nsCSSSelectorList* sel = rule->Selector(); sel;
+ sel = sel->mNext, --aIndex) {
+ if (aIndex == 0) {
+ return sel;
+ }
+ }
+
+ // Ran out of selectors
+ rv.Throw(NS_ERROR_INVALID_ARG);
+ return nullptr;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetSelectorText(nsIDOMCSSStyleRule* aRule,
+ uint32_t aSelectorIndex,
+ nsAString& aText)
+{
+ ErrorResult rv;
+ nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
+ if (rv.Failed()) {
+ return rv.StealNSResult();
+ }
+
+ RefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
+ MOZ_ASSERT(!rv.Failed(), "How could we get a selector but not a rule?");
+
+ sel->mSelectors->ToString(aText, rule->GetStyleSheet(), false);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetSpecificity(nsIDOMCSSStyleRule* aRule,
+ uint32_t aSelectorIndex,
+ uint64_t* aSpecificity)
+{
+ ErrorResult rv;
+ nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
+ if (rv.Failed()) {
+ return rv.StealNSResult();
+ }
+
+ *aSpecificity = sel->mWeight;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement,
+ nsIDOMCSSStyleRule* aRule,
+ uint32_t aSelectorIndex,
+ const nsAString& aPseudo,
+ bool* aMatches)
+{
+ nsCOMPtr<Element> element = do_QueryInterface(aElement);
+ NS_ENSURE_ARG_POINTER(element);
+
+ ErrorResult rv;
+ nsCSSSelectorList* tail = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
+ if (rv.Failed()) {
+ return rv.StealNSResult();
+ }
+
+ // We want just the one list item, not the whole list tail
+ nsAutoPtr<nsCSSSelectorList> sel(tail->Clone(false));
+
+ // Do not attempt to match if a pseudo element is requested and this is not
+ // a pseudo element selector, or vice versa.
+ if (aPseudo.IsEmpty() == sel->mSelectors->IsPseudoElement()) {
+ *aMatches = false;
+ return NS_OK;
+ }
+
+ if (!aPseudo.IsEmpty()) {
+ // We need to make sure that the requested pseudo element type
+ // matches the selector pseudo element type before proceeding.
+ nsCOMPtr<nsIAtom> pseudoElt = NS_Atomize(aPseudo);
+ if (sel->mSelectors->PseudoType() != nsCSSPseudoElements::
+ GetPseudoType(pseudoElt, CSSEnabledState::eIgnoreEnabledState)) {
+ *aMatches = false;
+ return NS_OK;
+ }
+
+ // We have a matching pseudo element, now remove it so we can compare
+ // directly against |element| when proceeding into SelectorListMatches.
+ // It's OK to do this - we just cloned sel and nothing else is using it.
+ sel->RemoveRightmostSelector();
+ }
+
+ element->OwnerDoc()->FlushPendingLinkUpdates();
+ // XXXbz what exactly should we do with visited state here?
+ TreeMatchContext matchingContext(false,
+ nsRuleWalker::eRelevantLinkUnvisited,
+ element->OwnerDoc(),
+ TreeMatchContext::eNeverMatchVisited);
+ *aMatches = nsCSSRuleProcessor::SelectorListMatches(element, matchingContext,
+ sel);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::IsInheritedProperty(const nsAString &aPropertyName, bool *_retval)
+{
+ nsCSSPropertyID prop = nsCSSProps::
+ LookupProperty(aPropertyName, CSSEnabledState::eIgnoreEnabledState);
+ if (prop == eCSSProperty_UNKNOWN) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ if (prop == eCSSPropertyExtra_variable) {
+ *_retval = true;
+ return NS_OK;
+ }
+
+ if (nsCSSProps::IsShorthand(prop)) {
+ prop = nsCSSProps::SubpropertyEntryFor(prop)[0];
+ }
+
+ nsStyleStructID sid = nsCSSProps::kSIDTable[prop];
+ *_retval = !nsCachedStyleData::IsReset(sid);
+ return NS_OK;
+}
+
+extern const char* const kCSSRawProperties[];
+
+NS_IMETHODIMP
+inDOMUtils::GetCSSPropertyNames(uint32_t aFlags, uint32_t* aCount,
+ char16_t*** aProps)
+{
+ // maxCount is the largest number of properties we could have; our actual
+ // number might be smaller because properties might be disabled.
+ uint32_t maxCount;
+ if (aFlags & EXCLUDE_SHORTHANDS) {
+ maxCount = eCSSProperty_COUNT_no_shorthands;
+ } else {
+ maxCount = eCSSProperty_COUNT;
+ }
+
+ if (aFlags & INCLUDE_ALIASES) {
+ maxCount += (eCSSProperty_COUNT_with_aliases - eCSSProperty_COUNT);
+ }
+
+ char16_t** props =
+ static_cast<char16_t**>(moz_xmalloc(maxCount * sizeof(char16_t*)));
+
+#define DO_PROP(_prop) \
+ PR_BEGIN_MACRO \
+ nsCSSPropertyID cssProp = nsCSSPropertyID(_prop); \
+ if (nsCSSProps::IsEnabled(cssProp, CSSEnabledState::eForAllContent)) { \
+ props[propCount] = \
+ ToNewUnicode(nsDependentCString(kCSSRawProperties[_prop])); \
+ ++propCount; \
+ } \
+ PR_END_MACRO
+
+ // prop is the property id we're considering; propCount is how many properties
+ // we've put into props so far.
+ uint32_t prop = 0, propCount = 0;
+ for ( ; prop < eCSSProperty_COUNT_no_shorthands; ++prop) {
+ if (nsCSSProps::PropertyParseType(nsCSSPropertyID(prop)) !=
+ CSS_PROPERTY_PARSE_INACCESSIBLE) {
+ DO_PROP(prop);
+ }
+ }
+
+ if (!(aFlags & EXCLUDE_SHORTHANDS)) {
+ for ( ; prop < eCSSProperty_COUNT; ++prop) {
+ // Some shorthands are also aliases
+ if ((aFlags & INCLUDE_ALIASES) ||
+ !nsCSSProps::PropHasFlags(nsCSSPropertyID(prop),
+ CSS_PROPERTY_IS_ALIAS)) {
+ DO_PROP(prop);
+ }
+ }
+ }
+
+ if (aFlags & INCLUDE_ALIASES) {
+ for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; ++prop) {
+ DO_PROP(prop);
+ }
+ }
+
+#undef DO_PROP
+
+ *aCount = propCount;
+ *aProps = props;
+
+ return NS_OK;
+}
+
+static void InsertNoDuplicates(nsTArray<nsString>& aArray,
+ const nsAString& aString)
+{
+ size_t i = aArray.IndexOfFirstElementGt(aString);
+ if (i > 0 && aArray[i-1].Equals(aString)) {
+ return;
+ }
+ aArray.InsertElementAt(i, aString);
+}
+
+static void GetKeywordsForProperty(const nsCSSPropertyID aProperty,
+ nsTArray<nsString>& aArray)
+{
+ if (nsCSSProps::IsShorthand(aProperty)) {
+ // Shorthand props have no keywords.
+ return;
+ }
+ const nsCSSProps::KTableEntry* keywordTable =
+ nsCSSProps::kKeywordTableTable[aProperty];
+ if (keywordTable) {
+ for (size_t i = 0; keywordTable[i].mKeyword != eCSSKeyword_UNKNOWN; ++i) {
+ nsCSSKeyword word = keywordTable[i].mKeyword;
+ InsertNoDuplicates(aArray,
+ NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word)));
+ }
+ }
+}
+
+static void GetColorsForProperty(const uint32_t aParserVariant,
+ nsTArray<nsString>& aArray)
+{
+ if (aParserVariant & VARIANT_COLOR) {
+ // GetKeywordsForProperty and GetOtherValuesForProperty assume aArray is sorted,
+ // and if aArray is not empty here, then it's not going to be sorted coming out.
+ MOZ_ASSERT(aArray.Length() == 0);
+ size_t size;
+ const char * const *allColorNames = NS_AllColorNames(&size);
+ nsString* utf16Names = aArray.AppendElements(size);
+ for (size_t i = 0; i < size; i++) {
+ CopyASCIItoUTF16(allColorNames[i], utf16Names[i]);
+ }
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("currentColor"));
+ }
+ return;
+}
+
+static void GetOtherValuesForProperty(const uint32_t aParserVariant,
+ nsTArray<nsString>& aArray)
+{
+ if (aParserVariant & VARIANT_AUTO) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("auto"));
+ }
+ if (aParserVariant & VARIANT_NORMAL) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("normal"));
+ }
+ if(aParserVariant & VARIANT_ALL) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("all"));
+ }
+ if (aParserVariant & VARIANT_NONE) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("none"));
+ }
+ if (aParserVariant & VARIANT_ELEMENT) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-element"));
+ }
+ if (aParserVariant & VARIANT_IMAGE_RECT) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-image-rect"));
+ }
+ if (aParserVariant & VARIANT_COLOR) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgb"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsl"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgba"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsla"));
+ }
+ if (aParserVariant & VARIANT_TIMING_FUNCTION) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("cubic-bezier"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("steps"));
+ }
+ if (aParserVariant & VARIANT_CALC) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("calc"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-calc"));
+ }
+ if (aParserVariant & VARIANT_URL) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("url"));
+ }
+ if (aParserVariant & VARIANT_GRADIENT) {
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("linear-gradient"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("radial-gradient"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-linear-gradient"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-radial-gradient"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-linear-gradient"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-radial-gradient"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-linear-gradient"));
+ InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-radial-gradient"));
+ }
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetSubpropertiesForCSSProperty(const nsAString& aProperty,
+ uint32_t* aLength,
+ char16_t*** aValues)
+{
+ nsCSSPropertyID propertyID =
+ nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
+
+ if (propertyID == eCSSProperty_UNKNOWN) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (propertyID == eCSSPropertyExtra_variable) {
+ *aValues = static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t*)));
+ (*aValues)[0] = ToNewUnicode(aProperty);
+ *aLength = 1;
+ return NS_OK;
+ }
+
+ if (!nsCSSProps::IsShorthand(propertyID)) {
+ *aValues = static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t*)));
+ (*aValues)[0] = ToNewUnicode(nsCSSProps::GetStringValue(propertyID));
+ *aLength = 1;
+ return NS_OK;
+ }
+
+ // Count up how many subproperties we have.
+ size_t subpropCount = 0;
+ for (const nsCSSPropertyID *props = nsCSSProps::SubpropertyEntryFor(propertyID);
+ *props != eCSSProperty_UNKNOWN; ++props) {
+ ++subpropCount;
+ }
+
+ *aValues =
+ static_cast<char16_t**>(moz_xmalloc(subpropCount * sizeof(char16_t*)));
+ *aLength = subpropCount;
+ for (const nsCSSPropertyID *props = nsCSSProps::SubpropertyEntryFor(propertyID),
+ *props_start = props;
+ *props != eCSSProperty_UNKNOWN; ++props) {
+ (*aValues)[props-props_start] = ToNewUnicode(nsCSSProps::GetStringValue(*props));
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::CssPropertyIsShorthand(const nsAString& aProperty, bool *_retval)
+{
+ nsCSSPropertyID propertyID =
+ nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
+ if (propertyID == eCSSProperty_UNKNOWN) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (propertyID == eCSSPropertyExtra_variable) {
+ *_retval = false;
+ } else {
+ *_retval = nsCSSProps::IsShorthand(propertyID);
+ }
+ return NS_OK;
+}
+
+// A helper function that determines whether the given property
+// supports the given type.
+static bool
+PropertySupportsVariant(nsCSSPropertyID aPropertyID, uint32_t aVariant)
+{
+ if (nsCSSProps::IsShorthand(aPropertyID)) {
+ // We need a special case for border here, because while it resets
+ // border-image, it can't actually parse an image.
+ if (aPropertyID == eCSSProperty_border) {
+ return (aVariant & (VARIANT_COLOR | VARIANT_LENGTH)) != 0;
+ }
+
+ for (const nsCSSPropertyID* props = nsCSSProps::SubpropertyEntryFor(aPropertyID);
+ *props != eCSSProperty_UNKNOWN; ++props) {
+ if (PropertySupportsVariant(*props, aVariant)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Properties that are parsed by functions must have their
+ // attributes hand-maintained here.
+ if (nsCSSProps::PropHasFlags(aPropertyID, CSS_PROPERTY_VALUE_PARSER_FUNCTION) ||
+ nsCSSProps::PropertyParseType(aPropertyID) == CSS_PROPERTY_PARSE_FUNCTION) {
+ // These must all be special-cased.
+ uint32_t supported;
+ switch (aPropertyID) {
+ case eCSSProperty_border_image_slice:
+ case eCSSProperty_grid_template:
+ case eCSSProperty_grid:
+ supported = VARIANT_PN;
+ break;
+
+ case eCSSProperty_border_image_outset:
+ supported = VARIANT_LN;
+ break;
+
+ case eCSSProperty_border_image_width:
+ case eCSSProperty_stroke_dasharray:
+ supported = VARIANT_LPN;
+ break;
+
+ case eCSSProperty_border_top_left_radius:
+ case eCSSProperty_border_top_right_radius:
+ case eCSSProperty_border_bottom_left_radius:
+ case eCSSProperty_border_bottom_right_radius:
+ case eCSSProperty_background_position:
+ case eCSSProperty_background_position_x:
+ case eCSSProperty_background_position_y:
+ case eCSSProperty_background_size:
+#ifdef MOZ_ENABLE_MASK_AS_SHORTHAND
+ case eCSSProperty_mask_position:
+ case eCSSProperty_mask_position_x:
+ case eCSSProperty_mask_position_y:
+ case eCSSProperty_mask_size:
+#endif
+ case eCSSProperty_grid_auto_columns:
+ case eCSSProperty_grid_auto_rows:
+ case eCSSProperty_grid_template_columns:
+ case eCSSProperty_grid_template_rows:
+ case eCSSProperty_object_position:
+ case eCSSProperty_scroll_snap_coordinate:
+ case eCSSProperty_scroll_snap_destination:
+ case eCSSProperty_transform_origin:
+ case eCSSProperty_perspective_origin:
+ case eCSSProperty__moz_outline_radius_topLeft:
+ case eCSSProperty__moz_outline_radius_topRight:
+ case eCSSProperty__moz_outline_radius_bottomLeft:
+ case eCSSProperty__moz_outline_radius_bottomRight:
+ supported = VARIANT_LP;
+ break;
+
+ case eCSSProperty_border_bottom_colors:
+ case eCSSProperty_border_left_colors:
+ case eCSSProperty_border_right_colors:
+ case eCSSProperty_border_top_colors:
+ supported = VARIANT_COLOR;
+ break;
+
+ case eCSSProperty_text_shadow:
+ case eCSSProperty_box_shadow:
+ supported = VARIANT_LENGTH | VARIANT_COLOR;
+ break;
+
+ case eCSSProperty_border_spacing:
+ supported = VARIANT_LENGTH;
+ break;
+
+ case eCSSProperty_content:
+ case eCSSProperty_cursor:
+ case eCSSProperty_clip_path:
+ case eCSSProperty_shape_outside:
+ supported = VARIANT_URL;
+ break;
+
+ case eCSSProperty_fill:
+ case eCSSProperty_stroke:
+ supported = VARIANT_COLOR | VARIANT_URL;
+ break;
+
+ case eCSSProperty_image_orientation:
+ supported = VARIANT_ANGLE;
+ break;
+
+ case eCSSProperty_filter:
+ supported = VARIANT_URL;
+ break;
+
+ case eCSSProperty_grid_column_start:
+ case eCSSProperty_grid_column_end:
+ case eCSSProperty_grid_row_start:
+ case eCSSProperty_grid_row_end:
+ case eCSSProperty_font_weight:
+ case eCSSProperty_initial_letter:
+ supported = VARIANT_NUMBER;
+ break;
+
+ default:
+ supported = 0;
+ break;
+ }
+
+ return (supported & aVariant) != 0;
+ }
+
+ return (nsCSSProps::ParserVariant(aPropertyID) & aVariant) != 0;
+}
+
+NS_IMETHODIMP
+inDOMUtils::CssPropertySupportsType(const nsAString& aProperty, uint32_t aType,
+ bool *_retval)
+{
+ nsCSSPropertyID propertyID =
+ nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
+ if (propertyID == eCSSProperty_UNKNOWN) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (propertyID >= eCSSProperty_COUNT) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ uint32_t variant;
+ switch (aType) {
+ case TYPE_LENGTH:
+ variant = VARIANT_LENGTH;
+ break;
+ case TYPE_PERCENTAGE:
+ variant = VARIANT_PERCENT;
+ break;
+ case TYPE_COLOR:
+ variant = VARIANT_COLOR;
+ break;
+ case TYPE_URL:
+ variant = VARIANT_URL;
+ break;
+ case TYPE_ANGLE:
+ variant = VARIANT_ANGLE;
+ break;
+ case TYPE_FREQUENCY:
+ variant = VARIANT_FREQUENCY;
+ break;
+ case TYPE_TIME:
+ variant = VARIANT_TIME;
+ break;
+ case TYPE_GRADIENT:
+ variant = VARIANT_GRADIENT;
+ break;
+ case TYPE_TIMING_FUNCTION:
+ variant = VARIANT_TIMING_FUNCTION;
+ break;
+ case TYPE_IMAGE_RECT:
+ variant = VARIANT_IMAGE_RECT;
+ break;
+ case TYPE_NUMBER:
+ // Include integers under "number"?
+ variant = VARIANT_NUMBER | VARIANT_INTEGER;
+ break;
+ default:
+ // Unknown type
+ return NS_ERROR_NOT_AVAILABLE;
+ }
+
+ *_retval = PropertySupportsVariant(propertyID, variant);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty,
+ uint32_t* aLength,
+ char16_t*** aValues)
+{
+ nsCSSPropertyID propertyID = nsCSSProps::
+ LookupProperty(aProperty, CSSEnabledState::eForAllContent);
+ if (propertyID == eCSSProperty_UNKNOWN) {
+ return NS_ERROR_FAILURE;
+ }
+
+ nsTArray<nsString> array;
+ // We start collecting the values, BUT colors need to go in first, because array
+ // needs to stay sorted, and the colors are sorted, so we just append them.
+ if (propertyID == eCSSPropertyExtra_variable) {
+ // No other values we can report.
+ } else if (!nsCSSProps::IsShorthand(propertyID)) {
+ // Property is longhand.
+ uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID);
+ // Get colors first.
+ GetColorsForProperty(propertyParserVariant, array);
+ if (propertyParserVariant & VARIANT_KEYWORD) {
+ GetKeywordsForProperty(propertyID, array);
+ }
+ GetOtherValuesForProperty(propertyParserVariant, array);
+ } else {
+ // Property is shorthand.
+ CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
+ CSSEnabledState::eForAllContent) {
+ // Get colors (once) first.
+ uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
+ if (propertyParserVariant & VARIANT_COLOR) {
+ GetColorsForProperty(propertyParserVariant, array);
+ break;
+ }
+ }
+ CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
+ CSSEnabledState::eForAllContent) {
+ uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
+ if (propertyParserVariant & VARIANT_KEYWORD) {
+ GetKeywordsForProperty(*subproperty, array);
+ }
+ GetOtherValuesForProperty(propertyParserVariant, array);
+ }
+ }
+ // All CSS properties take initial, inherit and unset.
+ InsertNoDuplicates(array, NS_LITERAL_STRING("initial"));
+ InsertNoDuplicates(array, NS_LITERAL_STRING("inherit"));
+ InsertNoDuplicates(array, NS_LITERAL_STRING("unset"));
+
+ *aLength = array.Length();
+ char16_t** ret =
+ static_cast<char16_t**>(moz_xmalloc(*aLength * sizeof(char16_t*)));
+ for (uint32_t i = 0; i < *aLength; ++i) {
+ ret[i] = ToNewUnicode(array[i]);
+ }
+ *aValues = ret;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::ColorNameToRGB(const nsAString& aColorName, JSContext* aCx,
+ JS::MutableHandle<JS::Value> aValue)
+{
+ nscolor color;
+ if (!NS_ColorNameToRGB(aColorName, &color)) {
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ InspectorRGBTriple triple;
+ triple.mR = NS_GET_R(color);
+ triple.mG = NS_GET_G(color);
+ triple.mB = NS_GET_B(color);
+
+ if (!ToJSValue(aCx, triple, aValue)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::RgbToColorName(uint8_t aR, uint8_t aG, uint8_t aB,
+ nsAString& aColorName)
+{
+ const char* color = NS_RGBToColorName(NS_RGB(aR, aG, aB));
+ if (!color) {
+ aColorName.Truncate();
+ return NS_ERROR_INVALID_ARG;
+ }
+
+ aColorName.AssignASCII(color);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::ColorToRGBA(const nsAString& aColorString, JSContext* aCx,
+ JS::MutableHandle<JS::Value> aValue)
+{
+ nscolor color = 0;
+ nsCSSParser cssParser;
+ nsCSSValue cssValue;
+
+ bool isColor = cssParser.ParseColorString(aColorString, nullptr, 0,
+ cssValue, true);
+
+ if (!isColor) {
+ aValue.setNull();
+ return NS_OK;
+ }
+
+ nsRuleNode::ComputeColor(cssValue, nullptr, nullptr, color);
+
+ InspectorRGBATuple tuple;
+ 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));
+
+ if (!ToJSValue(aCx, tuple, aValue)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::IsValidCSSColor(const nsAString& aColorString, bool *_retval)
+{
+ nsCSSParser cssParser;
+ nsCSSValue cssValue;
+ *_retval = cssParser.ParseColorString(aColorString, nullptr, 0, cssValue, true);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::CssPropertyIsValid(const nsAString& aPropertyName,
+ const nsAString& aPropertyValue,
+ bool *_retval)
+{
+ nsCSSPropertyID propertyID = nsCSSProps::
+ LookupProperty(aPropertyName, CSSEnabledState::eIgnoreEnabledState);
+
+ if (propertyID == eCSSProperty_UNKNOWN) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ if (propertyID == eCSSPropertyExtra_variable) {
+ *_retval = true;
+ return NS_OK;
+ }
+
+ // Get a parser, parse the property.
+ nsCSSParser parser;
+ *_retval = parser.IsValueValidForProperty(propertyID, aPropertyValue);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetBindingURLs(nsIDOMElement *aElement, nsIArray **_retval)
+{
+ NS_ENSURE_ARG_POINTER(aElement);
+
+ *_retval = nullptr;
+
+ nsCOMPtr<nsIMutableArray> urls = do_CreateInstance(NS_ARRAY_CONTRACTID);
+ if (!urls)
+ return NS_ERROR_FAILURE;
+
+ nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
+ NS_ENSURE_ARG_POINTER(content);
+
+ nsXBLBinding *binding = content->GetXBLBinding();
+
+ while (binding) {
+ urls->AppendElement(binding->PrototypeBinding()->BindingURI(), false);
+ binding = binding->GetBaseBinding();
+ }
+
+ urls.forget(_retval);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::SetContentState(nsIDOMElement* aElement,
+ EventStates::InternalType aState,
+ bool* aRetVal)
+{
+ NS_ENSURE_ARG_POINTER(aElement);
+
+ RefPtr<EventStateManager> esm =
+ inLayoutUtils::GetEventStateManagerFor(aElement);
+ NS_ENSURE_TRUE(esm, NS_ERROR_INVALID_ARG);
+
+ nsCOMPtr<nsIContent> content;
+ content = do_QueryInterface(aElement);
+ NS_ENSURE_TRUE(content, NS_ERROR_INVALID_ARG);
+
+ *aRetVal = esm->SetContentState(content, EventStates(aState));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::RemoveContentState(nsIDOMElement* aElement,
+ EventStates::InternalType aState,
+ bool* aRetVal)
+{
+ NS_ENSURE_ARG_POINTER(aElement);
+
+ RefPtr<EventStateManager> esm =
+ inLayoutUtils::GetEventStateManagerFor(aElement);
+ NS_ENSURE_TRUE(esm, NS_ERROR_INVALID_ARG);
+
+ *aRetVal = esm->SetContentState(nullptr, EventStates(aState));
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetContentState(nsIDOMElement* aElement,
+ EventStates::InternalType* aState)
+{
+ *aState = 0;
+ nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
+ NS_ENSURE_ARG_POINTER(content);
+
+ // NOTE: if this method is removed,
+ // please remove GetInternalValue from EventStates
+ *aState = content->AsElement()->State().GetInternalValue();
+ return NS_OK;
+}
+
+/* static */ nsresult
+inDOMUtils::GetRuleNodeForElement(dom::Element* aElement,
+ nsIAtom* aPseudo,
+ nsStyleContext** aStyleContext,
+ nsRuleNode** aRuleNode)
+{
+ MOZ_ASSERT(aElement);
+
+ *aRuleNode = nullptr;
+ *aStyleContext = nullptr;
+
+ nsIDocument* doc = aElement->GetComposedDoc();
+ NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
+
+ nsIPresShell *presShell = doc->GetShell();
+ NS_ENSURE_TRUE(presShell, NS_ERROR_UNEXPECTED);
+
+ nsPresContext *presContext = presShell->GetPresContext();
+ NS_ENSURE_TRUE(presContext, NS_ERROR_UNEXPECTED);
+
+ presContext->EnsureSafeToHandOutCSSRules();
+
+ RefPtr<nsStyleContext> sContext =
+ nsComputedDOMStyle::GetStyleContextForElement(aElement, aPseudo, presShell);
+ if (sContext) {
+ *aRuleNode = sContext->RuleNode();
+ sContext.forget(aStyleContext);
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetUsedFontFaces(nsIDOMRange* aRange,
+ nsIDOMFontFaceList** aFontFaceList)
+{
+ return static_cast<nsRange*>(aRange)->GetUsedFontFaces(aFontFaceList);
+}
+
+static EventStates
+GetStatesForPseudoClass(const nsAString& aStatePseudo)
+{
+ // An array of the states that are relevant for various pseudoclasses.
+ // XXXbz this duplicates code in nsCSSRuleProcessor
+ static const EventStates sPseudoClassStates[] = {
+#define CSS_PSEUDO_CLASS(_name, _value, _flags, _pref) \
+ EventStates(),
+#define CSS_STATE_PSEUDO_CLASS(_name, _value, _flags, _pref, _states) \
+ _states,
+#include "nsCSSPseudoClassList.h"
+#undef CSS_STATE_PSEUDO_CLASS
+#undef CSS_PSEUDO_CLASS
+
+ // Add more entries for our fake values to make sure we can't
+ // index out of bounds into this array no matter what.
+ EventStates(),
+ EventStates()
+ };
+ static_assert(MOZ_ARRAY_LENGTH(sPseudoClassStates) ==
+ static_cast<size_t>(CSSPseudoClassType::MAX),
+ "Length of PseudoClassStates array is incorrect");
+
+ nsCOMPtr<nsIAtom> atom = NS_Atomize(aStatePseudo);
+ CSSPseudoClassType type = nsCSSPseudoClasses::
+ GetPseudoType(atom, CSSEnabledState::eIgnoreEnabledState);
+
+ // Ignore :any-link so we don't give the element simultaneous
+ // visited and unvisited style state
+ if (type == CSSPseudoClassType::anyLink ||
+ type == CSSPseudoClassType::mozAnyLink) {
+ return EventStates();
+ }
+ // Our array above is long enough that indexing into it with
+ // NotPseudo is ok.
+ return sPseudoClassStates[static_cast<CSSPseudoClassTypeBase>(type)];
+}
+
+NS_IMETHODIMP
+inDOMUtils::GetCSSPseudoElementNames(uint32_t* aLength, char16_t*** aNames)
+{
+ nsTArray<nsIAtom*> array;
+
+ const CSSPseudoElementTypeBase pseudoCount =
+ static_cast<CSSPseudoElementTypeBase>(CSSPseudoElementType::Count);
+ for (CSSPseudoElementTypeBase i = 0; i < pseudoCount; ++i) {
+ CSSPseudoElementType type = static_cast<CSSPseudoElementType>(i);
+ if (nsCSSPseudoElements::IsEnabled(type, CSSEnabledState::eForAllContent)) {
+ nsIAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type);
+ array.AppendElement(atom);
+ }
+ }
+
+ *aLength = array.Length();
+ char16_t** ret =
+ static_cast<char16_t**>(moz_xmalloc(*aLength * sizeof(char16_t*)));
+ for (uint32_t i = 0; i < *aLength; ++i) {
+ ret[i] = ToNewUnicode(nsDependentAtomString(array[i]));
+ }
+ *aNames = ret;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
+ const nsAString &aPseudoClass)
+{
+ EventStates state = GetStatesForPseudoClass(aPseudoClass);
+ if (state.IsEmpty()) {
+ return NS_OK;
+ }
+
+ nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
+ NS_ENSURE_ARG_POINTER(element);
+
+ element->LockStyleStates(state);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::RemovePseudoClassLock(nsIDOMElement *aElement,
+ const nsAString &aPseudoClass)
+{
+ EventStates state = GetStatesForPseudoClass(aPseudoClass);
+ if (state.IsEmpty()) {
+ return NS_OK;
+ }
+
+ nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
+ NS_ENSURE_ARG_POINTER(element);
+
+ element->UnlockStyleStates(state);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::HasPseudoClassLock(nsIDOMElement *aElement,
+ const nsAString &aPseudoClass,
+ bool *_retval)
+{
+ EventStates state = GetStatesForPseudoClass(aPseudoClass);
+ if (state.IsEmpty()) {
+ *_retval = false;
+ return NS_OK;
+ }
+
+ nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
+ NS_ENSURE_ARG_POINTER(element);
+
+ EventStates locks = element->LockedStyleStates();
+
+ *_retval = locks.HasAllStates(state);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::ClearPseudoClassLocks(nsIDOMElement *aElement)
+{
+ nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
+ NS_ENSURE_ARG_POINTER(element);
+
+ element->ClearStyleStateLocks();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+inDOMUtils::ParseStyleSheet(nsIDOMCSSStyleSheet *aSheet,
+ const nsAString& aInput)
+{
+ RefPtr<CSSStyleSheet> sheet = do_QueryObject(aSheet);
+ NS_ENSURE_ARG_POINTER(sheet);
+
+ return sheet->ReparseSheet(aInput);
+}
+
+NS_IMETHODIMP
+inDOMUtils::ScrollElementIntoView(nsIDOMElement *aElement)
+{
+ nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
+ NS_ENSURE_ARG_POINTER(content);
+
+ nsIPresShell* presShell = content->OwnerDoc()->GetShell();
+ if (!presShell) {
+ return NS_OK;
+ }
+
+ presShell->ScrollContentIntoView(content,
+ nsIPresShell::ScrollAxis(),
+ nsIPresShell::ScrollAxis(),
+ nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
+
+ return NS_OK;
+}