blob: e8c258026dea60961bc8e966ca165d1c7cf1d479 [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 DisplayItemList_h
#define DisplayItemList_h
#include "platform/PlatformExport.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/graphics/ContiguousContainer.h"
#include "platform/graphics/paint/DisplayItem.h"
#include "platform/graphics/paint/Transform3DDisplayItem.h"
#include "wtf/Alignment.h"
#include "wtf/HashMap.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/Utility.h"
#include "wtf/Vector.h"
namespace blink {
class GraphicsContext;
// kDisplayItemAlignment must be a multiple of alignof(derived display item) for
// each derived display item; the ideal value is the least common multiple.
// Currently the limiting factor is TransformtionMatrix (in
// BeginTransform3DDisplayItem), which requests 16-byte alignment.
static const size_t kDisplayItemAlignment = WTF_ALIGN_OF(BeginTransform3DDisplayItem);
static const size_t kInitialDisplayItemsCapacity = 64;
static const size_t kMaximumDisplayItemSize = sizeof(BeginTransform3DDisplayItem);
// Map from SimpleLayer.startPoint to the DrawingDisplayItems within its range
// which were invalidated on this frame and do not change SimpleLayers.
using DisplayListDiff = HashMap<DisplayItemClient, DisplayItem*>;
using DisplayItems = ContiguousContainer<DisplayItem, kDisplayItemAlignment>;
class PLATFORM_EXPORT DisplayItemList {
WTF_MAKE_NONCOPYABLE(DisplayItemList);
WTF_MAKE_FAST_ALLOCATED(DisplayItemList);
public:
static PassOwnPtr<DisplayItemList> create()
{
return adoptPtr(new DisplayItemList());
}
// These methods are called during paint invalidation.
void invalidate(const DisplayItemClientWrapper&);
void invalidateUntracked(DisplayItemClient);
void invalidateAll();
// These methods are called during painting.
template <typename DisplayItemClass, typename... Args>
DisplayItemClass& createAndAppend(Args&&... args)
{
static_assert(WTF::IsSubclass<DisplayItemClass, DisplayItem>::value,
"Can only createAndAppend subclasses of DisplayItem.");
static_assert(sizeof(DisplayItemClass) <= kMaximumDisplayItemSize,
"DisplayItem subclass is larger than kMaximumDisplayItemSize.");
DisplayItemClass& displayItem = m_newDisplayItems.allocateAndConstruct<DisplayItemClass>(WTF::forward<Args>(args)...);
processNewItem(&displayItem);
return displayItem;
}
// Scopes must be used to avoid duplicated display item ids when we paint some object
// multiple times and generate multiple display items with the same type.
// We don't cache display items added in scopes.
void beginScope();
void endScope();
// True if the last display item is a begin that doesn't draw content.
bool lastDisplayItemIsNoopBegin() const;
void removeLastDisplayItem();
void beginSkippingCache() { ++m_skippingCacheCount; }
void endSkippingCache() { ASSERT(m_skippingCacheCount > 0); --m_skippingCacheCount; }
bool skippingCache() const { return m_skippingCacheCount; }
// Must be called when a painting is finished. If passed, a DisplayListDiff
// is initialized and created.
void commitNewDisplayItems(DisplayListDiff* = 0);
// Returns the approximate memory usage, excluding memory likely to be
// shared with the embedder after copying to WebDisplayItemList.
// Should only be called right after commitNewDisplayItems.
size_t approximateUnsharedMemoryUsage() const;
// Get the paint list generated after the last painting.
const DisplayItems& displayItems() const;
bool clientCacheIsValid(DisplayItemClient) const;
// Commits the new display items and plays back the updated display items into the given context.
void commitNewDisplayItemsAndReplay(GraphicsContext& context)
{
commitNewDisplayItems();
replay(context);
}
void appendToWebDisplayItemList(WebDisplayItemList*);
void commitNewDisplayItemsAndAppendToWebDisplayItemList(WebDisplayItemList*);
bool displayItemConstructionIsDisabled() const { return m_constructionDisabled; }
void setDisplayItemConstructionIsDisabled(const bool disable) { m_constructionDisabled = disable; }
#if ENABLE(ASSERT)
size_t newDisplayItemsSize() const { return m_newDisplayItems.size(); }
#endif
#ifndef NDEBUG
void showDebugData() const;
#endif
void startTrackingPaintInvalidationObjects()
{
ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
m_trackedPaintInvalidationObjects = adoptPtr(new Vector<String>());
}
void stopTrackingPaintInvalidationObjects()
{
ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
m_trackedPaintInvalidationObjects = nullptr;
}
Vector<String> trackedPaintInvalidationObjects()
{
ASSERT(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
return m_trackedPaintInvalidationObjects ? *m_trackedPaintInvalidationObjects : Vector<String>();
}
protected:
DisplayItemList()
: m_currentDisplayItems(kMaximumDisplayItemSize, 0)
, m_newDisplayItems(kMaximumDisplayItemSize, kInitialDisplayItemsCapacity * kMaximumDisplayItemSize)
, m_validlyCachedClientsDirty(false)
, m_constructionDisabled(false)
, m_skippingCacheCount(0)
, m_numCachedItems(0)
, m_nextScope(1) { }
private:
friend class DisplayItemListTest;
friend class DisplayItemListPaintTest;
friend class DisplayItemListPaintTestForSlimmingPaintV2;
friend class LayoutObjectDrawingRecorderTest;
// Set new item state (scopes, cache skipping, etc) for a new item.
// TODO(pdr): This only passes a pointer to make the patch easier to review. Change to a reference.
void processNewItem(DisplayItem*);
void updateValidlyCachedClientsIfNeeded() const;
#ifndef NDEBUG
WTF::String displayItemsAsDebugString(const DisplayItems&) const;
#endif
// Indices into PaintList of all DrawingDisplayItems and BeginSubsequenceDisplayItems of each client.
// Temporarily used during merge to find out-of-order display items.
using DisplayItemIndicesByClientMap = HashMap<DisplayItemClient, Vector<size_t>>;
static size_t findMatchingItemFromIndex(const DisplayItem::Id&, const DisplayItemIndicesByClientMap&, const DisplayItems&);
static void addItemToIndexIfNeeded(const DisplayItem&, size_t index, DisplayItemIndicesByClientMap&);
struct OutOfOrderIndexContext;
DisplayItems::iterator findOutOfOrderCachedItem(DisplayItems::iterator currentIt, const DisplayItem::Id&, OutOfOrderIndexContext&);
DisplayItems::iterator findOutOfOrderCachedItemForward(DisplayItems::iterator currentIt, const DisplayItem::Id&, OutOfOrderIndexContext&);
void copyCachedSubsequence(DisplayItems::iterator& currentIt, DisplayItems& updatedList);
#if ENABLE(ASSERT)
// The following two methods are for checking under-invalidations
// (when RuntimeEnabledFeatures::slimmingPaintUnderInvalidationCheckingEnabled).
void checkCachedDisplayItemIsUnchanged(const DisplayItem&, DisplayItemIndicesByClientMap&);
void checkNoRemainingCachedDisplayItems();
#endif
void replay(GraphicsContext&);
DisplayItems m_currentDisplayItems;
DisplayItems m_newDisplayItems;
// Contains all clients having valid cached paintings if updated.
// It's lazily updated in updateValidlyCachedClientsIfNeeded().
// FIXME: In the future we can replace this with client-side repaint flags
// to avoid the cost of building and querying the hash table.
mutable HashSet<DisplayItemClient> m_validlyCachedClients;
mutable bool m_validlyCachedClientsDirty;
// Allow display item construction to be disabled to isolate the costs of construction
// in performance metrics.
bool m_constructionDisabled;
int m_skippingCacheCount;
int m_numCachedItems;
unsigned m_nextScope;
Vector<unsigned> m_scopeStack;
#if ENABLE(ASSERT)
// This is used to check duplicated ids during add(). We could also check during
// updatePaintList(), but checking during add() helps developer easily find where
// the duplicated ids are from.
DisplayItemIndicesByClientMap m_newDisplayItemIndicesByClient;
#endif
OwnPtr<Vector<String>> m_trackedPaintInvalidationObjects;
};
} // namespace blink
#endif // DisplayItemList_h