Index: ui/snapshot/snapshot_aura.cc |
diff --git a/ui/snapshot/snapshot_aura.cc b/ui/snapshot/snapshot_aura.cc |
index 5fdd4dc519110e8b747685dc03420d019a4ceeaf..620d312283dd5e05758115ff4da460413eeebf86 100644 |
--- a/ui/snapshot/snapshot_aura.cc |
+++ b/ui/snapshot/snapshot_aura.cc |
@@ -40,9 +40,43 @@ void OnFrameScalingFinished( |
callback.Run(gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(scaled_bitmap))); |
} |
-void ScaleCopyOutputResult( |
+void RotateBitmap(SkBitmap* bitmap, gfx::Display::Rotation rotation) { |
+ switch (rotation) { |
+ case gfx::Display::ROTATE_0: |
+ break; |
+ case gfx::Display::ROTATE_90: |
+ *bitmap = SkBitmapOperations::Rotate(*bitmap, |
+ SkBitmapOperations::ROTATION_270_CW); |
+ break; |
+ case gfx::Display::ROTATE_180: |
+ *bitmap = SkBitmapOperations::Rotate(*bitmap, |
+ SkBitmapOperations::ROTATION_180_CW); |
+ break; |
+ case gfx::Display::ROTATE_270: |
+ *bitmap = SkBitmapOperations::Rotate(*bitmap, |
+ SkBitmapOperations::ROTATION_90_CW); |
+ break; |
+ } |
+} |
+ |
+SkBitmap ScaleAndRotateBitmap(const SkBitmap& input_bitmap, |
+ gfx::Size target_size_pre_rotation, |
+ gfx::Display::Rotation rotation) { |
+ SkBitmap bitmap; |
+ bitmap = |
+ skia::ImageOperations::Resize(input_bitmap, |
+ skia::ImageOperations::RESIZE_GOOD, |
+ target_size_pre_rotation.width(), |
+ target_size_pre_rotation.height(), |
+ static_cast<SkBitmap::Allocator*>(NULL)); |
+ RotateBitmap(&bitmap, rotation); |
+ return bitmap; |
+} |
+ |
+void ScaleAndRotateCopyOutputResult( |
const GrabWindowSnapshotAsyncCallback& callback, |
const gfx::Size& target_size, |
+ gfx::Display::Rotation rotation, |
scoped_refptr<base::TaskRunner> background_task_runner, |
scoped_ptr<cc::CopyOutputResult> result) { |
if (result->IsEmpty()) { |
@@ -50,40 +84,20 @@ void ScaleCopyOutputResult( |
return; |
} |
- // There are two overrides for skia::ImageOperations::Resize(), so we need get |
- // pointer to the right override explicitly (otherwise the base::Bind() call |
- // below won't compile). |
- SkBitmap (*resize_function)(const SkBitmap&, |
- skia::ImageOperations::ResizeMethod, int, int, |
- SkBitmap::Allocator* allocator) = |
- &skia::ImageOperations::Resize; |
- |
// TODO(sergeyu): Potentially images can be scaled on GPU before reading it |
// from GPU. Image scaling is implemented in content::GlHelper, but it's can't |
// be used here because it's not in content/public. Move the scaling code |
// somewhere so that it can be reused here. |
base::PostTaskAndReplyWithResult( |
- background_task_runner, FROM_HERE, |
- base::Bind(resize_function, *result->TakeBitmap(), |
- skia::ImageOperations::RESIZE_GOOD, |
- target_size.width(), target_size.height(), |
- static_cast<SkBitmap::Allocator*>(NULL)), |
+ background_task_runner, |
+ FROM_HERE, |
+ base::Bind( |
+ ScaleAndRotateBitmap, *result->TakeBitmap(), target_size, rotation), |
base::Bind(&OnFrameScalingFinished, callback)); |
} |
-} // namespace |
- |
-bool GrabViewSnapshot(gfx::NativeView view, |
- std::vector<unsigned char>* png_representation, |
- const gfx::Rect& snapshot_bounds) { |
- return GrabWindowSnapshot(view, png_representation, snapshot_bounds); |
-} |
- |
-bool GrabWindowSnapshot(gfx::NativeWindow window, |
- std::vector<unsigned char>* png_representation, |
- const gfx::Rect& snapshot_bounds) { |
- ui::Compositor* compositor = window->layer()->GetCompositor(); |
- |
+gfx::Rect GetTargetBoundsFromWindow(gfx::NativeWindow window, |
+ gfx::Rect snapshot_bounds) { |
gfx::RectF read_pixels_bounds = snapshot_bounds; |
// We must take into account the window's position on the desktop. |
@@ -98,33 +112,37 @@ bool GrabWindowSnapshot(gfx::NativeWindow window, |
// Sometimes (i.e. when using Aero on Windows) the compositor's size is |
// smaller than the window bounds. So trim appropriately. |
+ ui::Compositor* compositor = window->layer()->GetCompositor(); |
read_pixels_bounds_in_pixel.Intersect(gfx::Rect(compositor->size())); |
DCHECK_LE(0, read_pixels_bounds.x()); |
DCHECK_LE(0, read_pixels_bounds.y()); |
+ return read_pixels_bounds_in_pixel; |
+} |
+ |
+} // namespace |
+ |
+bool GrabViewSnapshot(gfx::NativeView view, |
+ std::vector<unsigned char>* png_representation, |
+ const gfx::Rect& snapshot_bounds) { |
+ return GrabWindowSnapshot(view, png_representation, snapshot_bounds); |
+} |
+ |
+bool GrabWindowSnapshot(gfx::NativeWindow window, |
+ std::vector<unsigned char>* png_representation, |
+ const gfx::Rect& snapshot_bounds) { |
+ gfx::Rect read_pixels_bounds_in_pixel = |
+ GetTargetBoundsFromWindow(window, snapshot_bounds); |
+ |
+ ui::Compositor* compositor = window->layer()->GetCompositor(); |
SkBitmap bitmap; |
if (!compositor->ReadPixels(&bitmap, read_pixels_bounds_in_pixel)) |
return false; |
gfx::Display display = |
gfx::Screen::GetScreenFor(window)->GetDisplayNearestWindow(window); |
- switch (display.rotation()) { |
- case gfx::Display::ROTATE_0: |
- break; |
- case gfx::Display::ROTATE_90: |
- bitmap = SkBitmapOperations::Rotate( |
- bitmap, SkBitmapOperations::ROTATION_270_CW); |
- break; |
- case gfx::Display::ROTATE_180: |
- bitmap = SkBitmapOperations::Rotate( |
- bitmap, SkBitmapOperations::ROTATION_180_CW); |
- break; |
- case gfx::Display::ROTATE_270: |
- bitmap = SkBitmapOperations::Rotate( |
- bitmap, SkBitmapOperations::ROTATION_90_CW); |
- break; |
- } |
+ RotateBitmap(&bitmap, display.rotation()); |
unsigned char* pixels = reinterpret_cast<unsigned char*>( |
bitmap.pixelRef()->pixels()); |
@@ -136,18 +154,66 @@ bool GrabWindowSnapshot(gfx::NativeWindow window, |
png_representation); |
} |
-SNAPSHOT_EXPORT void GrabWindowSnapshotAsync( |
+void MakeAsyncCopyRequest( |
gfx::NativeWindow window, |
const gfx::Rect& source_rect, |
const gfx::Size& target_size, |
scoped_refptr<base::TaskRunner> background_task_runner, |
const GrabWindowSnapshotAsyncCallback& callback) { |
+ gfx::Display::Rotation rotation = gfx::Screen::GetScreenFor(window) |
+ ->GetDisplayNearestWindow(window) |
+ .rotation(); |
scoped_ptr<cc::CopyOutputRequest> request = |
cc::CopyOutputRequest::CreateBitmapRequest( |
- base::Bind(&ScaleCopyOutputResult, callback, target_size, |
+ base::Bind(&ScaleAndRotateCopyOutputResult, |
+ callback, |
+ target_size, |
+ rotation, |
background_task_runner)); |
request->set_area(ui::ConvertRectToPixel(window->layer(), source_rect)); |
window->layer()->RequestCopyOfOutput(request.Pass()); |
} |
+void GrabWindowSnapshotAndScaleAsync( |
+ gfx::NativeWindow window, |
+ const gfx::Rect& source_rect, |
+ const gfx::Size& target_size, |
+ scoped_refptr<base::TaskRunner> background_task_runner, |
+ const GrabWindowSnapshotAsyncCallback& callback) { |
+ // target_size is post-rotation, and so logically this is a rotate and then |
+ // scale operation. However, it will usually be more efficient to scale first |
+ // (given that this is mostly used for thumbnails) and then rotate. |
+ gfx::Display::Rotation rotation = gfx::Screen::GetScreenFor(window) |
+ ->GetDisplayNearestWindow(window) |
+ .rotation(); |
+ gfx::Size rotated_target_size; |
+ switch (rotation) { |
+ case gfx::Display::ROTATE_0: |
+ case gfx::Display::ROTATE_180: |
+ rotated_target_size = target_size; |
+ break; |
+ case gfx::Display::ROTATE_90: |
+ case gfx::Display::ROTATE_270: |
+ rotated_target_size = |
+ gfx::Size(target_size.height(), target_size.width()); |
+ break; |
+ }; |
+ |
+ MakeAsyncCopyRequest(window, |
+ source_rect, |
+ rotated_target_size, |
+ background_task_runner, |
+ callback); |
+} |
+ |
+void GrabWindowSnapshotAsync( |
+ gfx::NativeWindow window, |
+ const gfx::Rect& source_rect, |
+ scoped_refptr<base::TaskRunner> background_task_runner, |
+ const GrabWindowSnapshotAsyncCallback& callback) { |
+ gfx::Size target_size = GetTargetBoundsFromWindow(window, source_rect).size(); |
+ MakeAsyncCopyRequest( |
+ window, source_rect, target_size, background_task_runner, callback); |
+} |
+ |
} // namespace ui |