diff options
Diffstat (limited to 'layout/painting/DisplayListClipState.h')
-rw-r--r-- | layout/painting/DisplayListClipState.h | 301 |
1 files changed, 301 insertions, 0 deletions
diff --git a/layout/painting/DisplayListClipState.h b/layout/painting/DisplayListClipState.h new file mode 100644 index 0000000000..0f1df2ca58 --- /dev/null +++ b/layout/painting/DisplayListClipState.h @@ -0,0 +1,301 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef DISPLAYLISTCLIPSTATE_H_ +#define DISPLAYLISTCLIPSTATE_H_ + +#include "DisplayItemClip.h" +#include "DisplayItemClipChain.h" + +#include "mozilla/DebugOnly.h" + +class nsIFrame; +class nsIScrollableFrame; + +namespace mozilla { + +class nsDisplayListBuilder; + +/** + * All clip coordinates are in appunits relative to the reference frame + * for the display item we're building. + */ +class DisplayListClipState { + public: + DisplayListClipState() + : mClipChainContentDescendants(nullptr), + mClipChainContainingBlockDescendants(nullptr), + mCurrentCombinedClipChain(nullptr), + mCurrentCombinedClipChainIsValid(false), + mClippedToDisplayPort(false) {} + + void SetClippedToDisplayPort() { mClippedToDisplayPort = true; } + bool IsClippedToDisplayPort() const { return mClippedToDisplayPort; } + + /** + * Returns intersection of mClipChainContainingBlockDescendants and + * mClipChainContentDescendants, allocated on aBuilder's arena. + */ + const DisplayItemClipChain* GetCurrentCombinedClipChain( + nsDisplayListBuilder* aBuilder); + + const DisplayItemClipChain* GetClipChainForContainingBlockDescendants() + const { + return mClipChainContainingBlockDescendants; + } + const DisplayItemClipChain* GetClipChainForContentDescendants() const { + return mClipChainContentDescendants; + } + + const ActiveScrolledRoot* GetContentClipASR() const { + return mClipChainContentDescendants ? mClipChainContentDescendants->mASR + : nullptr; + } + + class AutoSaveRestore; + + class AutoClipContainingBlockDescendantsToContentBox; + + class AutoClipMultiple; + + enum { ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT = 0x01 }; + + private: + void Clear() { + mClipChainContentDescendants = nullptr; + mClipChainContainingBlockDescendants = nullptr; + mCurrentCombinedClipChain = nullptr; + mCurrentCombinedClipChainIsValid = false; + mClippedToDisplayPort = false; + } + + void SetClipChainForContainingBlockDescendants( + const DisplayItemClipChain* aClipChain) { + mClipChainContainingBlockDescendants = aClipChain; + InvalidateCurrentCombinedClipChain(aClipChain ? aClipChain->mASR : nullptr); + } + + /** + * Intersects the given clip rect (with optional aRadii) with the current + * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to + * the result, stored in aClipOnStack. + */ + void ClipContainingBlockDescendants(nsDisplayListBuilder* aBuilder, + const nsRect& aRect, + const nscoord* aRadii, + DisplayItemClipChain& aClipChainOnStack); + + void ClipContentDescendants(nsDisplayListBuilder* aBuilder, + const nsRect& aRect, const nscoord* aRadii, + DisplayItemClipChain& aClipChainOnStack); + void ClipContentDescendants(nsDisplayListBuilder* aBuilder, + const nsRect& aRect, const nsRect& aRoundedRect, + const nscoord* aRadii, + DisplayItemClipChain& aClipChainOnStack); + + void InvalidateCurrentCombinedClipChain( + const ActiveScrolledRoot* aInvalidateUpTo); + + /** + * Clips containing-block descendants to the frame's content-box, + * taking border-radius into account. + * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then + * we assume display items will not draw outside the content rect, so + * clipping is only required if there is a border-radius. This is an + * optimization to reduce the amount of clipping required. + */ + void ClipContainingBlockDescendantsToContentBox( + nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, + DisplayItemClipChain& aClipChainOnStack, uint32_t aFlags); + + /** + * All content descendants (i.e. following placeholder frames to their + * out-of-flows if necessary) should be clipped by + * mClipChainContentDescendants. Null if no clipping applies. + */ + const DisplayItemClipChain* mClipChainContentDescendants; + /** + * All containing-block descendants (i.e. frame descendants), including + * display items for the current frame, should be clipped by + * mClipChainContainingBlockDescendants. + * Null if no clipping applies. + */ + const DisplayItemClipChain* mClipChainContainingBlockDescendants; + /** + * The intersection of mClipChainContentDescendants and + * mClipChainContainingBlockDescendants. + * Allocated in the nsDisplayListBuilder arena. Null if none has been + * allocated or both mClipChainContentDescendants and + * mClipChainContainingBlockDescendants are null. + */ + const DisplayItemClipChain* mCurrentCombinedClipChain; + bool mCurrentCombinedClipChainIsValid; + /** + * A flag that is used by sticky positioned items to know if the clip applied + * to them is just the displayport clip or if there is additional clipping. + */ + bool mClippedToDisplayPort; +}; + +/** + * A class to automatically save and restore the current clip state. Also + * offers methods for modifying the clip state. Only one modification is allowed + * to be in scope at a time using one of these objects; multiple modifications + * require nested objects. The interface is written this way to prevent + * dangling pointers to DisplayItemClips. + */ +class DisplayListClipState::AutoSaveRestore { + public: + explicit AutoSaveRestore(nsDisplayListBuilder* aBuilder); + void Restore() { + mState = mSavedState; +#ifdef DEBUG + mRestored = true; +#endif + } + ~AutoSaveRestore() { Restore(); } + + void Clear() { + NS_ASSERTION(!mRestored, "Already restored!"); + mState.Clear(); +#ifdef DEBUG + mClipUsed = false; +#endif + } + + void SetClipChainForContainingBlockDescendants( + const DisplayItemClipChain* aClipChain) { + mState.SetClipChainForContainingBlockDescendants(aClipChain); + } + + /** + * Intersects the given clip rect (with optional aRadii) with the current + * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to + * the result, stored in aClipOnStack. + */ + void ClipContainingBlockDescendants(const nsRect& aRect, + const nscoord* aRadii = nullptr) { + NS_ASSERTION(!mRestored, "Already restored!"); + NS_ASSERTION(!mClipUsed, "mClip already used"); +#ifdef DEBUG + mClipUsed = true; +#endif + mState.ClipContainingBlockDescendants(mBuilder, aRect, aRadii, mClipChain); + } + + void ClipContentDescendants(const nsRect& aRect, + const nscoord* aRadii = nullptr) { + NS_ASSERTION(!mRestored, "Already restored!"); + NS_ASSERTION(!mClipUsed, "mClip already used"); +#ifdef DEBUG + mClipUsed = true; +#endif + mState.ClipContentDescendants(mBuilder, aRect, aRadii, mClipChain); + } + + void ClipContentDescendants(const nsRect& aRect, const nsRect& aRoundedRect, + const nscoord* aRadii = nullptr) { + NS_ASSERTION(!mRestored, "Already restored!"); + NS_ASSERTION(!mClipUsed, "mClip already used"); +#ifdef DEBUG + mClipUsed = true; +#endif + mState.ClipContentDescendants(mBuilder, aRect, aRoundedRect, aRadii, + mClipChain); + } + + /** + * Clips containing-block descendants to the frame's content-box, + * taking border-radius into account. + * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then + * we assume display items will not draw outside the content rect, so + * clipping is only required if there is a border-radius. This is an + * optimization to reduce the amount of clipping required. + */ + void ClipContainingBlockDescendantsToContentBox( + nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, uint32_t aFlags = 0) { + NS_ASSERTION(!mRestored, "Already restored!"); + NS_ASSERTION(!mClipUsed, "mClip already used"); +#ifdef DEBUG + mClipUsed = true; +#endif + mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, + mClipChain, aFlags); + } + + void SetClippedToDisplayPort() { mState.SetClippedToDisplayPort(); } + bool IsClippedToDisplayPort() const { + return mState.IsClippedToDisplayPort(); + } + + protected: + nsDisplayListBuilder* mBuilder; + DisplayListClipState& mState; + DisplayListClipState mSavedState; + DisplayItemClipChain mClipChain; +#ifdef DEBUG + bool mClipUsed; + bool mRestored; +#endif +}; + +class DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox + : public AutoSaveRestore { + public: + AutoClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, + nsIFrame* aFrame, + uint32_t aFlags = 0) + : AutoSaveRestore(aBuilder) { +#ifdef DEBUG + mClipUsed = true; +#endif + mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, + mClipChain, aFlags); + } +}; + +/** + * Do not use this outside of nsIFrame::BuildDisplayListForChild, use + * multiple AutoSaveRestores instead. We provide this class just to ensure + * BuildDisplayListForChild is as efficient as possible. + */ +class DisplayListClipState::AutoClipMultiple : public AutoSaveRestore { + public: + explicit AutoClipMultiple(nsDisplayListBuilder* aBuilder) + : AutoSaveRestore(aBuilder) +#ifdef DEBUG + , + mExtraClipUsed(false) +#endif + { + } + + /** + * Intersects the given clip rect (with optional aRadii) with the current + * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to + * the result, stored in aClipOnStack. + */ + void ClipContainingBlockDescendantsExtra(const nsRect& aRect, + const nscoord* aRadii) { + NS_ASSERTION(!mRestored, "Already restored!"); + NS_ASSERTION(!mExtraClipUsed, "mExtraClip already used"); +#ifdef DEBUG + mExtraClipUsed = true; +#endif + mState.ClipContainingBlockDescendants(mBuilder, aRect, aRadii, + mExtraClipChain); + } + + protected: + DisplayItemClipChain mExtraClipChain; +#ifdef DEBUG + bool mExtraClipUsed; +#endif +}; + +} // namespace mozilla + +#endif /* DISPLAYLISTCLIPSTATE_H_ */ |