blob: 2d0437b79a926931d6c739c4220e764219751c53 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/platform/graphics/compositing/content_layer_client_impl.h"
#include <memory>
#include "base/optional.h"
#include "base/trace_event/traced_value.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/paint_op_buffer.h"
#include "third_party/blink/renderer/platform/geometry/geometry_as_json.h"
#include "third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h"
#include "third_party/blink/renderer/platform/graphics/logging_canvas.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item_list.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_chunk_subset.h"
#include "third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h"
#include "third_party/blink/renderer/platform/json/json_values.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
namespace blink {
ContentLayerClientImpl::ContentLayerClientImpl()
: cc_picture_layer_(cc::PictureLayer::Create(this)),
raster_invalidator_([this](const IntRect& rect) {
cc_picture_layer_->SetNeedsDisplayRect(rect);
}),
layer_state_(nullptr, nullptr, nullptr),
weak_ptr_factory_(this) {
cc_picture_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr());
}
ContentLayerClientImpl::~ContentLayerClientImpl() = default;
static int GetTransformId(const TransformPaintPropertyNode* transform,
ContentLayerClientImpl::LayerAsJSONContext& context) {
if (!transform)
return 0;
auto it = context.transform_id_map.find(transform);
if (it != context.transform_id_map.end())
return it->value;
int parent_id = GetTransformId(transform->Parent(), context);
if (transform->Matrix().IsIdentity() && !transform->RenderingContextId()) {
context.transform_id_map.Set(transform, parent_id);
return parent_id;
}
int transform_id = context.next_transform_id++;
context.transform_id_map.Set(transform, transform_id);
auto json = JSONObject::Create();
json->SetInteger("id", transform_id);
if (parent_id)
json->SetInteger("parent", parent_id);
if (!transform->Matrix().IsIdentity())
json->SetArray("transform", TransformAsJSONArray(transform->Matrix()));
if (!transform->Matrix().IsIdentityOrTranslation())
json->SetArray("origin", PointAsJSONArray(transform->Origin()));
if (!transform->FlattensInheritedTransform())
json->SetBoolean("flattenInheritedTransform", false);
if (auto rendering_context = transform->RenderingContextId()) {
auto it = context.rendering_context_map.find(rendering_context);
int rendering_id = context.rendering_context_map.size() + 1;
if (it == context.rendering_context_map.end())
context.rendering_context_map.Set(rendering_context, rendering_id);
else
rendering_id = it->value;
json->SetInteger("renderingContext", rendering_id);
}
if (!context.transforms_json)
context.transforms_json = JSONArray::Create();
context.transforms_json->PushObject(std::move(json));
return transform_id;
}
// This is the CAP version of GraphicsLayer::LayerAsJSONInternal().
std::unique_ptr<JSONObject> ContentLayerClientImpl::LayerAsJSON(
LayerAsJSONContext& context) const {
std::unique_ptr<JSONObject> json = JSONObject::Create();
json->SetString("name", debug_name_);
if (context.flags & kLayerTreeIncludesDebugInfo)
json->SetString("this", String::Format("%p", cc_picture_layer_.get()));
FloatPoint position(cc_picture_layer_->offset_to_transform_parent().x(),
cc_picture_layer_->offset_to_transform_parent().y());
if (position != FloatPoint())
json->SetArray("position", PointAsJSONArray(position));
IntSize bounds(cc_picture_layer_->bounds().width(),
cc_picture_layer_->bounds().height());
if (!bounds.IsEmpty())
json->SetArray("bounds", SizeAsJSONArray(bounds));
if (cc_picture_layer_->contents_opaque())
json->SetBoolean("contentsOpaque", true);
if (!cc_picture_layer_->DrawsContent())
json->SetBoolean("drawsContent", false);
if (!cc_picture_layer_->double_sided())
json->SetString("backfaceVisibility", "hidden");
Color background_color(cc_picture_layer_->background_color());
if (background_color.Alpha()) {
json->SetString("backgroundColor",
background_color.NameForLayoutTreeAsText());
}
#if DCHECK_IS_ON()
if (context.flags & kLayerTreeIncludesDebugInfo)
json->SetValue("paintChunkContents", paint_chunk_debug_data_->Clone());
#endif
if ((context.flags & kLayerTreeIncludesPaintInvalidations) &&
raster_invalidator_.GetTracking())
raster_invalidator_.GetTracking()->AsJSON(json.get());
if (int transform_id = GetTransformId(layer_state_.Transform(), context))
json->SetInteger("transform", transform_id);
#if DCHECK_IS_ON()
if (context.flags & kLayerTreeIncludesPaintRecords) {
LoggingCanvas canvas;
cc_display_item_list_->Raster(&canvas);
json->SetValue("paintRecord", canvas.Log());
}
#endif
return json;
}
std::unique_ptr<base::trace_event::TracedValue>
ContentLayerClientImpl::TakeDebugInfo(cc::Layer* layer) {
DCHECK_EQ(layer, cc_picture_layer_.get());
auto traced_value = std::make_unique<base::trace_event::TracedValue>();
traced_value->SetString("layer_name",
WTF::StringUTF8Adaptor(debug_name_).AsStringPiece());
if (auto* tracking = raster_invalidator_.GetTracking()) {
tracking->AddToTracedValue(*traced_value);
tracking->ClearInvalidations();
}
// TODO(wangxianzhu): Do we need compositing_reasons,
// squashing_disallowed_reasons and owner_node_id?
return traced_value;
}
static SkColor DisplayItemBackgroundColor(const DisplayItem& item) {
if (item.GetType() != DisplayItem::kBoxDecorationBackground &&
item.GetType() != DisplayItem::kDocumentBackground)
return SK_ColorTRANSPARENT;
const auto& drawing_item = static_cast<const DrawingDisplayItem&>(item);
const auto record = drawing_item.GetPaintRecord();
if (!record)
return SK_ColorTRANSPARENT;
for (cc::PaintOpBuffer::Iterator it(record.get()); it; ++it) {
const auto* op = *it;
if (op->GetType() == cc::PaintOpType::DrawRect ||
op->GetType() == cc::PaintOpType::DrawRRect) {
const auto& flags = static_cast<const cc::PaintOpWithFlags*>(op)->flags;
// Skip op with looper which may modify the color.
if (!flags.getLooper() && flags.getStyle() == cc::PaintFlags::kFill_Style)
return flags.getColor();
}
}
return SK_ColorTRANSPARENT;
}
scoped_refptr<cc::PictureLayer> ContentLayerClientImpl::UpdateCcPictureLayer(
scoped_refptr<const PaintArtifact> paint_artifact,
const PaintChunkSubset& paint_chunks,
const gfx::Rect& layer_bounds,
const PropertyTreeState& layer_state) {
if (paint_chunks[0].is_cacheable)
id_.emplace(paint_chunks[0].id);
else
id_ = base::nullopt;
// TODO(wangxianzhu): Avoid calling DebugName() in official release build.
debug_name_ = paint_chunks[0].id.client.DebugName();
const auto& display_item_list = paint_artifact->GetDisplayItemList();
#if DCHECK_IS_ON()
paint_chunk_debug_data_ = JSONArray::Create();
for (const auto& chunk : paint_chunks) {
auto json = JSONObject::Create();
json->SetString("data", chunk.ToString());
json->SetArray("displayItems",
paint_artifact->GetDisplayItemList().SubsequenceAsJSON(
chunk.begin_index, chunk.end_index,
DisplayItemList::kShownOnlyDisplayItemTypes));
paint_chunk_debug_data_->PushObject(std::move(json));
}
#endif
raster_invalidator_.Generate(paint_artifact, paint_chunks, layer_bounds,
layer_state);
layer_state_ = layer_state;
cc_picture_layer_->SetBounds(layer_bounds.size());
cc_picture_layer_->SetIsDrawable(true);
base::Optional<RasterUnderInvalidationCheckingParams> params;
if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) {
params.emplace(*raster_invalidator_.GetTracking(),
IntRect(0, 0, layer_bounds.width(), layer_bounds.height()),
debug_name_);
}
cc_display_item_list_ = PaintChunksToCcLayer::Convert(
paint_chunks, layer_state, layer_bounds.OffsetFromOrigin(),
display_item_list, cc::DisplayItemList::kTopLevelDisplayItemList,
base::OptionalOrNullptr(params));
if (paint_chunks[0].size()) {
cc_picture_layer_->SetBackgroundColor(DisplayItemBackgroundColor(
display_item_list[paint_chunks[0].begin_index]));
}
return cc_picture_layer_;
}
} // namespace blink