NSCSSRULEPROCESSOR.CPP coverage: 94.29 %func 76.27 %block
1) /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2) // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
3) /* ***** BEGIN LICENSE BLOCK *****
4) * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5) *
6) * The contents of this file are subject to the Mozilla Public License Version
7) * 1.1 (the "License"); you may not use this file except in compliance with
8) * the License. You may obtain a copy of the License at
9) * http://www.mozilla.org/MPL/
10) *
11) * Software distributed under the License is distributed on an "AS IS" basis,
12) * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13) * for the specific language governing rights and limitations under the
14) * License.
15) *
16) * The Original Code is mozilla.org code.
17) *
18) * The Initial Developer of the Original Code is
19) * Netscape Communications Corporation.
20) * Portions created by the Initial Developer are Copyright (C) 1998
21) * the Initial Developer. All Rights Reserved.
22) *
23) * Contributor(s):
24) * L. David Baron <dbaron@dbaron.org>
25) * Daniel Glazman <glazman@netscape.com>
26) * Ehsan Akhgari <ehsan.akhgari@gmail.com>
27) * Rob Arnold <robarnold@mozilla.com>
28) *
29) * Alternatively, the contents of this file may be used under the terms of
30) * either of the GNU General Public License Version 2 or later (the "GPL"),
31) * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
32) * in which case the provisions of the GPL or the LGPL are applicable instead
33) * of those above. If you wish to allow use of your version of this file only
34) * under the terms of either the GPL or the LGPL, and not to allow others to
35) * use your version of this file under the terms of the MPL, indicate your
36) * decision by deleting the provisions above and replace them with the notice
37) * and other provisions required by the GPL or the LGPL. If you do not delete
38) * the provisions above, a recipient may use your version of this file under
39) * the terms of any one of the MPL, the GPL or the LGPL.
40) *
41) * ***** END LICENSE BLOCK ***** */
42)
43) /*
44) * style rule processor for CSS style sheets, responsible for selector
45) * matching and cascading
46) */
47)
48) #include "nsCSSRuleProcessor.h"
49)
50) #define PL_ARENA_CONST_ALIGN_MASK 7
51) #define NS_RULEHASH_ARENA_BLOCK_SIZE (256)
52) #include "plarena.h"
53)
54) #include "nsCRT.h"
55) #include "nsIAtom.h"
56) #include "pldhash.h"
57) #include "nsHashtable.h"
58) #include "nsICSSPseudoComparator.h"
59) #include "nsCSSRuleProcessor.h"
60) #include "nsICSSStyleRule.h"
61) #include "nsICSSGroupRule.h"
62) #include "nsIDocument.h"
63) #include "nsPresContext.h"
64) #include "nsIEventStateManager.h"
65) #include "nsGkAtoms.h"
66) #include "nsString.h"
67) #include "nsUnicharUtils.h"
68) #include "nsDOMError.h"
69) #include "nsRuleWalker.h"
70) #include "nsCSSPseudoClasses.h"
71) #include "nsIContent.h"
72) #include "nsCOMPtr.h"
73) #include "nsHashKeys.h"
74) #include "nsStyleUtil.h"
75) #include "nsQuickSort.h"
76) #include "nsAttrValue.h"
77) #include "nsAttrName.h"
78) #include "nsILookAndFeel.h"
79) #include "nsWidgetsCID.h"
80) #include "nsServiceManagerUtils.h"
81) #include "nsTArray.h"
82) #include "nsContentUtils.h"
83) #include "nsIMediaList.h"
84) #include "nsCSSRules.h"
85) #include "nsIPrincipal.h"
86) #include "nsStyleSet.h"
87)
88) #define VISITED_PSEUDO_PREF "layout.css.visited_links_enabled"
89)
90) static PRBool gSupportVisitedPseudo = PR_TRUE;
91)
92) static NS_DEFINE_CID(kLookAndFeelCID, NS_LOOKANDFEEL_CID);
93) static nsTArray< nsCOMPtr<nsIAtom> >* sSystemMetrics = 0;
94)
95) struct RuleValue {
96) /**
97) * |RuleValue|s are constructed before they become part of the
98) * |RuleHash|, to act as rule/selector pairs. |Add| is called when
99) * they are added to the |RuleHash|, and can be considered the second
100) * half of the constructor.
101) *
102) * |RuleValue|s are added to the rule hash from highest weight/order
103) * to lowest (since this is the fast way to build a singly linked
104) * list), so the index used to remember the order is backwards.
105) */
106) RuleValue(nsICSSStyleRule* aRule, nsCSSSelector* aSelector)
^ 39,013
107) : mRule(aRule), mSelector(aSelector) {}
108)
109) RuleValue* Add(PRInt32 aBackwardIndex, RuleValue *aNext)
^ 39,013
110) {
111) mBackwardIndex = aBackwardIndex;
112) mNext = aNext;
113) return this;
114) }
115)
116) // CAUTION: ~RuleValue will never get called as RuleValues are arena
117) // allocated and arena cleanup will take care of deleting memory.
118) // Add code to RuleHash::~RuleHash to get it to call the destructor
119) // if any more cleanup needs to happen.
120) ~RuleValue()
121) {
122) // Rule values are arena allocated. No need for any deletion.
123) }
124)
125) // Placement new to arena allocate the RuleValues
126) void *operator new(size_t aSize, PLArenaPool &aArena) CPP_THROW_NEW {
^ 39,013
127) void *mem;
128) PL_ARENA_ALLOCATE(mem, &aArena, aSize);
^ 119,371 (5)
129) return mem;
^ 39,013
130) }
131)
132) nsICSSStyleRule* mRule;
133) nsCSSSelector* mSelector; // which of |mRule|'s selectors
134) PRInt32 mBackwardIndex; // High index means low weight/order.
135) RuleValue* mNext;
136) };
137)
138) // ------------------------------
139) // Rule hash table
140) //
141)
142) // Uses any of the sets of ops below.
143) struct RuleHashTableEntry : public PLDHashEntryHdr {
144) RuleValue *mRules; // linked list of |RuleValue|, null-terminated
145) };
146)
147) static PLDHashNumber
148) RuleHash_CIHashKey(PLDHashTable *table, const void *key)
^ 159,120
149) {
150) nsIAtom *atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
151)
152) nsAutoString str;
153) atom->ToString(str);
^ 159,120
154) ToUpperCase(str);
^ 159,120
155) return HashString(str);
^ 477,360 (3)
156) }
157)
158) typedef nsIAtom*
159) (* RuleHashGetKey) (PLDHashTable *table, const PLDHashEntryHdr *entry);
160)
161) struct RuleHashTableOps {
162) PLDHashTableOps ops;
163) // Extra callback to avoid duplicating the matchEntry callback for
164) // each table. (There used to be a getKey callback in
165) // PLDHashTableOps.)
166) RuleHashGetKey getKey;
167) };
168)
169) inline const RuleHashTableOps*
170) ToLocalOps(const PLDHashTableOps *aOps)
^ 434,181
171) {
172) return (const RuleHashTableOps*)
173) (((const char*) aOps) - offsetof(RuleHashTableOps, ops));
174) }
175)
176) static PRBool
177) RuleHash_CIMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
^ 26,678
178) const void *key)
179) {
180) nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>
181) (key));
182) // Use our extra |getKey| callback to avoid code duplication.
183) nsIAtom *entry_atom = ToLocalOps(table->ops)->getKey(table, hdr);
^ 53,356 (2)
184)
185) // Check for case-sensitive match first.
186) if (match_atom == entry_atom)
187) return PR_TRUE;
^ 26,621
188)
189) const char *match_str, *entry_str;
190) match_atom->GetUTF8String(&match_str);
^ 57
191) entry_atom->GetUTF8String(&entry_str);
^ 57
192)
193) return (nsCRT::strcasecmp(entry_str, match_str) == 0);
^ 114 (2)
194) }
195)
196) static PRBool
197) RuleHash_CSMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
^ 407,503
198) const void *key)
199) {
200) nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>
201) (key));
202) // Use our extra |getKey| callback to avoid code duplication.
203) nsIAtom *entry_atom = ToLocalOps(table->ops)->getKey(table, hdr);
^ 815,006 (2)
204)
205) return match_atom == entry_atom;
206) }
207)
208) static nsIAtom*
209) RuleHash_TagTable_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
^ 401,547
210) {
211) const RuleHashTableEntry *entry =
212) static_cast<const RuleHashTableEntry*>(hdr);
213) return entry->mRules->mSelector->mTag;
^ 401,547
214) }
215)
216) static nsIAtom*
217) RuleHash_ClassTable_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
^ 30,998
218) {
219) const RuleHashTableEntry *entry =
220) static_cast<const RuleHashTableEntry*>(hdr);
221) return entry->mRules->mSelector->mClassList->mAtom;
^ 30,998
222) }
223)
224) static nsIAtom*
225) RuleHash_IdTable_GetKey(PLDHashTable *table, const PLDHashEntryHdr *hdr)
^ 1,636
226) {
227) const RuleHashTableEntry *entry =
228) static_cast<const RuleHashTableEntry*>(hdr);
229) return entry->mRules->mSelector->mIDList->mAtom;
^ 1,636
230) }
231)
232) static PLDHashNumber
233) RuleHash_NameSpaceTable_HashKey(PLDHashTable *table, const void *key)
^ 135,425
234) {
235) return NS_PTR_TO_INT32(key);
236) }
237)
238) static PRBool
239) RuleHash_NameSpaceTable_MatchEntry(PLDHashTable *table,
^ 52,898
240) const PLDHashEntryHdr *hdr,
241) const void *key)
242) {
243) const RuleHashTableEntry *entry =
244) static_cast<const RuleHashTableEntry*>(hdr);
245)
246) return NS_PTR_TO_INT32(key) ==
247) entry->mRules->mSelector->mNameSpace;
248) }
249)
250) static const RuleHashTableOps RuleHash_TagTable_Ops = {
251) {
252) PL_DHashAllocTable,
253) PL_DHashFreeTable,
254) PL_DHashVoidPtrKeyStub,
255) RuleHash_CSMatchEntry,
256) PL_DHashMoveEntryStub,
257) PL_DHashClearEntryStub,
258) PL_DHashFinalizeStub,
259) NULL
260) },
261) RuleHash_TagTable_GetKey
262) };
263)
264) // Case-sensitive ops.
265) static const RuleHashTableOps RuleHash_ClassTable_CSOps = {
266) {
267) PL_DHashAllocTable,
268) PL_DHashFreeTable,
269) PL_DHashVoidPtrKeyStub,
270) RuleHash_CSMatchEntry,
271) PL_DHashMoveEntryStub,
272) PL_DHashClearEntryStub,
273) PL_DHashFinalizeStub,
274) NULL
275) },
276) RuleHash_ClassTable_GetKey
277) };
278)
279) // Case-insensitive ops.
280) static const RuleHashTableOps RuleHash_ClassTable_CIOps = {
281) {
282) PL_DHashAllocTable,
283) PL_DHashFreeTable,
284) RuleHash_CIHashKey,
285) RuleHash_CIMatchEntry,
286) PL_DHashMoveEntryStub,
287) PL_DHashClearEntryStub,
288) PL_DHashFinalizeStub,
289) NULL
290) },
291) RuleHash_ClassTable_GetKey
292) };
293)
294) // Case-sensitive ops.
295) static const RuleHashTableOps RuleHash_IdTable_CSOps = {
296) {
297) PL_DHashAllocTable,
298) PL_DHashFreeTable,
299) PL_DHashVoidPtrKeyStub,
300) RuleHash_CSMatchEntry,
301) PL_DHashMoveEntryStub,
302) PL_DHashClearEntryStub,
303) PL_DHashFinalizeStub,
304) NULL
305) },
306) RuleHash_IdTable_GetKey
307) };
308)
309) // Case-insensitive ops.
310) static const RuleHashTableOps RuleHash_IdTable_CIOps = {
311) {
312) PL_DHashAllocTable,
313) PL_DHashFreeTable,
314) RuleHash_CIHashKey,
315) RuleHash_CIMatchEntry,
316) PL_DHashMoveEntryStub,
317) PL_DHashClearEntryStub,
318) PL_DHashFinalizeStub,
319) NULL
320) },
321) RuleHash_IdTable_GetKey
322) };
323)
324) static const PLDHashTableOps RuleHash_NameSpaceTable_Ops = {
325) PL_DHashAllocTable,
326) PL_DHashFreeTable,
327) RuleHash_NameSpaceTable_HashKey,
328) RuleHash_NameSpaceTable_MatchEntry,
329) PL_DHashMoveEntryStub,
330) PL_DHashClearEntryStub,
331) PL_DHashFinalizeStub,
332) NULL,
333) };
334)
335) #undef RULE_HASH_STATS
336) #undef PRINT_UNIVERSAL_RULES
337)
338) #ifdef RULE_HASH_STATS
339) #define RULE_HASH_STAT_INCREMENT(var_) PR_BEGIN_MACRO ++(var_); PR_END_MACRO
340) #else
341) #define RULE_HASH_STAT_INCREMENT(var_) PR_BEGIN_MACRO PR_END_MACRO
342) #endif
343)
344) // Enumerator callback function.
345) typedef void (*RuleEnumFunc)(nsICSSStyleRule* aRule,
346) nsCSSSelector* aSelector,
347) void *aData);
348)
349) class RuleHash {
350) public:
351) RuleHash(PRBool aQuirksMode);
352) ~RuleHash();
353) void PrependRule(RuleValue *aRuleInfo);
354) void EnumerateAllRules(PRInt32 aNameSpace, nsIAtom* aTag, nsIAtom* aID,
355) const nsAttrValue* aClassList,
356) RuleEnumFunc aFunc, void* aData);
357) void EnumerateTagRules(nsIAtom* aTag,
358) RuleEnumFunc aFunc, void* aData);
359) PLArenaPool& Arena() { return mArena; }
^ 122
360)
361) protected:
362) void PrependRuleToTable(PLDHashTable* aTable, const void* aKey,
363) RuleValue* aRuleInfo);
364) void PrependUniversalRule(RuleValue* aRuleInfo);
365)
366) // All rule values in these hashtables are arena allocated
367) PRInt32 mRuleCount;
368) PLDHashTable mIdTable;
369) PLDHashTable mClassTable;
370) PLDHashTable mTagTable;
371) PLDHashTable mNameSpaceTable;
372) RuleValue *mUniversalRules;
373)
374) RuleValue** mEnumList;
375) PRInt32 mEnumListSize;
376)
377) PLArenaPool mArena;
378)
379) #ifdef RULE_HASH_STATS
380) PRUint32 mUniversalSelectors;
381) PRUint32 mNameSpaceSelectors;
382) PRUint32 mTagSelectors;
383) PRUint32 mClassSelectors;
384) PRUint32 mIdSelectors;
385)
386) PRUint32 mElementsMatched;
387) PRUint32 mPseudosMatched;
388)
389) PRUint32 mElementUniversalCalls;
390) PRUint32 mElementNameSpaceCalls;
391) PRUint32 mElementTagCalls;
392) PRUint32 mElementClassCalls;
393) PRUint32 mElementIdCalls;
394)
395) PRUint32 mPseudoTagCalls;
396) #endif // RULE_HASH_STATS
397) };
398)
399) RuleHash::RuleHash(PRBool aQuirksMode)
^ 122
400) : mRuleCount(0),
401) mUniversalRules(nsnull),
402) mEnumList(nsnull), mEnumListSize(0)
403) #ifdef RULE_HASH_STATS
404) ,
405) mUniversalSelectors(0),
406) mNameSpaceSelectors(0),
407) mTagSelectors(0),
408) mClassSelectors(0),
409) mIdSelectors(0),
410) mElementsMatched(0),
411) mPseudosMatched(0),
412) mElementUniversalCalls(0),
413) mElementNameSpaceCalls(0),
414) mElementTagCalls(0),
415) mElementClassCalls(0),
416) mElementIdCalls(0),
417) mPseudoTagCalls(0)
418) #endif
419) {
420) // Initialize our arena
421) PL_INIT_ARENA_POOL(&mArena, "RuleHashArena", NS_RULEHASH_ARENA_BLOCK_SIZE);
422)
423) PL_DHashTableInit(&mTagTable, &RuleHash_TagTable_Ops.ops, nsnull,
^ 122
424) sizeof(RuleHashTableEntry), 64);
425) PL_DHashTableInit(&mIdTable,
^ 366 (4)
426) aQuirksMode ? &RuleHash_IdTable_CIOps.ops
427) : &RuleHash_IdTable_CSOps.ops,
428) nsnull, sizeof(RuleHashTableEntry), 16);
429) PL_DHashTableInit(&mClassTable,
^ 366 (4)
430) aQuirksMode ? &RuleHash_ClassTable_CIOps.ops
431) : &RuleHash_ClassTable_CSOps.ops,
432) nsnull, sizeof(RuleHashTableEntry), 16);
433) PL_DHashTableInit(&mNameSpaceTable, &RuleHash_NameSpaceTable_Ops, nsnull,
^ 122
434) sizeof(RuleHashTableEntry), 16);
435) }
^ 122
436)
437) RuleHash::~RuleHash()
^ 122
438) {
439) #ifdef RULE_HASH_STATS
440) printf(
441) "RuleHash(%p):\n"
442) " Selectors: Universal (%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
443) " Content Nodes: Elements(%u) Pseudo-Elements(%u)\n"
444) " Element Calls: Universal(%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
445) " Pseudo-Element Calls: Tag(%u)\n",
446) static_cast<void*>(this),
447) mUniversalSelectors, mNameSpaceSelectors, mTagSelectors,
448) mClassSelectors, mIdSelectors,
449) mElementsMatched,
450) mPseudosMatched,
451) mElementUniversalCalls, mElementNameSpaceCalls, mElementTagCalls,
452) mElementClassCalls, mElementIdCalls,
453) mPseudoTagCalls);
454) #ifdef PRINT_UNIVERSAL_RULES
455) {
456) RuleValue* value = mUniversalRules;
457) if (value) {
458) printf(" Universal rules:\n");
459) do {
460) nsAutoString selectorText;
461) PRUint32 lineNumber = value->mRule->GetLineNumber();
462) nsCOMPtr<nsIStyleSheet> sheet;
463) value->mRule->GetStyleSheet(*getter_AddRefs(sheet));
464) nsCOMPtr<nsICSSStyleSheet> cssSheet = do_QueryInterface(sheet);
465) value->mSelector->ToString(selectorText, cssSheet);
466)
467) printf(" line %d, %s\n",
468) lineNumber, NS_ConvertUTF16toUTF8(selectorText).get());
469) value = value->mNext;
470) } while (value);
471) }
472) }
473) #endif // PRINT_UNIVERSAL_RULES
474) #endif // RULE_HASH_STATS
475) // Rule Values are arena allocated no need to delete them. Their destructor
476) // isn't doing any cleanup. So we dont even bother to enumerate through
477) // the hash tables and call their destructors.
478) if (nsnull != mEnumList) {
479) delete [] mEnumList;
^ 122
480) }
481) // delete arena for strings and small objects
482) PL_DHashTableFinish(&mIdTable);
^ 122
483) PL_DHashTableFinish(&mClassTable);
^ 122
484) PL_DHashTableFinish(&mTagTable);
^ 122
485) PL_DHashTableFinish(&mNameSpaceTable);
^ 122
486) PL_FinishArenaPool(&mArena);
^ 122
487) }
^ 122
488)
489) void RuleHash::PrependRuleToTable(PLDHashTable* aTable, const void* aKey,
^ 38,678
490) RuleValue* aRuleInfo)
491) {
492) // Get a new or existing entry.
493) RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
^ 38,678
494) (PL_DHashTableOperate(aTable, aKey, PL_DHASH_ADD));
495) if (!entry)
496) return;
^ 0
497) entry->mRules = aRuleInfo->Add(mRuleCount++, entry->mRules);
^ 77,356 (2)
498) }
499)
500) void RuleHash::PrependUniversalRule(RuleValue *aRuleInfo)
^ 335
501) {
502) mUniversalRules = aRuleInfo->Add(mRuleCount++, mUniversalRules);
^ 335
503) }
504)
505) void RuleHash::PrependRule(RuleValue *aRuleInfo)
^ 39,013
506) {
507) nsCSSSelector *selector = aRuleInfo->mSelector;
508) if (nsnull != selector->mIDList) {
509) PrependRuleToTable(&mIdTable, selector->mIDList->mAtom, aRuleInfo);
^ 1,938 (2)
510) RULE_HASH_STAT_INCREMENT(mIdSelectors);
^ 969
511) }
512) else if (nsnull != selector->mClassList) {
^ 38,044
513) PrependRuleToTable(&mClassTable, selector->mClassList->mAtom, aRuleInfo);
^ 15,356 (2)
514) RULE_HASH_STAT_INCREMENT(mClassSelectors);
^ 7,678
515) }
516) else if (nsnull != selector->mTag) {
^ 60,732 (2)
517) PrependRuleToTable(&mTagTable, selector->mTag, aRuleInfo);
^ 59,506 (2)
518) RULE_HASH_STAT_INCREMENT(mTagSelectors);
^ 29,753
519) }
520) else if (kNameSpaceID_Unknown != selector->mNameSpace) {
^ 613
521) PrependRuleToTable(&mNameSpaceTable,
^ 278
522) NS_INT32_TO_PTR(selector->mNameSpace), aRuleInfo);
523) RULE_HASH_STAT_INCREMENT(mNameSpaceSelectors);
^ 278
524) }
525) else { // universal tag selector
526) PrependUniversalRule(aRuleInfo);
^ 335
527) RULE_HASH_STAT_INCREMENT(mUniversalSelectors);
^ 335
528) }
529) }
^ 39,013
530)
531) // this should cover practically all cases so we don't need to reallocate
532) #define MIN_ENUM_LIST_SIZE 8
533)
534) #ifdef RULE_HASH_STATS
535) #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
536) do { ++(var_); (list_) = (list_)->mNext; } while (list_)
537) #else
538) #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
539) PR_BEGIN_MACRO PR_END_MACRO
540) #endif
541)
542) void RuleHash::EnumerateAllRules(PRInt32 aNameSpace, nsIAtom* aTag,
^ 135,147
543) nsIAtom* aID, const nsAttrValue* aClassList,
544) RuleEnumFunc aFunc, void* aData)
545) {
546) PRInt32 classCount = aClassList ? aClassList->GetAtomCount() : 0;
^ 342,515 (4)
547)
548) // assume 1 universal, tag, id, and namespace, rather than wasting
549) // time counting
550) PRInt32 testCount = classCount + 4;
551)
552) if (mEnumListSize < testCount) {
553) delete [] mEnumList;
^ 132
554) mEnumListSize = PR_MAX(testCount, MIN_ENUM_LIST_SIZE);
^ 132
555) mEnumList = new RuleValue*[mEnumListSize];
^ 132
556) }
557)
558) PRInt32 valueCount = 0;
^ 135,147
559) RULE_HASH_STAT_INCREMENT(mElementsMatched);
^ 135,147
560)
561) { // universal rules
562) RuleValue* value = mUniversalRules;
^ 135,147
563) if (nsnull != value) {
564) mEnumList[valueCount++] = value;
^ 125,024
565) RULE_HASH_STAT_INCREMENT_LIST_COUNT(value, mElementUniversalCalls);
^ 125,024
566) }
567) }
568) // universal rules within the namespace
569) if (kNameSpaceID_Unknown != aNameSpace) {
^ 135,147
570) RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
^ 270,294 (2)
571) (PL_DHashTableOperate(&mNameSpaceTable, NS_INT32_TO_PTR(aNameSpace),
572) PL_DHASH_LOOKUP));
573) if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
574) RuleValue *value = entry->mRules;
^ 52,692
575) mEnumList[valueCount++] = value;
576) RULE_HASH_STAT_INCREMENT_LIST_COUNT(value, mElementNameSpaceCalls);
^ 52,692
577) }
578) }
579) if (nsnull != aTag) {
^ 135,147
580) RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
^ 270,294 (2)
581) (PL_DHashTableOperate(&mTagTable, aTag, PL_DHASH_LOOKUP));
582) if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
583) RuleValue *value = entry->mRules;
^ 80,537
584) mEnumList[valueCount++] = value;
585) RULE_HASH_STAT_INCREMENT_LIST_COUNT(value, mElementTagCalls);
^ 80,537
586) }
587) }
588) if (nsnull != aID) {
^ 135,147
589) RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
^ 109,456 (2)
590) (PL_DHashTableOperate(&mIdTable, aID, PL_DHASH_LOOKUP));
591) if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
592) RuleValue *value = entry->mRules;
^ 1,086
593) mEnumList[valueCount++] = value;
594) RULE_HASH_STAT_INCREMENT_LIST_COUNT(value, mElementIdCalls);
^ 1,086
595) }
596) }
597) { // extra scope to work around compiler bugs with |for| scoping.
598) for (PRInt32 index = 0; index < classCount; ++index) {
^ 246,820 (2) ^ 135,147
599) RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
^ 335,019 (3)
600) (PL_DHashTableOperate(&mClassTable, aClassList->AtomAt(index),
601) PL_DHASH_LOOKUP));
602) if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
603) RuleValue *value = entry->mRules;
^ 29,276
604) mEnumList[valueCount++] = value;
605) RULE_HASH_STAT_INCREMENT_LIST_COUNT(value, mElementClassCalls);
^ 29,276
606) }
607) }
608) }
609) NS_ASSERTION(valueCount <= testCount, "values exceeded list size");
^ 135,147
610)
611) if (valueCount > 0) {
^ 135,147
612) // Merge the lists while there are still multiple lists to merge.
613) while (valueCount > 1) {
^ 2,288,339 (2)
614) PRInt32 valueIndex = 0;
^ 2,155,622
615) PRInt32 highestRuleIndex = mEnumList[valueIndex]->mBackwardIndex;
616) for (PRInt32 index = 1; index < valueCount; ++index) {
^ 5,186,311 (2)
617) PRInt32 ruleIndex = mEnumList[index]->mBackwardIndex;
^ 3,030,689
618) if (ruleIndex > highestRuleIndex) {
619) valueIndex = index;
^ 1,920,683
620) highestRuleIndex = ruleIndex;
621) }
622) }
623) RuleValue *cur = mEnumList[valueIndex];
^ 2,155,622
624) (*aFunc)(cur->mRule, cur->mSelector, aData);
625) RuleValue *next = cur->mNext;
^ 2,155,622
626) mEnumList[valueIndex] = next ? next : mEnumList[--valueCount];
^ 2,155,622 (2)
627) }
628)
629) // Fast loop over single value.
630) RuleValue* value = mEnumList[0];
^ 132,717
631) do {
632) (*aFunc)(value->mRule, value->mSelector, aData);
^ 428,513
633) value = value->mNext;
^ 428,513
634) } while (value);
635) }
636) }
^ 135,147
637)
638) void RuleHash::EnumerateTagRules(nsIAtom* aTag, RuleEnumFunc aFunc, void* aData)
^ 718,369
639) {
640) RuleHashTableEntry *entry = static_cast<RuleHashTableEntry*>
^ 718,369
641) (PL_DHashTableOperate(&mTagTable, aTag, PL_DHASH_LOOKUP));
642)
643) RULE_HASH_STAT_INCREMENT(mPseudosMatched);
^ 718,369
644) if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
^ 718,369
645) RuleValue *tagValue = entry->mRules;
^ 300,615
646) do {
647) RULE_HASH_STAT_INCREMENT(mPseudoTagCalls);
^ 1,292,423
648) (*aFunc)(tagValue->mRule, tagValue->mSelector, aData);
^ 1,292,423
649) tagValue = tagValue->mNext;
^ 1,292,423
650) } while (tagValue);
651) }
652) }
^ 718,369
653)
654) //--------------------------------
655)
656) // Attribute selectors hash table.
657) struct AttributeSelectorEntry : public PLDHashEntryHdr {
658) nsIAtom *mAttribute;
659) nsTArray<nsCSSSelector*> *mSelectors;
660) };
661)
662) static void
663) AttributeSelectorClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
^ 1,596
664) {
665) AttributeSelectorEntry *entry = static_cast<AttributeSelectorEntry*>(hdr);
666) delete entry->mSelectors;
^ 1,596
667) memset(entry, 0, table->entrySize);
^ 1,596
668) }
^ 1,596
669)
670) static const PLDHashTableOps AttributeSelectorOps = {
671) PL_DHashAllocTable,
672) PL_DHashFreeTable,
673) PL_DHashVoidPtrKeyStub,
674) PL_DHashMatchEntryStub,
675) PL_DHashMoveEntryStub,
676) AttributeSelectorClearEntry,
677) PL_DHashFinalizeStub,
678) NULL
679) };
680)
681)
682) //--------------------------------
683)
684) struct RuleCascadeData {
685) RuleCascadeData(nsIAtom *aMedium, PRBool aQuirksMode)
^ 854 (7)
686) : mRuleHash(aQuirksMode),
687) mStateSelectors(),
688) mCacheKey(aMedium),
689) mNext(nsnull)
690) {
691) PL_DHashTableInit(&mAttributeSelectors, &AttributeSelectorOps, nsnull,
692) sizeof(AttributeSelectorEntry), 16);
693) }
^ 122
694)
695) ~RuleCascadeData()
^ 122
696) {
697) PL_DHashTableFinish(&mAttributeSelectors);
698) }
^ 854 (7)
699) RuleHash mRuleHash;
700) nsTArray<nsCSSSelector*> mStateSelectors;
701) nsTArray<nsCSSSelector*> mClassSelectors;
702) nsTArray<nsCSSSelector*> mIDSelectors;
703) PLDHashTable mAttributeSelectors;
704)
705) nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
706)
707) // Looks up or creates the appropriate list in |mAttributeSelectors|.
708) // Returns null only on allocation failure.
709) nsTArray<nsCSSSelector*>* AttributeListFor(nsIAtom* aAttribute);
710)
711) nsMediaQueryResultCacheKey mCacheKey;
712) RuleCascadeData* mNext; // for a different medium
713) };
714)
715) nsTArray<nsCSSSelector*>*
716) RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
^ 8,866
717) {
718) AttributeSelectorEntry *entry = static_cast<AttributeSelectorEntry*>
^ 8,866
719) (PL_DHashTableOperate(&mAttributeSelectors, aAttribute, PL_DHASH_ADD));
720) if (!entry)
721) return nsnull;
^ 0
722) if (!entry->mSelectors) {
^ 8,866
723) if (!(entry->mSelectors = new nsTArray<nsCSSSelector*>)) {
^ 7,980 (5/6)
724) PL_DHashTableRawRemove(&mAttributeSelectors, entry);
^ 0
725) return nsnull;
^ 0
726) }
727) entry->mAttribute = aAttribute;
^ 1,596
728) }
729) return entry->mSelectors;
^ 8,866
730) }
731)
732) // -------------------------------
733) // CSS Style rule processor implementation
734) //
735)
736) nsCSSRuleProcessor::nsCSSRuleProcessor(const nsCOMArray<nsICSSStyleSheet>& aSheets,
^ 644 (4)
737) PRUint8 aSheetType)
738) : mSheets(aSheets)
739) , mRuleCascades(nsnull)
740) , mLastPresContext(nsnull)
741) , mSheetType(aSheetType)
742) {
743) for (PRInt32 i = mSheets.Count() - 1; i >= 0; --i)
^ 551 (2) ^ 161
744) mSheets[i]->AddRuleProcessor(this);
^ 780 (2)
745) }
^ 161
746)
747) nsCSSRuleProcessor::~nsCSSRuleProcessor()
^ 161
748) {
749) for (PRInt32 i = mSheets.Count() - 1; i >= 0; --i)
^ 551 (2) ^ 161
750) mSheets[i]->DropRuleProcessor(this);
^ 780 (2)
751) mSheets.Clear();
^ 161
752) ClearRuleCascades();
^ 161
753) }
^ 322 (2)
754)
755) NS_IMPL_ISUPPORTS1(nsCSSRuleProcessor, nsIStyleRuleProcessor)
^ 2,415 (16/18)
756)
757) /* static */ void
758) nsCSSRuleProcessor::Startup()
759) {
^ 1
760) nsContentUtils::AddBoolPrefVarCache(VISITED_PSEUDO_PREF,
761) &gSupportVisitedPseudo);
762) // We want to default to true, not false as AddBoolPrefVarCache does.
763) gSupportVisitedPseudo =
^ 2 (2)
764) nsContentUtils::GetBoolPref(VISITED_PSEUDO_PREF, PR_TRUE);
765) }
766)
767) static PRBool
768) InitSystemMetrics()
^ 1
769) {
770) NS_ASSERTION(!sSystemMetrics, "already initialized");
^ 1
771)
772) sSystemMetrics = new nsTArray< nsCOMPtr<nsIAtom> >;
^ 5 (5/6)
773) NS_ENSURE_TRUE(sSystemMetrics, PR_FALSE);
^ 2 (2/4)
774)
775) nsresult rv;
776) nsCOMPtr<nsILookAndFeel> lookAndFeel(do_GetService(kLookAndFeelCID, &rv));
^ 2 (2)
777) NS_ENSURE_SUCCESS(rv, PR_FALSE);
^ 2 (2/5)
778)
779) PRInt32 metricResult;
780) lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ScrollArrowStyle, metricResult);
^ 2 (2)
781) if (metricResult & nsILookAndFeel::eMetric_ScrollArrowStartBackward) {
^ 1
782) sSystemMetrics->AppendElement(do_GetAtom("scrollbar-start-backward"));
^ 2 (2)
783) }
784) if (metricResult & nsILookAndFeel::eMetric_ScrollArrowStartForward) {
^ 1
785) sSystemMetrics->AppendElement(do_GetAtom("scrollbar-start-forward"));
^ 0 (2)
786) }
787) if (metricResult & nsILookAndFeel::eMetric_ScrollArrowEndBackward) {
^ 1
788) sSystemMetrics->AppendElement(do_GetAtom("scrollbar-end-backward"));
^ 0 (2)
789) }
790) if (metricResult & nsILookAndFeel::eMetric_ScrollArrowEndForward) {
^ 1
791) sSystemMetrics->AppendElement(do_GetAtom("scrollbar-end-forward"));
^ 2 (2)
792) }
793)
794) lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ScrollSliderStyle, metricResult);
^ 2 (2)
795) if (metricResult != nsILookAndFeel::eMetric_ScrollThumbStyleNormal) {
^ 1
796) sSystemMetrics->AppendElement(do_GetAtom("scrollbar-thumb-proportional"));
^ 2 (2)
797) }
798)
799) lookAndFeel->GetMetric(nsILookAndFeel::eMetric_ImagesInMenus, metricResult);
^ 2 (2)
800) if (metricResult) {
^ 1
801) sSystemMetrics->AppendElement(do_GetAtom("images-in-menus"));
^ 0 (2)
802) }
803)
804) rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_WindowsDefaultTheme, metricResult);
^ 3 (3)
805) if (NS_SUCCEEDED(rv) && metricResult) {
^ 1
806) sSystemMetrics->AppendElement(do_GetAtom("windows-default-theme"));
^ 2 (2)
807) }
808)
809) rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_MacGraphiteTheme, metricResult);
^ 3 (3)
810) if (NS_SUCCEEDED(rv) && metricResult) {
^ 0
811) sSystemMetrics->AppendElement(do_GetAtom("mac-graphite-theme"));
^ 0 (2)
812) }
813)
814) rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_DWMCompositor, metricResult);
^ 3 (3)
815) if (NS_SUCCEEDED(rv) && metricResult) {
^ 1
816) sSystemMetrics->AppendElement(do_GetAtom("windows-compositor"));
^ 0 (2)
817) }
818)
819) rv = lookAndFeel->GetMetric(nsILookAndFeel::eMetric_WindowsClassic, metricResult);
^ 3 (3)
820) if (NS_SUCCEEDED(rv) && metricResult) {
^ 1
821) sSystemMetrics->AppendElement(do_GetAtom("windows-classic"));
^ 0 (2)
822) }
823)
824) return PR_TRUE;
^ 2 (2)
825) }
826)
827) /* static */ void
828) nsCSSRuleProcessor::FreeSystemMetrics()
829) {
^ 1
830) delete sSystemMetrics;
^ 1
831) sSystemMetrics = nsnull;
^ 1
832) }
833)
834) RuleProcessorData::RuleProcessorData(nsPresContext* aPresContext,
^ 916,140
835) nsIContent* aContent,
836) nsRuleWalker* aRuleWalker,
837) nsCompatibility* aCompat /*= nsnull*/)
838) {
839) MOZ_COUNT_CTOR(RuleProcessorData);
840)
841) NS_ASSERTION(!aContent || aContent->IsNodeOfType(nsINode::eELEMENT),
^ 916,140
842) "non-element leaked into SelectorMatches");
843)
844) mPresContext = aPresContext;
^ 916,140
845) mContent = aContent;
846) mParentContent = nsnull;
847) mRuleWalker = aRuleWalker;
848) mScopedRoot = nsnull;
849)
850) mContentTag = nsnull;
851) mContentID = nsnull;
852) mHasAttributes = PR_FALSE;
853) mIsHTMLContent = PR_FALSE;
854) mIsLink = PR_FALSE;
855) mLinkState = eLinkState_Unknown;
856) mEventState = 0;
857) mNameSpaceID = kNameSpaceID_Unknown;
858) mPreviousSiblingData = nsnull;
859) mParentData = nsnull;
860) mLanguage = nsnull;
861) mClasses = nsnull;
862) mNthIndices[0][0] = -2;
863) mNthIndices[0][1] = -2;
864) mNthIndices[1][0] = -2;
865) mNthIndices[1][1] = -2;
866)
867) // get the compat. mode (unless it is provided)
868) // XXXbz is passing in the compat mode really that much of an optimization?
869) if (aCompat) {
870) mCompatMode = *aCompat;
^ 597,313
871) } else if (NS_LIKELY(mPresContext)) {
^ 318,827
872) mCompatMode = mPresContext->CompatibilityMode();
^ 637,654 (2)
873) } else {
874) NS_ASSERTION(aContent, "Must have content");
^ 0
875) NS_ASSERTION(aContent->GetOwnerDoc(), "Must have document");
^ 0
876) mCompatMode = aContent->GetOwnerDoc()->GetCompatibilityMode();
^ 0 (3)
877) }
878)
879) if (aContent) {
^ 916,140
880) NS_ASSERTION(aContent->GetOwnerDoc(), "Document-less node here?");
^ 916,069
881)
882) // get the tag and parent
883) mContentTag = aContent->Tag();
^ 1,832,138 (2)
884) mParentContent = aContent->GetParent();
^ 916,069
885)
886) // get the event state
887) if (mPresContext) {
888) mPresContext->EventStateManager()->GetContentState(aContent, mEventState);
^ 1,832,138 (2)
889) } else {
890) mEventState = aContent->IntrinsicState();
^ 0 (2)
891) }
892)
893) // get the ID and classes for the content
894) mContentID = aContent->GetID();
^ 1,832,138 (2)
895) mClasses = aContent->GetClasses();
^ 916,069
896)
897) // see if there are attributes for the content
898) mHasAttributes = aContent->GetAttrCount() > 0;
^ 916,069
899)
900) // check for HTMLContent and Link status
901) if (aContent->IsNodeOfType(nsINode::eHTML)) {
^ 916,069
902) mIsHTMLContent = PR_TRUE;
^ 860,276
903) // Note that we want to treat non-XML HTML content as XHTML for namespace
904) // purposes, since html.css has that namespace declared.
905) mNameSpaceID = kNameSpaceID_XHTML;
906) } else {
907) // get the namespace
908) mNameSpaceID = aContent->GetNameSpaceID();
^ 111,586 (2)
909) }
910)
911) // if HTML content and it has some attributes, check for an HTML link
912) // NOTE: optimization: cannot be a link if no attributes (since it needs an href)
913) nsILinkHandler* linkHandler =
^ 3,664,276 (4/5)
914) mPresContext ? mPresContext->GetLinkHandler() : nsnull;
915) if (mIsHTMLContent && mHasAttributes) {
^ 860,276
916) // check if it is an HTML Link
917) if(nsStyleUtil::IsHTMLLink(aContent, mContentTag, linkHandler,
^ 1,226,974 (2)
918) &mLinkState)) {
919) mIsLink = PR_TRUE;
^ 604
920) }
921) }
922)
923) // if not an HTML link, check for a simple xlink (cannot be both HTML link and xlink)
924) // NOTE: optimization: cannot be an XLink if no attributes (since it needs an
925) if(!mIsLink &&
^ 3,941,288 (8/11)
926) mHasAttributes &&
927) !(mIsHTMLContent || aContent->IsNodeOfType(nsINode::eXUL)) &&
928) nsStyleUtil::IsLink(aContent, linkHandler, &mLinkState)) {
929) mIsLink = PR_TRUE;
^ 0
930) }
931) }
932)
933) if (mLinkState == eLinkState_Visited && !gSupportVisitedPseudo) {
^ 916,148 (2)
934) mLinkState = eLinkState_Unvisited;
^ 0
935) }
936) }
^ 916,140
937)
938) RuleProcessorData::~RuleProcessorData()
^ 916,140
939) {
940) MOZ_COUNT_DTOR(RuleProcessorData);
941)
942) // Destroy potentially long chains of previous sibling and parent data
943) // without more than one level of recursion.
944) if (mPreviousSiblingData || mParentData) {
^ 916,116
945) nsAutoVoidArray destroyQueue;
^ 55,442
946) destroyQueue.AppendElement(this);
^ 55,442
947)
948) do {
949) RuleProcessorData *d = static_cast<RuleProcessorData*>
^ 1,958,265 (3)
950) (destroyQueue.FastElementAt(destroyQueue.Count() - 1));
951) destroyQueue.RemoveElementAt(destroyQueue.Count() - 1);
^ 652,755
952)
953) if (d->mPreviousSiblingData) {
^ 652,755
954) destroyQueue.AppendElement(d->mPreviousSiblingData);
^ 55
955) d->mPreviousSiblingData = nsnull;
^ 55
956) }
957) if (d->mParentData) {
^ 652,755
958) destroyQueue.AppendElement(d->mParentData);
^ 597,258
959) d->mParentData = nsnull;
^ 597,258
960) }
961)
962) if (d != this)
^ 652,755
963) d->Destroy();
^ 597,313
964) } while (destroyQueue.Count());
^ 1,305,510 (2)
965) }
^ 55,442
966)
967) delete mLanguage;
^ 916,140 (1/2)
968) }
^ 916,140
969)
970) const nsString* RuleProcessorData::GetLang()
^ 0
971) {
972) if (!mLanguage) {
973) mLanguage = new nsString();
974) if (!mLanguage)
975) return nsnull;
976) for (nsIContent* content = mContent; content;
977) content = content->GetParent()) {
978) if (content->GetAttrCount() > 0) {
979) // xml:lang has precedence over lang on HTML elements (see
980) // XHTML1 section C.7).
981) PRBool hasAttr = content->GetAttr(kNameSpaceID_XML, nsGkAtoms::lang,
982) *mLanguage);
983) if (!hasAttr && content->IsNodeOfType(nsINode::eHTML)) {
984) hasAttr = content->GetAttr(kNameSpaceID_None, nsGkAtoms::lang,
985) *mLanguage);
986) }
987) NS_ASSERTION(hasAttr || mLanguage->IsEmpty(),
988) "GetAttr that returns false should not make string non-empty");
989) if (hasAttr) {
990) break;
991) }
992) }
993) }
994) }
995) return mLanguage;
996) }
997)
998) static inline PRInt32
999) CSSNameSpaceID(nsIContent *aContent)
^ 0
1000) {
1001) return aContent->IsNodeOfType(nsINode::eHTML)
1002) ? kNameSpaceID_XHTML
1003) : aContent->GetNameSpaceID();
1004) }
1005)
1006) PRInt32
1007) RuleProcessorData::GetNthIndex(PRBool aIsOfType, PRBool aIsFromEnd,
^ 352
1008) PRBool aCheckEdgeOnly)
1009) {
1010) NS_ASSERTION(mParentContent, "caller should check mParentContent");
^ 352
1011) NS_ASSERTION(!mPreviousSiblingData ||
^ 352
1012) mPreviousSiblingData->mContent->IsNodeOfType(nsINode::eELEMENT),
1013) "Unexpected previous sibling data");
1014)
1015) PRInt32 &slot = mNthIndices[aIsOfType][aIsFromEnd];
^ 352
1016) if (slot != -2 && (slot != -1 || aCheckEdgeOnly))
^ 128 (1/2)
1017) return slot;
^ 128
1018)
1019) if (mPreviousSiblingData &&
^ 224 (1/4)
1020) (!aIsOfType ||
1021) (mPreviousSiblingData->mNameSpaceID == mNameSpaceID &&
1022) mPreviousSiblingData->mContentTag == mContentTag))) {
1023) slot = mPreviousSiblingData->mNthIndices[aIsOfType][aIsFromEnd];
^ 0
1024) if (slot > 0) {
1025) slot += (aIsFromEnd ? -1 : 1);
^ 0 (4)
1026) NS_ASSERTION(slot > 0, "How did that happen?");
^ 0
1027) return slot;
^ 0
1028) }
1029) }
1030)
1031) PRInt32 result = 1;
^ 224
1032) nsIContent* parent = mParentContent;
1033)
1034) PRUint32 childCount;
1035) nsIContent * const * curChildPtr = parent->GetChildArray(&childCount);
^ 224
1036)
1037) #ifdef DEBUG
1038) nsMutationGuard debugMutationGuard;
1039) #endif
1040)
1041) PRInt32 increment;
1042) nsIContent * const * stopPtr;
1043) if (aIsFromEnd) {
1044) stopPtr = curChildPtr - 1;
^ 64
1045) curChildPtr = stopPtr + childCount;
1046) increment = -1;
1047) } else {
1048) increment = 1;
^ 160
1049) stopPtr = curChildPtr + childCount;
1050) }
1051)
1052) for ( ; ; curChildPtr += increment) {
^ 224 (1/2)
1053) if (curChildPtr == stopPtr) {
^ 224
1054) // mContent is the root of an anonymous content subtree.
1055) result = 0; // special value to indicate that it is not at any index
^ 0
1056) break;
1057) }
1058) nsIContent* child = *curChildPtr;
^ 224
1059) if (child == mContent)
1060) break;
1061) if (child->IsNodeOfType(nsINode::eELEMENT) &&
^ 72 (3/7)
1062) (!aIsOfType ||
1063) (child->Tag() == mContentTag &&
1064) CSSNameSpaceID(child) == mNameSpaceID))) {
1065) if (aCheckEdgeOnly) {
^ 24
1066) // The caller only cares whether or not the result is 1, and we
1067) // now know it's not.
1068) result = -1;
^ 24
1069) break;
1070) }
1071) ++result;
^ 0
1072) }
1073) }
1074)
1075) #ifdef DEBUG
1076) NS_ASSERTION(!debugMutationGuard.Mutated(0), "Unexpected mutations happened");
1077) #endif
1078)
1079) slot = result;
^ 224
1080) return result;
1081) }
1082)
1083) static PRBool ValueIncludes(const nsSubstring& aValueList,
^ 293
1084) const nsSubstring& aValue,
1085) const nsStringComparator& aComparator)
1086) {
1087) const PRUnichar *p = aValueList.BeginReading(),
^ 293
1088) *p_end = aValueList.EndReading();
^ 293
1089)
1090) while (p < p_end) {
^ 488 (2)
1091) // skip leading space
1092) while (p != p_end && nsContentUtils::IsHTMLWhitespace(*p))
^ 774 (3/4)
1093) ++p;
1094)
1095) const PRUnichar *val_start = p;
^ 258
1096)
1097) // look for space or end
1098) while (p != p_end && !nsContentUtils::IsHTMLWhitespace(*p))
^ 7,224 (4)
1099) ++p;
1100)
1101) const PRUnichar *val_end = p;
^ 258
1102)
1103) if (val_start < val_end &&
^ 1,806 (8/9)
1104) aValue.Equals(Substring(val_start, val_end), aComparator))
1105) return PR_TRUE;
^ 63
1106)
1107) ++p; // we know the next character is not whitespace
1108) }
1109) return PR_FALSE;
^ 230
1110) }
1111)
1112) inline PRBool IsLinkPseudo(nsIAtom* aAtom)
^ 268,972
1113) {
1114) return PRBool ((nsCSSPseudoClasses::link == aAtom) ||
^ 941,834 (5)
1115) (nsCSSPseudoClasses::visited == aAtom) ||
1116) (nsCSSPseudoClasses::mozAnyLink == aAtom));
1117) }
1118)
1119) // Return whether we should apply a "global" (i.e., universal-tag)
1120) // selector for event states in quirks mode. Note that
1121) // |data.mIsLink| is checked separately by the caller, so we return
1122) // false for |nsGkAtoms::a|, which here means a named anchor.
1123) inline PRBool IsQuirkEventSensitive(nsIAtom *aContentTag)
^ 10,054
1124) {
1125) return PRBool ((nsGkAtoms::button == aContentTag) ||
^ 67,734 (8)
1126) (nsGkAtoms::img == aContentTag) ||
1127) (nsGkAtoms::input == aContentTag) ||
1128) (nsGkAtoms::label == aContentTag) ||
1129) (nsGkAtoms::select == aContentTag) ||
1130) (nsGkAtoms::textarea == aContentTag));
1131) }
1132)
1133)
1134) static inline PRBool
1135) IsSignificantChild(nsIContent* aChild, PRBool aTextIsSignificant,
^ 620
1136) PRBool aWhitespaceIsSignificant)
1137) {
1138) return nsStyleUtil::IsSignificantChild(aChild, aTextIsSignificant,
^ 620
1139) aWhitespaceIsSignificant);
1140) }
1141)
1142) // This function is to be called once we have fetched a value for an attribute
1143) // whose namespace and name match those of aAttrSelector. This function
1144) // performs comparisons on the value only, based on aAttrSelector->mFunction.
1145) static PRBool AttrMatchesValue(const nsAttrSelector* aAttrSelector,
^ 357
1146) const nsString& aValue)
1147) {
1148) NS_PRECONDITION(aAttrSelector, "Must have an attribute selector");
^ 357
1149)
1150) // http://lists.w3.org/Archives/Public/www-style/2008Apr/0038.html
1151) // *= (CONTAINSMATCH) ~= (INCLUDES) ^= (BEGINSMATCH) $= (ENDSMATCH)
1152) // all accept the empty string, but match nothing.
1153) if (aAttrSelector->mValue.IsEmpty() &&
^ 714 (2/8)
1154) (aAttrSelector->mFunction == NS_ATTR_FUNC_INCLUDES ||
1155) aAttrSelector->mFunction == NS_ATTR_FUNC_ENDSMATCH ||
1156) aAttrSelector->mFunction == NS_ATTR_FUNC_BEGINSMATCH ||
1157) aAttrSelector->mFunction == NS_ATTR_FUNC_CONTAINSMATCH))
1158) return PR_FALSE;
^ 0
1159)
1160) const nsDefaultStringComparator defaultComparator;
^ 357
1161) const nsCaseInsensitiveStringComparator ciComparator;
^ 357
1162) const nsStringComparator& comparator = aAttrSelector->mCaseSensitive
^ 1,071 (3/4)
1163) ? static_cast<const nsStringComparator&>(defaultComparator)
1164) : static_cast<const nsStringComparator&>(ciComparator);
1165) switch (aAttrSelector->mFunction) {
^ 357
1166) case NS_ATTR_FUNC_EQUALS:
1167) return aValue.Equals(aAttrSelector->mValue, comparator);
^ 0 (3)
1168) case NS_ATTR_FUNC_INCLUDES:
1169) return ValueIncludes(aValue, aAttrSelector->mValue, comparator);
^ 879 (3)
1170) case NS_ATTR_FUNC_DASHMATCH:
1171) return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
^ 0 (3)
1172) case NS_ATTR_FUNC_ENDSMATCH:
1173) return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
^ 192 (3)
1174) case NS_ATTR_FUNC_BEGINSMATCH:
1175) return StringBeginsWith(aValue, aAttrSelector->mValue, comparator);
^ 0 (3)
1176) case NS_ATTR_FUNC_CONTAINSMATCH:
1177) return FindInReadable(aAttrSelector->mValue, aValue, comparator);
^ 0 (3)
1178) default:
1179) NS_NOTREACHED("Shouldn't be ending up here");
^ 0
1180) return PR_FALSE;
^ 0
1181) }
1182) }
1183)
1184) // NOTE: For |aStateMask| and |aAttribute| to work correctly, it's
1185) // important that any change that changes multiple state bits and
1186) // maybe an attribute include all those state bits and the attribute
1187) // in the notification. Otherwise, if multiple states change but we
1188) // do separate notifications then we might determine the style is not
1189) // state-dependent when it really is (e.g., determining that a
1190) // :hover:active rule no longer matches when both states are unset).
1191)
1192) // If |aForStyling| is false, we shouldn't mark slow-selector bits on nodes.
1193)
1194) // |aDependence| has two functions:
1195) // * when non-null, it indicates that we're processing a negation,
1196) // which is done only when SelectorMatches calls itself recursively
1197) // * what it points to should be set to true whenever a test is skipped
1198) // because of aStateMask or aAttribute
1199) static PRBool SelectorMatches(RuleProcessorData &data,
^ 40,311,512
1200) nsCSSSelector* aSelector,
1201) PRInt32 aStateMask, // states NOT to test
1202) nsIAtom* aAttribute, // attribute NOT to test
1203) PRBool aForStyling,
1204) PRBool* const aDependence = nsnull)
1205)
1206) {
1207) // namespace/tag match
1208) if ((kNameSpaceID_Unknown != aSelector->mNameSpace &&
^ 94,139,863 (5)
1209) data.mNameSpaceID != aSelector->mNameSpace) ||
1210) (aSelector->mTag && aSelector->mTag != data.mContentTag)) {
1211) // optimization : bail out early if we can
1212) return PR_FALSE;
^ 4,672,505
1213) }
1214)
1215) PRBool result = PR_TRUE;
^ 35,639,007
1216) const PRBool isNegated = (aDependence != nsnull);
^ 35,639,007 (2)
1217) // The selectors for which we set node bits are, unfortunately, early
1218) // in this function (because they're pseudo-classes, which are
1219) // generally quick to test, and thus earlier). If they were later,
1220) // we'd probably avoid setting those bits in more cases where setting
1221) // them is unnecessary.
1222) const PRBool setNodeFlags = aForStyling && aStateMask == 0 && !aAttribute;
^ 142,515,359 (5)
1223)
1224) // test for pseudo class match
1225) // first-child, root, lang, active, focus, hover, link, visited...
1226) // XXX disabled, enabled, selected, selection
1227) for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
^ 36,615,112 (3) ^ 35,639,007
1228) pseudoClass && result; pseudoClass = pseudoClass->mNext) {
1229) PRInt32 stateToCheck = 0;
^ 431,460
1230) if (nsCSSPseudoClasses::firstNode == pseudoClass->mAtom) {
^ 431,460
1231) nsIContent *firstNode = nsnull;
^ 245
1232) nsIContent *parent = data.mParentContent;
1233) if (parent) {
1234) if (setNodeFlags)
^ 245
1235) parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
^ 245
1236)
1237) PRInt32 index = -1;
^ 245
1238) do {
1239) firstNode = parent->GetChildAt(++index);
^ 584 (4)
1240) // stop at first non-comment and non-whitespace node
1241) } while (firstNode &&
^ 584 (2)
1242) !IsSignificantChild(firstNode, PR_TRUE, PR_FALSE));
1243) }
1244) result = (data.mContent == firstNode);
^ 490 (3)
1245) }
1246) else if (nsCSSPseudoClasses::lastNode == pseudoClass->mAtom) {
^ 862,430 (2)
1247) nsIContent *lastNode = nsnull;
^ 132
1248) nsIContent *parent = data.mParentContent;
1249) if (parent) {
1250) if (setNodeFlags)
^ 132
1251) parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
^ 132
1252)
1253) PRUint32 index = parent->GetChildCount();
^ 264 (2)
1254) do {
1255) lastNode = parent->GetChildAt(--index);
^ 296 (4)
1256) // stop at first non-comment and non-whitespace node
1257) } while (lastNode &&
^ 296 (2)
1258) !IsSignificantChild(lastNode, PR_TRUE, PR_FALSE));
1259) }
1260) result = (data.mContent == lastNode);
^ 264 (3)
1261) }
1262) else if (nsCSSPseudoClasses::firstChild == pseudoClass->mAtom ||
^ 2,586,362 (6)
1263) nsCSSPseudoClasses::lastChild == pseudoClass->mAtom ||
1264) nsCSSPseudoClasses::onlyChild == pseudoClass->mAtom) {
1265) nsIContent *parent = data.mParentContent;
^ 162
1266) if (parent) {
1267) const PRBool checkFirst =
^ 324 (2)
1268) pseudoClass->mAtom != nsCSSPseudoClasses::lastChild;
1269) const PRBool checkLast =
^ 162
1270) pseudoClass->mAtom != nsCSSPseudoClasses::firstChild;
1271) if (setNodeFlags)
1272) parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
^ 162
1273)
1274) result = (!checkFirst ||
^ 1,204 (10/11)
1275) data.GetNthIndex(PR_FALSE, PR_FALSE, PR_TRUE) == 1) &&
1276) (!checkLast ||
1277) data.GetNthIndex(PR_FALSE, PR_TRUE, PR_TRUE) == 1);
1278) } else {
1279) result = PR_FALSE;
^ 0
1280) }
1281) }
1282) else if (nsCSSPseudoClasses::nthChild == pseudoClass->mAtom ||
^ 3,447,368 (8)
1283) nsCSSPseudoClasses::nthLastChild == pseudoClass->mAtom ||
1284) nsCSSPseudoClasses::nthOfType == pseudoClass->mAtom ||
1285) nsCSSPseudoClasses::nthLastOfType == pseudoClass->mAtom) {
1286) nsIContent *parent = data.mParentContent;
^ 0
1287) if (parent) {
1288) PRBool isOfType =
^ 0 (8)
1289) nsCSSPseudoClasses::nthOfType == pseudoClass->mAtom ||
1290) nsCSSPseudoClasses::nthLastOfType == pseudoClass->mAtom;
1291) PRBool isFromEnd =
^ 0 (7)
1292) nsCSSPseudoClasses::nthLastChild == pseudoClass->mAtom ||
1293) nsCSSPseudoClasses::nthLastOfType == pseudoClass->mAtom;
1294) if (setNodeFlags) {
1295) if (isFromEnd)
^ 0
1296) parent->SetFlags(NODE_HAS_SLOW_SELECTOR);
^ 0
1297) else
1298) parent->SetFlags(NODE_HAS_SLOW_SELECTOR_NOAPPEND);
^ 0
1299) }
1300)
1301) const PRInt32 index = data.GetNthIndex(isOfType, isFromEnd, PR_FALSE);
^ 0 (2)
1302) if (index <= 0) {
1303) // Node is anonymous content (not really a child of its parent).
1304) result = PR_FALSE;
^ 0
1305) } else {
1306) const PRInt32 a = pseudoClass->u.mNumbers[0];
^ 0
1307) const PRInt32 b = pseudoClass->u.mNumbers[1];
1308) // result should be true if there exists n >= 0 such that
1309) // a * n + b == index.
1310) if (a == 0) {
1311) result = b == index;
^ 0 (3)
1312) } else {
1313) // Integer division in C does truncation (towards 0). So
1314) // check that the result is nonnegative, and that there was no
1315) // truncation.
1316) const PRInt32 n = (index - b) / a;
^ 0
1317) result = n >= 0 && (a * n == index - b);
^ 0 (3)
1318) }
1319) }
1320) } else {
1321) result = PR_FALSE;
^ 0
1322) }
1323) }
1324) else if (nsCSSPseudoClasses::firstOfType == pseudoClass->mAtom ||
^ 2,585,278 (6)
1325) nsCSSPseudoClasses::lastOfType == pseudoClass->mAtom ||
1326) nsCSSPseudoClasses::onlyOfType == pseudoClass->mAtom) {
1327) nsIContent *parent = data.mParentContent;
^ 62
1328) if (parent) {
1329) const PRBool checkFirst =
^ 124 (2)
1330) pseudoClass->mAtom != nsCSSPseudoClasses::lastOfType;
1331) const PRBool checkLast =
^ 62
1332) pseudoClass->mAtom != nsCSSPseudoClasses::firstOfType;
1333) if (setNodeFlags) {
1334) if (checkLast)
^ 62
1335) parent->SetFlags(NODE_HAS_SLOW_SELECTOR);
^ 0
1336) else
1337) parent->SetFlags(NODE_HAS_SLOW_SELECTOR_NOAPPEND);
^ 62
1338) }
1339)
1340) result = (!checkFirst ||
^ 372 (6/11)
1341) data.GetNthIndex(PR_TRUE, PR_FALSE, PR_TRUE) == 1) &&
1342) (!checkLast ||
1343) data.GetNthIndex(PR_TRUE, PR_TRUE, PR_TRUE) == 1);
1344) } else {
1345) result = PR_FALSE;
^ 0
1346) }
1347) }
1348) else if (nsCSSPseudoClasses::empty == pseudoClass->mAtom ||
^ 1,723,250 (4)
1349) nsCSSPseudoClasses::mozOnlyWhitespace == pseudoClass->mAtom) {
1350) nsIContent *child = nsnull;
^ 333
1351) nsIContent *element = data.mContent;
1352) const PRBool isWhitespaceSignificant =
^ 333
1353) nsCSSPseudoClasses::empty == pseudoClass->mAtom;
1354) PRInt32 index = -1;
1355)
1356) if (setNodeFlags)
1357) element->SetFlags(NODE_HAS_EMPTY_SELECTOR);
^ 333
1358)
1359) do {
1360) child = element->GetChildAt(++index);
^ 710 (4)
1361) // stop at first non-comment (and non-whitespace for
1362) // :-moz-only-whitespace) node
1363) } while (child && !IsSignificantChild(child, PR_TRUE, isWhitespaceSignificant));
^ 360 (2)
1364) result = (child == nsnull);
^ 666 (3)
1365) }
1366) else if (nsCSSPseudoClasses::mozEmptyExceptChildrenWithLocalname == pseudoClass->mAtom) {
^ 861,052 (2)
1367) NS_ASSERTION(pseudoClass->u.mString, "Must have string!");
^ 0
1368) nsIContent *child = nsnull;
^ 0
1369) nsIContent *element = data.mContent;
1370) PRInt32 index = -1;
1371)
1372) if (setNodeFlags)
1373) element->SetFlags(NODE_HAS_SLOW_SELECTOR);
^ 0
1374)
1375) do {
1376) child = element->GetChildAt(++index);
^ 0 (2)
1377) } while (child &&
^ 0 (16)
1378) (!IsSignificantChild(child, PR_TRUE, PR_FALSE) ||
1379) (child->GetNameSpaceID() == element->GetNameSpaceID() &&
1380) child->Tag()->Equals(nsDependentString(pseudoClass->u.mString)))));
1381) result = (child == nsnull);
^ 0 (3)
1382) }
1383) else if (nsCSSPseudoClasses::mozSystemMetric == pseudoClass->mAtom) {
^ 861,052 (2)
1384) if (!sSystemMetrics && !InitSystemMetrics()) {
^ 8,356 (3)
1385) return PR_FALSE;
^ 0
1386) }
1387) NS_ASSERTION(pseudoClass->u.mString, "Must have string!");
^ 8,354
1388) nsCOMPtr<nsIAtom> metric = do_GetAtom(pseudoClass->u.mString);
^ 16,708 (2)
1389) result = sSystemMetrics->IndexOf(metric) !=
^ 25,062 (4)
1390) sSystemMetrics->NoIndex;
1391) }
^ 8,354
1392) else if (nsCSSPseudoClasses::mozHasHandlerRef == pseudoClass->mAtom) {
^ 844,344 (2)
1393) nsIContent *child = nsnull;
^ 0
1394) nsIContent *element = data.mContent;
1395) PRInt32 index = -1;
1396)
1397) result = PR_FALSE;
1398) if (element) {
1399) do {
1400) child = element->GetChildAt(++index);
^ 0 (2)
1401) if (child && child->IsNodeOfType(nsINode::eHTML) &&
^ 0 (13)
1402) child->Tag() == nsGkAtoms::param &&
1403) child->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
1404) NS_LITERAL_STRING("pluginurl"), eIgnoreCase)) {
1405) result = PR_TRUE;
^ 0
1406) break;
1407) }
1408) } while (child);
^ 0
1409) }
1410) }
1411) else if (nsCSSPseudoClasses::root == pseudoClass->mAtom) {
^ 844,344 (2)
1412) result = (data.mParentContent == nsnull &&
^ 27,459 (8/9)
1413) data.mContent &&
1414) data.mContent ==
1415) data.mContent->GetOwnerDoc()->GetRootContent());
1416) }
1417) else if (nsCSSPseudoClasses::mozBoundElement == pseudoClass->mAtom) {
^ 826,070 (2)
1418) // XXXldb How do we know where the selector came from? And what
1419) // if there are multiple bindings, and we should be matching the
1420) // outer one?
1421) result = (data.mScopedRoot && data.mScopedRoot == data.mContent);
^ 0 (4)
1422) }
1423) else if (nsCSSPseudoClasses::lang == pseudoClass->mAtom) {
^ 826,070 (2)
1424) NS_ASSERTION(nsnull != pseudoClass->u.mString, "null lang parameter");
^ 0
1425) result = PR_FALSE;
^ 0
1426) if (pseudoClass->u.mString && *pseudoClass->u.mString) {
^ 0
1427) // We have to determine the language of the current element. Since
1428) // this is currently no property and since the language is inherited
1429) // from the parent we have to be prepared to look at all parent
1430) // nodes. The language itself is encoded in the LANG attribute.
1431) const nsString* lang = data.GetLang();
^ 0 (2)
1432) if (lang && !lang->IsEmpty()) { // null check for out-of-memory
^ 0 (2)
1433) result = nsStyleUtil::DashMatchCompare(*lang,
^ 0 (4)
1434) nsDependentString(pseudoClass->u.mString),
1435) nsCaseInsensitiveStringComparator());
1436) }
1437) else if (data.mContent) {
^ 0
1438) nsIDocument* doc = data.mContent->GetDocument();
^ 0 (2)
1439) if (doc) {
1440) // Try to get the language from the HTTP header or if this
1441) // is missing as well from the preferences.
1442) // The content language can be a comma-separated list of
1443) // language codes.
1444) nsAutoString language;
^ 0
1445) doc->GetContentLanguage(language);
^ 0
1446)
1447) nsDependentString langString(pseudoClass->u.mString);
^ 0
1448) language.StripWhitespace();
^ 0
1449) PRInt32 begin = 0;
^ 0
1450) PRInt32 len = language.Length();
^ 0
1451) while (begin < len) {
^ 0 (2)
1452) PRInt32 end = language.FindChar(PRUnichar(','), begin);
^ 0 (2)
1453) if (end == kNotFound) {
1454) end = len;
^ 0
1455) }
1456) if (nsStyleUtil::DashMatchCompare(Substring(language, begin, end-begin),
^ 0 (5)
1457) langString,
1458) nsCaseInsensitiveStringComparator())) {
1459) result = PR_TRUE;
^ 0
1460) break;
1461) }
1462) begin = end + 1;
1463) }
1464) }
^ 0 (2)
1465) }
1466) }
1467) } else if (nsCSSPseudoClasses::active == pseudoClass->mAtom) {
^ 826,070 (2)
1468) stateToCheck = NS_EVENT_STATE_ACTIVE;
^ 26,091
1469) }
1470) else if (nsCSSPseudoClasses::focus == pseudoClass->mAtom) {
^ 773,888 (2)
1471) stateToCheck = NS_EVENT_STATE_FOCUS;
^ 43,661
1472) }
1473) else if (nsCSSPseudoClasses::hover == pseudoClass->mAtom) {
^ 686,566 (2)
1474) stateToCheck = NS_EVENT_STATE_HOVER;
^ 74,311
1475) }
1476) else if (nsCSSPseudoClasses::mozDragOver == pseudoClass->mAtom) {
^ 537,944 (2)
1477) stateToCheck = NS_EVENT_STATE_DRAGOVER;
^ 0
1478) }
1479) else if (nsCSSPseudoClasses::target == pseudoClass->mAtom) {
^ 537,944 (2)
1480) stateToCheck = NS_EVENT_STATE_URLTARGET;
^ 0
1481) }
1482) else if (IsLinkPseudo(pseudoClass->mAtom)) {
^ 806,916 (3)
1483) if (data.mIsLink) {
^ 266,901
1484) if (nsCSSPseudoClasses::mozAnyLink == pseudoClass->mAtom) {
^ 2,632 (2)
1485) result = PR_TRUE;
^ 528
1486) }
1487) else {
1488) NS_ASSERTION(nsCSSPseudoClasses::link == pseudoClass->mAtom ||
^ 788
1489) nsCSSPseudoClasses::visited == pseudoClass->mAtom,
1490) "somebody changed IsLinkPseudo");
1491) NS_ASSERTION(data.mLinkState == eLinkState_Unvisited ||
^ 788
1492) data.mLinkState == eLinkState_Visited,
1493) "unexpected link state for mIsLink");
1494) if (aStateMask & NS_EVENT_STATE_VISITED) {
^ 788
1495) result = PR_TRUE;
^ 0
1496) if (aDependence)
1497) *aDependence = PR_TRUE;
^ 0
1498) } else {
1499) result = ((eLinkState_Unvisited == data.mLinkState) ==
^ 2,364 (4)
1500) (nsCSSPseudoClasses::link == pseudoClass->mAtom));
1501) }
1502) }
1503) }
1504) else {
1505) result = PR_FALSE; // not a link
^ 265,585
1506) }
1507) }
1508) else if (nsCSSPseudoClasses::checked == pseudoClass->mAtom) {
^ 4,142 (2)
1509) // This pseudoclass matches the selected state on the following elements:
1510) // <option>
1511) // <input type=checkbox>
1512) // <input type=radio>
1513) stateToCheck = NS_EVENT_STATE_CHECKED;
^ 12
1514) }
1515) else if (nsCSSPseudoClasses::enabled == pseudoClass->mAtom) {
^ 4,118 (2)
1516) stateToCheck = NS_EVENT_STATE_ENABLED;
^ 0
1517) }
1518) else if (nsCSSPseudoClasses::disabled == pseudoClass->mAtom) {
^ 4,118 (2)
1519) stateToCheck = NS_EVENT_STATE_DISABLED;
^ 0
1520) }
1521) else if (nsCSSPseudoClasses::mozBroken == pseudoClass->mAtom) {
^ 4,118 (2)
1522) stateToCheck = NS_EVENT_STATE_BROKEN;
^ 186
1523) }
1524) else if (nsCSSPseudoClasses::mozUserDisabled == pseudoClass->mAtom) {
^ 3,746 (2)
1525) stateToCheck = NS_EVENT_STATE_USERDISABLED;
^ 186
1526) }
1527) else if (nsCSSPseudoClasses::mozSuppressed == pseudoClass->mAtom) {
^ 3,374 (2)
1528) stateToCheck = NS_EVENT_STATE_SUPPRESSED;
^ 697
1529) }
1530) else if (nsCSSPseudoClasses::mozLoading == pseudoClass->mAtom) {
^ 1,980 (2)
1531) stateToCheck = NS_EVENT_STATE_LOADING;
^ 188
1532) }
1533) else if (nsCSSPseudoClasses::mozTypeUnsupported == pseudoClass->mAtom) {
^ 1,604 (2)
1534) stateToCheck = NS_EVENT_STATE_TYPE_UNSUPPORTED;
^ 0
1535) }
1536) else if (nsCSSPseudoClasses::mozHandlerDisabled == pseudoClass->mAtom) {
^ 1,604 (2)
1537) stateToCheck = NS_EVENT_STATE_HANDLER_DISABLED;
^ 0
1538) }
1539) else if (nsCSSPseudoClasses::mozHandlerBlocked == pseudoClass->mAtom) {
^ 1,604 (2)
1540) stateToCheck = NS_EVENT_STATE_HANDLER_BLOCKED;
^ 0
1541) }
1542) else if (nsCSSPseudoClasses::defaultPseudo == pseudoClass->mAtom) {
^ 1,604 (2)
1543) stateToCheck = NS_EVENT_STATE_DEFAULT;
^ 0
1544) }
1545) else if (nsCSSPseudoClasses::required == pseudoClass->mAtom) {
^ 1,604 (2)
1546) stateToCheck = NS_EVENT_STATE_REQUIRED;
^ 0
1547) }
1548) else if (nsCSSPseudoClasses::optional == pseudoClass->mAtom) {
^ 1,604 (2)
1549) stateToCheck = NS_EVENT_STATE_OPTIONAL;
^ 0
1550) }
1551) else if (nsCSSPseudoClasses::valid == pseudoClass->mAtom) {
^ 1,604 (2)
1552) stateToCheck = NS_EVENT_STATE_VALID;
^ 0
1553) }
1554) else if (nsCSSPseudoClasses::invalid == pseudoClass->mAtom) {
^ 1,604 (2)
1555) stateToCheck = NS_EVENT_STATE_INVALID;
^ 0
1556) }
1557) else if (nsCSSPseudoClasses::inRange == pseudoClass->mAtom) {
^ 1,604 (2)
1558) stateToCheck = NS_EVENT_STATE_INRANGE;
^ 0
1559) }
1560) else if (nsCSSPseudoClasses::outOfRange == pseudoClass->mAtom) {
^ 1,604 (2)
1561) stateToCheck = NS_EVENT_STATE_OUTOFRANGE;
^ 0
1562) }
1563) else if (nsCSSPseudoClasses::mozReadOnly == pseudoClass->mAtom) {
^ 1,604 (2)
1564) stateToCheck = NS_EVENT_STATE_MOZ_READONLY;
^ 0
1565) }
1566) else if (nsCSSPseudoClasses::mozReadWrite == pseudoClass->mAtom) {
^ 1,604 (2)
1567) stateToCheck = NS_EVENT_STATE_MOZ_READWRITE;
^ 767
1568) }
1569) else if (nsCSSPseudoClasses::indeterminate == pseudoClass->mAtom) {
^ 70 (2)
1570) stateToCheck = NS_EVENT_STATE_INDETERMINATE;
^ 0
1571) }
1572) else if (nsCSSPseudoClasses::mozIsHTML == pseudoClass->mAtom) {
^ 70 (2)
1573) result = data.mIsHTMLContent &&
^ 175 (5/7)
1574) data.mContent->GetNameSpaceID() == kNameSpaceID_None;
1575) }
1576) #ifdef MOZ_MATHML
1577) else if (nsCSSPseudoClasses::mozMathIncrementScriptLevel == pseudoClass->mAtom) {
^ 0 (2)
1578) stateToCheck = NS_EVENT_STATE_INCREMENT_SCRIPT_LEVEL;
^ 0
1579) }
1580) #endif
1581) else {
1582) NS_ERROR("CSS parser parsed a pseudo-class that we do not handle");
^ 0
1583) result = PR_FALSE; // unknown pseudo class
^ 0
1584) }
1585) if (stateToCheck) {
^ 431,460
1586) // check if the element is event-sensitive for :hover and :active
1587) if ((stateToCheck & (NS_EVENT_STATE_HOVER | NS_EVENT_STATE_ACTIVE)) &&
^ 370,709 (11)
1588) data.mCompatMode == eCompatibility_NavQuirks &&
1589) // global selector (but don't check .class):
1590) !aSelector->mTag && !aSelector->mIDList && !aSelector->mAttrList &&
1591) // This (or the other way around) both make :not() asymmetric
1592) // in quirks mode (and it's hard to work around since we're
1593) // testing the current mNegations, not the first
1594) // (unnegated)). This at least makes it closer to the spec.
1595) !isNegated &&
1596) // important for |IsQuirkEventSensitive|:
1597) data.mIsHTMLContent && !data.mIsLink &&
1598) !IsQuirkEventSensitive(data.mContentTag)) {
1599) // In quirks mode, only make certain elements sensitive to
1600) // selectors ":hover" and ":active".
1601) result = PR_FALSE;
^ 9,100
1602) } else {
1603) if (aStateMask & stateToCheck) {
^ 136,999
1604) result = PR_TRUE;
^ 26,846
1605) if (aDependence)
1606) *aDependence = PR_TRUE;
^ 0
1607) } else {
1608) result = (0 != (data.mEventState & stateToCheck));
^ 220,306 (3)
1609) }
1610) }
1611) }
1612) }
1613)
1614) if (result && aSelector->mAttrList) {
^ 70,882,345 (2)
1615) // test for attribute match
1616) if (!data.mHasAttributes && !aAttribute) {
^ 316,174 (2)
1617) // if no attributes on the content, no match
1618) result = PR_FALSE;
^ 36,038
1619) } else {
1620) NS_ASSERTION(data.mContent,
^ 244,098
1621) "Must have content if either data.mHasAttributes or "
1622) "aAttribute is set!");
1623) result = PR_TRUE;
^ 244,098
1624) nsAttrSelector* attr = aSelector->mAttrList;
1625) do {
1626) if (attr->mAttr == aAttribute) {
^ 507,370 (2)
1627) // XXX we should really have a namespace, not just an attr
1628) // name, in HasAttributeDependentStyle!
1629) result = PR_TRUE;
^ 12,251
1630) if (aDependence)
1631) *aDependence = PR_TRUE;
^ 144
1632) }
1633) else if (attr->mNameSpace == kNameSpaceID_Unknown) {
^ 241,434
1634) // Attr selector with a wildcard namespace. We have to examine all
1635) // the attributes on our content node.... This sort of selector is
1636) // essentially a boolean OR, over all namespaces, of equivalent attr
1637) // selectors with those namespaces. So to evaluate whether it
1638) // matches, evaluate for each namespace (the only namespaces that
1639) // have a chance at matching, of course, are ones that the element
1640) // actually has attributes in), short-circuiting if we ever match.
1641) PRUint32 attrCount = data.mContent->GetAttrCount();
^ 0 (2)
1642) result = PR_FALSE;
1643) for (PRUint32 i = 0; i < attrCount; ++i) {
^ 0 (2)
1644) const nsAttrName* attrName =
^ 0 (2)
1645) data.mContent->GetAttrNameAt(i);
1646) NS_ASSERTION(attrName, "GetAttrCount lied or GetAttrNameAt failed");
^ 0
1647) if (attrName->LocalName() != attr->mAttr) {
^ 0 (3)
1648) continue;
1649) }
1650) if (attr->mFunction == NS_ATTR_FUNC_SET) {
^ 0
1651) result = PR_TRUE;
^ 0
1652) } else {
1653) nsAutoString value;
^ 0
1654) #ifdef DEBUG
1655) PRBool hasAttr =
1656) #endif
1657) data.mContent->GetAttr(attrName->NamespaceID(),
^ 0 (3)
1658) attrName->LocalName(), value);
1659) NS_ASSERTION(hasAttr, "GetAttrNameAt lied");
^ 0
1660) result = AttrMatchesValue(attr, value);
^ 0 (2)
1661) }
1662)
1663) // At this point |result| has been set by us
1664) // explicitly in this loop. If it's PR_FALSE, we may still match
1665) // -- the content may have another attribute with the same name but
1666) // in a different namespace. But if it's PR_TRUE, we are done (we
1667) // can short-circuit the boolean OR described above).
1668) if (result) {
^ 0
1669) break;
1670) }
1671) }
1672) }
1673) else if (attr->mFunction == NS_ATTR_FUNC_EQUALS) {
^ 241,434
1674) result =
^ 1,009,380 (6)
1675) data.mContent->
1676) AttrValueIs(attr->mNameSpace, attr->mAttr, attr->mValue,
1677) attr->mCaseSensitive ? eCaseMatters : eIgnoreCase);
1678) }
1679) else if (!data.mContent->HasAttr(attr->mNameSpace, attr->mAttr)) {
^ 118,674 (3)
1680) result = PR_FALSE;
^ 38,415
1681) }
1682) else if (attr->mFunction != NS_ATTR_FUNC_SET) {
^ 1,143
1683) nsAutoString value;
^ 357
1684) #ifdef DEBUG
1685) PRBool hasAttr =
1686) #endif
1687) data.mContent->GetAttr(attr->mNameSpace, attr->mAttr, value);
^ 714 (2)
1688) NS_ASSERTION(hasAttr, "HasAttr lied");
^ 357
1689) result = AttrMatchesValue(attr, value);
^ 714 (2)
1690) }
1691)
1692) attr = attr->mNext;
^ 253,685
1693) } while (attr && result);
^ 28,546
1694) }
1695) }
1696) nsAtomList* IDList = aSelector->mIDList;
^ 35,639,007
1697) if (result && IDList) {
^ 35,000,057
1698) // test for ID match
1699) result = PR_FALSE;
^ 3,079,701
1700)
1701) if (aAttribute && aAttribute == data.mContent->GetIDAttributeName()) {
^ 16,960 (2)
1702) result = PR_TRUE;
^ 266
1703) if (aDependence)
1704) *aDependence = PR_TRUE;
^ 2
1705) }
1706) else if (nsnull != data.mContentID) {
^ 3,079,435
1707) // case sensitivity: bug 93371
1708) const PRBool isCaseSensitive =
^ 2,966,716 (3)
1709) data.mCompatMode != eCompatibility_NavQuirks;
1710)
1711) result = PR_TRUE;
^ 1,483,358
1712) if (isCaseSensitive) {
1713) do {
1714) if (IDList->mAtom != data.mContentID) {
^ 48,518 (2)
1715) result = PR_FALSE;
^ 21,988
1716) break;
1717) }
1718) IDList = IDList->mNext;
^ 2,271
1719) } while (IDList);
1720) } else {
1721) const char* id1Str;
1722) data.mContentID->GetUTF8String(&id1Str);
^ 1,459,099
1723) nsDependentCString id1(id1Str);
^ 1,459,099
1724) do {
1725) const char* id2Str;
1726) IDList->mAtom->GetUTF8String(&id2Str);
^ 2,918,198 (2)
1727) if (!id1.Equals(id2Str, nsCaseInsensitiveCStringComparator())) {
^ 4,377,297 (3)
1728) result = PR_FALSE;
^ 1,455,376
1729) break;
1730) }
1731) IDList = IDList->mNext;
^ 3,723
1732) } while (IDList);
1733) }
^ 1,459,099
1734) }
1735) }
1736)
1737) if (result && aSelector->mClassList) {
^ 67,565,623 (2)
1738) // test for class match
1739) if (aAttribute && aAttribute == data.mContent->GetClassAttributeName()) {
^ 31,879,177 (3)
1740) result = PR_TRUE;
^ 939,186
1741) if (aDependence)
1742) *aDependence = PR_TRUE;
^ 0
1743) }
1744) else {
1745) // case sensitivity: bug 93371
1746) const PRBool isCaseSensitive =
^ 58,119,774 (3)
1747) data.mCompatMode != eCompatibility_NavQuirks;
1748)
1749) nsAtomList* classList = aSelector->mClassList;
^ 29,059,887
1750) const nsAttrValue *elementClasses = data.mClasses;
1751) while (nsnull != classList) {
^ 29,277,540 (2)
1752) if (!(elementClasses && elementClasses->Contains(classList->mAtom, isCaseSensitive ? eCaseMatters : eIgnoreCase))) {
^ 138,905,271 (11)
1753) result = PR_FALSE;
^ 28,842,234
1754) break;
1755) }
1756) classList = classList->mNext;
1757) }
1758) }
1759) }
1760)
1761) // apply SelectorMatches to the negated selectors in the chain
1762) if (!isNegated) {
^ 35,639,007
1763) for (nsCSSSelector *negation = aSelector->mNegations;
^ 38,727,785 (3) ^ 35,629,985
1764) result && negation; negation = negation->mNegations) {
1765) PRBool dependence = PR_FALSE;
^ 9,022
1766) result = !SelectorMatches(data, negation, aStateMask,
^ 18,044 (3)
1767) aAttribute, aForStyling, &dependence);
1768) // If the selector does match due to the dependence on aStateMask
1769) // or aAttribute, then we want to keep result true so that the
1770) // final result of SelectorMatches is true. Doing so tells
1771) // StateEnumFunc or AttributeEnumFunc that there is a dependence
1772) // on the state or attribute.
1773) result = result || dependence;
^ 20,430 (4)
1774) }
1775) }
1776) return result;
^ 35,639,007
1777) }
1778)
1779) #undef STATE_CHECK
1780)
1781) // Right now, there are four operators:
1782) // PRUnichar(0), the descendant combinator, is greedy
1783) // '~', the indirect adjacent sibling combinator, is greedy
1784) // '+' and '>', the direct adjacent sibling and child combinators, are not
1785) #define NS_IS_GREEDY_OPERATOR(ch) (ch == PRUnichar(0) || ch == PRUnichar('~'))
1786)
1787) static PRBool SelectorMatchesTree(RuleProcessorData& aPrevData,
^ 2,783,365
1788) nsCSSSelector* aSelector,
1789) PRBool aForStyling)
1790) {
1791) nsCSSSelector* selector = aSelector;
1792) RuleProcessorData* prevdata = &aPrevData;
1793) while (selector) { // check compound selectors
^ 37,381,663 (2)
1794) // If we don't already have a RuleProcessorData for the next
1795) // appropriate content (whether parent or previous sibling), create
1796) // one.
1797)
1798) // for adjacent sibling combinators, the content to test against the
1799) // selector is the previous sibling *element*
1800) RuleProcessorData* data;
1801) if (PRUnichar('+') == selector->mOperator ||
^ 74,640,434 (2)
1802) PRUnichar('~') == selector->mOperator) {
1803) data = prevdata->mPreviousSiblingData;
^ 185
1804) if (!data) {
1805) nsIContent* content = prevdata->mContent;
^ 185
1806) nsIContent* parent = content->GetParent();
^ 185
1807) if (parent) {
1808) parent->SetFlags(NODE_HAS_SLOW_SELECTOR_NOAPPEND);
^ 185
1809)
1810) PRInt32 index = parent->IndexOf(content);
^ 370 (2)
1811) while (0 <= --index) {
^ 185 (1/2)
1812) content = parent->GetChildAt(index);
^ 110 (2)
1813) if (content->IsNodeOfType(nsINode::eELEMENT)) {
^ 55
1814) data = RuleProcessorData::Create(prevdata->mPresContext, content,
^ 110 (2)
1815) prevdata->mRuleWalker,
1816) prevdata->mCompatMode);
1817) prevdata->mPreviousSiblingData = data;
1818) break;
1819) }
1820) }
1821) }
1822) }
1823) }
1824) // for descendant combinators and child combinators, the content
1825) // to test against is the parent
1826) else {
1827) data = prevdata->mParentData;
^ 37,320,032
1828) if (!data) {
1829) nsIContent *content = prevdata->mContent->GetParent();
^ 6,237,570 (2)
1830) // GetParent could return a document fragment; we only want
1831) // element parents.
1832) if (content && content->IsNodeOfType(nsINode::eELEMENT)) {
^ 1,194,516 (2)
1833) data = RuleProcessorData::Create(prevdata->mPresContext, content,
^ 1,194,516 (2)
1834) prevdata->mRuleWalker,
1835) prevdata->mCompatMode);
1836) prevdata->mParentData = data;
1837) }
1838) }
1839) }
1840) if (! data) {
^ 37,320,217
1841) return PR_FALSE;
^ 2,521,657
1842) }
1843) if (SelectorMatches(*data, selector, 0, nsnull, aForStyling)) {
^ 69,597,120 (2)
1844) // to avoid greedy matching, we need to recur if this is a
1845) // descendant or general sibling combinator and the next
1846) // combinator is different, but we can make an exception for
1847) // sibling, then parent, since a sibling's parent is always the
1848) // same.
1849) if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) &&
^ 411,124 (4/6)
1850) (selector->mNext) &&
1851) (selector->mNext->mOperator != selector->mOperator) &&
1852) !(selector->mOperator == '~' &&
1853) selector->mNext->mOperator == PRUnichar(0))) {
1854)
1855) // pretend the selector didn't match, and step through content
1856) // while testing the same selector
1857)
1858) // This approach is slightly strange in that when it recurs
1859) // it tests from the top of the content tree, down. This
1860) // doesn't matter much for performance since most selectors
1861) // don't match. (If most did, it might be faster...)
1862) if (SelectorMatchesTree(*data, selector, aForStyling)) {
^ 0 (2)
1863) return PR_TRUE;
^ 0
1864) }
1865) }
1866) selector = selector->mNext;
^ 117,714
1867) }
1868) else {
1869) // for adjacent sibling and child combinators, if we didn't find
1870) // a match, we're done
1871) if (!NS_IS_GREEDY_OPERATOR(selector->mOperator)) {
^ 34,881,108 (2)
1872) return PR_FALSE; // parent was required to match
^ 200,262
1873) }
1874) }
1875) prevdata = data;
1876) }
1877) return PR_TRUE; // all the selectors matched.
^ 61,446
1878) }
1879)
1880) static void ContentEnumFunc(nsICSSStyleRule* aRule, nsCSSSelector* aSelector,
^ 2,584,135
1881) void* aData)
1882) {
1883) ElementRuleProcessorData* data = (ElementRuleProcessorData*)aData;
1884)
1885) if (SelectorMatches(*data, aSelector, 0, nsnull, PR_TRUE)) {
^ 2,584,135
1886) nsCSSSelector *next = aSelector->mNext;
^ 2,019,108
1887) if (!next || SelectorMatchesTree(*data, next, PR_TRUE)) {
^ 3,680,968 (2)
1888) // for performance, require that every implementation of
1889) // nsICSSStyleRule return the same pointer for nsIStyleRule (why
1890) // would anything multiply inherit nsIStyleRule anyway?)
1891) #ifdef DEBUG
1892) nsCOMPtr<nsIStyleRule> iRule = do_QueryInterface(aRule);
1893) NS_ASSERTION(static_cast<nsIStyleRule*>(aRule) == iRule.get(),
1894) "Please fix QI so this performance optimization is valid");
1895) #endif
1896) data->mRuleWalker->Forward(static_cast<nsIStyleRule*>(aRule));
^ 227,664
1897) // nsStyleSet will deal with the !important rule
1898) }
1899) }
1900) }
^ 2,584,135
1901)
1902) NS_IMETHODIMP
1903) nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData)
^ 135,147
1904) {
1905) NS_PRECONDITION(aData->mContent->IsNodeOfType(nsINode::eELEMENT),
^ 135,147
1906) "content must be element");
1907)
1908) RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
^ 270,294 (2)
1909)
1910) if (cascade) {
1911) cascade->mRuleHash.EnumerateAllRules(aData->mNameSpaceID,
^ 135,147
1912) aData->mContentTag,
1913) aData->mContentID,
1914) aData->mClasses,
1915) ContentEnumFunc,
1916) aData);
1917) }
1918) return NS_OK;
^ 135,147
1919) }
1920)
1921) static void PseudoEnumFunc(nsICSSStyleRule* aRule, nsCSSSelector* aSelector,
^ 1,292,423
1922) void* aData)
1923) {
1924) PseudoRuleProcessorData* data = (PseudoRuleProcessorData*)aData;
1925)
1926) NS_ASSERTION(aSelector->mTag == data->mPseudoTag, "RuleHash failure");
^ 1,292,423
1927) PRBool matches = PR_TRUE;
^ 1,292,423
1928) if (data->mComparator)
1929) data->mComparator->PseudoMatches(data->mPseudoTag, aSelector, &matches);
^ 0
1930)
1931) if (matches) {
^ 1,292,423
1932) nsCSSSelector *selector = aSelector->mNext;
^ 1,292,423
1933)
1934) if (selector) { // test next selector specially
1935) if (PRUnichar('+') == selector->mOperator) {
^ 1,257,115
1936) return; // not valid here, can't match
^ 0
1937) }
1938) if (SelectorMatches(*data, selector, 0, nsnull, PR_TRUE)) {
^ 2,514,230 (2)
1939) selector = selector->mNext;
^ 54
1940) }
1941) else {
1942) if (PRUnichar('>') == selector->mOperator) {
^ 1,257,061
1943) return; // immediate parent didn't match
^ 1,257,061
1944) }
1945) }
1946) }
1947)
1948) if (selector &&
^ 35,364 (3)
1949) (! SelectorMatchesTree(*data, selector, PR_TRUE))) {
1950) return; // remaining selectors didn't match
^ 1
1951) }
1952)
1953) // for performance, require that every implementation of
1954) // nsICSSStyleRule return the same pointer for nsIStyleRule (why
1955) // would anything multiply inherit nsIStyleRule anyway?)
1956) #ifdef DEBUG
1957) nsCOMPtr<nsIStyleRule> iRule = do_QueryInterface(aRule);
1958) NS_ASSERTION(static_cast<nsIStyleRule*>(aRule) == iRule.get(),
1959) "Please fix QI so this performance optimization is valid");
1960) #endif
1961) data->mRuleWalker->Forward(static_cast<nsIStyleRule*>(aRule));
^ 35,361
1962) // nsStyleSet will deal with the !important rule
1963) }
1964) }
^ 35,361
1965)
1966) NS_IMETHODIMP
1967) nsCSSRuleProcessor::RulesMatching(PseudoRuleProcessorData* aData)
^ 718,369
1968) {
1969) NS_PRECONDITION(!aData->mContent ||
^ 718,369
1970) aData->mContent->IsNodeOfType(nsINode::eELEMENT),
1971) "content (if present) must be element");
1972)
1973) RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
^ 1,436,738 (2)
1974)
1975) if (cascade) {
1976) cascade->mRuleHash.EnumerateTagRules(aData->mPseudoTag,
^ 718,369
1977) PseudoEnumFunc, aData);
1978) }
1979) return NS_OK;
^ 718,369
1980) }
1981)
1982) inline PRBool
1983) IsSiblingOperator(PRUnichar oper)
^ 12,185,324
1984) {
1985) return oper == PRUnichar('+') || oper == PRUnichar('~');
^ 36,555,916 (4)
1986) }
1987)
1988) NS_IMETHODIMP
1989) nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData,
^ 1,821
1990) nsReStyleHint* aResult)
1991) {
1992) NS_PRECONDITION(aData->mContent->IsNodeOfType(nsINode::eELEMENT),
^ 1,821
1993) "content must be element");
1994)
1995) RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
^ 3,642 (2)
1996)
1997) // Look up the content node in the state rule list, which points to
1998) // any (CSS2 definition) simple selector (whether or not it is the
1999) // subject) that has a state pseudo-class on it. This means that this
2000) // code will be matching selectors that aren't real selectors in any
2001) // stylesheet (e.g., if there is a selector "body > p:hover > a", then
2002) // "body > p:hover" will be in |cascade->mStateSelectors|). Note that
2003) // |IsStateSelector| below determines which selectors are in
2004) // |cascade->mStateSelectors|.
2005) if (cascade) {
2006) *aResult = nsReStyleHint(0);
^ 1,821
2007) nsCSSSelector **iter = cascade->mStateSelectors.Elements(),
^ 1,821
2008) **end = iter + cascade->mStateSelectors.Length();
^ 1,821
2009) for(; iter != end; ++iter) {
^ 112,732 (2)
2010) nsCSSSelector* selector = *iter;
^ 110,911
2011)
2012) nsReStyleHint possibleChange = IsSiblingOperator(selector->mOperator) ?
^ 443,644 (5/6)
2013) eReStyle_LaterSiblings :
2014) (selector->mIsNextOfSomething ? eReStyle_Subtree : eReStyle_Self);
2015)
2016) // If *aResult already includes all the bits of possibleChange,
2017) // don't bother calling SelectorMatches, since even if it returns false
2018) // *aResult won't change.
2019) if ((possibleChange & ~(*aResult)) &&
^ 206,246 (4)
2020) SelectorMatches(*aData, selector, aData->mStateMask, nsnull, PR_TRUE) &&
2021) SelectorMatchesTree(*aData, selector->mNext, PR_TRUE)) {
2022) *aResult = nsReStyleHint(*aResult | possibleChange);
^ 147
2023) }
2024) }
2025) }
2026) return NS_OK;
^ 1,821
2027) }
2028)
2029) struct AttributeEnumData {
2030) AttributeEnumData(AttributeRuleProcessorData *aData)
^ 34,833
2031) : data(aData), change(nsReStyleHint(0)) {}
2032)
2033) AttributeRuleProcessorData *data;
2034) nsReStyleHint change;
2035) };
2036)
2037)
2038) static void
2039) AttributeEnumFunc(nsCSSSelector* aSelector, AttributeEnumData* aData)
^ 12,074,413
2040) {
2041) AttributeRuleProcessorData *data = aData->data;
2042)
2043) nsReStyleHint possibleChange = IsSiblingOperator(aSelector->mOperator) ?
^ 48,297,596 (6)
2044) eReStyle_LaterSiblings :
2045) (aSelector->mIsNextOfSomething ? eReStyle_Subtree : eReStyle_Self);
2046)
2047) // If enumData->change already includes all the bits of possibleChange, don't
2048) // bother calling SelectorMatches, since even if it returns false
2049) // enumData->change won't change.
2050) if ((possibleChange & ~(aData->change)) &&
^ 5,004,874 (4)
2051) SelectorMatches(*data, aSelector, data->mStateMask, data->mAttribute,
2052) PR_TRUE) &&
2053) SelectorMatchesTree(*data, aSelector->mNext, PR_TRUE)) {
2054) aData->change = nsReStyleHint(aData->change | possibleChange);
^ 12,259
2055) }
2056) }
^ 12,074,413
2057)
2058) NS_IMETHODIMP
2059) nsCSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
^ 34,833
2060) nsReStyleHint* aResult)
2061) {
2062) NS_PRECONDITION(aData->mContent->IsNodeOfType(nsINode::eELEMENT),
^ 34,833
2063) "content must be element");
2064)
2065) AttributeEnumData data(aData);
^ 34,833
2066)
2067) // Since we always have :-moz-any-link (and almost always have :link
2068) // and :visited rules from prefs), rather than hacking AddRule below
2069) // to add |href| to the hash, we'll just handle it here.
2070) if (aData->mAttribute == nsGkAtoms::href &&
^ 34,839 (3/5)
2071) aData->mIsHTMLContent &&
2072) (aData->mContentTag == nsGkAtoms::a ||
2073) aData->mContentTag == nsGkAtoms::area ||
2074) aData->mContentTag == nsGkAtoms::link)) {
2075) data.change = nsReStyleHint(data.change | eReStyle_Self);
^ 3
2076) }
2077) // XXX What about XLinks?
2078) #ifdef MOZ_SVG
2079) // XXX should really check the attribute namespace is XLink
2080) if (aData->mAttribute == nsGkAtoms::href &&
^ 34,836 (2/3)
2081) aData->mNameSpaceID == kNameSpaceID_SVG &&
2082) aData->mContentTag == nsGkAtoms::a) {
2083) data.change = nsReStyleHint(data.change | eReStyle_Self);
^ 0
2084) }
2085) #endif
2086) // XXXbz now that :link and :visited are also states, do we need a
2087) // similar optimization in HasStateDependentStyle?
2088)
2089) RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
^ 69,666 (2)
2090)
2091) // We do the same thing for attributes that we do for state selectors
2092) // (see HasStateDependentStyle), except that instead of one big list
2093) // we have a hashtable with a per-attribute list.
2094)
2095) if (cascade) {
2096) if (aData->mAttribute == aData->mContent->GetIDAttributeName()) {
^ 69,666 (2)
2097) nsCSSSelector **iter = cascade->mIDSelectors.Elements(),
^ 420 (2)
2098) **end = iter + cascade->mIDSelectors.Length();
^ 210
2099) for(; iter != end; ++iter) {
^ 8,672 (2)
2100) AttributeEnumFunc(*iter, &data);
^ 8,462
2101) }
2102) }
2103)
2104) if (aData->mAttribute == aData->mContent->GetClassAttributeName()) {
^ 69,666 (2)
2105) nsCSSSelector **iter = cascade->mClassSelectors.Elements(),
^ 30,856 (2)
2106) **end = iter + cascade->mClassSelectors.Length();
^ 15,428
2107) for(; iter != end; ++iter) {
^ 11,968,956 (2)
2108) AttributeEnumFunc(*iter, &data);
^ 11,953,528
2109) }
2110) }
2111)
2112) AttributeSelectorEntry *entry = static_cast<AttributeSelectorEntry*>
^ 69,666 (2)
2113) (PL_DHashTableOperate(&cascade->mAttributeSelectors, aData->mAttribute,
2114) PL_DHASH_LOOKUP));
2115) if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
2116) nsCSSSelector **iter = entry->mSelectors->Elements(),
^ 7,924 (2)
2117) **end = iter + entry->mSelectors->Length();
^ 3,962
2118) for(; iter != end; ++iter) {
^ 116,385 (2)
2119) AttributeEnumFunc(*iter, &data);
^ 112,423
2120) }
2121) }
2122) }
2123)
2124) *aResult = data.change;
^ 34,833
2125) return NS_OK;
2126) }
2127)
2128) NS_IMETHODIMP
2129) nsCSSRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext,
^ 91
2130) PRBool* aRulesChanged)
2131) {
2132) RuleCascadeData *old = mRuleCascades;
2133) // We don't want to do anything if there aren't any sets of rules
2134) // cached yet (or somebody cleared them and is thus responsible for
2135) // rebuilding things), since we should not build the rule cascade too
2136) // early (e.g., before we know whether the quirk style sheet should be
2137) // enabled). And if there's nothing cached, it doesn't matter if
2138) // anything changed. See bug 448281.
2139) if (old) {
2140) RefreshRuleCascade(aPresContext);
^ 91
2141) }
2142) *aRulesChanged = (old != mRuleCascades);
^ 182 (2/3)
2143) return NS_OK;
^ 91
2144) }
2145)
2146) // Append all the currently-active font face rules to aArray. Return
2147) // true for success and false for failure.
2148) PRBool
2149) nsCSSRuleProcessor::AppendFontFaceRules(
^ 142
2150) nsPresContext *aPresContext,
2151) nsTArray<nsFontFaceRuleContainer>& aArray)
2152) {
2153) RuleCascadeData* cascade = GetRuleCascade(aPresContext);
^ 142
2154)
2155) if (cascade) {
2156) if (!aArray.AppendElements(cascade->mFontFaceRules))
^ 284 (2)
2157) return PR_FALSE;
^ 0
2158) }
2159)
2160) return PR_TRUE;
^ 142
2161) }
2162)
2163) nsresult
2164) nsCSSRuleProcessor::ClearRuleCascades()
^ 168
2165) {
2166) // We rely on our caller (perhaps indirectly) to do something that
2167) // will rebuild style data and the user font set (either
2168) // nsIPresShell::ReconstructStyleData or
2169) // nsPresContext::RebuildAllStyleData).
2170) RuleCascadeData *data = mRuleCascades;
2171) mRuleCascades = nsnull;
2172) while (data) {
^ 290 (2)
2173) RuleCascadeData *next = data->mNext;
^ 122
2174) delete data;
^ 122
2175) data = next;
2176) }
2177) return NS_OK;
^ 168
2178) }
2179)
2180)
2181) // This function should return true only for selectors that need to be
2182) // checked by |HasStateDependentStyle|.
2183) inline
2184) PRBool IsStateSelector(nsCSSSelector& aSelector)
^ 56,148
2185) {
2186) for (nsPseudoClassList* pseudoClass = aSelector.mPseudoClassList;
^ 64,883 (2)
2187) pseudoClass; pseudoClass = pseudoClass->mNext) {
2188) if ((pseudoClass->mAtom == nsCSSPseudoClasses::active) ||
^ 487,054 (50)
2189) (pseudoClass->mAtom == nsCSSPseudoClasses::checked) ||
2190) (pseudoClass->mAtom == nsCSSPseudoClasses::mozDragOver) ||
2191) (pseudoClass->mAtom == nsCSSPseudoClasses::focus) ||
2192) (pseudoClass->mAtom == nsCSSPseudoClasses::hover) ||
2193) (pseudoClass->mAtom == nsCSSPseudoClasses::target) ||
2194) (pseudoClass->mAtom == nsCSSPseudoClasses::link) ||
2195) (pseudoClass->mAtom == nsCSSPseudoClasses::visited) ||
2196) (pseudoClass->mAtom == nsCSSPseudoClasses::enabled) ||
2197) (pseudoClass->mAtom == nsCSSPseudoClasses::disabled) ||
2198) (pseudoClass->mAtom == nsCSSPseudoClasses::mozBroken) ||
2199) (pseudoClass->mAtom == nsCSSPseudoClasses::mozUserDisabled) ||
2200) (pseudoClass->mAtom == nsCSSPseudoClasses::mozSuppressed) ||
2201) (pseudoClass->mAtom == nsCSSPseudoClasses::mozLoading) ||
2202) (pseudoClass->mAtom == nsCSSPseudoClasses::required) ||
2203) (pseudoClass->mAtom == nsCSSPseudoClasses::optional) ||
2204) (pseudoClass->mAtom == nsCSSPseudoClasses::valid) ||
2205) (pseudoClass->mAtom == nsCSSPseudoClasses::invalid) ||
2206) (pseudoClass->mAtom == nsCSSPseudoClasses::inRange) ||
2207) (pseudoClass->mAtom == nsCSSPseudoClasses::outOfRange) ||
2208) (pseudoClass->mAtom == nsCSSPseudoClasses::mozReadOnly) ||
2209) (pseudoClass->mAtom == nsCSSPseudoClasses::mozReadWrite) ||
2210) (pseudoClass->mAtom == nsCSSPseudoClasses::indeterminate) ||
2211) #ifdef MOZ_MATHML
2212) (pseudoClass->mAtom == nsCSSPseudoClasses::mozMathIncrementScriptLevel) ||
2213) #endif
2214) (pseudoClass->mAtom == nsCSSPseudoClasses::defaultPseudo)) {
2215) return PR_TRUE;
^ 4,844
2216) }
2217) }
2218) return PR_FALSE;
^ 51,304
2219) }
2220)
2221) static PRBool
2222) AddRule(RuleValue* aRuleInfo, void* aCascade)
^ 39,013
2223) {
2224) RuleCascadeData *cascade = static_cast<RuleCascadeData*>(aCascade);
2225)
2226) // Build the rule hash.
2227) cascade->mRuleHash.PrependRule(aRuleInfo);
2228)
2229) nsTArray<nsCSSSelector*>* stateArray = &cascade->mStateSelectors;
^ 39,013
2230) nsTArray<nsCSSSelector*>* classArray = &cascade->mClassSelectors;
2231) nsTArray<nsCSSSelector*>* idArray = &cascade->mIDSelectors;
2232)
2233) for (nsCSSSelector* selector = aRuleInfo->mSelector;
^ 94,458 (2)
2234) selector; selector = selector->mNext) {
2235) // It's worth noting that this loop over negations isn't quite
2236) // optimal for two reasons. One, we could add something to one of
2237) // these lists twice, which means we'll check it twice, but I don't
2238) // think that's worth worrying about. (We do the same for multiple
2239) // attribute selectors on the same attribute.) Two, we don't really
2240) // need to check negations past the first in the current
2241) // implementation (and they're rare as well), but that might change
2242) // in the future if :not() is extended.
2243) for (nsCSSSelector* negation = selector; negation;
^ 111,593 (2) ^ 55,445
2244) negation = negation->mNegations) {
2245) // Build mStateSelectors.
2246) if (IsStateSelector(*negation))
^ 112,296 (2)
2247) stateArray->AppendElement(selector);
^ 4,844
2248)
2249) // Build mIDSelectors
2250) if (negation->mIDList) {
^ 56,148
2251) idArray->AppendElement(selector);
^ 1,370
2252) }
2253)
2254) // Build mClassSelectors
2255) if (negation->mClassList) {
^ 56,148
2256) classArray->AppendElement(selector);
^ 9,653
2257) }
2258)
2259) // Build mAttributeSelectors.
2260) for (nsAttrSelector *attr = negation->mAttrList; attr;
^ 65,014 (2) ^ 56,148
2261) attr = attr->mNext) {
2262) nsTArray<nsCSSSelector*> *array = cascade->AttributeListFor(attr->mAttr);
^ 26,598 (3)
2263) if (!array)
2264) return PR_FALSE;
^ 0
2265) array->AppendElement(selector);
^ 8,866
2266) }
2267) }
2268) }
2269)
2270) return PR_TRUE;
^ 39,013
2271) }
2272)
2273) struct PerWeightData {
2274) PRInt32 mWeight;
2275) RuleValue* mRules; // linked list (reverse order)
2276) };
2277)
2278) struct RuleByWeightEntry : public PLDHashEntryHdr {
2279) PerWeightData data; // mWeight is key, mRules are value
2280) };
2281)
2282) static PLDHashNumber
2283) HashIntKey(PLDHashTable *table, const void *key)
^ 39,013
2284) {
2285) return PLDHashNumber(NS_PTR_TO_INT32(key));
2286) }
2287)
2288) static PRBool
2289) MatchWeightEntry(PLDHashTable *table, const PLDHashEntryHdr *hdr,
^ 38,011
2290) const void *key)
2291) {
2292) const RuleByWeightEntry *entry = (const RuleByWeightEntry *)hdr;
2293) return entry->data.mWeight == NS_PTR_TO_INT32(key);
2294) }
2295)
2296) static PLDHashTableOps gRulesByWeightOps = {
2297) PL_DHashAllocTable,
2298) PL_DHashFreeTable,
2299) HashIntKey,
2300) MatchWeightEntry,
2301) PL_DHashMoveEntryStub,
2302) PL_DHashClearEntryStub,
2303) PL_DHashFinalizeStub,
2304) NULL
2305) };
2306)
2307) struct CascadeEnumData {
2308) CascadeEnumData(nsPresContext* aPresContext,
^ 122
2309) nsTArray<nsFontFaceRuleContainer>& aFontFaceRules,
2310) nsMediaQueryResultCacheKey& aKey,
2311) PLArenaPool& aArena,
2312) PRUint8 aSheetType)
2313) : mPresContext(aPresContext),
2314) mFontFaceRules(aFontFaceRules),
2315) mCacheKey(aKey),
2316) mArena(aArena),
2317) mSheetType(aSheetType)
2318) {
2319) if (!PL_DHashTableInit(&mRulesByWeight, &gRulesByWeightOps, nsnull,
^ 122
2320) sizeof(RuleByWeightEntry), 64))
2321) mRulesByWeight.ops = nsnull;
^ 0
2322) }
^ 122
2323)
2324) ~CascadeEnumData()
^ 122
2325) {
2326) if (mRulesByWeight.ops)
2327) PL_DHashTableFinish(&mRulesByWeight);
^ 122
2328) }
^ 122
2329)
2330) nsPresContext* mPresContext;
2331) nsTArray<nsFontFaceRuleContainer>& mFontFaceRules;
2332) nsMediaQueryResultCacheKey& mCacheKey;
2333) PLArenaPool& mArena;
2334) // Hooray, a manual PLDHashTable since nsClassHashtable doesn't
2335) // provide a getter that gives me a *reference* to the value.
2336) PLDHashTable mRulesByWeight; // of RuleValue* linked lists (?)
2337) PRUint8 mSheetType;
2338) };
2339)
2340) /*
2341) * This enumerates style rules in a sheet (and recursively into any
2342) * grouping rules) in order to:
2343) * (1) add any style rules, in order, into data->mRulesByWeight (for
2344) * the primary CSS cascade), where they are separated by weight
2345) * but kept in order per-weight, and
2346) * (2) add any @font-face rules, in order, into data->mFontFaceRules.
2347) */
2348) static PRBool
2349) CascadeRuleEnumFunc(nsICSSRule* aRule, void* aData)
^ 21,262
2350) {
2351) CascadeEnumData* data = (CascadeEnumData*)aData;
2352) PRInt32 type = nsICSSRule::UNKNOWN_RULE;
2353) aRule->GetType(type);
2354)
2355) if (nsICSSRule::STYLE_RULE == type) {
^ 23,231 (4)
2356) nsICSSStyleRule* styleRule = (nsICSSStyleRule*)aRule;
^ 20,558
2357)
2358) for (nsCSSSelectorList *sel = styleRule->Selector();
^ 59,571 (2) ^ 20,558
2359) sel; sel = sel->mNext) {
2360) PRInt32 weight = sel->mWeight;
^ 39,013
2361) RuleByWeightEntry *entry = static_cast<RuleByWeightEntry*>(
^ 39,013
2362) PL_DHashTableOperate(&data->mRulesByWeight, NS_INT32_TO_PTR(weight),
2363) PL_DHASH_ADD));
2364) if (!entry)
2365) return PR_FALSE;
^ 0
2366) entry->data.mWeight = weight;
^ 39,013
2367) RuleValue *info =
^ 117,039 (3/4)
2368) new (data->mArena) RuleValue(styleRule, sel->mSelectors);
2369) // entry->data.mRules must be in backwards order.
2370) info->mNext = entry->data.mRules;
2371) entry->data.mRules = info;
2372) }
2373) }
2374) else if (nsICSSRule::MEDIA_RULE == type ||
2375) nsICSSRule::DOCUMENT_RULE == type) {
2376) nsICSSGroupRule* groupRule = (nsICSSGroupRule*)aRule;
^ 143
2377) if (groupRule->UseForPresentation(data->mPresContext, data->mCacheKey))
^ 143
2378) if (!groupRule->EnumerateRulesForwards(CascadeRuleEnumFunc, aData))
^ 6 (2)
2379) return PR_FALSE;
^ 0
2380) }
2381) else if (nsICSSRule::FONT_FACE_RULE == type) {
2382) nsCSSFontFaceRule *fontFaceRule = static_cast<nsCSSFontFaceRule*>(aRule);
^ 0 (4)
2383) nsFontFaceRuleContainer *ptr = data->mFontFaceRules.AppendElement();
^ 0
2384) if (!ptr)
2385) return PR_FALSE;
^ 0
2386) ptr->mRule = fontFaceRule;
^ 0
2387) ptr->mSheetType = data->mSheetType;
^ 0
2388) }
2389)
2390) return PR_TRUE;
^ 21,262
2391) }
2392)
2393) /* static */ PRBool
2394) nsCSSRuleProcessor::CascadeSheetEnumFunc(nsICSSStyleSheet* aSheet, void* aData)
^ 353
2395) {
2396) nsCSSStyleSheet* sheet = static_cast<nsCSSStyleSheet*>(aSheet);
2397) CascadeEnumData* data = static_cast<CascadeEnumData*>(aData);
2398) PRBool bSheetApplicable = PR_TRUE;
2399) sheet->GetApplicable(bSheetApplicable);
2400)
2401) if (bSheetApplicable &&
^ 1,400 (4)
2402) sheet->UseForPresentation(data->mPresContext, data->mCacheKey) &&
2403) sheet->mInner) {
2404) nsCSSStyleSheet* child = sheet->mInner->mFirstChild;
^ 698 (2)
2405) while (child) {
^ 424 (2)
2406) CascadeSheetEnumFunc(child, data);
^ 75
2407) child = child->mNext;
^ 75
2408) }
2409)
2410) if (!sheet->mInner->mOrderedRules.EnumerateForwards(CascadeRuleEnumFunc,
^ 698 (2)
2411) data))
2412) return PR_FALSE;
^ 0
2413) }
2414) return PR_TRUE;
^ 353
2415) }
2416)
2417) static int CompareWeightData(const void* aArg1, const void* aArg2,
^ 2,457
2418) void* closure)
2419) {
2420) const PerWeightData* arg1 = static_cast<const PerWeightData*>(aArg1);
2421) const PerWeightData* arg2 = static_cast<const PerWeightData*>(aArg2);
2422) return arg1->mWeight - arg2->mWeight; // put lower weight first
2423) }
2424)
2425)
2426) struct FillWeightArrayData {
2427) FillWeightArrayData(PerWeightData* aArrayData) :
^ 122
2428) mIndex(0),
2429) mWeightArray(aArrayData)
2430) {
2431) }
2432) PRInt32 mIndex;
2433) PerWeightData* mWeightArray;
2434) };
2435)
2436)
2437) static PLDHashOperator
2438) FillWeightArray(PLDHashTable *table, PLDHashEntryHdr *hdr,
^ 1,002
2439) PRUint32 number, void *arg)
2440) {
2441) FillWeightArrayData* data = static_cast<FillWeightArrayData*>(arg);
2442) const RuleByWeightEntry *entry = (const RuleByWeightEntry *)hdr;
2443)
2444) data->mWeightArray[data->mIndex++] = entry->data;
2445)
2446) return PL_DHASH_NEXT;
2447) }
2448)
2449) RuleCascadeData*
2450) nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext)
^ 890,312
2451) {
2452) // If anything changes about the presentation context, we will be
2453) // notified. Otherwise, our cache is valid if mLastPresContext
2454) // matches aPresContext. (The only rule processors used for multiple
2455) // pres contexts are for XBL. These rule processors are probably less
2456) // likely to have @media rules, and thus the cache is pretty likely to
2457) // hit instantly even when we're switching between pres contexts.)
2458)
2459) if (!mRuleCascades || aPresContext != mLastPresContext) {
^ 890,190
2460) RefreshRuleCascade(aPresContext);
^ 261
2461) }
2462) mLastPresContext = aPresContext;
^ 890,312
2463)
2464) return mRuleCascades;
2465) }
2466)
2467) void
2468) nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
^ 352
2469) {
2470) // Having RuleCascadeData objects be per-medium (over all variation
2471) // caused by media queries, handled through mCacheKey) works for now
2472) // since nsCSSRuleProcessor objects are per-document. (For a given
2473) // set of stylesheets they can vary based on medium (@media) or
2474) // document (@-moz-document).)
2475)
2476) for (RuleCascadeData **cascadep = &mRuleCascades, *cascade;
^ 352 (1/2)
2477) (cascade = *cascadep); cascadep = &cascade->mNext) {
2478) if (cascade->mCacheKey.Matches(aPresContext)) {
^ 460 (2)
2479) // Ensure that the current one is always mRuleCascades.
2480) *cascadep = cascade->mNext;
^ 230
2481) cascade->mNext = mRuleCascades;
2482) mRuleCascades = cascade;
2483)
2484) return;
2485) }
2486) }
2487)
2488) if (mSheets.Count() != 0) {
^ 244 (2)
2489) nsAutoPtr<RuleCascadeData> newCascade(
^ 976 (8/9)
2490) new RuleCascadeData(aPresContext->Medium(),
2491) eCompatibility_NavQuirks == aPresContext->CompatibilityMode()));
2492) if (newCascade) {
^ 244 (2)
2493) CascadeEnumData data(aPresContext, newCascade->mFontFaceRules,
^ 610 (5)
2494) newCascade->mCacheKey,
2495) newCascade->mRuleHash.Arena(),
2496) mSheetType);
2497) if (!data.mRulesByWeight.ops)
^ 122
2498) return; /* out of memory */
^ 0 (3)
2499) if (!mSheets.EnumerateForwards(CascadeSheetEnumFunc, &data))
^ 244 (2)
2500) return; /* out of memory */
^ 0 (3)
2501)
2502) // Sort the hash table of per-weight linked lists by weight.
2503) PRUint32 weightCount = data.mRulesByWeight.entryCount;
^ 122
2504) nsAutoArrayPtr<PerWeightData> weightArray(new PerWeightData[weightCount]);
^ 122
2505) FillWeightArrayData fwData(weightArray);
^ 244 (2)
2506) PL_DHashTableEnumerate(&data.mRulesByWeight, FillWeightArray, &fwData);
^ 122
2507) NS_QuickSort(weightArray, weightCount, sizeof(PerWeightData),
^ 244 (2)
2508) CompareWeightData, nsnull);
2509)
2510) // Put things into the rule hash backwards because it's easier to
2511) // build a singly linked list lowest-first that way.
2512) // The primary sort is by weight...
2513) PRUint32 i = weightCount;
^ 122
2514) while (i > 0) {
^ 1,124 (2)
2515) --i;
^ 1,002
2516) // and the secondary sort is by order. mRules are already backwards.
2517) RuleValue *ruleValue = weightArray[i].mRules;
^ 1,002
2518) do {
2519) // Calling |AddRule| reuses mNext!
2520) RuleValue *next = ruleValue->mNext;
^ 39,013
2521) if (!AddRule(ruleValue, newCascade))
^ 78,026 (2)
2522) return; /* out of memory */
^ 0 (4)
2523) ruleValue = next;
^ 39,013
2524) } while (ruleValue);
2525) }
2526)
2527) // Ensure that the current one is always mRuleCascades.
2528) newCascade->mNext = mRuleCascades;
^ 244 (2)
2529) mRuleCascades = newCascade.forget();
^ 122
2530) }
^ 122
2531) }
^ 122
2532) return;
^ 122
2533) }
2534)
2535) /* static */ PRBool
2536) nsCSSRuleProcessor::SelectorListMatches(RuleProcessorData& aData,
^ 0
2537) nsCSSSelectorList* aSelectorList)
2538) {
2539) while (aSelectorList) {
2540) nsCSSSelector* sel = aSelectorList->mSelectors;
2541) NS_ASSERTION(sel, "Should have *some* selectors");
2542) if (SelectorMatches(aData, sel, 0, nsnull, PR_FALSE)) {
2543) nsCSSSelector* next = sel->mNext;
2544) if (!next || SelectorMatchesTree(aData, next, PR_FALSE)) {
2545) return PR_TRUE;
2546) }
2547) }
2548)
2549) aSelectorList = aSelectorList->mNext;
2550) }
2551)
2552) return PR_FALSE;
2553) }