nsStyleContext.cpp 69 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. /* the interface (to internal code) for retrieving computed style data */
  6. #include "CSSVariableImageTable.h"
  7. #include "mozilla/DebugOnly.h"
  8. #include "mozilla/Maybe.h"
  9. #include "nsCSSAnonBoxes.h"
  10. #include "nsCSSPseudoElements.h"
  11. #include "nsStyleConsts.h"
  12. #include "nsStyleStruct.h"
  13. #include "nsStyleStructInlines.h"
  14. #include "nsString.h"
  15. #include "nsPresContext.h"
  16. #include "nsIStyleRule.h"
  17. #include "nsCOMPtr.h"
  18. #include "nsStyleSet.h"
  19. #include "nsIPresShell.h"
  20. #include "nsRuleNode.h"
  21. #include "nsStyleContext.h"
  22. #include "mozilla/StyleAnimationValue.h"
  23. #include "GeckoProfiler.h"
  24. #include "nsIDocument.h"
  25. #include "nsPrintfCString.h"
  26. #include "RubyUtils.h"
  27. #include "mozilla/Preferences.h"
  28. #include "mozilla/ArenaObjectID.h"
  29. #include "mozilla/StyleSetHandle.h"
  30. #include "mozilla/StyleSetHandleInlines.h"
  31. #include "mozilla/ReflowInput.h"
  32. #include "nsLayoutUtils.h"
  33. #include "nsCoord.h"
  34. #include "nsFontMetrics.h"
  35. // Ensure the binding function declarations in nsStyleContext.h matches
  36. // those in ServoBindings.h.
  37. #include "mozilla/ServoBindings.h"
  38. using namespace mozilla;
  39. //----------------------------------------------------------------------
  40. #ifdef DEBUG
  41. // Check that the style struct IDs are in the same order as they are
  42. // in nsStyleStructList.h, since when we set up the IDs, we include
  43. // the inherited and reset structs spearately from nsStyleStructList.h
  44. enum DebugStyleStruct {
  45. #define STYLE_STRUCT(name, checkdata_cb) eDebugStyleStruct_##name,
  46. #include "nsStyleStructList.h"
  47. #undef STYLE_STRUCT
  48. };
  49. #define STYLE_STRUCT(name, checkdata_cb) \
  50. static_assert(static_cast<int>(eDebugStyleStruct_##name) == \
  51. static_cast<int>(eStyleStruct_##name), \
  52. "Style struct IDs are not declared in order?");
  53. #include "nsStyleStructList.h"
  54. #undef STYLE_STRUCT
  55. const uint32_t nsStyleContext::sDependencyTable[] = {
  56. #define STYLE_STRUCT(name, checkdata_cb)
  57. #define STYLE_STRUCT_DEP(dep) NS_STYLE_INHERIT_BIT(dep) |
  58. #define STYLE_STRUCT_END() 0,
  59. #include "nsStyleStructList.h"
  60. #undef STYLE_STRUCT
  61. #undef STYLE_STRUCT_DEP
  62. #undef STYLE_STRUCT_END
  63. };
  64. // Whether to perform expensive assertions in the nsStyleContext destructor.
  65. static bool sExpensiveStyleStructAssertionsEnabled;
  66. #endif
  67. nsStyleContext::nsStyleContext(nsStyleContext* aParent,
  68. OwningStyleContextSource&& aSource,
  69. nsIAtom* aPseudoTag,
  70. CSSPseudoElementType aPseudoType)
  71. : mParent(aParent)
  72. , mChild(nullptr)
  73. , mEmptyChild(nullptr)
  74. , mPseudoTag(aPseudoTag)
  75. , mSource(Move(aSource))
  76. #ifdef MOZ_STYLO
  77. , mPresContext(nullptr)
  78. #endif
  79. , mCachedResetData(nullptr)
  80. , mBits(((uint64_t)aPseudoType) << NS_STYLE_CONTEXT_TYPE_SHIFT)
  81. , mRefCnt(0)
  82. #ifdef MOZ_STYLO
  83. , mStoredChangeHint(nsChangeHint(0))
  84. #ifdef DEBUG
  85. , mConsumedChangeHint(false)
  86. #endif
  87. #endif
  88. #ifdef DEBUG
  89. , mFrameRefCnt(0)
  90. , mComputingStruct(nsStyleStructID_None)
  91. #endif
  92. {
  93. MOZ_COUNT_CTOR(nsStyleContext);
  94. }
  95. nsStyleContext::nsStyleContext(nsStyleContext* aParent,
  96. nsIAtom* aPseudoTag,
  97. CSSPseudoElementType aPseudoType,
  98. already_AddRefed<nsRuleNode> aRuleNode,
  99. bool aSkipParentDisplayBasedStyleFixup)
  100. : nsStyleContext(aParent, OwningStyleContextSource(Move(aRuleNode)),
  101. aPseudoTag, aPseudoType)
  102. {
  103. #ifdef MOZ_STYLO
  104. mPresContext = mSource.AsGeckoRuleNode()->PresContext();
  105. #endif
  106. if (aParent) {
  107. #ifdef DEBUG
  108. nsRuleNode *r1 = mParent->RuleNode(), *r2 = mSource.AsGeckoRuleNode();
  109. while (r1->GetParent())
  110. r1 = r1->GetParent();
  111. while (r2->GetParent())
  112. r2 = r2->GetParent();
  113. NS_ASSERTION(r1 == r2, "must be in the same rule tree as parent");
  114. #endif
  115. } else {
  116. PresContext()->PresShell()->StyleSet()->RootStyleContextAdded();
  117. }
  118. mSource.AsGeckoRuleNode()->SetUsedDirectly(); // before ApplyStyleFixups()!
  119. FinishConstruction(aSkipParentDisplayBasedStyleFixup);
  120. }
  121. nsStyleContext::nsStyleContext(nsStyleContext* aParent,
  122. nsPresContext* aPresContext,
  123. nsIAtom* aPseudoTag,
  124. CSSPseudoElementType aPseudoType,
  125. already_AddRefed<ServoComputedValues> aComputedValues,
  126. bool aSkipParentDisplayBasedStyleFixup)
  127. : nsStyleContext(aParent, OwningStyleContextSource(Move(aComputedValues)),
  128. aPseudoTag, aPseudoType)
  129. {
  130. #ifdef MOZ_STYLO
  131. mPresContext = aPresContext;
  132. #endif
  133. FinishConstruction(aSkipParentDisplayBasedStyleFixup);
  134. }
  135. void
  136. nsStyleContext::FinishConstruction(bool aSkipParentDisplayBasedStyleFixup)
  137. {
  138. // This check has to be done "backward", because if it were written the
  139. // more natural way it wouldn't fail even when it needed to.
  140. static_assert((UINT64_MAX >> NS_STYLE_CONTEXT_TYPE_SHIFT) >=
  141. static_cast<CSSPseudoElementTypeBase>(
  142. CSSPseudoElementType::MAX),
  143. "pseudo element bits no longer fit in a uint64_t");
  144. MOZ_ASSERT(!mSource.IsNull());
  145. #ifdef DEBUG
  146. static_assert(MOZ_ARRAY_LENGTH(nsStyleContext::sDependencyTable)
  147. == nsStyleStructID_Length,
  148. "Number of items in dependency table doesn't match IDs");
  149. #endif
  150. mNextSibling = this;
  151. mPrevSibling = this;
  152. if (mParent) {
  153. mParent->AddChild(this);
  154. }
  155. SetStyleBits();
  156. if (!mSource.IsServoComputedValues()) {
  157. ApplyStyleFixups(aSkipParentDisplayBasedStyleFixup);
  158. }
  159. #define eStyleStruct_LastItem (nsStyleStructID_Length - 1)
  160. NS_ASSERTION(NS_STYLE_INHERIT_MASK & NS_STYLE_INHERIT_BIT(LastItem),
  161. "NS_STYLE_INHERIT_MASK must be bigger, and other bits shifted");
  162. #undef eStyleStruct_LastItem
  163. }
  164. nsStyleContext::~nsStyleContext()
  165. {
  166. MOZ_COUNT_DTOR(nsStyleContext);
  167. NS_ASSERTION((nullptr == mChild) && (nullptr == mEmptyChild), "destructing context with children");
  168. #ifdef DEBUG
  169. if (sExpensiveStyleStructAssertionsEnabled) {
  170. // Assert that the style structs we are about to destroy are not referenced
  171. // anywhere else in the style context tree. These checks are expensive,
  172. // which is why they are not enabled by default.
  173. nsStyleContext* root = this;
  174. while (root->mParent) {
  175. root = root->mParent;
  176. }
  177. root->AssertStructsNotUsedElsewhere(this,
  178. std::numeric_limits<int32_t>::max());
  179. } else {
  180. // In DEBUG builds when the pref is not enabled, we perform a more limited
  181. // check just of the children of this style context.
  182. AssertStructsNotUsedElsewhere(this, 2);
  183. }
  184. #endif
  185. nsPresContext *presContext = PresContext();
  186. DebugOnly<nsStyleSet*> geckoStyleSet = presContext->PresShell()->StyleSet()->GetAsGecko();
  187. NS_ASSERTION(!geckoStyleSet ||
  188. geckoStyleSet->GetRuleTree() == mSource.AsGeckoRuleNode()->RuleTree() ||
  189. geckoStyleSet->IsInRuleTreeReconstruct(),
  190. "destroying style context from old rule tree too late");
  191. if (mParent) {
  192. mParent->RemoveChild(this);
  193. } else {
  194. presContext->StyleSet()->RootStyleContextRemoved();
  195. }
  196. // Free up our data structs.
  197. mCachedInheritedData.DestroyStructs(mBits, presContext);
  198. if (mCachedResetData) {
  199. mCachedResetData->Destroy(mBits, presContext);
  200. }
  201. // Free any ImageValues we were holding on to for CSS variable values.
  202. CSSVariableImageTable::RemoveAll(this);
  203. }
  204. #ifdef DEBUG
  205. void
  206. nsStyleContext::AssertStructsNotUsedElsewhere(
  207. nsStyleContext* aDestroyingContext,
  208. int32_t aLevels) const
  209. {
  210. if (aLevels == 0) {
  211. return;
  212. }
  213. void* data;
  214. if (mBits & NS_STYLE_IS_GOING_AWAY) {
  215. return;
  216. }
  217. if (this != aDestroyingContext) {
  218. nsInheritedStyleData& destroyingInheritedData =
  219. aDestroyingContext->mCachedInheritedData;
  220. #define STYLE_STRUCT_INHERITED(name_, checkdata_cb) \
  221. data = destroyingInheritedData.mStyleStructs[eStyleStruct_##name_]; \
  222. if (data && \
  223. !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
  224. (mCachedInheritedData.mStyleStructs[eStyleStruct_##name_] == data)) { \
  225. printf_stderr("style struct %p found on style context %p\n", data, this);\
  226. nsString url; \
  227. nsresult rv = PresContext()->Document()->GetURL(url); \
  228. if (NS_SUCCEEDED(rv)) { \
  229. printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
  230. } \
  231. MOZ_ASSERT(false, "destroying " #name_ " style struct still present " \
  232. "in style context tree"); \
  233. }
  234. #define STYLE_STRUCT_RESET(name_, checkdata_cb)
  235. #include "nsStyleStructList.h"
  236. #undef STYLE_STRUCT_INHERITED
  237. #undef STYLE_STRUCT_RESET
  238. if (mCachedResetData) {
  239. nsResetStyleData* destroyingResetData =
  240. aDestroyingContext->mCachedResetData;
  241. if (destroyingResetData) {
  242. #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_)
  243. #define STYLE_STRUCT_RESET(name_, checkdata_cb) \
  244. data = destroyingResetData->mStyleStructs[eStyleStruct_##name_]; \
  245. if (data && \
  246. !(aDestroyingContext->mBits & NS_STYLE_INHERIT_BIT(name_)) && \
  247. (mCachedResetData->mStyleStructs[eStyleStruct_##name_] == data)) { \
  248. printf_stderr("style struct %p found on style context %p\n", data, \
  249. this); \
  250. nsString url; \
  251. nsresult rv = PresContext()->Document()->GetURL(url); \
  252. if (NS_SUCCEEDED(rv)) { \
  253. printf_stderr(" in %s\n", NS_ConvertUTF16toUTF8(url).get()); \
  254. } \
  255. MOZ_ASSERT(false, "destroying " #name_ " style struct still present "\
  256. "in style context tree"); \
  257. }
  258. #include "nsStyleStructList.h"
  259. #undef STYLE_STRUCT_INHERITED
  260. #undef STYLE_STRUCT_RESET
  261. }
  262. }
  263. }
  264. if (mChild) {
  265. const nsStyleContext* child = mChild;
  266. do {
  267. child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
  268. child = child->mNextSibling;
  269. } while (child != mChild);
  270. }
  271. if (mEmptyChild) {
  272. const nsStyleContext* child = mEmptyChild;
  273. do {
  274. child->AssertStructsNotUsedElsewhere(aDestroyingContext, aLevels - 1);
  275. child = child->mNextSibling;
  276. } while (child != mEmptyChild);
  277. }
  278. }
  279. #endif
  280. void nsStyleContext::AddChild(nsStyleContext* aChild)
  281. {
  282. NS_ASSERTION(aChild->mPrevSibling == aChild &&
  283. aChild->mNextSibling == aChild,
  284. "child already in a child list");
  285. nsStyleContext **listPtr = aChild->mSource.MatchesNoRules() ? &mEmptyChild : &mChild;
  286. // Explicitly dereference listPtr so that compiler doesn't have to know that mNextSibling
  287. // etc. don't alias with what ever listPtr points at.
  288. nsStyleContext *list = *listPtr;
  289. // Insert at the beginning of the list. See also FindChildWithRules.
  290. if (list) {
  291. // Link into existing elements, if there are any.
  292. aChild->mNextSibling = list;
  293. aChild->mPrevSibling = list->mPrevSibling;
  294. list->mPrevSibling->mNextSibling = aChild;
  295. list->mPrevSibling = aChild;
  296. }
  297. (*listPtr) = aChild;
  298. }
  299. void nsStyleContext::RemoveChild(nsStyleContext* aChild)
  300. {
  301. NS_PRECONDITION(nullptr != aChild && this == aChild->mParent, "bad argument");
  302. nsStyleContext **list = aChild->mSource.MatchesNoRules() ? &mEmptyChild : &mChild;
  303. if (aChild->mPrevSibling != aChild) { // has siblings
  304. if ((*list) == aChild) {
  305. (*list) = (*list)->mNextSibling;
  306. }
  307. }
  308. else {
  309. NS_ASSERTION((*list) == aChild, "bad sibling pointers");
  310. (*list) = nullptr;
  311. }
  312. aChild->mPrevSibling->mNextSibling = aChild->mNextSibling;
  313. aChild->mNextSibling->mPrevSibling = aChild->mPrevSibling;
  314. aChild->mNextSibling = aChild;
  315. aChild->mPrevSibling = aChild;
  316. }
  317. void
  318. nsStyleContext::MoveTo(nsStyleContext* aNewParent)
  319. {
  320. MOZ_ASSERT(aNewParent != mParent);
  321. // This function shouldn't be getting called if the parents have different
  322. // values for some flags in mBits (unless the flag is also set on this style
  323. // context) because if that were the case we would need to recompute those
  324. // bits for |this|.
  325. #define CHECK_FLAG(bit_) \
  326. MOZ_ASSERT((mParent->mBits & (bit_)) == (aNewParent->mBits & (bit_)) || \
  327. (mBits & (bit_)), \
  328. "MoveTo cannot be called if " #bit_ " value on old and new " \
  329. "style context parents do not match, unless the flag is set " \
  330. "on this style context");
  331. CHECK_FLAG(NS_STYLE_HAS_PSEUDO_ELEMENT_DATA)
  332. CHECK_FLAG(NS_STYLE_IN_DISPLAY_NONE_SUBTREE)
  333. CHECK_FLAG(NS_STYLE_HAS_TEXT_DECORATION_LINES)
  334. CHECK_FLAG(NS_STYLE_RELEVANT_LINK_VISITED)
  335. #undef CHECK_FLAG
  336. // Assertions checking for visited style are just to avoid some tricky
  337. // cases we can't be bothered handling at the moment.
  338. MOZ_ASSERT(!IsStyleIfVisited());
  339. MOZ_ASSERT(!mParent->IsStyleIfVisited());
  340. MOZ_ASSERT(!aNewParent->IsStyleIfVisited());
  341. MOZ_ASSERT(!mStyleIfVisited || mStyleIfVisited->mParent == mParent);
  342. if (mParent->HasChildThatUsesResetStyle()) {
  343. aNewParent->AddStyleBit(NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE);
  344. }
  345. mParent->RemoveChild(this);
  346. mParent = aNewParent;
  347. mParent->AddChild(this);
  348. if (mStyleIfVisited) {
  349. mStyleIfVisited->mParent->RemoveChild(mStyleIfVisited);
  350. mStyleIfVisited->mParent = aNewParent;
  351. mStyleIfVisited->mParent->AddChild(mStyleIfVisited);
  352. }
  353. }
  354. already_AddRefed<nsStyleContext>
  355. nsStyleContext::FindChildWithRules(const nsIAtom* aPseudoTag,
  356. NonOwningStyleContextSource aSource,
  357. NonOwningStyleContextSource aSourceIfVisited,
  358. bool aRelevantLinkVisited)
  359. {
  360. uint32_t threshold = 10; // The # of siblings we're willing to examine
  361. // before just giving this whole thing up.
  362. RefPtr<nsStyleContext> result;
  363. nsStyleContext *list = aSource.MatchesNoRules() ? mEmptyChild : mChild;
  364. if (list) {
  365. nsStyleContext *child = list;
  366. do {
  367. if (child->mSource.AsRaw() == aSource &&
  368. child->mPseudoTag == aPseudoTag &&
  369. !child->IsStyleIfVisited() &&
  370. child->RelevantLinkVisited() == aRelevantLinkVisited) {
  371. bool match = false;
  372. if (!aSourceIfVisited.IsNull()) {
  373. match = child->GetStyleIfVisited() &&
  374. child->GetStyleIfVisited()->mSource.AsRaw() == aSourceIfVisited;
  375. } else {
  376. match = !child->GetStyleIfVisited();
  377. }
  378. if (match && !(child->mBits & NS_STYLE_INELIGIBLE_FOR_SHARING)) {
  379. result = child;
  380. break;
  381. }
  382. }
  383. child = child->mNextSibling;
  384. threshold--;
  385. if (threshold == 0)
  386. break;
  387. } while (child != list);
  388. }
  389. if (result) {
  390. if (result != list) {
  391. // Move result to the front of the list.
  392. RemoveChild(result);
  393. AddChild(result);
  394. }
  395. result->mBits |= NS_STYLE_IS_SHARED;
  396. }
  397. return result.forget();
  398. }
  399. const void* nsStyleContext::StyleData(nsStyleStructID aSID)
  400. {
  401. const void* cachedData = GetCachedStyleData(aSID);
  402. if (cachedData)
  403. return cachedData; // We have computed data stored on this node in the context tree.
  404. // Our style source will take care of it for us.
  405. const void* newData;
  406. if (mSource.IsGeckoRuleNode()) {
  407. newData = mSource.AsGeckoRuleNode()->GetStyleData(aSID, this, true);
  408. if (!nsCachedStyleData::IsReset(aSID)) {
  409. // always cache inherited data on the style context; the rule
  410. // node set the bit in mBits for us if needed.
  411. mCachedInheritedData.mStyleStructs[aSID] = const_cast<void*>(newData);
  412. }
  413. } else {
  414. newData = StyleStructFromServoComputedValues(aSID);
  415. // perform any remaining main thread work on the struct
  416. switch (aSID) {
  417. #define STYLE_STRUCT(name_, checkdata_cb_) \
  418. case eStyleStruct_##name_: { \
  419. auto data = static_cast<const nsStyle##name_*>(newData); \
  420. const_cast<nsStyle##name_*>(data)->FinishStyle(PresContext()); \
  421. break; \
  422. }
  423. #include "nsStyleStructList.h"
  424. #undef STYLE_STRUCT
  425. default:
  426. MOZ_ASSERT_UNREACHABLE("unexpected nsStyleStructID value");
  427. break;
  428. }
  429. // The Servo-backed StyleContextSource owns the struct.
  430. AddStyleBit(nsCachedStyleData::GetBitForSID(aSID));
  431. // XXXbholley: Unconditionally caching reset structs here defeats the memory
  432. // optimization where we lazily allocate mCachedResetData, so that we can avoid
  433. // performing an FFI call each time we want to get the style structs. We should
  434. // measure the tradeoffs at some point. If the FFI overhead is low and the memory
  435. // win significant, we should consider _always_ grabbing the struct over FFI, and
  436. // potentially giving mCachedInheritedData the same treatment.
  437. //
  438. // Note that there is a similar comment in the struct getters in nsStyleContext.h.
  439. SetStyle(aSID, const_cast<void*>(newData));
  440. }
  441. return newData;
  442. }
  443. // This is an evil evil function, since it forces you to alloc your own separate copy of
  444. // style data! Do not use this function unless you absolutely have to! You should avoid
  445. // this at all costs! -dwh
  446. void*
  447. nsStyleContext::GetUniqueStyleData(const nsStyleStructID& aSID)
  448. {
  449. MOZ_ASSERT(!mSource.IsServoComputedValues(),
  450. "Can't COW-mutate servo values from Gecko!");
  451. // If we already own the struct and no kids could depend on it, then
  452. // just return it. (We leak in this case if there are kids -- and this
  453. // function really shouldn't be called for style contexts that could
  454. // have kids depending on the data. ClearStyleData would be OK, but
  455. // this test for no mChild or mEmptyChild doesn't catch that case.)
  456. const void *current = StyleData(aSID);
  457. if (!mChild && !mEmptyChild &&
  458. !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
  459. GetCachedStyleData(aSID))
  460. return const_cast<void*>(current);
  461. void* result;
  462. nsPresContext *presContext = PresContext();
  463. switch (aSID) {
  464. #define UNIQUE_CASE(c_) \
  465. case eStyleStruct_##c_: \
  466. result = new (presContext) nsStyle##c_( \
  467. * static_cast<const nsStyle##c_ *>(current)); \
  468. break;
  469. UNIQUE_CASE(Font)
  470. UNIQUE_CASE(Display)
  471. UNIQUE_CASE(Text)
  472. UNIQUE_CASE(TextReset)
  473. UNIQUE_CASE(Visibility)
  474. #undef UNIQUE_CASE
  475. default:
  476. NS_ERROR("Struct type not supported. Please find another way to do this if you can!");
  477. return nullptr;
  478. }
  479. SetStyle(aSID, result);
  480. mBits &= ~static_cast<uint64_t>(nsCachedStyleData::GetBitForSID(aSID));
  481. return result;
  482. }
  483. // This is an evil function, but less evil than GetUniqueStyleData. It
  484. // creates an empty style struct for this nsStyleContext.
  485. void*
  486. nsStyleContext::CreateEmptyStyleData(const nsStyleStructID& aSID)
  487. {
  488. MOZ_ASSERT(!mChild && !mEmptyChild &&
  489. !(mBits & nsCachedStyleData::GetBitForSID(aSID)) &&
  490. !GetCachedStyleData(aSID),
  491. "This style should not have been computed");
  492. void* result;
  493. nsPresContext* presContext = PresContext();
  494. switch (aSID) {
  495. #define UNIQUE_CASE(c_) \
  496. case eStyleStruct_##c_: \
  497. result = new (presContext) nsStyle##c_(presContext); \
  498. break;
  499. UNIQUE_CASE(Border)
  500. UNIQUE_CASE(Padding)
  501. #undef UNIQUE_CASE
  502. default:
  503. NS_ERROR("Struct type not supported.");
  504. return nullptr;
  505. }
  506. // The new struct is owned by this style context, but that we don't
  507. // need to clear the bit in mBits because we've asserted that at the
  508. // top of this function.
  509. SetStyle(aSID, result);
  510. return result;
  511. }
  512. void
  513. nsStyleContext::SetStyle(nsStyleStructID aSID, void* aStruct)
  514. {
  515. // This method should only be called from nsRuleNode! It is not a public
  516. // method!
  517. NS_ASSERTION(aSID >= 0 && aSID < nsStyleStructID_Length, "out of bounds");
  518. // NOTE: nsCachedStyleData::GetStyleData works roughly the same way.
  519. // See the comments there (in nsRuleNode.h) for more details about
  520. // what this is doing and why.
  521. void** dataSlot;
  522. if (nsCachedStyleData::IsReset(aSID)) {
  523. if (!mCachedResetData) {
  524. mCachedResetData = new (PresContext()) nsResetStyleData;
  525. }
  526. dataSlot = &mCachedResetData->mStyleStructs[aSID];
  527. } else {
  528. dataSlot = &mCachedInheritedData.mStyleStructs[aSID];
  529. }
  530. NS_ASSERTION(!*dataSlot || (mBits & nsCachedStyleData::GetBitForSID(aSID)),
  531. "Going to leak style data");
  532. *dataSlot = aStruct;
  533. }
  534. static bool
  535. ShouldSuppressLineBreak(const nsStyleContext* aContext,
  536. const nsStyleDisplay* aDisplay,
  537. const nsStyleContext* aParentContext,
  538. const nsStyleDisplay* aParentDisplay)
  539. {
  540. // The display change should only occur for "in-flow" children
  541. if (aDisplay->IsOutOfFlowStyle()) {
  542. return false;
  543. }
  544. // Display value of any anonymous box should not be touched. In most
  545. // cases, anonymous boxes are actually not in ruby frame, but instead,
  546. // some other frame with a ruby display value. Non-element pseudos
  547. // which represents text frames, as well as ruby pseudos are excluded
  548. // because we still want to set the flag for them.
  549. if (aContext->GetPseudoType() == CSSPseudoElementType::AnonBox &&
  550. !nsCSSAnonBoxes::IsNonElement(aContext->GetPseudo()) &&
  551. !RubyUtils::IsRubyPseudo(aContext->GetPseudo())) {
  552. return false;
  553. }
  554. if (aParentContext->ShouldSuppressLineBreak()) {
  555. // Line break suppressing bit is propagated to any children of
  556. // line participants, which include inline, contents, and inline
  557. // ruby boxes.
  558. if (aParentDisplay->mDisplay == mozilla::StyleDisplay::Inline ||
  559. aParentDisplay->mDisplay == mozilla::StyleDisplay::Contents ||
  560. aParentDisplay->mDisplay == mozilla::StyleDisplay::Ruby ||
  561. aParentDisplay->mDisplay == mozilla::StyleDisplay::RubyBaseContainer) {
  562. return true;
  563. }
  564. }
  565. // Any descendant of ruby level containers is non-breakable, but
  566. // the level containers themselves are breakable. We have to check
  567. // the container display type against all ruby display type here
  568. // because any of the ruby boxes could be anonymous.
  569. // Note that, when certain HTML tags, e.g. form controls, have ruby
  570. // level container display type, they could also escape from this flag
  571. // while they shouldn't. However, it is generally fine since they
  572. // won't usually break the assertion that there is no line break
  573. // inside ruby, because:
  574. // 1. their display types, the ruby level container types, are inline-
  575. // outside, which means they won't cause any forced line break; and
  576. // 2. they never start an inline span, which means their children, if
  577. // any, won't be able to break the line its ruby ancestor lays; and
  578. // 3. their parent frame is always a ruby content frame (due to
  579. // anonymous ruby box generation), which makes line layout suppress
  580. // any optional line break around this frame.
  581. // However, there is one special case which is BR tag, because it
  582. // directly affects the line layout. This case is handled by the BR
  583. // frame which checks the flag of its parent frame instead of itself.
  584. if ((aParentDisplay->IsRubyDisplayType() &&
  585. aDisplay->mDisplay != mozilla::StyleDisplay::RubyBaseContainer &&
  586. aDisplay->mDisplay != mozilla::StyleDisplay::RubyTextContainer) ||
  587. // Since ruby base and ruby text may exist themselves without any
  588. // non-anonymous frame outside, we should also check them.
  589. aDisplay->mDisplay == mozilla::StyleDisplay::RubyBase ||
  590. aDisplay->mDisplay == mozilla::StyleDisplay::RubyText) {
  591. return true;
  592. }
  593. return false;
  594. }
  595. // Flex & grid containers blockify their children.
  596. // "The display value of a flex item is blockified"
  597. // https://drafts.csswg.org/css-flexbox-1/#flex-items
  598. // "The display value of a grid item is blockified"
  599. // https://drafts.csswg.org/css-grid/#grid-items
  600. static bool
  601. ShouldBlockifyChildren(const nsStyleDisplay* aStyleDisp)
  602. {
  603. auto displayVal = aStyleDisp->mDisplay;
  604. return mozilla::StyleDisplay::Flex == displayVal ||
  605. mozilla::StyleDisplay::InlineFlex == displayVal ||
  606. mozilla::StyleDisplay::Grid == displayVal ||
  607. mozilla::StyleDisplay::InlineGrid == displayVal;
  608. }
  609. void
  610. nsStyleContext::SetStyleBits()
  611. {
  612. // XXXbholley: We should get this information directly from the
  613. // ServoComputedValues rather than computing it here. This setup for
  614. // ServoComputedValues-backed nsStyleContexts is probably not something
  615. // we should ship.
  616. //
  617. // For example, NS_STYLE_IS_TEXT_COMBINED is still set in ApplyStyleFixups,
  618. // which isn't called for ServoComputedValues.
  619. // See if we have any text decorations.
  620. // First see if our parent has text decorations. If our parent does, then we inherit the bit.
  621. if (mParent && mParent->HasTextDecorationLines()) {
  622. mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
  623. } else {
  624. // We might have defined a decoration.
  625. if (StyleTextReset()->HasTextDecorationLines()) {
  626. mBits |= NS_STYLE_HAS_TEXT_DECORATION_LINES;
  627. }
  628. }
  629. if ((mParent && mParent->HasPseudoElementData()) || IsPseudoElement()) {
  630. mBits |= NS_STYLE_HAS_PSEUDO_ELEMENT_DATA;
  631. }
  632. // Set the NS_STYLE_IN_DISPLAY_NONE_SUBTREE bit
  633. const nsStyleDisplay* disp = StyleDisplay();
  634. if ((mParent && mParent->IsInDisplayNoneSubtree()) ||
  635. disp->mDisplay == mozilla::StyleDisplay::None) {
  636. mBits |= NS_STYLE_IN_DISPLAY_NONE_SUBTREE;
  637. }
  638. }
  639. void
  640. nsStyleContext::ApplyStyleFixups(bool aSkipParentDisplayBasedStyleFixup)
  641. {
  642. MOZ_ASSERT(!mSource.IsServoComputedValues(),
  643. "Can't do Gecko style fixups on Servo values");
  644. #define GET_UNIQUE_STYLE_DATA(name_) \
  645. static_cast<nsStyle##name_*>(GetUniqueStyleData(eStyleStruct_##name_))
  646. // CSS Inline Layout Level 3 - 3.5 Sizing Initial Letters:
  647. // For an N-line drop initial in a Western script, the cap-height of the
  648. // letter needs to be (N – 1) times the line-height, plus the cap-height
  649. // of the surrounding text.
  650. if (mPseudoTag == nsCSSPseudoElements::firstLetter) {
  651. const nsStyleTextReset* textReset = StyleTextReset();
  652. if (textReset->mInitialLetterSize != 0.0f) {
  653. nsStyleContext* containerSC = mParent;
  654. const nsStyleDisplay* containerDisp = containerSC->StyleDisplay();
  655. while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
  656. if (!containerSC->GetParent()) {
  657. break;
  658. }
  659. containerSC = containerSC->GetParent();
  660. containerDisp = containerSC->StyleDisplay();
  661. }
  662. nscoord containerLH =
  663. ReflowInput::CalcLineHeight(nullptr, containerSC, NS_AUTOHEIGHT, 1.0f);
  664. RefPtr<nsFontMetrics> containerFM =
  665. nsLayoutUtils::GetFontMetricsForStyleContext(containerSC);
  666. MOZ_ASSERT(containerFM, "Should have fontMetrics!!");
  667. nscoord containerCH = containerFM->CapHeight();
  668. RefPtr<nsFontMetrics> firstLetterFM =
  669. nsLayoutUtils::GetFontMetricsForStyleContext(this);
  670. MOZ_ASSERT(firstLetterFM, "Should have fontMetrics!!");
  671. nscoord firstLetterCH = firstLetterFM->CapHeight();
  672. nsStyleFont* mutableStyleFont = GET_UNIQUE_STYLE_DATA(Font);
  673. float invCapHeightRatio =
  674. mutableStyleFont->mFont.size / NSCoordToFloat(firstLetterCH);
  675. mutableStyleFont->mFont.size =
  676. NSToCoordRound(((textReset->mInitialLetterSize - 1) * containerLH +
  677. containerCH) *
  678. invCapHeightRatio);
  679. }
  680. }
  681. // Change writing mode of text frame for text-combine-upright. We use
  682. // style structs of the parent to avoid triggering computation before
  683. // we change the writing mode.
  684. // It is safe to look at the parent's style because we are looking at
  685. // inherited properties, and ::-moz-text never matches any rules.
  686. if (mPseudoTag == nsCSSAnonBoxes::mozText && mParent &&
  687. mParent->StyleVisibility()->mWritingMode !=
  688. NS_STYLE_WRITING_MODE_HORIZONTAL_TB &&
  689. mParent->StyleText()->mTextCombineUpright ==
  690. NS_STYLE_TEXT_COMBINE_UPRIGHT_ALL) {
  691. MOZ_ASSERT(!PeekStyleVisibility(), "If StyleVisibility was already "
  692. "computed, some properties may have been computed "
  693. "incorrectly based on the old writing mode value");
  694. nsStyleVisibility* mutableVis = GET_UNIQUE_STYLE_DATA(Visibility);
  695. mutableVis->mWritingMode = NS_STYLE_WRITING_MODE_HORIZONTAL_TB;
  696. AddStyleBit(NS_STYLE_IS_TEXT_COMBINED);
  697. }
  698. // CSS 2.1 10.1: Propagate the root element's 'direction' to the ICB.
  699. // (PageContentFrame/CanvasFrame etc will inherit 'direction')
  700. if (mPseudoTag == nsCSSAnonBoxes::viewport) {
  701. nsPresContext* presContext = PresContext();
  702. mozilla::dom::Element* docElement = presContext->Document()->GetRootElement();
  703. if (docElement) {
  704. RefPtr<nsStyleContext> rootStyle =
  705. presContext->StyleSet()->ResolveStyleFor(docElement, nullptr);
  706. auto dir = rootStyle->StyleVisibility()->mDirection;
  707. if (dir != StyleVisibility()->mDirection) {
  708. nsStyleVisibility* uniqueVisibility = GET_UNIQUE_STYLE_DATA(Visibility);
  709. uniqueVisibility->mDirection = dir;
  710. }
  711. }
  712. }
  713. // Correct tables.
  714. const nsStyleDisplay* disp = StyleDisplay();
  715. if (disp->mDisplay == mozilla::StyleDisplay::Table) {
  716. // -moz-center and -moz-right are used for HTML's alignment
  717. // This is covering the <div align="right"><table>...</table></div> case.
  718. // In this case, we don't want to inherit the text alignment into the table.
  719. const nsStyleText* text = StyleText();
  720. if (text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_LEFT ||
  721. text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_CENTER ||
  722. text->mTextAlign == NS_STYLE_TEXT_ALIGN_MOZ_RIGHT)
  723. {
  724. nsStyleText* uniqueText = GET_UNIQUE_STYLE_DATA(Text);
  725. uniqueText->mTextAlign = NS_STYLE_TEXT_ALIGN_START;
  726. }
  727. }
  728. // CSS2.1 section 9.2.4 specifies fixups for the 'display' property of
  729. // the root element. We can't implement them in nsRuleNode because we
  730. // don't want to store all display structs that aren't 'block',
  731. // 'inline', or 'table' in the style context tree on the off chance
  732. // that the root element has its style reresolved later. So do them
  733. // here if needed, by changing the style data, so that other code
  734. // doesn't get confused by looking at the style data.
  735. if (!mParent) {
  736. auto displayVal = disp->mDisplay;
  737. if (displayVal != mozilla::StyleDisplay::Contents) {
  738. nsRuleNode::EnsureBlockDisplay(displayVal, true);
  739. } else {
  740. // http://dev.w3.org/csswg/css-display/#transformations
  741. // "... a display-outside of 'contents' computes to block-level
  742. // on the root element."
  743. displayVal = mozilla::StyleDisplay::Block;
  744. }
  745. if (displayVal != disp->mDisplay) {
  746. nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
  747. disp = mutable_display;
  748. // If we're in this code, then mOriginalDisplay doesn't matter
  749. // for purposes of the cascade (because this nsStyleDisplay
  750. // isn't living in the ruletree anyway), and for determining
  751. // hypothetical boxes it's better to have mOriginalDisplay
  752. // matching mDisplay here.
  753. mutable_display->mOriginalDisplay = mutable_display->mDisplay =
  754. displayVal;
  755. }
  756. }
  757. // Adjust the "display" values of flex and grid items (but not for raw text
  758. // or placeholders). CSS3 Flexbox section 4 says:
  759. // # The computed 'display' of a flex item is determined
  760. // # by applying the table in CSS 2.1 Chapter 9.7.
  761. // ...which converts inline-level elements to their block-level equivalents.
  762. // Any block-level element directly contained by elements with ruby display
  763. // values are converted to their inline-level equivalents.
  764. if (!aSkipParentDisplayBasedStyleFixup && mParent) {
  765. // Skip display:contents ancestors to reach the potential container.
  766. // (If there are only display:contents ancestors between this node and
  767. // a flex/grid container ancestor, then this node is a flex/grid item, since
  768. // its parent *in the frame tree* will be the flex/grid container. So we treat
  769. // it like a flex/grid item here.)
  770. nsStyleContext* containerContext = mParent;
  771. const nsStyleDisplay* containerDisp = containerContext->StyleDisplay();
  772. while (containerDisp->mDisplay == mozilla::StyleDisplay::Contents) {
  773. if (!containerContext->GetParent()) {
  774. break;
  775. }
  776. containerContext = containerContext->GetParent();
  777. containerDisp = containerContext->StyleDisplay();
  778. }
  779. if (ShouldBlockifyChildren(containerDisp) &&
  780. !nsCSSAnonBoxes::IsNonElement(GetPseudo())) {
  781. // NOTE: Technically, we shouldn't modify the 'display' value of
  782. // positioned elements, since they aren't flex/grid items. However,
  783. // we don't need to worry about checking for that, because if we're
  784. // positioned, we'll have already been through a call to
  785. // EnsureBlockDisplay() in nsRuleNode, so this call here won't change
  786. // anything. So we're OK.
  787. auto displayVal = disp->mDisplay;
  788. nsRuleNode::EnsureBlockDisplay(displayVal);
  789. if (displayVal != disp->mDisplay) {
  790. NS_ASSERTION(!disp->IsAbsolutelyPositionedStyle(),
  791. "We shouldn't be changing the display value of "
  792. "positioned content (and we should have already "
  793. "converted its display value to be block-level...)");
  794. nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
  795. disp = mutable_display;
  796. mutable_display->mDisplay = displayVal;
  797. }
  798. }
  799. }
  800. // Note: This must come after the blockification above, otherwise we fail
  801. // the grid-item-blockifying-001.html reftest.
  802. if (mParent && ::ShouldSuppressLineBreak(this, disp, mParent,
  803. mParent->StyleDisplay())) {
  804. mBits |= NS_STYLE_SUPPRESS_LINEBREAK;
  805. auto displayVal = disp->mDisplay;
  806. nsRuleNode::EnsureInlineDisplay(displayVal);
  807. if (displayVal != disp->mDisplay) {
  808. nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
  809. disp = mutable_display;
  810. mutable_display->mDisplay = displayVal;
  811. }
  812. }
  813. // Suppress border/padding of ruby level containers
  814. if (disp->mDisplay == mozilla::StyleDisplay::RubyBaseContainer ||
  815. disp->mDisplay == mozilla::StyleDisplay::RubyTextContainer) {
  816. CreateEmptyStyleData(eStyleStruct_Border);
  817. CreateEmptyStyleData(eStyleStruct_Padding);
  818. }
  819. if (disp->IsRubyDisplayType()) {
  820. // Per CSS Ruby spec section Bidi Reordering, for all ruby boxes,
  821. // the 'normal' and 'embed' values of 'unicode-bidi' should compute to
  822. // 'isolate', and 'bidi-override' should compute to 'isolate-override'.
  823. const nsStyleTextReset* textReset = StyleTextReset();
  824. uint8_t unicodeBidi = textReset->mUnicodeBidi;
  825. if (unicodeBidi == NS_STYLE_UNICODE_BIDI_NORMAL ||
  826. unicodeBidi == NS_STYLE_UNICODE_BIDI_EMBED) {
  827. unicodeBidi = NS_STYLE_UNICODE_BIDI_ISOLATE;
  828. } else if (unicodeBidi == NS_STYLE_UNICODE_BIDI_BIDI_OVERRIDE) {
  829. unicodeBidi = NS_STYLE_UNICODE_BIDI_ISOLATE_OVERRIDE;
  830. }
  831. if (unicodeBidi != textReset->mUnicodeBidi) {
  832. nsStyleTextReset* mutableTextReset = GET_UNIQUE_STYLE_DATA(TextReset);
  833. mutableTextReset->mUnicodeBidi = unicodeBidi;
  834. }
  835. }
  836. /*
  837. * According to https://drafts.csswg.org/css-writing-modes-3/#block-flow:
  838. *
  839. * If a box has a different block flow direction than its containing block:
  840. * * If the box has a specified display of inline, its display computes
  841. * to inline-block. [CSS21]
  842. * ...etc.
  843. */
  844. if (disp->mDisplay == mozilla::StyleDisplay::Inline &&
  845. !nsCSSAnonBoxes::IsNonElement(mPseudoTag) &&
  846. mParent) {
  847. auto cbContext = mParent;
  848. while (cbContext->StyleDisplay()->mDisplay == mozilla::StyleDisplay::Contents) {
  849. cbContext = cbContext->mParent;
  850. }
  851. MOZ_ASSERT(cbContext, "the root context can't have display:contents");
  852. // We don't need the full mozilla::WritingMode value (incorporating dir
  853. // and text-orientation) here; just the writing-mode property is enough.
  854. if (StyleVisibility()->mWritingMode !=
  855. cbContext->StyleVisibility()->mWritingMode) {
  856. nsStyleDisplay* mutable_display = GET_UNIQUE_STYLE_DATA(Display);
  857. disp = mutable_display;
  858. mutable_display->mOriginalDisplay = mutable_display->mDisplay =
  859. mozilla::StyleDisplay::InlineBlock;
  860. }
  861. }
  862. // Compute User Interface style, to trigger loads of cursors
  863. StyleUserInterface();
  864. #undef GET_UNIQUE_STYLE_DATA
  865. }
  866. template<class StyleContextLike>
  867. nsChangeHint
  868. nsStyleContext::CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
  869. nsChangeHint aParentHintsNotHandledForDescendants,
  870. uint32_t* aEqualStructs,
  871. uint32_t* aSamePointerStructs)
  872. {
  873. PROFILER_LABEL("nsStyleContext", "CalcStyleDifference",
  874. js::ProfileEntry::Category::CSS);
  875. MOZ_ASSERT(NS_IsHintSubset(aParentHintsNotHandledForDescendants,
  876. nsChangeHint_Hints_NotHandledForDescendants),
  877. "caller is passing inherited hints, but shouldn't be");
  878. static_assert(nsStyleStructID_Length <= 32,
  879. "aEqualStructs is not big enough");
  880. *aEqualStructs = 0;
  881. nsChangeHint hint = nsChangeHint(0);
  882. NS_ENSURE_TRUE(aNewContext, hint);
  883. // We must always ensure that we populate the structs on the new style
  884. // context that are filled in on the old context, so that if we get
  885. // two style changes in succession, the second of which causes a real
  886. // style change, the PeekStyleData doesn't return null (implying that
  887. // nobody ever looked at that struct's data). In other words, we
  888. // can't skip later structs if we get a big change up front, because
  889. // we could later get a small change in one of those structs that we
  890. // don't want to miss.
  891. // If our sources are the same, then any differences in style data
  892. // are already accounted for by differences on ancestors. We know
  893. // this because CalcStyleDifference is always called on two style
  894. // contexts that point to the same element, so we know that our
  895. // position in the style context tree is the same and our position in
  896. // the rule node tree (if applicable) is also the same.
  897. // However, if there were noninherited style change hints on the
  898. // parent, we might produce these same noninherited hints on this
  899. // style context's frame due to 'inherit' values, so we do need to
  900. // compare.
  901. // (Things like 'em' units are handled by the change hint produced
  902. // by font-size changing, so we don't need to worry about them like
  903. // we worry about 'inherit' values.)
  904. bool compare = StyleSource() != aNewContext->StyleSource();
  905. DebugOnly<uint32_t> structsFound = 0;
  906. // If we had any change in variable values, then we'll need to examine
  907. // all of the other style structs too, even if the new style context has
  908. // the same source as the old one.
  909. const nsStyleVariables* thisVariables = PeekStyleVariables();
  910. if (thisVariables) {
  911. structsFound |= NS_STYLE_INHERIT_BIT(Variables);
  912. const nsStyleVariables* otherVariables = aNewContext->StyleVariables();
  913. if (thisVariables->mVariables == otherVariables->mVariables) {
  914. *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
  915. } else {
  916. compare = true;
  917. }
  918. } else {
  919. *aEqualStructs |= NS_STYLE_INHERIT_BIT(Variables);
  920. }
  921. DebugOnly<int> styleStructCount = 1; // count Variables already
  922. #define DO_STRUCT_DIFFERENCE(struct_) \
  923. PR_BEGIN_MACRO \
  924. const nsStyle##struct_* this##struct_ = PeekStyle##struct_(); \
  925. if (this##struct_) { \
  926. structsFound |= NS_STYLE_INHERIT_BIT(struct_); \
  927. const nsStyle##struct_* other##struct_ = aNewContext->Style##struct_(); \
  928. nsChangeHint maxDifference = nsStyle##struct_::MaxDifference(); \
  929. nsChangeHint differenceAlwaysHandledForDescendants = \
  930. nsStyle##struct_::DifferenceAlwaysHandledForDescendants(); \
  931. if (this##struct_ == other##struct_) { \
  932. /* The very same struct, so we know that there will be no */ \
  933. /* differences. */ \
  934. *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
  935. } else if (compare || \
  936. ((maxDifference & ~differenceAlwaysHandledForDescendants) & \
  937. aParentHintsNotHandledForDescendants)) { \
  938. nsChangeHint difference = \
  939. this##struct_->CalcDifference(*other##struct_ EXTRA_DIFF_ARGS); \
  940. NS_ASSERTION(NS_IsHintSubset(difference, maxDifference), \
  941. "CalcDifference() returned bigger hint than " \
  942. "MaxDifference()"); \
  943. hint |= difference; \
  944. if (!difference) { \
  945. *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
  946. } \
  947. } else { \
  948. /* We still must call CalcDifference to see if there were any */ \
  949. /* changes so that we can set *aEqualStructs appropriately. */ \
  950. nsChangeHint difference = \
  951. this##struct_->CalcDifference(*other##struct_ EXTRA_DIFF_ARGS); \
  952. NS_ASSERTION(NS_IsHintSubset(difference, maxDifference), \
  953. "CalcDifference() returned bigger hint than " \
  954. "MaxDifference()"); \
  955. if (!difference) { \
  956. *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
  957. } \
  958. } \
  959. } else { \
  960. *aEqualStructs |= NS_STYLE_INHERIT_BIT(struct_); \
  961. } \
  962. styleStructCount++; \
  963. PR_END_MACRO
  964. // In general, we want to examine structs starting with those that can
  965. // cause the largest style change, down to those that can cause the
  966. // smallest. This lets us skip later ones if we already have a hint
  967. // that subsumes their MaxDifference. (As the hints get
  968. // finer-grained, this optimization is becoming less useful, though.)
  969. #define EXTRA_DIFF_ARGS /* nothing */
  970. DO_STRUCT_DIFFERENCE(Display);
  971. DO_STRUCT_DIFFERENCE(XUL);
  972. DO_STRUCT_DIFFERENCE(Column);
  973. DO_STRUCT_DIFFERENCE(Content);
  974. DO_STRUCT_DIFFERENCE(UserInterface);
  975. DO_STRUCT_DIFFERENCE(Visibility);
  976. DO_STRUCT_DIFFERENCE(Outline);
  977. DO_STRUCT_DIFFERENCE(TableBorder);
  978. DO_STRUCT_DIFFERENCE(Table);
  979. DO_STRUCT_DIFFERENCE(UIReset);
  980. DO_STRUCT_DIFFERENCE(Text);
  981. DO_STRUCT_DIFFERENCE(List);
  982. DO_STRUCT_DIFFERENCE(SVGReset);
  983. DO_STRUCT_DIFFERENCE(SVG);
  984. #undef EXTRA_DIFF_ARGS
  985. #define EXTRA_DIFF_ARGS , PeekStyleVisibility()
  986. DO_STRUCT_DIFFERENCE(Position);
  987. #undef EXTRA_DIFF_ARGS
  988. #define EXTRA_DIFF_ARGS /* nothing */
  989. DO_STRUCT_DIFFERENCE(Font);
  990. DO_STRUCT_DIFFERENCE(Margin);
  991. DO_STRUCT_DIFFERENCE(Padding);
  992. DO_STRUCT_DIFFERENCE(Border);
  993. DO_STRUCT_DIFFERENCE(TextReset);
  994. DO_STRUCT_DIFFERENCE(Effects);
  995. DO_STRUCT_DIFFERENCE(Background);
  996. DO_STRUCT_DIFFERENCE(Color);
  997. #undef EXTRA_DIFF_ARGS
  998. #undef DO_STRUCT_DIFFERENCE
  999. MOZ_ASSERT(styleStructCount == nsStyleStructID_Length,
  1000. "missing a call to DO_STRUCT_DIFFERENCE");
  1001. #ifdef DEBUG
  1002. #define STYLE_STRUCT(name_, callback_) \
  1003. MOZ_ASSERT(!!(structsFound & NS_STYLE_INHERIT_BIT(name_)) == \
  1004. !!PeekStyle##name_(), \
  1005. "PeekStyleData results must not change in the middle of " \
  1006. "difference calculation.");
  1007. #include "nsStyleStructList.h"
  1008. #undef STYLE_STRUCT
  1009. #endif
  1010. // We check for struct pointer equality here rather than as part of the
  1011. // DO_STRUCT_DIFFERENCE calls, since those calls can result in structs
  1012. // we previously examined and found to be null on this style context
  1013. // getting computed by later DO_STRUCT_DIFFERENCE calls (which can
  1014. // happen when the nsRuleNode::ComputeXXXData method looks up another
  1015. // struct.) This is important for callers in RestyleManager that
  1016. // need to know the equality or not of the final set of cached struct
  1017. // pointers.
  1018. *aSamePointerStructs = 0;
  1019. #define STYLE_STRUCT(name_, callback_) \
  1020. { \
  1021. const nsStyle##name_* data = PeekStyle##name_(); \
  1022. if (!data || data == aNewContext->Style##name_()) { \
  1023. *aSamePointerStructs |= NS_STYLE_INHERIT_BIT(name_); \
  1024. } \
  1025. }
  1026. #include "nsStyleStructList.h"
  1027. #undef STYLE_STRUCT
  1028. // Note that we do not check whether this->RelevantLinkVisited() !=
  1029. // aNewContext->RelevantLinkVisited(); we don't need to since
  1030. // nsCSSFrameConstructor::DoContentStateChanged always adds
  1031. // nsChangeHint_RepaintFrame for NS_EVENT_STATE_VISITED changes (and
  1032. // needs to, since HasStateDependentStyle probably doesn't work right
  1033. // for NS_EVENT_STATE_VISITED). Hopefully this doesn't actually
  1034. // expose whether links are visited to performance tests since all
  1035. // link coloring happens asynchronously at a time when it's hard for
  1036. // the page to measure.
  1037. // However, we do need to compute the larger of the changes that can
  1038. // happen depending on whether the link is visited or unvisited, since
  1039. // doing only the one that's currently appropriate would expose which
  1040. // links are in history to easy performance measurement. Therefore,
  1041. // here, we add nsChangeHint_RepaintFrame hints (the maximum for
  1042. // things that can depend on :visited) for the properties on which we
  1043. // call GetVisitedDependentColor.
  1044. nsStyleContext *thisVis = GetStyleIfVisited(),
  1045. *otherVis = aNewContext->GetStyleIfVisited();
  1046. if (!thisVis != !otherVis) {
  1047. // One style context has a style-if-visited and the other doesn't.
  1048. // Presume a difference.
  1049. hint |= nsChangeHint_RepaintFrame;
  1050. } else if (thisVis && !NS_IsHintSubset(nsChangeHint_RepaintFrame, hint)) {
  1051. // Both style contexts have a style-if-visited.
  1052. bool change = false;
  1053. // NB: Calling Peek on |this|, not |thisVis|, since callers may look
  1054. // at a struct on |this| without looking at the same struct on
  1055. // |thisVis| (including this function if we skip one of these checks
  1056. // due to change being true already or due to the old style context
  1057. // not having a style-if-visited), but not the other way around.
  1058. if (PeekStyleColor()) {
  1059. if (thisVis->StyleColor()->mColor !=
  1060. otherVis->StyleColor()->mColor) {
  1061. change = true;
  1062. }
  1063. }
  1064. // NB: Calling Peek on |this|, not |thisVis| (see above).
  1065. if (!change && PeekStyleBackground()) {
  1066. if (thisVis->StyleBackground()->mBackgroundColor !=
  1067. otherVis->StyleBackground()->mBackgroundColor) {
  1068. change = true;
  1069. }
  1070. }
  1071. // NB: Calling Peek on |this|, not |thisVis| (see above).
  1072. if (!change && PeekStyleBorder()) {
  1073. const nsStyleBorder *thisVisBorder = thisVis->StyleBorder();
  1074. const nsStyleBorder *otherVisBorder = otherVis->StyleBorder();
  1075. NS_FOR_CSS_SIDES(side) {
  1076. if (thisVisBorder->mBorderColor[side] !=
  1077. otherVisBorder->mBorderColor[side]) {
  1078. change = true;
  1079. break;
  1080. }
  1081. }
  1082. }
  1083. // NB: Calling Peek on |this|, not |thisVis| (see above).
  1084. if (!change && PeekStyleOutline()) {
  1085. const nsStyleOutline *thisVisOutline = thisVis->StyleOutline();
  1086. const nsStyleOutline *otherVisOutline = otherVis->StyleOutline();
  1087. if (thisVisOutline->mOutlineColor != otherVisOutline->mOutlineColor) {
  1088. change = true;
  1089. }
  1090. }
  1091. // NB: Calling Peek on |this|, not |thisVis| (see above).
  1092. if (!change && PeekStyleColumn()) {
  1093. const nsStyleColumn *thisVisColumn = thisVis->StyleColumn();
  1094. const nsStyleColumn *otherVisColumn = otherVis->StyleColumn();
  1095. if (thisVisColumn->mColumnRuleColor != otherVisColumn->mColumnRuleColor) {
  1096. change = true;
  1097. }
  1098. }
  1099. // NB: Calling Peek on |this|, not |thisVis| (see above).
  1100. if (!change && PeekStyleText()) {
  1101. const nsStyleText* thisVisText = thisVis->StyleText();
  1102. const nsStyleText* otherVisText = otherVis->StyleText();
  1103. if (thisVisText->mTextEmphasisColor != otherVisText->mTextEmphasisColor ||
  1104. thisVisText->mWebkitTextFillColor != otherVisText->mWebkitTextFillColor ||
  1105. thisVisText->mWebkitTextStrokeColor != otherVisText->mWebkitTextStrokeColor) {
  1106. change = true;
  1107. }
  1108. }
  1109. // NB: Calling Peek on |this|, not |thisVis| (see above).
  1110. if (!change && PeekStyleTextReset()) {
  1111. const nsStyleTextReset *thisVisTextReset = thisVis->StyleTextReset();
  1112. const nsStyleTextReset *otherVisTextReset = otherVis->StyleTextReset();
  1113. if (thisVisTextReset->mTextDecorationColor !=
  1114. otherVisTextReset->mTextDecorationColor) {
  1115. change = true;
  1116. }
  1117. }
  1118. // NB: Calling Peek on |this|, not |thisVis| (see above).
  1119. if (!change && PeekStyleSVG()) {
  1120. const nsStyleSVG *thisVisSVG = thisVis->StyleSVG();
  1121. const nsStyleSVG *otherVisSVG = otherVis->StyleSVG();
  1122. if (thisVisSVG->mFill != otherVisSVG->mFill ||
  1123. thisVisSVG->mStroke != otherVisSVG->mStroke) {
  1124. change = true;
  1125. }
  1126. }
  1127. // NB: Calling Peek on |this|, not |thisVis| (see above).
  1128. if (!change && PeekStyleUserInterface()) {
  1129. const nsStyleUserInterface *thisVisUserInterface = thisVis->StyleUserInterface();
  1130. const nsStyleUserInterface *otherVisUserInterface = otherVis->StyleUserInterface();
  1131. if (thisVisUserInterface->mCaretColor !=
  1132. otherVisUserInterface->mCaretColor) {
  1133. change = true;
  1134. }
  1135. }
  1136. if (change) {
  1137. hint |= nsChangeHint_RepaintFrame;
  1138. }
  1139. }
  1140. if (hint & nsChangeHint_UpdateContainingBlock) {
  1141. // If a struct returned nsChangeHint_UpdateContainingBlock, that
  1142. // means that one property's influence on whether we're a containing
  1143. // block for abs-pos or fixed-pos elements has changed. However, we
  1144. // only need to return the hint if the overall computation of
  1145. // whether we establish a containing block has changed.
  1146. // This depends on data in nsStyleDisplay and nsStyleEffects, so we
  1147. // do it here.
  1148. // Note that it's perhaps good for this test to be last because it
  1149. // doesn't use Peek* functions to get the structs on the old
  1150. // context. But this isn't a big concern because these struct
  1151. // getters should be called during frame construction anyway.
  1152. if (StyleDisplay()->IsAbsPosContainingBlockForAppropriateFrame(this) ==
  1153. aNewContext->StyleDisplay()->
  1154. IsAbsPosContainingBlockForAppropriateFrame(aNewContext) &&
  1155. StyleDisplay()->IsFixedPosContainingBlockForAppropriateFrame(this) ==
  1156. aNewContext->StyleDisplay()->
  1157. IsFixedPosContainingBlockForAppropriateFrame(aNewContext)) {
  1158. // While some styles that cause the frame to be a containing block
  1159. // has changed, the overall result hasn't.
  1160. hint &= ~nsChangeHint_UpdateContainingBlock;
  1161. }
  1162. }
  1163. MOZ_ASSERT(NS_IsHintSubset(hint, nsChangeHint_AllHints),
  1164. "Added a new hint without bumping AllHints?");
  1165. return hint & ~nsChangeHint_NeutralChange;
  1166. }
  1167. nsChangeHint
  1168. nsStyleContext::CalcStyleDifference(nsStyleContext* aNewContext,
  1169. nsChangeHint aParentHintsNotHandledForDescendants,
  1170. uint32_t* aEqualStructs,
  1171. uint32_t* aSamePointerStructs)
  1172. {
  1173. return CalcStyleDifferenceInternal(aNewContext, aParentHintsNotHandledForDescendants,
  1174. aEqualStructs, aSamePointerStructs);
  1175. }
  1176. class MOZ_STACK_CLASS FakeStyleContext
  1177. {
  1178. public:
  1179. explicit FakeStyleContext(const ServoComputedValues* aComputedValues)
  1180. : mComputedValues(aComputedValues) {}
  1181. mozilla::NonOwningStyleContextSource StyleSource() const {
  1182. return mozilla::NonOwningStyleContextSource(mComputedValues);
  1183. }
  1184. nsStyleContext* GetStyleIfVisited() {
  1185. // XXXbholley: This is wrong. Need to implement to get visited handling
  1186. // corrrect!
  1187. return nullptr;
  1188. }
  1189. #define STYLE_STRUCT(name_, checkdata_cb_) \
  1190. const nsStyle##name_ * Style##name_() { \
  1191. return Servo_GetStyle##name_(mComputedValues); \
  1192. }
  1193. #include "nsStyleStructList.h"
  1194. #undef STYLE_STRUCT
  1195. private:
  1196. const ServoComputedValues* MOZ_NON_OWNING_REF mComputedValues;
  1197. };
  1198. nsChangeHint
  1199. nsStyleContext::CalcStyleDifference(const ServoComputedValues* aNewComputedValues,
  1200. nsChangeHint aParentHintsNotHandledForDescendants,
  1201. uint32_t* aEqualStructs,
  1202. uint32_t* aSamePointerStructs)
  1203. {
  1204. FakeStyleContext newContext(aNewComputedValues);
  1205. return CalcStyleDifferenceInternal(&newContext, aParentHintsNotHandledForDescendants,
  1206. aEqualStructs, aSamePointerStructs);
  1207. }
  1208. #ifdef DEBUG
  1209. void nsStyleContext::List(FILE* out, int32_t aIndent, bool aListDescendants)
  1210. {
  1211. nsAutoCString str;
  1212. // Indent
  1213. int32_t ix;
  1214. for (ix = aIndent; --ix >= 0; ) {
  1215. str.AppendLiteral(" ");
  1216. }
  1217. str.Append(nsPrintfCString("%p(%d) parent=%p ",
  1218. (void*)this, mRefCnt, (void *)mParent));
  1219. if (mPseudoTag) {
  1220. nsAutoString buffer;
  1221. mPseudoTag->ToString(buffer);
  1222. AppendUTF16toUTF8(buffer, str);
  1223. str.Append(' ');
  1224. }
  1225. if (mSource.IsServoComputedValues()) {
  1226. fprintf_stderr(out, "%s{ServoComputedValues}\n", str.get());
  1227. } else if (mSource.IsGeckoRuleNode()) {
  1228. fprintf_stderr(out, "%s{\n", str.get());
  1229. str.Truncate();
  1230. nsRuleNode* ruleNode = mSource.AsGeckoRuleNode();
  1231. while (ruleNode) {
  1232. nsIStyleRule *styleRule = ruleNode->GetRule();
  1233. if (styleRule) {
  1234. styleRule->List(out, aIndent + 1);
  1235. }
  1236. ruleNode = ruleNode->GetParent();
  1237. }
  1238. for (ix = aIndent; --ix >= 0; ) {
  1239. str.AppendLiteral(" ");
  1240. }
  1241. fprintf_stderr(out, "%s}\n", str.get());
  1242. }
  1243. else {
  1244. fprintf_stderr(out, "%s{}\n", str.get());
  1245. }
  1246. if (aListDescendants) {
  1247. if (nullptr != mChild) {
  1248. nsStyleContext* child = mChild;
  1249. do {
  1250. child->List(out, aIndent + 1, aListDescendants);
  1251. child = child->mNextSibling;
  1252. } while (mChild != child);
  1253. }
  1254. if (nullptr != mEmptyChild) {
  1255. nsStyleContext* child = mEmptyChild;
  1256. do {
  1257. child->List(out, aIndent + 1, aListDescendants);
  1258. child = child->mNextSibling;
  1259. } while (mEmptyChild != child);
  1260. }
  1261. }
  1262. }
  1263. #endif
  1264. // Overloaded new operator. Initializes the memory to 0 and relies on an arena
  1265. // (which comes from the presShell) to perform the allocation.
  1266. void*
  1267. nsStyleContext::operator new(size_t sz, nsPresContext* aPresContext)
  1268. {
  1269. // Check the recycle list first.
  1270. return aPresContext->PresShell()->
  1271. AllocateByObjectID(eArenaObjectID_nsStyleContext, sz);
  1272. }
  1273. // Overridden to prevent the global delete from being called, since the memory
  1274. // came out of an nsIArena instead of the global delete operator's heap.
  1275. void
  1276. nsStyleContext::Destroy()
  1277. {
  1278. // Get the pres context.
  1279. RefPtr<nsPresContext> presContext = PresContext();
  1280. // Call our destructor.
  1281. this->~nsStyleContext();
  1282. // Don't let the memory be freed, since it will be recycled
  1283. // instead. Don't call the global operator delete.
  1284. presContext->PresShell()->
  1285. FreeByObjectID(eArenaObjectID_nsStyleContext, this);
  1286. }
  1287. already_AddRefed<nsStyleContext>
  1288. NS_NewStyleContext(nsStyleContext* aParentContext,
  1289. nsIAtom* aPseudoTag,
  1290. CSSPseudoElementType aPseudoType,
  1291. nsRuleNode* aRuleNode,
  1292. bool aSkipParentDisplayBasedStyleFixup)
  1293. {
  1294. RefPtr<nsRuleNode> node = aRuleNode;
  1295. RefPtr<nsStyleContext> context =
  1296. new (aRuleNode->PresContext())
  1297. nsStyleContext(aParentContext, aPseudoTag, aPseudoType, node.forget(),
  1298. aSkipParentDisplayBasedStyleFixup);
  1299. return context.forget();
  1300. }
  1301. already_AddRefed<nsStyleContext>
  1302. NS_NewStyleContext(nsStyleContext* aParentContext,
  1303. nsPresContext* aPresContext,
  1304. nsIAtom* aPseudoTag,
  1305. CSSPseudoElementType aPseudoType,
  1306. already_AddRefed<ServoComputedValues> aComputedValues,
  1307. bool aSkipParentDisplayBasedStyleFixup)
  1308. {
  1309. RefPtr<nsStyleContext> context =
  1310. new (aPresContext)
  1311. nsStyleContext(aParentContext, aPresContext, aPseudoTag, aPseudoType,
  1312. Move(aComputedValues), aSkipParentDisplayBasedStyleFixup);
  1313. return context.forget();
  1314. }
  1315. nsIPresShell*
  1316. nsStyleContext::Arena()
  1317. {
  1318. return PresContext()->PresShell();
  1319. }
  1320. static inline void
  1321. ExtractAnimationValue(nsCSSPropertyID aProperty,
  1322. nsStyleContext* aStyleContext,
  1323. StyleAnimationValue& aResult)
  1324. {
  1325. DebugOnly<bool> success =
  1326. StyleAnimationValue::ExtractComputedValue(aProperty, aStyleContext,
  1327. aResult);
  1328. MOZ_ASSERT(success,
  1329. "aProperty must be extractable by StyleAnimationValue");
  1330. }
  1331. static Maybe<nscolor>
  1332. ExtractColor(nsCSSPropertyID aProperty,
  1333. nsStyleContext *aStyleContext)
  1334. {
  1335. StyleAnimationValue val;
  1336. ExtractAnimationValue(aProperty, aStyleContext, val);
  1337. switch (val.GetUnit()) {
  1338. case StyleAnimationValue::eUnit_Color:
  1339. return Some(val.GetCSSValueValue()->GetColorValue());
  1340. case StyleAnimationValue::eUnit_CurrentColor:
  1341. return Some(aStyleContext->StyleColor()->mColor);
  1342. case StyleAnimationValue::eUnit_ComplexColor:
  1343. return Some(aStyleContext->StyleColor()->
  1344. CalcComplexColor(val.GetStyleComplexColorValue()));
  1345. case StyleAnimationValue::eUnit_Auto:
  1346. return Some(aStyleContext->StyleColor()->
  1347. CalcComplexColor(StyleComplexColor::Auto()));
  1348. default:
  1349. return Nothing();
  1350. }
  1351. }
  1352. static nscolor
  1353. ExtractColorLenient(nsCSSPropertyID aProperty,
  1354. nsStyleContext *aStyleContext)
  1355. {
  1356. return ExtractColor(aProperty, aStyleContext).valueOr(NS_RGBA(0, 0, 0, 0));
  1357. }
  1358. struct ColorIndexSet {
  1359. uint8_t colorIndex, alphaIndex;
  1360. };
  1361. static const ColorIndexSet gVisitedIndices[2] = { { 0, 0 }, { 1, 0 } };
  1362. nscolor
  1363. nsStyleContext::GetVisitedDependentColor(nsCSSPropertyID aProperty)
  1364. {
  1365. NS_ASSERTION(aProperty == eCSSProperty_caret_color ||
  1366. aProperty == eCSSProperty_color ||
  1367. aProperty == eCSSProperty_background_color ||
  1368. aProperty == eCSSProperty_border_top_color ||
  1369. aProperty == eCSSProperty_border_right_color ||
  1370. aProperty == eCSSProperty_border_bottom_color ||
  1371. aProperty == eCSSProperty_border_left_color ||
  1372. aProperty == eCSSProperty_outline_color ||
  1373. aProperty == eCSSProperty_column_rule_color ||
  1374. aProperty == eCSSProperty_text_decoration_color ||
  1375. aProperty == eCSSProperty_text_emphasis_color ||
  1376. aProperty == eCSSProperty__webkit_text_fill_color ||
  1377. aProperty == eCSSProperty__webkit_text_stroke_color ||
  1378. aProperty == eCSSProperty_fill ||
  1379. aProperty == eCSSProperty_stroke,
  1380. "we need to add to nsStyleContext::CalcStyleDifference");
  1381. bool isPaintProperty = aProperty == eCSSProperty_fill ||
  1382. aProperty == eCSSProperty_stroke;
  1383. nscolor colors[2];
  1384. colors[0] = isPaintProperty ? ExtractColorLenient(aProperty, this)
  1385. : ExtractColor(aProperty, this).value();
  1386. nsStyleContext *visitedStyle = this->GetStyleIfVisited();
  1387. if (!visitedStyle) {
  1388. return colors[0];
  1389. }
  1390. colors[1] = isPaintProperty ? ExtractColorLenient(aProperty, visitedStyle)
  1391. : ExtractColor(aProperty, visitedStyle).value();
  1392. return nsStyleContext::CombineVisitedColors(colors,
  1393. this->RelevantLinkVisited());
  1394. }
  1395. /* static */ nscolor
  1396. nsStyleContext::CombineVisitedColors(nscolor *aColors, bool aLinkIsVisited)
  1397. {
  1398. if (NS_GET_A(aColors[1]) == 0) {
  1399. // If the style-if-visited is transparent, then just use the
  1400. // unvisited style rather than using the (meaningless) color
  1401. // components of the visited style along with a potentially
  1402. // non-transparent alpha value.
  1403. aLinkIsVisited = false;
  1404. }
  1405. // NOTE: We want this code to have as little timing dependence as
  1406. // possible on whether this->RelevantLinkVisited() is true.
  1407. const ColorIndexSet &set =
  1408. gVisitedIndices[aLinkIsVisited ? 1 : 0];
  1409. nscolor colorColor = aColors[set.colorIndex];
  1410. nscolor alphaColor = aColors[set.alphaIndex];
  1411. return NS_RGBA(NS_GET_R(colorColor), NS_GET_G(colorColor),
  1412. NS_GET_B(colorColor), NS_GET_A(alphaColor));
  1413. }
  1414. #ifdef DEBUG
  1415. /* static */ void
  1416. nsStyleContext::AssertStyleStructMaxDifferenceValid()
  1417. {
  1418. #define STYLE_STRUCT(name, checkdata_cb) \
  1419. MOZ_ASSERT(NS_IsHintSubset(nsStyle##name::DifferenceAlwaysHandledForDescendants(), \
  1420. nsStyle##name::MaxDifference()));
  1421. #include "nsStyleStructList.h"
  1422. #undef STYLE_STRUCT
  1423. }
  1424. /* static */ const char*
  1425. nsStyleContext::StructName(nsStyleStructID aSID)
  1426. {
  1427. switch (aSID) {
  1428. #define STYLE_STRUCT(name_, checkdata_cb) \
  1429. case eStyleStruct_##name_: \
  1430. return #name_;
  1431. #include "nsStyleStructList.h"
  1432. #undef STYLE_STRUCT
  1433. default:
  1434. return "Unknown";
  1435. }
  1436. }
  1437. /* static */ bool
  1438. nsStyleContext::LookupStruct(const nsACString& aName, nsStyleStructID& aResult)
  1439. {
  1440. if (false)
  1441. ;
  1442. #define STYLE_STRUCT(name_, checkdata_cb_) \
  1443. else if (aName.EqualsLiteral(#name_)) \
  1444. aResult = eStyleStruct_##name_;
  1445. #include "nsStyleStructList.h"
  1446. #undef STYLE_STRUCT
  1447. else
  1448. return false;
  1449. return true;
  1450. }
  1451. #endif
  1452. void
  1453. nsStyleContext::SwapStyleData(nsStyleContext* aNewContext, uint32_t aStructs)
  1454. {
  1455. static_assert(nsStyleStructID_Length <= 32, "aStructs is not big enough");
  1456. for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
  1457. i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
  1458. i = nsStyleStructID(i + 1)) {
  1459. uint32_t bit = nsCachedStyleData::GetBitForSID(i);
  1460. if (!(aStructs & bit)) {
  1461. continue;
  1462. }
  1463. void*& thisData = mCachedInheritedData.mStyleStructs[i];
  1464. void*& otherData = aNewContext->mCachedInheritedData.mStyleStructs[i];
  1465. if (mBits & bit) {
  1466. if (thisData == otherData) {
  1467. thisData = nullptr;
  1468. }
  1469. } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
  1470. std::swap(thisData, otherData);
  1471. }
  1472. }
  1473. for (nsStyleStructID i = nsStyleStructID_Reset_Start;
  1474. i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
  1475. i = nsStyleStructID(i + 1)) {
  1476. uint32_t bit = nsCachedStyleData::GetBitForSID(i);
  1477. if (!(aStructs & bit)) {
  1478. continue;
  1479. }
  1480. if (!mCachedResetData) {
  1481. mCachedResetData = new (PresContext()) nsResetStyleData;
  1482. }
  1483. if (!aNewContext->mCachedResetData) {
  1484. aNewContext->mCachedResetData = new (PresContext()) nsResetStyleData;
  1485. }
  1486. void*& thisData = mCachedResetData->mStyleStructs[i];
  1487. void*& otherData = aNewContext->mCachedResetData->mStyleStructs[i];
  1488. if (mBits & bit) {
  1489. if (thisData == otherData) {
  1490. thisData = nullptr;
  1491. }
  1492. } else if (!(aNewContext->mBits & bit) && thisData && otherData) {
  1493. std::swap(thisData, otherData);
  1494. }
  1495. }
  1496. }
  1497. void
  1498. nsStyleContext::ClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
  1499. {
  1500. if (mChild) {
  1501. nsStyleContext* child = mChild;
  1502. do {
  1503. child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
  1504. child = child->mNextSibling;
  1505. } while (mChild != child);
  1506. }
  1507. if (mEmptyChild) {
  1508. nsStyleContext* child = mEmptyChild;
  1509. do {
  1510. child->DoClearCachedInheritedStyleDataOnDescendants(aStructs);
  1511. child = child->mNextSibling;
  1512. } while (mEmptyChild != child);
  1513. }
  1514. }
  1515. void
  1516. nsStyleContext::DoClearCachedInheritedStyleDataOnDescendants(uint32_t aStructs)
  1517. {
  1518. NS_ASSERTION(mFrameRefCnt == 0, "frame still referencing style context");
  1519. for (nsStyleStructID i = nsStyleStructID_Inherited_Start;
  1520. i < nsStyleStructID_Inherited_Start + nsStyleStructID_Inherited_Count;
  1521. i = nsStyleStructID(i + 1)) {
  1522. uint32_t bit = nsCachedStyleData::GetBitForSID(i);
  1523. if (aStructs & bit) {
  1524. if (!(mBits & bit) && mCachedInheritedData.mStyleStructs[i]) {
  1525. aStructs &= ~bit;
  1526. } else {
  1527. mCachedInheritedData.mStyleStructs[i] = nullptr;
  1528. }
  1529. }
  1530. }
  1531. if (mCachedResetData) {
  1532. for (nsStyleStructID i = nsStyleStructID_Reset_Start;
  1533. i < nsStyleStructID_Reset_Start + nsStyleStructID_Reset_Count;
  1534. i = nsStyleStructID(i + 1)) {
  1535. uint32_t bit = nsCachedStyleData::GetBitForSID(i);
  1536. if (aStructs & bit) {
  1537. if (!(mBits & bit) && mCachedResetData->mStyleStructs[i]) {
  1538. aStructs &= ~bit;
  1539. } else {
  1540. mCachedResetData->mStyleStructs[i] = nullptr;
  1541. }
  1542. }
  1543. }
  1544. }
  1545. if (aStructs == 0) {
  1546. return;
  1547. }
  1548. ClearCachedInheritedStyleDataOnDescendants(aStructs);
  1549. }
  1550. void
  1551. nsStyleContext::SetIneligibleForSharing()
  1552. {
  1553. if (mBits & NS_STYLE_INELIGIBLE_FOR_SHARING) {
  1554. return;
  1555. }
  1556. mBits |= NS_STYLE_INELIGIBLE_FOR_SHARING;
  1557. if (mChild) {
  1558. nsStyleContext* child = mChild;
  1559. do {
  1560. child->SetIneligibleForSharing();
  1561. child = child->mNextSibling;
  1562. } while (mChild != child);
  1563. }
  1564. if (mEmptyChild) {
  1565. nsStyleContext* child = mEmptyChild;
  1566. do {
  1567. child->SetIneligibleForSharing();
  1568. child = child->mNextSibling;
  1569. } while (mEmptyChild != child);
  1570. }
  1571. }
  1572. #ifdef RESTYLE_LOGGING
  1573. nsCString
  1574. nsStyleContext::GetCachedStyleDataAsString(uint32_t aStructs)
  1575. {
  1576. nsCString structs;
  1577. for (nsStyleStructID i = nsStyleStructID(0);
  1578. i < nsStyleStructID_Length;
  1579. i = nsStyleStructID(i + 1)) {
  1580. if (aStructs & nsCachedStyleData::GetBitForSID(i)) {
  1581. const void* data = GetCachedStyleData(i);
  1582. if (!structs.IsEmpty()) {
  1583. structs.Append(' ');
  1584. }
  1585. structs.AppendPrintf("%s=%p", StructName(i), data);
  1586. if (HasCachedDependentStyleData(i)) {
  1587. structs.AppendLiteral("(dependent)");
  1588. } else {
  1589. structs.AppendLiteral("(owned)");
  1590. }
  1591. }
  1592. }
  1593. return structs;
  1594. }
  1595. int32_t&
  1596. nsStyleContext::LoggingDepth()
  1597. {
  1598. static int32_t depth = 0;
  1599. return depth;
  1600. }
  1601. void
  1602. nsStyleContext::LogStyleContextTree(int32_t aLoggingDepth, uint32_t aStructs)
  1603. {
  1604. LoggingDepth() = aLoggingDepth;
  1605. LogStyleContextTree(true, aStructs);
  1606. }
  1607. void
  1608. nsStyleContext::LogStyleContextTree(bool aFirst, uint32_t aStructs)
  1609. {
  1610. nsCString structs = GetCachedStyleDataAsString(aStructs);
  1611. if (!structs.IsEmpty()) {
  1612. structs.Append(' ');
  1613. }
  1614. nsCString pseudo;
  1615. if (mPseudoTag) {
  1616. nsAutoString pseudoTag;
  1617. mPseudoTag->ToString(pseudoTag);
  1618. AppendUTF16toUTF8(pseudoTag, pseudo);
  1619. pseudo.Append(' ');
  1620. }
  1621. nsCString flags;
  1622. if (IsStyleIfVisited()) {
  1623. flags.AppendLiteral("IS_STYLE_IF_VISITED ");
  1624. }
  1625. if (HasChildThatUsesGrandancestorStyle()) {
  1626. flags.AppendLiteral("CHILD_USES_GRANDANCESTOR_STYLE ");
  1627. }
  1628. if (IsShared()) {
  1629. flags.AppendLiteral("IS_SHARED ");
  1630. }
  1631. nsCString parent;
  1632. if (aFirst) {
  1633. parent.AppendPrintf("parent=%p ", mParent.get());
  1634. }
  1635. LOG_RESTYLE("%p(%d) %s%s%s%s",
  1636. this, mRefCnt,
  1637. structs.get(), pseudo.get(), flags.get(), parent.get());
  1638. LOG_RESTYLE_INDENT();
  1639. if (nullptr != mChild) {
  1640. nsStyleContext* child = mChild;
  1641. do {
  1642. child->LogStyleContextTree(false, aStructs);
  1643. child = child->mNextSibling;
  1644. } while (mChild != child);
  1645. }
  1646. if (nullptr != mEmptyChild) {
  1647. nsStyleContext* child = mEmptyChild;
  1648. do {
  1649. child->LogStyleContextTree(false, aStructs);
  1650. child = child->mNextSibling;
  1651. } while (mEmptyChild != child);
  1652. }
  1653. }
  1654. #endif
  1655. #ifdef DEBUG
  1656. /* static */ void
  1657. nsStyleContext::Initialize()
  1658. {
  1659. Preferences::AddBoolVarCache(
  1660. &sExpensiveStyleStructAssertionsEnabled,
  1661. "layout.css.expensive-style-struct-assertions.enabled");
  1662. }
  1663. #endif