/* -*- 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 "nsIServiceManager.h" #include "nsISupportsArray.h" #include "nsString.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/CSSStyleSheet.h" #include "mozilla/dom/Element.h" #include "nsRuleWalker.h" #include "nsRuleProcessorData.h" #include "nsCSSRuleProcessor.h" #include "mozilla/dom/InspectorUtilsBinding.h" #include "mozilla/dom/ToJSValue.h" #include "nsCSSProps.h" #include "nsColor.h" #include "nsStyleSet.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); nsCOMArray sheets; nsCOMPtr document = do_QueryInterface(aDocument); MOZ_ASSERT(document); // Get the agent, then user sheets in the style set. nsIPresShell* presShell = document->GetShell(); if (presShell) { nsStyleSet* styleSet = presShell->StyleSet(); nsStyleSet::sheetType sheetType = nsStyleSet::eAgentSheet; for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) { sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i)); } sheetType = nsStyleSet::eUserSheet; for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) { sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i)); } } // Get the document sheets. for (int32_t i = 0; i < document->GetNumberOfStyleSheets(); i++) { sheets.AppendElement(document->GetStyleSheetAt(i)); } nsISupports** ret = static_cast(NS_Alloc(sheets.Count() * sizeof(nsISupports*))); for (int32_t i = 0; i < sheets.Count(); i++) { NS_ADDREF(ret[i] = sheets[i]); } *aLength = sheets.Count(); *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 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 \n *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 doc(do_QueryInterface(aNode)); nsCOMPtr parent; if (doc) { parent = inLayoutUtils::GetContainerFor(*doc); } else if (aShowingAnonymousContent) { nsCOMPtr content = do_QueryInterface(aNode); if (content) { nsIContent* bparent = content->GetXBLInsertionParent(); 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 kids; if (aShowingAnonymousContent) { nsCOMPtr 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, nsISupportsArray **_retval) { NS_ENSURE_ARG_POINTER(aElement); *_retval = nullptr; nsCOMPtr pseudoElt; if (!aPseudo.IsEmpty()) { pseudoElt = do_GetAtom(aPseudo); } nsRuleNode* ruleNode = nullptr; nsCOMPtr element = do_QueryInterface(aElement); NS_ENSURE_STATE(element); nsRefPtr 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; } nsCOMPtr rules; NS_NewISupportsArray(getter_AddRefs(rules)); if (!rules) return NS_ERROR_OUT_OF_MEMORY; nsRefPtr cssRule; for ( ; !ruleNode->IsRoot(); ruleNode = ruleNode->GetParent()) { cssRule = do_QueryObject(ruleNode->GetRule()); if (cssRule) { nsCOMPtr domRule = cssRule->GetDOMRule(); if (domRule) rules->InsertElementAt(domRule, 0); } } *_retval = rules; NS_ADDREF(*_retval); return NS_OK; } static already_AddRefed GetRuleFromDOMRule(nsIDOMCSSStyleRule *aRule, ErrorResult& rv) { nsCOMPtr rule = do_QueryInterface(aRule); if (!rule) { rv.Throw(NS_ERROR_INVALID_POINTER); return nullptr; } nsRefPtr 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(nsIDOMCSSStyleRule *aRule, uint32_t *_retval) { ErrorResult rv; nsRefPtr rule = GetRuleFromDOMRule(aRule, rv); if (rv.Failed()) { return rv.ErrorCode(); } *_retval = rule->GetLineNumber(); return NS_OK; } NS_IMETHODIMP inDOMUtils::GetRuleColumn(nsIDOMCSSStyleRule *aRule, uint32_t *_retval) { ErrorResult rv; nsRefPtr rule = GetRuleFromDOMRule(aRule, rv); if (rv.Failed()) { return rv.ErrorCode(); } *_retval = rule->GetColumnNumber(); return NS_OK; } NS_IMETHODIMP inDOMUtils::GetSelectorCount(nsIDOMCSSStyleRule* aRule, uint32_t *aCount) { ErrorResult rv; nsRefPtr rule = GetRuleFromDOMRule(aRule, rv); if (rv.Failed()) { return rv.ErrorCode(); } 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) { nsRefPtr 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.ErrorCode(); } nsRefPtr 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.ErrorCode(); } *aSpecificity = sel->mWeight; return NS_OK; } NS_IMETHODIMP inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement, nsIDOMCSSStyleRule* aRule, uint32_t aSelectorIndex, bool* aMatches) { nsCOMPtr element = do_QueryInterface(aElement); NS_ENSURE_ARG_POINTER(element); ErrorResult rv; nsCSSSelectorList* tail = GetSelectorAtIndex(aRule, aSelectorIndex, rv); if (rv.Failed()) { return rv.ErrorCode(); } // We want just the one list item, not the whole list tail nsAutoPtr sel(tail->Clone(false)); // SelectorListMatches does not handle selectors that begin with a // pseudo-element, which you can get from selectors like // |input::-moz-placeholder:hover|. This function doesn't take // a pseudo-element nsIAtom*, so we know we can't match. if (sel->mSelectors->IsPseudoElement()) { *aMatches = false; return NS_OK; } 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) { nsCSSProperty prop = nsCSSProps::LookupProperty(aPropertyName, nsCSSProps::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(nsMemory::Alloc(maxCount * sizeof(char16_t*))); #define DO_PROP(_prop) \ PR_BEGIN_MACRO \ nsCSSProperty cssProp = nsCSSProperty(_prop); \ if (nsCSSProps::IsEnabled(cssProp)) { \ 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(nsCSSProperty(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(nsCSSProperty(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& 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 nsCSSProperty aProperty, nsTArray& aArray) { if (nsCSSProps::IsShorthand(aProperty)) { // Shorthand props have no keywords. return; } const nsCSSProps::KTableValue *keywordTable = nsCSSProps::kKeywordTableTable[aProperty]; if (keywordTable && keywordTable != nsCSSProps::kBoxPropSourceKTable) { size_t i = 0; while (nsCSSKeyword(keywordTable[i]) != eCSSKeyword_UNKNOWN) { nsCSSKeyword word = nsCSSKeyword(keywordTable[i]); InsertNoDuplicates(aArray, NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word))); // Increment counter by 2, because in this table every second // element is a nsCSSKeyword. i += 2; } } } static void GetColorsForProperty(const uint32_t aParserVariant, nsTArray& 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); for (size_t i = 0; i < size; i++) { CopyASCIItoUTF16(allColorNames[i], *aArray.AppendElement()); } } return; } static void GetOtherValuesForProperty(const uint32_t aParserVariant, nsTArray& 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) { nsCSSProperty propertyID = nsCSSProps::LookupProperty(aProperty, nsCSSProps::eEnabledForAllContent); if (propertyID == eCSSProperty_UNKNOWN) { return NS_ERROR_FAILURE; } nsTArray array; if (!nsCSSProps::IsShorthand(propertyID)) { *aValues = static_cast(nsMemory::Alloc(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 nsCSSProperty *props = nsCSSProps::SubpropertyEntryFor(propertyID); *props != eCSSProperty_UNKNOWN; ++props) { ++subpropCount; } *aValues = static_cast(nsMemory::Alloc(subpropCount * sizeof(char16_t*))); *aLength = subpropCount; for (const nsCSSProperty *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) { nsCSSProperty propertyID = nsCSSProps::LookupProperty(aProperty, nsCSSProps::eEnabledForAllContent); if (propertyID == eCSSProperty_UNKNOWN) { return NS_ERROR_FAILURE; } *_retval = nsCSSProps::IsShorthand(propertyID); return NS_OK; } NS_IMETHODIMP inDOMUtils::CssPropertySupportsType(const nsAString& aProperty, uint32_t aType, bool *_retval) { nsCSSProperty propertyID = nsCSSProps::LookupProperty(aProperty, nsCSSProps::eEnabledForAllContent); if (propertyID == eCSSProperty_UNKNOWN) { return NS_ERROR_FAILURE; } 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; } if (!nsCSSProps::IsShorthand(propertyID)) { *_retval = nsCSSProps::ParserVariant(propertyID) & variant; return NS_OK; } for (const nsCSSProperty* props = nsCSSProps::SubpropertyEntryFor(propertyID); *props != eCSSProperty_UNKNOWN; ++props) { if (nsCSSProps::ParserVariant(*props) & variant) { *_retval = true; return NS_OK; } } *_retval = false; return NS_OK; } NS_IMETHODIMP inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty, uint32_t* aLength, char16_t*** aValues) { nsCSSProperty propertyID = nsCSSProps::LookupProperty(aProperty, nsCSSProps::eEnabledForAllContent); if (propertyID == eCSSProperty_UNKNOWN) { return NS_ERROR_FAILURE; } nsTArray 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) { // Get colors (once) first. uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty); if (propertyParserVariant & VARIANT_COLOR) { GetColorsForProperty(propertyParserVariant, array); break; } } CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) { 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(NS_Alloc(*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 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::GetBindingURLs(nsIDOMElement *aElement, nsIArray **_retval) { NS_ENSURE_ARG_POINTER(aElement); *_retval = nullptr; nsCOMPtr urls = do_CreateInstance(NS_ARRAY_CONTRACTID); if (!urls) return NS_ERROR_FAILURE; nsCOMPtr content = do_QueryInterface(aElement); NS_ENSURE_ARG_POINTER(content); nsXBLBinding *binding = content->GetXBLBinding(); while (binding) { urls->AppendElement(binding->PrototypeBinding()->BindingURI(), false); binding = binding->GetBaseBinding(); } NS_ADDREF(*_retval = urls); return NS_OK; } NS_IMETHODIMP inDOMUtils::SetContentState(nsIDOMElement* aElement, EventStates::InternalType aState) { NS_ENSURE_ARG_POINTER(aElement); nsRefPtr esm = inLayoutUtils::GetEventStateManagerFor(aElement); if (esm) { nsCOMPtr content; content = do_QueryInterface(aElement); // XXX Invalid cast of bool to nsresult (bug 778108) return (nsresult)esm->SetContentState(content, EventStates(aState)); } return NS_ERROR_FAILURE; } NS_IMETHODIMP inDOMUtils::GetContentState(nsIDOMElement* aElement, EventStates::InternalType* aState) { *aState = 0; nsCOMPtr 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->GetDocument(); 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(); nsRefPtr 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(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, _pref) \ EventStates(), #define CSS_STATE_PSEUDO_CLASS(_name, _value, _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) == nsCSSPseudoClasses::ePseudoClass_NotPseudoClass + 1, "Length of PseudoClassStates array is incorrect"); nsCOMPtr atom = do_GetAtom(aStatePseudo); // Ignore :moz-any-link so we don't give the element simultaneous // visited and unvisited style state if (nsCSSPseudoClasses::GetPseudoType(atom) == nsCSSPseudoClasses::ePseudoClass_mozAnyLink) { return EventStates(); } // Our array above is long enough that indexing into it with // NotPseudoClass is ok. return sPseudoClassStates[nsCSSPseudoClasses::GetPseudoType(atom)]; } NS_IMETHODIMP inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement, const nsAString &aPseudoClass) { EventStates state = GetStatesForPseudoClass(aPseudoClass); if (state.IsEmpty()) { return NS_OK; } nsCOMPtr 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 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 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 element = do_QueryInterface(aElement); NS_ENSURE_ARG_POINTER(element); element->ClearStyleStateLocks(); return NS_OK; } NS_IMETHODIMP inDOMUtils::ParseStyleSheet(nsIDOMCSSStyleSheet *aSheet, const nsAString& aInput) { nsRefPtr sheet = do_QueryObject(aSheet); NS_ENSURE_ARG_POINTER(sheet); return sheet->ParseSheet(aInput); } NS_IMETHODIMP inDOMUtils::ScrollElementIntoView(nsIDOMElement *aElement) { nsCOMPtr 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; }