Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(772)

Side by Side Diff: chrome/browser/devtools/devtools_eye_dropper.cc

Issue 2817593004: [DevTools] Move eye dropper functionality from protocol to embedder (Closed)
Patch Set: rebased Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/devtools/protocol/color_picker.h" 5 #include "chrome/browser/devtools/devtools_eye_dropper.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "build/build_config.h" 8 #include "build/build_config.h"
9 #include "content/browser/renderer_host/render_view_host_impl.h" 9 #include "content/public/browser/render_view_host.h"
10 #include "content/browser/renderer_host/render_widget_host_view_base.h" 10 #include "content/public/browser/render_widget_host.h"
11 #include "content/common/cursors/webcursor.h" 11 #include "content/public/browser/render_widget_host_view.h"
12 #include "content/public/browser/web_contents.h"
13 #include "content/public/common/cursor_info.h"
12 #include "content/public/common/screen_info.h" 14 #include "content/public/common/screen_info.h"
13 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
14 #include "third_party/WebKit/public/platform/WebInputEvent.h" 15 #include "third_party/WebKit/public/platform/WebInputEvent.h"
16 #include "third_party/WebKit/public/platform/WebMouseEvent.h"
15 #include "third_party/skia/include/core/SkCanvas.h" 17 #include "third_party/skia/include/core/SkCanvas.h"
16 #include "third_party/skia/include/core/SkPaint.h" 18 #include "third_party/skia/include/core/SkPaint.h"
17 #include "third_party/skia/include/core/SkPath.h" 19 #include "third_party/skia/include/core/SkPath.h"
18 #include "ui/gfx/geometry/size_conversions.h" 20 #include "ui/gfx/geometry/size_conversions.h"
19 21
20 namespace content { 22 DevToolsEyeDropper::DevToolsEyeDropper(content::WebContents* web_contents,
21 namespace protocol { 23 EyeDropperCallback callback)
22 24 : content::WebContentsObserver(web_contents),
23 ColorPicker::ColorPicker(ColorPickedCallback callback) 25 callback_(callback),
24 : callback_(callback),
25 enabled_(false),
26 last_cursor_x_(-1), 26 last_cursor_x_(-1),
27 last_cursor_y_(-1), 27 last_cursor_y_(-1),
28 host_(nullptr), 28 host_(nullptr),
29 weak_factory_(this) { 29 weak_factory_(this) {
30 mouse_event_callback_ = base::Bind( 30 mouse_event_callback_ =
31 &ColorPicker::HandleMouseEvent, 31 base::Bind(&DevToolsEyeDropper::HandleMouseEvent, base::Unretained(this));
32 base::Unretained(this)); 32 content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
33 } 33 if (rvh) {
34 34 AttachToHost(rvh->GetWidget());
35 ColorPicker::~ColorPicker() {
36 }
37
38 void ColorPicker::SetRenderWidgetHost(RenderWidgetHostImpl* host) {
39 if (host_ == host)
40 return;
41
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_);
48 }
49
50 void ColorPicker::SetEnabled(bool enabled) {
51 if (enabled_ == enabled)
52 return;
53
54 enabled_ = enabled;
55 if (!host_)
56 return;
57
58 if (enabled) {
59 host_->AddMouseEventCallback(mouse_event_callback_);
60 UpdateFrame(); 35 UpdateFrame();
61 } else {
62 host_->RemoveMouseEventCallback(mouse_event_callback_);
63 ResetFrame();
64
65 WebCursor pointer_cursor;
66 CursorInfo cursor_info;
67 cursor_info.type = blink::WebCursorInfo::kTypePointer;
68 pointer_cursor.InitFromCursorInfo(cursor_info);
69 host_->SetCursor(pointer_cursor);
70 } 36 }
71 } 37 }
72 38
73 void ColorPicker::OnSwapCompositorFrame() { 39 DevToolsEyeDropper::~DevToolsEyeDropper() {
74 if (enabled_) 40 DetachFromHost();
75 UpdateFrame();
76 } 41 }
77 42
78 void ColorPicker::UpdateFrame() { 43 void DevToolsEyeDropper::AttachToHost(content::RenderWidgetHost* host) {
44 host_ = host;
45 host_->AddMouseEventCallback(mouse_event_callback_);
46 }
47
48 void DevToolsEyeDropper::DetachFromHost() {
79 if (!host_) 49 if (!host_)
80 return; 50 return;
81 RenderWidgetHostViewBase* view = 51 host_->RemoveMouseEventCallback(mouse_event_callback_);
82 static_cast<RenderWidgetHostViewBase*>(host_->GetView()); 52 content::CursorInfo cursor_info;
83 if (!view) 53 cursor_info.type = blink::WebCursorInfo::kTypePointer;
54 host_->SetCursor(cursor_info);
55 host_ = nullptr;
56 }
57
58 void DevToolsEyeDropper::RenderViewCreated(content::RenderViewHost* host) {
59 if (!host_) {
60 AttachToHost(host->GetWidget());
61 UpdateFrame();
62 }
63 }
64
65 void DevToolsEyeDropper::RenderViewDeleted(content::RenderViewHost* host) {
66 if (host->GetWidget() == host_) {
67 DetachFromHost();
68 ResetFrame();
69 }
70 }
71
72 void DevToolsEyeDropper::RenderViewHostChanged(
73 content::RenderViewHost* old_host,
74 content::RenderViewHost* new_host) {
75 if ((old_host && old_host->GetWidget() == host_) || (!old_host && !host_)) {
76 DetachFromHost();
77 AttachToHost(new_host->GetWidget());
78 UpdateFrame();
79 }
80 }
81
82 void DevToolsEyeDropper::DidReceiveCompositorFrame() {
83 UpdateFrame();
84 }
85
86 void DevToolsEyeDropper::UpdateFrame() {
87 if (!host_ || !host_->GetView())
84 return; 88 return;
85 89
86 // TODO(miu): This is the wrong size. It's the size of the view on-screen, and 90 // TODO(miu): This is the wrong size. It's the size of the view on-screen, and
87 // not the rendering size of the view. The latter is what is wanted here, so 91 // not the rendering size of the view. The latter is what is wanted here, so
88 // that the resulting bitmap's pixel coordinates line-up with the 92 // that the resulting bitmap's pixel coordinates line-up with the
89 // blink::WebMouseEvent coordinates. http://crbug.com/73362 93 // blink::WebMouseEvent coordinates. http://crbug.com/73362
90 gfx::Size should_be_rendering_size = view->GetViewBounds().size(); 94 gfx::Size should_be_rendering_size = host_->GetView()->GetViewBounds().size();
91 view->CopyFromSurface( 95 host_->GetView()->CopyFromSurface(
92 gfx::Rect(), should_be_rendering_size, 96 gfx::Rect(), should_be_rendering_size,
93 base::Bind(&ColorPicker::FrameUpdated, weak_factory_.GetWeakPtr()), 97 base::Bind(&DevToolsEyeDropper::FrameUpdated, weak_factory_.GetWeakPtr()),
94 kN32_SkColorType); 98 kN32_SkColorType);
95 } 99 }
96 100
97 void ColorPicker::ResetFrame() { 101 void DevToolsEyeDropper::ResetFrame() {
98 frame_.reset(); 102 frame_.reset();
99 last_cursor_x_ = -1; 103 last_cursor_x_ = -1;
100 last_cursor_y_ = -1; 104 last_cursor_y_ = -1;
101 } 105 }
102 106
103 void ColorPicker::FrameUpdated(const SkBitmap& bitmap, 107 void DevToolsEyeDropper::FrameUpdated(const SkBitmap& bitmap,
104 ReadbackResponse response) { 108 content::ReadbackResponse response) {
105 if (!enabled_) 109 if (response == content::READBACK_SUCCESS) {
106 return;
107
108 if (response == READBACK_SUCCESS) {
109 frame_ = bitmap; 110 frame_ = bitmap;
110 UpdateCursor(); 111 UpdateCursor();
111 } 112 }
112 } 113 }
113 114
114 bool ColorPicker::HandleMouseEvent(const blink::WebMouseEvent& event) { 115 bool DevToolsEyeDropper::HandleMouseEvent(const blink::WebMouseEvent& event) {
115 last_cursor_x_ = event.PositionInWidget().x; 116 last_cursor_x_ = event.PositionInWidget().x;
116 last_cursor_y_ = event.PositionInWidget().y; 117 last_cursor_y_ = event.PositionInWidget().y;
117 if (frame_.drawsNothing()) 118 if (frame_.drawsNothing())
118 return true; 119 return true;
119 120
120 if (event.button == blink::WebMouseEvent::Button::kLeft && 121 if (event.button == blink::WebMouseEvent::Button::kLeft &&
121 (event.GetType() == blink::WebInputEvent::kMouseDown || 122 (event.GetType() == blink::WebInputEvent::kMouseDown ||
122 event.GetType() == blink::WebInputEvent::kMouseMove)) { 123 event.GetType() == blink::WebInputEvent::kMouseMove)) {
123 if (last_cursor_x_ < 0 || last_cursor_x_ >= frame_.width() || 124 if (last_cursor_x_ < 0 || last_cursor_x_ >= frame_.width() ||
124 last_cursor_y_ < 0 || last_cursor_y_ >= frame_.height()) { 125 last_cursor_y_ < 0 || last_cursor_y_ >= frame_.height()) {
125 return true; 126 return true;
126 } 127 }
127 128
128 SkAutoLockPixels lock_image(frame_); 129 SkAutoLockPixels lock_image(frame_);
129 SkColor sk_color = frame_.getColor(last_cursor_x_, last_cursor_y_); 130 SkColor sk_color = frame_.getColor(last_cursor_x_, last_cursor_y_);
130 callback_.Run(SkColorGetR(sk_color), SkColorGetG(sk_color), 131 callback_.Run(SkColorGetR(sk_color), SkColorGetG(sk_color),
131 SkColorGetB(sk_color), SkColorGetA(sk_color)); 132 SkColorGetB(sk_color), SkColorGetA(sk_color));
132 } 133 }
133 UpdateCursor(); 134 UpdateCursor();
134 return true; 135 return true;
135 } 136 }
136 137
137 void ColorPicker::UpdateCursor() { 138 void DevToolsEyeDropper::UpdateCursor() {
138 if (!host_ || frame_.drawsNothing()) 139 if (!host_ || frame_.drawsNothing())
139 return; 140 return;
140 141
141 if (last_cursor_x_ < 0 || last_cursor_x_ >= frame_.width() || 142 if (last_cursor_x_ < 0 || last_cursor_x_ >= frame_.width() ||
142 last_cursor_y_ < 0 || last_cursor_y_ >= frame_.height()) { 143 last_cursor_y_ < 0 || last_cursor_y_ >= frame_.height()) {
143 return; 144 return;
144 } 145 }
145 146
146 RenderWidgetHostViewBase* view = static_cast<RenderWidgetHostViewBase*>( 147 // Due to platform limitations, we are using two different cursors
147 host_->GetView()); 148 // depending on the platform. Mac and Win have large cursors with two circles
148 if (!view) 149 // for original spot and its magnified projection; Linux gets smaller (64 px)
149 return; 150 // magnified projection only with centered hotspot.
150 151 // Mac Retina requires cursor to be > 120px in order to render smoothly.
151 // Due to platform limitations, we are using two different cursors
152 // depending on the platform. Mac and Win have large cursors with two circles
153 // for original spot and its magnified projection; Linux gets smaller (64 px)
154 // magnified projection only with centered hotspot.
155 // Mac Retina requires cursor to be > 120px in order to render smoothly.
156 152
157 #if defined(OS_LINUX) 153 #if defined(OS_LINUX)
158 const float kCursorSize = 63; 154 const float kCursorSize = 63;
159 const float kDiameter = 63; 155 const float kDiameter = 63;
160 const float kHotspotOffset = 32; 156 const float kHotspotOffset = 32;
161 const float kHotspotRadius = 0; 157 const float kHotspotRadius = 0;
162 const float kPixelSize = 9; 158 const float kPixelSize = 9;
163 #else 159 #else
164 const float kCursorSize = 150; 160 const float kCursorSize = 150;
165 const float kDiameter = 110; 161 const float kDiameter = 110;
(...skipping 18 matching lines...) Expand all
184 SkPaint paint; 180 SkPaint paint;
185 181
186 // Paint original spot with cross. 182 // Paint original spot with cross.
187 if (kHotspotRadius > 0) { 183 if (kHotspotRadius > 0) {
188 paint.setStrokeWidth(1); 184 paint.setStrokeWidth(1);
189 paint.setAntiAlias(false); 185 paint.setAntiAlias(false);
190 paint.setColor(SK_ColorDKGRAY); 186 paint.setColor(SK_ColorDKGRAY);
191 paint.setStyle(SkPaint::kStroke_Style); 187 paint.setStyle(SkPaint::kStroke_Style);
192 188
193 canvas.drawLine(kHotspotOffset, kHotspotOffset - 2 * kHotspotRadius, 189 canvas.drawLine(kHotspotOffset, kHotspotOffset - 2 * kHotspotRadius,
194 kHotspotOffset, kHotspotOffset - kHotspotRadius, 190 kHotspotOffset, kHotspotOffset - kHotspotRadius, paint);
195 paint);
196 canvas.drawLine(kHotspotOffset, kHotspotOffset + kHotspotRadius, 191 canvas.drawLine(kHotspotOffset, kHotspotOffset + kHotspotRadius,
197 kHotspotOffset, kHotspotOffset + 2 * kHotspotRadius, 192 kHotspotOffset, kHotspotOffset + 2 * kHotspotRadius, paint);
198 paint);
199 canvas.drawLine(kHotspotOffset - 2 * kHotspotRadius, kHotspotOffset, 193 canvas.drawLine(kHotspotOffset - 2 * kHotspotRadius, kHotspotOffset,
200 kHotspotOffset - kHotspotRadius, kHotspotOffset, 194 kHotspotOffset - kHotspotRadius, kHotspotOffset, paint);
201 paint);
202 canvas.drawLine(kHotspotOffset + kHotspotRadius, kHotspotOffset, 195 canvas.drawLine(kHotspotOffset + kHotspotRadius, kHotspotOffset,
203 kHotspotOffset + 2 * kHotspotRadius, kHotspotOffset, 196 kHotspotOffset + 2 * kHotspotRadius, kHotspotOffset, paint);
204 paint);
205 197
206 paint.setStrokeWidth(2); 198 paint.setStrokeWidth(2);
207 paint.setAntiAlias(true); 199 paint.setAntiAlias(true);
208 canvas.drawCircle(kHotspotOffset, kHotspotOffset, kHotspotRadius, paint); 200 canvas.drawCircle(kHotspotOffset, kHotspotOffset, kHotspotRadius, paint);
209 } 201 }
210 202
211 // Clip circle for magnified projection. 203 // Clip circle for magnified projection.
212 float padding = (kCursorSize - kDiameter) / 2; 204 float padding = (kCursorSize - kDiameter) / 2;
213 SkPath clip_path; 205 SkPath clip_path;
214 clip_path.addOval(SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter)); 206 clip_path.addOval(SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter));
215 clip_path.close(); 207 clip_path.close();
216 canvas.clipPath(clip_path, SkClipOp::kIntersect, true); 208 canvas.clipPath(clip_path, SkClipOp::kIntersect, true);
217 209
218 // Project pixels. 210 // Project pixels.
219 int pixel_count = kDiameter / kPixelSize; 211 int pixel_count = kDiameter / kPixelSize;
220 SkRect src_rect = SkRect::MakeXYWH(last_cursor_x_ - pixel_count / 2, 212 SkRect src_rect = SkRect::MakeXYWH(last_cursor_x_ - pixel_count / 2,
221 last_cursor_y_ - pixel_count / 2, 213 last_cursor_y_ - pixel_count / 2,
222 pixel_count, pixel_count); 214 pixel_count, pixel_count);
223 SkRect dst_rect = SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter); 215 SkRect dst_rect = SkRect::MakeXYWH(padding, padding, kDiameter, kDiameter);
224 canvas.drawBitmapRect(frame_, src_rect, dst_rect, NULL); 216 canvas.drawBitmapRect(frame_, src_rect, dst_rect, NULL);
225 217
226 // Paint grid. 218 // Paint grid.
227 paint.setStrokeWidth(1); 219 paint.setStrokeWidth(1);
228 paint.setAntiAlias(false); 220 paint.setAntiAlias(false);
229 paint.setColor(SK_ColorGRAY); 221 paint.setColor(SK_ColorGRAY);
230 for (int i = 0; i < pixel_count; ++i) { 222 for (int i = 0; i < pixel_count; ++i) {
231 canvas.drawLine(padding + i * kPixelSize, padding, 223 canvas.drawLine(padding + i * kPixelSize, padding, padding + i * kPixelSize,
232 padding + i * kPixelSize, kCursorSize - padding, paint); 224 kCursorSize - padding, paint);
233 canvas.drawLine(padding, padding + i * kPixelSize, 225 canvas.drawLine(padding, padding + i * kPixelSize, kCursorSize - padding,
234 kCursorSize - padding, padding + i * kPixelSize, paint); 226 padding + i * kPixelSize, paint);
235 } 227 }
236 228
237 // Paint central pixel in red. 229 // Paint central pixel in red.
238 SkRect pixel = SkRect::MakeXYWH((kCursorSize - kPixelSize) / 2, 230 SkRect pixel =
239 (kCursorSize - kPixelSize) / 2, 231 SkRect::MakeXYWH((kCursorSize - kPixelSize) / 2,
240 kPixelSize, kPixelSize); 232 (kCursorSize - kPixelSize) / 2, kPixelSize, kPixelSize);
241 paint.setColor(SK_ColorRED); 233 paint.setColor(SK_ColorRED);
242 paint.setStyle(SkPaint::kStroke_Style); 234 paint.setStyle(SkPaint::kStroke_Style);
243 canvas.drawRect(pixel, paint); 235 canvas.drawRect(pixel, paint);
244 236
245 // Paint outline. 237 // Paint outline.
246 paint.setStrokeWidth(2); 238 paint.setStrokeWidth(2);
247 paint.setColor(SK_ColorDKGRAY); 239 paint.setColor(SK_ColorDKGRAY);
248 paint.setAntiAlias(true); 240 paint.setAntiAlias(true);
249 canvas.drawCircle(kCursorSize / 2, kCursorSize / 2, kDiameter / 2, paint); 241 canvas.drawCircle(kCursorSize / 2, kCursorSize / 2, kDiameter / 2, paint);
250 242
251 WebCursor cursor; 243 content::CursorInfo cursor_info;
252 CursorInfo cursor_info;
253 cursor_info.type = blink::WebCursorInfo::kTypeCustom; 244 cursor_info.type = blink::WebCursorInfo::kTypeCustom;
254 cursor_info.image_scale_factor = device_scale_factor; 245 cursor_info.image_scale_factor = device_scale_factor;
255 cursor_info.custom_image = result; 246 cursor_info.custom_image = result;
256 cursor_info.hotspot = 247 cursor_info.hotspot = gfx::Point(kHotspotOffset * device_scale_factor,
257 gfx::Point(kHotspotOffset * device_scale_factor, 248 kHotspotOffset * device_scale_factor);
258 kHotspotOffset * device_scale_factor); 249 host_->SetCursor(cursor_info);
259
260 cursor.InitFromCursorInfo(cursor_info);
261 DCHECK(host_);
262 host_->SetCursor(cursor);
263 } 250 }
264
265 } // namespace protocol
266 } // namespace content
OLDNEW
« no previous file with comments | « chrome/browser/devtools/devtools_eye_dropper.h ('k') | chrome/browser/devtools/devtools_ui_bindings.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698