michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef DISPLAYLISTCLIPSTATE_H_ michael@0: #define DISPLAYLISTCLIPSTATE_H_ michael@0: michael@0: #include "DisplayItemClip.h" michael@0: michael@0: #include "mozilla/DebugOnly.h" michael@0: michael@0: class nsIFrame; michael@0: class nsDisplayListBuilder; michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * All clip coordinates are in appunits relative to the reference frame michael@0: * for the display item we're building. michael@0: */ michael@0: class DisplayListClipState { michael@0: public: michael@0: DisplayListClipState() michael@0: : mClipContentDescendants(nullptr) michael@0: , mClipContainingBlockDescendants(nullptr) michael@0: , mCurrentCombinedClip(nullptr) michael@0: {} michael@0: michael@0: /** michael@0: * Returns intersection of mClipContainingBlockDescendants and michael@0: * mClipContentDescendants, allocated on aBuilder's arena. michael@0: */ michael@0: const DisplayItemClip* GetCurrentCombinedClip(nsDisplayListBuilder* aBuilder); michael@0: michael@0: const DisplayItemClip* GetClipForContainingBlockDescendants() const michael@0: { michael@0: return mClipContainingBlockDescendants; michael@0: } michael@0: const DisplayItemClip* GetClipForContentDescendants() const michael@0: { michael@0: return mClipContentDescendants; michael@0: } michael@0: michael@0: class AutoSaveRestore; michael@0: friend class AutoSaveRestore; michael@0: michael@0: class AutoClipContainingBlockDescendantsToContentBox; michael@0: friend class AutoClipContainingBlockDescendantsToContentBox; michael@0: michael@0: class AutoClipMultiple; michael@0: friend class AutoClipMultiple; michael@0: michael@0: enum { michael@0: ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT = 0x01 michael@0: }; michael@0: michael@0: private: michael@0: void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip) michael@0: { michael@0: mClipContainingBlockDescendants = aClip; michael@0: mCurrentCombinedClip = nullptr; michael@0: } michael@0: michael@0: void Clear() michael@0: { michael@0: mClipContentDescendants = nullptr; michael@0: mClipContainingBlockDescendants = nullptr; michael@0: mCurrentCombinedClip = nullptr; michael@0: } michael@0: michael@0: /** michael@0: * Intersects the given clip rect (with optional aRadii) with the current michael@0: * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to michael@0: * the result, stored in aClipOnStack. michael@0: */ michael@0: void ClipContainingBlockDescendants(const nsRect& aRect, michael@0: const nscoord* aRadii, michael@0: DisplayItemClip& aClipOnStack); michael@0: michael@0: void ClipContentDescendants(const nsRect& aRect, michael@0: const nscoord* aRadii, michael@0: DisplayItemClip& aClipOnStack); michael@0: michael@0: /** michael@0: * Clips containing-block descendants to the frame's content-box, michael@0: * taking border-radius into account. michael@0: * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then michael@0: * we assume display items will not draw outside the content rect, so michael@0: * clipping is only required if there is a border-radius. This is an michael@0: * optimization to reduce the amount of clipping required. michael@0: */ michael@0: void ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame, michael@0: DisplayItemClip& aClipOnStack, michael@0: uint32_t aFlags); michael@0: michael@0: /** michael@0: * All content descendants (i.e. following placeholder frames to their michael@0: * out-of-flows if necessary) should be clipped by mClipContentDescendants. michael@0: * Null if no clipping applies. michael@0: */ michael@0: const DisplayItemClip* mClipContentDescendants; michael@0: /** michael@0: * All containing-block descendants (i.e. frame descendants), including michael@0: * display items for the current frame, should be clipped by michael@0: * mClipContainingBlockDescendants. michael@0: * Null if no clipping applies. michael@0: */ michael@0: const DisplayItemClip* mClipContainingBlockDescendants; michael@0: /** michael@0: * The intersection of mClipContentDescendants and michael@0: * mClipContainingBlockDescendants. michael@0: * Allocated in the nsDisplayListBuilder arena. Null if none has been michael@0: * allocated or both mClipContentDescendants and mClipContainingBlockDescendants michael@0: * are null. michael@0: */ michael@0: const DisplayItemClip* mCurrentCombinedClip; michael@0: }; michael@0: michael@0: /** michael@0: * A class to automatically save and restore the current clip state. Also michael@0: * offers methods for modifying the clip state. Only one modification is allowed michael@0: * to be in scope at a time using one of these objects; multiple modifications michael@0: * require nested objects. The interface is written this way to prevent michael@0: * dangling pointers to DisplayItemClips. michael@0: */ michael@0: class DisplayListClipState::AutoSaveRestore { michael@0: public: michael@0: AutoSaveRestore(nsDisplayListBuilder* aBuilder); michael@0: void Restore() michael@0: { michael@0: mState = mSavedState; michael@0: mRestored = true; michael@0: } michael@0: ~AutoSaveRestore() michael@0: { michael@0: mState = mSavedState; michael@0: } michael@0: michael@0: void Clear() michael@0: { michael@0: NS_ASSERTION(!mRestored, "Already restored!"); michael@0: mState.Clear(); michael@0: mClipUsed = false; michael@0: } michael@0: michael@0: /** michael@0: * Intersects the given clip rect (with optional aRadii) with the current michael@0: * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to michael@0: * the result, stored in aClipOnStack. michael@0: */ michael@0: void ClipContainingBlockDescendants(const nsRect& aRect, michael@0: const nscoord* aRadii = nullptr) michael@0: { michael@0: NS_ASSERTION(!mRestored, "Already restored!"); michael@0: NS_ASSERTION(!mClipUsed, "mClip already used"); michael@0: mClipUsed = true; michael@0: mState.ClipContainingBlockDescendants(aRect, aRadii, mClip); michael@0: } michael@0: michael@0: void ClipContentDescendants(const nsRect& aRect, michael@0: const nscoord* aRadii = nullptr) michael@0: { michael@0: NS_ASSERTION(!mRestored, "Already restored!"); michael@0: NS_ASSERTION(!mClipUsed, "mClip already used"); michael@0: mClipUsed = true; michael@0: mState.ClipContentDescendants(aRect, aRadii, mClip); michael@0: } michael@0: michael@0: /** michael@0: * Clips containing-block descendants to the frame's content-box, michael@0: * taking border-radius into account. michael@0: * If aFlags contains ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT then michael@0: * we assume display items will not draw outside the content rect, so michael@0: * clipping is only required if there is a border-radius. This is an michael@0: * optimization to reduce the amount of clipping required. michael@0: */ michael@0: void ClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame, michael@0: uint32_t aFlags = 0) michael@0: { michael@0: NS_ASSERTION(!mRestored, "Already restored!"); michael@0: NS_ASSERTION(!mClipUsed, "mClip already used"); michael@0: mClipUsed = true; michael@0: mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClip, aFlags); michael@0: } michael@0: michael@0: protected: michael@0: DisplayListClipState& mState; michael@0: DisplayListClipState mSavedState; michael@0: DisplayItemClip mClip; michael@0: DebugOnly mClipUsed; michael@0: DebugOnly mRestored; michael@0: }; michael@0: michael@0: class DisplayListClipState::AutoClipContainingBlockDescendantsToContentBox : public AutoSaveRestore { michael@0: public: michael@0: AutoClipContainingBlockDescendantsToContentBox(nsDisplayListBuilder* aBuilder, michael@0: nsIFrame* aFrame, michael@0: uint32_t aFlags = 0) michael@0: : AutoSaveRestore(aBuilder) michael@0: { michael@0: mClipUsed = true; michael@0: mState.ClipContainingBlockDescendantsToContentBox(aBuilder, aFrame, mClip, aFlags); michael@0: } michael@0: }; michael@0: michael@0: /** michael@0: * Do not use this outside of nsFrame::BuildDisplayListForChild, use michael@0: * multiple AutoSaveRestores instead. We provide this class just to ensure michael@0: * BuildDisplayListForChild is as efficient as possible. michael@0: */ michael@0: class DisplayListClipState::AutoClipMultiple : public AutoSaveRestore { michael@0: public: michael@0: AutoClipMultiple(nsDisplayListBuilder* aBuilder) michael@0: : AutoSaveRestore(aBuilder) michael@0: , mExtraClipUsed(false) michael@0: {} michael@0: michael@0: /** michael@0: * *aClip must survive longer than this object. Be careful!!! michael@0: */ michael@0: void SetClipForContainingBlockDescendants(const DisplayItemClip* aClip) michael@0: { michael@0: mState.SetClipForContainingBlockDescendants(aClip); michael@0: } michael@0: michael@0: /** michael@0: * Intersects the given clip rect (with optional aRadii) with the current michael@0: * mClipContainingBlockDescendants and sets mClipContainingBlockDescendants to michael@0: * the result, stored in aClipOnStack. michael@0: */ michael@0: void ClipContainingBlockDescendantsExtra(const nsRect& aRect, michael@0: const nscoord* aRadii) michael@0: { michael@0: NS_ASSERTION(!mRestored, "Already restored!"); michael@0: NS_ASSERTION(!mExtraClipUsed, "mExtraClip already used"); michael@0: mExtraClipUsed = true; michael@0: mState.ClipContainingBlockDescendants(aRect, aRadii, mExtraClip); michael@0: } michael@0: michael@0: protected: michael@0: DisplayItemClip mExtraClip; michael@0: DebugOnly mExtraClipUsed; michael@0: }; michael@0: michael@0: } michael@0: michael@0: #endif /* DISPLAYLISTCLIPSTATE_H_ */