diff -r 000000000000 -r 6474c204b198 layout/inspector/inDOMUtils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/layout/inspector/inDOMUtils.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,880 @@ +/* -*- 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/dom/Element.h" +#include "nsCSSStyleSheet.h" +#include "nsRuleWalker.h" +#include "nsRuleProcessorData.h" +#include "nsCSSRuleProcessor.h" +#include "mozilla/dom/InspectorUtilsBinding.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::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 (!triple.ToObject(aCx, 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); +}