OLD | NEW |
---|---|
(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 | |
OLD | NEW |