blob: 5819e84d72129a36e188d4ef308f1fb12b783d19 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/layers/nine_patch_thumb_scrollbar_layer.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "base/auto_reset.h"
#include "cc/base/math_util.h"
#include "cc/layers/nine_patch_thumb_scrollbar_layer_impl.h"
#include "cc/paint/skia_paint_canvas.h"
#include "cc/resources/ui_resource_bitmap.h"
#include "cc/resources/ui_resource_manager.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSize.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
namespace cc {
std::unique_ptr<LayerImpl> NinePatchThumbScrollbarLayer::CreateLayerImpl(
LayerTreeImpl* tree_impl) const {
return NinePatchThumbScrollbarLayerImpl::Create(
tree_impl, id(), orientation(), is_left_side_vertical_scrollbar());
}
scoped_refptr<NinePatchThumbScrollbarLayer>
NinePatchThumbScrollbarLayer::CreateOrReuse(
scoped_refptr<Scrollbar> scrollbar,
NinePatchThumbScrollbarLayer* existing_layer) {
if (existing_layer &&
existing_layer->scrollbar_.Read(*existing_layer)->IsSame(*scrollbar))
return existing_layer;
return Create(std::move(scrollbar));
}
scoped_refptr<NinePatchThumbScrollbarLayer>
NinePatchThumbScrollbarLayer::Create(scoped_refptr<Scrollbar> scrollbar) {
return base::WrapRefCounted(
new NinePatchThumbScrollbarLayer(std::move(scrollbar)));
}
NinePatchThumbScrollbarLayer::NinePatchThumbScrollbarLayer(
scoped_refptr<Scrollbar> scrollbar)
: ScrollbarLayerBase(scrollbar->Orientation(),
scrollbar->IsLeftSideVerticalScrollbar()),
scrollbar_(std::move(scrollbar)) {
DCHECK(scrollbar_.Read(*this)->HasThumb());
DCHECK(scrollbar_.Read(*this)->IsOverlay());
DCHECK(scrollbar_.Read(*this)->UsesNinePatchThumbResource());
}
NinePatchThumbScrollbarLayer::~NinePatchThumbScrollbarLayer() = default;
bool NinePatchThumbScrollbarLayer::OpacityCanAnimateOnImplThread() const {
return true;
}
void NinePatchThumbScrollbarLayer::PushPropertiesTo(
LayerImpl* layer,
const CommitState& commit_state,
const ThreadUnsafeCommitState& unsafe_state) {
ScrollbarLayerBase::PushPropertiesTo(layer, commit_state, unsafe_state);
NinePatchThumbScrollbarLayerImpl* scrollbar_layer =
static_cast<NinePatchThumbScrollbarLayerImpl*>(layer);
if (orientation() == ScrollbarOrientation::kHorizontal) {
scrollbar_layer->SetThumbThickness(thumb_size_.Read(*this).height());
scrollbar_layer->SetThumbLength(thumb_size_.Read(*this).width());
scrollbar_layer->SetTrackStart(track_rect_.Read(*this).x());
scrollbar_layer->SetTrackLength(track_rect_.Read(*this).width());
} else {
scrollbar_layer->SetThumbThickness(thumb_size_.Read(*this).width());
scrollbar_layer->SetThumbLength(thumb_size_.Read(*this).height());
scrollbar_layer->SetTrackStart(track_rect_.Read(*this).y());
scrollbar_layer->SetTrackLength(track_rect_.Read(*this).height());
}
if (thumb_resource_.Read(*this)) {
auto iter =
commit_state.ui_resource_sizes.find(thumb_resource_.Read(*this)->id());
gfx::Size image_bounds = (iter == commit_state.ui_resource_sizes.end())
? gfx::Size()
: iter->second;
scrollbar_layer->SetImageBounds(image_bounds);
scrollbar_layer->SetAperture(aperture_.Read(*this));
scrollbar_layer->set_thumb_ui_resource_id(
thumb_resource_.Read(*this)->id());
} else {
scrollbar_layer->SetImageBounds(gfx::Size());
scrollbar_layer->SetAperture(gfx::Rect());
scrollbar_layer->set_thumb_ui_resource_id(0);
}
if (track_resource_.Read(*this))
scrollbar_layer->set_track_ui_resource_id(
track_resource_.Read(*this)->id());
else
scrollbar_layer->set_track_ui_resource_id(0);
}
void NinePatchThumbScrollbarLayer::SetLayerTreeHost(LayerTreeHost* host) {
// When the LTH is set to null or has changed, then this layer should remove
// all of its associated resources.
if (host != layer_tree_host()) {
thumb_resource_.Write(*this).reset();
track_resource_.Write(*this).reset();
}
ScrollbarLayerBase::SetLayerTreeHost(host);
}
bool NinePatchThumbScrollbarLayer::Update() {
// These properties should never change.
DCHECK_EQ(orientation(), scrollbar_.Read(*this)->Orientation());
DCHECK_EQ(is_left_side_vertical_scrollbar(),
scrollbar_.Read(*this)->IsLeftSideVerticalScrollbar());
DCHECK(scrollbar_.Read(*this)->HasThumb());
DCHECK(scrollbar_.Read(*this)->IsOverlay());
DCHECK(scrollbar_.Read(*this)->UsesNinePatchThumbResource());
bool updated = false;
updated |= Layer::Update();
updated |= UpdateProperty(scrollbar_.Read(*this)->TrackRect(),
&track_rect_.Write(*this));
// Ignore ThumbRect's location because the NinePatchThumbScrollbarLayerImpl
// will compute it from scroll offset.
updated |= UpdateProperty(scrollbar_.Read(*this)->ThumbRect().size(),
&thumb_size_.Write(*this));
updated |= PaintThumbIfNeeded();
updated |= SetHasFindInPageTickmarks(scrollbar_.Read(*this)->HasTickmarks());
updated |= PaintTickmarks();
return updated;
}
bool NinePatchThumbScrollbarLayer::PaintThumbIfNeeded() {
auto& scrollbar = scrollbar_.Read(*this);
if (!scrollbar->NeedsRepaintPart(ScrollbarPart::kThumb) &&
thumb_resource_.Read(*this)) {
return false;
}
gfx::Size paint_size = scrollbar->NinePatchThumbCanvasSize();
DCHECK(!paint_size.IsEmpty());
aperture_.Write(*this) = scrollbar->NinePatchThumbAperture();
SkBitmap skbitmap;
skbitmap.allocN32Pixels(paint_size.width(), paint_size.height());
SkiaPaintCanvas canvas(skbitmap);
canvas.clear(SkColors::kTransparent);
scrollbar->PaintPart(&canvas, ScrollbarPart::kThumb, gfx::Rect(paint_size));
// Make sure that the pixels are no longer mutable to unavoid unnecessary
// allocation and copying.
skbitmap.setImmutable();
thumb_resource_.Write(*this) = ScopedUIResource::Create(
layer_tree_host()->GetUIResourceManager(), UIResourceBitmap(skbitmap));
SetNeedsPushProperties();
return true;
}
bool NinePatchThumbScrollbarLayer::PaintTickmarks() {
if (!has_find_in_page_tickmarks()) {
if (!track_resource_.Read(*this)) {
return false;
} else {
// Remove previous tickmarks.
track_resource_.Write(*this).reset();
SetNeedsPushProperties();
return true;
}
}
gfx::Size paint_size = track_rect_.Read(*this).size();
DCHECK(!paint_size.IsEmpty());
SkBitmap skbitmap;
skbitmap.allocN32Pixels(paint_size.width(), paint_size.height());
SkiaPaintCanvas canvas(skbitmap);
canvas.clear(SkColors::kTransparent);
scrollbar_.Write(*this)->PaintPart(
&canvas, ScrollbarPart::kTrackButtonsTickmarks, gfx::Rect(paint_size));
// Make sure that the pixels are no longer mutable to unavoid unnecessary
// allocation and copying.
skbitmap.setImmutable();
track_resource_.Write(*this) = ScopedUIResource::Create(
layer_tree_host()->GetUIResourceManager(), UIResourceBitmap(skbitmap));
SetNeedsPushProperties();
return true;
}
ScrollbarLayerBase::ScrollbarLayerType
NinePatchThumbScrollbarLayer::GetScrollbarLayerType() const {
return kNinePatchThumb;
}
} // namespace cc