forked from mirrors/gecko-dev
		
	 d6d99aaf8a
			
		
	
	
		d6d99aaf8a
		
	
	
	
	
		
			
			Does nothing, and it's unused. Differential Revision: https://phabricator.services.mozilla.com/D58914 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			709 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			709 lines
		
	
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | |
| /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | |
| /* 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 "inLayoutUtils.h"
 | |
| 
 | |
| #include "gfxTextRun.h"
 | |
| #include "nsArray.h"
 | |
| #include "nsAutoPtr.h"
 | |
| #include "nsString.h"
 | |
| #include "nsIStyleSheetLinkingElement.h"
 | |
| #include "nsIContentInlines.h"
 | |
| #include "mozilla/dom/Document.h"
 | |
| #include "ChildIterator.h"
 | |
| #include "nsComputedDOMStyle.h"
 | |
| #include "mozilla/EventStateManager.h"
 | |
| #include "nsAtom.h"
 | |
| #include "nsPresContext.h"
 | |
| #include "nsRange.h"
 | |
| #include "mozilla/PresShell.h"
 | |
| #include "mozilla/PresShellInlines.h"
 | |
| #include "mozilla/StyleSheetInlines.h"
 | |
| #include "mozilla/dom/CharacterData.h"
 | |
| #include "mozilla/dom/Element.h"
 | |
| #include "mozilla/dom/CSSStyleRule.h"
 | |
| #include "mozilla/dom/InspectorUtilsBinding.h"
 | |
| #include "mozilla/dom/ToJSValue.h"
 | |
| #include "nsCSSProps.h"
 | |
| #include "nsCSSValue.h"
 | |
| #include "nsColor.h"
 | |
| #include "mozilla/ServoStyleSet.h"
 | |
| #include "nsStyleUtil.h"
 | |
| #include "nsQueryObject.h"
 | |
| #include "mozilla/ServoBindings.h"
 | |
| #include "mozilla/ServoStyleRuleMap.h"
 | |
| #include "mozilla/ServoCSSParser.h"
 | |
| #include "mozilla/StaticPrefs_layout.h"
 | |
| #include "mozilla/dom/InspectorUtils.h"
 | |
| #include "mozilla/dom/InspectorFontFace.h"
 | |
| 
 | |
| using namespace mozilla;
 | |
| using namespace mozilla::css;
 | |
| using namespace mozilla::dom;
 | |
| 
 | |
| namespace mozilla {
 | |
| namespace dom {
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetAllStyleSheets(GlobalObject& aGlobalObject,
 | |
|                                        Document& aDocument, bool aDocumentOnly,
 | |
|                                        nsTArray<RefPtr<StyleSheet>>& aResult) {
 | |
|   // Get the agent, then user and finally xbl sheets in the style set.
 | |
|   PresShell* presShell = aDocument.GetPresShell();
 | |
| 
 | |
|   if (presShell) {
 | |
|     ServoStyleSet* styleSet = presShell->StyleSet();
 | |
| 
 | |
|     if (!aDocumentOnly) {
 | |
|       const StyleOrigin kOrigins[] = {StyleOrigin::UserAgent,
 | |
|                                       StyleOrigin::User};
 | |
|       for (const auto origin : kOrigins) {
 | |
|         for (size_t i = 0, count = styleSet->SheetCount(origin); i < count;
 | |
|              i++) {
 | |
|           aResult.AppendElement(styleSet->SheetAt(origin, i));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     AutoTArray<StyleSheet*, 32> xblSheetArray;
 | |
|     styleSet->AppendAllNonDocumentAuthorSheets(xblSheetArray);
 | |
| 
 | |
|     // The XBL stylesheet array will quite often be full of duplicates. Cope:
 | |
|     //
 | |
|     // FIXME(emilio, bug 1454467): I think this is not true since bug 1452525.
 | |
|     nsTHashtable<nsPtrHashKey<StyleSheet>> sheetSet;
 | |
|     for (StyleSheet* sheet : xblSheetArray) {
 | |
|       if (!sheetSet.Contains(sheet)) {
 | |
|         sheetSet.PutEntry(sheet);
 | |
|         aResult.AppendElement(sheet);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Get the document sheets.
 | |
|   for (size_t i = 0; i < aDocument.SheetCount(); i++) {
 | |
|     aResult.AppendElement(aDocument.SheetAt(i));
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool InspectorUtils::IsIgnorableWhitespace(CharacterData& aDataNode) {
 | |
|   if (!aDataNode.TextIsOnlyWhitespace()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Okay.  We have only white space.  Let's check the white-space
 | |
|   // property now and make sure that this isn't preformatted text...
 | |
|   if (nsIFrame* frame = aDataNode.GetPrimaryFrame()) {
 | |
|     return !frame->StyleText()->WhiteSpaceIsSignificant();
 | |
|   }
 | |
| 
 | |
|   // empty inter-tag text node without frame, e.g., in between <table>\n<tr>
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| nsINode* InspectorUtils::GetParentForNode(nsINode& aNode,
 | |
|                                           bool aShowingAnonymousContent) {
 | |
|   // First do the special cases -- document nodes and anonymous content
 | |
|   nsINode* parent = nullptr;
 | |
| 
 | |
|   if (aNode.IsDocument()) {
 | |
|     parent = inLayoutUtils::GetContainerFor(*aNode.AsDocument());
 | |
|   } else if (aShowingAnonymousContent) {
 | |
|     if (aNode.IsContent()) {
 | |
|       parent = aNode.AsContent()->GetFlattenedTreeParent();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!parent) {
 | |
|     // Ok, just get the normal DOM parent node
 | |
|     return aNode.GetParentNode();
 | |
|   }
 | |
| 
 | |
|   return parent;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| already_AddRefed<nsINodeList> InspectorUtils::GetChildrenForNode(
 | |
|     nsINode& aNode, bool aShowingAnonymousContent) {
 | |
|   nsCOMPtr<nsINodeList> kids;
 | |
| 
 | |
|   if (aShowingAnonymousContent) {
 | |
|     if (aNode.IsContent()) {
 | |
|       kids = aNode.AsContent()->GetChildren(nsIContent::eAllChildren);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (!kids) {
 | |
|     kids = aNode.ChildNodes();
 | |
|   }
 | |
| 
 | |
|   return kids.forget();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetCSSStyleRules(
 | |
|     GlobalObject& aGlobalObject, Element& aElement, const nsAString& aPseudo,
 | |
|     bool aIncludeVisitedStyle, nsTArray<RefPtr<BindingStyleRule>>& aResult) {
 | |
|   RefPtr<nsAtom> pseudoElt;
 | |
|   if (!aPseudo.IsEmpty()) {
 | |
|     pseudoElt = NS_Atomize(aPseudo);
 | |
|   }
 | |
| 
 | |
|   RefPtr<ComputedStyle> computedStyle =
 | |
|       GetCleanComputedStyleForElement(&aElement, pseudoElt);
 | |
|   if (!computedStyle) {
 | |
|     // 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;
 | |
|   }
 | |
| 
 | |
|   if (aIncludeVisitedStyle) {
 | |
|     if (ComputedStyle* styleIfVisited = computedStyle->GetStyleIfVisited()) {
 | |
|       computedStyle = styleIfVisited;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Document* doc = aElement.OwnerDoc();
 | |
|   PresShell* presShell = doc->GetPresShell();
 | |
|   if (!presShell) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   nsTArray<const RawServoStyleRule*> rawRuleList;
 | |
|   Servo_ComputedValues_GetStyleRuleList(computedStyle, &rawRuleList);
 | |
| 
 | |
|   AutoTArray<ServoStyleRuleMap*, 1> maps;
 | |
|   {
 | |
|     ServoStyleSet* styleSet = presShell->StyleSet();
 | |
|     ServoStyleRuleMap* map = styleSet->StyleRuleMap();
 | |
|     maps.AppendElement(map);
 | |
|   }
 | |
| 
 | |
|   // Now shadow DOM stuff...
 | |
|   if (auto* shadow = aElement.GetShadowRoot()) {
 | |
|     maps.AppendElement(&shadow->ServoStyleRuleMap());
 | |
|   }
 | |
| 
 | |
|   for (auto* shadow = aElement.GetContainingShadow(); shadow;
 | |
|        shadow = shadow->Host()->GetContainingShadow()) {
 | |
|     maps.AppendElement(&shadow->ServoStyleRuleMap());
 | |
|   }
 | |
| 
 | |
|   // Rules from the assigned slot.
 | |
|   for (auto* slot = aElement.GetAssignedSlot(); slot;
 | |
|        slot = slot->GetAssignedSlot()) {
 | |
|     if (auto* shadow = slot->GetContainingShadow()) {
 | |
|       maps.AppendElement(&shadow->ServoStyleRuleMap());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Find matching rules in the table.
 | |
|   for (const RawServoStyleRule* rawRule : Reversed(rawRuleList)) {
 | |
|     CSSStyleRule* rule = nullptr;
 | |
|     for (ServoStyleRuleMap* map : maps) {
 | |
|       rule = map->Lookup(rawRule);
 | |
|       if (rule) {
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     if (rule) {
 | |
|       aResult.AppendElement(rule);
 | |
|     } else {
 | |
| #ifdef DEBUG
 | |
|       nsAutoCString str;
 | |
|       fprintf(stderr, "%s\n", str.get());
 | |
|       Servo_StyleRule_Debug(rawRule, &str);
 | |
|       MOZ_CRASH_UNSAFE_PRINTF(
 | |
|           "We should be able to map a raw rule to a rule: %s\n", str.get());
 | |
| #endif
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| uint32_t InspectorUtils::GetRuleLine(GlobalObject& aGlobal, css::Rule& aRule) {
 | |
|   return aRule.GetLineNumber();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| uint32_t InspectorUtils::GetRuleColumn(GlobalObject& aGlobal,
 | |
|                                        css::Rule& aRule) {
 | |
|   return aRule.GetColumnNumber();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| uint32_t InspectorUtils::GetRelativeRuleLine(GlobalObject& aGlobal,
 | |
|                                              css::Rule& aRule) {
 | |
|   uint32_t lineNumber = aRule.GetLineNumber();
 | |
| 
 | |
|   // If aRule was parsed along with its stylesheet, then it will
 | |
|   // have an absolute lineNumber that we need to remap to its
 | |
|   // containing node. But if aRule was added via CSSOM after parsing,
 | |
|   // then it has a sort-of relative line number already:
 | |
|   // Gecko gives all rules a 0 lineNumber.
 | |
|   // Servo gives the first line of a rule a 0 lineNumber, and then
 | |
|   //   counts up from there.
 | |
| 
 | |
|   // The Servo behavior is arguably more correct, but harder to
 | |
|   // interpret for purposes of deciding whether a lineNumber is
 | |
|   // relative or absolute.
 | |
| 
 | |
|   // Since most of the time, inserted rules are single line and
 | |
|   // therefore have 0 lineNumbers in both Gecko and Servo, we use
 | |
|   // that to detect that a lineNumber is already relative.
 | |
| 
 | |
|   // There is one ugly edge case that we avoid: if an inserted rule
 | |
|   // is multi-line, then Servo will give it 0+ lineNumbers. If we
 | |
|   // do relative number mapping on those line numbers, we could get
 | |
|   // negative underflow. So we check for underflow and instead report
 | |
|   // a 0 lineNumber.
 | |
|   StyleSheet* sheet = aRule.GetStyleSheet();
 | |
|   if (sheet && lineNumber != 0) {
 | |
|     nsINode* owningNode = sheet->GetOwnerNode();
 | |
|     if (owningNode) {
 | |
|       nsCOMPtr<nsIStyleSheetLinkingElement> link =
 | |
|           do_QueryInterface(owningNode);
 | |
|       if (link) {
 | |
|         // Check for underflow, which is one indication that we're
 | |
|         // trying to remap an already relative lineNumber.
 | |
|         uint32_t linkLineIndex0 = link->GetLineNumber() - 1;
 | |
|         if (linkLineIndex0 > lineNumber) {
 | |
|           lineNumber = 0;
 | |
|         } else {
 | |
|           lineNumber -= linkLineIndex0;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return lineNumber;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool InspectorUtils::HasRulesModifiedByCSSOM(GlobalObject& aGlobal,
 | |
|                                              StyleSheet& aSheet) {
 | |
|   return aSheet.HasModifiedRulesForDevtools();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| uint32_t InspectorUtils::GetSelectorCount(GlobalObject& aGlobal,
 | |
|                                           BindingStyleRule& aRule) {
 | |
|   return aRule.GetSelectorCount();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetSelectorText(GlobalObject& aGlobal,
 | |
|                                      BindingStyleRule& aRule,
 | |
|                                      uint32_t aSelectorIndex, nsString& aText,
 | |
|                                      ErrorResult& aRv) {
 | |
|   aRv = aRule.GetSelectorText(aSelectorIndex, aText);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| uint64_t InspectorUtils::GetSpecificity(GlobalObject& aGlobal,
 | |
|                                         BindingStyleRule& aRule,
 | |
|                                         uint32_t aSelectorIndex,
 | |
|                                         ErrorResult& aRv) {
 | |
|   uint64_t s;
 | |
|   aRv = aRule.GetSpecificity(aSelectorIndex, &s);
 | |
|   return s;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool InspectorUtils::SelectorMatchesElement(
 | |
|     GlobalObject& aGlobalObject, Element& aElement, BindingStyleRule& aRule,
 | |
|     uint32_t aSelectorIndex, const nsAString& aPseudo,
 | |
|     bool aRelevantLinkVisited, ErrorResult& aRv) {
 | |
|   bool result = false;
 | |
|   aRv = aRule.SelectorMatchesElement(&aElement, aSelectorIndex, aPseudo,
 | |
|                                      aRelevantLinkVisited, &result);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool InspectorUtils::IsInheritedProperty(GlobalObject& aGlobalObject,
 | |
|                                          const nsACString& aPropertyName) {
 | |
|   return Servo_Property_IsInherited(&aPropertyName);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetCSSPropertyNames(GlobalObject& aGlobalObject,
 | |
|                                          const PropertyNamesOptions& aOptions,
 | |
|                                          nsTArray<nsString>& aResult) {
 | |
|   CSSEnabledState enabledState = aOptions.mIncludeExperimentals
 | |
|                                      ? CSSEnabledState::IgnoreEnabledState
 | |
|                                      : CSSEnabledState::ForAllContent;
 | |
| 
 | |
|   auto appendProperty = [enabledState, &aResult](uint32_t prop) {
 | |
|     nsCSSPropertyID cssProp = nsCSSPropertyID(prop);
 | |
|     if (nsCSSProps::IsEnabled(cssProp, enabledState)) {
 | |
|       aResult.AppendElement(
 | |
|           NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(cssProp)));
 | |
|     }
 | |
|   };
 | |
| 
 | |
|   uint32_t prop = 0;
 | |
|   for (; prop < eCSSProperty_COUNT_no_shorthands; ++prop) {
 | |
|     if (!nsCSSProps::PropHasFlags(nsCSSPropertyID(prop),
 | |
|                                   CSSPropFlags::Inaccessible)) {
 | |
|       appendProperty(prop);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (aOptions.mIncludeShorthands) {
 | |
|     for (; prop < eCSSProperty_COUNT; ++prop) {
 | |
|       appendProperty(prop);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (aOptions.mIncludeAliases) {
 | |
|     for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases;
 | |
|          ++prop) {
 | |
|       appendProperty(prop);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetCSSPropertyPrefs(GlobalObject& aGlobalObject,
 | |
|                                          nsTArray<PropertyPref>& aResult) {
 | |
|   for (const auto* src = nsCSSProps::kPropertyPrefTable;
 | |
|        src->mPropID != eCSSProperty_UNKNOWN; src++) {
 | |
|     PropertyPref& dest = *aResult.AppendElement();
 | |
|     dest.mName.Assign(
 | |
|         NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(src->mPropID)));
 | |
|     dest.mPref.AssignASCII(src->mPref);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetSubpropertiesForCSSProperty(GlobalObject& aGlobal,
 | |
|                                                     const nsACString& aProperty,
 | |
|                                                     nsTArray<nsString>& aResult,
 | |
|                                                     ErrorResult& aRv) {
 | |
|   nsCSSPropertyID propertyID = nsCSSProps::LookupProperty(aProperty);
 | |
| 
 | |
|   if (propertyID == eCSSProperty_UNKNOWN) {
 | |
|     aRv.Throw(NS_ERROR_FAILURE);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (propertyID == eCSSPropertyExtra_variable) {
 | |
|     aResult.AppendElement(NS_ConvertUTF8toUTF16(aProperty));
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (!nsCSSProps::IsShorthand(propertyID)) {
 | |
|     nsString* name = aResult.AppendElement();
 | |
|     CopyASCIItoUTF16(nsCSSProps::GetStringValue(propertyID), *name);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   for (const nsCSSPropertyID* props =
 | |
|            nsCSSProps::SubpropertyEntryFor(propertyID);
 | |
|        *props != eCSSProperty_UNKNOWN; ++props) {
 | |
|     nsString* name = aResult.AppendElement();
 | |
|     CopyASCIItoUTF16(nsCSSProps::GetStringValue(*props), *name);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool InspectorUtils::CssPropertyIsShorthand(GlobalObject& aGlobalObject,
 | |
|                                             const nsACString& aProperty,
 | |
|                                             ErrorResult& aRv) {
 | |
|   bool found;
 | |
|   bool isShorthand = Servo_Property_IsShorthand(&aProperty, &found);
 | |
|   if (!found) {
 | |
|     aRv.Throw(NS_ERROR_FAILURE);
 | |
|   }
 | |
|   return isShorthand;
 | |
| }
 | |
| 
 | |
| // This should match the constants in specified_value_info.rs
 | |
| //
 | |
| // Once we can use bitflags in consts, we can also cbindgen that and use them
 | |
| // here instead.
 | |
| static uint8_t ToServoCssType(InspectorPropertyType aType) {
 | |
|   switch (aType) {
 | |
|     case InspectorPropertyType::Color:
 | |
|       return 1;
 | |
|     case InspectorPropertyType::Gradient:
 | |
|       return 1 << 1;
 | |
|     case InspectorPropertyType::Timing_function:
 | |
|       return 1 << 2;
 | |
|     default:
 | |
|       MOZ_ASSERT_UNREACHABLE("Unknown property type?");
 | |
|       return 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool InspectorUtils::CssPropertySupportsType(GlobalObject& aGlobalObject,
 | |
|                                              const nsACString& aProperty,
 | |
|                                              InspectorPropertyType aType,
 | |
|                                              ErrorResult& aRv) {
 | |
|   bool found;
 | |
|   bool result =
 | |
|       Servo_Property_SupportsType(&aProperty, ToServoCssType(aType), &found);
 | |
|   if (!found) {
 | |
|     aRv.Throw(NS_ERROR_FAILURE);
 | |
|     return false;
 | |
|   }
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetCSSValuesForProperty(GlobalObject& aGlobalObject,
 | |
|                                              const nsACString& aProperty,
 | |
|                                              nsTArray<nsString>& aResult,
 | |
|                                              ErrorResult& aRv) {
 | |
|   bool found;
 | |
|   Servo_Property_GetCSSValuesForProperty(&aProperty, &found, &aResult);
 | |
|   if (!found) {
 | |
|     aRv.Throw(NS_ERROR_FAILURE);
 | |
|   }
 | |
|   return;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::RgbToColorName(GlobalObject& aGlobalObject, uint8_t aR,
 | |
|                                     uint8_t aG, uint8_t aB,
 | |
|                                     nsAString& aColorName, ErrorResult& aRv) {
 | |
|   const char* color = NS_RGBToColorName(NS_RGB(aR, aG, aB));
 | |
|   if (!color) {
 | |
|     aColorName.Truncate();
 | |
|     aRv.Throw(NS_ERROR_INVALID_ARG);
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aColorName.AssignASCII(color);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::ColorToRGBA(GlobalObject& aGlobalObject,
 | |
|                                  const nsACString& aColorString,
 | |
|                                  Nullable<InspectorRGBATuple>& aResult) {
 | |
|   nscolor color = NS_RGB(0, 0, 0);
 | |
| 
 | |
|   if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), aColorString,
 | |
|                                     &color)) {
 | |
|     aResult.SetNull();
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   InspectorRGBATuple& tuple = aResult.SetValue();
 | |
|   tuple.mR = NS_GET_R(color);
 | |
|   tuple.mG = NS_GET_G(color);
 | |
|   tuple.mB = NS_GET_B(color);
 | |
|   tuple.mA = nsStyleUtil::ColorComponentToFloat(NS_GET_A(color));
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool InspectorUtils::IsValidCSSColor(GlobalObject& aGlobalObject,
 | |
|                                      const nsACString& aColorString) {
 | |
|   return ServoCSSParser::IsValidCSSColor(aColorString);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool InspectorUtils::SetContentState(GlobalObject& aGlobalObject,
 | |
|                                      Element& aElement, uint64_t aState,
 | |
|                                      ErrorResult& aRv) {
 | |
|   RefPtr<EventStateManager> esm =
 | |
|       inLayoutUtils::GetEventStateManagerFor(aElement);
 | |
|   EventStates state(aState);
 | |
|   if (!esm || !EventStateManager::ManagesState(state)) {
 | |
|     aRv.Throw(NS_ERROR_INVALID_ARG);
 | |
|     return false;
 | |
|   }
 | |
|   return esm->SetContentState(&aElement, state);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool InspectorUtils::RemoveContentState(GlobalObject& aGlobalObject,
 | |
|                                         Element& aElement, uint64_t aState,
 | |
|                                         bool aClearActiveDocument,
 | |
|                                         ErrorResult& aRv) {
 | |
|   RefPtr<EventStateManager> esm =
 | |
|       inLayoutUtils::GetEventStateManagerFor(aElement);
 | |
|   EventStates state(aState);
 | |
|   if (!esm || !EventStateManager::ManagesState(state)) {
 | |
|     aRv.Throw(NS_ERROR_INVALID_ARG);
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   bool result = esm->SetContentState(nullptr, state);
 | |
| 
 | |
|   if (aClearActiveDocument && state == NS_EVENT_STATE_ACTIVE) {
 | |
|     EventStateManager* activeESM = static_cast<EventStateManager*>(
 | |
|         EventStateManager::GetActiveEventStateManager());
 | |
|     if (activeESM == esm) {
 | |
|       EventStateManager::ClearGlobalActiveContent(nullptr);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| uint64_t InspectorUtils::GetContentState(GlobalObject& aGlobalObject,
 | |
|                                          Element& aElement) {
 | |
|   // NOTE: if this method is removed,
 | |
|   // please remove GetInternalValue from EventStates
 | |
|   return aElement.State().GetInternalValue();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| already_AddRefed<ComputedStyle> InspectorUtils::GetCleanComputedStyleForElement(
 | |
|     dom::Element* aElement, nsAtom* aPseudo) {
 | |
|   MOZ_ASSERT(aElement);
 | |
| 
 | |
|   Document* doc = aElement->GetComposedDoc();
 | |
|   if (!doc) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   PresShell* presShell = doc->GetPresShell();
 | |
|   if (!presShell) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   nsPresContext* presContext = presShell->GetPresContext();
 | |
|   if (!presContext) {
 | |
|     return nullptr;
 | |
|   }
 | |
| 
 | |
|   presContext->EnsureSafeToHandOutCSSRules();
 | |
| 
 | |
|   return nsComputedDOMStyle::GetComputedStyle(aElement, aPseudo);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetUsedFontFaces(
 | |
|     GlobalObject& aGlobalObject, nsRange& aRange, uint32_t aMaxRanges,
 | |
|     bool aSkipCollapsedWhitespace,
 | |
|     nsTArray<nsAutoPtr<InspectorFontFace>>& aResult, ErrorResult& aRv) {
 | |
|   nsresult rv =
 | |
|       aRange.GetUsedFontFaces(aResult, aMaxRanges, aSkipCollapsedWhitespace);
 | |
|   if (NS_FAILED(rv)) {
 | |
|     aRv.Throw(rv);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static EventStates GetStatesForPseudoClass(const nsAString& aStatePseudo) {
 | |
|   if (aStatePseudo.IsEmpty() || aStatePseudo[0] != u':') {
 | |
|     return EventStates();
 | |
|   }
 | |
|   NS_ConvertUTF16toUTF8 statePseudo(Substring(aStatePseudo, 1));
 | |
|   return EventStates(Servo_PseudoClass_GetStates(&statePseudo));
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::GetCSSPseudoElementNames(GlobalObject& aGlobalObject,
 | |
|                                               nsTArray<nsString>& aResult) {
 | |
|   const auto kPseudoCount =
 | |
|       static_cast<size_t>(PseudoStyleType::CSSPseudoElementsEnd);
 | |
|   for (size_t i = 0; i < kPseudoCount; ++i) {
 | |
|     PseudoStyleType type = static_cast<PseudoStyleType>(i);
 | |
|     if (nsCSSPseudoElements::IsEnabled(type, CSSEnabledState::ForAllContent)) {
 | |
|       nsAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type);
 | |
|       aResult.AppendElement(nsDependentAtomString(atom));
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::AddPseudoClassLock(GlobalObject& aGlobalObject,
 | |
|                                         Element& aElement,
 | |
|                                         const nsAString& aPseudoClass,
 | |
|                                         bool aEnabled) {
 | |
|   EventStates state = GetStatesForPseudoClass(aPseudoClass);
 | |
|   if (state.IsEmpty()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aElement.LockStyleStates(state, aEnabled);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::RemovePseudoClassLock(GlobalObject& aGlobal,
 | |
|                                            Element& aElement,
 | |
|                                            const nsAString& aPseudoClass) {
 | |
|   EventStates state = GetStatesForPseudoClass(aPseudoClass);
 | |
|   if (state.IsEmpty()) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   aElement.UnlockStyleStates(state);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| bool InspectorUtils::HasPseudoClassLock(GlobalObject& aGlobalObject,
 | |
|                                         Element& aElement,
 | |
|                                         const nsAString& aPseudoClass) {
 | |
|   EventStates state = GetStatesForPseudoClass(aPseudoClass);
 | |
|   if (state.IsEmpty()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   EventStates locks = aElement.LockedStyleStates().mLocks;
 | |
|   return locks.HasAllStates(state);
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::ClearPseudoClassLocks(GlobalObject& aGlobalObject,
 | |
|                                            Element& aElement) {
 | |
|   aElement.ClearStyleStateLocks();
 | |
| }
 | |
| 
 | |
| /* static */
 | |
| void InspectorUtils::ParseStyleSheet(GlobalObject& aGlobalObject,
 | |
|                                      StyleSheet& aSheet,
 | |
|                                      const nsACString& aInput,
 | |
|                                      ErrorResult& aRv) {
 | |
|   aRv = aSheet.ReparseSheet(aInput);
 | |
| }
 | |
| 
 | |
| bool InspectorUtils::IsCustomElementName(GlobalObject&, const nsAString& aName,
 | |
|                                          const nsAString& aNamespaceURI) {
 | |
|   if (aName.IsEmpty()) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   int32_t namespaceID;
 | |
|   nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
 | |
|                                                         namespaceID);
 | |
| 
 | |
|   RefPtr<nsAtom> nameElt = NS_Atomize(aName);
 | |
|   return nsContentUtils::IsCustomElementName(nameElt, namespaceID);
 | |
| }
 | |
| 
 | |
| bool InspectorUtils::IsElementThemed(GlobalObject&, Element& aElement) {
 | |
|   // IsThemed will check if the native theme supports the widget using
 | |
|   // ThemeSupportsWidget which in turn will check that the widget is not
 | |
|   // already styled by content through nsNativeTheme::IsWidgetStyled. We
 | |
|   // assume that if the native theme styles the widget and the author did not
 | |
|   // override the appropriate styles, the theme will provide focus styling.
 | |
|   nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames);
 | |
|   return frame && frame->IsThemed();
 | |
| }
 | |
| 
 | |
| Element* InspectorUtils::ContainingBlockOf(GlobalObject&, Element& aElement) {
 | |
|   nsIFrame* frame = aElement.GetPrimaryFrame(FlushType::Frames);
 | |
|   if (!frame) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   nsIFrame* cb = frame->GetContainingBlock();
 | |
|   if (!cb) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return Element::FromNodeOrNull(cb->GetContent());
 | |
| }
 | |
| 
 | |
| }  // namespace dom
 | |
| }  // namespace mozilla
 |