blob: 9889add4240ff9cf93fab736fde26d61810be3ab [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/bind.h"
#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"
namespace blink {
ContentLayerClientImpl::ContentLayerClientImpl()
: cc_picture_layer_(cc::PictureLayer::Create(this)),
raster_invalidator_(
base::BindRepeating(&ContentLayerClientImpl::InvalidateRect,
base::Unretained(this))),
layer_state_(PropertyTreeState::Uninitialized()) {
cc_picture_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr());
}
ContentLayerClientImpl::~ContentLayerClientImpl() {
cc_picture_layer_->ClearClient();
}
static int GetTransformId(const TransformPaintPropertyNode* transform,
ContentLayerClientImpl::LayerAsJSONContext& context) {
if (!transform)
return 0;
auto transform_lookup_result = context.transform_id_map.find(transform);
if (transform_lookup_result != context.transform_id_map.end())
return transform_lookup_result->value;
int parent_id = GetTransformId(transform->Parent(), context);
if (transform->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 = std::make_unique<JSONObject>();
json->SetInteger("id", transform_id);
if (parent_id)
json->SetInteger("parent", parent_id);
if (!transform->IsIdentity())
json->SetArray("transform", TransformAsJSONArray(transform->SlowMatrix()));
if (!transform->IsIdentityOr2DTranslation() &&
!transform->Matrix().IsIdentityOrTranslation())
json->SetArray("origin", PointAsJSONArray(transform->Origin()));
if (!transform->FlattensInheritedTransform())
json->SetBoolean("flattenInheritedTransform", false);
if (auto rendering_context = transform->RenderingContextId()) {
auto context_lookup_result =
context.rendering_context_map.find(rendering_context);
int rendering_id = context.rendering_context_map.size() + 1;
if (context_lookup_result == context.rendering_context_map.end())
context.rendering_context_map.Set(rendering_context, rendering_id);
else
rendering_id = context_lookup_result->value;
json->SetInteger("renderingContext", rendering_id);
}
if (!context.transforms_json)
context.transforms_json = std::make_unique<JSONArray>();
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 {
auto json = std::make_unique<JSONObject>();
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(const 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", LayerDebugName(layer));
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;
}
std::string ContentLayerClientImpl::LayerDebugName(
const cc::Layer* layer) const {
DCHECK_EQ(layer, cc_picture_layer_.get());
return debug_name_.Utf8();
}
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_ = std::make_unique<JSONArray>();
for (const auto& chunk : paint_chunks) {
auto json = std::make_unique<JSONObject>();
json->SetString("data", chunk.ToString());
json->SetArray("displayItems",
paint_artifact->GetDisplayItemList().SubsequenceAsJSON(
chunk.begin_index, chunk.end_index,
DisplayItemList::kShowOnlyDisplayItemTypes));
paint_chunk_debug_data_->PushObject(std::move(json));
}
#endif
// The raster invalidator will only handle invalidations within a cc::Layer so
// we need this invalidation if the layer's properties have changed.
if (layer_state != layer_state_)
cc_picture_layer_->SetSubtreePropertyChanged();
raster_invalidator_.Generate(paint_artifact, paint_chunks, layer_bounds,
layer_state);
layer_state_ = layer_state;
// Note: cc::Layer API assumes the layer bounds start at (0, 0), but the
// bounding box of a paint chunk does not necessarily start at (0, 0) (and
// could even be negative). Internally the generated layer translates the
// paint chunk to align the bounding box to (0, 0) and we set the layer's
// offset_to_transform_parent with the origin of the paint chunk here.
cc_picture_layer_->SetOffsetToTransformParent(
layer_bounds.OffsetFromOrigin());
cc_picture_layer_->SetBounds(layer_bounds.size());
cc_picture_layer_->SetIsDrawable(true);
cc_picture_layer_->SetHitTestable(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));
cc_picture_layer_->SetSafeOpaqueBackgroundColor(
paint_chunks[0].safe_opaque_background_color);
// TODO(masonfreed): We don't need to set the background color here; only the
// safe opaque background color matters. But making that change would require
// rebaselining 787 tests to remove the "background_color" property from the
// layer dumps.
cc_picture_layer_->SetBackgroundColor(
paint_chunks[0].safe_opaque_background_color);
return cc_picture_layer_;
}
} // namespace blink