nsChangeHint.h (21267B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* constants for what needs to be recomputed in response to style changes */ 8 9 #ifndef nsChangeHint_h___ 10 #define nsChangeHint_h___ 11 12 #include "mozilla/Assertions.h" 13 14 // Defines for various style related constants 15 16 enum nsChangeHint : uint32_t { 17 nsChangeHint_Empty = 0, 18 19 // change was visual only (e.g., COLOR=) 20 // Invalidates all descendant frames (including following 21 // placeholders to out-of-flow frames). 22 nsChangeHint_RepaintFrame = 1 << 0, 23 24 // For reflow, we want flags to give us arbitrary FrameNeedsReflow behavior. 25 // just do a FrameNeedsReflow. 26 nsChangeHint_NeedReflow = 1 << 1, 27 28 // Invalidate intrinsic widths on the frame's ancestors. Must not be set 29 // without setting nsChangeHint_NeedReflow. 30 nsChangeHint_ClearAncestorIntrinsics = 1 << 2, 31 32 // Invalidate intrinsic widths on the frame's descendants. Must not be set 33 // without also setting nsChangeHint_ClearAncestorIntrinsics, 34 // nsChangeHint_NeedDirtyReflow and nsChangeHint_NeedReflow. 35 nsChangeHint_ClearDescendantIntrinsics = 1 << 3, 36 37 // Force unconditional reflow of all descendants. Must not be set without 38 // setting nsChangeHint_NeedReflow, but can be set regardless of whether the 39 // Clear*Intrinsics flags are set. 40 nsChangeHint_NeedDirtyReflow = 1 << 4, 41 42 // The currently shown mouse cursor needs to be updated 43 nsChangeHint_UpdateCursor = 1 << 5, 44 45 /** 46 * Used when the computed value (a URI) of one or more of an element's 47 * filter/mask/clip/etc CSS properties changes, causing the element's frame 48 * to start/stop referencing (or reference different) SVG resource elements. 49 * (_Not_ used to handle changes to referenced resource elements.) Using this 50 * hint results in SVGObserverUtils::UpdateEffects being called on the 51 * element's frame. 52 */ 53 nsChangeHint_UpdateEffects = 1 << 6, 54 55 /** 56 * Visual change only, but the change can be handled entirely by 57 * updating the layer(s) for the frame. 58 * Updates all descendants (including following placeholders to out-of-flows). 59 */ 60 nsChangeHint_UpdateOpacityLayer = 1 << 7, 61 /** 62 * Updates all descendants. Any placeholder descendants' out-of-flows 63 * are also descendants of the transformed frame, so they're updated. 64 */ 65 nsChangeHint_UpdateTransformLayer = 1 << 8, 66 67 /** 68 * Change requires frame change (e.g., display:). 69 * Reconstructs all frame descendants, including following placeholders 70 * to out-of-flows. 71 * 72 * Note that this subsumes all the other change hints. (see 73 * RestyleManager::ProcessRestyledFrames for details). 74 */ 75 nsChangeHint_ReconstructFrame = 1 << 9, 76 77 /** 78 * The frame's overflow area has changed. Does not update any descendant 79 * frames. 80 */ 81 nsChangeHint_UpdateOverflow = 1 << 10, 82 83 /** 84 * The overflow area of the frame and all of its descendants has changed. This 85 * can happen through a text-decoration change. 86 */ 87 nsChangeHint_UpdateSubtreeOverflow = 1 << 11, 88 89 /** 90 * The frame's overflow area has changed, through a change in its transform. 91 * In other words, the frame's pre-transform overflow is unchanged, but 92 * its post-transform overflow has changed, and thus its effect on its 93 * parent's overflow has changed. If the pre-transform overflow has 94 * changed, see nsChangeHint_UpdateOverflow. 95 * Does not update any descendant frames. 96 */ 97 nsChangeHint_UpdatePostTransformOverflow = 1 << 12, 98 99 /** 100 * This frame's effect on its parent's overflow area has changed. 101 * (But neither its pre-transform nor post-transform overflow have 102 * changed; if those are the case, see 103 * nsChangeHint_UpdatePostTransformOverflow.) 104 */ 105 nsChangeHint_UpdateParentOverflow = 1 << 13, 106 107 /** 108 * The children-only transform of an SVG frame changed, requiring overflows to 109 * be updated. 110 */ 111 nsChangeHint_ChildrenOnlyTransform = 1 << 14, 112 113 /** 114 * The frame's offsets have changed, while its dimensions might have 115 * changed as well. This hint is used for positioned frames if their 116 * offset changes. If we decide that the dimensions are likely to 117 * change, this will trigger a reflow. 118 * 119 * Note that this should probably be used in combination with 120 * nsChangeHint_UpdateOverflow in order to get the overflow areas of 121 * the ancestors updated as well. 122 */ 123 nsChangeHint_RecomputePosition = 1 << 15, 124 125 /** 126 * Behaves like ReconstructFrame, but only if the frame has descendants 127 * that are absolutely or fixed position. Use this hint when a style change 128 * has changed whether the frame is a container for fixed-pos or abs-pos 129 * elements, but reframing is otherwise not needed. 130 * 131 * Note that ComputedStyle::CalcStyleDifference adjusts results 132 * returned by style struct CalcDifference methods to return this hint 133 * only if there was a change to whether the element's overall style 134 * indicates that it establishes a containing block. 135 */ 136 nsChangeHint_UpdateContainingBlock = 1 << 16, 137 138 /** 139 * This will schedule an invalidating paint. This is useful if something 140 * has changed which will be invalidated by DLBI. 141 */ 142 nsChangeHint_SchedulePaint = 1 << 17, 143 144 /** 145 * A hint reflecting that style data changed with no change handling 146 * behavior. We need to return this, rather than nsChangeHint(0), 147 * so that certain optimizations that manipulate the style tree are 148 * correct. 149 * 150 * nsChangeHint_NeutralChange must be returned by CalcDifference on a given 151 * style struct if the data in the style structs are meaningfully different 152 * and if no other change hints are returned. If any other change hints are 153 * set, then nsChangeHint_NeutralChange need not also be included, but it is 154 * safe to do so. (An example of style structs having non-meaningfully 155 * different data would be cached information that would be re-calculated 156 * to the same values, such as nsStyleBorder::mSubImages.) 157 */ 158 nsChangeHint_NeutralChange = 1 << 18, 159 160 /** 161 * This will cause rendering observers to be invalidated. 162 */ 163 nsChangeHint_InvalidateRenderingObservers = 1 << 19, 164 165 /** 166 * Indicates that the reflow changes the size or position of the 167 * element, and thus the reflow must start from at least the frame's 168 * parent. Must be not be set without also setting nsChangeHint_NeedReflow. 169 * And consider adding nsChangeHint_ClearAncestorIntrinsics if needed. 170 */ 171 nsChangeHint_ReflowChangesSizeOrPosition = 1 << 20, 172 173 /** 174 * Indicates that the style changes the computed BSize --- e.g. 'height'. 175 * Must not be set without also setting nsChangeHint_NeedReflow. 176 */ 177 nsChangeHint_UpdateComputedBSize = 1 << 21, 178 179 /** 180 * Indicates that the 'opacity' property changed between 1 and non-1. 181 * 182 * Used as extra data for handling UpdateOpacityLayer hints. 183 * 184 * Note that we do not send this hint if the non-1 value was 0.99 or 185 * greater, since in that case we send a RepaintFrame hint instead. 186 */ 187 nsChangeHint_UpdateUsesOpacity = 1 << 22, 188 189 /** 190 * Indicates that the 'background-position' property changed. 191 * Regular frames can invalidate these changes using DLBI, but 192 * for some frame types we need to repaint the whole frame because 193 * the frame does not build individual background image display items 194 * for each background layer. 195 */ 196 nsChangeHint_UpdateBackgroundPosition = 1 << 23, 197 198 /** 199 * Indicates that a frame has changed to or from having the CSS 200 * transform property set. 201 */ 202 nsChangeHint_AddOrRemoveTransform = 1 << 24, 203 204 /** 205 * Indicates that the presence of scrollbars might have changed. 206 * 207 * This happens when at least one of overflow-{x,y} properties changed. 208 * 209 * In most cases, this is equivalent to nsChangeHint_ReconstructFrame. But 210 * in some special cases where the change is really targeting the viewport's 211 * scrollframe, this is instead equivalent to nsChangeHint_AllReflowHints 212 * (because the viewport always has an associated scrollframe). 213 */ 214 nsChangeHint_ScrollbarChange = 1 << 25, 215 216 /** 217 * Indicates that there has been a colspan or rowspan attribute change 218 * on the cells of a table. 219 */ 220 nsChangeHint_UpdateTableCellSpans = 1 << 26, 221 222 /** 223 * Indicates that the visiblity property changed. 224 * This change hint is used for skip restyling for animations on 225 * visibility:hidden elements in the case where the elements have no visible 226 * descendants. 227 */ 228 nsChangeHint_VisibilityChange = 1u << 27, 229 230 // IMPORTANT NOTE: When adding a new hint, you will need to add it to 231 // one of: 232 // 233 // * nsChangeHint_Hints_NeverHandledForDescendants 234 // * nsChangeHint_Hints_AlwaysHandledForDescendants 235 // * nsChangeHint_Hints_SometimesHandledForDescendants 236 // 237 // and you also may need to handle it in NS_HintsNotHandledForDescendantsIn. 238 // 239 // Please also add it to RestyleManager::ChangeHintToString and 240 // modify nsChangeHint_AllHints below accordingly. 241 242 /** 243 * Dummy hint value for all hints. It exists for compile time check. 244 */ 245 nsChangeHint_AllHints = uint32_t((1ull << 28) - 1), 246 }; 247 248 // Redefine these operators to return nothing. This will catch any use 249 // of these operators on hints. We should not be using these operators 250 // on nsChangeHints 251 inline void operator<(nsChangeHint s1, nsChangeHint s2) {} 252 inline void operator>(nsChangeHint s1, nsChangeHint s2) {} 253 inline void operator!=(nsChangeHint s1, nsChangeHint s2) {} 254 inline void operator==(nsChangeHint s1, nsChangeHint s2) {} 255 inline void operator<=(nsChangeHint s1, nsChangeHint s2) {} 256 inline void operator>=(nsChangeHint s1, nsChangeHint s2) {} 257 258 // Operators on nsChangeHints 259 260 // Returns true iff the second hint contains all the hints of the first hint 261 inline bool NS_IsHintSubset(nsChangeHint aSubset, nsChangeHint aSuperSet) { 262 return (aSubset & aSuperSet) == aSubset; 263 } 264 265 // The functions below need an integral type to cast to to avoid 266 // infinite recursion. 267 typedef decltype(nsChangeHint(0) + nsChangeHint(0)) nsChangeHint_size_t; 268 269 inline nsChangeHint constexpr operator|(nsChangeHint aLeft, 270 nsChangeHint aRight) { 271 return nsChangeHint(nsChangeHint_size_t(aLeft) | nsChangeHint_size_t(aRight)); 272 } 273 274 inline nsChangeHint constexpr operator&(nsChangeHint aLeft, 275 nsChangeHint aRight) { 276 return nsChangeHint(nsChangeHint_size_t(aLeft) & nsChangeHint_size_t(aRight)); 277 } 278 279 inline nsChangeHint& operator|=(nsChangeHint& aLeft, nsChangeHint aRight) { 280 return aLeft = aLeft | aRight; 281 } 282 283 inline nsChangeHint& operator&=(nsChangeHint& aLeft, nsChangeHint aRight) { 284 return aLeft = aLeft & aRight; 285 } 286 287 inline nsChangeHint constexpr operator~(nsChangeHint aArg) { 288 return nsChangeHint(~nsChangeHint_size_t(aArg)); 289 } 290 291 inline nsChangeHint constexpr operator^(nsChangeHint aLeft, 292 nsChangeHint aRight) { 293 return nsChangeHint(nsChangeHint_size_t(aLeft) ^ nsChangeHint_size_t(aRight)); 294 } 295 296 inline nsChangeHint operator^=(nsChangeHint& aLeft, nsChangeHint aRight) { 297 return aLeft = aLeft ^ aRight; 298 } 299 300 /** 301 * We have an optimization when processing change hints which prevents 302 * us from visiting the descendants of a node when a hint on that node 303 * is being processed. This optimization does not apply in some of the 304 * cases where applying a hint to an element does not necessarily result 305 * in the same hint being handled on the descendants. 306 */ 307 308 // The change hints that are always handled for descendants. 309 #define nsChangeHint_Hints_AlwaysHandledForDescendants \ 310 (nsChangeHint_ClearDescendantIntrinsics | nsChangeHint_NeedDirtyReflow | \ 311 nsChangeHint_NeutralChange | nsChangeHint_ReconstructFrame | \ 312 nsChangeHint_RepaintFrame | nsChangeHint_SchedulePaint | \ 313 nsChangeHint_UpdateCursor | nsChangeHint_UpdateSubtreeOverflow | \ 314 nsChangeHint_VisibilityChange) 315 316 // The change hints that are never handled for descendants. 317 #define nsChangeHint_Hints_NeverHandledForDescendants \ 318 (nsChangeHint_ChildrenOnlyTransform | nsChangeHint_ScrollbarChange | \ 319 nsChangeHint_InvalidateRenderingObservers | \ 320 nsChangeHint_RecomputePosition | nsChangeHint_UpdateBackgroundPosition | \ 321 nsChangeHint_UpdateComputedBSize | nsChangeHint_UpdateContainingBlock | \ 322 nsChangeHint_UpdateEffects | nsChangeHint_UpdateOpacityLayer | \ 323 nsChangeHint_UpdateOverflow | nsChangeHint_UpdateParentOverflow | \ 324 nsChangeHint_UpdatePostTransformOverflow | \ 325 nsChangeHint_UpdateTableCellSpans | nsChangeHint_UpdateTransformLayer | \ 326 nsChangeHint_UpdateUsesOpacity | nsChangeHint_AddOrRemoveTransform) 327 328 // The change hints that are sometimes considered to be handled for descendants. 329 #define nsChangeHint_Hints_SometimesHandledForDescendants \ 330 (nsChangeHint_ClearAncestorIntrinsics | nsChangeHint_NeedReflow | \ 331 nsChangeHint_ReflowChangesSizeOrPosition) 332 333 static_assert(!(nsChangeHint_Hints_AlwaysHandledForDescendants & 334 nsChangeHint_Hints_NeverHandledForDescendants) && 335 !(nsChangeHint_Hints_AlwaysHandledForDescendants & 336 nsChangeHint_Hints_SometimesHandledForDescendants) && 337 !(nsChangeHint_Hints_NeverHandledForDescendants & 338 nsChangeHint_Hints_SometimesHandledForDescendants) && 339 !(nsChangeHint_AllHints ^ 340 nsChangeHint_Hints_AlwaysHandledForDescendants ^ 341 nsChangeHint_Hints_NeverHandledForDescendants ^ 342 nsChangeHint_Hints_SometimesHandledForDescendants), 343 "change hints must be present in exactly one of " 344 "nsChangeHint_Hints_{Always,Never,Sometimes}" 345 "HandledForDescendants"); 346 347 // The most hints that NS_HintsNotHandledForDescendantsIn could possibly return: 348 #define nsChangeHint_Hints_NotHandledForDescendants \ 349 (nsChangeHint_Hints_NeverHandledForDescendants | \ 350 nsChangeHint_Hints_SometimesHandledForDescendants) 351 352 // Redefine the old NS_STYLE_HINT constants in terms of the new hint structure 353 #define NS_STYLE_HINT_VISUAL \ 354 nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_SchedulePaint) 355 #define nsChangeHint_AllReflowHints \ 356 nsChangeHint( \ 357 nsChangeHint_NeedReflow | nsChangeHint_ReflowChangesSizeOrPosition | \ 358 nsChangeHint_ClearAncestorIntrinsics | \ 359 nsChangeHint_ClearDescendantIntrinsics | nsChangeHint_NeedDirtyReflow) 360 361 // Below are the change hints that we send for ISize & BSize changes. 362 // Each is similar to nsChangeHint_AllReflowHints with a few changes. 363 364 // * For an ISize change, we send nsChangeHint_AllReflowHints, with two bits 365 // excluded: nsChangeHint_ClearDescendantIntrinsics (because an ancestor's 366 // inline-size change can't affect descendant intrinsic sizes), and 367 // nsChangeHint_NeedDirtyReflow (because ISize changes don't need to *force* 368 // all descendants to reflow). 369 #define nsChangeHint_ReflowHintsForISizeChange \ 370 nsChangeHint(nsChangeHint_AllReflowHints & \ 371 ~(nsChangeHint_ClearDescendantIntrinsics | \ 372 nsChangeHint_NeedDirtyReflow)) 373 374 // * For a BSize change, we send almost the same hints as for ISize changes, 375 // with one extra: nsChangeHint_UpdateComputedBSize. We need this hint because 376 // BSize changes CAN affect descendant intrinsic sizes, due to replaced 377 // elements with percentage BSizes in descendants which also have percentage 378 // BSizes. nsChangeHint_UpdateComputedBSize clears intrinsic sizes for frames 379 // that have such replaced elements. (We could instead send 380 // nsChangeHint_ClearDescendantIntrinsics, but that's broader than we need.) 381 // 382 // NOTE: You might think that BSize changes could exclude 383 // nsChangeHint_ClearAncestorIntrinsics (which is inline-axis specific), but we 384 // do need to send it, to clear cached results from CSS Flex measuring reflows. 385 #define nsChangeHint_ReflowHintsForBSizeChange \ 386 nsChangeHint( \ 387 (nsChangeHint_AllReflowHints | nsChangeHint_UpdateComputedBSize) & \ 388 ~(nsChangeHint_ClearDescendantIntrinsics | \ 389 nsChangeHint_NeedDirtyReflow)) 390 391 // For a change in whether a scrollframe displays or not scrollbars. 392 // 393 // When requesting this reflow, we send the exact same change hints that "width" 394 // and "height" would send (since conceptually, adding/removing scrollbars is 395 // like changing the available space). 396 // 397 // FIXME(emilio): Seems we could be a bit more efficient here, as adding or 398 // removing scrollbars doesn't change the size of the element itself, so maybe 399 // ClearAncestorIntrinsics or ReflowChangesSizeOrPosition are not needed... I 400 // think this ideally should be just nsChangehint_NeedReflow. 401 #define nsChangeHint_ReflowHintsForScrollbarChange \ 402 nsChangeHint(nsChangeHint_ReflowHintsForBSizeChange | \ 403 nsChangeHint_ReflowHintsForISizeChange) 404 405 // * For changes to the float area of an already-floated element, we need all 406 // reflow hints, but not the ones that apply to descendants. 407 // Our descendants aren't impacted when our float area only changes 408 // placement but not size/shape. (e.g. if we change which side we float to). 409 // But our ancestors/siblings are potentially impacted, so we need to send 410 // the non-descendant reflow hints. 411 #define nsChangeHint_ReflowHintsForFloatAreaChange \ 412 nsChangeHint(nsChangeHint_AllReflowHints & \ 413 ~(nsChangeHint_ClearDescendantIntrinsics | \ 414 nsChangeHint_NeedDirtyReflow)) 415 416 #define NS_STYLE_HINT_REFLOW \ 417 nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_AllReflowHints) 418 419 // Change hints for added or removed transform style. 420 // 421 // If we've added or removed the transform property, we need to reconstruct the 422 // frame to add or remove the view object, and also to handle abs-pos and 423 // fixed-pos containers. 424 // 425 // We do not need to apply nsChangeHint_UpdateTransformLayer since 426 // nsChangeHint_RepaintFrame will forcibly invalidate the frame area and 427 // ensure layers are rebuilt (or removed). 428 #define nsChangeHint_ComprehensiveAddOrRemoveTransform \ 429 nsChangeHint(nsChangeHint_UpdateContainingBlock | \ 430 nsChangeHint_AddOrRemoveTransform | \ 431 nsChangeHint_UpdateOverflow | nsChangeHint_RepaintFrame) 432 433 // NB: Once we drop support for the old style system, this logic should be 434 // inlined in the Servo style system to eliminate the FFI call. 435 inline nsChangeHint NS_HintsNotHandledForDescendantsIn( 436 nsChangeHint aChangeHint) { 437 nsChangeHint result = 438 aChangeHint & nsChangeHint_Hints_NeverHandledForDescendants; 439 440 if (!(aChangeHint & nsChangeHint_NeedDirtyReflow)) { 441 if (aChangeHint & nsChangeHint_NeedReflow) { 442 // If NeedDirtyReflow is *not* set, then NeedReflow is a 443 // non-inherited hint. 444 result |= nsChangeHint_NeedReflow; 445 } 446 447 if (aChangeHint & nsChangeHint_ReflowChangesSizeOrPosition) { 448 // If NeedDirtyReflow is *not* set, then ReflowChangesSizeOrPosition is a 449 // non-inherited hint. 450 result |= nsChangeHint_ReflowChangesSizeOrPosition; 451 } 452 } 453 454 if (!(aChangeHint & nsChangeHint_ClearDescendantIntrinsics) && 455 (aChangeHint & nsChangeHint_ClearAncestorIntrinsics)) { 456 // If ClearDescendantIntrinsics is *not* set, then 457 // ClearAncestorIntrinsics is a non-inherited hint. 458 result |= nsChangeHint_ClearAncestorIntrinsics; 459 } 460 461 MOZ_ASSERT( 462 NS_IsHintSubset(result, nsChangeHint_Hints_NotHandledForDescendants), 463 "something is inconsistent"); 464 465 return result; 466 } 467 468 inline nsChangeHint NS_HintsHandledForDescendantsIn(nsChangeHint aChangeHint) { 469 return aChangeHint & ~NS_HintsNotHandledForDescendantsIn(aChangeHint); 470 } 471 472 // Returns the change hints in aOurChange that are not subsumed by those 473 // in aHintsHandled (which are hints that have been handled by an ancestor). 474 inline nsChangeHint NS_RemoveSubsumedHints(nsChangeHint aOurChange, 475 nsChangeHint aHintsHandled) { 476 nsChangeHint result = 477 aOurChange & ~NS_HintsHandledForDescendantsIn(aHintsHandled); 478 479 if (result & 480 (nsChangeHint_ClearAncestorIntrinsics | 481 nsChangeHint_ClearDescendantIntrinsics | nsChangeHint_NeedDirtyReflow | 482 nsChangeHint_ReflowChangesSizeOrPosition | 483 nsChangeHint_UpdateComputedBSize)) { 484 result |= nsChangeHint_NeedReflow; 485 } 486 487 if (result & (nsChangeHint_ClearDescendantIntrinsics)) { 488 MOZ_ASSERT(result & nsChangeHint_ClearAncestorIntrinsics); 489 result |= // nsChangeHint_ClearAncestorIntrinsics | 490 nsChangeHint_NeedDirtyReflow; 491 } 492 493 return result; 494 } 495 496 namespace mozilla { 497 498 struct StyleRestyleHint; 499 500 using RestyleHint = StyleRestyleHint; 501 502 } // namespace mozilla 503 504 #endif /* nsChangeHint_h___ */