Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/ArrayUtils.h"
7 #include "mozilla/EventStates.h"
9 #include "inDOMUtils.h"
10 #include "inLayoutUtils.h"
12 #include "nsIServiceManager.h"
13 #include "nsISupportsArray.h"
14 #include "nsString.h"
15 #include "nsIDOMElement.h"
16 #include "nsIDocument.h"
17 #include "nsIPresShell.h"
18 #include "nsIDOMDocument.h"
19 #include "nsIDOMCharacterData.h"
20 #include "nsRuleNode.h"
21 #include "nsIStyleRule.h"
22 #include "mozilla/css/StyleRule.h"
23 #include "nsICSSStyleRuleDOMWrapper.h"
24 #include "nsIDOMWindow.h"
25 #include "nsXBLBinding.h"
26 #include "nsXBLPrototypeBinding.h"
27 #include "nsIMutableArray.h"
28 #include "nsBindingManager.h"
29 #include "ChildIterator.h"
30 #include "nsComputedDOMStyle.h"
31 #include "mozilla/EventStateManager.h"
32 #include "nsIAtom.h"
33 #include "nsRange.h"
34 #include "nsContentList.h"
35 #include "mozilla/dom/Element.h"
36 #include "nsCSSStyleSheet.h"
37 #include "nsRuleWalker.h"
38 #include "nsRuleProcessorData.h"
39 #include "nsCSSRuleProcessor.h"
40 #include "mozilla/dom/InspectorUtilsBinding.h"
41 #include "nsCSSProps.h"
42 #include "nsColor.h"
43 #include "nsStyleSet.h"
45 using namespace mozilla;
46 using namespace mozilla::css;
47 using namespace mozilla::dom;
49 ///////////////////////////////////////////////////////////////////////////////
51 inDOMUtils::inDOMUtils()
52 {
53 }
55 inDOMUtils::~inDOMUtils()
56 {
57 }
59 NS_IMPL_ISUPPORTS(inDOMUtils, inIDOMUtils)
61 ///////////////////////////////////////////////////////////////////////////////
62 // inIDOMUtils
64 NS_IMETHODIMP
65 inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
66 nsISupports ***aSheets)
67 {
68 NS_ENSURE_ARG_POINTER(aDocument);
70 nsCOMArray<nsISupports> sheets;
72 nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument);
73 MOZ_ASSERT(document);
75 // Get the agent, then user sheets in the style set.
76 nsIPresShell* presShell = document->GetShell();
77 if (presShell) {
78 nsStyleSet* styleSet = presShell->StyleSet();
79 nsStyleSet::sheetType sheetType = nsStyleSet::eAgentSheet;
80 for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
81 sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
82 }
83 sheetType = nsStyleSet::eUserSheet;
84 for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
85 sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
86 }
87 }
89 // Get the document sheets.
90 for (int32_t i = 0; i < document->GetNumberOfStyleSheets(); i++) {
91 sheets.AppendElement(document->GetStyleSheetAt(i));
92 }
94 nsISupports** ret = static_cast<nsISupports**>(NS_Alloc(sheets.Count() *
95 sizeof(nsISupports*)));
97 for (int32_t i = 0; i < sheets.Count(); i++) {
98 NS_ADDREF(ret[i] = sheets[i]);
99 }
101 *aLength = sheets.Count();
102 *aSheets = ret;
104 return NS_OK;
105 }
107 NS_IMETHODIMP
108 inDOMUtils::IsIgnorableWhitespace(nsIDOMCharacterData *aDataNode,
109 bool *aReturn)
110 {
111 NS_PRECONDITION(aReturn, "Must have an out parameter");
113 NS_ENSURE_ARG_POINTER(aDataNode);
115 *aReturn = false;
117 nsCOMPtr<nsIContent> content = do_QueryInterface(aDataNode);
118 NS_ASSERTION(content, "Does not implement nsIContent!");
120 if (!content->TextIsOnlyWhitespace()) {
121 return NS_OK;
122 }
124 // Okay. We have only white space. Let's check the white-space
125 // property now and make sure that this isn't preformatted text...
126 nsIFrame* frame = content->GetPrimaryFrame();
127 if (frame) {
128 const nsStyleText* text = frame->StyleText();
129 *aReturn = !text->WhiteSpaceIsSignificant();
130 }
131 else {
132 // empty inter-tag text node without frame, e.g., in between <table>\n<tr>
133 *aReturn = true;
134 }
136 return NS_OK;
137 }
139 NS_IMETHODIMP
140 inDOMUtils::GetParentForNode(nsIDOMNode* aNode,
141 bool aShowingAnonymousContent,
142 nsIDOMNode** aParent)
143 {
144 NS_ENSURE_ARG_POINTER(aNode);
146 // First do the special cases -- document nodes and anonymous content
147 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode));
148 nsCOMPtr<nsIDOMNode> parent;
150 if (doc) {
151 parent = inLayoutUtils::GetContainerFor(*doc);
152 } else if (aShowingAnonymousContent) {
153 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
154 if (content) {
155 nsIContent* bparent = content->GetXBLInsertionParent();
156 parent = do_QueryInterface(bparent);
157 }
158 }
160 if (!parent) {
161 // Ok, just get the normal DOM parent node
162 aNode->GetParentNode(getter_AddRefs(parent));
163 }
165 NS_IF_ADDREF(*aParent = parent);
166 return NS_OK;
167 }
169 NS_IMETHODIMP
170 inDOMUtils::GetChildrenForNode(nsIDOMNode* aNode,
171 bool aShowingAnonymousContent,
172 nsIDOMNodeList** aChildren)
173 {
174 NS_ENSURE_ARG_POINTER(aNode);
175 NS_PRECONDITION(aChildren, "Must have an out parameter");
177 nsCOMPtr<nsIDOMNodeList> kids;
179 if (aShowingAnonymousContent) {
180 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
181 if (content) {
182 kids = content->GetChildren(nsIContent::eAllChildren);
183 }
184 }
186 if (!kids) {
187 aNode->GetChildNodes(getter_AddRefs(kids));
188 }
190 kids.forget(aChildren);
191 return NS_OK;
192 }
194 NS_IMETHODIMP
195 inDOMUtils::GetCSSStyleRules(nsIDOMElement *aElement,
196 const nsAString& aPseudo,
197 nsISupportsArray **_retval)
198 {
199 NS_ENSURE_ARG_POINTER(aElement);
201 *_retval = nullptr;
203 nsCOMPtr<nsIAtom> pseudoElt;
204 if (!aPseudo.IsEmpty()) {
205 pseudoElt = do_GetAtom(aPseudo);
206 }
208 nsRuleNode* ruleNode = nullptr;
209 nsCOMPtr<Element> element = do_QueryInterface(aElement);
210 NS_ENSURE_STATE(element);
211 nsRefPtr<nsStyleContext> styleContext;
212 GetRuleNodeForElement(element, pseudoElt, getter_AddRefs(styleContext), &ruleNode);
213 if (!ruleNode) {
214 // This can fail for elements that are not in the document or
215 // if the document they're in doesn't have a presshell. Bail out.
216 return NS_OK;
217 }
219 nsCOMPtr<nsISupportsArray> rules;
220 NS_NewISupportsArray(getter_AddRefs(rules));
221 if (!rules) return NS_ERROR_OUT_OF_MEMORY;
223 nsRefPtr<mozilla::css::StyleRule> cssRule;
224 for ( ; !ruleNode->IsRoot(); ruleNode = ruleNode->GetParent()) {
225 cssRule = do_QueryObject(ruleNode->GetRule());
226 if (cssRule) {
227 nsCOMPtr<nsIDOMCSSRule> domRule = cssRule->GetDOMRule();
228 if (domRule)
229 rules->InsertElementAt(domRule, 0);
230 }
231 }
233 *_retval = rules;
234 NS_ADDREF(*_retval);
236 return NS_OK;
237 }
239 static already_AddRefed<StyleRule>
240 GetRuleFromDOMRule(nsIDOMCSSStyleRule *aRule, ErrorResult& rv)
241 {
242 nsCOMPtr<nsICSSStyleRuleDOMWrapper> rule = do_QueryInterface(aRule);
243 if (!rule) {
244 rv.Throw(NS_ERROR_INVALID_POINTER);
245 return nullptr;
246 }
248 nsRefPtr<StyleRule> cssrule;
249 rv = rule->GetCSSStyleRule(getter_AddRefs(cssrule));
250 if (rv.Failed()) {
251 return nullptr;
252 }
254 if (!cssrule) {
255 rv.Throw(NS_ERROR_FAILURE);
256 }
257 return cssrule.forget();
258 }
260 NS_IMETHODIMP
261 inDOMUtils::GetRuleLine(nsIDOMCSSStyleRule *aRule, uint32_t *_retval)
262 {
263 ErrorResult rv;
264 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
265 if (rv.Failed()) {
266 return rv.ErrorCode();
267 }
269 *_retval = rule->GetLineNumber();
270 return NS_OK;
271 }
273 NS_IMETHODIMP
274 inDOMUtils::GetRuleColumn(nsIDOMCSSStyleRule *aRule, uint32_t *_retval)
275 {
276 ErrorResult rv;
277 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
278 if (rv.Failed()) {
279 return rv.ErrorCode();
280 }
281 *_retval = rule->GetColumnNumber();
282 return NS_OK;
283 }
285 NS_IMETHODIMP
286 inDOMUtils::GetSelectorCount(nsIDOMCSSStyleRule* aRule, uint32_t *aCount)
287 {
288 ErrorResult rv;
289 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
290 if (rv.Failed()) {
291 return rv.ErrorCode();
292 }
294 uint32_t count = 0;
295 for (nsCSSSelectorList* sel = rule->Selector(); sel; sel = sel->mNext) {
296 ++count;
297 }
298 *aCount = count;
299 return NS_OK;
300 }
302 static nsCSSSelectorList*
303 GetSelectorAtIndex(nsIDOMCSSStyleRule* aRule, uint32_t aIndex, ErrorResult& rv)
304 {
305 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
306 if (rv.Failed()) {
307 return nullptr;
308 }
310 for (nsCSSSelectorList* sel = rule->Selector(); sel;
311 sel = sel->mNext, --aIndex) {
312 if (aIndex == 0) {
313 return sel;
314 }
315 }
317 // Ran out of selectors
318 rv.Throw(NS_ERROR_INVALID_ARG);
319 return nullptr;
320 }
322 NS_IMETHODIMP
323 inDOMUtils::GetSelectorText(nsIDOMCSSStyleRule* aRule,
324 uint32_t aSelectorIndex,
325 nsAString& aText)
326 {
327 ErrorResult rv;
328 nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
329 if (rv.Failed()) {
330 return rv.ErrorCode();
331 }
333 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
334 MOZ_ASSERT(!rv.Failed(), "How could we get a selector but not a rule?");
336 sel->mSelectors->ToString(aText, rule->GetStyleSheet(), false);
337 return NS_OK;
338 }
340 NS_IMETHODIMP
341 inDOMUtils::GetSpecificity(nsIDOMCSSStyleRule* aRule,
342 uint32_t aSelectorIndex,
343 uint64_t* aSpecificity)
344 {
345 ErrorResult rv;
346 nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
347 if (rv.Failed()) {
348 return rv.ErrorCode();
349 }
351 *aSpecificity = sel->mWeight;
352 return NS_OK;
353 }
355 NS_IMETHODIMP
356 inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement,
357 nsIDOMCSSStyleRule* aRule,
358 uint32_t aSelectorIndex,
359 bool* aMatches)
360 {
361 nsCOMPtr<Element> element = do_QueryInterface(aElement);
362 NS_ENSURE_ARG_POINTER(element);
364 ErrorResult rv;
365 nsCSSSelectorList* tail = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
366 if (rv.Failed()) {
367 return rv.ErrorCode();
368 }
370 // We want just the one list item, not the whole list tail
371 nsAutoPtr<nsCSSSelectorList> sel(tail->Clone(false));
373 // SelectorListMatches does not handle selectors that begin with a
374 // pseudo-element, which you can get from selectors like
375 // |input::-moz-placeholder:hover|. This function doesn't take
376 // a pseudo-element nsIAtom*, so we know we can't match.
377 if (sel->mSelectors->IsPseudoElement()) {
378 *aMatches = false;
379 return NS_OK;
380 }
382 element->OwnerDoc()->FlushPendingLinkUpdates();
383 // XXXbz what exactly should we do with visited state here?
384 TreeMatchContext matchingContext(false,
385 nsRuleWalker::eRelevantLinkUnvisited,
386 element->OwnerDoc(),
387 TreeMatchContext::eNeverMatchVisited);
388 *aMatches = nsCSSRuleProcessor::SelectorListMatches(element, matchingContext,
389 sel);
390 return NS_OK;
391 }
393 NS_IMETHODIMP
394 inDOMUtils::IsInheritedProperty(const nsAString &aPropertyName, bool *_retval)
395 {
396 nsCSSProperty prop =
397 nsCSSProps::LookupProperty(aPropertyName, nsCSSProps::eIgnoreEnabledState);
398 if (prop == eCSSProperty_UNKNOWN) {
399 *_retval = false;
400 return NS_OK;
401 }
403 if (prop == eCSSPropertyExtra_variable) {
404 *_retval = true;
405 return NS_OK;
406 }
408 if (nsCSSProps::IsShorthand(prop)) {
409 prop = nsCSSProps::SubpropertyEntryFor(prop)[0];
410 }
412 nsStyleStructID sid = nsCSSProps::kSIDTable[prop];
413 *_retval = !nsCachedStyleData::IsReset(sid);
414 return NS_OK;
415 }
417 extern const char* const kCSSRawProperties[];
419 NS_IMETHODIMP
420 inDOMUtils::GetCSSPropertyNames(uint32_t aFlags, uint32_t* aCount,
421 char16_t*** aProps)
422 {
423 // maxCount is the largest number of properties we could have; our actual
424 // number might be smaller because properties might be disabled.
425 uint32_t maxCount;
426 if (aFlags & EXCLUDE_SHORTHANDS) {
427 maxCount = eCSSProperty_COUNT_no_shorthands;
428 } else {
429 maxCount = eCSSProperty_COUNT;
430 }
432 if (aFlags & INCLUDE_ALIASES) {
433 maxCount += (eCSSProperty_COUNT_with_aliases - eCSSProperty_COUNT);
434 }
436 char16_t** props =
437 static_cast<char16_t**>(nsMemory::Alloc(maxCount * sizeof(char16_t*)));
439 #define DO_PROP(_prop) \
440 PR_BEGIN_MACRO \
441 nsCSSProperty cssProp = nsCSSProperty(_prop); \
442 if (nsCSSProps::IsEnabled(cssProp)) { \
443 props[propCount] = \
444 ToNewUnicode(nsDependentCString(kCSSRawProperties[_prop])); \
445 ++propCount; \
446 } \
447 PR_END_MACRO
449 // prop is the property id we're considering; propCount is how many properties
450 // we've put into props so far.
451 uint32_t prop = 0, propCount = 0;
452 for ( ; prop < eCSSProperty_COUNT_no_shorthands; ++prop) {
453 if (nsCSSProps::PropertyParseType(nsCSSProperty(prop)) !=
454 CSS_PROPERTY_PARSE_INACCESSIBLE) {
455 DO_PROP(prop);
456 }
457 }
459 if (!(aFlags & EXCLUDE_SHORTHANDS)) {
460 for ( ; prop < eCSSProperty_COUNT; ++prop) {
461 // Some shorthands are also aliases
462 if ((aFlags & INCLUDE_ALIASES) ||
463 !nsCSSProps::PropHasFlags(nsCSSProperty(prop),
464 CSS_PROPERTY_IS_ALIAS)) {
465 DO_PROP(prop);
466 }
467 }
468 }
470 if (aFlags & INCLUDE_ALIASES) {
471 for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; ++prop) {
472 DO_PROP(prop);
473 }
474 }
476 #undef DO_PROP
478 *aCount = propCount;
479 *aProps = props;
481 return NS_OK;
482 }
484 static void InsertNoDuplicates(nsTArray<nsString>& aArray,
485 const nsAString& aString)
486 {
487 size_t i = aArray.IndexOfFirstElementGt(aString);
488 if (i > 0 && aArray[i-1].Equals(aString)) {
489 return;
490 }
491 aArray.InsertElementAt(i, aString);
492 }
494 static void GetKeywordsForProperty(const nsCSSProperty aProperty,
495 nsTArray<nsString>& aArray)
496 {
497 if (nsCSSProps::IsShorthand(aProperty)) {
498 // Shorthand props have no keywords.
499 return;
500 }
501 const nsCSSProps::KTableValue *keywordTable =
502 nsCSSProps::kKeywordTableTable[aProperty];
503 if (keywordTable && keywordTable != nsCSSProps::kBoxPropSourceKTable) {
504 size_t i = 0;
505 while (nsCSSKeyword(keywordTable[i]) != eCSSKeyword_UNKNOWN) {
506 nsCSSKeyword word = nsCSSKeyword(keywordTable[i]);
507 InsertNoDuplicates(aArray,
508 NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word)));
509 // Increment counter by 2, because in this table every second
510 // element is a nsCSSKeyword.
511 i += 2;
512 }
513 }
514 }
516 static void GetColorsForProperty(const uint32_t aParserVariant,
517 nsTArray<nsString>& aArray)
518 {
519 if (aParserVariant & VARIANT_COLOR) {
520 // GetKeywordsForProperty and GetOtherValuesForProperty assume aArray is sorted,
521 // and if aArray is not empty here, then it's not going to be sorted coming out.
522 MOZ_ASSERT(aArray.Length() == 0);
523 size_t size;
524 const char * const *allColorNames = NS_AllColorNames(&size);
525 for (size_t i = 0; i < size; i++) {
526 CopyASCIItoUTF16(allColorNames[i], *aArray.AppendElement());
527 }
528 }
529 return;
530 }
532 static void GetOtherValuesForProperty(const uint32_t aParserVariant,
533 nsTArray<nsString>& aArray)
534 {
535 if (aParserVariant & VARIANT_AUTO) {
536 InsertNoDuplicates(aArray, NS_LITERAL_STRING("auto"));
537 }
538 if (aParserVariant & VARIANT_NORMAL) {
539 InsertNoDuplicates(aArray, NS_LITERAL_STRING("normal"));
540 }
541 if(aParserVariant & VARIANT_ALL) {
542 InsertNoDuplicates(aArray, NS_LITERAL_STRING("all"));
543 }
544 if (aParserVariant & VARIANT_NONE) {
545 InsertNoDuplicates(aArray, NS_LITERAL_STRING("none"));
546 }
547 if (aParserVariant & VARIANT_ELEMENT) {
548 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-element"));
549 }
550 if (aParserVariant & VARIANT_IMAGE_RECT) {
551 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-image-rect"));
552 }
553 if (aParserVariant & VARIANT_COLOR) {
554 InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgb"));
555 InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsl"));
556 InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgba"));
557 InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsla"));
558 }
559 if (aParserVariant & VARIANT_TIMING_FUNCTION) {
560 InsertNoDuplicates(aArray, NS_LITERAL_STRING("cubic-bezier"));
561 InsertNoDuplicates(aArray, NS_LITERAL_STRING("steps"));
562 }
563 if (aParserVariant & VARIANT_CALC) {
564 InsertNoDuplicates(aArray, NS_LITERAL_STRING("calc"));
565 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-calc"));
566 }
567 if (aParserVariant & VARIANT_URL) {
568 InsertNoDuplicates(aArray, NS_LITERAL_STRING("url"));
569 }
570 if (aParserVariant & VARIANT_GRADIENT) {
571 InsertNoDuplicates(aArray, NS_LITERAL_STRING("linear-gradient"));
572 InsertNoDuplicates(aArray, NS_LITERAL_STRING("radial-gradient"));
573 InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-linear-gradient"));
574 InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-radial-gradient"));
575 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-linear-gradient"));
576 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-radial-gradient"));
577 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-linear-gradient"));
578 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-radial-gradient"));
579 }
580 }
582 NS_IMETHODIMP
583 inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty,
584 uint32_t* aLength,
585 char16_t*** aValues)
586 {
587 nsCSSProperty propertyID = nsCSSProps::LookupProperty(aProperty,
588 nsCSSProps::eEnabledForAllContent);
589 if (propertyID == eCSSProperty_UNKNOWN) {
590 return NS_ERROR_FAILURE;
591 }
593 nsTArray<nsString> array;
594 // We start collecting the values, BUT colors need to go in first, because array
595 // needs to stay sorted, and the colors are sorted, so we just append them.
596 if (propertyID == eCSSPropertyExtra_variable) {
597 // No other values we can report.
598 } else if (!nsCSSProps::IsShorthand(propertyID)) {
599 // Property is longhand.
600 uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID);
601 // Get colors first.
602 GetColorsForProperty(propertyParserVariant, array);
603 if (propertyParserVariant & VARIANT_KEYWORD) {
604 GetKeywordsForProperty(propertyID, array);
605 }
606 GetOtherValuesForProperty(propertyParserVariant, array);
607 } else {
608 // Property is shorthand.
609 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) {
610 // Get colors (once) first.
611 uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
612 if (propertyParserVariant & VARIANT_COLOR) {
613 GetColorsForProperty(propertyParserVariant, array);
614 break;
615 }
616 }
617 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) {
618 uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
619 if (propertyParserVariant & VARIANT_KEYWORD) {
620 GetKeywordsForProperty(*subproperty, array);
621 }
622 GetOtherValuesForProperty(propertyParserVariant, array);
623 }
624 }
625 // All CSS properties take initial, inherit and unset.
626 InsertNoDuplicates(array, NS_LITERAL_STRING("initial"));
627 InsertNoDuplicates(array, NS_LITERAL_STRING("inherit"));
628 InsertNoDuplicates(array, NS_LITERAL_STRING("unset"));
630 *aLength = array.Length();
631 char16_t** ret =
632 static_cast<char16_t**>(NS_Alloc(*aLength * sizeof(char16_t*)));
633 for (uint32_t i = 0; i < *aLength; ++i) {
634 ret[i] = ToNewUnicode(array[i]);
635 }
636 *aValues = ret;
637 return NS_OK;
638 }
640 NS_IMETHODIMP
641 inDOMUtils::ColorNameToRGB(const nsAString& aColorName, JSContext* aCx,
642 JS::MutableHandle<JS::Value> aValue)
643 {
644 nscolor color;
645 if (!NS_ColorNameToRGB(aColorName, &color)) {
646 return NS_ERROR_INVALID_ARG;
647 }
649 InspectorRGBTriple triple;
650 triple.mR = NS_GET_R(color);
651 triple.mG = NS_GET_G(color);
652 triple.mB = NS_GET_B(color);
654 if (!triple.ToObject(aCx, aValue)) {
655 return NS_ERROR_FAILURE;
656 }
658 return NS_OK;
659 }
661 NS_IMETHODIMP
662 inDOMUtils::RgbToColorName(uint8_t aR, uint8_t aG, uint8_t aB,
663 nsAString& aColorName)
664 {
665 const char* color = NS_RGBToColorName(NS_RGB(aR, aG, aB));
666 if (!color) {
667 aColorName.Truncate();
668 return NS_ERROR_INVALID_ARG;
669 }
671 aColorName.AssignASCII(color);
672 return NS_OK;
673 }
675 NS_IMETHODIMP
676 inDOMUtils::GetBindingURLs(nsIDOMElement *aElement, nsIArray **_retval)
677 {
678 NS_ENSURE_ARG_POINTER(aElement);
680 *_retval = nullptr;
682 nsCOMPtr<nsIMutableArray> urls = do_CreateInstance(NS_ARRAY_CONTRACTID);
683 if (!urls)
684 return NS_ERROR_FAILURE;
686 nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
687 NS_ENSURE_ARG_POINTER(content);
689 nsXBLBinding *binding = content->GetXBLBinding();
691 while (binding) {
692 urls->AppendElement(binding->PrototypeBinding()->BindingURI(), false);
693 binding = binding->GetBaseBinding();
694 }
696 NS_ADDREF(*_retval = urls);
697 return NS_OK;
698 }
700 NS_IMETHODIMP
701 inDOMUtils::SetContentState(nsIDOMElement* aElement,
702 EventStates::InternalType aState)
703 {
704 NS_ENSURE_ARG_POINTER(aElement);
706 nsRefPtr<EventStateManager> esm =
707 inLayoutUtils::GetEventStateManagerFor(aElement);
708 if (esm) {
709 nsCOMPtr<nsIContent> content;
710 content = do_QueryInterface(aElement);
712 // XXX Invalid cast of bool to nsresult (bug 778108)
713 return (nsresult)esm->SetContentState(content, EventStates(aState));
714 }
716 return NS_ERROR_FAILURE;
717 }
719 NS_IMETHODIMP
720 inDOMUtils::GetContentState(nsIDOMElement* aElement,
721 EventStates::InternalType* aState)
722 {
723 *aState = 0;
724 nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
725 NS_ENSURE_ARG_POINTER(content);
727 // NOTE: if this method is removed,
728 // please remove GetInternalValue from EventStates
729 *aState = content->AsElement()->State().GetInternalValue();
730 return NS_OK;
731 }
733 /* static */ nsresult
734 inDOMUtils::GetRuleNodeForElement(dom::Element* aElement,
735 nsIAtom* aPseudo,
736 nsStyleContext** aStyleContext,
737 nsRuleNode** aRuleNode)
738 {
739 MOZ_ASSERT(aElement);
741 *aRuleNode = nullptr;
742 *aStyleContext = nullptr;
744 nsIDocument* doc = aElement->GetDocument();
745 NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
747 nsIPresShell *presShell = doc->GetShell();
748 NS_ENSURE_TRUE(presShell, NS_ERROR_UNEXPECTED);
750 nsPresContext *presContext = presShell->GetPresContext();
751 NS_ENSURE_TRUE(presContext, NS_ERROR_UNEXPECTED);
753 presContext->EnsureSafeToHandOutCSSRules();
755 nsRefPtr<nsStyleContext> sContext =
756 nsComputedDOMStyle::GetStyleContextForElement(aElement, aPseudo, presShell);
757 if (sContext) {
758 *aRuleNode = sContext->RuleNode();
759 sContext.forget(aStyleContext);
760 }
761 return NS_OK;
762 }
764 NS_IMETHODIMP
765 inDOMUtils::GetUsedFontFaces(nsIDOMRange* aRange,
766 nsIDOMFontFaceList** aFontFaceList)
767 {
768 return static_cast<nsRange*>(aRange)->GetUsedFontFaces(aFontFaceList);
769 }
771 static EventStates
772 GetStatesForPseudoClass(const nsAString& aStatePseudo)
773 {
774 // An array of the states that are relevant for various pseudoclasses.
775 // XXXbz this duplicates code in nsCSSRuleProcessor
776 static const EventStates sPseudoClassStates[] = {
777 #define CSS_PSEUDO_CLASS(_name, _value, _pref) \
778 EventStates(),
779 #define CSS_STATE_PSEUDO_CLASS(_name, _value, _pref, _states) \
780 _states,
781 #include "nsCSSPseudoClassList.h"
782 #undef CSS_STATE_PSEUDO_CLASS
783 #undef CSS_PSEUDO_CLASS
785 // Add more entries for our fake values to make sure we can't
786 // index out of bounds into this array no matter what.
787 EventStates(),
788 EventStates()
789 };
790 static_assert(MOZ_ARRAY_LENGTH(sPseudoClassStates) ==
791 nsCSSPseudoClasses::ePseudoClass_NotPseudoClass + 1,
792 "Length of PseudoClassStates array is incorrect");
794 nsCOMPtr<nsIAtom> atom = do_GetAtom(aStatePseudo);
796 // Ignore :moz-any-link so we don't give the element simultaneous
797 // visited and unvisited style state
798 if (nsCSSPseudoClasses::GetPseudoType(atom) ==
799 nsCSSPseudoClasses::ePseudoClass_mozAnyLink) {
800 return EventStates();
801 }
802 // Our array above is long enough that indexing into it with
803 // NotPseudoClass is ok.
804 return sPseudoClassStates[nsCSSPseudoClasses::GetPseudoType(atom)];
805 }
807 NS_IMETHODIMP
808 inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
809 const nsAString &aPseudoClass)
810 {
811 EventStates state = GetStatesForPseudoClass(aPseudoClass);
812 if (state.IsEmpty()) {
813 return NS_OK;
814 }
816 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
817 NS_ENSURE_ARG_POINTER(element);
819 element->LockStyleStates(state);
821 return NS_OK;
822 }
824 NS_IMETHODIMP
825 inDOMUtils::RemovePseudoClassLock(nsIDOMElement *aElement,
826 const nsAString &aPseudoClass)
827 {
828 EventStates state = GetStatesForPseudoClass(aPseudoClass);
829 if (state.IsEmpty()) {
830 return NS_OK;
831 }
833 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
834 NS_ENSURE_ARG_POINTER(element);
836 element->UnlockStyleStates(state);
838 return NS_OK;
839 }
841 NS_IMETHODIMP
842 inDOMUtils::HasPseudoClassLock(nsIDOMElement *aElement,
843 const nsAString &aPseudoClass,
844 bool *_retval)
845 {
846 EventStates state = GetStatesForPseudoClass(aPseudoClass);
847 if (state.IsEmpty()) {
848 *_retval = false;
849 return NS_OK;
850 }
852 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
853 NS_ENSURE_ARG_POINTER(element);
855 EventStates locks = element->LockedStyleStates();
857 *_retval = locks.HasAllStates(state);
858 return NS_OK;
859 }
861 NS_IMETHODIMP
862 inDOMUtils::ClearPseudoClassLocks(nsIDOMElement *aElement)
863 {
864 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
865 NS_ENSURE_ARG_POINTER(element);
867 element->ClearStyleStateLocks();
869 return NS_OK;
870 }
872 NS_IMETHODIMP
873 inDOMUtils::ParseStyleSheet(nsIDOMCSSStyleSheet *aSheet,
874 const nsAString& aInput)
875 {
876 nsRefPtr<nsCSSStyleSheet> sheet = do_QueryObject(aSheet);
877 NS_ENSURE_ARG_POINTER(sheet);
879 return sheet->ParseSheet(aInput);
880 }