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

Side by Side Diff: content/browser/media/capture/cursor_renderer.cc

Issue 2553763002: Fix cursor missing in tabCapture on OSX Sierra (Closed)
Patch Set: implement CursorRenderer Created 3 years, 12 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
(Empty)
1 // Copyright (c) 2016 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.
4
5 #include "content/browser/media/capture/cursor_renderer.h"
6
7 #include "base/logging.h"
8 #include "base/memory/ptr_util.h"
9 #include "skia/ext/image_operations.h"
10
11 #if defined(USE_AURA)
miu 2016/12/27 23:21:03 It seems these platform-specific includes should b
braveyao 2017/01/04 01:57:48 Done.
12 #include "content/browser/media/capture/cursor_renderer_aura.h"
13 #elif defined(OS_MACOSX)
14 #include "content/browser/media/capture/cursor_renderer_mac.h"
15 #endif
16
17 namespace content {
18
19 namespace {
20
21 inline int clip_byte(int x) {
22 return std::max(0, std::min(x, 255));
23 }
24
25 inline int alpha_blend(int alpha, int src, int dst) {
26 return (src * alpha + dst * (255 - alpha)) / 255;
27 }
28
29 } // namespace
30
31 CursorRenderer::CursorRenderer(gfx::NativeView view,
32 CursorDisplaySetting cursor_display_setting)
33 : captured_view_(view),
34 cursor_display_setting_(cursor_display_setting),
35 tick_clock_(&default_tick_clock_),
36 weak_factory_(this) {
37 Clear();
38 }
39
40 CursorRenderer::~CursorRenderer() {}
41
42 base::WeakPtr<CursorRenderer> CursorRenderer::GetWeakPtr() {
43 return weak_factory_.GetWeakPtr();
44 }
45
46 void CursorRenderer::Clear() {
47 last_cursor_ = gfx::NativeCursor();
48 last_cursor_hot_point_ = gfx::Point();
49 window_size_when_cursor_last_updated_ = gfx::Size();
50 scaled_cursor_bitmap_.reset();
51 last_mouse_position_x_ = 0;
52 last_mouse_position_y_ = 0;
53 last_mouse_movement_timestamp_ = base::TimeTicks::Now();
54 if (cursor_display_setting_ == kCursorEnabledOnMouseMovement) {
55 cursor_displayed_ = false;
56 } else {
57 cursor_displayed_ = true;
58 }
59 }
60
61 bool CursorRenderer::SnapshotCursorState(const gfx::Rect& region_in_frame) {
62 if (!captured_view_) {
63 DVLOG(2) << "Skipping update with no window being tracked";
miu 2016/12/27 23:21:02 nit: For consistency, let's call it a "view" inste
braveyao 2017/01/04 01:57:48 Done.
64 return false;
65 }
66
67 // If we are sharing the root window, or namely the whole screen, we will
68 // render the mouse cursor. For ordinary window, we only render the mouse
69 // cursor when the window is active.
70 if (!IsCapturedViewActive()) {
71 // Return early if the target window is not active.
72 DVLOG(2) << "Skipping update on an inactive window";
73 Clear();
74 return false;
75 }
76
77 gfx::NativeCursor cursor = GetLastKnownCursor();
miu 2016/12/27 23:21:03 Please move this down to just before it will first
braveyao 2017/01/04 01:57:49 Done.
78 gfx::Point cursor_position = GetCursorPositionInView();
miu 2016/12/27 23:21:03 Please move this down to just before it will first
braveyao 2017/01/04 01:57:48 Done.
79 gfx::Size view_size = GetCapturedViewSize();
80
81 if (view_size.IsEmpty()) {
82 DVLOG(2) << "Skipping update on an empty view";
83 Clear();
84 return false;
85 }
86
87 if (cursor_position.x() < 0 || cursor_position.y() < 0 ||
miu 2016/12/27 23:21:02 nit: A trick to make this simpler: if (!gfx::Re
braveyao 2017/01/04 01:57:49 Done.
88 cursor_position.x() > view_size.width() ||
89 cursor_position.y() > view_size.height()) {
90 DVLOG(2) << "Skipping update with cursor outside the window";
91 Clear();
92 return false;
93 }
94
95 if (cursor_display_setting_ == kCursorEnabledOnMouseMovement) {
96 if (cursor_displayed_) {
97 // Stop displaying cursor if there has been no mouse movement
98 base::TimeTicks now = tick_clock_->NowTicks();
99 if ((now - last_mouse_movement_timestamp_) >
100 base::TimeDelta::FromSeconds(MAX_IDLE_TIME_SECONDS)) {
101 cursor_displayed_ = false;
102 DVLOG(2) << "Turning off cursor display after idle time";
103 }
104 }
105 if (!cursor_displayed_)
106 return false;
107 }
108
109 const float x_scale =
110 static_cast<float>(region_in_frame.width()) / view_size.width();
111 const float y_scale =
112 static_cast<float>(region_in_frame.height()) / view_size.height();
113
114 if (last_cursor_ != cursor ||
115 window_size_when_cursor_last_updated_ != view_size) {
miu 2016/12/27 23:21:03 The scaled size also depends on |region_in_frame.s
braveyao 2017/01/04 01:57:48 Done.
116 SkBitmap cursor_bitmap = GetLastKnownCursorImage();
117 const int scaled_width = cursor_bitmap.width() * x_scale;
118 const int scaled_height = cursor_bitmap.height() * y_scale;
119 if (scaled_width <= 0 || scaled_height <= 0) {
120 DVLOG(2) << "scaled_width <= 0";
121 Clear();
122 return false;
123 }
124 scaled_cursor_bitmap_ = skia::ImageOperations::Resize(
125 cursor_bitmap, skia::ImageOperations::RESIZE_BEST, scaled_width,
126 scaled_height);
127
128 last_cursor_hot_point_ = GetLastKnownCursorHotPoint();
129 last_cursor_ = cursor;
130 window_size_when_cursor_last_updated_ = view_size;
131 }
132
133 cursor_position.Offset(-last_cursor_hot_point_.x(),
134 -last_cursor_hot_point_.y());
135 cursor_position_in_frame_ =
136 gfx::Point(region_in_frame.x() + cursor_position.x() * x_scale,
137 region_in_frame.y() + cursor_position.y() * y_scale);
138 return true;
139 }
140
141 // Helper function to composite a cursor bitmap on a YUV420 video frame.
142 void CursorRenderer::RenderOnVideoFrame(
143 const scoped_refptr<media::VideoFrame>& target) const {
144 if (scaled_cursor_bitmap_.isNull())
145 return;
146
147 DCHECK(target);
148
149 gfx::Rect rect = gfx::IntersectRects(
150 gfx::Rect(scaled_cursor_bitmap_.width(), scaled_cursor_bitmap_.height()) +
151 gfx::Vector2d(cursor_position_in_frame_.x(),
152 cursor_position_in_frame_.y()),
153 target->visible_rect());
154
155 scaled_cursor_bitmap_.lockPixels();
156 for (int y = rect.y(); y < rect.bottom(); ++y) {
157 int cursor_y = y - cursor_position_in_frame_.y();
158 uint8_t* yplane = target->data(media::VideoFrame::kYPlane) +
159 y * target->row_bytes(media::VideoFrame::kYPlane);
160 uint8_t* uplane = target->data(media::VideoFrame::kUPlane) +
161 (y / 2) * target->row_bytes(media::VideoFrame::kUPlane);
162 uint8_t* vplane = target->data(media::VideoFrame::kVPlane) +
163 (y / 2) * target->row_bytes(media::VideoFrame::kVPlane);
164 for (int x = rect.x(); x < rect.right(); ++x) {
165 int cursor_x = x - cursor_position_in_frame_.x();
166 SkColor color = scaled_cursor_bitmap_.getColor(cursor_x, cursor_y);
167 int alpha = SkColorGetA(color);
168 int color_r = SkColorGetR(color);
169 int color_g = SkColorGetG(color);
170 int color_b = SkColorGetB(color);
171 int color_y = clip_byte(
172 ((color_r * 66 + color_g * 129 + color_b * 25 + 128) >> 8) + 16);
173 yplane[x] = alpha_blend(alpha, color_y, yplane[x]);
174
175 // Only sample U and V at even coordinates.
176 if ((x % 2 == 0) && (y % 2 == 0)) {
177 int color_u = clip_byte(
178 ((color_r * -38 + color_g * -74 + color_b * 112 + 128) >> 8) + 128);
179 int color_v = clip_byte(
180 ((color_r * 112 + color_g * -94 + color_b * -18 + 128) >> 8) + 128);
181 uplane[x / 2] = alpha_blend(alpha, color_u, uplane[x / 2]);
182 vplane[x / 2] = alpha_blend(alpha, color_v, vplane[x / 2]);
183 }
184 }
185 }
186 scaled_cursor_bitmap_.unlockPixels();
187 }
188
189 void CursorRenderer::OnMouseMoved(const gfx::Point& location,
190 base::TimeTicks timestamp) {
191 if (!cursor_displayed_) {
192 if (std::abs(location.x() - last_mouse_position_x_) > MIN_MOVEMENT_PIXELS ||
193 std::abs(location.y() - last_mouse_position_y_) > MIN_MOVEMENT_PIXELS)
194 cursor_displayed_ = true;
195 }
196
197 if (cursor_displayed_) {
198 last_mouse_movement_timestamp_ = timestamp;
199 last_mouse_position_x_ = location.x();
200 last_mouse_position_y_ = location.y();
201 }
202 }
203
204 void CursorRenderer::OnMouseClicked(const gfx::Point& location,
205 base::TimeTicks timestamp) {
206 cursor_displayed_ = true;
207 last_mouse_movement_timestamp_ = timestamp;
208 last_mouse_position_x_ = location.x();
209 last_mouse_position_y_ = location.y();
210 }
211
212 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698