// Copyright (c) 2012 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 "ui/compositor/layer.h" #include #include #include #include #include "base/auto_reset.h" #include "base/bind.h" #include "base/check_op.h" #include "base/command_line.h" #include "base/json/json_writer.h" #include "base/memory/ptr_util.h" #include "base/trace_event/trace_event.h" #include "cc/layers/mirror_layer.h" #include "cc/layers/nine_patch_layer.h" #include "cc/layers/picture_layer.h" #include "cc/layers/solid_color_layer.h" #include "cc/layers/surface_layer.h" #include "cc/layers/texture_layer.h" #include "cc/paint/filter_operation.h" #include "cc/paint/filter_operations.h" #include "cc/trees/layer_tree_settings.h" #include "components/viz/common/frame_sinks/copy_output_request.h" #include "components/viz/common/resources/transferable_resource.h" #include "ui/compositor/compositor_switches.h" #include "ui/compositor/layer_animator.h" #include "ui/compositor/layer_delegate.h" #include "ui/compositor/layer_observer.h" #include "ui/compositor/paint_context.h" #include "ui/gfx/animation/animation.h" #include "ui/gfx/canvas.h" #include "ui/gfx/geometry/dip_util.h" #include "ui/gfx/geometry/point3_f.h" #include "ui/gfx/geometry/point_conversions.h" #include "ui/gfx/geometry/rect_conversions.h" #include "ui/gfx/geometry/rounded_corners_f.h" #include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/interpolated_transform.h" #include "ui/gfx/transform.h" namespace ui { namespace { const Layer* GetRoot(const Layer* layer) { // Parent walk cannot be done on a layer that is being used as a mask. Get the // layer to which this layer is a mask of. if (layer->layer_mask_back_link()) layer = layer->layer_mask_back_link(); while (layer->parent()) layer = layer->parent(); return layer; } #if DCHECK_IS_ON() void CheckSnapped(float snapped_position) { // The acceptable error epsilon should be small enough to detect visible // artifacts as well as large enough to not cause false crashes when an // uncommon device scale factor is applied. const float kEplison = 0.003f; float diff = std::abs(snapped_position - std::round(snapped_position)); DCHECK_LT(diff, kEplison); } #endif } // namespace class Layer::LayerMirror : public LayerDelegate, LayerObserver { public: LayerMirror(Layer* source, Layer* dest) : source_(source), dest_(dest) { dest->AddObserver(this); dest->set_delegate(this); } LayerMirror(const LayerMirror&) = delete; LayerMirror& operator=(const LayerMirror&) = delete; ~LayerMirror() override { dest_->RemoveObserver(this); dest_->set_delegate(nullptr); } Layer* dest() { return dest_; } // LayerDelegate: void OnPaintLayer(const PaintContext& context) override { if (auto* delegate = source_->delegate()) delegate->OnPaintLayer(context); } void OnDeviceScaleFactorChanged(float old_device_scale_factor, float new_device_scale_factor) override {} // LayerObserver: void LayerDestroyed(Layer* layer) override { DCHECK_EQ(dest_, layer); source_->OnMirrorDestroyed(this); } private: Layer* const source_; Layer* const dest_; }; // Manages the subpixel offset data for a given set of parameters (device // scale factor and DIP offset from parent layer). class Layer::SubpixelPositionOffsetCache { public: SubpixelPositionOffsetCache() = default; SubpixelPositionOffsetCache(const SubpixelPositionOffsetCache&) = delete; SubpixelPositionOffsetCache& operator=(const SubpixelPositionOffsetCache&) = delete; ~SubpixelPositionOffsetCache() = default; gfx::Vector2dF GetSubpixelOffset(float device_scale_factor, const gfx::Point& origin, const gfx::Transform& tm) const { if (has_explicit_subpixel_offset_) return offset_; if (device_scale_factor <= 0) return gfx::Vector2dF(); // Compute the effective offset (position + transform) from the parent. gfx::PointF offset_from_parent(origin); if (!tm.IsIdentity() && tm.Preserves2dAxisAlignment()) offset_from_parent += tm.To2dTranslation(); if (device_scale_factor == device_scale_factor_ && offset_from_parent == offset_from_parent_) { return offset_; } // Compute subpixel offset for the given parameters. gfx::PointF scaled_offset_from_parent(offset_from_parent); scaled_offset_from_parent.Scale(device_scale_factor, device_scale_factor); gfx::PointF snapped_offset_from_parent( gfx::ToRoundedPoint(scaled_offset_from_parent)); gfx::Vector2dF offset = snapped_offset_from_parent - scaled_offset_from_parent; offset.Scale(1.f / device_scale_factor); // Store key and value information for the cache. offset_ = offset; device_scale_factor_ = device_scale_factor; offset_from_parent_ = offset_from_parent; #if DCHECK_IS_ON() const gfx::PointF snapped_position = offset_from_parent_ + offset_; CheckSnapped(snapped_position.x() * device_scale_factor); CheckSnapped(snapped_position.y() * device_scale_factor); #endif return offset_; } void SetExplicitSubpixelPositionOffset(const gfx::Vector2dF& offset) { has_explicit_subpixel_offset_ = true; offset_ = offset; } bool has_explicit_subpixel_offset() const { return has_explicit_subpixel_offset_; } private: // The subpixel offset value. mutable gfx::Vector2dF offset_; // The device scale factor for which the |offset_| was computed. mutable float device_scale_factor_ = 1.f; // The offset of the layer from its parent for which |offset_| was computed. mutable gfx::PointF offset_from_parent_; // True if the subpixel offset was computed and set by an external source. bool has_explicit_subpixel_offset_ = false; }; Layer::Layer(LayerType type) : type_(type), compositor_(nullptr), parent_(nullptr), subpixel_position_offset_( std::make_unique()), visible_(true), fills_bounds_opaquely_(true), fills_bounds_completely_(false), background_blur_sigma_(0.0f), layer_saturation_(0.0f), layer_brightness_(0.0f), layer_grayscale_(0.0f), layer_inverted_(false), layer_blur_sigma_(0.0f), layer_mask_(nullptr), layer_mask_back_link_(nullptr), zoom_(1), zoom_inset_(0), delegate_(nullptr), owner_(nullptr), cc_layer_(nullptr), device_scale_factor_(1.0f), cache_render_surface_requests_(0), deferred_paint_requests_(0), backdrop_filter_quality_(1.0f), trilinear_filtering_request_(0) { CreateCcLayer(); } Layer::~Layer() { for (auto& observer : observer_list_) observer.LayerDestroyed(this); // Destroying the animator may cause observers to use the layer. Destroy the // animator first so that the layer is still around. #if defined(ADDRESS_SANITIZER) destroyed_ = true; #endif SetAnimator(nullptr); if (compositor_) compositor_->SetRootLayer(nullptr); if (parent_) parent_->Remove(this); if (layer_mask_) SetMaskLayer(nullptr); if (layer_mask_back_link_) layer_mask_back_link_->SetMaskLayer(nullptr); for (auto* child : children_) child->parent_ = nullptr; if (content_layer_) content_layer_->ClearClient(); cc_layer_->RemoveFromParent(); if (transfer_release_callback_) std::move(transfer_release_callback_).Run(gpu::SyncToken(), false); ResetSubtreeReflectedLayer(); } std::unique_ptr Layer::Clone() const { auto clone = std::make_unique(type_); // Background filters. clone->SetBackgroundBlur(background_blur_sigma_); clone->SetBackgroundZoom(zoom_, zoom_inset_); // Filters. clone->SetLayerSaturation(layer_saturation_); clone->SetLayerBrightness(GetTargetBrightness()); clone->SetLayerGrayscale(GetTargetGrayscale()); clone->SetLayerInverted(layer_inverted_); clone->SetLayerBlur(layer_blur_sigma_); if (alpha_shape_) clone->SetAlphaShape(std::make_unique(*alpha_shape_)); // cc::Layer state. if (surface_layer_) { clone->SetShowSurface(surface_layer_->surface_id(), frame_size_in_dip_, surface_layer_->background_color(), surface_layer_->deadline_in_frames() ? cc::DeadlinePolicy::UseSpecifiedDeadline( *surface_layer_->deadline_in_frames()) : cc::DeadlinePolicy::UseDefaultDeadline(), surface_layer_->stretch_content_to_fill_bounds()); if (surface_layer_->oldest_acceptable_fallback()) clone->SetOldestAcceptableFallback( *surface_layer_->oldest_acceptable_fallback()); } else if (type_ == LAYER_SOLID_COLOR) { clone->SetColor(GetTargetColor()); } clone->SetTransform(GetTargetTransform()); clone->SetBounds(bounds_); if (subpixel_position_offset_->has_explicit_subpixel_offset()) clone->SetSubpixelPositionOffset(GetSubpixelOffset()); clone->SetMasksToBounds(GetMasksToBounds()); clone->SetOpacity(GetTargetOpacity()); clone->SetVisible(GetTargetVisibility()); clone->SetClipRect(GetTargetClipRect()); clone->SetAcceptEvents(accept_events()); clone->SetFillsBoundsOpaquely(fills_bounds_opaquely_); clone->SetFillsBoundsCompletely(fills_bounds_completely_); clone->SetRoundedCornerRadius(rounded_corner_radii()); clone->SetIsFastRoundedCorner(is_fast_rounded_corner()); clone->SetName(name_); // the |damaged_region_| will be sent to cc later in SendDamagedRects(). clone->damaged_region_ = damaged_region_; return clone; } std::unique_ptr Layer::Mirror() { auto mirror = Clone(); mirrors_.emplace_back(std::make_unique(this, mirror.get())); if (!transfer_resource_.mailbox_holder.mailbox.IsZero()) { // Send an empty release callback because we don't want the resource to be // freed up until the original layer releases it. mirror->SetTransferableResource( transfer_resource_, base::BindOnce([](const gpu::SyncToken& sync_token, bool is_lost) {}), frame_size_in_dip_); } return mirror; } void Layer::SetShowReflectedLayerSubtree(Layer* subtree_reflected_layer) { DCHECK(subtree_reflected_layer); DCHECK_EQ(type_, LAYER_SOLID_COLOR); if (subtree_reflected_layer_ == subtree_reflected_layer) return; scoped_refptr new_layer = cc::MirrorLayer::Create(subtree_reflected_layer->cc_layer_); if (!SwitchToLayer(new_layer)) return; mirror_layer_ = std::move(new_layer); subtree_reflected_layer_ = subtree_reflected_layer; auto insert_pair = subtree_reflected_layer_->subtree_reflecting_layers_.insert(this); DCHECK(insert_pair.second); MatchLayerSize(subtree_reflected_layer_); RecomputeDrawsContentAndUVRect(); } const Compositor* Layer::GetCompositor() const { return GetRoot(this)->compositor_; } float Layer::opacity() const { return cc_layer_->opacity(); } void Layer::SetCompositor(Compositor* compositor, scoped_refptr root_layer) { // This function must only be called to set the compositor on the root ui // layer. DCHECK(compositor); DCHECK(!compositor_); DCHECK(compositor->root_layer() == this); DCHECK(!parent_); compositor_ = compositor; OnDeviceScaleFactorChanged(compositor->device_scale_factor()); root_layer->AddChild(cc_layer_); SetCompositorForAnimatorsInTree(compositor); } void Layer::ResetCompositor() { DCHECK(!parent_); if (compositor_) { ResetCompositorForAnimatorsInTree(compositor_); compositor_ = nullptr; } } void Layer::AddObserver(LayerObserver* observer) { observer_list_.AddObserver(observer); } void Layer::RemoveObserver(LayerObserver* observer) { observer_list_.RemoveObserver(observer); } void Layer::Add(Layer* child) { DCHECK(!child->compositor_); if (child->parent_) child->parent_->Remove(child); child->parent_ = this; children_.push_back(child); cc_layer_->AddChild(child->cc_layer_); child->OnDeviceScaleFactorChanged(device_scale_factor_); Compositor* compositor = GetCompositor(); if (compositor) child->SetCompositorForAnimatorsInTree(compositor); } void Layer::Remove(Layer* child) { base::WeakPtr weak_this = weak_ptr_factory_.GetWeakPtr(); base::WeakPtr weak_child = child->weak_ptr_factory_.GetWeakPtr(); // Current bounds are used to calculate offsets when layers are reparented. // Stop (and complete) an ongoing animation to update the bounds immediately. LayerAnimator* child_animator = child->animator_.get(); if (child_animator) child_animator->StopAnimatingProperty(LayerAnimationElement::BOUNDS); // Do not proceed if |this| or |child| is released by an animation observer // of |child|'s bounds animation. if (!weak_this || !weak_child) return; Compositor* compositor = GetCompositor(); if (compositor) child->ResetCompositorForAnimatorsInTree(compositor); auto i = std::find(children_.begin(), children_.end(), child); DCHECK(i != children_.end()); children_.erase(i); child->parent_ = nullptr; child->cc_layer_->RemoveFromParent(); } void Layer::StackAtTop(Layer* child) { if (children_.size() <= 1 || child == children_.back()) return; // Already in front. StackAbove(child, children_.back()); } void Layer::StackAbove(Layer* child, Layer* other) { StackRelativeTo(child, other, true); } void Layer::StackAtBottom(Layer* child) { if (children_.size() <= 1 || child == children_.front()) return; // Already on bottom. StackBelow(child, children_.front()); } void Layer::StackBelow(Layer* child, Layer* other) { StackRelativeTo(child, other, false); } bool Layer::Contains(const Layer* other) const { for (const Layer* parent = other; parent; parent = parent->parent()) { if (parent == this) return true; } return false; } void Layer::SetAnimator(LayerAnimator* animator) { #if defined(ADDRESS_SANITIZER) CHECK(!destroyed_ || !animator); #endif Compositor* compositor = GetCompositor(); if (animator_) { if (compositor && !layer_mask_back_link()) animator_->DetachLayerAndTimeline(compositor); animator_->SetDelegate(nullptr); } animator_ = animator; if (animator_) { animator_->SetDelegate(this); if (compositor && !layer_mask_back_link()) animator_->AttachLayerAndTimeline(compositor); } } LayerAnimator* Layer::GetAnimator() { if (!animator_) SetAnimator(LayerAnimator::CreateDefaultAnimator()); return animator_.get(); } void Layer::SetSubtreeCaptureId(viz::SubtreeCaptureId subtree_id) { cc_layer_->SetSubtreeCaptureId(subtree_id); } viz::SubtreeCaptureId Layer::GetSubtreeCaptureId() const { return cc_layer_->subtree_capture_id(); } void Layer::SetTransform(const gfx::Transform& transform) { GetAnimator()->SetTransform(transform); } gfx::Transform Layer::GetTargetTransform() const { if (animator_ && animator_->IsAnimatingProperty( LayerAnimationElement::TRANSFORM)) { return animator_->GetTargetTransform(); } return transform(); } void Layer::SetBounds(const gfx::Rect& bounds) { GetAnimator()->SetBounds(bounds); } void Layer::SetSubpixelPositionOffset(const gfx::Vector2dF& offset) { subpixel_position_offset_->SetExplicitSubpixelPositionOffset(offset); RecomputePosition(); } const gfx::Vector2dF Layer::GetSubpixelOffset() const { return subpixel_position_offset_->GetSubpixelOffset( device_scale_factor_, GetTargetBounds().origin(), GetTargetTransform()); } gfx::Rect Layer::GetTargetBounds() const { if (animator_ && animator_->IsAnimatingProperty( LayerAnimationElement::BOUNDS)) { return animator_->GetTargetBounds(); } return bounds_; } void Layer::SetMasksToBounds(bool masks_to_bounds) { cc_layer_->SetMasksToBounds(masks_to_bounds); } bool Layer::GetMasksToBounds() const { return cc_layer_->masks_to_bounds(); } gfx::Rect Layer::GetTargetClipRect() const { if (animator_ && animator_->IsAnimatingProperty(LayerAnimationElement::CLIP)) { return animator_->GetTargetClipRect(); } return clip_rect(); } void Layer::SetClipRect(const gfx::Rect& clip_rect) { GetAnimator()->SetClipRect(clip_rect); } void Layer::SetOpacity(float opacity) { GetAnimator()->SetOpacity(opacity); } float Layer::GetCombinedOpacity() const { float opacity = this->opacity(); Layer* current = this->parent_; while (current) { opacity *= current->opacity(); current = current->parent_; } return opacity; } void Layer::SetBackgroundBlur(float blur_sigma) { background_blur_sigma_ = blur_sigma; SetLayerBackgroundFilters(); } void Layer::SetLayerBlur(float blur_sigma) { layer_blur_sigma_ = blur_sigma; SetLayerFilters(); } void Layer::SetLayerSaturation(float saturation) { layer_saturation_ = saturation; SetLayerFilters(); } void Layer::SetLayerBrightness(float brightness) { GetAnimator()->SetBrightness(brightness); } float Layer::GetTargetBrightness() const { if (animator_ && animator_->IsAnimatingProperty( LayerAnimationElement::BRIGHTNESS)) { return animator_->GetTargetBrightness(); } return layer_brightness(); } void Layer::SetLayerGrayscale(float grayscale) { GetAnimator()->SetGrayscale(grayscale); } float Layer::GetTargetGrayscale() const { if (animator_ && animator_->IsAnimatingProperty( LayerAnimationElement::GRAYSCALE)) { return animator_->GetTargetGrayscale(); } return layer_grayscale(); } void Layer::SetLayerInverted(bool inverted) { layer_inverted_ = inverted; SetLayerFilters(); } void Layer::SetMaskLayer(Layer* layer_mask) { if (layer_mask_ == layer_mask) return; // The provided mask should not have a layer mask itself. DCHECK(!layer_mask || (!layer_mask->layer_mask_layer() && layer_mask->children().empty() && !layer_mask->layer_mask_back_link_)); DCHECK(!layer_mask_back_link_); DCHECK(!layer_mask || layer_mask->type_ == LAYER_TEXTURED); // Masks must be backed by a PictureLayer. DCHECK(!layer_mask || layer_mask->content_layer_); // We need to de-reference the currently linked object so that no problem // arises if the mask layer gets deleted before this object. if (layer_mask_) layer_mask_->layer_mask_back_link_ = nullptr; layer_mask_ = layer_mask; cc_layer_->SetMaskLayer(layer_mask ? layer_mask->content_layer_.get() : nullptr); // We need to reference the linked object so that it can properly break the // link to us when it gets deleted. if (layer_mask) { layer_mask->layer_mask_back_link_ = this; layer_mask->OnDeviceScaleFactorChanged(device_scale_factor_); } } void Layer::SetBackgroundZoom(float zoom, int inset) { zoom_ = zoom; zoom_inset_ = inset; SetLayerBackgroundFilters(); } void Layer::SetAlphaShape(std::unique_ptr shape) { alpha_shape_ = std::move(shape); SetLayerFilters(); if (delegate_) delegate_->OnLayerAlphaShapeChanged(); } void Layer::SetLayerFilters() { cc::FilterOperations filters; if (layer_saturation_) { filters.Append(cc::FilterOperation::CreateSaturateFilter( layer_saturation_)); } if (layer_grayscale_) { filters.Append(cc::FilterOperation::CreateGrayscaleFilter( layer_grayscale_)); } if (layer_inverted_) filters.Append(cc::FilterOperation::CreateInvertFilter(1.0)); if (layer_blur_sigma_) { filters.Append(cc::FilterOperation::CreateBlurFilter(layer_blur_sigma_, SkTileMode::kClamp)); } // Brightness goes last, because the resulting colors neeed clamping, which // cause further color matrix filters to be applied separately. In this order, // they all can be combined in a single pass. if (layer_brightness_) { filters.Append(cc::FilterOperation::CreateSaturatingBrightnessFilter( layer_brightness_)); } if (alpha_shape_) { filters.Append(cc::FilterOperation::CreateAlphaThresholdFilter( *alpha_shape_, 0.f, 0.f)); } cc_layer_->SetFilters(filters); } void Layer::SetLayerBackgroundFilters() { cc::FilterOperations filters; if (zoom_ != 1) filters.Append(cc::FilterOperation::CreateZoomFilter(zoom_, zoom_inset_)); if (background_blur_sigma_) { filters.Append(cc::FilterOperation::CreateBlurFilter(background_blur_sigma_, SkTileMode::kClamp)); } cc_layer_->SetBackdropFilters(filters); } float Layer::GetTargetOpacity() const { if (animator_ && animator_->IsAnimatingProperty( LayerAnimationElement::OPACITY)) return animator_->GetTargetOpacity(); return opacity(); } void Layer::SetVisible(bool visible) { GetAnimator()->SetVisibility(visible); } void Layer::SetAcceptEvents(bool accept_events) { if (accept_events_ == accept_events) return; accept_events_ = accept_events; cc_layer_->SetHitTestable(IsHitTestableForCC()); } bool Layer::GetTargetVisibility() const { if (animator_ && animator_->IsAnimatingProperty( LayerAnimationElement::VISIBILITY)) return animator_->GetTargetVisibility(); return visible_; } bool Layer::IsDrawn() const { const Layer* layer = this; while (layer && layer->visible_) layer = layer->parent_; return layer == nullptr; } void Layer::SetRoundedCornerRadius(const gfx::RoundedCornersF& corner_radii) { GetAnimator()->SetRoundedCorners(corner_radii); } void Layer::SetIsFastRoundedCorner(bool enable) { cc_layer_->SetIsFastRoundedCorner(enable); ScheduleDraw(); for (const auto& mirror : mirrors_) mirror->dest()->SetIsFastRoundedCorner(enable); } bool Layer::GetTargetTransformRelativeTo(const Layer* ancestor, gfx::Transform* transform) const { return GetTransformRelativeToImpl(ancestor, /*is_target_transform=*/true, transform); } bool Layer::GetTransformRelativeTo(const Layer* ancestor, gfx::Transform* transform) const { return GetTransformRelativeToImpl(ancestor, /*is_target_transform=*/false, transform); } // static void Layer::ConvertPointToLayer(const Layer* source, const Layer* target, bool use_target_transform, gfx::PointF* point) { if (source == target) return; const Layer* root_layer = GetRoot(source); CHECK_EQ(root_layer, GetRoot(target)); if (source != root_layer) source->ConvertPointForAncestor(root_layer, use_target_transform, point); if (target != root_layer) target->ConvertPointFromAncestor(root_layer, use_target_transform, point); } void Layer::SetFillsBoundsOpaquely(bool fills_bounds_opaquely) { SetFillsBoundsOpaquelyWithReason(fills_bounds_opaquely, PropertyChangeReason::NOT_FROM_ANIMATION); } void Layer::SetFillsBoundsCompletely(bool fills_bounds_completely) { fills_bounds_completely_ = fills_bounds_completely; } void Layer::SetName(const std::string& name) { name_ = name; cc_layer_->SetDebugName(name); } bool Layer::SwitchToLayer(scoped_refptr new_layer) { // Finish animations being handled by cc_layer_. if (animator_) { base::WeakPtr weak_this = weak_ptr_factory_.GetWeakPtr(); animator_->StopAnimatingProperty(LayerAnimationElement::TRANSFORM); if (!weak_this) return false; animator_->StopAnimatingProperty(LayerAnimationElement::OPACITY); if (!weak_this) return false; animator_->SwitchToLayer(new_layer); } ResetSubtreeReflectedLayer(); if (texture_layer_.get()) texture_layer_->ClearClient(); cc_layer_->RemoveAllChildren(); if (cc_layer_->parent()) { cc_layer_->parent()->ReplaceChild(cc_layer_, new_layer); } cc_layer_->ClearDebugInfo(); new_layer->SetOpacity(cc_layer_->opacity()); new_layer->SetTransform(cc_layer_->transform()); new_layer->SetPosition(cc_layer_->position()); new_layer->SetBackgroundColor(cc_layer_->background_color()); new_layer->SetSafeOpaqueBackgroundColor( cc_layer_->SafeOpaqueBackgroundColor()); new_layer->SetSubtreeCaptureId(cc_layer_->subtree_capture_id()); new_layer->SetCacheRenderSurface(cc_layer_->cache_render_surface()); new_layer->SetTrilinearFiltering(cc_layer_->trilinear_filtering()); new_layer->SetRoundedCorner(cc_layer_->corner_radii()); new_layer->SetIsFastRoundedCorner(cc_layer_->is_fast_rounded_corner()); new_layer->SetMasksToBounds(cc_layer_->masks_to_bounds()); cc_layer_ = new_layer.get(); if (content_layer_) { content_layer_->ClearClient(); content_layer_ = nullptr; } solid_color_layer_ = nullptr; texture_layer_ = nullptr; surface_layer_ = nullptr; mirror_layer_ = nullptr; for (auto* child : children_) { DCHECK(child->cc_layer_); cc_layer_->AddChild(child->cc_layer_); } cc_layer_->SetTransformOrigin(gfx::Point3F()); cc_layer_->SetContentsOpaque(fills_bounds_opaquely_); cc_layer_->SetIsDrawable(type_ != LAYER_NOT_DRAWN); cc_layer_->SetHitTestable(IsHitTestableForCC()); cc_layer_->SetHideLayerAndSubtree(!visible_); cc_layer_->SetBackdropFilterQuality(backdrop_filter_quality_); cc_layer_->SetElementId(cc::ElementId(cc_layer_->id())); cc_layer_->SetDebugName(name_); SetLayerFilters(); SetLayerBackgroundFilters(); return true; } bool Layer::SwitchCCLayerForTest() { scoped_refptr new_layer = cc::PictureLayer::Create(this); if (!SwitchToLayer(new_layer)) return false; content_layer_ = std::move(new_layer); return true; } // Note: The code that sets this flag would be responsible to unset it on that // Layer. We do not want to clone this flag to a cloned layer by accident, // which could be a supprise. But we want to preserve it after switching to a // new cc::Layer. There could be a whole subtree and the root changed, but does // not mean we want to treat the cache all different. void Layer::AddCacheRenderSurfaceRequest() { ++cache_render_surface_requests_; TRACE_COUNTER_ID1("ui", "CacheRenderSurfaceRequests", this, cache_render_surface_requests_); if (cache_render_surface_requests_ == 1) cc_layer_->SetCacheRenderSurface(true); } void Layer::RemoveCacheRenderSurfaceRequest() { DCHECK_GT(cache_render_surface_requests_, 0u); --cache_render_surface_requests_; TRACE_COUNTER_ID1("ui", "CacheRenderSurfaceRequests", this, cache_render_surface_requests_); if (cache_render_surface_requests_ == 0) cc_layer_->SetCacheRenderSurface(false); } void Layer::SetBackdropFilterQuality(const float quality) { backdrop_filter_quality_ = quality / GetDeviceScaleFactor(); cc_layer_->SetBackdropFilterQuality(backdrop_filter_quality_); } void Layer::AddDeferredPaintRequest() { ++deferred_paint_requests_; TRACE_COUNTER_ID1("ui", "DeferredPaintRequests", this, deferred_paint_requests_); } void Layer::RemoveDeferredPaintRequest() { DCHECK_GT(deferred_paint_requests_, 0u); --deferred_paint_requests_; TRACE_COUNTER_ID1("ui", "DeferredPaintRequests", this, deferred_paint_requests_); if (!deferred_paint_requests_ && !damaged_region_.IsEmpty()) ScheduleDraw(); } // Note: The code that sets this flag would be responsible to unset it on that // Layer. We do not want to clone this flag to a cloned layer by accident, // which could be a supprise. But we want to preserve it after switching to a // new cc::Layer. There could be a whole subtree and the root changed, but does // not mean we want to treat the trilinear filtering all different. void Layer::AddTrilinearFilteringRequest() { ++trilinear_filtering_request_; TRACE_COUNTER_ID1("ui", "TrilinearFilteringRequests", this, trilinear_filtering_request_); if (trilinear_filtering_request_ == 1) cc_layer_->SetTrilinearFiltering(true); } void Layer::RemoveTrilinearFilteringRequest() { DCHECK_GT(trilinear_filtering_request_, 0u); --trilinear_filtering_request_; TRACE_COUNTER_ID1("ui", "TrilinearFilteringRequests", this, trilinear_filtering_request_); if (trilinear_filtering_request_ == 0) cc_layer_->SetTrilinearFiltering(false); } bool Layer::StretchContentToFillBounds() const { DCHECK(surface_layer_); return surface_layer_->stretch_content_to_fill_bounds(); } void Layer::SetSurfaceSize(gfx::Size surface_size_in_dip) { DCHECK(surface_layer_); if (frame_size_in_dip_ == surface_size_in_dip) return; frame_size_in_dip_ = surface_size_in_dip; RecomputeDrawsContentAndUVRect(); } bool Layer::ContainsMirrorForTest(Layer* mirror) const { const auto it = std::find_if(mirrors_.begin(), mirrors_.end(), [mirror](const std::unique_ptr& mirror_ptr) { return mirror_ptr.get()->dest() == mirror; }); return it != mirrors_.end(); } void Layer::SetTransferableResource(const viz::TransferableResource& resource, viz::ReleaseCallback release_callback, gfx::Size texture_size_in_dip) { DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR); DCHECK(!resource.mailbox_holder.mailbox.IsZero()); DCHECK(release_callback); DCHECK(!resource.is_software); if (!texture_layer_.get()) { scoped_refptr new_layer = cc::TextureLayer::CreateForMailbox(this); new_layer->SetFlipped(true); if (!SwitchToLayer(new_layer)) return; texture_layer_ = new_layer; // Reset the frame_size_in_dip_ so that SetTextureSize() will not early out, // the frame_size_in_dip_ was for a previous (different) |texture_layer_|. frame_size_in_dip_ = gfx::Size(); } if (transfer_release_callback_) std::move(transfer_release_callback_).Run(gpu::SyncToken(), false); transfer_release_callback_ = std::move(release_callback); transfer_resource_ = resource; SetTextureSize(texture_size_in_dip); for (const auto& mirror : mirrors_) { // The release callbacks should be empty as only the source layer // should be able to release the texture resource. mirror->dest()->SetTransferableResource( transfer_resource_, base::BindOnce([](const gpu::SyncToken& sync_token, bool is_lost) {}), frame_size_in_dip_); } } void Layer::SetTextureSize(gfx::Size texture_size_in_dip) { DCHECK(texture_layer_.get()); if (frame_size_in_dip_ == texture_size_in_dip) return; frame_size_in_dip_ = texture_size_in_dip; RecomputeDrawsContentAndUVRect(); texture_layer_->SetNeedsDisplay(); } void Layer::SetTextureFlipped(bool flipped) { DCHECK(texture_layer_.get()); texture_layer_->SetFlipped(flipped); } bool Layer::TextureFlipped() const { DCHECK(texture_layer_.get()); return texture_layer_->flipped(); } void Layer::SetShowSurface(const viz::SurfaceId& surface_id, const gfx::Size& frame_size_in_dip, SkColor default_background_color, const cc::DeadlinePolicy& deadline_policy, bool stretch_content_to_fill_bounds) { DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR); CreateSurfaceLayerIfNecessary(); surface_layer_->SetSurfaceId(surface_id, deadline_policy); surface_layer_->SetBackgroundColor(default_background_color); surface_layer_->SetSafeOpaqueBackgroundColor(default_background_color); surface_layer_->SetStretchContentToFillBounds(stretch_content_to_fill_bounds); frame_size_in_dip_ = frame_size_in_dip; RecomputeDrawsContentAndUVRect(); for (const auto& mirror : mirrors_) { mirror->dest()->SetShowSurface(surface_id, frame_size_in_dip, default_background_color, deadline_policy, stretch_content_to_fill_bounds); } } void Layer::SetOldestAcceptableFallback(const viz::SurfaceId& surface_id) { DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR); CreateSurfaceLayerIfNecessary(); surface_layer_->SetOldestAcceptableFallback(surface_id); for (const auto& mirror : mirrors_) mirror->dest()->SetOldestAcceptableFallback(surface_id); } void Layer::SetShowReflectedSurface(const viz::SurfaceId& surface_id, const gfx::Size& frame_size_in_pixels) { DCHECK(type_ == LAYER_TEXTURED || type_ == LAYER_SOLID_COLOR); if (!surface_layer_) { scoped_refptr new_layer = cc::SurfaceLayer::Create(); if (!SwitchToLayer(new_layer)) return; surface_layer_ = new_layer; } surface_layer_->SetSurfaceId(surface_id, cc::DeadlinePolicy::UseInfiniteDeadline()); surface_layer_->SetBackgroundColor(SK_ColorBLACK); surface_layer_->SetSafeOpaqueBackgroundColor(SK_ColorBLACK); surface_layer_->SetStretchContentToFillBounds(true); surface_layer_->SetIsReflection(true); // The reflecting surface uses the native size of the reflected display. frame_size_in_dip_ = frame_size_in_pixels; RecomputeDrawsContentAndUVRect(); } const viz::SurfaceId* Layer::GetSurfaceId() const { if (surface_layer_) return &surface_layer_->surface_id(); return nullptr; } const viz::SurfaceId* Layer::GetOldestAcceptableFallback() const { if (surface_layer_ && surface_layer_->oldest_acceptable_fallback()) return &surface_layer_->oldest_acceptable_fallback().value(); return nullptr; } void Layer::SetShowSolidColorContent() { DCHECK_EQ(type_, LAYER_SOLID_COLOR); if (solid_color_layer_.get()) return; scoped_refptr new_layer = cc::SolidColorLayer::Create(); if (!SwitchToLayer(new_layer)) return; solid_color_layer_ = new_layer; transfer_resource_ = viz::TransferableResource(); if (transfer_release_callback_) { std::move(transfer_release_callback_).Run(gpu::SyncToken(), false); } RecomputeDrawsContentAndUVRect(); for (const auto& mirror : mirrors_) mirror->dest()->SetShowSolidColorContent(); } void Layer::UpdateNinePatchLayerImage(const gfx::ImageSkia& image) { DCHECK_EQ(type_, LAYER_NINE_PATCH); DCHECK(nine_patch_layer_.get()); nine_patch_layer_image_ = image; // TODO(estade): we don't clean up old bitmaps in the UIResourceManager when // the scale factor changes. Currently for the way NinePatchLayers are used, // we don't need/want to, but we should address this in the future if it // becomes an issue. nine_patch_layer_->SetBitmap( image.GetRepresentation(device_scale_factor_).GetBitmap()); } void Layer::UpdateNinePatchLayerAperture(const gfx::Rect& aperture_in_dip) { DCHECK_EQ(type_, LAYER_NINE_PATCH); DCHECK(nine_patch_layer_.get()); nine_patch_layer_aperture_ = aperture_in_dip; // TODO(danakj): Specifying the aperture in DIPs as integers is not sufficient // and means the resulting aperture in pixels will not be exact. gfx::Rect aperture_in_pixel = gfx::ToEnclosingRect( gfx::ConvertRectToPixels(aperture_in_dip, device_scale_factor())); nine_patch_layer_->SetAperture(aperture_in_pixel); } void Layer::UpdateNinePatchLayerBorder(const gfx::Rect& border) { DCHECK_EQ(type_, LAYER_NINE_PATCH); DCHECK(nine_patch_layer_.get()); nine_patch_layer_->SetBorder(border); } void Layer::UpdateNinePatchOcclusion(const gfx::Rect& occlusion) { DCHECK_EQ(type_, LAYER_NINE_PATCH); DCHECK(nine_patch_layer_.get()); nine_patch_layer_->SetLayerOcclusion(occlusion); } void Layer::SetColor(SkColor color) { GetAnimator()->SetColor(color); } SkColor Layer::GetTargetColor() const { if (animator_ && animator_->IsAnimatingProperty( LayerAnimationElement::COLOR)) return animator_->GetTargetColor(); return cc_layer_->background_color(); } SkColor Layer::background_color() const { return cc_layer_->background_color(); } bool Layer::SchedulePaint(const gfx::Rect& invalid_rect) { if (type_ == LAYER_SOLID_COLOR && !texture_layer_) return false; if (type_ == LAYER_NINE_PATCH) return false; if (!delegate_ && transfer_resource_.mailbox_holder.mailbox.IsZero()) return false; damaged_region_.Union(invalid_rect); if (layer_mask_) layer_mask_->damaged_region_.Union(invalid_rect); if (!content_layer_ || !deferred_paint_requests_) ScheduleDraw(); return true; } void Layer::ScheduleDraw() { Compositor* compositor = GetCompositor(); if (compositor) compositor->ScheduleDraw(); } void Layer::SendDamagedRects() { if (layer_mask_) layer_mask_->SendDamagedRects(); if (delegate_) delegate_->UpdateVisualState(); if (damaged_region_.IsEmpty()) return; if (!delegate_ && transfer_resource_.mailbox_holder.mailbox.IsZero()) return; if (content_layer_ && deferred_paint_requests_) return; for (gfx::Rect damaged_rect : damaged_region_) cc_layer_->SetNeedsDisplayRect(damaged_rect); if (content_layer_) paint_region_.Union(damaged_region_); damaged_region_.Clear(); } void Layer::CompleteAllAnimations() { typedef std::vector > LayerAnimatorVector; LayerAnimatorVector animators; CollectAnimators(&animators); for (LayerAnimatorVector::const_iterator it = animators.begin(); it != animators.end(); ++it) { (*it)->StopAnimating(); } } void Layer::StackChildrenAtBottom( const std::vector& new_leading_children) { std::vector new_children_order; new_children_order.reserve(children_.size()); cc::LayerList new_cc_children_order; new_cc_children_order.reserve(cc_layer_->children().size()); for (Layer* leading_child : new_leading_children) { DCHECK_EQ(leading_child->cc_layer_->parent(), cc_layer_); DCHECK_EQ(leading_child->parent(), this); new_children_order.emplace_back(leading_child); new_cc_children_order.emplace_back( scoped_refptr(leading_child->cc_layer_)); } base::flat_set reordered_children(new_children_order); const cc::LayerList& old_cc_children_order = cc_layer_->children(); for (size_t i = 0; i < children_.size(); ++i) { if (reordered_children.count(children_.at(i)) > 0) continue; new_children_order.emplace_back(children_.at(i)); new_cc_children_order.emplace_back(old_cc_children_order.at(i)); } children_ = std::move(new_children_order); cc_layer_->ReorderChildren(&new_cc_children_order); } void Layer::SuppressPaint() { if (!delegate_) return; delegate_ = nullptr; for (auto* child : children_) child->SuppressPaint(); } void Layer::OnDeviceScaleFactorChanged(float device_scale_factor) { if (device_scale_factor_ == device_scale_factor) return; base::WeakPtr weak_this = weak_ptr_factory_.GetWeakPtr(); // Some animation observers may mutate the tree (e.g. destroy the layer, // change ancestor/sibling z-order etc) when the animation ends. This break // the tree traversal and could lead to a crash. Collect all descendants (and // their mask layers) in a flattened WeakPtr list at the root level then stop // animations to let potential tree mutations happen before traversing the // tree. See https://crbug.com/1037852. const bool is_root_layer = !parent(); if (is_root_layer) { std::vector> flattened; GetFlattenedWeakList(&flattened); for (auto& weak_layer : flattened) { // Skip if layer is gone or not animating. if (!weak_layer || !weak_layer->animator_) continue; weak_layer->animator_->StopAnimatingProperty( LayerAnimationElement::TRANSFORM); // Do not proceed if the root layer was destroyed due to an animation // observer. if (!weak_this) return; } } const float old_device_scale_factor = device_scale_factor_; device_scale_factor_ = device_scale_factor; RecomputeDrawsContentAndUVRect(); RecomputePosition(); if (nine_patch_layer_) { if (!nine_patch_layer_image_.isNull()) UpdateNinePatchLayerImage(nine_patch_layer_image_); UpdateNinePatchLayerAperture(nine_patch_layer_aperture_); } SchedulePaint(gfx::Rect(bounds_.size())); if (delegate_) { delegate_->OnDeviceScaleFactorChanged(old_device_scale_factor, device_scale_factor); } for (auto* child : children_) { child->OnDeviceScaleFactorChanged(device_scale_factor); // A child layer may have triggered a delegate or an observer to delete // |this| layer. In which case return early to avoid crash. if (!weak_this) return; } if (layer_mask_) layer_mask_->OnDeviceScaleFactorChanged(device_scale_factor); } void Layer::SetDidScrollCallback( base::RepeatingCallback callback) { cc_layer_->SetDidScrollCallback(std::move(callback)); } void Layer::SetScrollable(const gfx::Size& container_bounds) { cc_layer_->SetScrollable(container_bounds); cc_layer_->SetUserScrollable(true, true); } gfx::ScrollOffset Layer::CurrentScrollOffset() const { const Compositor* compositor = GetCompositor(); gfx::ScrollOffset offset; if (compositor && compositor->GetScrollOffsetForLayer(cc_layer_->element_id(), &offset)) return offset; return cc_layer_->scroll_offset(); } void Layer::SetScrollOffset(const gfx::ScrollOffset& offset) { Compositor* compositor = GetCompositor(); bool scrolled_on_impl_side = compositor && compositor->ScrollLayerTo(cc_layer_->element_id(), offset); if (!scrolled_on_impl_side) cc_layer_->SetScrollOffset(offset); // TODO(crbug.com/1219662): If this layer was also resized since the last // commit synchronizing |cc_layer_| with the cc::LayerImpl backing // |compositor|, the scroll might not be completed. } void Layer::RequestCopyOfOutput( std::unique_ptr request) { cc_layer_->RequestCopyOfOutput(std::move(request)); } gfx::Rect Layer::PaintableRegion() const { return gfx::Rect(size()); } scoped_refptr Layer::PaintContentsToDisplayList() { TRACE_EVENT1("ui", "Layer::PaintContentsToDisplayList", "name", name_); gfx::Rect local_bounds(bounds().size()); gfx::Rect invalidation( gfx::IntersectRects(paint_region_.bounds(), local_bounds)); paint_region_.Clear(); auto display_list = base::MakeRefCounted(); if (delegate_) { delegate_->OnPaintLayer(PaintContext(display_list.get(), device_scale_factor_, invalidation, GetCompositor()->is_pixel_canvas())); } display_list->Finalize(); // TODO(domlaskowski): Move mirror invalidation to Layer::SchedulePaint. for (const auto& mirror : mirrors_) mirror->dest()->SchedulePaint(invalidation); return display_list; } bool Layer::FillsBoundsCompletely() const { return fills_bounds_completely_; } bool Layer::PrepareTransferableResource( cc::SharedBitmapIdRegistrar* bitmap_registar, viz::TransferableResource* resource, viz::ReleaseCallback* release_callback) { if (!transfer_release_callback_) return false; *resource = transfer_resource_; *release_callback = std::move(transfer_release_callback_); return true; } void Layer::CollectAnimators( std::vector>* animators) { if (animator_ && animator_->is_animating()) animators->push_back(animator_); for (auto* child : children_) child->CollectAnimators(animators); } void Layer::StackRelativeTo(Layer* child, Layer* other, bool above) { DCHECK_NE(child, other); DCHECK_EQ(this, child->parent()); DCHECK_EQ(this, other->parent()); const size_t child_i = std::find(children_.begin(), children_.end(), child) - children_.begin(); const size_t other_i = std::find(children_.begin(), children_.end(), other) - children_.begin(); if ((above && child_i == other_i + 1) || (!above && child_i + 1 == other_i)) return; const size_t dest_i = above ? (child_i < other_i ? other_i : other_i + 1) : (child_i < other_i ? other_i - 1 : other_i); children_.erase(children_.begin() + child_i); children_.insert(children_.begin() + dest_i, child); child->cc_layer_->RemoveFromParent(); cc_layer_->InsertChild(child->cc_layer_, dest_i); } bool Layer::ConvertPointForAncestor(const Layer* ancestor, bool use_target_transform, gfx::PointF* point) const { gfx::Transform transform; bool result = use_target_transform ? GetTargetTransformRelativeTo(ancestor, &transform) : GetTransformRelativeTo(ancestor, &transform); auto p = gfx::Point3F(*point); transform.TransformPoint(&p); *point = p.AsPointF(); return result; } bool Layer::ConvertPointFromAncestor(const Layer* ancestor, bool use_target_transform, gfx::PointF* point) const { gfx::Transform transform; bool result = use_target_transform ? GetTargetTransformRelativeTo(ancestor, &transform) : GetTransformRelativeTo(ancestor, &transform); auto p = gfx::Point3F(*point); transform.TransformPointReverse(&p); *point = p.AsPointF(); return result; } void Layer::SetBoundsFromAnimation(const gfx::Rect& bounds, PropertyChangeReason reason) { if (bounds == bounds_) return; const gfx::Rect old_bounds = bounds_; bounds_ = bounds; RecomputeDrawsContentAndUVRect(); if (old_bounds.origin() != bounds_.origin()) RecomputePosition(); auto ptr = weak_ptr_factory_.GetWeakPtr(); if (delegate_) delegate_->OnLayerBoundsChanged(old_bounds, reason); // The layer may be deleted in the observer. if (!ptr) return; if (bounds.size() == old_bounds.size()) { // Don't schedule a draw if we're invisible. We'll schedule one // automatically when we get visible. if (IsDrawn()) ScheduleDraw(); } else { // Always schedule a paint, even if we're invisible. SchedulePaint(gfx::Rect(bounds.size())); } for (const auto& mirror : mirrors_) { Layer* mirror_dest = mirror->dest(); if (mirror_dest->sync_bounds_with_source_) mirror_dest->SetBounds(bounds); } for (auto* reflecting_layer : subtree_reflecting_layers_) reflecting_layer->MatchLayerSize(this); } void Layer::SetTransformFromAnimation(const gfx::Transform& new_transform, PropertyChangeReason reason) { const gfx::Transform old_transform = transform(); if (old_transform == new_transform) return; cc_layer_->SetTransform(new_transform); // Skip recomputing position if the subpixel offset does not need updating // which is the case if an explicit offset is set. if (!subpixel_position_offset_->has_explicit_subpixel_offset()) RecomputePosition(); if (delegate_) delegate_->OnLayerTransformed(old_transform, reason); } void Layer::SetOpacityFromAnimation(float opacity, PropertyChangeReason reason) { cc_layer_->SetOpacity(opacity); if (delegate_) delegate_->OnLayerOpacityChanged(reason); ScheduleDraw(); } void Layer::SetVisibilityFromAnimation(bool visible, PropertyChangeReason reason) { // Sync changes with the mirror layers only if they want so. for (const auto& mirror : mirrors_) { Layer* mirror_dest = mirror->dest(); if (mirror_dest->sync_visibility_with_source_) mirror_dest->SetVisible(visible); } if (visible_ == visible) return; visible_ = visible; cc_layer_->SetHideLayerAndSubtree(!visible_); cc_layer_->SetHitTestable(IsHitTestableForCC()); } void Layer::SetBrightnessFromAnimation(float brightness, PropertyChangeReason reason) { layer_brightness_ = brightness; SetLayerFilters(); } void Layer::SetGrayscaleFromAnimation(float grayscale, PropertyChangeReason reason) { layer_grayscale_ = grayscale; SetLayerFilters(); } void Layer::SetColorFromAnimation(SkColor color, PropertyChangeReason reason) { DCHECK_EQ(type_, LAYER_SOLID_COLOR); cc_layer_->SetBackgroundColor(color); cc_layer_->SetSafeOpaqueBackgroundColor(color); SetFillsBoundsOpaquelyWithReason(SkColorGetA(color) == 0xFF, reason); } void Layer::SetClipRectFromAnimation(const gfx::Rect& clip_rect, PropertyChangeReason reason) { cc_layer_->SetClipRect(clip_rect); } void Layer::SetRoundedCornersFromAnimation( const gfx::RoundedCornersF& rounded_corners, PropertyChangeReason reason) { cc_layer_->SetRoundedCorner(rounded_corners); for (const auto& mirror : mirrors_) mirror->dest()->SetRoundedCornersFromAnimation(rounded_corners, reason); } void Layer::ScheduleDrawForAnimation() { ScheduleDraw(); } const gfx::Rect& Layer::GetBoundsForAnimation() const { return bounds(); } gfx::Transform Layer::GetTransformForAnimation() const { return transform(); } float Layer::GetOpacityForAnimation() const { return opacity(); } bool Layer::GetVisibilityForAnimation() const { return visible(); } float Layer::GetBrightnessForAnimation() const { return layer_brightness(); } float Layer::GetGrayscaleForAnimation() const { return layer_grayscale(); } SkColor Layer::GetColorForAnimation() const { // The NULL check is here since this is invoked regardless of whether we have // been configured as LAYER_SOLID_COLOR. return solid_color_layer_.get() ? solid_color_layer_->background_color() : SK_ColorBLACK; } gfx::Rect Layer::GetClipRectForAnimation() const { if (clip_rect().IsEmpty()) return gfx::Rect(size()); return clip_rect(); } gfx::RoundedCornersF Layer::GetRoundedCornersForAnimation() const { return rounded_corner_radii(); } float Layer::GetDeviceScaleFactor() const { return device_scale_factor_; } LayerAnimatorCollection* Layer::GetLayerAnimatorCollection() { Compositor* compositor = GetCompositor(); return compositor ? compositor->layer_animator_collection() : nullptr; } absl::optional Layer::GetFrameNumber() const { if (const Compositor* compositor = GetCompositor()) { return compositor->activated_frame_count(); } return absl::nullopt; } float Layer::GetRefreshRate() const { const Compositor* compositor = GetCompositor(); return compositor ? compositor->refresh_rate() : 60.0; } Layer* Layer::GetLayer() { return this; } cc::Layer* Layer::GetCcLayer() const { return cc_layer_; } LayerThreadedAnimationDelegate* Layer::GetThreadedAnimationDelegate() { DCHECK(animator_); return animator_.get(); } void Layer::CreateCcLayer() { if (type_ == LAYER_SOLID_COLOR) { solid_color_layer_ = cc::SolidColorLayer::Create(); cc_layer_ = solid_color_layer_.get(); } else if (type_ == LAYER_NINE_PATCH) { nine_patch_layer_ = cc::NinePatchLayer::Create(); cc_layer_ = nine_patch_layer_.get(); } else { content_layer_ = cc::PictureLayer::Create(this); cc_layer_ = content_layer_.get(); } cc_layer_->SetTransformOrigin(gfx::Point3F()); cc_layer_->SetContentsOpaque(true); cc_layer_->SetSafeOpaqueBackgroundColor(SK_ColorWHITE); cc_layer_->SetIsDrawable(type_ != LAYER_NOT_DRAWN); cc_layer_->SetHitTestable(IsHitTestableForCC()); cc_layer_->SetElementId(cc::ElementId(cc_layer_->id())); RecomputePosition(); } void Layer::RecomputeDrawsContentAndUVRect() { DCHECK(cc_layer_); gfx::Size size(bounds_.size()); if (texture_layer_.get()) { size.SetToMin(frame_size_in_dip_); gfx::PointF uv_top_left(0.f, 0.f); gfx::PointF uv_bottom_right( static_cast(size.width()) / frame_size_in_dip_.width(), static_cast(size.height()) / frame_size_in_dip_.height()); texture_layer_->SetUV(uv_top_left, uv_bottom_right); } else if (surface_layer_.get()) { size.SetToMin(frame_size_in_dip_); } cc_layer_->SetBounds(size); } void Layer::RecomputePosition() { cc_layer_->SetPosition(gfx::PointF(bounds_.origin()) + GetSubpixelOffset()); } void Layer::SetCompositorForAnimatorsInTree(Compositor* compositor) { DCHECK(compositor); LayerAnimatorCollection* collection = compositor->layer_animator_collection(); if (animator_) { if (animator_->is_animating()) animator_->AddToCollection(collection); animator_->AttachLayerAndTimeline(compositor); } for (auto* child : children_) child->SetCompositorForAnimatorsInTree(compositor); } void Layer::ResetCompositorForAnimatorsInTree(Compositor* compositor) { DCHECK(compositor); LayerAnimatorCollection* collection = compositor->layer_animator_collection(); if (animator_) { animator_->DetachLayerAndTimeline(compositor); animator_->RemoveFromCollection(collection); } for (auto* child : children_) child->ResetCompositorForAnimatorsInTree(compositor); } void Layer::OnMirrorDestroyed(LayerMirror* mirror) { const auto it = std::find_if(mirrors_.begin(), mirrors_.end(), [mirror](const std::unique_ptr& mirror_ptr) { return mirror_ptr.get() == mirror; }); DCHECK(it != mirrors_.end()); mirrors_.erase(it); } void Layer::CreateSurfaceLayerIfNecessary() { if (surface_layer_) return; scoped_refptr new_layer = cc::SurfaceLayer::Create(); new_layer->SetSurfaceHitTestable(true); if (!SwitchToLayer(new_layer)) return; surface_layer_ = new_layer; } void Layer::MatchLayerSize(const Layer* layer) { gfx::Rect new_bounds = bounds_; gfx::Size new_size = layer->bounds().size(); new_bounds.set_size(new_size); SetBounds(new_bounds); } void Layer::ResetSubtreeReflectedLayer() { if (!subtree_reflected_layer_) return; size_t result = subtree_reflected_layer_->subtree_reflecting_layers_.erase(this); DCHECK_EQ(1u, result); subtree_reflected_layer_ = nullptr; } void Layer::GetFlattenedWeakList( std::vector>* flattened_list) { flattened_list->emplace_back(weak_ptr_factory_.GetWeakPtr()); if (layer_mask_) flattened_list->emplace_back(layer_mask_->weak_ptr_factory_.GetWeakPtr()); for (auto* child : children_) child->GetFlattenedWeakList(flattened_list); } void Layer::SetFillsBoundsOpaquelyWithReason(bool fills_bounds_opaquely, PropertyChangeReason reason) { if (fills_bounds_opaquely_ == fills_bounds_opaquely) return; fills_bounds_opaquely_ = fills_bounds_opaquely; cc_layer_->SetContentsOpaque(fills_bounds_opaquely); if (delegate_) delegate_->OnLayerFillsBoundsOpaquelyChanged(reason); } bool Layer::GetTransformRelativeToImpl(const Layer* ancestor, bool is_target_transform, gfx::Transform* transform) const { const Layer* p = this; for (; p && p != ancestor; p = p->parent()) { gfx::Transform translation; translation.Translate(static_cast(p->bounds().x()), static_cast(p->bounds().y())); const gfx::Transform& layer_transform = is_target_transform ? p->GetTargetTransform() : p->transform(); if (!layer_transform.IsIdentity()) transform->ConcatTransform(layer_transform); transform->ConcatTransform(translation); } return p == ancestor; } } // namespace ui