michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/ArrayUtils.h" michael@0: #include "mozilla/EventStates.h" michael@0: michael@0: #include "inDOMUtils.h" michael@0: #include "inLayoutUtils.h" michael@0: michael@0: #include "nsIServiceManager.h" michael@0: #include "nsISupportsArray.h" michael@0: #include "nsString.h" michael@0: #include "nsIDOMElement.h" michael@0: #include "nsIDocument.h" michael@0: #include "nsIPresShell.h" michael@0: #include "nsIDOMDocument.h" michael@0: #include "nsIDOMCharacterData.h" michael@0: #include "nsRuleNode.h" michael@0: #include "nsIStyleRule.h" michael@0: #include "mozilla/css/StyleRule.h" michael@0: #include "nsICSSStyleRuleDOMWrapper.h" michael@0: #include "nsIDOMWindow.h" michael@0: #include "nsXBLBinding.h" michael@0: #include "nsXBLPrototypeBinding.h" michael@0: #include "nsIMutableArray.h" michael@0: #include "nsBindingManager.h" michael@0: #include "ChildIterator.h" michael@0: #include "nsComputedDOMStyle.h" michael@0: #include "mozilla/EventStateManager.h" michael@0: #include "nsIAtom.h" michael@0: #include "nsRange.h" michael@0: #include "nsContentList.h" michael@0: #include "mozilla/dom/Element.h" michael@0: #include "nsCSSStyleSheet.h" michael@0: #include "nsRuleWalker.h" michael@0: #include "nsRuleProcessorData.h" michael@0: #include "nsCSSRuleProcessor.h" michael@0: #include "mozilla/dom/InspectorUtilsBinding.h" michael@0: #include "nsCSSProps.h" michael@0: #include "nsColor.h" michael@0: #include "nsStyleSet.h" michael@0: michael@0: using namespace mozilla; michael@0: using namespace mozilla::css; michael@0: using namespace mozilla::dom; michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: inDOMUtils::inDOMUtils() michael@0: { michael@0: } michael@0: michael@0: inDOMUtils::~inDOMUtils() michael@0: { michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(inDOMUtils, inIDOMUtils) michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // inIDOMUtils michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength, michael@0: nsISupports ***aSheets) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aDocument); michael@0: michael@0: nsCOMArray sheets; michael@0: michael@0: nsCOMPtr document = do_QueryInterface(aDocument); michael@0: MOZ_ASSERT(document); michael@0: michael@0: // Get the agent, then user sheets in the style set. michael@0: nsIPresShell* presShell = document->GetShell(); michael@0: if (presShell) { michael@0: nsStyleSet* styleSet = presShell->StyleSet(); michael@0: nsStyleSet::sheetType sheetType = nsStyleSet::eAgentSheet; michael@0: for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) { michael@0: sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i)); michael@0: } michael@0: sheetType = nsStyleSet::eUserSheet; michael@0: for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) { michael@0: sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i)); michael@0: } michael@0: } michael@0: michael@0: // Get the document sheets. michael@0: for (int32_t i = 0; i < document->GetNumberOfStyleSheets(); i++) { michael@0: sheets.AppendElement(document->GetStyleSheetAt(i)); michael@0: } michael@0: michael@0: nsISupports** ret = static_cast(NS_Alloc(sheets.Count() * michael@0: sizeof(nsISupports*))); michael@0: michael@0: for (int32_t i = 0; i < sheets.Count(); i++) { michael@0: NS_ADDREF(ret[i] = sheets[i]); michael@0: } michael@0: michael@0: *aLength = sheets.Count(); michael@0: *aSheets = ret; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::IsIgnorableWhitespace(nsIDOMCharacterData *aDataNode, michael@0: bool *aReturn) michael@0: { michael@0: NS_PRECONDITION(aReturn, "Must have an out parameter"); michael@0: michael@0: NS_ENSURE_ARG_POINTER(aDataNode); michael@0: michael@0: *aReturn = false; michael@0: michael@0: nsCOMPtr content = do_QueryInterface(aDataNode); michael@0: NS_ASSERTION(content, "Does not implement nsIContent!"); michael@0: michael@0: if (!content->TextIsOnlyWhitespace()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Okay. We have only white space. Let's check the white-space michael@0: // property now and make sure that this isn't preformatted text... michael@0: nsIFrame* frame = content->GetPrimaryFrame(); michael@0: if (frame) { michael@0: const nsStyleText* text = frame->StyleText(); michael@0: *aReturn = !text->WhiteSpaceIsSignificant(); michael@0: } michael@0: else { michael@0: // empty inter-tag text node without frame, e.g., in between \n michael@0: *aReturn = true; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetParentForNode(nsIDOMNode* aNode, michael@0: bool aShowingAnonymousContent, michael@0: nsIDOMNode** aParent) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aNode); michael@0: michael@0: // First do the special cases -- document nodes and anonymous content michael@0: nsCOMPtr doc(do_QueryInterface(aNode)); michael@0: nsCOMPtr parent; michael@0: michael@0: if (doc) { michael@0: parent = inLayoutUtils::GetContainerFor(*doc); michael@0: } else if (aShowingAnonymousContent) { michael@0: nsCOMPtr content = do_QueryInterface(aNode); michael@0: if (content) { michael@0: nsIContent* bparent = content->GetXBLInsertionParent(); michael@0: parent = do_QueryInterface(bparent); michael@0: } michael@0: } michael@0: michael@0: if (!parent) { michael@0: // Ok, just get the normal DOM parent node michael@0: aNode->GetParentNode(getter_AddRefs(parent)); michael@0: } michael@0: michael@0: NS_IF_ADDREF(*aParent = parent); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetChildrenForNode(nsIDOMNode* aNode, michael@0: bool aShowingAnonymousContent, michael@0: nsIDOMNodeList** aChildren) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aNode); michael@0: NS_PRECONDITION(aChildren, "Must have an out parameter"); michael@0: michael@0: nsCOMPtr kids; michael@0: michael@0: if (aShowingAnonymousContent) { michael@0: nsCOMPtr content = do_QueryInterface(aNode); michael@0: if (content) { michael@0: kids = content->GetChildren(nsIContent::eAllChildren); michael@0: } michael@0: } michael@0: michael@0: if (!kids) { michael@0: aNode->GetChildNodes(getter_AddRefs(kids)); michael@0: } michael@0: michael@0: kids.forget(aChildren); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetCSSStyleRules(nsIDOMElement *aElement, michael@0: const nsAString& aPseudo, michael@0: nsISupportsArray **_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aElement); michael@0: michael@0: *_retval = nullptr; michael@0: michael@0: nsCOMPtr pseudoElt; michael@0: if (!aPseudo.IsEmpty()) { michael@0: pseudoElt = do_GetAtom(aPseudo); michael@0: } michael@0: michael@0: nsRuleNode* ruleNode = nullptr; michael@0: nsCOMPtr element = do_QueryInterface(aElement); michael@0: NS_ENSURE_STATE(element); michael@0: nsRefPtr styleContext; michael@0: GetRuleNodeForElement(element, pseudoElt, getter_AddRefs(styleContext), &ruleNode); michael@0: if (!ruleNode) { michael@0: // This can fail for elements that are not in the document or michael@0: // if the document they're in doesn't have a presshell. Bail out. michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr rules; michael@0: NS_NewISupportsArray(getter_AddRefs(rules)); michael@0: if (!rules) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: nsRefPtr cssRule; michael@0: for ( ; !ruleNode->IsRoot(); ruleNode = ruleNode->GetParent()) { michael@0: cssRule = do_QueryObject(ruleNode->GetRule()); michael@0: if (cssRule) { michael@0: nsCOMPtr domRule = cssRule->GetDOMRule(); michael@0: if (domRule) michael@0: rules->InsertElementAt(domRule, 0); michael@0: } michael@0: } michael@0: michael@0: *_retval = rules; michael@0: NS_ADDREF(*_retval); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static already_AddRefed michael@0: GetRuleFromDOMRule(nsIDOMCSSStyleRule *aRule, ErrorResult& rv) michael@0: { michael@0: nsCOMPtr rule = do_QueryInterface(aRule); michael@0: if (!rule) { michael@0: rv.Throw(NS_ERROR_INVALID_POINTER); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr cssrule; michael@0: rv = rule->GetCSSStyleRule(getter_AddRefs(cssrule)); michael@0: if (rv.Failed()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: if (!cssrule) { michael@0: rv.Throw(NS_ERROR_FAILURE); michael@0: } michael@0: return cssrule.forget(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetRuleLine(nsIDOMCSSStyleRule *aRule, uint32_t *_retval) michael@0: { michael@0: ErrorResult rv; michael@0: nsRefPtr rule = GetRuleFromDOMRule(aRule, rv); michael@0: if (rv.Failed()) { michael@0: return rv.ErrorCode(); michael@0: } michael@0: michael@0: *_retval = rule->GetLineNumber(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetRuleColumn(nsIDOMCSSStyleRule *aRule, uint32_t *_retval) michael@0: { michael@0: ErrorResult rv; michael@0: nsRefPtr rule = GetRuleFromDOMRule(aRule, rv); michael@0: if (rv.Failed()) { michael@0: return rv.ErrorCode(); michael@0: } michael@0: *_retval = rule->GetColumnNumber(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetSelectorCount(nsIDOMCSSStyleRule* aRule, uint32_t *aCount) michael@0: { michael@0: ErrorResult rv; michael@0: nsRefPtr rule = GetRuleFromDOMRule(aRule, rv); michael@0: if (rv.Failed()) { michael@0: return rv.ErrorCode(); michael@0: } michael@0: michael@0: uint32_t count = 0; michael@0: for (nsCSSSelectorList* sel = rule->Selector(); sel; sel = sel->mNext) { michael@0: ++count; michael@0: } michael@0: *aCount = count; michael@0: return NS_OK; michael@0: } michael@0: michael@0: static nsCSSSelectorList* michael@0: GetSelectorAtIndex(nsIDOMCSSStyleRule* aRule, uint32_t aIndex, ErrorResult& rv) michael@0: { michael@0: nsRefPtr rule = GetRuleFromDOMRule(aRule, rv); michael@0: if (rv.Failed()) { michael@0: return nullptr; michael@0: } michael@0: michael@0: for (nsCSSSelectorList* sel = rule->Selector(); sel; michael@0: sel = sel->mNext, --aIndex) { michael@0: if (aIndex == 0) { michael@0: return sel; michael@0: } michael@0: } michael@0: michael@0: // Ran out of selectors michael@0: rv.Throw(NS_ERROR_INVALID_ARG); michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetSelectorText(nsIDOMCSSStyleRule* aRule, michael@0: uint32_t aSelectorIndex, michael@0: nsAString& aText) michael@0: { michael@0: ErrorResult rv; michael@0: nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv); michael@0: if (rv.Failed()) { michael@0: return rv.ErrorCode(); michael@0: } michael@0: michael@0: nsRefPtr rule = GetRuleFromDOMRule(aRule, rv); michael@0: MOZ_ASSERT(!rv.Failed(), "How could we get a selector but not a rule?"); michael@0: michael@0: sel->mSelectors->ToString(aText, rule->GetStyleSheet(), false); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetSpecificity(nsIDOMCSSStyleRule* aRule, michael@0: uint32_t aSelectorIndex, michael@0: uint64_t* aSpecificity) michael@0: { michael@0: ErrorResult rv; michael@0: nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv); michael@0: if (rv.Failed()) { michael@0: return rv.ErrorCode(); michael@0: } michael@0: michael@0: *aSpecificity = sel->mWeight; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement, michael@0: nsIDOMCSSStyleRule* aRule, michael@0: uint32_t aSelectorIndex, michael@0: bool* aMatches) michael@0: { michael@0: nsCOMPtr element = do_QueryInterface(aElement); michael@0: NS_ENSURE_ARG_POINTER(element); michael@0: michael@0: ErrorResult rv; michael@0: nsCSSSelectorList* tail = GetSelectorAtIndex(aRule, aSelectorIndex, rv); michael@0: if (rv.Failed()) { michael@0: return rv.ErrorCode(); michael@0: } michael@0: michael@0: // We want just the one list item, not the whole list tail michael@0: nsAutoPtr sel(tail->Clone(false)); michael@0: michael@0: // SelectorListMatches does not handle selectors that begin with a michael@0: // pseudo-element, which you can get from selectors like michael@0: // |input::-moz-placeholder:hover|. This function doesn't take michael@0: // a pseudo-element nsIAtom*, so we know we can't match. michael@0: if (sel->mSelectors->IsPseudoElement()) { michael@0: *aMatches = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: element->OwnerDoc()->FlushPendingLinkUpdates(); michael@0: // XXXbz what exactly should we do with visited state here? michael@0: TreeMatchContext matchingContext(false, michael@0: nsRuleWalker::eRelevantLinkUnvisited, michael@0: element->OwnerDoc(), michael@0: TreeMatchContext::eNeverMatchVisited); michael@0: *aMatches = nsCSSRuleProcessor::SelectorListMatches(element, matchingContext, michael@0: sel); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::IsInheritedProperty(const nsAString &aPropertyName, bool *_retval) michael@0: { michael@0: nsCSSProperty prop = michael@0: nsCSSProps::LookupProperty(aPropertyName, nsCSSProps::eIgnoreEnabledState); michael@0: if (prop == eCSSProperty_UNKNOWN) { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (prop == eCSSPropertyExtra_variable) { michael@0: *_retval = true; michael@0: return NS_OK; michael@0: } michael@0: michael@0: if (nsCSSProps::IsShorthand(prop)) { michael@0: prop = nsCSSProps::SubpropertyEntryFor(prop)[0]; michael@0: } michael@0: michael@0: nsStyleStructID sid = nsCSSProps::kSIDTable[prop]; michael@0: *_retval = !nsCachedStyleData::IsReset(sid); michael@0: return NS_OK; michael@0: } michael@0: michael@0: extern const char* const kCSSRawProperties[]; michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetCSSPropertyNames(uint32_t aFlags, uint32_t* aCount, michael@0: char16_t*** aProps) michael@0: { michael@0: // maxCount is the largest number of properties we could have; our actual michael@0: // number might be smaller because properties might be disabled. michael@0: uint32_t maxCount; michael@0: if (aFlags & EXCLUDE_SHORTHANDS) { michael@0: maxCount = eCSSProperty_COUNT_no_shorthands; michael@0: } else { michael@0: maxCount = eCSSProperty_COUNT; michael@0: } michael@0: michael@0: if (aFlags & INCLUDE_ALIASES) { michael@0: maxCount += (eCSSProperty_COUNT_with_aliases - eCSSProperty_COUNT); michael@0: } michael@0: michael@0: char16_t** props = michael@0: static_cast(nsMemory::Alloc(maxCount * sizeof(char16_t*))); michael@0: michael@0: #define DO_PROP(_prop) \ michael@0: PR_BEGIN_MACRO \ michael@0: nsCSSProperty cssProp = nsCSSProperty(_prop); \ michael@0: if (nsCSSProps::IsEnabled(cssProp)) { \ michael@0: props[propCount] = \ michael@0: ToNewUnicode(nsDependentCString(kCSSRawProperties[_prop])); \ michael@0: ++propCount; \ michael@0: } \ michael@0: PR_END_MACRO michael@0: michael@0: // prop is the property id we're considering; propCount is how many properties michael@0: // we've put into props so far. michael@0: uint32_t prop = 0, propCount = 0; michael@0: for ( ; prop < eCSSProperty_COUNT_no_shorthands; ++prop) { michael@0: if (nsCSSProps::PropertyParseType(nsCSSProperty(prop)) != michael@0: CSS_PROPERTY_PARSE_INACCESSIBLE) { michael@0: DO_PROP(prop); michael@0: } michael@0: } michael@0: michael@0: if (!(aFlags & EXCLUDE_SHORTHANDS)) { michael@0: for ( ; prop < eCSSProperty_COUNT; ++prop) { michael@0: // Some shorthands are also aliases michael@0: if ((aFlags & INCLUDE_ALIASES) || michael@0: !nsCSSProps::PropHasFlags(nsCSSProperty(prop), michael@0: CSS_PROPERTY_IS_ALIAS)) { michael@0: DO_PROP(prop); michael@0: } michael@0: } michael@0: } michael@0: michael@0: if (aFlags & INCLUDE_ALIASES) { michael@0: for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; ++prop) { michael@0: DO_PROP(prop); michael@0: } michael@0: } michael@0: michael@0: #undef DO_PROP michael@0: michael@0: *aCount = propCount; michael@0: *aProps = props; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void InsertNoDuplicates(nsTArray& aArray, michael@0: const nsAString& aString) michael@0: { michael@0: size_t i = aArray.IndexOfFirstElementGt(aString); michael@0: if (i > 0 && aArray[i-1].Equals(aString)) { michael@0: return; michael@0: } michael@0: aArray.InsertElementAt(i, aString); michael@0: } michael@0: michael@0: static void GetKeywordsForProperty(const nsCSSProperty aProperty, michael@0: nsTArray& aArray) michael@0: { michael@0: if (nsCSSProps::IsShorthand(aProperty)) { michael@0: // Shorthand props have no keywords. michael@0: return; michael@0: } michael@0: const nsCSSProps::KTableValue *keywordTable = michael@0: nsCSSProps::kKeywordTableTable[aProperty]; michael@0: if (keywordTable && keywordTable != nsCSSProps::kBoxPropSourceKTable) { michael@0: size_t i = 0; michael@0: while (nsCSSKeyword(keywordTable[i]) != eCSSKeyword_UNKNOWN) { michael@0: nsCSSKeyword word = nsCSSKeyword(keywordTable[i]); michael@0: InsertNoDuplicates(aArray, michael@0: NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word))); michael@0: // Increment counter by 2, because in this table every second michael@0: // element is a nsCSSKeyword. michael@0: i += 2; michael@0: } michael@0: } michael@0: } michael@0: michael@0: static void GetColorsForProperty(const uint32_t aParserVariant, michael@0: nsTArray& aArray) michael@0: { michael@0: if (aParserVariant & VARIANT_COLOR) { michael@0: // GetKeywordsForProperty and GetOtherValuesForProperty assume aArray is sorted, michael@0: // and if aArray is not empty here, then it's not going to be sorted coming out. michael@0: MOZ_ASSERT(aArray.Length() == 0); michael@0: size_t size; michael@0: const char * const *allColorNames = NS_AllColorNames(&size); michael@0: for (size_t i = 0; i < size; i++) { michael@0: CopyASCIItoUTF16(allColorNames[i], *aArray.AppendElement()); michael@0: } michael@0: } michael@0: return; michael@0: } michael@0: michael@0: static void GetOtherValuesForProperty(const uint32_t aParserVariant, michael@0: nsTArray& aArray) michael@0: { michael@0: if (aParserVariant & VARIANT_AUTO) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("auto")); michael@0: } michael@0: if (aParserVariant & VARIANT_NORMAL) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("normal")); michael@0: } michael@0: if(aParserVariant & VARIANT_ALL) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("all")); michael@0: } michael@0: if (aParserVariant & VARIANT_NONE) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("none")); michael@0: } michael@0: if (aParserVariant & VARIANT_ELEMENT) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-element")); michael@0: } michael@0: if (aParserVariant & VARIANT_IMAGE_RECT) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-image-rect")); michael@0: } michael@0: if (aParserVariant & VARIANT_COLOR) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgb")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsl")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgba")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsla")); michael@0: } michael@0: if (aParserVariant & VARIANT_TIMING_FUNCTION) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("cubic-bezier")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("steps")); michael@0: } michael@0: if (aParserVariant & VARIANT_CALC) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("calc")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-calc")); michael@0: } michael@0: if (aParserVariant & VARIANT_URL) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("url")); michael@0: } michael@0: if (aParserVariant & VARIANT_GRADIENT) { michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("linear-gradient")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("radial-gradient")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-linear-gradient")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-radial-gradient")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-linear-gradient")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-radial-gradient")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-linear-gradient")); michael@0: InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-radial-gradient")); michael@0: } michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty, michael@0: uint32_t* aLength, michael@0: char16_t*** aValues) michael@0: { michael@0: nsCSSProperty propertyID = nsCSSProps::LookupProperty(aProperty, michael@0: nsCSSProps::eEnabledForAllContent); michael@0: if (propertyID == eCSSProperty_UNKNOWN) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: nsTArray array; michael@0: // We start collecting the values, BUT colors need to go in first, because array michael@0: // needs to stay sorted, and the colors are sorted, so we just append them. michael@0: if (propertyID == eCSSPropertyExtra_variable) { michael@0: // No other values we can report. michael@0: } else if (!nsCSSProps::IsShorthand(propertyID)) { michael@0: // Property is longhand. michael@0: uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID); michael@0: // Get colors first. michael@0: GetColorsForProperty(propertyParserVariant, array); michael@0: if (propertyParserVariant & VARIANT_KEYWORD) { michael@0: GetKeywordsForProperty(propertyID, array); michael@0: } michael@0: GetOtherValuesForProperty(propertyParserVariant, array); michael@0: } else { michael@0: // Property is shorthand. michael@0: CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) { michael@0: // Get colors (once) first. michael@0: uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty); michael@0: if (propertyParserVariant & VARIANT_COLOR) { michael@0: GetColorsForProperty(propertyParserVariant, array); michael@0: break; michael@0: } michael@0: } michael@0: CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) { michael@0: uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty); michael@0: if (propertyParserVariant & VARIANT_KEYWORD) { michael@0: GetKeywordsForProperty(*subproperty, array); michael@0: } michael@0: GetOtherValuesForProperty(propertyParserVariant, array); michael@0: } michael@0: } michael@0: // All CSS properties take initial, inherit and unset. michael@0: InsertNoDuplicates(array, NS_LITERAL_STRING("initial")); michael@0: InsertNoDuplicates(array, NS_LITERAL_STRING("inherit")); michael@0: InsertNoDuplicates(array, NS_LITERAL_STRING("unset")); michael@0: michael@0: *aLength = array.Length(); michael@0: char16_t** ret = michael@0: static_cast(NS_Alloc(*aLength * sizeof(char16_t*))); michael@0: for (uint32_t i = 0; i < *aLength; ++i) { michael@0: ret[i] = ToNewUnicode(array[i]); michael@0: } michael@0: *aValues = ret; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::ColorNameToRGB(const nsAString& aColorName, JSContext* aCx, michael@0: JS::MutableHandle aValue) michael@0: { michael@0: nscolor color; michael@0: if (!NS_ColorNameToRGB(aColorName, &color)) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: InspectorRGBTriple triple; michael@0: triple.mR = NS_GET_R(color); michael@0: triple.mG = NS_GET_G(color); michael@0: triple.mB = NS_GET_B(color); michael@0: michael@0: if (!triple.ToObject(aCx, aValue)) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::RgbToColorName(uint8_t aR, uint8_t aG, uint8_t aB, michael@0: nsAString& aColorName) michael@0: { michael@0: const char* color = NS_RGBToColorName(NS_RGB(aR, aG, aB)); michael@0: if (!color) { michael@0: aColorName.Truncate(); michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: aColorName.AssignASCII(color); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetBindingURLs(nsIDOMElement *aElement, nsIArray **_retval) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aElement); michael@0: michael@0: *_retval = nullptr; michael@0: michael@0: nsCOMPtr urls = do_CreateInstance(NS_ARRAY_CONTRACTID); michael@0: if (!urls) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: nsCOMPtr content = do_QueryInterface(aElement); michael@0: NS_ENSURE_ARG_POINTER(content); michael@0: michael@0: nsXBLBinding *binding = content->GetXBLBinding(); michael@0: michael@0: while (binding) { michael@0: urls->AppendElement(binding->PrototypeBinding()->BindingURI(), false); michael@0: binding = binding->GetBaseBinding(); michael@0: } michael@0: michael@0: NS_ADDREF(*_retval = urls); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::SetContentState(nsIDOMElement* aElement, michael@0: EventStates::InternalType aState) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aElement); michael@0: michael@0: nsRefPtr esm = michael@0: inLayoutUtils::GetEventStateManagerFor(aElement); michael@0: if (esm) { michael@0: nsCOMPtr content; michael@0: content = do_QueryInterface(aElement); michael@0: michael@0: // XXX Invalid cast of bool to nsresult (bug 778108) michael@0: return (nsresult)esm->SetContentState(content, EventStates(aState)); michael@0: } michael@0: michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetContentState(nsIDOMElement* aElement, michael@0: EventStates::InternalType* aState) michael@0: { michael@0: *aState = 0; michael@0: nsCOMPtr content = do_QueryInterface(aElement); michael@0: NS_ENSURE_ARG_POINTER(content); michael@0: michael@0: // NOTE: if this method is removed, michael@0: // please remove GetInternalValue from EventStates michael@0: *aState = content->AsElement()->State().GetInternalValue(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* static */ nsresult michael@0: inDOMUtils::GetRuleNodeForElement(dom::Element* aElement, michael@0: nsIAtom* aPseudo, michael@0: nsStyleContext** aStyleContext, michael@0: nsRuleNode** aRuleNode) michael@0: { michael@0: MOZ_ASSERT(aElement); michael@0: michael@0: *aRuleNode = nullptr; michael@0: *aStyleContext = nullptr; michael@0: michael@0: nsIDocument* doc = aElement->GetDocument(); michael@0: NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsIPresShell *presShell = doc->GetShell(); michael@0: NS_ENSURE_TRUE(presShell, NS_ERROR_UNEXPECTED); michael@0: michael@0: nsPresContext *presContext = presShell->GetPresContext(); michael@0: NS_ENSURE_TRUE(presContext, NS_ERROR_UNEXPECTED); michael@0: michael@0: presContext->EnsureSafeToHandOutCSSRules(); michael@0: michael@0: nsRefPtr sContext = michael@0: nsComputedDOMStyle::GetStyleContextForElement(aElement, aPseudo, presShell); michael@0: if (sContext) { michael@0: *aRuleNode = sContext->RuleNode(); michael@0: sContext.forget(aStyleContext); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::GetUsedFontFaces(nsIDOMRange* aRange, michael@0: nsIDOMFontFaceList** aFontFaceList) michael@0: { michael@0: return static_cast(aRange)->GetUsedFontFaces(aFontFaceList); michael@0: } michael@0: michael@0: static EventStates michael@0: GetStatesForPseudoClass(const nsAString& aStatePseudo) michael@0: { michael@0: // An array of the states that are relevant for various pseudoclasses. michael@0: // XXXbz this duplicates code in nsCSSRuleProcessor michael@0: static const EventStates sPseudoClassStates[] = { michael@0: #define CSS_PSEUDO_CLASS(_name, _value, _pref) \ michael@0: EventStates(), michael@0: #define CSS_STATE_PSEUDO_CLASS(_name, _value, _pref, _states) \ michael@0: _states, michael@0: #include "nsCSSPseudoClassList.h" michael@0: #undef CSS_STATE_PSEUDO_CLASS michael@0: #undef CSS_PSEUDO_CLASS michael@0: michael@0: // Add more entries for our fake values to make sure we can't michael@0: // index out of bounds into this array no matter what. michael@0: EventStates(), michael@0: EventStates() michael@0: }; michael@0: static_assert(MOZ_ARRAY_LENGTH(sPseudoClassStates) == michael@0: nsCSSPseudoClasses::ePseudoClass_NotPseudoClass + 1, michael@0: "Length of PseudoClassStates array is incorrect"); michael@0: michael@0: nsCOMPtr atom = do_GetAtom(aStatePseudo); michael@0: michael@0: // Ignore :moz-any-link so we don't give the element simultaneous michael@0: // visited and unvisited style state michael@0: if (nsCSSPseudoClasses::GetPseudoType(atom) == michael@0: nsCSSPseudoClasses::ePseudoClass_mozAnyLink) { michael@0: return EventStates(); michael@0: } michael@0: // Our array above is long enough that indexing into it with michael@0: // NotPseudoClass is ok. michael@0: return sPseudoClassStates[nsCSSPseudoClasses::GetPseudoType(atom)]; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement, michael@0: const nsAString &aPseudoClass) michael@0: { michael@0: EventStates state = GetStatesForPseudoClass(aPseudoClass); michael@0: if (state.IsEmpty()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr element = do_QueryInterface(aElement); michael@0: NS_ENSURE_ARG_POINTER(element); michael@0: michael@0: element->LockStyleStates(state); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::RemovePseudoClassLock(nsIDOMElement *aElement, michael@0: const nsAString &aPseudoClass) michael@0: { michael@0: EventStates state = GetStatesForPseudoClass(aPseudoClass); michael@0: if (state.IsEmpty()) { michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr element = do_QueryInterface(aElement); michael@0: NS_ENSURE_ARG_POINTER(element); michael@0: michael@0: element->UnlockStyleStates(state); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::HasPseudoClassLock(nsIDOMElement *aElement, michael@0: const nsAString &aPseudoClass, michael@0: bool *_retval) michael@0: { michael@0: EventStates state = GetStatesForPseudoClass(aPseudoClass); michael@0: if (state.IsEmpty()) { michael@0: *_retval = false; michael@0: return NS_OK; michael@0: } michael@0: michael@0: nsCOMPtr element = do_QueryInterface(aElement); michael@0: NS_ENSURE_ARG_POINTER(element); michael@0: michael@0: EventStates locks = element->LockedStyleStates(); michael@0: michael@0: *_retval = locks.HasAllStates(state); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::ClearPseudoClassLocks(nsIDOMElement *aElement) michael@0: { michael@0: nsCOMPtr element = do_QueryInterface(aElement); michael@0: NS_ENSURE_ARG_POINTER(element); michael@0: michael@0: element->ClearStyleStateLocks(); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: inDOMUtils::ParseStyleSheet(nsIDOMCSSStyleSheet *aSheet, michael@0: const nsAString& aInput) michael@0: { michael@0: nsRefPtr sheet = do_QueryObject(aSheet); michael@0: NS_ENSURE_ARG_POINTER(sheet); michael@0: michael@0: return sheet->ParseSheet(aInput); michael@0: }