blob: 1615455d7c720edbcaf936084ce820cdfd9d9018 [file] [log] [blame] [edit]
// 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/Assertions.h"
#include "wtf/PassOwnPtr.h"
#ifndef NDEBUG
#include "wtf/text/StringBuilder.h"
#include "wtf/text/WTFString.h"
#endif
namespace blink {
class GraphicsContext;
class WebDisplayItemList;
class PLATFORM_EXPORT DisplayItem {
public:
enum {
// Must be kept in sync with core/paint/PaintPhase.h.
PaintPhaseMax = 12,
};
// 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 {
DrawingFirst,
DrawingPaintPhaseFirst = DrawingFirst,
DrawingPaintPhaseLast = DrawingFirst + PaintPhaseMax,
BoxDecorationBackground,
Caret,
ColumnRules,
DebugRedFill,
DragImage,
SVGImage,
LinkHighlight,
PageOverlay,
PageWidgetDelegateBackgroundFallback,
PopupContainerBorder,
PopupListBoxBackground,
PopupListBoxRow,
PrintedContentBackground,
PrintedContentLineBoundary,
PrintedContentPDFURLRect,
Resizer,
SVGClip,
SVGFilter,
SVGMask,
ScrollbarBackButtonEnd,
ScrollbarBackButtonStart,
ScrollbarBackground,
ScrollbarBackTrack,
ScrollbarCorner,
ScrollbarForwardButtonEnd,
ScrollbarForwardButtonStart,
ScrollbarForwardTrack,
ScrollbarHorizontal, // For ScrollbarThemeMacNonOverlayAPI only.
ScrollbarThumb,
ScrollbarTickmarks,
ScrollbarTrackBackground,
ScrollbarVertical, // For ScrollbarThemeMacNonOverlayAPI only.
SelectionGap,
SelectionTint,
TableCellBackgroundFromContainers,
TableCellBackgroundFromSelfPaintingRow,
// 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.
TableCollapsedBorderUnalignedBase,
TableCollapsedBorderBase = (((TableCollapsedBorderUnalignedBase - 1) >> 4) + 1) << 4,
TableCollapsedBorderLast = TableCollapsedBorderBase + 0x0f,
VideoBitmap,
WebPlugin,
WebFont,
DrawingLast = WebFont,
CachedDrawingFirst,
CachedDrawingLast = CachedDrawingFirst + DrawingLast - DrawingFirst,
ClipFirst,
ClipBoxPaintPhaseFirst = ClipFirst,
ClipBoxPaintPhaseLast = ClipBoxPaintPhaseFirst + PaintPhaseMax,
ClipColumnBoundsPaintPhaseFirst,
ClipColumnBoundsPaintPhaseLast = ClipColumnBoundsPaintPhaseFirst + PaintPhaseMax,
ClipLayerFragmentPaintPhaseFirst,
ClipLayerFragmentPaintPhaseLast = ClipLayerFragmentPaintPhaseFirst + PaintPhaseMax,
ClipFileUploadControlRect,
ClipFrameToVisibleContentRect,
ClipFrameScrollbars,
ClipLayerBackground,
ClipLayerColumnBounds,
ClipLayerFilter,
ClipLayerForeground,
ClipLayerParent,
ClipLayerOverflowControls,
ClipNodeImage,
ClipPopupListBoxFrame,
ClipSelectionImage,
PageWidgetDelegateClip,
ClipPrintedPage,
ClipLast = ClipPrintedPage,
EndClipFirst,
EndClipLast = EndClipFirst + ClipLast - ClipFirst,
FloatClipFirst,
FloatClipPaintPhaseFirst = FloatClipFirst,
FloatClipPaintPhaseLast = FloatClipFirst + PaintPhaseMax,
FloatClipLast = FloatClipPaintPhaseLast,
EndFloatClipFirst,
EndFloatClipLast = EndFloatClipFirst + FloatClipLast - FloatClipFirst,
ScrollFirst,
ScrollPaintPhaseFirst = ScrollFirst,
ScrollPaintPhaseLast = ScrollPaintPhaseFirst + PaintPhaseMax,
ScrollLast = ScrollPaintPhaseLast,
EndScrollFirst,
EndScrollLast = EndScrollFirst + ScrollLast - ScrollFirst,
Transform3DFirst,
Transform3DElementTransform = Transform3DFirst,
Transform3DLast = Transform3DElementTransform,
EndTransform3DFirst,
EndTransform3DLast = EndTransform3DFirst + Transform3DLast - Transform3DFirst,
BeginFilter,
EndFilter,
BeginCompositing,
EndCompositing,
BeginTransform,
EndTransform,
BeginClipPath,
EndClipPath,
BeginFixedPosition,
EndFixedPosition,
BeginFixedPositionContainer,
EndFixedPositionContainer,
BeginSubsequence,
EndSubsequence,
CachedSubsequence,
UninitializedType,
TypeLast = UninitializedType
};
static_assert(TableCollapsedBorderBase >= TableCollapsedBorderUnalignedBase, "TableCollapsedBorder types overlap with other types");
static_assert((TableCollapsedBorderBase & 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 TableCollspaedBorderSides {
TableCollapsedBorderTop = 1 << 0,
TableCollapsedBorderRight = 1 << 1,
TableCollapsedBorderBottom = 1 << 2,
TableCollapsedBorderLeft = 1 << 3,
};
DisplayItem(const DisplayItemClientWrapper& client, Type type, size_t derivedSize)
: m_client(client.displayItemClient())
, m_scope(0)
, 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 {
Id(const DisplayItemClient client, const Type type, const unsigned scope)
: client(client)
, type(type)
, scope(scope) { }
bool matches(const DisplayItem& item) const
{
// We should always convert to non-cached types before matching.
ASSERT(!isCachedType(item.m_type));
ASSERT(!isCachedType(type));
return client == item.m_client
&& type == item.m_type
&& scope == item.m_scope;
}
const DisplayItemClient client;
const Type type;
const unsigned scope;
};
// Convert cached type to non-cached type (e.g., Type::CachedSVGImage -> Type::SVGImage).
static Type nonCachedType(Type type)
{
if (isCachedDrawingType(type))
return cachedDrawingTypeToDrawingType(type);
if (type == CachedSubsequence)
return BeginSubsequence;
return type;
}
// Return the Id with cached type converted to non-cached type.
Id nonCachedId() const
{
return Id(m_client, nonCachedType(m_type), m_scope);
}
virtual void replay(GraphicsContext&) { }
DisplayItemClient client() const { return m_client; }
Type type() const { return m_type; }
void setScope(unsigned scope) { m_scope = scope; }
unsigned scope() { return m_scope; }
// 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 DisplayItemList only. Painters should use DisplayItemCacheSkipper instead.
void setSkippedCache() { m_skippedCache = true; }
bool skippedCache() const { return m_skippedCache; }
virtual void appendToWebDisplayItemList(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 >= Category##First && type <= Category##Last; } \
bool is##Category() const { return is##Category##Type(type()); }
#define DEFINE_CONVERSION_METHODS(Category1, category1, Category2, category2) \
static Type category1##TypeTo##Category2##Type(Type type) \
{ \
static_assert(Category1##Last - Category1##First == Category2##Last - 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 - Category1##First + Category2##First); \
} \
static Type category2##TypeTo##Category1##Type(Type type) \
{ \
ASSERT(is##Category2##Type(type)); \
return static_cast<Type>(type - Category2##First + 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(Category##PaintPhaseLast - Category##PaintPhaseFirst == PaintPhaseMax, \
"Invalid paint-phase-based category " #Category ". See comments of DisplayItem::Type"); \
return static_cast<Type>(paintPhase + Category##PaintPhaseFirst); \
}
DEFINE_CATEGORY_METHODS(Drawing)
DEFINE_PAINT_PHASE_CONVERSION_METHOD(Drawing)
DEFINE_CATEGORY_METHODS(CachedDrawing)
DEFINE_CONVERSION_METHODS(Drawing, drawing, CachedDrawing, cachedDrawing)
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 isCachedType(Type type) { return isCachedDrawingType(type) || type == CachedSubsequence; }
bool isCached() const { return isCachedType(m_type); }
static bool isCacheableType(Type type) { return isDrawingType(type) || type == BeginSubsequence; }
bool isCacheable() const { return !skippedCache() && isCacheableType(m_type); }
virtual bool isBegin() const { return false; }
virtual bool isEnd() const { return false; }
#if ENABLE(ASSERT)
virtual bool isEndAndPairedWith(DisplayItem::Type otherType) const { return false; }
virtual bool equals(const DisplayItem& other) const
{
return m_client == other.m_client
&& m_scope == other.m_scope
&& m_type == other.m_type
&& m_derivedSize == other.m_derivedSize
&& m_skippedCache == other.m_skippedCache;
}
#endif
virtual bool drawsContent() const { return false; }
bool isValid() const { return m_client; }
#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_scope(0)
, m_type(UninitializedType)
, m_derivedSize(sizeof(*this))
, m_skippedCache(false)
{ }
const DisplayItemClient m_client;
unsigned m_scope;
static_assert(TypeLast < (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
};
class PLATFORM_EXPORT PairedBeginDisplayItem : public DisplayItem {
protected:
PairedBeginDisplayItem(const DisplayItemClientWrapper& 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 DisplayItemClientWrapper& 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