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 /* constants for what needs to be recomputed in response to style changes */
7 
8 #ifndef nsChangeHint_h___
9 #define nsChangeHint_h___
10 
11 #include "mozilla/Types.h"
12 #include "nsDebug.h"
13 #include "nsTArray.h"
14 
15 struct nsCSSSelector;
16 
17 // Defines for various style related constants
18 
19 enum nsChangeHint {
20   // change was visual only (e.g., COLOR=)
21   // Invalidates all descendant frames (including following
22   // placeholders to out-of-flow frames).
23   nsChangeHint_RepaintFrame = 1 << 0,
24 
25   // For reflow, we want flags to give us arbitrary FrameNeedsReflow behavior.
26   // just do a FrameNeedsReflow.
27   nsChangeHint_NeedReflow = 1 << 1,
28 
29   // Invalidate intrinsic widths on the frame's ancestors.  Must not be set
30   // without setting nsChangeHint_NeedReflow.
31   nsChangeHint_ClearAncestorIntrinsics = 1 << 2,
32 
33   // Invalidate intrinsic widths on the frame's descendants.  Must not be set
34   // without also setting nsChangeHint_ClearAncestorIntrinsics.
35   nsChangeHint_ClearDescendantIntrinsics = 1 << 3,
36 
37   // Force unconditional reflow of all descendants.  Must not be set without
38   // setting nsChangeHint_NeedReflow, but is independent of both the
39   // Clear*Intrinsics flags.
40   nsChangeHint_NeedDirtyReflow = 1 << 4,
41 
42   // change requires view to be updated, if there is one (e.g., clip:).
43   // Updates all descendants (including following placeholders to out-of-flows).
44   nsChangeHint_SyncFrameView = 1 << 5,
45 
46   // The currently shown mouse cursor needs to be updated
47   nsChangeHint_UpdateCursor = 1 << 6,
48 
49   /**
50    * Used when the computed value (a URI) of one or more of an element's
51    * filter/mask/clip/etc CSS properties changes, causing the element's frame
52    * to start/stop referencing (or reference different) SVG resource elements.
53    * (_Not_ used to handle changes to referenced resource elements.) Using this
54    * hint results in nsSVGEffects::UpdateEffects being called on the element's
55    * frame.
56    */
57   nsChangeHint_UpdateEffects = 1 << 7,
58 
59   /**
60    * Visual change only, but the change can be handled entirely by
61    * updating the layer(s) for the frame.
62    * Updates all descendants (including following placeholders to out-of-flows).
63    */
64   nsChangeHint_UpdateOpacityLayer = 1 << 8,
65   /**
66    * Updates all descendants. Any placeholder descendants' out-of-flows
67    * are also descendants of the transformed frame, so they're updated.
68    */
69   nsChangeHint_UpdateTransformLayer = 1 << 9,
70 
71   /**
72    * Change requires frame change (e.g., display:).
73    * Reconstructs all frame descendants, including following placeholders
74    * to out-of-flows.
75    *
76    * Note that this subsumes all the other change hints. (see
77    * RestyleManager::ProcessRestyledFrames for details).
78    */
79   nsChangeHint_ReconstructFrame = 1 << 10,
80 
81   /**
82    * The frame's overflow area has changed. Does not update any descendant
83    * frames.
84    */
85   nsChangeHint_UpdateOverflow = 1 << 11,
86 
87   /**
88    * The overflow area of the frame and all of its descendants has changed. This
89    * can happen through a text-decoration change.
90    */
91   nsChangeHint_UpdateSubtreeOverflow = 1 << 12,
92 
93   /**
94    * The frame's overflow area has changed, through a change in its transform.
95    * In other words, the frame's pre-transform overflow is unchanged, but
96    * its post-transform overflow has changed, and thus its effect on its
97    * parent's overflow has changed.  If the pre-transform overflow has
98    * changed, see nsChangeHint_UpdateOverflow.
99    * Does not update any descendant frames.
100    */
101   nsChangeHint_UpdatePostTransformOverflow = 1 << 13,
102 
103   /**
104    * This frame's effect on its parent's overflow area has changed.
105    * (But neither its pre-transform nor post-transform overflow have
106    * changed; if those are the case, see
107    * nsChangeHint_UpdatePostTransformOverflow.)
108    */
109   nsChangeHint_UpdateParentOverflow = 1 << 14,
110 
111   /**
112    * The children-only transform of an SVG frame changed, requiring the
113    * overflow rects of the frame's immediate children to be updated.
114    */
115   nsChangeHint_ChildrenOnlyTransform = 1 << 15,
116 
117   /**
118    * The frame's offsets have changed, while its dimensions might have
119    * changed as well.  This hint is used for positioned frames if their
120    * offset changes.  If we decide that the dimensions are likely to
121    * change, this will trigger a reflow.
122    *
123    * Note that this should probably be used in combination with
124    * nsChangeHint_UpdateOverflow in order to get the overflow areas of
125    * the ancestors updated as well.
126    */
127   nsChangeHint_RecomputePosition = 1 << 16,
128 
129   /**
130    * Behaves like ReconstructFrame, but only if the frame has descendants
131    * that are absolutely or fixed position. Use this hint when a style change
132    * has changed whether the frame is a container for fixed-pos or abs-pos
133    * elements, but reframing is otherwise not needed.
134    *
135    * Note that nsStyleContext::CalcStyleDifference adjusts results
136    * returned by style struct CalcDifference methods to return this hint
137    * only if there was a change to whether the element's overall style
138    * indicates that it establishes a containing block.
139    */
140   nsChangeHint_UpdateContainingBlock = 1 << 17,
141 
142   /**
143    * This change hint has *no* change handling behavior.  However, it
144    * exists to be a non-inherited hint, because when the border-style
145    * changes, and it's inherited by a child, that might require a reflow
146    * due to the border-width change on the child.
147    */
148   nsChangeHint_BorderStyleNoneChange = 1 << 18,
149 
150   /**
151    * SVG textPath needs to be recomputed because the path has changed.
152    * This means that the glyph positions of the text need to be recomputed.
153    */
154   nsChangeHint_UpdateTextPath = 1 << 19,
155 
156   /**
157    * This will schedule an invalidating paint. This is useful if something
158    * has changed which will be invalidated by DLBI.
159    */
160   nsChangeHint_SchedulePaint = 1 << 20,
161 
162   /**
163    * A hint reflecting that style data changed with no change handling
164    * behavior.  We need to return this, rather than nsChangeHint(0),
165    * so that certain optimizations that manipulate the style context tree are
166    * correct.
167    *
168    * nsChangeHint_NeutralChange must be returned by CalcDifference on a given
169    * style struct if the data in the style structs are meaningfully different
170    * and if no other change hints are returned.  If any other change hints are
171    * set, then nsChangeHint_NeutralChange need not also be included, but it is
172    * safe to do so.  (An example of style structs having non-meaningfully
173    * different data would be cached information that would be re-calculated
174    * to the same values, such as nsStyleBorder::mSubImages.)
175    */
176   nsChangeHint_NeutralChange = 1 << 21,
177 
178   /**
179    * This will cause rendering observers to be invalidated.
180    */
181   nsChangeHint_InvalidateRenderingObservers = 1 << 22,
182 
183   /**
184    * Indicates that the reflow changes the size or position of the
185    * element, and thus the reflow must start from at least the frame's
186    * parent.
187    */
188   nsChangeHint_ReflowChangesSizeOrPosition = 1 << 23,
189 
190   /**
191    * Indicates that the style changes the computed BSize --- e.g. 'height'.
192    */
193   nsChangeHint_UpdateComputedBSize = 1 << 24,
194 
195   /**
196    * Indicates that the 'opacity' property changed between 1 and non-1.
197    *
198    * Used as extra data for handling UpdateOpacityLayer hints.
199    *
200    * Note that we do not send this hint if the non-1 value was 0.99 or
201    * greater, since in that case we send a RepaintFrame hint instead.
202    */
203   nsChangeHint_UpdateUsesOpacity = 1 << 25,
204 
205   /**
206    * Indicates that the 'background-position' property changed.
207    * Regular frames can invalidate these changes using DLBI, but
208    * for some frame types we need to repaint the whole frame because
209    * the frame does not build individual background image display items
210    * for each background layer.
211    */
212   nsChangeHint_UpdateBackgroundPosition = 1 << 26,
213 
214   /**
215    * Indicates that a frame has changed to or from having the CSS
216    * transform property set.
217    */
218   nsChangeHint_AddOrRemoveTransform = 1 << 27,
219 
220   // IMPORTANT NOTE: When adding new hints, consider whether you need
221   // to add them to NS_HintsNotHandledForDescendantsIn() below. Please
222   // also add them to RestyleManager::ChangeHintToString and modify
223   // nsChangeHint_AllHints below accordingly.
224 
225   /**
226    * Dummy hint value for all hints. It exists for compile time check.
227    */
228   nsChangeHint_AllHints = (1 << 28) - 1,
229 };
230 
231 // Redefine these operators to return nothing. This will catch any use
232 // of these operators on hints. We should not be using these operators
233 // on nsChangeHints
234 inline void operator<(nsChangeHint s1, nsChangeHint s2) {}
235 inline void operator>(nsChangeHint s1, nsChangeHint s2) {}
236 inline void operator!=(nsChangeHint s1, nsChangeHint s2) {}
237 inline void operator==(nsChangeHint s1, nsChangeHint s2) {}
238 inline void operator<=(nsChangeHint s1, nsChangeHint s2) {}
239 inline void operator>=(nsChangeHint s1, nsChangeHint s2) {}
240 
241 // Operators on nsChangeHints
242 
243 // Returns true iff the second hint contains all the hints of the first hint
NS_IsHintSubset(nsChangeHint aSubset,nsChangeHint aSuperSet)244 inline bool NS_IsHintSubset(nsChangeHint aSubset, nsChangeHint aSuperSet) {
245   return (aSubset & aSuperSet) == aSubset;
246 }
247 
248 // The functions below need an integral type to cast to to avoid
249 // infinite recursion.
250 typedef decltype(nsChangeHint(0) + nsChangeHint(0)) nsChangeHint_size_t;
251 
252 inline nsChangeHint constexpr
253 operator|(nsChangeHint aLeft, nsChangeHint aRight)
254 {
255   return nsChangeHint(nsChangeHint_size_t(aLeft) | nsChangeHint_size_t(aRight));
256 }
257 
258 inline nsChangeHint constexpr
259 operator&(nsChangeHint aLeft, nsChangeHint aRight)
260 {
261   return nsChangeHint(nsChangeHint_size_t(aLeft) & nsChangeHint_size_t(aRight));
262 }
263 
264 inline nsChangeHint& operator|=(nsChangeHint& aLeft, nsChangeHint aRight)
265 {
266   return aLeft = aLeft | aRight;
267 }
268 
269 inline nsChangeHint& operator&=(nsChangeHint& aLeft, nsChangeHint aRight)
270 {
271   return aLeft = aLeft & aRight;
272 }
273 
274 inline nsChangeHint constexpr
275 operator~(nsChangeHint aArg)
276 {
277   return nsChangeHint(~nsChangeHint_size_t(aArg));
278 }
279 
280 inline nsChangeHint constexpr
281 operator^(nsChangeHint aLeft, nsChangeHint aRight)
282 {
283   return nsChangeHint(nsChangeHint_size_t(aLeft) ^ nsChangeHint_size_t(aRight));
284 }
285 
286 inline nsChangeHint operator^=(nsChangeHint& aLeft, nsChangeHint aRight)
287 {
288   return aLeft = aLeft ^ aRight;
289 }
290 
291 /**
292  * We have an optimization when processing change hints which prevents
293  * us from visiting the descendants of a node when a hint on that node
294  * is being processed.  This optimization does not apply in some of the
295  * cases where applying a hint to an element does not necessarily result
296  * in the same hint being handled on the descendants.
297  */
298 
299 // The most hints that NS_HintsNotHandledForDescendantsIn could possibly return:
300 #define nsChangeHint_Hints_NotHandledForDescendants nsChangeHint( \
301           nsChangeHint_UpdateTransformLayer | \
302           nsChangeHint_UpdateEffects | \
303           nsChangeHint_InvalidateRenderingObservers | \
304           nsChangeHint_UpdateOpacityLayer | \
305           nsChangeHint_UpdateOverflow | \
306           nsChangeHint_UpdatePostTransformOverflow | \
307           nsChangeHint_UpdateParentOverflow | \
308           nsChangeHint_ChildrenOnlyTransform | \
309           nsChangeHint_RecomputePosition | \
310           nsChangeHint_UpdateContainingBlock | \
311           nsChangeHint_AddOrRemoveTransform | \
312           nsChangeHint_BorderStyleNoneChange | \
313           nsChangeHint_NeedReflow | \
314           nsChangeHint_ReflowChangesSizeOrPosition | \
315           nsChangeHint_ClearAncestorIntrinsics | \
316           nsChangeHint_UpdateComputedBSize | \
317           nsChangeHint_UpdateUsesOpacity | \
318           nsChangeHint_UpdateBackgroundPosition)
319 
NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint)320 inline nsChangeHint NS_HintsNotHandledForDescendantsIn(nsChangeHint aChangeHint) {
321   nsChangeHint result = nsChangeHint(aChangeHint & (
322     nsChangeHint_UpdateTransformLayer |
323     nsChangeHint_UpdateEffects |
324     nsChangeHint_InvalidateRenderingObservers |
325     nsChangeHint_UpdateOpacityLayer |
326     nsChangeHint_UpdateOverflow |
327     nsChangeHint_UpdatePostTransformOverflow |
328     nsChangeHint_UpdateParentOverflow |
329     nsChangeHint_ChildrenOnlyTransform |
330     nsChangeHint_RecomputePosition |
331     nsChangeHint_UpdateContainingBlock |
332     nsChangeHint_AddOrRemoveTransform |
333     nsChangeHint_BorderStyleNoneChange |
334     nsChangeHint_UpdateComputedBSize |
335     nsChangeHint_UpdateUsesOpacity | \
336     nsChangeHint_UpdateBackgroundPosition));
337 
338   if (!NS_IsHintSubset(nsChangeHint_NeedDirtyReflow, aChangeHint)) {
339     if (NS_IsHintSubset(nsChangeHint_NeedReflow, aChangeHint)) {
340       // If NeedDirtyReflow is *not* set, then NeedReflow is a
341       // non-inherited hint.
342       result |= nsChangeHint_NeedReflow;
343     }
344 
345     if (NS_IsHintSubset(nsChangeHint_ReflowChangesSizeOrPosition,
346                         aChangeHint)) {
347       // If NeedDirtyReflow is *not* set, then ReflowChangesSizeOrPosition is a
348       // non-inherited hint.
349       result |= nsChangeHint_ReflowChangesSizeOrPosition;
350     }
351   }
352 
353   if (!NS_IsHintSubset(nsChangeHint_ClearDescendantIntrinsics, aChangeHint) &&
354       NS_IsHintSubset(nsChangeHint_ClearAncestorIntrinsics, aChangeHint)) {
355     // If ClearDescendantIntrinsics is *not* set, then
356     // ClearAncestorIntrinsics is a non-inherited hint.
357     result |= nsChangeHint_ClearAncestorIntrinsics;
358   }
359 
360   MOZ_ASSERT(NS_IsHintSubset(result,
361                              nsChangeHint_Hints_NotHandledForDescendants),
362              "something is inconsistent");
363 
364   return result;
365 }
366 
367 // Redefine the old NS_STYLE_HINT constants in terms of the new hint structure
368 #define NS_STYLE_HINT_VISUAL \
369   nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_SyncFrameView | \
370                nsChangeHint_SchedulePaint)
371 #define nsChangeHint_AllReflowHints                     \
372   nsChangeHint(nsChangeHint_NeedReflow |                \
373                nsChangeHint_ReflowChangesSizeOrPosition|\
374                nsChangeHint_ClearAncestorIntrinsics |   \
375                nsChangeHint_ClearDescendantIntrinsics | \
376                nsChangeHint_NeedDirtyReflow)
377 #define NS_STYLE_HINT_REFLOW \
378   nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_AllReflowHints)
379 
380 #define nsChangeHint_Hints_CanIgnoreIfNotVisible   \
381   nsChangeHint(NS_STYLE_HINT_VISUAL |              \
382                nsChangeHint_NeutralChange |        \
383                nsChangeHint_UpdateOpacityLayer |   \
384                nsChangeHint_UpdateTransformLayer | \
385                nsChangeHint_UpdateUsesOpacity)
386 
387 /**
388  * |nsRestyleHint| is a bitfield for the result of
389  * |HasStateDependentStyle| and |HasAttributeDependentStyle|.  When no
390  * restyling is necessary, use |nsRestyleHint(0)|.
391  *
392  * Without eRestyle_Force or eRestyle_ForceDescendants, the restyling process
393  * can stop processing at a frame when it detects no style changes and it is
394  * known that the styles of the subtree beneath it will not change, leaving
395  * the old style context on the frame.  eRestyle_Force can be used to skip this
396  * optimization on a frame, and to force its new style context to be used.
397  *
398  * Similarly, eRestyle_ForceDescendants will cause the frame and all of its
399  * descendants to be traversed and for the new style contexts that are created
400  * to be set on the frames.
401  *
402  * NOTE: When adding new restyle hints, please also add them to
403  * RestyleManager::RestyleHintToString.
404  */
405 enum nsRestyleHint {
406   // Rerun selector matching on the element.  If a new style context
407   // results, update the style contexts of descendants.  (Irrelevant if
408   // eRestyle_Subtree is also set, since that implies a superset of the
409   // work.)
410   eRestyle_Self = 1 << 0,
411 
412   // Rerun selector matching on descendants of the element that match
413   // a given selector.
414   eRestyle_SomeDescendants = 1 << 1,
415 
416   // Rerun selector matching on the element and all of its descendants.
417   // (Implies eRestyle_ForceDescendants, which ensures that we continue
418   // the restyling process for all descendants, but doesn't cause
419   // selector matching.)
420   eRestyle_Subtree = 1 << 2,
421 
422   // Rerun selector matching on all later siblings of the element and
423   // all of their descendants.
424   eRestyle_LaterSiblings = 1 << 3,
425 
426   // Replace the style data coming from CSS transitions without updating
427   // any other style data.  If a new style context results, update style
428   // contexts on the descendants.  (Irrelevant if eRestyle_Self or
429   // eRestyle_Subtree is also set, since those imply a superset of the
430   // work.)
431   eRestyle_CSSTransitions = 1 << 4,
432 
433   // Replace the style data coming from CSS animations without updating
434   // any other style data.  If a new style context results, update style
435   // contexts on the descendants.  (Irrelevant if eRestyle_Self or
436   // eRestyle_Subtree is also set, since those imply a superset of the
437   // work.)
438   eRestyle_CSSAnimations = 1 << 5,
439 
440   // Replace the style data coming from SVG animations (SMIL Animations)
441   // without updating any other style data.  If a new style context
442   // results, update style contexts on the descendants.  (Irrelevant if
443   // eRestyle_Self or eRestyle_Subtree is also set, since those imply a
444   // superset of the work.)
445   eRestyle_SVGAttrAnimations = 1 << 6,
446 
447   // Replace the style data coming from inline style without updating
448   // any other style data.  If a new style context results, update style
449   // contexts on the descendants.  (Irrelevant if eRestyle_Self or
450   // eRestyle_Subtree is also set, since those imply a superset of the
451   // work.)  Supported only for element style contexts and not for
452   // pseudo-elements or anonymous boxes, on which it converts to
453   // eRestyle_Self.
454   // If the change is for the advance of a declarative animation, use
455   // the value below instead.
456   eRestyle_StyleAttribute = 1 << 7,
457 
458   // Same as eRestyle_StyleAttribute, but for when the change results
459   // from the advance of a declarative animation.
460   eRestyle_StyleAttribute_Animations = 1 << 8,
461 
462   // Continue the restyling process to the current frame's children even
463   // if this frame's restyling resulted in no style changes.
464   eRestyle_Force = 1 << 9,
465 
466   // Continue the restyling process to all of the current frame's
467   // descendants, even if any frame's restyling resulted in no style
468   // changes.  (Implies eRestyle_Force.)  Note that this is weaker than
469   // eRestyle_Subtree, which makes us rerun selector matching on all
470   // descendants rather than just continuing the restyling process.
471   eRestyle_ForceDescendants = 1 << 10,
472 
473   // Useful unions:
474   eRestyle_AllHintsWithAnimations = eRestyle_CSSTransitions |
475                                     eRestyle_CSSAnimations |
476                                     eRestyle_SVGAttrAnimations |
477                                     eRestyle_StyleAttribute_Animations,
478 };
479 
480 // The functions below need an integral type to cast to to avoid
481 // infinite recursion.
482 typedef decltype(nsRestyleHint(0) + nsRestyleHint(0)) nsRestyleHint_size_t;
483 
484 inline constexpr nsRestyleHint operator|(nsRestyleHint aLeft,
485                                              nsRestyleHint aRight)
486 {
487   return nsRestyleHint(nsRestyleHint_size_t(aLeft) |
488                        nsRestyleHint_size_t(aRight));
489 }
490 
491 inline constexpr nsRestyleHint operator&(nsRestyleHint aLeft,
492                                              nsRestyleHint aRight)
493 {
494   return nsRestyleHint(nsRestyleHint_size_t(aLeft) &
495                        nsRestyleHint_size_t(aRight));
496 }
497 
498 inline nsRestyleHint& operator|=(nsRestyleHint& aLeft, nsRestyleHint aRight)
499 {
500   return aLeft = aLeft | aRight;
501 }
502 
503 inline nsRestyleHint& operator&=(nsRestyleHint& aLeft, nsRestyleHint aRight)
504 {
505   return aLeft = aLeft & aRight;
506 }
507 
508 inline constexpr nsRestyleHint operator~(nsRestyleHint aArg)
509 {
510   return nsRestyleHint(~nsRestyleHint_size_t(aArg));
511 }
512 
513 inline constexpr nsRestyleHint operator^(nsRestyleHint aLeft,
514                                              nsRestyleHint aRight)
515 {
516   return nsRestyleHint(nsRestyleHint_size_t(aLeft) ^
517                        nsRestyleHint_size_t(aRight));
518 }
519 
520 inline nsRestyleHint operator^=(nsRestyleHint& aLeft, nsRestyleHint aRight)
521 {
522   return aLeft = aLeft ^ aRight;
523 }
524 
525 namespace mozilla {
526 
527 /**
528  * Additional data used in conjunction with an nsRestyleHint to control the
529  * restyle process.
530  */
531 struct RestyleHintData
532 {
533   // When eRestyle_SomeDescendants is used, this array contains the selectors
534   // that identify which descendants will be restyled.
535   nsTArray<nsCSSSelector*> mSelectorsForDescendants;
536 };
537 
538 } // namespace mozilla
539 
540 #endif /* nsChangeHint_h___ */
541