OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ui/snapshot/snapshot.h" | 5 #include "ui/snapshot/snapshot.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/callback.h" | 8 #include "base/callback.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/safe_numerics.h" | 10 #include "base/safe_numerics.h" |
(...skipping 22 matching lines...) Expand all Loading... | |
33 namespace ui { | 33 namespace ui { |
34 | 34 |
35 namespace { | 35 namespace { |
36 | 36 |
37 void OnFrameScalingFinished( | 37 void OnFrameScalingFinished( |
38 const GrabWindowSnapshotAsyncCallback& callback, | 38 const GrabWindowSnapshotAsyncCallback& callback, |
39 const SkBitmap& scaled_bitmap) { | 39 const SkBitmap& scaled_bitmap) { |
40 callback.Run(gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(scaled_bitmap))); | 40 callback.Run(gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(scaled_bitmap))); |
41 } | 41 } |
42 | 42 |
43 void ScaleCopyOutputResult( | 43 void RotateBitmap(SkBitmap* bitmap, gfx::Display::Rotation rotation) { |
44 switch (rotation) { | |
45 case gfx::Display::ROTATE_0: | |
46 break; | |
47 case gfx::Display::ROTATE_90: | |
48 *bitmap = SkBitmapOperations::Rotate(*bitmap, | |
49 SkBitmapOperations::ROTATION_270_CW); | |
50 break; | |
51 case gfx::Display::ROTATE_180: | |
52 *bitmap = SkBitmapOperations::Rotate(*bitmap, | |
53 SkBitmapOperations::ROTATION_180_CW); | |
54 break; | |
55 case gfx::Display::ROTATE_270: | |
56 *bitmap = SkBitmapOperations::Rotate(*bitmap, | |
57 SkBitmapOperations::ROTATION_90_CW); | |
58 break; | |
59 } | |
60 } | |
61 | |
62 SkBitmap ScaleAndRotateBitmap(const SkBitmap& input_bitmap, | |
63 gfx::Size target_size_pre_rotation, | |
64 gfx::Display::Rotation rotation) { | |
65 SkBitmap bitmap; | |
66 bitmap = | |
67 skia::ImageOperations::Resize(input_bitmap, | |
68 skia::ImageOperations::RESIZE_GOOD, | |
69 target_size_pre_rotation.width(), | |
70 target_size_pre_rotation.height(), | |
71 static_cast<SkBitmap::Allocator*>(NULL)); | |
72 RotateBitmap(&bitmap, rotation); | |
73 return bitmap; | |
74 } | |
75 | |
76 void ScaleAndRotateCopyOutputResult( | |
44 const GrabWindowSnapshotAsyncCallback& callback, | 77 const GrabWindowSnapshotAsyncCallback& callback, |
45 const gfx::Size& target_size, | 78 const gfx::Size& target_size, |
79 gfx::Display::Rotation rotation, | |
46 scoped_refptr<base::TaskRunner> background_task_runner, | 80 scoped_refptr<base::TaskRunner> background_task_runner, |
47 scoped_ptr<cc::CopyOutputResult> result) { | 81 scoped_ptr<cc::CopyOutputResult> result) { |
48 if (result->IsEmpty()) { | 82 if (result->IsEmpty()) { |
49 callback.Run(gfx::Image()); | 83 callback.Run(gfx::Image()); |
50 return; | 84 return; |
51 } | 85 } |
52 | 86 |
53 // There are two overrides for skia::ImageOperations::Resize(), so we need get | |
54 // pointer to the right override explicitly (otherwise the base::Bind() call | |
55 // below won't compile). | |
56 SkBitmap (*resize_function)(const SkBitmap&, | |
57 skia::ImageOperations::ResizeMethod, int, int, | |
58 SkBitmap::Allocator* allocator) = | |
59 &skia::ImageOperations::Resize; | |
60 | |
61 // TODO(sergeyu): Potentially images can be scaled on GPU before reading it | 87 // TODO(sergeyu): Potentially images can be scaled on GPU before reading it |
62 // from GPU. Image scaling is implemented in content::GlHelper, but it's can't | 88 // from GPU. Image scaling is implemented in content::GlHelper, but it's can't |
63 // be used here because it's not in content/public. Move the scaling code | 89 // be used here because it's not in content/public. Move the scaling code |
64 // somewhere so that it can be reused here. | 90 // somewhere so that it can be reused here. |
65 base::PostTaskAndReplyWithResult( | 91 base::PostTaskAndReplyWithResult( |
66 background_task_runner, FROM_HERE, | 92 background_task_runner, |
67 base::Bind(resize_function, *result->TakeBitmap(), | 93 FROM_HERE, |
68 skia::ImageOperations::RESIZE_GOOD, | 94 base::Bind( |
69 target_size.width(), target_size.height(), | 95 ScaleAndRotateBitmap, *result->TakeBitmap(), target_size, rotation), |
70 static_cast<SkBitmap::Allocator*>(NULL)), | |
71 base::Bind(&OnFrameScalingFinished, callback)); | 96 base::Bind(&OnFrameScalingFinished, callback)); |
72 } | 97 } |
73 | 98 |
74 } // namespace | 99 gfx::Rect GetTargetBoundsFromWindow(gfx::NativeWindow window, |
75 | 100 gfx::Rect snapshot_bounds) { |
76 bool GrabViewSnapshot(gfx::NativeView view, | |
77 std::vector<unsigned char>* png_representation, | |
78 const gfx::Rect& snapshot_bounds) { | |
79 return GrabWindowSnapshot(view, png_representation, snapshot_bounds); | |
80 } | |
81 | |
82 bool GrabWindowSnapshot(gfx::NativeWindow window, | |
83 std::vector<unsigned char>* png_representation, | |
84 const gfx::Rect& snapshot_bounds) { | |
85 ui::Compositor* compositor = window->layer()->GetCompositor(); | |
86 | |
87 gfx::RectF read_pixels_bounds = snapshot_bounds; | 101 gfx::RectF read_pixels_bounds = snapshot_bounds; |
88 | 102 |
89 // We must take into account the window's position on the desktop. | 103 // We must take into account the window's position on the desktop. |
90 read_pixels_bounds.Offset( | 104 read_pixels_bounds.Offset( |
91 window->GetBoundsInRootWindow().origin().OffsetFromOrigin()); | 105 window->GetBoundsInRootWindow().origin().OffsetFromOrigin()); |
92 aura::WindowEventDispatcher* dispatcher = window->GetDispatcher(); | 106 aura::WindowEventDispatcher* dispatcher = window->GetDispatcher(); |
93 if (dispatcher) | 107 if (dispatcher) |
94 dispatcher->host()->GetRootTransform().TransformRect(&read_pixels_bounds); | 108 dispatcher->host()->GetRootTransform().TransformRect(&read_pixels_bounds); |
95 | 109 |
96 gfx::Rect read_pixels_bounds_in_pixel = | 110 gfx::Rect read_pixels_bounds_in_pixel = |
97 gfx::ToEnclosingRect(read_pixels_bounds); | 111 gfx::ToEnclosingRect(read_pixels_bounds); |
98 | 112 |
99 // Sometimes (i.e. when using Aero on Windows) the compositor's size is | 113 // Sometimes (i.e. when using Aero on Windows) the compositor's size is |
100 // smaller than the window bounds. So trim appropriately. | 114 // smaller than the window bounds. So trim appropriately. |
115 ui::Compositor* compositor = window->layer()->GetCompositor(); | |
101 read_pixels_bounds_in_pixel.Intersect(gfx::Rect(compositor->size())); | 116 read_pixels_bounds_in_pixel.Intersect(gfx::Rect(compositor->size())); |
102 | 117 |
103 DCHECK_LE(0, read_pixels_bounds.x()); | 118 DCHECK_LE(0, read_pixels_bounds.x()); |
104 DCHECK_LE(0, read_pixels_bounds.y()); | 119 DCHECK_LE(0, read_pixels_bounds.y()); |
105 | 120 |
121 return read_pixels_bounds_in_pixel; | |
122 } | |
123 | |
124 } // namespace | |
125 | |
126 bool GrabViewSnapshot(gfx::NativeView view, | |
127 std::vector<unsigned char>* png_representation, | |
128 const gfx::Rect& snapshot_bounds) { | |
129 return GrabWindowSnapshot(view, png_representation, snapshot_bounds); | |
130 } | |
131 | |
132 bool GrabWindowSnapshot(gfx::NativeWindow window, | |
133 std::vector<unsigned char>* png_representation, | |
134 const gfx::Rect& snapshot_bounds) { | |
135 gfx::Rect read_pixels_bounds_in_pixel = | |
136 GetTargetBoundsFromWindow(window, snapshot_bounds); | |
137 | |
138 ui::Compositor* compositor = window->layer()->GetCompositor(); | |
106 SkBitmap bitmap; | 139 SkBitmap bitmap; |
107 if (!compositor->ReadPixels(&bitmap, read_pixels_bounds_in_pixel)) | 140 if (!compositor->ReadPixels(&bitmap, read_pixels_bounds_in_pixel)) |
108 return false; | 141 return false; |
109 | 142 |
110 gfx::Display display = | 143 gfx::Display display = |
111 gfx::Screen::GetScreenFor(window)->GetDisplayNearestWindow(window); | 144 gfx::Screen::GetScreenFor(window)->GetDisplayNearestWindow(window); |
112 switch (display.rotation()) { | 145 RotateBitmap(&bitmap, display.rotation()); |
113 case gfx::Display::ROTATE_0: | |
114 break; | |
115 case gfx::Display::ROTATE_90: | |
116 bitmap = SkBitmapOperations::Rotate( | |
117 bitmap, SkBitmapOperations::ROTATION_270_CW); | |
118 break; | |
119 case gfx::Display::ROTATE_180: | |
120 bitmap = SkBitmapOperations::Rotate( | |
121 bitmap, SkBitmapOperations::ROTATION_180_CW); | |
122 break; | |
123 case gfx::Display::ROTATE_270: | |
124 bitmap = SkBitmapOperations::Rotate( | |
125 bitmap, SkBitmapOperations::ROTATION_90_CW); | |
126 break; | |
127 } | |
128 | 146 |
129 unsigned char* pixels = reinterpret_cast<unsigned char*>( | 147 unsigned char* pixels = reinterpret_cast<unsigned char*>( |
130 bitmap.pixelRef()->pixels()); | 148 bitmap.pixelRef()->pixels()); |
131 return gfx::PNGCodec::Encode( | 149 return gfx::PNGCodec::Encode( |
132 pixels, gfx::PNGCodec::FORMAT_BGRA, | 150 pixels, gfx::PNGCodec::FORMAT_BGRA, |
133 gfx::Size(bitmap.width(), bitmap.height()), | 151 gfx::Size(bitmap.width(), bitmap.height()), |
134 base::checked_numeric_cast<int>(bitmap.rowBytes()), | 152 base::checked_numeric_cast<int>(bitmap.rowBytes()), |
135 true, std::vector<gfx::PNGCodec::Comment>(), | 153 true, std::vector<gfx::PNGCodec::Comment>(), |
136 png_representation); | 154 png_representation); |
137 } | 155 } |
138 | 156 |
139 SNAPSHOT_EXPORT void GrabWindowSnapshotAsync( | 157 void GrabWindowSnapshotAndScaleAsync( |
140 gfx::NativeWindow window, | 158 gfx::NativeWindow window, |
141 const gfx::Rect& source_rect, | 159 const gfx::Rect& source_rect, |
142 const gfx::Size& target_size, | 160 const gfx::Size& target_size, |
143 scoped_refptr<base::TaskRunner> background_task_runner, | 161 scoped_refptr<base::TaskRunner> background_task_runner, |
144 const GrabWindowSnapshotAsyncCallback& callback) { | 162 const GrabWindowSnapshotAsyncCallback& callback) { |
163 // target_size is post-rotation, and so logically this is a rotate and then | |
164 // scale operation. However, it will usually be more efficient to scale first | |
165 // (given that this is mostly used for thumbnails) and then rotate. | |
166 gfx::Display::Rotation rotation = gfx::Screen::GetScreenFor(window) | |
167 ->GetDisplayNearestWindow(window) | |
168 .rotation(); | |
169 gfx::Size rotated_target_size; | |
170 switch (rotation) { | |
171 case gfx::Display::ROTATE_0: | |
172 case gfx::Display::ROTATE_180: | |
173 rotated_target_size = target_size; | |
174 break; | |
175 case gfx::Display::ROTATE_90: | |
176 case gfx::Display::ROTATE_270: | |
177 rotated_target_size = | |
178 gfx::Size(target_size.height(), target_size.width()); | |
179 break; | |
180 }; | |
181 | |
145 scoped_ptr<cc::CopyOutputRequest> request = | 182 scoped_ptr<cc::CopyOutputRequest> request = |
146 cc::CopyOutputRequest::CreateBitmapRequest( | 183 cc::CopyOutputRequest::CreateBitmapRequest( |
147 base::Bind(&ScaleCopyOutputResult, callback, target_size, | 184 base::Bind(&ScaleAndRotateCopyOutputResult, |
185 callback, | |
186 rotated_target_size, | |
187 rotation, | |
148 background_task_runner)); | 188 background_task_runner)); |
149 request->set_area(ui::ConvertRectToPixel(window->layer(), source_rect)); | 189 request->set_area(ui::ConvertRectToPixel(window->layer(), source_rect)); |
150 window->layer()->RequestCopyOfOutput(request.Pass()); | 190 window->layer()->RequestCopyOfOutput(request.Pass()); |
191 } | |
192 | |
193 void GrabWindowSnapshotAsync( | |
194 gfx::NativeWindow window, | |
195 const gfx::Rect& source_rect, | |
196 scoped_refptr<base::TaskRunner> background_task_runner, | |
197 const GrabWindowSnapshotAsyncCallback& callback) { | |
198 gfx::Size target_size = GetTargetBoundsFromWindow(window, source_rect).size(); | |
199 gfx::Display::Rotation rotation = gfx::Screen::GetScreenFor(window) | |
200 ->GetDisplayNearestWindow(window) | |
201 .rotation(); | |
202 scoped_ptr<cc::CopyOutputRequest> request = | |
Sergey Ulanov
2014/01/08 02:24:16
It looks like a lot of code in this function is du
enne (OOO)
2014/01/08 18:50:48
Done. Can't call GrabWindowSnapshotAndScaleAsync
| |
203 cc::CopyOutputRequest::CreateBitmapRequest( | |
204 base::Bind(&ScaleAndRotateCopyOutputResult, | |
205 callback, | |
206 target_size, | |
207 rotation, | |
208 background_task_runner)); | |
209 request->set_area(ui::ConvertRectToPixel(window->layer(), source_rect)); | |
210 window->layer()->RequestCopyOfOutput(request.Pass()); | |
151 } | 211 } |
152 | 212 |
153 } // namespace ui | 213 } // namespace ui |
OLD | NEW |