mirror of
https://github.com/ManchildProductions/UXP-Fixed.git
synced 2026-05-27 01:59:05 +00:00
b8c604196b
I got very anxious about making sure I included VARIANT_OPACITY in all the places VARIANT_NUMBER was included to make sure it couldn't possibly break unexpectedly, and that led to me accidentally breaking a mechanism that prevented percentages from serializing as numbers in other parts of the code. It was a total accident, and these additions were unnecessary. Basically, the situation is that there was one part of the code where it determines what's allowed for the flex statement (and possibly other statements) by checking whether it got stored as a "number", and basically only disallows percentages if it attempted to store/serialize them as percentages. However, it only got to that part of the code because I accidentally allowed VARIANT_OPACITY as a valid way for certain tokens to parse where it wasn't necessary. If it tries to parse it that way under very specific circumstances... percentages will be marked valid and fed through the system as numbers rather than being rejected and not serialized at all, because the check to disallow percentages there relied on them being stored as percentages. It's a really weird thing to have a problem with in a lot of ways, because if percentages aren't allowed in a field, you would think people wouldn't try to use them there, much less depend on the broken behavior that results from them not parsing as a related value.
1346 lines
39 KiB
C++
1346 lines
39 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 "nsIAtom.h"
|
|
#include "nsRange.h"
|
|
#include "nsContentList.h"
|
|
#include "mozilla/StyleSheetInlines.h"
|
|
#include "mozilla/dom/Element.h"
|
|
#include "nsRuleWalker.h"
|
|
#include "nsRuleProcessorData.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/StyleSetHandle.h"
|
|
#include "mozilla/StyleSetHandleInlines.h"
|
|
#include "nsStyleUtil.h"
|
|
#include "nsQueryObject.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));
|
|
}
|
|
if (styleSet->IsGecko()) {
|
|
AutoTArray<CSSStyleSheet*, 32> xblSheetArray;
|
|
styleSet->AsGecko()->AppendAllXBLStyleSheets(xblSheetArray);
|
|
|
|
// The XBL stylesheet array will quite often be full of duplicates. Cope:
|
|
nsTHashtable<nsPtrHashKey<CSSStyleSheet>> sheetSet;
|
|
for (CSSStyleSheet* sheet : xblSheetArray) {
|
|
if (!sheetSet.Contains(sheet)) {
|
|
sheetSet.PutEntry(sheet);
|
|
sheets.AppendElement(sheet);
|
|
}
|
|
}
|
|
} else {
|
|
NS_WARNING("stylo: XBL style sheets not supported yet");
|
|
}
|
|
}
|
|
|
|
// 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;
|
|
|
|
nsCOMPtr<nsIAtom> pseudoElt;
|
|
if (!aPseudo.IsEmpty()) {
|
|
pseudoElt = NS_Atomize(aPseudo);
|
|
}
|
|
|
|
nsRuleNode* ruleNode = nullptr;
|
|
nsCOMPtr<Element> element = do_QueryInterface(aElement);
|
|
NS_ENSURE_STATE(element);
|
|
RefPtr<nsStyleContext> styleContext;
|
|
GetRuleNodeForElement(element, pseudoElt, getter_AddRefs(styleContext), &ruleNode);
|
|
if (!ruleNode) {
|
|
// 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;
|
|
}
|
|
|
|
AutoTArray<nsRuleNode*, 16> ruleNodes;
|
|
while (!ruleNode->IsRoot()) {
|
|
ruleNodes.AppendElement(ruleNode);
|
|
ruleNode = ruleNode->GetParent();
|
|
}
|
|
|
|
nsCOMPtr<nsIMutableArray> rules = nsArray::Create();
|
|
for (nsRuleNode* ruleNode : Reversed(ruleNodes)) {
|
|
RefPtr<Declaration> decl = do_QueryObject(ruleNode->GetRule());
|
|
if (decl) {
|
|
RefPtr<mozilla::css::StyleRule> styleRule =
|
|
do_QueryObject(decl->GetOwningRule());
|
|
if (styleRule) {
|
|
nsCOMPtr<nsIDOMCSSRule> domRule = styleRule->GetDOMRule();
|
|
if (domRule) {
|
|
rules->AppendElement(domRule, /*weak =*/ false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
rules.forget(_retval);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
static already_AddRefed<StyleRule>
|
|
GetRuleFromDOMRule(nsIDOMCSSStyleRule *aRule, ErrorResult& rv)
|
|
{
|
|
nsCOMPtr<nsICSSStyleRuleDOMWrapper> rule = do_QueryInterface(aRule);
|
|
if (!rule) {
|
|
rv.Throw(NS_ERROR_INVALID_POINTER);
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<StyleRule> 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();
|
|
CSSStyleSheet* 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<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
uint32_t count = 0;
|
|
for (nsCSSSelectorList* sel = rule->Selector(); sel; sel = sel->mNext) {
|
|
++count;
|
|
}
|
|
*aCount = count;
|
|
return NS_OK;
|
|
}
|
|
|
|
static nsCSSSelectorList*
|
|
GetSelectorAtIndex(nsIDOMCSSStyleRule* aRule, uint32_t aIndex, ErrorResult& rv)
|
|
{
|
|
RefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
|
|
if (rv.Failed()) {
|
|
return nullptr;
|
|
}
|
|
|
|
for (nsCSSSelectorList* sel = rule->Selector(); sel;
|
|
sel = sel->mNext, --aIndex) {
|
|
if (aIndex == 0) {
|
|
return sel;
|
|
}
|
|
}
|
|
|
|
// Ran out of selectors
|
|
rv.Throw(NS_ERROR_INVALID_ARG);
|
|
return nullptr;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetSelectorText(nsIDOMCSSStyleRule* aRule,
|
|
uint32_t aSelectorIndex,
|
|
nsAString& aText)
|
|
{
|
|
ErrorResult rv;
|
|
nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
RefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
|
|
MOZ_ASSERT(!rv.Failed(), "How could we get a selector but not a rule?");
|
|
|
|
sel->mSelectors->ToString(aText, rule->GetStyleSheet(), false);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::GetSpecificity(nsIDOMCSSStyleRule* aRule,
|
|
uint32_t aSelectorIndex,
|
|
uint64_t* aSpecificity)
|
|
{
|
|
ErrorResult rv;
|
|
nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
*aSpecificity = sel->mWeight;
|
|
return NS_OK;
|
|
}
|
|
|
|
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;
|
|
nsCSSSelectorList* tail = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
|
|
if (rv.Failed()) {
|
|
return rv.StealNSResult();
|
|
}
|
|
|
|
// We want just the one list item, not the whole list tail
|
|
nsAutoPtr<nsCSSSelectorList> sel(tail->Clone(false));
|
|
|
|
// Do not attempt to match if a pseudo element is requested and this is not
|
|
// a pseudo element selector, or vice versa.
|
|
if (aPseudo.IsEmpty() == sel->mSelectors->IsPseudoElement()) {
|
|
*aMatches = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (!aPseudo.IsEmpty()) {
|
|
// We need to make sure that the requested pseudo element type
|
|
// matches the selector pseudo element type before proceeding.
|
|
nsCOMPtr<nsIAtom> pseudoElt = NS_Atomize(aPseudo);
|
|
if (sel->mSelectors->PseudoType() != nsCSSPseudoElements::
|
|
GetPseudoType(pseudoElt, CSSEnabledState::eIgnoreEnabledState)) {
|
|
*aMatches = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
// We have a matching pseudo element, now remove it so we can compare
|
|
// directly against |element| when proceeding into SelectorListMatches.
|
|
// It's OK to do this - we just cloned sel and nothing else is using it.
|
|
sel->RemoveRightmostSelector();
|
|
}
|
|
|
|
element->OwnerDoc()->FlushPendingLinkUpdates();
|
|
// XXXbz what exactly should we do with visited state here?
|
|
TreeMatchContext matchingContext(false,
|
|
nsRuleWalker::eRelevantLinkUnvisited,
|
|
element->OwnerDoc(),
|
|
TreeMatchContext::eNeverMatchVisited);
|
|
*aMatches = nsCSSRuleProcessor::SelectorListMatches(element, matchingContext,
|
|
sel);
|
|
return NS_OK;
|
|
}
|
|
|
|
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 = !nsCachedStyleData::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;
|
|
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"));
|
|
}
|
|
return;
|
|
}
|
|
|
|
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"));
|
|
InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-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:
|
|
supported = VARIANT_LP;
|
|
break;
|
|
|
|
case eCSSProperty_border_bottom_colors:
|
|
case eCSSProperty_border_left_colors:
|
|
case eCSSProperty_border_right_colors:
|
|
case eCSSProperty_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:
|
|
case eCSSProperty_shape_outside:
|
|
supported = VARIANT_URL;
|
|
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 | VARIANT_OPACITY;
|
|
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);
|
|
if (propertyParserVariant & VARIANT_KEYWORD) {
|
|
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);
|
|
if (propertyParserVariant & VARIANT_KEYWORD) {
|
|
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 = 0;
|
|
nsCSSParser cssParser;
|
|
nsCSSValue cssValue;
|
|
|
|
bool isColor = cssParser.ParseColorString(aColorString, nullptr, 0,
|
|
cssValue, true);
|
|
|
|
if (!isColor) {
|
|
aValue.setNull();
|
|
return NS_OK;
|
|
}
|
|
|
|
nsRuleNode::ComputeColor(cssValue, nullptr, nullptr, color);
|
|
|
|
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)
|
|
{
|
|
nsCSSParser cssParser;
|
|
nsCSSValue cssValue;
|
|
*_retval = cssParser.ParseColorString(aColorString, nullptr, 0, cssValue, true);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
inDOMUtils::CssPropertyIsValid(const nsAString& aPropertyName,
|
|
const nsAString& aPropertyValue,
|
|
bool *_retval)
|
|
{
|
|
nsCSSPropertyID propertyID = nsCSSProps::
|
|
LookupProperty(aPropertyName, CSSEnabledState::eIgnoreEnabledState);
|
|
|
|
if (propertyID == eCSSProperty_UNKNOWN) {
|
|
*_retval = false;
|
|
return NS_OK;
|
|
}
|
|
|
|
if (propertyID == eCSSPropertyExtra_variable) {
|
|
*_retval = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
// Get a parser, parse the property.
|
|
nsCSSParser parser;
|
|
*_retval = parser.IsValueValidForProperty(propertyID, aPropertyValue);
|
|
|
|
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(), false);
|
|
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* 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));
|
|
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 */ nsresult
|
|
inDOMUtils::GetRuleNodeForElement(dom::Element* aElement,
|
|
nsIAtom* aPseudo,
|
|
nsStyleContext** aStyleContext,
|
|
nsRuleNode** aRuleNode)
|
|
{
|
|
MOZ_ASSERT(aElement);
|
|
|
|
*aRuleNode = nullptr;
|
|
*aStyleContext = nullptr;
|
|
|
|
nsIDocument* doc = aElement->GetComposedDoc();
|
|
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
|
|
|
|
nsIPresShell *presShell = doc->GetShell();
|
|
NS_ENSURE_TRUE(presShell, NS_ERROR_UNEXPECTED);
|
|
|
|
nsPresContext *presContext = presShell->GetPresContext();
|
|
NS_ENSURE_TRUE(presContext, NS_ERROR_UNEXPECTED);
|
|
|
|
presContext->EnsureSafeToHandOutCSSRules();
|
|
|
|
RefPtr<nsStyleContext> sContext =
|
|
nsComputedDOMStyle::GetStyleContextForElement(aElement, aPseudo, presShell);
|
|
if (sContext) {
|
|
*aRuleNode = sContext->RuleNode();
|
|
sContext.forget(aStyleContext);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
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");
|
|
|
|
nsCOMPtr<nsIAtom> 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<nsIAtom*> 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)) {
|
|
nsIAtom* 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)
|
|
{
|
|
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);
|
|
|
|
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();
|
|
|
|
*_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> sheet = do_QueryObject(aSheet);
|
|
NS_ENSURE_ARG_POINTER(sheet);
|
|
|
|
return sheet->ReparseSheet(aInput);
|
|
}
|
|
|
|
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;
|
|
}
|