Index: cc/pinch_zoom_scrollbar_layer_impl.cc |
diff --git a/cc/pinch_zoom_scrollbar_layer_impl.cc b/cc/pinch_zoom_scrollbar_layer_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..dc592911e3f28884cc3d66c75e960432705cb950 |
--- /dev/null |
+++ b/cc/pinch_zoom_scrollbar_layer_impl.cc |
@@ -0,0 +1,248 @@ |
+// Copyright 2013 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/pinch_zoom_scrollbar_layer_impl.h" |
+ |
+#include "cc/layer_tree_host_impl.h" |
+#include "cc/layer_tree_impl.h" |
+#include "cc/quad_sink.h" |
+#include "cc/renderer.h" |
+#include "cc/texture_draw_quad.h" |
+#include "skia/ext/platform_canvas.h" |
+#include "ui/gfx/rect.h" |
+#include "ui/gfx/rect_conversions.h" |
+ |
+namespace cc { |
+ |
+PinchZoomScrollbarState::PinchZoomScrollbarState( |
+ WebKit::WebScrollbar::Orientation orientation, PinchZoomViewport* owner) |
+ : owner_(owner), |
+ orientation_(orientation) { |
+ DCHECK(owner_); |
+} |
+ |
+PinchZoomScrollbarState::~PinchZoomScrollbarState() {} |
+ |
+gfx::SizeF PinchZoomScrollbarState::layout_viewport_size() const { |
+ return owner_->layout_viewport_size(); |
+} |
+ |
+gfx::Vector2dF PinchZoomScrollbarState::zoomed_viewport_offset() const { |
+ return owner_->zoomed_viewport_offset(); |
+} |
+ |
+float PinchZoomScrollbarState::total_page_scale_factor() const { |
+ return owner_->total_page_scale_factor(); |
+} |
+ |
+float PinchZoomScrollbarState::device_scale_factor() const { |
+ return owner_->device_scale_factor(); |
+} |
+ |
+LayerImpl* PinchZoomScrollbarState::root_scroll_layer() { |
+ return owner_->root_scroll_layer(); |
+} |
+ |
+void PinchZoomScrollbarState::RefreshSizeAndPosition(LayerImpl* layer_impl) |
+{ |
+ gfx::SizeF size = owner_->layout_viewport_size(); |
+ if (orientation_ == WebKit::WebScrollbar::Vertical) { |
+ gfx::Size bounds = gfx::Size(kTrackWidth, size.height()); |
+ layer_impl->setContentBounds(bounds); |
+ layer_impl->setBounds(bounds); |
+ layer_impl->setPosition(gfx::Point(size.width() - kTrackWidth, 0)); |
+ } else { |
+ gfx::Size bounds = gfx::Size(size.width(), kTrackWidth); |
+ layer_impl->setContentBounds(bounds); |
+ layer_impl->setBounds(bounds); |
+ layer_impl->setPosition(gfx::Point(0, size.height() - kTrackWidth)); |
+ } |
+} |
+ |
+bool PinchZoomScrollbarState::ShouldDisplayPinchZoomScrollbars() { |
+ return owner_->total_page_scale_factor() > 1 && owner_->currently_scrolling_layer(); |
+} |
+ |
+scoped_ptr<PinchZoomScrollbarLayerImpl> PinchZoomScrollbarLayerImpl::create( |
+ LayerTreeImpl* treeImpl, |
+ int id, |
+ PinchZoomScrollbarState* state) { |
+ return make_scoped_ptr(new PinchZoomScrollbarLayerImpl(treeImpl, id, state)); |
+} |
+ |
+PinchZoomScrollbarLayerImpl::PinchZoomScrollbarLayerImpl( |
+ LayerTreeImpl* treeImpl, |
+ int id, PinchZoomScrollbarState* state) |
+ : ScrollbarLayerImplBase(treeImpl, id), |
+ state_(state) { |
+ DCHECK(state_); |
+ std::string debugName = "Layer for Pinch Zoom Scrollbar "; |
+ debugName += ((state_->orientation() == WebKit::WebScrollbar::Vertical) ? |
+ "(vertical)" : "(horizontal)"); |
+ setDebugName(debugName); |
+ |
+ state_->RefreshSizeAndPosition(this); |
+} |
+ |
+PinchZoomScrollbarLayerImpl::~PinchZoomScrollbarLayerImpl() {} |
+ |
+float PinchZoomScrollbarLayerImpl::currentPos() const { |
+ return state_->thumb_position(); |
+} |
+ |
+int PinchZoomScrollbarLayerImpl::totalSize() const { |
+ return state_->track_length(); |
+} |
+ |
+int PinchZoomScrollbarLayerImpl::maximum() const { |
+ return state_->maximum_position(); |
+} |
+ |
+WebKit::WebScrollbar::Orientation PinchZoomScrollbarLayerImpl::orientation() |
+ const { |
+ return state_->orientation(); |
+} |
+ |
+void PinchZoomScrollbarLayerImpl::appendQuads( |
+ QuadSink& quad_sink, AppendQuadsData& append_quads_data) { |
+ if (!state_->ShouldDisplayPinchZoomScrollbars()) |
+ return; |
+ |
+ if (state_->thumb_rect().IsEmpty() || !state_->thumb_texture()->id()) |
+ return; |
+ |
+ bool premultipled_alpha = false; |
+ bool flipped = false; |
+ gfx::RectF uv_rect(0, 0, 1, 1); |
+ |
+ SharedQuadState* shared_quad_state = |
+ quad_sink.useSharedQuadState(createSharedQuadState()); |
+ appendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data); |
+ |
+ gfx::Rect quad_rect(gfx::ToEnclosingRect( |
+ gfx::ScaleRect(state_->thumb_rect(), |
+ contentsScaleX(), contentsScaleY()))); |
+ |
+ gfx::Rect opaque_rect; |
+ const float opacity[] = {1.0f, 1.0f, 1.0f, 1.0f}; |
+ scoped_ptr<TextureDrawQuad> quad = TextureDrawQuad::Create(); |
+ quad->SetNew(shared_quad_state, quad_rect, opaque_rect, |
+ state_->thumb_texture()->id(), |
+ premultipled_alpha, uv_rect, opacity, flipped); |
+ quad_sink.append(quad.PassAs<DrawQuad>(), append_quads_data); |
+} |
+ |
+void PinchZoomScrollbarLayerImpl::willDraw( |
+ ResourceProvider* resource_provider) { |
+ LayerImpl::willDraw(resource_provider); |
+ |
+ if (!state_->ShouldDisplayPinchZoomScrollbars()) |
+ return; |
+ |
+ gfx::Size layout_document_size(layerTreeImpl()->ContentSize()); |
+ |
+ gfx::SizeF layout_viewport_size = state_->layout_viewport_size(); |
+ gfx::Vector2dF layout_viewport_position = state_->zoomed_viewport_offset(); |
+ float page_scale_factor = state_->total_page_scale_factor(); |
+ float device_scale_factor = state_->device_scale_factor(); |
+ |
+ DCHECK(!layout_document_size.IsEmpty()); |
+ |
+ gfx::Vector2d root_scroll_offset; |
+ gfx::Vector2d root_max_scroll_offset; |
+ LayerImpl* root_scroll_layer = state_->root_scroll_layer(); |
+ if (root_scroll_layer) { |
+ root_scroll_offset = root_scroll_layer->scrollOffset(); |
+ root_max_scroll_offset = root_scroll_layer->maxScrollOffset(); |
+ } |
+ |
+ gfx::Rect new_thumb_rect; |
+ int& track_length = state_->track_length(); |
+ float& thumb_position = state_->thumb_position(); |
+ int& maximum_position = state_->maximum_position(); |
+ int track_width = state_->track_width(); |
+ |
+ int thumb_length; |
+ if (state_->orientation() == WebKit::WebScrollbar::Vertical) { |
+ track_length = layout_viewport_size.height() - track_width; |
+ thumb_length = layout_viewport_size.height() / |
+ layout_document_size.height() * device_scale_factor * track_length; |
+ maximum_position = state_->track_length() - thumb_length; |
+ |
+ float max_offset = root_max_scroll_offset.y() + (page_scale_factor - 1) |
+ / page_scale_factor * layout_viewport_size.height(); |
+ float offset = (max_offset >= 1) ? root_scroll_offset.y() + |
+ layout_viewport_position.y() : 0; |
+ thumb_position = offset / max_offset * maximum_position; |
+ |
+ // Thumb rect position is with respect to the layer, so the x-coordinate |
+ // should be 0. |
+ new_thumb_rect = gfx::Rect(0, thumb_position, track_width, thumb_length); |
+ } else { |
+ track_length = layout_viewport_size.width() - track_width; |
+ thumb_length = layout_viewport_size.width() / layout_document_size.width() * |
+ device_scale_factor * track_length; |
+ maximum_position = track_length - thumb_length; |
+ |
+ float max_offset = root_max_scroll_offset.x() + (page_scale_factor - 1) |
+ / page_scale_factor * layout_viewport_size.width(); |
+ float offset = (max_offset >= 1) ? root_scroll_offset.x() + |
+ layout_viewport_position.x() : 0; |
+ thumb_position = offset / max_offset * maximum_position; |
+ |
+ // Thumb rect position is with respect to the layer, so the y-coordinate |
+ // should be 0. |
+ new_thumb_rect = gfx::Rect(thumb_position, 0, thumb_length, track_width); |
+ } |
+ |
+ gfx::Rect& thumb_rect = state_->thumb_rect(); |
+ scoped_ptr<ScopedResource>& thumb_texture = state_->thumb_texture(); |
+ |
+ bool thumb_size_not_changed = thumb_rect.size() == new_thumb_rect.size(); |
+ thumb_rect = new_thumb_rect; |
+ if (thumb_size_not_changed && thumb_texture) |
+ return; |
+ |
+ // Does texture exist, if not, create it. |
+ if (!thumb_texture) |
+ thumb_texture = ScopedResource::create(resource_provider); |
+ |
+ if (thumb_texture->size() != thumb_rect.size()) |
+ thumb_texture->Free(); |
+ |
+ if (!thumb_texture->id()) |
+ thumb_texture->Allocate(thumb_rect.size(), GL_RGBA, |
+ ResourceProvider::TextureUsageAny); |
+ |
+ // Paint canvas and upload to texture. |
+ scoped_ptr<SkCanvas> canvas = make_scoped_ptr( |
+ skia::CreateBitmapCanvas(thumb_rect.width(), thumb_rect.height(), |
+ false /* opaque */)); |
+ canvas->clear(SkColorSetARGB(0, 0, 0, 0)); |
+ SkPaint paint; |
+ // Below 255 refers to blue, not red, but we do this to avoid an |
+ // explicit swizzle. |
+ paint.setColor(SkColorSetARGB(128, 255, 0, 0)); |
+ SkScalar border = device_scale_factor; |
+ SkScalar corner_radius = device_scale_factor * (track_width / 3); |
+ DCHECK(corner_radius); |
+ SkRect rect = SkRect::MakeXYWH(border, border, |
+ thumb_rect.width() - 2 * border, |
+ thumb_rect.height() - 2 * border); |
+ canvas->drawRoundRect(rect, corner_radius, corner_radius, paint); |
+ |
+ const SkBitmap* bitmap = &canvas->getDevice()->accessBitmap(false); |
+ SkAutoLockPixels locker(*bitmap); |
+ gfx::Rect layer_rect(gfx::Point(), thumb_rect.size()); |
+ DCHECK(bitmap->config() == SkBitmap::kARGB_8888_Config); |
+ resource_provider->setPixels(thumb_texture->id(), static_cast<const uint8_t*>( |
+ bitmap->getPixels()), layer_rect, layer_rect, |
+ gfx::Vector2d()); |
+} |
+ |
+void PinchZoomScrollbarLayerImpl::didLoseOutputSurface() { |
+ state_->thumb_texture().reset(0);; |
+} |
+ |
+} // namespace cc |