1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/DisplayListClipState.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,250 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#ifndef DISPLAYLISTCLIPSTATE_H_ 1.10 +#define DISPLAYLISTCLIPSTATE_H_ 1.11 + 1.12 +#include "DisplayItemClip.h" 1.13 + 1.14 +#include "mozilla/DebugOnly.h" 1.15 + 1.16 +class nsIFrame; 1.17 +class nsDisplayListBuilder; 1.18 + 1.19 +namespace mozilla { 1.20 + 1.21 +/** 1.22 + * All clip coordinates are in appunits relative to the reference frame 1.23 + * for the display item we're building. 1.24 + */ 1.25 +class DisplayListClipState { 1.26 +public: 1.27 + DisplayListClipState() 1.28 + : mClipContentDescendants(nullptr) 1.29 + , mClipContainingBlockDescendants(nullptr) 1.30 + , mCurrentCombinedClip(nullptr) 1.31 + {} 1.32 + 1.33 + /** 1.34 + * Returns intersection of mClipContainingBlockDescendants and 1.35 + * mClipContentDescendants, allocated on aBuilder's arena. 1.36 + */ 1.37 + const DisplayItemClip* GetCurrentCombinedClip(nsDisplayListBuilder* aBuilder); 1.38 + 1.39 + const DisplayItemClip* GetClipForContainingBlockDescendants() const 1.40 + { 1.41 + return mClipContainingBlockDescendants; 1.42 + } 1.43 + const DisplayItemClip* GetClipForContentDescendants() const 1.44 + { 1.45 + return mClipContentDescendants; 1.46 + } 1.47 + 1.48 + class AutoSaveRestore; 1.49 + friend class AutoSaveRestore; 1.50 + 1.51 + class AutoClipContainingBlockDescendantsToContentBox; 1.52 + friend class AutoClipContainingBlockDescendantsToContentBox; 1.53 + 1.54 + class AutoClipMultiple; 1.55 + friend class AutoClipMultiple; 1.56 + 1.57 + enum { 1.58 + ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT = 0x01 1.59 + }; 1.60 + 1.61 +private: 1.62 + void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip) 1.63 + { 1.64 + mClipContainingBlockDescendants = aClip; 1.65 + mCurrentCombinedClip = nullptr; 1.66 + } 1.67 + 1.68 + void Clear() 1.69 + { 1.70 + mClipContentDescendants = nullptr; 1.71 + mClipContainingBlockDescendants = nullptr; 1.72 + mCurrentCombinedClip = nullptr; 1.73 + } 1.74 + 1.75 + /** 1.76 + * Intersects the given clip rect (with optional aRadii) with the current 1.77 + * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to 1.78 + * the result, stored in aClipOnStack. 1.79 + */ 1.80 + void ClipContainingBlockDescendants(const nsRect& aRect, 1.81 + const nscoord* aRadii, 1.82 + DisplayItemClip& aClipOnStack); 1.83 + 1.84 + void ClipContentDescendants(const nsRect& aRect, 1.85 + const nscoord* aRadii, 1.86 + DisplayItemClip& aClipOnStack); 1.87 + 1.88 + /** 1.89 + * Clips containing-block descendants to the frame's content-box, 1.90 + * taking border-radius into account. 1.91 + * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then 1.92 + * we assume display items will not draw outside the content rect, so 1.93 + * clipping is only required if there is a border-radius. This is an 1.94 + * optimization to reduce the amount of clipping required. 1.95 + */ 1.96 + void ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, 1.97 + nsIFrame* aFrame, 1.98 + DisplayItemClip& aClipOnStack, 1.99 + uint32_t aFlags); 1.100 + 1.101 + /** 1.102 + * All content descendants (i.e. following placeholder frames to their 1.103 + * out-of-flows if necessary) should be clipped by mClipContentDescendants. 1.104 + * Null if no clipping applies. 1.105 + */ 1.106 + const DisplayItemClip* mClipContentDescendants; 1.107 + /** 1.108 + * All containing-block descendants (i.e. frame descendants), including 1.109 + * display items for the current frame, should be clipped by 1.110 + * mClipContainingBlockDescendants. 1.111 + * Null if no clipping applies. 1.112 + */ 1.113 + const DisplayItemClip* mClipContainingBlockDescendants; 1.114 + /** 1.115 + * The intersection of mClipContentDescendants and 1.116 + * mClipContainingBlockDescendants. 1.117 + * Allocated in the nsDisplayListBuilder arena. Null if none has been 1.118 + * allocated or both mClipContentDescendants and mClipContainingBlockDescendants 1.119 + * are null. 1.120 + */ 1.121 + const DisplayItemClip* mCurrentCombinedClip; 1.122 +}; 1.123 + 1.124 +/** 1.125 + * A class to automatically save and restore the current clip state. Also 1.126 + * offers methods for modifying the clip state. Only one modification is allowed 1.127 + * to be in scope at a time using one of these objects; multiple modifications 1.128 + * require nested objects. The interface is written this way to prevent 1.129 + * dangling pointers to DisplayItemClips. 1.130 + */ 1.131 +class DisplayListClipState::AutoSaveRestore { 1.132 +public: 1.133 + AutoSaveRestore(nsDisplayListBuilder* aBuilder); 1.134 + void Restore() 1.135 + { 1.136 + mState = mSavedState; 1.137 + mRestored = true; 1.138 + } 1.139 + ~AutoSaveRestore() 1.140 + { 1.141 + mState = mSavedState; 1.142 + } 1.143 + 1.144 + void Clear() 1.145 + { 1.146 + NS_ASSERTION(!mRestored, "Already restored!"); 1.147 + mState.Clear(); 1.148 + mClipUsed = false; 1.149 + } 1.150 + 1.151 + /** 1.152 + * Intersects the given clip rect (with optional aRadii) with the current 1.153 + * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to 1.154 + * the result, stored in aClipOnStack. 1.155 + */ 1.156 + void ClipContainingBlockDescendants(const nsRect& aRect, 1.157 + const nscoord* aRadii = nullptr) 1.158 + { 1.159 + NS_ASSERTION(!mRestored, "Already restored!"); 1.160 + NS_ASSERTION(!mClipUsed, "mClip already used"); 1.161 + mClipUsed = true; 1.162 + mState.ClipContainingBlockDescendants(aRect, aRadii, mClip); 1.163 + } 1.164 + 1.165 + void ClipContentDescendants(const nsRect& aRect, 1.166 + const nscoord* aRadii = nullptr) 1.167 + { 1.168 + NS_ASSERTION(!mRestored, "Already restored!"); 1.169 + NS_ASSERTION(!mClipUsed, "mClip already used"); 1.170 + mClipUsed = true; 1.171 + mState.ClipContentDescendants(aRect, aRadii, mClip); 1.172 + } 1.173 + 1.174 + /** 1.175 + * Clips containing-block descendants to the frame's content-box, 1.176 + * taking border-radius into account. 1.177 + * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then 1.178 + * we assume display items will not draw outside the content rect, so 1.179 + * clipping is only required if there is a border-radius. This is an 1.180 + * optimization to reduce the amount of clipping required. 1.181 + */ 1.182 + void ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, 1.183 + nsIFrame* aFrame, 1.184 + uint32_t aFlags = 0) 1.185 + { 1.186 + NS_ASSERTION(!mRestored, "Already restored!"); 1.187 + NS_ASSERTION(!mClipUsed, "mClip already used"); 1.188 + mClipUsed = true; 1.189 + mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClip, aFlags); 1.190 + } 1.191 + 1.192 +protected: 1.193 + DisplayListClipState& mState; 1.194 + DisplayListClipState mSavedState; 1.195 + DisplayItemClip mClip; 1.196 + DebugOnly<bool> mClipUsed; 1.197 + DebugOnly<bool> mRestored; 1.198 +}; 1.199 + 1.200 +class DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox : public AutoSaveRestore { 1.201 +public: 1.202 + AutoClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, 1.203 + nsIFrame* aFrame, 1.204 + uint32_t aFlags = 0) 1.205 + : AutoSaveRestore(aBuilder) 1.206 + { 1.207 + mClipUsed = true; 1.208 + mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClip, aFlags); 1.209 + } 1.210 +}; 1.211 + 1.212 +/** 1.213 + * Do not use this outside of nsFrame::BuildDisplayListForChild, use 1.214 + * multiple AutoSaveRestores instead. We provide this class just to ensure 1.215 + * BuildDisplayListForChild is as efficient as possible. 1.216 + */ 1.217 +class DisplayListClipState::AutoClipMultiple : public AutoSaveRestore { 1.218 +public: 1.219 + AutoClipMultiple(nsDisplayListBuilder* aBuilder) 1.220 + : AutoSaveRestore(aBuilder) 1.221 + , mExtraClipUsed(false) 1.222 + {} 1.223 + 1.224 + /** 1.225 + * *aClip must survive longer than this object. Be careful!!! 1.226 + */ 1.227 + void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip) 1.228 + { 1.229 + mState.SetClipForContainingBlockDescendants(aClip); 1.230 + } 1.231 + 1.232 + /** 1.233 + * Intersects the given clip rect (with optional aRadii) with the current 1.234 + * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to 1.235 + * the result, stored in aClipOnStack. 1.236 + */ 1.237 + void ClipContainingBlockDescendantsExtra(const nsRect& aRect, 1.238 + const nscoord* aRadii) 1.239 + { 1.240 + NS_ASSERTION(!mRestored, "Already restored!"); 1.241 + NS_ASSERTION(!mExtraClipUsed, "mExtraClip already used"); 1.242 + mExtraClipUsed = true; 1.243 + mState.ClipContainingBlockDescendants(aRect, aRadii, mExtraClip); 1.244 + } 1.245 + 1.246 +protected: 1.247 + DisplayItemClip mExtraClip; 1.248 + DebugOnly<bool> mExtraClipUsed; 1.249 +}; 1.250 + 1.251 +} 1.252 + 1.253 +#endif /* DISPLAYLISTCLIPSTATE_H_ */