blob: cb7af888ee1d12930b3b77f5b4d33c9c1a91811b [file] [log] [blame]
// 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 "wtf/Allocator.h"
#include "wtf/Assertions.h"
#include "wtf/Noncopyable.h"
#ifndef NDEBUG
#include "wtf/text/StringBuilder.h"
#include "wtf/text/WTFString.h"
#endif
class SkPictureGpuAnalyzer;
namespace blink {
class GraphicsContext;
class IntRect;
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,
kSVGImage,
kLinkHighlight,
kImageAreaFocusRing,
kPageOverlay,
kPageWidgetDelegateBackgroundFallback,
kPopupContainerBorder,
kPopupListBoxBackground,
kPopupListBoxRow,
kPrintedContentBackground,
kPrintedContentDestinationLocations,
kPrintedContentLineBoundary,
kPrintedContentPDFURLRect,
kResizer,
kSVGClip,
kSVGFilter,
kSVGMask,
kScrollbarBackButtonEnd,
kScrollbarBackButtonStart,
kScrollbarBackground,
kScrollbarBackTrack,
kScrollbarCorner,
kScrollbarForwardButtonEnd,
kScrollbarForwardButtonStart,
kScrollbarForwardTrack,
kScrollbarThumb,
kScrollbarTickmarks,
kScrollbarTrackBackground,
kScrollbarCompositedScrollbar,
kSelectionTint,
kTableCellBackgroundFromColumnGroup,
kTableCellBackgroundFromColumn,
kTableCellBackgroundFromSection,
kTableCellBackgroundFromRow,
// Table collapsed borders can be painted together (e.g., left & top) but
// there are at most 4 phases of collapsed border painting for a single
// cell. To disambiguate these phases of collapsed border painting, a mask
// is used. TableCollapsedBorderBase can be larger than
// TableCollapsedBorderUnalignedBase to ensure the base lower bits are 0's.
kTableCollapsedBorderUnalignedBase,
kTableCollapsedBorderBase =
(((kTableCollapsedBorderUnalignedBase - 1) >> 4) + 1) << 4,
kTableCollapsedBorderLast = kTableCollapsedBorderBase + 0x0f,
kTableSectionBoxShadowInset,
kTableSectionBoxShadowNormal,
kTableRowBoxShadowInset,
kTableRowBoxShadowNormal,
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,
kClipNodeImage,
kClipPopupListBoxFrame,
kClipScrollbarsToBoxBounds,
kClipSelectionImage,
kPageWidgetDelegateClip,
kClipPrintedPage,
kClipLast = kClipPrintedPage,
kEndClipFirst,
kEndClipLast = kEndClipFirst + kClipLast - kClipFirst,
kFloatClipFirst,
kFloatClipPaintPhaseFirst = kFloatClipFirst,
kFloatClipPaintPhaseLast = kFloatClipFirst + kPaintPhaseMax,
kFloatClipLast = kFloatClipPaintPhaseLast,
kEndFloatClipFirst,
kEndFloatClipLast = kEndFloatClipFirst + kFloatClipLast - kFloatClipFirst,
kScrollFirst,
kScrollPaintPhaseFirst = kScrollFirst,
kScrollPaintPhaseLast = kScrollPaintPhaseFirst + kPaintPhaseMax,
kScrollOverflowControls,
kScrollLast = kScrollOverflowControls,
kEndScrollFirst,
kEndScrollLast = kEndScrollFirst + kScrollLast - kScrollFirst,
kTransform3DFirst,
kTransform3DElementTransform = kTransform3DFirst,
kTransform3DLast = kTransform3DElementTransform,
kEndTransform3DFirst,
kEndTransform3DLast =
kEndTransform3DFirst + kTransform3DLast - kTransform3DFirst,
kBeginFilter,
kEndFilter,
kBeginCompositing,
kEndCompositing,
kBeginTransform,
kEndTransform,
kBeginClipPath,
kEndClipPath,
kSubsequence,
kEndSubsequence,
kUninitializedType,
kTypeLast = kUninitializedType
};
static_assert(kTableCollapsedBorderBase >= kTableCollapsedBorderUnalignedBase,
"TableCollapsedBorder types overlap with other types");
static_assert((kTableCollapsedBorderBase & 0xf) == 0,
"The lowest 4 bits of TableCollapsedBorderBase should be zero");
// Bits or'ed onto TableCollapsedBorderBase to generate a real table collapsed
// border type.
enum TableCollapsedBorderSides {
TableCollapsedBorderTop = 1 << 0,
TableCollapsedBorderRight = 1 << 1,
TableCollapsedBorderBottom = 1 << 2,
TableCollapsedBorderLeft = 1 << 3,
};
DisplayItem(const DisplayItemClient& client, Type type, size_t derivedSize)
: m_client(&client),
m_type(type),
m_derivedSize(derivedSize),
m_skippedCache(false)
#ifndef NDEBUG
,
m_clientDebugString(client.debugName())
#endif
{
// derivedSize must fit in m_derivedSize.
// If it doesn't, enlarge m_derivedSize and fix this assert.
ASSERT_WITH_SECURITY_IMPLICATION(derivedSize < (1 << 8));
ASSERT_WITH_SECURITY_IMPLICATION(derivedSize >= sizeof(*this));
}
virtual ~DisplayItem() {}
// Ids are for matching new DisplayItems with existing DisplayItems.
struct Id {
DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
Id(const DisplayItemClient& client, const Type type)
: client(client), type(type) {}
const DisplayItemClient& client;
const Type type;
};
Id getId() const { return Id(*m_client, m_type); }
virtual void replay(GraphicsContext&) const {}
const DisplayItemClient& client() const {
ASSERT(m_client);
return *m_client;
}
Type getType() const { return m_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 m_derivedSize; }
// For PaintController only. Painters should use DisplayItemCacheSkipper
// instead.
void setSkippedCache() { m_skippedCache = true; }
bool skippedCache() const { return m_skippedCache; }
// TODO(wkorman): Only DrawingDisplayItem needs the visual rect argument.
// Consider refactoring class hierarchy to make this more explicit.
virtual void appendToWebDisplayItemList(const IntRect&,
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"); \
ASSERT(is##Category1##Type(type)); \
return static_cast<Type>(type - k##Category1##First + \
k##Category2##First); \
} \
static Type category2##TypeTo##Category1##Type(Type type) { \
ASSERT(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(int paintPhase) { \
static_assert( \
k##Category##PaintPhaseLast - k##Category##PaintPhaseFirst == \
k##PaintPhaseMax, \
"Invalid paint-phase-based category " #Category \
". See comments of DisplayItem::Type"); \
return static_cast<Type>(paintPhase + 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_PAIRED_CATEGORY_METHODS(Transform3D, transform3D)
static bool isCacheableType(Type type) {
return isDrawingType(type) || type == kSubsequence;
}
bool isCacheable() const {
return !skippedCache() && isCacheableType(m_type);
}
virtual bool isBegin() const { return false; }
virtual bool isEnd() const { return false; }
#if DCHECK_IS_ON()
virtual bool isEndAndPairedWith(DisplayItem::Type otherType) const {
return false;
}
#endif
virtual bool equals(const DisplayItem& other) const {
return m_client == other.m_client && m_type == other.m_type &&
m_derivedSize == other.m_derivedSize &&
m_skippedCache == other.m_skippedCache;
}
// True if the client is non-null. Because m_client is const, this should
// never be false except when we explicitly create a tombstone/"dead display
// item" as part of moving an item from one list to another (see:
// DisplayItemList::appendByMoving).
bool hasValidClient() const { return m_client; }
virtual bool drawsContent() const { return false; }
// Override to implement specific analysis strategies.
virtual void analyzeForGpuRasterization(SkPictureGpuAnalyzer&) const {}
#ifndef NDEBUG
static WTF::String typeAsDebugString(DisplayItem::Type);
const WTF::String clientDebugString() const { return m_clientDebugString; }
void setClientDebugString(const WTF::String& s) { m_clientDebugString = s; }
WTF::String asDebugString() const;
virtual void dumpPropertiesAsDebugString(WTF::StringBuilder&) const;
#endif
private:
// The default DisplayItem constructor is only used by
// ContiguousContainer::appendByMoving where an invalid DisplaItem is
// constructed at the source location.
template <typename T, unsigned alignment>
friend class ContiguousContainer;
DisplayItem()
: m_client(nullptr),
m_type(kUninitializedType),
m_derivedSize(sizeof(*this)),
m_skippedCache(false) {}
const DisplayItemClient* m_client;
static_assert(kTypeLast < (1 << 16),
"DisplayItem::Type should fit in 16 bits");
const Type m_type : 16;
const unsigned m_derivedSize : 8; // size of the actual derived class
unsigned m_skippedCache : 1;
#ifndef NDEBUG
WTF::String m_clientDebugString;
#endif
};
inline bool operator==(const DisplayItem::Id& a, const DisplayItem::Id& b) {
return a.client == b.client && a.type == b.type;
}
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 derivedSize)
: DisplayItem(client, type, derivedSize) {}
private:
bool isBegin() const final { return true; }
};
class PLATFORM_EXPORT PairedEndDisplayItem : public DisplayItem {
protected:
PairedEndDisplayItem(const DisplayItemClient& client,
Type type,
size_t derivedSize)
: DisplayItem(client, type, derivedSize) {}
#if ENABLE(ASSERT)
bool isEndAndPairedWith(DisplayItem::Type otherType) const override = 0;
#endif
private:
bool isEnd() const final { return true; }
};
} // namespace blink
#endif // DisplayItem_h