Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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_ */