Chromium Code Reviews| 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 |