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 {
const EffectPaintPropertyNodeOrAlias& e,
const IntRect& bounds = IntRect(0, 0, 100, 100),
const base::Optional<IntRect>& drawable_bounds = base::nullopt) {
auto& items = paint_artifact_->GetDisplayItemList();
auto i = items.size();
items.AllocateAndConstruct<DrawingDisplayItem>(
DefaultId().client, DefaultId().type,
drawable_bounds ? *drawable_bounds : bounds, std::move(record));
auto& chunks = paint_artifact_->PaintChunks();
chunks.emplace_back(i, i + 1, DefaultId(),
PropertyTreeStateOrAlias(t, c, e));
chunks.back().bounds = bounds;
......@@ -193,19 +196,19 @@ class TestChunks {
const ClipPaintPropertyNode& c,
const EffectPaintPropertyNode& e,
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.back().bounds = bounds;
}
PaintChunkSubset Build() {
return PaintChunkSubset(base::MakeRefCounted<PaintArtifact>(
std::move(items), std::move(chunks)));
return PaintChunkSubset(std::move(paint_artifact_));
}
private:
Vector<PaintChunk> chunks;
DisplayItemList items;
scoped_refptr<PaintArtifact> paint_artifact_ =
base::MakeRefCounted<PaintArtifact>();
};
TEST_P(PaintChunksToCcLayerTest, EffectGroupingSimple) {
......
......@@ -12,12 +12,6 @@
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,
const DisplayItemClient& display_item_client,
DisplayItem::Type display_item_type,
......@@ -44,11 +38,6 @@ DrawingRecorder::DrawingRecorder(GraphicsContext& context,
context.SetDOMNodeId(dom_node_id);
}
}
#if DCHECK_IS_ON()
initial_display_item_list_size_ =
context_.GetPaintController().NewDisplayItemList().size();
#endif
}
DrawingRecorder::~DrawingRecorder() {
......@@ -57,13 +46,6 @@ DrawingRecorder::~DrawingRecorder() {
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>(
client_, type_, visual_rect_, context_.EndRecording());
}
......
......@@ -84,11 +84,6 @@ class PLATFORM_EXPORT DrawingRecorder {
IntRect visual_rect_;
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);
};
......
......@@ -14,13 +14,6 @@
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 total_size = sizeof(*this) + display_item_list_.MemoryUsageInBytes() +
chunks_.capacity() * sizeof(chunks_[0]);
......
......@@ -34,9 +34,9 @@ class PLATFORM_EXPORT PaintArtifact final : public RefCounted<PaintArtifact> {
USING_FAST_MALLOC(PaintArtifact);
public:
PaintArtifact() = default;
PaintArtifact(DisplayItemList, Vector<PaintChunk>);
~PaintArtifact();
explicit PaintArtifact(
wtf_size_t initial_display_item_list_capacity_in_bytes = 0)
: display_item_list_(initial_display_item_list_capacity_in_bytes) {}
PaintArtifact(const PaintArtifact& other) = delete;
PaintArtifact& operator=(const PaintArtifact& other) = delete;
......
......@@ -8,11 +8,18 @@
namespace blink {
PaintChunker::PaintChunker()
: current_properties_(PropertyTreeState::Uninitialized()),
force_new_chunk_(true) {}
PaintChunker::~PaintChunker() = default;
void PaintChunker::ResetChunks(Vector<PaintChunk>* chunks) {
if (chunks_) {
FinalizeLastChunkProperties();
SetWillForceNewChunk(true);
current_properties_ = PropertyTreeState::Uninitialized();
}
chunks_ = chunks;
#if DCHECK_IS_ON()
DCHECK(!chunks || chunks->IsEmpty());
DCHECK(IsInInitialState());
#endif
}
#if DCHECK_IS_ON()
bool PaintChunker::IsInInitialState() const {
......@@ -20,7 +27,8 @@ bool PaintChunker::IsInInitialState() const {
return false;
DCHECK_EQ(candidate_background_color_.Rgb(), Color::kTransparent);
DCHECK_EQ(candidate_background_area_, 0u);
DCHECK(chunks_.IsEmpty());
DCHECK(will_force_new_chunk_);
DCHECK(!chunks_ || chunks_->IsEmpty());
return true;
}
#endif
......@@ -41,14 +49,16 @@ void PaintChunker::UpdateCurrentPaintChunkProperties(
}
void PaintChunker::AppendByMoving(PaintChunk&& chunk) {
DCHECK(chunks_);
FinalizeLastChunkProperties();
wtf_size_t next_chunk_begin_index =
chunks_.IsEmpty() ? 0 : LastChunk().end_index;
chunks_.emplace_back(next_chunk_begin_index, std::move(chunk));
chunks_->IsEmpty() ? 0 : chunks_->back().end_index;
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()
DCHECK(chunks_);
// If this DCHECKs are hit we are missing a call to update the properties.
// See: ScopedPaintChunkProperties.
DCHECK(!IsInInitialState());
......@@ -56,28 +66,31 @@ PaintChunk& PaintChunker::EnsureCurrentChunk(const PaintChunk::Id& id) {
DCHECK(current_properties_.IsInitialized());
#endif
if (WillForceNewChunk() || current_properties_ != LastChunk().properties) {
if (WillForceNewChunk() ||
current_properties_ != chunks_->back().properties) {
if (!next_chunk_id_)
next_chunk_id_.emplace(id);
FinalizeLastChunkProperties();
wtf_size_t begin = chunks_.IsEmpty() ? 0 : LastChunk().end_index;
chunks_.emplace_back(begin, begin, *next_chunk_id_, current_properties_);
wtf_size_t begin = chunks_->IsEmpty() ? 0 : chunks_->back().end_index;
chunks_->emplace_back(begin, begin, *next_chunk_id_, current_properties_);
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) {
DCHECK(chunks_);
bool item_forces_new_chunk = item.IsForeignLayer() ||
item.IsGraphicsLayerWrapper() ||
item.IsScrollbar();
if (item_forces_new_chunk)
SetForceNewChunk(true);
SetWillForceNewChunk(true);
auto previous_size = size();
auto& chunk = EnsureCurrentChunk(item.GetId());
bool created_new_chunk = size() > previous_size;
bool created_new_chunk = EnsureCurrentChunk(item.GetId());
auto& chunk = chunks_->back();
chunk.bounds.Unite(item.VisualRect());
if (item.DrawsContent())
......@@ -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
// display item. Otherwise reset force_new_chunk_ to false.
DCHECK(!force_new_chunk_);
DCHECK(!will_force_new_chunk_);
if (item_forces_new_chunk) {
DCHECK(created_new_chunk);
SetForceNewChunk(true);
SetWillForceNewChunk(true);
}
return created_new_chunk;
}
void PaintChunker::AddHitTestDataToCurrentChunk(const PaintChunk::Id& id,
bool PaintChunker::AddHitTestDataToCurrentChunk(const PaintChunk::Id& id,
const IntRect& rect,
TouchAction touch_action) {
// In CompositeAfterPaint, we ensure a paint chunk for correct composited
......@@ -124,14 +137,16 @@ void PaintChunker::AddHitTestDataToCurrentChunk(const PaintChunk::Id& id,
if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
touch_action == TouchAction::kAuto &&
&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);
if (touch_action != TouchAction::kAuto) {
chunk.EnsureHitTestData().touch_action_rects.push_back(
TouchActionRect{rect, touch_action});
}
return created_new_chunk;
}
void PaintChunker::CreateScrollHitTestChunk(
......@@ -154,50 +169,47 @@ void PaintChunker::CreateScrollHitTestChunk(
}
#endif
SetForceNewChunk(true);
auto& chunk = EnsureCurrentChunk(id);
SetWillForceNewChunk(true);
bool created_new_chunk = EnsureCurrentChunk(id);
DCHECK(created_new_chunk);
auto& chunk = chunks_->back();
chunk.bounds.Unite(rect);
auto& hit_test_data = chunk.EnsureHitTestData();
hit_test_data.scroll_translation = scroll_translation;
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,
uint64_t area) {
EnsureCurrentChunk(id);
bool created_new_chunk = EnsureCurrentChunk(id);
if (color != Color::kTransparent &&
(candidate_background_color_ == Color::kTransparent ||
(area >= candidate_background_area_))) {
candidate_background_color_ = color;
candidate_background_area_ = area;
}
return created_new_chunk;
}
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;
LastChunk().known_to_be_opaque =
last_chunk_known_to_be_opaque_region_.Contains(LastChunk().bounds);
auto& chunk = chunks_->back();
chunk.known_to_be_opaque =
last_chunk_known_to_be_opaque_region_.Contains(chunk.bounds);
last_chunk_known_to_be_opaque_region_ = Region();
if (candidate_background_color_ != Color::kTransparent) {
LastChunk().background_color = candidate_background_color_;
LastChunk().background_color_area = candidate_background_area_;
chunk.background_color = candidate_background_color_;
chunk.background_color_area = candidate_background_area_;
}
candidate_background_color_ = Color::kTransparent;
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
......@@ -25,8 +25,11 @@ class PLATFORM_EXPORT PaintChunker final {
DISALLOW_NEW();
public:
PaintChunker();
~PaintChunker();
explicit PaintChunker(Vector<PaintChunk>& chunks) { ResetChunks(&chunks); }
// 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()
bool IsInInitialState() const;
......@@ -43,28 +46,20 @@ class PLATFORM_EXPORT PaintChunker final {
// display item and then automatically resets the status. Some special display
// item (e.g. ForeignLayerDisplayItem) also automatically sets the status on
// before and after the item to force a dedicated paint chunk.
void SetForceNewChunk(bool force) {
force_new_chunk_ = force;
void SetWillForceNewChunk(bool force) {
will_force_new_chunk_ = force;
next_chunk_id_ = base::nullopt;
}
bool WillForceNewChunk() const {
return force_new_chunk_ || chunks_.IsEmpty();
}
bool WillForceNewChunk() const { return will_force_new_chunk_; }
void AppendByMoving(PaintChunk&&);
// Returns true if a new chunk is created.
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.
// Otherwise it's ignored.
void AddHitTestDataToCurrentChunk(const PaintChunk::Id&,
// Otherwise it's ignored. Returns true if a new chunk is added.
bool AddHitTestDataToCurrentChunk(const PaintChunk::Id&,
const IntRect&,
TouchAction);
void CreateScrollHitTestChunk(
......@@ -72,20 +67,21 @@ class PLATFORM_EXPORT PaintChunker final {
const TransformPaintPropertyNode* scroll_translation,
const IntRect&);
void ProcessBackgroundColorCandidate(const PaintChunk::Id& id,
// Returns true if a new chunk is created.
bool ProcessBackgroundColorCandidate(const PaintChunk::Id& id,
Color color,
uint64_t area);
void EnsureChunk() { EnsureCurrentChunk(*next_chunk_id_); }
// Releases the generated paint chunk list and raster invalidations and
// resets the state of this object.
Vector<PaintChunk> ReleasePaintChunks();
// Returns true if a new chunk is created.
bool EnsureChunk() { return EnsureCurrentChunk(*next_chunk_id_); }
private:
PaintChunk& EnsureCurrentChunk(const PaintChunk::Id&);
// Returns true if a new chunk is created.
bool EnsureCurrentChunk(const PaintChunk::Id&);
void FinalizeLastChunkProperties();
Vector<PaintChunk> chunks_;
Vector<PaintChunk>* chunks_ = nullptr;
// 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
......@@ -95,14 +91,15 @@ class PLATFORM_EXPORT PaintChunker final {
// forced to create a new chunk).
base::Optional<PaintChunk::Id> next_chunk_id_;
PropertyTreeStateOrAlias current_properties_;
PropertyTreeStateOrAlias current_properties_ =
PropertyTreeState::Uninitialized();
Region last_chunk_known_to_be_opaque_region_;
// 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
// before and after subsequences by calling ForceNewChunk().
bool force_new_chunk_;
bool will_force_new_chunk_ = true;
Color candidate_background_color_ = Color::kTransparent;
uint64_t candidate_background_area_ = 0;
......
......@@ -93,46 +93,31 @@ class PLATFORM_EXPORT PaintController {
void UpdateCurrentPaintChunkProperties(const PaintChunk::Id*,
const PropertyTreeStateOrAlias&);
const PropertyTreeStateOrAlias& CurrentPaintChunkProperties() const {
return new_paint_chunks_.CurrentPaintChunkProperties();
return paint_chunker_.CurrentPaintChunkProperties();
}
// See PaintChunker for documentation of the following methods.
wtf_size_t NumNewChunks() const { return new_paint_chunks_.size(); }
void SetForceNewChunk(bool force) {
new_paint_chunks_.SetForceNewChunk(force);
}
bool WillForceNewChunk() const {
return new_paint_chunks_.WillForceNewChunk();
}
const IntRect& LastChunkBounds() const {
return new_paint_chunks_.LastChunk().bounds;
void SetWillForceNewChunk(bool force) {
paint_chunker_.SetWillForceNewChunk(force);
}
bool WillForceNewChunk() const { return paint_chunker_.WillForceNewChunk(); }
void EnsureChunk() { new_paint_chunks_.EnsureChunk(); }
void RecordHitTestData(const DisplayItemClient& client,
const IntRect& rect,
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 EnsureChunk();
void RecordHitTestData(const DisplayItemClient&, const IntRect&, TouchAction);
void RecordScrollHitTestData(
const DisplayItemClient& client,
DisplayItem::Type type,
const DisplayItemClient&,
DisplayItem::Type,
const TransformPaintPropertyNode* scroll_translation,
const IntRect& rect) {
PaintChunk::Id id(client, type, current_fragment_);
CheckDuplicatePaintChunkId(id);
new_paint_chunks_.CreateScrollHitTestChunk(id, scroll_translation, rect);
}
const IntRect&);
void SetPossibleBackgroundColor(const DisplayItemClient&,
Color,
uint64_t area);
void SetPossibleBackgroundColor(const DisplayItemClient& client,
Color color,
uint64_t area) {
PaintChunk::Id id = {client, DisplayItem::kBoxDecorationBackground,
current_fragment_};
new_paint_chunks_.ProcessBackgroundColorCandidate(id, color, area);
wtf_size_t NumNewChunks() const {
return new_paint_artifact_->PaintChunks().size();
}
const IntRect& LastChunkBounds() const {
return new_paint_artifact_->PaintChunks().back().bounds;
}
template <typename DisplayItemClass, typename... Args>
......@@ -147,7 +132,8 @@ class PLATFORM_EXPORT PaintController {
"kDisplayItemAlignment.");
DisplayItemClass& display_item =
new_display_item_list_.AllocateAndConstruct<DisplayItemClass>(
new_paint_artifact_->GetDisplayItemList()
.AllocateAndConstruct<DisplayItemClass>(
std::forward<Args>(args)...);
display_item.SetFragment(current_fragment_);
ProcessNewItem(display_item);
......@@ -210,15 +196,12 @@ class PLATFORM_EXPORT PaintController {
// Get the artifact generated after the last commit.
const PaintArtifact& GetPaintArtifact() const {
#if DCHECK_IS_ON()
DCHECK(new_display_item_list_.IsEmpty());
DCHECK(new_paint_chunks_.IsInInitialState());
DCHECK(current_paint_artifact_);
#endif
CheckNoNewPaint();
return *current_paint_artifact_;
}
scoped_refptr<const PaintArtifact> GetPaintArtifactShared() const {
return base::WrapRefCounted(&GetPaintArtifact());
CheckNoNewPaint();
return current_paint_artifact_;
}
const DisplayItemList& GetDisplayItemList() const {
return GetPaintArtifact().GetDisplayItemList();
......@@ -227,6 +210,11 @@ class PLATFORM_EXPORT PaintController {
return GetPaintArtifact().PaintChunks();
}
scoped_refptr<const PaintArtifact> GetNewPaintArtifactShared() const {
DCHECK(new_paint_artifact_);
return new_paint_artifact_;
}
class ScopedBenchmarkMode {
STACK_ALLOCATED();
......@@ -255,10 +243,6 @@ class PLATFORM_EXPORT PaintController {
void SetTextPainted();
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()
void ShowCompactDebugData() const;
void ShowDebugData() const;
......@@ -403,6 +387,14 @@ class PLATFORM_EXPORT PaintController {
bool ShouldInvalidateDisplayItemForBenchmark();
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_;
// The last paint artifact after CommitNewDisplayItems().
......@@ -410,8 +402,8 @@ class PLATFORM_EXPORT PaintController {
scoped_refptr<PaintArtifact> current_paint_artifact_;
// Data being used to build the next paint artifact.
DisplayItemList new_display_item_list_;
PaintChunker new_paint_chunks_;
scoped_refptr<PaintArtifact> new_paint_artifact_;
PaintChunker paint_chunker_;
bool cache_is_all_invalid_ = true;
bool committed_ = false;
......@@ -486,7 +478,7 @@ class PLATFORM_EXPORT PaintController {
static size_t sum_num_subsequences_;
static size_t sum_num_cached_subsequences_;
class DisplayItemListAsJSON;
class PaintArtifactAsJSON;
DISALLOW_COPY_AND_ASSIGN(PaintController);
};
......
......@@ -10,17 +10,17 @@
namespace blink {
class PaintController::DisplayItemListAsJSON {
class PaintController::PaintArtifactAsJSON {
STACK_ALLOCATED();
public:
DisplayItemListAsJSON(const DisplayItemList&,
PaintArtifactAsJSON(const PaintArtifact&,
const CachedSubsequenceMap&,
const Vector<PaintChunk>&,
DisplayItemList::JsonFlags);
String ToString() {
return ChunksAsJSONArrayRecursive(0, chunks_.size())->ToPrettyJSONString();
return ChunksAsJSONArrayRecursive(0, artifact_.PaintChunks().size())
->ToPrettyJSONString();
}
private:
......@@ -35,21 +35,17 @@ class PaintController::DisplayItemListAsJSON {
wtf_size_t end_chunk_index;
};
const DisplayItemList& list_;
const PaintArtifact& artifact_;
Vector<SubsequenceInfo> subsequences_;
Vector<SubsequenceInfo>::const_iterator current_subsequence_;
const Vector<PaintChunk>& chunks_;
Vector<SubsequenceInfo>::const_iterator next_subsequence_;
DisplayItemList::JsonFlags flags_;
};
PaintController::DisplayItemListAsJSON::DisplayItemListAsJSON(
const DisplayItemList& list,
PaintController::PaintArtifactAsJSON::PaintArtifactAsJSON(
const PaintArtifact& artifact,
const CachedSubsequenceMap& subsequence_map,
const Vector<PaintChunk>& chunks,
DisplayItemList::JsonFlags flags)
: list_(list),
chunks_(chunks),
flags_(flags) {
: artifact_(artifact), flags_(flags) {
for (const auto& item : subsequence_map) {
subsequences_.push_back(SubsequenceInfo{
item.key, item.value.start_chunk_index, item.value.end_chunk_index});
......@@ -61,13 +57,13 @@ PaintController::DisplayItemListAsJSON::DisplayItemListAsJSON(
: a.start_chunk_index < b.start_chunk_index;
});
current_subsequence_ = subsequences_.begin();
next_subsequence_ = subsequences_.begin();
}
std::unique_ptr<JSONObject>
PaintController::DisplayItemListAsJSON::SubsequenceAsJSONObjectRecursive() {
const auto& subsequence = *current_subsequence_;
++current_subsequence_;
PaintController::PaintArtifactAsJSON::SubsequenceAsJSONObjectRecursive() {
const auto& subsequence = *next_subsequence_;
++next_subsequence_;
auto json_object = std::make_unique<JSONObject>();
......@@ -82,15 +78,15 @@ PaintController::DisplayItemListAsJSON::SubsequenceAsJSONObjectRecursive() {
}
std::unique_ptr<JSONArray>
PaintController::DisplayItemListAsJSON::ChunksAsJSONArrayRecursive(
PaintController::PaintArtifactAsJSON::ChunksAsJSONArrayRecursive(
wtf_size_t start_chunk_index,
wtf_size_t end_chunk_index) {
auto array = std::make_unique<JSONArray>();
auto chunk_index = start_chunk_index;
while (current_subsequence_ != subsequences_.end() &&
current_subsequence_->start_chunk_index < end_chunk_index) {
const auto& subsequence = *current_subsequence_;
while (next_subsequence_ != subsequences_.end() &&
next_subsequence_->start_chunk_index < end_chunk_index) {
const auto& subsequence = *next_subsequence_;
DCHECK_GE(subsequence.start_chunk_index, chunk_index);
DCHECK_LE(subsequence.end_chunk_index, end_chunk_index);
......@@ -106,13 +102,13 @@ PaintController::DisplayItemListAsJSON::ChunksAsJSONArrayRecursive(
return array;
}
void PaintController::DisplayItemListAsJSON::AppendChunksAsJSON(
void PaintController::PaintArtifactAsJSON::AppendChunksAsJSON(
wtf_size_t start_chunk_index,
wtf_size_t end_chunk_index,
JSONArray& json_array) {
DCHECK_GT(end_chunk_index, start_chunk_index);
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>();
json_object->SetString(
......@@ -122,16 +118,15 @@ void PaintController::DisplayItemListAsJSON::AppendChunksAsJSON(
if (flags_ & DisplayItemList::kShowPaintRecords)
json_object->SetString("chunkData", chunk.ToString());
json_object->SetArray(
"displayItems",
json_object->SetArray("displayItems",
DisplayItemList::DisplayItemsAsJSON(
list_.ItemsInRange(chunk.begin_index, chunk.end_index), flags_));
artifact_.DisplayItemsInChunk(i), flags_));
json_array.PushObject(std::move(json_object));
}
}
String PaintController::DisplayItemListAsJSON::ClientName(
String PaintController::PaintArtifactAsJSON::ClientName(
const DisplayItemClient& client) const {
return client.SafeDebugName(flags_ & DisplayItemList::kClientKnownToBeAlive);
}
......@@ -142,22 +137,25 @@ void PaintController::ShowDebugDataInternal(
// The clients in the current list are known to be alive before FinishCycle().
if (committed_)
current_list_flags |= DisplayItemList::kClientKnownToBeAlive;
LOG(INFO) << "current display item list: "
<< DisplayItemListAsJSON(
current_paint_artifact_->GetDisplayItemList(),
LOG(INFO) << "current paint artifact: "
<< (current_paint_artifact_
? PaintArtifactAsJSON(*current_paint_artifact_,
current_cached_subsequences_,
current_paint_artifact_->PaintChunks(), current_list_flags)
current_list_flags)
.ToString()
.Utf8();
LOG(INFO) << "new display item list: "
<< DisplayItemListAsJSON(
new_display_item_list_, new_cached_subsequences_,
new_paint_chunks_.PaintChunks(),
.Utf8()
: "null");
LOG(INFO)
<< "new paint artifact: "
<< (new_paint_artifact_
? PaintArtifactAsJSON(
*new_paint_artifact_, new_cached_subsequences_,
// The clients in new_display_item_list_ are all alive.
flags | DisplayItemList::kClientKnownToBeAlive)
.ToString()
.Utf8();
.Utf8()
: "null");
}
void PaintController::ShowCompactDebugData() const {
......
......@@ -844,6 +844,85 @@ TEST_P(PaintControllerTest, CachedSubsequenceAndDisplayItemsSwapOrder) {
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) {
GraphicsContext context(GetPaintController());
FakeDisplayItemClient root("root");
......@@ -1246,16 +1325,18 @@ TEST_P(PaintControllerTest, SkipCache) {
GetPaintController().EndSkippingCache();
// 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),
IsSameId(&content, kForegroundType),
IsSameId(&content, kForegroundType),
IsSameId(&content, kForegroundType)));
EXPECT_NE(record1, static_cast<const DrawingDisplayItem&>(
GetPaintController().NewDisplayItemList()[1])
EXPECT_NE(record1,
static_cast<const DrawingDisplayItem&>(display_item_list[1])
.GetPaintRecord());
EXPECT_NE(record2, static_cast<const DrawingDisplayItem&>(
GetPaintController().NewDisplayItemList()[2])
EXPECT_NE(record2,
static_cast<const DrawingDisplayItem&>(display_item_list[2])
.GetPaintRecord());
CommitAndFinishCycle();
......
......@@ -46,7 +46,7 @@ class ScopedPaintChunkHint {
previous_force_new_chunk_(paint_controller_.WillForceNewChunk()) {
if (!previous_force_new_chunk_ && previous_num_chunks_ &&
!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
// use the specified id.
paint_chunk_properties_.emplace(paint_controller, properties, client, type);
......@@ -55,7 +55,7 @@ class ScopedPaintChunkHint {
~ScopedPaintChunkHint() {
paint_chunk_properties_ = base::nullopt;
if (!HasCreatedPaintChunk())
paint_controller_.SetForceNewChunk(previous_force_new_chunk_);
paint_controller_.SetWillForceNewChunk(previous_force_new_chunk_);
}
bool HasCreatedPaintChunk() const {
......
......@@ -38,17 +38,18 @@ TestPaintArtifact& TestPaintArtifact::Chunk(int id) {
TestPaintArtifact& TestPaintArtifact::Chunk(DisplayItemClient& client,
DisplayItem::Type type) {
paint_chunks_.push_back(
PaintChunk(display_item_list_.size(), display_item_list_.size(),
PaintChunk::Id(client, type), PropertyTreeState::Root()));
auto& display_item_list = paint_artifact_->GetDisplayItemList();
paint_artifact_->PaintChunks().emplace_back(
display_item_list.size(), display_item_list.size(),
PaintChunk::Id(client, type), PropertyTreeState::Root());
// 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;
}
TestPaintArtifact& TestPaintArtifact::Properties(
const PropertyTreeStateOrAlias& properties) {
paint_chunks_.back().properties = properties;
paint_artifact_->PaintChunks().back().properties = properties;
return *this;
}
......@@ -66,7 +67,8 @@ TestPaintArtifact& TestPaintArtifact::ForeignLayer(
scoped_refptr<cc::Layer> layer,
const IntPoint& offset) {
DEFINE_STATIC_LOCAL(LiteralDebugNameClient, client, ("ForeignLayer"));
display_item_list_.AllocateAndConstruct<ForeignLayerDisplayItem>(
paint_artifact_->GetDisplayItemList()
.AllocateAndConstruct<ForeignLayerDisplayItem>(
client, DisplayItem::kForeignLayerFirst, std::move(layer), offset);
DidAddDisplayItem();
return *this;
......@@ -82,7 +84,8 @@ TestPaintArtifact& TestPaintArtifact::RectDrawing(DisplayItemClient& client,
flags.setColor(color.Rgb());
canvas->drawRect(bounds, flags);
}
display_item_list_.AllocateAndConstruct<DrawingDisplayItem>(
paint_artifact_->GetDisplayItemList()
.AllocateAndConstruct<DrawingDisplayItem>(
client, DisplayItem::kDrawingFirst, bounds,
recorder.finishRecordingAsPicture());
DidAddDisplayItem();
......@@ -92,43 +95,44 @@ TestPaintArtifact& TestPaintArtifact::RectDrawing(DisplayItemClient& client,
TestPaintArtifact& TestPaintArtifact::ScrollHitTest(
DisplayItemClient& client,
const TransformPaintPropertyNode* scroll_translation) {
paint_chunks_.back().EnsureHitTestData().scroll_translation =
paint_artifact_->PaintChunks().back().EnsureHitTestData().scroll_translation =
scroll_translation;
return *this;
}
TestPaintArtifact& TestPaintArtifact::SetRasterEffectOutset(
RasterEffectOutset outset) {
paint_chunks_.back().raster_effect_outset = outset;
paint_artifact_->PaintChunks().back().raster_effect_outset = outset;
return *this;
}
TestPaintArtifact& TestPaintArtifact::KnownToBeOpaque() {
paint_chunks_.back().known_to_be_opaque = true;
paint_artifact_->PaintChunks().back().known_to_be_opaque = true;
return *this;
}
TestPaintArtifact& TestPaintArtifact::Bounds(const IntRect& bounds) {
paint_chunks_.back().bounds = bounds;
paint_chunks_.back().drawable_bounds = bounds;
auto& chunk = paint_artifact_->PaintChunks().back();
chunk.bounds = bounds;
chunk.drawable_bounds = bounds;
return *this;
}
TestPaintArtifact& TestPaintArtifact::DrawableBounds(
const IntRect& drawable_bounds) {
paint_chunks_.back().drawable_bounds = drawable_bounds;
DCHECK(paint_chunks_.back().bounds.Contains(drawable_bounds));
auto& chunk = paint_artifact_->PaintChunks().back();
chunk.drawable_bounds = drawable_bounds;
DCHECK(chunk.bounds.Contains(drawable_bounds));
return *this;
}
TestPaintArtifact& TestPaintArtifact::Uncacheable() {
paint_chunks_.back().is_cacheable = false;
paint_artifact_->PaintChunks().back().is_cacheable = false;
return *this;
}
scoped_refptr<PaintArtifact> TestPaintArtifact::Build() {
return base::MakeRefCounted<PaintArtifact>(std::move(display_item_list_),
std::move(paint_chunks_));
return std::move(paint_artifact_);
}
FakeDisplayItemClient& TestPaintArtifact::NewClient() {
......@@ -141,9 +145,9 @@ FakeDisplayItemClient& TestPaintArtifact::Client(wtf_size_t i) const {
}
void TestPaintArtifact::DidAddDisplayItem() {
auto& chunk = paint_chunks_.back();
DCHECK_EQ(chunk.end_index, display_item_list_.size() - 1);
const auto& item = display_item_list_.Last();
auto& chunk = paint_artifact_->PaintChunks().back();
DCHECK_EQ(chunk.end_index, paint_artifact_->GetDisplayItemList().size() - 1);
const auto& item = paint_artifact_->GetDisplayItemList().Last();
chunk.bounds.Unite(item.VisualRect());
if (item.DrawsContent())
chunk.drawable_bounds.Unite(item.VisualRect());
......
......@@ -132,9 +132,8 @@ class TestPaintArtifact {
void DidAddDisplayItem();
Vector<std::unique_ptr<FakeDisplayItemClient>> clients_;
DisplayItemList display_item_list_;
Vector<PaintChunk> paint_chunks_;
scoped_refptr<PaintArtifact> paint_artifact_ =
base::MakeRefCounted<PaintArtifact>();
};
} // 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