layout/inspector/inDOMUtils.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "mozilla/ArrayUtils.h"
michael@0 7 #include "mozilla/EventStates.h"
michael@0 8
michael@0 9 #include "inDOMUtils.h"
michael@0 10 #include "inLayoutUtils.h"
michael@0 11
michael@0 12 #include "nsIServiceManager.h"
michael@0 13 #include "nsISupportsArray.h"
michael@0 14 #include "nsString.h"
michael@0 15 #include "nsIDOMElement.h"
michael@0 16 #include "nsIDocument.h"
michael@0 17 #include "nsIPresShell.h"
michael@0 18 #include "nsIDOMDocument.h"
michael@0 19 #include "nsIDOMCharacterData.h"
michael@0 20 #include "nsRuleNode.h"
michael@0 21 #include "nsIStyleRule.h"
michael@0 22 #include "mozilla/css/StyleRule.h"
michael@0 23 #include "nsICSSStyleRuleDOMWrapper.h"
michael@0 24 #include "nsIDOMWindow.h"
michael@0 25 #include "nsXBLBinding.h"
michael@0 26 #include "nsXBLPrototypeBinding.h"
michael@0 27 #include "nsIMutableArray.h"
michael@0 28 #include "nsBindingManager.h"
michael@0 29 #include "ChildIterator.h"
michael@0 30 #include "nsComputedDOMStyle.h"
michael@0 31 #include "mozilla/EventStateManager.h"
michael@0 32 #include "nsIAtom.h"
michael@0 33 #include "nsRange.h"
michael@0 34 #include "nsContentList.h"
michael@0 35 #include "mozilla/dom/Element.h"
michael@0 36 #include "nsCSSStyleSheet.h"
michael@0 37 #include "nsRuleWalker.h"
michael@0 38 #include "nsRuleProcessorData.h"
michael@0 39 #include "nsCSSRuleProcessor.h"
michael@0 40 #include "mozilla/dom/InspectorUtilsBinding.h"
michael@0 41 #include "nsCSSProps.h"
michael@0 42 #include "nsColor.h"
michael@0 43 #include "nsStyleSet.h"
michael@0 44
michael@0 45 using namespace mozilla;
michael@0 46 using namespace mozilla::css;
michael@0 47 using namespace mozilla::dom;
michael@0 48
michael@0 49 ///////////////////////////////////////////////////////////////////////////////
michael@0 50
michael@0 51 inDOMUtils::inDOMUtils()
michael@0 52 {
michael@0 53 }
michael@0 54
michael@0 55 inDOMUtils::~inDOMUtils()
michael@0 56 {
michael@0 57 }
michael@0 58
michael@0 59 NS_IMPL_ISUPPORTS(inDOMUtils, inIDOMUtils)
michael@0 60
michael@0 61 ///////////////////////////////////////////////////////////////////////////////
michael@0 62 // inIDOMUtils
michael@0 63
michael@0 64 NS_IMETHODIMP
michael@0 65 inDOMUtils::GetAllStyleSheets(nsIDOMDocument *aDocument, uint32_t *aLength,
michael@0 66 nsISupports ***aSheets)
michael@0 67 {
michael@0 68 NS_ENSURE_ARG_POINTER(aDocument);
michael@0 69
michael@0 70 nsCOMArray<nsISupports> sheets;
michael@0 71
michael@0 72 nsCOMPtr<nsIDocument> document = do_QueryInterface(aDocument);
michael@0 73 MOZ_ASSERT(document);
michael@0 74
michael@0 75 // Get the agent, then user sheets in the style set.
michael@0 76 nsIPresShell* presShell = document->GetShell();
michael@0 77 if (presShell) {
michael@0 78 nsStyleSet* styleSet = presShell->StyleSet();
michael@0 79 nsStyleSet::sheetType sheetType = nsStyleSet::eAgentSheet;
michael@0 80 for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
michael@0 81 sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
michael@0 82 }
michael@0 83 sheetType = nsStyleSet::eUserSheet;
michael@0 84 for (int32_t i = 0; i < styleSet->SheetCount(sheetType); i++) {
michael@0 85 sheets.AppendElement(styleSet->StyleSheetAt(sheetType, i));
michael@0 86 }
michael@0 87 }
michael@0 88
michael@0 89 // Get the document sheets.
michael@0 90 for (int32_t i = 0; i < document->GetNumberOfStyleSheets(); i++) {
michael@0 91 sheets.AppendElement(document->GetStyleSheetAt(i));
michael@0 92 }
michael@0 93
michael@0 94 nsISupports** ret = static_cast<nsISupports**>(NS_Alloc(sheets.Count() *
michael@0 95 sizeof(nsISupports*)));
michael@0 96
michael@0 97 for (int32_t i = 0; i < sheets.Count(); i++) {
michael@0 98 NS_ADDREF(ret[i] = sheets[i]);
michael@0 99 }
michael@0 100
michael@0 101 *aLength = sheets.Count();
michael@0 102 *aSheets = ret;
michael@0 103
michael@0 104 return NS_OK;
michael@0 105 }
michael@0 106
michael@0 107 NS_IMETHODIMP
michael@0 108 inDOMUtils::IsIgnorableWhitespace(nsIDOMCharacterData *aDataNode,
michael@0 109 bool *aReturn)
michael@0 110 {
michael@0 111 NS_PRECONDITION(aReturn, "Must have an out parameter");
michael@0 112
michael@0 113 NS_ENSURE_ARG_POINTER(aDataNode);
michael@0 114
michael@0 115 *aReturn = false;
michael@0 116
michael@0 117 nsCOMPtr<nsIContent> content = do_QueryInterface(aDataNode);
michael@0 118 NS_ASSERTION(content, "Does not implement nsIContent!");
michael@0 119
michael@0 120 if (!content->TextIsOnlyWhitespace()) {
michael@0 121 return NS_OK;
michael@0 122 }
michael@0 123
michael@0 124 // Okay. We have only white space. Let's check the white-space
michael@0 125 // property now and make sure that this isn't preformatted text...
michael@0 126 nsIFrame* frame = content->GetPrimaryFrame();
michael@0 127 if (frame) {
michael@0 128 const nsStyleText* text = frame->StyleText();
michael@0 129 *aReturn = !text->WhiteSpaceIsSignificant();
michael@0 130 }
michael@0 131 else {
michael@0 132 // empty inter-tag text node without frame, e.g., in between <table>\n<tr>
michael@0 133 *aReturn = true;
michael@0 134 }
michael@0 135
michael@0 136 return NS_OK;
michael@0 137 }
michael@0 138
michael@0 139 NS_IMETHODIMP
michael@0 140 inDOMUtils::GetParentForNode(nsIDOMNode* aNode,
michael@0 141 bool aShowingAnonymousContent,
michael@0 142 nsIDOMNode** aParent)
michael@0 143 {
michael@0 144 NS_ENSURE_ARG_POINTER(aNode);
michael@0 145
michael@0 146 // First do the special cases -- document nodes and anonymous content
michael@0 147 nsCOMPtr<nsIDocument> doc(do_QueryInterface(aNode));
michael@0 148 nsCOMPtr<nsIDOMNode> parent;
michael@0 149
michael@0 150 if (doc) {
michael@0 151 parent = inLayoutUtils::GetContainerFor(*doc);
michael@0 152 } else if (aShowingAnonymousContent) {
michael@0 153 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
michael@0 154 if (content) {
michael@0 155 nsIContent* bparent = content->GetXBLInsertionParent();
michael@0 156 parent = do_QueryInterface(bparent);
michael@0 157 }
michael@0 158 }
michael@0 159
michael@0 160 if (!parent) {
michael@0 161 // Ok, just get the normal DOM parent node
michael@0 162 aNode->GetParentNode(getter_AddRefs(parent));
michael@0 163 }
michael@0 164
michael@0 165 NS_IF_ADDREF(*aParent = parent);
michael@0 166 return NS_OK;
michael@0 167 }
michael@0 168
michael@0 169 NS_IMETHODIMP
michael@0 170 inDOMUtils::GetChildrenForNode(nsIDOMNode* aNode,
michael@0 171 bool aShowingAnonymousContent,
michael@0 172 nsIDOMNodeList** aChildren)
michael@0 173 {
michael@0 174 NS_ENSURE_ARG_POINTER(aNode);
michael@0 175 NS_PRECONDITION(aChildren, "Must have an out parameter");
michael@0 176
michael@0 177 nsCOMPtr<nsIDOMNodeList> kids;
michael@0 178
michael@0 179 if (aShowingAnonymousContent) {
michael@0 180 nsCOMPtr<nsIContent> content = do_QueryInterface(aNode);
michael@0 181 if (content) {
michael@0 182 kids = content->GetChildren(nsIContent::eAllChildren);
michael@0 183 }
michael@0 184 }
michael@0 185
michael@0 186 if (!kids) {
michael@0 187 aNode->GetChildNodes(getter_AddRefs(kids));
michael@0 188 }
michael@0 189
michael@0 190 kids.forget(aChildren);
michael@0 191 return NS_OK;
michael@0 192 }
michael@0 193
michael@0 194 NS_IMETHODIMP
michael@0 195 inDOMUtils::GetCSSStyleRules(nsIDOMElement *aElement,
michael@0 196 const nsAString& aPseudo,
michael@0 197 nsISupportsArray **_retval)
michael@0 198 {
michael@0 199 NS_ENSURE_ARG_POINTER(aElement);
michael@0 200
michael@0 201 *_retval = nullptr;
michael@0 202
michael@0 203 nsCOMPtr<nsIAtom> pseudoElt;
michael@0 204 if (!aPseudo.IsEmpty()) {
michael@0 205 pseudoElt = do_GetAtom(aPseudo);
michael@0 206 }
michael@0 207
michael@0 208 nsRuleNode* ruleNode = nullptr;
michael@0 209 nsCOMPtr<Element> element = do_QueryInterface(aElement);
michael@0 210 NS_ENSURE_STATE(element);
michael@0 211 nsRefPtr<nsStyleContext> styleContext;
michael@0 212 GetRuleNodeForElement(element, pseudoElt, getter_AddRefs(styleContext), &ruleNode);
michael@0 213 if (!ruleNode) {
michael@0 214 // This can fail for elements that are not in the document or
michael@0 215 // if the document they're in doesn't have a presshell. Bail out.
michael@0 216 return NS_OK;
michael@0 217 }
michael@0 218
michael@0 219 nsCOMPtr<nsISupportsArray> rules;
michael@0 220 NS_NewISupportsArray(getter_AddRefs(rules));
michael@0 221 if (!rules) return NS_ERROR_OUT_OF_MEMORY;
michael@0 222
michael@0 223 nsRefPtr<mozilla::css::StyleRule> cssRule;
michael@0 224 for ( ; !ruleNode->IsRoot(); ruleNode = ruleNode->GetParent()) {
michael@0 225 cssRule = do_QueryObject(ruleNode->GetRule());
michael@0 226 if (cssRule) {
michael@0 227 nsCOMPtr<nsIDOMCSSRule> domRule = cssRule->GetDOMRule();
michael@0 228 if (domRule)
michael@0 229 rules->InsertElementAt(domRule, 0);
michael@0 230 }
michael@0 231 }
michael@0 232
michael@0 233 *_retval = rules;
michael@0 234 NS_ADDREF(*_retval);
michael@0 235
michael@0 236 return NS_OK;
michael@0 237 }
michael@0 238
michael@0 239 static already_AddRefed<StyleRule>
michael@0 240 GetRuleFromDOMRule(nsIDOMCSSStyleRule *aRule, ErrorResult& rv)
michael@0 241 {
michael@0 242 nsCOMPtr<nsICSSStyleRuleDOMWrapper> rule = do_QueryInterface(aRule);
michael@0 243 if (!rule) {
michael@0 244 rv.Throw(NS_ERROR_INVALID_POINTER);
michael@0 245 return nullptr;
michael@0 246 }
michael@0 247
michael@0 248 nsRefPtr<StyleRule> cssrule;
michael@0 249 rv = rule->GetCSSStyleRule(getter_AddRefs(cssrule));
michael@0 250 if (rv.Failed()) {
michael@0 251 return nullptr;
michael@0 252 }
michael@0 253
michael@0 254 if (!cssrule) {
michael@0 255 rv.Throw(NS_ERROR_FAILURE);
michael@0 256 }
michael@0 257 return cssrule.forget();
michael@0 258 }
michael@0 259
michael@0 260 NS_IMETHODIMP
michael@0 261 inDOMUtils::GetRuleLine(nsIDOMCSSStyleRule *aRule, uint32_t *_retval)
michael@0 262 {
michael@0 263 ErrorResult rv;
michael@0 264 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
michael@0 265 if (rv.Failed()) {
michael@0 266 return rv.ErrorCode();
michael@0 267 }
michael@0 268
michael@0 269 *_retval = rule->GetLineNumber();
michael@0 270 return NS_OK;
michael@0 271 }
michael@0 272
michael@0 273 NS_IMETHODIMP
michael@0 274 inDOMUtils::GetRuleColumn(nsIDOMCSSStyleRule *aRule, uint32_t *_retval)
michael@0 275 {
michael@0 276 ErrorResult rv;
michael@0 277 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
michael@0 278 if (rv.Failed()) {
michael@0 279 return rv.ErrorCode();
michael@0 280 }
michael@0 281 *_retval = rule->GetColumnNumber();
michael@0 282 return NS_OK;
michael@0 283 }
michael@0 284
michael@0 285 NS_IMETHODIMP
michael@0 286 inDOMUtils::GetSelectorCount(nsIDOMCSSStyleRule* aRule, uint32_t *aCount)
michael@0 287 {
michael@0 288 ErrorResult rv;
michael@0 289 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
michael@0 290 if (rv.Failed()) {
michael@0 291 return rv.ErrorCode();
michael@0 292 }
michael@0 293
michael@0 294 uint32_t count = 0;
michael@0 295 for (nsCSSSelectorList* sel = rule->Selector(); sel; sel = sel->mNext) {
michael@0 296 ++count;
michael@0 297 }
michael@0 298 *aCount = count;
michael@0 299 return NS_OK;
michael@0 300 }
michael@0 301
michael@0 302 static nsCSSSelectorList*
michael@0 303 GetSelectorAtIndex(nsIDOMCSSStyleRule* aRule, uint32_t aIndex, ErrorResult& rv)
michael@0 304 {
michael@0 305 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
michael@0 306 if (rv.Failed()) {
michael@0 307 return nullptr;
michael@0 308 }
michael@0 309
michael@0 310 for (nsCSSSelectorList* sel = rule->Selector(); sel;
michael@0 311 sel = sel->mNext, --aIndex) {
michael@0 312 if (aIndex == 0) {
michael@0 313 return sel;
michael@0 314 }
michael@0 315 }
michael@0 316
michael@0 317 // Ran out of selectors
michael@0 318 rv.Throw(NS_ERROR_INVALID_ARG);
michael@0 319 return nullptr;
michael@0 320 }
michael@0 321
michael@0 322 NS_IMETHODIMP
michael@0 323 inDOMUtils::GetSelectorText(nsIDOMCSSStyleRule* aRule,
michael@0 324 uint32_t aSelectorIndex,
michael@0 325 nsAString& aText)
michael@0 326 {
michael@0 327 ErrorResult rv;
michael@0 328 nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
michael@0 329 if (rv.Failed()) {
michael@0 330 return rv.ErrorCode();
michael@0 331 }
michael@0 332
michael@0 333 nsRefPtr<StyleRule> rule = GetRuleFromDOMRule(aRule, rv);
michael@0 334 MOZ_ASSERT(!rv.Failed(), "How could we get a selector but not a rule?");
michael@0 335
michael@0 336 sel->mSelectors->ToString(aText, rule->GetStyleSheet(), false);
michael@0 337 return NS_OK;
michael@0 338 }
michael@0 339
michael@0 340 NS_IMETHODIMP
michael@0 341 inDOMUtils::GetSpecificity(nsIDOMCSSStyleRule* aRule,
michael@0 342 uint32_t aSelectorIndex,
michael@0 343 uint64_t* aSpecificity)
michael@0 344 {
michael@0 345 ErrorResult rv;
michael@0 346 nsCSSSelectorList* sel = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
michael@0 347 if (rv.Failed()) {
michael@0 348 return rv.ErrorCode();
michael@0 349 }
michael@0 350
michael@0 351 *aSpecificity = sel->mWeight;
michael@0 352 return NS_OK;
michael@0 353 }
michael@0 354
michael@0 355 NS_IMETHODIMP
michael@0 356 inDOMUtils::SelectorMatchesElement(nsIDOMElement* aElement,
michael@0 357 nsIDOMCSSStyleRule* aRule,
michael@0 358 uint32_t aSelectorIndex,
michael@0 359 bool* aMatches)
michael@0 360 {
michael@0 361 nsCOMPtr<Element> element = do_QueryInterface(aElement);
michael@0 362 NS_ENSURE_ARG_POINTER(element);
michael@0 363
michael@0 364 ErrorResult rv;
michael@0 365 nsCSSSelectorList* tail = GetSelectorAtIndex(aRule, aSelectorIndex, rv);
michael@0 366 if (rv.Failed()) {
michael@0 367 return rv.ErrorCode();
michael@0 368 }
michael@0 369
michael@0 370 // We want just the one list item, not the whole list tail
michael@0 371 nsAutoPtr<nsCSSSelectorList> sel(tail->Clone(false));
michael@0 372
michael@0 373 // SelectorListMatches does not handle selectors that begin with a
michael@0 374 // pseudo-element, which you can get from selectors like
michael@0 375 // |input::-moz-placeholder:hover|. This function doesn't take
michael@0 376 // a pseudo-element nsIAtom*, so we know we can't match.
michael@0 377 if (sel->mSelectors->IsPseudoElement()) {
michael@0 378 *aMatches = false;
michael@0 379 return NS_OK;
michael@0 380 }
michael@0 381
michael@0 382 element->OwnerDoc()->FlushPendingLinkUpdates();
michael@0 383 // XXXbz what exactly should we do with visited state here?
michael@0 384 TreeMatchContext matchingContext(false,
michael@0 385 nsRuleWalker::eRelevantLinkUnvisited,
michael@0 386 element->OwnerDoc(),
michael@0 387 TreeMatchContext::eNeverMatchVisited);
michael@0 388 *aMatches = nsCSSRuleProcessor::SelectorListMatches(element, matchingContext,
michael@0 389 sel);
michael@0 390 return NS_OK;
michael@0 391 }
michael@0 392
michael@0 393 NS_IMETHODIMP
michael@0 394 inDOMUtils::IsInheritedProperty(const nsAString &aPropertyName, bool *_retval)
michael@0 395 {
michael@0 396 nsCSSProperty prop =
michael@0 397 nsCSSProps::LookupProperty(aPropertyName, nsCSSProps::eIgnoreEnabledState);
michael@0 398 if (prop == eCSSProperty_UNKNOWN) {
michael@0 399 *_retval = false;
michael@0 400 return NS_OK;
michael@0 401 }
michael@0 402
michael@0 403 if (prop == eCSSPropertyExtra_variable) {
michael@0 404 *_retval = true;
michael@0 405 return NS_OK;
michael@0 406 }
michael@0 407
michael@0 408 if (nsCSSProps::IsShorthand(prop)) {
michael@0 409 prop = nsCSSProps::SubpropertyEntryFor(prop)[0];
michael@0 410 }
michael@0 411
michael@0 412 nsStyleStructID sid = nsCSSProps::kSIDTable[prop];
michael@0 413 *_retval = !nsCachedStyleData::IsReset(sid);
michael@0 414 return NS_OK;
michael@0 415 }
michael@0 416
michael@0 417 extern const char* const kCSSRawProperties[];
michael@0 418
michael@0 419 NS_IMETHODIMP
michael@0 420 inDOMUtils::GetCSSPropertyNames(uint32_t aFlags, uint32_t* aCount,
michael@0 421 char16_t*** aProps)
michael@0 422 {
michael@0 423 // maxCount is the largest number of properties we could have; our actual
michael@0 424 // number might be smaller because properties might be disabled.
michael@0 425 uint32_t maxCount;
michael@0 426 if (aFlags & EXCLUDE_SHORTHANDS) {
michael@0 427 maxCount = eCSSProperty_COUNT_no_shorthands;
michael@0 428 } else {
michael@0 429 maxCount = eCSSProperty_COUNT;
michael@0 430 }
michael@0 431
michael@0 432 if (aFlags & INCLUDE_ALIASES) {
michael@0 433 maxCount += (eCSSProperty_COUNT_with_aliases - eCSSProperty_COUNT);
michael@0 434 }
michael@0 435
michael@0 436 char16_t** props =
michael@0 437 static_cast<char16_t**>(nsMemory::Alloc(maxCount * sizeof(char16_t*)));
michael@0 438
michael@0 439 #define DO_PROP(_prop) \
michael@0 440 PR_BEGIN_MACRO \
michael@0 441 nsCSSProperty cssProp = nsCSSProperty(_prop); \
michael@0 442 if (nsCSSProps::IsEnabled(cssProp)) { \
michael@0 443 props[propCount] = \
michael@0 444 ToNewUnicode(nsDependentCString(kCSSRawProperties[_prop])); \
michael@0 445 ++propCount; \
michael@0 446 } \
michael@0 447 PR_END_MACRO
michael@0 448
michael@0 449 // prop is the property id we're considering; propCount is how many properties
michael@0 450 // we've put into props so far.
michael@0 451 uint32_t prop = 0, propCount = 0;
michael@0 452 for ( ; prop < eCSSProperty_COUNT_no_shorthands; ++prop) {
michael@0 453 if (nsCSSProps::PropertyParseType(nsCSSProperty(prop)) !=
michael@0 454 CSS_PROPERTY_PARSE_INACCESSIBLE) {
michael@0 455 DO_PROP(prop);
michael@0 456 }
michael@0 457 }
michael@0 458
michael@0 459 if (!(aFlags & EXCLUDE_SHORTHANDS)) {
michael@0 460 for ( ; prop < eCSSProperty_COUNT; ++prop) {
michael@0 461 // Some shorthands are also aliases
michael@0 462 if ((aFlags & INCLUDE_ALIASES) ||
michael@0 463 !nsCSSProps::PropHasFlags(nsCSSProperty(prop),
michael@0 464 CSS_PROPERTY_IS_ALIAS)) {
michael@0 465 DO_PROP(prop);
michael@0 466 }
michael@0 467 }
michael@0 468 }
michael@0 469
michael@0 470 if (aFlags & INCLUDE_ALIASES) {
michael@0 471 for (prop = eCSSProperty_COUNT; prop < eCSSProperty_COUNT_with_aliases; ++prop) {
michael@0 472 DO_PROP(prop);
michael@0 473 }
michael@0 474 }
michael@0 475
michael@0 476 #undef DO_PROP
michael@0 477
michael@0 478 *aCount = propCount;
michael@0 479 *aProps = props;
michael@0 480
michael@0 481 return NS_OK;
michael@0 482 }
michael@0 483
michael@0 484 static void InsertNoDuplicates(nsTArray<nsString>& aArray,
michael@0 485 const nsAString& aString)
michael@0 486 {
michael@0 487 size_t i = aArray.IndexOfFirstElementGt(aString);
michael@0 488 if (i > 0 && aArray[i-1].Equals(aString)) {
michael@0 489 return;
michael@0 490 }
michael@0 491 aArray.InsertElementAt(i, aString);
michael@0 492 }
michael@0 493
michael@0 494 static void GetKeywordsForProperty(const nsCSSProperty aProperty,
michael@0 495 nsTArray<nsString>& aArray)
michael@0 496 {
michael@0 497 if (nsCSSProps::IsShorthand(aProperty)) {
michael@0 498 // Shorthand props have no keywords.
michael@0 499 return;
michael@0 500 }
michael@0 501 const nsCSSProps::KTableValue *keywordTable =
michael@0 502 nsCSSProps::kKeywordTableTable[aProperty];
michael@0 503 if (keywordTable && keywordTable != nsCSSProps::kBoxPropSourceKTable) {
michael@0 504 size_t i = 0;
michael@0 505 while (nsCSSKeyword(keywordTable[i]) != eCSSKeyword_UNKNOWN) {
michael@0 506 nsCSSKeyword word = nsCSSKeyword(keywordTable[i]);
michael@0 507 InsertNoDuplicates(aArray,
michael@0 508 NS_ConvertASCIItoUTF16(nsCSSKeywords::GetStringValue(word)));
michael@0 509 // Increment counter by 2, because in this table every second
michael@0 510 // element is a nsCSSKeyword.
michael@0 511 i += 2;
michael@0 512 }
michael@0 513 }
michael@0 514 }
michael@0 515
michael@0 516 static void GetColorsForProperty(const uint32_t aParserVariant,
michael@0 517 nsTArray<nsString>& aArray)
michael@0 518 {
michael@0 519 if (aParserVariant & VARIANT_COLOR) {
michael@0 520 // GetKeywordsForProperty and GetOtherValuesForProperty assume aArray is sorted,
michael@0 521 // and if aArray is not empty here, then it's not going to be sorted coming out.
michael@0 522 MOZ_ASSERT(aArray.Length() == 0);
michael@0 523 size_t size;
michael@0 524 const char * const *allColorNames = NS_AllColorNames(&size);
michael@0 525 for (size_t i = 0; i < size; i++) {
michael@0 526 CopyASCIItoUTF16(allColorNames[i], *aArray.AppendElement());
michael@0 527 }
michael@0 528 }
michael@0 529 return;
michael@0 530 }
michael@0 531
michael@0 532 static void GetOtherValuesForProperty(const uint32_t aParserVariant,
michael@0 533 nsTArray<nsString>& aArray)
michael@0 534 {
michael@0 535 if (aParserVariant & VARIANT_AUTO) {
michael@0 536 InsertNoDuplicates(aArray, NS_LITERAL_STRING("auto"));
michael@0 537 }
michael@0 538 if (aParserVariant & VARIANT_NORMAL) {
michael@0 539 InsertNoDuplicates(aArray, NS_LITERAL_STRING("normal"));
michael@0 540 }
michael@0 541 if(aParserVariant & VARIANT_ALL) {
michael@0 542 InsertNoDuplicates(aArray, NS_LITERAL_STRING("all"));
michael@0 543 }
michael@0 544 if (aParserVariant & VARIANT_NONE) {
michael@0 545 InsertNoDuplicates(aArray, NS_LITERAL_STRING("none"));
michael@0 546 }
michael@0 547 if (aParserVariant & VARIANT_ELEMENT) {
michael@0 548 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-element"));
michael@0 549 }
michael@0 550 if (aParserVariant & VARIANT_IMAGE_RECT) {
michael@0 551 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-image-rect"));
michael@0 552 }
michael@0 553 if (aParserVariant & VARIANT_COLOR) {
michael@0 554 InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgb"));
michael@0 555 InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsl"));
michael@0 556 InsertNoDuplicates(aArray, NS_LITERAL_STRING("rgba"));
michael@0 557 InsertNoDuplicates(aArray, NS_LITERAL_STRING("hsla"));
michael@0 558 }
michael@0 559 if (aParserVariant & VARIANT_TIMING_FUNCTION) {
michael@0 560 InsertNoDuplicates(aArray, NS_LITERAL_STRING("cubic-bezier"));
michael@0 561 InsertNoDuplicates(aArray, NS_LITERAL_STRING("steps"));
michael@0 562 }
michael@0 563 if (aParserVariant & VARIANT_CALC) {
michael@0 564 InsertNoDuplicates(aArray, NS_LITERAL_STRING("calc"));
michael@0 565 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-calc"));
michael@0 566 }
michael@0 567 if (aParserVariant & VARIANT_URL) {
michael@0 568 InsertNoDuplicates(aArray, NS_LITERAL_STRING("url"));
michael@0 569 }
michael@0 570 if (aParserVariant & VARIANT_GRADIENT) {
michael@0 571 InsertNoDuplicates(aArray, NS_LITERAL_STRING("linear-gradient"));
michael@0 572 InsertNoDuplicates(aArray, NS_LITERAL_STRING("radial-gradient"));
michael@0 573 InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-linear-gradient"));
michael@0 574 InsertNoDuplicates(aArray, NS_LITERAL_STRING("repeating-radial-gradient"));
michael@0 575 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-linear-gradient"));
michael@0 576 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-radial-gradient"));
michael@0 577 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-linear-gradient"));
michael@0 578 InsertNoDuplicates(aArray, NS_LITERAL_STRING("-moz-repeating-radial-gradient"));
michael@0 579 }
michael@0 580 }
michael@0 581
michael@0 582 NS_IMETHODIMP
michael@0 583 inDOMUtils::GetCSSValuesForProperty(const nsAString& aProperty,
michael@0 584 uint32_t* aLength,
michael@0 585 char16_t*** aValues)
michael@0 586 {
michael@0 587 nsCSSProperty propertyID = nsCSSProps::LookupProperty(aProperty,
michael@0 588 nsCSSProps::eEnabledForAllContent);
michael@0 589 if (propertyID == eCSSProperty_UNKNOWN) {
michael@0 590 return NS_ERROR_FAILURE;
michael@0 591 }
michael@0 592
michael@0 593 nsTArray<nsString> array;
michael@0 594 // We start collecting the values, BUT colors need to go in first, because array
michael@0 595 // needs to stay sorted, and the colors are sorted, so we just append them.
michael@0 596 if (propertyID == eCSSPropertyExtra_variable) {
michael@0 597 // No other values we can report.
michael@0 598 } else if (!nsCSSProps::IsShorthand(propertyID)) {
michael@0 599 // Property is longhand.
michael@0 600 uint32_t propertyParserVariant = nsCSSProps::ParserVariant(propertyID);
michael@0 601 // Get colors first.
michael@0 602 GetColorsForProperty(propertyParserVariant, array);
michael@0 603 if (propertyParserVariant & VARIANT_KEYWORD) {
michael@0 604 GetKeywordsForProperty(propertyID, array);
michael@0 605 }
michael@0 606 GetOtherValuesForProperty(propertyParserVariant, array);
michael@0 607 } else {
michael@0 608 // Property is shorthand.
michael@0 609 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) {
michael@0 610 // Get colors (once) first.
michael@0 611 uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
michael@0 612 if (propertyParserVariant & VARIANT_COLOR) {
michael@0 613 GetColorsForProperty(propertyParserVariant, array);
michael@0 614 break;
michael@0 615 }
michael@0 616 }
michael@0 617 CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(subproperty, propertyID) {
michael@0 618 uint32_t propertyParserVariant = nsCSSProps::ParserVariant(*subproperty);
michael@0 619 if (propertyParserVariant & VARIANT_KEYWORD) {
michael@0 620 GetKeywordsForProperty(*subproperty, array);
michael@0 621 }
michael@0 622 GetOtherValuesForProperty(propertyParserVariant, array);
michael@0 623 }
michael@0 624 }
michael@0 625 // All CSS properties take initial, inherit and unset.
michael@0 626 InsertNoDuplicates(array, NS_LITERAL_STRING("initial"));
michael@0 627 InsertNoDuplicates(array, NS_LITERAL_STRING("inherit"));
michael@0 628 InsertNoDuplicates(array, NS_LITERAL_STRING("unset"));
michael@0 629
michael@0 630 *aLength = array.Length();
michael@0 631 char16_t** ret =
michael@0 632 static_cast<char16_t**>(NS_Alloc(*aLength * sizeof(char16_t*)));
michael@0 633 for (uint32_t i = 0; i < *aLength; ++i) {
michael@0 634 ret[i] = ToNewUnicode(array[i]);
michael@0 635 }
michael@0 636 *aValues = ret;
michael@0 637 return NS_OK;
michael@0 638 }
michael@0 639
michael@0 640 NS_IMETHODIMP
michael@0 641 inDOMUtils::ColorNameToRGB(const nsAString& aColorName, JSContext* aCx,
michael@0 642 JS::MutableHandle<JS::Value> aValue)
michael@0 643 {
michael@0 644 nscolor color;
michael@0 645 if (!NS_ColorNameToRGB(aColorName, &color)) {
michael@0 646 return NS_ERROR_INVALID_ARG;
michael@0 647 }
michael@0 648
michael@0 649 InspectorRGBTriple triple;
michael@0 650 triple.mR = NS_GET_R(color);
michael@0 651 triple.mG = NS_GET_G(color);
michael@0 652 triple.mB = NS_GET_B(color);
michael@0 653
michael@0 654 if (!triple.ToObject(aCx, aValue)) {
michael@0 655 return NS_ERROR_FAILURE;
michael@0 656 }
michael@0 657
michael@0 658 return NS_OK;
michael@0 659 }
michael@0 660
michael@0 661 NS_IMETHODIMP
michael@0 662 inDOMUtils::RgbToColorName(uint8_t aR, uint8_t aG, uint8_t aB,
michael@0 663 nsAString& aColorName)
michael@0 664 {
michael@0 665 const char* color = NS_RGBToColorName(NS_RGB(aR, aG, aB));
michael@0 666 if (!color) {
michael@0 667 aColorName.Truncate();
michael@0 668 return NS_ERROR_INVALID_ARG;
michael@0 669 }
michael@0 670
michael@0 671 aColorName.AssignASCII(color);
michael@0 672 return NS_OK;
michael@0 673 }
michael@0 674
michael@0 675 NS_IMETHODIMP
michael@0 676 inDOMUtils::GetBindingURLs(nsIDOMElement *aElement, nsIArray **_retval)
michael@0 677 {
michael@0 678 NS_ENSURE_ARG_POINTER(aElement);
michael@0 679
michael@0 680 *_retval = nullptr;
michael@0 681
michael@0 682 nsCOMPtr<nsIMutableArray> urls = do_CreateInstance(NS_ARRAY_CONTRACTID);
michael@0 683 if (!urls)
michael@0 684 return NS_ERROR_FAILURE;
michael@0 685
michael@0 686 nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
michael@0 687 NS_ENSURE_ARG_POINTER(content);
michael@0 688
michael@0 689 nsXBLBinding *binding = content->GetXBLBinding();
michael@0 690
michael@0 691 while (binding) {
michael@0 692 urls->AppendElement(binding->PrototypeBinding()->BindingURI(), false);
michael@0 693 binding = binding->GetBaseBinding();
michael@0 694 }
michael@0 695
michael@0 696 NS_ADDREF(*_retval = urls);
michael@0 697 return NS_OK;
michael@0 698 }
michael@0 699
michael@0 700 NS_IMETHODIMP
michael@0 701 inDOMUtils::SetContentState(nsIDOMElement* aElement,
michael@0 702 EventStates::InternalType aState)
michael@0 703 {
michael@0 704 NS_ENSURE_ARG_POINTER(aElement);
michael@0 705
michael@0 706 nsRefPtr<EventStateManager> esm =
michael@0 707 inLayoutUtils::GetEventStateManagerFor(aElement);
michael@0 708 if (esm) {
michael@0 709 nsCOMPtr<nsIContent> content;
michael@0 710 content = do_QueryInterface(aElement);
michael@0 711
michael@0 712 // XXX Invalid cast of bool to nsresult (bug 778108)
michael@0 713 return (nsresult)esm->SetContentState(content, EventStates(aState));
michael@0 714 }
michael@0 715
michael@0 716 return NS_ERROR_FAILURE;
michael@0 717 }
michael@0 718
michael@0 719 NS_IMETHODIMP
michael@0 720 inDOMUtils::GetContentState(nsIDOMElement* aElement,
michael@0 721 EventStates::InternalType* aState)
michael@0 722 {
michael@0 723 *aState = 0;
michael@0 724 nsCOMPtr<nsIContent> content = do_QueryInterface(aElement);
michael@0 725 NS_ENSURE_ARG_POINTER(content);
michael@0 726
michael@0 727 // NOTE: if this method is removed,
michael@0 728 // please remove GetInternalValue from EventStates
michael@0 729 *aState = content->AsElement()->State().GetInternalValue();
michael@0 730 return NS_OK;
michael@0 731 }
michael@0 732
michael@0 733 /* static */ nsresult
michael@0 734 inDOMUtils::GetRuleNodeForElement(dom::Element* aElement,
michael@0 735 nsIAtom* aPseudo,
michael@0 736 nsStyleContext** aStyleContext,
michael@0 737 nsRuleNode** aRuleNode)
michael@0 738 {
michael@0 739 MOZ_ASSERT(aElement);
michael@0 740
michael@0 741 *aRuleNode = nullptr;
michael@0 742 *aStyleContext = nullptr;
michael@0 743
michael@0 744 nsIDocument* doc = aElement->GetDocument();
michael@0 745 NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
michael@0 746
michael@0 747 nsIPresShell *presShell = doc->GetShell();
michael@0 748 NS_ENSURE_TRUE(presShell, NS_ERROR_UNEXPECTED);
michael@0 749
michael@0 750 nsPresContext *presContext = presShell->GetPresContext();
michael@0 751 NS_ENSURE_TRUE(presContext, NS_ERROR_UNEXPECTED);
michael@0 752
michael@0 753 presContext->EnsureSafeToHandOutCSSRules();
michael@0 754
michael@0 755 nsRefPtr<nsStyleContext> sContext =
michael@0 756 nsComputedDOMStyle::GetStyleContextForElement(aElement, aPseudo, presShell);
michael@0 757 if (sContext) {
michael@0 758 *aRuleNode = sContext->RuleNode();
michael@0 759 sContext.forget(aStyleContext);
michael@0 760 }
michael@0 761 return NS_OK;
michael@0 762 }
michael@0 763
michael@0 764 NS_IMETHODIMP
michael@0 765 inDOMUtils::GetUsedFontFaces(nsIDOMRange* aRange,
michael@0 766 nsIDOMFontFaceList** aFontFaceList)
michael@0 767 {
michael@0 768 return static_cast<nsRange*>(aRange)->GetUsedFontFaces(aFontFaceList);
michael@0 769 }
michael@0 770
michael@0 771 static EventStates
michael@0 772 GetStatesForPseudoClass(const nsAString& aStatePseudo)
michael@0 773 {
michael@0 774 // An array of the states that are relevant for various pseudoclasses.
michael@0 775 // XXXbz this duplicates code in nsCSSRuleProcessor
michael@0 776 static const EventStates sPseudoClassStates[] = {
michael@0 777 #define CSS_PSEUDO_CLASS(_name, _value, _pref) \
michael@0 778 EventStates(),
michael@0 779 #define CSS_STATE_PSEUDO_CLASS(_name, _value, _pref, _states) \
michael@0 780 _states,
michael@0 781 #include "nsCSSPseudoClassList.h"
michael@0 782 #undef CSS_STATE_PSEUDO_CLASS
michael@0 783 #undef CSS_PSEUDO_CLASS
michael@0 784
michael@0 785 // Add more entries for our fake values to make sure we can't
michael@0 786 // index out of bounds into this array no matter what.
michael@0 787 EventStates(),
michael@0 788 EventStates()
michael@0 789 };
michael@0 790 static_assert(MOZ_ARRAY_LENGTH(sPseudoClassStates) ==
michael@0 791 nsCSSPseudoClasses::ePseudoClass_NotPseudoClass + 1,
michael@0 792 "Length of PseudoClassStates array is incorrect");
michael@0 793
michael@0 794 nsCOMPtr<nsIAtom> atom = do_GetAtom(aStatePseudo);
michael@0 795
michael@0 796 // Ignore :moz-any-link so we don't give the element simultaneous
michael@0 797 // visited and unvisited style state
michael@0 798 if (nsCSSPseudoClasses::GetPseudoType(atom) ==
michael@0 799 nsCSSPseudoClasses::ePseudoClass_mozAnyLink) {
michael@0 800 return EventStates();
michael@0 801 }
michael@0 802 // Our array above is long enough that indexing into it with
michael@0 803 // NotPseudoClass is ok.
michael@0 804 return sPseudoClassStates[nsCSSPseudoClasses::GetPseudoType(atom)];
michael@0 805 }
michael@0 806
michael@0 807 NS_IMETHODIMP
michael@0 808 inDOMUtils::AddPseudoClassLock(nsIDOMElement *aElement,
michael@0 809 const nsAString &aPseudoClass)
michael@0 810 {
michael@0 811 EventStates state = GetStatesForPseudoClass(aPseudoClass);
michael@0 812 if (state.IsEmpty()) {
michael@0 813 return NS_OK;
michael@0 814 }
michael@0 815
michael@0 816 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
michael@0 817 NS_ENSURE_ARG_POINTER(element);
michael@0 818
michael@0 819 element->LockStyleStates(state);
michael@0 820
michael@0 821 return NS_OK;
michael@0 822 }
michael@0 823
michael@0 824 NS_IMETHODIMP
michael@0 825 inDOMUtils::RemovePseudoClassLock(nsIDOMElement *aElement,
michael@0 826 const nsAString &aPseudoClass)
michael@0 827 {
michael@0 828 EventStates state = GetStatesForPseudoClass(aPseudoClass);
michael@0 829 if (state.IsEmpty()) {
michael@0 830 return NS_OK;
michael@0 831 }
michael@0 832
michael@0 833 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
michael@0 834 NS_ENSURE_ARG_POINTER(element);
michael@0 835
michael@0 836 element->UnlockStyleStates(state);
michael@0 837
michael@0 838 return NS_OK;
michael@0 839 }
michael@0 840
michael@0 841 NS_IMETHODIMP
michael@0 842 inDOMUtils::HasPseudoClassLock(nsIDOMElement *aElement,
michael@0 843 const nsAString &aPseudoClass,
michael@0 844 bool *_retval)
michael@0 845 {
michael@0 846 EventStates state = GetStatesForPseudoClass(aPseudoClass);
michael@0 847 if (state.IsEmpty()) {
michael@0 848 *_retval = false;
michael@0 849 return NS_OK;
michael@0 850 }
michael@0 851
michael@0 852 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
michael@0 853 NS_ENSURE_ARG_POINTER(element);
michael@0 854
michael@0 855 EventStates locks = element->LockedStyleStates();
michael@0 856
michael@0 857 *_retval = locks.HasAllStates(state);
michael@0 858 return NS_OK;
michael@0 859 }
michael@0 860
michael@0 861 NS_IMETHODIMP
michael@0 862 inDOMUtils::ClearPseudoClassLocks(nsIDOMElement *aElement)
michael@0 863 {
michael@0 864 nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aElement);
michael@0 865 NS_ENSURE_ARG_POINTER(element);
michael@0 866
michael@0 867 element->ClearStyleStateLocks();
michael@0 868
michael@0 869 return NS_OK;
michael@0 870 }
michael@0 871
michael@0 872 NS_IMETHODIMP
michael@0 873 inDOMUtils::ParseStyleSheet(nsIDOMCSSStyleSheet *aSheet,
michael@0 874 const nsAString& aInput)
michael@0 875 {
michael@0 876 nsRefPtr<nsCSSStyleSheet> sheet = do_QueryObject(aSheet);
michael@0 877 NS_ENSURE_ARG_POINTER(sheet);
michael@0 878
michael@0 879 return sheet->ParseSheet(aInput);
michael@0 880 }

mercurial