diff options
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc')
-rw-r--r-- | chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc | 1482 |
1 files changed, 1482 insertions, 0 deletions
diff --git a/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc new file mode 100644 index 00000000000..09694f3d582 --- /dev/null +++ b/chromium/third_party/blink/renderer/platform/graphics/graphics_layer.cc @@ -0,0 +1,1482 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "third_party/blink/renderer/platform/graphics/graphics_layer.h" + +#include <algorithm> +#include <cmath> +#include <memory> +#include <utility> +#include "SkMatrix44.h" +#include "base/memory/ptr_util.h" +#include "base/trace_event/trace_event_argument.h" +#include "cc/layers/layer.h" +#include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/public/platform/web_compositor_support.h" +#include "third_party/blink/public/platform/web_display_item_list.h" +#include "third_party/blink/public/platform/web_float_point.h" +#include "third_party/blink/public/platform/web_float_rect.h" +#include "third_party/blink/public/platform/web_layer.h" +#include "third_party/blink/public/platform/web_point.h" +#include "third_party/blink/public/platform/web_size.h" +#include "third_party/blink/renderer/platform/bindings/runtime_call_stats.h" +#include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h" +#include "third_party/blink/renderer/platform/drag_image.h" +#include "third_party/blink/renderer/platform/geometry/float_rect.h" +#include "third_party/blink/renderer/platform/geometry/geometry_as_json.h" +#include "third_party/blink/renderer/platform/geometry/layout_rect.h" +#include "third_party/blink/renderer/platform/geometry/region.h" +#include "third_party/blink/renderer/platform/graphics/bitmap_image.h" +#include "third_party/blink/renderer/platform/graphics/compositing/composited_layer_raster_invalidator.h" +#include "third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h" +#include "third_party/blink/renderer/platform/graphics/compositor_filter_operations.h" +#include "third_party/blink/renderer/platform/graphics/first_paint_invalidation_tracking.h" +#include "third_party/blink/renderer/platform/graphics/graphics_context.h" +#include "third_party/blink/renderer/platform/graphics/image.h" +#include "third_party/blink/renderer/platform/graphics/link_highlight.h" +#include "third_party/blink/renderer/platform/graphics/logging_canvas.h" +#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h" +#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h" +#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h" +#include "third_party/blink/renderer/platform/graphics/paint/raster_invalidation_tracking.h" +#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" +#include "third_party/blink/renderer/platform/json/json_values.h" +#include "third_party/blink/renderer/platform/scroll/scroll_snap_data.h" +#include "third_party/blink/renderer/platform/scroll/scrollable_area.h" +#include "third_party/blink/renderer/platform/text/text_stream.h" +#include "third_party/blink/renderer/platform/wtf/hash_map.h" +#include "third_party/blink/renderer/platform/wtf/hash_set.h" +#include "third_party/blink/renderer/platform/wtf/math_extras.h" +#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" +#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" +#include "third_party/blink/renderer/platform/wtf/time.h" + +namespace blink { + +std::unique_ptr<GraphicsLayer> GraphicsLayer::Create( + GraphicsLayerClient& client) { + return base::WrapUnique(new GraphicsLayer(client)); +} + +GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client) + : client_(client), + background_color_(Color::kTransparent), + opacity_(1), + blend_mode_(WebBlendMode::kNormal), + has_transform_origin_(false), + contents_opaque_(false), + should_flatten_transform_(true), + backface_visibility_(true), + draws_content_(false), + contents_visible_(true), + is_root_for_isolated_group_(false), + hit_testable_without_draws_content_(false), + needs_check_raster_invalidation_(false), + has_scroll_parent_(false), + has_clip_parent_(false), + painted_(false), + painting_phase_(kGraphicsLayerPaintAllWithOverflowClip), + parent_(nullptr), + mask_layer_(nullptr), + contents_clipping_mask_layer_(nullptr), + paint_count_(0), + contents_layer_(nullptr), + contents_layer_id_(0), + scrollable_area_(nullptr), + rendering_context3d_(0), + weak_ptr_factory_(this) { +#if DCHECK_IS_ON() + client.VerifyNotPainting(); +#endif + layer_ = Platform::Current()->CompositorSupport()->CreateContentLayer(this); + layer_->Layer()->SetDrawsContent(draws_content_ && contents_visible_); + layer_->Layer()->SetLayerClient(weak_ptr_factory_.GetWeakPtr()); + + UpdateTrackingRasterInvalidations(); +} + +GraphicsLayer::~GraphicsLayer() { + layer_->Layer()->SetLayerClient(nullptr); + SetContentsLayer(nullptr); + for (size_t i = 0; i < link_highlights_.size(); ++i) + link_highlights_[i]->ClearCurrentGraphicsLayer(); + link_highlights_.clear(); + +#if DCHECK_IS_ON() + client_.VerifyNotPainting(); +#endif + + RemoveAllChildren(); + RemoveFromParent(); + DCHECK(!parent_); +} + +LayoutRect GraphicsLayer::VisualRect() const { + LayoutRect bounds = LayoutRect(FloatPoint(), Size()); + if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) { + DCHECK(layer_state_); + bounds.MoveBy(layer_state_->offset); + } else { + bounds.Move(OffsetFromLayoutObjectWithSubpixelAccumulation()); + } + return bounds; +} + +void GraphicsLayer::SetHasWillChangeTransformHint( + bool has_will_change_transform) { + layer_->Layer()->SetHasWillChangeTransformHint(has_will_change_transform); +} + +void GraphicsLayer::SetOverscrollBehavior( + const WebOverscrollBehavior& behavior) { + layer_->Layer()->SetOverscrollBehavior(behavior); +} + +void GraphicsLayer::SetSnapContainerData(Optional<SnapContainerData> data) { + layer_->Layer()->SetSnapContainerData(std::move(data)); +} + +void GraphicsLayer::SetIsResizedByBrowserControls( + bool is_resized_by_browser_controls) { + PlatformLayer()->SetIsResizedByBrowserControls( + is_resized_by_browser_controls); +} + +void GraphicsLayer::SetIsContainerForFixedPositionLayers(bool is_container) { + PlatformLayer()->SetIsContainerForFixedPositionLayers(is_container); +} + +void GraphicsLayer::SetParent(GraphicsLayer* layer) { +#if DCHECK_IS_ON() + DCHECK(!layer || !layer->HasAncestor(this)); +#endif + parent_ = layer; +} + +#if DCHECK_IS_ON() + +bool GraphicsLayer::HasAncestor(GraphicsLayer* ancestor) const { + for (GraphicsLayer* curr = Parent(); curr; curr = curr->Parent()) { + if (curr == ancestor) + return true; + } + + return false; +} + +#endif + +bool GraphicsLayer::SetChildren(const GraphicsLayerVector& new_children) { + // If the contents of the arrays are the same, nothing to do. + if (new_children == children_) + return false; + + RemoveAllChildren(); + + size_t list_size = new_children.size(); + for (size_t i = 0; i < list_size; ++i) + AddChildInternal(new_children[i]); + + UpdateChildList(); + + return true; +} + +void GraphicsLayer::AddChildInternal(GraphicsLayer* child_layer) { + DCHECK_NE(child_layer, this); + + if (child_layer->Parent()) + child_layer->RemoveFromParent(); + + child_layer->SetParent(this); + children_.push_back(child_layer); + + // Don't call updateChildList here, this function is used in cases where it + // should not be called until all children are processed. +} + +void GraphicsLayer::AddChild(GraphicsLayer* child_layer) { + AddChildInternal(child_layer); + UpdateChildList(); +} + +void GraphicsLayer::AddChildBelow(GraphicsLayer* child_layer, + GraphicsLayer* sibling) { + DCHECK_NE(child_layer, this); + child_layer->RemoveFromParent(); + + bool found = false; + for (unsigned i = 0; i < children_.size(); i++) { + if (sibling == children_[i]) { + children_.insert(i, child_layer); + found = true; + break; + } + } + + child_layer->SetParent(this); + + if (!found) + children_.push_back(child_layer); + + UpdateChildList(); +} + +void GraphicsLayer::RemoveAllChildren() { + while (!children_.IsEmpty()) { + GraphicsLayer* cur_layer = children_.back(); + DCHECK(cur_layer->Parent()); + cur_layer->RemoveFromParent(); + } +} + +void GraphicsLayer::RemoveFromParent() { + if (parent_) { + // We use reverseFind so that removeAllChildren() isn't n^2. + parent_->children_.EraseAt(parent_->children_.ReverseFind(this)); + SetParent(nullptr); + } + + PlatformLayer()->RemoveFromParent(); +} + +void GraphicsLayer::SetOffsetFromLayoutObject( + const IntSize& offset, + ShouldSetNeedsDisplay should_set_needs_display) { + SetOffsetDoubleFromLayoutObject(offset); +} + +void GraphicsLayer::SetOffsetDoubleFromLayoutObject( + const DoubleSize& offset, + ShouldSetNeedsDisplay should_set_needs_display) { + if (offset == offset_from_layout_object_) + return; + + offset_from_layout_object_ = offset; + PlatformLayer()->SetFiltersOrigin(FloatPoint() - ToFloatSize(offset)); + + // If the compositing layer offset changes, we need to repaint. + if (should_set_needs_display == kSetNeedsDisplay) + SetNeedsDisplay(); +} + +LayoutSize GraphicsLayer::OffsetFromLayoutObjectWithSubpixelAccumulation() + const { + return LayoutSize(OffsetFromLayoutObject()) + client_.SubpixelAccumulation(); +} + +IntRect GraphicsLayer::InterestRect() { + return previous_interest_rect_; +} + +void GraphicsLayer::PaintRecursively() { + Vector<GraphicsLayer*> repainted_layers; + PaintRecursivelyInternal(repainted_layers); + + if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) { + // Clear paint property change flags that are for this paint only. + for (auto* layer : repainted_layers) { + for (const auto& chunk : + layer->GetPaintController().GetPaintArtifact().PaintChunks()) + chunk.properties.property_tree_state.ClearChangedToRoot(); + } + } + +#if DCHECK_IS_ON() + if (VLOG_IS_ON(2)) { + static String s_previous_tree; + LayerTreeFlags flags = VLOG_IS_ON(3) ? 0xffffffff : kOutputAsLayerTree; + String new_tree = GetLayerTreeAsTextForTesting(flags); + if (new_tree != s_previous_tree) { + LOG(ERROR) << "After GraphicsLayer::PaintRecursively()\n" + << "GraphicsLayer tree:\n" + << new_tree.Utf8().data(); + s_previous_tree = new_tree; + } + } +#endif +} + +void GraphicsLayer::PaintRecursivelyInternal( + Vector<GraphicsLayer*>& repainted_layers) { + if (DrawsContent()) { + if (Paint(nullptr)) + repainted_layers.push_back(this); + } + + if (MaskLayer()) + MaskLayer()->PaintRecursivelyInternal(repainted_layers); + if (ContentsClippingMaskLayer()) + ContentsClippingMaskLayer()->PaintRecursivelyInternal(repainted_layers); + + for (auto* child : Children()) + child->PaintRecursivelyInternal(repainted_layers); +} + +bool GraphicsLayer::Paint(const IntRect* interest_rect, + GraphicsContext::DisabledMode disabled_mode) { + if (PaintWithoutCommit(interest_rect, disabled_mode)) + GetPaintController().CommitNewDisplayItems(); + else if (!needs_check_raster_invalidation_) + return false; + +#if DCHECK_IS_ON() + if (VLOG_IS_ON(2)) { + LOG(ERROR) << "Painted GraphicsLayer: " << DebugName() + << " interest_rect=" << InterestRect().ToString(); + } +#endif + + if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) { + DCHECK(layer_state_) << "No layer state for GraphicsLayer: " << DebugName(); + // Generate raster invalidations for SPv175 (but not SPv2). + IntRect layer_bounds(layer_state_->offset, ExpandedIntSize(Size())); + EnsureRasterInvalidator().Generate( + layer_bounds, GetPaintController().GetPaintArtifact().PaintChunks(), + layer_state_->state, VisualRectSubpixelOffset()); + } + + if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled() && + DrawsContent()) { + auto& tracking = EnsureRasterInvalidator().EnsureTracking(); + tracking.CheckUnderInvalidations(DebugName(), CapturePaintRecord(), + InterestRect()); + if (auto record = tracking.UnderInvalidationRecord()) { + // Add the under-invalidation overlay onto the painted result. + GetPaintController().AppendDebugDrawingAfterCommit( + *this, std::move(record), + layer_state_ ? &layer_state_->state : nullptr); + // Ensure the compositor will raster the under-invalidation overlay. + layer_->Layer()->Invalidate(); + } + } + + needs_check_raster_invalidation_ = false; + return true; +} + +bool GraphicsLayer::PaintWithoutCommit( + const IntRect* interest_rect, + GraphicsContext::DisabledMode disabled_mode) { + DCHECK(DrawsContent()); + + if (client_.ShouldThrottleRendering()) + return false; + + if (FirstPaintInvalidationTracking::IsEnabled()) + debug_info_.ClearAnnotatedInvalidateRects(); + IncrementPaintCount(); + + IntRect new_interest_rect; + if (!interest_rect) { + new_interest_rect = + client_.ComputeInterestRect(this, previous_interest_rect_); + interest_rect = &new_interest_rect; + } + + if (!GetPaintController().SubsequenceCachingIsDisabled() && + !client_.NeedsRepaint(*this) && + !GetPaintController().CacheIsAllInvalid() && + previous_interest_rect_ == *interest_rect) { + return false; + } + + GraphicsContext context(GetPaintController(), disabled_mode, nullptr); + if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) { + DCHECK(layer_state_) << "No layer state for GraphicsLayer: " << DebugName(); + GetPaintController().UpdateCurrentPaintChunkProperties( + WTF::nullopt, PaintChunkProperties(layer_state_->state)); + } + + previous_interest_rect_ = *interest_rect; + client_.PaintContents(this, context, painting_phase_, *interest_rect); + return true; +} + +void GraphicsLayer::UpdateChildList() { + WebLayer* child_host = layer_->Layer(); + child_host->RemoveAllChildren(); + + ClearContentsLayerIfUnregistered(); + + if (contents_layer_) { + // FIXME: Add the contents layer in the correct order with negative z-order + // children. This does not currently cause visible rendering issues because + // contents layers are only used for replaced elements that don't have + // children. + child_host->AddChild(contents_layer_); + } + + for (size_t i = 0; i < children_.size(); ++i) + child_host->AddChild(children_[i]->PlatformLayer()); + + for (size_t i = 0; i < link_highlights_.size(); ++i) + child_host->AddChild(link_highlights_[i]->Layer()); +} + +void GraphicsLayer::UpdateLayerIsDrawable() { + // For the rest of the accelerated compositor code, there is no reason to make + // a distinction between drawsContent and contentsVisible. So, for + // m_layer->layer(), these two flags are combined here. |m_contentsLayer| + // shouldn't receive the drawsContent flag, so it is only given + // contentsVisible. + + layer_->Layer()->SetDrawsContent(draws_content_ && contents_visible_); + if (WebLayer* contents_layer = ContentsLayerIfRegistered()) + contents_layer->SetDrawsContent(contents_visible_); + + if (draws_content_) { + layer_->Layer()->Invalidate(); + for (size_t i = 0; i < link_highlights_.size(); ++i) + link_highlights_[i]->Invalidate(); + } +} + +void GraphicsLayer::UpdateContentsRect() { + WebLayer* contents_layer = ContentsLayerIfRegistered(); + if (!contents_layer) + return; + + contents_layer->SetPosition( + FloatPoint(contents_rect_.X(), contents_rect_.Y())); + contents_layer->SetBounds( + IntSize(contents_rect_.Width(), contents_rect_.Height())); + + if (contents_clipping_mask_layer_) { + if (contents_clipping_mask_layer_->Size() != contents_rect_.Size()) { + contents_clipping_mask_layer_->SetSize(FloatSize(contents_rect_.Size())); + contents_clipping_mask_layer_->SetNeedsDisplay(); + } + contents_clipping_mask_layer_->SetPosition(FloatPoint()); + contents_clipping_mask_layer_->SetOffsetFromLayoutObject( + OffsetFromLayoutObject() + + IntSize(contents_rect_.Location().X(), contents_rect_.Location().Y())); + } +} + +static HashSet<int>* g_registered_layer_set; + +void GraphicsLayer::RegisterContentsLayer(WebLayer* layer) { + if (!g_registered_layer_set) + g_registered_layer_set = new HashSet<int>; + CHECK(!g_registered_layer_set->Contains(layer->Id())); + g_registered_layer_set->insert(layer->Id()); +} + +void GraphicsLayer::UnregisterContentsLayer(WebLayer* layer) { + DCHECK(g_registered_layer_set); + CHECK(g_registered_layer_set->Contains(layer->Id())); + g_registered_layer_set->erase(layer->Id()); + layer->SetLayerClient(nullptr); +} + +void GraphicsLayer::SetContentsTo(WebLayer* layer) { + bool children_changed = false; + if (layer) { + DCHECK(g_registered_layer_set); + CHECK(g_registered_layer_set->Contains(layer->Id())); + if (contents_layer_id_ != layer->Id()) { + SetupContentsLayer(layer); + children_changed = true; + } + UpdateContentsRect(); + } else { + if (contents_layer_) { + children_changed = true; + + // The old contents layer will be removed via updateChildList. + SetContentsLayer(nullptr); + } + } + + if (children_changed) + UpdateChildList(); +} + +void GraphicsLayer::SetupContentsLayer(WebLayer* contents_layer) { + DCHECK(contents_layer); + SetContentsLayer(contents_layer); + + contents_layer_->SetTransformOrigin(FloatPoint3D()); + contents_layer_->SetUseParentBackfaceVisibility(true); + + // It is necessary to call setDrawsContent as soon as we receive the new + // contentsLayer, for the correctness of early exit conditions in + // setDrawsContent() and setContentsVisible(). + contents_layer_->SetDrawsContent(contents_visible_); + + // Insert the content layer first. Video elements require this, because they + // have shadow content that must display in front of the video. + layer_->Layer()->InsertChild(contents_layer_, 0); + WebLayer* border_web_layer = + contents_clipping_mask_layer_ + ? contents_clipping_mask_layer_->PlatformLayer() + : nullptr; + contents_layer_->SetMaskLayer(border_web_layer); + + contents_layer_->SetRenderingContext(rendering_context3d_); +} + +void GraphicsLayer::ClearContentsLayerIfUnregistered() { + if (!contents_layer_id_ || + g_registered_layer_set->Contains(contents_layer_id_)) + return; + + SetContentsLayer(nullptr); +} + +void GraphicsLayer::SetContentsLayer(WebLayer* contents_layer) { + // If we have a previous contents layer which is still registered, then unset + // this client pointer. If unregistered, it has already nulled out the client + // pointer and may have been deleted. + if (contents_layer_ && g_registered_layer_set->Contains(contents_layer_id_)) + contents_layer_->SetLayerClient(nullptr); + contents_layer_ = contents_layer; + if (!contents_layer_) { + contents_layer_id_ = 0; + return; + } + contents_layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr()); + contents_layer_id_ = contents_layer_->Id(); +} + +GraphicsLayerDebugInfo& GraphicsLayer::DebugInfo() { + return debug_info_; +} + +WebLayer* GraphicsLayer::ContentsLayerIfRegistered() { + ClearContentsLayerIfUnregistered(); + return contents_layer_; +} + +CompositedLayerRasterInvalidator& GraphicsLayer::EnsureRasterInvalidator() { + if (!raster_invalidator_) { + raster_invalidator_ = std::make_unique<CompositedLayerRasterInvalidator>( + [this](const IntRect& r) { SetNeedsDisplayInRectInternal(r); }); + raster_invalidator_->SetTracksRasterInvalidations( + client_.IsTrackingRasterInvalidations()); + } + return *raster_invalidator_; +} + +void GraphicsLayer::UpdateTrackingRasterInvalidations() { + bool should_track = client_.IsTrackingRasterInvalidations(); + if (should_track) + EnsureRasterInvalidator().SetTracksRasterInvalidations(true); + else if (raster_invalidator_) + raster_invalidator_->SetTracksRasterInvalidations(false); + + if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled() && paint_controller_) + paint_controller_->SetTracksRasterInvalidations(should_track); +} + +void GraphicsLayer::ResetTrackedRasterInvalidations() { + if (auto* tracking = GetRasterInvalidationTracking()) + tracking->ClearInvalidations(); +} + +bool GraphicsLayer::HasTrackedRasterInvalidations() const { + if (auto* tracking = GetRasterInvalidationTracking()) + return tracking->HasInvalidations(); + return false; +} + +RasterInvalidationTracking* GraphicsLayer::GetRasterInvalidationTracking() + const { + return raster_invalidator_ ? raster_invalidator_->GetTracking() : nullptr; +} + +void GraphicsLayer::TrackRasterInvalidation(const DisplayItemClient& client, + const IntRect& rect, + PaintInvalidationReason reason) { + if (FirstPaintInvalidationTracking::IsEnabled()) + debug_info_.AppendAnnotatedInvalidateRect(rect, reason); + + if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) + EnsureRasterInvalidator().EnsureTracking(); + + // For SPv175, this only tracks invalidations that the WebLayer is fully + // invalidated directly, e.g. from SetContentsNeedsDisplay(), etc. + if (auto* tracking = GetRasterInvalidationTracking()) + tracking->AddInvalidation(&client, client.DebugName(), rect, reason); +} + +static String PointerAsString(const void* ptr) { + TextStream ts; + ts << ptr; + return ts.Release(); +} + +class GraphicsLayer::LayersAsJSONArray { + public: + LayersAsJSONArray(LayerTreeFlags flags) + : flags_(flags), + next_transform_id_(1), + layers_json_(JSONArray::Create()), + transforms_json_(JSONArray::Create()) {} + + // Outputs the layer tree rooted at |layer| as a JSON array, in paint order, + // and the transform tree also as a JSON array. + std::unique_ptr<JSONObject> operator()(const GraphicsLayer& layer) { + auto json = JSONObject::Create(); + Walk(layer, 0, FloatPoint()); + json->SetArray("layers", std::move(layers_json_)); + if (transforms_json_->size()) + json->SetArray("transforms", std::move(transforms_json_)); + return json; + } + + JSONObject* AddTransformJSON(int& transform_id) { + auto transform_json = JSONObject::Create(); + int parent_transform_id = transform_id; + transform_id = next_transform_id_++; + transform_json->SetInteger("id", transform_id); + if (parent_transform_id) + transform_json->SetInteger("parent", parent_transform_id); + auto* result = transform_json.get(); + transforms_json_->PushObject(std::move(transform_json)); + return result; + } + + static FloatPoint ScrollPosition(const GraphicsLayer& layer) { + const auto* scrollable_area = layer.GetScrollableArea(); + if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled()) { + // The LayoutView layer's scrollable area is on the "Frame Scrolling + // Layer" ancestor. + if (layer.DebugName() == "LayoutView #document") + scrollable_area = layer.Parent()->Parent()->GetScrollableArea(); + else if (layer.DebugName() == "Frame Scrolling Layer") + scrollable_area = nullptr; + } + return scrollable_area ? scrollable_area->ScrollPosition() : FloatPoint(); + } + + void AddLayer(const GraphicsLayer& layer, + int& transform_id, + FloatPoint& position) { + FloatPoint scroll_position = ScrollPosition(layer); + if (scroll_position != FloatPoint()) { + // Output scroll position as a transform. + auto* scroll_translate_json = AddTransformJSON(transform_id); + scroll_translate_json->SetArray( + "transform", TransformAsJSONArray(TransformationMatrix().Translate( + -scroll_position.X(), -scroll_position.Y()))); + layer.AddFlattenInheritedTransformJSON(*scroll_translate_json); + } + + if (!layer.transform_.IsIdentity() || layer.rendering_context3d_ || + layer.GetCompositingReasons() & CompositingReason::k3DTransform) { + if (position != FloatPoint()) { + // Output position offset as a transform. + auto* position_translate_json = AddTransformJSON(transform_id); + position_translate_json->SetArray( + "transform", TransformAsJSONArray(TransformationMatrix().Translate( + position.X(), position.Y()))); + layer.AddFlattenInheritedTransformJSON(*position_translate_json); + if (layer.Parent() && !layer.Parent()->should_flatten_transform_) { + position_translate_json->SetBoolean("flattenInheritedTransform", + false); + } + position = FloatPoint(); + } + + if (!layer.transform_.IsIdentity() || layer.rendering_context3d_) { + auto* transform_json = AddTransformJSON(transform_id); + layer.AddTransformJSONProperties(*transform_json, + rendering_context_map_); + } + } + + auto json = + layer.LayerAsJSONInternal(flags_, rendering_context_map_, position); + if (transform_id) + json->SetInteger("transform", transform_id); + layers_json_->PushObject(std::move(json)); + } + + void Walk(const GraphicsLayer& layer, + int parent_transform_id, + const FloatPoint& parent_position) { + FloatPoint position = parent_position + layer.position_; + int transform_id = parent_transform_id; + AddLayer(layer, transform_id, position); + for (auto& child : layer.children_) + Walk(*child, transform_id, position); + } + + private: + LayerTreeFlags flags_; + int next_transform_id_; + RenderingContextMap rendering_context_map_; + std::unique_ptr<JSONArray> layers_json_; + std::unique_ptr<JSONArray> transforms_json_; +}; + +std::unique_ptr<JSONObject> GraphicsLayer::LayerTreeAsJSON( + LayerTreeFlags flags) const { + if (flags & kOutputAsLayerTree) { + RenderingContextMap rendering_context_map; + return LayerTreeAsJSONInternal(flags, rendering_context_map); + } + + return LayersAsJSONArray(flags)(*this); +} + +// This is the SPv1 version of ContentLayerClientImpl::LayerAsJSON(). +std::unique_ptr<JSONObject> GraphicsLayer::LayerAsJSONInternal( + LayerTreeFlags flags, + RenderingContextMap& rendering_context_map, + const FloatPoint& position) const { + std::unique_ptr<JSONObject> json = JSONObject::Create(); + + if (flags & kLayerTreeIncludesDebugInfo) + json->SetString("this", PointerAsString(this)); + + json->SetString("name", DebugName()); + + if (position != FloatPoint()) + json->SetArray("position", PointAsJSONArray(position)); + + if (flags & kLayerTreeIncludesDebugInfo && + offset_from_layout_object_ != DoubleSize()) { + json->SetArray("offsetFromLayoutObject", + SizeAsJSONArray(offset_from_layout_object_)); + } + + if (size_ != IntSize()) + json->SetArray("bounds", SizeAsJSONArray(size_)); + + if (opacity_ != 1) + json->SetDouble("opacity", opacity_); + + if (blend_mode_ != WebBlendMode::kNormal) { + json->SetString("blendMode", + CompositeOperatorName(kCompositeSourceOver, blend_mode_)); + } + + if (is_root_for_isolated_group_) + json->SetBoolean("isolate", true); + + if (contents_opaque_) + json->SetBoolean("contentsOpaque", true); + + if (!draws_content_) + json->SetBoolean("drawsContent", false); + + if (!contents_visible_) + json->SetBoolean("contentsVisible", false); + + if (!backface_visibility_) + json->SetString("backfaceVisibility", "hidden"); + + if (flags & kLayerTreeIncludesDebugInfo) + json->SetString("client", PointerAsString(&client_)); + + if (background_color_.Alpha()) { + json->SetString("backgroundColor", + background_color_.NameForLayoutTreeAsText()); + } + + if (flags & kOutputAsLayerTree) { + AddTransformJSONProperties(*json, rendering_context_map); + if (!should_flatten_transform_) + json->SetBoolean("shouldFlattenTransform", false); + if (scrollable_area_ && + scrollable_area_->ScrollPosition() != FloatPoint()) { + json->SetArray("scrollPosition", + PointAsJSONArray(scrollable_area_->ScrollPosition())); + } + } + + if ((flags & kLayerTreeIncludesPaintInvalidations) && + client_.IsTrackingRasterInvalidations() && + GetRasterInvalidationTracking()) + GetRasterInvalidationTracking()->AsJSON(json.get()); + + if ((flags & kLayerTreeIncludesPaintingPhases) && painting_phase_) { + std::unique_ptr<JSONArray> painting_phases_json = JSONArray::Create(); + if (painting_phase_ & kGraphicsLayerPaintBackground) + painting_phases_json->PushString("GraphicsLayerPaintBackground"); + if (painting_phase_ & kGraphicsLayerPaintForeground) + painting_phases_json->PushString("GraphicsLayerPaintForeground"); + if (painting_phase_ & kGraphicsLayerPaintMask) + painting_phases_json->PushString("GraphicsLayerPaintMask"); + if (painting_phase_ & kGraphicsLayerPaintChildClippingMask) + painting_phases_json->PushString("GraphicsLayerPaintChildClippingMask"); + if (painting_phase_ & kGraphicsLayerPaintAncestorClippingMask) + painting_phases_json->PushString( + "GraphicsLayerPaintAncestorClippingMask"); + if (painting_phase_ & kGraphicsLayerPaintOverflowContents) + painting_phases_json->PushString("GraphicsLayerPaintOverflowContents"); + if (painting_phase_ & kGraphicsLayerPaintCompositedScroll) + painting_phases_json->PushString("GraphicsLayerPaintCompositedScroll"); + if (painting_phase_ & kGraphicsLayerPaintDecoration) + painting_phases_json->PushString("GraphicsLayerPaintDecoration"); + json->SetArray("paintingPhases", std::move(painting_phases_json)); + } + + if (flags & kLayerTreeIncludesClipAndScrollParents) { + if (has_scroll_parent_) + json->SetBoolean("hasScrollParent", true); + if (has_clip_parent_) + json->SetBoolean("hasClipParent", true); + } + + if (flags & + (kLayerTreeIncludesDebugInfo | kLayerTreeIncludesCompositingReasons)) { + bool debug = flags & kLayerTreeIncludesDebugInfo; + { + std::unique_ptr<JSONArray> compositing_reasons_json = JSONArray::Create(); + auto reasons = debug_info_.GetCompositingReasons(); + auto names = debug ? CompositingReason::Descriptions(reasons) + : CompositingReason::ShortNames(reasons); + for (const char* name : names) + compositing_reasons_json->PushString(name); + json->SetArray("compositingReasons", std::move(compositing_reasons_json)); + } + { + std::unique_ptr<JSONArray> squashing_disallowed_reasons_json = + JSONArray::Create(); + auto reasons = debug_info_.GetSquashingDisallowedReasons(); + auto names = debug ? SquashingDisallowedReason::Descriptions(reasons) + : SquashingDisallowedReason::ShortNames(reasons); + for (const char* name : names) + squashing_disallowed_reasons_json->PushString(name); + json->SetArray("squashingDisallowedReasons", + std::move(squashing_disallowed_reasons_json)); + } + } + + if (mask_layer_) { + std::unique_ptr<JSONArray> mask_layer_json = JSONArray::Create(); + mask_layer_json->PushObject(mask_layer_->LayerAsJSONInternal( + flags, rendering_context_map, mask_layer_->position_)); + json->SetArray("maskLayer", std::move(mask_layer_json)); + } + + if (contents_clipping_mask_layer_) { + std::unique_ptr<JSONArray> contents_clipping_mask_layer_json = + JSONArray::Create(); + contents_clipping_mask_layer_json->PushObject( + contents_clipping_mask_layer_->LayerAsJSONInternal( + flags, rendering_context_map, + contents_clipping_mask_layer_->position_)); + json->SetArray("contentsClippingMaskLayer", + std::move(contents_clipping_mask_layer_json)); + } + + if (layer_state_ && (flags & (kLayerTreeIncludesDebugInfo | + kLayerTreeIncludesPaintRecords))) { + json->SetString("layerState", layer_state_->state.ToString()); + json->SetValue("layerOffset", PointAsJSONArray(layer_state_->offset)); + } + +#if DCHECK_IS_ON() + if (DrawsContent() && (flags & kLayerTreeIncludesPaintRecords)) + json->SetValue("paintRecord", RecordAsJSON(*CapturePaintRecord())); +#endif + + return json; +} + +std::unique_ptr<JSONObject> GraphicsLayer::LayerTreeAsJSONInternal( + LayerTreeFlags flags, + RenderingContextMap& rendering_context_map) const { + std::unique_ptr<JSONObject> json = + LayerAsJSONInternal(flags, rendering_context_map, position_); + + if (children_.size()) { + std::unique_ptr<JSONArray> children_json = JSONArray::Create(); + for (size_t i = 0; i < children_.size(); i++) { + children_json->PushObject( + children_[i]->LayerTreeAsJSONInternal(flags, rendering_context_map)); + } + json->SetArray("children", std::move(children_json)); + } + + return json; +} + +void GraphicsLayer::AddTransformJSONProperties( + JSONObject& json, + RenderingContextMap& rendering_context_map) const { + if (!transform_.IsIdentity()) + json.SetArray("transform", TransformAsJSONArray(transform_)); + + if (!transform_.IsIdentityOrTranslation()) + json.SetArray("origin", PointAsJSONArray(transform_origin_)); + + AddFlattenInheritedTransformJSON(json); + + if (rendering_context3d_) { + auto it = rendering_context_map.find(rendering_context3d_); + int context_id = rendering_context_map.size() + 1; + if (it == rendering_context_map.end()) + rendering_context_map.Set(rendering_context3d_, context_id); + else + context_id = it->value; + + json.SetInteger("renderingContext", context_id); + } +} + +void GraphicsLayer::AddFlattenInheritedTransformJSON(JSONObject& json) const { + if (Parent() && !Parent()->should_flatten_transform_) + json.SetBoolean("flattenInheritedTransform", false); +} + +String GraphicsLayer::GetLayerTreeAsTextForTesting(LayerTreeFlags flags) const { + return LayerTreeAsJSON(flags)->ToPrettyJSONString(); +} + +static const cc::Layer* CcLayerForWebLayer(const WebLayer* web_layer) { + return web_layer ? web_layer->CcLayer() : nullptr; +} + +String GraphicsLayer::DebugName(cc::Layer* layer) const { + if (layer->id() == contents_layer_id_) + return "ContentsLayer for " + client_.DebugName(this); + + for (size_t i = 0; i < link_highlights_.size(); ++i) { + if (layer == CcLayerForWebLayer(link_highlights_[i]->Layer())) { + return "LinkHighlight[" + String::Number(i) + "] for " + + client_.DebugName(this); + } + } + + if (layer == CcLayerForWebLayer(layer_->Layer())) + return client_.DebugName(this); + + NOTREACHED(); + return ""; +} + +void GraphicsLayer::SetCompositingReasons(CompositingReasons reasons) { + debug_info_.SetCompositingReasons(reasons); +} + +void GraphicsLayer::SetSquashingDisallowedReasons( + SquashingDisallowedReasons reasons) { + debug_info_.SetSquashingDisallowedReasons(reasons); +} + +void GraphicsLayer::SetOwnerNodeId(int node_id) { + debug_info_.SetOwnerNodeId(node_id); +} + +void GraphicsLayer::SetPosition(const FloatPoint& point) { + position_ = point; + PlatformLayer()->SetPosition(position_); +} + +void GraphicsLayer::SetSize(const FloatSize& size) { + // We are receiving negative sizes here that cause assertions to fail in the + // compositor. Clamp them to 0 to avoid those assertions. + // FIXME: This should be an DCHECK instead, as negative sizes should not exist + // in WebCore. + FloatSize clamped_size = size; + if (clamped_size.Width() < 0 || clamped_size.Height() < 0) + clamped_size = FloatSize(); + + if (clamped_size == size_) + return; + + size_ = clamped_size; + + // Invalidate the layer as a DisplayItemClient. + SetDisplayItemsUncached(); + + layer_->Layer()->SetBounds(FlooredIntSize(size_)); + // Note that we don't resize m_contentsLayer. It's up the caller to do that. +} + +void GraphicsLayer::SetTransform(const TransformationMatrix& transform) { + transform_ = transform; + PlatformLayer()->SetTransform(TransformationMatrix::ToSkMatrix44(transform_)); +} + +void GraphicsLayer::SetTransformOrigin(const FloatPoint3D& transform_origin) { + has_transform_origin_ = true; + transform_origin_ = transform_origin; + PlatformLayer()->SetTransformOrigin(transform_origin); +} + +void GraphicsLayer::SetShouldFlattenTransform(bool should_flatten) { + if (should_flatten == should_flatten_transform_) + return; + + should_flatten_transform_ = should_flatten; + + layer_->Layer()->SetShouldFlattenTransform(should_flatten); +} + +void GraphicsLayer::SetRenderingContext(int context) { + if (rendering_context3d_ == context) + return; + + rendering_context3d_ = context; + layer_->Layer()->SetRenderingContext(context); + + if (contents_layer_) + contents_layer_->SetRenderingContext(rendering_context3d_); +} + +bool GraphicsLayer::MasksToBounds() const { + return layer_->Layer()->MasksToBounds(); +} + +void GraphicsLayer::SetMasksToBounds(bool masks_to_bounds) { + layer_->Layer()->SetMasksToBounds(masks_to_bounds); +} + +void GraphicsLayer::SetDrawsContent(bool draws_content) { + // NOTE: This early-exit is only correct because we also properly call + // WebLayer::setDrawsContent() whenever |m_contentsLayer| is set to a new + // layer in setupContentsLayer(). + if (draws_content == draws_content_) + return; + + draws_content_ = draws_content; + UpdateLayerIsDrawable(); + + if (!draws_content) { + paint_controller_.reset(); + raster_invalidator_.reset(); + } +} + +void GraphicsLayer::SetContentsVisible(bool contents_visible) { + // NOTE: This early-exit is only correct because we also properly call + // WebLayer::setDrawsContent() whenever |m_contentsLayer| is set to a new + // layer in setupContentsLayer(). + if (contents_visible == contents_visible_) + return; + + contents_visible_ = contents_visible; + UpdateLayerIsDrawable(); +} + +void GraphicsLayer::SetClipParent(WebLayer* parent) { + has_clip_parent_ = !!parent; + layer_->Layer()->SetClipParent(parent); +} + +void GraphicsLayer::SetScrollParent(WebLayer* parent) { + has_scroll_parent_ = !!parent; + layer_->Layer()->SetScrollParent(parent); +} + +void GraphicsLayer::SetBackgroundColor(const Color& color) { + if (color == background_color_) + return; + + background_color_ = color; + layer_->Layer()->SetBackgroundColor(background_color_.Rgb()); +} + +void GraphicsLayer::SetContentsOpaque(bool opaque) { + contents_opaque_ = opaque; + layer_->Layer()->SetOpaque(contents_opaque_); + ClearContentsLayerIfUnregistered(); + if (contents_layer_) + contents_layer_->SetOpaque(opaque); +} + +void GraphicsLayer::SetMaskLayer(GraphicsLayer* mask_layer) { + if (mask_layer == mask_layer_) + return; + + mask_layer_ = mask_layer; + WebLayer* mask_web_layer = + mask_layer_ ? mask_layer_->PlatformLayer() : nullptr; + layer_->Layer()->SetMaskLayer(mask_web_layer); +} + +void GraphicsLayer::SetContentsClippingMaskLayer( + GraphicsLayer* contents_clipping_mask_layer) { + if (contents_clipping_mask_layer == contents_clipping_mask_layer_) + return; + + contents_clipping_mask_layer_ = contents_clipping_mask_layer; + WebLayer* contents_layer = ContentsLayerIfRegistered(); + if (!contents_layer) + return; + WebLayer* contents_clipping_mask_web_layer = + contents_clipping_mask_layer_ + ? contents_clipping_mask_layer_->PlatformLayer() + : nullptr; + contents_layer->SetMaskLayer(contents_clipping_mask_web_layer); + UpdateContentsRect(); +} + +void GraphicsLayer::SetBackfaceVisibility(bool visible) { + backface_visibility_ = visible; + PlatformLayer()->SetDoubleSided(backface_visibility_); +} + +void GraphicsLayer::SetOpacity(float opacity) { + float clamped_opacity = clampTo(opacity, 0.0f, 1.0f); + opacity_ = clamped_opacity; + PlatformLayer()->SetOpacity(opacity); +} + +void GraphicsLayer::SetBlendMode(WebBlendMode blend_mode) { + if (blend_mode_ == blend_mode) + return; + blend_mode_ = blend_mode; + PlatformLayer()->SetBlendMode(blend_mode); +} + +void GraphicsLayer::SetIsRootForIsolatedGroup(bool isolated) { + if (is_root_for_isolated_group_ == isolated) + return; + is_root_for_isolated_group_ = isolated; + PlatformLayer()->SetIsRootForIsolatedGroup(isolated); +} + +void GraphicsLayer::SetHitTestableWithoutDrawsContent(bool should_hit_test) { + if (hit_testable_without_draws_content_ == should_hit_test) + return; + hit_testable_without_draws_content_ = should_hit_test; + PlatformLayer()->SetHitTestableWithoutDrawsContent(should_hit_test); +} + +void GraphicsLayer::SetContentsNeedsDisplay() { + if (WebLayer* contents_layer = ContentsLayerIfRegistered()) { + contents_layer->Invalidate(); + TrackRasterInvalidation(*this, contents_rect_, + PaintInvalidationReason::kFull); + } +} + +void GraphicsLayer::SetNeedsDisplay() { + if (!DrawsContent()) + return; + + // TODO(chrishtr): Stop invalidating the rects once + // FrameView::paintRecursively() does so. + layer_->Layer()->Invalidate(); + for (size_t i = 0; i < link_highlights_.size(); ++i) + link_highlights_[i]->Invalidate(); + GetPaintController().InvalidateAll(); + + TrackRasterInvalidation(*this, IntRect(IntPoint(), ExpandedIntSize(size_)), + PaintInvalidationReason::kFull); +} + +DISABLE_CFI_PERF +void GraphicsLayer::SetNeedsDisplayInRect( + const IntRect& rect, + PaintInvalidationReason invalidation_reason, + const DisplayItemClient& client) { + DCHECK(!RuntimeEnabledFeatures::SlimmingPaintV175Enabled()); + if (!DrawsContent()) + return; + + if (!ScopedSetNeedsDisplayInRectForTrackingOnly::s_enabled_) + SetNeedsDisplayInRectInternal(rect); + + TrackRasterInvalidation(client, rect, invalidation_reason); +} + +void GraphicsLayer::SetNeedsDisplayInRectInternal(const IntRect& rect) { + DCHECK(DrawsContent()); + + layer_->Layer()->InvalidateRect(rect); + for (auto* link_highlight : link_highlights_) + link_highlight->Invalidate(); +} + +void GraphicsLayer::SetContentsRect(const IntRect& rect) { + if (rect == contents_rect_) + return; + + contents_rect_ = rect; + UpdateContentsRect(); +} + +void GraphicsLayer::SetContentsToImage( + Image* image, + Image::ImageDecodingMode decode_mode, + RespectImageOrientationEnum respect_image_orientation) { + PaintImage paint_image; + if (image) + paint_image = image->PaintImageForCurrentFrame(); + + ImageOrientation image_orientation = kOriginTopLeft; + SkMatrix matrix; + if (paint_image && image->IsBitmapImage() && + respect_image_orientation == kRespectImageOrientation) { + image_orientation = ToBitmapImage(image)->CurrentFrameOrientation(); + FloatSize size(paint_image.width(), paint_image.height()); + if (image_orientation.UsesWidthAsHeight()) + size = size.TransposedSize(); + auto affine = image_orientation.TransformFromDefault(size); + auto transform = affine.ToTransformationMatrix(); + matrix = TransformationMatrix::ToSkMatrix44(transform); + } else { + matrix = SkMatrix::I(); + } + + if (paint_image) { + paint_image = + PaintImageBuilder::WithCopy(std::move(paint_image)) + .set_decoding_mode(Image::ToPaintImageDecodingMode(decode_mode)) + .TakePaintImage(); + if (!image_layer_) { + image_layer_ = + Platform::Current()->CompositorSupport()->CreateImageLayer(); + RegisterContentsLayer(image_layer_->Layer()); + } + image_layer_->SetImage(std::move(paint_image), matrix, + image_orientation.UsesWidthAsHeight()); + image_layer_->Layer()->SetOpaque(image->CurrentFrameKnownToBeOpaque()); + UpdateContentsRect(); + } else if (image_layer_) { + UnregisterContentsLayer(image_layer_->Layer()); + image_layer_.reset(); + } + + SetContentsTo(image_layer_ ? image_layer_->Layer() : nullptr); +} + +WebLayer* GraphicsLayer::PlatformLayer() const { + return layer_->Layer(); +} + +void GraphicsLayer::SetFilters(CompositorFilterOperations filters) { + PlatformLayer()->SetFilters(filters.ReleaseCcFilterOperations()); +} + +void GraphicsLayer::SetBackdropFilters(CompositorFilterOperations filters) { + PlatformLayer()->SetBackgroundFilters(filters.ReleaseCcFilterOperations()); +} + +void GraphicsLayer::SetStickyPositionConstraint( + const WebLayerStickyPositionConstraint& sticky_constraint) { + layer_->Layer()->SetStickyPositionConstraint(sticky_constraint); +} + +void GraphicsLayer::SetFilterQuality(SkFilterQuality filter_quality) { + if (image_layer_) + image_layer_->SetNearestNeighbor(filter_quality == kNone_SkFilterQuality); +} + +void GraphicsLayer::SetPaintingPhase(GraphicsLayerPaintingPhase phase) { + if (painting_phase_ == phase) + return; + painting_phase_ = phase; + SetNeedsDisplay(); +} + +void GraphicsLayer::AddLinkHighlight(LinkHighlight* link_highlight) { + DCHECK(link_highlight && !link_highlights_.Contains(link_highlight)); + link_highlights_.push_back(link_highlight); + link_highlight->Layer()->SetLayerClient(weak_ptr_factory_.GetWeakPtr()); + UpdateChildList(); +} + +void GraphicsLayer::RemoveLinkHighlight(LinkHighlight* link_highlight) { + link_highlights_.EraseAt(link_highlights_.Find(link_highlight)); + UpdateChildList(); +} + +void GraphicsLayer::SetScrollableArea(ScrollableArea* scrollable_area) { + if (scrollable_area_ == scrollable_area) + return; + scrollable_area_ = scrollable_area; +} + +std::unique_ptr<base::trace_event::ConvertableToTraceFormat> +GraphicsLayer::TakeDebugInfo(cc::Layer* layer) { + std::unique_ptr<base::trace_event::TracedValue> traced_value( + debug_info_.AsTracedValue()); + traced_value->SetString( + "layer_name", WTF::StringUTF8Adaptor(DebugName(layer)).AsStringPiece()); + return std::move(traced_value); +} + +void GraphicsLayer::didUpdateMainThreadScrollingReasons() { + debug_info_.SetMainThreadScrollingReasons( + PlatformLayer()->MainThreadScrollingReasons()); +} + +void GraphicsLayer::didChangeScrollbarsHiddenIfOverlay(bool hidden) { + if (scrollable_area_) + scrollable_area_->SetScrollbarsHiddenIfOverlay(hidden); +} + +PaintController& GraphicsLayer::GetPaintController() const { + CHECK(DrawsContent()); + if (!paint_controller_) { + paint_controller_ = PaintController::Create(); + if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) { + paint_controller_->SetTracksRasterInvalidations( + client_.IsTrackingRasterInvalidations()); + } + } + return *paint_controller_; +} + +void GraphicsLayer::SetElementId(const CompositorElementId& id) { + if (WebLayer* layer = PlatformLayer()) + layer->SetElementId(id); +} + +CompositorElementId GraphicsLayer::GetElementId() const { + if (WebLayer* layer = PlatformLayer()) + return layer->GetElementId(); + return CompositorElementId(); +} + +sk_sp<PaintRecord> GraphicsLayer::CapturePaintRecord() const { + DCHECK(DrawsContent()); + + if (client_.ShouldThrottleRendering()) + return sk_sp<PaintRecord>(new PaintRecord); + + FloatRect bounds(IntRect(IntPoint(0, 0), ExpandedIntSize(Size()))); + GraphicsContext graphics_context(GetPaintController()); + graphics_context.BeginRecording(bounds); + if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) { + DCHECK(layer_state_) << "No layer state for GraphicsLayer: " << DebugName(); + GetPaintController().GetPaintArtifact().Replay( + graphics_context, layer_state_->state, layer_state_->offset); + } else { + GetPaintController().GetPaintArtifact().Replay(graphics_context, + PropertyTreeState::Root()); + } + return graphics_context.EndRecording(); +} + +void GraphicsLayer::SetLayerState(const PropertyTreeState& layer_state, + const IntPoint& layer_offset) { + DCHECK(RuntimeEnabledFeatures::SlimmingPaintV175Enabled()); + + if (!layer_state_) { + layer_state_ = + std::make_unique<LayerState>(LayerState{layer_state, layer_offset}); + return; + } + layer_state_->state = layer_state; + layer_state_->offset = layer_offset; +} + +void GraphicsLayer::PaintContents(WebDisplayItemList* web_display_item_list, + PaintingControlSetting painting_control) { + TRACE_EVENT0("blink,benchmark", "GraphicsLayer::PaintContents"); + + PaintController& paint_controller = GetPaintController(); + paint_controller.SetDisplayItemConstructionIsDisabled( + painting_control == kDisplayListConstructionDisabled); + paint_controller.SetSubsequenceCachingIsDisabled(painting_control == + kSubsequenceCachingDisabled); + + if (painting_control == kPartialInvalidation) + client_.InvalidateTargetElementForTesting(); + + // We also disable caching when Painting or Construction are disabled. In both + // cases we would like to compare assuming the full cost of recording, not the + // cost of re-using cached content. + if (painting_control == kDisplayListCachingDisabled || + painting_control == kDisplayListPaintingDisabled || + painting_control == kDisplayListConstructionDisabled) + paint_controller.InvalidateAll(); + + GraphicsContext::DisabledMode disabled_mode = + GraphicsContext::kNothingDisabled; + if (painting_control == kDisplayListPaintingDisabled || + painting_control == kDisplayListConstructionDisabled) + disabled_mode = GraphicsContext::kFullyDisabled; + + // Anything other than PaintDefaultBehavior is for testing. In non-testing + // scenarios, it is an error to call GraphicsLayer::Paint. Actual painting + // occurs in LocalFrameView::PaintTree() which calls GraphicsLayer::Paint(); + // this method merely copies the painted output to the WebDisplayItemList. + if (painting_control != kPaintDefaultBehavior) + Paint(nullptr, disabled_mode); + + if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled()) { + DCHECK(layer_state_) << "No layer state for GraphicsLayer: " << DebugName(); + PaintChunksToCcLayer::ConvertInto( + GetPaintController().GetPaintArtifact().PaintChunks(), + layer_state_->state, + gfx::Vector2dF(layer_state_->offset.X(), layer_state_->offset.Y()), + VisualRectSubpixelOffset(), + paint_controller.GetPaintArtifact().GetDisplayItemList(), + *web_display_item_list->GetCcDisplayItemList()); + } else { + paint_controller.GetPaintArtifact().AppendToWebDisplayItemList( + FloatSize(OffsetFromLayoutObjectWithSubpixelAccumulation()), + web_display_item_list); + } + + paint_controller.SetDisplayItemConstructionIsDisabled(false); + paint_controller.SetSubsequenceCachingIsDisabled(false); +} + +size_t GraphicsLayer::ApproximateUnsharedMemoryUsage() const { + size_t result = sizeof(*this); + result += GetPaintController().ApproximateUnsharedMemoryUsage(); + if (raster_invalidator_) + result += raster_invalidator_->ApproximateUnsharedMemoryUsage(); + return result; +} + +// Subpixel offset for visual rects which excluded composited layer's subpixel +// accumulation during paint invalidation. +// See PaintInvalidator::ExcludeCompositedLayerSubpixelAccumulation(). +FloatSize GraphicsLayer::VisualRectSubpixelOffset() const { + if (GetCompositingReasons() & CompositingReason::kComboAllDirectReasons) + return FloatSize(client_.SubpixelAccumulation()); + return FloatSize(); +} + +bool ScopedSetNeedsDisplayInRectForTrackingOnly::s_enabled_ = false; + +} // namespace blink + +#if DCHECK_IS_ON() +void showGraphicsLayerTree(const blink::GraphicsLayer* layer) { + if (!layer) { + LOG(ERROR) << "Cannot showGraphicsLayerTree for (nil)."; + return; + } + + String output = layer->GetLayerTreeAsTextForTesting(0xffffffff); + LOG(ERROR) << output.Utf8().data(); +} + +void showGraphicsLayers(const blink::GraphicsLayer* layer) { + if (!layer) { + LOG(ERROR) << "Cannot showGraphicsLayers for (nil)."; + return; + } + + String output = layer->GetLayerTreeAsTextForTesting( + 0xffffffff & ~blink::kOutputAsLayerTree); + LOG(ERROR) << output.Utf8().data(); +} +#endif |