DisplayListClipState.h (11298B)
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 #ifndef DISPLAYLISTCLIPSTATE_H_ 8 #define DISPLAYLISTCLIPSTATE_H_ 9 10 #include "DisplayItemClip.h" 11 #include "DisplayItemClipChain.h" 12 13 class nsIFrame; 14 15 namespace mozilla { 16 17 class nsDisplayListBuilder; 18 19 /** 20 * All clip coordinates are in appunits relative to the reference frame 21 * for the display item we're building. 22 */ 23 class DisplayListClipState { 24 public: 25 DisplayListClipState() 26 : mClipChainContentDescendants(nullptr), 27 mClipChainContainingBlockDescendants(nullptr), 28 mCurrentCombinedClipChain(nullptr), 29 mCurrentCombinedClipChainIsValid(false) {} 30 31 /** 32 * Returns intersection of mClipChainContainingBlockDescendants and 33 * mClipChainContentDescendants, allocated on aBuilder's arena. 34 */ 35 const DisplayItemClipChain* GetCurrentCombinedClipChain( 36 nsDisplayListBuilder* aBuilder); 37 38 const DisplayItemClipChain* GetClipChainForContainingBlockDescendants() 39 const { 40 return mClipChainContainingBlockDescendants; 41 } 42 const DisplayItemClipChain* GetClipChainForContentDescendants() const { 43 return mClipChainContentDescendants; 44 } 45 46 const ActiveScrolledRoot* GetContentClipASR() const { 47 return mClipChainContentDescendants ? mClipChainContentDescendants->mASR 48 : nullptr; 49 } 50 51 class AutoSaveRestore; 52 53 class AutoClipContainingBlockDescendantsToContentBox; 54 55 class AutoClipMultiple; 56 57 enum { ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT = 0x01 }; 58 59 private: 60 void Clear() { 61 mClipChainContentDescendants = nullptr; 62 mClipChainContainingBlockDescendants = nullptr; 63 mCurrentCombinedClipChain = nullptr; 64 mCurrentCombinedClipChainIsValid = false; 65 mClippedToDisplayPort = false; 66 } 67 68 void SetClipChainForContainingBlockDescendants( 69 const DisplayItemClipChain* aClipChain) { 70 mClipChainContainingBlockDescendants = aClipChain; 71 InvalidateCurrentCombinedClipChain(aClipChain ? aClipChain->mASR : nullptr); 72 } 73 74 /** 75 * Intersects the given clip rect (with optional aRadii) with the current 76 * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to 77 * the result, stored in aClipOnStack. 78 */ 79 void ClipContainingBlockDescendants(nsDisplayListBuilder* aBuilder, 80 const nsRect& aRect, 81 const nsRectCornerRadii* aRadii, 82 DisplayItemClipChain& aClipChainOnStack); 83 84 void ClipToDisplayPort(nsDisplayListBuilder* aBuilder, const nsRect& aRect, 85 DisplayItemClipChain& aClipChainOnStack); 86 87 void ClipContentDescendants(nsDisplayListBuilder* aBuilder, 88 const nsRect& aRect, 89 const nsRectCornerRadii* aRadii, 90 DisplayItemClipChain& aClipChainOnStack); 91 void ClipContentDescendants(nsDisplayListBuilder* aBuilder, 92 const nsRect& aRect, const nsRect& aRoundedRect, 93 const nsRectCornerRadii* aRadii, 94 DisplayItemClipChain& aClipChainOnStack); 95 96 void InvalidateCurrentCombinedClipChain( 97 const ActiveScrolledRoot* aInvalidateUpTo); 98 99 /** 100 * Clips containing-block descendants to the frame's content-box, 101 * taking border-radius into account. 102 * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then 103 * we assume display items will not draw outside the content rect, so 104 * clipping is only required if there is a border-radius. This is an 105 * optimization to reduce the amount of clipping required. 106 */ 107 void ClipContainingBlockDescendantsToContentBox( 108 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, 109 DisplayItemClipChain& aClipChainOnStack, uint32_t aFlags); 110 111 /** 112 * All content descendants (i.e. following placeholder frames to their 113 * out-of-flows if necessary) should be clipped by 114 * mClipChainContentDescendants. Null if no clipping applies. 115 */ 116 const DisplayItemClipChain* mClipChainContentDescendants; 117 /** 118 * All containing-block descendants (i.e. frame descendants), including 119 * display items for the current frame, should be clipped by 120 * mClipChainContainingBlockDescendants. 121 * Null if no clipping applies. 122 */ 123 const DisplayItemClipChain* mClipChainContainingBlockDescendants; 124 /** 125 * The intersection of mClipChainContentDescendants and 126 * mClipChainContainingBlockDescendants. 127 * Allocated in the nsDisplayListBuilder arena. Null if none has been 128 * allocated or both mClipChainContentDescendants and 129 * mClipChainContainingBlockDescendants are null. 130 */ 131 const DisplayItemClipChain* mCurrentCombinedClipChain; 132 bool mCurrentCombinedClipChainIsValid; 133 /** 134 * A flag that is used by sticky positioned items to know if the clip applied 135 * to them is just the displayport clip or if there is additional clipping. 136 */ 137 bool mClippedToDisplayPort; 138 }; 139 140 /** 141 * A class to automatically save and restore the current clip state. Also 142 * offers methods for modifying the clip state. Only one modification is allowed 143 * to be in scope at a time using one of these objects; multiple modifications 144 * require nested objects. The interface is written this way to prevent 145 * dangling pointers to DisplayItemClips. 146 */ 147 class DisplayListClipState::AutoSaveRestore { 148 public: 149 explicit AutoSaveRestore(nsDisplayListBuilder* aBuilder); 150 void Restore() { 151 mState = mSavedState; 152 #ifdef DEBUG 153 mRestored = true; 154 #endif 155 } 156 ~AutoSaveRestore() { Restore(); } 157 158 void Clear() { 159 NS_ASSERTION(!mRestored, "Already restored!"); 160 mState.Clear(); 161 #ifdef DEBUG 162 mClipUsed = false; 163 #endif 164 } 165 166 void SetClipChainForContainingBlockDescendants( 167 const DisplayItemClipChain* aClipChain) { 168 mState.SetClipChainForContainingBlockDescendants(aClipChain); 169 } 170 171 /** 172 * Intersects the given clip rect (with optional aRadii) with the current 173 * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to 174 * the result, stored in aClipOnStack. 175 */ 176 void ClipContainingBlockDescendants( 177 const nsRect& aRect, const nsRectCornerRadii* aRadii = nullptr) { 178 NS_ASSERTION(!mRestored, "Already restored!"); 179 NS_ASSERTION(!mClipUsed, "mClip already used"); 180 #ifdef DEBUG 181 mClipUsed = true; 182 #endif 183 mState.ClipContainingBlockDescendants(mBuilder, aRect, aRadii, mClipChain); 184 } 185 186 void ClipToDisplayPort(const nsRect& aRect) { 187 NS_ASSERTION(!mRestored, "Already restored!"); 188 NS_ASSERTION(!mClipUsed, "mClip already used"); 189 #ifdef DEBUG 190 mClipUsed = true; 191 #endif 192 mState.ClipToDisplayPort(mBuilder, aRect, mClipChain); 193 } 194 195 void ClipContentDescendants(const nsRect& aRect, 196 const nsRectCornerRadii* aRadii = nullptr) { 197 NS_ASSERTION(!mRestored, "Already restored!"); 198 NS_ASSERTION(!mClipUsed, "mClip already used"); 199 #ifdef DEBUG 200 mClipUsed = true; 201 #endif 202 mState.ClipContentDescendants(mBuilder, aRect, aRadii, mClipChain); 203 } 204 205 void ClipContentDescendants(const nsRect& aRect, const nsRect& aRoundedRect, 206 const nsRectCornerRadii* aRadii = nullptr) { 207 NS_ASSERTION(!mRestored, "Already restored!"); 208 NS_ASSERTION(!mClipUsed, "mClip already used"); 209 #ifdef DEBUG 210 mClipUsed = true; 211 #endif 212 mState.ClipContentDescendants(mBuilder, aRect, aRoundedRect, aRadii, 213 mClipChain); 214 } 215 216 /** 217 * Clips containing-block descendants to the frame's content-box, 218 * taking border-radius into account. 219 * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then 220 * we assume display items will not draw outside the content rect, so 221 * clipping is only required if there is a border-radius. This is an 222 * optimization to reduce the amount of clipping required. 223 */ 224 void ClipContainingBlockDescendantsToContentBox( 225 nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, uint32_t aFlags = 0) { 226 NS_ASSERTION(!mRestored, "Already restored!"); 227 NS_ASSERTION(!mClipUsed, "mClip already used"); 228 #ifdef DEBUG 229 mClipUsed = true; 230 #endif 231 mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, 232 mClipChain, aFlags); 233 } 234 235 void MaybeRemoveDisplayportClip() { 236 if (!mState.mClipChainContainingBlockDescendants) return; 237 238 // Only remove the displayport clip in the case where it's the first 239 // element of the clip chain. This covers the vast majority of cases, 240 // and handling displayport clips later in the clip chain would introduce 241 // significant added complexity. 242 if (mState.mClipChainContainingBlockDescendants->IsDisplayportClip()) { 243 auto* displayportClipItem = mState.mClipChainContainingBlockDescendants; 244 mState.mClipChainContainingBlockDescendants = 245 mState.mClipChainContainingBlockDescendants->mParent; 246 mState.InvalidateCurrentCombinedClipChain(displayportClipItem->mASR); 247 } 248 } 249 250 protected: 251 nsDisplayListBuilder* mBuilder; 252 DisplayListClipState& mState; 253 DisplayListClipState mSavedState; 254 DisplayItemClipChain mClipChain; 255 #ifdef DEBUG 256 bool mClipUsed; 257 bool mRestored; 258 #endif 259 }; 260 261 class DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox 262 : public AutoSaveRestore { 263 public: 264 AutoClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, 265 nsIFrame* aFrame, 266 uint32_t aFlags = 0) 267 : AutoSaveRestore(aBuilder) { 268 #ifdef DEBUG 269 mClipUsed = true; 270 #endif 271 mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, 272 mClipChain, aFlags); 273 } 274 }; 275 276 /** 277 * Do not use this outside of nsIFrame::BuildDisplayListForChild, use 278 * multiple AutoSaveRestores instead. We provide this class just to ensure 279 * BuildDisplayListForChild is as efficient as possible. 280 */ 281 class DisplayListClipState::AutoClipMultiple : public AutoSaveRestore { 282 public: 283 explicit AutoClipMultiple(nsDisplayListBuilder* aBuilder) 284 : AutoSaveRestore(aBuilder) 285 #ifdef DEBUG 286 , 287 mExtraClipUsed(false) 288 #endif 289 { 290 } 291 292 /** 293 * Intersects the given clip rect (with optional aRadii) with the current 294 * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to 295 * the result, stored in aClipOnStack. 296 */ 297 void ClipContainingBlockDescendantsExtra(const nsRect& aRect, 298 const nsRectCornerRadii* aRadii) { 299 NS_ASSERTION(!mRestored, "Already restored!"); 300 NS_ASSERTION(!mExtraClipUsed, "mExtraClip already used"); 301 #ifdef DEBUG 302 mExtraClipUsed = true; 303 #endif 304 mState.ClipContainingBlockDescendants(mBuilder, aRect, aRadii, 305 mExtraClipChain); 306 } 307 308 protected: 309 DisplayItemClipChain mExtraClipChain; 310 #ifdef DEBUG 311 bool mExtraClipUsed; 312 #endif 313 }; 314 315 } // namespace mozilla 316 317 #endif /* DISPLAYLISTCLIPSTATE_H_ */