Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /* the interface (to internal code) for retrieving computed style data */
7 :
8 : #ifndef _nsStyleContext_h_
9 : #define _nsStyleContext_h_
10 :
11 : #include "mozilla/Assertions.h"
12 : #include "mozilla/RestyleLogging.h"
13 : #include "mozilla/ServoStyleSet.h"
14 : #include "mozilla/ServoUtils.h"
15 : #include "mozilla/StyleComplexColor.h"
16 : #include "nsCSSAnonBoxes.h"
17 : #include "nsStyleSet.h"
18 :
19 : class nsIAtom;
20 : class nsPresContext;
21 :
22 : namespace mozilla {
23 : enum class CSSPseudoElementType : uint8_t;
24 : class GeckoStyleContext;
25 : class ServoStyleContext;
26 : } // namespace mozilla
27 :
28 : extern "C" {
29 : #define STYLE_STRUCT(name_, checkdata_cb_) \
30 : struct nsStyle##name_; \
31 : const nsStyle##name_* Servo_GetStyle##name_( \
32 : ServoComputedValuesBorrowedOrNull computed_values);
33 : #include "nsStyleStructList.h"
34 : #undef STYLE_STRUCT
35 : }
36 :
37 : /**
38 : * An nsStyleContext represents the computed style data for an element.
39 : * The computed style data are stored in a set of structs (see
40 : * nsStyleStruct.h) that are cached either on the style context or in
41 : * the rule tree (see nsRuleNode.h for a description of this caching and
42 : * how the cached structs are shared).
43 : *
44 : * Since the data in |nsIStyleRule|s and |nsRuleNode|s are immutable
45 : * (with a few exceptions, like system color changes), the data in an
46 : * nsStyleContext are also immutable (with the additional exception of
47 : * GetUniqueStyleData). When style data change,
48 : * ElementRestyler::Restyle creates a new style context.
49 : *
50 : * Style contexts are reference counted. References are generally held
51 : * by:
52 : * 1. the |nsIFrame|s that are using the style context and
53 : * 2. any *child* style contexts (this might be the reverse of
54 : * expectation, but it makes sense in this case)
55 : */
56 :
57 : class nsStyleContext
58 : {
59 : public:
60 : #ifdef MOZ_STYLO
61 : bool IsGecko() const { return !IsServo(); }
62 : bool IsServo() const { return (mBits & NS_STYLE_CONTEXT_IS_GECKO) == 0; }
63 : #else
64 1187646 : bool IsGecko() const { return true; }
65 77891 : bool IsServo() const { return false; }
66 : #endif
67 : MOZ_DECL_STYLO_CONVERT_METHODS(mozilla::GeckoStyleContext, mozilla::ServoStyleContext);
68 :
69 : void Destroy();
70 :
71 : // These two methods are for use by ArenaRefPtr.
72 8 : static mozilla::ArenaObjectID ArenaObjectID()
73 : {
74 8 : return mozilla::eArenaObjectID_GeckoStyleContext;
75 : }
76 : nsIPresShell* Arena();
77 :
78 : #ifdef DEBUG
79 : /**
80 : * Initializes a cached pref, which is only used in DEBUG code.
81 : */
82 : static void Initialize();
83 : #endif
84 :
85 14604 : nsrefcnt AddRef() {
86 14604 : if (mRefCnt == UINT32_MAX) {
87 0 : NS_WARNING("refcount overflow, leaking object");
88 0 : return mRefCnt;
89 : }
90 14604 : ++mRefCnt;
91 14604 : NS_LOG_ADDREF(this, mRefCnt, "nsStyleContext", sizeof(nsStyleContext));
92 14604 : return mRefCnt;
93 : }
94 :
95 13323 : nsrefcnt Release() {
96 13323 : if (mRefCnt == UINT32_MAX) {
97 0 : NS_WARNING("refcount overflow, leaking object");
98 0 : return mRefCnt;
99 : }
100 13323 : --mRefCnt;
101 13323 : NS_LOG_RELEASE(this, mRefCnt, "nsStyleContext");
102 13323 : if (mRefCnt == 0) {
103 1618 : Destroy();
104 1618 : return 0;
105 : }
106 11705 : return mRefCnt;
107 : }
108 :
109 : #ifdef DEBUG
110 1411 : void FrameAddRef() {
111 1411 : ++mFrameRefCnt;
112 1411 : }
113 :
114 871 : void FrameRelease() {
115 871 : --mFrameRefCnt;
116 871 : }
117 :
118 : uint32_t FrameRefCnt() const {
119 : return mFrameRefCnt;
120 : }
121 : #endif
122 :
123 412 : bool HasSingleReference() const {
124 412 : NS_ASSERTION(mRefCnt != 0,
125 : "do not call HasSingleReference on a newly created "
126 : "nsStyleContext with no references yet");
127 412 : return mRefCnt == 1;
128 : }
129 :
130 : inline nsPresContext* PresContext() const;
131 :
132 : inline mozilla::GeckoStyleContext* GetParent() const;
133 :
134 476 : nsStyleContext* GetParentAllowServo() const {
135 476 : return mParent;
136 : }
137 :
138 36057 : nsIAtom* GetPseudo() const { return mPseudoTag; }
139 30418 : mozilla::CSSPseudoElementType GetPseudoType() const {
140 : return static_cast<mozilla::CSSPseudoElementType>(
141 30418 : mBits >> NS_STYLE_CONTEXT_TYPE_SHIFT);
142 : }
143 :
144 389 : bool IsAnonBox() const {
145 : return
146 435 : GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox ||
147 435 : GetPseudoType() == mozilla::CSSPseudoElementType::NonInheritingAnonBox;
148 : }
149 2140 : bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); }
150 :
151 :
152 : // Does this style context or any of its ancestors have text
153 : // decoration lines?
154 : // Differs from nsStyleTextReset::HasTextDecorationLines, which tests
155 : // only the data for a single context.
156 2448 : bool HasTextDecorationLines() const
157 2448 : { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
158 :
159 : // Whether any line break inside should be suppressed? If this returns
160 : // true, the line should not be broken inside, which means inlines act
161 : // as if nowrap is set, <br> is suppressed, and blocks are inlinized.
162 : // This bit is propogated to all children of line partitipants. It is
163 : // currently used by ruby to make its content frames unbreakable.
164 : // NOTE: for nsTextFrame, use nsTextFrame::ShouldSuppressLineBreak()
165 : // instead of this method.
166 2164 : bool ShouldSuppressLineBreak() const
167 2164 : { return !!(mBits & NS_STYLE_SUPPRESS_LINEBREAK); }
168 :
169 : // Does this style context or any of its ancestors have display:none set?
170 5136 : bool IsInDisplayNoneSubtree() const
171 5136 : { return !!(mBits & NS_STYLE_IN_DISPLAY_NONE_SUBTREE); }
172 :
173 : // Is this horizontal-in-vertical (tate-chu-yoko) text? This flag is
174 : // only set on style contexts whose pseudo is nsCSSAnonBoxes::mozText.
175 697 : bool IsTextCombined() const
176 697 : { return !!(mBits & NS_STYLE_IS_TEXT_COMBINED); }
177 :
178 : // Does this style context represent the style for a pseudo-element or
179 : // inherit data from such a style context? Whether this returns true
180 : // is equivalent to whether it or any of its ancestors returns
181 : // non-null for IsPseudoElement().
182 4419 : bool HasPseudoElementData() const
183 4419 : { return !!(mBits & NS_STYLE_HAS_PSEUDO_ELEMENT_DATA); }
184 :
185 37 : bool HasChildThatUsesResetStyle() const
186 37 : { return mBits & NS_STYLE_HAS_CHILD_THAT_USES_RESET_STYLE; }
187 :
188 : // Is the only link whose visitedness is allowed to influence the
189 : // style of the node this style context is for (which is that element
190 : // or its nearest ancestor that is a link) visited?
191 4676 : bool RelevantLinkVisited() const
192 4676 : { return !!(mBits & NS_STYLE_RELEVANT_LINK_VISITED); }
193 :
194 : // Is this a style context for a link?
195 : inline bool IsLinkContext() const;
196 :
197 : // Is this style context the GetStyleIfVisited() for some other style
198 : // context?
199 11197 : bool IsStyleIfVisited() const
200 11197 : { return !!(mBits & NS_STYLE_IS_STYLE_IF_VISITED); }
201 :
202 : // Tells this style context that it should return true from
203 : // IsStyleIfVisited.
204 0 : void SetIsStyleIfVisited()
205 0 : { mBits |= NS_STYLE_IS_STYLE_IF_VISITED; }
206 :
207 : // Return the style context whose style data should be used for the R,
208 : // G, and B components of color, background-color, and border-*-color
209 : // if RelevantLinkIsVisited().
210 : //
211 : // GetPseudo() and GetPseudoType() on this style context return the
212 : // same as on |this|, and its depth in the tree (number of GetParent()
213 : // calls until null is returned) is the same as |this|, since its
214 : // parent is either |this|'s parent or |this|'s parent's
215 : // style-if-visited.
216 : //
217 : // Structs on this context should never be examined without also
218 : // examining the corresponding struct on |this|. Doing so will likely
219 : // both (1) lead to a privacy leak and (2) lead to dynamic change bugs
220 : // related to the Peek code in nsStyleContext::CalcStyleDifference.
221 12946 : nsStyleContext* GetStyleIfVisited() const
222 12946 : { return mStyleIfVisited; }
223 :
224 : // To be called only from nsStyleSet / ServoStyleSet.
225 0 : void SetStyleIfVisited(already_AddRefed<nsStyleContext> aStyleIfVisited)
226 : {
227 0 : MOZ_ASSERT(!IsStyleIfVisited(), "this context is not visited data");
228 0 : NS_ASSERTION(!mStyleIfVisited, "should only be set once");
229 :
230 0 : mStyleIfVisited = aStyleIfVisited;
231 :
232 0 : MOZ_ASSERT(mStyleIfVisited->IsStyleIfVisited(),
233 : "other context is visited data");
234 0 : MOZ_ASSERT(!mStyleIfVisited->GetStyleIfVisited(),
235 : "other context does not have visited data");
236 0 : NS_ASSERTION(GetStyleIfVisited()->GetPseudo() == GetPseudo(),
237 : "pseudo tag mismatch");
238 0 : if (GetParentAllowServo() && GetParentAllowServo()->GetStyleIfVisited()) {
239 0 : NS_ASSERTION(GetStyleIfVisited()->GetParentAllowServo() ==
240 : GetParentAllowServo()->GetStyleIfVisited() ||
241 : GetStyleIfVisited()->GetParentAllowServo() ==
242 : GetParentAllowServo(),
243 : "parent mismatch");
244 : } else {
245 0 : NS_ASSERTION(GetStyleIfVisited()->GetParentAllowServo() ==
246 : GetParentAllowServo(),
247 : "parent mismatch");
248 : }
249 0 : }
250 :
251 : // Does any descendant of this style context have any style values
252 : // that were computed based on this style context's ancestors?
253 1112 : bool HasChildThatUsesGrandancestorStyle() const
254 1112 : { return !!(mBits & NS_STYLE_CHILD_USES_GRANDANCESTOR_STYLE); }
255 :
256 : // Is this style context shared with a sibling or cousin?
257 : // (See nsStyleSet::GetContext.)
258 2632 : bool IsShared() const
259 2632 : { return !!(mBits & NS_STYLE_IS_SHARED); }
260 :
261 : /**
262 : * Returns whether this style context has cached style data for a
263 : * given style struct and it does NOT own that struct. This can
264 : * happen because it was inherited from the parent style context, or
265 : * because it was stored conditionally on the rule node.
266 : */
267 903 : bool HasCachedDependentStyleData(nsStyleStructID aSID) {
268 903 : return mBits & nsCachedStyleData::GetBitForSID(aSID);
269 : }
270 :
271 : inline nsRuleNode* RuleNode();
272 : inline ServoComputedValues* ComputedValues();
273 :
274 4906 : void AddStyleBit(const uint64_t& aBit) { mBits |= aBit; }
275 :
276 : /**
277 : * Define typesafe getter functions for each style struct by
278 : * preprocessing the list of style structs. These functions are the
279 : * preferred way to get style data. The macro creates functions like:
280 : * const nsStyleBorder* StyleBorder();
281 : * const nsStyleColor* StyleColor();
282 : */
283 : #define STYLE_STRUCT(name_, checkdata_cb_) \
284 : inline const nsStyle##name_ * Style##name_() MOZ_NONNULL_RETURN;
285 : #include "nsStyleStructList.h"
286 : #undef STYLE_STRUCT
287 :
288 : /**
289 : * Equivalent to StyleFoo(), except that we skip the cache write during the
290 : * servo traversal. This can cause incorrect behavior if used improperly,
291 : * since we won't record that layout potentially depends on the values in
292 : * this style struct. Use with care.
293 : */
294 :
295 : #define STYLE_STRUCT(name_, checkdata_cb_) \
296 : inline const nsStyle##name_ * ThreadsafeStyle##name_();
297 : #include "nsStyleStructList.h"
298 : #undef STYLE_STRUCT
299 :
300 :
301 : /**
302 : * PeekStyle* is like Style* but doesn't trigger style
303 : * computation if the data is not cached on either the style context
304 : * or the rule node.
305 : *
306 : * Perhaps this shouldn't be a public nsStyleContext API.
307 : */
308 : #define STYLE_STRUCT(name_, checkdata_cb_) \
309 : inline const nsStyle##name_ * PeekStyle##name_();
310 : #include "nsStyleStructList.h"
311 : #undef STYLE_STRUCT
312 :
313 : /**
314 : * Compute the style changes needed during restyling when this style
315 : * context is being replaced by aNewContext. (This is nonsymmetric since
316 : * we optimize by skipping comparison for styles that have never been
317 : * requested.)
318 : *
319 : * This method returns a change hint (see nsChangeHint.h). All change
320 : * hints apply to the frame and its later continuations or ib-split
321 : * siblings. Most (all of those except the "NotHandledForDescendants"
322 : * hints) also apply to all descendants.
323 : *
324 : * aEqualStructs must not be null. Into it will be stored a bitfield
325 : * representing which structs were compared to be non-equal.
326 : */
327 : nsChangeHint CalcStyleDifference(nsStyleContext* aNewContext,
328 : uint32_t* aEqualStructs,
329 : uint32_t* aSamePointerStructs);
330 :
331 : /**
332 : * Like the above, but allows comparing ServoComputedValues instead of needing
333 : * a full-fledged style context.
334 : */
335 : nsChangeHint CalcStyleDifference(const ServoComputedValues* aNewComputedValues,
336 : uint32_t* aEqualStructs,
337 : uint32_t* aSamePointerStructs);
338 :
339 : private:
340 : template<class StyleContextLike>
341 : nsChangeHint CalcStyleDifferenceInternal(StyleContextLike* aNewContext,
342 : uint32_t* aEqualStructs,
343 : uint32_t* aSamePointerStructs);
344 :
345 : public:
346 : /**
347 : * Get a color that depends on link-visitedness using this and
348 : * this->GetStyleIfVisited().
349 : *
350 : * @param aField A pointer to a member variable in a style struct.
351 : * The member variable and its style struct must have
352 : * been listed in nsCSSVisitedDependentPropList.h.
353 : */
354 : template<typename T, typename S>
355 : nscolor GetVisitedDependentColor(T S::* aField);
356 :
357 : /**
358 : * aColors should be a two element array of nscolor in which the first
359 : * color is the unvisited color and the second is the visited color.
360 : *
361 : * Combine the R, G, and B components of whichever of aColors should
362 : * be used based on aLinkIsVisited with the A component of aColors[0].
363 : */
364 : static nscolor CombineVisitedColors(nscolor *aColors,
365 : bool aLinkIsVisited);
366 :
367 : /**
368 : * Start the background image loads for this style context.
369 : */
370 : inline void StartBackgroundImageLoads();
371 :
372 : /**
373 : * Moves this style context to a new parent.
374 : *
375 : * This function violates style context tree immutability, and
376 : * is a very low-level function and should only be used after verifying
377 : * many conditions that make it safe to call.
378 : */
379 : void MoveTo(nsStyleContext* aNewParent);
380 :
381 : #ifdef DEBUG
382 : void List(FILE* out, int32_t aIndent, bool aListDescendants = true);
383 : static const char* StructName(nsStyleStructID aSID);
384 : static bool LookupStruct(const nsACString& aName, nsStyleStructID& aResult);
385 : #endif
386 :
387 : protected:
388 : // protected destructor to discourage deletion outside of Release()
389 1618 : ~nsStyleContext() {}
390 : // Where the actual destructor lives
391 : // We use this instead of a real destructor because we need
392 : // this to be called *before* the subclass fields are destroyed
393 : // by the subclass destructor
394 : void Destructor();
395 : // Delegated Helper constructor.
396 : nsStyleContext(nsStyleContext* aParent,
397 : nsIAtom* aPseudoTag,
398 : mozilla::CSSPseudoElementType aPseudoType);
399 :
400 : // Helper post-contruct hook.
401 : void FinishConstruction();
402 :
403 : // Only does stuff in Gecko mode
404 : void AddChild(nsStyleContext* aChild);
405 : void RemoveChild(nsStyleContext* aChild);
406 :
407 : void SetStyleBits();
408 :
409 : const void* StyleStructFromServoComputedValues(nsStyleStructID aSID) {
410 : switch (aSID) {
411 : #define STYLE_STRUCT(name_, checkdata_cb_) \
412 : case eStyleStruct_##name_: \
413 : return Servo_GetStyle##name_(ComputedValues());
414 : #include "nsStyleStructList.h"
415 : #undef STYLE_STRUCT
416 : default:
417 : MOZ_ASSERT_UNREACHABLE("unexpected nsStyleStructID value");
418 : return nullptr;
419 : }
420 : }
421 :
422 : // Helper functions for GetStyle* and PeekStyle*
423 : #define STYLE_STRUCT_INHERITED(name_, checkdata_cb_) \
424 : template<bool aComputeData> \
425 : const nsStyle##name_ * DoGetStyle##name_();
426 : #define STYLE_STRUCT_RESET(name_, checkdata_cb_) \
427 : template<bool aComputeData> \
428 : const nsStyle##name_ * DoGetStyle##name_();
429 :
430 : #include "nsStyleStructList.h"
431 : #undef STYLE_STRUCT_RESET
432 : #undef STYLE_STRUCT_INHERITED
433 :
434 : RefPtr<nsStyleContext> mParent;
435 :
436 : // Style to be used instead for the R, G, and B components of color,
437 : // background-color, and border-*-color if the nearest ancestor link
438 : // element is visited (see RelevantLinkVisited()).
439 : RefPtr<nsStyleContext> mStyleIfVisited;
440 :
441 : // If this style context is for a pseudo-element or anonymous box,
442 : // the relevant atom.
443 : nsCOMPtr<nsIAtom> mPseudoTag;
444 :
445 : // mBits stores a number of things:
446 : // - It records (using the style struct bits) which structs are
447 : // inherited from the parent context or owned by the rule node (i.e.,
448 : // not owned by the style context).
449 : // - It also stores the additional bits listed at the top of
450 : // nsStyleStruct.h.
451 : uint64_t mBits;
452 :
453 : uint32_t mRefCnt;
454 :
455 : #ifdef DEBUG
456 : uint32_t mFrameRefCnt; // number of frames that use this
457 : // as their style context
458 :
459 67 : static bool DependencyAllowed(nsStyleStructID aOuterSID,
460 : nsStyleStructID aInnerSID)
461 : {
462 134 : return !!(sDependencyTable[aOuterSID] &
463 134 : nsCachedStyleData::GetBitForSID(aInnerSID));
464 : }
465 :
466 : static const uint32_t sDependencyTable[];
467 : #endif
468 : };
469 :
470 : already_AddRefed<nsStyleContext>
471 : NS_NewStyleContext(nsStyleContext* aParentContext,
472 : nsIAtom* aPseudoTag,
473 : mozilla::CSSPseudoElementType aPseudoType,
474 : nsRuleNode* aRuleNode,
475 : bool aSkipParentDisplayBasedStyleFixup);
476 :
477 : #endif
|