Commit 139880d7 authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

Let PaintController build PaintArtifact

This prepares for unified PaintController for pre-CompositeAfterPaint
and CompositeAfterPaint. Unified PaintController needs to create
PaintChunkSubset for the painting of a pre-composited layer
(GraphicsLayer) which needs to hold a reference to the PaintArtifact.

Bug: 1132717
Change-Id: I9ec46fdda2eb6ad1d755f2d9f20a0d081db26973
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2447121
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#814501}
parent d8ed49a5
...@@ -179,10 +179,13 @@ class TestChunks { ...@@ -179,10 +179,13 @@ class TestChunks {
const EffectPaintPropertyNodeOrAlias& e, const EffectPaintPropertyNodeOrAlias& e,
const IntRect& bounds = IntRect(0, 0, 100, 100), const IntRect& bounds = IntRect(0, 0, 100, 100),
const base::Optional<IntRect>& drawable_bounds = base::nullopt) { const base::Optional<IntRect>& drawable_bounds = base::nullopt) {
auto& items = paint_artifact_->GetDisplayItemList();
auto i = items.size(); auto i = items.size();
items.AllocateAndConstruct<DrawingDisplayItem>( items.AllocateAndConstruct<DrawingDisplayItem>(
DefaultId().client, DefaultId().type, DefaultId().client, DefaultId().type,
drawable_bounds ? *drawable_bounds : bounds, std::move(record)); drawable_bounds ? *drawable_bounds : bounds, std::move(record));
auto& chunks = paint_artifact_->PaintChunks();
chunks.emplace_back(i, i + 1, DefaultId(), chunks.emplace_back(i, i + 1, DefaultId(),
PropertyTreeStateOrAlias(t, c, e)); PropertyTreeStateOrAlias(t, c, e));
chunks.back().bounds = bounds; chunks.back().bounds = bounds;
...@@ -193,19 +196,19 @@ class TestChunks { ...@@ -193,19 +196,19 @@ class TestChunks {
const ClipPaintPropertyNode& c, const ClipPaintPropertyNode& c,
const EffectPaintPropertyNode& e, const EffectPaintPropertyNode& e,
const IntRect& bounds = IntRect(0, 0, 100, 100)) { const IntRect& bounds = IntRect(0, 0, 100, 100)) {
auto i = items.size(); auto& chunks = paint_artifact_->PaintChunks();
auto i = paint_artifact_->GetDisplayItemList().size();
chunks.emplace_back(i, i, DefaultId(), PropertyTreeState(t, c, e)); chunks.emplace_back(i, i, DefaultId(), PropertyTreeState(t, c, e));
chunks.back().bounds = bounds; chunks.back().bounds = bounds;
} }
PaintChunkSubset Build() { PaintChunkSubset Build() {
return PaintChunkSubset(base::MakeRefCounted<PaintArtifact>( return PaintChunkSubset(std::move(paint_artifact_));
std::move(items), std::move(chunks)));
} }
private: private:
Vector<PaintChunk> chunks; scoped_refptr<PaintArtifact> paint_artifact_ =
DisplayItemList items; base::MakeRefCounted<PaintArtifact>();
}; };
TEST_P(PaintChunksToCcLayerTest, EffectGroupingSimple) { TEST_P(PaintChunksToCcLayerTest, EffectGroupingSimple) {
......
...@@ -12,12 +12,6 @@ ...@@ -12,12 +12,6 @@
namespace blink { namespace blink {
#if DCHECK_IS_ON()
static bool g_list_modification_check_disabled = false;
DisableListModificationCheck::DisableListModificationCheck()
: disabler_(&g_list_modification_check_disabled, true) {}
#endif
DrawingRecorder::DrawingRecorder(GraphicsContext& context, DrawingRecorder::DrawingRecorder(GraphicsContext& context,
const DisplayItemClient& display_item_client, const DisplayItemClient& display_item_client,
DisplayItem::Type display_item_type, DisplayItem::Type display_item_type,
...@@ -44,11 +38,6 @@ DrawingRecorder::DrawingRecorder(GraphicsContext& context, ...@@ -44,11 +38,6 @@ DrawingRecorder::DrawingRecorder(GraphicsContext& context,
context.SetDOMNodeId(dom_node_id); context.SetDOMNodeId(dom_node_id);
} }
} }
#if DCHECK_IS_ON()
initial_display_item_list_size_ =
context_.GetPaintController().NewDisplayItemList().size();
#endif
} }
DrawingRecorder::~DrawingRecorder() { DrawingRecorder::~DrawingRecorder() {
...@@ -57,13 +46,6 @@ DrawingRecorder::~DrawingRecorder() { ...@@ -57,13 +46,6 @@ DrawingRecorder::~DrawingRecorder() {
context_.SetInDrawingRecorder(false); context_.SetInDrawingRecorder(false);
#if DCHECK_IS_ON()
if (!g_list_modification_check_disabled) {
DCHECK(initial_display_item_list_size_ ==
context_.GetPaintController().NewDisplayItemList().size());
}
#endif
context_.GetPaintController().CreateAndAppend<DrawingDisplayItem>( context_.GetPaintController().CreateAndAppend<DrawingDisplayItem>(
client_, type_, visual_rect_, context_.EndRecording()); client_, type_, visual_rect_, context_.EndRecording());
} }
......
...@@ -84,11 +84,6 @@ class PLATFORM_EXPORT DrawingRecorder { ...@@ -84,11 +84,6 @@ class PLATFORM_EXPORT DrawingRecorder {
IntRect visual_rect_; IntRect visual_rect_;
base::Optional<DOMNodeId> dom_node_id_to_restore_; base::Optional<DOMNodeId> dom_node_id_to_restore_;
#if DCHECK_IS_ON()
// Ensures the list size does not change during the recorder's scope.
wtf_size_t initial_display_item_list_size_;
#endif
DISALLOW_COPY_AND_ASSIGN(DrawingRecorder); DISALLOW_COPY_AND_ASSIGN(DrawingRecorder);
}; };
......
...@@ -14,13 +14,6 @@ ...@@ -14,13 +14,6 @@
namespace blink { namespace blink {
PaintArtifact::PaintArtifact(DisplayItemList display_items,
Vector<PaintChunk> chunks)
: display_item_list_(std::move(display_items)), chunks_(std::move(chunks)) {
}
PaintArtifact::~PaintArtifact() = default;
size_t PaintArtifact::ApproximateUnsharedMemoryUsage() const { size_t PaintArtifact::ApproximateUnsharedMemoryUsage() const {
size_t total_size = sizeof(*this) + display_item_list_.MemoryUsageInBytes() + size_t total_size = sizeof(*this) + display_item_list_.MemoryUsageInBytes() +
chunks_.capacity() * sizeof(chunks_[0]); chunks_.capacity() * sizeof(chunks_[0]);
......
...@@ -34,9 +34,9 @@ class PLATFORM_EXPORT PaintArtifact final : public RefCounted<PaintArtifact> { ...@@ -34,9 +34,9 @@ class PLATFORM_EXPORT PaintArtifact final : public RefCounted<PaintArtifact> {
USING_FAST_MALLOC(PaintArtifact); USING_FAST_MALLOC(PaintArtifact);
public: public:
PaintArtifact() = default; explicit PaintArtifact(
PaintArtifact(DisplayItemList, Vector<PaintChunk>); wtf_size_t initial_display_item_list_capacity_in_bytes = 0)
~PaintArtifact(); : display_item_list_(initial_display_item_list_capacity_in_bytes) {}
PaintArtifact(const PaintArtifact& other) = delete; PaintArtifact(const PaintArtifact& other) = delete;
PaintArtifact& operator=(const PaintArtifact& other) = delete; PaintArtifact& operator=(const PaintArtifact& other) = delete;
......
...@@ -8,11 +8,18 @@ ...@@ -8,11 +8,18 @@
namespace blink { namespace blink {
PaintChunker::PaintChunker() void PaintChunker::ResetChunks(Vector<PaintChunk>* chunks) {
: current_properties_(PropertyTreeState::Uninitialized()), if (chunks_) {
force_new_chunk_(true) {} FinalizeLastChunkProperties();
SetWillForceNewChunk(true);
PaintChunker::~PaintChunker() = default; current_properties_ = PropertyTreeState::Uninitialized();
}
chunks_ = chunks;
#if DCHECK_IS_ON()
DCHECK(!chunks || chunks->IsEmpty());
DCHECK(IsInInitialState());
#endif
}
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
bool PaintChunker::IsInInitialState() const { bool PaintChunker::IsInInitialState() const {
...@@ -20,7 +27,8 @@ bool PaintChunker::IsInInitialState() const { ...@@ -20,7 +27,8 @@ bool PaintChunker::IsInInitialState() const {
return false; return false;
DCHECK_EQ(candidate_background_color_.Rgb(), Color::kTransparent); DCHECK_EQ(candidate_background_color_.Rgb(), Color::kTransparent);
DCHECK_EQ(candidate_background_area_, 0u); DCHECK_EQ(candidate_background_area_, 0u);
DCHECK(chunks_.IsEmpty()); DCHECK(will_force_new_chunk_);
DCHECK(!chunks_ || chunks_->IsEmpty());
return true; return true;
} }
#endif #endif
...@@ -41,14 +49,16 @@ void PaintChunker::UpdateCurrentPaintChunkProperties( ...@@ -41,14 +49,16 @@ void PaintChunker::UpdateCurrentPaintChunkProperties(
} }
void PaintChunker::AppendByMoving(PaintChunk&& chunk) { void PaintChunker::AppendByMoving(PaintChunk&& chunk) {
DCHECK(chunks_);
FinalizeLastChunkProperties(); FinalizeLastChunkProperties();
wtf_size_t next_chunk_begin_index = wtf_size_t next_chunk_begin_index =
chunks_.IsEmpty() ? 0 : LastChunk().end_index; chunks_->IsEmpty() ? 0 : chunks_->back().end_index;
chunks_.emplace_back(next_chunk_begin_index, std::move(chunk)); chunks_->emplace_back(next_chunk_begin_index, std::move(chunk));
} }
PaintChunk& PaintChunker::EnsureCurrentChunk(const PaintChunk::Id& id) { bool PaintChunker::EnsureCurrentChunk(const PaintChunk::Id& id) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK(chunks_);
// If this DCHECKs are hit we are missing a call to update the properties. // If this DCHECKs are hit we are missing a call to update the properties.
// See: ScopedPaintChunkProperties. // See: ScopedPaintChunkProperties.
DCHECK(!IsInInitialState()); DCHECK(!IsInInitialState());
...@@ -56,28 +66,31 @@ PaintChunk& PaintChunker::EnsureCurrentChunk(const PaintChunk::Id& id) { ...@@ -56,28 +66,31 @@ PaintChunk& PaintChunker::EnsureCurrentChunk(const PaintChunk::Id& id) {
DCHECK(current_properties_.IsInitialized()); DCHECK(current_properties_.IsInitialized());
#endif #endif
if (WillForceNewChunk() || current_properties_ != LastChunk().properties) { if (WillForceNewChunk() ||
current_properties_ != chunks_->back().properties) {
if (!next_chunk_id_) if (!next_chunk_id_)
next_chunk_id_.emplace(id); next_chunk_id_.emplace(id);
FinalizeLastChunkProperties(); FinalizeLastChunkProperties();
wtf_size_t begin = chunks_.IsEmpty() ? 0 : LastChunk().end_index; wtf_size_t begin = chunks_->IsEmpty() ? 0 : chunks_->back().end_index;
chunks_.emplace_back(begin, begin, *next_chunk_id_, current_properties_); chunks_->emplace_back(begin, begin, *next_chunk_id_, current_properties_);
next_chunk_id_ = base::nullopt; next_chunk_id_ = base::nullopt;
force_new_chunk_ = false; will_force_new_chunk_ = false;
return true;
} }
return LastChunk(); return false;
} }
bool PaintChunker::IncrementDisplayItemIndex(const DisplayItem& item) { bool PaintChunker::IncrementDisplayItemIndex(const DisplayItem& item) {
DCHECK(chunks_);
bool item_forces_new_chunk = item.IsForeignLayer() || bool item_forces_new_chunk = item.IsForeignLayer() ||
item.IsGraphicsLayerWrapper() || item.IsGraphicsLayerWrapper() ||
item.IsScrollbar(); item.IsScrollbar();
if (item_forces_new_chunk) if (item_forces_new_chunk)
SetForceNewChunk(true); SetWillForceNewChunk(true);
auto previous_size = size(); bool created_new_chunk = EnsureCurrentChunk(item.GetId());
auto& chunk = EnsureCurrentChunk(item.GetId()); auto& chunk = chunks_->back();
bool created_new_chunk = size() > previous_size;
chunk.bounds.Unite(item.VisualRect()); chunk.bounds.Unite(item.VisualRect());
if (item.DrawsContent()) if (item.DrawsContent())
...@@ -105,16 +118,16 @@ bool PaintChunker::IncrementDisplayItemIndex(const DisplayItem& item) { ...@@ -105,16 +118,16 @@ bool PaintChunker::IncrementDisplayItemIndex(const DisplayItem& item) {
// When forcing a new chunk, we still need to force new chunk for the next // When forcing a new chunk, we still need to force new chunk for the next
// display item. Otherwise reset force_new_chunk_ to false. // display item. Otherwise reset force_new_chunk_ to false.
DCHECK(!force_new_chunk_); DCHECK(!will_force_new_chunk_);
if (item_forces_new_chunk) { if (item_forces_new_chunk) {
DCHECK(created_new_chunk); DCHECK(created_new_chunk);
SetForceNewChunk(true); SetWillForceNewChunk(true);
} }
return created_new_chunk; return created_new_chunk;
} }
void PaintChunker::AddHitTestDataToCurrentChunk(const PaintChunk::Id& id, bool PaintChunker::AddHitTestDataToCurrentChunk(const PaintChunk::Id& id,
const IntRect& rect, const IntRect& rect,
TouchAction touch_action) { TouchAction touch_action) {
// In CompositeAfterPaint, we ensure a paint chunk for correct composited // In CompositeAfterPaint, we ensure a paint chunk for correct composited
...@@ -124,14 +137,16 @@ void PaintChunker::AddHitTestDataToCurrentChunk(const PaintChunk::Id& id, ...@@ -124,14 +137,16 @@ void PaintChunker::AddHitTestDataToCurrentChunk(const PaintChunk::Id& id,
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() && if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
touch_action == TouchAction::kAuto && touch_action == TouchAction::kAuto &&
&current_properties_.Effect() == &EffectPaintPropertyNode::Root()) &current_properties_.Effect() == &EffectPaintPropertyNode::Root())
return; return false;
auto& chunk = EnsureCurrentChunk(id); bool created_new_chunk = EnsureCurrentChunk(id);
auto& chunk = chunks_->back();
chunk.bounds.Unite(rect); chunk.bounds.Unite(rect);
if (touch_action != TouchAction::kAuto) { if (touch_action != TouchAction::kAuto) {
chunk.EnsureHitTestData().touch_action_rects.push_back( chunk.EnsureHitTestData().touch_action_rects.push_back(
TouchActionRect{rect, touch_action}); TouchActionRect{rect, touch_action});
} }
return created_new_chunk;
} }
void PaintChunker::CreateScrollHitTestChunk( void PaintChunker::CreateScrollHitTestChunk(
...@@ -154,50 +169,47 @@ void PaintChunker::CreateScrollHitTestChunk( ...@@ -154,50 +169,47 @@ void PaintChunker::CreateScrollHitTestChunk(
} }
#endif #endif
SetForceNewChunk(true); SetWillForceNewChunk(true);
auto& chunk = EnsureCurrentChunk(id); bool created_new_chunk = EnsureCurrentChunk(id);
DCHECK(created_new_chunk);
auto& chunk = chunks_->back();
chunk.bounds.Unite(rect); chunk.bounds.Unite(rect);
auto& hit_test_data = chunk.EnsureHitTestData(); auto& hit_test_data = chunk.EnsureHitTestData();
hit_test_data.scroll_translation = scroll_translation; hit_test_data.scroll_translation = scroll_translation;
hit_test_data.scroll_hit_test_rect = rect; hit_test_data.scroll_hit_test_rect = rect;
SetForceNewChunk(true); SetWillForceNewChunk(true);
} }
void PaintChunker::ProcessBackgroundColorCandidate(const PaintChunk::Id& id, bool PaintChunker::ProcessBackgroundColorCandidate(const PaintChunk::Id& id,
Color color, Color color,
uint64_t area) { uint64_t area) {
EnsureCurrentChunk(id); bool created_new_chunk = EnsureCurrentChunk(id);
if (color != Color::kTransparent && if (color != Color::kTransparent &&
(candidate_background_color_ == Color::kTransparent || (candidate_background_color_ == Color::kTransparent ||
(area >= candidate_background_area_))) { (area >= candidate_background_area_))) {
candidate_background_color_ = color; candidate_background_color_ = color;
candidate_background_area_ = area; candidate_background_area_ = area;
} }
return created_new_chunk;
} }
void PaintChunker::FinalizeLastChunkProperties() { void PaintChunker::FinalizeLastChunkProperties() {
if (chunks_.IsEmpty() || LastChunk().is_moved_from_cached_subsequence) DCHECK(chunks_);
if (chunks_->IsEmpty() || chunks_->back().is_moved_from_cached_subsequence)
return; return;
LastChunk().known_to_be_opaque = auto& chunk = chunks_->back();
last_chunk_known_to_be_opaque_region_.Contains(LastChunk().bounds); chunk.known_to_be_opaque =
last_chunk_known_to_be_opaque_region_.Contains(chunk.bounds);
last_chunk_known_to_be_opaque_region_ = Region(); last_chunk_known_to_be_opaque_region_ = Region();
if (candidate_background_color_ != Color::kTransparent) { if (candidate_background_color_ != Color::kTransparent) {
LastChunk().background_color = candidate_background_color_; chunk.background_color = candidate_background_color_;
LastChunk().background_color_area = candidate_background_area_; chunk.background_color_area = candidate_background_area_;
} }
candidate_background_color_ = Color::kTransparent; candidate_background_color_ = Color::kTransparent;
candidate_background_area_ = 0u; candidate_background_area_ = 0u;
} }
Vector<PaintChunk> PaintChunker::ReleasePaintChunks() {
FinalizeLastChunkProperties();
next_chunk_id_ = base::nullopt;
current_properties_ = PropertyTreeState::Uninitialized();
chunks_.ShrinkToFit();
force_new_chunk_ = true;
return std::move(chunks_);
}
} // namespace blink } // namespace blink
...@@ -25,8 +25,11 @@ class PLATFORM_EXPORT PaintChunker final { ...@@ -25,8 +25,11 @@ class PLATFORM_EXPORT PaintChunker final {
DISALLOW_NEW(); DISALLOW_NEW();
public: public:
PaintChunker(); explicit PaintChunker(Vector<PaintChunk>& chunks) { ResetChunks(&chunks); }
~PaintChunker();
// Finishes current chunks if any, and makes it ready to create chunks into
// the given vector if not null.
void ResetChunks(Vector<PaintChunk>*);
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
bool IsInInitialState() const; bool IsInInitialState() const;
...@@ -43,28 +46,20 @@ class PLATFORM_EXPORT PaintChunker final { ...@@ -43,28 +46,20 @@ class PLATFORM_EXPORT PaintChunker final {
// display item and then automatically resets the status. Some special display // display item and then automatically resets the status. Some special display
// item (e.g. ForeignLayerDisplayItem) also automatically sets the status on // item (e.g. ForeignLayerDisplayItem) also automatically sets the status on
// before and after the item to force a dedicated paint chunk. // before and after the item to force a dedicated paint chunk.
void SetForceNewChunk(bool force) { void SetWillForceNewChunk(bool force) {
force_new_chunk_ = force; will_force_new_chunk_ = force;
next_chunk_id_ = base::nullopt; next_chunk_id_ = base::nullopt;
} }
bool WillForceNewChunk() const { bool WillForceNewChunk() const { return will_force_new_chunk_; }
return force_new_chunk_ || chunks_.IsEmpty();
}
void AppendByMoving(PaintChunk&&); void AppendByMoving(PaintChunk&&);
// Returns true if a new chunk is created. // Returns true if a new chunk is created.
bool IncrementDisplayItemIndex(const DisplayItem&); bool IncrementDisplayItemIndex(const DisplayItem&);
const Vector<PaintChunk>& PaintChunks() const { return chunks_; }
wtf_size_t size() const { return chunks_.size(); }
PaintChunk& LastChunk() { return chunks_.back(); }
const PaintChunk& LastChunk() const { return chunks_.back(); }
// The id will be used when we need to create a new current chunk. // The id will be used when we need to create a new current chunk.
// Otherwise it's ignored. // Otherwise it's ignored. Returns true if a new chunk is added.
void AddHitTestDataToCurrentChunk(const PaintChunk::Id&, bool AddHitTestDataToCurrentChunk(const PaintChunk::Id&,
const IntRect&, const IntRect&,
TouchAction); TouchAction);
void CreateScrollHitTestChunk( void CreateScrollHitTestChunk(
...@@ -72,20 +67,21 @@ class PLATFORM_EXPORT PaintChunker final { ...@@ -72,20 +67,21 @@ class PLATFORM_EXPORT PaintChunker final {
const TransformPaintPropertyNode* scroll_translation, const TransformPaintPropertyNode* scroll_translation,
const IntRect&); const IntRect&);
void ProcessBackgroundColorCandidate(const PaintChunk::Id& id, // Returns true if a new chunk is created.
bool ProcessBackgroundColorCandidate(const PaintChunk::Id& id,
Color color, Color color,
uint64_t area); uint64_t area);
void EnsureChunk() { EnsureCurrentChunk(*next_chunk_id_); }
// Releases the generated paint chunk list and raster invalidations and // Returns true if a new chunk is created.
// resets the state of this object. bool EnsureChunk() { return EnsureCurrentChunk(*next_chunk_id_); }
Vector<PaintChunk> ReleasePaintChunks();
private: private:
PaintChunk& EnsureCurrentChunk(const PaintChunk::Id&); // Returns true if a new chunk is created.
bool EnsureCurrentChunk(const PaintChunk::Id&);
void FinalizeLastChunkProperties(); void FinalizeLastChunkProperties();
Vector<PaintChunk> chunks_; Vector<PaintChunk>* chunks_ = nullptr;
// The id specified by UpdateCurrentPaintChunkProperties(). If it is not // The id specified by UpdateCurrentPaintChunkProperties(). If it is not
// nullopt, we will use it as the id of the next new chunk. Otherwise we will // nullopt, we will use it as the id of the next new chunk. Otherwise we will
...@@ -95,14 +91,15 @@ class PLATFORM_EXPORT PaintChunker final { ...@@ -95,14 +91,15 @@ class PLATFORM_EXPORT PaintChunker final {
// forced to create a new chunk). // forced to create a new chunk).
base::Optional<PaintChunk::Id> next_chunk_id_; base::Optional<PaintChunk::Id> next_chunk_id_;
PropertyTreeStateOrAlias current_properties_; PropertyTreeStateOrAlias current_properties_ =
PropertyTreeState::Uninitialized();
Region last_chunk_known_to_be_opaque_region_; Region last_chunk_known_to_be_opaque_region_;
// True when an item forces a new chunk (e.g., foreign display items), and for // True when an item forces a new chunk (e.g., foreign display items), and for
// the item following a forced chunk. PaintController also forces new chunks // the item following a forced chunk. PaintController also forces new chunks
// before and after subsequences by calling ForceNewChunk(). // before and after subsequences by calling ForceNewChunk().
bool force_new_chunk_; bool will_force_new_chunk_ = true;
Color candidate_background_color_ = Color::kTransparent; Color candidate_background_color_ = Color::kTransparent;
uint64_t candidate_background_area_ = 0; uint64_t candidate_background_area_ = 0;
......
...@@ -62,32 +62,35 @@ class TestDisplayItemRequiringSeparateChunk : public ForeignLayerDisplayItem { ...@@ -62,32 +62,35 @@ class TestDisplayItemRequiringSeparateChunk : public ForeignLayerDisplayItem {
}; };
TEST_F(PaintChunkerTest, Empty) { TEST_F(PaintChunkerTest, Empty) {
PaintChunker chunker; Vector<PaintChunk> chunks;
EXPECT_TRUE(chunker.PaintChunks().IsEmpty()); PaintChunker chunker(chunks);
EXPECT_TRUE(chunks.IsEmpty());
auto chunks = chunker.ReleasePaintChunks(); chunker.ResetChunks(&chunks);
EXPECT_TRUE(chunks.IsEmpty()); EXPECT_TRUE(chunks.IsEmpty());
} }
TEST_F(PaintChunkerTest, SingleNonEmptyRange) { TEST_F(PaintChunkerTest, SingleNonEmptyRange) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id(client_, DisplayItemType(1)); PaintChunk::Id id(client_, DisplayItemType(1));
chunker.UpdateCurrentPaintChunkProperties(&id, DefaultPaintChunkProperties()); chunker.UpdateCurrentPaintChunkProperties(&id, DefaultPaintChunkProperties());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
const auto& chunks = chunker.PaintChunks();
EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 2, id, EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 2, id,
DefaultPaintChunkProperties()))); DefaultPaintChunkProperties())));
auto chunks1 = chunker.ReleasePaintChunks(); Vector<PaintChunk> chunks1;
EXPECT_TRUE(chunker.PaintChunks().IsEmpty()); chunker.ResetChunks(&chunks1);
EXPECT_THAT(chunks1, ElementsAre(IsPaintChunk( EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 2, id,
0, 2, id, DefaultPaintChunkProperties()))); DefaultPaintChunkProperties())));
EXPECT_TRUE(chunks1.IsEmpty());
} }
TEST_F(PaintChunkerTest, SamePropertiesTwiceCombineIntoOneChunk) { TEST_F(PaintChunkerTest, SamePropertiesTwiceCombineIntoOneChunk) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id(client_, DisplayItemType(1)); PaintChunk::Id id(client_, DisplayItemType(1));
chunker.UpdateCurrentPaintChunkProperties(&id, DefaultPaintChunkProperties()); chunker.UpdateCurrentPaintChunkProperties(&id, DefaultPaintChunkProperties());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
...@@ -95,18 +98,19 @@ TEST_F(PaintChunkerTest, SamePropertiesTwiceCombineIntoOneChunk) { ...@@ -95,18 +98,19 @@ TEST_F(PaintChunkerTest, SamePropertiesTwiceCombineIntoOneChunk) {
chunker.UpdateCurrentPaintChunkProperties(&id, DefaultPaintChunkProperties()); chunker.UpdateCurrentPaintChunkProperties(&id, DefaultPaintChunkProperties());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
const auto& chunks = chunker.PaintChunks();
EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 3, id, EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 3, id,
DefaultPaintChunkProperties()))); DefaultPaintChunkProperties())));
auto chunks1 = chunker.ReleasePaintChunks(); Vector<PaintChunk> chunks1;
EXPECT_TRUE(chunker.PaintChunks().IsEmpty()); chunker.ResetChunks(&chunks1);
EXPECT_THAT(chunks1, ElementsAre(IsPaintChunk( EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 3, id,
0, 3, id, DefaultPaintChunkProperties()))); DefaultPaintChunkProperties())));
EXPECT_TRUE(chunks1.IsEmpty());
} }
TEST_F(PaintChunkerTest, BuildMultipleChunksWithSinglePropertyChanging) { TEST_F(PaintChunkerTest, BuildMultipleChunksWithSinglePropertyChanging) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id1(client_, DisplayItemType(1)); PaintChunk::Id id1(client_, DisplayItemType(1));
chunker.UpdateCurrentPaintChunkProperties(&id1, chunker.UpdateCurrentPaintChunkProperties(&id1,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
...@@ -130,15 +134,15 @@ TEST_F(PaintChunkerTest, BuildMultipleChunksWithSinglePropertyChanging) { ...@@ -130,15 +134,15 @@ TEST_F(PaintChunkerTest, BuildMultipleChunksWithSinglePropertyChanging) {
chunker.UpdateCurrentPaintChunkProperties(&id3, another_transform); chunker.UpdateCurrentPaintChunkProperties(&id3, another_transform);
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_THAT( EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 2, id1,
chunker.PaintChunks(), DefaultPaintChunkProperties()),
ElementsAre(IsPaintChunk(0, 2, id1, DefaultPaintChunkProperties()), IsPaintChunk(2, 3, id2, simple_transform),
IsPaintChunk(2, 3, id2, simple_transform), IsPaintChunk(3, 4, id3, another_transform)));
IsPaintChunk(3, 4, id3, another_transform)));
} }
TEST_F(PaintChunkerTest, BuildMultipleChunksWithDifferentPropertyChanges) { TEST_F(PaintChunkerTest, BuildMultipleChunksWithDifferentPropertyChanges) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id1(client_, DisplayItemType(1)); PaintChunk::Id id1(client_, DisplayItemType(1));
chunker.UpdateCurrentPaintChunkProperties(&id1, chunker.UpdateCurrentPaintChunkProperties(&id1,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
...@@ -186,7 +190,7 @@ TEST_F(PaintChunkerTest, BuildMultipleChunksWithDifferentPropertyChanges) { ...@@ -186,7 +190,7 @@ TEST_F(PaintChunkerTest, BuildMultipleChunksWithDifferentPropertyChanges) {
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_THAT( EXPECT_THAT(
chunker.PaintChunks(), chunks,
ElementsAre( ElementsAre(
IsPaintChunk(0, 1, id1, DefaultPaintChunkProperties()), IsPaintChunk(0, 1, id1, DefaultPaintChunkProperties()),
IsPaintChunk(1, 3, id2, simple_transform), IsPaintChunk(1, 3, id2, simple_transform),
...@@ -207,7 +211,8 @@ TEST_F(PaintChunkerTest, BuildChunksFromNestedTransforms) { ...@@ -207,7 +211,8 @@ TEST_F(PaintChunkerTest, BuildChunksFromNestedTransforms) {
// </a xform> // </a xform>
// <paint> // <paint>
// </root xform> // </root xform>
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id1(client_, DisplayItemType(1)); PaintChunk::Id id1(client_, DisplayItemType(1));
chunker.UpdateCurrentPaintChunkProperties(&id1, chunker.UpdateCurrentPaintChunkProperties(&id1,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
...@@ -227,17 +232,17 @@ TEST_F(PaintChunkerTest, BuildChunksFromNestedTransforms) { ...@@ -227,17 +232,17 @@ TEST_F(PaintChunkerTest, BuildChunksFromNestedTransforms) {
TestChunkerDisplayItem item_after_restore(client_, DisplayItemType(10)); TestChunkerDisplayItem item_after_restore(client_, DisplayItemType(10));
chunker.IncrementDisplayItemIndex(item_after_restore); chunker.IncrementDisplayItemIndex(item_after_restore);
EXPECT_THAT( EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 1, id1,
chunker.PaintChunks(), DefaultPaintChunkProperties()),
ElementsAre(IsPaintChunk(0, 1, id1, DefaultPaintChunkProperties()), IsPaintChunk(1, 3, id2, simple_transform),
IsPaintChunk(1, 3, id2, simple_transform), IsPaintChunk(3, 4, item_after_restore.GetId(),
IsPaintChunk(3, 4, item_after_restore.GetId(), DefaultPaintChunkProperties())));
DefaultPaintChunkProperties())));
} }
TEST_F(PaintChunkerTest, ChangingPropertiesWithoutItems) { TEST_F(PaintChunkerTest, ChangingPropertiesWithoutItems) {
// Test that properties can change without display items being generated. // Test that properties can change without display items being generated.
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id1(client_, DisplayItemType(1)); PaintChunk::Id id1(client_, DisplayItemType(1));
chunker.UpdateCurrentPaintChunkProperties(&id1, chunker.UpdateCurrentPaintChunkProperties(&id1,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
...@@ -258,16 +263,16 @@ TEST_F(PaintChunkerTest, ChangingPropertiesWithoutItems) { ...@@ -258,16 +263,16 @@ TEST_F(PaintChunkerTest, ChangingPropertiesWithoutItems) {
chunker.UpdateCurrentPaintChunkProperties(&id3, second_transform); chunker.UpdateCurrentPaintChunkProperties(&id3, second_transform);
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_THAT( EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 1, id1,
chunker.PaintChunks(), DefaultPaintChunkProperties()),
ElementsAre(IsPaintChunk(0, 1, id1, DefaultPaintChunkProperties()), IsPaintChunk(1, 2, id3, second_transform)));
IsPaintChunk(1, 2, id3, second_transform)));
} }
TEST_F(PaintChunkerTest, CreatesSeparateChunksWhenRequested) { TEST_F(PaintChunkerTest, CreatesSeparateChunksWhenRequested) {
// Tests that the chunker creates a separate chunks for display items which // Tests that the chunker creates a separate chunks for display items which
// require it. // require it.
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
FakeDisplayItemClient client1; FakeDisplayItemClient client1;
TestDisplayItemRequiringSeparateChunk i1(client1); TestDisplayItemRequiringSeparateChunk i1(client1);
FakeDisplayItemClient client2; FakeDisplayItemClient client2;
...@@ -289,7 +294,7 @@ TEST_F(PaintChunkerTest, CreatesSeparateChunksWhenRequested) { ...@@ -289,7 +294,7 @@ TEST_F(PaintChunkerTest, CreatesSeparateChunksWhenRequested) {
chunker.IncrementDisplayItemIndex(i3); chunker.IncrementDisplayItemIndex(i3);
EXPECT_THAT( EXPECT_THAT(
chunker.PaintChunks(), chunks,
ElementsAre( ElementsAre(
IsPaintChunk(0, 1, id0, DefaultPaintChunkProperties()), IsPaintChunk(0, 1, id0, DefaultPaintChunkProperties()),
IsPaintChunk(1, 2, i1.GetId(), DefaultPaintChunkProperties()), IsPaintChunk(1, 2, i1.GetId(), DefaultPaintChunkProperties()),
...@@ -299,118 +304,121 @@ TEST_F(PaintChunkerTest, CreatesSeparateChunksWhenRequested) { ...@@ -299,118 +304,121 @@ TEST_F(PaintChunkerTest, CreatesSeparateChunksWhenRequested) {
} }
TEST_F(PaintChunkerTest, ForceNewChunkWithNewId) { TEST_F(PaintChunkerTest, ForceNewChunkWithNewId) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id0(client_, DisplayItemType(0)); PaintChunk::Id id0(client_, DisplayItemType(0));
chunker.UpdateCurrentPaintChunkProperties(&id0, chunker.UpdateCurrentPaintChunkProperties(&id0,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
EXPECT_TRUE(chunker.WillForceNewChunk()); EXPECT_TRUE(chunker.WillForceNewChunk());
EXPECT_EQ(0u, chunker.size()); EXPECT_EQ(0u, chunks.size());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_FALSE(chunker.WillForceNewChunk()); EXPECT_FALSE(chunker.WillForceNewChunk());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_EQ(1u, chunker.size()); EXPECT_EQ(1u, chunks.size());
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
EXPECT_TRUE(chunker.WillForceNewChunk()); EXPECT_TRUE(chunker.WillForceNewChunk());
EXPECT_EQ(1u, chunker.size()); EXPECT_EQ(1u, chunks.size());
PaintChunk::Id id1(client_, DisplayItemType(1)); PaintChunk::Id id1(client_, DisplayItemType(1));
chunker.UpdateCurrentPaintChunkProperties(&id1, chunker.UpdateCurrentPaintChunkProperties(&id1,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_EQ(2u, chunker.size()); EXPECT_EQ(2u, chunks.size());
EXPECT_FALSE(chunker.WillForceNewChunk()); EXPECT_FALSE(chunker.WillForceNewChunk());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_EQ(2u, chunker.size()); EXPECT_EQ(2u, chunks.size());
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
PaintChunk::Id id2(client_, DisplayItemType(2)); PaintChunk::Id id2(client_, DisplayItemType(2));
EXPECT_TRUE(chunker.WillForceNewChunk()); EXPECT_TRUE(chunker.WillForceNewChunk());
chunker.UpdateCurrentPaintChunkProperties(&id2, chunker.UpdateCurrentPaintChunkProperties(&id2,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
EXPECT_EQ(2u, chunker.size()); EXPECT_EQ(2u, chunks.size());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_EQ(3u, chunker.size()); EXPECT_EQ(3u, chunks.size());
EXPECT_FALSE(chunker.WillForceNewChunk()); EXPECT_FALSE(chunker.WillForceNewChunk());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_THAT( EXPECT_THAT(
chunker.PaintChunks(), chunks,
ElementsAre(IsPaintChunk(0, 2, id0, DefaultPaintChunkProperties()), ElementsAre(IsPaintChunk(0, 2, id0, DefaultPaintChunkProperties()),
IsPaintChunk(2, 4, id1, DefaultPaintChunkProperties()), IsPaintChunk(2, 4, id1, DefaultPaintChunkProperties()),
IsPaintChunk(4, 6, id2, DefaultPaintChunkProperties()))); IsPaintChunk(4, 6, id2, DefaultPaintChunkProperties())));
} }
TEST_F(PaintChunkerTest, ForceNewChunkWithoutNewId) { TEST_F(PaintChunkerTest, ForceNewChunkWithoutNewId) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id0(client_, DisplayItemType(0)); PaintChunk::Id id0(client_, DisplayItemType(0));
chunker.UpdateCurrentPaintChunkProperties(nullptr, chunker.UpdateCurrentPaintChunkProperties(nullptr,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
EXPECT_TRUE(chunker.WillForceNewChunk()); EXPECT_TRUE(chunker.WillForceNewChunk());
EXPECT_EQ(0u, chunker.size()); EXPECT_EQ(0u, chunks.size());
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(id0.client, id0.type)); TestChunkerDisplayItem(id0.client, id0.type));
EXPECT_FALSE(chunker.WillForceNewChunk()); EXPECT_FALSE(chunker.WillForceNewChunk());
EXPECT_EQ(1u, chunker.size()); EXPECT_EQ(1u, chunks.size());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
EXPECT_TRUE(chunker.WillForceNewChunk()); EXPECT_TRUE(chunker.WillForceNewChunk());
EXPECT_EQ(1u, chunker.size()); EXPECT_EQ(1u, chunks.size());
PaintChunk::Id id1(client_, DisplayItemType(1)); PaintChunk::Id id1(client_, DisplayItemType(1));
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(id1.client, id1.type)); TestChunkerDisplayItem(id1.client, id1.type));
EXPECT_FALSE(chunker.WillForceNewChunk()); EXPECT_FALSE(chunker.WillForceNewChunk());
EXPECT_EQ(2u, chunker.size()); EXPECT_EQ(2u, chunks.size());
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(client_, DisplayItemType(2))); TestChunkerDisplayItem(client_, DisplayItemType(2)));
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
EXPECT_TRUE(chunker.WillForceNewChunk()); EXPECT_TRUE(chunker.WillForceNewChunk());
EXPECT_EQ(2u, chunker.size()); EXPECT_EQ(2u, chunks.size());
PaintChunk::Id id2(client_, DisplayItemType(3)); PaintChunk::Id id2(client_, DisplayItemType(3));
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(id2.client, id2.type)); TestChunkerDisplayItem(id2.client, id2.type));
EXPECT_FALSE(chunker.WillForceNewChunk()); EXPECT_FALSE(chunker.WillForceNewChunk());
EXPECT_EQ(3u, chunker.size()); EXPECT_EQ(3u, chunks.size());
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(client_, DisplayItemType(4))); TestChunkerDisplayItem(client_, DisplayItemType(4)));
EXPECT_THAT( EXPECT_THAT(
chunker.PaintChunks(), chunks,
ElementsAre(IsPaintChunk(0, 2, id0, DefaultPaintChunkProperties()), ElementsAre(IsPaintChunk(0, 2, id0, DefaultPaintChunkProperties()),
IsPaintChunk(2, 4, id1, DefaultPaintChunkProperties()), IsPaintChunk(2, 4, id1, DefaultPaintChunkProperties()),
IsPaintChunk(4, 6, id2, DefaultPaintChunkProperties()))); IsPaintChunk(4, 6, id2, DefaultPaintChunkProperties())));
} }
TEST_F(PaintChunkerTest, SetAndImmediatelyUnsetForceNewChunk) { TEST_F(PaintChunkerTest, SetAndImmediatelyUnSetWillForceNewChunk) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id0(client_, DisplayItemType(0)); PaintChunk::Id id0(client_, DisplayItemType(0));
chunker.UpdateCurrentPaintChunkProperties(nullptr, chunker.UpdateCurrentPaintChunkProperties(nullptr,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
EXPECT_TRUE(chunker.WillForceNewChunk()); EXPECT_TRUE(chunker.WillForceNewChunk());
EXPECT_EQ(0u, chunker.size()); EXPECT_EQ(0u, chunks.size());
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(id0.client, id0.type)); TestChunkerDisplayItem(id0.client, id0.type));
EXPECT_FALSE(chunker.WillForceNewChunk()); EXPECT_FALSE(chunker.WillForceNewChunk());
EXPECT_EQ(1u, chunker.size()); EXPECT_EQ(1u, chunks.size());
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
// This should not force a new chunk. Simulates a ScopedPaintChunkHint // This should not force a new chunk. Simulates a ScopedPaintChunkHint
// without any painting in the scope. // without any painting in the scope.
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
chunker.SetForceNewChunk(false); chunker.SetWillForceNewChunk(false);
EXPECT_FALSE(chunker.WillForceNewChunk()); EXPECT_FALSE(chunker.WillForceNewChunk());
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(client_, DisplayItemType(1))); TestChunkerDisplayItem(client_, DisplayItemType(1)));
EXPECT_EQ(1u, chunker.size()); EXPECT_EQ(1u, chunks.size());
EXPECT_THAT( EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 3, id0,
chunker.PaintChunks(), DefaultPaintChunkProperties())));
ElementsAre(IsPaintChunk(0, 3, id0, DefaultPaintChunkProperties())));
} }
TEST_F(PaintChunkerTest, NoNewChunkForSamePropertyDifferentIds) { TEST_F(PaintChunkerTest, NoNewChunkForSamePropertyDifferentIds) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id0(client_, DisplayItemType(0)); PaintChunk::Id id0(client_, DisplayItemType(0));
chunker.UpdateCurrentPaintChunkProperties(&id0, chunker.UpdateCurrentPaintChunkProperties(&id0,
DefaultPaintChunkProperties()); DefaultPaintChunkProperties());
...@@ -428,15 +436,15 @@ TEST_F(PaintChunkerTest, NoNewChunkForSamePropertyDifferentIds) { ...@@ -428,15 +436,15 @@ TEST_F(PaintChunkerTest, NoNewChunkForSamePropertyDifferentIds) {
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_)); chunker.IncrementDisplayItemIndex(TestChunkerDisplayItem(client_));
EXPECT_THAT( EXPECT_THAT(chunks, ElementsAre(IsPaintChunk(0, 6, id0,
chunker.PaintChunks(), DefaultPaintChunkProperties())));
ElementsAre(IsPaintChunk(0, 6, id0, DefaultPaintChunkProperties())));
} }
// Ensure that items following a forced chunk begin using the next display // Ensure that items following a forced chunk begin using the next display
// item's id. // item's id.
TEST_F(PaintChunkerTest, ChunksFollowingForcedChunk) { TEST_F(PaintChunkerTest, ChunksFollowingForcedChunk) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
FakeDisplayItemClient client; FakeDisplayItemClient client;
TestChunkerDisplayItem before_forced1(client, DisplayItemType(1)); TestChunkerDisplayItem before_forced1(client, DisplayItemType(1));
TestChunkerDisplayItem before_forced2(client, DisplayItemType(2)); TestChunkerDisplayItem before_forced2(client, DisplayItemType(2));
...@@ -457,7 +465,7 @@ TEST_F(PaintChunkerTest, ChunksFollowingForcedChunk) { ...@@ -457,7 +465,7 @@ TEST_F(PaintChunkerTest, ChunksFollowingForcedChunk) {
chunker.IncrementDisplayItemIndex(after_forced2); chunker.IncrementDisplayItemIndex(after_forced2);
EXPECT_THAT( EXPECT_THAT(
chunker.PaintChunks(), chunks,
ElementsAre( ElementsAre(
IsPaintChunk(0, 2, id0, DefaultPaintChunkProperties()), IsPaintChunk(0, 2, id0, DefaultPaintChunkProperties()),
IsPaintChunk(2, 3, forced.GetId(), DefaultPaintChunkProperties()), IsPaintChunk(2, 3, forced.GetId(), DefaultPaintChunkProperties()),
...@@ -466,7 +474,8 @@ TEST_F(PaintChunkerTest, ChunksFollowingForcedChunk) { ...@@ -466,7 +474,8 @@ TEST_F(PaintChunkerTest, ChunksFollowingForcedChunk) {
} }
TEST_F(PaintChunkerTest, ChunkIdsSkippingCache) { TEST_F(PaintChunkerTest, ChunkIdsSkippingCache) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id1(client_, DisplayItemType(1)); PaintChunk::Id id1(client_, DisplayItemType(1));
chunker.UpdateCurrentPaintChunkProperties(&id1, chunker.UpdateCurrentPaintChunkProperties(&id1,
...@@ -500,7 +509,6 @@ TEST_F(PaintChunkerTest, ChunkIdsSkippingCache) { ...@@ -500,7 +509,6 @@ TEST_F(PaintChunkerTest, ChunkIdsSkippingCache) {
TestChunkerDisplayItem after_restore(client_, DisplayItemType(4)); TestChunkerDisplayItem after_restore(client_, DisplayItemType(4));
chunker.IncrementDisplayItemIndex(after_restore); chunker.IncrementDisplayItemIndex(after_restore);
const auto& chunks = chunker.PaintChunks();
EXPECT_THAT( EXPECT_THAT(
chunks, chunks,
ElementsAre( ElementsAre(
...@@ -519,7 +527,8 @@ TEST_F(PaintChunkerTest, ChunkIdsSkippingCache) { ...@@ -519,7 +527,8 @@ TEST_F(PaintChunkerTest, ChunkIdsSkippingCache) {
} }
TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) { TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) {
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
PaintChunk::Id id1(client_, DisplayItemType(1)); PaintChunk::Id id1(client_, DisplayItemType(1));
...@@ -539,7 +548,7 @@ TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) { ...@@ -539,7 +548,7 @@ TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) {
chunker.AddHitTestDataToCurrentChunk(hit_test_id, IntRect(20, 30, 40, 50), chunker.AddHitTestDataToCurrentChunk(hit_test_id, IntRect(20, 30, 40, 50),
TouchAction::kPan); TouchAction::kPan);
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
PaintChunk::Id id3(client_, DisplayItemType(4)); PaintChunk::Id id3(client_, DisplayItemType(4));
chunker.AddHitTestDataToCurrentChunk(id3, IntRect(40, 50, 60, 70), chunker.AddHitTestDataToCurrentChunk(id3, IntRect(40, 50, 60, 70),
TouchAction::kAuto); TouchAction::kAuto);
...@@ -551,7 +560,7 @@ TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) { ...@@ -551,7 +560,7 @@ TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) {
{IntRect(20, 30, 40, 50), TouchAction::kPan}}; {IntRect(20, 30, 40, 50), TouchAction::kPan}};
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) { if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
EXPECT_THAT( EXPECT_THAT(
chunker.PaintChunks(), chunks,
ElementsAre(IsPaintChunk(0, 1, id1, DefaultPaintChunkProperties(), ElementsAre(IsPaintChunk(0, 1, id1, DefaultPaintChunkProperties(),
nullptr, IntRect(0, 0, 10, 10)), nullptr, IntRect(0, 0, 10, 10)),
IsPaintChunk(1, 1, id2, properties, &hit_test_data, IsPaintChunk(1, 1, id2, properties, &hit_test_data,
...@@ -560,7 +569,7 @@ TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) { ...@@ -560,7 +569,7 @@ TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) {
IntRect(0, 0, 100, 120)))); IntRect(0, 0, 100, 120))));
} else { } else {
EXPECT_THAT( EXPECT_THAT(
chunker.PaintChunks(), chunks,
ElementsAre( ElementsAre(
IsPaintChunk(0, 1, id1, DefaultPaintChunkProperties(), nullptr, IsPaintChunk(0, 1, id1, DefaultPaintChunkProperties(), nullptr,
IntRect(0, 0, 10, 10)), IntRect(0, 0, 10, 10)),
...@@ -573,7 +582,8 @@ TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) { ...@@ -573,7 +582,8 @@ TEST_F(PaintChunkerTest, AddHitTestDataToCurrentChunk) {
TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueAllOpaqueItems) { TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueAllOpaqueItems) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCompositeAfterPaintForTest cap(true);
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
FakeDisplayItemClient client1("client1"); FakeDisplayItemClient client1("client1");
FakeDisplayItemClient client2("client2"); FakeDisplayItemClient client2("client2");
FakeDisplayItemClient client3("client3"); FakeDisplayItemClient client3("client3");
...@@ -583,20 +593,19 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueAllOpaqueItems) { ...@@ -583,20 +593,19 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueAllOpaqueItems) {
// Single opaque item. // Single opaque item.
chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem( chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem(
client1, DisplayItemType(0), IntRect(0, 0, 100, 100))); client1, DisplayItemType(0), IntRect(0, 0, 100, 100)));
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
// Two opaque items. No empty area in the united bounds. // Two opaque items. No empty area in the united bounds.
chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem( chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem(
client1, DisplayItemType(1), IntRect(0, 0, 100, 100))); client1, DisplayItemType(1), IntRect(0, 0, 100, 100)));
chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem( chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem(
client2, DisplayItemType(2), IntRect(0, 100, 100, 50))); client2, DisplayItemType(2), IntRect(0, 100, 100, 50)));
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
// Two opaque items. Has empty area in the united bounds. // Two opaque items. Has empty area in the united bounds.
chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem( chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem(
client1, DisplayItemType(3), IntRect(0, 0, 100, 100))); client1, DisplayItemType(3), IntRect(0, 0, 100, 100)));
chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem( chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem(
client3, DisplayItemType(4), IntRect(50, 50, 100, 100))); client3, DisplayItemType(4), IntRect(50, 50, 100, 100)));
Vector<PaintChunk> chunks = chunker.ReleasePaintChunks();
EXPECT_THAT( EXPECT_THAT(
chunks, chunks,
ElementsAre( ElementsAre(
...@@ -614,7 +623,8 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueAllOpaqueItems) { ...@@ -614,7 +623,8 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueAllOpaqueItems) {
TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueWithHitTest) { TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueWithHitTest) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCompositeAfterPaintForTest cap(true);
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
FakeDisplayItemClient client1("client1"); FakeDisplayItemClient client1("client1");
FakeDisplayItemClient client2("client2"); FakeDisplayItemClient client2("client2");
FakeDisplayItemClient client3("client3"); FakeDisplayItemClient client3("client3");
...@@ -625,21 +635,21 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueWithHitTest) { ...@@ -625,21 +635,21 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueWithHitTest) {
chunker.AddHitTestDataToCurrentChunk( chunker.AddHitTestDataToCurrentChunk(
PaintChunk::Id(client1, DisplayItemType(0)), IntRect(10, 20, 30, 40), PaintChunk::Id(client1, DisplayItemType(0)), IntRect(10, 20, 30, 40),
TouchAction::kAuto); TouchAction::kAuto);
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
// Hit test rect is smaller than the opaque item. // Hit test rect is smaller than the opaque item.
chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem( chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem(
client1, DisplayItemType(1), IntRect(0, 0, 100, 100))); client1, DisplayItemType(1), IntRect(0, 0, 100, 100)));
chunker.AddHitTestDataToCurrentChunk( chunker.AddHitTestDataToCurrentChunk(
PaintChunk::Id(client1, DisplayItemType(2)), IntRect(0, 0, 50, 100), PaintChunk::Id(client1, DisplayItemType(2)), IntRect(0, 0, 50, 100),
TouchAction::kAuto); TouchAction::kAuto);
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
// Hit test rect is the same as the opaque item. // Hit test rect is the same as the opaque item.
chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem( chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem(
client1, DisplayItemType(3), IntRect(0, 0, 100, 100))); client1, DisplayItemType(3), IntRect(0, 0, 100, 100)));
chunker.AddHitTestDataToCurrentChunk( chunker.AddHitTestDataToCurrentChunk(
PaintChunk::Id(client1, DisplayItemType(4)), IntRect(0, 0, 100, 100), PaintChunk::Id(client1, DisplayItemType(4)), IntRect(0, 0, 100, 100),
TouchAction::kAuto); TouchAction::kAuto);
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
// Hit test rect is bigger than the opaque item. // Hit test rect is bigger than the opaque item.
chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem( chunker.IncrementDisplayItemIndex(TestChunkerOpaqueDisplayItem(
client1, DisplayItemType(5), IntRect(0, 0, 100, 100))); client1, DisplayItemType(5), IntRect(0, 0, 100, 100)));
...@@ -647,7 +657,6 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueWithHitTest) { ...@@ -647,7 +657,6 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueWithHitTest) {
PaintChunk::Id(client1, DisplayItemType(6)), IntRect(0, 100, 200, 100), PaintChunk::Id(client1, DisplayItemType(6)), IntRect(0, 100, 200, 100),
TouchAction::kAuto); TouchAction::kAuto);
Vector<PaintChunk> chunks = chunker.ReleasePaintChunks();
EXPECT_THAT( EXPECT_THAT(
chunks, chunks,
ElementsAre( ElementsAre(
...@@ -668,7 +677,8 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueWithHitTest) { ...@@ -668,7 +677,8 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueWithHitTest) {
TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueMixedOpaquenessItems) { TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueMixedOpaquenessItems) {
ScopedCompositeAfterPaintForTest cap(true); ScopedCompositeAfterPaintForTest cap(true);
PaintChunker chunker; Vector<PaintChunk> chunks;
PaintChunker chunker(chunks);
FakeDisplayItemClient client1("client1"); FakeDisplayItemClient client1("client1");
FakeDisplayItemClient client2("client2"); FakeDisplayItemClient client2("client2");
IntRect visual_rect1(0, 0, 100, 100); IntRect visual_rect1(0, 0, 100, 100);
...@@ -679,20 +689,20 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueMixedOpaquenessItems) { ...@@ -679,20 +689,20 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueMixedOpaquenessItems) {
// Single translucent item . // Single translucent item .
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(client1, DisplayItemType(1), visual_rect1)); TestChunkerDisplayItem(client1, DisplayItemType(1), visual_rect1));
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
// Two items, one translucent, one opaque. The opaque item doesn't contain // Two items, one translucent, one opaque. The opaque item doesn't contain
// the translucent item. // the translucent item.
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(client1, DisplayItemType(2), visual_rect1)); TestChunkerDisplayItem(client1, DisplayItemType(2), visual_rect1));
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerOpaqueDisplayItem(client2, DisplayItemType(3), visual_rect2)); TestChunkerOpaqueDisplayItem(client2, DisplayItemType(3), visual_rect2));
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
// Two items, one translucent, one opaque, with the same visual rect. // Two items, one translucent, one opaque, with the same visual rect.
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(client1, DisplayItemType(4), visual_rect1)); TestChunkerDisplayItem(client1, DisplayItemType(4), visual_rect1));
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerOpaqueDisplayItem(client1, DisplayItemType(5), visual_rect1)); TestChunkerOpaqueDisplayItem(client1, DisplayItemType(5), visual_rect1));
chunker.SetForceNewChunk(true); chunker.SetWillForceNewChunk(true);
// Two items, one opaque, one translucent. The opaque item contains the // Two items, one opaque, one translucent. The opaque item contains the
// translucent item. // translucent item.
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
...@@ -700,7 +710,8 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueMixedOpaquenessItems) { ...@@ -700,7 +710,8 @@ TEST_F(PaintChunkerTest, ChunkBoundsAndKnownToBeOpaqueMixedOpaquenessItems) {
chunker.IncrementDisplayItemIndex( chunker.IncrementDisplayItemIndex(
TestChunkerDisplayItem(client2, DisplayItemType(7), visual_rect2)); TestChunkerDisplayItem(client2, DisplayItemType(7), visual_rect2));
Vector<PaintChunk> chunks = chunker.ReleasePaintChunks(); chunker.ResetChunks(nullptr);
EXPECT_THAT( EXPECT_THAT(
chunks, chunks,
ElementsAre( ElementsAre(
......
...@@ -15,16 +15,13 @@ ...@@ -15,16 +15,13 @@
namespace blink { namespace blink {
// This is just for initializing current_paint_artifact_ to avoid allocation of
// a PaintArtifacts that might not be used.
static scoped_refptr<PaintArtifact> EmptyPaintArtifact() {
DEFINE_STATIC_REF(PaintArtifact, empty, base::AdoptRef(new PaintArtifact()));
DCHECK(empty->IsEmpty());
return empty;
}
PaintController::PaintController(Usage usage) PaintController::PaintController(Usage usage)
: usage_(usage), current_paint_artifact_(EmptyPaintArtifact()) { : usage_(usage),
current_paint_artifact_(usage == kMultiplePaints
? base::MakeRefCounted<PaintArtifact>()
: nullptr),
new_paint_artifact_(base::MakeRefCounted<PaintArtifact>()),
paint_chunker_(new_paint_artifact_->PaintChunks()) {
// frame_first_paints_ should have one null frame since the beginning, so // frame_first_paints_ should have one null frame since the beginning, so
// that PaintController is robust even if it paints outside of BeginFrame // that PaintController is robust even if it paints outside of BeginFrame
// and EndFrame cycles. It will also enable us to combine the first paint // and EndFrame cycles. It will also enable us to combine the first paint
...@@ -34,12 +31,61 @@ PaintController::PaintController(Usage usage) ...@@ -34,12 +31,61 @@ PaintController::PaintController(Usage usage)
} }
PaintController::~PaintController() { PaintController::~PaintController() {
#if DCHECK_IS_ON()
if (usage_ == kMultiplePaints) { if (usage_ == kMultiplePaints) {
// New display items should have been committed. // New display items should have been committed.
DCHECK(new_display_item_list_.IsEmpty()); DCHECK(new_paint_artifact_->IsEmpty());
// And the committed_ flag should have been cleared by FinishCycle(). // And the committed_ flag should have been cleared by FinishCycle().
DCHECK(!committed_); DCHECK(!committed_);
} }
#endif
}
void PaintController::EnsureChunk() {
if (paint_chunker_.EnsureChunk())
DidAppendChunk();
}
void PaintController::RecordHitTestData(const DisplayItemClient& client,
const IntRect& rect,
TouchAction touch_action) {
if (rect.IsEmpty())
return;
// In CompositeAfterPaint, we ensure a paint chunk for correct composited
// hit testing. In pre-CompositeAfterPaint, this is unnecessary, except that
// there is special touch action, and that we have a non-root effect so that
// PaintChunksToCcLayer will emit paint operations for filters.
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
touch_action == TouchAction::kAuto &&
CurrentPaintChunkProperties().Effect().IsRoot())
return;
PaintChunk::Id id(client, DisplayItem::kHitTest, current_fragment_);
CheckDuplicatePaintChunkId(id);
if (paint_chunker_.AddHitTestDataToCurrentChunk(id, rect, touch_action))
DidAppendChunk();
}
void PaintController::RecordScrollHitTestData(
const DisplayItemClient& client,
DisplayItem::Type type,
const TransformPaintPropertyNode* scroll_translation,
const IntRect& rect) {
PaintChunk::Id id(client, type, current_fragment_);
CheckDuplicatePaintChunkId(id);
paint_chunker_.CreateScrollHitTestChunk(id, scroll_translation, rect);
DidAppendChunk();
}
void PaintController::SetPossibleBackgroundColor(
const DisplayItemClient& client,
Color color,
uint64_t area) {
PaintChunk::Id id(client, DisplayItem::kBoxDecorationBackground,
current_fragment_);
CheckDuplicatePaintChunkId(id);
if (paint_chunker_.ProcessBackgroundColorCandidate(id, color, area))
DidAppendChunk();
} }
bool PaintController::UseCachedItemIfPossible(const DisplayItemClient& client, bool PaintController::UseCachedItemIfPossible(const DisplayItemClient& client,
...@@ -173,13 +219,13 @@ PaintController::SubsequenceMarkers* PaintController::GetSubsequenceMarkers( ...@@ -173,13 +219,13 @@ PaintController::SubsequenceMarkers* PaintController::GetSubsequenceMarkers(
wtf_size_t PaintController::BeginSubsequence() { wtf_size_t PaintController::BeginSubsequence() {
// Force new paint chunk which is required for subsequence caching. // Force new paint chunk which is required for subsequence caching.
SetForceNewChunk(true); SetWillForceNewChunk(true);
return new_paint_chunks_.size(); return NumNewChunks();
} }
void PaintController::EndSubsequence(const DisplayItemClient& client, void PaintController::EndSubsequence(const DisplayItemClient& client,
wtf_size_t start_chunk_index) { wtf_size_t start_chunk_index) {
auto end_chunk_index = new_paint_chunks_.size(); auto end_chunk_index = NumNewChunks();
if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() && if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() &&
IsCheckingUnderInvalidation()) { IsCheckingUnderInvalidation()) {
...@@ -204,7 +250,7 @@ void PaintController::EndSubsequence(const DisplayItemClient& client, ...@@ -204,7 +250,7 @@ void PaintController::EndSubsequence(const DisplayItemClient& client,
const auto& old_chunk = const auto& old_chunk =
current_paint_artifact_->PaintChunks()[old_chunk_index]; current_paint_artifact_->PaintChunks()[old_chunk_index];
const auto& new_chunk = const auto& new_chunk =
new_paint_chunks_.PaintChunks()[new_chunk_index]; new_paint_artifact_->PaintChunks()[new_chunk_index];
if (!old_chunk.EqualsForUnderInvalidationChecking(new_chunk)) { if (!old_chunk.EqualsForUnderInvalidationChecking(new_chunk)) {
ShowSequenceUnderInvalidationError( ShowSequenceUnderInvalidationError(
"under-invalidation: chunk changed", client); "under-invalidation: chunk changed", client);
...@@ -223,7 +269,7 @@ void PaintController::EndSubsequence(const DisplayItemClient& client, ...@@ -223,7 +269,7 @@ void PaintController::EndSubsequence(const DisplayItemClient& client,
} }
// Force new paint chunk which is required for subsequence caching. // Force new paint chunk which is required for subsequence caching.
SetForceNewChunk(true); SetWillForceNewChunk(true);
DCHECK(!new_cached_subsequences_.Contains(&client)) DCHECK(!new_cached_subsequences_.Contains(&client))
<< "Multiple subsequences for client: " << client.DebugName(); << "Multiple subsequences for client: " << client.DebugName();
...@@ -238,17 +284,18 @@ void PaintController::DidAppendItem(DisplayItem& display_item) { ...@@ -238,17 +284,18 @@ void PaintController::DidAppendItem(DisplayItem& display_item) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
if (display_item.IsCacheable()) { if (display_item.IsCacheable()) {
auto& new_display_item_list = new_paint_artifact_->GetDisplayItemList();
auto index = FindItemFromIdIndexMap(display_item.GetId(), auto index = FindItemFromIdIndexMap(display_item.GetId(),
new_display_item_id_index_map_, new_display_item_id_index_map_,
new_display_item_list_); new_display_item_list);
if (index != kNotFound) { if (index != kNotFound) {
ShowDebugData(); ShowDebugData();
NOTREACHED() << "DisplayItem " << display_item.AsDebugString().Utf8() NOTREACHED() << "DisplayItem " << display_item.AsDebugString().Utf8()
<< " has duplicated id with previous " << " has duplicated id with previous "
<< new_display_item_list_[index].AsDebugString().Utf8() << new_display_item_list[index].AsDebugString().Utf8()
<< " (index=" << index << ")"; << " (index=" << index << ")";
} }
AddToIdIndexMap(display_item.GetId(), new_display_item_list_.size() - 1, AddToIdIndexMap(display_item.GetId(), new_display_item_list.size() - 1,
new_display_item_id_index_map_); new_display_item_id_index_map_);
} }
#endif #endif
...@@ -263,7 +310,7 @@ void PaintController::ProcessNewItem(DisplayItem& display_item) { ...@@ -263,7 +310,7 @@ void PaintController::ProcessNewItem(DisplayItem& display_item) {
display_item.SetUncacheable(); display_item.SetUncacheable();
} }
if (new_paint_chunks_.IncrementDisplayItemIndex(display_item)) if (paint_chunker_.IncrementDisplayItemIndex(display_item))
DidAppendChunk(); DidAppendChunk();
if (!frame_first_paints_.back().first_painted && display_item.IsDrawing() && if (!frame_first_paints_.back().first_painted && display_item.IsDrawing() &&
...@@ -281,15 +328,15 @@ void PaintController::ProcessNewItem(DisplayItem& display_item) { ...@@ -281,15 +328,15 @@ void PaintController::ProcessNewItem(DisplayItem& display_item) {
DisplayItem& PaintController::MoveItemFromCurrentListToNewList( DisplayItem& PaintController::MoveItemFromCurrentListToNewList(
wtf_size_t index) { wtf_size_t index) {
return new_display_item_list_.AppendByMoving( return new_paint_artifact_->GetDisplayItemList().AppendByMoving(
current_paint_artifact_->GetDisplayItemList()[index]); current_paint_artifact_->GetDisplayItemList()[index]);
} }
void PaintController::DidAppendChunk() { void PaintController::DidAppendChunk() {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
if (new_paint_chunks_.LastChunk().is_cacheable) { auto& chunks = new_paint_artifact_->PaintChunks();
AddToIdIndexMap(new_paint_chunks_.LastChunk().id, if (chunks.back().is_cacheable) {
new_paint_chunks_.size() - 1, AddToIdIndexMap(chunks.back().id, chunks.size() - 1,
new_paint_chunk_id_index_map_); new_paint_chunk_id_index_map_);
} }
#endif #endif
...@@ -303,8 +350,8 @@ void PaintController::InvalidateAll() { ...@@ -303,8 +350,8 @@ void PaintController::InvalidateAll() {
void PaintController::InvalidateAllInternal() { void PaintController::InvalidateAllInternal() {
// TODO(wangxianzhu): Rename this to InvalidateAllForTesting() for CAP. // TODO(wangxianzhu): Rename this to InvalidateAllForTesting() for CAP.
// Can only be called during layout/paintInvalidation, not during painting. // Can only be called during layout/paintInvalidation, not during painting.
DCHECK(new_display_item_list_.IsEmpty()); CheckNoNewPaint();
current_paint_artifact_ = EmptyPaintArtifact(); current_paint_artifact_ = base::MakeRefCounted<PaintArtifact>();
current_cached_subsequences_.clear(); current_cached_subsequences_.clear();
cache_is_all_invalid_ = true; cache_is_all_invalid_ = true;
} }
...@@ -320,17 +367,17 @@ void PaintController::UpdateCurrentPaintChunkProperties( ...@@ -320,17 +367,17 @@ void PaintController::UpdateCurrentPaintChunkProperties(
const PropertyTreeStateOrAlias& properties) { const PropertyTreeStateOrAlias& properties) {
if (id) { if (id) {
PaintChunk::Id id_with_fragment(*id, current_fragment_); PaintChunk::Id id_with_fragment(*id, current_fragment_);
new_paint_chunks_.UpdateCurrentPaintChunkProperties(&id_with_fragment, paint_chunker_.UpdateCurrentPaintChunkProperties(&id_with_fragment,
properties); properties);
CheckDuplicatePaintChunkId(id_with_fragment); CheckDuplicatePaintChunkId(id_with_fragment);
} else { } else {
new_paint_chunks_.UpdateCurrentPaintChunkProperties(nullptr, properties); paint_chunker_.UpdateCurrentPaintChunkProperties(nullptr, properties);
} }
} }
void PaintController::AppendChunkByMoving(PaintChunk&& chunk) { void PaintController::AppendChunkByMoving(PaintChunk&& chunk) {
CheckDuplicatePaintChunkId(chunk.id); CheckDuplicatePaintChunkId(chunk.id);
new_paint_chunks_.AppendByMoving(std::move(chunk)); paint_chunker_.AppendByMoving(std::move(chunk));
DidAppendChunk(); DidAppendChunk();
} }
...@@ -448,8 +495,7 @@ void PaintController::CopyCachedSubsequence(wtf_size_t start_chunk_index, ...@@ -448,8 +495,7 @@ void PaintController::CopyCachedSubsequence(wtf_size_t start_chunk_index,
wtf_size_t end_chunk_index) { wtf_size_t end_chunk_index) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK(!RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()); DCHECK(!RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled());
auto properties_before_subsequence = auto properties_before_subsequence = CurrentPaintChunkProperties();
new_paint_chunks_.CurrentPaintChunkProperties();
#endif #endif
for (auto chunk_index = start_chunk_index; chunk_index < end_chunk_index; for (auto chunk_index = start_chunk_index; chunk_index < end_chunk_index;
...@@ -471,7 +517,7 @@ void PaintController::CopyCachedSubsequence(wtf_size_t start_chunk_index, ...@@ -471,7 +517,7 @@ void PaintController::CopyCachedSubsequence(wtf_size_t start_chunk_index,
AppendChunkByMoving(std::move(cached_chunk)); AppendChunkByMoving(std::move(cached_chunk));
} }
SetForceNewChunk(true); SetWillForceNewChunk(true);
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
DCHECK_EQ(properties_before_subsequence, CurrentPaintChunkProperties()); DCHECK_EQ(properties_before_subsequence, CurrentPaintChunkProperties());
...@@ -487,11 +533,14 @@ void PaintController::ResetCurrentListIndices() { ...@@ -487,11 +533,14 @@ void PaintController::ResetCurrentListIndices() {
DISABLE_CFI_PERF DISABLE_CFI_PERF
void PaintController::CommitNewDisplayItems() { void PaintController::CommitNewDisplayItems() {
TRACE_EVENT2("blink,benchmark", "PaintController::commitNewDisplayItems", TRACE_EVENT2(
"current_display_list_size", "blink,benchmark", "PaintController::commitNewDisplayItems",
(int)current_paint_artifact_->GetDisplayItemList().size(), "current_display_list_size",
"num_non_cached_new_items", current_paint_artifact_
(int)new_display_item_list_.size() - num_cached_new_items_); ? current_paint_artifact_->GetDisplayItemList().size()
: 0,
"num_non_cached_new_items",
new_paint_artifact_->GetDisplayItemList().size() - num_cached_new_items_);
if (usage_ == kMultiplePaints) if (usage_ == kMultiplePaints)
UpdateUMACounts(); UpdateUMACounts();
...@@ -509,17 +558,19 @@ void PaintController::CommitNewDisplayItems() { ...@@ -509,17 +558,19 @@ void PaintController::CommitNewDisplayItems() {
new_cached_subsequences_.swap(current_cached_subsequences_); new_cached_subsequences_.swap(current_cached_subsequences_);
new_cached_subsequences_.clear(); new_cached_subsequences_.clear();
current_paint_artifact_ = base::MakeRefCounted<PaintArtifact>( current_paint_artifact_ = std::move(new_paint_artifact_);
std::move(new_display_item_list_), if (usage_ == kMultiplePaints) {
new_paint_chunks_.ReleasePaintChunks()); new_paint_artifact_ = base::MakeRefCounted<PaintArtifact>(
current_paint_artifact_->GetDisplayItemList().UsedCapacityInBytes());
paint_chunker_.ResetChunks(&new_paint_artifact_->PaintChunks());
} else {
new_paint_artifact_ = nullptr;
paint_chunker_.ResetChunks(nullptr);
}
ResetCurrentListIndices(); ResetCurrentListIndices();
out_of_order_item_id_index_map_.clear(); out_of_order_item_id_index_map_.clear();
// We'll allocate the initial buffer when we start the next paint.
new_display_item_list_ =
DisplayItemList(GetDisplayItemList().UsedCapacityInBytes());
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
num_indexed_items_ = 0; num_indexed_items_ = 0;
num_sequential_matches_ = 0; num_sequential_matches_ = 0;
...@@ -531,11 +582,7 @@ void PaintController::FinishCycle() { ...@@ -531,11 +582,7 @@ void PaintController::FinishCycle() {
if (usage_ == kTransient || !committed_) if (usage_ == kTransient || !committed_)
return; return;
#if DCHECK_IS_ON() CheckNoNewPaint();
DCHECK(new_display_item_list_.IsEmpty());
DCHECK(new_paint_chunks_.IsInInitialState());
#endif
committed_ = false; committed_ = false;
// Validate display item clients that have validly cached subsequence or // Validate display item clients that have validly cached subsequence or
...@@ -597,17 +644,14 @@ void PaintController::ClearPropertyTreeChangedStateTo( ...@@ -597,17 +644,14 @@ void PaintController::ClearPropertyTreeChangedStateTo(
size_t PaintController::ApproximateUnsharedMemoryUsage() const { size_t PaintController::ApproximateUnsharedMemoryUsage() const {
size_t memory_usage = sizeof(*this); size_t memory_usage = sizeof(*this);
// Memory outside this class due to current_paint_artifact_. // Memory outside this class due to paint artifacts.
memory_usage += current_paint_artifact_->ApproximateUnsharedMemoryUsage(); memory_usage += current_paint_artifact_->ApproximateUnsharedMemoryUsage();
memory_usage += new_paint_artifact_->ApproximateUnsharedMemoryUsage();
// External objects, shared with the embedder, such as PaintRecord, should be // External objects, shared with the embedder, such as PaintRecord, should be
// excluded to avoid double counting. It is the embedder's responsibility to // excluded to avoid double counting. It is the embedder's responsibility to
// count such objects. // count such objects.
// Memory outside this class due to new_display_item_list_.
DCHECK(new_display_item_list_.IsEmpty());
memory_usage += new_display_item_list_.MemoryUsageInBytes();
// Memory outside this class due to current_cached_subsequences_ and // Memory outside this class due to current_cached_subsequences_ and
// new_cached_subsequences_. // new_cached_subsequences_.
memory_usage += current_cached_subsequences_.Capacity() * memory_usage += current_cached_subsequences_.Capacity() *
...@@ -683,7 +727,7 @@ void PaintController::CheckUnderInvalidation() { ...@@ -683,7 +727,7 @@ void PaintController::CheckUnderInvalidation() {
return; return;
} }
DisplayItem& new_item = new_display_item_list_.Last(); DisplayItem& new_item = new_paint_artifact_->GetDisplayItemList().Last();
auto old_item_index = under_invalidation_checking_begin_; auto old_item_index = under_invalidation_checking_begin_;
DisplayItem* old_item = DisplayItem* old_item =
old_item_index < current_paint_artifact_->GetDisplayItemList().size() old_item_index < current_paint_artifact_->GetDisplayItemList().size()
...@@ -693,11 +737,8 @@ void PaintController::CheckUnderInvalidation() { ...@@ -693,11 +737,8 @@ void PaintController::CheckUnderInvalidation() {
if (!old_item || !new_item.Equals(*old_item)) { if (!old_item || !new_item.Equals(*old_item)) {
// If we ever skipped reporting any under-invalidations, report the earliest // If we ever skipped reporting any under-invalidations, report the earliest
// one. // one.
ShowUnderInvalidationError( ShowUnderInvalidationError("under-invalidation: display item changed",
"under-invalidation: display item changed", new_item, old_item);
new_display_item_list_.Last(),
&current_paint_artifact_
->GetDisplayItemList()[under_invalidation_checking_begin_]);
CHECK(false); CHECK(false);
} }
...@@ -706,7 +747,7 @@ void PaintController::CheckUnderInvalidation() { ...@@ -706,7 +747,7 @@ void PaintController::CheckUnderInvalidation() {
// non-under-invalidation-checking path to empty the original cached slot, // non-under-invalidation-checking path to empty the original cached slot,
// leaving only disappeared or invalidated display items in the old list after // leaving only disappeared or invalidated display items in the old list after
// painting. // painting.
new_display_item_list_.RemoveLast(); new_paint_artifact_->GetDisplayItemList().RemoveLast();
MoveItemFromCurrentListToNewList(old_item_index); MoveItemFromCurrentListToNewList(old_item_index);
++under_invalidation_checking_begin_; ++under_invalidation_checking_begin_;
...@@ -753,7 +794,7 @@ void PaintController::CheckDuplicatePaintChunkId(const PaintChunk::Id& id) { ...@@ -753,7 +794,7 @@ void PaintController::CheckDuplicatePaintChunkId(const PaintChunk::Id& id) {
ShowDebugData(); ShowDebugData();
NOTREACHED() << "New paint chunk id " << id NOTREACHED() << "New paint chunk id " << id
<< " has duplicated id with previous chuck " << " has duplicated id with previous chuck "
<< new_paint_chunks_.PaintChunks()[it->value]; << new_paint_artifact_->PaintChunks()[it->value];
} }
#endif #endif
} }
...@@ -765,7 +806,7 @@ size_t PaintController::sum_num_cached_subsequences_ = 0; ...@@ -765,7 +806,7 @@ size_t PaintController::sum_num_cached_subsequences_ = 0;
void PaintController::UpdateUMACounts() { void PaintController::UpdateUMACounts() {
DCHECK_EQ(usage_, kMultiplePaints); DCHECK_EQ(usage_, kMultiplePaints);
sum_num_items_ += new_display_item_list_.size(); sum_num_items_ += new_paint_artifact_->GetDisplayItemList().size();
sum_num_cached_items_ += num_cached_new_items_; sum_num_cached_items_ += num_cached_new_items_;
sum_num_subsequences_ += new_cached_subsequences_.size(); sum_num_subsequences_ += new_cached_subsequences_.size();
sum_num_cached_subsequences_ += num_cached_new_subsequences_; sum_num_cached_subsequences_ += num_cached_new_subsequences_;
......
...@@ -93,46 +93,31 @@ class PLATFORM_EXPORT PaintController { ...@@ -93,46 +93,31 @@ class PLATFORM_EXPORT PaintController {
void UpdateCurrentPaintChunkProperties(const PaintChunk::Id*, void UpdateCurrentPaintChunkProperties(const PaintChunk::Id*,
const PropertyTreeStateOrAlias&); const PropertyTreeStateOrAlias&);
const PropertyTreeStateOrAlias& CurrentPaintChunkProperties() const { const PropertyTreeStateOrAlias& CurrentPaintChunkProperties() const {
return new_paint_chunks_.CurrentPaintChunkProperties(); return paint_chunker_.CurrentPaintChunkProperties();
} }
// See PaintChunker for documentation of the following methods. // See PaintChunker for documentation of the following methods.
wtf_size_t NumNewChunks() const { return new_paint_chunks_.size(); } void SetWillForceNewChunk(bool force) {
void SetForceNewChunk(bool force) { paint_chunker_.SetWillForceNewChunk(force);
new_paint_chunks_.SetForceNewChunk(force);
}
bool WillForceNewChunk() const {
return new_paint_chunks_.WillForceNewChunk();
}
const IntRect& LastChunkBounds() const {
return new_paint_chunks_.LastChunk().bounds;
} }
bool WillForceNewChunk() const { return paint_chunker_.WillForceNewChunk(); }
void EnsureChunk() { new_paint_chunks_.EnsureChunk(); } void EnsureChunk();
void RecordHitTestData(const DisplayItemClient& client,
const IntRect& rect, void RecordHitTestData(const DisplayItemClient&, const IntRect&, TouchAction);
TouchAction touch_action) {
if (rect.IsEmpty())
return;
PaintChunk::Id id(client, DisplayItem::kHitTest, current_fragment_);
CheckDuplicatePaintChunkId(id);
new_paint_chunks_.AddHitTestDataToCurrentChunk(id, rect, touch_action);
}
void RecordScrollHitTestData( void RecordScrollHitTestData(
const DisplayItemClient& client, const DisplayItemClient&,
DisplayItem::Type type, DisplayItem::Type,
const TransformPaintPropertyNode* scroll_translation, const TransformPaintPropertyNode* scroll_translation,
const IntRect& rect) { const IntRect&);
PaintChunk::Id id(client, type, current_fragment_); void SetPossibleBackgroundColor(const DisplayItemClient&,
CheckDuplicatePaintChunkId(id); Color,
new_paint_chunks_.CreateScrollHitTestChunk(id, scroll_translation, rect); uint64_t area);
}
void SetPossibleBackgroundColor(const DisplayItemClient& client, wtf_size_t NumNewChunks() const {
Color color, return new_paint_artifact_->PaintChunks().size();
uint64_t area) { }
PaintChunk::Id id = {client, DisplayItem::kBoxDecorationBackground, const IntRect& LastChunkBounds() const {
current_fragment_}; return new_paint_artifact_->PaintChunks().back().bounds;
new_paint_chunks_.ProcessBackgroundColorCandidate(id, color, area);
} }
template <typename DisplayItemClass, typename... Args> template <typename DisplayItemClass, typename... Args>
...@@ -147,8 +132,9 @@ class PLATFORM_EXPORT PaintController { ...@@ -147,8 +132,9 @@ class PLATFORM_EXPORT PaintController {
"kDisplayItemAlignment."); "kDisplayItemAlignment.");
DisplayItemClass& display_item = DisplayItemClass& display_item =
new_display_item_list_.AllocateAndConstruct<DisplayItemClass>( new_paint_artifact_->GetDisplayItemList()
std::forward<Args>(args)...); .AllocateAndConstruct<DisplayItemClass>(
std::forward<Args>(args)...);
display_item.SetFragment(current_fragment_); display_item.SetFragment(current_fragment_);
ProcessNewItem(display_item); ProcessNewItem(display_item);
} }
...@@ -210,15 +196,12 @@ class PLATFORM_EXPORT PaintController { ...@@ -210,15 +196,12 @@ class PLATFORM_EXPORT PaintController {
// Get the artifact generated after the last commit. // Get the artifact generated after the last commit.
const PaintArtifact& GetPaintArtifact() const { const PaintArtifact& GetPaintArtifact() const {
#if DCHECK_IS_ON() CheckNoNewPaint();
DCHECK(new_display_item_list_.IsEmpty());
DCHECK(new_paint_chunks_.IsInInitialState());
DCHECK(current_paint_artifact_);
#endif
return *current_paint_artifact_; return *current_paint_artifact_;
} }
scoped_refptr<const PaintArtifact> GetPaintArtifactShared() const { scoped_refptr<const PaintArtifact> GetPaintArtifactShared() const {
return base::WrapRefCounted(&GetPaintArtifact()); CheckNoNewPaint();
return current_paint_artifact_;
} }
const DisplayItemList& GetDisplayItemList() const { const DisplayItemList& GetDisplayItemList() const {
return GetPaintArtifact().GetDisplayItemList(); return GetPaintArtifact().GetDisplayItemList();
...@@ -227,6 +210,11 @@ class PLATFORM_EXPORT PaintController { ...@@ -227,6 +210,11 @@ class PLATFORM_EXPORT PaintController {
return GetPaintArtifact().PaintChunks(); return GetPaintArtifact().PaintChunks();
} }
scoped_refptr<const PaintArtifact> GetNewPaintArtifactShared() const {
DCHECK(new_paint_artifact_);
return new_paint_artifact_;
}
class ScopedBenchmarkMode { class ScopedBenchmarkMode {
STACK_ALLOCATED(); STACK_ALLOCATED();
...@@ -255,10 +243,6 @@ class PLATFORM_EXPORT PaintController { ...@@ -255,10 +243,6 @@ class PLATFORM_EXPORT PaintController {
void SetTextPainted(); void SetTextPainted();
void SetImagePainted(); void SetImagePainted();
// Returns DisplayItemList added using CreateAndAppend() since beginning or
// the last CommitNewDisplayItems(). Use with care.
DisplayItemList& NewDisplayItemList() { return new_display_item_list_; }
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
void ShowCompactDebugData() const; void ShowCompactDebugData() const;
void ShowDebugData() const; void ShowDebugData() const;
...@@ -403,6 +387,14 @@ class PLATFORM_EXPORT PaintController { ...@@ -403,6 +387,14 @@ class PLATFORM_EXPORT PaintController {
bool ShouldInvalidateDisplayItemForBenchmark(); bool ShouldInvalidateDisplayItemForBenchmark();
bool ShouldInvalidateSubsequenceForBenchmark(); bool ShouldInvalidateSubsequenceForBenchmark();
void CheckNoNewPaint() const {
#if DCHECK_IS_ON()
DCHECK(!new_paint_artifact_ || new_paint_artifact_->IsEmpty());
DCHECK(paint_chunker_.IsInInitialState());
DCHECK(current_paint_artifact_);
#endif
}
Usage usage_; Usage usage_;
// The last paint artifact after CommitNewDisplayItems(). // The last paint artifact after CommitNewDisplayItems().
...@@ -410,8 +402,8 @@ class PLATFORM_EXPORT PaintController { ...@@ -410,8 +402,8 @@ class PLATFORM_EXPORT PaintController {
scoped_refptr<PaintArtifact> current_paint_artifact_; scoped_refptr<PaintArtifact> current_paint_artifact_;
// Data being used to build the next paint artifact. // Data being used to build the next paint artifact.
DisplayItemList new_display_item_list_; scoped_refptr<PaintArtifact> new_paint_artifact_;
PaintChunker new_paint_chunks_; PaintChunker paint_chunker_;
bool cache_is_all_invalid_ = true; bool cache_is_all_invalid_ = true;
bool committed_ = false; bool committed_ = false;
...@@ -486,7 +478,7 @@ class PLATFORM_EXPORT PaintController { ...@@ -486,7 +478,7 @@ class PLATFORM_EXPORT PaintController {
static size_t sum_num_subsequences_; static size_t sum_num_subsequences_;
static size_t sum_num_cached_subsequences_; static size_t sum_num_cached_subsequences_;
class DisplayItemListAsJSON; class PaintArtifactAsJSON;
DISALLOW_COPY_AND_ASSIGN(PaintController); DISALLOW_COPY_AND_ASSIGN(PaintController);
}; };
......
...@@ -10,17 +10,17 @@ ...@@ -10,17 +10,17 @@
namespace blink { namespace blink {
class PaintController::DisplayItemListAsJSON { class PaintController::PaintArtifactAsJSON {
STACK_ALLOCATED(); STACK_ALLOCATED();
public: public:
DisplayItemListAsJSON(const DisplayItemList&, PaintArtifactAsJSON(const PaintArtifact&,
const CachedSubsequenceMap&, const CachedSubsequenceMap&,
const Vector<PaintChunk>&, DisplayItemList::JsonFlags);
DisplayItemList::JsonFlags);
String ToString() { String ToString() {
return ChunksAsJSONArrayRecursive(0, chunks_.size())->ToPrettyJSONString(); return ChunksAsJSONArrayRecursive(0, artifact_.PaintChunks().size())
->ToPrettyJSONString();
} }
private: private:
...@@ -35,21 +35,17 @@ class PaintController::DisplayItemListAsJSON { ...@@ -35,21 +35,17 @@ class PaintController::DisplayItemListAsJSON {
wtf_size_t end_chunk_index; wtf_size_t end_chunk_index;
}; };
const DisplayItemList& list_; const PaintArtifact& artifact_;
Vector<SubsequenceInfo> subsequences_; Vector<SubsequenceInfo> subsequences_;
Vector<SubsequenceInfo>::const_iterator current_subsequence_; Vector<SubsequenceInfo>::const_iterator next_subsequence_;
const Vector<PaintChunk>& chunks_;
DisplayItemList::JsonFlags flags_; DisplayItemList::JsonFlags flags_;
}; };
PaintController::DisplayItemListAsJSON::DisplayItemListAsJSON( PaintController::PaintArtifactAsJSON::PaintArtifactAsJSON(
const DisplayItemList& list, const PaintArtifact& artifact,
const CachedSubsequenceMap& subsequence_map, const CachedSubsequenceMap& subsequence_map,
const Vector<PaintChunk>& chunks,
DisplayItemList::JsonFlags flags) DisplayItemList::JsonFlags flags)
: list_(list), : artifact_(artifact), flags_(flags) {
chunks_(chunks),
flags_(flags) {
for (const auto& item : subsequence_map) { for (const auto& item : subsequence_map) {
subsequences_.push_back(SubsequenceInfo{ subsequences_.push_back(SubsequenceInfo{
item.key, item.value.start_chunk_index, item.value.end_chunk_index}); item.key, item.value.start_chunk_index, item.value.end_chunk_index});
...@@ -61,13 +57,13 @@ PaintController::DisplayItemListAsJSON::DisplayItemListAsJSON( ...@@ -61,13 +57,13 @@ PaintController::DisplayItemListAsJSON::DisplayItemListAsJSON(
: a.start_chunk_index < b.start_chunk_index; : a.start_chunk_index < b.start_chunk_index;
}); });
current_subsequence_ = subsequences_.begin(); next_subsequence_ = subsequences_.begin();
} }
std::unique_ptr<JSONObject> std::unique_ptr<JSONObject>
PaintController::DisplayItemListAsJSON::SubsequenceAsJSONObjectRecursive() { PaintController::PaintArtifactAsJSON::SubsequenceAsJSONObjectRecursive() {
const auto& subsequence = *current_subsequence_; const auto& subsequence = *next_subsequence_;
++current_subsequence_; ++next_subsequence_;
auto json_object = std::make_unique<JSONObject>(); auto json_object = std::make_unique<JSONObject>();
...@@ -82,15 +78,15 @@ PaintController::DisplayItemListAsJSON::SubsequenceAsJSONObjectRecursive() { ...@@ -82,15 +78,15 @@ PaintController::DisplayItemListAsJSON::SubsequenceAsJSONObjectRecursive() {
} }
std::unique_ptr<JSONArray> std::unique_ptr<JSONArray>
PaintController::DisplayItemListAsJSON::ChunksAsJSONArrayRecursive( PaintController::PaintArtifactAsJSON::ChunksAsJSONArrayRecursive(
wtf_size_t start_chunk_index, wtf_size_t start_chunk_index,
wtf_size_t end_chunk_index) { wtf_size_t end_chunk_index) {
auto array = std::make_unique<JSONArray>(); auto array = std::make_unique<JSONArray>();
auto chunk_index = start_chunk_index; auto chunk_index = start_chunk_index;
while (current_subsequence_ != subsequences_.end() && while (next_subsequence_ != subsequences_.end() &&
current_subsequence_->start_chunk_index < end_chunk_index) { next_subsequence_->start_chunk_index < end_chunk_index) {
const auto& subsequence = *current_subsequence_; const auto& subsequence = *next_subsequence_;
DCHECK_GE(subsequence.start_chunk_index, chunk_index); DCHECK_GE(subsequence.start_chunk_index, chunk_index);
DCHECK_LE(subsequence.end_chunk_index, end_chunk_index); DCHECK_LE(subsequence.end_chunk_index, end_chunk_index);
...@@ -106,13 +102,13 @@ PaintController::DisplayItemListAsJSON::ChunksAsJSONArrayRecursive( ...@@ -106,13 +102,13 @@ PaintController::DisplayItemListAsJSON::ChunksAsJSONArrayRecursive(
return array; return array;
} }
void PaintController::DisplayItemListAsJSON::AppendChunksAsJSON( void PaintController::PaintArtifactAsJSON::AppendChunksAsJSON(
wtf_size_t start_chunk_index, wtf_size_t start_chunk_index,
wtf_size_t end_chunk_index, wtf_size_t end_chunk_index,
JSONArray& json_array) { JSONArray& json_array) {
DCHECK_GT(end_chunk_index, start_chunk_index); DCHECK_GT(end_chunk_index, start_chunk_index);
for (auto i = start_chunk_index; i < end_chunk_index; ++i) { for (auto i = start_chunk_index; i < end_chunk_index; ++i) {
const auto& chunk = chunks_[i]; const auto& chunk = artifact_.PaintChunks()[i];
auto json_object = std::make_unique<JSONObject>(); auto json_object = std::make_unique<JSONObject>();
json_object->SetString( json_object->SetString(
...@@ -122,16 +118,15 @@ void PaintController::DisplayItemListAsJSON::AppendChunksAsJSON( ...@@ -122,16 +118,15 @@ void PaintController::DisplayItemListAsJSON::AppendChunksAsJSON(
if (flags_ & DisplayItemList::kShowPaintRecords) if (flags_ & DisplayItemList::kShowPaintRecords)
json_object->SetString("chunkData", chunk.ToString()); json_object->SetString("chunkData", chunk.ToString());
json_object->SetArray( json_object->SetArray("displayItems",
"displayItems", DisplayItemList::DisplayItemsAsJSON(
DisplayItemList::DisplayItemsAsJSON( artifact_.DisplayItemsInChunk(i), flags_));
list_.ItemsInRange(chunk.begin_index, chunk.end_index), flags_));
json_array.PushObject(std::move(json_object)); json_array.PushObject(std::move(json_object));
} }
} }
String PaintController::DisplayItemListAsJSON::ClientName( String PaintController::PaintArtifactAsJSON::ClientName(
const DisplayItemClient& client) const { const DisplayItemClient& client) const {
return client.SafeDebugName(flags_ & DisplayItemList::kClientKnownToBeAlive); return client.SafeDebugName(flags_ & DisplayItemList::kClientKnownToBeAlive);
} }
...@@ -142,22 +137,25 @@ void PaintController::ShowDebugDataInternal( ...@@ -142,22 +137,25 @@ void PaintController::ShowDebugDataInternal(
// The clients in the current list are known to be alive before FinishCycle(). // The clients in the current list are known to be alive before FinishCycle().
if (committed_) if (committed_)
current_list_flags |= DisplayItemList::kClientKnownToBeAlive; current_list_flags |= DisplayItemList::kClientKnownToBeAlive;
LOG(INFO) << "current display item list: " LOG(INFO) << "current paint artifact: "
<< DisplayItemListAsJSON( << (current_paint_artifact_
current_paint_artifact_->GetDisplayItemList(), ? PaintArtifactAsJSON(*current_paint_artifact_,
current_cached_subsequences_, current_cached_subsequences_,
current_paint_artifact_->PaintChunks(), current_list_flags) current_list_flags)
.ToString() .ToString()
.Utf8(); .Utf8()
: "null");
LOG(INFO) << "new display item list: "
<< DisplayItemListAsJSON( LOG(INFO)
new_display_item_list_, new_cached_subsequences_, << "new paint artifact: "
new_paint_chunks_.PaintChunks(), << (new_paint_artifact_
// The clients in new_display_item_list_ are all alive. ? PaintArtifactAsJSON(
flags | DisplayItemList::kClientKnownToBeAlive) *new_paint_artifact_, new_cached_subsequences_,
.ToString() // The clients in new_display_item_list_ are all alive.
.Utf8(); flags | DisplayItemList::kClientKnownToBeAlive)
.ToString()
.Utf8()
: "null");
} }
void PaintController::ShowCompactDebugData() const { void PaintController::ShowCompactDebugData() const {
......
...@@ -844,6 +844,85 @@ TEST_P(PaintControllerTest, CachedSubsequenceAndDisplayItemsSwapOrder) { ...@@ -844,6 +844,85 @@ TEST_P(PaintControllerTest, CachedSubsequenceAndDisplayItemsSwapOrder) {
DefaultPaintChunkProperties()))); DefaultPaintChunkProperties())));
} }
TEST_P(PaintControllerTest, DisplayItemSwapOrderBeforeCachedSubsequence) {
FakeDisplayItemClient content1a("content1a");
FakeDisplayItemClient content1b("content1b");
FakeDisplayItemClient container2("container2");
FakeDisplayItemClient content3("content3");
GraphicsContext context(GetPaintController());
PaintChunk::Id content1a_id(content1a, kBackgroundType);
PaintChunk::Id content1b_id(content1b, kBackgroundType);
PaintChunk::Id container2_id(container2, kBackgroundType);
PaintChunk::Id content3_id(content3, kBackgroundType);
IntRect rect(100, 100, 50, 200);
InitRootChunk();
DrawRect(context, content1a, kBackgroundType, rect);
DrawRect(context, content1b, kBackgroundType, rect);
{
SubsequenceRecorder r(context, container2);
DrawRect(context, container2, kBackgroundType, rect);
}
DrawRect(context, content3, kBackgroundType, rect);
CommitAndFinishCycle();
EXPECT_THAT(GetPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&content1a, kBackgroundType),
IsSameId(&content1b, kBackgroundType),
IsSameId(&container2, kBackgroundType),
IsSameId(&content3, kBackgroundType)));
// New paint order:
// Subsequence(container1): container1, content1b(cached), content1a(cached).
// Subsequence(container2): cached
// Subsequence(contaienr3): container3, content3
InitRootChunk();
if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) {
EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1b,
kBackgroundType));
DrawRect(context, content1b, kBackgroundType, rect);
EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1a,
kBackgroundType));
DrawRect(context, content1a, kBackgroundType, rect);
{
EXPECT_FALSE(SubsequenceRecorder::UseCachedSubsequenceIfPossible(
context, container2));
SubsequenceRecorder r(context, container2);
DrawRect(context, container2, kBackgroundType, rect);
}
EXPECT_FALSE(DrawingRecorder::UseCachedDrawingIfPossible(context, content3,
kBackgroundType));
DrawRect(context, content3, kBackgroundType, rect);
} else {
EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1b,
kBackgroundType));
EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content1a,
kBackgroundType));
EXPECT_TRUE(SubsequenceRecorder::UseCachedSubsequenceIfPossible(
context, container2));
EXPECT_TRUE(DrawingRecorder::UseCachedDrawingIfPossible(context, content3,
kBackgroundType));
}
EXPECT_EQ(4u, NumCachedNewItems());
EXPECT_EQ(1u, NumCachedNewSubsequences());
#if DCHECK_IS_ON()
EXPECT_EQ(1u, NumIndexedItems());
EXPECT_EQ(2u, NumSequentialMatches());
EXPECT_EQ(1u, NumOutOfOrderMatches());
#endif
CommitAndFinishCycle();
EXPECT_THAT(GetPaintController().GetDisplayItemList(),
ElementsAre(IsSameId(&content1b, kBackgroundType),
IsSameId(&content1a, kBackgroundType),
IsSameId(&container2, kBackgroundType),
IsSameId(&content3, kBackgroundType)));
}
TEST_P(PaintControllerTest, CachedSubsequenceContainingFragments) { TEST_P(PaintControllerTest, CachedSubsequenceContainingFragments) {
GraphicsContext context(GetPaintController()); GraphicsContext context(GetPaintController());
FakeDisplayItemClient root("root"); FakeDisplayItemClient root("root");
...@@ -1246,17 +1325,19 @@ TEST_P(PaintControllerTest, SkipCache) { ...@@ -1246,17 +1325,19 @@ TEST_P(PaintControllerTest, SkipCache) {
GetPaintController().EndSkippingCache(); GetPaintController().EndSkippingCache();
// We should repaint everything on invalidation of the scope container. // We should repaint everything on invalidation of the scope container.
EXPECT_THAT(GetPaintController().NewDisplayItemList(), const auto& display_item_list =
GetPaintController().GetNewPaintArtifactShared()->GetDisplayItemList();
EXPECT_THAT(display_item_list,
ElementsAre(IsSameId(&multicol, kBackgroundType), ElementsAre(IsSameId(&multicol, kBackgroundType),
IsSameId(&content, kForegroundType), IsSameId(&content, kForegroundType),
IsSameId(&content, kForegroundType), IsSameId(&content, kForegroundType),
IsSameId(&content, kForegroundType))); IsSameId(&content, kForegroundType)));
EXPECT_NE(record1, static_cast<const DrawingDisplayItem&>( EXPECT_NE(record1,
GetPaintController().NewDisplayItemList()[1]) static_cast<const DrawingDisplayItem&>(display_item_list[1])
.GetPaintRecord()); .GetPaintRecord());
EXPECT_NE(record2, static_cast<const DrawingDisplayItem&>( EXPECT_NE(record2,
GetPaintController().NewDisplayItemList()[2]) static_cast<const DrawingDisplayItem&>(display_item_list[2])
.GetPaintRecord()); .GetPaintRecord());
CommitAndFinishCycle(); CommitAndFinishCycle();
EXPECT_DEFAULT_ROOT_CHUNK(4); EXPECT_DEFAULT_ROOT_CHUNK(4);
......
...@@ -46,7 +46,7 @@ class ScopedPaintChunkHint { ...@@ -46,7 +46,7 @@ class ScopedPaintChunkHint {
previous_force_new_chunk_(paint_controller_.WillForceNewChunk()) { previous_force_new_chunk_(paint_controller_.WillForceNewChunk()) {
if (!previous_force_new_chunk_ && previous_num_chunks_ && if (!previous_force_new_chunk_ && previous_num_chunks_ &&
!paint_controller_.LastChunkBounds().Contains(visual_rect)) !paint_controller_.LastChunkBounds().Contains(visual_rect))
paint_controller_.SetForceNewChunk(true); paint_controller_.SetWillForceNewChunk(true);
// This is after SetForceNewChunk(true) so that the possible new chunk will // This is after SetForceNewChunk(true) so that the possible new chunk will
// use the specified id. // use the specified id.
paint_chunk_properties_.emplace(paint_controller, properties, client, type); paint_chunk_properties_.emplace(paint_controller, properties, client, type);
...@@ -55,7 +55,7 @@ class ScopedPaintChunkHint { ...@@ -55,7 +55,7 @@ class ScopedPaintChunkHint {
~ScopedPaintChunkHint() { ~ScopedPaintChunkHint() {
paint_chunk_properties_ = base::nullopt; paint_chunk_properties_ = base::nullopt;
if (!HasCreatedPaintChunk()) if (!HasCreatedPaintChunk())
paint_controller_.SetForceNewChunk(previous_force_new_chunk_); paint_controller_.SetWillForceNewChunk(previous_force_new_chunk_);
} }
bool HasCreatedPaintChunk() const { bool HasCreatedPaintChunk() const {
......
...@@ -38,17 +38,18 @@ TestPaintArtifact& TestPaintArtifact::Chunk(int id) { ...@@ -38,17 +38,18 @@ TestPaintArtifact& TestPaintArtifact::Chunk(int id) {
TestPaintArtifact& TestPaintArtifact::Chunk(DisplayItemClient& client, TestPaintArtifact& TestPaintArtifact::Chunk(DisplayItemClient& client,
DisplayItem::Type type) { DisplayItem::Type type) {
paint_chunks_.push_back( auto& display_item_list = paint_artifact_->GetDisplayItemList();
PaintChunk(display_item_list_.size(), display_item_list_.size(), paint_artifact_->PaintChunks().emplace_back(
PaintChunk::Id(client, type), PropertyTreeState::Root())); display_item_list.size(), display_item_list.size(),
PaintChunk::Id(client, type), PropertyTreeState::Root());
// Assume PaintController has processed this chunk. // Assume PaintController has processed this chunk.
paint_chunks_.back().client_is_just_created = false; paint_artifact_->PaintChunks().back().client_is_just_created = false;
return *this; return *this;
} }
TestPaintArtifact& TestPaintArtifact::Properties( TestPaintArtifact& TestPaintArtifact::Properties(
const PropertyTreeStateOrAlias& properties) { const PropertyTreeStateOrAlias& properties) {
paint_chunks_.back().properties = properties; paint_artifact_->PaintChunks().back().properties = properties;
return *this; return *this;
} }
...@@ -66,8 +67,9 @@ TestPaintArtifact& TestPaintArtifact::ForeignLayer( ...@@ -66,8 +67,9 @@ TestPaintArtifact& TestPaintArtifact::ForeignLayer(
scoped_refptr<cc::Layer> layer, scoped_refptr<cc::Layer> layer,
const IntPoint& offset) { const IntPoint& offset) {
DEFINE_STATIC_LOCAL(LiteralDebugNameClient, client, ("ForeignLayer")); DEFINE_STATIC_LOCAL(LiteralDebugNameClient, client, ("ForeignLayer"));
display_item_list_.AllocateAndConstruct<ForeignLayerDisplayItem>( paint_artifact_->GetDisplayItemList()
client, DisplayItem::kForeignLayerFirst, std::move(layer), offset); .AllocateAndConstruct<ForeignLayerDisplayItem>(
client, DisplayItem::kForeignLayerFirst, std::move(layer), offset);
DidAddDisplayItem(); DidAddDisplayItem();
return *this; return *this;
} }
...@@ -82,9 +84,10 @@ TestPaintArtifact& TestPaintArtifact::RectDrawing(DisplayItemClient& client, ...@@ -82,9 +84,10 @@ TestPaintArtifact& TestPaintArtifact::RectDrawing(DisplayItemClient& client,
flags.setColor(color.Rgb()); flags.setColor(color.Rgb());
canvas->drawRect(bounds, flags); canvas->drawRect(bounds, flags);
} }
display_item_list_.AllocateAndConstruct<DrawingDisplayItem>( paint_artifact_->GetDisplayItemList()
client, DisplayItem::kDrawingFirst, bounds, .AllocateAndConstruct<DrawingDisplayItem>(
recorder.finishRecordingAsPicture()); client, DisplayItem::kDrawingFirst, bounds,
recorder.finishRecordingAsPicture());
DidAddDisplayItem(); DidAddDisplayItem();
return *this; return *this;
} }
...@@ -92,43 +95,44 @@ TestPaintArtifact& TestPaintArtifact::RectDrawing(DisplayItemClient& client, ...@@ -92,43 +95,44 @@ TestPaintArtifact& TestPaintArtifact::RectDrawing(DisplayItemClient& client,
TestPaintArtifact& TestPaintArtifact::ScrollHitTest( TestPaintArtifact& TestPaintArtifact::ScrollHitTest(
DisplayItemClient& client, DisplayItemClient& client,
const TransformPaintPropertyNode* scroll_translation) { const TransformPaintPropertyNode* scroll_translation) {
paint_chunks_.back().EnsureHitTestData().scroll_translation = paint_artifact_->PaintChunks().back().EnsureHitTestData().scroll_translation =
scroll_translation; scroll_translation;
return *this; return *this;
} }
TestPaintArtifact& TestPaintArtifact::SetRasterEffectOutset( TestPaintArtifact& TestPaintArtifact::SetRasterEffectOutset(
RasterEffectOutset outset) { RasterEffectOutset outset) {
paint_chunks_.back().raster_effect_outset = outset; paint_artifact_->PaintChunks().back().raster_effect_outset = outset;
return *this; return *this;
} }
TestPaintArtifact& TestPaintArtifact::KnownToBeOpaque() { TestPaintArtifact& TestPaintArtifact::KnownToBeOpaque() {
paint_chunks_.back().known_to_be_opaque = true; paint_artifact_->PaintChunks().back().known_to_be_opaque = true;
return *this; return *this;
} }
TestPaintArtifact& TestPaintArtifact::Bounds(const IntRect& bounds) { TestPaintArtifact& TestPaintArtifact::Bounds(const IntRect& bounds) {
paint_chunks_.back().bounds = bounds; auto& chunk = paint_artifact_->PaintChunks().back();
paint_chunks_.back().drawable_bounds = bounds; chunk.bounds = bounds;
chunk.drawable_bounds = bounds;
return *this; return *this;
} }
TestPaintArtifact& TestPaintArtifact::DrawableBounds( TestPaintArtifact& TestPaintArtifact::DrawableBounds(
const IntRect& drawable_bounds) { const IntRect& drawable_bounds) {
paint_chunks_.back().drawable_bounds = drawable_bounds; auto& chunk = paint_artifact_->PaintChunks().back();
DCHECK(paint_chunks_.back().bounds.Contains(drawable_bounds)); chunk.drawable_bounds = drawable_bounds;
DCHECK(chunk.bounds.Contains(drawable_bounds));
return *this; return *this;
} }
TestPaintArtifact& TestPaintArtifact::Uncacheable() { TestPaintArtifact& TestPaintArtifact::Uncacheable() {
paint_chunks_.back().is_cacheable = false; paint_artifact_->PaintChunks().back().is_cacheable = false;
return *this; return *this;
} }
scoped_refptr<PaintArtifact> TestPaintArtifact::Build() { scoped_refptr<PaintArtifact> TestPaintArtifact::Build() {
return base::MakeRefCounted<PaintArtifact>(std::move(display_item_list_), return std::move(paint_artifact_);
std::move(paint_chunks_));
} }
FakeDisplayItemClient& TestPaintArtifact::NewClient() { FakeDisplayItemClient& TestPaintArtifact::NewClient() {
...@@ -141,9 +145,9 @@ FakeDisplayItemClient& TestPaintArtifact::Client(wtf_size_t i) const { ...@@ -141,9 +145,9 @@ FakeDisplayItemClient& TestPaintArtifact::Client(wtf_size_t i) const {
} }
void TestPaintArtifact::DidAddDisplayItem() { void TestPaintArtifact::DidAddDisplayItem() {
auto& chunk = paint_chunks_.back(); auto& chunk = paint_artifact_->PaintChunks().back();
DCHECK_EQ(chunk.end_index, display_item_list_.size() - 1); DCHECK_EQ(chunk.end_index, paint_artifact_->GetDisplayItemList().size() - 1);
const auto& item = display_item_list_.Last(); const auto& item = paint_artifact_->GetDisplayItemList().Last();
chunk.bounds.Unite(item.VisualRect()); chunk.bounds.Unite(item.VisualRect());
if (item.DrawsContent()) if (item.DrawsContent())
chunk.drawable_bounds.Unite(item.VisualRect()); chunk.drawable_bounds.Unite(item.VisualRect());
......
...@@ -132,9 +132,8 @@ class TestPaintArtifact { ...@@ -132,9 +132,8 @@ class TestPaintArtifact {
void DidAddDisplayItem(); void DidAddDisplayItem();
Vector<std::unique_ptr<FakeDisplayItemClient>> clients_; Vector<std::unique_ptr<FakeDisplayItemClient>> clients_;
scoped_refptr<PaintArtifact> paint_artifact_ =
DisplayItemList display_item_list_; base::MakeRefCounted<PaintArtifact>();
Vector<PaintChunk> paint_chunks_;
}; };
} // namespace blink } // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment