diff options
Diffstat (limited to 'layout/base/nsDisplayListInvalidation.h')
-rw-r--r-- | layout/base/nsDisplayListInvalidation.h | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/layout/base/nsDisplayListInvalidation.h b/layout/base/nsDisplayListInvalidation.h new file mode 100644 index 000000000..250ca94ce --- /dev/null +++ b/layout/base/nsDisplayListInvalidation.h @@ -0,0 +1,322 @@ +/*-*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * 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 NSDISPLAYLISTINVALIDATION_H_ +#define NSDISPLAYLISTINVALIDATION_H_ + +#include "mozilla/Attributes.h" +#include "FrameLayerBuilder.h" +#include "imgIContainer.h" +#include "nsRect.h" +#include "nsColor.h" +#include "gfxRect.h" + +class nsDisplayBackgroundImage; +class nsCharClipDisplayItem; +class nsDisplayItem; +class nsDisplayListBuilder; +class nsDisplayTableItem; +class nsDisplayThemedBackground; +class nsDisplaySVGEffects; +class nsDisplayMask; +class nsDisplayFilter; + +namespace mozilla { +namespace gfx { +struct Color; +} +} + +/** + * This stores the geometry of an nsDisplayItem, and the area + * that will be affected when painting the item. + * + * It is used to retain information about display items so they + * can be compared against new display items in the next paint. + */ +class nsDisplayItemGeometry +{ +public: + nsDisplayItemGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); + virtual ~nsDisplayItemGeometry(); + + /** + * Compute the area required to be invalidated if this + * display item is removed. + */ + const nsRect& ComputeInvalidationRegion() { return mBounds; } + + /** + * Shifts all retained areas of the nsDisplayItemGeometry by the given offset. + * + * This is used to compensate for scrolling, since the destination buffer + * can scroll without requiring a full repaint. + * + * @param aOffset Offset to shift by. + */ + virtual void MoveBy(const nsPoint& aOffset) + { + mBounds.MoveBy(aOffset); + } + + /** + * Bounds of the display item + */ + nsRect mBounds; +}; + +/** + * A default geometry implementation, used by nsDisplayItem. Retains + * and compares the bounds, and border rect. + * + * This should be sufficient for the majority of display items. + */ +class nsDisplayItemGenericGeometry : public nsDisplayItemGeometry +{ +public: + nsDisplayItemGenericGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); + + virtual void MoveBy(const nsPoint& aOffset) override; + + nsRect mBorderRect; +}; + +bool ShouldSyncDecodeImages(nsDisplayListBuilder* aBuilder); + +/** + * nsImageGeometryMixin is a mixin for geometry items that draw images. + * Geometry items that include this mixin can track drawing results and use + * that information to inform invalidation decisions. + * + * This mixin uses CRTP; its template parameter should be the type of the class + * that is inheriting from it. See nsDisplayItemGenericImageGeometry for an + * example. + */ +template <typename T> +class nsImageGeometryMixin +{ +public: + nsImageGeometryMixin(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder) + : mLastDrawResult(mozilla::image::DrawResult::NOT_READY) + , mWaitingForPaint(false) + { + // Transfer state from the previous version of this geometry item. + auto lastGeometry = + static_cast<T*>(mozilla::FrameLayerBuilder::GetMostRecentGeometry(aItem)); + if (lastGeometry) { + mLastDrawResult = lastGeometry->mLastDrawResult; + mWaitingForPaint = lastGeometry->mWaitingForPaint; + } + + // If our display item is going to invalidate to trigger sync decoding of + // images, mark ourselves as waiting for a paint. If we actually get + // painted, UpdateDrawResult will get called, and we'll clear the flag. + if (ShouldSyncDecodeImages(aBuilder) && + ShouldInvalidateToSyncDecodeImages()) { + mWaitingForPaint = true; + } + } + + static void UpdateDrawResult(nsDisplayItem* aItem, + mozilla::image::DrawResult aResult) + { + auto lastGeometry = + static_cast<T*>(mozilla::FrameLayerBuilder::GetMostRecentGeometry(aItem)); + if (lastGeometry) { + lastGeometry->mLastDrawResult = aResult; + lastGeometry->mWaitingForPaint = false; + } + } + + bool ShouldInvalidateToSyncDecodeImages() const + { + if (mWaitingForPaint) { + // We previously invalidated for sync decoding and haven't gotten painted + // since them. This suggests that our display item is completely occluded + // and there's no point in invalidating again - and because the reftest + // harness takes a new snapshot every time we invalidate, doing so might + // lead to an invalidation loop if we're in a reftest. + return false; + } + + if (mLastDrawResult == mozilla::image::DrawResult::SUCCESS || + mLastDrawResult == mozilla::image::DrawResult::BAD_IMAGE) { + return false; + } + + return true; + } + +private: + mozilla::image::DrawResult mLastDrawResult; + bool mWaitingForPaint; +}; + +/** + * nsDisplayItemGenericImageGeometry is a generic geometry item class that + * includes nsImageGeometryMixin. + * + * This should be sufficient for most display items that draw images. + */ +class nsDisplayItemGenericImageGeometry + : public nsDisplayItemGenericGeometry + , public nsImageGeometryMixin<nsDisplayItemGenericImageGeometry> +{ +public: + nsDisplayItemGenericImageGeometry(nsDisplayItem* aItem, + nsDisplayListBuilder* aBuilder) + : nsDisplayItemGenericGeometry(aItem, aBuilder) + , nsImageGeometryMixin(aItem, aBuilder) + { } +}; + +class nsDisplayItemBoundsGeometry : public nsDisplayItemGeometry +{ +public: + nsDisplayItemBoundsGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); + + bool mHasRoundedCorners; +}; + +class nsDisplayBorderGeometry + : public nsDisplayItemGeometry + , public nsImageGeometryMixin<nsDisplayBorderGeometry> +{ +public: + nsDisplayBorderGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); + + virtual void MoveBy(const nsPoint& aOffset) override; + + nsRect mContentRect; +}; + +class nsDisplayBackgroundGeometry + : public nsDisplayItemGeometry + , public nsImageGeometryMixin<nsDisplayBackgroundGeometry> +{ +public: + nsDisplayBackgroundGeometry(nsDisplayBackgroundImage* aItem, nsDisplayListBuilder* aBuilder); + + virtual void MoveBy(const nsPoint& aOffset) override; + + nsRect mPositioningArea; + nsRect mDestRect; +}; + +class nsDisplayThemedBackgroundGeometry : public nsDisplayItemGeometry +{ +public: + nsDisplayThemedBackgroundGeometry(nsDisplayThemedBackground* aItem, nsDisplayListBuilder* aBuilder); + + virtual void MoveBy(const nsPoint& aOffset) override; + + nsRect mPositioningArea; + bool mWindowIsActive; +}; + +class nsDisplayBoxShadowInnerGeometry : public nsDisplayItemGeometry +{ +public: + nsDisplayBoxShadowInnerGeometry(nsDisplayItem* aItem, nsDisplayListBuilder* aBuilder); + + virtual void MoveBy(const nsPoint& aOffset) override; + + nsRect mPaddingRect; +}; + +class nsDisplayBoxShadowOuterGeometry : public nsDisplayItemGenericGeometry +{ +public: + nsDisplayBoxShadowOuterGeometry(nsDisplayItem* aItem, + nsDisplayListBuilder* aBuilder, + float aOpacity); + + float mOpacity; +}; + +class nsDisplaySolidColorGeometry : public nsDisplayItemBoundsGeometry +{ +public: + nsDisplaySolidColorGeometry(nsDisplayItem* aItem, + nsDisplayListBuilder* aBuilder, + nscolor aColor) + : nsDisplayItemBoundsGeometry(aItem, aBuilder) + , mColor(aColor) + { } + + nscolor mColor; +}; + +class nsDisplaySolidColorRegionGeometry : public nsDisplayItemBoundsGeometry +{ +public: + nsDisplaySolidColorRegionGeometry(nsDisplayItem* aItem, + nsDisplayListBuilder* aBuilder, + const nsRegion& aRegion, + mozilla::gfx::Color aColor) + : nsDisplayItemBoundsGeometry(aItem, aBuilder) + , mRegion(aRegion) + , mColor(aColor) + { } + + virtual void MoveBy(const nsPoint& aOffset) override; + + nsRegion mRegion; + mozilla::gfx::Color mColor; +}; + +class nsDisplaySVGEffectGeometry : public nsDisplayItemGeometry +{ +public: + nsDisplaySVGEffectGeometry(nsDisplaySVGEffects* aItem, + nsDisplayListBuilder* aBuilder); + + virtual void MoveBy(const nsPoint& aOffset) override; + + gfxRect mBBox; + gfxPoint mUserSpaceOffset; + nsPoint mFrameOffsetToReferenceFrame; +}; + +class nsDisplayMaskGeometry : public nsDisplaySVGEffectGeometry + , public nsImageGeometryMixin<nsDisplayMaskGeometry> +{ +public: + nsDisplayMaskGeometry(nsDisplayMask* aItem, nsDisplayListBuilder* aBuilder); + + nsTArray<nsRect> mDestRects; +}; + +class nsDisplayFilterGeometry : public nsDisplaySVGEffectGeometry + , public nsImageGeometryMixin<nsDisplayFilterGeometry> +{ +public: + nsDisplayFilterGeometry(nsDisplayFilter* aItem, + nsDisplayListBuilder* aBuilder); +}; + +class nsCharClipGeometry : public nsDisplayItemGenericGeometry +{ +public: + nsCharClipGeometry(nsCharClipDisplayItem* aItem, + nsDisplayListBuilder* aBuilder); + + nscoord mVisIStartEdge; + nscoord mVisIEndEdge; +}; + +class nsDisplayTableItemGeometry + : public nsDisplayItemGenericGeometry + , public nsImageGeometryMixin<nsDisplayTableItemGeometry> +{ +public: + nsDisplayTableItemGeometry(nsDisplayTableItem* aItem, + nsDisplayListBuilder* aBuilder, + const nsPoint& aFrameOffsetToViewport); + + nsPoint mFrameOffsetToViewport; +}; + +#endif /*NSDISPLAYLISTINVALIDATION_H_*/ |