/src/mozilla-central/layout/inspector/InspectorUtils.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "mozilla/ArrayUtils.h" |
8 | | #include "mozilla/EventStates.h" |
9 | | |
10 | | #include "inLayoutUtils.h" |
11 | | |
12 | | #include "nsArray.h" |
13 | | #include "nsAutoPtr.h" |
14 | | #include "nsIServiceManager.h" |
15 | | #include "nsString.h" |
16 | | #include "nsIStyleSheetLinkingElement.h" |
17 | | #include "nsIContentInlines.h" |
18 | | #include "nsIDocument.h" |
19 | | #include "nsIPresShell.h" |
20 | | #include "nsIDOMWindow.h" |
21 | | #include "nsXBLBinding.h" |
22 | | #include "nsXBLPrototypeBinding.h" |
23 | | #include "nsIMutableArray.h" |
24 | | #include "nsBindingManager.h" |
25 | | #include "ChildIterator.h" |
26 | | #include "nsComputedDOMStyle.h" |
27 | | #include "mozilla/EventStateManager.h" |
28 | | #include "nsAtom.h" |
29 | | #include "nsRange.h" |
30 | | #include "mozilla/StyleSheetInlines.h" |
31 | | #include "mozilla/dom/CharacterData.h" |
32 | | #include "mozilla/dom/Element.h" |
33 | | #include "mozilla/dom/CSSStyleRule.h" |
34 | | #include "mozilla/dom/InspectorUtilsBinding.h" |
35 | | #include "mozilla/dom/ToJSValue.h" |
36 | | #include "nsCSSProps.h" |
37 | | #include "nsCSSValue.h" |
38 | | #include "nsColor.h" |
39 | | #include "mozilla/ServoStyleSet.h" |
40 | | #include "nsStyleUtil.h" |
41 | | #include "nsQueryObject.h" |
42 | | #include "mozilla/ServoBindings.h" |
43 | | #include "mozilla/ServoStyleRuleMap.h" |
44 | | #include "mozilla/ServoCSSParser.h" |
45 | | #include "mozilla/dom/InspectorUtils.h" |
46 | | #include "mozilla/dom/InspectorFontFace.h" |
47 | | |
48 | | using namespace mozilla; |
49 | | using namespace mozilla::css; |
50 | | using namespace mozilla::dom; |
51 | | |
52 | | namespace mozilla { |
53 | | namespace dom { |
54 | | |
55 | | /* static */ void |
56 | | InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject, |
57 | | nsIDocument& aDocument, |
58 | | bool aDocumentOnly, |
59 | | nsTArray<RefPtr<StyleSheet>>& aResult) |
60 | 0 | { |
61 | 0 | // Get the agent, then user and finally xbl sheets in the style set. |
62 | 0 | nsIPresShell* presShell = aDocument.GetShell(); |
63 | 0 |
|
64 | 0 | if (presShell) { |
65 | 0 | ServoStyleSet* styleSet = presShell->StyleSet(); |
66 | 0 |
|
67 | 0 | if (!aDocumentOnly) { |
68 | 0 | SheetType sheetType = SheetType::Agent; |
69 | 0 | for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) { |
70 | 0 | aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i)); |
71 | 0 | } |
72 | 0 | sheetType = SheetType::User; |
73 | 0 | for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) { |
74 | 0 | aResult.AppendElement(styleSet->StyleSheetAt(sheetType, i)); |
75 | 0 | } |
76 | 0 | } |
77 | 0 |
|
78 | 0 | AutoTArray<StyleSheet*, 32> xblSheetArray; |
79 | 0 | styleSet->AppendAllNonDocumentAuthorSheets(xblSheetArray); |
80 | 0 |
|
81 | 0 | // The XBL stylesheet array will quite often be full of duplicates. Cope: |
82 | 0 | // |
83 | 0 | // FIXME(emilio, bug 1454467): I think this is not true since bug 1452525. |
84 | 0 | nsTHashtable<nsPtrHashKey<StyleSheet>> sheetSet; |
85 | 0 | for (StyleSheet* sheet : xblSheetArray) { |
86 | 0 | if (!sheetSet.Contains(sheet)) { |
87 | 0 | sheetSet.PutEntry(sheet); |
88 | 0 | aResult.AppendElement(sheet); |
89 | 0 | } |
90 | 0 | } |
91 | 0 | } |
92 | 0 |
|
93 | 0 | // Get the document sheets. |
94 | 0 | for (size_t i = 0; i < aDocument.SheetCount(); i++) { |
95 | 0 | aResult.AppendElement(aDocument.SheetAt(i)); |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | bool |
100 | | InspectorUtils::IsIgnorableWhitespace(CharacterData& aDataNode) |
101 | 0 | { |
102 | 0 | if (!aDataNode.TextIsOnlyWhitespace()) { |
103 | 0 | return false; |
104 | 0 | } |
105 | 0 | |
106 | 0 | // Okay. We have only white space. Let's check the white-space |
107 | 0 | // property now and make sure that this isn't preformatted text... |
108 | 0 | if (nsIFrame* frame = aDataNode.GetPrimaryFrame()) { |
109 | 0 | return !frame->StyleText()->WhiteSpaceIsSignificant(); |
110 | 0 | } |
111 | 0 | |
112 | 0 | // empty inter-tag text node without frame, e.g., in between <table>\n<tr> |
113 | 0 | return true; |
114 | 0 | } |
115 | | |
116 | | /* static */ nsINode* |
117 | | InspectorUtils::GetParentForNode(nsINode& aNode, |
118 | | bool aShowingAnonymousContent) |
119 | 0 | { |
120 | 0 | // First do the special cases -- document nodes and anonymous content |
121 | 0 | nsINode* parent = nullptr; |
122 | 0 |
|
123 | 0 | if (aNode.IsDocument()) { |
124 | 0 | parent = inLayoutUtils::GetContainerFor(*aNode.AsDocument()); |
125 | 0 | } else if (aShowingAnonymousContent) { |
126 | 0 | if (aNode.IsContent()) { |
127 | 0 | parent = aNode.AsContent()->GetFlattenedTreeParent(); |
128 | 0 | } |
129 | 0 | } |
130 | 0 |
|
131 | 0 | if (!parent) { |
132 | 0 | // Ok, just get the normal DOM parent node |
133 | 0 | return aNode.GetParentNode(); |
134 | 0 | } |
135 | 0 | |
136 | 0 | return parent; |
137 | 0 | } |
138 | | |
139 | | /* static */ already_AddRefed<nsINodeList> |
140 | | InspectorUtils::GetChildrenForNode(nsINode& aNode, |
141 | | bool aShowingAnonymousContent) |
142 | 0 | { |
143 | 0 | nsCOMPtr<nsINodeList> kids; |
144 | 0 |
|
145 | 0 | if (aShowingAnonymousContent) { |
146 | 0 | if (aNode.IsContent()) { |
147 | 0 | kids = aNode.AsContent()->GetChildren(nsIContent::eAllChildren); |
148 | 0 | } |
149 | 0 | } |
150 | 0 |
|
151 | 0 | if (!kids) { |
152 | 0 | kids = aNode.ChildNodes(); |
153 | 0 | } |
154 | 0 |
|
155 | 0 | return kids.forget(); |
156 | 0 | } |
157 | | |
158 | | /* static */ void |
159 | | InspectorUtils::GetCSSStyleRules(GlobalObject& aGlobalObject, |
160 | | Element& aElement, |
161 | | const nsAString& aPseudo, |
162 | | nsTArray<RefPtr<css::Rule>>& aResult) |
163 | 0 | { |
164 | 0 | RefPtr<nsAtom> pseudoElt; |
165 | 0 | if (!aPseudo.IsEmpty()) { |
166 | 0 | pseudoElt = NS_Atomize(aPseudo); |
167 | 0 | } |
168 | 0 |
|
169 | 0 | RefPtr<ComputedStyle> computedStyle = |
170 | 0 | GetCleanComputedStyleForElement(&aElement, pseudoElt); |
171 | 0 | if (!computedStyle) { |
172 | 0 | // This can fail for elements that are not in the document or |
173 | 0 | // if the document they're in doesn't have a presshell. Bail out. |
174 | 0 | return; |
175 | 0 | } |
176 | 0 | |
177 | 0 | |
178 | 0 | nsIDocument* doc = aElement.OwnerDoc(); |
179 | 0 | nsIPresShell* shell = doc->GetShell(); |
180 | 0 | if (!shell) { |
181 | 0 | return; |
182 | 0 | } |
183 | 0 | |
184 | 0 | nsTArray<const RawServoStyleRule*> rawRuleList; |
185 | 0 | Servo_ComputedValues_GetStyleRuleList(computedStyle, &rawRuleList); |
186 | 0 |
|
187 | 0 | AutoTArray<ServoStyleRuleMap*, 1> maps; |
188 | 0 | { |
189 | 0 | ServoStyleSet* styleSet = shell->StyleSet(); |
190 | 0 | ServoStyleRuleMap* map = styleSet->StyleRuleMap(); |
191 | 0 | maps.AppendElement(map); |
192 | 0 | } |
193 | 0 |
|
194 | 0 | // Collect style rule maps for bindings. |
195 | 0 | for (nsIContent* bindingContent = &aElement; bindingContent; |
196 | 0 | bindingContent = bindingContent->GetBindingParent()) { |
197 | 0 | for (nsXBLBinding* binding = bindingContent->GetXBLBinding(); |
198 | 0 | binding; binding = binding->GetBaseBinding()) { |
199 | 0 | if (auto* map = binding->PrototypeBinding()->GetServoStyleRuleMap()) { |
200 | 0 | maps.AppendElement(map); |
201 | 0 | } |
202 | 0 | } |
203 | 0 | // Note that we intentionally don't cut off here, unlike when we |
204 | 0 | // do styling, because even if style rules from parent binding |
205 | 0 | // do not apply to the element directly in those cases, their |
206 | 0 | // rules may still show up in the list we get above due to the |
207 | 0 | // inheritance in cascading. |
208 | 0 | } |
209 | 0 |
|
210 | 0 | // Now shadow DOM stuff... |
211 | 0 | if (auto* shadow = aElement.GetShadowRoot()) { |
212 | 0 | maps.AppendElement(&shadow->ServoStyleRuleMap()); |
213 | 0 | } |
214 | 0 |
|
215 | 0 | for (auto* shadow = aElement.GetContainingShadow(); |
216 | 0 | shadow; |
217 | 0 | shadow = shadow->Host()->GetContainingShadow()) { |
218 | 0 | maps.AppendElement(&shadow->ServoStyleRuleMap()); |
219 | 0 | } |
220 | 0 |
|
221 | 0 | // Find matching rules in the table. |
222 | 0 | for (const RawServoStyleRule* rawRule : Reversed(rawRuleList)) { |
223 | 0 | CSSStyleRule* rule = nullptr; |
224 | 0 | for (ServoStyleRuleMap* map : maps) { |
225 | 0 | rule = map->Lookup(rawRule); |
226 | 0 | if (rule) { |
227 | 0 | break; |
228 | 0 | } |
229 | 0 | } |
230 | 0 | if (rule) { |
231 | 0 | aResult.AppendElement(rule); |
232 | 0 | } else { |
233 | | #ifdef DEBUG |
234 | | nsAutoCString str; |
235 | | fprintf(stderr, "%s\n", str.get()); |
236 | | Servo_StyleRule_Debug(rawRule, &str); |
237 | | MOZ_CRASH_UNSAFE_PRINTF( |
238 | | "We should be able to map a raw rule to a rule: %s\n", |
239 | | str.get() |
240 | | ); |
241 | | #endif |
242 | | } |
243 | 0 | } |
244 | 0 | } |
245 | | |
246 | | /* static */ uint32_t |
247 | | InspectorUtils::GetRuleLine(GlobalObject& aGlobal, css::Rule& aRule) |
248 | 0 | { |
249 | 0 | return aRule.GetLineNumber(); |
250 | 0 | } |
251 | | |
252 | | /* static */ uint32_t |
253 | | InspectorUtils::GetRuleColumn(GlobalObject& aGlobal, css::Rule& aRule) |
254 | 0 | { |
255 | 0 | return aRule.GetColumnNumber(); |
256 | 0 | } |
257 | | |
258 | | /* static */ uint32_t |
259 | | InspectorUtils::GetRelativeRuleLine(GlobalObject& aGlobal, css::Rule& aRule) |
260 | 0 | { |
261 | 0 | uint32_t lineNumber = aRule.GetLineNumber(); |
262 | 0 |
|
263 | 0 | // If aRule was parsed along with its stylesheet, then it will |
264 | 0 | // have an absolute lineNumber that we need to remap to its |
265 | 0 | // containing node. But if aRule was added via CSSOM after parsing, |
266 | 0 | // then it has a sort-of relative line number already: |
267 | 0 | // Gecko gives all rules a 0 lineNumber. |
268 | 0 | // Servo gives the first line of a rule a 0 lineNumber, and then |
269 | 0 | // counts up from there. |
270 | 0 |
|
271 | 0 | // The Servo behavior is arguably more correct, but harder to |
272 | 0 | // interpret for purposes of deciding whether a lineNumber is |
273 | 0 | // relative or absolute. |
274 | 0 |
|
275 | 0 | // Since most of the time, inserted rules are single line and |
276 | 0 | // therefore have 0 lineNumbers in both Gecko and Servo, we use |
277 | 0 | // that to detect that a lineNumber is already relative. |
278 | 0 |
|
279 | 0 | // There is one ugly edge case that we avoid: if an inserted rule |
280 | 0 | // is multi-line, then Servo will give it 0+ lineNumbers. If we |
281 | 0 | // do relative number mapping on those line numbers, we could get |
282 | 0 | // negative underflow. So we check for underflow and instead report |
283 | 0 | // a 0 lineNumber. |
284 | 0 | StyleSheet* sheet = aRule.GetStyleSheet(); |
285 | 0 | if (sheet && lineNumber != 0) { |
286 | 0 | nsINode* owningNode = sheet->GetOwnerNode(); |
287 | 0 | if (owningNode) { |
288 | 0 | nsCOMPtr<nsIStyleSheetLinkingElement> link = |
289 | 0 | do_QueryInterface(owningNode); |
290 | 0 | if (link) { |
291 | 0 | // Check for underflow, which is one indication that we're |
292 | 0 | // trying to remap an already relative lineNumber. |
293 | 0 | uint32_t linkLineIndex0 = link->GetLineNumber() - 1; |
294 | 0 | if (linkLineIndex0 > lineNumber ) { |
295 | 0 | lineNumber = 0; |
296 | 0 | } else { |
297 | 0 | lineNumber -= linkLineIndex0; |
298 | 0 | } |
299 | 0 | } |
300 | 0 | } |
301 | 0 | } |
302 | 0 |
|
303 | 0 | return lineNumber; |
304 | 0 | } |
305 | | |
306 | | /* static */ bool |
307 | | InspectorUtils::HasRulesModifiedByCSSOM(GlobalObject& aGlobal, StyleSheet& aSheet) |
308 | 0 | { |
309 | 0 | return aSheet.HasModifiedRules(); |
310 | 0 | } |
311 | | |
312 | | /* static */ uint32_t |
313 | | InspectorUtils::GetSelectorCount(GlobalObject& aGlobal, |
314 | | BindingStyleRule& aRule) |
315 | 0 | { |
316 | 0 | return aRule.GetSelectorCount(); |
317 | 0 | } |
318 | | |
319 | | /* static */ void |
320 | | InspectorUtils::GetSelectorText(GlobalObject& aGlobal, |
321 | | BindingStyleRule& aRule, |
322 | | uint32_t aSelectorIndex, |
323 | | nsString& aText, |
324 | | ErrorResult& aRv) |
325 | 0 | { |
326 | 0 | aRv = aRule.GetSelectorText(aSelectorIndex, aText); |
327 | 0 | } |
328 | | |
329 | | /* static */ uint64_t |
330 | | InspectorUtils::GetSpecificity(GlobalObject& aGlobal, |
331 | | BindingStyleRule& aRule, |
332 | | uint32_t aSelectorIndex, |
333 | | ErrorResult& aRv) |
334 | 0 | { |
335 | 0 | uint64_t s; |
336 | 0 | aRv = aRule.GetSpecificity(aSelectorIndex, &s); |
337 | 0 | return s; |
338 | 0 | } |
339 | | |
340 | | /* static */ bool |
341 | | InspectorUtils::SelectorMatchesElement(GlobalObject& aGlobalObject, |
342 | | Element& aElement, |
343 | | BindingStyleRule& aRule, |
344 | | uint32_t aSelectorIndex, |
345 | | const nsAString& aPseudo, |
346 | | ErrorResult& aRv) |
347 | 0 | { |
348 | 0 | bool result = false; |
349 | 0 | aRv = aRule.SelectorMatchesElement(&aElement, aSelectorIndex, aPseudo, |
350 | 0 | &result); |
351 | 0 | return result; |
352 | 0 | } |
353 | | |
354 | | /* static */ bool |
355 | | InspectorUtils::IsInheritedProperty(GlobalObject& aGlobalObject, |
356 | | const nsAString& aPropertyName) |
357 | 0 | { |
358 | 0 | NS_ConvertUTF16toUTF8 propName(aPropertyName); |
359 | 0 | return Servo_Property_IsInherited(&propName); |
360 | 0 | } |
361 | | |
362 | | /* static */ void |
363 | | InspectorUtils::GetCSSPropertyNames(GlobalObject& aGlobalObject, |
364 | | const PropertyNamesOptions& aOptions, |
365 | | nsTArray<nsString>& aResult) |
366 | 0 | { |
367 | 0 | CSSEnabledState enabledState = aOptions.mIncludeExperimentals |
368 | 0 | ? CSSEnabledState::eIgnoreEnabledState |
369 | 0 | : CSSEnabledState::eForAllContent; |
370 | 0 |
|
371 | 0 | auto appendProperty = [enabledState, &aResult](uint32_t prop) { |
372 | 0 | nsCSSPropertyID cssProp = nsCSSPropertyID(prop); |
373 | 0 | if (nsCSSProps::IsEnabled(cssProp, enabledState)) { |
374 | 0 | aResult.AppendElement(NS_ConvertASCIItoUTF16( |
375 | 0 | nsCSSProps::GetStringValue(cssProp))); |
376 | 0 | } |
377 | 0 | }; |
378 | 0 |
|
379 | 0 | uint32_t prop = 0; |
380 | 0 | for ( ; prop < eCSSProperty_COUNT_no_shorthands; ++prop) { |
381 | 0 | if (!nsCSSProps::PropHasFlags(nsCSSPropertyID(prop), |
382 | 0 | CSSPropFlags::Inaccessible)) { |
383 | 0 | appendProperty(prop); |
384 | 0 | } |
385 | 0 | } |
386 | 0 |
|
387 | 0 | if (aOptions.mIncludeShorthands) { |
388 | 0 | for ( ; prop < eCSSProperty_COUNT; ++prop) { |
389 | 0 | appendProperty(prop); |
390 | 0 | } |
391 | 0 | } |
392 | 0 |
|
393 | 0 | if (aOptions.mIncludeAliases) { |
394 | 0 | for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; ++prop) { |
395 | 0 | appendProperty(prop); |
396 | 0 | } |
397 | 0 | } |
398 | 0 | } |
399 | | |
400 | | /* static */ void |
401 | | InspectorUtils::GetCSSPropertyPrefs(GlobalObject& aGlobalObject, |
402 | | nsTArray<PropertyPref>& aResult) |
403 | 0 | { |
404 | 0 | for (const auto* src = nsCSSProps::kPropertyPrefTable; |
405 | 0 | src->mPropID != eCSSProperty_UNKNOWN; src++) { |
406 | 0 | PropertyPref& dest = *aResult.AppendElement(); |
407 | 0 | dest.mName.Assign(NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(src->mPropID))); |
408 | 0 | dest.mPref.AssignASCII(src->mPref); |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | | /* static */ void |
413 | | InspectorUtils::GetSubpropertiesForCSSProperty(GlobalObject& aGlobal, |
414 | | const nsAString& aProperty, |
415 | | nsTArray<nsString>& aResult, |
416 | | ErrorResult& aRv) |
417 | 0 | { |
418 | 0 | nsCSSPropertyID propertyID = nsCSSProps::LookupProperty(aProperty); |
419 | 0 |
|
420 | 0 | if (propertyID == eCSSProperty_UNKNOWN) { |
421 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
422 | 0 | return; |
423 | 0 | } |
424 | 0 | |
425 | 0 | if (propertyID == eCSSPropertyExtra_variable) { |
426 | 0 | aResult.AppendElement(aProperty); |
427 | 0 | return; |
428 | 0 | } |
429 | 0 | |
430 | 0 | if (!nsCSSProps::IsShorthand(propertyID)) { |
431 | 0 | nsString* name = aResult.AppendElement(); |
432 | 0 | CopyASCIItoUTF16(nsCSSProps::GetStringValue(propertyID), *name); |
433 | 0 | return; |
434 | 0 | } |
435 | 0 | |
436 | 0 | for (const nsCSSPropertyID* props = nsCSSProps::SubpropertyEntryFor(propertyID); |
437 | 0 | *props != eCSSProperty_UNKNOWN; ++props) { |
438 | 0 | nsString* name = aResult.AppendElement(); |
439 | 0 | CopyASCIItoUTF16(nsCSSProps::GetStringValue(*props), *name); |
440 | 0 | } |
441 | 0 | } |
442 | | |
443 | | /* static */ bool |
444 | | InspectorUtils::CssPropertyIsShorthand(GlobalObject& aGlobalObject, |
445 | | const nsAString& aProperty, |
446 | | ErrorResult& aRv) |
447 | 0 | { |
448 | 0 | NS_ConvertUTF16toUTF8 prop(aProperty); |
449 | 0 | bool found; |
450 | 0 | bool isShorthand = Servo_Property_IsShorthand(&prop, &found); |
451 | 0 | if (!found) { |
452 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
453 | 0 | } |
454 | 0 | return isShorthand; |
455 | 0 | } |
456 | | |
457 | | bool |
458 | | InspectorUtils::CssPropertySupportsType(GlobalObject& aGlobalObject, |
459 | | const nsAString& aProperty, |
460 | | uint32_t aType, |
461 | | ErrorResult& aRv) |
462 | 0 | { |
463 | 0 | NS_ConvertUTF16toUTF8 property(aProperty); |
464 | 0 | bool found; |
465 | 0 | bool result = Servo_Property_SupportsType(&property, aType, &found); |
466 | 0 | if (!found) { |
467 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
468 | 0 | return false; |
469 | 0 | } |
470 | 0 | return result; |
471 | 0 | } |
472 | | |
473 | | /* static */ void |
474 | | InspectorUtils::GetCSSValuesForProperty(GlobalObject& aGlobalObject, |
475 | | const nsAString& aProperty, |
476 | | nsTArray<nsString>& aResult, |
477 | | ErrorResult& aRv) |
478 | 0 | { |
479 | 0 | NS_ConvertUTF16toUTF8 property(aProperty); |
480 | 0 | bool found; |
481 | 0 | Servo_Property_GetCSSValuesForProperty(&property, &found, &aResult); |
482 | 0 | if (!found) { |
483 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
484 | 0 | } |
485 | 0 | return; |
486 | 0 | } |
487 | | |
488 | | /* static */ void |
489 | | InspectorUtils::RgbToColorName(GlobalObject& aGlobalObject, |
490 | | uint8_t aR, uint8_t aG, uint8_t aB, |
491 | | nsAString& aColorName, |
492 | | ErrorResult& aRv) |
493 | 0 | { |
494 | 0 | const char* color = NS_RGBToColorName(NS_RGB(aR, aG, aB)); |
495 | 0 | if (!color) { |
496 | 0 | aColorName.Truncate(); |
497 | 0 | aRv.Throw(NS_ERROR_INVALID_ARG); |
498 | 0 | return; |
499 | 0 | } |
500 | 0 | |
501 | 0 | aColorName.AssignASCII(color); |
502 | 0 | } |
503 | | |
504 | | /* static */ void |
505 | | InspectorUtils::ColorToRGBA(GlobalObject& aGlobalObject, |
506 | | const nsAString& aColorString, |
507 | | Nullable<InspectorRGBATuple>& aResult) |
508 | 0 | { |
509 | 0 | nscolor color = NS_RGB(0, 0, 0); |
510 | 0 |
|
511 | 0 | if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), aColorString, |
512 | 0 | &color)) { |
513 | 0 | aResult.SetNull(); |
514 | 0 | return; |
515 | 0 | } |
516 | 0 | |
517 | 0 | InspectorRGBATuple& tuple = aResult.SetValue(); |
518 | 0 | tuple.mR = NS_GET_R(color); |
519 | 0 | tuple.mG = NS_GET_G(color); |
520 | 0 | tuple.mB = NS_GET_B(color); |
521 | 0 | tuple.mA = nsStyleUtil::ColorComponentToFloat(NS_GET_A(color)); |
522 | 0 | } |
523 | | |
524 | | /* static */ bool |
525 | | InspectorUtils::IsValidCSSColor(GlobalObject& aGlobalObject, |
526 | | const nsAString& aColorString) |
527 | 0 | { |
528 | 0 | return ServoCSSParser::IsValidCSSColor(aColorString); |
529 | 0 | } |
530 | | |
531 | | void |
532 | | InspectorUtils::GetBindingURLs(GlobalObject& aGlobalObject, |
533 | | Element& aElement, |
534 | | nsTArray<nsString>& aResult) |
535 | 0 | { |
536 | 0 | nsXBLBinding* binding = aElement.GetXBLBinding(); |
537 | 0 |
|
538 | 0 | while (binding) { |
539 | 0 | nsCString spec; |
540 | 0 | nsCOMPtr<nsIURI> bindingURI = binding->PrototypeBinding()->BindingURI(); |
541 | 0 | bindingURI->GetSpec(spec); |
542 | 0 | nsString* resultURI = aResult.AppendElement(); |
543 | 0 | CopyASCIItoUTF16(spec, *resultURI); |
544 | 0 | binding = binding->GetBaseBinding(); |
545 | 0 | } |
546 | 0 | } |
547 | | |
548 | | /* static */ bool |
549 | | InspectorUtils::SetContentState(GlobalObject& aGlobalObject, |
550 | | Element& aElement, |
551 | | uint64_t aState, |
552 | | ErrorResult& aRv) |
553 | 0 | { |
554 | 0 | RefPtr<EventStateManager> esm = |
555 | 0 | inLayoutUtils::GetEventStateManagerFor(aElement); |
556 | 0 | if (!esm) { |
557 | 0 | aRv.Throw(NS_ERROR_INVALID_ARG); |
558 | 0 | return false; |
559 | 0 | } |
560 | 0 | |
561 | 0 | return esm->SetContentState(&aElement, EventStates(aState)); |
562 | 0 | } |
563 | | |
564 | | /* static */ bool |
565 | | InspectorUtils::RemoveContentState(GlobalObject& aGlobalObject, |
566 | | Element& aElement, |
567 | | uint64_t aState, |
568 | | bool aClearActiveDocument, |
569 | | ErrorResult& aRv) |
570 | 0 | { |
571 | 0 | RefPtr<EventStateManager> esm = |
572 | 0 | inLayoutUtils::GetEventStateManagerFor(aElement); |
573 | 0 | if (!esm) { |
574 | 0 | aRv.Throw(NS_ERROR_INVALID_ARG); |
575 | 0 | return false; |
576 | 0 | } |
577 | 0 | |
578 | 0 | bool result = esm->SetContentState(nullptr, EventStates(aState)); |
579 | 0 |
|
580 | 0 | if (aClearActiveDocument && EventStates(aState) == NS_EVENT_STATE_ACTIVE) { |
581 | 0 | EventStateManager* activeESM = static_cast<EventStateManager*>( |
582 | 0 | EventStateManager::GetActiveEventStateManager()); |
583 | 0 | if (activeESM == esm) { |
584 | 0 | EventStateManager::ClearGlobalActiveContent(nullptr); |
585 | 0 | } |
586 | 0 | } |
587 | 0 |
|
588 | 0 | return result; |
589 | 0 | } |
590 | | |
591 | | /* static */ uint64_t |
592 | | InspectorUtils::GetContentState(GlobalObject& aGlobalObject, |
593 | | Element& aElement) |
594 | 0 | { |
595 | 0 | // NOTE: if this method is removed, |
596 | 0 | // please remove GetInternalValue from EventStates |
597 | 0 | return aElement.State().GetInternalValue(); |
598 | 0 | } |
599 | | |
600 | | /* static */ already_AddRefed<ComputedStyle> |
601 | | InspectorUtils::GetCleanComputedStyleForElement(dom::Element* aElement, |
602 | | nsAtom* aPseudo) |
603 | 0 | { |
604 | 0 | MOZ_ASSERT(aElement); |
605 | 0 |
|
606 | 0 | nsIDocument* doc = aElement->GetComposedDoc(); |
607 | 0 | if (!doc) { |
608 | 0 | return nullptr; |
609 | 0 | } |
610 | 0 | |
611 | 0 | nsIPresShell *presShell = doc->GetShell(); |
612 | 0 | if (!presShell) { |
613 | 0 | return nullptr; |
614 | 0 | } |
615 | 0 | |
616 | 0 | nsPresContext *presContext = presShell->GetPresContext(); |
617 | 0 | if (!presContext) { |
618 | 0 | return nullptr; |
619 | 0 | } |
620 | 0 | |
621 | 0 | presContext->EnsureSafeToHandOutCSSRules(); |
622 | 0 |
|
623 | 0 | return nsComputedDOMStyle::GetComputedStyle(aElement, aPseudo); |
624 | 0 | } |
625 | | |
626 | | /* static */ void |
627 | | InspectorUtils::GetUsedFontFaces(GlobalObject& aGlobalObject, |
628 | | nsRange& aRange, |
629 | | uint32_t aMaxRanges, |
630 | | bool aSkipCollapsedWhitespace, |
631 | | nsTArray<nsAutoPtr<InspectorFontFace>>& aResult, |
632 | | ErrorResult& aRv) |
633 | 0 | { |
634 | 0 | nsresult rv = aRange.GetUsedFontFaces(aResult, aMaxRanges, |
635 | 0 | aSkipCollapsedWhitespace); |
636 | 0 | if (NS_FAILED(rv)) { |
637 | 0 | aRv.Throw(rv); |
638 | 0 | } |
639 | 0 | } |
640 | | |
641 | | static EventStates |
642 | | GetStatesForPseudoClass(const nsAString& aStatePseudo) |
643 | 0 | { |
644 | 0 | if (aStatePseudo.IsEmpty() || aStatePseudo[0] != u':') { |
645 | 0 | return EventStates(); |
646 | 0 | } |
647 | 0 | NS_ConvertUTF16toUTF8 statePseudo(Substring(aStatePseudo, 1)); |
648 | 0 | return EventStates(Servo_PseudoClass_GetStates(&statePseudo)); |
649 | 0 | } |
650 | | |
651 | | /* static */ void |
652 | | InspectorUtils::GetCSSPseudoElementNames(GlobalObject& aGlobalObject, |
653 | | nsTArray<nsString>& aResult) |
654 | 0 | { |
655 | 0 | const CSSPseudoElementTypeBase pseudoCount = |
656 | 0 | static_cast<CSSPseudoElementTypeBase>(CSSPseudoElementType::Count); |
657 | 0 | for (CSSPseudoElementTypeBase i = 0; i < pseudoCount; ++i) { |
658 | 0 | CSSPseudoElementType type = static_cast<CSSPseudoElementType>(i); |
659 | 0 | if (nsCSSPseudoElements::IsEnabled(type, CSSEnabledState::eForAllContent)) { |
660 | 0 | nsAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type); |
661 | 0 | aResult.AppendElement(nsDependentAtomString(atom)); |
662 | 0 | } |
663 | 0 | } |
664 | 0 | } |
665 | | |
666 | | /* static */ void |
667 | | InspectorUtils::AddPseudoClassLock(GlobalObject& aGlobalObject, |
668 | | Element& aElement, |
669 | | const nsAString& aPseudoClass, |
670 | | bool aEnabled) |
671 | 0 | { |
672 | 0 | EventStates state = GetStatesForPseudoClass(aPseudoClass); |
673 | 0 | if (state.IsEmpty()) { |
674 | 0 | return; |
675 | 0 | } |
676 | 0 | |
677 | 0 | aElement.LockStyleStates(state, aEnabled); |
678 | 0 | } |
679 | | |
680 | | /* static */ void |
681 | | InspectorUtils::RemovePseudoClassLock(GlobalObject& aGlobal, |
682 | | Element& aElement, |
683 | | const nsAString& aPseudoClass) |
684 | 0 | { |
685 | 0 | EventStates state = GetStatesForPseudoClass(aPseudoClass); |
686 | 0 | if (state.IsEmpty()) { |
687 | 0 | return; |
688 | 0 | } |
689 | 0 | |
690 | 0 | aElement.UnlockStyleStates(state); |
691 | 0 | } |
692 | | |
693 | | /* static */ bool |
694 | | InspectorUtils::HasPseudoClassLock(GlobalObject& aGlobalObject, |
695 | | Element& aElement, |
696 | | const nsAString& aPseudoClass) |
697 | 0 | { |
698 | 0 | EventStates state = GetStatesForPseudoClass(aPseudoClass); |
699 | 0 | if (state.IsEmpty()) { |
700 | 0 | return false; |
701 | 0 | } |
702 | 0 | |
703 | 0 | EventStates locks = aElement.LockedStyleStates().mLocks; |
704 | 0 | return locks.HasAllStates(state); |
705 | 0 | } |
706 | | |
707 | | /* static */ void |
708 | | InspectorUtils::ClearPseudoClassLocks(GlobalObject& aGlobalObject, |
709 | | Element& aElement) |
710 | 0 | { |
711 | 0 | aElement.ClearStyleStateLocks(); |
712 | 0 | } |
713 | | |
714 | | /* static */ void |
715 | | InspectorUtils::ParseStyleSheet(GlobalObject& aGlobalObject, |
716 | | StyleSheet& aSheet, |
717 | | const nsAString& aInput, |
718 | | ErrorResult& aRv) |
719 | 0 | { |
720 | 0 |
|
721 | 0 | aRv = aSheet.ReparseSheet(aInput); |
722 | 0 | } |
723 | | |
724 | | void |
725 | | InspectorUtils::ScrollElementIntoView(GlobalObject& aGlobalObject, |
726 | | Element& aElement) |
727 | 0 | { |
728 | 0 | nsIPresShell* presShell = aElement.OwnerDoc()->GetShell(); |
729 | 0 | if (!presShell) { |
730 | 0 | return; |
731 | 0 | } |
732 | 0 | |
733 | 0 | presShell->ScrollContentIntoView(&aElement, |
734 | 0 | nsIPresShell::ScrollAxis(), |
735 | 0 | nsIPresShell::ScrollAxis(), |
736 | 0 | nsIPresShell::SCROLL_OVERFLOW_HIDDEN); |
737 | 0 | } |
738 | | |
739 | | |
740 | | bool |
741 | | InspectorUtils::IsCustomElementName(GlobalObject&, |
742 | | const nsAString& aName, |
743 | | const nsAString& aNamespaceURI) |
744 | 0 | { |
745 | 0 | if (aName.IsEmpty()) { |
746 | 0 | return false; |
747 | 0 | } |
748 | 0 | |
749 | 0 | int32_t namespaceID; |
750 | 0 | nsContentUtils::NameSpaceManager()->RegisterNameSpace( |
751 | 0 | aNamespaceURI, |
752 | 0 | namespaceID); |
753 | 0 |
|
754 | 0 | RefPtr<nsAtom> nameElt = NS_Atomize(aName); |
755 | 0 | return nsContentUtils::IsCustomElementName( |
756 | 0 | nameElt, |
757 | 0 | namespaceID); |
758 | 0 | } |
759 | | |
760 | | } // namespace dom |
761 | | } // namespace mozilla |