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 MakeAsyncCopyRequest( |
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 gfx::Display::Rotation rotation = gfx::Screen::GetScreenFor(window) |
| 164 ->GetDisplayNearestWindow(window) |
| 165 .rotation(); |
145 scoped_ptr<cc::CopyOutputRequest> request = | 166 scoped_ptr<cc::CopyOutputRequest> request = |
146 cc::CopyOutputRequest::CreateBitmapRequest( | 167 cc::CopyOutputRequest::CreateBitmapRequest( |
147 base::Bind(&ScaleCopyOutputResult, callback, target_size, | 168 base::Bind(&ScaleAndRotateCopyOutputResult, |
| 169 callback, |
| 170 target_size, |
| 171 rotation, |
148 background_task_runner)); | 172 background_task_runner)); |
149 request->set_area(ui::ConvertRectToPixel(window->layer(), source_rect)); | 173 request->set_area(ui::ConvertRectToPixel(window->layer(), source_rect)); |
150 window->layer()->RequestCopyOfOutput(request.Pass()); | 174 window->layer()->RequestCopyOfOutput(request.Pass()); |
151 } | 175 } |
152 | 176 |
| 177 void GrabWindowSnapshotAndScaleAsync( |
| 178 gfx::NativeWindow window, |
| 179 const gfx::Rect& source_rect, |
| 180 const gfx::Size& target_size, |
| 181 scoped_refptr<base::TaskRunner> background_task_runner, |
| 182 const GrabWindowSnapshotAsyncCallback& callback) { |
| 183 // target_size is post-rotation, and so logically this is a rotate and then |
| 184 // scale operation. However, it will usually be more efficient to scale first |
| 185 // (given that this is mostly used for thumbnails) and then rotate. |
| 186 gfx::Display::Rotation rotation = gfx::Screen::GetScreenFor(window) |
| 187 ->GetDisplayNearestWindow(window) |
| 188 .rotation(); |
| 189 gfx::Size rotated_target_size; |
| 190 switch (rotation) { |
| 191 case gfx::Display::ROTATE_0: |
| 192 case gfx::Display::ROTATE_180: |
| 193 rotated_target_size = target_size; |
| 194 break; |
| 195 case gfx::Display::ROTATE_90: |
| 196 case gfx::Display::ROTATE_270: |
| 197 rotated_target_size = |
| 198 gfx::Size(target_size.height(), target_size.width()); |
| 199 break; |
| 200 }; |
| 201 |
| 202 MakeAsyncCopyRequest(window, |
| 203 source_rect, |
| 204 rotated_target_size, |
| 205 background_task_runner, |
| 206 callback); |
| 207 } |
| 208 |
| 209 void GrabWindowSnapshotAsync( |
| 210 gfx::NativeWindow window, |
| 211 const gfx::Rect& source_rect, |
| 212 scoped_refptr<base::TaskRunner> background_task_runner, |
| 213 const GrabWindowSnapshotAsyncCallback& callback) { |
| 214 gfx::Size target_size = GetTargetBoundsFromWindow(window, source_rect).size(); |
| 215 MakeAsyncCopyRequest( |
| 216 window, source_rect, target_size, background_task_runner, callback); |
| 217 } |
| 218 |
153 } // namespace ui | 219 } // namespace ui |
OLD | NEW |