This also removes some confusing comments around nsIDocument regarding some kind of "special" stylesheets, which don't seem to exist anymore, and consolidates StyleSheetList so that we only have one implementation. I think that fixes a potential leak on the shadow root code (even though the API is v0 only), given the pointer from the ShadowRootStyleSheetList to the ShadowRoot wasn't being CCd. Also, more stuff could be renamed, methods removed, etc, feel free to suggest more cleanup, I've done mostly the minimal. Next steps are moving the stylesets there and stop using the proto binding sheet list / resources. MozReview-Commit-ID: D9hnDgPQAS5
1345 lines
39 KiB
C++
1345 lines
39 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 "inDOMUtils.h"
|
|
#include "inLayoutUtils.h"
|
|
|
|
#include "nsArray.h"
|
|
#include "nsAutoPtr.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsString.h"
|
|
#include "nsIStyleSheetLinkingElement.h"
|
|
#include "nsIContentInlines.h"
|
|
#include "nsIDOMElement.h"
|
|
#include "nsIDocument.h"
|
|
#include "nsIPresShell.h"
|
|
#include "nsIDOMDocument.h"
|
|
#include "nsIDOMCharacterData.h"
|
|
#include "nsRuleNode.h"
|
|
#include "nsIStyleRule.h"
|
|
#include "mozilla/css/StyleRule.h"
|
|
#include "nsICSSStyleRuleDOMWrapper.h"
|
|
#include "nsIDOMWindow.h"
|
|
#include "nsXBLBinding.h"
|
|
#include "nsXBLPrototypeBinding.h"
|
|
#include "nsIMutableArray.h"
|
|
#include "nsBindingManager.h"
|
|
#include "ChildIterator.h"
|
|
#include "nsComputedDOMStyle.h"
|
|
#include "mozilla/EventStateManager.h"
|
|
#include "nsAtom.h"
|
|
#include "nsRange.h"
|
|
#include "mozilla/StyleSheetInlines.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include "nsRuleWalker.h"
|
|
#include "nsCSSPseudoClasses.h"
|
|
#include "nsCSSRuleProcessor.h"
|
|
#include "mozilla/dom/CSSLexer.h"
|
|
#include "mozilla/dom/InspectorUtilsBinding.h"
|
|
#include "mozilla/dom/ToJSValue.h"
|
|
#include "nsCSSParser.h"
|
|
#include "nsCSSProps.h"
|
|
#include "nsCSSValue.h"
|
|
#include "nsColor.h"
|
|
#include "mozilla/StyleSetHandleInlines.h"
|
|
#include "nsStyleUtil.h"
|
|
#include "nsQueryObject.h"
|
|
#include "mozilla/ServoBindings.h"
|
|
#include "mozilla/ServoStyleRule.h"
|
|
#include "mozilla/ServoStyleRuleMap.h"
|
|
#include "mozilla/ServoCSSParser.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::css;
|
|
using namespace mozilla::dom;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
inDOMUtils::inDOMUtils()
|
|
{
|
|
}
|
|
|
|
inDOMUtils::~inDOMUtils()
|
|
{
|
|
}
|
|
|
|
NS_IMPL_ISUPPORTS(inDOMUtils, inIDOMUtils)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// inIDOMUtils
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
|
|
nsISupports ***aSheets)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aDocument);
|
|
|
|
nsTArray<RefPtr<StyleSheet>> sheets;
|
|
|
|
nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument);
|
|
MOZ_ASSERT(document);
|
|
|
|
// Get the agent, then user and finally xbl sheets in the style set.
|
|
nsIPresShell* presShell = document->GetShell();
|
|
|
|
if (presShell) {
|
|
StyleSetHandle styleSet = presShell->StyleSet();
|
|
SheetType sheetType = SheetType::Agent;
|
|
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
|
|
sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
|
|
}
|
|
sheetType = SheetType::User;
|
|
for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
|
|
sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
|
|
}
|
|
|
|
AutoTArray<StyleSheet*, 32> xblSheetArray;
|
|
styleSet->AppendAllXBLStyleSheets(xblSheetArray);
|
|
|
|
// The XBL stylesheet array will quite often be full of duplicates. Cope:
|
|
nsTHashtable<nsPtrHashKey<StyleSheet>> sheetSet;
|
|
for (StyleSheet* sheet : xblSheetArray) {
|
|
if (!sheetSet.Contains(sheet)) {
|
|
sheetSet.PutEntry(sheet);
|
|
sheets.AppendElement(sheet);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get the document sheets.
|
|
for (size_t i = 0; i < document->SheetCount(); i++) {
|
|
sheets.AppendElement(document->SheetAt(i));
|
|
}
|
|
|
|
nsISupports** ret = static_cast<nsISupports**>(moz_xmalloc(sheets.Length() *
|
|
sizeof(nsISupports*)));
|
|
|
|
for (size_t i = 0; i < sheets.Length(); i++) {
|
|
NS_ADDREF(ret[i] = NS_ISUPPORTS_CAST(nsIDOMCSSStyleSheet*, sheets[i]));
|
|
}
|
|
|
|
*aLength = sheets.Length();
|
|
*aSheets = ret;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::IsIgnorableWhitespace(nsIDOMCharacterData *aDataNode,
|
|
bool *aReturn)
|
|
{
|
|
NS_PRECONDITION(aReturn, "Must have an out parameter");
|
|
|
|
NS_ENSURE_ARG_POINTER(aDataNode);
|
|
|
|
*aReturn = false;
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aDataNode);
|
|
NS_ASSERTION(content, "Does not implement nsIContent!");
|
|
|
|
if (!content->TextIsOnlyWhitespace()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// Okay. We have only white space. Let's check the white-space
|
|
// property now and make sure that this isn't preformatted text...
|
|
nsIFrame* frame = content->GetPrimaryFrame();
|
|
if (frame) {
|
|
const nsStyleText* text = frame->StyleText();
|
|
*aReturn = !text->WhiteSpaceIsSignificant();
|
|
}
|
|
else {
|
|
// empty inter-tag text node without frame, e.g., in between <table>\n<tr>
|
|
*aReturn = true;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetParentForNode(nsIDOMNode* aNode,
|
|
bool aShowingAnonymousContent,
|
|
nsIDOMNode** aParent)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aNode);
|
|
|
|
// First do the special cases -- document nodes and anonymous content
|
|
nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode));
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
if (doc) {
|
|
parent = inLayoutUtils::GetContainerFor(*doc);
|
|
} else if (aShowingAnonymousContent) {
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
|
if (content) {
|
|
nsIContent* bparent = content->GetFlattenedTreeParent();
|
|
parent = do_QueryInterface(bparent);
|
|
}
|
|
}
|
|
|
|
if (!parent) {
|
|
// Ok, just get the normal DOM parent node
|
|
aNode->GetParentNode(getter_AddRefs(parent));
|
|
}
|
|
|
|
NS_IF_ADDREF(*aParent = parent);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetChildrenForNode(nsIDOMNode* aNode,
|
|
bool aShowingAnonymousContent,
|
|
nsIDOMNodeList** aChildren)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aNode);
|
|
NS_PRECONDITION(aChildren, "Must have an out parameter");
|
|
|
|
nsCOMPtr<nsIDOMNodeList> kids;
|
|
|
|
if (aShowingAnonymousContent) {
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
|
|
if (content) {
|
|
kids = content->GetChildren(nsIContent::eAllChildren);
|
|
}
|
|
}
|
|
|
|
if (!kids) {
|
|
aNode->GetChildNodes(getter_AddRefs(kids));
|
|
}
|
|
|
|
kids.forget(aChildren);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetCSSStyleRules(nsIDOMElement *aElement,
|
|
const nsAString& aPseudo,
|
|
nsIArrayExtensions **_retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aElement);
|
|
|
|
*_retval = nullptr;
|
|
|
|
RefPtr<nsAtom> pseudoElt;
|
|
if (!aPseudo.IsEmpty()) {
|
|
pseudoElt = NS_Atomize(aPseudo);
|
|
}
|
|
|
|
nsCOMPtr<Element> element = do_QueryInterface(aElement);
|
|
NS_ENSURE_STATE(element);
|
|
RefPtr<nsStyleContext> styleContext =
|
|
GetCleanStyleContextForElement(element, pseudoElt);
|
|
if (!styleContext) {
|
|
// 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 NS_OK;
|
|
}
|
|
|
|
|
|
nsCOMPtr<nsIMutableArray> rules = nsArray::Create();
|
|
if (auto gecko = styleContext->GetAsGecko()) {
|
|
nsRuleNode* ruleNode = gecko->RuleNode();
|
|
if (!ruleNode) {
|
|
return NS_OK;
|
|
}
|
|
|
|
AutoTArray<nsRuleNode*, 16> ruleNodes;
|
|
while (!ruleNode->IsRoot()) {
|
|
ruleNodes.AppendElement(ruleNode);
|
|
ruleNode = ruleNode->GetParent();
|
|
}
|
|
|
|
for (nsRuleNode* ruleNode : Reversed(ruleNodes)) {
|
|
RefPtr<Declaration> decl = do_QueryObject(ruleNode->GetRule());
|
|
if (decl) {
|
|
css::Rule* owningRule = decl->GetOwningRule();
|
|
if (owningRule) {
|
|
rules->AppendElement(owningRule);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
nsIDocument* doc = element->GetOwnerDocument();
|
|
nsIPresShell* shell = doc->GetShell();
|
|
if (!shell) {
|
|
return NS_OK;
|
|
}
|
|
|
|
ServoStyleContext* servo = styleContext->AsServo();
|
|
nsTArray<const RawServoStyleRule*> rawRuleList;
|
|
Servo_ComputedValues_GetStyleRuleList(servo, &rawRuleList);
|
|
|
|
AutoTArray<ServoStyleRuleMap*, 1> maps;
|
|
{
|
|
ServoStyleSet* styleSet = shell->StyleSet()->AsServo();
|
|
ServoStyleRuleMap* map = styleSet->StyleRuleMap();
|
|
map->EnsureTable();
|
|
maps.AppendElement(map);
|
|
}
|
|
|
|
// Collect style rule maps for bindings.
|
|
for (nsIContent* bindingContent = element; bindingContent;
|
|
bindingContent = bindingContent->GetBindingParent()) {
|
|
for (nsXBLBinding* binding = bindingContent->GetXBLBinding();
|
|
binding; binding = binding->GetBaseBinding()) {
|
|
if (ServoStyleSet* styleSet = binding->GetServoStyleSet()) {
|
|
ServoStyleRuleMap* map = styleSet->StyleRuleMap();
|
|
map->EnsureTable();
|
|
maps.AppendElement(map);
|
|
}
|
|
}
|
|
// Note that we intentionally don't cut off here, unlike when we
|
|
// do styling, because even if style rules from parent binding
|
|
// do not apply to the element directly in those cases, their
|
|
// rules may still show up in the list we get above due to the
|
|
// inheritance in cascading.
|
|
}
|
|
|
|
// Find matching rules in the table.
|
|
for (const RawServoStyleRule* rawRule : Reversed(rawRuleList)) {
|
|
ServoStyleRule* rule = nullptr;
|
|
for (ServoStyleRuleMap* map : maps) {
|
|
rule = map->Lookup(rawRule);
|
|
if (rule) {
|
|
break;
|
|
}
|
|
}
|
|
if (rule) {
|
|
rules->AppendElement(static_cast<css::Rule*>(rule));
|
|
} else {
|
|
MOZ_ASSERT_UNREACHABLE("We should be able to map a raw rule to a rule");
|
|
}
|
|
}
|
|
}
|
|
|
|
rules.forget(_retval);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
static already_AddRefed<BindingStyleRule>
|
|
GetRuleFromDOMRule(nsIDOMCSSStyleRule *aRule, ErrorResult& rv)
|
|
{
|
|
nsCOMPtr<nsICSSStyleRuleDOMWrapper> rule = do_QueryInterface(aRule);
|
|
if (!rule) {
|
|
rv.Throw(NS_ERROR_INVALID_POINTER);
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<BindingStyleRule> cssrule;
|
|
rv = rule->GetCSSStyleRule(getter_AddRefs(cssrule));
|
|
if (rv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
|
|
if (!cssrule) {
|
|
rv.Throw(NS_ERROR_FAILURE);
|
|
}
|
|
return cssrule.forget();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetRuleLine(nsIDOMCSSRule* aRule, uint32_t* _retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aRule);
|
|
|
|
Rule* rule = aRule->GetCSSRule();
|
|
if (!rule) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
*_retval = rule->GetLineNumber();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetRuleColumn(nsIDOMCSSRule* aRule, uint32_t* _retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aRule);
|
|
|
|
Rule* rule = aRule->GetCSSRule();
|
|
if (!rule) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
*_retval = rule->GetColumnNumber();
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetRelativeRuleLine(nsIDOMCSSRule* aRule, uint32_t* _retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aRule);
|
|
|
|
Rule* rule = aRule->GetCSSRule();
|
|
if (!rule) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
uint32_t lineNumber = rule->GetLineNumber();
|
|
StyleSheet* sheet = rule->GetStyleSheet();
|
|
if (sheet && lineNumber != 0) {
|
|
nsINode* owningNode = sheet->GetOwnerNode();
|
|
if (owningNode) {
|
|
nsCOMPtr<nsIStyleSheetLinkingElement> link =
|
|
do_QueryInterface(owningNode);
|
|
if (link) {
|
|
lineNumber -= link->GetLineNumber() - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
*_retval = lineNumber;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetCSSLexer(const nsAString& aText, JSContext* aCx,
|
|
JS::MutableHandleValue aResult)
|
|
{
|
|
MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx));
|
|
JS::Rooted<JSObject*> scope(aCx, JS::CurrentGlobalOrNull(aCx));
|
|
nsAutoPtr<CSSLexer> lexer(new CSSLexer(aText));
|
|
if (!WrapNewBindingNonWrapperCachedObject(aCx, scope, lexer, aResult)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetSelectorCount(nsIDOMCSSStyleRule* aRule, uint32_t *aCount)
|
|
{
|
|
ErrorResult rv;
|
|
RefPtr<BindingStyleRule> rule = GetRuleFromDOMRule(aRule, rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
*aCount = rule->GetSelectorCount();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetSelectorText(nsIDOMCSSStyleRule* aRule,
|
|
uint32_t aSelectorIndex,
|
|
nsAString& aText)
|
|
{
|
|
ErrorResult rv;
|
|
RefPtr<BindingStyleRule> rule = GetRuleFromDOMRule(aRule, rv);
|
|
MOZ_ASSERT(!rv.Failed(), "How could we get a selector but not a rule?");
|
|
|
|
return rule->GetSelectorText(aSelectorIndex, aText);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetSpecificity(nsIDOMCSSStyleRule* aRule,
|
|
uint32_t aSelectorIndex,
|
|
uint64_t* aSpecificity)
|
|
{
|
|
ErrorResult rv;
|
|
RefPtr<BindingStyleRule> rule = GetRuleFromDOMRule(aRule, rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
return rule->GetSpecificity(aSelectorIndex, aSpecificity);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement,
|
|
nsIDOMCSSStyleRule* aRule,
|
|
uint32_t aSelectorIndex,
|
|
const nsAString& aPseudo,
|
|
bool* aMatches)
|
|
{
|
|
nsCOMPtr<Element> element = do_QueryInterface(aElement);
|
|
NS_ENSURE_ARG_POINTER(element);
|
|
|
|
ErrorResult rv;
|
|
RefPtr<BindingStyleRule> rule = GetRuleFromDOMRule(aRule, rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
return rule->SelectorMatchesElement(element, aSelectorIndex, aPseudo,
|
|
aMatches);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::IsInheritedProperty(const nsAString &aPropertyName, bool *_retval)
|
|
{
|
|
nsCSSPropertyID prop = nsCSSProps::
|
|
LookupProperty(aPropertyName, CSSEnabledState::eIgnoreEnabledState);
|
|
if (prop == eCSSProperty_UNKNOWN) {
|
|
*_retval = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (prop == eCSSPropertyExtra_variable) {
|
|
*_retval = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (nsCSSProps::IsShorthand(prop)) {
|
|
prop = nsCSSProps::SubpropertyEntryFor(prop)[0];
|
|
}
|
|
|
|
nsStyleStructID sid = nsCSSProps::kSIDTable[prop];
|
|
*_retval = !nsStyleContext::IsReset(sid);
|
|
return NS_OK;
|
|
}
|
|
|
|
extern const char* const kCSSRawProperties[];
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetCSSPropertyNames(uint32_t aFlags, uint32_t* aCount,
|
|
char16_t*** aProps)
|
|
{
|
|
// maxCount is the largest number of properties we could have; our actual
|
|
// number might be smaller because properties might be disabled.
|
|
uint32_t maxCount;
|
|
if (aFlags & EXCLUDE_SHORTHANDS) {
|
|
maxCount = eCSSProperty_COUNT_no_shorthands;
|
|
} else {
|
|
maxCount = eCSSProperty_COUNT;
|
|
}
|
|
|
|
if (aFlags & INCLUDE_ALIASES) {
|
|
maxCount += (eCSSProperty_COUNT_with_aliases - eCSSProperty_COUNT);
|
|
}
|
|
|
|
char16_t** props =
|
|
static_cast<char16_t**>(moz_xmalloc(maxCount * sizeof(char16_t*)));
|
|
|
|
#define DO_PROP(_prop) \
|
|
PR_BEGIN_MACRO \
|
|
nsCSSPropertyID cssProp = nsCSSPropertyID(_prop); \
|
|
if (nsCSSProps::IsEnabled(cssProp, CSSEnabledState::eForAllContent)) { \
|
|
props[propCount] = \
|
|
ToNewUnicode(nsDependentCString(kCSSRawProperties[_prop])); \
|
|
++propCount; \
|
|
} \
|
|
PR_END_MACRO
|
|
|
|
// prop is the property id we're considering; propCount is how many properties
|
|
// we've put into props so far.
|
|
uint32_t prop = 0, propCount = 0;
|
|
for ( ; prop < eCSSProperty_COUNT_no_shorthands; ++prop) {
|
|
if (nsCSSProps::PropertyParseType(nsCSSPropertyID(prop)) !=
|
|
CSS_PROPERTY_PARSE_INACCESSIBLE) {
|
|
DO_PROP(prop);
|
|
}
|
|
}
|
|
|
|
if (!(aFlags & EXCLUDE_SHORTHANDS)) {
|
|
for ( ; prop < eCSSProperty_COUNT; ++prop) {
|
|
// Some shorthands are also aliases
|
|
if ((aFlags & INCLUDE_ALIASES) ||
|
|
!nsCSSProps::PropHasFlags(nsCSSPropertyID(prop),
|
|
CSS_PROPERTY_IS_ALIAS)) {
|
|
DO_PROP(prop);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aFlags & INCLUDE_ALIASES) {
|
|
for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; ++prop) {
|
|
DO_PROP(prop);
|
|
}
|
|
}
|
|
|
|
#undef DO_PROP
|
|
|
|
*aCount = propCount;
|
|
*aProps = props;
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
static void InsertNoDuplicates(nsTArray<nsString>& aArray,
|
|
const nsAString& aString)
|
|
{
|
|
size_t i = aArray.IndexOfFirstElementGt(aString);
|
|
if (i > 0 && aArray[i-1].Equals(aString)) {
|
|
return;
|
|
}
|
|
aArray.InsertElementAt(i, aString);
|
|
}
|
|
|
|
static void GetKeywordsForProperty(const nsCSSPropertyID aProperty,
|
|
nsTArray<nsString>& aArray)
|
|
{
|
|
if (nsCSSProps::IsShorthand(aProperty)) {
|
|
// Shorthand props have no keywords.
|
|
return;
|
|
}
|
|
const nsCSSProps::KTableEntry* keywordTable =
|
|
nsCSSProps::kKeywordTableTable[aProperty];
|
|
if (keywordTable) {
|
|
for (size_t i = 0; keywordTable[i].mKeyword != eCSSKeyword_UNKNOWN; ++i) {
|
|
nsCSSKeyword word = keywordTable[i].mKeyword;
|
|
|
|
// These are extra -moz values which are added while rebuilding
|
|
// the properties db. These values are not relevant and are not
|
|
// documented on MDN, so filter these out
|
|
if (word != eCSSKeyword__moz_zoom_in && word != eCSSKeyword__moz_zoom_out &&
|
|
word != eCSSKeyword__moz_grab && word != eCSSKeyword__moz_grabbing) {
|
|
InsertNoDuplicates(aArray,
|
|
NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void GetColorsForProperty(const uint32_t aParserVariant,
|
|
nsTArray<nsString>& aArray)
|
|
{
|
|
if (aParserVariant & VARIANT_COLOR) {
|
|
// GetKeywordsForProperty and GetOtherValuesForProperty assume aArray is sorted,
|
|
// and if aArray is not empty here, then it's not going to be sorted coming out.
|
|
MOZ_ASSERT(aArray.Length() == 0);
|
|
size_t size;
|
|
const char * const *allColorNames = NS_AllColorNames(&size);
|
|
nsString* utf16Names = aArray.AppendElements(size);
|
|
for (size_t i = 0; i < size; i++) {
|
|
CopyASCIItoUTF16(allColorNames[i], utf16Names[i]);
|
|
}
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("currentColor"));
|
|
}
|
|
}
|
|
|
|
static void GetOtherValuesForProperty(const uint32_t aParserVariant,
|
|
nsTArray<nsString>& aArray)
|
|
{
|
|
if (aParserVariant & VARIANT_AUTO) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("auto"));
|
|
}
|
|
if (aParserVariant & VARIANT_NORMAL) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("normal"));
|
|
}
|
|
if(aParserVariant & VARIANT_ALL) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("all"));
|
|
}
|
|
if (aParserVariant & VARIANT_NONE) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("none"));
|
|
}
|
|
if (aParserVariant & VARIANT_ELEMENT) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-element"));
|
|
}
|
|
if (aParserVariant & VARIANT_IMAGE_RECT) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-image-rect"));
|
|
}
|
|
if (aParserVariant & VARIANT_COLOR) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgb"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsl"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgba"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsla"));
|
|
}
|
|
if (aParserVariant & VARIANT_TIMING_FUNCTION) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("cubic-bezier"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("steps"));
|
|
}
|
|
if (aParserVariant & VARIANT_CALC) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("calc"));
|
|
}
|
|
if (aParserVariant & VARIANT_URL) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("url"));
|
|
}
|
|
if (aParserVariant & VARIANT_GRADIENT) {
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("linear-gradient"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("radial-gradient"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-linear-gradient"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-radial-gradient"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-linear-gradient"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-radial-gradient"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-linear-gradient"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-radial-gradient"));
|
|
}
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetSubpropertiesForCSSProperty(const nsAString& aProperty,
|
|
uint32_t* aLength,
|
|
char16_t*** aValues)
|
|
{
|
|
nsCSSPropertyID propertyID =
|
|
nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
|
|
|
|
if (propertyID == eCSSProperty_UNKNOWN) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if (propertyID == eCSSPropertyExtra_variable) {
|
|
*aValues = static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t*)));
|
|
(*aValues)[0] = ToNewUnicode(aProperty);
|
|
*aLength = 1;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (!nsCSSProps::IsShorthand(propertyID)) {
|
|
*aValues = static_cast<char16_t**>(moz_xmalloc(sizeof(char16_t*)));
|
|
(*aValues)[0] = ToNewUnicode(nsCSSProps::GetStringValue(propertyID));
|
|
*aLength = 1;
|
|
return NS_OK;
|
|
}
|
|
|
|
// Count up how many subproperties we have.
|
|
size_t subpropCount = 0;
|
|
for (const nsCSSPropertyID *props = nsCSSProps::SubpropertyEntryFor(propertyID);
|
|
*props != eCSSProperty_UNKNOWN; ++props) {
|
|
++subpropCount;
|
|
}
|
|
|
|
*aValues =
|
|
static_cast<char16_t**>(moz_xmalloc(subpropCount * sizeof(char16_t*)));
|
|
*aLength = subpropCount;
|
|
for (const nsCSSPropertyID *props = nsCSSProps::SubpropertyEntryFor(propertyID),
|
|
*props_start = props;
|
|
*props != eCSSProperty_UNKNOWN; ++props) {
|
|
(*aValues)[props-props_start] = ToNewUnicode(nsCSSProps::GetStringValue(*props));
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::CssPropertyIsShorthand(const nsAString& aProperty, bool *_retval)
|
|
{
|
|
nsCSSPropertyID propertyID =
|
|
nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
|
|
if (propertyID == eCSSProperty_UNKNOWN) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if (propertyID == eCSSPropertyExtra_variable) {
|
|
*_retval = false;
|
|
} else {
|
|
*_retval = nsCSSProps::IsShorthand(propertyID);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
// A helper function that determines whether the given property
|
|
// supports the given type.
|
|
static bool
|
|
PropertySupportsVariant(nsCSSPropertyID aPropertyID, uint32_t aVariant)
|
|
{
|
|
if (nsCSSProps::IsShorthand(aPropertyID)) {
|
|
// We need a special case for border here, because while it resets
|
|
// border-image, it can't actually parse an image.
|
|
if (aPropertyID == eCSSProperty_border) {
|
|
return (aVariant & (VARIANT_COLOR | VARIANT_LENGTH)) != 0;
|
|
}
|
|
|
|
for (const nsCSSPropertyID* props = nsCSSProps::SubpropertyEntryFor(aPropertyID);
|
|
*props != eCSSProperty_UNKNOWN; ++props) {
|
|
if (PropertySupportsVariant(*props, aVariant)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Properties that are parsed by functions must have their
|
|
// attributes hand-maintained here.
|
|
if (nsCSSProps::PropHasFlags(aPropertyID, CSS_PROPERTY_VALUE_PARSER_FUNCTION) ||
|
|
nsCSSProps::PropertyParseType(aPropertyID) == CSS_PROPERTY_PARSE_FUNCTION) {
|
|
// These must all be special-cased.
|
|
uint32_t supported;
|
|
switch (aPropertyID) {
|
|
case eCSSProperty_border_image_slice:
|
|
case eCSSProperty_grid_template:
|
|
case eCSSProperty_grid:
|
|
supported = VARIANT_PN;
|
|
break;
|
|
|
|
case eCSSProperty_border_image_outset:
|
|
supported = VARIANT_LN;
|
|
break;
|
|
|
|
case eCSSProperty_border_image_width:
|
|
case eCSSProperty_stroke_dasharray:
|
|
supported = VARIANT_LPN;
|
|
break;
|
|
|
|
case eCSSProperty_border_top_left_radius:
|
|
case eCSSProperty_border_top_right_radius:
|
|
case eCSSProperty_border_bottom_left_radius:
|
|
case eCSSProperty_border_bottom_right_radius:
|
|
case eCSSProperty_background_position:
|
|
case eCSSProperty_background_position_x:
|
|
case eCSSProperty_background_position_y:
|
|
case eCSSProperty_background_size:
|
|
case eCSSProperty_mask_position:
|
|
case eCSSProperty_mask_position_x:
|
|
case eCSSProperty_mask_position_y:
|
|
case eCSSProperty_mask_size:
|
|
case eCSSProperty_grid_auto_columns:
|
|
case eCSSProperty_grid_auto_rows:
|
|
case eCSSProperty_grid_template_columns:
|
|
case eCSSProperty_grid_template_rows:
|
|
case eCSSProperty_object_position:
|
|
case eCSSProperty_scroll_snap_coordinate:
|
|
case eCSSProperty_scroll_snap_destination:
|
|
case eCSSProperty_transform_origin:
|
|
case eCSSProperty_perspective_origin:
|
|
case eCSSProperty__moz_outline_radius_topleft:
|
|
case eCSSProperty__moz_outline_radius_topright:
|
|
case eCSSProperty__moz_outline_radius_bottomleft:
|
|
case eCSSProperty__moz_outline_radius_bottomright:
|
|
case eCSSProperty__moz_window_transform_origin:
|
|
supported = VARIANT_LP;
|
|
break;
|
|
|
|
case eCSSProperty__moz_border_bottom_colors:
|
|
case eCSSProperty__moz_border_left_colors:
|
|
case eCSSProperty__moz_border_right_colors:
|
|
case eCSSProperty__moz_border_top_colors:
|
|
supported = VARIANT_COLOR;
|
|
break;
|
|
|
|
case eCSSProperty_text_shadow:
|
|
case eCSSProperty_box_shadow:
|
|
supported = VARIANT_LENGTH | VARIANT_COLOR;
|
|
break;
|
|
|
|
case eCSSProperty_border_spacing:
|
|
supported = VARIANT_LENGTH;
|
|
break;
|
|
|
|
case eCSSProperty_content:
|
|
case eCSSProperty_cursor:
|
|
case eCSSProperty_clip_path:
|
|
supported = VARIANT_URL;
|
|
break;
|
|
|
|
case eCSSProperty_shape_outside:
|
|
supported = VARIANT_IMAGE;
|
|
break;
|
|
|
|
case eCSSProperty_fill:
|
|
case eCSSProperty_stroke:
|
|
supported = VARIANT_COLOR | VARIANT_URL;
|
|
break;
|
|
|
|
case eCSSProperty_image_orientation:
|
|
supported = VARIANT_ANGLE;
|
|
break;
|
|
|
|
case eCSSProperty_filter:
|
|
supported = VARIANT_URL;
|
|
break;
|
|
|
|
case eCSSProperty_grid_column_start:
|
|
case eCSSProperty_grid_column_end:
|
|
case eCSSProperty_grid_row_start:
|
|
case eCSSProperty_grid_row_end:
|
|
case eCSSProperty_font_weight:
|
|
case eCSSProperty_initial_letter:
|
|
supported = VARIANT_NUMBER;
|
|
break;
|
|
|
|
default:
|
|
supported = 0;
|
|
break;
|
|
}
|
|
|
|
return (supported & aVariant) != 0;
|
|
}
|
|
|
|
return (nsCSSProps::ParserVariant(aPropertyID) & aVariant) != 0;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::CssPropertySupportsType(const nsAString& aProperty, uint32_t aType,
|
|
bool *_retval)
|
|
{
|
|
nsCSSPropertyID propertyID =
|
|
nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
|
|
if (propertyID == eCSSProperty_UNKNOWN) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
if (propertyID >= eCSSProperty_COUNT) {
|
|
*_retval = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
uint32_t variant;
|
|
switch (aType) {
|
|
case TYPE_LENGTH:
|
|
variant = VARIANT_LENGTH;
|
|
break;
|
|
case TYPE_PERCENTAGE:
|
|
variant = VARIANT_PERCENT;
|
|
break;
|
|
case TYPE_COLOR:
|
|
variant = VARIANT_COLOR;
|
|
break;
|
|
case TYPE_URL:
|
|
variant = VARIANT_URL;
|
|
break;
|
|
case TYPE_ANGLE:
|
|
variant = VARIANT_ANGLE;
|
|
break;
|
|
case TYPE_FREQUENCY:
|
|
variant = VARIANT_FREQUENCY;
|
|
break;
|
|
case TYPE_TIME:
|
|
variant = VARIANT_TIME;
|
|
break;
|
|
case TYPE_GRADIENT:
|
|
variant = VARIANT_GRADIENT;
|
|
break;
|
|
case TYPE_TIMING_FUNCTION:
|
|
variant = VARIANT_TIMING_FUNCTION;
|
|
break;
|
|
case TYPE_IMAGE_RECT:
|
|
variant = VARIANT_IMAGE_RECT;
|
|
break;
|
|
case TYPE_NUMBER:
|
|
// Include integers under "number"?
|
|
variant = VARIANT_NUMBER | VARIANT_INTEGER;
|
|
break;
|
|
default:
|
|
// Unknown type
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
}
|
|
|
|
*_retval = PropertySupportsVariant(propertyID, variant);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty,
|
|
uint32_t* aLength,
|
|
char16_t*** aValues)
|
|
{
|
|
nsCSSPropertyID propertyID = nsCSSProps::
|
|
LookupProperty(aProperty, CSSEnabledState::eForAllContent);
|
|
if (propertyID == eCSSProperty_UNKNOWN) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsTArray<nsString> array;
|
|
// We start collecting the values, BUT colors need to go in first, because array
|
|
// needs to stay sorted, and the colors are sorted, so we just append them.
|
|
if (propertyID == eCSSPropertyExtra_variable) {
|
|
// No other values we can report.
|
|
} else if (!nsCSSProps::IsShorthand(propertyID)) {
|
|
// Property is longhand.
|
|
uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID);
|
|
// Get colors first.
|
|
GetColorsForProperty(propertyParserVariant, array);
|
|
GetKeywordsForProperty(propertyID, array);
|
|
GetOtherValuesForProperty(propertyParserVariant, array);
|
|
} else {
|
|
// Property is shorthand.
|
|
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
|
|
CSSEnabledState::eForAllContent) {
|
|
// Get colors (once) first.
|
|
uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
|
|
if (propertyParserVariant & VARIANT_COLOR) {
|
|
GetColorsForProperty(propertyParserVariant, array);
|
|
break;
|
|
}
|
|
}
|
|
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID,
|
|
CSSEnabledState::eForAllContent) {
|
|
uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
|
|
GetKeywordsForProperty(*subproperty, array);
|
|
GetOtherValuesForProperty(propertyParserVariant, array);
|
|
}
|
|
}
|
|
// All CSS properties take initial, inherit and unset.
|
|
InsertNoDuplicates(array, NS_LITERAL_STRING("initial"));
|
|
InsertNoDuplicates(array, NS_LITERAL_STRING("inherit"));
|
|
InsertNoDuplicates(array, NS_LITERAL_STRING("unset"));
|
|
|
|
*aLength = array.Length();
|
|
char16_t** ret =
|
|
static_cast<char16_t**>(moz_xmalloc(*aLength * sizeof(char16_t*)));
|
|
for (uint32_t i = 0; i < *aLength; ++i) {
|
|
ret[i] = ToNewUnicode(array[i]);
|
|
}
|
|
*aValues = ret;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::ColorNameToRGB(const nsAString& aColorName, JSContext* aCx,
|
|
JS::MutableHandle<JS::Value> aValue)
|
|
{
|
|
nscolor color;
|
|
if (!NS_ColorNameToRGB(aColorName, &color)) {
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
InspectorRGBTriple triple;
|
|
triple.mR = NS_GET_R(color);
|
|
triple.mG = NS_GET_G(color);
|
|
triple.mB = NS_GET_B(color);
|
|
|
|
if (!ToJSValue(aCx, triple, aValue)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::RgbToColorName(uint8_t aR, uint8_t aG, uint8_t aB,
|
|
nsAString& aColorName)
|
|
{
|
|
const char* color = NS_RGBToColorName(NS_RGB(aR, aG, aB));
|
|
if (!color) {
|
|
aColorName.Truncate();
|
|
return NS_ERROR_INVALID_ARG;
|
|
}
|
|
|
|
aColorName.AssignASCII(color);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::ColorToRGBA(const nsAString& aColorString, JSContext* aCx,
|
|
JS::MutableHandle<JS::Value> aValue)
|
|
{
|
|
nscolor color = NS_RGB(0, 0, 0);
|
|
|
|
#ifdef MOZ_STYLO
|
|
if (!ServoCSSParser::ComputeColor(nullptr, NS_RGB(0, 0, 0), aColorString,
|
|
&color)) {
|
|
aValue.setNull();
|
|
return NS_OK;
|
|
}
|
|
#else
|
|
nsCSSParser cssParser;
|
|
nsCSSValue cssValue;
|
|
|
|
if (!cssParser.ParseColorString(aColorString, nullptr, 0, cssValue, true)) {
|
|
aValue.setNull();
|
|
return NS_OK;
|
|
}
|
|
|
|
nsRuleNode::ComputeColor(cssValue, nullptr, nullptr, color);
|
|
#endif
|
|
|
|
InspectorRGBATuple tuple;
|
|
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));
|
|
|
|
if (!ToJSValue(aCx, tuple, aValue)) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::IsValidCSSColor(const nsAString& aColorString, bool *_retval)
|
|
{
|
|
#ifdef MOZ_STYLO
|
|
*_retval = ServoCSSParser::IsValidCSSColor(aColorString);
|
|
#else
|
|
nsCSSParser cssParser;
|
|
nsCSSValue cssValue;
|
|
*_retval = cssParser.ParseColorString(aColorString, nullptr, 0, cssValue, true);
|
|
#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetBindingURLs(nsIDOMElement *aElement, nsIArray **_retval)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aElement);
|
|
|
|
*_retval = nullptr;
|
|
|
|
nsCOMPtr<nsIMutableArray> urls = do_CreateInstance(NS_ARRAY_CONTRACTID);
|
|
if (!urls)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
|
NS_ENSURE_ARG_POINTER(content);
|
|
|
|
nsXBLBinding *binding = content->GetXBLBinding();
|
|
|
|
while (binding) {
|
|
urls->AppendElement(binding->PrototypeBinding()->BindingURI());
|
|
binding = binding->GetBaseBinding();
|
|
}
|
|
|
|
urls.forget(_retval);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::SetContentState(nsIDOMElement* aElement,
|
|
EventStates::InternalType aState,
|
|
bool* aRetVal)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aElement);
|
|
|
|
RefPtr<EventStateManager> esm =
|
|
inLayoutUtils::GetEventStateManagerFor(aElement);
|
|
NS_ENSURE_TRUE(esm, NS_ERROR_INVALID_ARG);
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
content = do_QueryInterface(aElement);
|
|
NS_ENSURE_TRUE(content, NS_ERROR_INVALID_ARG);
|
|
|
|
*aRetVal = esm->SetContentState(content, EventStates(aState));
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::RemoveContentState(nsIDOMElement* aElement,
|
|
EventStates::InternalType aState,
|
|
bool aClearActiveDocument,
|
|
bool* aRetVal)
|
|
{
|
|
NS_ENSURE_ARG_POINTER(aElement);
|
|
|
|
RefPtr<EventStateManager> esm =
|
|
inLayoutUtils::GetEventStateManagerFor(aElement);
|
|
NS_ENSURE_TRUE(esm, NS_ERROR_INVALID_ARG);
|
|
|
|
*aRetVal = esm->SetContentState(nullptr, EventStates(aState));
|
|
|
|
if (aClearActiveDocument && EventStates(aState) == NS_EVENT_STATE_ACTIVE) {
|
|
EventStateManager* activeESM = static_cast<EventStateManager*>(
|
|
EventStateManager::GetActiveEventStateManager());
|
|
if (activeESM == esm) {
|
|
EventStateManager::ClearGlobalActiveContent(nullptr);
|
|
}
|
|
}
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetContentState(nsIDOMElement* aElement,
|
|
EventStates::InternalType* aState)
|
|
{
|
|
*aState = 0;
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
|
NS_ENSURE_ARG_POINTER(content);
|
|
|
|
// NOTE: if this method is removed,
|
|
// please remove GetInternalValue from EventStates
|
|
*aState = content->AsElement()->State().GetInternalValue();
|
|
return NS_OK;
|
|
}
|
|
|
|
/* static */ already_AddRefed<nsStyleContext>
|
|
inDOMUtils::GetCleanStyleContextForElement(dom::Element* aElement,
|
|
nsAtom* aPseudo)
|
|
{
|
|
MOZ_ASSERT(aElement);
|
|
|
|
nsIDocument* doc = aElement->GetComposedDoc();
|
|
if (!doc) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsIPresShell *presShell = doc->GetShell();
|
|
if (!presShell) {
|
|
return nullptr;
|
|
}
|
|
|
|
nsPresContext *presContext = presShell->GetPresContext();
|
|
if (!presContext) {
|
|
return nullptr;
|
|
}
|
|
|
|
presContext->EnsureSafeToHandOutCSSRules();
|
|
|
|
RefPtr<nsStyleContext> styleContext =
|
|
nsComputedDOMStyle::GetStyleContext(aElement, aPseudo, presShell);
|
|
return styleContext.forget();
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetUsedFontFaces(nsIDOMRange* aRange,
|
|
nsIDOMFontFaceList** aFontFaceList)
|
|
{
|
|
return static_cast<nsRange*>(aRange)->GetUsedFontFaces(aFontFaceList);
|
|
}
|
|
|
|
static EventStates
|
|
GetStatesForPseudoClass(const nsAString& aStatePseudo)
|
|
{
|
|
// An array of the states that are relevant for various pseudoclasses.
|
|
// XXXbz this duplicates code in nsCSSRuleProcessor
|
|
static const EventStates sPseudoClassStates[] = {
|
|
#define CSS_PSEUDO_CLASS(_name, _value, _flags, _pref) \
|
|
EventStates(),
|
|
#define CSS_STATE_PSEUDO_CLASS(_name, _value, _flags, _pref, _states) \
|
|
_states,
|
|
#include "nsCSSPseudoClassList.h"
|
|
#undef CSS_STATE_PSEUDO_CLASS
|
|
#undef CSS_PSEUDO_CLASS
|
|
|
|
// Add more entries for our fake values to make sure we can't
|
|
// index out of bounds into this array no matter what.
|
|
EventStates(),
|
|
EventStates()
|
|
};
|
|
static_assert(MOZ_ARRAY_LENGTH(sPseudoClassStates) ==
|
|
static_cast<size_t>(CSSPseudoClassType::MAX),
|
|
"Length of PseudoClassStates array is incorrect");
|
|
|
|
RefPtr<nsAtom> atom = NS_Atomize(aStatePseudo);
|
|
CSSPseudoClassType type = nsCSSPseudoClasses::
|
|
GetPseudoType(atom, CSSEnabledState::eIgnoreEnabledState);
|
|
|
|
// Ignore :any-link so we don't give the element simultaneous
|
|
// visited and unvisited style state
|
|
if (type == CSSPseudoClassType::anyLink ||
|
|
type == CSSPseudoClassType::mozAnyLink) {
|
|
return EventStates();
|
|
}
|
|
// Our array above is long enough that indexing into it with
|
|
// NotPseudo is ok.
|
|
return sPseudoClassStates[static_cast<CSSPseudoClassTypeBase>(type)];
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetCSSPseudoElementNames(uint32_t* aLength, char16_t*** aNames)
|
|
{
|
|
nsTArray<nsAtom*> array;
|
|
|
|
const CSSPseudoElementTypeBase pseudoCount =
|
|
static_cast<CSSPseudoElementTypeBase>(CSSPseudoElementType::Count);
|
|
for (CSSPseudoElementTypeBase i = 0; i < pseudoCount; ++i) {
|
|
CSSPseudoElementType type = static_cast<CSSPseudoElementType>(i);
|
|
if (nsCSSPseudoElements::IsEnabled(type, CSSEnabledState::eForAllContent)) {
|
|
nsAtom* atom = nsCSSPseudoElements::GetPseudoAtom(type);
|
|
array.AppendElement(atom);
|
|
}
|
|
}
|
|
|
|
*aLength = array.Length();
|
|
char16_t** ret =
|
|
static_cast<char16_t**>(moz_xmalloc(*aLength * sizeof(char16_t*)));
|
|
for (uint32_t i = 0; i < *aLength; ++i) {
|
|
ret[i] = ToNewUnicode(nsDependentAtomString(array[i]));
|
|
}
|
|
*aNames = ret;
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
|
|
const nsAString &aPseudoClass,
|
|
bool aEnabled,
|
|
uint8_t aArgc)
|
|
{
|
|
EventStates state = GetStatesForPseudoClass(aPseudoClass);
|
|
if (state.IsEmpty()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
|
NS_ENSURE_ARG_POINTER(element);
|
|
|
|
element->LockStyleStates(state, aArgc > 0 ? aEnabled : true);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::RemovePseudoClassLock(nsIDOMElement *aElement,
|
|
const nsAString &aPseudoClass)
|
|
{
|
|
EventStates state = GetStatesForPseudoClass(aPseudoClass);
|
|
if (state.IsEmpty()) {
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
|
NS_ENSURE_ARG_POINTER(element);
|
|
|
|
element->UnlockStyleStates(state);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::HasPseudoClassLock(nsIDOMElement *aElement,
|
|
const nsAString &aPseudoClass,
|
|
bool *_retval)
|
|
{
|
|
EventStates state = GetStatesForPseudoClass(aPseudoClass);
|
|
if (state.IsEmpty()) {
|
|
*_retval = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
|
NS_ENSURE_ARG_POINTER(element);
|
|
|
|
EventStates locks = element->LockedStyleStates().mLocks;
|
|
|
|
*_retval = locks.HasAllStates(state);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::ClearPseudoClassLocks(nsIDOMElement *aElement)
|
|
{
|
|
nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
|
|
NS_ENSURE_ARG_POINTER(element);
|
|
|
|
element->ClearStyleStateLocks();
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::ParseStyleSheet(nsIDOMCSSStyleSheet *aSheet,
|
|
const nsAString& aInput)
|
|
{
|
|
RefPtr<CSSStyleSheet> geckoSheet = do_QueryObject(aSheet);
|
|
if (geckoSheet) {
|
|
NS_ENSURE_ARG_POINTER(geckoSheet);
|
|
return geckoSheet->ReparseSheet(aInput);
|
|
}
|
|
|
|
RefPtr<ServoStyleSheet> servoSheet = do_QueryObject(aSheet);
|
|
if (servoSheet) {
|
|
NS_ENSURE_ARG_POINTER(servoSheet);
|
|
return servoSheet->ReparseSheet(aInput);
|
|
}
|
|
|
|
return NS_ERROR_INVALID_POINTER;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::ScrollElementIntoView(nsIDOMElement *aElement)
|
|
{
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
|
|
NS_ENSURE_ARG_POINTER(content);
|
|
|
|
nsIPresShell* presShell = content->OwnerDoc()->GetShell();
|
|
if (!presShell) {
|
|
return NS_OK;
|
|
}
|
|
|
|
presShell->ScrollContentIntoView(content,
|
|
nsIPresShell::ScrollAxis(),
|
|
nsIPresShell::ScrollAxis(),
|
|
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
|
|
|
|
return NS_OK;
|
|
}
|