|
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/. */ |
|
5 |
|
6 #include "mozilla/ArrayUtils.h" |
|
7 #include "mozilla/EventStates.h" |
|
8 |
|
9 #include "inDOMUtils.h" |
|
10 #include "inLayoutUtils.h" |
|
11 |
|
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" |
|
44 |
|
45 using namespace mozilla; |
|
46 using namespace mozilla::css; |
|
47 using namespace mozilla::dom; |
|
48 |
|
49 /////////////////////////////////////////////////////////////////////////////// |
|
50 |
|
51 inDOMUtils::inDOMUtils() |
|
52 { |
|
53 } |
|
54 |
|
55 inDOMUtils::~inDOMUtils() |
|
56 { |
|
57 } |
|
58 |
|
59 NS_IMPL_ISUPPORTS(inDOMUtils, inIDOMUtils) |
|
60 |
|
61 /////////////////////////////////////////////////////////////////////////////// |
|
62 // inIDOMUtils |
|
63 |
|
64 NS_IMETHODIMP |
|
65 inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength, |
|
66 nsISupports ***aSheets) |
|
67 { |
|
68 NS_ENSURE_ARG_POINTER(aDocument); |
|
69 |
|
70 nsCOMArray<nsISupports> sheets; |
|
71 |
|
72 nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument); |
|
73 MOZ_ASSERT(document); |
|
74 |
|
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 } |
|
88 |
|
89 // Get the document sheets. |
|
90 for (int32_t i = 0; i < document->GetNumberOfStyleSheets(); i++) { |
|
91 sheets.AppendElement(document->GetStyleSheetAt(i)); |
|
92 } |
|
93 |
|
94 nsISupports** ret = static_cast<nsISupports**>(NS_Alloc(sheets.Count() * |
|
95 sizeof(nsISupports*))); |
|
96 |
|
97 for (int32_t i = 0; i < sheets.Count(); i++) { |
|
98 NS_ADDREF(ret[i] = sheets[i]); |
|
99 } |
|
100 |
|
101 *aLength = sheets.Count(); |
|
102 *aSheets = ret; |
|
103 |
|
104 return NS_OK; |
|
105 } |
|
106 |
|
107 NS_IMETHODIMP |
|
108 inDOMUtils::IsIgnorableWhitespace(nsIDOMCharacterData *aDataNode, |
|
109 bool *aReturn) |
|
110 { |
|
111 NS_PRECONDITION(aReturn, "Must have an out parameter"); |
|
112 |
|
113 NS_ENSURE_ARG_POINTER(aDataNode); |
|
114 |
|
115 *aReturn = false; |
|
116 |
|
117 nsCOMPtr<nsIContent> content = do_QueryInterface(aDataNode); |
|
118 NS_ASSERTION(content, "Does not implement nsIContent!"); |
|
119 |
|
120 if (!content->TextIsOnlyWhitespace()) { |
|
121 return NS_OK; |
|
122 } |
|
123 |
|
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 } |
|
135 |
|
136 return NS_OK; |
|
137 } |
|
138 |
|
139 NS_IMETHODIMP |
|
140 inDOMUtils::GetParentForNode(nsIDOMNode* aNode, |
|
141 bool aShowingAnonymousContent, |
|
142 nsIDOMNode** aParent) |
|
143 { |
|
144 NS_ENSURE_ARG_POINTER(aNode); |
|
145 |
|
146 // First do the special cases -- document nodes and anonymous content |
|
147 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode)); |
|
148 nsCOMPtr<nsIDOMNode> parent; |
|
149 |
|
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 } |
|
159 |
|
160 if (!parent) { |
|
161 // Ok, just get the normal DOM parent node |
|
162 aNode->GetParentNode(getter_AddRefs(parent)); |
|
163 } |
|
164 |
|
165 NS_IF_ADDREF(*aParent = parent); |
|
166 return NS_OK; |
|
167 } |
|
168 |
|
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"); |
|
176 |
|
177 nsCOMPtr<nsIDOMNodeList> kids; |
|
178 |
|
179 if (aShowingAnonymousContent) { |
|
180 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode); |
|
181 if (content) { |
|
182 kids = content->GetChildren(nsIContent::eAllChildren); |
|
183 } |
|
184 } |
|
185 |
|
186 if (!kids) { |
|
187 aNode->GetChildNodes(getter_AddRefs(kids)); |
|
188 } |
|
189 |
|
190 kids.forget(aChildren); |
|
191 return NS_OK; |
|
192 } |
|
193 |
|
194 NS_IMETHODIMP |
|
195 inDOMUtils::GetCSSStyleRules(nsIDOMElement *aElement, |
|
196 const nsAString& aPseudo, |
|
197 nsISupportsArray **_retval) |
|
198 { |
|
199 NS_ENSURE_ARG_POINTER(aElement); |
|
200 |
|
201 *_retval = nullptr; |
|
202 |
|
203 nsCOMPtr<nsIAtom> pseudoElt; |
|
204 if (!aPseudo.IsEmpty()) { |
|
205 pseudoElt = do_GetAtom(aPseudo); |
|
206 } |
|
207 |
|
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 } |
|
218 |
|
219 nsCOMPtr<nsISupportsArray> rules; |
|
220 NS_NewISupportsArray(getter_AddRefs(rules)); |
|
221 if (!rules) return NS_ERROR_OUT_OF_MEMORY; |
|
222 |
|
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 } |
|
232 |
|
233 *_retval = rules; |
|
234 NS_ADDREF(*_retval); |
|
235 |
|
236 return NS_OK; |
|
237 } |
|
238 |
|
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 } |
|
247 |
|
248 nsRefPtr<StyleRule> cssrule; |
|
249 rv = rule->GetCSSStyleRule(getter_AddRefs(cssrule)); |
|
250 if (rv.Failed()) { |
|
251 return nullptr; |
|
252 } |
|
253 |
|
254 if (!cssrule) { |
|
255 rv.Throw(NS_ERROR_FAILURE); |
|
256 } |
|
257 return cssrule.forget(); |
|
258 } |
|
259 |
|
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 } |
|
268 |
|
269 *_retval = rule->GetLineNumber(); |
|
270 return NS_OK; |
|
271 } |
|
272 |
|
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 } |
|
284 |
|
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 } |
|
293 |
|
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 } |
|
301 |
|
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 } |
|
309 |
|
310 for (nsCSSSelectorList* sel = rule->Selector(); sel; |
|
311 sel = sel->mNext, --aIndex) { |
|
312 if (aIndex == 0) { |
|
313 return sel; |
|
314 } |
|
315 } |
|
316 |
|
317 // Ran out of selectors |
|
318 rv.Throw(NS_ERROR_INVALID_ARG); |
|
319 return nullptr; |
|
320 } |
|
321 |
|
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 } |
|
332 |
|
333 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv); |
|
334 MOZ_ASSERT(!rv.Failed(), "How could we get a selector but not a rule?"); |
|
335 |
|
336 sel->mSelectors->ToString(aText, rule->GetStyleSheet(), false); |
|
337 return NS_OK; |
|
338 } |
|
339 |
|
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 } |
|
350 |
|
351 *aSpecificity = sel->mWeight; |
|
352 return NS_OK; |
|
353 } |
|
354 |
|
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); |
|
363 |
|
364 ErrorResult rv; |
|
365 nsCSSSelectorList* tail = GetSelectorAtIndex(aRule, aSelectorIndex, rv); |
|
366 if (rv.Failed()) { |
|
367 return rv.ErrorCode(); |
|
368 } |
|
369 |
|
370 // We want just the one list item, not the whole list tail |
|
371 nsAutoPtr<nsCSSSelectorList> sel(tail->Clone(false)); |
|
372 |
|
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 } |
|
381 |
|
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 } |
|
392 |
|
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 } |
|
402 |
|
403 if (prop == eCSSPropertyExtra_variable) { |
|
404 *_retval = true; |
|
405 return NS_OK; |
|
406 } |
|
407 |
|
408 if (nsCSSProps::IsShorthand(prop)) { |
|
409 prop = nsCSSProps::SubpropertyEntryFor(prop)[0]; |
|
410 } |
|
411 |
|
412 nsStyleStructID sid = nsCSSProps::kSIDTable[prop]; |
|
413 *_retval = !nsCachedStyleData::IsReset(sid); |
|
414 return NS_OK; |
|
415 } |
|
416 |
|
417 extern const char* const kCSSRawProperties[]; |
|
418 |
|
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 } |
|
431 |
|
432 if (aFlags & INCLUDE_ALIASES) { |
|
433 maxCount += (eCSSProperty_COUNT_with_aliases - eCSSProperty_COUNT); |
|
434 } |
|
435 |
|
436 char16_t** props = |
|
437 static_cast<char16_t**>(nsMemory::Alloc(maxCount * sizeof(char16_t*))); |
|
438 |
|
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 |
|
448 |
|
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 } |
|
458 |
|
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 } |
|
469 |
|
470 if (aFlags & INCLUDE_ALIASES) { |
|
471 for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; ++prop) { |
|
472 DO_PROP(prop); |
|
473 } |
|
474 } |
|
475 |
|
476 #undef DO_PROP |
|
477 |
|
478 *aCount = propCount; |
|
479 *aProps = props; |
|
480 |
|
481 return NS_OK; |
|
482 } |
|
483 |
|
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 } |
|
493 |
|
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 } |
|
515 |
|
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 } |
|
531 |
|
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 } |
|
581 |
|
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 } |
|
592 |
|
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")); |
|
629 |
|
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 } |
|
639 |
|
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 } |
|
648 |
|
649 InspectorRGBTriple triple; |
|
650 triple.mR = NS_GET_R(color); |
|
651 triple.mG = NS_GET_G(color); |
|
652 triple.mB = NS_GET_B(color); |
|
653 |
|
654 if (!triple.ToObject(aCx, aValue)) { |
|
655 return NS_ERROR_FAILURE; |
|
656 } |
|
657 |
|
658 return NS_OK; |
|
659 } |
|
660 |
|
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 } |
|
670 |
|
671 aColorName.AssignASCII(color); |
|
672 return NS_OK; |
|
673 } |
|
674 |
|
675 NS_IMETHODIMP |
|
676 inDOMUtils::GetBindingURLs(nsIDOMElement *aElement, nsIArray **_retval) |
|
677 { |
|
678 NS_ENSURE_ARG_POINTER(aElement); |
|
679 |
|
680 *_retval = nullptr; |
|
681 |
|
682 nsCOMPtr<nsIMutableArray> urls = do_CreateInstance(NS_ARRAY_CONTRACTID); |
|
683 if (!urls) |
|
684 return NS_ERROR_FAILURE; |
|
685 |
|
686 nsCOMPtr<nsIContent> content = do_QueryInterface(aElement); |
|
687 NS_ENSURE_ARG_POINTER(content); |
|
688 |
|
689 nsXBLBinding *binding = content->GetXBLBinding(); |
|
690 |
|
691 while (binding) { |
|
692 urls->AppendElement(binding->PrototypeBinding()->BindingURI(), false); |
|
693 binding = binding->GetBaseBinding(); |
|
694 } |
|
695 |
|
696 NS_ADDREF(*_retval = urls); |
|
697 return NS_OK; |
|
698 } |
|
699 |
|
700 NS_IMETHODIMP |
|
701 inDOMUtils::SetContentState(nsIDOMElement* aElement, |
|
702 EventStates::InternalType aState) |
|
703 { |
|
704 NS_ENSURE_ARG_POINTER(aElement); |
|
705 |
|
706 nsRefPtr<EventStateManager> esm = |
|
707 inLayoutUtils::GetEventStateManagerFor(aElement); |
|
708 if (esm) { |
|
709 nsCOMPtr<nsIContent> content; |
|
710 content = do_QueryInterface(aElement); |
|
711 |
|
712 // XXX Invalid cast of bool to nsresult (bug 778108) |
|
713 return (nsresult)esm->SetContentState(content, EventStates(aState)); |
|
714 } |
|
715 |
|
716 return NS_ERROR_FAILURE; |
|
717 } |
|
718 |
|
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); |
|
726 |
|
727 // NOTE: if this method is removed, |
|
728 // please remove GetInternalValue from EventStates |
|
729 *aState = content->AsElement()->State().GetInternalValue(); |
|
730 return NS_OK; |
|
731 } |
|
732 |
|
733 /* static */ nsresult |
|
734 inDOMUtils::GetRuleNodeForElement(dom::Element* aElement, |
|
735 nsIAtom* aPseudo, |
|
736 nsStyleContext** aStyleContext, |
|
737 nsRuleNode** aRuleNode) |
|
738 { |
|
739 MOZ_ASSERT(aElement); |
|
740 |
|
741 *aRuleNode = nullptr; |
|
742 *aStyleContext = nullptr; |
|
743 |
|
744 nsIDocument* doc = aElement->GetDocument(); |
|
745 NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED); |
|
746 |
|
747 nsIPresShell *presShell = doc->GetShell(); |
|
748 NS_ENSURE_TRUE(presShell, NS_ERROR_UNEXPECTED); |
|
749 |
|
750 nsPresContext *presContext = presShell->GetPresContext(); |
|
751 NS_ENSURE_TRUE(presContext, NS_ERROR_UNEXPECTED); |
|
752 |
|
753 presContext->EnsureSafeToHandOutCSSRules(); |
|
754 |
|
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 } |
|
763 |
|
764 NS_IMETHODIMP |
|
765 inDOMUtils::GetUsedFontFaces(nsIDOMRange* aRange, |
|
766 nsIDOMFontFaceList** aFontFaceList) |
|
767 { |
|
768 return static_cast<nsRange*>(aRange)->GetUsedFontFaces(aFontFaceList); |
|
769 } |
|
770 |
|
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 |
|
784 |
|
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"); |
|
793 |
|
794 nsCOMPtr<nsIAtom> atom = do_GetAtom(aStatePseudo); |
|
795 |
|
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 } |
|
806 |
|
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 } |
|
815 |
|
816 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement); |
|
817 NS_ENSURE_ARG_POINTER(element); |
|
818 |
|
819 element->LockStyleStates(state); |
|
820 |
|
821 return NS_OK; |
|
822 } |
|
823 |
|
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 } |
|
832 |
|
833 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement); |
|
834 NS_ENSURE_ARG_POINTER(element); |
|
835 |
|
836 element->UnlockStyleStates(state); |
|
837 |
|
838 return NS_OK; |
|
839 } |
|
840 |
|
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 } |
|
851 |
|
852 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement); |
|
853 NS_ENSURE_ARG_POINTER(element); |
|
854 |
|
855 EventStates locks = element->LockedStyleStates(); |
|
856 |
|
857 *_retval = locks.HasAllStates(state); |
|
858 return NS_OK; |
|
859 } |
|
860 |
|
861 NS_IMETHODIMP |
|
862 inDOMUtils::ClearPseudoClassLocks(nsIDOMElement *aElement) |
|
863 { |
|
864 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement); |
|
865 NS_ENSURE_ARG_POINTER(element); |
|
866 |
|
867 element->ClearStyleStateLocks(); |
|
868 |
|
869 return NS_OK; |
|
870 } |
|
871 |
|
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); |
|
878 |
|
879 return sheet->ParseSheet(aInput); |
|
880 } |