nsStyleSet.cpp 87 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /*
  6. * the container for the style sheets that apply to a presentation, and
  7. * the internal API that the style system exposes for creating (and
  8. * potentially re-creating) style contexts
  9. */
  10. #include "nsStyleSet.h"
  11. #include "mozilla/ArrayUtils.h"
  12. #include "mozilla/StyleSheetInlines.h"
  13. #include "mozilla/EffectCompositor.h"
  14. #include "mozilla/EnumeratedRange.h"
  15. #include "mozilla/EventStates.h"
  16. #include "mozilla/MemoryReporting.h"
  17. #include "mozilla/RuleProcessorCache.h"
  18. #include "mozilla/StyleSheetInlines.h"
  19. #include "nsIDocumentInlines.h"
  20. #include "nsRuleWalker.h"
  21. #include "nsStyleContext.h"
  22. #include "mozilla/css/StyleRule.h"
  23. #include "nsCSSAnonBoxes.h"
  24. #include "nsCSSPseudoElements.h"
  25. #include "nsCSSRuleProcessor.h"
  26. #include "nsDataHashtable.h"
  27. #include "nsIContent.h"
  28. #include "nsRuleData.h"
  29. #include "nsRuleProcessorData.h"
  30. #include "nsAnimationManager.h"
  31. #include "nsStyleSheetService.h"
  32. #include "mozilla/dom/Element.h"
  33. #include "GeckoProfiler.h"
  34. #include "nsHTMLCSSStyleSheet.h"
  35. #include "nsHTMLStyleSheet.h"
  36. #include "SVGAttrAnimationRuleProcessor.h"
  37. #include "nsCSSRules.h"
  38. #include "nsPrintfCString.h"
  39. #include "nsIFrame.h"
  40. #include "mozilla/RestyleManagerHandle.h"
  41. #include "mozilla/RestyleManagerHandleInlines.h"
  42. #include "nsQueryObject.h"
  43. #include <inttypes.h>
  44. using namespace mozilla;
  45. using namespace mozilla::dom;
  46. NS_IMPL_ISUPPORTS(nsEmptyStyleRule, nsIStyleRule)
  47. /* virtual */ void
  48. nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
  49. {
  50. }
  51. /* virtual */ bool
  52. nsEmptyStyleRule::MightMapInheritedStyleData()
  53. {
  54. return false;
  55. }
  56. /* virtual */ bool
  57. nsEmptyStyleRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
  58. nsCSSValue* aValue)
  59. {
  60. MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
  61. return false;
  62. }
  63. #ifdef DEBUG
  64. /* virtual */ void
  65. nsEmptyStyleRule::List(FILE* out, int32_t aIndent) const
  66. {
  67. nsAutoCString indentStr;
  68. for (int32_t index = aIndent; --index >= 0; ) {
  69. indentStr.AppendLiteral(" ");
  70. }
  71. fprintf_stderr(out, "%s[empty style rule] {}\n", indentStr.get());
  72. }
  73. #endif
  74. NS_IMPL_ISUPPORTS(nsInitialStyleRule, nsIStyleRule)
  75. /* virtual */ void
  76. nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
  77. {
  78. // Iterate over the property groups
  79. for (nsStyleStructID sid = nsStyleStructID(0);
  80. sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
  81. if (aRuleData->mSIDs & (1 << sid)) {
  82. // Iterate over nsCSSValues within the property group
  83. nsCSSValue * const value_start =
  84. aRuleData->mValueStorage + aRuleData->mValueOffsets[sid];
  85. for (nsCSSValue *value = value_start,
  86. *value_end = value + nsCSSProps::PropertyCountInStruct(sid);
  87. value != value_end; ++value) {
  88. // If MathML is disabled take care not to set MathML properties (or we
  89. // will trigger assertions in nsRuleNode)
  90. if (sid == eStyleStruct_Font &&
  91. !aRuleData->mPresContext->Document()->GetMathMLEnabled()) {
  92. size_t index = value - value_start;
  93. if (index == nsCSSProps::PropertyIndexInStruct(
  94. eCSSProperty_script_level) ||
  95. index == nsCSSProps::PropertyIndexInStruct(
  96. eCSSProperty_script_size_multiplier) ||
  97. index == nsCSSProps::PropertyIndexInStruct(
  98. eCSSProperty_script_min_size) ||
  99. index == nsCSSProps::PropertyIndexInStruct(
  100. eCSSProperty_math_variant) ||
  101. index == nsCSSProps::PropertyIndexInStruct(
  102. eCSSProperty_math_display)) {
  103. continue;
  104. }
  105. }
  106. if (value->GetUnit() == eCSSUnit_Null) {
  107. value->SetInitialValue();
  108. }
  109. }
  110. }
  111. }
  112. }
  113. /* virtual */ bool
  114. nsInitialStyleRule::MightMapInheritedStyleData()
  115. {
  116. return true;
  117. }
  118. /* virtual */ bool
  119. nsInitialStyleRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
  120. nsCSSValue* aValue)
  121. {
  122. MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
  123. return false;
  124. }
  125. #ifdef DEBUG
  126. /* virtual */ void
  127. nsInitialStyleRule::List(FILE* out, int32_t aIndent) const
  128. {
  129. nsAutoCString indentStr;
  130. for (int32_t index = aIndent; --index >= 0; ) {
  131. indentStr.AppendLiteral(" ");
  132. }
  133. fprintf_stderr(out, "%s[initial style rule] {}\n", indentStr.get());
  134. }
  135. #endif
  136. NS_IMPL_ISUPPORTS(nsDisableTextZoomStyleRule, nsIStyleRule)
  137. /* virtual */ void
  138. nsDisableTextZoomStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
  139. {
  140. if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Font)))
  141. return;
  142. nsCSSValue* value = aRuleData->ValueForTextZoom();
  143. if (value->GetUnit() == eCSSUnit_Null)
  144. value->SetNoneValue();
  145. }
  146. /* virtual */ bool
  147. nsDisableTextZoomStyleRule::MightMapInheritedStyleData()
  148. {
  149. return true;
  150. }
  151. /* virtual */ bool
  152. nsDisableTextZoomStyleRule::
  153. GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty, nsCSSValue* aValue)
  154. {
  155. MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
  156. return false;
  157. }
  158. #ifdef DEBUG
  159. /* virtual */ void
  160. nsDisableTextZoomStyleRule::List(FILE* out, int32_t aIndent) const
  161. {
  162. nsAutoCString indentStr;
  163. for (int32_t index = aIndent; --index >= 0; ) {
  164. indentStr.AppendLiteral(" ");
  165. }
  166. fprintf_stderr(out, "%s[disable text zoom style rule] {}\n", indentStr.get());
  167. }
  168. #endif
  169. static const SheetType gCSSSheetTypes[] = {
  170. // From lowest to highest in cascading order.
  171. SheetType::Agent,
  172. SheetType::User,
  173. SheetType::Doc,
  174. SheetType::ScopedDoc,
  175. SheetType::Override
  176. };
  177. /* static */ bool
  178. nsStyleSet::IsCSSSheetType(SheetType aSheetType)
  179. {
  180. for (SheetType type : gCSSSheetTypes) {
  181. if (type == aSheetType) {
  182. return true;
  183. }
  184. }
  185. return false;
  186. }
  187. nsStyleSet::nsStyleSet()
  188. : mRuleTree(nullptr),
  189. mBatching(0),
  190. mInShutdown(false),
  191. mInGC(false),
  192. mAuthorStyleDisabled(false),
  193. mInReconstruct(false),
  194. mInitFontFeatureValuesLookup(true),
  195. mNeedsRestyleAfterEnsureUniqueInner(false),
  196. mDirty(0),
  197. mRootStyleContextCount(0),
  198. #ifdef DEBUG
  199. mOldRootNode(nullptr),
  200. #endif
  201. mUnusedRuleNodeCount(0)
  202. {
  203. }
  204. nsStyleSet::~nsStyleSet()
  205. {
  206. for (SheetType type : gCSSSheetTypes) {
  207. for (CSSStyleSheet* sheet : mSheets[type]) {
  208. sheet->DropStyleSet(this);
  209. }
  210. }
  211. // drop reference to cached rule processors
  212. nsCSSRuleProcessor* rp;
  213. rp = static_cast<nsCSSRuleProcessor*>(mRuleProcessors[SheetType::Agent].get());
  214. if (rp) {
  215. MOZ_ASSERT(rp->IsShared());
  216. rp->ReleaseStyleSetRef();
  217. }
  218. rp = static_cast<nsCSSRuleProcessor*>(mRuleProcessors[SheetType::User].get());
  219. if (rp) {
  220. MOZ_ASSERT(rp->IsShared());
  221. rp->ReleaseStyleSetRef();
  222. }
  223. }
  224. size_t
  225. nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
  226. {
  227. size_t n = aMallocSizeOf(this);
  228. for (SheetType type : MakeEnumeratedRange(SheetType::Count)) {
  229. if (mRuleProcessors[type]) {
  230. bool shared = false;
  231. if (type == SheetType::Agent || type == SheetType::User) {
  232. // The only two origins we consider caching rule processors for.
  233. nsCSSRuleProcessor* rp =
  234. static_cast<nsCSSRuleProcessor*>(mRuleProcessors[type].get());
  235. shared = rp->IsShared();
  236. }
  237. if (!shared) {
  238. n += mRuleProcessors[type]->SizeOfIncludingThis(aMallocSizeOf);
  239. }
  240. }
  241. // We don't own the sheets (either the nsLayoutStyleSheetCache singleton
  242. // or our document owns them).
  243. n += mSheets[type].ShallowSizeOfExcludingThis(aMallocSizeOf);
  244. }
  245. for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
  246. n += mScopedDocSheetRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
  247. }
  248. n += mScopedDocSheetRuleProcessors.ShallowSizeOfExcludingThis(aMallocSizeOf);
  249. return n;
  250. }
  251. void
  252. nsStyleSet::Init(nsPresContext *aPresContext)
  253. {
  254. mFirstLineRule = new nsEmptyStyleRule;
  255. mFirstLetterRule = new nsEmptyStyleRule;
  256. mPlaceholderRule = new nsEmptyStyleRule;
  257. mDisableTextZoomStyleRule = new nsDisableTextZoomStyleRule;
  258. mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
  259. // Make an explicit GatherRuleProcessors call for the levels that
  260. // don't have style sheets. The other levels will have their calls
  261. // triggered by DirtyRuleProcessors.
  262. GatherRuleProcessors(SheetType::PresHint);
  263. GatherRuleProcessors(SheetType::SVGAttrAnimation);
  264. GatherRuleProcessors(SheetType::StyleAttr);
  265. GatherRuleProcessors(SheetType::Animation);
  266. GatherRuleProcessors(SheetType::Transition);
  267. }
  268. nsresult
  269. nsStyleSet::BeginReconstruct()
  270. {
  271. NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
  272. NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
  273. mInReconstruct = true;
  274. // Clear any ArenaRefPtr-managed style contexts, as we don't want them
  275. // held on to after the rule tree has been reconstructed.
  276. PresContext()->PresShell()->ClearArenaRefPtrs(eArenaObjectID_nsStyleContext);
  277. #ifdef DEBUG
  278. MOZ_ASSERT(!mOldRootNode);
  279. mOldRootNode = mRuleTree;
  280. #endif
  281. // Create a new rule tree root, dropping the reference to our old rule tree.
  282. // After reconstruction, we will re-enable GC, and allow everything to be
  283. // collected.
  284. mRuleTree = nsRuleNode::CreateRootNode(mRuleTree->PresContext());
  285. return NS_OK;
  286. }
  287. void
  288. nsStyleSet::EndReconstruct()
  289. {
  290. NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
  291. mInReconstruct = false;
  292. GCRuleTrees();
  293. }
  294. typedef nsDataHashtable<nsPtrHashKey<nsINode>, uint32_t> ScopeDepthCache;
  295. // Returns the depth of a style scope element, with 1 being the depth of
  296. // a style scope element that has no ancestor style scope elements. The
  297. // depth does not count intervening non-scope elements.
  298. static uint32_t
  299. GetScopeDepth(nsINode* aScopeElement, ScopeDepthCache& aCache)
  300. {
  301. nsINode* parent = aScopeElement->GetParent();
  302. if (!parent || !parent->IsElementInStyleScope()) {
  303. return 1;
  304. }
  305. uint32_t depth = aCache.Get(aScopeElement);
  306. if (!depth) {
  307. for (nsINode* n = parent; n; n = n->GetParent()) {
  308. if (n->IsScopedStyleRoot()) {
  309. depth = GetScopeDepth(n, aCache) + 1;
  310. aCache.Put(aScopeElement, depth);
  311. break;
  312. }
  313. }
  314. }
  315. return depth;
  316. }
  317. struct ScopedSheetOrder
  318. {
  319. CSSStyleSheet* mSheet;
  320. uint32_t mDepth;
  321. uint32_t mOrder;
  322. bool operator==(const ScopedSheetOrder& aRHS) const
  323. {
  324. return mDepth == aRHS.mDepth &&
  325. mOrder == aRHS.mOrder;
  326. }
  327. bool operator<(const ScopedSheetOrder& aRHS) const
  328. {
  329. if (mDepth != aRHS.mDepth) {
  330. return mDepth < aRHS.mDepth;
  331. }
  332. return mOrder < aRHS.mOrder;
  333. }
  334. };
  335. // Sorts aSheets such that style sheets for ancestor scopes come
  336. // before those for descendant scopes, and with sheets for a single
  337. // scope in document order.
  338. static void
  339. SortStyleSheetsByScope(nsTArray<CSSStyleSheet*>& aSheets)
  340. {
  341. uint32_t n = aSheets.Length();
  342. if (n == 1) {
  343. return;
  344. }
  345. ScopeDepthCache cache;
  346. nsTArray<ScopedSheetOrder> sheets;
  347. sheets.SetLength(n);
  348. // For each sheet, record the depth of its scope element and its original
  349. // document order.
  350. for (uint32_t i = 0; i < n; i++) {
  351. sheets[i].mSheet = aSheets[i];
  352. sheets[i].mDepth = GetScopeDepth(aSheets[i]->GetScopeElement(), cache);
  353. sheets[i].mOrder = i;
  354. }
  355. // Sort by depth first, then document order.
  356. sheets.Sort();
  357. for (uint32_t i = 0; i < n; i++) {
  358. aSheets[i] = sheets[i].mSheet;
  359. }
  360. }
  361. nsresult
  362. nsStyleSet::GatherRuleProcessors(SheetType aType)
  363. {
  364. NS_ENSURE_FALSE(mInShutdown, NS_ERROR_FAILURE);
  365. // We might be in GatherRuleProcessors because we are dropping a sheet,
  366. // resulting in an nsCSSSelector being destroyed. Tell the
  367. // RestyleManager for each document we're used in so that they can
  368. // drop any nsCSSSelector pointers (used for eRestyle_SomeDescendants)
  369. // in their mPendingRestyles.
  370. if (IsCSSSheetType(aType)) {
  371. ClearSelectors();
  372. }
  373. nsCOMPtr<nsIStyleRuleProcessor> oldRuleProcessor(mRuleProcessors[aType]);
  374. nsTArray<nsCOMPtr<nsIStyleRuleProcessor>> oldScopedDocRuleProcessors;
  375. if (aType == SheetType::Agent || aType == SheetType::User) {
  376. // drop reference to cached rule processor
  377. nsCSSRuleProcessor* rp =
  378. static_cast<nsCSSRuleProcessor*>(mRuleProcessors[aType].get());
  379. if (rp) {
  380. MOZ_ASSERT(rp->IsShared());
  381. rp->ReleaseStyleSetRef();
  382. }
  383. }
  384. mRuleProcessors[aType] = nullptr;
  385. if (aType == SheetType::ScopedDoc) {
  386. for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
  387. nsIStyleRuleProcessor* processor = mScopedDocSheetRuleProcessors[i].get();
  388. Element* scope =
  389. static_cast<nsCSSRuleProcessor*>(processor)->GetScopeElement();
  390. scope->ClearIsScopedStyleRoot();
  391. }
  392. // Clear mScopedDocSheetRuleProcessors, but save it.
  393. oldScopedDocRuleProcessors.SwapElements(mScopedDocSheetRuleProcessors);
  394. }
  395. if (mAuthorStyleDisabled && (aType == SheetType::Doc ||
  396. aType == SheetType::ScopedDoc ||
  397. aType == SheetType::StyleAttr)) {
  398. // Don't regather if this level is disabled. Note that we gather
  399. // preshint sheets no matter what, but then skip them for some
  400. // elements later if mAuthorStyleDisabled.
  401. return NS_OK;
  402. }
  403. switch (aType) {
  404. // levels that do not contain CSS style sheets
  405. case SheetType::Animation:
  406. MOZ_ASSERT(mSheets[aType].IsEmpty());
  407. mRuleProcessors[aType] = PresContext()->EffectCompositor()->
  408. RuleProcessor(EffectCompositor::CascadeLevel::Animations);
  409. return NS_OK;
  410. case SheetType::Transition:
  411. MOZ_ASSERT(mSheets[aType].IsEmpty());
  412. mRuleProcessors[aType] = PresContext()->EffectCompositor()->
  413. RuleProcessor(EffectCompositor::CascadeLevel::Transitions);
  414. return NS_OK;
  415. case SheetType::StyleAttr:
  416. MOZ_ASSERT(mSheets[aType].IsEmpty());
  417. mRuleProcessors[aType] = PresContext()->Document()->GetInlineStyleSheet();
  418. return NS_OK;
  419. case SheetType::PresHint:
  420. MOZ_ASSERT(mSheets[aType].IsEmpty());
  421. mRuleProcessors[aType] =
  422. PresContext()->Document()->GetAttributeStyleSheet();
  423. return NS_OK;
  424. case SheetType::SVGAttrAnimation:
  425. MOZ_ASSERT(mSheets[aType].IsEmpty());
  426. mRuleProcessors[aType] =
  427. PresContext()->Document()->GetSVGAttrAnimationRuleProcessor();
  428. return NS_OK;
  429. default:
  430. // keep going
  431. break;
  432. }
  433. MOZ_ASSERT(IsCSSSheetType(aType));
  434. if (aType == SheetType::ScopedDoc) {
  435. // Create a rule processor for each scope.
  436. uint32_t count = mSheets[SheetType::ScopedDoc].Length();
  437. if (count) {
  438. // Gather the scoped style sheets into an array as
  439. // CSSStyleSheets, and mark all of their scope elements
  440. // as scoped style roots.
  441. nsTArray<CSSStyleSheet*> sheets(count);
  442. for (CSSStyleSheet* sheet : mSheets[SheetType::ScopedDoc]) {
  443. sheets.AppendElement(sheet);
  444. Element* scope = sheet->GetScopeElement();
  445. scope->SetIsScopedStyleRoot();
  446. }
  447. // Sort the scoped style sheets so that those for the same scope are
  448. // adjacent and that ancestor scopes come before descendent scopes.
  449. SortStyleSheetsByScope(sheets);
  450. // Put the old scoped rule processors in a hashtable so that we
  451. // can retrieve them efficiently, even in edge cases like the
  452. // simultaneous removal and addition of a large number of elements
  453. // with scoped sheets.
  454. nsDataHashtable<nsPtrHashKey<Element>,
  455. nsCSSRuleProcessor*> oldScopedRuleProcessorHash;
  456. for (size_t i = oldScopedDocRuleProcessors.Length(); i-- != 0; ) {
  457. nsCSSRuleProcessor* oldRP =
  458. static_cast<nsCSSRuleProcessor*>(oldScopedDocRuleProcessors[i].get());
  459. Element* scope = oldRP->GetScopeElement();
  460. MOZ_ASSERT(!oldScopedRuleProcessorHash.Get(scope),
  461. "duplicate rule processors for same scope element?");
  462. oldScopedRuleProcessorHash.Put(scope, oldRP);
  463. }
  464. uint32_t start = 0, end;
  465. do {
  466. // Find the range of style sheets with the same scope.
  467. Element* scope = sheets[start]->GetScopeElement();
  468. end = start + 1;
  469. while (end < count && sheets[end]->GetScopeElement() == scope) {
  470. end++;
  471. }
  472. scope->SetIsScopedStyleRoot();
  473. // Create a rule processor for the scope.
  474. nsTArray<RefPtr<CSSStyleSheet>> sheetsForScope;
  475. sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
  476. nsCSSRuleProcessor* oldRP = oldScopedRuleProcessorHash.Get(scope);
  477. mScopedDocSheetRuleProcessors.AppendElement
  478. (new nsCSSRuleProcessor(Move(sheetsForScope), aType, scope, oldRP));
  479. start = end;
  480. } while (start < count);
  481. }
  482. return NS_OK;
  483. }
  484. if (!mSheets[aType].IsEmpty()) {
  485. switch (aType) {
  486. case SheetType::Agent:
  487. case SheetType::User: {
  488. // levels containing non-scoped CSS style sheets whose rule processors
  489. // we want to re-use
  490. nsTArray<CSSStyleSheet*> sheets(mSheets[aType].Length());
  491. for (CSSStyleSheet* sheet : mSheets[aType]) {
  492. sheets.AppendElement(sheet);
  493. }
  494. nsCSSRuleProcessor* rp =
  495. RuleProcessorCache::GetRuleProcessor(sheets, PresContext());
  496. if (!rp) {
  497. rp = new nsCSSRuleProcessor(mSheets[aType], aType, nullptr,
  498. static_cast<nsCSSRuleProcessor*>(
  499. oldRuleProcessor.get()),
  500. true /* aIsShared */);
  501. nsTArray<css::DocumentRule*> documentRules;
  502. nsDocumentRuleResultCacheKey cacheKey;
  503. rp->TakeDocumentRulesAndCacheKey(PresContext(),
  504. documentRules, cacheKey);
  505. RuleProcessorCache::PutRuleProcessor(sheets,
  506. Move(documentRules),
  507. cacheKey, rp);
  508. }
  509. mRuleProcessors[aType] = rp;
  510. rp->AddStyleSetRef();
  511. break;
  512. }
  513. case SheetType::Doc:
  514. case SheetType::Override: {
  515. // levels containing non-scoped CSS stylesheets whose rule processors
  516. // we don't want to re-use
  517. mRuleProcessors[aType] =
  518. new nsCSSRuleProcessor(mSheets[aType], aType, nullptr,
  519. static_cast<nsCSSRuleProcessor*>(
  520. oldRuleProcessor.get()));
  521. } break;
  522. default:
  523. MOZ_ASSERT_UNREACHABLE("non-CSS sheet types should be handled above");
  524. break;
  525. }
  526. }
  527. return NS_OK;
  528. }
  529. nsresult
  530. nsStyleSet::AppendStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
  531. {
  532. NS_PRECONDITION(aSheet, "null arg");
  533. NS_ASSERTION(aSheet->IsApplicable(),
  534. "Inapplicable sheet being placed in style set");
  535. bool present = mSheets[aType].RemoveElement(aSheet);
  536. mSheets[aType].AppendElement(aSheet);
  537. if (!present && IsCSSSheetType(aType)) {
  538. aSheet->AddStyleSet(this);
  539. }
  540. return DirtyRuleProcessors(aType);
  541. }
  542. nsresult
  543. nsStyleSet::PrependStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
  544. {
  545. NS_PRECONDITION(aSheet, "null arg");
  546. NS_ASSERTION(aSheet->IsApplicable(),
  547. "Inapplicable sheet being placed in style set");
  548. bool present = mSheets[aType].RemoveElement(aSheet);
  549. mSheets[aType].InsertElementAt(0, aSheet);
  550. if (!present && IsCSSSheetType(aType)) {
  551. aSheet->AddStyleSet(this);
  552. }
  553. return DirtyRuleProcessors(aType);
  554. }
  555. nsresult
  556. nsStyleSet::RemoveStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
  557. {
  558. NS_PRECONDITION(aSheet, "null arg");
  559. NS_ASSERTION(aSheet->IsComplete(),
  560. "Incomplete sheet being removed from style set");
  561. if (mSheets[aType].RemoveElement(aSheet)) {
  562. if (IsCSSSheetType(aType)) {
  563. aSheet->DropStyleSet(this);
  564. }
  565. }
  566. return DirtyRuleProcessors(aType);
  567. }
  568. nsresult
  569. nsStyleSet::ReplaceSheets(SheetType aType,
  570. const nsTArray<RefPtr<CSSStyleSheet>>& aNewSheets)
  571. {
  572. bool cssSheetType = IsCSSSheetType(aType);
  573. if (cssSheetType) {
  574. for (CSSStyleSheet* sheet : mSheets[aType]) {
  575. sheet->DropStyleSet(this);
  576. }
  577. }
  578. mSheets[aType].Clear();
  579. mSheets[aType].AppendElements(aNewSheets);
  580. if (cssSheetType) {
  581. for (CSSStyleSheet* sheet : mSheets[aType]) {
  582. sheet->AddStyleSet(this);
  583. }
  584. }
  585. return DirtyRuleProcessors(aType);
  586. }
  587. nsresult
  588. nsStyleSet::InsertStyleSheetBefore(SheetType aType, CSSStyleSheet* aNewSheet,
  589. CSSStyleSheet* aReferenceSheet)
  590. {
  591. NS_PRECONDITION(aNewSheet && aReferenceSheet, "null arg");
  592. NS_ASSERTION(aNewSheet->IsApplicable(),
  593. "Inapplicable sheet being placed in style set");
  594. bool present = mSheets[aType].RemoveElement(aNewSheet);
  595. int32_t idx = mSheets[aType].IndexOf(aReferenceSheet);
  596. if (idx < 0)
  597. return NS_ERROR_INVALID_ARG;
  598. mSheets[aType].InsertElementAt(idx, aNewSheet);
  599. if (!present && IsCSSSheetType(aType)) {
  600. aNewSheet->AddStyleSet(this);
  601. }
  602. return DirtyRuleProcessors(aType);
  603. }
  604. static inline uint32_t
  605. DirtyBit(SheetType aType)
  606. {
  607. return 1 << uint32_t(aType);
  608. }
  609. nsresult
  610. nsStyleSet::DirtyRuleProcessors(SheetType aType)
  611. {
  612. if (!mBatching)
  613. return GatherRuleProcessors(aType);
  614. mDirty |= DirtyBit(aType);
  615. return NS_OK;
  616. }
  617. bool
  618. nsStyleSet::GetAuthorStyleDisabled() const
  619. {
  620. return mAuthorStyleDisabled;
  621. }
  622. nsresult
  623. nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
  624. {
  625. if (aStyleDisabled == !mAuthorStyleDisabled) {
  626. mAuthorStyleDisabled = aStyleDisabled;
  627. BeginUpdate();
  628. mDirty |= DirtyBit(SheetType::Doc) |
  629. DirtyBit(SheetType::ScopedDoc) |
  630. DirtyBit(SheetType::StyleAttr);
  631. return EndUpdate();
  632. }
  633. return NS_OK;
  634. }
  635. // -------- Doc Sheets
  636. nsresult
  637. nsStyleSet::AddDocStyleSheet(CSSStyleSheet* aSheet, nsIDocument* aDocument)
  638. {
  639. NS_PRECONDITION(aSheet && aDocument, "null arg");
  640. NS_ASSERTION(aSheet->IsApplicable(),
  641. "Inapplicable sheet being placed in style set");
  642. SheetType type = aSheet->GetScopeElement() ?
  643. SheetType::ScopedDoc :
  644. SheetType::Doc;
  645. nsTArray<RefPtr<CSSStyleSheet>>& sheets = mSheets[type];
  646. bool present = sheets.RemoveElement(aSheet);
  647. size_t index = aDocument->FindDocStyleSheetInsertionPoint(sheets, *aSheet);
  648. sheets.InsertElementAt(index, aSheet);
  649. if (!present) {
  650. aSheet->AddStyleSet(this);
  651. }
  652. return DirtyRuleProcessors(type);
  653. }
  654. void
  655. nsStyleSet::AppendAllXBLStyleSheets(nsTArray<mozilla::CSSStyleSheet*>& aArray) const
  656. {
  657. if (mBindingManager) {
  658. // XXXheycam stylo: AppendAllSheets will need to be able to return either
  659. // CSSStyleSheets or ServoStyleSheets, on request (and then here requesting
  660. // CSSStyleSheets).
  661. AutoTArray<StyleSheet*, 32> sheets;
  662. mBindingManager->AppendAllSheets(sheets);
  663. for (StyleSheet* handle : sheets) {
  664. MOZ_ASSERT(handle->IsGecko(), "stylo: AppendAllSheets shouldn't give us "
  665. "ServoStyleSheets yet");
  666. aArray.AppendElement(handle->AsGecko());
  667. }
  668. }
  669. }
  670. nsresult
  671. nsStyleSet::RemoveDocStyleSheet(CSSStyleSheet* aSheet)
  672. {
  673. bool isScoped = aSheet->GetScopeElement();
  674. return RemoveStyleSheet(isScoped ? SheetType::ScopedDoc : SheetType::Doc,
  675. aSheet);
  676. }
  677. // Batching
  678. void
  679. nsStyleSet::BeginUpdate()
  680. {
  681. ++mBatching;
  682. }
  683. nsresult
  684. nsStyleSet::EndUpdate()
  685. {
  686. NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
  687. if (--mBatching) {
  688. // We're not completely done yet.
  689. return NS_OK;
  690. }
  691. for (SheetType type : MakeEnumeratedRange(SheetType::Count)) {
  692. if (mDirty & DirtyBit(type)) {
  693. nsresult rv = GatherRuleProcessors(type);
  694. NS_ENSURE_SUCCESS(rv, rv);
  695. }
  696. }
  697. mDirty = 0;
  698. return NS_OK;
  699. }
  700. template<class T>
  701. static bool
  702. EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
  703. {
  704. T* data = static_cast<T*>(aData);
  705. aProcessor->RulesMatching(data);
  706. return true;
  707. }
  708. static inline bool
  709. IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
  710. {
  711. return !aRuleNode->IsRoot() &&
  712. (aRuleNode->GetLevel() == SheetType::Transition ||
  713. aRuleNode->IsImportantRule());
  714. }
  715. static nsIStyleRule*
  716. GetAnimationRule(nsRuleNode *aRuleNode)
  717. {
  718. nsRuleNode *n = aRuleNode;
  719. while (IsMoreSpecificThanAnimation(n)) {
  720. n = n->GetParent();
  721. }
  722. if (n->IsRoot() || n->GetLevel() != SheetType::Animation) {
  723. return nullptr;
  724. }
  725. return n->GetRule();
  726. }
  727. static nsRuleNode*
  728. ReplaceAnimationRule(nsRuleNode *aOldRuleNode,
  729. nsIStyleRule *aOldAnimRule,
  730. nsIStyleRule *aNewAnimRule)
  731. {
  732. nsTArray<nsRuleNode*> moreSpecificNodes;
  733. nsRuleNode *n = aOldRuleNode;
  734. while (IsMoreSpecificThanAnimation(n)) {
  735. moreSpecificNodes.AppendElement(n);
  736. n = n->GetParent();
  737. }
  738. if (aOldAnimRule) {
  739. MOZ_ASSERT(n->GetRule() == aOldAnimRule, "wrong rule");
  740. MOZ_ASSERT(n->GetLevel() == SheetType::Animation,
  741. "wrong level");
  742. n = n->GetParent();
  743. }
  744. MOZ_ASSERT(!IsMoreSpecificThanAnimation(n) &&
  745. (n->IsRoot() || n->GetLevel() != SheetType::Animation),
  746. "wrong level");
  747. if (aNewAnimRule) {
  748. n = n->Transition(aNewAnimRule, SheetType::Animation, false);
  749. n->SetIsAnimationRule();
  750. }
  751. for (uint32_t i = moreSpecificNodes.Length(); i-- != 0; ) {
  752. nsRuleNode *oldNode = moreSpecificNodes[i];
  753. n = n->Transition(oldNode->GetRule(), oldNode->GetLevel(),
  754. oldNode->IsImportantRule());
  755. }
  756. return n;
  757. }
  758. /**
  759. * |GetContext| implements sharing of style contexts (not just the data
  760. * on the rule nodes) between siblings and cousins of the same
  761. * generation. (It works for cousins of the same generation since
  762. * |aParentContext| could itself be a shared context.)
  763. */
  764. already_AddRefed<nsStyleContext>
  765. nsStyleSet::GetContext(nsStyleContext* aParentContext,
  766. nsRuleNode* aRuleNode,
  767. // aVisitedRuleNode may be null; if it is null
  768. // it means that we don't need to force creation
  769. // of a StyleIfVisited. (But if we make one
  770. // because aParentContext has one, then aRuleNode
  771. // should be used.)
  772. nsRuleNode* aVisitedRuleNode,
  773. nsIAtom* aPseudoTag,
  774. CSSPseudoElementType aPseudoType,
  775. Element* aElementForAnimation,
  776. uint32_t aFlags)
  777. {
  778. NS_PRECONDITION((!aPseudoTag &&
  779. aPseudoType ==
  780. CSSPseudoElementType::NotPseudo) ||
  781. (aPseudoTag &&
  782. nsCSSPseudoElements::GetPseudoType(
  783. aPseudoTag, CSSEnabledState::eIgnoreEnabledState) ==
  784. aPseudoType),
  785. "Pseudo mismatch");
  786. if (aVisitedRuleNode == aRuleNode) {
  787. // No need to force creation of a visited style in this case.
  788. aVisitedRuleNode = nullptr;
  789. }
  790. // Ensure |aVisitedRuleNode != nullptr| corresponds to the need to
  791. // create an if-visited style context, and that in that case, we have
  792. // parentIfVisited set correctly.
  793. nsStyleContext *parentIfVisited =
  794. aParentContext ? aParentContext->GetStyleIfVisited() : nullptr;
  795. if (parentIfVisited) {
  796. if (!aVisitedRuleNode) {
  797. aVisitedRuleNode = aRuleNode;
  798. }
  799. } else {
  800. if (aVisitedRuleNode) {
  801. parentIfVisited = aParentContext;
  802. }
  803. }
  804. if (aFlags & eIsLink) {
  805. // If this node is a link, we want its visited's style context's
  806. // parent to be the regular style context of its parent, because
  807. // only the visitedness of the relevant link should influence style.
  808. parentIfVisited = aParentContext;
  809. }
  810. bool relevantLinkVisited = (aFlags & eIsLink) ?
  811. (aFlags & eIsVisitedLink) :
  812. (aParentContext && aParentContext->RelevantLinkVisited());
  813. RefPtr<nsStyleContext> result;
  814. if (aParentContext)
  815. result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
  816. aVisitedRuleNode,
  817. relevantLinkVisited);
  818. if (!result) {
  819. // |aVisitedRuleNode| may have a ref-count of zero since we are yet
  820. // to create the style context that will hold an owning reference to it.
  821. // As a result, we need to make sure it stays alive until that point
  822. // in case something in the first call to NS_NewStyleContext triggers a
  823. // GC sweep of rule nodes.
  824. RefPtr<nsRuleNode> kungFuDeathGrip{aVisitedRuleNode};
  825. result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
  826. aRuleNode,
  827. aFlags & eSkipParentDisplayBasedStyleFixup);
  828. if (aVisitedRuleNode) {
  829. RefPtr<nsStyleContext> resultIfVisited =
  830. NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
  831. aVisitedRuleNode,
  832. aFlags & eSkipParentDisplayBasedStyleFixup);
  833. resultIfVisited->SetIsStyleIfVisited();
  834. result->SetStyleIfVisited(resultIfVisited.forget());
  835. if (relevantLinkVisited) {
  836. result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
  837. }
  838. }
  839. }
  840. else {
  841. NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
  842. NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
  843. }
  844. if (aFlags & eDoAnimation) {
  845. nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
  846. nsIStyleRule *animRule = nullptr;
  847. // Ignore animations for print or print preview, and for elements
  848. // that are not attached to the document tree.
  849. if (PresContext()->IsDynamic() &&
  850. aElementForAnimation->IsInComposedDoc()) {
  851. // Update CSS animations in case the animation-name has just changed.
  852. PresContext()->AnimationManager()->UpdateAnimations(result,
  853. aElementForAnimation);
  854. PresContext()->EffectCompositor()->UpdateEffectProperties(
  855. result, aElementForAnimation, result->GetPseudoType());
  856. animRule = PresContext()->EffectCompositor()->
  857. GetAnimationRule(aElementForAnimation,
  858. result->GetPseudoType(),
  859. EffectCompositor::CascadeLevel::Animations,
  860. result);
  861. }
  862. MOZ_ASSERT(result->RuleNode() == aRuleNode,
  863. "unexpected rule node");
  864. MOZ_ASSERT(!result->GetStyleIfVisited() == !aVisitedRuleNode,
  865. "unexpected visited rule node");
  866. MOZ_ASSERT(!aVisitedRuleNode ||
  867. result->GetStyleIfVisited()->RuleNode() == aVisitedRuleNode,
  868. "unexpected visited rule node");
  869. MOZ_ASSERT(!aVisitedRuleNode ||
  870. oldAnimRule == GetAnimationRule(aVisitedRuleNode),
  871. "animation rule mismatch between rule nodes");
  872. if (oldAnimRule != animRule) {
  873. nsRuleNode *ruleNode =
  874. ReplaceAnimationRule(aRuleNode, oldAnimRule, animRule);
  875. nsRuleNode *visitedRuleNode = aVisitedRuleNode
  876. ? ReplaceAnimationRule(aVisitedRuleNode, oldAnimRule, animRule)
  877. : nullptr;
  878. MOZ_ASSERT(!visitedRuleNode ||
  879. GetAnimationRule(ruleNode) ==
  880. GetAnimationRule(visitedRuleNode),
  881. "animation rule mismatch between rule nodes");
  882. result = GetContext(aParentContext, ruleNode, visitedRuleNode,
  883. aPseudoTag, aPseudoType, nullptr,
  884. aFlags & ~eDoAnimation);
  885. }
  886. }
  887. if (aElementForAnimation &&
  888. aElementForAnimation->IsHTMLElement(nsGkAtoms::body) &&
  889. aPseudoType == CSSPseudoElementType::NotPseudo &&
  890. PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
  891. nsIDocument* doc = aElementForAnimation->GetUncomposedDoc();
  892. if (doc && doc->GetBodyElement() == aElementForAnimation) {
  893. // Update the prescontext's body color
  894. PresContext()->SetBodyTextColor(result->StyleColor()->mColor);
  895. }
  896. }
  897. return result.forget();
  898. }
  899. void
  900. nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
  901. nsRuleNode* aLastPrevLevelNode,
  902. nsRuleWalker* aRuleWalker)
  903. {
  904. NS_ASSERTION(aCurrLevelNode &&
  905. aCurrLevelNode != aLastPrevLevelNode, "How did we get here?");
  906. AutoTArray<nsIStyleRule*, 16> importantRules;
  907. for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
  908. node = node->GetParent()) {
  909. // We guarantee that we never walk the root node here, so no need
  910. // to null-check GetRule(). Furthermore, it must be a CSS rule.
  911. NS_ASSERTION(RefPtr<css::Declaration>(do_QueryObject(node->GetRule())),
  912. "Unexpected non-CSS rule");
  913. nsIStyleRule* impRule =
  914. static_cast<css::Declaration*>(node->GetRule())->GetImportantStyleData();
  915. if (impRule)
  916. importantRules.AppendElement(impRule);
  917. }
  918. NS_ASSERTION(importantRules.Length() != 0,
  919. "Why did we think there were important rules?");
  920. for (uint32_t i = importantRules.Length(); i-- != 0; ) {
  921. aRuleWalker->Forward(importantRules[i]);
  922. }
  923. }
  924. #ifdef DEBUG
  925. void
  926. nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
  927. nsRuleNode* aLastPrevLevelNode)
  928. {
  929. if (!aCurrLevelNode)
  930. return;
  931. for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
  932. node = node->GetParent()) {
  933. RefPtr<css::Declaration> declaration(do_QueryObject(node->GetRule()));
  934. NS_ASSERTION(declaration, "Unexpected non-CSS rule");
  935. NS_ASSERTION(!declaration->GetImportantStyleData(),
  936. "Unexpected important style source");
  937. }
  938. }
  939. void
  940. nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
  941. nsRuleNode* aLastPrevLevelNode)
  942. {
  943. if (!aCurrLevelNode)
  944. return;
  945. for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
  946. node = node->GetParent()) {
  947. nsIStyleRule *rule = node->GetRule();
  948. RefPtr<css::Declaration> declaration(do_QueryObject(rule));
  949. if (declaration) {
  950. RefPtr<css::StyleRule> cssRule =
  951. do_QueryObject(declaration->GetOwningRule());
  952. NS_ASSERTION(!cssRule || !cssRule->Selector(),
  953. "Unexpected CSS rule");
  954. }
  955. }
  956. }
  957. #endif
  958. // Enumerate the rules in a way that cares about the order of the rules.
  959. void
  960. nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
  961. RuleProcessorData* aData, Element* aElement,
  962. nsRuleWalker* aRuleWalker)
  963. {
  964. PROFILER_LABEL("nsStyleSet", "FileRules",
  965. js::ProfileEntry::Category::CSS);
  966. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  967. // Cascading order:
  968. // [least important]
  969. // - UA normal rules = Agent normal
  970. // - User normal rules = User normal
  971. // - Presentation hints = PresHint normal
  972. // - SVG Animation (highest pres hint) = SVGAttrAnimation normal
  973. // - Author normal rules = Document normal
  974. // - Override normal rules = Override normal
  975. // - animation rules = Animation normal
  976. // - Author !important rules = Document !important
  977. // - Override !important rules = Override !important
  978. // - User !important rules = User !important
  979. // - UA !important rules = Agent !important
  980. // - transition rules = Transition normal
  981. // [most important]
  982. // Save off the last rule before we start walking our agent sheets;
  983. // this will be either the root or one of the restriction rules.
  984. nsRuleNode* lastRestrictionRN = aRuleWalker->CurrentNode();
  985. aRuleWalker->SetLevel(SheetType::Agent, false, true);
  986. if (mRuleProcessors[SheetType::Agent])
  987. (*aCollectorFunc)(mRuleProcessors[SheetType::Agent], aData);
  988. nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
  989. bool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
  990. aRuleWalker->SetLevel(SheetType::User, false, true);
  991. bool skipUserStyles =
  992. aElement && aElement->IsInNativeAnonymousSubtree();
  993. if (!skipUserStyles && mRuleProcessors[SheetType::User]) // NOTE: different
  994. (*aCollectorFunc)(mRuleProcessors[SheetType::User], aData);
  995. nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
  996. bool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
  997. aRuleWalker->SetLevel(SheetType::PresHint, false, false);
  998. if (mRuleProcessors[SheetType::PresHint])
  999. (*aCollectorFunc)(mRuleProcessors[SheetType::PresHint], aData);
  1000. aRuleWalker->SetLevel(SheetType::SVGAttrAnimation, false, false);
  1001. if (mRuleProcessors[SheetType::SVGAttrAnimation])
  1002. (*aCollectorFunc)(mRuleProcessors[SheetType::SVGAttrAnimation], aData);
  1003. nsRuleNode* lastSVGAttrAnimationRN = aRuleWalker->CurrentNode();
  1004. aRuleWalker->SetLevel(SheetType::Doc, false, true);
  1005. bool cutOffInheritance = false;
  1006. if (mBindingManager && aElement) {
  1007. // We can supply additional document-level sheets that should be walked.
  1008. mBindingManager->WalkRules(aCollectorFunc,
  1009. static_cast<ElementDependentRuleProcessorData*>(aData),
  1010. &cutOffInheritance);
  1011. }
  1012. if (!skipUserStyles && !cutOffInheritance && // NOTE: different
  1013. mRuleProcessors[SheetType::Doc])
  1014. (*aCollectorFunc)(mRuleProcessors[SheetType::Doc], aData);
  1015. nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
  1016. bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
  1017. nsTArray<nsRuleNode*> lastScopedRNs;
  1018. nsTArray<bool> haveImportantScopedRules;
  1019. bool haveAnyImportantScopedRules = false;
  1020. if (!skipUserStyles && !cutOffInheritance &&
  1021. aElement && aElement->IsElementInStyleScope()) {
  1022. lastScopedRNs.SetLength(mScopedDocSheetRuleProcessors.Length());
  1023. haveImportantScopedRules.SetLength(mScopedDocSheetRuleProcessors.Length());
  1024. for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
  1025. aRuleWalker->SetLevel(SheetType::ScopedDoc, false, true);
  1026. nsCSSRuleProcessor* processor =
  1027. static_cast<nsCSSRuleProcessor*>(mScopedDocSheetRuleProcessors[i].get());
  1028. aData->mScope = processor->GetScopeElement();
  1029. (*aCollectorFunc)(mScopedDocSheetRuleProcessors[i], aData);
  1030. lastScopedRNs[i] = aRuleWalker->CurrentNode();
  1031. haveImportantScopedRules[i] = !aRuleWalker->GetCheckForImportantRules();
  1032. haveAnyImportantScopedRules = haveAnyImportantScopedRules || haveImportantScopedRules[i];
  1033. }
  1034. aData->mScope = nullptr;
  1035. }
  1036. nsRuleNode* lastScopedRN = aRuleWalker->CurrentNode();
  1037. aRuleWalker->SetLevel(SheetType::StyleAttr, false, true);
  1038. if (mRuleProcessors[SheetType::StyleAttr])
  1039. (*aCollectorFunc)(mRuleProcessors[SheetType::StyleAttr], aData);
  1040. nsRuleNode* lastStyleAttrRN = aRuleWalker->CurrentNode();
  1041. bool haveImportantStyleAttrRules = !aRuleWalker->GetCheckForImportantRules();
  1042. aRuleWalker->SetLevel(SheetType::Override, false, true);
  1043. if (mRuleProcessors[SheetType::Override])
  1044. (*aCollectorFunc)(mRuleProcessors[SheetType::Override], aData);
  1045. nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
  1046. bool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
  1047. // This needs to match IsMoreSpecificThanAnimation() above.
  1048. aRuleWalker->SetLevel(SheetType::Animation, false, false);
  1049. (*aCollectorFunc)(mRuleProcessors[SheetType::Animation], aData);
  1050. if (haveAnyImportantScopedRules) {
  1051. for (uint32_t i = lastScopedRNs.Length(); i-- != 0; ) {
  1052. aRuleWalker->SetLevel(SheetType::ScopedDoc, true, false);
  1053. nsRuleNode* startRN = lastScopedRNs[i];
  1054. nsRuleNode* endRN = i == 0 ? lastDocRN : lastScopedRNs[i - 1];
  1055. if (haveImportantScopedRules[i]) {
  1056. AddImportantRules(startRN, endRN, aRuleWalker); // scoped
  1057. }
  1058. #ifdef DEBUG
  1059. else {
  1060. AssertNoImportantRules(startRN, endRN);
  1061. }
  1062. #endif
  1063. }
  1064. }
  1065. #ifdef DEBUG
  1066. else {
  1067. AssertNoImportantRules(lastScopedRN, lastDocRN);
  1068. }
  1069. #endif
  1070. if (haveImportantDocRules) {
  1071. aRuleWalker->SetLevel(SheetType::Doc, true, false);
  1072. AddImportantRules(lastDocRN, lastSVGAttrAnimationRN, aRuleWalker); // doc
  1073. }
  1074. #ifdef DEBUG
  1075. else {
  1076. AssertNoImportantRules(lastDocRN, lastSVGAttrAnimationRN);
  1077. }
  1078. #endif
  1079. if (haveImportantStyleAttrRules) {
  1080. aRuleWalker->SetLevel(SheetType::StyleAttr, true, false);
  1081. AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker); // style attr
  1082. }
  1083. #ifdef DEBUG
  1084. else {
  1085. AssertNoImportantRules(lastStyleAttrRN, lastScopedRN);
  1086. }
  1087. #endif
  1088. if (haveImportantOverrideRules) {
  1089. aRuleWalker->SetLevel(SheetType::Override, true, false);
  1090. AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker); // override
  1091. }
  1092. #ifdef DEBUG
  1093. else {
  1094. AssertNoImportantRules(lastOvrRN, lastStyleAttrRN);
  1095. }
  1096. #endif
  1097. #ifdef DEBUG
  1098. AssertNoCSSRules(lastSVGAttrAnimationRN, lastUserRN);
  1099. #endif
  1100. if (haveImportantUserRules) {
  1101. aRuleWalker->SetLevel(SheetType::User, true, false);
  1102. AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
  1103. }
  1104. #ifdef DEBUG
  1105. else {
  1106. AssertNoImportantRules(lastUserRN, lastAgentRN);
  1107. }
  1108. #endif
  1109. if (haveImportantUARules) {
  1110. aRuleWalker->SetLevel(SheetType::Agent, true, false);
  1111. AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
  1112. }
  1113. #ifdef DEBUG
  1114. else {
  1115. AssertNoImportantRules(lastAgentRN, lastRestrictionRN);
  1116. }
  1117. #endif
  1118. #ifdef DEBUG
  1119. AssertNoCSSRules(lastRestrictionRN, mRuleTree);
  1120. #endif
  1121. #ifdef DEBUG
  1122. nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
  1123. #endif
  1124. aRuleWalker->SetLevel(SheetType::Transition, false, false);
  1125. (*aCollectorFunc)(mRuleProcessors[SheetType::Transition], aData);
  1126. #ifdef DEBUG
  1127. AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
  1128. #endif
  1129. }
  1130. // Enumerate all the rules in a way that doesn't care about the order
  1131. // of the rules and doesn't walk !important-rules.
  1132. void
  1133. nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
  1134. ElementDependentRuleProcessorData* aData,
  1135. bool aWalkAllXBLStylesheets)
  1136. {
  1137. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  1138. if (mRuleProcessors[SheetType::Agent])
  1139. (*aFunc)(mRuleProcessors[SheetType::Agent], aData);
  1140. bool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
  1141. if (!skipUserStyles && mRuleProcessors[SheetType::User]) // NOTE: different
  1142. (*aFunc)(mRuleProcessors[SheetType::User], aData);
  1143. if (mRuleProcessors[SheetType::PresHint])
  1144. (*aFunc)(mRuleProcessors[SheetType::PresHint], aData);
  1145. if (mRuleProcessors[SheetType::SVGAttrAnimation])
  1146. (*aFunc)(mRuleProcessors[SheetType::SVGAttrAnimation], aData);
  1147. bool cutOffInheritance = false;
  1148. if (mBindingManager) {
  1149. // We can supply additional document-level sheets that should be walked.
  1150. if (aWalkAllXBLStylesheets) {
  1151. mBindingManager->WalkAllRules(aFunc, aData);
  1152. } else {
  1153. mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
  1154. }
  1155. }
  1156. if (!skipUserStyles && !cutOffInheritance) {
  1157. if (mRuleProcessors[SheetType::Doc]) // NOTE: different
  1158. (*aFunc)(mRuleProcessors[SheetType::Doc], aData);
  1159. if (aData->mElement->IsElementInStyleScope()) {
  1160. for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++)
  1161. (*aFunc)(mScopedDocSheetRuleProcessors[i], aData);
  1162. }
  1163. }
  1164. if (mRuleProcessors[SheetType::StyleAttr])
  1165. (*aFunc)(mRuleProcessors[SheetType::StyleAttr], aData);
  1166. if (mRuleProcessors[SheetType::Override])
  1167. (*aFunc)(mRuleProcessors[SheetType::Override], aData);
  1168. (*aFunc)(mRuleProcessors[SheetType::Animation], aData);
  1169. (*aFunc)(mRuleProcessors[SheetType::Transition], aData);
  1170. }
  1171. static void
  1172. InitStyleScopes(TreeMatchContext& aTreeContext, Element* aElement)
  1173. {
  1174. if (aElement->IsElementInStyleScope()) {
  1175. aTreeContext.InitStyleScopes(aElement->GetParentElementCrossingShadowRoot());
  1176. }
  1177. }
  1178. already_AddRefed<nsStyleContext>
  1179. nsStyleSet::ResolveStyleFor(Element* aElement,
  1180. nsStyleContext* aParentContext)
  1181. {
  1182. TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
  1183. aElement->OwnerDoc());
  1184. InitStyleScopes(treeContext, aElement);
  1185. return ResolveStyleFor(aElement, aParentContext, treeContext);
  1186. }
  1187. already_AddRefed<nsStyleContext>
  1188. nsStyleSet::ResolveStyleFor(Element* aElement,
  1189. nsStyleContext* aParentContext,
  1190. TreeMatchContext& aTreeMatchContext)
  1191. {
  1192. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1193. NS_ASSERTION(aElement, "aElement must not be null");
  1194. nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1195. aTreeMatchContext.ResetForUnvisitedMatching();
  1196. ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker,
  1197. aTreeMatchContext);
  1198. WalkDisableTextZoomRule(aElement, &ruleWalker);
  1199. FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
  1200. &ruleWalker);
  1201. nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1202. nsRuleNode *visitedRuleNode = nullptr;
  1203. if (aTreeMatchContext.HaveRelevantLink()) {
  1204. aTreeMatchContext.ResetForVisitedMatching();
  1205. ruleWalker.Reset();
  1206. FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
  1207. &ruleWalker);
  1208. visitedRuleNode = ruleWalker.CurrentNode();
  1209. }
  1210. uint32_t flags = eDoAnimation;
  1211. if (nsCSSRuleProcessor::IsLink(aElement)) {
  1212. flags |= eIsLink;
  1213. }
  1214. if (nsCSSRuleProcessor::GetContentState(aElement, aTreeMatchContext).
  1215. HasState(NS_EVENT_STATE_VISITED)) {
  1216. flags |= eIsVisitedLink;
  1217. }
  1218. if (aTreeMatchContext.mSkippingParentDisplayBasedStyleFixup) {
  1219. flags |= eSkipParentDisplayBasedStyleFixup;
  1220. }
  1221. return GetContext(aParentContext, ruleNode, visitedRuleNode,
  1222. nullptr, CSSPseudoElementType::NotPseudo,
  1223. aElement, flags);
  1224. }
  1225. already_AddRefed<nsStyleContext>
  1226. nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
  1227. const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules)
  1228. {
  1229. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1230. nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1231. // FIXME: Perhaps this should be passed in, but it probably doesn't
  1232. // matter.
  1233. ruleWalker.SetLevel(SheetType::Doc, false, false);
  1234. for (uint32_t i = 0; i < aRules.Length(); i++) {
  1235. ruleWalker.ForwardOnPossiblyCSSRule(aRules.ElementAt(i));
  1236. }
  1237. return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
  1238. nullptr, CSSPseudoElementType::NotPseudo,
  1239. nullptr, eNoFlags);
  1240. }
  1241. already_AddRefed<nsStyleContext>
  1242. nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
  1243. const nsCOMArray<nsIStyleRule> &aRules)
  1244. {
  1245. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1246. nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1247. ruleWalker.SetCurrentNode(aBaseContext->RuleNode());
  1248. // This needs to be the transition sheet because that is the highest
  1249. // level of the cascade, and thus the only thing that makes sense if
  1250. // we are ever going to call ResolveStyleWithReplacement on the
  1251. // resulting context. It's also the right thing for the one case (the
  1252. // transition manager's cover rule) where we put the result of this
  1253. // function in the style context tree.
  1254. ruleWalker.SetLevel(SheetType::Transition, false, false);
  1255. for (int32_t i = 0; i < aRules.Count(); i++) {
  1256. ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
  1257. }
  1258. nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1259. nsRuleNode *visitedRuleNode = nullptr;
  1260. if (aBaseContext->GetStyleIfVisited()) {
  1261. ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->RuleNode());
  1262. for (int32_t i = 0; i < aRules.Count(); i++) {
  1263. ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
  1264. }
  1265. visitedRuleNode = ruleWalker.CurrentNode();
  1266. }
  1267. uint32_t flags = eNoFlags;
  1268. if (aBaseContext->IsLinkContext()) {
  1269. flags |= eIsLink;
  1270. // GetContext handles propagating RelevantLinkVisited state from the
  1271. // parent in non-link cases; all we need to pass in is if this link
  1272. // is visited.
  1273. if (aBaseContext->RelevantLinkVisited()) {
  1274. flags |= eIsVisitedLink;
  1275. }
  1276. }
  1277. return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
  1278. aBaseContext->GetPseudo(),
  1279. aBaseContext->GetPseudoType(),
  1280. nullptr, flags);
  1281. }
  1282. struct RuleNodeInfo {
  1283. nsIStyleRule* mRule;
  1284. SheetType mLevel;
  1285. bool mIsImportant;
  1286. bool mIsAnimationRule;
  1287. };
  1288. struct CascadeLevel {
  1289. SheetType mLevel;
  1290. bool mIsImportant;
  1291. bool mCheckForImportantRules;
  1292. nsRestyleHint mLevelReplacementHint;
  1293. };
  1294. static const CascadeLevel gCascadeLevels[] = {
  1295. { SheetType::Agent, false, false, nsRestyleHint(0) },
  1296. { SheetType::User, false, false, nsRestyleHint(0) },
  1297. { SheetType::PresHint, false, false, nsRestyleHint(0) },
  1298. { SheetType::SVGAttrAnimation, false, false, eRestyle_SVGAttrAnimations },
  1299. { SheetType::Doc, false, false, nsRestyleHint(0) },
  1300. { SheetType::ScopedDoc, false, false, nsRestyleHint(0) },
  1301. { SheetType::StyleAttr, false, true, eRestyle_StyleAttribute |
  1302. eRestyle_StyleAttribute_Animations },
  1303. { SheetType::Override, false, false, nsRestyleHint(0) },
  1304. { SheetType::Animation, false, false, eRestyle_CSSAnimations },
  1305. { SheetType::ScopedDoc, true, false, nsRestyleHint(0) },
  1306. { SheetType::Doc, true, false, nsRestyleHint(0) },
  1307. { SheetType::StyleAttr, true, false, eRestyle_StyleAttribute |
  1308. eRestyle_StyleAttribute_Animations },
  1309. { SheetType::Override, true, false, nsRestyleHint(0) },
  1310. { SheetType::User, true, false, nsRestyleHint(0) },
  1311. { SheetType::Agent, true, false, nsRestyleHint(0) },
  1312. { SheetType::Transition, false, false, eRestyle_CSSTransitions },
  1313. };
  1314. nsRuleNode*
  1315. nsStyleSet::RuleNodeWithReplacement(Element* aElement,
  1316. Element* aPseudoElement,
  1317. nsRuleNode* aOldRuleNode,
  1318. CSSPseudoElementType aPseudoType,
  1319. nsRestyleHint aReplacements)
  1320. {
  1321. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  1322. MOZ_ASSERT(!aPseudoElement ==
  1323. (aPseudoType >= CSSPseudoElementType::Count ||
  1324. !(nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(aPseudoType) ||
  1325. nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudoType))),
  1326. "should have aPseudoElement only for certain pseudo elements");
  1327. MOZ_ASSERT(!(aReplacements & ~(eRestyle_CSSTransitions |
  1328. eRestyle_CSSAnimations |
  1329. eRestyle_SVGAttrAnimations |
  1330. eRestyle_StyleAttribute |
  1331. eRestyle_StyleAttribute_Animations |
  1332. eRestyle_Force |
  1333. eRestyle_ForceDescendants)),
  1334. "unexpected replacement bits");
  1335. // FIXME (perf): This should probably not rebuild the whole path, but
  1336. // only the path from the last change in the rule tree, like
  1337. // ReplaceAnimationRule in nsStyleSet.cpp does. (That could then
  1338. // perhaps share this code, too?)
  1339. // But if we do that, we'll need to pass whether we are rebuilding the
  1340. // rule tree from ElementRestyler::RestyleSelf to avoid taking that
  1341. // path when we're rebuilding the rule tree.
  1342. // This array can be hot and often grows to ~20 elements, so inline storage
  1343. // is best.
  1344. AutoTArray<RuleNodeInfo, 30> rules;
  1345. for (nsRuleNode* ruleNode = aOldRuleNode; !ruleNode->IsRoot();
  1346. ruleNode = ruleNode->GetParent()) {
  1347. RuleNodeInfo* curRule = rules.AppendElement();
  1348. curRule->mRule = ruleNode->GetRule();
  1349. curRule->mLevel = ruleNode->GetLevel();
  1350. curRule->mIsImportant = ruleNode->IsImportantRule();
  1351. curRule->mIsAnimationRule = ruleNode->IsAnimationRule();
  1352. }
  1353. nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1354. auto rulesIndex = rules.Length();
  1355. // We need to transfer this information between the non-!important and
  1356. // !important phases for the style attribute level.
  1357. nsRuleNode* lastScopedRN = nullptr;
  1358. nsRuleNode* lastStyleAttrRN = nullptr;
  1359. bool haveImportantStyleAttrRules = false;
  1360. for (const CascadeLevel *level = gCascadeLevels,
  1361. *levelEnd = ArrayEnd(gCascadeLevels);
  1362. level != levelEnd; ++level) {
  1363. bool doReplace = level->mLevelReplacementHint & aReplacements;
  1364. ruleWalker.SetLevel(level->mLevel, level->mIsImportant,
  1365. level->mCheckForImportantRules && doReplace);
  1366. if (doReplace) {
  1367. switch (level->mLevel) {
  1368. case SheetType::Animation: {
  1369. if (aPseudoType == CSSPseudoElementType::NotPseudo ||
  1370. aPseudoType == CSSPseudoElementType::before ||
  1371. aPseudoType == CSSPseudoElementType::after) {
  1372. nsIStyleRule* rule = PresContext()->EffectCompositor()->
  1373. GetAnimationRule(aElement, aPseudoType,
  1374. EffectCompositor::CascadeLevel::Animations,
  1375. nullptr);
  1376. if (rule) {
  1377. ruleWalker.ForwardOnPossiblyCSSRule(rule);
  1378. ruleWalker.CurrentNode()->SetIsAnimationRule();
  1379. }
  1380. }
  1381. break;
  1382. }
  1383. case SheetType::Transition: {
  1384. if (aPseudoType == CSSPseudoElementType::NotPseudo ||
  1385. aPseudoType == CSSPseudoElementType::before ||
  1386. aPseudoType == CSSPseudoElementType::after) {
  1387. nsIStyleRule* rule = PresContext()->EffectCompositor()->
  1388. GetAnimationRule(aElement, aPseudoType,
  1389. EffectCompositor::CascadeLevel::Transitions,
  1390. nullptr);
  1391. if (rule) {
  1392. ruleWalker.ForwardOnPossiblyCSSRule(rule);
  1393. ruleWalker.CurrentNode()->SetIsAnimationRule();
  1394. }
  1395. }
  1396. break;
  1397. }
  1398. case SheetType::SVGAttrAnimation: {
  1399. SVGAttrAnimationRuleProcessor* ruleProcessor =
  1400. static_cast<SVGAttrAnimationRuleProcessor*>(
  1401. mRuleProcessors[SheetType::SVGAttrAnimation].get());
  1402. if (ruleProcessor &&
  1403. aPseudoType == CSSPseudoElementType::NotPseudo) {
  1404. ruleProcessor->ElementRulesMatching(aElement, &ruleWalker);
  1405. }
  1406. break;
  1407. }
  1408. case SheetType::StyleAttr: {
  1409. if (!level->mIsImportant) {
  1410. // First time through, we handle the non-!important rule.
  1411. nsHTMLCSSStyleSheet* ruleProcessor =
  1412. static_cast<nsHTMLCSSStyleSheet*>(
  1413. mRuleProcessors[SheetType::StyleAttr].get());
  1414. if (ruleProcessor) {
  1415. lastScopedRN = ruleWalker.CurrentNode();
  1416. if (aPseudoType ==
  1417. CSSPseudoElementType::NotPseudo) {
  1418. ruleProcessor->ElementRulesMatching(PresContext(),
  1419. aElement,
  1420. &ruleWalker);
  1421. } else if (aPseudoType <
  1422. CSSPseudoElementType::Count &&
  1423. nsCSSPseudoElements::
  1424. PseudoElementSupportsStyleAttribute(aPseudoType)) {
  1425. ruleProcessor->PseudoElementRulesMatching(aPseudoElement,
  1426. aPseudoType,
  1427. &ruleWalker);
  1428. }
  1429. lastStyleAttrRN = ruleWalker.CurrentNode();
  1430. haveImportantStyleAttrRules =
  1431. !ruleWalker.GetCheckForImportantRules();
  1432. }
  1433. } else {
  1434. // Second time through, we handle the !important rule(s).
  1435. if (haveImportantStyleAttrRules) {
  1436. AddImportantRules(lastStyleAttrRN, lastScopedRN, &ruleWalker);
  1437. }
  1438. }
  1439. break;
  1440. }
  1441. default:
  1442. MOZ_ASSERT(false, "unexpected result from gCascadeLevels lookup");
  1443. break;
  1444. }
  1445. }
  1446. while (rulesIndex != 0) {
  1447. --rulesIndex;
  1448. const RuleNodeInfo& ruleInfo = rules[rulesIndex];
  1449. if (ruleInfo.mLevel != level->mLevel ||
  1450. ruleInfo.mIsImportant != level->mIsImportant) {
  1451. ++rulesIndex;
  1452. break;
  1453. }
  1454. if (!doReplace) {
  1455. ruleWalker.ForwardOnPossiblyCSSRule(ruleInfo.mRule);
  1456. if (ruleInfo.mIsAnimationRule) {
  1457. ruleWalker.CurrentNode()->SetIsAnimationRule();
  1458. }
  1459. }
  1460. }
  1461. }
  1462. NS_ASSERTION(rulesIndex == 0,
  1463. "rules are in incorrect cascading order, "
  1464. "which means we replaced them incorrectly");
  1465. return ruleWalker.CurrentNode();
  1466. }
  1467. already_AddRefed<nsStyleContext>
  1468. nsStyleSet::ResolveStyleWithReplacement(Element* aElement,
  1469. Element* aPseudoElement,
  1470. nsStyleContext* aNewParentContext,
  1471. nsStyleContext* aOldStyleContext,
  1472. nsRestyleHint aReplacements,
  1473. uint32_t aFlags)
  1474. {
  1475. nsRuleNode* ruleNode =
  1476. RuleNodeWithReplacement(aElement, aPseudoElement,
  1477. aOldStyleContext->RuleNode(),
  1478. aOldStyleContext->GetPseudoType(), aReplacements);
  1479. nsRuleNode* visitedRuleNode = nullptr;
  1480. nsStyleContext* oldStyleIfVisited = aOldStyleContext->GetStyleIfVisited();
  1481. if (oldStyleIfVisited) {
  1482. if (oldStyleIfVisited->RuleNode() == aOldStyleContext->RuleNode()) {
  1483. visitedRuleNode = ruleNode;
  1484. } else {
  1485. visitedRuleNode =
  1486. RuleNodeWithReplacement(aElement, aPseudoElement,
  1487. oldStyleIfVisited->RuleNode(),
  1488. oldStyleIfVisited->GetPseudoType(),
  1489. aReplacements);
  1490. }
  1491. }
  1492. uint32_t flags = eNoFlags;
  1493. if (aOldStyleContext->IsLinkContext()) {
  1494. flags |= eIsLink;
  1495. // GetContext handles propagating RelevantLinkVisited state from the
  1496. // parent in non-link cases; all we need to pass in is if this link
  1497. // is visited.
  1498. if (aOldStyleContext->RelevantLinkVisited()) {
  1499. flags |= eIsVisitedLink;
  1500. }
  1501. }
  1502. CSSPseudoElementType pseudoType = aOldStyleContext->GetPseudoType();
  1503. Element* elementForAnimation = nullptr;
  1504. if (!(aFlags & eSkipStartingAnimations) &&
  1505. (pseudoType == CSSPseudoElementType::NotPseudo ||
  1506. pseudoType == CSSPseudoElementType::before ||
  1507. pseudoType == CSSPseudoElementType::after)) {
  1508. // We want to compute a correct elementForAnimation to pass in
  1509. // because at this point the parameter is more than just the element
  1510. // for animation; it's also used for the SetBodyTextColor call when
  1511. // it's the body element.
  1512. // However, we only want to set the flag to call CheckAnimationRule
  1513. // if we're dealing with a replacement (such as style attribute
  1514. // replacement) that could lead to the animation property changing,
  1515. // and we explicitly do NOT want to call CheckAnimationRule when
  1516. // we're trying to do an animation-only update.
  1517. if (aReplacements & ~(eRestyle_CSSTransitions | eRestyle_CSSAnimations)) {
  1518. flags |= eDoAnimation;
  1519. }
  1520. elementForAnimation = aElement;
  1521. #ifdef DEBUG
  1522. {
  1523. nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(elementForAnimation);
  1524. NS_ASSERTION(pseudoType == CSSPseudoElementType::NotPseudo ||
  1525. !styleFrame ||
  1526. styleFrame->StyleContext()->GetPseudoType() ==
  1527. CSSPseudoElementType::NotPseudo,
  1528. "aElement should be the element and not the pseudo-element");
  1529. }
  1530. #endif
  1531. }
  1532. if (aElement && aElement->IsRootOfAnonymousSubtree()) {
  1533. // For anonymous subtree roots, don't tweak "display" value based on whether
  1534. // or not the parent is styled as a flex/grid container. (If the parent
  1535. // has anonymous-subtree kids, then we know it's not actually going to get
  1536. // a flex/grid container frame, anyway.)
  1537. flags |= eSkipParentDisplayBasedStyleFixup;
  1538. }
  1539. return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
  1540. aOldStyleContext->GetPseudo(), pseudoType,
  1541. elementForAnimation, flags);
  1542. }
  1543. already_AddRefed<nsStyleContext>
  1544. nsStyleSet::ResolveStyleWithoutAnimation(dom::Element* aTarget,
  1545. nsStyleContext* aStyleContext,
  1546. nsRestyleHint aWhichToRemove)
  1547. {
  1548. #ifdef DEBUG
  1549. CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
  1550. #endif
  1551. MOZ_ASSERT(pseudoType == CSSPseudoElementType::NotPseudo ||
  1552. pseudoType == CSSPseudoElementType::before ||
  1553. pseudoType == CSSPseudoElementType::after,
  1554. "unexpected type for animations");
  1555. MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
  1556. "stylo: the style set and restyle manager must have the same "
  1557. "StyleBackendType");
  1558. RestyleManager* restyleManager = PresContext()->RestyleManager()->AsGecko();
  1559. bool oldSkipAnimationRules = restyleManager->SkipAnimationRules();
  1560. restyleManager->SetSkipAnimationRules(true);
  1561. RefPtr<nsStyleContext> result =
  1562. ResolveStyleWithReplacement(aTarget, nullptr, aStyleContext->GetParent(),
  1563. aStyleContext, aWhichToRemove,
  1564. eSkipStartingAnimations);
  1565. restyleManager->SetSkipAnimationRules(oldSkipAnimationRules);
  1566. return result.forget();
  1567. }
  1568. already_AddRefed<nsStyleContext>
  1569. nsStyleSet::ResolveStyleForText(nsIContent* aTextNode,
  1570. nsStyleContext* aParentContext)
  1571. {
  1572. MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
  1573. return GetContext(aParentContext, mRuleTree, nullptr,
  1574. nsCSSAnonBoxes::mozText,
  1575. CSSPseudoElementType::AnonBox, nullptr, eNoFlags);
  1576. }
  1577. already_AddRefed<nsStyleContext>
  1578. nsStyleSet::ResolveStyleForOtherNonElement(nsStyleContext* aParentContext)
  1579. {
  1580. return GetContext(aParentContext, mRuleTree, nullptr,
  1581. nsCSSAnonBoxes::mozOtherNonElement,
  1582. CSSPseudoElementType::AnonBox, nullptr, eNoFlags);
  1583. }
  1584. void
  1585. nsStyleSet::WalkRestrictionRule(CSSPseudoElementType aPseudoType,
  1586. nsRuleWalker* aRuleWalker)
  1587. {
  1588. // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
  1589. aRuleWalker->SetLevel(SheetType::Agent, false, false);
  1590. if (aPseudoType == CSSPseudoElementType::firstLetter)
  1591. aRuleWalker->Forward(mFirstLetterRule);
  1592. else if (aPseudoType == CSSPseudoElementType::firstLine)
  1593. aRuleWalker->Forward(mFirstLineRule);
  1594. else if (aPseudoType == CSSPseudoElementType::placeholder)
  1595. aRuleWalker->Forward(mPlaceholderRule);
  1596. }
  1597. void
  1598. nsStyleSet::WalkDisableTextZoomRule(Element* aElement, nsRuleWalker* aRuleWalker)
  1599. {
  1600. aRuleWalker->SetLevel(SheetType::Agent, false, false);
  1601. if (aElement->IsSVGElement(nsGkAtoms::text))
  1602. aRuleWalker->Forward(mDisableTextZoomStyleRule);
  1603. }
  1604. already_AddRefed<nsStyleContext>
  1605. nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
  1606. CSSPseudoElementType aType,
  1607. nsStyleContext* aParentContext,
  1608. Element* aPseudoElement)
  1609. {
  1610. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1611. NS_ASSERTION(aType < CSSPseudoElementType::Count,
  1612. "must have pseudo element type");
  1613. NS_ASSERTION(aParentElement, "Must have parent element");
  1614. nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1615. TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
  1616. aParentElement->OwnerDoc());
  1617. InitStyleScopes(treeContext, aParentElement);
  1618. PseudoElementRuleProcessorData data(PresContext(), aParentElement,
  1619. &ruleWalker, aType, treeContext,
  1620. aPseudoElement);
  1621. WalkRestrictionRule(aType, &ruleWalker);
  1622. FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
  1623. aParentElement, &ruleWalker);
  1624. nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1625. nsRuleNode *visitedRuleNode = nullptr;
  1626. if (treeContext.HaveRelevantLink()) {
  1627. treeContext.ResetForVisitedMatching();
  1628. ruleWalker.Reset();
  1629. WalkRestrictionRule(aType, &ruleWalker);
  1630. FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
  1631. aParentElement, &ruleWalker);
  1632. visitedRuleNode = ruleWalker.CurrentNode();
  1633. }
  1634. // For pseudos, |data.IsLink()| being true means that
  1635. // our parent node is a link.
  1636. uint32_t flags = eNoFlags;
  1637. if (aType == CSSPseudoElementType::before ||
  1638. aType == CSSPseudoElementType::after) {
  1639. flags |= eDoAnimation;
  1640. } else {
  1641. // Flex and grid containers don't expect to have any pseudo-element children
  1642. // aside from ::before and ::after. So if we have such a child, we're not
  1643. // actually in a flex/grid container, and we should skip flex/grid item
  1644. // style fixup.
  1645. flags |= eSkipParentDisplayBasedStyleFixup;
  1646. }
  1647. return GetContext(aParentContext, ruleNode, visitedRuleNode,
  1648. nsCSSPseudoElements::GetPseudoAtom(aType), aType,
  1649. aParentElement, flags);
  1650. }
  1651. already_AddRefed<nsStyleContext>
  1652. nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
  1653. CSSPseudoElementType aType,
  1654. nsStyleContext* aParentContext)
  1655. {
  1656. TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
  1657. aParentElement->OwnerDoc());
  1658. InitStyleScopes(treeContext, aParentElement);
  1659. return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
  1660. treeContext);
  1661. }
  1662. already_AddRefed<nsStyleContext>
  1663. nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
  1664. CSSPseudoElementType aType,
  1665. nsStyleContext* aParentContext,
  1666. TreeMatchContext& aTreeMatchContext,
  1667. Element* aPseudoElement)
  1668. {
  1669. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1670. NS_ASSERTION(aType < CSSPseudoElementType::Count,
  1671. "must have pseudo element type");
  1672. NS_ASSERTION(aParentElement, "aParentElement must not be null");
  1673. nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
  1674. nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1675. aTreeMatchContext.ResetForUnvisitedMatching();
  1676. PseudoElementRuleProcessorData data(PresContext(), aParentElement,
  1677. &ruleWalker, aType, aTreeMatchContext,
  1678. aPseudoElement);
  1679. WalkRestrictionRule(aType, &ruleWalker);
  1680. // not the root if there was a restriction rule
  1681. nsRuleNode *adjustedRoot = ruleWalker.CurrentNode();
  1682. FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
  1683. aParentElement, &ruleWalker);
  1684. nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1685. if (ruleNode == adjustedRoot) {
  1686. return nullptr;
  1687. }
  1688. nsRuleNode *visitedRuleNode = nullptr;
  1689. if (aTreeMatchContext.HaveRelevantLink()) {
  1690. aTreeMatchContext.ResetForVisitedMatching();
  1691. ruleWalker.Reset();
  1692. WalkRestrictionRule(aType, &ruleWalker);
  1693. FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
  1694. aParentElement, &ruleWalker);
  1695. visitedRuleNode = ruleWalker.CurrentNode();
  1696. }
  1697. // For pseudos, |data.IsLink()| being true means that
  1698. // our parent node is a link.
  1699. uint32_t flags = eNoFlags;
  1700. if (aType == CSSPseudoElementType::before ||
  1701. aType == CSSPseudoElementType::after) {
  1702. flags |= eDoAnimation;
  1703. } else {
  1704. // Flex and grid containers don't expect to have any pseudo-element children
  1705. // aside from ::before and ::after. So if we have such a child, we're not
  1706. // actually in a flex/grid container, and we should skip flex/grid item
  1707. // style fixup.
  1708. flags |= eSkipParentDisplayBasedStyleFixup;
  1709. }
  1710. RefPtr<nsStyleContext> result =
  1711. GetContext(aParentContext, ruleNode, visitedRuleNode,
  1712. pseudoTag, aType,
  1713. aParentElement, flags);
  1714. // For :before and :after pseudo-elements, having display: none or no
  1715. // 'content' property is equivalent to not having the pseudo-element
  1716. // at all.
  1717. if (result &&
  1718. (pseudoTag == nsCSSPseudoElements::before ||
  1719. pseudoTag == nsCSSPseudoElements::after)) {
  1720. const nsStyleDisplay *display = result->StyleDisplay();
  1721. const nsStyleContent *content = result->StyleContent();
  1722. // XXXldb What is contentCount for |content: ""|?
  1723. if (display->mDisplay == StyleDisplay::None ||
  1724. content->ContentCount() == 0) {
  1725. result = nullptr;
  1726. }
  1727. }
  1728. return result.forget();
  1729. }
  1730. already_AddRefed<nsStyleContext>
  1731. nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
  1732. nsStyleContext* aParentContext,
  1733. uint32_t aFlags)
  1734. {
  1735. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1736. #ifdef DEBUG
  1737. bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag)
  1738. #ifdef MOZ_XUL
  1739. && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
  1740. #endif
  1741. ;
  1742. NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
  1743. #endif
  1744. nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1745. AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
  1746. FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
  1747. &ruleWalker);
  1748. if (aPseudoTag == nsCSSAnonBoxes::pageContent) {
  1749. // Add any @page rules that are specified.
  1750. nsTArray<nsCSSPageRule*> rules;
  1751. nsTArray<css::ImportantStyleData*> importantRules;
  1752. AppendPageRules(rules);
  1753. for (uint32_t i = 0, i_end = rules.Length(); i != i_end; ++i) {
  1754. css::Declaration* declaration = rules[i]->Declaration();
  1755. declaration->SetImmutable();
  1756. ruleWalker.Forward(declaration);
  1757. css::ImportantStyleData* importantRule =
  1758. declaration->GetImportantStyleData();
  1759. if (importantRule) {
  1760. importantRules.AppendElement(importantRule);
  1761. }
  1762. }
  1763. for (uint32_t i = 0, i_end = importantRules.Length(); i != i_end; ++i) {
  1764. ruleWalker.Forward(importantRules[i]);
  1765. }
  1766. }
  1767. return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
  1768. aPseudoTag, CSSPseudoElementType::AnonBox,
  1769. nullptr, aFlags);
  1770. }
  1771. #ifdef MOZ_XUL
  1772. already_AddRefed<nsStyleContext>
  1773. nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
  1774. nsIAtom* aPseudoTag,
  1775. nsStyleContext* aParentContext,
  1776. nsICSSPseudoComparator* aComparator)
  1777. {
  1778. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1779. NS_ASSERTION(aPseudoTag, "must have pseudo tag");
  1780. NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
  1781. "Unexpected pseudo");
  1782. nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
  1783. TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
  1784. aParentElement->OwnerDoc());
  1785. InitStyleScopes(treeContext, aParentElement);
  1786. XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
  1787. aPseudoTag, aComparator, treeContext);
  1788. FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
  1789. &ruleWalker);
  1790. nsRuleNode *ruleNode = ruleWalker.CurrentNode();
  1791. nsRuleNode *visitedRuleNode = nullptr;
  1792. if (treeContext.HaveRelevantLink()) {
  1793. treeContext.ResetForVisitedMatching();
  1794. ruleWalker.Reset();
  1795. FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data,
  1796. aParentElement, &ruleWalker);
  1797. visitedRuleNode = ruleWalker.CurrentNode();
  1798. }
  1799. return GetContext(aParentContext, ruleNode, visitedRuleNode,
  1800. // For pseudos, |data.IsLink()| being true means that
  1801. // our parent node is a link.
  1802. aPseudoTag, CSSPseudoElementType::XULTree,
  1803. nullptr, eNoFlags);
  1804. }
  1805. #endif
  1806. bool
  1807. nsStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
  1808. {
  1809. NS_ENSURE_FALSE(mInShutdown, false);
  1810. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  1811. nsPresContext* presContext = PresContext();
  1812. for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
  1813. if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
  1814. continue;
  1815. nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
  1816. (mRuleProcessors[gCSSSheetTypes[i]].get());
  1817. if (ruleProc && !ruleProc->AppendFontFaceRules(presContext, aArray))
  1818. return false;
  1819. }
  1820. return true;
  1821. }
  1822. nsCSSKeyframesRule*
  1823. nsStyleSet::KeyframesRuleForName(const nsString& aName)
  1824. {
  1825. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1826. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  1827. nsPresContext* presContext = PresContext();
  1828. for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
  1829. if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
  1830. continue;
  1831. nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
  1832. (mRuleProcessors[gCSSSheetTypes[i]].get());
  1833. if (!ruleProc)
  1834. continue;
  1835. nsCSSKeyframesRule* result =
  1836. ruleProc->KeyframesRuleForName(presContext, aName);
  1837. if (result)
  1838. return result;
  1839. }
  1840. return nullptr;
  1841. }
  1842. nsCSSCounterStyleRule*
  1843. nsStyleSet::CounterStyleRuleForName(const nsAString& aName)
  1844. {
  1845. NS_ENSURE_FALSE(mInShutdown, nullptr);
  1846. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  1847. nsPresContext* presContext = PresContext();
  1848. for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
  1849. if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
  1850. continue;
  1851. nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
  1852. (mRuleProcessors[gCSSSheetTypes[i]].get());
  1853. if (!ruleProc)
  1854. continue;
  1855. nsCSSCounterStyleRule *result =
  1856. ruleProc->CounterStyleRuleForName(presContext, aName);
  1857. if (result)
  1858. return result;
  1859. }
  1860. return nullptr;
  1861. }
  1862. bool
  1863. nsStyleSet::AppendFontFeatureValuesRules(
  1864. nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
  1865. {
  1866. NS_ENSURE_FALSE(mInShutdown, false);
  1867. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  1868. nsPresContext* presContext = PresContext();
  1869. for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
  1870. nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
  1871. (mRuleProcessors[gCSSSheetTypes[i]].get());
  1872. if (ruleProc &&
  1873. !ruleProc->AppendFontFeatureValuesRules(presContext, aArray))
  1874. {
  1875. return false;
  1876. }
  1877. }
  1878. return true;
  1879. }
  1880. already_AddRefed<gfxFontFeatureValueSet>
  1881. nsStyleSet::GetFontFeatureValuesLookup()
  1882. {
  1883. if (mInitFontFeatureValuesLookup) {
  1884. mInitFontFeatureValuesLookup = false;
  1885. nsTArray<nsCSSFontFeatureValuesRule*> rules;
  1886. AppendFontFeatureValuesRules(rules);
  1887. mFontFeatureValuesLookup = new gfxFontFeatureValueSet();
  1888. uint32_t i, numRules = rules.Length();
  1889. for (i = 0; i < numRules; i++) {
  1890. nsCSSFontFeatureValuesRule *rule = rules[i];
  1891. const nsTArray<FontFamilyName>& familyList = rule->GetFamilyList().GetFontlist();
  1892. const nsTArray<gfxFontFeatureValueSet::FeatureValues>&
  1893. featureValues = rule->GetFeatureValues();
  1894. // for each family
  1895. size_t f, numFam;
  1896. numFam = familyList.Length();
  1897. for (f = 0; f < numFam; f++) {
  1898. mFontFeatureValuesLookup->AddFontFeatureValues(familyList[f].mName,
  1899. featureValues);
  1900. }
  1901. }
  1902. }
  1903. RefPtr<gfxFontFeatureValueSet> lookup = mFontFeatureValuesLookup;
  1904. return lookup.forget();
  1905. }
  1906. bool
  1907. nsStyleSet::AppendPageRules(nsTArray<nsCSSPageRule*>& aArray)
  1908. {
  1909. NS_ENSURE_FALSE(mInShutdown, false);
  1910. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  1911. nsPresContext* presContext = PresContext();
  1912. for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
  1913. if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
  1914. continue;
  1915. nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
  1916. (mRuleProcessors[gCSSSheetTypes[i]].get());
  1917. if (ruleProc && !ruleProc->AppendPageRules(presContext, aArray))
  1918. return false;
  1919. }
  1920. return true;
  1921. }
  1922. void
  1923. nsStyleSet::BeginShutdown()
  1924. {
  1925. mInShutdown = 1;
  1926. }
  1927. void
  1928. nsStyleSet::Shutdown()
  1929. {
  1930. mRuleTree = nullptr;
  1931. GCRuleTrees();
  1932. MOZ_ASSERT(mUnusedRuleNodeList.isEmpty());
  1933. MOZ_ASSERT(mUnusedRuleNodeCount == 0);
  1934. }
  1935. void
  1936. nsStyleSet::GCRuleTrees()
  1937. {
  1938. MOZ_ASSERT(!mInReconstruct);
  1939. MOZ_ASSERT(!mInGC);
  1940. mInGC = true;
  1941. while (!mUnusedRuleNodeList.isEmpty()) {
  1942. nsRuleNode* node = mUnusedRuleNodeList.popFirst();
  1943. #ifdef DEBUG
  1944. if (node == mOldRootNode) {
  1945. // Flag that we've GCed the old root, if any.
  1946. mOldRootNode = nullptr;
  1947. }
  1948. #endif
  1949. node->Destroy();
  1950. }
  1951. #ifdef DEBUG
  1952. NS_ASSERTION(!mOldRootNode, "Should have GCed old root node");
  1953. mOldRootNode = nullptr;
  1954. #endif
  1955. mUnusedRuleNodeCount = 0;
  1956. mInGC = false;
  1957. }
  1958. already_AddRefed<nsStyleContext>
  1959. nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
  1960. nsStyleContext* aNewParentContext,
  1961. Element* aElement)
  1962. {
  1963. MOZ_ASSERT(aStyleContext, "aStyleContext must not be null");
  1964. // This short-circuit is OK because we don't call TryInitatingTransition
  1965. // during style reresolution if the style context pointer hasn't changed.
  1966. if (aStyleContext->GetParent() == aNewParentContext) {
  1967. RefPtr<nsStyleContext> ret = aStyleContext;
  1968. return ret.forget();
  1969. }
  1970. nsIAtom* pseudoTag = aStyleContext->GetPseudo();
  1971. CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
  1972. nsRuleNode* ruleNode = aStyleContext->RuleNode();
  1973. MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
  1974. "stylo: the style set and restyle manager must have the same "
  1975. "StyleBackendType");
  1976. NS_ASSERTION(!PresContext()->RestyleManager()->AsGecko()->SkipAnimationRules(),
  1977. "we no longer handle SkipAnimationRules()");
  1978. nsRuleNode* visitedRuleNode = nullptr;
  1979. nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
  1980. // Reparenting a style context just changes where we inherit from,
  1981. // not what rules we match or what our DOM looks like. In
  1982. // particular, it doesn't change whether this is a style context for
  1983. // a link.
  1984. if (visitedContext) {
  1985. visitedRuleNode = visitedContext->RuleNode();
  1986. }
  1987. uint32_t flags = eNoFlags;
  1988. if (aStyleContext->IsLinkContext()) {
  1989. flags |= eIsLink;
  1990. // GetContext handles propagating RelevantLinkVisited state from the
  1991. // parent in non-link cases; all we need to pass in is if this link
  1992. // is visited.
  1993. if (aStyleContext->RelevantLinkVisited()) {
  1994. flags |= eIsVisitedLink;
  1995. }
  1996. }
  1997. if (pseudoType == CSSPseudoElementType::NotPseudo ||
  1998. pseudoType == CSSPseudoElementType::before ||
  1999. pseudoType == CSSPseudoElementType::after) {
  2000. flags |= eDoAnimation;
  2001. }
  2002. if (aElement && aElement->IsRootOfAnonymousSubtree()) {
  2003. // For anonymous subtree roots, don't tweak "display" value based on whether
  2004. // or not the parent is styled as a flex/grid container. (If the parent
  2005. // has anonymous-subtree kids, then we know it's not actually going to get
  2006. // a flex/grid container frame, anyway.)
  2007. flags |= eSkipParentDisplayBasedStyleFixup;
  2008. }
  2009. return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
  2010. pseudoTag, pseudoType,
  2011. aElement, flags);
  2012. }
  2013. struct MOZ_STACK_CLASS StatefulData : public StateRuleProcessorData {
  2014. StatefulData(nsPresContext* aPresContext, Element* aElement,
  2015. EventStates aStateMask, TreeMatchContext& aTreeMatchContext)
  2016. : StateRuleProcessorData(aPresContext, aElement, aStateMask,
  2017. aTreeMatchContext),
  2018. mHint(nsRestyleHint(0))
  2019. {}
  2020. nsRestyleHint mHint;
  2021. };
  2022. struct MOZ_STACK_CLASS StatefulPseudoElementData : public PseudoElementStateRuleProcessorData {
  2023. StatefulPseudoElementData(nsPresContext* aPresContext, Element* aElement,
  2024. EventStates aStateMask, CSSPseudoElementType aPseudoType,
  2025. TreeMatchContext& aTreeMatchContext, Element* aPseudoElement)
  2026. : PseudoElementStateRuleProcessorData(aPresContext, aElement, aStateMask,
  2027. aPseudoType, aTreeMatchContext,
  2028. aPseudoElement),
  2029. mHint(nsRestyleHint(0))
  2030. {}
  2031. nsRestyleHint mHint;
  2032. };
  2033. static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
  2034. void *aData)
  2035. {
  2036. StatefulData* data = (StatefulData*)aData;
  2037. if (aProcessor->HasDocumentStateDependentStyle(data)) {
  2038. data->mHint = eRestyle_Self;
  2039. return false; // don't continue
  2040. }
  2041. return true; // continue
  2042. }
  2043. // Test if style is dependent on a document state.
  2044. bool
  2045. nsStyleSet::HasDocumentStateDependentStyle(nsIContent* aContent,
  2046. EventStates aStateMask)
  2047. {
  2048. if (!aContent || !aContent->IsElement())
  2049. return false;
  2050. TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
  2051. aContent->OwnerDoc());
  2052. InitStyleScopes(treeContext, aContent->AsElement());
  2053. StatefulData data(PresContext(), aContent->AsElement(), aStateMask,
  2054. treeContext);
  2055. WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
  2056. return data.mHint != 0;
  2057. }
  2058. static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
  2059. void *aData)
  2060. {
  2061. StatefulData* data = (StatefulData*)aData;
  2062. nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
  2063. data->mHint = nsRestyleHint(data->mHint | hint);
  2064. return true; // continue
  2065. }
  2066. static bool SheetHasStatefulPseudoElementStyle(nsIStyleRuleProcessor* aProcessor,
  2067. void *aData)
  2068. {
  2069. StatefulPseudoElementData* data = (StatefulPseudoElementData*)aData;
  2070. nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
  2071. data->mHint = nsRestyleHint(data->mHint | hint);
  2072. return true; // continue
  2073. }
  2074. // Test if style is dependent on content state
  2075. nsRestyleHint
  2076. nsStyleSet::HasStateDependentStyle(Element* aElement,
  2077. EventStates aStateMask)
  2078. {
  2079. TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
  2080. aElement->OwnerDoc());
  2081. InitStyleScopes(treeContext, aElement);
  2082. StatefulData data(PresContext(), aElement, aStateMask, treeContext);
  2083. WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
  2084. return data.mHint;
  2085. }
  2086. nsRestyleHint
  2087. nsStyleSet::HasStateDependentStyle(Element* aElement,
  2088. CSSPseudoElementType aPseudoType,
  2089. Element* aPseudoElement,
  2090. EventStates aStateMask)
  2091. {
  2092. TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
  2093. aElement->OwnerDoc());
  2094. InitStyleScopes(treeContext, aElement);
  2095. StatefulPseudoElementData data(PresContext(), aElement, aStateMask,
  2096. aPseudoType, treeContext, aPseudoElement);
  2097. WalkRuleProcessors(SheetHasStatefulPseudoElementStyle, &data, false);
  2098. return data.mHint;
  2099. }
  2100. struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
  2101. AttributeData(nsPresContext* aPresContext, Element* aElement,
  2102. int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType,
  2103. bool aAttrHasChanged, const nsAttrValue* aOtherValue,
  2104. TreeMatchContext& aTreeMatchContext)
  2105. : AttributeRuleProcessorData(aPresContext, aElement, aNameSpaceID,
  2106. aAttribute, aModType, aAttrHasChanged,
  2107. aOtherValue, aTreeMatchContext),
  2108. mHint(nsRestyleHint(0))
  2109. {}
  2110. nsRestyleHint mHint;
  2111. RestyleHintData mHintData;
  2112. };
  2113. static bool
  2114. SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
  2115. {
  2116. AttributeData* data = (AttributeData*)aData;
  2117. nsRestyleHint hint =
  2118. aProcessor->HasAttributeDependentStyle(data, data->mHintData);
  2119. data->mHint = nsRestyleHint(data->mHint | hint);
  2120. return true; // continue
  2121. }
  2122. // Test if style is dependent on content state
  2123. nsRestyleHint
  2124. nsStyleSet::HasAttributeDependentStyle(Element* aElement,
  2125. int32_t aNameSpaceID,
  2126. nsIAtom* aAttribute,
  2127. int32_t aModType,
  2128. bool aAttrHasChanged,
  2129. const nsAttrValue* aOtherValue,
  2130. mozilla::RestyleHintData&
  2131. aRestyleHintDataResult)
  2132. {
  2133. TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
  2134. aElement->OwnerDoc());
  2135. InitStyleScopes(treeContext, aElement);
  2136. AttributeData data(PresContext(), aElement, aNameSpaceID, aAttribute,
  2137. aModType, aAttrHasChanged, aOtherValue, treeContext);
  2138. WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
  2139. if (!(data.mHint & eRestyle_Subtree)) {
  2140. // No point keeping the list of selectors around if we are going to
  2141. // restyle the whole subtree unconditionally.
  2142. aRestyleHintDataResult = Move(data.mHintData);
  2143. }
  2144. return data.mHint;
  2145. }
  2146. bool
  2147. nsStyleSet::MediumFeaturesChanged()
  2148. {
  2149. NS_ASSERTION(mBatching == 0, "rule processors out of date");
  2150. // We can't use WalkRuleProcessors without a content node.
  2151. nsPresContext* presContext = PresContext();
  2152. bool stylesChanged = false;
  2153. for (nsIStyleRuleProcessor* processor : mRuleProcessors) {
  2154. if (!processor) {
  2155. continue;
  2156. }
  2157. bool thisChanged = processor->MediumFeaturesChanged(presContext);
  2158. stylesChanged = stylesChanged || thisChanged;
  2159. }
  2160. for (nsIStyleRuleProcessor* processor : mScopedDocSheetRuleProcessors) {
  2161. bool thisChanged = processor->MediumFeaturesChanged(presContext);
  2162. stylesChanged = stylesChanged || thisChanged;
  2163. }
  2164. if (mBindingManager) {
  2165. bool thisChanged = false;
  2166. mBindingManager->MediumFeaturesChanged(presContext, &thisChanged);
  2167. stylesChanged = stylesChanged || thisChanged;
  2168. }
  2169. return stylesChanged;
  2170. }
  2171. bool
  2172. nsStyleSet::EnsureUniqueInnerOnCSSSheets()
  2173. {
  2174. AutoTArray<CSSStyleSheet*, 32> queue;
  2175. for (SheetType type : gCSSSheetTypes) {
  2176. for (CSSStyleSheet* sheet : mSheets[type]) {
  2177. queue.AppendElement(sheet);
  2178. }
  2179. }
  2180. if (mBindingManager) {
  2181. AutoTArray<StyleSheet*, 32> sheets;
  2182. // XXXheycam stylo: AppendAllSheets will need to be able to return either
  2183. // CSSStyleSheets or ServoStyleSheets, on request (and then here requesting
  2184. // CSSStyleSheets).
  2185. mBindingManager->AppendAllSheets(sheets);
  2186. for (StyleSheet* sheet : sheets) {
  2187. MOZ_ASSERT(sheet->IsGecko(), "stylo: AppendAllSheets shouldn't give us "
  2188. "ServoStyleSheets yet");
  2189. queue.AppendElement(sheet->AsGecko());
  2190. }
  2191. }
  2192. while (!queue.IsEmpty()) {
  2193. uint32_t idx = queue.Length() - 1;
  2194. CSSStyleSheet* sheet = queue[idx];
  2195. queue.RemoveElementAt(idx);
  2196. sheet->EnsureUniqueInner();
  2197. // Enqueue all the sheet's children.
  2198. sheet->AppendAllChildSheets(queue);
  2199. }
  2200. bool res = mNeedsRestyleAfterEnsureUniqueInner;
  2201. mNeedsRestyleAfterEnsureUniqueInner = false;
  2202. return res;
  2203. }
  2204. nsIStyleRule*
  2205. nsStyleSet::InitialStyleRule()
  2206. {
  2207. if (!mInitialStyleRule) {
  2208. mInitialStyleRule = new nsInitialStyleRule;
  2209. }
  2210. return mInitialStyleRule;
  2211. }
  2212. bool
  2213. nsStyleSet::HasRuleProcessorUsedByMultipleStyleSets(SheetType aSheetType)
  2214. {
  2215. MOZ_ASSERT(size_t(aSheetType) < ArrayLength(mRuleProcessors));
  2216. if (!IsCSSSheetType(aSheetType) || !mRuleProcessors[aSheetType]) {
  2217. return false;
  2218. }
  2219. nsCSSRuleProcessor* rp =
  2220. static_cast<nsCSSRuleProcessor*>(mRuleProcessors[aSheetType].get());
  2221. return rp->IsUsedByMultipleStyleSets();
  2222. }
  2223. void
  2224. nsStyleSet::ClearSelectors()
  2225. {
  2226. // We might be called before we've done our first rule tree construction.
  2227. if (!mRuleTree) {
  2228. return;
  2229. }
  2230. MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
  2231. "stylo: the style set and restyle manager must have the same "
  2232. "StyleBackendType");
  2233. PresContext()->RestyleManager()->AsGecko()->ClearSelectors();
  2234. }