123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538 |
- /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- /*
- * the container for the style sheets that apply to a presentation, and
- * the internal API that the style system exposes for creating (and
- * potentially re-creating) style contexts
- */
- #include "nsStyleSet.h"
- #include "mozilla/ArrayUtils.h"
- #include "mozilla/StyleSheetInlines.h"
- #include "mozilla/EffectCompositor.h"
- #include "mozilla/EnumeratedRange.h"
- #include "mozilla/EventStates.h"
- #include "mozilla/MemoryReporting.h"
- #include "mozilla/RuleProcessorCache.h"
- #include "mozilla/StyleSheetInlines.h"
- #include "nsIDocumentInlines.h"
- #include "nsRuleWalker.h"
- #include "nsStyleContext.h"
- #include "mozilla/css/StyleRule.h"
- #include "nsCSSAnonBoxes.h"
- #include "nsCSSPseudoElements.h"
- #include "nsCSSRuleProcessor.h"
- #include "nsDataHashtable.h"
- #include "nsIContent.h"
- #include "nsRuleData.h"
- #include "nsRuleProcessorData.h"
- #include "nsAnimationManager.h"
- #include "nsStyleSheetService.h"
- #include "mozilla/dom/Element.h"
- #include "GeckoProfiler.h"
- #include "nsHTMLCSSStyleSheet.h"
- #include "nsHTMLStyleSheet.h"
- #include "SVGAttrAnimationRuleProcessor.h"
- #include "nsCSSRules.h"
- #include "nsPrintfCString.h"
- #include "nsIFrame.h"
- #include "mozilla/RestyleManagerHandle.h"
- #include "mozilla/RestyleManagerHandleInlines.h"
- #include "nsQueryObject.h"
- #include <inttypes.h>
- using namespace mozilla;
- using namespace mozilla::dom;
- NS_IMPL_ISUPPORTS(nsEmptyStyleRule, nsIStyleRule)
- /* virtual */ void
- nsEmptyStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
- {
- }
- /* virtual */ bool
- nsEmptyStyleRule::MightMapInheritedStyleData()
- {
- return false;
- }
- /* virtual */ bool
- nsEmptyStyleRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
- nsCSSValue* aValue)
- {
- MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
- return false;
- }
- #ifdef DEBUG
- /* virtual */ void
- nsEmptyStyleRule::List(FILE* out, int32_t aIndent) const
- {
- nsAutoCString indentStr;
- for (int32_t index = aIndent; --index >= 0; ) {
- indentStr.AppendLiteral(" ");
- }
- fprintf_stderr(out, "%s[empty style rule] {}\n", indentStr.get());
- }
- #endif
- NS_IMPL_ISUPPORTS(nsInitialStyleRule, nsIStyleRule)
- /* virtual */ void
- nsInitialStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
- {
- // Iterate over the property groups
- for (nsStyleStructID sid = nsStyleStructID(0);
- sid < nsStyleStructID_Length; sid = nsStyleStructID(sid + 1)) {
- if (aRuleData->mSIDs & (1 << sid)) {
- // Iterate over nsCSSValues within the property group
- nsCSSValue * const value_start =
- aRuleData->mValueStorage + aRuleData->mValueOffsets[sid];
- for (nsCSSValue *value = value_start,
- *value_end = value + nsCSSProps::PropertyCountInStruct(sid);
- value != value_end; ++value) {
- // If MathML is disabled take care not to set MathML properties (or we
- // will trigger assertions in nsRuleNode)
- if (sid == eStyleStruct_Font &&
- !aRuleData->mPresContext->Document()->GetMathMLEnabled()) {
- size_t index = value - value_start;
- if (index == nsCSSProps::PropertyIndexInStruct(
- eCSSProperty_script_level) ||
- index == nsCSSProps::PropertyIndexInStruct(
- eCSSProperty_script_size_multiplier) ||
- index == nsCSSProps::PropertyIndexInStruct(
- eCSSProperty_script_min_size) ||
- index == nsCSSProps::PropertyIndexInStruct(
- eCSSProperty_math_variant) ||
- index == nsCSSProps::PropertyIndexInStruct(
- eCSSProperty_math_display)) {
- continue;
- }
- }
- if (value->GetUnit() == eCSSUnit_Null) {
- value->SetInitialValue();
- }
- }
- }
- }
- }
- /* virtual */ bool
- nsInitialStyleRule::MightMapInheritedStyleData()
- {
- return true;
- }
- /* virtual */ bool
- nsInitialStyleRule::GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
- nsCSSValue* aValue)
- {
- MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
- return false;
- }
- #ifdef DEBUG
- /* virtual */ void
- nsInitialStyleRule::List(FILE* out, int32_t aIndent) const
- {
- nsAutoCString indentStr;
- for (int32_t index = aIndent; --index >= 0; ) {
- indentStr.AppendLiteral(" ");
- }
- fprintf_stderr(out, "%s[initial style rule] {}\n", indentStr.get());
- }
- #endif
- NS_IMPL_ISUPPORTS(nsDisableTextZoomStyleRule, nsIStyleRule)
- /* virtual */ void
- nsDisableTextZoomStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
- {
- if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Font)))
- return;
- nsCSSValue* value = aRuleData->ValueForTextZoom();
- if (value->GetUnit() == eCSSUnit_Null)
- value->SetNoneValue();
- }
- /* virtual */ bool
- nsDisableTextZoomStyleRule::MightMapInheritedStyleData()
- {
- return true;
- }
- /* virtual */ bool
- nsDisableTextZoomStyleRule::
- GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty, nsCSSValue* aValue)
- {
- MOZ_ASSERT(false, "GetDiscretelyAnimatedCSSValue is not implemented yet");
- return false;
- }
- #ifdef DEBUG
- /* virtual */ void
- nsDisableTextZoomStyleRule::List(FILE* out, int32_t aIndent) const
- {
- nsAutoCString indentStr;
- for (int32_t index = aIndent; --index >= 0; ) {
- indentStr.AppendLiteral(" ");
- }
- fprintf_stderr(out, "%s[disable text zoom style rule] {}\n", indentStr.get());
- }
- #endif
- static const SheetType gCSSSheetTypes[] = {
- // From lowest to highest in cascading order.
- SheetType::Agent,
- SheetType::User,
- SheetType::Doc,
- SheetType::ScopedDoc,
- SheetType::Override
- };
- /* static */ bool
- nsStyleSet::IsCSSSheetType(SheetType aSheetType)
- {
- for (SheetType type : gCSSSheetTypes) {
- if (type == aSheetType) {
- return true;
- }
- }
- return false;
- }
- nsStyleSet::nsStyleSet()
- : mRuleTree(nullptr),
- mBatching(0),
- mInShutdown(false),
- mInGC(false),
- mAuthorStyleDisabled(false),
- mInReconstruct(false),
- mInitFontFeatureValuesLookup(true),
- mNeedsRestyleAfterEnsureUniqueInner(false),
- mDirty(0),
- mRootStyleContextCount(0),
- #ifdef DEBUG
- mOldRootNode(nullptr),
- #endif
- mUnusedRuleNodeCount(0)
- {
- }
- nsStyleSet::~nsStyleSet()
- {
- for (SheetType type : gCSSSheetTypes) {
- for (CSSStyleSheet* sheet : mSheets[type]) {
- sheet->DropStyleSet(this);
- }
- }
- // drop reference to cached rule processors
- nsCSSRuleProcessor* rp;
- rp = static_cast<nsCSSRuleProcessor*>(mRuleProcessors[SheetType::Agent].get());
- if (rp) {
- MOZ_ASSERT(rp->IsShared());
- rp->ReleaseStyleSetRef();
- }
- rp = static_cast<nsCSSRuleProcessor*>(mRuleProcessors[SheetType::User].get());
- if (rp) {
- MOZ_ASSERT(rp->IsShared());
- rp->ReleaseStyleSetRef();
- }
- }
- size_t
- nsStyleSet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
- {
- size_t n = aMallocSizeOf(this);
- for (SheetType type : MakeEnumeratedRange(SheetType::Count)) {
- if (mRuleProcessors[type]) {
- bool shared = false;
- if (type == SheetType::Agent || type == SheetType::User) {
- // The only two origins we consider caching rule processors for.
- nsCSSRuleProcessor* rp =
- static_cast<nsCSSRuleProcessor*>(mRuleProcessors[type].get());
- shared = rp->IsShared();
- }
- if (!shared) {
- n += mRuleProcessors[type]->SizeOfIncludingThis(aMallocSizeOf);
- }
- }
- // We don't own the sheets (either the nsLayoutStyleSheetCache singleton
- // or our document owns them).
- n += mSheets[type].ShallowSizeOfExcludingThis(aMallocSizeOf);
- }
- for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
- n += mScopedDocSheetRuleProcessors[i]->SizeOfIncludingThis(aMallocSizeOf);
- }
- n += mScopedDocSheetRuleProcessors.ShallowSizeOfExcludingThis(aMallocSizeOf);
- return n;
- }
- void
- nsStyleSet::Init(nsPresContext *aPresContext)
- {
- mFirstLineRule = new nsEmptyStyleRule;
- mFirstLetterRule = new nsEmptyStyleRule;
- mPlaceholderRule = new nsEmptyStyleRule;
- mDisableTextZoomStyleRule = new nsDisableTextZoomStyleRule;
- mRuleTree = nsRuleNode::CreateRootNode(aPresContext);
- // Make an explicit GatherRuleProcessors call for the levels that
- // don't have style sheets. The other levels will have their calls
- // triggered by DirtyRuleProcessors.
- GatherRuleProcessors(SheetType::PresHint);
- GatherRuleProcessors(SheetType::SVGAttrAnimation);
- GatherRuleProcessors(SheetType::StyleAttr);
- GatherRuleProcessors(SheetType::Animation);
- GatherRuleProcessors(SheetType::Transition);
- }
- nsresult
- nsStyleSet::BeginReconstruct()
- {
- NS_ASSERTION(!mInReconstruct, "Unmatched begin/end?");
- NS_ASSERTION(mRuleTree, "Reconstructing before first construction?");
- mInReconstruct = true;
- // Clear any ArenaRefPtr-managed style contexts, as we don't want them
- // held on to after the rule tree has been reconstructed.
- PresContext()->PresShell()->ClearArenaRefPtrs(eArenaObjectID_nsStyleContext);
- #ifdef DEBUG
- MOZ_ASSERT(!mOldRootNode);
- mOldRootNode = mRuleTree;
- #endif
- // Create a new rule tree root, dropping the reference to our old rule tree.
- // After reconstruction, we will re-enable GC, and allow everything to be
- // collected.
- mRuleTree = nsRuleNode::CreateRootNode(mRuleTree->PresContext());
- return NS_OK;
- }
- void
- nsStyleSet::EndReconstruct()
- {
- NS_ASSERTION(mInReconstruct, "Unmatched begin/end?");
- mInReconstruct = false;
- GCRuleTrees();
- }
- typedef nsDataHashtable<nsPtrHashKey<nsINode>, uint32_t> ScopeDepthCache;
- // Returns the depth of a style scope element, with 1 being the depth of
- // a style scope element that has no ancestor style scope elements. The
- // depth does not count intervening non-scope elements.
- static uint32_t
- GetScopeDepth(nsINode* aScopeElement, ScopeDepthCache& aCache)
- {
- nsINode* parent = aScopeElement->GetParent();
- if (!parent || !parent->IsElementInStyleScope()) {
- return 1;
- }
- uint32_t depth = aCache.Get(aScopeElement);
- if (!depth) {
- for (nsINode* n = parent; n; n = n->GetParent()) {
- if (n->IsScopedStyleRoot()) {
- depth = GetScopeDepth(n, aCache) + 1;
- aCache.Put(aScopeElement, depth);
- break;
- }
- }
- }
- return depth;
- }
- struct ScopedSheetOrder
- {
- CSSStyleSheet* mSheet;
- uint32_t mDepth;
- uint32_t mOrder;
- bool operator==(const ScopedSheetOrder& aRHS) const
- {
- return mDepth == aRHS.mDepth &&
- mOrder == aRHS.mOrder;
- }
- bool operator<(const ScopedSheetOrder& aRHS) const
- {
- if (mDepth != aRHS.mDepth) {
- return mDepth < aRHS.mDepth;
- }
- return mOrder < aRHS.mOrder;
- }
- };
- // Sorts aSheets such that style sheets for ancestor scopes come
- // before those for descendant scopes, and with sheets for a single
- // scope in document order.
- static void
- SortStyleSheetsByScope(nsTArray<CSSStyleSheet*>& aSheets)
- {
- uint32_t n = aSheets.Length();
- if (n == 1) {
- return;
- }
- ScopeDepthCache cache;
- nsTArray<ScopedSheetOrder> sheets;
- sheets.SetLength(n);
- // For each sheet, record the depth of its scope element and its original
- // document order.
- for (uint32_t i = 0; i < n; i++) {
- sheets[i].mSheet = aSheets[i];
- sheets[i].mDepth = GetScopeDepth(aSheets[i]->GetScopeElement(), cache);
- sheets[i].mOrder = i;
- }
- // Sort by depth first, then document order.
- sheets.Sort();
- for (uint32_t i = 0; i < n; i++) {
- aSheets[i] = sheets[i].mSheet;
- }
- }
- nsresult
- nsStyleSet::GatherRuleProcessors(SheetType aType)
- {
- NS_ENSURE_FALSE(mInShutdown, NS_ERROR_FAILURE);
- // We might be in GatherRuleProcessors because we are dropping a sheet,
- // resulting in an nsCSSSelector being destroyed. Tell the
- // RestyleManager for each document we're used in so that they can
- // drop any nsCSSSelector pointers (used for eRestyle_SomeDescendants)
- // in their mPendingRestyles.
- if (IsCSSSheetType(aType)) {
- ClearSelectors();
- }
- nsCOMPtr<nsIStyleRuleProcessor> oldRuleProcessor(mRuleProcessors[aType]);
- nsTArray<nsCOMPtr<nsIStyleRuleProcessor>> oldScopedDocRuleProcessors;
- if (aType == SheetType::Agent || aType == SheetType::User) {
- // drop reference to cached rule processor
- nsCSSRuleProcessor* rp =
- static_cast<nsCSSRuleProcessor*>(mRuleProcessors[aType].get());
- if (rp) {
- MOZ_ASSERT(rp->IsShared());
- rp->ReleaseStyleSetRef();
- }
- }
- mRuleProcessors[aType] = nullptr;
- if (aType == SheetType::ScopedDoc) {
- for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
- nsIStyleRuleProcessor* processor = mScopedDocSheetRuleProcessors[i].get();
- Element* scope =
- static_cast<nsCSSRuleProcessor*>(processor)->GetScopeElement();
- scope->ClearIsScopedStyleRoot();
- }
- // Clear mScopedDocSheetRuleProcessors, but save it.
- oldScopedDocRuleProcessors.SwapElements(mScopedDocSheetRuleProcessors);
- }
- if (mAuthorStyleDisabled && (aType == SheetType::Doc ||
- aType == SheetType::ScopedDoc ||
- aType == SheetType::StyleAttr)) {
- // Don't regather if this level is disabled. Note that we gather
- // preshint sheets no matter what, but then skip them for some
- // elements later if mAuthorStyleDisabled.
- return NS_OK;
- }
- switch (aType) {
- // levels that do not contain CSS style sheets
- case SheetType::Animation:
- MOZ_ASSERT(mSheets[aType].IsEmpty());
- mRuleProcessors[aType] = PresContext()->EffectCompositor()->
- RuleProcessor(EffectCompositor::CascadeLevel::Animations);
- return NS_OK;
- case SheetType::Transition:
- MOZ_ASSERT(mSheets[aType].IsEmpty());
- mRuleProcessors[aType] = PresContext()->EffectCompositor()->
- RuleProcessor(EffectCompositor::CascadeLevel::Transitions);
- return NS_OK;
- case SheetType::StyleAttr:
- MOZ_ASSERT(mSheets[aType].IsEmpty());
- mRuleProcessors[aType] = PresContext()->Document()->GetInlineStyleSheet();
- return NS_OK;
- case SheetType::PresHint:
- MOZ_ASSERT(mSheets[aType].IsEmpty());
- mRuleProcessors[aType] =
- PresContext()->Document()->GetAttributeStyleSheet();
- return NS_OK;
- case SheetType::SVGAttrAnimation:
- MOZ_ASSERT(mSheets[aType].IsEmpty());
- mRuleProcessors[aType] =
- PresContext()->Document()->GetSVGAttrAnimationRuleProcessor();
- return NS_OK;
- default:
- // keep going
- break;
- }
- MOZ_ASSERT(IsCSSSheetType(aType));
- if (aType == SheetType::ScopedDoc) {
- // Create a rule processor for each scope.
- uint32_t count = mSheets[SheetType::ScopedDoc].Length();
- if (count) {
- // Gather the scoped style sheets into an array as
- // CSSStyleSheets, and mark all of their scope elements
- // as scoped style roots.
- nsTArray<CSSStyleSheet*> sheets(count);
- for (CSSStyleSheet* sheet : mSheets[SheetType::ScopedDoc]) {
- sheets.AppendElement(sheet);
- Element* scope = sheet->GetScopeElement();
- scope->SetIsScopedStyleRoot();
- }
- // Sort the scoped style sheets so that those for the same scope are
- // adjacent and that ancestor scopes come before descendent scopes.
- SortStyleSheetsByScope(sheets);
- // Put the old scoped rule processors in a hashtable so that we
- // can retrieve them efficiently, even in edge cases like the
- // simultaneous removal and addition of a large number of elements
- // with scoped sheets.
- nsDataHashtable<nsPtrHashKey<Element>,
- nsCSSRuleProcessor*> oldScopedRuleProcessorHash;
- for (size_t i = oldScopedDocRuleProcessors.Length(); i-- != 0; ) {
- nsCSSRuleProcessor* oldRP =
- static_cast<nsCSSRuleProcessor*>(oldScopedDocRuleProcessors[i].get());
- Element* scope = oldRP->GetScopeElement();
- MOZ_ASSERT(!oldScopedRuleProcessorHash.Get(scope),
- "duplicate rule processors for same scope element?");
- oldScopedRuleProcessorHash.Put(scope, oldRP);
- }
- uint32_t start = 0, end;
- do {
- // Find the range of style sheets with the same scope.
- Element* scope = sheets[start]->GetScopeElement();
- end = start + 1;
- while (end < count && sheets[end]->GetScopeElement() == scope) {
- end++;
- }
- scope->SetIsScopedStyleRoot();
- // Create a rule processor for the scope.
- nsTArray<RefPtr<CSSStyleSheet>> sheetsForScope;
- sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
- nsCSSRuleProcessor* oldRP = oldScopedRuleProcessorHash.Get(scope);
- mScopedDocSheetRuleProcessors.AppendElement
- (new nsCSSRuleProcessor(Move(sheetsForScope), aType, scope, oldRP));
- start = end;
- } while (start < count);
- }
- return NS_OK;
- }
- if (!mSheets[aType].IsEmpty()) {
- switch (aType) {
- case SheetType::Agent:
- case SheetType::User: {
- // levels containing non-scoped CSS style sheets whose rule processors
- // we want to re-use
- nsTArray<CSSStyleSheet*> sheets(mSheets[aType].Length());
- for (CSSStyleSheet* sheet : mSheets[aType]) {
- sheets.AppendElement(sheet);
- }
- nsCSSRuleProcessor* rp =
- RuleProcessorCache::GetRuleProcessor(sheets, PresContext());
- if (!rp) {
- rp = new nsCSSRuleProcessor(mSheets[aType], aType, nullptr,
- static_cast<nsCSSRuleProcessor*>(
- oldRuleProcessor.get()),
- true /* aIsShared */);
- nsTArray<css::DocumentRule*> documentRules;
- nsDocumentRuleResultCacheKey cacheKey;
- rp->TakeDocumentRulesAndCacheKey(PresContext(),
- documentRules, cacheKey);
- RuleProcessorCache::PutRuleProcessor(sheets,
- Move(documentRules),
- cacheKey, rp);
- }
- mRuleProcessors[aType] = rp;
- rp->AddStyleSetRef();
- break;
- }
- case SheetType::Doc:
- case SheetType::Override: {
- // levels containing non-scoped CSS stylesheets whose rule processors
- // we don't want to re-use
- mRuleProcessors[aType] =
- new nsCSSRuleProcessor(mSheets[aType], aType, nullptr,
- static_cast<nsCSSRuleProcessor*>(
- oldRuleProcessor.get()));
- } break;
- default:
- MOZ_ASSERT_UNREACHABLE("non-CSS sheet types should be handled above");
- break;
- }
- }
- return NS_OK;
- }
- nsresult
- nsStyleSet::AppendStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
- {
- NS_PRECONDITION(aSheet, "null arg");
- NS_ASSERTION(aSheet->IsApplicable(),
- "Inapplicable sheet being placed in style set");
- bool present = mSheets[aType].RemoveElement(aSheet);
- mSheets[aType].AppendElement(aSheet);
- if (!present && IsCSSSheetType(aType)) {
- aSheet->AddStyleSet(this);
- }
- return DirtyRuleProcessors(aType);
- }
- nsresult
- nsStyleSet::PrependStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
- {
- NS_PRECONDITION(aSheet, "null arg");
- NS_ASSERTION(aSheet->IsApplicable(),
- "Inapplicable sheet being placed in style set");
- bool present = mSheets[aType].RemoveElement(aSheet);
- mSheets[aType].InsertElementAt(0, aSheet);
- if (!present && IsCSSSheetType(aType)) {
- aSheet->AddStyleSet(this);
- }
- return DirtyRuleProcessors(aType);
- }
- nsresult
- nsStyleSet::RemoveStyleSheet(SheetType aType, CSSStyleSheet* aSheet)
- {
- NS_PRECONDITION(aSheet, "null arg");
- NS_ASSERTION(aSheet->IsComplete(),
- "Incomplete sheet being removed from style set");
- if (mSheets[aType].RemoveElement(aSheet)) {
- if (IsCSSSheetType(aType)) {
- aSheet->DropStyleSet(this);
- }
- }
- return DirtyRuleProcessors(aType);
- }
- nsresult
- nsStyleSet::ReplaceSheets(SheetType aType,
- const nsTArray<RefPtr<CSSStyleSheet>>& aNewSheets)
- {
- bool cssSheetType = IsCSSSheetType(aType);
- if (cssSheetType) {
- for (CSSStyleSheet* sheet : mSheets[aType]) {
- sheet->DropStyleSet(this);
- }
- }
- mSheets[aType].Clear();
- mSheets[aType].AppendElements(aNewSheets);
- if (cssSheetType) {
- for (CSSStyleSheet* sheet : mSheets[aType]) {
- sheet->AddStyleSet(this);
- }
- }
- return DirtyRuleProcessors(aType);
- }
- nsresult
- nsStyleSet::InsertStyleSheetBefore(SheetType aType, CSSStyleSheet* aNewSheet,
- CSSStyleSheet* aReferenceSheet)
- {
- NS_PRECONDITION(aNewSheet && aReferenceSheet, "null arg");
- NS_ASSERTION(aNewSheet->IsApplicable(),
- "Inapplicable sheet being placed in style set");
- bool present = mSheets[aType].RemoveElement(aNewSheet);
- int32_t idx = mSheets[aType].IndexOf(aReferenceSheet);
- if (idx < 0)
- return NS_ERROR_INVALID_ARG;
- mSheets[aType].InsertElementAt(idx, aNewSheet);
- if (!present && IsCSSSheetType(aType)) {
- aNewSheet->AddStyleSet(this);
- }
- return DirtyRuleProcessors(aType);
- }
- static inline uint32_t
- DirtyBit(SheetType aType)
- {
- return 1 << uint32_t(aType);
- }
- nsresult
- nsStyleSet::DirtyRuleProcessors(SheetType aType)
- {
- if (!mBatching)
- return GatherRuleProcessors(aType);
- mDirty |= DirtyBit(aType);
- return NS_OK;
- }
- bool
- nsStyleSet::GetAuthorStyleDisabled() const
- {
- return mAuthorStyleDisabled;
- }
- nsresult
- nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
- {
- if (aStyleDisabled == !mAuthorStyleDisabled) {
- mAuthorStyleDisabled = aStyleDisabled;
- BeginUpdate();
- mDirty |= DirtyBit(SheetType::Doc) |
- DirtyBit(SheetType::ScopedDoc) |
- DirtyBit(SheetType::StyleAttr);
- return EndUpdate();
- }
- return NS_OK;
- }
- // -------- Doc Sheets
- nsresult
- nsStyleSet::AddDocStyleSheet(CSSStyleSheet* aSheet, nsIDocument* aDocument)
- {
- NS_PRECONDITION(aSheet && aDocument, "null arg");
- NS_ASSERTION(aSheet->IsApplicable(),
- "Inapplicable sheet being placed in style set");
- SheetType type = aSheet->GetScopeElement() ?
- SheetType::ScopedDoc :
- SheetType::Doc;
- nsTArray<RefPtr<CSSStyleSheet>>& sheets = mSheets[type];
- bool present = sheets.RemoveElement(aSheet);
- size_t index = aDocument->FindDocStyleSheetInsertionPoint(sheets, *aSheet);
- sheets.InsertElementAt(index, aSheet);
- if (!present) {
- aSheet->AddStyleSet(this);
- }
- return DirtyRuleProcessors(type);
- }
- void
- nsStyleSet::AppendAllXBLStyleSheets(nsTArray<mozilla::CSSStyleSheet*>& aArray) const
- {
- if (mBindingManager) {
- // XXXheycam stylo: AppendAllSheets will need to be able to return either
- // CSSStyleSheets or ServoStyleSheets, on request (and then here requesting
- // CSSStyleSheets).
- AutoTArray<StyleSheet*, 32> sheets;
- mBindingManager->AppendAllSheets(sheets);
- for (StyleSheet* handle : sheets) {
- MOZ_ASSERT(handle->IsGecko(), "stylo: AppendAllSheets shouldn't give us "
- "ServoStyleSheets yet");
- aArray.AppendElement(handle->AsGecko());
- }
- }
- }
- nsresult
- nsStyleSet::RemoveDocStyleSheet(CSSStyleSheet* aSheet)
- {
- bool isScoped = aSheet->GetScopeElement();
- return RemoveStyleSheet(isScoped ? SheetType::ScopedDoc : SheetType::Doc,
- aSheet);
- }
- // Batching
- void
- nsStyleSet::BeginUpdate()
- {
- ++mBatching;
- }
- nsresult
- nsStyleSet::EndUpdate()
- {
- NS_ASSERTION(mBatching > 0, "Unbalanced EndUpdate");
- if (--mBatching) {
- // We're not completely done yet.
- return NS_OK;
- }
- for (SheetType type : MakeEnumeratedRange(SheetType::Count)) {
- if (mDirty & DirtyBit(type)) {
- nsresult rv = GatherRuleProcessors(type);
- NS_ENSURE_SUCCESS(rv, rv);
- }
- }
- mDirty = 0;
- return NS_OK;
- }
- template<class T>
- static bool
- EnumRulesMatching(nsIStyleRuleProcessor* aProcessor, void* aData)
- {
- T* data = static_cast<T*>(aData);
- aProcessor->RulesMatching(data);
- return true;
- }
- static inline bool
- IsMoreSpecificThanAnimation(nsRuleNode *aRuleNode)
- {
- return !aRuleNode->IsRoot() &&
- (aRuleNode->GetLevel() == SheetType::Transition ||
- aRuleNode->IsImportantRule());
- }
- static nsIStyleRule*
- GetAnimationRule(nsRuleNode *aRuleNode)
- {
- nsRuleNode *n = aRuleNode;
- while (IsMoreSpecificThanAnimation(n)) {
- n = n->GetParent();
- }
- if (n->IsRoot() || n->GetLevel() != SheetType::Animation) {
- return nullptr;
- }
- return n->GetRule();
- }
- static nsRuleNode*
- ReplaceAnimationRule(nsRuleNode *aOldRuleNode,
- nsIStyleRule *aOldAnimRule,
- nsIStyleRule *aNewAnimRule)
- {
- nsTArray<nsRuleNode*> moreSpecificNodes;
- nsRuleNode *n = aOldRuleNode;
- while (IsMoreSpecificThanAnimation(n)) {
- moreSpecificNodes.AppendElement(n);
- n = n->GetParent();
- }
- if (aOldAnimRule) {
- MOZ_ASSERT(n->GetRule() == aOldAnimRule, "wrong rule");
- MOZ_ASSERT(n->GetLevel() == SheetType::Animation,
- "wrong level");
- n = n->GetParent();
- }
- MOZ_ASSERT(!IsMoreSpecificThanAnimation(n) &&
- (n->IsRoot() || n->GetLevel() != SheetType::Animation),
- "wrong level");
- if (aNewAnimRule) {
- n = n->Transition(aNewAnimRule, SheetType::Animation, false);
- n->SetIsAnimationRule();
- }
- for (uint32_t i = moreSpecificNodes.Length(); i-- != 0; ) {
- nsRuleNode *oldNode = moreSpecificNodes[i];
- n = n->Transition(oldNode->GetRule(), oldNode->GetLevel(),
- oldNode->IsImportantRule());
- }
- return n;
- }
- /**
- * |GetContext| implements sharing of style contexts (not just the data
- * on the rule nodes) between siblings and cousins of the same
- * generation. (It works for cousins of the same generation since
- * |aParentContext| could itself be a shared context.)
- */
- already_AddRefed<nsStyleContext>
- nsStyleSet::GetContext(nsStyleContext* aParentContext,
- nsRuleNode* aRuleNode,
- // aVisitedRuleNode may be null; if it is null
- // it means that we don't need to force creation
- // of a StyleIfVisited. (But if we make one
- // because aParentContext has one, then aRuleNode
- // should be used.)
- nsRuleNode* aVisitedRuleNode,
- nsIAtom* aPseudoTag,
- CSSPseudoElementType aPseudoType,
- Element* aElementForAnimation,
- uint32_t aFlags)
- {
- NS_PRECONDITION((!aPseudoTag &&
- aPseudoType ==
- CSSPseudoElementType::NotPseudo) ||
- (aPseudoTag &&
- nsCSSPseudoElements::GetPseudoType(
- aPseudoTag, CSSEnabledState::eIgnoreEnabledState) ==
- aPseudoType),
- "Pseudo mismatch");
- if (aVisitedRuleNode == aRuleNode) {
- // No need to force creation of a visited style in this case.
- aVisitedRuleNode = nullptr;
- }
- // Ensure |aVisitedRuleNode != nullptr| corresponds to the need to
- // create an if-visited style context, and that in that case, we have
- // parentIfVisited set correctly.
- nsStyleContext *parentIfVisited =
- aParentContext ? aParentContext->GetStyleIfVisited() : nullptr;
- if (parentIfVisited) {
- if (!aVisitedRuleNode) {
- aVisitedRuleNode = aRuleNode;
- }
- } else {
- if (aVisitedRuleNode) {
- parentIfVisited = aParentContext;
- }
- }
- if (aFlags & eIsLink) {
- // If this node is a link, we want its visited's style context's
- // parent to be the regular style context of its parent, because
- // only the visitedness of the relevant link should influence style.
- parentIfVisited = aParentContext;
- }
- bool relevantLinkVisited = (aFlags & eIsLink) ?
- (aFlags & eIsVisitedLink) :
- (aParentContext && aParentContext->RelevantLinkVisited());
- RefPtr<nsStyleContext> result;
- if (aParentContext)
- result = aParentContext->FindChildWithRules(aPseudoTag, aRuleNode,
- aVisitedRuleNode,
- relevantLinkVisited);
- if (!result) {
- // |aVisitedRuleNode| may have a ref-count of zero since we are yet
- // to create the style context that will hold an owning reference to it.
- // As a result, we need to make sure it stays alive until that point
- // in case something in the first call to NS_NewStyleContext triggers a
- // GC sweep of rule nodes.
- RefPtr<nsRuleNode> kungFuDeathGrip{aVisitedRuleNode};
- result = NS_NewStyleContext(aParentContext, aPseudoTag, aPseudoType,
- aRuleNode,
- aFlags & eSkipParentDisplayBasedStyleFixup);
- if (aVisitedRuleNode) {
- RefPtr<nsStyleContext> resultIfVisited =
- NS_NewStyleContext(parentIfVisited, aPseudoTag, aPseudoType,
- aVisitedRuleNode,
- aFlags & eSkipParentDisplayBasedStyleFixup);
- resultIfVisited->SetIsStyleIfVisited();
- result->SetStyleIfVisited(resultIfVisited.forget());
- if (relevantLinkVisited) {
- result->AddStyleBit(NS_STYLE_RELEVANT_LINK_VISITED);
- }
- }
- }
- else {
- NS_ASSERTION(result->GetPseudoType() == aPseudoType, "Unexpected type");
- NS_ASSERTION(result->GetPseudo() == aPseudoTag, "Unexpected pseudo");
- }
- if (aFlags & eDoAnimation) {
- nsIStyleRule *oldAnimRule = GetAnimationRule(aRuleNode);
- nsIStyleRule *animRule = nullptr;
- // Ignore animations for print or print preview, and for elements
- // that are not attached to the document tree.
- if (PresContext()->IsDynamic() &&
- aElementForAnimation->IsInComposedDoc()) {
- // Update CSS animations in case the animation-name has just changed.
- PresContext()->AnimationManager()->UpdateAnimations(result,
- aElementForAnimation);
- PresContext()->EffectCompositor()->UpdateEffectProperties(
- result, aElementForAnimation, result->GetPseudoType());
- animRule = PresContext()->EffectCompositor()->
- GetAnimationRule(aElementForAnimation,
- result->GetPseudoType(),
- EffectCompositor::CascadeLevel::Animations,
- result);
- }
- MOZ_ASSERT(result->RuleNode() == aRuleNode,
- "unexpected rule node");
- MOZ_ASSERT(!result->GetStyleIfVisited() == !aVisitedRuleNode,
- "unexpected visited rule node");
- MOZ_ASSERT(!aVisitedRuleNode ||
- result->GetStyleIfVisited()->RuleNode() == aVisitedRuleNode,
- "unexpected visited rule node");
- MOZ_ASSERT(!aVisitedRuleNode ||
- oldAnimRule == GetAnimationRule(aVisitedRuleNode),
- "animation rule mismatch between rule nodes");
- if (oldAnimRule != animRule) {
- nsRuleNode *ruleNode =
- ReplaceAnimationRule(aRuleNode, oldAnimRule, animRule);
- nsRuleNode *visitedRuleNode = aVisitedRuleNode
- ? ReplaceAnimationRule(aVisitedRuleNode, oldAnimRule, animRule)
- : nullptr;
- MOZ_ASSERT(!visitedRuleNode ||
- GetAnimationRule(ruleNode) ==
- GetAnimationRule(visitedRuleNode),
- "animation rule mismatch between rule nodes");
- result = GetContext(aParentContext, ruleNode, visitedRuleNode,
- aPseudoTag, aPseudoType, nullptr,
- aFlags & ~eDoAnimation);
- }
- }
- if (aElementForAnimation &&
- aElementForAnimation->IsHTMLElement(nsGkAtoms::body) &&
- aPseudoType == CSSPseudoElementType::NotPseudo &&
- PresContext()->CompatibilityMode() == eCompatibility_NavQuirks) {
- nsIDocument* doc = aElementForAnimation->GetUncomposedDoc();
- if (doc && doc->GetBodyElement() == aElementForAnimation) {
- // Update the prescontext's body color
- PresContext()->SetBodyTextColor(result->StyleColor()->mColor);
- }
- }
- return result.forget();
- }
- void
- nsStyleSet::AddImportantRules(nsRuleNode* aCurrLevelNode,
- nsRuleNode* aLastPrevLevelNode,
- nsRuleWalker* aRuleWalker)
- {
- NS_ASSERTION(aCurrLevelNode &&
- aCurrLevelNode != aLastPrevLevelNode, "How did we get here?");
- AutoTArray<nsIStyleRule*, 16> importantRules;
- for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
- node = node->GetParent()) {
- // We guarantee that we never walk the root node here, so no need
- // to null-check GetRule(). Furthermore, it must be a CSS rule.
- NS_ASSERTION(RefPtr<css::Declaration>(do_QueryObject(node->GetRule())),
- "Unexpected non-CSS rule");
- nsIStyleRule* impRule =
- static_cast<css::Declaration*>(node->GetRule())->GetImportantStyleData();
- if (impRule)
- importantRules.AppendElement(impRule);
- }
- NS_ASSERTION(importantRules.Length() != 0,
- "Why did we think there were important rules?");
- for (uint32_t i = importantRules.Length(); i-- != 0; ) {
- aRuleWalker->Forward(importantRules[i]);
- }
- }
- #ifdef DEBUG
- void
- nsStyleSet::AssertNoImportantRules(nsRuleNode* aCurrLevelNode,
- nsRuleNode* aLastPrevLevelNode)
- {
- if (!aCurrLevelNode)
- return;
- for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
- node = node->GetParent()) {
- RefPtr<css::Declaration> declaration(do_QueryObject(node->GetRule()));
- NS_ASSERTION(declaration, "Unexpected non-CSS rule");
- NS_ASSERTION(!declaration->GetImportantStyleData(),
- "Unexpected important style source");
- }
- }
- void
- nsStyleSet::AssertNoCSSRules(nsRuleNode* aCurrLevelNode,
- nsRuleNode* aLastPrevLevelNode)
- {
- if (!aCurrLevelNode)
- return;
- for (nsRuleNode *node = aCurrLevelNode; node != aLastPrevLevelNode;
- node = node->GetParent()) {
- nsIStyleRule *rule = node->GetRule();
- RefPtr<css::Declaration> declaration(do_QueryObject(rule));
- if (declaration) {
- RefPtr<css::StyleRule> cssRule =
- do_QueryObject(declaration->GetOwningRule());
- NS_ASSERTION(!cssRule || !cssRule->Selector(),
- "Unexpected CSS rule");
- }
- }
- }
- #endif
- // Enumerate the rules in a way that cares about the order of the rules.
- void
- nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
- RuleProcessorData* aData, Element* aElement,
- nsRuleWalker* aRuleWalker)
- {
- PROFILER_LABEL("nsStyleSet", "FileRules",
- js::ProfileEntry::Category::CSS);
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- // Cascading order:
- // [least important]
- // - UA normal rules = Agent normal
- // - User normal rules = User normal
- // - Presentation hints = PresHint normal
- // - SVG Animation (highest pres hint) = SVGAttrAnimation normal
- // - Author normal rules = Document normal
- // - Override normal rules = Override normal
- // - animation rules = Animation normal
- // - Author !important rules = Document !important
- // - Override !important rules = Override !important
- // - User !important rules = User !important
- // - UA !important rules = Agent !important
- // - transition rules = Transition normal
- // [most important]
- // Save off the last rule before we start walking our agent sheets;
- // this will be either the root or one of the restriction rules.
- nsRuleNode* lastRestrictionRN = aRuleWalker->CurrentNode();
- aRuleWalker->SetLevel(SheetType::Agent, false, true);
- if (mRuleProcessors[SheetType::Agent])
- (*aCollectorFunc)(mRuleProcessors[SheetType::Agent], aData);
- nsRuleNode* lastAgentRN = aRuleWalker->CurrentNode();
- bool haveImportantUARules = !aRuleWalker->GetCheckForImportantRules();
- aRuleWalker->SetLevel(SheetType::User, false, true);
- bool skipUserStyles =
- aElement && aElement->IsInNativeAnonymousSubtree();
- if (!skipUserStyles && mRuleProcessors[SheetType::User]) // NOTE: different
- (*aCollectorFunc)(mRuleProcessors[SheetType::User], aData);
- nsRuleNode* lastUserRN = aRuleWalker->CurrentNode();
- bool haveImportantUserRules = !aRuleWalker->GetCheckForImportantRules();
- aRuleWalker->SetLevel(SheetType::PresHint, false, false);
- if (mRuleProcessors[SheetType::PresHint])
- (*aCollectorFunc)(mRuleProcessors[SheetType::PresHint], aData);
- aRuleWalker->SetLevel(SheetType::SVGAttrAnimation, false, false);
- if (mRuleProcessors[SheetType::SVGAttrAnimation])
- (*aCollectorFunc)(mRuleProcessors[SheetType::SVGAttrAnimation], aData);
- nsRuleNode* lastSVGAttrAnimationRN = aRuleWalker->CurrentNode();
- aRuleWalker->SetLevel(SheetType::Doc, false, true);
- bool cutOffInheritance = false;
- if (mBindingManager && aElement) {
- // We can supply additional document-level sheets that should be walked.
- mBindingManager->WalkRules(aCollectorFunc,
- static_cast<ElementDependentRuleProcessorData*>(aData),
- &cutOffInheritance);
- }
- if (!skipUserStyles && !cutOffInheritance && // NOTE: different
- mRuleProcessors[SheetType::Doc])
- (*aCollectorFunc)(mRuleProcessors[SheetType::Doc], aData);
- nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
- bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
- nsTArray<nsRuleNode*> lastScopedRNs;
- nsTArray<bool> haveImportantScopedRules;
- bool haveAnyImportantScopedRules = false;
- if (!skipUserStyles && !cutOffInheritance &&
- aElement && aElement->IsElementInStyleScope()) {
- lastScopedRNs.SetLength(mScopedDocSheetRuleProcessors.Length());
- haveImportantScopedRules.SetLength(mScopedDocSheetRuleProcessors.Length());
- for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
- aRuleWalker->SetLevel(SheetType::ScopedDoc, false, true);
- nsCSSRuleProcessor* processor =
- static_cast<nsCSSRuleProcessor*>(mScopedDocSheetRuleProcessors[i].get());
- aData->mScope = processor->GetScopeElement();
- (*aCollectorFunc)(mScopedDocSheetRuleProcessors[i], aData);
- lastScopedRNs[i] = aRuleWalker->CurrentNode();
- haveImportantScopedRules[i] = !aRuleWalker->GetCheckForImportantRules();
- haveAnyImportantScopedRules = haveAnyImportantScopedRules || haveImportantScopedRules[i];
- }
- aData->mScope = nullptr;
- }
- nsRuleNode* lastScopedRN = aRuleWalker->CurrentNode();
- aRuleWalker->SetLevel(SheetType::StyleAttr, false, true);
- if (mRuleProcessors[SheetType::StyleAttr])
- (*aCollectorFunc)(mRuleProcessors[SheetType::StyleAttr], aData);
- nsRuleNode* lastStyleAttrRN = aRuleWalker->CurrentNode();
- bool haveImportantStyleAttrRules = !aRuleWalker->GetCheckForImportantRules();
- aRuleWalker->SetLevel(SheetType::Override, false, true);
- if (mRuleProcessors[SheetType::Override])
- (*aCollectorFunc)(mRuleProcessors[SheetType::Override], aData);
- nsRuleNode* lastOvrRN = aRuleWalker->CurrentNode();
- bool haveImportantOverrideRules = !aRuleWalker->GetCheckForImportantRules();
- // This needs to match IsMoreSpecificThanAnimation() above.
- aRuleWalker->SetLevel(SheetType::Animation, false, false);
- (*aCollectorFunc)(mRuleProcessors[SheetType::Animation], aData);
- if (haveAnyImportantScopedRules) {
- for (uint32_t i = lastScopedRNs.Length(); i-- != 0; ) {
- aRuleWalker->SetLevel(SheetType::ScopedDoc, true, false);
- nsRuleNode* startRN = lastScopedRNs[i];
- nsRuleNode* endRN = i == 0 ? lastDocRN : lastScopedRNs[i - 1];
- if (haveImportantScopedRules[i]) {
- AddImportantRules(startRN, endRN, aRuleWalker); // scoped
- }
- #ifdef DEBUG
- else {
- AssertNoImportantRules(startRN, endRN);
- }
- #endif
- }
- }
- #ifdef DEBUG
- else {
- AssertNoImportantRules(lastScopedRN, lastDocRN);
- }
- #endif
- if (haveImportantDocRules) {
- aRuleWalker->SetLevel(SheetType::Doc, true, false);
- AddImportantRules(lastDocRN, lastSVGAttrAnimationRN, aRuleWalker); // doc
- }
- #ifdef DEBUG
- else {
- AssertNoImportantRules(lastDocRN, lastSVGAttrAnimationRN);
- }
- #endif
- if (haveImportantStyleAttrRules) {
- aRuleWalker->SetLevel(SheetType::StyleAttr, true, false);
- AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker); // style attr
- }
- #ifdef DEBUG
- else {
- AssertNoImportantRules(lastStyleAttrRN, lastScopedRN);
- }
- #endif
- if (haveImportantOverrideRules) {
- aRuleWalker->SetLevel(SheetType::Override, true, false);
- AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker); // override
- }
- #ifdef DEBUG
- else {
- AssertNoImportantRules(lastOvrRN, lastStyleAttrRN);
- }
- #endif
- #ifdef DEBUG
- AssertNoCSSRules(lastSVGAttrAnimationRN, lastUserRN);
- #endif
- if (haveImportantUserRules) {
- aRuleWalker->SetLevel(SheetType::User, true, false);
- AddImportantRules(lastUserRN, lastAgentRN, aRuleWalker); //user
- }
- #ifdef DEBUG
- else {
- AssertNoImportantRules(lastUserRN, lastAgentRN);
- }
- #endif
- if (haveImportantUARules) {
- aRuleWalker->SetLevel(SheetType::Agent, true, false);
- AddImportantRules(lastAgentRN, lastRestrictionRN, aRuleWalker); //agent
- }
- #ifdef DEBUG
- else {
- AssertNoImportantRules(lastAgentRN, lastRestrictionRN);
- }
- #endif
- #ifdef DEBUG
- AssertNoCSSRules(lastRestrictionRN, mRuleTree);
- #endif
- #ifdef DEBUG
- nsRuleNode *lastImportantRN = aRuleWalker->CurrentNode();
- #endif
- aRuleWalker->SetLevel(SheetType::Transition, false, false);
- (*aCollectorFunc)(mRuleProcessors[SheetType::Transition], aData);
- #ifdef DEBUG
- AssertNoCSSRules(aRuleWalker->CurrentNode(), lastImportantRN);
- #endif
- }
- // Enumerate all the rules in a way that doesn't care about the order
- // of the rules and doesn't walk !important-rules.
- void
- nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
- ElementDependentRuleProcessorData* aData,
- bool aWalkAllXBLStylesheets)
- {
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- if (mRuleProcessors[SheetType::Agent])
- (*aFunc)(mRuleProcessors[SheetType::Agent], aData);
- bool skipUserStyles = aData->mElement->IsInNativeAnonymousSubtree();
- if (!skipUserStyles && mRuleProcessors[SheetType::User]) // NOTE: different
- (*aFunc)(mRuleProcessors[SheetType::User], aData);
- if (mRuleProcessors[SheetType::PresHint])
- (*aFunc)(mRuleProcessors[SheetType::PresHint], aData);
- if (mRuleProcessors[SheetType::SVGAttrAnimation])
- (*aFunc)(mRuleProcessors[SheetType::SVGAttrAnimation], aData);
- bool cutOffInheritance = false;
- if (mBindingManager) {
- // We can supply additional document-level sheets that should be walked.
- if (aWalkAllXBLStylesheets) {
- mBindingManager->WalkAllRules(aFunc, aData);
- } else {
- mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
- }
- }
- if (!skipUserStyles && !cutOffInheritance) {
- if (mRuleProcessors[SheetType::Doc]) // NOTE: different
- (*aFunc)(mRuleProcessors[SheetType::Doc], aData);
- if (aData->mElement->IsElementInStyleScope()) {
- for (uint32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++)
- (*aFunc)(mScopedDocSheetRuleProcessors[i], aData);
- }
- }
- if (mRuleProcessors[SheetType::StyleAttr])
- (*aFunc)(mRuleProcessors[SheetType::StyleAttr], aData);
- if (mRuleProcessors[SheetType::Override])
- (*aFunc)(mRuleProcessors[SheetType::Override], aData);
- (*aFunc)(mRuleProcessors[SheetType::Animation], aData);
- (*aFunc)(mRuleProcessors[SheetType::Transition], aData);
- }
- static void
- InitStyleScopes(TreeMatchContext& aTreeContext, Element* aElement)
- {
- if (aElement->IsElementInStyleScope()) {
- aTreeContext.InitStyleScopes(aElement->GetParentElementCrossingShadowRoot());
- }
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveStyleFor(Element* aElement,
- nsStyleContext* aParentContext)
- {
- TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
- aElement->OwnerDoc());
- InitStyleScopes(treeContext, aElement);
- return ResolveStyleFor(aElement, aParentContext, treeContext);
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveStyleFor(Element* aElement,
- nsStyleContext* aParentContext,
- TreeMatchContext& aTreeMatchContext)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- NS_ASSERTION(aElement, "aElement must not be null");
- nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
- aTreeMatchContext.ResetForUnvisitedMatching();
- ElementRuleProcessorData data(PresContext(), aElement, &ruleWalker,
- aTreeMatchContext);
- WalkDisableTextZoomRule(aElement, &ruleWalker);
- FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
- &ruleWalker);
- nsRuleNode *ruleNode = ruleWalker.CurrentNode();
- nsRuleNode *visitedRuleNode = nullptr;
- if (aTreeMatchContext.HaveRelevantLink()) {
- aTreeMatchContext.ResetForVisitedMatching();
- ruleWalker.Reset();
- FileRules(EnumRulesMatching<ElementRuleProcessorData>, &data, aElement,
- &ruleWalker);
- visitedRuleNode = ruleWalker.CurrentNode();
- }
- uint32_t flags = eDoAnimation;
- if (nsCSSRuleProcessor::IsLink(aElement)) {
- flags |= eIsLink;
- }
- if (nsCSSRuleProcessor::GetContentState(aElement, aTreeMatchContext).
- HasState(NS_EVENT_STATE_VISITED)) {
- flags |= eIsVisitedLink;
- }
- if (aTreeMatchContext.mSkippingParentDisplayBasedStyleFixup) {
- flags |= eSkipParentDisplayBasedStyleFixup;
- }
- return GetContext(aParentContext, ruleNode, visitedRuleNode,
- nullptr, CSSPseudoElementType::NotPseudo,
- aElement, flags);
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveStyleForRules(nsStyleContext* aParentContext,
- const nsTArray< nsCOMPtr<nsIStyleRule> > &aRules)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
- // FIXME: Perhaps this should be passed in, but it probably doesn't
- // matter.
- ruleWalker.SetLevel(SheetType::Doc, false, false);
- for (uint32_t i = 0; i < aRules.Length(); i++) {
- ruleWalker.ForwardOnPossiblyCSSRule(aRules.ElementAt(i));
- }
- return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
- nullptr, CSSPseudoElementType::NotPseudo,
- nullptr, eNoFlags);
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveStyleByAddingRules(nsStyleContext* aBaseContext,
- const nsCOMArray<nsIStyleRule> &aRules)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
- ruleWalker.SetCurrentNode(aBaseContext->RuleNode());
- // This needs to be the transition sheet because that is the highest
- // level of the cascade, and thus the only thing that makes sense if
- // we are ever going to call ResolveStyleWithReplacement on the
- // resulting context. It's also the right thing for the one case (the
- // transition manager's cover rule) where we put the result of this
- // function in the style context tree.
- ruleWalker.SetLevel(SheetType::Transition, false, false);
- for (int32_t i = 0; i < aRules.Count(); i++) {
- ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
- }
- nsRuleNode *ruleNode = ruleWalker.CurrentNode();
- nsRuleNode *visitedRuleNode = nullptr;
- if (aBaseContext->GetStyleIfVisited()) {
- ruleWalker.SetCurrentNode(aBaseContext->GetStyleIfVisited()->RuleNode());
- for (int32_t i = 0; i < aRules.Count(); i++) {
- ruleWalker.ForwardOnPossiblyCSSRule(aRules.ObjectAt(i));
- }
- visitedRuleNode = ruleWalker.CurrentNode();
- }
- uint32_t flags = eNoFlags;
- if (aBaseContext->IsLinkContext()) {
- flags |= eIsLink;
- // GetContext handles propagating RelevantLinkVisited state from the
- // parent in non-link cases; all we need to pass in is if this link
- // is visited.
- if (aBaseContext->RelevantLinkVisited()) {
- flags |= eIsVisitedLink;
- }
- }
- return GetContext(aBaseContext->GetParent(), ruleNode, visitedRuleNode,
- aBaseContext->GetPseudo(),
- aBaseContext->GetPseudoType(),
- nullptr, flags);
- }
- struct RuleNodeInfo {
- nsIStyleRule* mRule;
- SheetType mLevel;
- bool mIsImportant;
- bool mIsAnimationRule;
- };
- struct CascadeLevel {
- SheetType mLevel;
- bool mIsImportant;
- bool mCheckForImportantRules;
- nsRestyleHint mLevelReplacementHint;
- };
- static const CascadeLevel gCascadeLevels[] = {
- { SheetType::Agent, false, false, nsRestyleHint(0) },
- { SheetType::User, false, false, nsRestyleHint(0) },
- { SheetType::PresHint, false, false, nsRestyleHint(0) },
- { SheetType::SVGAttrAnimation, false, false, eRestyle_SVGAttrAnimations },
- { SheetType::Doc, false, false, nsRestyleHint(0) },
- { SheetType::ScopedDoc, false, false, nsRestyleHint(0) },
- { SheetType::StyleAttr, false, true, eRestyle_StyleAttribute |
- eRestyle_StyleAttribute_Animations },
- { SheetType::Override, false, false, nsRestyleHint(0) },
- { SheetType::Animation, false, false, eRestyle_CSSAnimations },
- { SheetType::ScopedDoc, true, false, nsRestyleHint(0) },
- { SheetType::Doc, true, false, nsRestyleHint(0) },
- { SheetType::StyleAttr, true, false, eRestyle_StyleAttribute |
- eRestyle_StyleAttribute_Animations },
- { SheetType::Override, true, false, nsRestyleHint(0) },
- { SheetType::User, true, false, nsRestyleHint(0) },
- { SheetType::Agent, true, false, nsRestyleHint(0) },
- { SheetType::Transition, false, false, eRestyle_CSSTransitions },
- };
- nsRuleNode*
- nsStyleSet::RuleNodeWithReplacement(Element* aElement,
- Element* aPseudoElement,
- nsRuleNode* aOldRuleNode,
- CSSPseudoElementType aPseudoType,
- nsRestyleHint aReplacements)
- {
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- MOZ_ASSERT(!aPseudoElement ==
- (aPseudoType >= CSSPseudoElementType::Count ||
- !(nsCSSPseudoElements::PseudoElementSupportsStyleAttribute(aPseudoType) ||
- nsCSSPseudoElements::PseudoElementSupportsUserActionState(aPseudoType))),
- "should have aPseudoElement only for certain pseudo elements");
- MOZ_ASSERT(!(aReplacements & ~(eRestyle_CSSTransitions |
- eRestyle_CSSAnimations |
- eRestyle_SVGAttrAnimations |
- eRestyle_StyleAttribute |
- eRestyle_StyleAttribute_Animations |
- eRestyle_Force |
- eRestyle_ForceDescendants)),
- "unexpected replacement bits");
- // FIXME (perf): This should probably not rebuild the whole path, but
- // only the path from the last change in the rule tree, like
- // ReplaceAnimationRule in nsStyleSet.cpp does. (That could then
- // perhaps share this code, too?)
- // But if we do that, we'll need to pass whether we are rebuilding the
- // rule tree from ElementRestyler::RestyleSelf to avoid taking that
- // path when we're rebuilding the rule tree.
- // This array can be hot and often grows to ~20 elements, so inline storage
- // is best.
- AutoTArray<RuleNodeInfo, 30> rules;
- for (nsRuleNode* ruleNode = aOldRuleNode; !ruleNode->IsRoot();
- ruleNode = ruleNode->GetParent()) {
- RuleNodeInfo* curRule = rules.AppendElement();
- curRule->mRule = ruleNode->GetRule();
- curRule->mLevel = ruleNode->GetLevel();
- curRule->mIsImportant = ruleNode->IsImportantRule();
- curRule->mIsAnimationRule = ruleNode->IsAnimationRule();
- }
- nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
- auto rulesIndex = rules.Length();
- // We need to transfer this information between the non-!important and
- // !important phases for the style attribute level.
- nsRuleNode* lastScopedRN = nullptr;
- nsRuleNode* lastStyleAttrRN = nullptr;
- bool haveImportantStyleAttrRules = false;
- for (const CascadeLevel *level = gCascadeLevels,
- *levelEnd = ArrayEnd(gCascadeLevels);
- level != levelEnd; ++level) {
- bool doReplace = level->mLevelReplacementHint & aReplacements;
- ruleWalker.SetLevel(level->mLevel, level->mIsImportant,
- level->mCheckForImportantRules && doReplace);
- if (doReplace) {
- switch (level->mLevel) {
- case SheetType::Animation: {
- if (aPseudoType == CSSPseudoElementType::NotPseudo ||
- aPseudoType == CSSPseudoElementType::before ||
- aPseudoType == CSSPseudoElementType::after) {
- nsIStyleRule* rule = PresContext()->EffectCompositor()->
- GetAnimationRule(aElement, aPseudoType,
- EffectCompositor::CascadeLevel::Animations,
- nullptr);
- if (rule) {
- ruleWalker.ForwardOnPossiblyCSSRule(rule);
- ruleWalker.CurrentNode()->SetIsAnimationRule();
- }
- }
- break;
- }
- case SheetType::Transition: {
- if (aPseudoType == CSSPseudoElementType::NotPseudo ||
- aPseudoType == CSSPseudoElementType::before ||
- aPseudoType == CSSPseudoElementType::after) {
- nsIStyleRule* rule = PresContext()->EffectCompositor()->
- GetAnimationRule(aElement, aPseudoType,
- EffectCompositor::CascadeLevel::Transitions,
- nullptr);
- if (rule) {
- ruleWalker.ForwardOnPossiblyCSSRule(rule);
- ruleWalker.CurrentNode()->SetIsAnimationRule();
- }
- }
- break;
- }
- case SheetType::SVGAttrAnimation: {
- SVGAttrAnimationRuleProcessor* ruleProcessor =
- static_cast<SVGAttrAnimationRuleProcessor*>(
- mRuleProcessors[SheetType::SVGAttrAnimation].get());
- if (ruleProcessor &&
- aPseudoType == CSSPseudoElementType::NotPseudo) {
- ruleProcessor->ElementRulesMatching(aElement, &ruleWalker);
- }
- break;
- }
- case SheetType::StyleAttr: {
- if (!level->mIsImportant) {
- // First time through, we handle the non-!important rule.
- nsHTMLCSSStyleSheet* ruleProcessor =
- static_cast<nsHTMLCSSStyleSheet*>(
- mRuleProcessors[SheetType::StyleAttr].get());
- if (ruleProcessor) {
- lastScopedRN = ruleWalker.CurrentNode();
- if (aPseudoType ==
- CSSPseudoElementType::NotPseudo) {
- ruleProcessor->ElementRulesMatching(PresContext(),
- aElement,
- &ruleWalker);
- } else if (aPseudoType <
- CSSPseudoElementType::Count &&
- nsCSSPseudoElements::
- PseudoElementSupportsStyleAttribute(aPseudoType)) {
- ruleProcessor->PseudoElementRulesMatching(aPseudoElement,
- aPseudoType,
- &ruleWalker);
- }
- lastStyleAttrRN = ruleWalker.CurrentNode();
- haveImportantStyleAttrRules =
- !ruleWalker.GetCheckForImportantRules();
- }
- } else {
- // Second time through, we handle the !important rule(s).
- if (haveImportantStyleAttrRules) {
- AddImportantRules(lastStyleAttrRN, lastScopedRN, &ruleWalker);
- }
- }
- break;
- }
- default:
- MOZ_ASSERT(false, "unexpected result from gCascadeLevels lookup");
- break;
- }
- }
- while (rulesIndex != 0) {
- --rulesIndex;
- const RuleNodeInfo& ruleInfo = rules[rulesIndex];
- if (ruleInfo.mLevel != level->mLevel ||
- ruleInfo.mIsImportant != level->mIsImportant) {
- ++rulesIndex;
- break;
- }
- if (!doReplace) {
- ruleWalker.ForwardOnPossiblyCSSRule(ruleInfo.mRule);
- if (ruleInfo.mIsAnimationRule) {
- ruleWalker.CurrentNode()->SetIsAnimationRule();
- }
- }
- }
- }
- NS_ASSERTION(rulesIndex == 0,
- "rules are in incorrect cascading order, "
- "which means we replaced them incorrectly");
- return ruleWalker.CurrentNode();
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveStyleWithReplacement(Element* aElement,
- Element* aPseudoElement,
- nsStyleContext* aNewParentContext,
- nsStyleContext* aOldStyleContext,
- nsRestyleHint aReplacements,
- uint32_t aFlags)
- {
- nsRuleNode* ruleNode =
- RuleNodeWithReplacement(aElement, aPseudoElement,
- aOldStyleContext->RuleNode(),
- aOldStyleContext->GetPseudoType(), aReplacements);
- nsRuleNode* visitedRuleNode = nullptr;
- nsStyleContext* oldStyleIfVisited = aOldStyleContext->GetStyleIfVisited();
- if (oldStyleIfVisited) {
- if (oldStyleIfVisited->RuleNode() == aOldStyleContext->RuleNode()) {
- visitedRuleNode = ruleNode;
- } else {
- visitedRuleNode =
- RuleNodeWithReplacement(aElement, aPseudoElement,
- oldStyleIfVisited->RuleNode(),
- oldStyleIfVisited->GetPseudoType(),
- aReplacements);
- }
- }
- uint32_t flags = eNoFlags;
- if (aOldStyleContext->IsLinkContext()) {
- flags |= eIsLink;
- // GetContext handles propagating RelevantLinkVisited state from the
- // parent in non-link cases; all we need to pass in is if this link
- // is visited.
- if (aOldStyleContext->RelevantLinkVisited()) {
- flags |= eIsVisitedLink;
- }
- }
- CSSPseudoElementType pseudoType = aOldStyleContext->GetPseudoType();
- Element* elementForAnimation = nullptr;
- if (!(aFlags & eSkipStartingAnimations) &&
- (pseudoType == CSSPseudoElementType::NotPseudo ||
- pseudoType == CSSPseudoElementType::before ||
- pseudoType == CSSPseudoElementType::after)) {
- // We want to compute a correct elementForAnimation to pass in
- // because at this point the parameter is more than just the element
- // for animation; it's also used for the SetBodyTextColor call when
- // it's the body element.
- // However, we only want to set the flag to call CheckAnimationRule
- // if we're dealing with a replacement (such as style attribute
- // replacement) that could lead to the animation property changing,
- // and we explicitly do NOT want to call CheckAnimationRule when
- // we're trying to do an animation-only update.
- if (aReplacements & ~(eRestyle_CSSTransitions | eRestyle_CSSAnimations)) {
- flags |= eDoAnimation;
- }
- elementForAnimation = aElement;
- #ifdef DEBUG
- {
- nsIFrame* styleFrame = nsLayoutUtils::GetStyleFrame(elementForAnimation);
- NS_ASSERTION(pseudoType == CSSPseudoElementType::NotPseudo ||
- !styleFrame ||
- styleFrame->StyleContext()->GetPseudoType() ==
- CSSPseudoElementType::NotPseudo,
- "aElement should be the element and not the pseudo-element");
- }
- #endif
- }
- if (aElement && aElement->IsRootOfAnonymousSubtree()) {
- // For anonymous subtree roots, don't tweak "display" value based on whether
- // or not the parent is styled as a flex/grid container. (If the parent
- // has anonymous-subtree kids, then we know it's not actually going to get
- // a flex/grid container frame, anyway.)
- flags |= eSkipParentDisplayBasedStyleFixup;
- }
- return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
- aOldStyleContext->GetPseudo(), pseudoType,
- elementForAnimation, flags);
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveStyleWithoutAnimation(dom::Element* aTarget,
- nsStyleContext* aStyleContext,
- nsRestyleHint aWhichToRemove)
- {
- #ifdef DEBUG
- CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
- #endif
- MOZ_ASSERT(pseudoType == CSSPseudoElementType::NotPseudo ||
- pseudoType == CSSPseudoElementType::before ||
- pseudoType == CSSPseudoElementType::after,
- "unexpected type for animations");
- MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
- "stylo: the style set and restyle manager must have the same "
- "StyleBackendType");
- RestyleManager* restyleManager = PresContext()->RestyleManager()->AsGecko();
- bool oldSkipAnimationRules = restyleManager->SkipAnimationRules();
- restyleManager->SetSkipAnimationRules(true);
- RefPtr<nsStyleContext> result =
- ResolveStyleWithReplacement(aTarget, nullptr, aStyleContext->GetParent(),
- aStyleContext, aWhichToRemove,
- eSkipStartingAnimations);
- restyleManager->SetSkipAnimationRules(oldSkipAnimationRules);
- return result.forget();
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveStyleForText(nsIContent* aTextNode,
- nsStyleContext* aParentContext)
- {
- MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
- return GetContext(aParentContext, mRuleTree, nullptr,
- nsCSSAnonBoxes::mozText,
- CSSPseudoElementType::AnonBox, nullptr, eNoFlags);
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveStyleForOtherNonElement(nsStyleContext* aParentContext)
- {
- return GetContext(aParentContext, mRuleTree, nullptr,
- nsCSSAnonBoxes::mozOtherNonElement,
- CSSPseudoElementType::AnonBox, nullptr, eNoFlags);
- }
- void
- nsStyleSet::WalkRestrictionRule(CSSPseudoElementType aPseudoType,
- nsRuleWalker* aRuleWalker)
- {
- // This needs to match GetPseudoRestriction in nsRuleNode.cpp.
- aRuleWalker->SetLevel(SheetType::Agent, false, false);
- if (aPseudoType == CSSPseudoElementType::firstLetter)
- aRuleWalker->Forward(mFirstLetterRule);
- else if (aPseudoType == CSSPseudoElementType::firstLine)
- aRuleWalker->Forward(mFirstLineRule);
- else if (aPseudoType == CSSPseudoElementType::placeholder)
- aRuleWalker->Forward(mPlaceholderRule);
- }
- void
- nsStyleSet::WalkDisableTextZoomRule(Element* aElement, nsRuleWalker* aRuleWalker)
- {
- aRuleWalker->SetLevel(SheetType::Agent, false, false);
- if (aElement->IsSVGElement(nsGkAtoms::text))
- aRuleWalker->Forward(mDisableTextZoomStyleRule);
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
- CSSPseudoElementType aType,
- nsStyleContext* aParentContext,
- Element* aPseudoElement)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- NS_ASSERTION(aType < CSSPseudoElementType::Count,
- "must have pseudo element type");
- NS_ASSERTION(aParentElement, "Must have parent element");
- nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
- TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
- aParentElement->OwnerDoc());
- InitStyleScopes(treeContext, aParentElement);
- PseudoElementRuleProcessorData data(PresContext(), aParentElement,
- &ruleWalker, aType, treeContext,
- aPseudoElement);
- WalkRestrictionRule(aType, &ruleWalker);
- FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
- aParentElement, &ruleWalker);
- nsRuleNode *ruleNode = ruleWalker.CurrentNode();
- nsRuleNode *visitedRuleNode = nullptr;
- if (treeContext.HaveRelevantLink()) {
- treeContext.ResetForVisitedMatching();
- ruleWalker.Reset();
- WalkRestrictionRule(aType, &ruleWalker);
- FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
- aParentElement, &ruleWalker);
- visitedRuleNode = ruleWalker.CurrentNode();
- }
- // For pseudos, |data.IsLink()| being true means that
- // our parent node is a link.
- uint32_t flags = eNoFlags;
- if (aType == CSSPseudoElementType::before ||
- aType == CSSPseudoElementType::after) {
- flags |= eDoAnimation;
- } else {
- // Flex and grid containers don't expect to have any pseudo-element children
- // aside from ::before and ::after. So if we have such a child, we're not
- // actually in a flex/grid container, and we should skip flex/grid item
- // style fixup.
- flags |= eSkipParentDisplayBasedStyleFixup;
- }
- return GetContext(aParentContext, ruleNode, visitedRuleNode,
- nsCSSPseudoElements::GetPseudoAtom(aType), aType,
- aParentElement, flags);
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
- CSSPseudoElementType aType,
- nsStyleContext* aParentContext)
- {
- TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
- aParentElement->OwnerDoc());
- InitStyleScopes(treeContext, aParentElement);
- return ProbePseudoElementStyle(aParentElement, aType, aParentContext,
- treeContext);
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ProbePseudoElementStyle(Element* aParentElement,
- CSSPseudoElementType aType,
- nsStyleContext* aParentContext,
- TreeMatchContext& aTreeMatchContext,
- Element* aPseudoElement)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- NS_ASSERTION(aType < CSSPseudoElementType::Count,
- "must have pseudo element type");
- NS_ASSERTION(aParentElement, "aParentElement must not be null");
- nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
- nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
- aTreeMatchContext.ResetForUnvisitedMatching();
- PseudoElementRuleProcessorData data(PresContext(), aParentElement,
- &ruleWalker, aType, aTreeMatchContext,
- aPseudoElement);
- WalkRestrictionRule(aType, &ruleWalker);
- // not the root if there was a restriction rule
- nsRuleNode *adjustedRoot = ruleWalker.CurrentNode();
- FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
- aParentElement, &ruleWalker);
- nsRuleNode *ruleNode = ruleWalker.CurrentNode();
- if (ruleNode == adjustedRoot) {
- return nullptr;
- }
- nsRuleNode *visitedRuleNode = nullptr;
- if (aTreeMatchContext.HaveRelevantLink()) {
- aTreeMatchContext.ResetForVisitedMatching();
- ruleWalker.Reset();
- WalkRestrictionRule(aType, &ruleWalker);
- FileRules(EnumRulesMatching<PseudoElementRuleProcessorData>, &data,
- aParentElement, &ruleWalker);
- visitedRuleNode = ruleWalker.CurrentNode();
- }
- // For pseudos, |data.IsLink()| being true means that
- // our parent node is a link.
- uint32_t flags = eNoFlags;
- if (aType == CSSPseudoElementType::before ||
- aType == CSSPseudoElementType::after) {
- flags |= eDoAnimation;
- } else {
- // Flex and grid containers don't expect to have any pseudo-element children
- // aside from ::before and ::after. So if we have such a child, we're not
- // actually in a flex/grid container, and we should skip flex/grid item
- // style fixup.
- flags |= eSkipParentDisplayBasedStyleFixup;
- }
- RefPtr<nsStyleContext> result =
- GetContext(aParentContext, ruleNode, visitedRuleNode,
- pseudoTag, aType,
- aParentElement, flags);
- // For :before and :after pseudo-elements, having display: none or no
- // 'content' property is equivalent to not having the pseudo-element
- // at all.
- if (result &&
- (pseudoTag == nsCSSPseudoElements::before ||
- pseudoTag == nsCSSPseudoElements::after)) {
- const nsStyleDisplay *display = result->StyleDisplay();
- const nsStyleContent *content = result->StyleContent();
- // XXXldb What is contentCount for |content: ""|?
- if (display->mDisplay == StyleDisplay::None ||
- content->ContentCount() == 0) {
- result = nullptr;
- }
- }
- return result.forget();
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
- nsStyleContext* aParentContext,
- uint32_t aFlags)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- #ifdef DEBUG
- bool isAnonBox = nsCSSAnonBoxes::IsAnonBox(aPseudoTag)
- #ifdef MOZ_XUL
- && !nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag)
- #endif
- ;
- NS_PRECONDITION(isAnonBox, "Unexpected pseudo");
- #endif
- nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
- AnonBoxRuleProcessorData data(PresContext(), aPseudoTag, &ruleWalker);
- FileRules(EnumRulesMatching<AnonBoxRuleProcessorData>, &data, nullptr,
- &ruleWalker);
- if (aPseudoTag == nsCSSAnonBoxes::pageContent) {
- // Add any @page rules that are specified.
- nsTArray<nsCSSPageRule*> rules;
- nsTArray<css::ImportantStyleData*> importantRules;
- AppendPageRules(rules);
- for (uint32_t i = 0, i_end = rules.Length(); i != i_end; ++i) {
- css::Declaration* declaration = rules[i]->Declaration();
- declaration->SetImmutable();
- ruleWalker.Forward(declaration);
- css::ImportantStyleData* importantRule =
- declaration->GetImportantStyleData();
- if (importantRule) {
- importantRules.AppendElement(importantRule);
- }
- }
- for (uint32_t i = 0, i_end = importantRules.Length(); i != i_end; ++i) {
- ruleWalker.Forward(importantRules[i]);
- }
- }
- return GetContext(aParentContext, ruleWalker.CurrentNode(), nullptr,
- aPseudoTag, CSSPseudoElementType::AnonBox,
- nullptr, aFlags);
- }
- #ifdef MOZ_XUL
- already_AddRefed<nsStyleContext>
- nsStyleSet::ResolveXULTreePseudoStyle(Element* aParentElement,
- nsIAtom* aPseudoTag,
- nsStyleContext* aParentContext,
- nsICSSPseudoComparator* aComparator)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- NS_ASSERTION(aPseudoTag, "must have pseudo tag");
- NS_ASSERTION(nsCSSAnonBoxes::IsTreePseudoElement(aPseudoTag),
- "Unexpected pseudo");
- nsRuleWalker ruleWalker(mRuleTree, mAuthorStyleDisabled);
- TreeMatchContext treeContext(true, nsRuleWalker::eRelevantLinkUnvisited,
- aParentElement->OwnerDoc());
- InitStyleScopes(treeContext, aParentElement);
- XULTreeRuleProcessorData data(PresContext(), aParentElement, &ruleWalker,
- aPseudoTag, aComparator, treeContext);
- FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data, aParentElement,
- &ruleWalker);
- nsRuleNode *ruleNode = ruleWalker.CurrentNode();
- nsRuleNode *visitedRuleNode = nullptr;
- if (treeContext.HaveRelevantLink()) {
- treeContext.ResetForVisitedMatching();
- ruleWalker.Reset();
- FileRules(EnumRulesMatching<XULTreeRuleProcessorData>, &data,
- aParentElement, &ruleWalker);
- visitedRuleNode = ruleWalker.CurrentNode();
- }
- return GetContext(aParentContext, ruleNode, visitedRuleNode,
- // For pseudos, |data.IsLink()| being true means that
- // our parent node is a link.
- aPseudoTag, CSSPseudoElementType::XULTree,
- nullptr, eNoFlags);
- }
- #endif
- bool
- nsStyleSet::AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray)
- {
- NS_ENSURE_FALSE(mInShutdown, false);
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- nsPresContext* presContext = PresContext();
- for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
- if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
- continue;
- nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
- (mRuleProcessors[gCSSSheetTypes[i]].get());
- if (ruleProc && !ruleProc->AppendFontFaceRules(presContext, aArray))
- return false;
- }
- return true;
- }
- nsCSSKeyframesRule*
- nsStyleSet::KeyframesRuleForName(const nsString& aName)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- nsPresContext* presContext = PresContext();
- for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
- if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
- continue;
- nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
- (mRuleProcessors[gCSSSheetTypes[i]].get());
- if (!ruleProc)
- continue;
- nsCSSKeyframesRule* result =
- ruleProc->KeyframesRuleForName(presContext, aName);
- if (result)
- return result;
- }
- return nullptr;
- }
- nsCSSCounterStyleRule*
- nsStyleSet::CounterStyleRuleForName(const nsAString& aName)
- {
- NS_ENSURE_FALSE(mInShutdown, nullptr);
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- nsPresContext* presContext = PresContext();
- for (uint32_t i = ArrayLength(gCSSSheetTypes); i-- != 0; ) {
- if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
- continue;
- nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
- (mRuleProcessors[gCSSSheetTypes[i]].get());
- if (!ruleProc)
- continue;
- nsCSSCounterStyleRule *result =
- ruleProc->CounterStyleRuleForName(presContext, aName);
- if (result)
- return result;
- }
- return nullptr;
- }
- bool
- nsStyleSet::AppendFontFeatureValuesRules(
- nsTArray<nsCSSFontFeatureValuesRule*>& aArray)
- {
- NS_ENSURE_FALSE(mInShutdown, false);
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- nsPresContext* presContext = PresContext();
- for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
- nsCSSRuleProcessor *ruleProc = static_cast<nsCSSRuleProcessor*>
- (mRuleProcessors[gCSSSheetTypes[i]].get());
- if (ruleProc &&
- !ruleProc->AppendFontFeatureValuesRules(presContext, aArray))
- {
- return false;
- }
- }
- return true;
- }
- already_AddRefed<gfxFontFeatureValueSet>
- nsStyleSet::GetFontFeatureValuesLookup()
- {
- if (mInitFontFeatureValuesLookup) {
- mInitFontFeatureValuesLookup = false;
- nsTArray<nsCSSFontFeatureValuesRule*> rules;
- AppendFontFeatureValuesRules(rules);
- mFontFeatureValuesLookup = new gfxFontFeatureValueSet();
- uint32_t i, numRules = rules.Length();
- for (i = 0; i < numRules; i++) {
- nsCSSFontFeatureValuesRule *rule = rules[i];
- const nsTArray<FontFamilyName>& familyList = rule->GetFamilyList().GetFontlist();
- const nsTArray<gfxFontFeatureValueSet::FeatureValues>&
- featureValues = rule->GetFeatureValues();
- // for each family
- size_t f, numFam;
- numFam = familyList.Length();
- for (f = 0; f < numFam; f++) {
- mFontFeatureValuesLookup->AddFontFeatureValues(familyList[f].mName,
- featureValues);
- }
- }
- }
- RefPtr<gfxFontFeatureValueSet> lookup = mFontFeatureValuesLookup;
- return lookup.forget();
- }
- bool
- nsStyleSet::AppendPageRules(nsTArray<nsCSSPageRule*>& aArray)
- {
- NS_ENSURE_FALSE(mInShutdown, false);
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- nsPresContext* presContext = PresContext();
- for (uint32_t i = 0; i < ArrayLength(gCSSSheetTypes); ++i) {
- if (gCSSSheetTypes[i] == SheetType::ScopedDoc)
- continue;
- nsCSSRuleProcessor* ruleProc = static_cast<nsCSSRuleProcessor*>
- (mRuleProcessors[gCSSSheetTypes[i]].get());
- if (ruleProc && !ruleProc->AppendPageRules(presContext, aArray))
- return false;
- }
- return true;
- }
- void
- nsStyleSet::BeginShutdown()
- {
- mInShutdown = 1;
- }
- void
- nsStyleSet::Shutdown()
- {
- mRuleTree = nullptr;
- GCRuleTrees();
- MOZ_ASSERT(mUnusedRuleNodeList.isEmpty());
- MOZ_ASSERT(mUnusedRuleNodeCount == 0);
- }
- void
- nsStyleSet::GCRuleTrees()
- {
- MOZ_ASSERT(!mInReconstruct);
- MOZ_ASSERT(!mInGC);
- mInGC = true;
- while (!mUnusedRuleNodeList.isEmpty()) {
- nsRuleNode* node = mUnusedRuleNodeList.popFirst();
- #ifdef DEBUG
- if (node == mOldRootNode) {
- // Flag that we've GCed the old root, if any.
- mOldRootNode = nullptr;
- }
- #endif
- node->Destroy();
- }
- #ifdef DEBUG
- NS_ASSERTION(!mOldRootNode, "Should have GCed old root node");
- mOldRootNode = nullptr;
- #endif
- mUnusedRuleNodeCount = 0;
- mInGC = false;
- }
- already_AddRefed<nsStyleContext>
- nsStyleSet::ReparentStyleContext(nsStyleContext* aStyleContext,
- nsStyleContext* aNewParentContext,
- Element* aElement)
- {
- MOZ_ASSERT(aStyleContext, "aStyleContext must not be null");
- // This short-circuit is OK because we don't call TryInitatingTransition
- // during style reresolution if the style context pointer hasn't changed.
- if (aStyleContext->GetParent() == aNewParentContext) {
- RefPtr<nsStyleContext> ret = aStyleContext;
- return ret.forget();
- }
- nsIAtom* pseudoTag = aStyleContext->GetPseudo();
- CSSPseudoElementType pseudoType = aStyleContext->GetPseudoType();
- nsRuleNode* ruleNode = aStyleContext->RuleNode();
- MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
- "stylo: the style set and restyle manager must have the same "
- "StyleBackendType");
- NS_ASSERTION(!PresContext()->RestyleManager()->AsGecko()->SkipAnimationRules(),
- "we no longer handle SkipAnimationRules()");
- nsRuleNode* visitedRuleNode = nullptr;
- nsStyleContext* visitedContext = aStyleContext->GetStyleIfVisited();
- // Reparenting a style context just changes where we inherit from,
- // not what rules we match or what our DOM looks like. In
- // particular, it doesn't change whether this is a style context for
- // a link.
- if (visitedContext) {
- visitedRuleNode = visitedContext->RuleNode();
- }
- uint32_t flags = eNoFlags;
- if (aStyleContext->IsLinkContext()) {
- flags |= eIsLink;
- // GetContext handles propagating RelevantLinkVisited state from the
- // parent in non-link cases; all we need to pass in is if this link
- // is visited.
- if (aStyleContext->RelevantLinkVisited()) {
- flags |= eIsVisitedLink;
- }
- }
- if (pseudoType == CSSPseudoElementType::NotPseudo ||
- pseudoType == CSSPseudoElementType::before ||
- pseudoType == CSSPseudoElementType::after) {
- flags |= eDoAnimation;
- }
- if (aElement && aElement->IsRootOfAnonymousSubtree()) {
- // For anonymous subtree roots, don't tweak "display" value based on whether
- // or not the parent is styled as a flex/grid container. (If the parent
- // has anonymous-subtree kids, then we know it's not actually going to get
- // a flex/grid container frame, anyway.)
- flags |= eSkipParentDisplayBasedStyleFixup;
- }
- return GetContext(aNewParentContext, ruleNode, visitedRuleNode,
- pseudoTag, pseudoType,
- aElement, flags);
- }
- struct MOZ_STACK_CLASS StatefulData : public StateRuleProcessorData {
- StatefulData(nsPresContext* aPresContext, Element* aElement,
- EventStates aStateMask, TreeMatchContext& aTreeMatchContext)
- : StateRuleProcessorData(aPresContext, aElement, aStateMask,
- aTreeMatchContext),
- mHint(nsRestyleHint(0))
- {}
- nsRestyleHint mHint;
- };
- struct MOZ_STACK_CLASS StatefulPseudoElementData : public PseudoElementStateRuleProcessorData {
- StatefulPseudoElementData(nsPresContext* aPresContext, Element* aElement,
- EventStates aStateMask, CSSPseudoElementType aPseudoType,
- TreeMatchContext& aTreeMatchContext, Element* aPseudoElement)
- : PseudoElementStateRuleProcessorData(aPresContext, aElement, aStateMask,
- aPseudoType, aTreeMatchContext,
- aPseudoElement),
- mHint(nsRestyleHint(0))
- {}
- nsRestyleHint mHint;
- };
- static bool SheetHasDocumentStateStyle(nsIStyleRuleProcessor* aProcessor,
- void *aData)
- {
- StatefulData* data = (StatefulData*)aData;
- if (aProcessor->HasDocumentStateDependentStyle(data)) {
- data->mHint = eRestyle_Self;
- return false; // don't continue
- }
- return true; // continue
- }
- // Test if style is dependent on a document state.
- bool
- nsStyleSet::HasDocumentStateDependentStyle(nsIContent* aContent,
- EventStates aStateMask)
- {
- if (!aContent || !aContent->IsElement())
- return false;
- TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
- aContent->OwnerDoc());
- InitStyleScopes(treeContext, aContent->AsElement());
- StatefulData data(PresContext(), aContent->AsElement(), aStateMask,
- treeContext);
- WalkRuleProcessors(SheetHasDocumentStateStyle, &data, true);
- return data.mHint != 0;
- }
- static bool SheetHasStatefulStyle(nsIStyleRuleProcessor* aProcessor,
- void *aData)
- {
- StatefulData* data = (StatefulData*)aData;
- nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
- data->mHint = nsRestyleHint(data->mHint | hint);
- return true; // continue
- }
- static bool SheetHasStatefulPseudoElementStyle(nsIStyleRuleProcessor* aProcessor,
- void *aData)
- {
- StatefulPseudoElementData* data = (StatefulPseudoElementData*)aData;
- nsRestyleHint hint = aProcessor->HasStateDependentStyle(data);
- data->mHint = nsRestyleHint(data->mHint | hint);
- return true; // continue
- }
- // Test if style is dependent on content state
- nsRestyleHint
- nsStyleSet::HasStateDependentStyle(Element* aElement,
- EventStates aStateMask)
- {
- TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
- aElement->OwnerDoc());
- InitStyleScopes(treeContext, aElement);
- StatefulData data(PresContext(), aElement, aStateMask, treeContext);
- WalkRuleProcessors(SheetHasStatefulStyle, &data, false);
- return data.mHint;
- }
- nsRestyleHint
- nsStyleSet::HasStateDependentStyle(Element* aElement,
- CSSPseudoElementType aPseudoType,
- Element* aPseudoElement,
- EventStates aStateMask)
- {
- TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
- aElement->OwnerDoc());
- InitStyleScopes(treeContext, aElement);
- StatefulPseudoElementData data(PresContext(), aElement, aStateMask,
- aPseudoType, treeContext, aPseudoElement);
- WalkRuleProcessors(SheetHasStatefulPseudoElementStyle, &data, false);
- return data.mHint;
- }
- struct MOZ_STACK_CLASS AttributeData : public AttributeRuleProcessorData {
- AttributeData(nsPresContext* aPresContext, Element* aElement,
- int32_t aNameSpaceID, nsIAtom* aAttribute, int32_t aModType,
- bool aAttrHasChanged, const nsAttrValue* aOtherValue,
- TreeMatchContext& aTreeMatchContext)
- : AttributeRuleProcessorData(aPresContext, aElement, aNameSpaceID,
- aAttribute, aModType, aAttrHasChanged,
- aOtherValue, aTreeMatchContext),
- mHint(nsRestyleHint(0))
- {}
- nsRestyleHint mHint;
- RestyleHintData mHintData;
- };
- static bool
- SheetHasAttributeStyle(nsIStyleRuleProcessor* aProcessor, void *aData)
- {
- AttributeData* data = (AttributeData*)aData;
- nsRestyleHint hint =
- aProcessor->HasAttributeDependentStyle(data, data->mHintData);
- data->mHint = nsRestyleHint(data->mHint | hint);
- return true; // continue
- }
- // Test if style is dependent on content state
- nsRestyleHint
- nsStyleSet::HasAttributeDependentStyle(Element* aElement,
- int32_t aNameSpaceID,
- nsIAtom* aAttribute,
- int32_t aModType,
- bool aAttrHasChanged,
- const nsAttrValue* aOtherValue,
- mozilla::RestyleHintData&
- aRestyleHintDataResult)
- {
- TreeMatchContext treeContext(false, nsRuleWalker::eLinksVisitedOrUnvisited,
- aElement->OwnerDoc());
- InitStyleScopes(treeContext, aElement);
- AttributeData data(PresContext(), aElement, aNameSpaceID, aAttribute,
- aModType, aAttrHasChanged, aOtherValue, treeContext);
- WalkRuleProcessors(SheetHasAttributeStyle, &data, false);
- if (!(data.mHint & eRestyle_Subtree)) {
- // No point keeping the list of selectors around if we are going to
- // restyle the whole subtree unconditionally.
- aRestyleHintDataResult = Move(data.mHintData);
- }
- return data.mHint;
- }
- bool
- nsStyleSet::MediumFeaturesChanged()
- {
- NS_ASSERTION(mBatching == 0, "rule processors out of date");
- // We can't use WalkRuleProcessors without a content node.
- nsPresContext* presContext = PresContext();
- bool stylesChanged = false;
- for (nsIStyleRuleProcessor* processor : mRuleProcessors) {
- if (!processor) {
- continue;
- }
- bool thisChanged = processor->MediumFeaturesChanged(presContext);
- stylesChanged = stylesChanged || thisChanged;
- }
- for (nsIStyleRuleProcessor* processor : mScopedDocSheetRuleProcessors) {
- bool thisChanged = processor->MediumFeaturesChanged(presContext);
- stylesChanged = stylesChanged || thisChanged;
- }
- if (mBindingManager) {
- bool thisChanged = false;
- mBindingManager->MediumFeaturesChanged(presContext, &thisChanged);
- stylesChanged = stylesChanged || thisChanged;
- }
- return stylesChanged;
- }
- bool
- nsStyleSet::EnsureUniqueInnerOnCSSSheets()
- {
- AutoTArray<CSSStyleSheet*, 32> queue;
- for (SheetType type : gCSSSheetTypes) {
- for (CSSStyleSheet* sheet : mSheets[type]) {
- queue.AppendElement(sheet);
- }
- }
- if (mBindingManager) {
- AutoTArray<StyleSheet*, 32> sheets;
- // XXXheycam stylo: AppendAllSheets will need to be able to return either
- // CSSStyleSheets or ServoStyleSheets, on request (and then here requesting
- // CSSStyleSheets).
- mBindingManager->AppendAllSheets(sheets);
- for (StyleSheet* sheet : sheets) {
- MOZ_ASSERT(sheet->IsGecko(), "stylo: AppendAllSheets shouldn't give us "
- "ServoStyleSheets yet");
- queue.AppendElement(sheet->AsGecko());
- }
- }
- while (!queue.IsEmpty()) {
- uint32_t idx = queue.Length() - 1;
- CSSStyleSheet* sheet = queue[idx];
- queue.RemoveElementAt(idx);
- sheet->EnsureUniqueInner();
- // Enqueue all the sheet's children.
- sheet->AppendAllChildSheets(queue);
- }
- bool res = mNeedsRestyleAfterEnsureUniqueInner;
- mNeedsRestyleAfterEnsureUniqueInner = false;
- return res;
- }
- nsIStyleRule*
- nsStyleSet::InitialStyleRule()
- {
- if (!mInitialStyleRule) {
- mInitialStyleRule = new nsInitialStyleRule;
- }
- return mInitialStyleRule;
- }
- bool
- nsStyleSet::HasRuleProcessorUsedByMultipleStyleSets(SheetType aSheetType)
- {
- MOZ_ASSERT(size_t(aSheetType) < ArrayLength(mRuleProcessors));
- if (!IsCSSSheetType(aSheetType) || !mRuleProcessors[aSheetType]) {
- return false;
- }
- nsCSSRuleProcessor* rp =
- static_cast<nsCSSRuleProcessor*>(mRuleProcessors[aSheetType].get());
- return rp->IsUsedByMultipleStyleSets();
- }
- void
- nsStyleSet::ClearSelectors()
- {
- // We might be called before we've done our first rule tree construction.
- if (!mRuleTree) {
- return;
- }
- MOZ_ASSERT(PresContext()->RestyleManager()->IsGecko(),
- "stylo: the style set and restyle manager must have the same "
- "StyleBackendType");
- PresContext()->RestyleManager()->AsGecko()->ClearSelectors();
- }
|