nsCSSRuleProcessor.cpp 140 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. // vim:cindent:tabstop=2:expandtab:shiftwidth=2:
  3. /* This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6. /*
  7. * style rule processor for CSS style sheets, responsible for selector
  8. * matching and cascading
  9. */
  10. #define PL_ARENA_CONST_ALIGN_MASK 7
  11. // We want page-sized arenas so there's no fragmentation involved.
  12. // Including plarena.h must come first to avoid it being included by some
  13. // header file thereby making PL_ARENA_CONST_ALIGN_MASK ineffective.
  14. #define NS_CASCADEENUMDATA_ARENA_BLOCK_SIZE (4096)
  15. #include "plarena.h"
  16. #include "nsAutoPtr.h"
  17. #include "nsCSSRuleProcessor.h"
  18. #include "nsRuleProcessorData.h"
  19. #include <algorithm>
  20. #include "nsIAtom.h"
  21. #include "PLDHashTable.h"
  22. #include "nsICSSPseudoComparator.h"
  23. #include "mozilla/MemoryReporting.h"
  24. #include "mozilla/css/StyleRule.h"
  25. #include "mozilla/css/GroupRule.h"
  26. #include "nsIDocument.h"
  27. #include "nsPresContext.h"
  28. #include "nsGkAtoms.h"
  29. #include "nsUnicharUtils.h"
  30. #include "nsError.h"
  31. #include "nsRuleWalker.h"
  32. #include "nsCSSPseudoClasses.h"
  33. #include "nsCSSPseudoElements.h"
  34. #include "nsIContent.h"
  35. #include "nsCOMPtr.h"
  36. #include "nsHashKeys.h"
  37. #include "nsStyleUtil.h"
  38. #include "nsQuickSort.h"
  39. #include "nsAttrValue.h"
  40. #include "nsAttrValueInlines.h"
  41. #include "nsAttrName.h"
  42. #include "nsTArray.h"
  43. #include "nsContentUtils.h"
  44. #include "nsIMediaList.h"
  45. #include "nsCSSRules.h"
  46. #include "nsStyleSet.h"
  47. #include "mozilla/dom/Element.h"
  48. #include "nsNthIndexCache.h"
  49. #include "mozilla/ArrayUtils.h"
  50. #include "mozilla/EventStates.h"
  51. #include "mozilla/Preferences.h"
  52. #include "mozilla/LookAndFeel.h"
  53. #include "mozilla/Likely.h"
  54. #include "mozilla/OperatorNewExtensions.h"
  55. #include "mozilla/TypedEnumBits.h"
  56. #include "RuleProcessorCache.h"
  57. #include "nsIDOMMutationEvent.h"
  58. #include "nsIMozBrowserFrame.h"
  59. using namespace mozilla;
  60. using namespace mozilla::dom;
  61. #define VISITED_PSEUDO_PREF "layout.css.visited_links_enabled"
  62. static bool gSupportVisitedPseudo = true;
  63. static nsTArray< nsCOMPtr<nsIAtom> >* sSystemMetrics = 0;
  64. #ifdef XP_WIN
  65. uint8_t nsCSSRuleProcessor::sWinThemeId = LookAndFeel::eWindowsTheme_Generic;
  66. #endif
  67. /**
  68. * A struct representing a given CSS rule and a particular selector
  69. * from that rule's selector list.
  70. */
  71. struct RuleSelectorPair {
  72. RuleSelectorPair(css::StyleRule* aRule, nsCSSSelector* aSelector)
  73. : mRule(aRule), mSelector(aSelector) {}
  74. // If this class ever grows a destructor, deal with
  75. // PerWeightDataListItem appropriately.
  76. css::StyleRule* mRule;
  77. nsCSSSelector* mSelector; // which of |mRule|'s selectors
  78. };
  79. #define NS_IS_ANCESTOR_OPERATOR(ch) \
  80. ((ch) == char16_t(' ') || (ch) == char16_t('>'))
  81. /**
  82. * A struct representing a particular rule in an ordered list of rules
  83. * (the ordering depending on the weight of mSelector and the order of
  84. * our rules to start with).
  85. */
  86. struct RuleValue : RuleSelectorPair {
  87. enum {
  88. eMaxAncestorHashes = 4
  89. };
  90. RuleValue(const RuleSelectorPair& aRuleSelectorPair, int32_t aIndex,
  91. bool aQuirksMode) :
  92. RuleSelectorPair(aRuleSelectorPair),
  93. mIndex(aIndex)
  94. {
  95. CollectAncestorHashes(aQuirksMode);
  96. }
  97. int32_t mIndex; // High index means high weight/order.
  98. uint32_t mAncestorSelectorHashes[eMaxAncestorHashes];
  99. private:
  100. void CollectAncestorHashes(bool aQuirksMode) {
  101. // Collect up our mAncestorSelectorHashes. It's not clear whether it's
  102. // better to stop once we've found eMaxAncestorHashes of them or to keep
  103. // going and preferentially collect information from selectors higher up the
  104. // chain... Let's do the former for now.
  105. size_t hashIndex = 0;
  106. for (nsCSSSelector* sel = mSelector->mNext; sel; sel = sel->mNext) {
  107. if (!NS_IS_ANCESTOR_OPERATOR(sel->mOperator)) {
  108. // |sel| is going to select something that's not actually one of our
  109. // ancestors, so don't add it to mAncestorSelectorHashes. But keep
  110. // going, because it'll select a sibling of one of our ancestors, so its
  111. // ancestors would be our ancestors too.
  112. continue;
  113. }
  114. // Now sel is supposed to select one of our ancestors. Grab
  115. // whatever info we can from it into mAncestorSelectorHashes.
  116. // But in qurks mode, don't grab IDs and classes because those
  117. // need to be matched case-insensitively.
  118. if (!aQuirksMode) {
  119. nsAtomList* ids = sel->mIDList;
  120. while (ids) {
  121. mAncestorSelectorHashes[hashIndex++] = ids->mAtom->hash();
  122. if (hashIndex == eMaxAncestorHashes) {
  123. return;
  124. }
  125. ids = ids->mNext;
  126. }
  127. nsAtomList* classes = sel->mClassList;
  128. while (classes) {
  129. mAncestorSelectorHashes[hashIndex++] = classes->mAtom->hash();
  130. if (hashIndex == eMaxAncestorHashes) {
  131. return;
  132. }
  133. classes = classes->mNext;
  134. }
  135. }
  136. // Only put in the tag name if it's all-lowercase. Otherwise we run into
  137. // trouble because we may test the wrong one of mLowercaseTag and
  138. // mCasedTag against the filter.
  139. if (sel->mLowercaseTag && sel->mCasedTag == sel->mLowercaseTag) {
  140. mAncestorSelectorHashes[hashIndex++] = sel->mLowercaseTag->hash();
  141. if (hashIndex == eMaxAncestorHashes) {
  142. return;
  143. }
  144. }
  145. }
  146. while (hashIndex != eMaxAncestorHashes) {
  147. mAncestorSelectorHashes[hashIndex++] = 0;
  148. }
  149. }
  150. };
  151. // ------------------------------
  152. // Rule hash table
  153. //
  154. // Uses any of the sets of ops below.
  155. struct RuleHashTableEntry : public PLDHashEntryHdr {
  156. // If you add members that have heap allocated memory be sure to change the
  157. // logic in SizeOfRuleHashTable().
  158. // Auto length 1, because we always have at least one entry in mRules.
  159. AutoTArray<RuleValue, 1> mRules;
  160. };
  161. struct RuleHashTagTableEntry : public RuleHashTableEntry {
  162. // If you add members that have heap allocated memory be sure to change the
  163. // logic in RuleHash::SizeOf{In,Ex}cludingThis.
  164. nsCOMPtr<nsIAtom> mTag;
  165. };
  166. static PLDHashNumber
  167. RuleHash_CIHashKey(const void *key)
  168. {
  169. nsIAtom *atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
  170. nsAutoString str;
  171. atom->ToString(str);
  172. nsContentUtils::ASCIIToLower(str);
  173. return HashString(str);
  174. }
  175. static inline nsCSSSelector*
  176. SubjectSelectorForRuleHash(const PLDHashEntryHdr *hdr)
  177. {
  178. auto entry = static_cast<const RuleHashTableEntry*>(hdr);
  179. nsCSSSelector* selector = entry->mRules[0].mSelector;
  180. if (selector->IsPseudoElement()) {
  181. selector = selector->mNext;
  182. }
  183. return selector;
  184. }
  185. static inline bool
  186. CIMatchAtoms(const void* key, nsIAtom *entry_atom)
  187. {
  188. auto match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
  189. // Check for case-sensitive match first.
  190. if (match_atom == entry_atom) {
  191. return true;
  192. }
  193. // Use EqualsIgnoreASCIICase instead of full on unicode case conversion
  194. // in order to save on performance. This is only used in quirks mode
  195. // anyway.
  196. return
  197. nsContentUtils::EqualsIgnoreASCIICase(nsDependentAtomString(entry_atom),
  198. nsDependentAtomString(match_atom));
  199. }
  200. static inline bool
  201. CSMatchAtoms(const void* key, nsIAtom *entry_atom)
  202. {
  203. auto match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
  204. return match_atom == entry_atom;
  205. }
  206. static bool
  207. RuleHash_ClassCIMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
  208. {
  209. return CIMatchAtoms(key, SubjectSelectorForRuleHash(hdr)->mClassList->mAtom);
  210. }
  211. static bool
  212. RuleHash_IdCIMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
  213. {
  214. return CIMatchAtoms(key, SubjectSelectorForRuleHash(hdr)->mIDList->mAtom);
  215. }
  216. static bool
  217. RuleHash_ClassCSMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
  218. {
  219. return CSMatchAtoms(key, SubjectSelectorForRuleHash(hdr)->mClassList->mAtom);
  220. }
  221. static bool
  222. RuleHash_IdCSMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
  223. {
  224. return CSMatchAtoms(key, SubjectSelectorForRuleHash(hdr)->mIDList->mAtom);
  225. }
  226. static void
  227. RuleHash_InitEntry(PLDHashEntryHdr *hdr, const void *key)
  228. {
  229. RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(hdr);
  230. new (KnownNotNull, entry) RuleHashTableEntry();
  231. }
  232. static void
  233. RuleHash_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
  234. {
  235. RuleHashTableEntry* entry = static_cast<RuleHashTableEntry*>(hdr);
  236. entry->~RuleHashTableEntry();
  237. }
  238. static void
  239. RuleHash_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
  240. PLDHashEntryHdr *to)
  241. {
  242. NS_PRECONDITION(from != to, "This is not going to work!");
  243. RuleHashTableEntry *oldEntry =
  244. const_cast<RuleHashTableEntry*>(
  245. static_cast<const RuleHashTableEntry*>(from));
  246. auto* newEntry = new (KnownNotNull, to) RuleHashTableEntry();
  247. newEntry->mRules.SwapElements(oldEntry->mRules);
  248. oldEntry->~RuleHashTableEntry();
  249. }
  250. static bool
  251. RuleHash_TagTable_MatchEntry(const PLDHashEntryHdr *hdr, const void *key)
  252. {
  253. nsIAtom *match_atom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
  254. nsIAtom *entry_atom = static_cast<const RuleHashTagTableEntry*>(hdr)->mTag;
  255. return match_atom == entry_atom;
  256. }
  257. static void
  258. RuleHash_TagTable_InitEntry(PLDHashEntryHdr *hdr, const void *key)
  259. {
  260. RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>(hdr);
  261. new (KnownNotNull, entry) RuleHashTagTableEntry();
  262. entry->mTag = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
  263. }
  264. static void
  265. RuleHash_TagTable_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
  266. {
  267. RuleHashTagTableEntry* entry = static_cast<RuleHashTagTableEntry*>(hdr);
  268. entry->~RuleHashTagTableEntry();
  269. }
  270. static void
  271. RuleHash_TagTable_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
  272. PLDHashEntryHdr *to)
  273. {
  274. NS_PRECONDITION(from != to, "This is not going to work!");
  275. RuleHashTagTableEntry *oldEntry =
  276. const_cast<RuleHashTagTableEntry*>(
  277. static_cast<const RuleHashTagTableEntry*>(from));
  278. auto* newEntry = new (KnownNotNull, to) RuleHashTagTableEntry();
  279. newEntry->mTag.swap(oldEntry->mTag);
  280. newEntry->mRules.SwapElements(oldEntry->mRules);
  281. oldEntry->~RuleHashTagTableEntry();
  282. }
  283. static PLDHashNumber
  284. RuleHash_NameSpaceTable_HashKey(const void *key)
  285. {
  286. return NS_PTR_TO_INT32(key);
  287. }
  288. static bool
  289. RuleHash_NameSpaceTable_MatchEntry(const PLDHashEntryHdr *hdr, const void *key)
  290. {
  291. const RuleHashTableEntry *entry =
  292. static_cast<const RuleHashTableEntry*>(hdr);
  293. nsCSSSelector* selector = entry->mRules[0].mSelector;
  294. if (selector->IsPseudoElement()) {
  295. selector = selector->mNext;
  296. }
  297. return NS_PTR_TO_INT32(key) == selector->mNameSpace;
  298. }
  299. static const PLDHashTableOps RuleHash_TagTable_Ops = {
  300. PLDHashTable::HashVoidPtrKeyStub,
  301. RuleHash_TagTable_MatchEntry,
  302. RuleHash_TagTable_MoveEntry,
  303. RuleHash_TagTable_ClearEntry,
  304. RuleHash_TagTable_InitEntry
  305. };
  306. // Case-sensitive ops.
  307. static const PLDHashTableOps RuleHash_ClassTable_CSOps = {
  308. PLDHashTable::HashVoidPtrKeyStub,
  309. RuleHash_ClassCSMatchEntry,
  310. RuleHash_MoveEntry,
  311. RuleHash_ClearEntry,
  312. RuleHash_InitEntry
  313. };
  314. // Case-insensitive ops.
  315. static const PLDHashTableOps RuleHash_ClassTable_CIOps = {
  316. RuleHash_CIHashKey,
  317. RuleHash_ClassCIMatchEntry,
  318. RuleHash_MoveEntry,
  319. RuleHash_ClearEntry,
  320. RuleHash_InitEntry
  321. };
  322. // Case-sensitive ops.
  323. static const PLDHashTableOps RuleHash_IdTable_CSOps = {
  324. PLDHashTable::HashVoidPtrKeyStub,
  325. RuleHash_IdCSMatchEntry,
  326. RuleHash_MoveEntry,
  327. RuleHash_ClearEntry,
  328. RuleHash_InitEntry
  329. };
  330. // Case-insensitive ops.
  331. static const PLDHashTableOps RuleHash_IdTable_CIOps = {
  332. RuleHash_CIHashKey,
  333. RuleHash_IdCIMatchEntry,
  334. RuleHash_MoveEntry,
  335. RuleHash_ClearEntry,
  336. RuleHash_InitEntry
  337. };
  338. static const PLDHashTableOps RuleHash_NameSpaceTable_Ops = {
  339. RuleHash_NameSpaceTable_HashKey,
  340. RuleHash_NameSpaceTable_MatchEntry,
  341. RuleHash_MoveEntry,
  342. RuleHash_ClearEntry,
  343. RuleHash_InitEntry
  344. };
  345. #undef RULE_HASH_STATS
  346. #undef PRINT_UNIVERSAL_RULES
  347. #ifdef RULE_HASH_STATS
  348. #define RULE_HASH_STAT_INCREMENT(var_) PR_BEGIN_MACRO ++(var_); PR_END_MACRO
  349. #else
  350. #define RULE_HASH_STAT_INCREMENT(var_) PR_BEGIN_MACRO PR_END_MACRO
  351. #endif
  352. struct NodeMatchContext;
  353. class RuleHash {
  354. public:
  355. explicit RuleHash(bool aQuirksMode);
  356. ~RuleHash();
  357. void AppendRule(const RuleSelectorPair &aRuleInfo);
  358. void EnumerateAllRules(Element* aElement, ElementDependentRuleProcessorData* aData,
  359. NodeMatchContext& aNodeMatchContext);
  360. size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
  361. size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
  362. protected:
  363. typedef nsTArray<RuleValue> RuleValueList;
  364. void AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
  365. const RuleSelectorPair& aRuleInfo);
  366. void AppendUniversalRule(const RuleSelectorPair& aRuleInfo);
  367. int32_t mRuleCount;
  368. PLDHashTable mIdTable;
  369. PLDHashTable mClassTable;
  370. PLDHashTable mTagTable;
  371. PLDHashTable mNameSpaceTable;
  372. RuleValueList mUniversalRules;
  373. struct EnumData {
  374. const RuleValue* mCurValue;
  375. const RuleValue* mEnd;
  376. };
  377. EnumData* mEnumList;
  378. int32_t mEnumListSize;
  379. bool mQuirksMode;
  380. inline EnumData ToEnumData(const RuleValueList& arr) {
  381. EnumData data = { arr.Elements(), arr.Elements() + arr.Length() };
  382. return data;
  383. }
  384. #ifdef RULE_HASH_STATS
  385. uint32_t mUniversalSelectors;
  386. uint32_t mNameSpaceSelectors;
  387. uint32_t mTagSelectors;
  388. uint32_t mClassSelectors;
  389. uint32_t mIdSelectors;
  390. uint32_t mElementsMatched;
  391. uint32_t mElementUniversalCalls;
  392. uint32_t mElementNameSpaceCalls;
  393. uint32_t mElementTagCalls;
  394. uint32_t mElementClassCalls;
  395. uint32_t mElementIdCalls;
  396. #endif // RULE_HASH_STATS
  397. };
  398. RuleHash::RuleHash(bool aQuirksMode)
  399. : mRuleCount(0),
  400. mIdTable(aQuirksMode ? &RuleHash_IdTable_CIOps
  401. : &RuleHash_IdTable_CSOps,
  402. sizeof(RuleHashTableEntry)),
  403. mClassTable(aQuirksMode ? &RuleHash_ClassTable_CIOps
  404. : &RuleHash_ClassTable_CSOps,
  405. sizeof(RuleHashTableEntry)),
  406. mTagTable(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
  407. mNameSpaceTable(&RuleHash_NameSpaceTable_Ops, sizeof(RuleHashTableEntry)),
  408. mUniversalRules(0),
  409. mEnumList(nullptr), mEnumListSize(0),
  410. mQuirksMode(aQuirksMode)
  411. #ifdef RULE_HASH_STATS
  412. ,
  413. mUniversalSelectors(0),
  414. mNameSpaceSelectors(0),
  415. mTagSelectors(0),
  416. mClassSelectors(0),
  417. mIdSelectors(0),
  418. mElementsMatched(0),
  419. mElementUniversalCalls(0),
  420. mElementNameSpaceCalls(0),
  421. mElementTagCalls(0),
  422. mElementClassCalls(0),
  423. mElementIdCalls(0)
  424. #endif
  425. {
  426. MOZ_COUNT_CTOR(RuleHash);
  427. }
  428. RuleHash::~RuleHash()
  429. {
  430. MOZ_COUNT_DTOR(RuleHash);
  431. #ifdef RULE_HASH_STATS
  432. printf(
  433. "RuleHash(%p):\n"
  434. " Selectors: Universal (%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
  435. " Content Nodes: Elements(%u)\n"
  436. " Element Calls: Universal(%u) NameSpace(%u) Tag(%u) Class(%u) Id(%u)\n"
  437. static_cast<void*>(this),
  438. mUniversalSelectors, mNameSpaceSelectors, mTagSelectors,
  439. mClassSelectors, mIdSelectors,
  440. mElementsMatched,
  441. mElementUniversalCalls, mElementNameSpaceCalls, mElementTagCalls,
  442. mElementClassCalls, mElementIdCalls);
  443. #ifdef PRINT_UNIVERSAL_RULES
  444. {
  445. if (mUniversalRules.Length() > 0) {
  446. printf(" Universal rules:\n");
  447. for (uint32_t i = 0; i < mUniversalRules.Length(); ++i) {
  448. RuleValue* value = &(mUniversalRules[i]);
  449. nsAutoString selectorText;
  450. uint32_t lineNumber = value->mRule->GetLineNumber();
  451. RefPtr<CSSStyleSheet> cssSheet = value->mRule->GetStyleSheet();
  452. value->mSelector->ToString(selectorText, cssSheet);
  453. printf(" line %d, %s\n",
  454. lineNumber, NS_ConvertUTF16toUTF8(selectorText).get());
  455. }
  456. }
  457. }
  458. #endif // PRINT_UNIVERSAL_RULES
  459. #endif // RULE_HASH_STATS
  460. // Rule Values are arena allocated no need to delete them. Their destructor
  461. // isn't doing any cleanup. So we dont even bother to enumerate through
  462. // the hash tables and call their destructors.
  463. if (nullptr != mEnumList) {
  464. delete [] mEnumList;
  465. }
  466. }
  467. void RuleHash::AppendRuleToTable(PLDHashTable* aTable, const void* aKey,
  468. const RuleSelectorPair& aRuleInfo)
  469. {
  470. // Get a new or existing entry.
  471. auto entry = static_cast<RuleHashTableEntry*>(aTable->Add(aKey, fallible));
  472. if (!entry)
  473. return;
  474. entry->mRules.AppendElement(RuleValue(aRuleInfo, mRuleCount++, mQuirksMode));
  475. }
  476. static void
  477. AppendRuleToTagTable(PLDHashTable* aTable, nsIAtom* aKey,
  478. const RuleValue& aRuleInfo)
  479. {
  480. // Get a new or exisiting entry
  481. auto entry = static_cast<RuleHashTagTableEntry*>(aTable->Add(aKey, fallible));
  482. if (!entry)
  483. return;
  484. entry->mRules.AppendElement(aRuleInfo);
  485. }
  486. void RuleHash::AppendUniversalRule(const RuleSelectorPair& aRuleInfo)
  487. {
  488. mUniversalRules.AppendElement(RuleValue(aRuleInfo, mRuleCount++, mQuirksMode));
  489. }
  490. void RuleHash::AppendRule(const RuleSelectorPair& aRuleInfo)
  491. {
  492. nsCSSSelector *selector = aRuleInfo.mSelector;
  493. if (selector->IsPseudoElement()) {
  494. selector = selector->mNext;
  495. }
  496. if (nullptr != selector->mIDList) {
  497. AppendRuleToTable(&mIdTable, selector->mIDList->mAtom, aRuleInfo);
  498. RULE_HASH_STAT_INCREMENT(mIdSelectors);
  499. }
  500. else if (nullptr != selector->mClassList) {
  501. AppendRuleToTable(&mClassTable, selector->mClassList->mAtom, aRuleInfo);
  502. RULE_HASH_STAT_INCREMENT(mClassSelectors);
  503. }
  504. else if (selector->mLowercaseTag) {
  505. RuleValue ruleValue(aRuleInfo, mRuleCount++, mQuirksMode);
  506. AppendRuleToTagTable(&mTagTable, selector->mLowercaseTag, ruleValue);
  507. RULE_HASH_STAT_INCREMENT(mTagSelectors);
  508. if (selector->mCasedTag &&
  509. selector->mCasedTag != selector->mLowercaseTag) {
  510. AppendRuleToTagTable(&mTagTable, selector->mCasedTag, ruleValue);
  511. RULE_HASH_STAT_INCREMENT(mTagSelectors);
  512. }
  513. }
  514. else if (kNameSpaceID_Unknown != selector->mNameSpace) {
  515. AppendRuleToTable(&mNameSpaceTable,
  516. NS_INT32_TO_PTR(selector->mNameSpace), aRuleInfo);
  517. RULE_HASH_STAT_INCREMENT(mNameSpaceSelectors);
  518. }
  519. else { // universal tag selector
  520. AppendUniversalRule(aRuleInfo);
  521. RULE_HASH_STAT_INCREMENT(mUniversalSelectors);
  522. }
  523. }
  524. // this should cover practically all cases so we don't need to reallocate
  525. #define MIN_ENUM_LIST_SIZE 8
  526. #ifdef RULE_HASH_STATS
  527. #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
  528. (var_) += (list_).Length()
  529. #else
  530. #define RULE_HASH_STAT_INCREMENT_LIST_COUNT(list_, var_) \
  531. PR_BEGIN_MACRO PR_END_MACRO
  532. #endif
  533. static inline
  534. void ContentEnumFunc(const RuleValue &value, nsCSSSelector* selector,
  535. ElementDependentRuleProcessorData* data, NodeMatchContext& nodeContext,
  536. AncestorFilter *ancestorFilter);
  537. void RuleHash::EnumerateAllRules(Element* aElement, ElementDependentRuleProcessorData* aData,
  538. NodeMatchContext& aNodeContext)
  539. {
  540. int32_t nameSpace = aElement->GetNameSpaceID();
  541. nsIAtom* tag = aElement->NodeInfo()->NameAtom();
  542. nsIAtom* id = aElement->GetID();
  543. const nsAttrValue* classList = aElement->GetClasses();
  544. MOZ_ASSERT(tag, "How could we not have a tag?");
  545. int32_t classCount = classList ? classList->GetAtomCount() : 0;
  546. // assume 1 universal, tag, id, and namespace, rather than wasting
  547. // time counting
  548. int32_t testCount = classCount + 4;
  549. if (mEnumListSize < testCount) {
  550. delete [] mEnumList;
  551. mEnumListSize = std::max(testCount, MIN_ENUM_LIST_SIZE);
  552. mEnumList = new EnumData[mEnumListSize];
  553. }
  554. int32_t valueCount = 0;
  555. RULE_HASH_STAT_INCREMENT(mElementsMatched);
  556. if (mUniversalRules.Length() != 0) { // universal rules
  557. mEnumList[valueCount++] = ToEnumData(mUniversalRules);
  558. RULE_HASH_STAT_INCREMENT_LIST_COUNT(mUniversalRules, mElementUniversalCalls);
  559. }
  560. // universal rules within the namespace
  561. if (kNameSpaceID_Unknown != nameSpace && mNameSpaceTable.EntryCount() > 0) {
  562. auto entry = static_cast<RuleHashTableEntry*>
  563. (mNameSpaceTable.Search(NS_INT32_TO_PTR(nameSpace)));
  564. if (entry) {
  565. mEnumList[valueCount++] = ToEnumData(entry->mRules);
  566. RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementNameSpaceCalls);
  567. }
  568. }
  569. if (mTagTable.EntryCount() > 0) {
  570. auto entry = static_cast<RuleHashTableEntry*>(mTagTable.Search(tag));
  571. if (entry) {
  572. mEnumList[valueCount++] = ToEnumData(entry->mRules);
  573. RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementTagCalls);
  574. }
  575. }
  576. if (id && mIdTable.EntryCount() > 0) {
  577. auto entry = static_cast<RuleHashTableEntry*>(mIdTable.Search(id));
  578. if (entry) {
  579. mEnumList[valueCount++] = ToEnumData(entry->mRules);
  580. RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementIdCalls);
  581. }
  582. }
  583. if (mClassTable.EntryCount() > 0) {
  584. for (int32_t index = 0; index < classCount; ++index) {
  585. auto entry = static_cast<RuleHashTableEntry*>
  586. (mClassTable.Search(classList->AtomAt(index)));
  587. if (entry) {
  588. mEnumList[valueCount++] = ToEnumData(entry->mRules);
  589. RULE_HASH_STAT_INCREMENT_LIST_COUNT(entry->mRules, mElementClassCalls);
  590. }
  591. }
  592. }
  593. NS_ASSERTION(valueCount <= testCount, "values exceeded list size");
  594. if (valueCount > 0) {
  595. AncestorFilter *filter =
  596. aData->mTreeMatchContext.mAncestorFilter.HasFilter() ?
  597. &aData->mTreeMatchContext.mAncestorFilter : nullptr;
  598. #ifdef DEBUG
  599. if (filter) {
  600. filter->AssertHasAllAncestors(aElement);
  601. }
  602. #endif
  603. // Merge the lists while there are still multiple lists to merge.
  604. while (valueCount > 1) {
  605. int32_t valueIndex = 0;
  606. int32_t lowestRuleIndex = mEnumList[valueIndex].mCurValue->mIndex;
  607. for (int32_t index = 1; index < valueCount; ++index) {
  608. int32_t ruleIndex = mEnumList[index].mCurValue->mIndex;
  609. if (ruleIndex < lowestRuleIndex) {
  610. valueIndex = index;
  611. lowestRuleIndex = ruleIndex;
  612. }
  613. }
  614. const RuleValue *cur = mEnumList[valueIndex].mCurValue;
  615. ContentEnumFunc(*cur, cur->mSelector, aData, aNodeContext, filter);
  616. cur++;
  617. if (cur == mEnumList[valueIndex].mEnd) {
  618. mEnumList[valueIndex] = mEnumList[--valueCount];
  619. } else {
  620. mEnumList[valueIndex].mCurValue = cur;
  621. }
  622. }
  623. // Fast loop over single value.
  624. for (const RuleValue *value = mEnumList[0].mCurValue,
  625. *end = mEnumList[0].mEnd;
  626. value != end; ++value) {
  627. ContentEnumFunc(*value, value->mSelector, aData, aNodeContext, filter);
  628. }
  629. }
  630. }
  631. static size_t
  632. SizeOfRuleHashTable(const PLDHashTable& aTable, MallocSizeOf aMallocSizeOf)
  633. {
  634. size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
  635. for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
  636. auto entry = static_cast<RuleHashTableEntry*>(iter.Get());
  637. n += entry->mRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
  638. }
  639. return n;
  640. }
  641. size_t
  642. RuleHash::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  643. {
  644. size_t n = 0;
  645. n += SizeOfRuleHashTable(mIdTable, aMallocSizeOf);
  646. n += SizeOfRuleHashTable(mClassTable, aMallocSizeOf);
  647. n += SizeOfRuleHashTable(mTagTable, aMallocSizeOf);
  648. n += SizeOfRuleHashTable(mNameSpaceTable, aMallocSizeOf);
  649. n += mUniversalRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
  650. return n;
  651. }
  652. size_t
  653. RuleHash::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
  654. {
  655. return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
  656. }
  657. //--------------------------------
  658. /**
  659. * A struct that stores an nsCSSSelector pointer along side a pointer to
  660. * the rightmost nsCSSSelector in the selector. For example, for
  661. *
  662. * .main p > span
  663. *
  664. * if mSelector points to the |p| nsCSSSelector, mRightmostSelector would
  665. * point to the |span| nsCSSSelector.
  666. *
  667. * Both mSelector and mRightmostSelector are always top-level selectors,
  668. * i.e. they aren't selectors within a :not() or :-moz-any().
  669. */
  670. struct SelectorPair
  671. {
  672. SelectorPair(nsCSSSelector* aSelector, nsCSSSelector* aRightmostSelector)
  673. : mSelector(aSelector), mRightmostSelector(aRightmostSelector)
  674. {
  675. MOZ_ASSERT(aSelector);
  676. MOZ_ASSERT(mRightmostSelector);
  677. }
  678. SelectorPair(const SelectorPair& aOther) = default;
  679. nsCSSSelector* const mSelector;
  680. nsCSSSelector* const mRightmostSelector;
  681. };
  682. // A hash table mapping atoms to lists of selectors
  683. struct AtomSelectorEntry : public PLDHashEntryHdr {
  684. nsIAtom *mAtom;
  685. // Auto length 2, because a decent fraction of these arrays ends up
  686. // with 2 elements, and each entry is cheap.
  687. AutoTArray<SelectorPair, 2> mSelectors;
  688. };
  689. static void
  690. AtomSelector_ClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
  691. {
  692. (static_cast<AtomSelectorEntry*>(hdr))->~AtomSelectorEntry();
  693. }
  694. static void
  695. AtomSelector_InitEntry(PLDHashEntryHdr *hdr, const void *key)
  696. {
  697. AtomSelectorEntry *entry = static_cast<AtomSelectorEntry*>(hdr);
  698. new (KnownNotNull, entry) AtomSelectorEntry();
  699. entry->mAtom = const_cast<nsIAtom*>(static_cast<const nsIAtom*>(key));
  700. }
  701. static void
  702. AtomSelector_MoveEntry(PLDHashTable *table, const PLDHashEntryHdr *from,
  703. PLDHashEntryHdr *to)
  704. {
  705. NS_PRECONDITION(from != to, "This is not going to work!");
  706. AtomSelectorEntry *oldEntry =
  707. const_cast<AtomSelectorEntry*>(static_cast<const AtomSelectorEntry*>(from));
  708. auto* newEntry = new (KnownNotNull, to) AtomSelectorEntry();
  709. newEntry->mAtom = oldEntry->mAtom;
  710. newEntry->mSelectors.SwapElements(oldEntry->mSelectors);
  711. oldEntry->~AtomSelectorEntry();
  712. }
  713. static bool
  714. AtomSelector_CIMatchEntry(const PLDHashEntryHdr *hdr, const void *key)
  715. {
  716. const AtomSelectorEntry *entry = static_cast<const AtomSelectorEntry*>(hdr);
  717. return CIMatchAtoms(key, entry->mAtom);
  718. }
  719. // Case-sensitive ops.
  720. static const PLDHashTableOps AtomSelector_CSOps = {
  721. PLDHashTable::HashVoidPtrKeyStub,
  722. PLDHashTable::MatchEntryStub,
  723. AtomSelector_MoveEntry,
  724. AtomSelector_ClearEntry,
  725. AtomSelector_InitEntry
  726. };
  727. // Case-insensitive ops.
  728. static const PLDHashTableOps AtomSelector_CIOps = {
  729. RuleHash_CIHashKey,
  730. AtomSelector_CIMatchEntry,
  731. AtomSelector_MoveEntry,
  732. AtomSelector_ClearEntry,
  733. AtomSelector_InitEntry
  734. };
  735. //--------------------------------
  736. struct RuleCascadeData {
  737. RuleCascadeData(nsIAtom *aMedium, bool aQuirksMode)
  738. : mRuleHash(aQuirksMode),
  739. mStateSelectors(),
  740. mSelectorDocumentStates(0),
  741. mClassSelectors(aQuirksMode ? &AtomSelector_CIOps
  742. : &AtomSelector_CSOps,
  743. sizeof(AtomSelectorEntry)),
  744. mIdSelectors(aQuirksMode ? &AtomSelector_CIOps
  745. : &AtomSelector_CSOps,
  746. sizeof(AtomSelectorEntry)),
  747. // mAttributeSelectors is matching on the attribute _name_, not the
  748. // value, and we case-fold names at parse-time, so this is a
  749. // case-sensitive match.
  750. mAttributeSelectors(&AtomSelector_CSOps, sizeof(AtomSelectorEntry)),
  751. mAnonBoxRules(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
  752. #ifdef MOZ_XUL
  753. mXULTreeRules(&RuleHash_TagTable_Ops, sizeof(RuleHashTagTableEntry)),
  754. #endif
  755. mKeyframesRuleTable(),
  756. mCounterStyleRuleTable(),
  757. mCacheKey(aMedium),
  758. mNext(nullptr),
  759. mQuirksMode(aQuirksMode)
  760. {
  761. memset(mPseudoElementRuleHashes, 0, sizeof(mPseudoElementRuleHashes));
  762. }
  763. ~RuleCascadeData()
  764. {
  765. for (uint32_t i = 0; i < ArrayLength(mPseudoElementRuleHashes); ++i) {
  766. delete mPseudoElementRuleHashes[i];
  767. }
  768. }
  769. size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
  770. RuleHash mRuleHash;
  771. RuleHash* mPseudoElementRuleHashes[
  772. static_cast<CSSPseudoElementTypeBase>(CSSPseudoElementType::Count)];
  773. nsTArray<nsCSSRuleProcessor::StateSelector> mStateSelectors;
  774. EventStates mSelectorDocumentStates;
  775. PLDHashTable mClassSelectors;
  776. PLDHashTable mIdSelectors;
  777. nsTArray<nsCSSSelector*> mPossiblyNegatedClassSelectors;
  778. nsTArray<nsCSSSelector*> mPossiblyNegatedIDSelectors;
  779. PLDHashTable mAttributeSelectors;
  780. PLDHashTable mAnonBoxRules;
  781. #ifdef MOZ_XUL
  782. PLDHashTable mXULTreeRules;
  783. #endif
  784. nsTArray<nsFontFaceRuleContainer> mFontFaceRules;
  785. nsTArray<nsCSSKeyframesRule*> mKeyframesRules;
  786. nsTArray<nsCSSFontFeatureValuesRule*> mFontFeatureValuesRules;
  787. nsTArray<nsCSSPageRule*> mPageRules;
  788. nsTArray<nsCSSCounterStyleRule*> mCounterStyleRules;
  789. nsDataHashtable<nsStringHashKey, nsCSSKeyframesRule*> mKeyframesRuleTable;
  790. nsDataHashtable<nsStringHashKey, nsCSSCounterStyleRule*> mCounterStyleRuleTable;
  791. // Looks up or creates the appropriate list in |mAttributeSelectors|.
  792. // Returns null only on allocation failure.
  793. nsTArray<SelectorPair>* AttributeListFor(nsIAtom* aAttribute);
  794. nsMediaQueryResultCacheKey mCacheKey;
  795. RuleCascadeData* mNext; // for a different medium
  796. const bool mQuirksMode;
  797. };
  798. static size_t
  799. SizeOfSelectorsHashTable(const PLDHashTable& aTable, MallocSizeOf aMallocSizeOf)
  800. {
  801. size_t n = aTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
  802. for (auto iter = aTable.ConstIter(); !iter.Done(); iter.Next()) {
  803. auto entry = static_cast<AtomSelectorEntry*>(iter.Get());
  804. n += entry->mSelectors.ShallowSizeOfExcludingThis(aMallocSizeOf);
  805. }
  806. return n;
  807. }
  808. size_t
  809. RuleCascadeData::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
  810. {
  811. size_t n = aMallocSizeOf(this);
  812. n += mRuleHash.SizeOfExcludingThis(aMallocSizeOf);
  813. for (uint32_t i = 0; i < ArrayLength(mPseudoElementRuleHashes); ++i) {
  814. if (mPseudoElementRuleHashes[i])
  815. n += mPseudoElementRuleHashes[i]->SizeOfIncludingThis(aMallocSizeOf);
  816. }
  817. n += mStateSelectors.ShallowSizeOfExcludingThis(aMallocSizeOf);
  818. n += SizeOfSelectorsHashTable(mIdSelectors, aMallocSizeOf);
  819. n += SizeOfSelectorsHashTable(mClassSelectors, aMallocSizeOf);
  820. n += mPossiblyNegatedClassSelectors.ShallowSizeOfExcludingThis(aMallocSizeOf);
  821. n += mPossiblyNegatedIDSelectors.ShallowSizeOfExcludingThis(aMallocSizeOf);
  822. n += SizeOfSelectorsHashTable(mAttributeSelectors, aMallocSizeOf);
  823. n += SizeOfRuleHashTable(mAnonBoxRules, aMallocSizeOf);
  824. #ifdef MOZ_XUL
  825. n += SizeOfRuleHashTable(mXULTreeRules, aMallocSizeOf);
  826. #endif
  827. n += mFontFaceRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
  828. n += mKeyframesRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
  829. n += mFontFeatureValuesRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
  830. n += mPageRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
  831. n += mCounterStyleRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
  832. n += mKeyframesRuleTable.ShallowSizeOfExcludingThis(aMallocSizeOf);
  833. for (auto iter = mKeyframesRuleTable.ConstIter(); !iter.Done(); iter.Next()) {
  834. // We don't own the nsCSSKeyframesRule objects so we don't count them. We
  835. // do care about the size of the keys' nsAString members' buffers though.
  836. //
  837. // Note that we depend on nsStringHashKey::GetKey() returning a reference,
  838. // since otherwise aKey would be a copy of the string key and we would not
  839. // be measuring the right object here.
  840. n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
  841. }
  842. return n;
  843. }
  844. nsTArray<SelectorPair>*
  845. RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
  846. {
  847. auto entry = static_cast<AtomSelectorEntry*>
  848. (mAttributeSelectors.Add(aAttribute, fallible));
  849. if (!entry)
  850. return nullptr;
  851. return &entry->mSelectors;
  852. }
  853. // -------------------------------
  854. // CSS Style rule processor implementation
  855. //
  856. nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets,
  857. SheetType aSheetType,
  858. Element* aScopeElement,
  859. nsCSSRuleProcessor*
  860. aPreviousCSSRuleProcessor,
  861. bool aIsShared)
  862. : nsCSSRuleProcessor(sheet_array_type(aSheets), aSheetType, aScopeElement,
  863. aPreviousCSSRuleProcessor, aIsShared)
  864. {
  865. }
  866. nsCSSRuleProcessor::nsCSSRuleProcessor(sheet_array_type&& aSheets,
  867. SheetType aSheetType,
  868. Element* aScopeElement,
  869. nsCSSRuleProcessor*
  870. aPreviousCSSRuleProcessor,
  871. bool aIsShared)
  872. : mSheets(aSheets)
  873. , mRuleCascades(nullptr)
  874. , mPreviousCacheKey(aPreviousCSSRuleProcessor
  875. ? aPreviousCSSRuleProcessor->CloneMQCacheKey()
  876. : UniquePtr<nsMediaQueryResultCacheKey>())
  877. , mLastPresContext(nullptr)
  878. , mScopeElement(aScopeElement)
  879. , mStyleSetRefCnt(0)
  880. , mSheetType(aSheetType)
  881. , mIsShared(aIsShared)
  882. , mMustGatherDocumentRules(aIsShared)
  883. , mInRuleProcessorCache(false)
  884. #ifdef DEBUG
  885. , mDocumentRulesAndCacheKeyValid(false)
  886. #endif
  887. {
  888. NS_ASSERTION(!!mScopeElement == (aSheetType == SheetType::ScopedDoc),
  889. "aScopeElement must be specified iff aSheetType is "
  890. "eScopedDocSheet");
  891. for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) {
  892. mSheets[i]->AddRuleProcessor(this);
  893. }
  894. }
  895. nsCSSRuleProcessor::~nsCSSRuleProcessor()
  896. {
  897. if (mInRuleProcessorCache) {
  898. RuleProcessorCache::RemoveRuleProcessor(this);
  899. }
  900. MOZ_ASSERT(!mExpirationState.IsTracked());
  901. MOZ_ASSERT(mStyleSetRefCnt == 0);
  902. ClearSheets();
  903. ClearRuleCascades();
  904. }
  905. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSRuleProcessor)
  906. NS_INTERFACE_MAP_ENTRY(nsIStyleRuleProcessor)
  907. NS_INTERFACE_MAP_END
  908. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSRuleProcessor)
  909. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSRuleProcessor)
  910. NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSRuleProcessor)
  911. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSRuleProcessor)
  912. tmp->ClearSheets();
  913. NS_IMPL_CYCLE_COLLECTION_UNLINK(mScopeElement)
  914. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  915. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSRuleProcessor)
  916. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSheets)
  917. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScopeElement)
  918. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  919. void
  920. nsCSSRuleProcessor::ClearSheets()
  921. {
  922. for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) {
  923. mSheets[i]->DropRuleProcessor(this);
  924. }
  925. mSheets.Clear();
  926. }
  927. /* static */ void
  928. nsCSSRuleProcessor::Startup()
  929. {
  930. Preferences::AddBoolVarCache(&gSupportVisitedPseudo, VISITED_PSEUDO_PREF,
  931. true);
  932. }
  933. static bool
  934. InitSystemMetrics()
  935. {
  936. NS_ASSERTION(!sSystemMetrics, "already initialized");
  937. sSystemMetrics = new nsTArray< nsCOMPtr<nsIAtom> >;
  938. NS_ENSURE_TRUE(sSystemMetrics, false);
  939. /***************************************************************************
  940. * ANY METRICS ADDED HERE SHOULD ALSO BE ADDED AS MEDIA QUERIES IN *
  941. * nsMediaFeatures.cpp *
  942. ***************************************************************************/
  943. int32_t metricResult =
  944. LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollArrowStyle);
  945. if (metricResult & LookAndFeel::eScrollArrow_StartBackward) {
  946. sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_start_backward);
  947. }
  948. if (metricResult & LookAndFeel::eScrollArrow_StartForward) {
  949. sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_start_forward);
  950. }
  951. if (metricResult & LookAndFeel::eScrollArrow_EndBackward) {
  952. sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_end_backward);
  953. }
  954. if (metricResult & LookAndFeel::eScrollArrow_EndForward) {
  955. sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_end_forward);
  956. }
  957. metricResult =
  958. LookAndFeel::GetInt(LookAndFeel::eIntID_ScrollSliderStyle);
  959. if (metricResult != LookAndFeel::eScrollThumbStyle_Normal) {
  960. sSystemMetrics->AppendElement(nsGkAtoms::scrollbar_thumb_proportional);
  961. }
  962. metricResult =
  963. LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars);
  964. if (metricResult) {
  965. sSystemMetrics->AppendElement(nsGkAtoms::overlay_scrollbars);
  966. }
  967. metricResult =
  968. LookAndFeel::GetInt(LookAndFeel::eIntID_MenuBarDrag);
  969. if (metricResult) {
  970. sSystemMetrics->AppendElement(nsGkAtoms::menubar_drag);
  971. }
  972. nsresult rv =
  973. LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsDefaultTheme, &metricResult);
  974. if (NS_SUCCEEDED(rv) && metricResult) {
  975. sSystemMetrics->AppendElement(nsGkAtoms::windows_default_theme);
  976. }
  977. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacGraphiteTheme, &metricResult);
  978. if (NS_SUCCEEDED(rv) && metricResult) {
  979. sSystemMetrics->AppendElement(nsGkAtoms::mac_graphite_theme);
  980. }
  981. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacLionTheme, &metricResult);
  982. if (NS_SUCCEEDED(rv) && metricResult) {
  983. sSystemMetrics->AppendElement(nsGkAtoms::mac_lion_theme);
  984. }
  985. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_MacYosemiteTheme, &metricResult);
  986. if (NS_SUCCEEDED(rv) && metricResult) {
  987. sSystemMetrics->AppendElement(nsGkAtoms::mac_yosemite_theme);
  988. }
  989. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsAccentColorApplies, &metricResult);
  990. if (NS_SUCCEEDED(rv) && metricResult) {
  991. sSystemMetrics->AppendElement(nsGkAtoms::windows_accent_color_applies);
  992. }
  993. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsAccentColorIsDark, &metricResult);
  994. if (NS_SUCCEEDED(rv) && metricResult) {
  995. sSystemMetrics->AppendElement(nsGkAtoms::windows_accent_color_is_dark);
  996. }
  997. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_DWMCompositor, &metricResult);
  998. if (NS_SUCCEEDED(rv) && metricResult) {
  999. sSystemMetrics->AppendElement(nsGkAtoms::windows_compositor);
  1000. }
  1001. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsGlass, &metricResult);
  1002. if (NS_SUCCEEDED(rv) && metricResult) {
  1003. sSystemMetrics->AppendElement(nsGkAtoms::windows_glass);
  1004. }
  1005. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_ColorPickerAvailable, &metricResult);
  1006. if (NS_SUCCEEDED(rv) && metricResult) {
  1007. sSystemMetrics->AppendElement(nsGkAtoms::color_picker_available);
  1008. }
  1009. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsClassic, &metricResult);
  1010. if (NS_SUCCEEDED(rv) && metricResult) {
  1011. sSystemMetrics->AppendElement(nsGkAtoms::windows_classic);
  1012. }
  1013. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_TouchEnabled, &metricResult);
  1014. if (NS_SUCCEEDED(rv) && metricResult) {
  1015. sSystemMetrics->AppendElement(nsGkAtoms::touch_enabled);
  1016. }
  1017. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_SwipeAnimationEnabled,
  1018. &metricResult);
  1019. if (NS_SUCCEEDED(rv) && metricResult) {
  1020. sSystemMetrics->AppendElement(nsGkAtoms::swipe_animation_enabled);
  1021. }
  1022. rv = LookAndFeel::GetInt(LookAndFeel::eIntID_PhysicalHomeButton,
  1023. &metricResult);
  1024. if (NS_SUCCEEDED(rv) && metricResult) {
  1025. sSystemMetrics->AppendElement(nsGkAtoms::physical_home_button);
  1026. }
  1027. #ifdef XP_WIN
  1028. if (NS_SUCCEEDED(
  1029. LookAndFeel::GetInt(LookAndFeel::eIntID_WindowsThemeIdentifier,
  1030. &metricResult))) {
  1031. nsCSSRuleProcessor::SetWindowsThemeIdentifier(static_cast<uint8_t>(metricResult));
  1032. switch(metricResult) {
  1033. case LookAndFeel::eWindowsTheme_Aero:
  1034. sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_aero);
  1035. break;
  1036. case LookAndFeel::eWindowsTheme_AeroLite:
  1037. sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_aero_lite);
  1038. break;
  1039. case LookAndFeel::eWindowsTheme_Generic:
  1040. sSystemMetrics->AppendElement(nsGkAtoms::windows_theme_generic);
  1041. break;
  1042. }
  1043. }
  1044. #endif
  1045. return true;
  1046. }
  1047. /* static */ void
  1048. nsCSSRuleProcessor::FreeSystemMetrics()
  1049. {
  1050. delete sSystemMetrics;
  1051. sSystemMetrics = nullptr;
  1052. }
  1053. /* static */ void
  1054. nsCSSRuleProcessor::Shutdown()
  1055. {
  1056. FreeSystemMetrics();
  1057. }
  1058. /* static */ bool
  1059. nsCSSRuleProcessor::HasSystemMetric(nsIAtom* aMetric)
  1060. {
  1061. if (!sSystemMetrics && !InitSystemMetrics()) {
  1062. return false;
  1063. }
  1064. return sSystemMetrics->IndexOf(aMetric) != sSystemMetrics->NoIndex;
  1065. }
  1066. #ifdef XP_WIN
  1067. /* static */ uint8_t
  1068. nsCSSRuleProcessor::GetWindowsThemeIdentifier()
  1069. {
  1070. if (!sSystemMetrics)
  1071. InitSystemMetrics();
  1072. return sWinThemeId;
  1073. }
  1074. #endif
  1075. /* static */
  1076. EventStates
  1077. nsCSSRuleProcessor::GetContentState(Element* aElement, const TreeMatchContext& aTreeMatchContext)
  1078. {
  1079. EventStates state = aElement->StyleState();
  1080. // If we are not supposed to mark visited links as such, be sure to
  1081. // flip the bits appropriately. We want to do this here, rather
  1082. // than in GetContentStateForVisitedHandling, so that we don't
  1083. // expose that :visited support is disabled to the Web page.
  1084. if (state.HasState(NS_EVENT_STATE_VISITED) &&
  1085. (!gSupportVisitedPseudo ||
  1086. aElement->OwnerDoc()->IsBeingUsedAsImage() ||
  1087. aTreeMatchContext.mUsingPrivateBrowsing)) {
  1088. state &= ~NS_EVENT_STATE_VISITED;
  1089. state |= NS_EVENT_STATE_UNVISITED;
  1090. }
  1091. return state;
  1092. }
  1093. /* static */
  1094. bool
  1095. nsCSSRuleProcessor::IsLink(const Element* aElement)
  1096. {
  1097. EventStates state = aElement->StyleState();
  1098. return state.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
  1099. }
  1100. /* static */
  1101. EventStates
  1102. nsCSSRuleProcessor::GetContentStateForVisitedHandling(
  1103. Element* aElement,
  1104. const TreeMatchContext& aTreeMatchContext,
  1105. nsRuleWalker::VisitedHandlingType aVisitedHandling,
  1106. bool aIsRelevantLink)
  1107. {
  1108. EventStates contentState = GetContentState(aElement, aTreeMatchContext);
  1109. if (contentState.HasAtLeastOneOfStates(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED)) {
  1110. MOZ_ASSERT(IsLink(aElement), "IsLink() should match state");
  1111. contentState &= ~(NS_EVENT_STATE_VISITED | NS_EVENT_STATE_UNVISITED);
  1112. if (aIsRelevantLink) {
  1113. switch (aVisitedHandling) {
  1114. case nsRuleWalker::eRelevantLinkUnvisited:
  1115. contentState |= NS_EVENT_STATE_UNVISITED;
  1116. break;
  1117. case nsRuleWalker::eRelevantLinkVisited:
  1118. contentState |= NS_EVENT_STATE_VISITED;
  1119. break;
  1120. case nsRuleWalker::eLinksVisitedOrUnvisited:
  1121. contentState |= NS_EVENT_STATE_UNVISITED | NS_EVENT_STATE_VISITED;
  1122. break;
  1123. }
  1124. } else {
  1125. contentState |= NS_EVENT_STATE_UNVISITED;
  1126. }
  1127. }
  1128. return contentState;
  1129. }
  1130. /**
  1131. * A |NodeMatchContext| has data about matching a selector (without
  1132. * combinators) against a single node. It contains only input to the
  1133. * matching.
  1134. *
  1135. * Unlike |RuleProcessorData|, which is similar, a |NodeMatchContext|
  1136. * can vary depending on the selector matching process. In other words,
  1137. * there might be multiple NodeMatchContexts corresponding to a single
  1138. * node, but only one possible RuleProcessorData.
  1139. */
  1140. struct NodeMatchContext {
  1141. // In order to implement nsCSSRuleProcessor::HasStateDependentStyle,
  1142. // we need to be able to see if a node might match an
  1143. // event-state-dependent selector for any value of that event state.
  1144. // So mStateMask contains the states that should NOT be tested.
  1145. //
  1146. // NOTE: For |mStateMask| to work correctly, it's important that any
  1147. // change that changes multiple state bits include all those state
  1148. // bits in the notification. Otherwise, if multiple states change but
  1149. // we do separate notifications then we might determine the style is
  1150. // not state-dependent when it really is (e.g., determining that a
  1151. // :hover:active rule no longer matches when both states are unset).
  1152. const EventStates mStateMask;
  1153. // Is this link the unique link whose visitedness can affect the style
  1154. // of the node being matched? (That link is the nearest link to the
  1155. // node being matched that is itself or an ancestor.)
  1156. //
  1157. // Always false when TreeMatchContext::mForStyling is false. (We
  1158. // could figure it out for SelectorListMatches, but we're starting
  1159. // from the middle of the selector list when doing
  1160. // Has{Attribute,State}DependentStyle, so we can't tell. So when
  1161. // mForStyling is false, we have to assume we don't know.)
  1162. const bool mIsRelevantLink;
  1163. NodeMatchContext(EventStates aStateMask, bool aIsRelevantLink)
  1164. : mStateMask(aStateMask)
  1165. , mIsRelevantLink(aIsRelevantLink)
  1166. {
  1167. }
  1168. };
  1169. /**
  1170. * Additional information about a selector (without combinators) that is
  1171. * being matched.
  1172. */
  1173. enum class SelectorMatchesFlags : uint8_t {
  1174. NONE = 0,
  1175. // The selector's flags are unknown. This happens when you don't know
  1176. // if you're starting from the top of a selector. Only used in cases
  1177. // where it's acceptable for matching to return a false positive.
  1178. // (It's not OK to return a false negative.)
  1179. UNKNOWN = 1 << 0,
  1180. // The selector is part of a compound selector which has been split in
  1181. // half, where the other half is a pseudo-element. The current
  1182. // selector is not a pseudo-element itself.
  1183. HAS_PSEUDO_ELEMENT = 1 << 1,
  1184. // The selector is part of an argument to a functional pseudo-class or
  1185. // pseudo-element.
  1186. IS_PSEUDO_CLASS_ARGUMENT = 1 << 2
  1187. };
  1188. MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(SelectorMatchesFlags)
  1189. // Return whether the selector matches conditions for the :active and
  1190. // :hover quirk.
  1191. static inline bool ActiveHoverQuirkMatches(nsCSSSelector* aSelector,
  1192. SelectorMatchesFlags aSelectorFlags)
  1193. {
  1194. if (aSelector->HasTagSelector() || aSelector->mAttrList ||
  1195. aSelector->mIDList || aSelector->mClassList ||
  1196. aSelector->IsPseudoElement() ||
  1197. // Having this quirk means that some selectors will no longer match,
  1198. // so it's better to return false when we aren't sure (i.e., the
  1199. // flags are unknown).
  1200. aSelectorFlags & (SelectorMatchesFlags::UNKNOWN |
  1201. SelectorMatchesFlags::HAS_PSEUDO_ELEMENT |
  1202. SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
  1203. return false;
  1204. }
  1205. // No pseudo-class other than :active and :hover.
  1206. for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
  1207. pseudoClass; pseudoClass = pseudoClass->mNext) {
  1208. if (pseudoClass->mType != CSSPseudoClassType::hover &&
  1209. pseudoClass->mType != CSSPseudoClassType::active) {
  1210. return false;
  1211. }
  1212. }
  1213. return true;
  1214. }
  1215. static inline bool
  1216. IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
  1217. bool aWhitespaceIsSignificant)
  1218. {
  1219. return nsStyleUtil::IsSignificantChild(aChild, aTextIsSignificant,
  1220. aWhitespaceIsSignificant);
  1221. }
  1222. // This function is to be called once we have fetched a value for an attribute
  1223. // whose namespace and name match those of aAttrSelector. This function
  1224. // performs comparisons on the value only, based on aAttrSelector->mFunction.
  1225. static bool AttrMatchesValue(const nsAttrSelector* aAttrSelector,
  1226. const nsString& aValue, bool isHTML)
  1227. {
  1228. NS_PRECONDITION(aAttrSelector, "Must have an attribute selector");
  1229. // http://lists.w3.org/Archives/Public/www-style/2008Apr/0038.html
  1230. // *= (CONTAINSMATCH) ~= (INCLUDES) ^= (BEGINSMATCH) $= (ENDSMATCH)
  1231. // all accept the empty string, but match nothing.
  1232. if (aAttrSelector->mValue.IsEmpty() &&
  1233. (aAttrSelector->mFunction == NS_ATTR_FUNC_INCLUDES ||
  1234. aAttrSelector->mFunction == NS_ATTR_FUNC_ENDSMATCH ||
  1235. aAttrSelector->mFunction == NS_ATTR_FUNC_BEGINSMATCH ||
  1236. aAttrSelector->mFunction == NS_ATTR_FUNC_CONTAINSMATCH))
  1237. return false;
  1238. const nsDefaultStringComparator defaultComparator;
  1239. const nsASCIICaseInsensitiveStringComparator ciComparator;
  1240. const nsStringComparator& comparator =
  1241. aAttrSelector->IsValueCaseSensitive(isHTML)
  1242. ? static_cast<const nsStringComparator&>(defaultComparator)
  1243. : static_cast<const nsStringComparator&>(ciComparator);
  1244. switch (aAttrSelector->mFunction) {
  1245. case NS_ATTR_FUNC_EQUALS:
  1246. return aValue.Equals(aAttrSelector->mValue, comparator);
  1247. case NS_ATTR_FUNC_INCLUDES:
  1248. return nsStyleUtil::ValueIncludes(aValue, aAttrSelector->mValue, comparator);
  1249. case NS_ATTR_FUNC_DASHMATCH:
  1250. return nsStyleUtil::DashMatchCompare(aValue, aAttrSelector->mValue, comparator);
  1251. case NS_ATTR_FUNC_ENDSMATCH:
  1252. return StringEndsWith(aValue, aAttrSelector->mValue, comparator);
  1253. case NS_ATTR_FUNC_BEGINSMATCH:
  1254. return StringBeginsWith(aValue, aAttrSelector->mValue, comparator);
  1255. case NS_ATTR_FUNC_CONTAINSMATCH:
  1256. return FindInReadable(aAttrSelector->mValue, aValue, comparator);
  1257. default:
  1258. NS_NOTREACHED("Shouldn't be ending up here");
  1259. return false;
  1260. }
  1261. }
  1262. static inline bool
  1263. edgeChildMatches(Element* aElement, TreeMatchContext& aTreeMatchContext,
  1264. bool checkFirst, bool checkLast)
  1265. {
  1266. nsIContent* parent = aElement->GetParent();
  1267. if (parent && aTreeMatchContext.mForStyling)
  1268. parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
  1269. return (!checkFirst ||
  1270. aTreeMatchContext.mNthIndexCache.
  1271. GetNthIndex(aElement, false, false, true) == 1) &&
  1272. (!checkLast ||
  1273. aTreeMatchContext.mNthIndexCache.
  1274. GetNthIndex(aElement, false, true, true) == 1);
  1275. }
  1276. static inline bool
  1277. nthChildGenericMatches(Element* aElement,
  1278. TreeMatchContext& aTreeMatchContext,
  1279. nsPseudoClassList* pseudoClass,
  1280. bool isOfType, bool isFromEnd)
  1281. {
  1282. nsIContent* parent = aElement->GetParent();
  1283. if (parent && aTreeMatchContext.mForStyling) {
  1284. if (isFromEnd)
  1285. parent->SetFlags(NODE_HAS_SLOW_SELECTOR);
  1286. else
  1287. parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
  1288. }
  1289. const int32_t index = aTreeMatchContext.mNthIndexCache.
  1290. GetNthIndex(aElement, isOfType, isFromEnd, false);
  1291. if (index <= 0) {
  1292. // Node is anonymous content (not really a child of its parent).
  1293. return false;
  1294. }
  1295. const int32_t a = pseudoClass->u.mNumbers[0];
  1296. const int32_t b = pseudoClass->u.mNumbers[1];
  1297. // result should be true if there exists n >= 0 such that
  1298. // a * n + b == index.
  1299. if (a == 0) {
  1300. return b == index;
  1301. }
  1302. // Integer division in C does truncation (towards 0). So
  1303. // check that the result is nonnegative, and that there was no
  1304. // truncation.
  1305. const CheckedInt<int32_t> indexMinusB = CheckedInt<int32_t>(index) - b;
  1306. const CheckedInt<int32_t> n = indexMinusB / a;
  1307. return n.isValid() &&
  1308. n.value() >= 0 &&
  1309. a * n == indexMinusB;
  1310. }
  1311. static inline bool
  1312. edgeOfTypeMatches(Element* aElement, TreeMatchContext& aTreeMatchContext,
  1313. bool checkFirst, bool checkLast)
  1314. {
  1315. nsIContent *parent = aElement->GetParent();
  1316. if (parent && aTreeMatchContext.mForStyling) {
  1317. if (checkLast)
  1318. parent->SetFlags(NODE_HAS_SLOW_SELECTOR);
  1319. else
  1320. parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
  1321. }
  1322. return (!checkFirst ||
  1323. aTreeMatchContext.mNthIndexCache.
  1324. GetNthIndex(aElement, true, false, true) == 1) &&
  1325. (!checkLast ||
  1326. aTreeMatchContext.mNthIndexCache.
  1327. GetNthIndex(aElement, true, true, true) == 1);
  1328. }
  1329. static inline bool
  1330. checkGenericEmptyMatches(Element* aElement,
  1331. TreeMatchContext& aTreeMatchContext,
  1332. bool isWhitespaceSignificant)
  1333. {
  1334. nsIContent *child = nullptr;
  1335. int32_t index = -1;
  1336. if (aTreeMatchContext.mForStyling)
  1337. aElement->SetFlags(NODE_HAS_EMPTY_SELECTOR);
  1338. do {
  1339. child = aElement->GetChildAt(++index);
  1340. // stop at first non-comment (and non-whitespace for
  1341. // :-moz-only-whitespace) node
  1342. } while (child && !IsSignificantChild(child, true, isWhitespaceSignificant));
  1343. return (child == nullptr);
  1344. }
  1345. // Arrays of the states that are relevant for various pseudoclasses.
  1346. static const EventStates sPseudoClassStateDependences[] = {
  1347. #define CSS_PSEUDO_CLASS(_name, _value, _flags, _pref) \
  1348. EventStates(),
  1349. #define CSS_STATE_DEPENDENT_PSEUDO_CLASS(_name, _value, _flags, _pref, _states) \
  1350. _states,
  1351. #include "nsCSSPseudoClassList.h"
  1352. #undef CSS_STATE_DEPENDENT_PSEUDO_CLASS
  1353. #undef CSS_PSEUDO_CLASS
  1354. // Add more entries for our fake values to make sure we can't
  1355. // index out of bounds into this array no matter what.
  1356. EventStates(),
  1357. EventStates()
  1358. };
  1359. static const EventStates sPseudoClassStates[] = {
  1360. #define CSS_PSEUDO_CLASS(_name, _value, _flags, _pref) \
  1361. EventStates(),
  1362. #define CSS_STATE_PSEUDO_CLASS(_name, _value, _flags, _pref, _states) \
  1363. _states,
  1364. #include "nsCSSPseudoClassList.h"
  1365. #undef CSS_STATE_PSEUDO_CLASS
  1366. #undef CSS_PSEUDO_CLASS
  1367. // Add more entries for our fake values to make sure we can't
  1368. // index out of bounds into this array no matter what.
  1369. EventStates(),
  1370. EventStates()
  1371. };
  1372. static_assert(MOZ_ARRAY_LENGTH(sPseudoClassStates) ==
  1373. static_cast<size_t>(CSSPseudoClassType::MAX),
  1374. "CSSPseudoClassType::MAX is no longer equal to the length of "
  1375. "sPseudoClassStates");
  1376. static bool
  1377. StateSelectorMatches(Element* aElement,
  1378. nsCSSSelector* aSelector,
  1379. NodeMatchContext& aNodeMatchContext,
  1380. TreeMatchContext& aTreeMatchContext,
  1381. SelectorMatchesFlags aSelectorFlags,
  1382. bool* const aDependence,
  1383. EventStates aStatesToCheck)
  1384. {
  1385. NS_PRECONDITION(!aStatesToCheck.IsEmpty(),
  1386. "should only need to call StateSelectorMatches if "
  1387. "aStatesToCheck is not empty");
  1388. // Bit-based pseudo-classes
  1389. if (aStatesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_ACTIVE |
  1390. NS_EVENT_STATE_HOVER) &&
  1391. aTreeMatchContext.mCompatMode == eCompatibility_NavQuirks &&
  1392. ActiveHoverQuirkMatches(aSelector, aSelectorFlags) &&
  1393. aElement->IsHTMLElement() && !nsCSSRuleProcessor::IsLink(aElement)) {
  1394. // In quirks mode, only make links sensitive to selectors ":active"
  1395. // and ":hover".
  1396. return false;
  1397. }
  1398. if (aTreeMatchContext.mForStyling &&
  1399. aStatesToCheck.HasAtLeastOneOfStates(NS_EVENT_STATE_HOVER)) {
  1400. // Mark the element as having :hover-dependent style
  1401. aElement->SetHasRelevantHoverRules();
  1402. }
  1403. if (aNodeMatchContext.mStateMask.HasAtLeastOneOfStates(aStatesToCheck)) {
  1404. if (aDependence) {
  1405. *aDependence = true;
  1406. }
  1407. } else {
  1408. EventStates contentState =
  1409. nsCSSRuleProcessor::GetContentStateForVisitedHandling(
  1410. aElement,
  1411. aTreeMatchContext,
  1412. aTreeMatchContext.VisitedHandling(),
  1413. aNodeMatchContext.mIsRelevantLink);
  1414. if (!contentState.HasAtLeastOneOfStates(aStatesToCheck)) {
  1415. return false;
  1416. }
  1417. }
  1418. return true;
  1419. }
  1420. static bool
  1421. StateSelectorMatches(Element* aElement,
  1422. nsCSSSelector* aSelector,
  1423. NodeMatchContext& aNodeMatchContext,
  1424. TreeMatchContext& aTreeMatchContext,
  1425. SelectorMatchesFlags aSelectorFlags)
  1426. {
  1427. for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
  1428. pseudoClass; pseudoClass = pseudoClass->mNext) {
  1429. auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
  1430. EventStates statesToCheck = sPseudoClassStates[idx];
  1431. if (!statesToCheck.IsEmpty() &&
  1432. !StateSelectorMatches(aElement, aSelector, aNodeMatchContext,
  1433. aTreeMatchContext, aSelectorFlags, nullptr,
  1434. statesToCheck)) {
  1435. return false;
  1436. }
  1437. }
  1438. return true;
  1439. }
  1440. // |aDependence| has two functions:
  1441. // * when non-null, it indicates that we're processing a negation,
  1442. // which is done only when SelectorMatches calls itself recursively
  1443. // * what it points to should be set to true whenever a test is skipped
  1444. // because of aNodeMatchContent.mStateMask
  1445. static bool SelectorMatches(Element* aElement,
  1446. nsCSSSelector* aSelector,
  1447. NodeMatchContext& aNodeMatchContext,
  1448. TreeMatchContext& aTreeMatchContext,
  1449. SelectorMatchesFlags aSelectorFlags,
  1450. bool* const aDependence = nullptr)
  1451. {
  1452. NS_PRECONDITION(!aSelector->IsPseudoElement(),
  1453. "Pseudo-element snuck into SelectorMatches?");
  1454. MOZ_ASSERT(aTreeMatchContext.mForStyling ||
  1455. !aNodeMatchContext.mIsRelevantLink,
  1456. "mIsRelevantLink should be set to false when mForStyling "
  1457. "is false since we don't know how to set it correctly in "
  1458. "Has(Attribute|State)DependentStyle");
  1459. // namespace/tag match
  1460. // optimization : bail out early if we can
  1461. if ((kNameSpaceID_Unknown != aSelector->mNameSpace &&
  1462. aElement->GetNameSpaceID() != aSelector->mNameSpace))
  1463. return false;
  1464. if (aSelector->mLowercaseTag) {
  1465. nsIAtom* selectorTag =
  1466. (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTMLElement()) ?
  1467. aSelector->mLowercaseTag : aSelector->mCasedTag;
  1468. if (selectorTag != aElement->NodeInfo()->NameAtom()) {
  1469. return false;
  1470. }
  1471. }
  1472. nsAtomList* IDList = aSelector->mIDList;
  1473. if (IDList) {
  1474. nsIAtom* id = aElement->GetID();
  1475. if (id) {
  1476. // case sensitivity: bug 93371
  1477. const bool isCaseSensitive =
  1478. aTreeMatchContext.mCompatMode != eCompatibility_NavQuirks;
  1479. if (isCaseSensitive) {
  1480. do {
  1481. if (IDList->mAtom != id) {
  1482. return false;
  1483. }
  1484. IDList = IDList->mNext;
  1485. } while (IDList);
  1486. } else {
  1487. // Use EqualsIgnoreASCIICase instead of full on unicode case conversion
  1488. // in order to save on performance. This is only used in quirks mode
  1489. // anyway.
  1490. nsDependentAtomString id1Str(id);
  1491. do {
  1492. if (!nsContentUtils::EqualsIgnoreASCIICase(id1Str,
  1493. nsDependentAtomString(IDList->mAtom))) {
  1494. return false;
  1495. }
  1496. IDList = IDList->mNext;
  1497. } while (IDList);
  1498. }
  1499. } else {
  1500. // Element has no id but we have an id selector
  1501. return false;
  1502. }
  1503. }
  1504. nsAtomList* classList = aSelector->mClassList;
  1505. if (classList) {
  1506. // test for class match
  1507. const nsAttrValue *elementClasses = aElement->GetClasses();
  1508. if (!elementClasses) {
  1509. // Element has no classes but we have a class selector
  1510. return false;
  1511. }
  1512. // case sensitivity: bug 93371
  1513. const bool isCaseSensitive =
  1514. aTreeMatchContext.mCompatMode != eCompatibility_NavQuirks;
  1515. while (classList) {
  1516. if (!elementClasses->Contains(classList->mAtom,
  1517. isCaseSensitive ?
  1518. eCaseMatters : eIgnoreCase)) {
  1519. return false;
  1520. }
  1521. classList = classList->mNext;
  1522. }
  1523. }
  1524. const bool isNegated = (aDependence != nullptr);
  1525. // The selectors for which we set node bits are, unfortunately, early
  1526. // in this function (because they're pseudo-classes, which are
  1527. // generally quick to test, and thus earlier). If they were later,
  1528. // we'd probably avoid setting those bits in more cases where setting
  1529. // them is unnecessary.
  1530. NS_ASSERTION(aNodeMatchContext.mStateMask.IsEmpty() ||
  1531. !aTreeMatchContext.mForStyling,
  1532. "mForStyling must be false if we're just testing for "
  1533. "state-dependence");
  1534. // test for pseudo class match
  1535. for (nsPseudoClassList* pseudoClass = aSelector->mPseudoClassList;
  1536. pseudoClass; pseudoClass = pseudoClass->mNext) {
  1537. auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
  1538. EventStates statesToCheck = sPseudoClassStates[idx];
  1539. if (statesToCheck.IsEmpty()) {
  1540. // keep the cases here in the same order as the list in
  1541. // nsCSSPseudoClassList.h
  1542. switch (pseudoClass->mType) {
  1543. case CSSPseudoClassType::empty:
  1544. if (!checkGenericEmptyMatches(aElement, aTreeMatchContext, true)) {
  1545. return false;
  1546. }
  1547. break;
  1548. case CSSPseudoClassType::mozOnlyWhitespace:
  1549. if (!checkGenericEmptyMatches(aElement, aTreeMatchContext, false)) {
  1550. return false;
  1551. }
  1552. break;
  1553. case CSSPseudoClassType::mozEmptyExceptChildrenWithLocalname:
  1554. {
  1555. NS_ASSERTION(pseudoClass->u.mString, "Must have string!");
  1556. nsIContent *child = nullptr;
  1557. int32_t index = -1;
  1558. if (aTreeMatchContext.mForStyling)
  1559. // FIXME: This isn't sufficient to handle:
  1560. // :-moz-empty-except-children-with-localname() + E
  1561. // :-moz-empty-except-children-with-localname() ~ E
  1562. // because we don't know to restyle the grandparent of the
  1563. // inserted/removed element (as in bug 534804 for :empty).
  1564. aElement->SetFlags(NODE_HAS_SLOW_SELECTOR);
  1565. do {
  1566. child = aElement->GetChildAt(++index);
  1567. } while (child &&
  1568. (!IsSignificantChild(child, true, false) ||
  1569. (child->GetNameSpaceID() == aElement->GetNameSpaceID() &&
  1570. child->NodeInfo()->NameAtom()->Equals(nsDependentString(pseudoClass->u.mString)))));
  1571. if (child != nullptr) {
  1572. return false;
  1573. }
  1574. }
  1575. break;
  1576. case CSSPseudoClassType::lang:
  1577. {
  1578. NS_ASSERTION(nullptr != pseudoClass->u.mString, "null lang parameter");
  1579. if (!pseudoClass->u.mString || !*pseudoClass->u.mString) {
  1580. return false;
  1581. }
  1582. // We have to determine the language of the current element. Since
  1583. // this is currently no property and since the language is inherited
  1584. // from the parent we have to be prepared to look at all parent
  1585. // nodes. The language itself is encoded in the LANG attribute.
  1586. nsAutoString language;
  1587. if (aElement->GetLang(language)) {
  1588. if (!nsStyleUtil::DashMatchCompare(language,
  1589. nsDependentString(pseudoClass->u.mString),
  1590. nsASCIICaseInsensitiveStringComparator())) {
  1591. return false;
  1592. }
  1593. // This pseudo-class matched; move on to the next thing
  1594. break;
  1595. }
  1596. nsIDocument* doc = aTreeMatchContext.mDocument;
  1597. if (doc) {
  1598. // Try to get the language from the HTTP header or if this
  1599. // is missing as well from the preferences.
  1600. // The content language can be a comma-separated list of
  1601. // language codes.
  1602. doc->GetContentLanguage(language);
  1603. nsDependentString langString(pseudoClass->u.mString);
  1604. language.StripWhitespace();
  1605. int32_t begin = 0;
  1606. int32_t len = language.Length();
  1607. while (begin < len) {
  1608. int32_t end = language.FindChar(char16_t(','), begin);
  1609. if (end == kNotFound) {
  1610. end = len;
  1611. }
  1612. if (nsStyleUtil::DashMatchCompare(Substring(language, begin,
  1613. end-begin),
  1614. langString,
  1615. nsASCIICaseInsensitiveStringComparator())) {
  1616. break;
  1617. }
  1618. begin = end + 1;
  1619. }
  1620. if (begin < len) {
  1621. // This pseudo-class matched
  1622. break;
  1623. }
  1624. }
  1625. }
  1626. return false;
  1627. case CSSPseudoClassType::mozBoundElement:
  1628. if (aTreeMatchContext.mScopedRoot != aElement) {
  1629. return false;
  1630. }
  1631. break;
  1632. case CSSPseudoClassType::root:
  1633. if (aElement != aElement->OwnerDoc()->GetRootElement()) {
  1634. return false;
  1635. }
  1636. break;
  1637. case CSSPseudoClassType::any:
  1638. {
  1639. nsCSSSelectorList *l;
  1640. for (l = pseudoClass->u.mSelectors; l; l = l->mNext) {
  1641. nsCSSSelector *s = l->mSelectors;
  1642. MOZ_ASSERT(!s->mNext && !s->IsPseudoElement(),
  1643. "parser failed");
  1644. if (SelectorMatches(
  1645. aElement, s, aNodeMatchContext, aTreeMatchContext,
  1646. SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT)) {
  1647. break;
  1648. }
  1649. }
  1650. if (!l) {
  1651. return false;
  1652. }
  1653. }
  1654. break;
  1655. case CSSPseudoClassType::firstChild:
  1656. if (!edgeChildMatches(aElement, aTreeMatchContext, true, false)) {
  1657. return false;
  1658. }
  1659. break;
  1660. case CSSPseudoClassType::firstNode:
  1661. {
  1662. nsIContent *firstNode = nullptr;
  1663. nsIContent *parent = aElement->GetParent();
  1664. if (parent) {
  1665. if (aTreeMatchContext.mForStyling)
  1666. parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
  1667. int32_t index = -1;
  1668. do {
  1669. firstNode = parent->GetChildAt(++index);
  1670. // stop at first non-comment and non-whitespace node
  1671. } while (firstNode &&
  1672. !IsSignificantChild(firstNode, true, false));
  1673. }
  1674. if (aElement != firstNode) {
  1675. return false;
  1676. }
  1677. }
  1678. break;
  1679. case CSSPseudoClassType::lastChild:
  1680. if (!edgeChildMatches(aElement, aTreeMatchContext, false, true)) {
  1681. return false;
  1682. }
  1683. break;
  1684. case CSSPseudoClassType::lastNode:
  1685. {
  1686. nsIContent *lastNode = nullptr;
  1687. nsIContent *parent = aElement->GetParent();
  1688. if (parent) {
  1689. if (aTreeMatchContext.mForStyling)
  1690. parent->SetFlags(NODE_HAS_EDGE_CHILD_SELECTOR);
  1691. uint32_t index = parent->GetChildCount();
  1692. do {
  1693. lastNode = parent->GetChildAt(--index);
  1694. // stop at first non-comment and non-whitespace node
  1695. } while (lastNode &&
  1696. !IsSignificantChild(lastNode, true, false));
  1697. }
  1698. if (aElement != lastNode) {
  1699. return false;
  1700. }
  1701. }
  1702. break;
  1703. case CSSPseudoClassType::onlyChild:
  1704. if (!edgeChildMatches(aElement, aTreeMatchContext, true, true)) {
  1705. return false;
  1706. }
  1707. break;
  1708. case CSSPseudoClassType::firstOfType:
  1709. if (!edgeOfTypeMatches(aElement, aTreeMatchContext, true, false)) {
  1710. return false;
  1711. }
  1712. break;
  1713. case CSSPseudoClassType::lastOfType:
  1714. if (!edgeOfTypeMatches(aElement, aTreeMatchContext, false, true)) {
  1715. return false;
  1716. }
  1717. break;
  1718. case CSSPseudoClassType::onlyOfType:
  1719. if (!edgeOfTypeMatches(aElement, aTreeMatchContext, true, true)) {
  1720. return false;
  1721. }
  1722. break;
  1723. case CSSPseudoClassType::nthChild:
  1724. if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
  1725. false, false)) {
  1726. return false;
  1727. }
  1728. break;
  1729. case CSSPseudoClassType::nthLastChild:
  1730. if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
  1731. false, true)) {
  1732. return false;
  1733. }
  1734. break;
  1735. case CSSPseudoClassType::nthOfType:
  1736. if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
  1737. true, false)) {
  1738. return false;
  1739. }
  1740. break;
  1741. case CSSPseudoClassType::nthLastOfType:
  1742. if (!nthChildGenericMatches(aElement, aTreeMatchContext, pseudoClass,
  1743. true, true)) {
  1744. return false;
  1745. }
  1746. break;
  1747. case CSSPseudoClassType::mozIsHTML:
  1748. if (!aTreeMatchContext.mIsHTMLDocument || !aElement->IsHTMLElement()) {
  1749. return false;
  1750. }
  1751. break;
  1752. case CSSPseudoClassType::mozNativeAnonymous:
  1753. if (!aElement->IsInNativeAnonymousSubtree()) {
  1754. return false;
  1755. }
  1756. break;
  1757. case CSSPseudoClassType::mozSystemMetric:
  1758. {
  1759. nsCOMPtr<nsIAtom> metric = NS_Atomize(pseudoClass->u.mString);
  1760. if (!nsCSSRuleProcessor::HasSystemMetric(metric)) {
  1761. return false;
  1762. }
  1763. }
  1764. break;
  1765. case CSSPseudoClassType::mozLocaleDir:
  1766. {
  1767. bool docIsRTL =
  1768. aTreeMatchContext.mDocument->GetDocumentState().
  1769. HasState(NS_DOCUMENT_STATE_RTL_LOCALE);
  1770. nsDependentString dirString(pseudoClass->u.mString);
  1771. if (dirString.EqualsLiteral("rtl")) {
  1772. if (!docIsRTL) {
  1773. return false;
  1774. }
  1775. } else if (dirString.EqualsLiteral("ltr")) {
  1776. if (docIsRTL) {
  1777. return false;
  1778. }
  1779. } else {
  1780. // Selectors specifying other directions never match.
  1781. return false;
  1782. }
  1783. }
  1784. break;
  1785. case CSSPseudoClassType::mozLWTheme:
  1786. {
  1787. if (aTreeMatchContext.mDocument->GetDocumentLWTheme() <=
  1788. nsIDocument::Doc_Theme_None) {
  1789. return false;
  1790. }
  1791. }
  1792. break;
  1793. case CSSPseudoClassType::mozLWThemeBrightText:
  1794. {
  1795. if (aTreeMatchContext.mDocument->GetDocumentLWTheme() !=
  1796. nsIDocument::Doc_Theme_Bright) {
  1797. return false;
  1798. }
  1799. }
  1800. break;
  1801. case CSSPseudoClassType::mozLWThemeDarkText:
  1802. {
  1803. if (aTreeMatchContext.mDocument->GetDocumentLWTheme() !=
  1804. nsIDocument::Doc_Theme_Dark) {
  1805. return false;
  1806. }
  1807. }
  1808. break;
  1809. case CSSPseudoClassType::mozWindowInactive:
  1810. if (!aTreeMatchContext.mDocument->GetDocumentState().
  1811. HasState(NS_DOCUMENT_STATE_WINDOW_INACTIVE)) {
  1812. return false;
  1813. }
  1814. break;
  1815. case CSSPseudoClassType::mozTableBorderNonzero:
  1816. {
  1817. if (!aElement->IsHTMLElement(nsGkAtoms::table)) {
  1818. return false;
  1819. }
  1820. const nsAttrValue *val = aElement->GetParsedAttr(nsGkAtoms::border);
  1821. if (!val ||
  1822. (val->Type() == nsAttrValue::eInteger &&
  1823. val->GetIntegerValue() == 0)) {
  1824. return false;
  1825. }
  1826. }
  1827. break;
  1828. case CSSPseudoClassType::mozBrowserFrame:
  1829. {
  1830. nsCOMPtr<nsIMozBrowserFrame>
  1831. browserFrame = do_QueryInterface(aElement);
  1832. if (!browserFrame ||
  1833. !browserFrame->GetReallyIsBrowserOrApp()) {
  1834. return false;
  1835. }
  1836. }
  1837. break;
  1838. case CSSPseudoClassType::mozDir:
  1839. case CSSPseudoClassType::dir:
  1840. {
  1841. if (aDependence) {
  1842. EventStates states = sPseudoClassStateDependences[
  1843. static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType)];
  1844. if (aNodeMatchContext.mStateMask.HasAtLeastOneOfStates(states)) {
  1845. *aDependence = true;
  1846. return false;
  1847. }
  1848. }
  1849. // If we only had to consider HTML, directionality would be
  1850. // exclusively LTR or RTL.
  1851. //
  1852. // However, in markup languages where there is no direction attribute
  1853. // we have to consider the possibility that neither dir(rtl) nor
  1854. // dir(ltr) matches.
  1855. EventStates state = aElement->StyleState();
  1856. nsDependentString dirString(pseudoClass->u.mString);
  1857. if (dirString.EqualsLiteral("rtl")) {
  1858. if (!state.HasState(NS_EVENT_STATE_RTL)) {
  1859. return false;
  1860. }
  1861. } else if (dirString.EqualsLiteral("ltr")) {
  1862. if (!state.HasState(NS_EVENT_STATE_LTR)) {
  1863. return false;
  1864. }
  1865. } else {
  1866. // Selectors specifying other directions never match.
  1867. return false;
  1868. }
  1869. }
  1870. break;
  1871. case CSSPseudoClassType::scope:
  1872. if (aTreeMatchContext.mForScopedStyle) {
  1873. if (aTreeMatchContext.mCurrentStyleScope) {
  1874. // If mCurrentStyleScope is null, aElement must be the style
  1875. // scope root. This is because the PopStyleScopeForSelectorMatching
  1876. // call in SelectorMatchesTree sets mCurrentStyleScope to null
  1877. // as soon as we visit the style scope element, and we won't
  1878. // progress further up the tree after this call to
  1879. // SelectorMatches. Thus if mCurrentStyleScope is still set,
  1880. // we know the selector does not match.
  1881. return false;
  1882. }
  1883. } else if (aTreeMatchContext.HasSpecifiedScope()) {
  1884. if (!aTreeMatchContext.IsScopeElement(aElement)) {
  1885. return false;
  1886. }
  1887. } else {
  1888. if (aElement != aElement->OwnerDoc()->GetRootElement()) {
  1889. return false;
  1890. }
  1891. }
  1892. break;
  1893. default:
  1894. MOZ_ASSERT(false, "How did that happen?");
  1895. }
  1896. } else {
  1897. if (!StateSelectorMatches(aElement, aSelector, aNodeMatchContext,
  1898. aTreeMatchContext, aSelectorFlags, aDependence,
  1899. statesToCheck)) {
  1900. return false;
  1901. }
  1902. }
  1903. }
  1904. bool result = true;
  1905. if (aSelector->mAttrList) {
  1906. // test for attribute match
  1907. if (!aElement->HasAttrs()) {
  1908. // if no attributes on the content, no match
  1909. return false;
  1910. } else {
  1911. result = true;
  1912. nsAttrSelector* attr = aSelector->mAttrList;
  1913. nsIAtom* matchAttribute;
  1914. do {
  1915. bool isHTML =
  1916. (aTreeMatchContext.mIsHTMLDocument && aElement->IsHTMLElement());
  1917. matchAttribute = isHTML ? attr->mLowercaseAttr : attr->mCasedAttr;
  1918. if (attr->mNameSpace == kNameSpaceID_Unknown) {
  1919. // Attr selector with a wildcard namespace. We have to examine all
  1920. // the attributes on our content node.... This sort of selector is
  1921. // essentially a boolean OR, over all namespaces, of equivalent attr
  1922. // selectors with those namespaces. So to evaluate whether it
  1923. // matches, evaluate for each namespace (the only namespaces that
  1924. // have a chance at matching, of course, are ones that the element
  1925. // actually has attributes in), short-circuiting if we ever match.
  1926. result = false;
  1927. const nsAttrName* attrName;
  1928. for (uint32_t i = 0; (attrName = aElement->GetAttrNameAt(i)); ++i) {
  1929. if (attrName->LocalName() != matchAttribute) {
  1930. continue;
  1931. }
  1932. if (attr->mFunction == NS_ATTR_FUNC_SET) {
  1933. result = true;
  1934. } else {
  1935. nsAutoString value;
  1936. #ifdef DEBUG
  1937. bool hasAttr =
  1938. #endif
  1939. aElement->GetAttr(attrName->NamespaceID(),
  1940. attrName->LocalName(), value);
  1941. NS_ASSERTION(hasAttr, "GetAttrNameAt lied");
  1942. result = AttrMatchesValue(attr, value, isHTML);
  1943. }
  1944. // At this point |result| has been set by us
  1945. // explicitly in this loop. If it's false, we may still match
  1946. // -- the content may have another attribute with the same name but
  1947. // in a different namespace. But if it's true, we are done (we
  1948. // can short-circuit the boolean OR described above).
  1949. if (result) {
  1950. break;
  1951. }
  1952. }
  1953. }
  1954. else if (attr->mFunction == NS_ATTR_FUNC_EQUALS) {
  1955. result =
  1956. aElement->
  1957. AttrValueIs(attr->mNameSpace, matchAttribute, attr->mValue,
  1958. attr->IsValueCaseSensitive(isHTML) ? eCaseMatters
  1959. : eIgnoreCase);
  1960. }
  1961. else if (!aElement->HasAttr(attr->mNameSpace, matchAttribute)) {
  1962. result = false;
  1963. }
  1964. else if (attr->mFunction != NS_ATTR_FUNC_SET) {
  1965. nsAutoString value;
  1966. #ifdef DEBUG
  1967. bool hasAttr =
  1968. #endif
  1969. aElement->GetAttr(attr->mNameSpace, matchAttribute, value);
  1970. NS_ASSERTION(hasAttr, "HasAttr lied");
  1971. result = AttrMatchesValue(attr, value, isHTML);
  1972. }
  1973. attr = attr->mNext;
  1974. } while (attr && result);
  1975. }
  1976. }
  1977. // apply SelectorMatches to the negated selectors in the chain
  1978. if (!isNegated) {
  1979. for (nsCSSSelector *negation = aSelector->mNegations;
  1980. result && negation; negation = negation->mNegations) {
  1981. bool dependence = false;
  1982. result = !SelectorMatches(aElement, negation, aNodeMatchContext,
  1983. aTreeMatchContext,
  1984. SelectorMatchesFlags::IS_PSEUDO_CLASS_ARGUMENT,
  1985. &dependence);
  1986. // If the selector does match due to the dependence on
  1987. // aNodeMatchContext.mStateMask, then we want to keep result true
  1988. // so that the final result of SelectorMatches is true. Doing so
  1989. // tells StateEnumFunc that there is a dependence on the state.
  1990. result = result || dependence;
  1991. }
  1992. }
  1993. return result;
  1994. }
  1995. #undef STATE_CHECK
  1996. #ifdef DEBUG
  1997. static bool
  1998. HasPseudoClassSelectorArgsWithCombinators(nsCSSSelector* aSelector)
  1999. {
  2000. for (nsPseudoClassList* p = aSelector->mPseudoClassList; p; p = p->mNext) {
  2001. if (nsCSSPseudoClasses::HasSelectorListArg(p->mType)) {
  2002. for (nsCSSSelectorList* l = p->u.mSelectors; l; l = l->mNext) {
  2003. if (l->mSelectors->mNext) {
  2004. return true;
  2005. }
  2006. }
  2007. }
  2008. }
  2009. for (nsCSSSelector* n = aSelector->mNegations; n; n = n->mNegations) {
  2010. if (n->mNext) {
  2011. return true;
  2012. }
  2013. }
  2014. return false;
  2015. }
  2016. #endif
  2017. /* static */ bool
  2018. nsCSSRuleProcessor::RestrictedSelectorMatches(
  2019. Element* aElement,
  2020. nsCSSSelector* aSelector,
  2021. TreeMatchContext& aTreeMatchContext)
  2022. {
  2023. MOZ_ASSERT(aSelector->IsRestrictedSelector(),
  2024. "aSelector must not have a pseudo-element");
  2025. NS_WARNING_ASSERTION(
  2026. !HasPseudoClassSelectorArgsWithCombinators(aSelector),
  2027. "processing eRestyle_SomeDescendants can be slow if pseudo-classes with "
  2028. "selector arguments can now have combinators in them");
  2029. // We match aSelector as if :visited and :link both match visited and
  2030. // unvisited links.
  2031. NodeMatchContext nodeContext(EventStates(),
  2032. nsCSSRuleProcessor::IsLink(aElement));
  2033. if (nodeContext.mIsRelevantLink) {
  2034. aTreeMatchContext.SetHaveRelevantLink();
  2035. }
  2036. aTreeMatchContext.ResetForUnvisitedMatching();
  2037. bool matches = SelectorMatches(aElement, aSelector, nodeContext,
  2038. aTreeMatchContext, SelectorMatchesFlags::NONE);
  2039. if (nodeContext.mIsRelevantLink) {
  2040. aTreeMatchContext.ResetForVisitedMatching();
  2041. if (SelectorMatches(aElement, aSelector, nodeContext, aTreeMatchContext,
  2042. SelectorMatchesFlags::NONE)) {
  2043. matches = true;
  2044. }
  2045. }
  2046. return matches;
  2047. }
  2048. // Right now, there are four operators:
  2049. // ' ', the descendant combinator, is greedy
  2050. // '~', the indirect adjacent sibling combinator, is greedy
  2051. // '+' and '>', the direct adjacent sibling and child combinators, are not
  2052. #define NS_IS_GREEDY_OPERATOR(ch) \
  2053. ((ch) == char16_t(' ') || (ch) == char16_t('~'))
  2054. /**
  2055. * Flags for SelectorMatchesTree.
  2056. */
  2057. enum SelectorMatchesTreeFlags {
  2058. // Whether we still have not found the closest ancestor link element and
  2059. // thus have to check the current element for it.
  2060. eLookForRelevantLink = 0x1,
  2061. // Whether SelectorMatchesTree should check for, and return true upon
  2062. // finding, an ancestor element that has an eRestyle_SomeDescendants
  2063. // restyle hint pending.
  2064. eMatchOnConditionalRestyleAncestor = 0x2,
  2065. };
  2066. static bool
  2067. SelectorMatchesTree(Element* aPrevElement,
  2068. nsCSSSelector* aSelector,
  2069. TreeMatchContext& aTreeMatchContext,
  2070. SelectorMatchesTreeFlags aFlags)
  2071. {
  2072. MOZ_ASSERT(!aSelector || !aSelector->IsPseudoElement());
  2073. nsCSSSelector* selector = aSelector;
  2074. Element* prevElement = aPrevElement;
  2075. while (selector) { // check compound selectors
  2076. NS_ASSERTION(!selector->mNext ||
  2077. selector->mNext->mOperator != char16_t(0),
  2078. "compound selector without combinator");
  2079. // If after the previous selector match we are now outside the
  2080. // current style scope, we don't need to match any further.
  2081. if (aTreeMatchContext.mForScopedStyle &&
  2082. !aTreeMatchContext.IsWithinStyleScopeForSelectorMatching()) {
  2083. return false;
  2084. }
  2085. // for adjacent sibling combinators, the content to test against the
  2086. // selector is the previous sibling *element*
  2087. Element* element = nullptr;
  2088. if (char16_t('+') == selector->mOperator ||
  2089. char16_t('~') == selector->mOperator) {
  2090. // The relevant link must be an ancestor of the node being matched.
  2091. aFlags = SelectorMatchesTreeFlags(aFlags & ~eLookForRelevantLink);
  2092. nsIContent* parent = prevElement->GetParent();
  2093. if (parent) {
  2094. if (aTreeMatchContext.mForStyling)
  2095. parent->SetFlags(NODE_HAS_SLOW_SELECTOR_LATER_SIBLINGS);
  2096. element = prevElement->GetPreviousElementSibling();
  2097. }
  2098. }
  2099. // for descendant combinators and child combinators, the element
  2100. // to test against is the parent
  2101. else {
  2102. nsIContent *content = prevElement->GetParent();
  2103. // GetParent could return a document fragment; we only want
  2104. // element parents.
  2105. if (content && content->IsElement()) {
  2106. element = content->AsElement();
  2107. if (aTreeMatchContext.mForScopedStyle) {
  2108. // We are moving up to the parent element; tell the
  2109. // TreeMatchContext, so that in case this element is the
  2110. // style scope element, selector matching stops before we
  2111. // traverse further up the tree.
  2112. aTreeMatchContext.PopStyleScopeForSelectorMatching(element);
  2113. }
  2114. // Compatibility hack: First try matching this selector as though the
  2115. // <xbl:children> element wasn't in the tree to allow old selectors
  2116. // were written before <xbl:children> participated in CSS selector
  2117. // matching to work.
  2118. if (selector->mOperator == '>' && element->IsActiveChildrenElement()) {
  2119. Element* styleScope = aTreeMatchContext.mCurrentStyleScope;
  2120. if (SelectorMatchesTree(element, selector, aTreeMatchContext,
  2121. aFlags)) {
  2122. // It matched, don't try matching on the <xbl:children> element at
  2123. // all.
  2124. return true;
  2125. }
  2126. // We want to reset mCurrentStyleScope on aTreeMatchContext
  2127. // back to its state before the SelectorMatchesTree call, in
  2128. // case that call happens to traverse past the style scope element
  2129. // and sets it to null.
  2130. aTreeMatchContext.mCurrentStyleScope = styleScope;
  2131. }
  2132. }
  2133. }
  2134. if (!element) {
  2135. return false;
  2136. }
  2137. if ((aFlags & eMatchOnConditionalRestyleAncestor) &&
  2138. element->HasFlag(ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR)) {
  2139. // If we're looking at an element that we already generated an
  2140. // eRestyle_SomeDescendants restyle hint for, then we should pretend
  2141. // that we matched here, because we don't know what the values of
  2142. // attributes on |element| were at the time we generated the
  2143. // eRestyle_SomeDescendants. This causes AttributeEnumFunc and
  2144. // HasStateDependentStyle below to generate a restyle hint for the
  2145. // change we're currently looking at, as we don't know whether the LHS
  2146. // of the selector we looked up matches or not. (We only pass in aFlags
  2147. // to cause us to look for eRestyle_SomeDescendants here under
  2148. // AttributeEnumFunc and HasStateDependentStyle.)
  2149. return true;
  2150. }
  2151. const bool isRelevantLink = (aFlags & eLookForRelevantLink) &&
  2152. nsCSSRuleProcessor::IsLink(element);
  2153. NodeMatchContext nodeContext(EventStates(), isRelevantLink);
  2154. if (isRelevantLink) {
  2155. // If we find an ancestor of the matched node that is a link
  2156. // during the matching process, then it's the relevant link (see
  2157. // constructor call above).
  2158. // Since we are still matching against selectors that contain
  2159. // :visited (they'll just fail), we will always find such a node
  2160. // during the selector matching process if there is a relevant
  2161. // link that can influence selector matching.
  2162. aFlags = SelectorMatchesTreeFlags(aFlags & ~eLookForRelevantLink);
  2163. aTreeMatchContext.SetHaveRelevantLink();
  2164. }
  2165. if (SelectorMatches(element, selector, nodeContext, aTreeMatchContext,
  2166. SelectorMatchesFlags::NONE)) {
  2167. // to avoid greedy matching, we need to recur if this is a
  2168. // descendant or general sibling combinator and the next
  2169. // combinator is different, but we can make an exception for
  2170. // sibling, then parent, since a sibling's parent is always the
  2171. // same.
  2172. if (NS_IS_GREEDY_OPERATOR(selector->mOperator) &&
  2173. selector->mNext &&
  2174. selector->mNext->mOperator != selector->mOperator &&
  2175. !(selector->mOperator == '~' &&
  2176. NS_IS_ANCESTOR_OPERATOR(selector->mNext->mOperator))) {
  2177. // pretend the selector didn't match, and step through content
  2178. // while testing the same selector
  2179. // This approach is slightly strange in that when it recurs
  2180. // it tests from the top of the content tree, down. This
  2181. // doesn't matter much for performance since most selectors
  2182. // don't match. (If most did, it might be faster...)
  2183. Element* styleScope = aTreeMatchContext.mCurrentStyleScope;
  2184. if (SelectorMatchesTree(element, selector, aTreeMatchContext, aFlags)) {
  2185. return true;
  2186. }
  2187. // We want to reset mCurrentStyleScope on aTreeMatchContext
  2188. // back to its state before the SelectorMatchesTree call, in
  2189. // case that call happens to traverse past the style scope element
  2190. // and sets it to null.
  2191. aTreeMatchContext.mCurrentStyleScope = styleScope;
  2192. }
  2193. selector = selector->mNext;
  2194. }
  2195. else {
  2196. // for adjacent sibling and child combinators, if we didn't find
  2197. // a match, we're done
  2198. if (!NS_IS_GREEDY_OPERATOR(selector->mOperator)) {
  2199. return false; // parent was required to match
  2200. }
  2201. }
  2202. prevElement = element;
  2203. }
  2204. return true; // all the selectors matched.
  2205. }
  2206. static inline
  2207. void ContentEnumFunc(const RuleValue& value, nsCSSSelector* aSelector,
  2208. ElementDependentRuleProcessorData* data, NodeMatchContext& nodeContext,
  2209. AncestorFilter *ancestorFilter)
  2210. {
  2211. if (nodeContext.mIsRelevantLink) {
  2212. data->mTreeMatchContext.SetHaveRelevantLink();
  2213. }
  2214. if (ancestorFilter &&
  2215. !ancestorFilter->MightHaveMatchingAncestor<RuleValue::eMaxAncestorHashes>(
  2216. value.mAncestorSelectorHashes)) {
  2217. // We won't match; nothing else to do here
  2218. return;
  2219. }
  2220. if (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement,
  2221. data->mScope)) {
  2222. // The selector is for a rule in a scoped style sheet, and the subject
  2223. // of the selector matching is not in its scope.
  2224. return;
  2225. }
  2226. nsCSSSelector* selector = aSelector;
  2227. if (selector->IsPseudoElement()) {
  2228. PseudoElementRuleProcessorData* pdata =
  2229. static_cast<PseudoElementRuleProcessorData*>(data);
  2230. if (!pdata->mPseudoElement && selector->mPseudoClassList) {
  2231. // We can get here when calling getComputedStyle(aElt, aPseudo) if:
  2232. //
  2233. // * aPseudo is a pseudo-element that supports a user action
  2234. // pseudo-class, like "::placeholder";
  2235. // * there is a style rule that uses a pseudo-class on this
  2236. // pseudo-element in the document, like ::placeholder:hover; and
  2237. // * aElt does not have such a pseudo-element.
  2238. //
  2239. // We know that the selector can't match, since there is no element for
  2240. // the user action pseudo-class to match against.
  2241. return;
  2242. }
  2243. if (!StateSelectorMatches(pdata->mPseudoElement, aSelector, nodeContext,
  2244. data->mTreeMatchContext,
  2245. SelectorMatchesFlags::NONE)) {
  2246. return;
  2247. }
  2248. selector = selector->mNext;
  2249. }
  2250. SelectorMatchesFlags selectorFlags = SelectorMatchesFlags::NONE;
  2251. if (aSelector->IsPseudoElement()) {
  2252. selectorFlags |= SelectorMatchesFlags::HAS_PSEUDO_ELEMENT;
  2253. }
  2254. if (SelectorMatches(data->mElement, selector, nodeContext,
  2255. data->mTreeMatchContext, selectorFlags)) {
  2256. nsCSSSelector *next = selector->mNext;
  2257. if (!next ||
  2258. SelectorMatchesTree(data->mElement, next,
  2259. data->mTreeMatchContext,
  2260. nodeContext.mIsRelevantLink ?
  2261. SelectorMatchesTreeFlags(0) :
  2262. eLookForRelevantLink)) {
  2263. css::Declaration* declaration = value.mRule->GetDeclaration();
  2264. declaration->SetImmutable();
  2265. data->mRuleWalker->Forward(declaration);
  2266. // nsStyleSet will deal with the !important rule
  2267. }
  2268. }
  2269. }
  2270. /* virtual */ void
  2271. nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData)
  2272. {
  2273. RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
  2274. if (cascade) {
  2275. NodeMatchContext nodeContext(EventStates(),
  2276. nsCSSRuleProcessor::IsLink(aData->mElement));
  2277. cascade->mRuleHash.EnumerateAllRules(aData->mElement, aData, nodeContext);
  2278. }
  2279. }
  2280. /* virtual */ void
  2281. nsCSSRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData)
  2282. {
  2283. RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
  2284. if (cascade) {
  2285. RuleHash* ruleHash = cascade->mPseudoElementRuleHashes[
  2286. static_cast<CSSPseudoElementTypeBase>(aData->mPseudoType)];
  2287. if (ruleHash) {
  2288. NodeMatchContext nodeContext(EventStates(),
  2289. nsCSSRuleProcessor::IsLink(aData->mElement));
  2290. ruleHash->EnumerateAllRules(aData->mElement, aData, nodeContext);
  2291. }
  2292. }
  2293. }
  2294. /* virtual */ void
  2295. nsCSSRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData)
  2296. {
  2297. RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
  2298. if (cascade && cascade->mAnonBoxRules.EntryCount()) {
  2299. auto entry = static_cast<RuleHashTagTableEntry*>
  2300. (cascade->mAnonBoxRules.Search(aData->mPseudoTag));
  2301. if (entry) {
  2302. nsTArray<RuleValue>& rules = entry->mRules;
  2303. for (RuleValue *value = rules.Elements(), *end = value + rules.Length();
  2304. value != end; ++value) {
  2305. css::Declaration* declaration = value->mRule->GetDeclaration();
  2306. declaration->SetImmutable();
  2307. aData->mRuleWalker->Forward(declaration);
  2308. }
  2309. }
  2310. }
  2311. }
  2312. #ifdef MOZ_XUL
  2313. /* virtual */ void
  2314. nsCSSRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData)
  2315. {
  2316. RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
  2317. if (cascade && cascade->mXULTreeRules.EntryCount()) {
  2318. auto entry = static_cast<RuleHashTagTableEntry*>
  2319. (cascade->mXULTreeRules.Search(aData->mPseudoTag));
  2320. if (entry) {
  2321. NodeMatchContext nodeContext(EventStates(),
  2322. nsCSSRuleProcessor::IsLink(aData->mElement));
  2323. nsTArray<RuleValue>& rules = entry->mRules;
  2324. for (RuleValue *value = rules.Elements(), *end = value + rules.Length();
  2325. value != end; ++value) {
  2326. if (aData->mComparator->PseudoMatches(value->mSelector)) {
  2327. ContentEnumFunc(*value, value->mSelector->mNext, aData, nodeContext,
  2328. nullptr);
  2329. }
  2330. }
  2331. }
  2332. }
  2333. }
  2334. #endif
  2335. static inline nsRestyleHint RestyleHintForOp(char16_t oper)
  2336. {
  2337. if (oper == char16_t('+') || oper == char16_t('~')) {
  2338. return eRestyle_LaterSiblings;
  2339. }
  2340. if (oper != char16_t(0)) {
  2341. return eRestyle_Subtree;
  2342. }
  2343. return eRestyle_Self;
  2344. }
  2345. nsRestyleHint
  2346. nsCSSRuleProcessor::HasStateDependentStyle(ElementDependentRuleProcessorData* aData,
  2347. Element* aStatefulElement,
  2348. CSSPseudoElementType aPseudoType,
  2349. EventStates aStateMask)
  2350. {
  2351. MOZ_ASSERT(!aData->mTreeMatchContext.mForScopedStyle,
  2352. "mCurrentStyleScope will need to be saved and restored after the "
  2353. "SelectorMatchesTree call");
  2354. bool isPseudoElement =
  2355. aPseudoType != CSSPseudoElementType::NotPseudo;
  2356. RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
  2357. // Look up the content node in the state rule list, which points to
  2358. // any (CSS2 definition) simple selector (whether or not it is the
  2359. // subject) that has a state pseudo-class on it. This means that this
  2360. // code will be matching selectors that aren't real selectors in any
  2361. // stylesheet (e.g., if there is a selector "body > p:hover > a", then
  2362. // "body > p:hover" will be in |cascade->mStateSelectors|). Note that
  2363. // |ComputeSelectorStateDependence| below determines which selectors are in
  2364. // |cascade->mStateSelectors|.
  2365. nsRestyleHint hint = nsRestyleHint(0);
  2366. if (cascade) {
  2367. StateSelector *iter = cascade->mStateSelectors.Elements(),
  2368. *end = iter + cascade->mStateSelectors.Length();
  2369. NodeMatchContext nodeContext(aStateMask, false);
  2370. for(; iter != end; ++iter) {
  2371. nsCSSSelector* selector = iter->mSelector;
  2372. EventStates states = iter->mStates;
  2373. if (selector->IsPseudoElement() != isPseudoElement) {
  2374. continue;
  2375. }
  2376. nsCSSSelector* selectorForPseudo;
  2377. if (isPseudoElement) {
  2378. if (selector->PseudoType() != aPseudoType) {
  2379. continue;
  2380. }
  2381. selectorForPseudo = selector;
  2382. selector = selector->mNext;
  2383. }
  2384. nsRestyleHint possibleChange = RestyleHintForOp(selector->mOperator);
  2385. SelectorMatchesFlags selectorFlags = SelectorMatchesFlags::UNKNOWN;
  2386. // If hint already includes all the bits of possibleChange,
  2387. // don't bother calling SelectorMatches, since even if it returns false
  2388. // hint won't change.
  2389. // Also don't bother calling SelectorMatches if none of the
  2390. // states passed in are relevant here.
  2391. if ((possibleChange & ~hint) &&
  2392. states.HasAtLeastOneOfStates(aStateMask) &&
  2393. // We can optimize away testing selectors that only involve :hover, a
  2394. // namespace, and a tag name against nodes that don't have the
  2395. // NodeHasRelevantHoverRules flag: such a selector didn't match
  2396. // the tag name or namespace the first time around (since the :hover
  2397. // didn't set the NodeHasRelevantHoverRules flag), so it won't
  2398. // match it now. Check for our selector only having :hover states, or
  2399. // the element having the hover rules flag, or the selector having
  2400. // some sort of non-namespace, non-tagname data in it.
  2401. (states != NS_EVENT_STATE_HOVER ||
  2402. aStatefulElement->HasRelevantHoverRules() ||
  2403. selector->mIDList || selector->mClassList ||
  2404. // We generally expect an mPseudoClassList, since we have a :hover.
  2405. // The question is whether we have anything else in there.
  2406. (selector->mPseudoClassList &&
  2407. (selector->mPseudoClassList->mNext ||
  2408. selector->mPseudoClassList->mType !=
  2409. CSSPseudoClassType::hover)) ||
  2410. selector->mAttrList || selector->mNegations) &&
  2411. (!isPseudoElement ||
  2412. StateSelectorMatches(aStatefulElement, selectorForPseudo,
  2413. nodeContext, aData->mTreeMatchContext,
  2414. selectorFlags, nullptr, aStateMask)) &&
  2415. SelectorMatches(aData->mElement, selector, nodeContext,
  2416. aData->mTreeMatchContext, selectorFlags) &&
  2417. SelectorMatchesTree(aData->mElement, selector->mNext,
  2418. aData->mTreeMatchContext,
  2419. eMatchOnConditionalRestyleAncestor))
  2420. {
  2421. hint = nsRestyleHint(hint | possibleChange);
  2422. }
  2423. }
  2424. }
  2425. return hint;
  2426. }
  2427. nsRestyleHint
  2428. nsCSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData)
  2429. {
  2430. return HasStateDependentStyle(aData,
  2431. aData->mElement,
  2432. CSSPseudoElementType::NotPseudo,
  2433. aData->mStateMask);
  2434. }
  2435. nsRestyleHint
  2436. nsCSSRuleProcessor::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData)
  2437. {
  2438. return HasStateDependentStyle(aData,
  2439. aData->mPseudoElement,
  2440. aData->mPseudoType,
  2441. aData->mStateMask);
  2442. }
  2443. bool
  2444. nsCSSRuleProcessor::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
  2445. {
  2446. RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
  2447. return cascade && cascade->mSelectorDocumentStates.HasAtLeastOneOfStates(aData->mStateMask);
  2448. }
  2449. struct AttributeEnumData {
  2450. AttributeEnumData(AttributeRuleProcessorData *aData,
  2451. RestyleHintData& aRestyleHintData)
  2452. : data(aData), change(nsRestyleHint(0)), hintData(aRestyleHintData) {}
  2453. AttributeRuleProcessorData *data;
  2454. nsRestyleHint change;
  2455. RestyleHintData& hintData;
  2456. };
  2457. static inline nsRestyleHint
  2458. RestyleHintForSelectorWithAttributeChange(nsRestyleHint aCurrentHint,
  2459. nsCSSSelector* aSelector,
  2460. nsCSSSelector* aRightmostSelector)
  2461. {
  2462. MOZ_ASSERT(aSelector);
  2463. char16_t oper = aSelector->mOperator;
  2464. if (oper == char16_t('+') || oper == char16_t('~')) {
  2465. return eRestyle_LaterSiblings;
  2466. }
  2467. if (oper == char16_t(':')) {
  2468. return eRestyle_Subtree;
  2469. }
  2470. if (oper != char16_t(0)) {
  2471. // Check whether the selector is in a form that supports
  2472. // eRestyle_SomeDescendants. If it isn't, return eRestyle_Subtree.
  2473. if (aCurrentHint & eRestyle_Subtree) {
  2474. // No point checking, since we'll end up restyling the whole
  2475. // subtree anyway.
  2476. return eRestyle_Subtree;
  2477. }
  2478. if (!aRightmostSelector) {
  2479. // aSelector wasn't a top-level selector, which means we were inside
  2480. // a :not() or :-moz-any(). We don't support that.
  2481. return eRestyle_Subtree;
  2482. }
  2483. MOZ_ASSERT(aSelector != aRightmostSelector,
  2484. "if aSelector == aRightmostSelector then we should have "
  2485. "no operator");
  2486. // Check that aRightmostSelector can be passed to RestrictedSelectorMatches.
  2487. if (!aRightmostSelector->IsRestrictedSelector()) {
  2488. return eRestyle_Subtree;
  2489. }
  2490. // We also don't support pseudo-elements on any of the selectors
  2491. // between aRightmostSelector and aSelector.
  2492. // XXX Can we lift this restriction, so that we don't have to loop
  2493. // over all the selectors?
  2494. for (nsCSSSelector* sel = aRightmostSelector->mNext;
  2495. sel != aSelector;
  2496. sel = sel->mNext) {
  2497. MOZ_ASSERT(sel, "aSelector must be reachable from aRightmostSelector");
  2498. if (sel->PseudoType() != CSSPseudoElementType::NotPseudo) {
  2499. return eRestyle_Subtree;
  2500. }
  2501. }
  2502. return eRestyle_SomeDescendants;
  2503. }
  2504. return eRestyle_Self;
  2505. }
  2506. static void
  2507. AttributeEnumFunc(nsCSSSelector* aSelector,
  2508. nsCSSSelector* aRightmostSelector,
  2509. AttributeEnumData* aData)
  2510. {
  2511. AttributeRuleProcessorData *data = aData->data;
  2512. if (!data->mTreeMatchContext.SetStyleScopeForSelectorMatching(data->mElement,
  2513. data->mScope)) {
  2514. // The selector is for a rule in a scoped style sheet, and the subject
  2515. // of the selector matching is not in its scope.
  2516. return;
  2517. }
  2518. nsRestyleHint possibleChange =
  2519. RestyleHintForSelectorWithAttributeChange(aData->change,
  2520. aSelector, aRightmostSelector);
  2521. // If, ignoring eRestyle_SomeDescendants, enumData->change already includes
  2522. // all the bits of possibleChange, don't bother calling SelectorMatches, since
  2523. // even if it returns false enumData->change won't change. If possibleChange
  2524. // has eRestyle_SomeDescendants, we need to call SelectorMatches(Tree)
  2525. // regardless as it might give us new selectors to append to
  2526. // mSelectorsForDescendants.
  2527. NodeMatchContext nodeContext(EventStates(), false);
  2528. if (((possibleChange & (~(aData->change) | eRestyle_SomeDescendants))) &&
  2529. SelectorMatches(data->mElement, aSelector, nodeContext,
  2530. data->mTreeMatchContext, SelectorMatchesFlags::UNKNOWN) &&
  2531. SelectorMatchesTree(data->mElement, aSelector->mNext,
  2532. data->mTreeMatchContext,
  2533. eMatchOnConditionalRestyleAncestor)) {
  2534. aData->change = nsRestyleHint(aData->change | possibleChange);
  2535. if (possibleChange & eRestyle_SomeDescendants) {
  2536. aData->hintData.mSelectorsForDescendants.AppendElement(aRightmostSelector);
  2537. }
  2538. }
  2539. }
  2540. static MOZ_ALWAYS_INLINE void
  2541. EnumerateSelectors(nsTArray<SelectorPair>& aSelectors, AttributeEnumData* aData)
  2542. {
  2543. SelectorPair *iter = aSelectors.Elements(),
  2544. *end = iter + aSelectors.Length();
  2545. for (; iter != end; ++iter) {
  2546. AttributeEnumFunc(iter->mSelector, iter->mRightmostSelector, aData);
  2547. }
  2548. }
  2549. static MOZ_ALWAYS_INLINE void
  2550. EnumerateSelectors(nsTArray<nsCSSSelector*>& aSelectors, AttributeEnumData* aData)
  2551. {
  2552. nsCSSSelector **iter = aSelectors.Elements(),
  2553. **end = iter + aSelectors.Length();
  2554. for (; iter != end; ++iter) {
  2555. AttributeEnumFunc(*iter, nullptr, aData);
  2556. }
  2557. }
  2558. nsRestyleHint
  2559. nsCSSRuleProcessor::HasAttributeDependentStyle(
  2560. AttributeRuleProcessorData* aData,
  2561. RestyleHintData& aRestyleHintDataResult)
  2562. {
  2563. // We could try making use of aData->mModType, but :not rules make it a bit
  2564. // of a pain to do so... So just ignore it for now.
  2565. AttributeEnumData data(aData, aRestyleHintDataResult);
  2566. // Don't do our special handling of certain attributes if the attr
  2567. // hasn't changed yet.
  2568. if (aData->mAttrHasChanged) {
  2569. // check for the lwtheme and lwthemetextcolor attribute on root XUL elements
  2570. if ((aData->mAttribute == nsGkAtoms::lwtheme ||
  2571. aData->mAttribute == nsGkAtoms::lwthemetextcolor) &&
  2572. aData->mElement->GetNameSpaceID() == kNameSpaceID_XUL &&
  2573. aData->mElement == aData->mElement->OwnerDoc()->GetRootElement())
  2574. {
  2575. data.change = nsRestyleHint(data.change | eRestyle_Subtree);
  2576. }
  2577. // We don't know the namespace of the attribute, and xml:lang applies to
  2578. // all elements. If the lang attribute changes, we need to restyle our
  2579. // whole subtree, since the :lang selector on our descendants can examine
  2580. // our lang attribute.
  2581. if (aData->mAttribute == nsGkAtoms::lang) {
  2582. data.change = nsRestyleHint(data.change | eRestyle_Subtree);
  2583. }
  2584. }
  2585. RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
  2586. // Since we get both before and after notifications for attributes, we
  2587. // don't have to ignore aData->mAttribute while matching. Just check
  2588. // whether we have selectors relevant to aData->mAttribute that we
  2589. // match. If this is the before change notification, that will catch
  2590. // rules we might stop matching; if the after change notification, the
  2591. // ones we might have started matching.
  2592. if (cascade) {
  2593. if (aData->mAttribute == nsGkAtoms::id) {
  2594. nsIAtom* id = aData->mElement->GetID();
  2595. if (id) {
  2596. auto entry =
  2597. static_cast<AtomSelectorEntry*>(cascade->mIdSelectors.Search(id));
  2598. if (entry) {
  2599. EnumerateSelectors(entry->mSelectors, &data);
  2600. }
  2601. }
  2602. EnumerateSelectors(cascade->mPossiblyNegatedIDSelectors, &data);
  2603. }
  2604. if (aData->mAttribute == nsGkAtoms::_class &&
  2605. aData->mNameSpaceID == kNameSpaceID_None) {
  2606. const nsAttrValue* otherClasses = aData->mOtherValue;
  2607. NS_ASSERTION(otherClasses ||
  2608. aData->mModType == nsIDOMMutationEvent::REMOVAL,
  2609. "All class values should be StoresOwnData and parsed"
  2610. "via Element::BeforeSetAttr, so available here");
  2611. // For WillChange, enumerate classes that will be removed to see which
  2612. // rules apply before the change.
  2613. // For Changed, enumerate classes that have been added to see which rules
  2614. // apply after the change.
  2615. // In both cases we're interested in the classes that are currently on
  2616. // the element but not in mOtherValue.
  2617. const nsAttrValue* elementClasses = aData->mElement->GetClasses();
  2618. if (elementClasses) {
  2619. int32_t atomCount = elementClasses->GetAtomCount();
  2620. if (atomCount > 0) {
  2621. nsTHashtable<nsPtrHashKey<nsIAtom>> otherClassesTable;
  2622. if (otherClasses) {
  2623. int32_t otherClassesCount = otherClasses->GetAtomCount();
  2624. for (int32_t i = 0; i < otherClassesCount; ++i) {
  2625. otherClassesTable.PutEntry(otherClasses->AtomAt(i));
  2626. }
  2627. }
  2628. for (int32_t i = 0; i < atomCount; ++i) {
  2629. nsIAtom* curClass = elementClasses->AtomAt(i);
  2630. if (!otherClassesTable.Contains(curClass)) {
  2631. auto entry =
  2632. static_cast<AtomSelectorEntry*>
  2633. (cascade->mClassSelectors.Search(curClass));
  2634. if (entry) {
  2635. EnumerateSelectors(entry->mSelectors, &data);
  2636. }
  2637. }
  2638. }
  2639. }
  2640. }
  2641. EnumerateSelectors(cascade->mPossiblyNegatedClassSelectors, &data);
  2642. }
  2643. auto entry =
  2644. static_cast<AtomSelectorEntry*>
  2645. (cascade->mAttributeSelectors.Search(aData->mAttribute));
  2646. if (entry) {
  2647. EnumerateSelectors(entry->mSelectors, &data);
  2648. }
  2649. }
  2650. return data.change;
  2651. }
  2652. /* virtual */ bool
  2653. nsCSSRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext)
  2654. {
  2655. // We don't want to do anything if there aren't any sets of rules
  2656. // cached yet, since we should not build the rule cascade too early
  2657. // (e.g., before we know whether the quirk style sheet should be
  2658. // enabled). And if there's nothing cached, it doesn't matter if
  2659. // anything changed. But in the cases where it does matter, we've
  2660. // cached a previous cache key to test against, instead of our current
  2661. // rule cascades. See bug 448281 and bug 1089417.
  2662. MOZ_ASSERT(!(mRuleCascades && mPreviousCacheKey));
  2663. RuleCascadeData *old = mRuleCascades;
  2664. if (old) {
  2665. RefreshRuleCascade(aPresContext);
  2666. return (old != mRuleCascades);
  2667. }
  2668. if (mPreviousCacheKey) {
  2669. // RefreshRuleCascade will get rid of mPreviousCacheKey anyway to
  2670. // maintain the invariant that we can't have both an mRuleCascades
  2671. // and an mPreviousCacheKey. But we need to hold it a little
  2672. // longer.
  2673. UniquePtr<nsMediaQueryResultCacheKey> previousCacheKey(
  2674. Move(mPreviousCacheKey));
  2675. RefreshRuleCascade(aPresContext);
  2676. // This test is a bit pessimistic since the cache key's operator==
  2677. // just does list comparison rather than set comparison, but it
  2678. // should catch all the cases we care about (i.e., where the cascade
  2679. // order hasn't changed). Other cases will do a restyle anyway, so
  2680. // we shouldn't need to worry about posting a second.
  2681. return !mRuleCascades || // all sheets gone, but we had sheets before
  2682. mRuleCascades->mCacheKey != *previousCacheKey;
  2683. }
  2684. return false;
  2685. }
  2686. UniquePtr<nsMediaQueryResultCacheKey>
  2687. nsCSSRuleProcessor::CloneMQCacheKey()
  2688. {
  2689. MOZ_ASSERT(!(mRuleCascades && mPreviousCacheKey));
  2690. RuleCascadeData* c = mRuleCascades;
  2691. if (!c) {
  2692. // We might have an mPreviousCacheKey. It already comes from a call
  2693. // to CloneMQCacheKey, so don't bother checking
  2694. // HasFeatureConditions().
  2695. if (mPreviousCacheKey) {
  2696. NS_ASSERTION(mPreviousCacheKey->HasFeatureConditions(),
  2697. "we shouldn't have a previous cache key unless it has "
  2698. "feature conditions");
  2699. return MakeUnique<nsMediaQueryResultCacheKey>(*mPreviousCacheKey);
  2700. }
  2701. return UniquePtr<nsMediaQueryResultCacheKey>();
  2702. }
  2703. if (!c->mCacheKey.HasFeatureConditions()) {
  2704. return UniquePtr<nsMediaQueryResultCacheKey>();
  2705. }
  2706. return MakeUnique<nsMediaQueryResultCacheKey>(c->mCacheKey);
  2707. }
  2708. /* virtual */ size_t
  2709. nsCSSRuleProcessor::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
  2710. {
  2711. size_t n = 0;
  2712. n += mSheets.ShallowSizeOfExcludingThis(aMallocSizeOf);
  2713. for (RuleCascadeData* cascade = mRuleCascades; cascade;
  2714. cascade = cascade->mNext) {
  2715. n += cascade->SizeOfIncludingThis(aMallocSizeOf);
  2716. }
  2717. return n;
  2718. }
  2719. /* virtual */ size_t
  2720. nsCSSRuleProcessor::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
  2721. {
  2722. return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
  2723. }
  2724. // Append all the currently-active font face rules to aArray. Return
  2725. // true for success and false for failure.
  2726. bool
  2727. nsCSSRuleProcessor::AppendFontFaceRules(
  2728. nsPresContext *aPresContext,
  2729. nsTArray<nsFontFaceRuleContainer>& aArray)
  2730. {
  2731. RuleCascadeData* cascade = GetRuleCascade(aPresContext);
  2732. if (cascade) {
  2733. if (!aArray.AppendElements(cascade->mFontFaceRules))
  2734. return false;
  2735. }
  2736. return true;
  2737. }
  2738. nsCSSKeyframesRule*
  2739. nsCSSRuleProcessor::KeyframesRuleForName(nsPresContext* aPresContext,
  2740. const nsString& aName)
  2741. {
  2742. RuleCascadeData* cascade = GetRuleCascade(aPresContext);
  2743. if (cascade) {
  2744. return cascade->mKeyframesRuleTable.Get(aName);
  2745. }
  2746. return nullptr;
  2747. }
  2748. nsCSSCounterStyleRule*
  2749. nsCSSRuleProcessor::CounterStyleRuleForName(nsPresContext* aPresContext,
  2750. const nsAString& aName)
  2751. {
  2752. RuleCascadeData* cascade = GetRuleCascade(aPresContext);
  2753. if (cascade) {
  2754. return cascade->mCounterStyleRuleTable.Get(aName);
  2755. }
  2756. return nullptr;
  2757. }
  2758. // Append all the currently-active page rules to aArray. Return
  2759. // true for success and false for failure.
  2760. bool
  2761. nsCSSRuleProcessor::AppendPageRules(
  2762. nsPresContext* aPresContext,
  2763. nsTArray<nsCSSPageRule*>& aArray)
  2764. {
  2765. RuleCascadeData* cascade = GetRuleCascade(aPresContext);
  2766. if (cascade) {
  2767. if (!aArray.AppendElements(cascade->mPageRules)) {
  2768. return false;
  2769. }
  2770. }
  2771. return true;
  2772. }
  2773. bool
  2774. nsCSSRuleProcessor::AppendFontFeatureValuesRules(
  2775. nsPresContext *aPresContext,
  2776. nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
  2777. {
  2778. RuleCascadeData* cascade = GetRuleCascade(aPresContext);
  2779. if (cascade) {
  2780. if (!aArray.AppendElements(cascade->mFontFeatureValuesRules))
  2781. return false;
  2782. }
  2783. return true;
  2784. }
  2785. nsresult
  2786. nsCSSRuleProcessor::ClearRuleCascades()
  2787. {
  2788. if (!mPreviousCacheKey) {
  2789. mPreviousCacheKey = CloneMQCacheKey();
  2790. }
  2791. // No need to remove the rule processor from the RuleProcessorCache here,
  2792. // since CSSStyleSheet::ClearRuleCascades will have called
  2793. // RuleProcessorCache::RemoveSheet() passing itself, which will catch
  2794. // this rule processor (and any others for different @-moz-document
  2795. // cache key results).
  2796. MOZ_ASSERT(!RuleProcessorCache::HasRuleProcessor(this));
  2797. #ifdef DEBUG
  2798. // For shared rule processors, if we've already gathered document
  2799. // rules, then they will now be out of date. We don't actually need
  2800. // them to be up-to-date (see the comment in RefreshRuleCascade), so
  2801. // record their invalidity so we can assert if we try to use them.
  2802. if (!mMustGatherDocumentRules) {
  2803. mDocumentRulesAndCacheKeyValid = false;
  2804. }
  2805. #endif
  2806. // We rely on our caller (perhaps indirectly) to do something that
  2807. // will rebuild style data and the user font set (either
  2808. // nsIPresShell::RestyleForCSSRuleChanges or
  2809. // nsPresContext::RebuildAllStyleData).
  2810. RuleCascadeData *data = mRuleCascades;
  2811. mRuleCascades = nullptr;
  2812. while (data) {
  2813. RuleCascadeData *next = data->mNext;
  2814. delete data;
  2815. data = next;
  2816. }
  2817. return NS_OK;
  2818. }
  2819. // This function should return the set of states that this selector
  2820. // depends on; this is used to implement HasStateDependentStyle. It
  2821. // does NOT recur down into things like :not and :-moz-any.
  2822. inline
  2823. EventStates ComputeSelectorStateDependence(nsCSSSelector& aSelector)
  2824. {
  2825. EventStates states;
  2826. for (nsPseudoClassList* pseudoClass = aSelector.mPseudoClassList;
  2827. pseudoClass; pseudoClass = pseudoClass->mNext) {
  2828. // Tree pseudo-elements overload mPseudoClassList for things that
  2829. // aren't pseudo-classes.
  2830. if (pseudoClass->mType >= CSSPseudoClassType::Count) {
  2831. continue;
  2832. }
  2833. auto idx = static_cast<CSSPseudoClassTypeBase>(pseudoClass->mType);
  2834. states |= sPseudoClassStateDependences[idx];
  2835. }
  2836. return states;
  2837. }
  2838. static bool
  2839. AddSelector(RuleCascadeData* aCascade,
  2840. // The part between combinators at the top level of the selector
  2841. nsCSSSelector* aSelectorInTopLevel,
  2842. // The part we should look through (might be in :not or :-moz-any())
  2843. nsCSSSelector* aSelectorPart,
  2844. // The right-most selector at the top level
  2845. nsCSSSelector* aRightmostSelector)
  2846. {
  2847. // It's worth noting that this loop over negations isn't quite
  2848. // optimal for two reasons. One, we could add something to one of
  2849. // these lists twice, which means we'll check it twice, but I don't
  2850. // think that's worth worrying about. (We do the same for multiple
  2851. // attribute selectors on the same attribute.) Two, we don't really
  2852. // need to check negations past the first in the current
  2853. // implementation (and they're rare as well), but that might change
  2854. // in the future if :not() is extended.
  2855. for (nsCSSSelector* negation = aSelectorPart; negation;
  2856. negation = negation->mNegations) {
  2857. // Track both document states and attribute dependence in pseudo-classes.
  2858. for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList;
  2859. pseudoClass; pseudoClass = pseudoClass->mNext) {
  2860. switch (pseudoClass->mType) {
  2861. case CSSPseudoClassType::mozLocaleDir: {
  2862. aCascade->mSelectorDocumentStates |= NS_DOCUMENT_STATE_RTL_LOCALE;
  2863. break;
  2864. }
  2865. case CSSPseudoClassType::mozWindowInactive: {
  2866. aCascade->mSelectorDocumentStates |= NS_DOCUMENT_STATE_WINDOW_INACTIVE;
  2867. break;
  2868. }
  2869. case CSSPseudoClassType::mozTableBorderNonzero: {
  2870. nsTArray<SelectorPair> *array =
  2871. aCascade->AttributeListFor(nsGkAtoms::border);
  2872. if (!array) {
  2873. return false;
  2874. }
  2875. array->AppendElement(SelectorPair(aSelectorInTopLevel,
  2876. aRightmostSelector));
  2877. break;
  2878. }
  2879. default: {
  2880. break;
  2881. }
  2882. }
  2883. }
  2884. // Build mStateSelectors.
  2885. EventStates dependentStates = ComputeSelectorStateDependence(*negation);
  2886. if (!dependentStates.IsEmpty()) {
  2887. aCascade->mStateSelectors.AppendElement(
  2888. nsCSSRuleProcessor::StateSelector(dependentStates,
  2889. aSelectorInTopLevel));
  2890. }
  2891. // Build mIDSelectors
  2892. if (negation == aSelectorInTopLevel) {
  2893. for (nsAtomList* curID = negation->mIDList; curID;
  2894. curID = curID->mNext) {
  2895. auto entry = static_cast<AtomSelectorEntry*>
  2896. (aCascade->mIdSelectors.Add(curID->mAtom, fallible));
  2897. if (entry) {
  2898. entry->mSelectors.AppendElement(SelectorPair(aSelectorInTopLevel,
  2899. aRightmostSelector));
  2900. }
  2901. }
  2902. } else if (negation->mIDList) {
  2903. aCascade->mPossiblyNegatedIDSelectors.AppendElement(aSelectorInTopLevel);
  2904. }
  2905. // Build mClassSelectors
  2906. if (negation == aSelectorInTopLevel) {
  2907. for (nsAtomList* curClass = negation->mClassList; curClass;
  2908. curClass = curClass->mNext) {
  2909. auto entry = static_cast<AtomSelectorEntry*>
  2910. (aCascade->mClassSelectors.Add(curClass->mAtom, fallible));
  2911. if (entry) {
  2912. entry->mSelectors.AppendElement(SelectorPair(aSelectorInTopLevel,
  2913. aRightmostSelector));
  2914. }
  2915. }
  2916. } else if (negation->mClassList) {
  2917. aCascade->mPossiblyNegatedClassSelectors.AppendElement(aSelectorInTopLevel);
  2918. }
  2919. // Build mAttributeSelectors.
  2920. for (nsAttrSelector *attr = negation->mAttrList; attr;
  2921. attr = attr->mNext) {
  2922. nsTArray<SelectorPair> *array =
  2923. aCascade->AttributeListFor(attr->mCasedAttr);
  2924. if (!array) {
  2925. return false;
  2926. }
  2927. array->AppendElement(SelectorPair(aSelectorInTopLevel,
  2928. aRightmostSelector));
  2929. if (attr->mLowercaseAttr != attr->mCasedAttr) {
  2930. array = aCascade->AttributeListFor(attr->mLowercaseAttr);
  2931. if (!array) {
  2932. return false;
  2933. }
  2934. array->AppendElement(SelectorPair(aSelectorInTopLevel,
  2935. aRightmostSelector));
  2936. }
  2937. }
  2938. // Recur through any :-moz-any selectors
  2939. for (nsPseudoClassList* pseudoClass = negation->mPseudoClassList;
  2940. pseudoClass; pseudoClass = pseudoClass->mNext) {
  2941. if (pseudoClass->mType == CSSPseudoClassType::any) {
  2942. for (nsCSSSelectorList *l = pseudoClass->u.mSelectors; l; l = l->mNext) {
  2943. nsCSSSelector *s = l->mSelectors;
  2944. if (!AddSelector(aCascade, aSelectorInTopLevel, s,
  2945. aRightmostSelector)) {
  2946. return false;
  2947. }
  2948. }
  2949. }
  2950. }
  2951. }
  2952. return true;
  2953. }
  2954. static bool
  2955. AddRule(RuleSelectorPair* aRuleInfo, RuleCascadeData* aCascade)
  2956. {
  2957. RuleCascadeData * const cascade = aCascade;
  2958. // Build the rule hash.
  2959. CSSPseudoElementType pseudoType = aRuleInfo->mSelector->PseudoType();
  2960. if (MOZ_LIKELY(pseudoType == CSSPseudoElementType::NotPseudo)) {
  2961. cascade->mRuleHash.AppendRule(*aRuleInfo);
  2962. } else if (pseudoType < CSSPseudoElementType::Count) {
  2963. RuleHash*& ruleHash = cascade->mPseudoElementRuleHashes[
  2964. static_cast<CSSPseudoElementTypeBase>(pseudoType)];
  2965. if (!ruleHash) {
  2966. ruleHash = new RuleHash(cascade->mQuirksMode);
  2967. if (!ruleHash) {
  2968. // Out of memory; give up
  2969. return false;
  2970. }
  2971. }
  2972. NS_ASSERTION(aRuleInfo->mSelector->mNext,
  2973. "Must have mNext; parser screwed up");
  2974. NS_ASSERTION(aRuleInfo->mSelector->mNext->mOperator == ':',
  2975. "Unexpected mNext combinator");
  2976. ruleHash->AppendRule(*aRuleInfo);
  2977. } else if (pseudoType == CSSPseudoElementType::AnonBox) {
  2978. NS_ASSERTION(!aRuleInfo->mSelector->mCasedTag &&
  2979. !aRuleInfo->mSelector->mIDList &&
  2980. !aRuleInfo->mSelector->mClassList &&
  2981. !aRuleInfo->mSelector->mPseudoClassList &&
  2982. !aRuleInfo->mSelector->mAttrList &&
  2983. !aRuleInfo->mSelector->mNegations &&
  2984. !aRuleInfo->mSelector->mNext &&
  2985. aRuleInfo->mSelector->mNameSpace == kNameSpaceID_Unknown,
  2986. "Parser messed up with anon box selector");
  2987. // Index doesn't matter here, since we'll just be walking these
  2988. // rules in order; just pass 0.
  2989. AppendRuleToTagTable(&cascade->mAnonBoxRules,
  2990. aRuleInfo->mSelector->mLowercaseTag,
  2991. RuleValue(*aRuleInfo, 0, aCascade->mQuirksMode));
  2992. } else {
  2993. #ifdef MOZ_XUL
  2994. NS_ASSERTION(pseudoType == CSSPseudoElementType::XULTree,
  2995. "Unexpected pseudo type");
  2996. // Index doesn't matter here, since we'll just be walking these
  2997. // rules in order; just pass 0.
  2998. AppendRuleToTagTable(&cascade->mXULTreeRules,
  2999. aRuleInfo->mSelector->mLowercaseTag,
  3000. RuleValue(*aRuleInfo, 0, aCascade->mQuirksMode));
  3001. #else
  3002. NS_NOTREACHED("Unexpected pseudo type");
  3003. #endif
  3004. }
  3005. for (nsCSSSelector* selector = aRuleInfo->mSelector;
  3006. selector; selector = selector->mNext) {
  3007. if (selector->IsPseudoElement()) {
  3008. CSSPseudoElementType pseudo = selector->PseudoType();
  3009. if (pseudo >= CSSPseudoElementType::Count ||
  3010. !nsCSSPseudoElements::PseudoElementSupportsUserActionState(pseudo)) {
  3011. NS_ASSERTION(!selector->mNegations, "Shouldn't have negations");
  3012. // We do store selectors ending with pseudo-elements that allow :hover
  3013. // and :active after them in the hashtables corresponding to that
  3014. // selector's mNext (i.e. the thing that matches against the element),
  3015. // but we want to make sure that selectors for any other kinds of
  3016. // pseudo-elements don't end up in the hashtables. In particular, tree
  3017. // pseudos store strange things in mPseudoClassList that we don't want
  3018. // to try to match elements against.
  3019. continue;
  3020. }
  3021. }
  3022. if (!AddSelector(cascade, selector, selector, aRuleInfo->mSelector)) {
  3023. return false;
  3024. }
  3025. }
  3026. return true;
  3027. }
  3028. struct PerWeightDataListItem : public RuleSelectorPair {
  3029. PerWeightDataListItem(css::StyleRule* aRule, nsCSSSelector* aSelector)
  3030. : RuleSelectorPair(aRule, aSelector)
  3031. , mNext(nullptr)
  3032. {}
  3033. // No destructor; these are arena-allocated
  3034. // Placement new to arena allocate the PerWeightDataListItem
  3035. void *operator new(size_t aSize, PLArenaPool &aArena) CPP_THROW_NEW {
  3036. void *mem;
  3037. PL_ARENA_ALLOCATE(mem, &aArena, aSize);
  3038. return mem;
  3039. }
  3040. PerWeightDataListItem *mNext;
  3041. };
  3042. struct PerWeightData {
  3043. PerWeightData()
  3044. : mRuleSelectorPairs(nullptr)
  3045. , mTail(&mRuleSelectorPairs)
  3046. {}
  3047. int32_t mWeight;
  3048. PerWeightDataListItem *mRuleSelectorPairs;
  3049. PerWeightDataListItem **mTail;
  3050. };
  3051. struct RuleByWeightEntry : public PLDHashEntryHdr {
  3052. PerWeightData data; // mWeight is key, mRuleSelectorPairs are value
  3053. };
  3054. static PLDHashNumber
  3055. HashIntKey(const void *key)
  3056. {
  3057. return PLDHashNumber(NS_PTR_TO_INT32(key));
  3058. }
  3059. static bool
  3060. MatchWeightEntry(const PLDHashEntryHdr *hdr, const void *key)
  3061. {
  3062. const RuleByWeightEntry *entry = (const RuleByWeightEntry *)hdr;
  3063. return entry->data.mWeight == NS_PTR_TO_INT32(key);
  3064. }
  3065. static void
  3066. InitWeightEntry(PLDHashEntryHdr *hdr, const void *key)
  3067. {
  3068. RuleByWeightEntry* entry = static_cast<RuleByWeightEntry*>(hdr);
  3069. new (KnownNotNull, entry) RuleByWeightEntry();
  3070. }
  3071. static const PLDHashTableOps gRulesByWeightOps = {
  3072. HashIntKey,
  3073. MatchWeightEntry,
  3074. PLDHashTable::MoveEntryStub,
  3075. PLDHashTable::ClearEntryStub,
  3076. InitWeightEntry
  3077. };
  3078. struct CascadeEnumData {
  3079. CascadeEnumData(nsPresContext* aPresContext,
  3080. nsTArray<nsFontFaceRuleContainer>& aFontFaceRules,
  3081. nsTArray<nsCSSKeyframesRule*>& aKeyframesRules,
  3082. nsTArray<nsCSSFontFeatureValuesRule*>& aFontFeatureValuesRules,
  3083. nsTArray<nsCSSPageRule*>& aPageRules,
  3084. nsTArray<nsCSSCounterStyleRule*>& aCounterStyleRules,
  3085. nsTArray<css::DocumentRule*>& aDocumentRules,
  3086. nsMediaQueryResultCacheKey& aKey,
  3087. nsDocumentRuleResultCacheKey& aDocumentKey,
  3088. SheetType aSheetType,
  3089. bool aMustGatherDocumentRules)
  3090. : mPresContext(aPresContext),
  3091. mFontFaceRules(aFontFaceRules),
  3092. mKeyframesRules(aKeyframesRules),
  3093. mFontFeatureValuesRules(aFontFeatureValuesRules),
  3094. mPageRules(aPageRules),
  3095. mCounterStyleRules(aCounterStyleRules),
  3096. mDocumentRules(aDocumentRules),
  3097. mCacheKey(aKey),
  3098. mDocumentCacheKey(aDocumentKey),
  3099. mRulesByWeight(&gRulesByWeightOps, sizeof(RuleByWeightEntry), 32),
  3100. mSheetType(aSheetType),
  3101. mMustGatherDocumentRules(aMustGatherDocumentRules)
  3102. {
  3103. // Initialize our arena
  3104. PL_INIT_ARENA_POOL(&mArena, "CascadeEnumDataArena",
  3105. NS_CASCADEENUMDATA_ARENA_BLOCK_SIZE);
  3106. }
  3107. ~CascadeEnumData()
  3108. {
  3109. PL_FinishArenaPool(&mArena);
  3110. }
  3111. nsPresContext* mPresContext;
  3112. nsTArray<nsFontFaceRuleContainer>& mFontFaceRules;
  3113. nsTArray<nsCSSKeyframesRule*>& mKeyframesRules;
  3114. nsTArray<nsCSSFontFeatureValuesRule*>& mFontFeatureValuesRules;
  3115. nsTArray<nsCSSPageRule*>& mPageRules;
  3116. nsTArray<nsCSSCounterStyleRule*>& mCounterStyleRules;
  3117. nsTArray<css::DocumentRule*>& mDocumentRules;
  3118. nsMediaQueryResultCacheKey& mCacheKey;
  3119. nsDocumentRuleResultCacheKey& mDocumentCacheKey;
  3120. PLArenaPool mArena;
  3121. // Hooray, a manual PLDHashTable since nsClassHashtable doesn't
  3122. // provide a getter that gives me a *reference* to the value.
  3123. PLDHashTable mRulesByWeight; // of PerWeightDataListItem linked lists
  3124. SheetType mSheetType;
  3125. bool mMustGatherDocumentRules;
  3126. };
  3127. /**
  3128. * Recursively traverses rules in order to:
  3129. * (1) add any @-moz-document rules into data->mDocumentRules.
  3130. * (2) record any @-moz-document rules whose conditions evaluate to true
  3131. * on data->mDocumentCacheKey.
  3132. *
  3133. * See also CascadeRuleEnumFunc below, which calls us via
  3134. * EnumerateRulesForwards. If modifying this function you may need to
  3135. * update CascadeRuleEnumFunc too.
  3136. */
  3137. static bool
  3138. GatherDocRuleEnumFunc(css::Rule* aRule, void* aData)
  3139. {
  3140. CascadeEnumData* data = (CascadeEnumData*)aData;
  3141. int32_t type = aRule->GetType();
  3142. MOZ_ASSERT(data->mMustGatherDocumentRules,
  3143. "should only call GatherDocRuleEnumFunc if "
  3144. "mMustGatherDocumentRules is true");
  3145. if (css::Rule::MEDIA_RULE == type ||
  3146. css::Rule::SUPPORTS_RULE == type) {
  3147. css::GroupRule* groupRule = static_cast<css::GroupRule*>(aRule);
  3148. if (!groupRule->EnumerateRulesForwards(GatherDocRuleEnumFunc, aData)) {
  3149. return false;
  3150. }
  3151. }
  3152. else if (css::Rule::DOCUMENT_RULE == type) {
  3153. css::DocumentRule* docRule = static_cast<css::DocumentRule*>(aRule);
  3154. if (!data->mDocumentRules.AppendElement(docRule)) {
  3155. return false;
  3156. }
  3157. if (docRule->UseForPresentation(data->mPresContext)) {
  3158. if (!data->mDocumentCacheKey.AddMatchingRule(docRule)) {
  3159. return false;
  3160. }
  3161. }
  3162. if (!docRule->EnumerateRulesForwards(GatherDocRuleEnumFunc, aData)) {
  3163. return false;
  3164. }
  3165. }
  3166. return true;
  3167. }
  3168. /*
  3169. * This enumerates style rules in a sheet (and recursively into any
  3170. * grouping rules) in order to:
  3171. * (1) add any style rules, in order, into data->mRulesByWeight (for
  3172. * the primary CSS cascade), where they are separated by weight
  3173. * but kept in order per-weight, and
  3174. * (2) add any @font-face rules, in order, into data->mFontFaceRules.
  3175. * (3) add any @keyframes rules, in order, into data->mKeyframesRules.
  3176. * (4) add any @font-feature-value rules, in order,
  3177. * into data->mFontFeatureValuesRules.
  3178. * (5) add any @page rules, in order, into data->mPageRules.
  3179. * (6) add any @counter-style rules, in order, into data->mCounterStyleRules.
  3180. * (7) add any @-moz-document rules into data->mDocumentRules.
  3181. * (8) record any @-moz-document rules whose conditions evaluate to true
  3182. * on data->mDocumentCacheKey.
  3183. *
  3184. * See also GatherDocRuleEnumFunc above, which we call to traverse into
  3185. * @-moz-document rules even if their (or an ancestor's) condition
  3186. * fails. This means we might look at the result of some @-moz-document
  3187. * rules that don't actually affect whether a RuleProcessorCache lookup
  3188. * is a hit or a miss. The presence of @-moz-document rules inside
  3189. * @media etc. rules should be rare, and looking at all of them in the
  3190. * sheets lets us avoid the complication of having different document
  3191. * cache key results for different media.
  3192. *
  3193. * If modifying this function you may need to update
  3194. * GatherDocRuleEnumFunc too.
  3195. */
  3196. static bool
  3197. CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
  3198. {
  3199. CascadeEnumData* data = (CascadeEnumData*)aData;
  3200. int32_t type = aRule->GetType();
  3201. if (css::Rule::STYLE_RULE == type) {
  3202. css::StyleRule* styleRule = static_cast<css::StyleRule*>(aRule);
  3203. for (nsCSSSelectorList *sel = styleRule->Selector();
  3204. sel; sel = sel->mNext) {
  3205. int32_t weight = sel->mWeight;
  3206. auto entry = static_cast<RuleByWeightEntry*>
  3207. (data->mRulesByWeight.Add(NS_INT32_TO_PTR(weight), fallible));
  3208. if (!entry)
  3209. return false;
  3210. entry->data.mWeight = weight;
  3211. // entry->data.mRuleSelectorPairs should be linked in forward order;
  3212. // entry->data.mTail is the slot to write to.
  3213. auto* newItem =
  3214. new (data->mArena) PerWeightDataListItem(styleRule, sel->mSelectors);
  3215. if (newItem) {
  3216. *(entry->data.mTail) = newItem;
  3217. entry->data.mTail = &newItem->mNext;
  3218. }
  3219. }
  3220. }
  3221. else if (css::Rule::MEDIA_RULE == type ||
  3222. css::Rule::SUPPORTS_RULE == type) {
  3223. css::GroupRule* groupRule = static_cast<css::GroupRule*>(aRule);
  3224. const bool use =
  3225. groupRule->UseForPresentation(data->mPresContext, data->mCacheKey);
  3226. if (use || data->mMustGatherDocumentRules) {
  3227. if (!groupRule->EnumerateRulesForwards(use ? CascadeRuleEnumFunc :
  3228. GatherDocRuleEnumFunc,
  3229. aData)) {
  3230. return false;
  3231. }
  3232. }
  3233. }
  3234. else if (css::Rule::DOCUMENT_RULE == type) {
  3235. css::DocumentRule* docRule = static_cast<css::DocumentRule*>(aRule);
  3236. if (data->mMustGatherDocumentRules) {
  3237. if (!data->mDocumentRules.AppendElement(docRule)) {
  3238. return false;
  3239. }
  3240. }
  3241. const bool use = docRule->UseForPresentation(data->mPresContext);
  3242. if (use && data->mMustGatherDocumentRules) {
  3243. if (!data->mDocumentCacheKey.AddMatchingRule(docRule)) {
  3244. return false;
  3245. }
  3246. }
  3247. if (use || data->mMustGatherDocumentRules) {
  3248. if (!docRule->EnumerateRulesForwards(use ? CascadeRuleEnumFunc
  3249. : GatherDocRuleEnumFunc,
  3250. aData)) {
  3251. return false;
  3252. }
  3253. }
  3254. }
  3255. else if (css::Rule::FONT_FACE_RULE == type) {
  3256. nsCSSFontFaceRule *fontFaceRule = static_cast<nsCSSFontFaceRule*>(aRule);
  3257. nsFontFaceRuleContainer *ptr = data->mFontFaceRules.AppendElement();
  3258. if (!ptr)
  3259. return false;
  3260. ptr->mRule = fontFaceRule;
  3261. ptr->mSheetType = data->mSheetType;
  3262. }
  3263. else if (css::Rule::KEYFRAMES_RULE == type) {
  3264. nsCSSKeyframesRule *keyframesRule =
  3265. static_cast<nsCSSKeyframesRule*>(aRule);
  3266. if (!data->mKeyframesRules.AppendElement(keyframesRule)) {
  3267. return false;
  3268. }
  3269. }
  3270. else if (css::Rule::FONT_FEATURE_VALUES_RULE == type) {
  3271. nsCSSFontFeatureValuesRule *fontFeatureValuesRule =
  3272. static_cast<nsCSSFontFeatureValuesRule*>(aRule);
  3273. if (!data->mFontFeatureValuesRules.AppendElement(fontFeatureValuesRule)) {
  3274. return false;
  3275. }
  3276. }
  3277. else if (css::Rule::PAGE_RULE == type) {
  3278. nsCSSPageRule* pageRule = static_cast<nsCSSPageRule*>(aRule);
  3279. if (!data->mPageRules.AppendElement(pageRule)) {
  3280. return false;
  3281. }
  3282. }
  3283. else if (css::Rule::COUNTER_STYLE_RULE == type) {
  3284. nsCSSCounterStyleRule* counterStyleRule =
  3285. static_cast<nsCSSCounterStyleRule*>(aRule);
  3286. if (!data->mCounterStyleRules.AppendElement(counterStyleRule)) {
  3287. return false;
  3288. }
  3289. }
  3290. return true;
  3291. }
  3292. /* static */ bool
  3293. nsCSSRuleProcessor::CascadeSheet(CSSStyleSheet* aSheet, CascadeEnumData* aData)
  3294. {
  3295. if (aSheet->IsApplicable() &&
  3296. aSheet->UseForPresentation(aData->mPresContext, aData->mCacheKey) &&
  3297. aSheet->mInner) {
  3298. CSSStyleSheet* child = aSheet->mInner->mFirstChild;
  3299. while (child) {
  3300. CascadeSheet(child, aData);
  3301. child = child->mNext;
  3302. }
  3303. if (!aSheet->mInner->mOrderedRules.EnumerateForwards(CascadeRuleEnumFunc,
  3304. aData))
  3305. return false;
  3306. }
  3307. return true;
  3308. }
  3309. static int CompareWeightData(const void* aArg1, const void* aArg2,
  3310. void* closure)
  3311. {
  3312. const PerWeightData* arg1 = static_cast<const PerWeightData*>(aArg1);
  3313. const PerWeightData* arg2 = static_cast<const PerWeightData*>(aArg2);
  3314. return arg1->mWeight - arg2->mWeight; // put lower weight first
  3315. }
  3316. RuleCascadeData*
  3317. nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext)
  3318. {
  3319. // FIXME: Make this infallible!
  3320. // If anything changes about the presentation context, we will be
  3321. // notified. Otherwise, our cache is valid if mLastPresContext
  3322. // matches aPresContext. (The only rule processors used for multiple
  3323. // pres contexts are for XBL. These rule processors are probably less
  3324. // likely to have @media rules, and thus the cache is pretty likely to
  3325. // hit instantly even when we're switching between pres contexts.)
  3326. if (!mRuleCascades || aPresContext != mLastPresContext) {
  3327. RefreshRuleCascade(aPresContext);
  3328. }
  3329. mLastPresContext = aPresContext;
  3330. return mRuleCascades;
  3331. }
  3332. void
  3333. nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
  3334. {
  3335. // Having RuleCascadeData objects be per-medium (over all variation
  3336. // caused by media queries, handled through mCacheKey) works for now
  3337. // since nsCSSRuleProcessor objects are per-document. (For a given
  3338. // set of stylesheets they can vary based on medium (@media) or
  3339. // document (@-moz-document).)
  3340. for (RuleCascadeData **cascadep = &mRuleCascades, *cascade;
  3341. (cascade = *cascadep); cascadep = &cascade->mNext) {
  3342. if (cascade->mCacheKey.Matches(aPresContext)) {
  3343. // Ensure that the current one is always mRuleCascades.
  3344. *cascadep = cascade->mNext;
  3345. cascade->mNext = mRuleCascades;
  3346. mRuleCascades = cascade;
  3347. return;
  3348. }
  3349. }
  3350. // We're going to make a new rule cascade; this means that we should
  3351. // now stop using the previous cache key that we're holding on to from
  3352. // the last time we had rule cascades.
  3353. mPreviousCacheKey = nullptr;
  3354. if (mSheets.Length() != 0) {
  3355. nsAutoPtr<RuleCascadeData> newCascade(
  3356. new RuleCascadeData(aPresContext->Medium(),
  3357. eCompatibility_NavQuirks == aPresContext->CompatibilityMode()));
  3358. if (newCascade) {
  3359. CascadeEnumData data(aPresContext, newCascade->mFontFaceRules,
  3360. newCascade->mKeyframesRules,
  3361. newCascade->mFontFeatureValuesRules,
  3362. newCascade->mPageRules,
  3363. newCascade->mCounterStyleRules,
  3364. mDocumentRules,
  3365. newCascade->mCacheKey,
  3366. mDocumentCacheKey,
  3367. mSheetType,
  3368. mMustGatherDocumentRules);
  3369. for (uint32_t i = 0; i < mSheets.Length(); ++i) {
  3370. if (!CascadeSheet(mSheets.ElementAt(i), &data))
  3371. return; /* out of memory */
  3372. }
  3373. // Sort the hash table of per-weight linked lists by weight.
  3374. uint32_t weightCount = data.mRulesByWeight.EntryCount();
  3375. auto weightArray = MakeUnique<PerWeightData[]>(weightCount);
  3376. int32_t j = 0;
  3377. for (auto iter = data.mRulesByWeight.Iter(); !iter.Done(); iter.Next()) {
  3378. auto entry = static_cast<const RuleByWeightEntry*>(iter.Get());
  3379. weightArray[j++] = entry->data;
  3380. }
  3381. NS_QuickSort(weightArray.get(), weightCount, sizeof(PerWeightData),
  3382. CompareWeightData, nullptr);
  3383. // Put things into the rule hash.
  3384. // The primary sort is by weight...
  3385. for (uint32_t i = 0; i < weightCount; ++i) {
  3386. // and the secondary sort is by order. mRuleSelectorPairs is already in
  3387. // the right order..
  3388. for (PerWeightDataListItem *cur = weightArray[i].mRuleSelectorPairs;
  3389. cur;
  3390. cur = cur->mNext) {
  3391. if (!AddRule(cur, newCascade))
  3392. return; /* out of memory */
  3393. }
  3394. }
  3395. // Build mKeyframesRuleTable.
  3396. for (nsTArray<nsCSSKeyframesRule*>::size_type i = 0,
  3397. iEnd = newCascade->mKeyframesRules.Length(); i < iEnd; ++i) {
  3398. nsCSSKeyframesRule* rule = newCascade->mKeyframesRules[i];
  3399. newCascade->mKeyframesRuleTable.Put(rule->GetName(), rule);
  3400. }
  3401. // Build mCounterStyleRuleTable
  3402. for (nsTArray<nsCSSCounterStyleRule*>::size_type i = 0,
  3403. iEnd = newCascade->mCounterStyleRules.Length(); i < iEnd; ++i) {
  3404. nsCSSCounterStyleRule* rule = newCascade->mCounterStyleRules[i];
  3405. newCascade->mCounterStyleRuleTable.Put(rule->GetName(), rule);
  3406. }
  3407. // mMustGatherDocumentRules controls whether we build mDocumentRules
  3408. // and mDocumentCacheKey so that they can be used as keys by the
  3409. // RuleProcessorCache, as obtained by TakeDocumentRulesAndCacheKey
  3410. // later. We set it to false just below so that we only do this
  3411. // the first time we build a RuleProcessorCache for a shared rule
  3412. // processor.
  3413. //
  3414. // An up-to-date mDocumentCacheKey is only needed if we
  3415. // are still in the RuleProcessorCache (as we store a copy of the
  3416. // cache key in the RuleProcessorCache), and an up-to-date
  3417. // mDocumentRules is only needed at the time TakeDocumentRulesAndCacheKey
  3418. // is called, which is immediately after the rule processor is created
  3419. // (by nsStyleSet).
  3420. //
  3421. // Note that when nsCSSRuleProcessor::ClearRuleCascades is called,
  3422. // by CSSStyleSheet::ClearRuleCascades, we will have called
  3423. // RuleProcessorCache::RemoveSheet, which will remove the rule
  3424. // processor from the cache. (This is because the list of document
  3425. // rules now may not match the one used as they key in the
  3426. // RuleProcessorCache.)
  3427. //
  3428. // Thus, as we'll no longer be in the RuleProcessorCache, and we won't
  3429. // have TakeDocumentRulesAndCacheKey called on us, we don't need to ensure
  3430. // mDocumentCacheKey and mDocumentRules are up-to-date after the
  3431. // first time GetRuleCascade is called.
  3432. if (mMustGatherDocumentRules) {
  3433. mDocumentRules.Sort();
  3434. mDocumentCacheKey.Finalize();
  3435. mMustGatherDocumentRules = false;
  3436. #ifdef DEBUG
  3437. mDocumentRulesAndCacheKeyValid = true;
  3438. #endif
  3439. }
  3440. // Ensure that the current one is always mRuleCascades.
  3441. newCascade->mNext = mRuleCascades;
  3442. mRuleCascades = newCascade.forget();
  3443. }
  3444. }
  3445. return;
  3446. }
  3447. /* static */ bool
  3448. nsCSSRuleProcessor::SelectorListMatches(Element* aElement,
  3449. TreeMatchContext& aTreeMatchContext,
  3450. nsCSSSelectorList* aSelectorList)
  3451. {
  3452. MOZ_ASSERT(!aTreeMatchContext.mForScopedStyle,
  3453. "mCurrentStyleScope will need to be saved and restored after the "
  3454. "SelectorMatchesTree call");
  3455. while (aSelectorList) {
  3456. nsCSSSelector* sel = aSelectorList->mSelectors;
  3457. NS_ASSERTION(sel, "Should have *some* selectors");
  3458. NS_ASSERTION(!sel->IsPseudoElement(), "Shouldn't have been called");
  3459. NodeMatchContext nodeContext(EventStates(), false);
  3460. if (SelectorMatches(aElement, sel, nodeContext, aTreeMatchContext,
  3461. SelectorMatchesFlags::NONE)) {
  3462. nsCSSSelector* next = sel->mNext;
  3463. if (!next ||
  3464. SelectorMatchesTree(aElement, next, aTreeMatchContext,
  3465. SelectorMatchesTreeFlags(0))) {
  3466. return true;
  3467. }
  3468. }
  3469. aSelectorList = aSelectorList->mNext;
  3470. }
  3471. return false;
  3472. }
  3473. void
  3474. nsCSSRuleProcessor::TakeDocumentRulesAndCacheKey(
  3475. nsPresContext* aPresContext,
  3476. nsTArray<css::DocumentRule*>& aDocumentRules,
  3477. nsDocumentRuleResultCacheKey& aCacheKey)
  3478. {
  3479. MOZ_ASSERT(mIsShared);
  3480. GetRuleCascade(aPresContext);
  3481. MOZ_ASSERT(mDocumentRulesAndCacheKeyValid);
  3482. aDocumentRules.Clear();
  3483. aDocumentRules.SwapElements(mDocumentRules);
  3484. aCacheKey.Swap(mDocumentCacheKey);
  3485. #ifdef DEBUG
  3486. mDocumentRulesAndCacheKeyValid = false;
  3487. #endif
  3488. }
  3489. void
  3490. nsCSSRuleProcessor::AddStyleSetRef()
  3491. {
  3492. MOZ_ASSERT(mIsShared);
  3493. if (++mStyleSetRefCnt == 1) {
  3494. RuleProcessorCache::StopTracking(this);
  3495. }
  3496. }
  3497. void
  3498. nsCSSRuleProcessor::ReleaseStyleSetRef()
  3499. {
  3500. MOZ_ASSERT(mIsShared);
  3501. MOZ_ASSERT(mStyleSetRefCnt > 0);
  3502. if (--mStyleSetRefCnt == 0 && mInRuleProcessorCache) {
  3503. RuleProcessorCache::StartTracking(this);
  3504. }
  3505. }
  3506. // TreeMatchContext and AncestorFilter out of line methods
  3507. void
  3508. TreeMatchContext::InitAncestors(Element *aElement)
  3509. {
  3510. MOZ_ASSERT(!mAncestorFilter.mFilter);
  3511. MOZ_ASSERT(mAncestorFilter.mHashes.IsEmpty());
  3512. MOZ_ASSERT(mStyleScopes.IsEmpty());
  3513. mAncestorFilter.mFilter = new AncestorFilter::Filter();
  3514. if (MOZ_LIKELY(aElement)) {
  3515. MOZ_ASSERT(aElement->GetUncomposedDoc() ||
  3516. aElement->HasFlag(NODE_IS_IN_SHADOW_TREE),
  3517. "aElement must be in the document or in shadow tree "
  3518. "for the assumption that GetParentNode() is non-null "
  3519. "on all element ancestors of aElement to be true");
  3520. // Collect up the ancestors
  3521. AutoTArray<Element*, 50> ancestors;
  3522. Element* cur = aElement;
  3523. do {
  3524. ancestors.AppendElement(cur);
  3525. cur = cur->GetParentElementCrossingShadowRoot();
  3526. } while (cur);
  3527. // Now push them in reverse order.
  3528. for (uint32_t i = ancestors.Length(); i-- != 0; ) {
  3529. mAncestorFilter.PushAncestor(ancestors[i]);
  3530. PushStyleScope(ancestors[i]);
  3531. }
  3532. }
  3533. }
  3534. void
  3535. TreeMatchContext::InitStyleScopes(Element* aElement)
  3536. {
  3537. MOZ_ASSERT(mStyleScopes.IsEmpty());
  3538. if (MOZ_LIKELY(aElement)) {
  3539. // Collect up the ancestors
  3540. AutoTArray<Element*, 50> ancestors;
  3541. Element* cur = aElement;
  3542. do {
  3543. ancestors.AppendElement(cur);
  3544. cur = cur->GetParentElementCrossingShadowRoot();
  3545. } while (cur);
  3546. // Now push them in reverse order.
  3547. for (uint32_t i = ancestors.Length(); i-- != 0; ) {
  3548. PushStyleScope(ancestors[i]);
  3549. }
  3550. }
  3551. }
  3552. void
  3553. AncestorFilter::PushAncestor(Element *aElement)
  3554. {
  3555. MOZ_ASSERT(mFilter);
  3556. uint32_t oldLength = mHashes.Length();
  3557. mPopTargets.AppendElement(oldLength);
  3558. #ifdef DEBUG
  3559. mElements.AppendElement(aElement);
  3560. #endif
  3561. mHashes.AppendElement(aElement->NodeInfo()->NameAtom()->hash());
  3562. nsIAtom *id = aElement->GetID();
  3563. if (id) {
  3564. mHashes.AppendElement(id->hash());
  3565. }
  3566. const nsAttrValue *classes = aElement->GetClasses();
  3567. if (classes) {
  3568. uint32_t classCount = classes->GetAtomCount();
  3569. for (uint32_t i = 0; i < classCount; ++i) {
  3570. mHashes.AppendElement(classes->AtomAt(i)->hash());
  3571. }
  3572. }
  3573. uint32_t newLength = mHashes.Length();
  3574. for (uint32_t i = oldLength; i < newLength; ++i) {
  3575. mFilter->add(mHashes[i]);
  3576. }
  3577. }
  3578. void
  3579. AncestorFilter::PopAncestor()
  3580. {
  3581. MOZ_ASSERT(!mPopTargets.IsEmpty());
  3582. MOZ_ASSERT(mPopTargets.Length() == mElements.Length());
  3583. uint32_t popTargetLength = mPopTargets.Length();
  3584. uint32_t newLength = mPopTargets[popTargetLength-1];
  3585. mPopTargets.TruncateLength(popTargetLength-1);
  3586. #ifdef DEBUG
  3587. mElements.TruncateLength(popTargetLength-1);
  3588. #endif
  3589. uint32_t oldLength = mHashes.Length();
  3590. for (uint32_t i = newLength; i < oldLength; ++i) {
  3591. mFilter->remove(mHashes[i]);
  3592. }
  3593. mHashes.TruncateLength(newLength);
  3594. }
  3595. #ifdef DEBUG
  3596. void
  3597. AncestorFilter::AssertHasAllAncestors(Element *aElement) const
  3598. {
  3599. Element* cur = aElement->GetParentElementCrossingShadowRoot();
  3600. while (cur) {
  3601. MOZ_ASSERT(mElements.Contains(cur));
  3602. cur = cur->GetParentElementCrossingShadowRoot();
  3603. }
  3604. }
  3605. void
  3606. TreeMatchContext::AssertHasAllStyleScopes(Element* aElement) const
  3607. {
  3608. if (aElement->IsInNativeAnonymousSubtree()) {
  3609. // Document style sheets are never applied to native anonymous content,
  3610. // so it's not possible for them to be in a <style scoped> scope.
  3611. return;
  3612. }
  3613. Element* cur = aElement->GetParentElementCrossingShadowRoot();
  3614. while (cur) {
  3615. if (cur->IsScopedStyleRoot()) {
  3616. MOZ_ASSERT(mStyleScopes.Contains(cur));
  3617. }
  3618. cur = cur->GetParentElementCrossingShadowRoot();
  3619. }
  3620. }
  3621. #endif