1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855 |
- /* -*- 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 interface (to internal code) for retrieving computed style data */
- #include "CSSVariableImageTable.h"
- #include "mozilla/DebugOnly.h"
- #include "mozilla/Maybe.h"
- #include "nsCSSAnonBoxes.h"
- #include "nsCSSPseudoElements.h"
- #include "nsStyleConsts.h"
- #include "nsStyleStruct.h"
- #include "nsStyleStructInlines.h"
- #include "nsString.h"
- #include "nsPresContext.h"
- #include "nsIStyleRule.h"
- #include "nsCOMPtr.h"
- #include "nsStyleSet.h"
- #include "nsIPresShell.h"
- #include "nsRuleNode.h"
- #include "nsStyleContext.h"
- #include "mozilla/StyleAnimationValue.h"
- #include "GeckoProfiler.h"
- #include "nsIDocument.h"
- #include "nsPrintfCString.h"
- #include "RubyUtils.h"
- #include "mozilla/Preferences.h"
- #include "mozilla/ArenaObjectID.h"
- #include "mozilla/StyleSetHandle.h"
- #include "mozilla/StyleSetHandleInlines.h"
- #include "mozilla/ReflowInput.h"
- #include "nsLayoutUtils.h"
- #include "nsCoord.h"
- #include "nsFontMetrics.h"
- // Ensure the binding function declarations in nsStyleContext.h matches
- // those in ServoBindings.h.
- #include "mozilla/ServoBindings.h"
- using namespace mozilla;
- //----------------------------------------------------------------------
- #ifdef DEBUG
- // Check that the style struct IDs are in the same order as they are
- // in nsStyleStructList.h, since when we set up the IDs, we include
- // the inherited and reset structs spearately from nsStyleStructList.h
- enum DebugStyleStruct {
- #define STYLE_STRUCT(name, checkdata_cb) eDebugStyleStruct_##name,
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- };
- #define STYLE_STRUCT(name, checkdata_cb) \
- static_assert(static_cast<int>(eDebugStyleStruct_##name) == \
- static_cast<int>(eStyleStruct_##name), \
- "Style struct IDs are not declared in order?");
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- const uint32_t nsStyleContext::sDependencyTable[] = {
- #define STYLE_STRUCT(name, checkdata_cb)
- #define STYLE_STRUCT_DEP(dep) NS_STYLE_INHERIT_BIT(dep) |
- #define STYLE_STRUCT_END() 0,
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- #undef STYLE_STRUCT_DEP
- #undef STYLE_STRUCT_END
- };
- // Whether to perform expensive assertions in the nsStyleContext destructor.
- static bool sExpensiveStyleStructAssertionsEnabled;
- #endif
- nsStyleContext::nsStyleContext(nsStyleContext* aParent,
- OwningStyleContextSource&& aSource,
- nsIAtom* aPseudoTag,
- CSSPseudoElementType aPseudoType)
- : mParent(aParent)
- , mChild(nullptr)
- , mEmptyChild(nullptr)
- , mPseudoTag(aPseudoTag)
- , mSource(Move(aSource))
- #ifdef MOZ_STYLO
- , mPresContext(nullptr)
- #endif
- , mCachedResetData(nullptr)
- , mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT)
- , mRefCnt(0)
- #ifdef MOZ_STYLO
- , mStoredChangeHint(nsChangeHint(0))
- #ifdef DEBUG
- , mConsumedChangeHint(false)
- #endif
- #endif
- #ifdef DEBUG
- , mFrameRefCnt(0)
- , mComputingStruct(nsStyleStructID_None)
- #endif
- {
- MOZ_COUNT_CTOR(nsStyleContext);
- }
- nsStyleContext::nsStyleContext(nsStyleContext* aParent,
- nsIAtom* aPseudoTag,
- CSSPseudoElementType aPseudoType,
- already_AddRefed<nsRuleNode> aRuleNode,
- bool aSkipParentDisplayBasedStyleFixup)
- : nsStyleContext(aParent, OwningStyleContextSource(Move(aRuleNode)),
- aPseudoTag, aPseudoType)
- {
- #ifdef MOZ_STYLO
- mPresContext = mSource.AsGeckoRuleNode()->PresContext();
- #endif
- if (aParent) {
- #ifdef DEBUG
- nsRuleNode *r1 = mParent->RuleNode(), *r2 = mSource.AsGeckoRuleNode();
- while (r1->GetParent())
- r1 = r1->GetParent();
- while (r2->GetParent())
- r2 = r2->GetParent();
- NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
- #endif
- } else {
- PresContext()->PresShell()->StyleSet()->RootStyleContextAdded();
- }
- mSource.AsGeckoRuleNode()->SetUsedDirectly(); // before ApplyStyleFixups()!
- FinishConstruction(aSkipParentDisplayBasedStyleFixup);
- }
- nsStyleContext::nsStyleContext(nsStyleContext* aParent,
- nsPresContext* aPresContext,
- nsIAtom* aPseudoTag,
- CSSPseudoElementType aPseudoType,
- already_AddRefed<ServoComputedValues> aComputedValues,
- bool aSkipParentDisplayBasedStyleFixup)
- : nsStyleContext(aParent, OwningStyleContextSource(Move(aComputedValues)),
- aPseudoTag, aPseudoType)
- {
- #ifdef MOZ_STYLO
- mPresContext = aPresContext;
- #endif
- FinishConstruction(aSkipParentDisplayBasedStyleFixup);
- }
- void
- nsStyleContext::FinishConstruction(bool aSkipParentDisplayBasedStyleFixup)
- {
- // This check has to be done "backward", because if it were written the
- // more natural way it wouldn't fail even when it needed to.
- static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
- static_cast<CSSPseudoElementTypeBase>(
- CSSPseudoElementType::MAX),
- "pseudo element bits no longer fit in a uint64_t");
- MOZ_ASSERT(!mSource.IsNull());
- #ifdef DEBUG
- static_assert(MOZ_ARRAY_LENGTH(nsStyleContext::sDependencyTable)
- == nsStyleStructID_Length,
- "Number of items in dependency table doesn't match IDs");
- #endif
- mNextSibling = this;
- mPrevSibling = this;
- if (mParent) {
- mParent->AddChild(this);
- }
- SetStyleBits();
- if (!mSource.IsServoComputedValues()) {
- ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup);
- }
- #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
- NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
- "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
- #undef eStyleStruct_LastItem
- }
- nsStyleContext::~nsStyleContext()
- {
- MOZ_COUNT_DTOR(nsStyleContext);
- NS_ASSERTION((nullptr == mChild) && (nullptr == mEmptyChild), "destructing context with children");
- #ifdef DEBUG
- if (sExpensiveStyleStructAssertionsEnabled) {
- // Assert that the style structs we are about to destroy are not referenced
- // anywhere else in the style context tree. These checks are expensive,
- // which is why they are not enabled by default.
- nsStyleContext* root = this;
- while (root->mParent) {
- root = root->mParent;
- }
- root->AssertStructsNotUsedElsewhere(this,
- std::numeric_limits<int32_t>::max());
- } else {
- // In DEBUG builds when the pref is not enabled, we perform a more limited
- // check just of the children of this style context.
- AssertStructsNotUsedElsewhere(this, 2);
- }
- #endif
- nsPresContext *presContext = PresContext();
- DebugOnly<nsStyleSet*> geckoStyleSet = presContext->PresShell()->StyleSet()->GetAsGecko();
- NS_ASSERTION(!geckoStyleSet ||
- geckoStyleSet->GetRuleTree() == mSource.AsGeckoRuleNode()->RuleTree() ||
- geckoStyleSet->IsInRuleTreeReconstruct(),
- "destroying style context from old rule tree too late");
- if (mParent) {
- mParent->RemoveChild(this);
- } else {
- presContext->StyleSet()->RootStyleContextRemoved();
- }
- // Free up our data structs.
- mCachedInheritedData.DestroyStructs(mBits, presContext);
- if (mCachedResetData) {
- mCachedResetData->Destroy(mBits, presContext);
- }
- // Free any ImageValues we were holding on to for CSS variable values.
- CSSVariableImageTable::RemoveAll(this);
- }
- #ifdef DEBUG
- void
- nsStyleContext::AssertStructsNotUsedElsewhere(
- nsStyleContext* aDestroyingContext,
- int32_t aLevels) const
- {
- if (aLevels == 0) {
- return;
- }
- void* data;
- if (mBits & NS_STYLE_IS_GOING_AWAY) {
- return;
- }
- if (this != aDestroyingContext) {
- nsInheritedStyleData& destroyingInheritedData =
- aDestroyingContext->mCachedInheritedData;
- #define STYLE_STRUCT_INHERITED(name_, checkdata_cb) \
- data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_]; \
- if (data && \
- !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
- (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
- printf_stderr("style struct %p found on style context %p\n", data, this);\
- nsString url; \
- nsresult rv = PresContext()->Document()->GetURL(url); \
- if (NS_SUCCEEDED(rv)) { \
- printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
- } \
- MOZ_ASSERT(false, "destroying " #name_ " style struct still present " \
- "in style context tree"); \
- }
- #define STYLE_STRUCT_RESET(name_, checkdata_cb)
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT_INHERITED
- #undef STYLE_STRUCT_RESET
- if (mCachedResetData) {
- nsResetStyleData* destroyingResetData =
- aDestroyingContext->mCachedResetData;
- if (destroyingResetData) {
- #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
- #define STYLE_STRUCT_RESET(name_, checkdata_cb) \
- data = destroyingResetData->mStyleStructs[eStyleStruct_##name_]; \
- if (data && \
- !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
- (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
- printf_stderr("style struct %p found on style context %p\n", data, \
- this); \
- nsString url; \
- nsresult rv = PresContext()->Document()->GetURL(url); \
- if (NS_SUCCEEDED(rv)) { \
- printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
- } \
- MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
- "in style context tree"); \
- }
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT_INHERITED
- #undef STYLE_STRUCT_RESET
- }
- }
- }
- if (mChild) {
- const nsStyleContext* child = mChild;
- do {
- child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
- child = child->mNextSibling;
- } while (child != mChild);
- }
- if (mEmptyChild) {
- const nsStyleContext* child = mEmptyChild;
- do {
- child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
- child = child->mNextSibling;
- } while (child != mEmptyChild);
- }
- }
- #endif
- void nsStyleContext::AddChild(nsStyleContext* aChild)
- {
- NS_ASSERTION(aChild->mPrevSibling == aChild &&
- aChild->mNextSibling == aChild,
- "child already in a child list");
- nsStyleContext **listPtr = aChild->mSource.MatchesNoRules() ? &mEmptyChild : &mChild;
- // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
- // etc. don't alias with what ever listPtr points at.
- nsStyleContext *list = *listPtr;
- // Insert at the beginning of the list. See also FindChildWithRules.
- if (list) {
- // Link into existing elements, if there are any.
- aChild->mNextSibling = list;
- aChild->mPrevSibling = list->mPrevSibling;
- list->mPrevSibling->mNextSibling = aChild;
- list->mPrevSibling = aChild;
- }
- (*listPtr) = aChild;
- }
- void nsStyleContext::RemoveChild(nsStyleContext* aChild)
- {
- NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument");
- nsStyleContext **list = aChild->mSource.MatchesNoRules() ? &mEmptyChild : &mChild;
- if (aChild->mPrevSibling != aChild) { // has siblings
- if ((*list) == aChild) {
- (*list) = (*list)->mNextSibling;
- }
- }
- else {
- NS_ASSERTION((*list) == aChild, "bad sibling pointers");
- (*list) = nullptr;
- }
- aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
- aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
- aChild->mNextSibling = aChild;
- aChild->mPrevSibling = aChild;
- }
- void
- nsStyleContext::MoveTo(nsStyleContext* aNewParent)
- {
- MOZ_ASSERT(aNewParent != mParent);
- // This function shouldn't be getting called if the parents have different
- // values for some flags in mBits (unless the flag is also set on this style
- // context) because if that were the case we would need to recompute those
- // bits for |this|.
- #define CHECK_FLAG(bit_) \
- MOZ_ASSERT((mParent->mBits & (bit_)) == (aNewParent->mBits & (bit_)) || \
- (mBits & (bit_)), \
- "MoveTo cannot be called if " #bit_ " value on old and new " \
- "style context parents do not match, unless the flag is set " \
- "on this style context");
- CHECK_FLAG(NS_STYLE_HAS_PSEUDO_ELEMENT_DATA)
- CHECK_FLAG(NS_STYLE_IN_DISPLAY_NONE_SUBTREE)
- CHECK_FLAG(NS_STYLE_HAS_TEXT_DECORATION_LINES)
- CHECK_FLAG(NS_STYLE_RELEVANT_LINK_VISITED)
- #undef CHECK_FLAG
- // Assertions checking for visited style are just to avoid some tricky
- // cases we can't be bothered handling at the moment.
- MOZ_ASSERT(!IsStyleIfVisited());
- MOZ_ASSERT(!mParent->IsStyleIfVisited());
- MOZ_ASSERT(!aNewParent->IsStyleIfVisited());
- MOZ_ASSERT(!mStyleIfVisited || mStyleIfVisited->mParent == mParent);
- if (mParent->HasChildThatUsesResetStyle()) {
- aNewParent->AddStyleBit(NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE);
- }
- mParent->RemoveChild(this);
- mParent = aNewParent;
- mParent->AddChild(this);
- if (mStyleIfVisited) {
- mStyleIfVisited->mParent->RemoveChild(mStyleIfVisited);
- mStyleIfVisited->mParent = aNewParent;
- mStyleIfVisited->mParent->AddChild(mStyleIfVisited);
- }
- }
- already_AddRefed<nsStyleContext>
- nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag,
- NonOwningStyleContextSource aSource,
- NonOwningStyleContextSource aSourceIfVisited,
- bool aRelevantLinkVisited)
- {
- uint32_t threshold = 10; // The # of siblings we're willing to examine
- // before just giving this whole thing up.
- RefPtr<nsStyleContext> result;
- nsStyleContext *list = aSource.MatchesNoRules() ? mEmptyChild : mChild;
- if (list) {
- nsStyleContext *child = list;
- do {
- if (child->mSource.AsRaw() == aSource &&
- child->mPseudoTag == aPseudoTag &&
- !child->IsStyleIfVisited() &&
- child->RelevantLinkVisited() == aRelevantLinkVisited) {
- bool match = false;
- if (!aSourceIfVisited.IsNull()) {
- match = child->GetStyleIfVisited() &&
- child->GetStyleIfVisited()->mSource.AsRaw() == aSourceIfVisited;
- } else {
- match = !child->GetStyleIfVisited();
- }
- if (match && !(child->mBits & NS_STYLE_INELIGIBLE_FOR_SHARING)) {
- result = child;
- break;
- }
- }
- child = child->mNextSibling;
- threshold--;
- if (threshold == 0)
- break;
- } while (child != list);
- }
- if (result) {
- if (result != list) {
- // Move result to the front of the list.
- RemoveChild(result);
- AddChild(result);
- }
- result->mBits |= NS_STYLE_IS_SHARED;
- }
- return result.forget();
- }
- const void* nsStyleContext::StyleData(nsStyleStructID aSID)
- {
- const void* cachedData = GetCachedStyleData(aSID);
- if (cachedData)
- return cachedData; // We have computed data stored on this node in the context tree.
- // Our style source will take care of it for us.
- const void* newData;
- if (mSource.IsGeckoRuleNode()) {
- newData = mSource.AsGeckoRuleNode()->GetStyleData(aSID, this, true);
- if (!nsCachedStyleData::IsReset(aSID)) {
- // always cache inherited data on the style context; the rule
- // node set the bit in mBits for us if needed.
- mCachedInheritedData.mStyleStructs[aSID] = const_cast<void*>(newData);
- }
- } else {
- newData = StyleStructFromServoComputedValues(aSID);
- // perform any remaining main thread work on the struct
- switch (aSID) {
- #define STYLE_STRUCT(name_, checkdata_cb_) \
- case eStyleStruct_##name_: { \
- auto data = static_cast<const nsStyle##name_*>(newData); \
- const_cast<nsStyle##name_*>(data)->FinishStyle(PresContext()); \
- break; \
- }
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- default:
- MOZ_ASSERT_UNREACHABLE("unexpected nsStyleStructID value");
- break;
- }
- // The Servo-backed StyleContextSource owns the struct.
- AddStyleBit(nsCachedStyleData::GetBitForSID(aSID));
- // XXXbholley: Unconditionally caching reset structs here defeats the memory
- // optimization where we lazily allocate mCachedResetData, so that we can avoid
- // performing an FFI call each time we want to get the style structs. We should
- // measure the tradeoffs at some point. If the FFI overhead is low and the memory
- // win significant, we should consider _always_ grabbing the struct over FFI, and
- // potentially giving mCachedInheritedData the same treatment.
- //
- // Note that there is a similar comment in the struct getters in nsStyleContext.h.
- SetStyle(aSID, const_cast<void*>(newData));
- }
- return newData;
- }
- // This is an evil evil function, since it forces you to alloc your own separate copy of
- // style data! Do not use this function unless you absolutely have to! You should avoid
- // this at all costs! -dwh
- void*
- nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
- {
- MOZ_ASSERT(!mSource.IsServoComputedValues(),
- "Can't COW-mutate servo values from Gecko!");
- // If we already own the struct and no kids could depend on it, then
- // just return it. (We leak in this case if there are kids -- and this
- // function really shouldn't be called for style contexts that could
- // have kids depending on the data. ClearStyleData would be OK, but
- // this test for no mChild or mEmptyChild doesn't catch that case.)
- const void *current = StyleData(aSID);
- if (!mChild && !mEmptyChild &&
- !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
- GetCachedStyleData(aSID))
- return const_cast<void*>(current);
- void* result;
- nsPresContext *presContext = PresContext();
- switch (aSID) {
- #define UNIQUE_CASE(c_) \
- case eStyleStruct_##c_: \
- result = new (presContext) nsStyle##c_( \
- * static_cast<const nsStyle##c_ *>(current)); \
- break;
- UNIQUE_CASE(Font)
- UNIQUE_CASE(Display)
- UNIQUE_CASE(Text)
- UNIQUE_CASE(TextReset)
- UNIQUE_CASE(Visibility)
- #undef UNIQUE_CASE
- default:
- NS_ERROR("Struct type not supported. Please find another way to do this if you can!");
- return nullptr;
- }
- SetStyle(aSID, result);
- mBits &= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID));
- return result;
- }
- // This is an evil function, but less evil than GetUniqueStyleData. It
- // creates an empty style struct for this nsStyleContext.
- void*
- nsStyleContext::CreateEmptyStyleData(const nsStyleStructID& aSID)
- {
- MOZ_ASSERT(!mChild && !mEmptyChild &&
- !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
- !GetCachedStyleData(aSID),
- "This style should not have been computed");
- void* result;
- nsPresContext* presContext = PresContext();
- switch (aSID) {
- #define UNIQUE_CASE(c_) \
- case eStyleStruct_##c_: \
- result = new (presContext) nsStyle##c_(presContext); \
- break;
- UNIQUE_CASE(Border)
- UNIQUE_CASE(Padding)
- #undef UNIQUE_CASE
- default:
- NS_ERROR("Struct type not supported.");
- return nullptr;
- }
- // The new struct is owned by this style context, but that we don't
- // need to clear the bit in mBits because we've asserted that at the
- // top of this function.
- SetStyle(aSID, result);
- return result;
- }
- void
- nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
- {
- // This method should only be called from nsRuleNode! It is not a public
- // method!
- NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
- // NOTE: nsCachedStyleData::GetStyleData works roughly the same way.
- // See the comments there (in nsRuleNode.h) for more details about
- // what this is doing and why.
- void** dataSlot;
- if (nsCachedStyleData::IsReset(aSID)) {
- if (!mCachedResetData) {
- mCachedResetData = new (PresContext()) nsResetStyleData;
- }
- dataSlot = &mCachedResetData->mStyleStructs[aSID];
- } else {
- dataSlot = &mCachedInheritedData.mStyleStructs[aSID];
- }
- NS_ASSERTION(!*dataSlot || (mBits & nsCachedStyleData::GetBitForSID(aSID)),
- "Going to leak style data");
- *dataSlot = aStruct;
- }
- static bool
- ShouldSuppressLineBreak(const nsStyleContext* aContext,
- const nsStyleDisplay* aDisplay,
- const nsStyleContext* aParentContext,
- const nsStyleDisplay* aParentDisplay)
- {
- // The display change should only occur for "in-flow" children
- if (aDisplay->IsOutOfFlowStyle()) {
- return false;
- }
- // Display value of any anonymous box should not be touched. In most
- // cases, anonymous boxes are actually not in ruby frame, but instead,
- // some other frame with a ruby display value. Non-element pseudos
- // which represents text frames, as well as ruby pseudos are excluded
- // because we still want to set the flag for them.
- if (aContext->GetPseudoType() == CSSPseudoElementType::AnonBox &&
- !nsCSSAnonBoxes::IsNonElement(aContext->GetPseudo()) &&
- !RubyUtils::IsRubyPseudo(aContext->GetPseudo())) {
- return false;
- }
- if (aParentContext->ShouldSuppressLineBreak()) {
- // Line break suppressing bit is propagated to any children of
- // line participants, which include inline, contents, and inline
- // ruby boxes.
- if (aParentDisplay->mDisplay == mozilla::StyleDisplay::Inline ||
- aParentDisplay->mDisplay == mozilla::StyleDisplay::Contents ||
- aParentDisplay->mDisplay == mozilla::StyleDisplay::Ruby ||
- aParentDisplay->mDisplay == mozilla::StyleDisplay::RubyBaseContainer) {
- return true;
- }
- }
- // Any descendant of ruby level containers is non-breakable, but
- // the level containers themselves are breakable. We have to check
- // the container display type against all ruby display type here
- // because any of the ruby boxes could be anonymous.
- // Note that, when certain HTML tags, e.g. form controls, have ruby
- // level container display type, they could also escape from this flag
- // while they shouldn't. However, it is generally fine since they
- // won't usually break the assertion that there is no line break
- // inside ruby, because:
- // 1. their display types, the ruby level container types, are inline-
- // outside, which means they won't cause any forced line break; and
- // 2. they never start an inline span, which means their children, if
- // any, won't be able to break the line its ruby ancestor lays; and
- // 3. their parent frame is always a ruby content frame (due to
- // anonymous ruby box generation), which makes line layout suppress
- // any optional line break around this frame.
- // However, there is one special case which is BR tag, because it
- // directly affects the line layout. This case is handled by the BR
- // frame which checks the flag of its parent frame instead of itself.
- if ((aParentDisplay->IsRubyDisplayType() &&
- aDisplay->mDisplay != mozilla::StyleDisplay::RubyBaseContainer &&
- aDisplay->mDisplay != mozilla::StyleDisplay::RubyTextContainer) ||
- // Since ruby base and ruby text may exist themselves without any
- // non-anonymous frame outside, we should also check them.
- aDisplay->mDisplay == mozilla::StyleDisplay::RubyBase ||
- aDisplay->mDisplay == mozilla::StyleDisplay::RubyText) {
- return true;
- }
- return false;
- }
- // Flex & grid containers blockify their children.
- // "The display value of a flex item is blockified"
- // https://drafts.csswg.org/css-flexbox-1/#flex-items
- // "The display value of a grid item is blockified"
- // https://drafts.csswg.org/css-grid/#grid-items
- static bool
- ShouldBlockifyChildren(const nsStyleDisplay* aStyleDisp)
- {
- auto displayVal = aStyleDisp->mDisplay;
- return mozilla::StyleDisplay::Flex == displayVal ||
- mozilla::StyleDisplay::InlineFlex == displayVal ||
- mozilla::StyleDisplay::Grid == displayVal ||
- mozilla::StyleDisplay::InlineGrid == displayVal;
- }
- void
- nsStyleContext::SetStyleBits()
- {
- // XXXbholley: We should get this information directly from the
- // ServoComputedValues rather than computing it here. This setup for
- // ServoComputedValues-backed nsStyleContexts is probably not something
- // we should ship.
- //
- // For example, NS_STYLE_IS_TEXT_COMBINED is still set in ApplyStyleFixups,
- // which isn't called for ServoComputedValues.
- // See if we have any text decorations.
- // First see if our parent has text decorations. If our parent does, then we inherit the bit.
- if (mParent && mParent->HasTextDecorationLines()) {
- mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
- } else {
- // We might have defined a decoration.
- if (StyleTextReset()->HasTextDecorationLines()) {
- mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
- }
- }
- if ((mParent && mParent->HasPseudoElementData()) || IsPseudoElement()) {
- mBits |= NS_STYLE_HAS_PSEUDO_ELEMENT_DATA;
- }
- // Set the NS_STYLE_IN_DISPLAY_NONE_SUBTREE bit
- const nsStyleDisplay* disp = StyleDisplay();
- if ((mParent && mParent->IsInDisplayNoneSubtree()) ||
- disp->mDisplay == mozilla::StyleDisplay::None) {
- mBits |= NS_STYLE_IN_DISPLAY_NONE_SUBTREE;
- }
- }
- void
- nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
- {
- MOZ_ASSERT(!mSource.IsServoComputedValues(),
- "Can't do Gecko style fixups on Servo values");
- #define GET_UNIQUE_STYLE_DATA(name_) \
- static_cast<nsStyle##name_*>(GetUniqueStyleData(eStyleStruct_##name_))
- // CSS Inline Layout Level 3 - 3.5 Sizing Initial Letters:
- // For an N-line drop initial in a Western script, the cap-height of the
- // letter needs to be (N – 1) times the line-height, plus the cap-height
- // of the surrounding text.
- if (mPseudoTag == nsCSSPseudoElements::firstLetter) {
- const nsStyleTextReset* textReset = StyleTextReset();
- if (textReset->mInitialLetterSize != 0.0f) {
- nsStyleContext* containerSC = mParent;
- const nsStyleDisplay* containerDisp = containerSC->StyleDisplay();
- while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
- if (!containerSC->GetParent()) {
- break;
- }
- containerSC = containerSC->GetParent();
- containerDisp = containerSC->StyleDisplay();
- }
- nscoord containerLH =
- ReflowInput::CalcLineHeight(nullptr, containerSC, NS_AUTOHEIGHT, 1.0f);
- RefPtr<nsFontMetrics> containerFM =
- nsLayoutUtils::GetFontMetricsForStyleContext(containerSC);
- MOZ_ASSERT(containerFM, "Should have fontMetrics!!");
- nscoord containerCH = containerFM->CapHeight();
- RefPtr<nsFontMetrics> firstLetterFM =
- nsLayoutUtils::GetFontMetricsForStyleContext(this);
- MOZ_ASSERT(firstLetterFM, "Should have fontMetrics!!");
- nscoord firstLetterCH = firstLetterFM->CapHeight();
- nsStyleFont* mutableStyleFont = GET_UNIQUE_STYLE_DATA(Font);
- float invCapHeightRatio =
- mutableStyleFont->mFont.size / NSCoordToFloat(firstLetterCH);
- mutableStyleFont->mFont.size =
- NSToCoordRound(((textReset->mInitialLetterSize - 1) * containerLH +
- containerCH) *
- invCapHeightRatio);
- }
- }
- // Change writing mode of text frame for text-combine-upright. We use
- // style structs of the parent to avoid triggering computation before
- // we change the writing mode.
- // It is safe to look at the parent's style because we are looking at
- // inherited properties, and ::-moz-text never matches any rules.
- if (mPseudoTag == nsCSSAnonBoxes::mozText && mParent &&
- mParent->StyleVisibility()->mWritingMode !=
- NS_STYLE_WRITING_MODE_HORIZONTAL_TB &&
- mParent->StyleText()->mTextCombineUpright ==
- NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
- MOZ_ASSERT(!PeekStyleVisibility(), "If StyleVisibility was already "
- "computed, some properties may have been computed "
- "incorrectly based on the old writing mode value");
- nsStyleVisibility* mutableVis = GET_UNIQUE_STYLE_DATA(Visibility);
- mutableVis->mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
- AddStyleBit(NS_STYLE_IS_TEXT_COMBINED);
- }
- // CSS 2.1 10.1: Propagate the root element's 'direction' to the ICB.
- // (PageContentFrame/CanvasFrame etc will inherit 'direction')
- if (mPseudoTag == nsCSSAnonBoxes::viewport) {
- nsPresContext* presContext = PresContext();
- mozilla::dom::Element* docElement = presContext->Document()->GetRootElement();
- if (docElement) {
- RefPtr<nsStyleContext> rootStyle =
- presContext->StyleSet()->ResolveStyleFor(docElement, nullptr);
- auto dir = rootStyle->StyleVisibility()->mDirection;
- if (dir != StyleVisibility()->mDirection) {
- nsStyleVisibility* uniqueVisibility = GET_UNIQUE_STYLE_DATA(Visibility);
- uniqueVisibility->mDirection = dir;
- }
- }
- }
- // Correct tables.
- const nsStyleDisplay* disp = StyleDisplay();
- if (disp->mDisplay == mozilla::StyleDisplay::Table) {
- // -moz-center and -moz-right are used for HTML's alignment
- // This is covering the <div align="right"><table>...</table></div> case.
- // In this case, we don't want to inherit the text alignment into the table.
- const nsStyleText* text = StyleText();
- if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_LEFT ||
- text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
- text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
- {
- nsStyleText* uniqueText = GET_UNIQUE_STYLE_DATA(Text);
- uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_START;
- }
- }
- // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
- // the root element. We can't implement them in nsRuleNode because we
- // don't want to store all display structs that aren't 'block',
- // 'inline', or 'table' in the style context tree on the off chance
- // that the root element has its style reresolved later. So do them
- // here if needed, by changing the style data, so that other code
- // doesn't get confused by looking at the style data.
- if (!mParent) {
- auto displayVal = disp->mDisplay;
- if (displayVal != mozilla::StyleDisplay::Contents) {
- nsRuleNode::EnsureBlockDisplay(displayVal, true);
- } else {
- // http://dev.w3.org/csswg/css-display/#transformations
- // "... a display-outside of 'contents' computes to block-level
- // on the root element."
- displayVal = mozilla::StyleDisplay::Block;
- }
- if (displayVal != disp->mDisplay) {
- nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
- disp = mutable_display;
- // If we're in this code, then mOriginalDisplay doesn't matter
- // for purposes of the cascade (because this nsStyleDisplay
- // isn't living in the ruletree anyway), and for determining
- // hypothetical boxes it's better to have mOriginalDisplay
- // matching mDisplay here.
- mutable_display->mOriginalDisplay = mutable_display->mDisplay =
- displayVal;
- }
- }
- // Adjust the "display" values of flex and grid items (but not for raw text
- // or placeholders). CSS3 Flexbox section 4 says:
- // # The computed 'display' of a flex item is determined
- // # by applying the table in CSS 2.1 Chapter 9.7.
- // ...which converts inline-level elements to their block-level equivalents.
- // Any block-level element directly contained by elements with ruby display
- // values are converted to their inline-level equivalents.
- if (!aSkipParentDisplayBasedStyleFixup && mParent) {
- // Skip display:contents ancestors to reach the potential container.
- // (If there are only display:contents ancestors between this node and
- // a flex/grid container ancestor, then this node is a flex/grid item, since
- // its parent *in the frame tree* will be the flex/grid container. So we treat
- // it like a flex/grid item here.)
- nsStyleContext* containerContext = mParent;
- const nsStyleDisplay* containerDisp = containerContext->StyleDisplay();
- while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
- if (!containerContext->GetParent()) {
- break;
- }
- containerContext = containerContext->GetParent();
- containerDisp = containerContext->StyleDisplay();
- }
- if (ShouldBlockifyChildren(containerDisp) &&
- !nsCSSAnonBoxes::IsNonElement(GetPseudo())) {
- // NOTE: Technically, we shouldn't modify the 'display' value of
- // positioned elements, since they aren't flex/grid items. However,
- // we don't need to worry about checking for that, because if we're
- // positioned, we'll have already been through a call to
- // EnsureBlockDisplay() in nsRuleNode, so this call here won't change
- // anything. So we're OK.
- auto displayVal = disp->mDisplay;
- nsRuleNode::EnsureBlockDisplay(displayVal);
- if (displayVal != disp->mDisplay) {
- NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle(),
- "We shouldn't be changing the display value of "
- "positioned content (and we should have already "
- "converted its display value to be block-level...)");
- nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
- disp = mutable_display;
- mutable_display->mDisplay = displayVal;
- }
- }
- }
- // Note: This must come after the blockification above, otherwise we fail
- // the grid-item-blockifying-001.html reftest.
- if (mParent && ::ShouldSuppressLineBreak(this, disp, mParent,
- mParent->StyleDisplay())) {
- mBits |= NS_STYLE_SUPPRESS_LINEBREAK;
- auto displayVal = disp->mDisplay;
- nsRuleNode::EnsureInlineDisplay(displayVal);
- if (displayVal != disp->mDisplay) {
- nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
- disp = mutable_display;
- mutable_display->mDisplay = displayVal;
- }
- }
- // Suppress border/padding of ruby level containers
- if (disp->mDisplay == mozilla::StyleDisplay::RubyBaseContainer ||
- disp->mDisplay == mozilla::StyleDisplay::RubyTextContainer) {
- CreateEmptyStyleData(eStyleStruct_Border);
- CreateEmptyStyleData(eStyleStruct_Padding);
- }
- if (disp->IsRubyDisplayType()) {
- // Per CSS Ruby spec section Bidi Reordering, for all ruby boxes,
- // the 'normal' and 'embed' values of 'unicode-bidi' should compute to
- // 'isolate', and 'bidi-override' should compute to 'isolate-override'.
- const nsStyleTextReset* textReset = StyleTextReset();
- uint8_t unicodeBidi = textReset->mUnicodeBidi;
- if (unicodeBidi == NS_STYLE_UNICODE_BIDI_NORMAL ||
- unicodeBidi == NS_STYLE_UNICODE_BIDI_EMBED) {
- unicodeBidi = NS_STYLE_UNICODE_BIDI_ISOLATE;
- } else if (unicodeBidi == NS_STYLE_UNICODE_BIDI_BIDI_OVERRIDE) {
- unicodeBidi = NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE;
- }
- if (unicodeBidi != textReset->mUnicodeBidi) {
- nsStyleTextReset* mutableTextReset = GET_UNIQUE_STYLE_DATA(TextReset);
- mutableTextReset->mUnicodeBidi = unicodeBidi;
- }
- }
- /*
- * According to https://drafts.csswg.org/css-writing-modes-3/#block-flow:
- *
- * If a box has a different block flow direction than its containing block:
- * * If the box has a specified display of inline, its display computes
- * to inline-block. [CSS21]
- * ...etc.
- */
- if (disp->mDisplay == mozilla::StyleDisplay::Inline &&
- !nsCSSAnonBoxes::IsNonElement(mPseudoTag) &&
- mParent) {
- auto cbContext = mParent;
- while (cbContext->StyleDisplay()->mDisplay == mozilla::StyleDisplay::Contents) {
- cbContext = cbContext->mParent;
- }
- MOZ_ASSERT(cbContext, "the root context can't have display:contents");
- // We don't need the full mozilla::WritingMode value (incorporating dir
- // and text-orientation) here; just the writing-mode property is enough.
- if (StyleVisibility()->mWritingMode !=
- cbContext->StyleVisibility()->mWritingMode) {
- nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
- disp = mutable_display;
- mutable_display->mOriginalDisplay = mutable_display->mDisplay =
- mozilla::StyleDisplay::InlineBlock;
- }
- }
- // Compute User Interface style, to trigger loads of cursors
- StyleUserInterface();
- #undef GET_UNIQUE_STYLE_DATA
- }
- template<class StyleContextLike>
- nsChangeHint
- nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
- nsChangeHint aParentHintsNotHandledForDescendants,
- uint32_t* aEqualStructs,
- uint32_t* aSamePointerStructs)
- {
- PROFILER_LABEL("nsStyleContext", "CalcStyleDifference",
- js::ProfileEntry::Category::CSS);
- MOZ_ASSERT(NS_IsHintSubset(aParentHintsNotHandledForDescendants,
- nsChangeHint_Hints_NotHandledForDescendants),
- "caller is passing inherited hints, but shouldn't be");
- static_assert(nsStyleStructID_Length <= 32,
- "aEqualStructs is not big enough");
- *aEqualStructs = 0;
- nsChangeHint hint = nsChangeHint(0);
- NS_ENSURE_TRUE(aNewContext, hint);
- // We must always ensure that we populate the structs on the new style
- // context that are filled in on the old context, so that if we get
- // two style changes in succession, the second of which causes a real
- // style change, the PeekStyleData doesn't return null (implying that
- // nobody ever looked at that struct's data). In other words, we
- // can't skip later structs if we get a big change up front, because
- // we could later get a small change in one of those structs that we
- // don't want to miss.
- // If our sources are the same, then any differences in style data
- // are already accounted for by differences on ancestors. We know
- // this because CalcStyleDifference is always called on two style
- // contexts that point to the same element, so we know that our
- // position in the style context tree is the same and our position in
- // the rule node tree (if applicable) is also the same.
- // However, if there were noninherited style change hints on the
- // parent, we might produce these same noninherited hints on this
- // style context's frame due to 'inherit' values, so we do need to
- // compare.
- // (Things like 'em' units are handled by the change hint produced
- // by font-size changing, so we don't need to worry about them like
- // we worry about 'inherit' values.)
- bool compare = StyleSource() != aNewContext->StyleSource();
- DebugOnly<uint32_t> structsFound = 0;
- // If we had any change in variable values, then we'll need to examine
- // all of the other style structs too, even if the new style context has
- // the same source as the old one.
- const nsStyleVariables* thisVariables = PeekStyleVariables();
- if (thisVariables) {
- structsFound |= NS_STYLE_INHERIT_BIT(Variables);
- const nsStyleVariables* otherVariables = aNewContext->StyleVariables();
- if (thisVariables->mVariables == otherVariables->mVariables) {
- *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
- } else {
- compare = true;
- }
- } else {
- *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
- }
- DebugOnly<int> styleStructCount = 1; // count Variables already
- #define DO_STRUCT_DIFFERENCE(struct_) \
- PR_BEGIN_MACRO \
- const nsStyle##struct_* this##struct_ = PeekStyle##struct_(); \
- if (this##struct_) { \
- structsFound |= NS_STYLE_INHERIT_BIT(struct_); \
- const nsStyle##struct_* other##struct_ = aNewContext->Style##struct_(); \
- nsChangeHint maxDifference = nsStyle##struct_::MaxDifference(); \
- nsChangeHint differenceAlwaysHandledForDescendants = \
- nsStyle##struct_::DifferenceAlwaysHandledForDescendants(); \
- if (this##struct_ == other##struct_) { \
- /* The very same struct, so we know that there will be no */ \
- /* differences. */ \
- *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
- } else if (compare || \
- ((maxDifference & ~differenceAlwaysHandledForDescendants) & \
- aParentHintsNotHandledForDescendants)) { \
- nsChangeHint difference = \
- this##struct_->CalcDifference(*other##struct_ EXTRA_DIFF_ARGS); \
- NS_ASSERTION(NS_IsHintSubset(difference, maxDifference), \
- "CalcDifference() returned bigger hint than " \
- "MaxDifference()"); \
- hint |= difference; \
- if (!difference) { \
- *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
- } \
- } else { \
- /* We still must call CalcDifference to see if there were any */ \
- /* changes so that we can set *aEqualStructs appropriately. */ \
- nsChangeHint difference = \
- this##struct_->CalcDifference(*other##struct_ EXTRA_DIFF_ARGS); \
- NS_ASSERTION(NS_IsHintSubset(difference, maxDifference), \
- "CalcDifference() returned bigger hint than " \
- "MaxDifference()"); \
- if (!difference) { \
- *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
- } \
- } \
- } else { \
- *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
- } \
- styleStructCount++; \
- PR_END_MACRO
- // In general, we want to examine structs starting with those that can
- // cause the largest style change, down to those that can cause the
- // smallest. This lets us skip later ones if we already have a hint
- // that subsumes their MaxDifference. (As the hints get
- // finer-grained, this optimization is becoming less useful, though.)
- #define EXTRA_DIFF_ARGS /* nothing */
- DO_STRUCT_DIFFERENCE(Display);
- DO_STRUCT_DIFFERENCE(XUL);
- DO_STRUCT_DIFFERENCE(Column);
- DO_STRUCT_DIFFERENCE(Content);
- DO_STRUCT_DIFFERENCE(UserInterface);
- DO_STRUCT_DIFFERENCE(Visibility);
- DO_STRUCT_DIFFERENCE(Outline);
- DO_STRUCT_DIFFERENCE(TableBorder);
- DO_STRUCT_DIFFERENCE(Table);
- DO_STRUCT_DIFFERENCE(UIReset);
- DO_STRUCT_DIFFERENCE(Text);
- DO_STRUCT_DIFFERENCE(List);
- DO_STRUCT_DIFFERENCE(SVGReset);
- DO_STRUCT_DIFFERENCE(SVG);
- #undef EXTRA_DIFF_ARGS
- #define EXTRA_DIFF_ARGS , PeekStyleVisibility()
- DO_STRUCT_DIFFERENCE(Position);
- #undef EXTRA_DIFF_ARGS
- #define EXTRA_DIFF_ARGS /* nothing */
- DO_STRUCT_DIFFERENCE(Font);
- DO_STRUCT_DIFFERENCE(Margin);
- DO_STRUCT_DIFFERENCE(Padding);
- DO_STRUCT_DIFFERENCE(Border);
- DO_STRUCT_DIFFERENCE(TextReset);
- DO_STRUCT_DIFFERENCE(Effects);
- DO_STRUCT_DIFFERENCE(Background);
- DO_STRUCT_DIFFERENCE(Color);
- #undef EXTRA_DIFF_ARGS
- #undef DO_STRUCT_DIFFERENCE
- MOZ_ASSERT(styleStructCount == nsStyleStructID_Length,
- "missing a call to DO_STRUCT_DIFFERENCE");
- #ifdef DEBUG
- #define STYLE_STRUCT(name_, callback_) \
- MOZ_ASSERT(!!(structsFound & NS_STYLE_INHERIT_BIT(name_)) == \
- !!PeekStyle##name_(), \
- "PeekStyleData results must not change in the middle of " \
- "difference calculation.");
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- #endif
- // We check for struct pointer equality here rather than as part of the
- // DO_STRUCT_DIFFERENCE calls, since those calls can result in structs
- // we previously examined and found to be null on this style context
- // getting computed by later DO_STRUCT_DIFFERENCE calls (which can
- // happen when the nsRuleNode::ComputeXXXData method looks up another
- // struct.) This is important for callers in RestyleManager that
- // need to know the equality or not of the final set of cached struct
- // pointers.
- *aSamePointerStructs = 0;
- #define STYLE_STRUCT(name_, callback_) \
- { \
- const nsStyle##name_* data = PeekStyle##name_(); \
- if (!data || data == aNewContext->Style##name_()) { \
- *aSamePointerStructs |= NS_STYLE_INHERIT_BIT(name_); \
- } \
- }
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- // Note that we do not check whether this->RelevantLinkVisited() !=
- // aNewContext->RelevantLinkVisited(); we don't need to since
- // nsCSSFrameConstructor::DoContentStateChanged always adds
- // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
- // needs to, since HasStateDependentStyle probably doesn't work right
- // for NS_EVENT_STATE_VISITED). Hopefully this doesn't actually
- // expose whether links are visited to performance tests since all
- // link coloring happens asynchronously at a time when it's hard for
- // the page to measure.
- // However, we do need to compute the larger of the changes that can
- // happen depending on whether the link is visited or unvisited, since
- // doing only the one that's currently appropriate would expose which
- // links are in history to easy performance measurement. Therefore,
- // here, we add nsChangeHint_RepaintFrame hints (the maximum for
- // things that can depend on :visited) for the properties on which we
- // call GetVisitedDependentColor.
- nsStyleContext *thisVis = GetStyleIfVisited(),
- *otherVis = aNewContext->GetStyleIfVisited();
- if (!thisVis != !otherVis) {
- // One style context has a style-if-visited and the other doesn't.
- // Presume a difference.
- hint |= nsChangeHint_RepaintFrame;
- } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
- // Both style contexts have a style-if-visited.
- bool change = false;
- // NB: Calling Peek on |this|, not |thisVis|, since callers may look
- // at a struct on |this| without looking at the same struct on
- // |thisVis| (including this function if we skip one of these checks
- // due to change being true already or due to the old style context
- // not having a style-if-visited), but not the other way around.
- if (PeekStyleColor()) {
- if (thisVis->StyleColor()->mColor !=
- otherVis->StyleColor()->mColor) {
- change = true;
- }
- }
- // NB: Calling Peek on |this|, not |thisVis| (see above).
- if (!change && PeekStyleBackground()) {
- if (thisVis->StyleBackground()->mBackgroundColor !=
- otherVis->StyleBackground()->mBackgroundColor) {
- change = true;
- }
- }
- // NB: Calling Peek on |this|, not |thisVis| (see above).
- if (!change && PeekStyleBorder()) {
- const nsStyleBorder *thisVisBorder = thisVis->StyleBorder();
- const nsStyleBorder *otherVisBorder = otherVis->StyleBorder();
- NS_FOR_CSS_SIDES(side) {
- if (thisVisBorder->mBorderColor[side] !=
- otherVisBorder->mBorderColor[side]) {
- change = true;
- break;
- }
- }
- }
- // NB: Calling Peek on |this|, not |thisVis| (see above).
- if (!change && PeekStyleOutline()) {
- const nsStyleOutline *thisVisOutline = thisVis->StyleOutline();
- const nsStyleOutline *otherVisOutline = otherVis->StyleOutline();
- if (thisVisOutline->mOutlineColor != otherVisOutline->mOutlineColor) {
- change = true;
- }
- }
- // NB: Calling Peek on |this|, not |thisVis| (see above).
- if (!change && PeekStyleColumn()) {
- const nsStyleColumn *thisVisColumn = thisVis->StyleColumn();
- const nsStyleColumn *otherVisColumn = otherVis->StyleColumn();
- if (thisVisColumn->mColumnRuleColor != otherVisColumn->mColumnRuleColor) {
- change = true;
- }
- }
- // NB: Calling Peek on |this|, not |thisVis| (see above).
- if (!change && PeekStyleText()) {
- const nsStyleText* thisVisText = thisVis->StyleText();
- const nsStyleText* otherVisText = otherVis->StyleText();
- if (thisVisText->mTextEmphasisColor != otherVisText->mTextEmphasisColor ||
- thisVisText->mWebkitTextFillColor != otherVisText->mWebkitTextFillColor ||
- thisVisText->mWebkitTextStrokeColor != otherVisText->mWebkitTextStrokeColor) {
- change = true;
- }
- }
- // NB: Calling Peek on |this|, not |thisVis| (see above).
- if (!change && PeekStyleTextReset()) {
- const nsStyleTextReset *thisVisTextReset = thisVis->StyleTextReset();
- const nsStyleTextReset *otherVisTextReset = otherVis->StyleTextReset();
- if (thisVisTextReset->mTextDecorationColor !=
- otherVisTextReset->mTextDecorationColor) {
- change = true;
- }
- }
- // NB: Calling Peek on |this|, not |thisVis| (see above).
- if (!change && PeekStyleSVG()) {
- const nsStyleSVG *thisVisSVG = thisVis->StyleSVG();
- const nsStyleSVG *otherVisSVG = otherVis->StyleSVG();
- if (thisVisSVG->mFill != otherVisSVG->mFill ||
- thisVisSVG->mStroke != otherVisSVG->mStroke) {
- change = true;
- }
- }
- // NB: Calling Peek on |this|, not |thisVis| (see above).
- if (!change && PeekStyleUserInterface()) {
- const nsStyleUserInterface *thisVisUserInterface = thisVis->StyleUserInterface();
- const nsStyleUserInterface *otherVisUserInterface = otherVis->StyleUserInterface();
- if (thisVisUserInterface->mCaretColor !=
- otherVisUserInterface->mCaretColor) {
- change = true;
- }
- }
- if (change) {
- hint |= nsChangeHint_RepaintFrame;
- }
- }
- if (hint & nsChangeHint_UpdateContainingBlock) {
- // If a struct returned nsChangeHint_UpdateContainingBlock, that
- // means that one property's influence on whether we're a containing
- // block for abs-pos or fixed-pos elements has changed. However, we
- // only need to return the hint if the overall computation of
- // whether we establish a containing block has changed.
- // This depends on data in nsStyleDisplay and nsStyleEffects, so we
- // do it here.
- // Note that it's perhaps good for this test to be last because it
- // doesn't use Peek* functions to get the structs on the old
- // context. But this isn't a big concern because these struct
- // getters should be called during frame construction anyway.
- if (StyleDisplay()->IsAbsPosContainingBlockForAppropriateFrame(this) ==
- aNewContext->StyleDisplay()->
- IsAbsPosContainingBlockForAppropriateFrame(aNewContext) &&
- StyleDisplay()->IsFixedPosContainingBlockForAppropriateFrame(this) ==
- aNewContext->StyleDisplay()->
- IsFixedPosContainingBlockForAppropriateFrame(aNewContext)) {
- // While some styles that cause the frame to be a containing block
- // has changed, the overall result hasn't.
- hint &= ~nsChangeHint_UpdateContainingBlock;
- }
- }
- MOZ_ASSERT(NS_IsHintSubset(hint, nsChangeHint_AllHints),
- "Added a new hint without bumping AllHints?");
- return hint & ~nsChangeHint_NeutralChange;
- }
- nsChangeHint
- nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
- nsChangeHint aParentHintsNotHandledForDescendants,
- uint32_t* aEqualStructs,
- uint32_t* aSamePointerStructs)
- {
- return CalcStyleDifferenceInternal(aNewContext, aParentHintsNotHandledForDescendants,
- aEqualStructs, aSamePointerStructs);
- }
- class MOZ_STACK_CLASS FakeStyleContext
- {
- public:
- explicit FakeStyleContext(const ServoComputedValues* aComputedValues)
- : mComputedValues(aComputedValues) {}
- mozilla::NonOwningStyleContextSource StyleSource() const {
- return mozilla::NonOwningStyleContextSource(mComputedValues);
- }
- nsStyleContext* GetStyleIfVisited() {
- // XXXbholley: This is wrong. Need to implement to get visited handling
- // corrrect!
- return nullptr;
- }
- #define STYLE_STRUCT(name_, checkdata_cb_) \
- const nsStyle##name_ * Style##name_() { \
- return Servo_GetStyle##name_(mComputedValues); \
- }
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- private:
- const ServoComputedValues* MOZ_NON_OWNING_REF mComputedValues;
- };
- nsChangeHint
- nsStyleContext::CalcStyleDifference(const ServoComputedValues* aNewComputedValues,
- nsChangeHint aParentHintsNotHandledForDescendants,
- uint32_t* aEqualStructs,
- uint32_t* aSamePointerStructs)
- {
- FakeStyleContext newContext(aNewComputedValues);
- return CalcStyleDifferenceInternal(&newContext, aParentHintsNotHandledForDescendants,
- aEqualStructs, aSamePointerStructs);
- }
- #ifdef DEBUG
- void nsStyleContext::List(FILE* out, int32_t aIndent, bool aListDescendants)
- {
- nsAutoCString str;
- // Indent
- int32_t ix;
- for (ix = aIndent; --ix >= 0; ) {
- str.AppendLiteral(" ");
- }
- str.Append(nsPrintfCString("%p(%d) parent=%p ",
- (void*)this, mRefCnt, (void *)mParent));
- if (mPseudoTag) {
- nsAutoString buffer;
- mPseudoTag->ToString(buffer);
- AppendUTF16toUTF8(buffer, str);
- str.Append(' ');
- }
- if (mSource.IsServoComputedValues()) {
- fprintf_stderr(out, "%s{ServoComputedValues}\n", str.get());
- } else if (mSource.IsGeckoRuleNode()) {
- fprintf_stderr(out, "%s{\n", str.get());
- str.Truncate();
- nsRuleNode* ruleNode = mSource.AsGeckoRuleNode();
- while (ruleNode) {
- nsIStyleRule *styleRule = ruleNode->GetRule();
- if (styleRule) {
- styleRule->List(out, aIndent + 1);
- }
- ruleNode = ruleNode->GetParent();
- }
- for (ix = aIndent; --ix >= 0; ) {
- str.AppendLiteral(" ");
- }
- fprintf_stderr(out, "%s}\n", str.get());
- }
- else {
- fprintf_stderr(out, "%s{}\n", str.get());
- }
- if (aListDescendants) {
- if (nullptr != mChild) {
- nsStyleContext* child = mChild;
- do {
- child->List(out, aIndent + 1, aListDescendants);
- child = child->mNextSibling;
- } while (mChild != child);
- }
- if (nullptr != mEmptyChild) {
- nsStyleContext* child = mEmptyChild;
- do {
- child->List(out, aIndent + 1, aListDescendants);
- child = child->mNextSibling;
- } while (mEmptyChild != child);
- }
- }
- }
- #endif
- // Overloaded new operator. Initializes the memory to 0 and relies on an arena
- // (which comes from the presShell) to perform the allocation.
- void*
- nsStyleContext::operator new(size_t sz, nsPresContext* aPresContext)
- {
- // Check the recycle list first.
- return aPresContext->PresShell()->
- AllocateByObjectID(eArenaObjectID_nsStyleContext, sz);
- }
- // Overridden to prevent the global delete from being called, since the memory
- // came out of an nsIArena instead of the global delete operator's heap.
- void
- nsStyleContext::Destroy()
- {
- // Get the pres context.
- RefPtr<nsPresContext> presContext = PresContext();
- // Call our destructor.
- this->~nsStyleContext();
- // Don't let the memory be freed, since it will be recycled
- // instead. Don't call the global operator delete.
- presContext->PresShell()->
- FreeByObjectID(eArenaObjectID_nsStyleContext, this);
- }
- already_AddRefed<nsStyleContext>
- NS_NewStyleContext(nsStyleContext* aParentContext,
- nsIAtom* aPseudoTag,
- CSSPseudoElementType aPseudoType,
- nsRuleNode* aRuleNode,
- bool aSkipParentDisplayBasedStyleFixup)
- {
- RefPtr<nsRuleNode> node = aRuleNode;
- RefPtr<nsStyleContext> context =
- new (aRuleNode->PresContext())
- nsStyleContext(aParentContext, aPseudoTag, aPseudoType, node.forget(),
- aSkipParentDisplayBasedStyleFixup);
- return context.forget();
- }
- already_AddRefed<nsStyleContext>
- NS_NewStyleContext(nsStyleContext* aParentContext,
- nsPresContext* aPresContext,
- nsIAtom* aPseudoTag,
- CSSPseudoElementType aPseudoType,
- already_AddRefed<ServoComputedValues> aComputedValues,
- bool aSkipParentDisplayBasedStyleFixup)
- {
- RefPtr<nsStyleContext> context =
- new (aPresContext)
- nsStyleContext(aParentContext, aPresContext, aPseudoTag, aPseudoType,
- Move(aComputedValues), aSkipParentDisplayBasedStyleFixup);
- return context.forget();
- }
- nsIPresShell*
- nsStyleContext::Arena()
- {
- return PresContext()->PresShell();
- }
- static inline void
- ExtractAnimationValue(nsCSSPropertyID aProperty,
- nsStyleContext* aStyleContext,
- StyleAnimationValue& aResult)
- {
- DebugOnly<bool> success =
- StyleAnimationValue::ExtractComputedValue(aProperty, aStyleContext,
- aResult);
- MOZ_ASSERT(success,
- "aProperty must be extractable by StyleAnimationValue");
- }
- static Maybe<nscolor>
- ExtractColor(nsCSSPropertyID aProperty,
- nsStyleContext *aStyleContext)
- {
- StyleAnimationValue val;
- ExtractAnimationValue(aProperty, aStyleContext, val);
- switch (val.GetUnit()) {
- case StyleAnimationValue::eUnit_Color:
- return Some(val.GetCSSValueValue()->GetColorValue());
- case StyleAnimationValue::eUnit_CurrentColor:
- return Some(aStyleContext->StyleColor()->mColor);
- case StyleAnimationValue::eUnit_ComplexColor:
- return Some(aStyleContext->StyleColor()->
- CalcComplexColor(val.GetStyleComplexColorValue()));
- case StyleAnimationValue::eUnit_Auto:
- return Some(aStyleContext->StyleColor()->
- CalcComplexColor(StyleComplexColor::Auto()));
- default:
- return Nothing();
- }
- }
- static nscolor
- ExtractColorLenient(nsCSSPropertyID aProperty,
- nsStyleContext *aStyleContext)
- {
- return ExtractColor(aProperty, aStyleContext).valueOr(NS_RGBA(0, 0, 0, 0));
- }
- struct ColorIndexSet {
- uint8_t colorIndex, alphaIndex;
- };
- static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
- nscolor
- nsStyleContext::GetVisitedDependentColor(nsCSSPropertyID aProperty)
- {
- NS_ASSERTION(aProperty == eCSSProperty_caret_color ||
- aProperty == eCSSProperty_color ||
- aProperty == eCSSProperty_background_color ||
- aProperty == eCSSProperty_border_top_color ||
- aProperty == eCSSProperty_border_right_color ||
- aProperty == eCSSProperty_border_bottom_color ||
- aProperty == eCSSProperty_border_left_color ||
- aProperty == eCSSProperty_outline_color ||
- aProperty == eCSSProperty_column_rule_color ||
- aProperty == eCSSProperty_text_decoration_color ||
- aProperty == eCSSProperty_text_emphasis_color ||
- aProperty == eCSSProperty__webkit_text_fill_color ||
- aProperty == eCSSProperty__webkit_text_stroke_color ||
- aProperty == eCSSProperty_fill ||
- aProperty == eCSSProperty_stroke,
- "we need to add to nsStyleContext::CalcStyleDifference");
- bool isPaintProperty = aProperty == eCSSProperty_fill ||
- aProperty == eCSSProperty_stroke;
- nscolor colors[2];
- colors[0] = isPaintProperty ? ExtractColorLenient(aProperty, this)
- : ExtractColor(aProperty, this).value();
- nsStyleContext *visitedStyle = this->GetStyleIfVisited();
- if (!visitedStyle) {
- return colors[0];
- }
- colors[1] = isPaintProperty ? ExtractColorLenient(aProperty, visitedStyle)
- : ExtractColor(aProperty, visitedStyle).value();
- return nsStyleContext::CombineVisitedColors(colors,
- this->RelevantLinkVisited());
- }
- /* static */ nscolor
- nsStyleContext::CombineVisitedColors(nscolor *aColors, bool aLinkIsVisited)
- {
- if (NS_GET_A(aColors[1]) == 0) {
- // If the style-if-visited is transparent, then just use the
- // unvisited style rather than using the (meaningless) color
- // components of the visited style along with a potentially
- // non-transparent alpha value.
- aLinkIsVisited = false;
- }
- // NOTE: We want this code to have as little timing dependence as
- // possible on whether this->RelevantLinkVisited() is true.
- const ColorIndexSet &set =
- gVisitedIndices[aLinkIsVisited ? 1 : 0];
- nscolor colorColor = aColors[set.colorIndex];
- nscolor alphaColor = aColors[set.alphaIndex];
- return NS_RGBA(NS_GET_R(colorColor), NS_GET_G(colorColor),
- NS_GET_B(colorColor), NS_GET_A(alphaColor));
- }
- #ifdef DEBUG
- /* static */ void
- nsStyleContext::AssertStyleStructMaxDifferenceValid()
- {
- #define STYLE_STRUCT(name, checkdata_cb) \
- MOZ_ASSERT(NS_IsHintSubset(nsStyle##name::DifferenceAlwaysHandledForDescendants(), \
- nsStyle##name::MaxDifference()));
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- }
- /* static */ const char*
- nsStyleContext::StructName(nsStyleStructID aSID)
- {
- switch (aSID) {
- #define STYLE_STRUCT(name_, checkdata_cb) \
- case eStyleStruct_##name_: \
- return #name_;
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- default:
- return "Unknown";
- }
- }
- /* static */ bool
- nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
- {
- if (false)
- ;
- #define STYLE_STRUCT(name_, checkdata_cb_) \
- else if (aName.EqualsLiteral(#name_)) \
- aResult = eStyleStruct_##name_;
- #include "nsStyleStructList.h"
- #undef STYLE_STRUCT
- else
- return false;
- return true;
- }
- #endif
- void
- nsStyleContext::SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs)
- {
- static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
- for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
- i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
- i = nsStyleStructID(i + 1)) {
- uint32_t bit = nsCachedStyleData::GetBitForSID(i);
- if (!(aStructs & bit)) {
- continue;
- }
- void*& thisData = mCachedInheritedData.mStyleStructs[i];
- void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
- if (mBits & bit) {
- if (thisData == otherData) {
- thisData = nullptr;
- }
- } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
- std::swap(thisData, otherData);
- }
- }
- for (nsStyleStructID i = nsStyleStructID_Reset_Start;
- i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
- i = nsStyleStructID(i + 1)) {
- uint32_t bit = nsCachedStyleData::GetBitForSID(i);
- if (!(aStructs & bit)) {
- continue;
- }
- if (!mCachedResetData) {
- mCachedResetData = new (PresContext()) nsResetStyleData;
- }
- if (!aNewContext->mCachedResetData) {
- aNewContext->mCachedResetData = new (PresContext()) nsResetStyleData;
- }
- void*& thisData = mCachedResetData->mStyleStructs[i];
- void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
- if (mBits & bit) {
- if (thisData == otherData) {
- thisData = nullptr;
- }
- } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
- std::swap(thisData, otherData);
- }
- }
- }
- void
- nsStyleContext::ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
- {
- if (mChild) {
- nsStyleContext* child = mChild;
- do {
- child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
- child = child->mNextSibling;
- } while (mChild != child);
- }
- if (mEmptyChild) {
- nsStyleContext* child = mEmptyChild;
- do {
- child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
- child = child->mNextSibling;
- } while (mEmptyChild != child);
- }
- }
- void
- nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
- {
- NS_ASSERTION(mFrameRefCnt == 0, "frame still referencing style context");
- for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
- i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
- i = nsStyleStructID(i + 1)) {
- uint32_t bit = nsCachedStyleData::GetBitForSID(i);
- if (aStructs & bit) {
- if (!(mBits & bit) && mCachedInheritedData.mStyleStructs[i]) {
- aStructs &= ~bit;
- } else {
- mCachedInheritedData.mStyleStructs[i] = nullptr;
- }
- }
- }
- if (mCachedResetData) {
- for (nsStyleStructID i = nsStyleStructID_Reset_Start;
- i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
- i = nsStyleStructID(i + 1)) {
- uint32_t bit = nsCachedStyleData::GetBitForSID(i);
- if (aStructs & bit) {
- if (!(mBits & bit) && mCachedResetData->mStyleStructs[i]) {
- aStructs &= ~bit;
- } else {
- mCachedResetData->mStyleStructs[i] = nullptr;
- }
- }
- }
- }
- if (aStructs == 0) {
- return;
- }
- ClearCachedInheritedStyleDataOnDescendants(aStructs);
- }
- void
- nsStyleContext::SetIneligibleForSharing()
- {
- if (mBits & NS_STYLE_INELIGIBLE_FOR_SHARING) {
- return;
- }
- mBits |= NS_STYLE_INELIGIBLE_FOR_SHARING;
- if (mChild) {
- nsStyleContext* child = mChild;
- do {
- child->SetIneligibleForSharing();
- child = child->mNextSibling;
- } while (mChild != child);
- }
- if (mEmptyChild) {
- nsStyleContext* child = mEmptyChild;
- do {
- child->SetIneligibleForSharing();
- child = child->mNextSibling;
- } while (mEmptyChild != child);
- }
- }
- #ifdef RESTYLE_LOGGING
- nsCString
- nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
- {
- nsCString structs;
- for (nsStyleStructID i = nsStyleStructID(0);
- i < nsStyleStructID_Length;
- i = nsStyleStructID(i + 1)) {
- if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
- const void* data = GetCachedStyleData(i);
- if (!structs.IsEmpty()) {
- structs.Append(' ');
- }
- structs.AppendPrintf("%s=%p", StructName(i), data);
- if (HasCachedDependentStyleData(i)) {
- structs.AppendLiteral("(dependent)");
- } else {
- structs.AppendLiteral("(owned)");
- }
- }
- }
- return structs;
- }
- int32_t&
- nsStyleContext::LoggingDepth()
- {
- static int32_t depth = 0;
- return depth;
- }
- void
- nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
- {
- LoggingDepth() = aLoggingDepth;
- LogStyleContextTree(true, aStructs);
- }
- void
- nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
- {
- nsCString structs = GetCachedStyleDataAsString(aStructs);
- if (!structs.IsEmpty()) {
- structs.Append(' ');
- }
- nsCString pseudo;
- if (mPseudoTag) {
- nsAutoString pseudoTag;
- mPseudoTag->ToString(pseudoTag);
- AppendUTF16toUTF8(pseudoTag, pseudo);
- pseudo.Append(' ');
- }
- nsCString flags;
- if (IsStyleIfVisited()) {
- flags.AppendLiteral("IS_STYLE_IF_VISITED ");
- }
- if (HasChildThatUsesGrandancestorStyle()) {
- flags.AppendLiteral("CHILD_USES_GRANDANCESTOR_STYLE ");
- }
- if (IsShared()) {
- flags.AppendLiteral("IS_SHARED ");
- }
- nsCString parent;
- if (aFirst) {
- parent.AppendPrintf("parent=%p ", mParent.get());
- }
- LOG_RESTYLE("%p(%d) %s%s%s%s",
- this, mRefCnt,
- structs.get(), pseudo.get(), flags.get(), parent.get());
- LOG_RESTYLE_INDENT();
- if (nullptr != mChild) {
- nsStyleContext* child = mChild;
- do {
- child->LogStyleContextTree(false, aStructs);
- child = child->mNextSibling;
- } while (mChild != child);
- }
- if (nullptr != mEmptyChild) {
- nsStyleContext* child = mEmptyChild;
- do {
- child->LogStyleContextTree(false, aStructs);
- child = child->mNextSibling;
- } while (mEmptyChild != child);
- }
- }
- #endif
- #ifdef DEBUG
- /* static */ void
- nsStyleContext::Initialize()
- {
- Preferences::AddBoolVarCache(
- &sExpensiveStyleStructAssertionsEnabled,
- "layout.css.expensive-style-struct-assertions.enabled");
- }
- #endif
|