blob: e6fcf5ff6eceed778369ca89fb60e040d8803d84 [file] [log] [blame]
// Copyright 2016 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 "cc/layers/painted_overlay_scrollbar_layer.h"
#include <algorithm>
#include "base/auto_reset.h"
#include "cc/base/math_util.h"
#include "cc/layers/painted_overlay_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/skia_util.h"
namespace cc {
std::unique_ptr<LayerImpl> PaintedOverlayScrollbarLayer::CreateLayerImpl(
LayerTreeImpl* tree_impl) {
return PaintedOverlayScrollbarLayerImpl::Create(
tree_impl, id(), scrollbar_->Orientation(),
scrollbar_->IsLeftSideVerticalScrollbar());
}
scoped_refptr<PaintedOverlayScrollbarLayer>
PaintedOverlayScrollbarLayer::Create(std::unique_ptr<Scrollbar> scrollbar,
ElementId scroll_element_id) {
return base::WrapRefCounted(new PaintedOverlayScrollbarLayer(
std::move(scrollbar), scroll_element_id));
}
PaintedOverlayScrollbarLayer::PaintedOverlayScrollbarLayer(
std::unique_ptr<Scrollbar> scrollbar,
ElementId scroll_element_id)
: scrollbar_(std::move(scrollbar)),
scroll_element_id_(scroll_element_id),
thumb_thickness_(scrollbar_->ThumbThickness()),
thumb_length_(scrollbar_->ThumbLength()) {
DCHECK(scrollbar_->UsesNinePatchThumbResource());
SetIsScrollbar(true);
}
PaintedOverlayScrollbarLayer::~PaintedOverlayScrollbarLayer() = default;
void PaintedOverlayScrollbarLayer::SetScrollElementId(ElementId element_id) {
if (element_id == scroll_element_id_)
return;
scroll_element_id_ = element_id;
SetNeedsCommit();
}
bool PaintedOverlayScrollbarLayer::OpacityCanAnimateOnImplThread() const {
return scrollbar_->IsOverlay();
}
void PaintedOverlayScrollbarLayer::PushPropertiesTo(LayerImpl* layer) {
Layer::PushPropertiesTo(layer);
PaintedOverlayScrollbarLayerImpl* scrollbar_layer =
static_cast<PaintedOverlayScrollbarLayerImpl*>(layer);
scrollbar_layer->SetScrollElementId(scroll_element_id_);
scrollbar_layer->SetThumbThickness(thumb_thickness_);
scrollbar_layer->SetThumbLength(thumb_length_);
if (scrollbar_->Orientation() == HORIZONTAL) {
scrollbar_layer->SetTrackStart(track_rect_.x());
scrollbar_layer->SetTrackLength(track_rect_.width());
} else {
scrollbar_layer->SetTrackStart(track_rect_.y());
scrollbar_layer->SetTrackLength(track_rect_.height());
}
if (thumb_resource_.get()) {
scrollbar_layer->SetImageBounds(
layer_tree_host()->GetUIResourceManager()->GetUIResourceSize(
thumb_resource_->id()));
scrollbar_layer->SetAperture(aperture_);
scrollbar_layer->set_thumb_ui_resource_id(thumb_resource_->id());
} else {
scrollbar_layer->SetImageBounds(gfx::Size());
scrollbar_layer->SetAperture(gfx::Rect());
scrollbar_layer->set_thumb_ui_resource_id(0);
}
if (track_resource_.get())
scrollbar_layer->set_track_ui_resource_id(track_resource_->id());
else
scrollbar_layer->set_track_ui_resource_id(0);
}
void PaintedOverlayScrollbarLayer::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_.reset();
track_resource_.reset();
}
Layer::SetLayerTreeHost(host);
}
gfx::Rect PaintedOverlayScrollbarLayer::OriginThumbRectForPainting() const {
return gfx::Rect(gfx::Point(), scrollbar_->NinePatchThumbCanvasSize());
}
bool PaintedOverlayScrollbarLayer::Update() {
bool updated = false;
updated |= Layer::Update();
DCHECK(scrollbar_->HasThumb());
DCHECK(scrollbar_->IsOverlay());
DCHECK(scrollbar_->UsesNinePatchThumbResource());
updated |= UpdateProperty(scrollbar_->TrackRect(), &track_rect_);
updated |= UpdateProperty(scrollbar_->Location(), &location_);
updated |= UpdateProperty(scrollbar_->ThumbThickness(), &thumb_thickness_);
updated |= UpdateProperty(scrollbar_->ThumbLength(), &thumb_length_);
updated |= PaintThumbIfNeeded();
updated |= PaintTickmarks();
return updated;
}
bool PaintedOverlayScrollbarLayer::PaintThumbIfNeeded() {
if (!scrollbar_->NeedsPaintPart(THUMB) && thumb_resource_)
return false;
gfx::Rect paint_rect = OriginThumbRectForPainting();
aperture_ = scrollbar_->NinePatchThumbAperture();
DCHECK(!paint_rect.size().IsEmpty());
DCHECK(paint_rect.origin().IsOrigin());
SkBitmap skbitmap;
skbitmap.allocN32Pixels(paint_rect.width(), paint_rect.height());
SkiaPaintCanvas canvas(skbitmap);
SkRect content_skrect = RectToSkRect(paint_rect);
PaintFlags flags;
flags.setAntiAlias(false);
flags.setBlendMode(SkBlendMode::kClear);
canvas.drawRect(content_skrect, flags);
canvas.clipRect(content_skrect);
scrollbar_->PaintPart(&canvas, THUMB, paint_rect);
// Make sure that the pixels are no longer mutable to unavoid unnecessary
// allocation and copying.
skbitmap.setImmutable();
thumb_resource_ = ScopedUIResource::Create(
layer_tree_host()->GetUIResourceManager(), UIResourceBitmap(skbitmap));
SetNeedsPushProperties();
return true;
}
bool PaintedOverlayScrollbarLayer::PaintTickmarks() {
if (!scrollbar_->HasTickmarks()) {
if (!track_resource_) {
return false;
} else {
// Remove previous tickmarks.
track_resource_.reset();
SetNeedsPushProperties();
return true;
}
}
gfx::Rect paint_rect = gfx::Rect(gfx::Point(), track_rect_.size());
DCHECK(!paint_rect.size().IsEmpty());
SkBitmap skbitmap;
skbitmap.allocN32Pixels(paint_rect.width(), paint_rect.height());
SkiaPaintCanvas canvas(skbitmap);
SkRect content_skrect = RectToSkRect(paint_rect);
PaintFlags flags;
flags.setAntiAlias(false);
flags.setBlendMode(SkBlendMode::kClear);
canvas.drawRect(content_skrect, flags);
canvas.clipRect(content_skrect);
scrollbar_->PaintPart(&canvas, TICKMARKS, paint_rect);
// Make sure that the pixels are no longer mutable to unavoid unnecessary
// allocation and copying.
skbitmap.setImmutable();
track_resource_ = ScopedUIResource::Create(
layer_tree_host()->GetUIResourceManager(), UIResourceBitmap(skbitmap));
SetNeedsPushProperties();
return true;
}
} // namespace cc