[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / devtools / protocol / color_picker.cc
blobd298927acdaf6e36db788d90dffdcc37c5bb6138
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/devtools/protocol/color_picker.h"
7 #include "base/bind.h"
8 #include "content/browser/renderer_host/render_view_host_impl.h"
9 #include "content/browser/renderer_host/render_widget_host_view_base.h"
10 #include "content/common/cursors/webcursor.h"
11 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
12 #include "third_party/WebKit/public/platform/WebScreenInfo.h"
13 #include "third_party/WebKit/public/web/WebInputEvent.h"
14 #include "third_party/skia/include/core/SkCanvas.h"
15 #include "third_party/skia/include/core/SkPaint.h"
16 #include "third_party/skia/include/core/SkPath.h"
17 #include "ui/gfx/geometry/size_conversions.h"
19 namespace content {
20 namespace devtools {
21 namespace page {
23 ColorPicker::ColorPicker(ColorPickedCallback callback)
24 : callback_(callback),
25 enabled_(false),
26 last_cursor_x_(-1),
27 last_cursor_y_(-1),
28 host_(nullptr),
29 weak_factory_(this) {
30 mouse_event_callback_ = base::Bind(
31 &ColorPicker::HandleMouseEvent,
32 base::Unretained(this));
35 ColorPicker::~ColorPicker() {
38 void ColorPicker::SetRenderWidgetHost(RenderWidgetHostImpl* host) {
39 if (host_ == host)
40 return;
42 if (enabled_ && host_)
43 host_->RemoveMouseEventCallback(mouse_event_callback_);
44 ResetFrame();
45 host_ = host;
46 if (enabled_ && host)
47 host->AddMouseEventCallback(mouse_event_callback_);
50 void ColorPicker::SetEnabled(bool enabled) {
51 if (enabled_ == enabled)
52 return;
54 enabled_ = enabled;
55 if (!host_)
56 return;
58 if (enabled) {
59 host_->AddMouseEventCallback(mouse_event_callback_);
60 UpdateFrame();
61 } else {
62 host_->RemoveMouseEventCallback(mouse_event_callback_);
63 ResetFrame();
65 WebCursor pointer_cursor;
66 WebCursor::CursorInfo cursor_info;
67 cursor_info.type = blink::WebCursorInfo::TypePointer;
68 pointer_cursor.InitFromCursorInfo(cursor_info);
69 host_->SetCursor(pointer_cursor);
73 void ColorPicker::OnSwapCompositorFrame() {
74 if (enabled_)
75 UpdateFrame();
78 void ColorPicker::UpdateFrame() {
79 if (!host_)
80 return;
81 RenderWidgetHostViewBase* view =
82 static_cast<RenderWidgetHostViewBase*>(host_->GetView());
83 if (!view)
84 return;
86 gfx::Size size = view->GetViewBounds().size();
87 view->CopyFromCompositingSurface(
88 gfx::Rect(size), size,
89 base::Bind(&ColorPicker::FrameUpdated,
90 weak_factory_.GetWeakPtr()),
91 kN32_SkColorType);
94 void ColorPicker::ResetFrame() {
95 frame_.reset();
96 last_cursor_x_ = -1;
97 last_cursor_y_ = -1;
100 void ColorPicker::FrameUpdated(const SkBitmap& bitmap,
101 ReadbackResponse response) {
102 if (!enabled_)
103 return;
105 if (response == READBACK_SUCCESS) {
106 frame_ = bitmap;
107 UpdateCursor();
111 bool ColorPicker::HandleMouseEvent(const blink::WebMouseEvent& event) {
112 last_cursor_x_ = event.x;
113 last_cursor_y_ = event.y;
114 if (frame_.drawsNothing())
115 return true;
117 if (event.button == blink::WebMouseEvent::ButtonLeft &&
118 event.type == blink::WebInputEvent::MouseDown) {
119 if (last_cursor_x_ < 0 || last_cursor_x_ >= frame_.width() ||
120 last_cursor_y_ < 0 || last_cursor_y_ >= frame_.height()) {
121 return true;
124 SkAutoLockPixels lock_image(frame_);
125 SkColor sk_color = frame_.getColor(last_cursor_x_, last_cursor_y_);
126 callback_.Run(SkColorGetR(sk_color), SkColorGetG(sk_color),
127 SkColorGetB(sk_color), SkColorGetA(sk_color));
129 UpdateCursor();
130 return true;
133 void ColorPicker::UpdateCursor() {
134 if (!host_ || frame_.drawsNothing())
135 return;
137 if (last_cursor_x_ < 0 || last_cursor_x_ >= frame_.width() ||
138 last_cursor_y_ < 0 || last_cursor_y_ >= frame_.height()) {
139 return;
142 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>(
143 host_->GetView());
144 if (!view)
145 return;
147 // Due to platform limitations, we are using two different cursors
148 // depending on the platform. Mac and Win have large cursors with two circles
149 // for original spot and its magnified projection; Linux gets smaller (64 px)
150 // magnified projection only with centered hotspot.
151 // Mac Retina requires cursor to be > 120px in order to render smoothly.
153 #if defined(OS_LINUX)
154 const float kCursorSize = 63;
155 const float kDiameter = 63;
156 const float kHotspotOffset = 32;
157 const float kHotspotRadius = 0;
158 const float kPixelSize = 9;
159 #else
160 const float kCursorSize = 150;
161 const float kDiameter = 110;
162 const float kHotspotOffset = 25;
163 const float kHotspotRadius = 5;
164 const float kPixelSize = 10;
165 #endif
167 blink::WebScreenInfo screen_info;
168 view->GetScreenInfo(&screen_info);
169 double device_scale_factor = screen_info.deviceScaleFactor;
171 SkBitmap result;
172 result.allocN32Pixels(kCursorSize * device_scale_factor,
173 kCursorSize * device_scale_factor);
174 result.eraseARGB(0, 0, 0, 0);
176 SkCanvas canvas(result);
177 canvas.scale(device_scale_factor, device_scale_factor);
178 canvas.translate(0.5f, 0.5f);
180 SkPaint paint;
182 // Paint original spot with cross.
183 if (kHotspotRadius) {
184 paint.setStrokeWidth(1);
185 paint.setAntiAlias(false);
186 paint.setColor(SK_ColorDKGRAY);
187 paint.setStyle(SkPaint::kStroke_Style);
189 canvas.drawLine(kHotspotOffset, kHotspotOffset - 2 * kHotspotRadius,
190 kHotspotOffset, kHotspotOffset - kHotspotRadius,
191 paint);
192 canvas.drawLine(kHotspotOffset, kHotspotOffset + kHotspotRadius,
193 kHotspotOffset, kHotspotOffset + 2 * kHotspotRadius,
194 paint);
195 canvas.drawLine(kHotspotOffset - 2 * kHotspotRadius, kHotspotOffset,
196 kHotspotOffset - kHotspotRadius, kHotspotOffset,
197 paint);
198 canvas.drawLine(kHotspotOffset + kHotspotRadius, kHotspotOffset,
199 kHotspotOffset + 2 * kHotspotRadius, kHotspotOffset,
200 paint);
202 paint.setStrokeWidth(2);
203 paint.setAntiAlias(true);
204 canvas.drawCircle(kHotspotOffset, kHotspotOffset, kHotspotRadius, paint);
207 // Clip circle for magnified projection.
208 float padding = (kCursorSize - kDiameter) / 2;
209 SkPath clip_path;
210 clip_path.addOval(SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter));
211 clip_path.close();
212 canvas.clipPath(clip_path, SkRegion::kIntersect_Op, true);
214 // Project pixels.
215 int pixel_count = kDiameter / kPixelSize;
216 SkRect src_rect = SkRect::MakeXYWH(last_cursor_x_ - pixel_count / 2,
217 last_cursor_y_ - pixel_count / 2,
218 pixel_count, pixel_count);
219 SkRect dst_rect = SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter);
220 canvas.drawBitmapRect(frame_, src_rect, dst_rect, NULL);
222 // Paint grid.
223 paint.setStrokeWidth(1);
224 paint.setAntiAlias(false);
225 paint.setColor(SK_ColorGRAY);
226 for (int i = 0; i < pixel_count; ++i) {
227 canvas.drawLine(padding + i * kPixelSize, padding,
228 padding + i * kPixelSize, kCursorSize - padding, paint);
229 canvas.drawLine(padding, padding + i * kPixelSize,
230 kCursorSize - padding, padding + i * kPixelSize, paint);
233 // Paint central pixel in red.
234 SkRect pixel = SkRect::MakeXYWH((kCursorSize - kPixelSize) / 2,
235 (kCursorSize - kPixelSize) / 2,
236 kPixelSize, kPixelSize);
237 paint.setColor(SK_ColorRED);
238 paint.setStyle(SkPaint::kStroke_Style);
239 canvas.drawRect(pixel, paint);
241 // Paint outline.
242 paint.setStrokeWidth(2);
243 paint.setColor(SK_ColorDKGRAY);
244 paint.setAntiAlias(true);
245 canvas.drawCircle(kCursorSize / 2, kCursorSize / 2, kDiameter / 2, paint);
247 WebCursor cursor;
248 WebCursor::CursorInfo cursor_info;
249 cursor_info.type = blink::WebCursorInfo::TypeCustom;
250 cursor_info.image_scale_factor = device_scale_factor;
251 cursor_info.custom_image = result;
252 cursor_info.hotspot =
253 gfx::Point(kHotspotOffset * device_scale_factor,
254 kHotspotOffset * device_scale_factor);
255 #if defined(OS_WIN)
256 cursor_info.external_handle = 0;
257 #endif
259 cursor.InitFromCursorInfo(cursor_info);
260 DCHECK(host_);
261 host_->SetCursor(cursor);
264 } // namespace page
265 } // namespace devtools
266 } // namespace content