forked from mirrors/gecko-dev
I'm about to introduce the concept of "Loader principal" (as in "the principal of the CSS loader"), and SheetLoadData already has an mLoaderPrincipal. However SheetLoadData's principal is just the triggering principal (the principal that initiated the load). So name it that with consistency with SheetInfo::mTriggeringPrincipal etc. Differential Revision: https://phabricator.services.mozilla.com/D77613
707 lines
23 KiB
C++
707 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 "nsString.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/LinkStyle.h"
|
|
#include "mozilla/dom/ToJSValue.h"
|
|
#include "nsCSSProps.h"
|
|
#include "nsCSSValue.h"
|
|
#include "nsColor.h"
|
|
#include "mozilla/ServoStyleSet.h"
|
|
#include "nsLayoutUtils.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> nonDocumentSheets;
|
|
styleSet->AppendAllNonDocumentAuthorSheets(nonDocumentSheets);
|
|
|
|
// The non-document stylesheet array can't have duplicates right now, but it
|
|
// could once we include adopted stylesheets.
|
|
nsTHashtable<nsPtrHashKey<StyleSheet>> sheetSet;
|
|
for (StyleSheet* sheet : nonDocumentSheets) {
|
|
if (sheetSet.EnsureInserted(sheet)) {
|
|
aResult.AppendElement(sheet);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the document sheets.
|
|
for (size_t i = 0; i < aDocument.SheetCount(); i++) {
|
|
aResult.AppendElement(aDocument.SheetAt(i));
|
|
}
|
|
|
|
// FIXME(emilio, bug 1617948): This doesn't deal with adopted stylesheets, and
|
|
// it should. It should also handle duplicates correctly when it does, see
|
|
// above.
|
|
}
|
|
|
|
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) {
|
|
if (auto* link = LinkStyle::FromNodeOrNull(sheet->GetOwnerNode())) {
|
|
// 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);
|
|
}
|
|
}
|
|
|
|
/* 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,
|
|
nsLayoutUtils::UsedFontFaceList& 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) {
|
|
aSheet.ReparseSheet(aInput, aRv);
|
|
}
|
|
|
|
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
|