| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef DisplayItem_h |
| #define DisplayItem_h |
| |
| #include "platform/PlatformExport.h" |
| #include "platform/graphics/ContiguousContainer.h" |
| #include "platform/graphics/paint/DisplayItemClient.h" |
| #include "platform/runtime_enabled_features.h" |
| #include "platform/wtf/Allocator.h" |
| #include "platform/wtf/Assertions.h" |
| #include "platform/wtf/Noncopyable.h" |
| |
| #if DCHECK_IS_ON() |
| #include "platform/json/JSONValues.h" |
| #include "platform/wtf/text/WTFString.h" |
| #endif |
| |
| namespace blink { |
| |
| class GraphicsContext; |
| class LayoutSize; |
| enum class PaintPhase; |
| class WebDisplayItemList; |
| |
| class PLATFORM_EXPORT DisplayItem { |
| DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); |
| |
| public: |
| enum { |
| // Must be kept in sync with core/paint/PaintPhase.h. |
| kPaintPhaseMax = 11, |
| }; |
| |
| // A display item type uniquely identifies a display item of a client. |
| // Some display item types can be categorized using the following directives: |
| // - In enum Type: |
| // - enum value <Category>First; |
| // - enum values of the category, first of which should equal |
| // <Category>First (for ease of maintenance, the values should be in |
| // alphabetic order); |
| // - enum value <Category>Last which should be equal to the last of the enum |
| // values of the category |
| // - DEFINE_CATEGORY_METHODS(<Category>) to define is<Category>Type(Type) and |
| // is<Category>() methods. |
| // |
| // A category or subset of a category can contain types each of which |
| // corresponds to a PaintPhase: |
| // - In enum Type: |
| // - enum value <Category>[<Subset>]PaintPhaseFirst; |
| // - enum value <Category>[<Subset>]PaintPhaseLast = |
| // <Category>[<Subset>]PaintPhaseFirst + PaintPhaseMax; |
| // - DEFINE_PAINT_PHASE_CONVERSION_METHOD(<Category>[<Subset>]) to define |
| // paintPhaseTo<Category>[<Subset>]Type(PaintPhase) method. |
| // |
| // A category can be derived from another category, containing types each of |
| // which corresponds to a value of the latter category: |
| // - In enum Type: |
| // - enum value <Category>First; |
| // - enum value <Category>Last = |
| // <Category>First + <BaseCategory>Last - <BaseCategory>First; |
| // - DEFINE_CONVERSION_METHODS(<Category>, |
| // <category>, |
| // <BaseCategory>, |
| // <baseCategory>) |
| // to define methods to convert types between the categories. |
| enum Type { |
| kDrawingFirst, |
| kDrawingPaintPhaseFirst = kDrawingFirst, |
| kDrawingPaintPhaseLast = kDrawingFirst + kPaintPhaseMax, |
| kBoxDecorationBackground, |
| kCaret, |
| kColumnRules, |
| kDebugDrawing, |
| kDocumentBackground, |
| kDragImage, |
| kDragCaret, |
| kEmptyContentForFilters, |
| kSVGImage, |
| kLinkHighlight, |
| kImageAreaFocusRing, |
| kPageOverlay, |
| kPageWidgetDelegateBackgroundFallback, |
| kPopupContainerBorder, |
| kPopupListBoxBackground, |
| kPopupListBoxRow, |
| kPrintedContentDestinationLocations, |
| kPrintedContentPDFURLRect, |
| kResizer, |
| kSVGClip, |
| kSVGFilter, |
| kSVGMask, |
| kScrollbarBackButtonEnd, |
| kScrollbarBackButtonStart, |
| kScrollbarBackground, |
| kScrollbarBackTrack, |
| kScrollbarCorner, |
| kScrollbarForwardButtonEnd, |
| kScrollbarForwardButtonStart, |
| kScrollbarForwardTrack, |
| kScrollbarThumb, |
| kScrollbarTickmarks, |
| kScrollbarTrackBackground, |
| kScrollbarCompositedScrollbar, |
| kSelectionTint, |
| kTableCollapsedBorders, |
| kVideoBitmap, |
| kWebPlugin, |
| kWebFont, |
| kReflectionMask, |
| kDrawingLast = kReflectionMask, |
| |
| kForeignLayerFirst, |
| kForeignLayerCanvas = kForeignLayerFirst, |
| kForeignLayerPlugin, |
| kForeignLayerVideo, |
| kForeignLayerLast = kForeignLayerVideo, |
| |
| kClipFirst, |
| kClipBoxPaintPhaseFirst = kClipFirst, |
| kClipBoxPaintPhaseLast = kClipBoxPaintPhaseFirst + kPaintPhaseMax, |
| kClipColumnBoundsPaintPhaseFirst, |
| kClipColumnBoundsPaintPhaseLast = |
| kClipColumnBoundsPaintPhaseFirst + kPaintPhaseMax, |
| kClipLayerFragmentPaintPhaseFirst, |
| kClipLayerFragmentPaintPhaseLast = |
| kClipLayerFragmentPaintPhaseFirst + kPaintPhaseMax, |
| kClipFileUploadControlRect, |
| kClipFrameToVisibleContentRect, |
| kClipFrameScrollbars, |
| kClipLayerBackground, |
| kClipLayerColumnBounds, |
| kClipLayerFilter, |
| kClipLayerForeground, |
| kClipLayerParent, |
| kClipLayerOverflowControls, |
| kClipPopupListBoxFrame, |
| kClipScrollbarsToBoxBounds, |
| kClipSelectionImage, |
| kPageWidgetDelegateClip, |
| kClipLast = kPageWidgetDelegateClip, |
| |
| kEndClipFirst, |
| kEndClipLast = kEndClipFirst + kClipLast - kClipFirst, |
| |
| kFloatClipFirst, |
| kFloatClipPaintPhaseFirst = kFloatClipFirst, |
| kFloatClipPaintPhaseLast = kFloatClipFirst + kPaintPhaseMax, |
| kFloatClipClipPathBounds, |
| kFloatClipLast = kFloatClipClipPathBounds, |
| kEndFloatClipFirst, |
| kEndFloatClipLast = kEndFloatClipFirst + kFloatClipLast - kFloatClipFirst, |
| |
| kScrollFirst, |
| kScrollPaintPhaseFirst = kScrollFirst, |
| kScrollPaintPhaseLast = kScrollPaintPhaseFirst + kPaintPhaseMax, |
| kScrollOverflowControls, |
| kScrollLast = kScrollOverflowControls, |
| kEndScrollFirst, |
| kEndScrollLast = kEndScrollFirst + kScrollLast - kScrollFirst, |
| |
| kSVGTransformPaintPhaseFirst, |
| kSVGTransformPaintPhaseLast = kSVGTransformPaintPhaseFirst + kPaintPhaseMax, |
| |
| kSVGEffectPaintPhaseFirst, |
| kSVGEffectPaintPhaseLast = kSVGEffectPaintPhaseFirst + kPaintPhaseMax, |
| |
| kTransform3DFirst, |
| kTransform3DElementTransform = kTransform3DFirst, |
| kTransform3DLast = kTransform3DElementTransform, |
| kEndTransform3DFirst, |
| kEndTransform3DLast = |
| kEndTransform3DFirst + kTransform3DLast - kTransform3DFirst, |
| |
| kBeginFilter, |
| kEndFilter, |
| kBeginCompositing, |
| kEndCompositing, |
| kBeginTransform, |
| kEndTransform, |
| kBeginClipPath, |
| kEndClipPath, |
| kScrollHitTest, |
| kUninitializedType, |
| kTypeLast = kUninitializedType |
| }; |
| |
| DisplayItem(const DisplayItemClient& client, Type type, size_t derived_size) |
| : client_(&client), |
| visual_rect_(client.VisualRect()), |
| outset_for_raster_effects_(client.VisualRectOutsetForRasterEffects()), |
| type_(type), |
| derived_size_(derived_size), |
| fragment_(0), |
| skipped_cache_(false), |
| is_tombstone_(false) { |
| // |derived_size| must fit in |derived_size_|. |
| // If it doesn't, enlarge |derived_size_| and fix this assert. |
| SECURITY_DCHECK(derived_size < (1 << 8)); |
| SECURITY_DCHECK(derived_size >= sizeof(*this)); |
| } |
| |
| virtual ~DisplayItem() = default; |
| |
| // Ids are for matching new DisplayItems with existing DisplayItems. |
| struct Id { |
| DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); |
| Id(const DisplayItemClient& client, const Type type, unsigned fragment = 0) |
| : client(client), type(type), fragment(fragment) {} |
| Id(const Id& id, unsigned fragment) |
| : client(id.client), type(id.type), fragment(fragment) {} |
| |
| String ToString() const; |
| |
| const DisplayItemClient& client; |
| const Type type; |
| const unsigned fragment; |
| }; |
| |
| Id GetId() const { return Id(*client_, GetType(), fragment_); } |
| |
| virtual void Replay(GraphicsContext&) const {} |
| |
| const DisplayItemClient& Client() const { |
| DCHECK(client_); |
| return *client_; |
| } |
| |
| // This equals to Client().VisualRect() as long as the client is alive and is |
| // not invalidated. Otherwise it saves the previous visual rect of the client. |
| // See DisplayItemClient::VisualRect() about its coordinate space. |
| const LayoutRect& VisualRect() const { return visual_rect_; } |
| LayoutUnit OutsetForRasterEffects() const { |
| return outset_for_raster_effects_; |
| } |
| |
| // Visual rect can change without needing invalidation of the client, e.g. |
| // when ancestor clip changes. This is called from PaintController:: |
| // UseCachedDrawingIfPossible() to update the visual rect of a cached display |
| // item. |
| void UpdateVisualRect() { visual_rect_ = client_->VisualRect(); } |
| |
| Type GetType() const { return static_cast<Type>(type_); } |
| |
| // Size of this object in memory, used to move it with memcpy. |
| // This is not sizeof(*this), because it needs to account for the size of |
| // the derived class (i.e. runtime type). Derived classes are expected to |
| // supply this to the DisplayItem constructor. |
| size_t DerivedSize() const { return derived_size_; } |
| |
| // The fragment is part of the id, to uniquely identify display items in |
| // different fragments for the same client and type. |
| unsigned Fragment() const { return fragment_; } |
| void SetFragment(unsigned fragment) { |
| DCHECK(fragment < (1 << 14)); |
| fragment_ = fragment; |
| } |
| |
| // For PaintController only. Painters should use DisplayItemCacheSkipper |
| // instead. |
| void SetSkippedCache() { skipped_cache_ = true; } |
| bool SkippedCache() const { return skipped_cache_; } |
| |
| // Appends this display item to the WebDisplayItemList, if applicable. |
| // |visual_rect_offset| is the offset between the space of the GraphicsLayer |
| // which owns the display item and the coordinate space of VisualRect(). |
| // TODO(wangxianzhu): Remove the parameter for slimming paint v2. |
| virtual void AppendToWebDisplayItemList(const LayoutSize& visual_rect_offset, |
| WebDisplayItemList*) const {} |
| |
| // See comments of enum Type for usage of the following macros. |
| #define DEFINE_CATEGORY_METHODS(Category) \ |
| static bool Is##Category##Type(Type type) { \ |
| return type >= k##Category##First && type <= k##Category##Last; \ |
| } \ |
| bool Is##Category() const { return Is##Category##Type(GetType()); } |
| |
| #define DEFINE_CONVERSION_METHODS(Category1, category1, Category2, category2) \ |
| static Type Category1##TypeTo##Category2##Type(Type type) { \ |
| static_assert(k##Category1##Last - k##Category1##First == \ |
| k##Category2##Last - k##Category2##First, \ |
| "Categories " #Category1 " and " #Category2 \ |
| " should have same number of enum values. See comments of " \ |
| "DisplayItem::Type"); \ |
| DCHECK(Is##Category1##Type(type)); \ |
| return static_cast<Type>(type - k##Category1##First + \ |
| k##Category2##First); \ |
| } \ |
| static Type category2##TypeTo##Category1##Type(Type type) { \ |
| DCHECK(Is##Category2##Type(type)); \ |
| return static_cast<Type>(type - k##Category2##First + \ |
| k##Category1##First); \ |
| } |
| |
| #define DEFINE_PAIRED_CATEGORY_METHODS(Category, category) \ |
| DEFINE_CATEGORY_METHODS(Category) \ |
| DEFINE_CATEGORY_METHODS(End##Category) \ |
| DEFINE_CONVERSION_METHODS(Category, category, End##Category, end##Category) |
| |
| #define DEFINE_PAINT_PHASE_CONVERSION_METHOD(Category) \ |
| static Type PaintPhaseTo##Category##Type(PaintPhase paint_phase) { \ |
| static_assert( \ |
| k##Category##PaintPhaseLast - k##Category##PaintPhaseFirst == \ |
| kPaintPhaseMax, \ |
| "Invalid paint-phase-based category " #Category \ |
| ". See comments of DisplayItem::Type"); \ |
| return static_cast<Type>(static_cast<int>(paint_phase) + \ |
| k##Category##PaintPhaseFirst); \ |
| } |
| |
| DEFINE_CATEGORY_METHODS(Drawing) |
| DEFINE_PAINT_PHASE_CONVERSION_METHOD(Drawing) |
| |
| DEFINE_CATEGORY_METHODS(ForeignLayer) |
| |
| DEFINE_PAIRED_CATEGORY_METHODS(Clip, clip) |
| DEFINE_PAINT_PHASE_CONVERSION_METHOD(ClipLayerFragment) |
| DEFINE_PAINT_PHASE_CONVERSION_METHOD(ClipBox) |
| DEFINE_PAINT_PHASE_CONVERSION_METHOD(ClipColumnBounds) |
| |
| DEFINE_PAIRED_CATEGORY_METHODS(FloatClip, floatClip) |
| DEFINE_PAINT_PHASE_CONVERSION_METHOD(FloatClip) |
| |
| DEFINE_PAIRED_CATEGORY_METHODS(Scroll, scroll) |
| DEFINE_PAINT_PHASE_CONVERSION_METHOD(Scroll) |
| |
| DEFINE_PAINT_PHASE_CONVERSION_METHOD(SVGTransform) |
| DEFINE_PAINT_PHASE_CONVERSION_METHOD(SVGEffect) |
| |
| DEFINE_PAIRED_CATEGORY_METHODS(Transform3D, transform3D) |
| |
| static bool IsScrollHitTestType(Type type) { return type == kScrollHitTest; } |
| bool IsScrollHitTest() const { return IsScrollHitTestType(GetType()); } |
| |
| // TODO(pdr): Should this return true for IsScrollHitTestType too? |
| static bool IsCacheableType(Type type) { return IsDrawingType(type); } |
| bool IsCacheable() const { |
| return !SkippedCache() && IsCacheableType(GetType()); |
| } |
| |
| virtual bool IsBegin() const { return false; } |
| virtual bool IsEnd() const { return false; } |
| |
| #if DCHECK_IS_ON() |
| virtual bool IsEndAndPairedWith(DisplayItem::Type other_type) const { |
| return false; |
| } |
| #endif |
| |
| virtual bool Equals(const DisplayItem& other) const { |
| // Failure of this DCHECK would cause bad casts in subclasses. |
| SECURITY_CHECK(!is_tombstone_); |
| return client_ == other.client_ && type_ == other.type_ && |
| fragment_ == other.fragment_ && |
| derived_size_ == other.derived_size_ && |
| skipped_cache_ == other.skipped_cache_; |
| } |
| |
| // True if this DisplayItem is the tombstone/"dead display item" as part of |
| // moving an item from one list to another. See the default constructor of |
| // DisplayItem. |
| bool IsTombstone() const { return is_tombstone_; } |
| |
| virtual bool DrawsContent() const { return false; } |
| |
| #if DCHECK_IS_ON() |
| static WTF::String TypeAsDebugString(DisplayItem::Type); |
| WTF::String AsDebugString() const; |
| virtual void PropertiesAsJSON(JSONObject&) const; |
| #endif |
| |
| private: |
| template <typename T, unsigned alignment> |
| friend class ContiguousContainer; |
| friend class DisplayItemList; |
| |
| // The default DisplayItem constructor is only used by ContiguousContainer:: |
| // AppendByMoving() where a tombstone DisplayItem is constructed at the source |
| // location. Only set is_tombstone_ to true, leaving other fields as-is so |
| // that we can get their original values for debugging. |visual_rect_| and |
| // |outset_for_raster_effects_| are special, see DisplayItemList:: |
| // AppendByMoving(). |
| DisplayItem() : is_tombstone_(true) {} |
| |
| const DisplayItemClient* client_; |
| LayoutRect visual_rect_; |
| LayoutUnit outset_for_raster_effects_; |
| |
| static_assert(kTypeLast < (1 << 8), "DisplayItem::Type should fit in 8 bits"); |
| unsigned type_ : 8; |
| unsigned derived_size_ : 8; // size of the actual derived class |
| unsigned fragment_ : 14; |
| unsigned skipped_cache_ : 1; |
| unsigned is_tombstone_ : 1; |
| }; |
| |
| inline bool operator==(const DisplayItem::Id& a, const DisplayItem::Id& b) { |
| return a.client == b.client && a.type == b.type && a.fragment == b.fragment; |
| } |
| |
| inline bool operator!=(const DisplayItem::Id& a, const DisplayItem::Id& b) { |
| return !(a == b); |
| } |
| |
| class PLATFORM_EXPORT PairedBeginDisplayItem : public DisplayItem { |
| protected: |
| PairedBeginDisplayItem(const DisplayItemClient& client, |
| Type type, |
| size_t derived_size) |
| : DisplayItem(client, type, derived_size) { |
| DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()); |
| } |
| |
| private: |
| bool IsBegin() const final { return true; } |
| }; |
| |
| class PLATFORM_EXPORT PairedEndDisplayItem : public DisplayItem { |
| protected: |
| PairedEndDisplayItem(const DisplayItemClient& client, |
| Type type, |
| size_t derived_size) |
| : DisplayItem(client, type, derived_size) { |
| DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()); |
| } |
| |
| #if DCHECK_IS_ON() |
| bool IsEndAndPairedWith(DisplayItem::Type other_type) const override = 0; |
| #endif |
| |
| private: |
| bool IsEnd() const final { return true; } |
| }; |
| |
| } // namespace blink |
| |
| #endif // DisplayItem_h |