summaryrefslogtreecommitdiffstats
path: root/layout/painting/DisplayListClipState.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'layout/painting/DisplayListClipState.cpp')
-rw-r--r--layout/painting/DisplayListClipState.cpp149
1 files changed, 149 insertions, 0 deletions
diff --git a/layout/painting/DisplayListClipState.cpp b/layout/painting/DisplayListClipState.cpp
new file mode 100644
index 0000000000..8a87e2906b
--- /dev/null
+++ b/layout/painting/DisplayListClipState.cpp
@@ -0,0 +1,149 @@
+/* -*- 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/. */
+
+#include "DisplayListClipState.h"
+
+#include "nsDisplayList.h"
+
+namespace mozilla {
+
+const DisplayItemClipChain* DisplayListClipState::GetCurrentCombinedClipChain(
+ nsDisplayListBuilder* aBuilder) {
+ if (mCurrentCombinedClipChainIsValid) {
+ return mCurrentCombinedClipChain;
+ }
+ if (!mClipChainContentDescendants && !mClipChainContainingBlockDescendants) {
+ mCurrentCombinedClipChain = nullptr;
+ mCurrentCombinedClipChainIsValid = true;
+ return nullptr;
+ }
+
+ mCurrentCombinedClipChain = aBuilder->CreateClipChainIntersection(
+ mCurrentCombinedClipChain, mClipChainContentDescendants,
+ mClipChainContainingBlockDescendants);
+ mCurrentCombinedClipChainIsValid = true;
+ return mCurrentCombinedClipChain;
+}
+
+static void ApplyClip(nsDisplayListBuilder* aBuilder,
+ const DisplayItemClipChain*& aClipToModify,
+ const ActiveScrolledRoot* aASR,
+ DisplayItemClipChain& aClipChainOnStack) {
+ aClipChainOnStack.mASR = aASR;
+ if (aClipToModify && aClipToModify->mASR == aASR) {
+ // Intersect with aClipToModify and replace the clip chain item.
+ aClipChainOnStack.mClip.IntersectWith(aClipToModify->mClip);
+ aClipChainOnStack.mParent = aClipToModify->mParent;
+ aClipToModify = &aClipChainOnStack;
+ } else if (!aClipToModify ||
+ ActiveScrolledRoot::IsAncestor(aClipToModify->mASR, aASR)) {
+ // Add a new clip chain item at the bottom.
+ aClipChainOnStack.mParent = aClipToModify;
+ aClipToModify = &aClipChainOnStack;
+ } else {
+ // We need to insert / intersect a DisplayItemClipChain in the middle of the
+ // aClipToModify chain. This is a very rare case.
+ // Find the common ancestor and have the builder create the
+ // DisplayItemClipChain intersection. This will create new
+ // DisplayItemClipChain objects for all descendants of ancestorSC and we
+ // will not hold on to a pointer to aClipChainOnStack.
+ const DisplayItemClipChain* ancestorSC = aClipToModify;
+ while (ancestorSC &&
+ ActiveScrolledRoot::IsAncestor(aASR, ancestorSC->mASR)) {
+ ancestorSC = ancestorSC->mParent;
+ }
+ ancestorSC = aBuilder->CopyWholeChain(ancestorSC);
+ aClipChainOnStack.mParent = nullptr;
+ aClipToModify = aBuilder->CreateClipChainIntersection(
+ ancestorSC, aClipToModify, &aClipChainOnStack);
+ }
+}
+
+void DisplayListClipState::ClipContainingBlockDescendants(
+ nsDisplayListBuilder* aBuilder, const nsRect& aRect, const nscoord* aRadii,
+ DisplayItemClipChain& aClipChainOnStack) {
+ if (aRadii) {
+ aClipChainOnStack.mClip.SetTo(aRect, aRadii);
+ } else {
+ aClipChainOnStack.mClip.SetTo(aRect);
+ }
+ const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
+ ApplyClip(aBuilder, mClipChainContainingBlockDescendants, asr,
+ aClipChainOnStack);
+ InvalidateCurrentCombinedClipChain(asr);
+}
+
+void DisplayListClipState::ClipContentDescendants(
+ nsDisplayListBuilder* aBuilder, const nsRect& aRect, const nscoord* aRadii,
+ DisplayItemClipChain& aClipChainOnStack) {
+ if (aRadii) {
+ aClipChainOnStack.mClip.SetTo(aRect, aRadii);
+ } else {
+ aClipChainOnStack.mClip.SetTo(aRect);
+ }
+ const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
+ ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack);
+ InvalidateCurrentCombinedClipChain(asr);
+}
+
+void DisplayListClipState::ClipContentDescendants(
+ nsDisplayListBuilder* aBuilder, const nsRect& aRect,
+ const nsRect& aRoundedRect, const nscoord* aRadii,
+ DisplayItemClipChain& aClipChainOnStack) {
+ if (aRadii) {
+ aClipChainOnStack.mClip.SetTo(aRect, aRoundedRect, aRadii);
+ } else {
+ nsRect intersect = aRect.Intersect(aRoundedRect);
+ aClipChainOnStack.mClip.SetTo(intersect);
+ }
+ const ActiveScrolledRoot* asr = aBuilder->CurrentActiveScrolledRoot();
+ ApplyClip(aBuilder, mClipChainContentDescendants, asr, aClipChainOnStack);
+ InvalidateCurrentCombinedClipChain(asr);
+}
+
+void DisplayListClipState::InvalidateCurrentCombinedClipChain(
+ const ActiveScrolledRoot* aInvalidateUpTo) {
+ mClippedToDisplayPort = false;
+ mCurrentCombinedClipChainIsValid = false;
+ while (mCurrentCombinedClipChain &&
+ ActiveScrolledRoot::IsAncestor(aInvalidateUpTo,
+ mCurrentCombinedClipChain->mASR)) {
+ mCurrentCombinedClipChain = mCurrentCombinedClipChain->mParent;
+ }
+}
+
+void DisplayListClipState::ClipContainingBlockDescendantsToContentBox(
+ nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+ DisplayItemClipChain& aClipChainOnStack, uint32_t aFlags) {
+ nscoord radii[8];
+ bool hasBorderRadius = aFrame->GetContentBoxBorderRadii(radii);
+ if (!hasBorderRadius &&
+ (aFlags & ASSUME_DRAWING_RESTRICTED_TO_CONTENT_RECT)) {
+ return;
+ }
+
+ nsRect clipRect = aFrame->GetContentRectRelativeToSelf() +
+ aBuilder->ToReferenceFrame(aFrame);
+ // If we have a border-radius, we have to clip our content to that
+ // radius.
+ ClipContainingBlockDescendants(
+ aBuilder, clipRect, hasBorderRadius ? radii : nullptr, aClipChainOnStack);
+}
+
+DisplayListClipState::AutoSaveRestore::AutoSaveRestore(
+ nsDisplayListBuilder* aBuilder)
+ : mBuilder(aBuilder),
+ mState(aBuilder->ClipState()),
+ mSavedState(aBuilder->ClipState())
+#ifdef DEBUG
+ ,
+ mClipUsed(false),
+ mRestored(false)
+#endif
+{
+}
+
+} // namespace mozilla