summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/aeropeek_manager.cc2
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc2
-rw-r--r--chrome/browser/tab_contents/thumbnail_generator.cc3
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.cc50
-rw-r--r--content/browser/renderer_host/render_widget_host_impl.h3
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.cc8
-rw-r--r--content/browser/renderer_host/render_widget_host_view_aura.h3
-rw-r--r--content/browser/renderer_host/render_widget_host_view_gtk.cc8
-rw-r--r--content/browser/renderer_host/render_widget_host_view_gtk.h3
-rw-r--r--content/browser/renderer_host/render_widget_host_view_mac.h3
-rw-r--r--content/browser/renderer_host/render_widget_host_view_mac.mm8
-rw-r--r--content/browser/renderer_host/render_widget_host_view_win.cc16
-rw-r--r--content/browser/renderer_host/render_widget_host_view_win.h3
-rw-r--r--content/browser/renderer_host/test_render_view_host.cc6
-rw-r--r--content/browser/renderer_host/test_render_view_host.h3
-rw-r--r--content/port/browser/render_widget_host_view_port.h6
-rw-r--r--content/public/browser/render_widget_host.h10
-rw-r--r--ui/gfx/surface/accelerated_surface_win.cc147
-rw-r--r--ui/gfx/surface/accelerated_surface_win.h7
19 files changed, 281 insertions, 10 deletions
diff --git a/chrome/browser/aeropeek_manager.cc b/chrome/browser/aeropeek_manager.cc
index 77360cf..8c65ecb 100644
--- a/chrome/browser/aeropeek_manager.cc
+++ b/chrome/browser/aeropeek_manager.cc
@@ -998,7 +998,7 @@ bool AeroPeekManager::GetTabPreview(int tab_id, SkBitmap* preview) {
// Create a copy of this BackingStore image.
// This code is just copied from "thumbnail_generator.cc".
skia::PlatformCanvas canvas;
- if (!render_view_host->CopyFromBackingStore(&canvas))
+ if (!render_view_host->CopyFromBackingStore(gfx::Size(), &canvas))
return false;
const SkBitmap& bitmap = skia::GetTopDevice(canvas)->accessBitmap(false);
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index dbf198b..67d5916 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -1653,7 +1653,7 @@ bool CaptureVisibleTabFunction::RunImpl() {
// For example, some uncommon X11 visual modes are not supported by
// CopyFromBackingStore().
skia::PlatformCanvas temp_canvas;
- if (render_view_host->CopyFromBackingStore(&temp_canvas)) {
+ if (render_view_host->CopyFromBackingStore(gfx::Size(), &temp_canvas)) {
VLOG(1) << "captureVisibleTab() got image from backing store.";
SendResultFromBitmap(skia::GetTopDevice(temp_canvas)->accessBitmap(false));
return true;
diff --git a/chrome/browser/tab_contents/thumbnail_generator.cc b/chrome/browser/tab_contents/thumbnail_generator.cc
index 79d8f10..398c2af 100644
--- a/chrome/browser/tab_contents/thumbnail_generator.cc
+++ b/chrome/browser/tab_contents/thumbnail_generator.cc
@@ -77,8 +77,9 @@ SkBitmap GetBitmapForRenderWidgetHost(
// Get the bitmap as a Skia object so we can resample it. This is a large
// allocation and we can tolerate failure here, so give up if the allocation
// fails.
+ // TODO(mazda): Copy a shrinked size of image instead of the whole view size.
skia::PlatformCanvas temp_canvas;
- if (!render_widget_host->CopyFromBackingStore(&temp_canvas))
+ if (!render_widget_host->CopyFromBackingStore(gfx::Size(), &temp_canvas))
return result;
const SkBitmap& bmp_with_scrollbars =
skia::GetTopDevice(temp_canvas)->accessBitmap(false);
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 26dff6c..e797f92 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -34,8 +34,11 @@
#include "content/public/browser/user_metrics.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/result_codes.h"
+#include "skia/ext/image_operations.h"
+#include "skia/ext/platform_canvas.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h"
#include "ui/base/keycodes/keyboard_codes.h"
+#include "ui/gfx/skbitmap_operations.h"
#include "webkit/glue/webcursor.h"
#include "webkit/glue/webpreferences.h"
#include "webkit/plugins/npapi/webplugin.h"
@@ -501,13 +504,54 @@ void RenderWidgetHostImpl::SetIsLoading(bool is_loading) {
view_->SetIsLoading(is_loading);
}
-bool RenderWidgetHostImpl::CopyFromBackingStore(skia::PlatformCanvas* output) {
+bool RenderWidgetHostImpl::CopyFromBackingStore(const gfx::Size& dest_size,
+ skia::PlatformCanvas* output) {
+ if (view_ && is_accelerated_compositing_active_) {
+ TRACE_EVENT0("browser",
+ "RenderWidgetHostImpl::CopyFromBackingStore::FromCompositingSurface");
+ gfx::Size result_size = view_->GetViewBounds().size();
+ if (!dest_size.IsEmpty()) {
+ result_size.SetSize(std::min(result_size.width(), dest_size.width()),
+ std::min(result_size.height(), dest_size.height()));
+ }
+ return view_->CopyFromCompositingSurface(result_size, output);
+ }
+
BackingStore* backing_store = GetBackingStore(false);
if (!backing_store)
return false;
- return backing_store->CopyFromBackingStore(
- gfx::Rect(backing_store->size()), output);
+ TRACE_EVENT0("browser",
+ "RenderWidgetHostImpl::CopyFromBackingStore::FromBackingStore");
+ const gfx::Size backing_store_size = backing_store->size();
+ gfx::Size result_size = backing_store->size();
+ if (!dest_size.IsEmpty()) {
+ result_size.SetSize(std::min(result_size.width(), dest_size.width()),
+ std::min(result_size.height(), dest_size.height()));
+ }
+ // When the result size is equal to the backing store size, copy from the
+ // backing store directly to the output canvas.
+ if (result_size == backing_store_size)
+ return backing_store->CopyFromBackingStore(gfx::Rect(result_size), output);
+
+ // Otherwise, first copy from the backing store to a temporary canvas, then
+ // resize it into the result size.
+ skia::PlatformCanvas temp_canvas;
+ if (!backing_store->CopyFromBackingStore(gfx::Rect(backing_store_size),
+ &temp_canvas))
+ return false;
+
+ SkBitmap downsampled_bitmap =
+ SkBitmapOperations::DownsampleByTwoUntilSize(
+ skia::GetTopDevice(temp_canvas)->accessBitmap(false),
+ result_size.width(), result_size.height());
+ SkBitmap result_bitmap = skia::ImageOperations::Resize(
+ downsampled_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
+ dest_size.width(), dest_size.height());
+ if (!output->initialize(result_size.width(), result_size.height(), true))
+ return false;
+ output->writePixels(result_bitmap, 0, 0);
+ return true;
}
#if defined(TOOLKIT_GTK)
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 5942911..207a37b 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -77,7 +77,8 @@ class CONTENT_EXPORT RenderWidgetHostImpl : virtual public RenderWidgetHost,
virtual void UpdateTextDirection(WebKit::WebTextDirection direction) OVERRIDE;
virtual void NotifyTextDirection() OVERRIDE;
virtual void Blur() OVERRIDE;
- virtual bool CopyFromBackingStore(skia::PlatformCanvas* output) OVERRIDE;
+ virtual bool CopyFromBackingStore(const gfx::Size& dest_size,
+ skia::PlatformCanvas* output) OVERRIDE;
#if defined(TOOLKIT_GTK)
virtual bool CopyFromBackingStoreToGtkWindow(const gfx::Rect& dest_rect,
GdkWindow* target) OVERRIDE;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index 6a5c159..a0e2ebd 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -525,6 +525,14 @@ void RenderWidgetHostViewAura::SetBackground(const SkBitmap& background) {
window_->layer()->SetFillsBoundsOpaquely(background.isOpaque());
}
+bool RenderWidgetHostViewAura::CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) {
+ // TODO(mazda): Implement this.
+ NOTIMPLEMENTED();
+ return false;
+}
+
void RenderWidgetHostViewAura::GetScreenInfo(WebKit::WebScreenInfo* results) {
GetDefaultScreenInfo(results);
}
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 3123c56..60257b4 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -67,6 +67,9 @@ class RenderWidgetHostViewAura
virtual void UnhandledWheelEvent(
const WebKit::WebMouseWheelEvent& event) OVERRIDE;
virtual void SetBackground(const SkBitmap& background) OVERRIDE;
+ virtual bool CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) OVERRIDE;
// Overridden from RenderWidgetHostViewPort:
virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view,
diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.cc b/content/browser/renderer_host/render_widget_host_view_gtk.cc
index a2cf64e..fa4b879 100644
--- a/content/browser/renderer_host/render_widget_host_view_gtk.cc
+++ b/content/browser/renderer_host/render_widget_host_view_gtk.cc
@@ -1047,6 +1047,14 @@ void RenderWidgetHostViewGtk::SetBackground(const SkBitmap& background) {
host_->Send(new ViewMsg_SetBackground(host_->GetRoutingID(), background));
}
+bool RenderWidgetHostViewGtk::CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) {
+ // TODO(mazda): Implement this.
+ NOTIMPLEMENTED();
+ return false;
+}
+
void RenderWidgetHostViewGtk::ModifyEventForEdgeDragging(
GtkWidget* widget, GdkEventMotion* event) {
// If the widget is aligned with an edge of the monitor its on and the user
diff --git a/content/browser/renderer_host/render_widget_host_view_gtk.h b/content/browser/renderer_host/render_widget_host_view_gtk.h
index 5b60ec3..f322d04 100644
--- a/content/browser/renderer_host/render_widget_host_view_gtk.h
+++ b/content/browser/renderer_host/render_widget_host_view_gtk.h
@@ -72,6 +72,9 @@ class RenderWidgetHostViewGtk : public content::RenderWidgetHostViewBase {
virtual void UnhandledWheelEvent(
const WebKit::WebMouseWheelEvent& event) OVERRIDE;
virtual void SetBackground(const SkBitmap& background) OVERRIDE;
+ virtual bool CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) OVERRIDE;
// RenderWidgetHostViewPort implementation.
virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view,
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.h b/content/browser/renderer_host/render_widget_host_view_mac.h
index 5e2a054..c8f5fd56 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -193,6 +193,9 @@ class RenderWidgetHostViewMac : public content::RenderWidgetHostViewBase {
virtual void UnhandledWheelEvent(
const WebKit::WebMouseWheelEvent& event) OVERRIDE;
virtual void SetBackground(const SkBitmap& background) OVERRIDE;
+ virtual bool CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) OVERRIDE;
// Implementation of RenderWidgetHostViewPort.
virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view,
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm
index 2f1e2da..9ace1d3 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -1126,6 +1126,14 @@ void RenderWidgetHostViewMac::SetBackground(const SkBitmap& background) {
render_widget_host_->GetRoutingID(), background));
}
+bool RenderWidgetHostViewMac::CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) {
+ // TODO(mazda): Implement this.
+ NOTIMPLEMENTED();
+ return false;
+}
+
void RenderWidgetHostViewMac::OnAccessibilityNotifications(
const std::vector<AccessibilityHostMsg_NotificationParams>& params) {
if (!GetBrowserAccessibilityManager()) {
diff --git a/content/browser/renderer_host/render_widget_host_view_win.cc b/content/browser/renderer_host/render_widget_host_view_win.cc
index 5be7dfa..33539a1 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.cc
+++ b/content/browser/renderer_host/render_widget_host_view_win.cc
@@ -907,6 +907,22 @@ void RenderWidgetHostViewWin::SetBackground(const SkBitmap& background) {
render_widget_host_->SetBackground(background);
}
+bool RenderWidgetHostViewWin::CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) {
+ if (!accelerated_surface_.get())
+ return false;
+
+ if (size.IsEmpty())
+ return false;
+
+ if (!output->initialize(size.width(), size.height(), true))
+ return false;
+
+ return accelerated_surface_->CopyTo(
+ size, output->getTopDevice()->accessBitmap(true).getPixels());
+}
+
void RenderWidgetHostViewWin::UnhandledWheelEvent(
const WebKit::WebMouseWheelEvent& event) {
}
diff --git a/content/browser/renderer_host/render_widget_host_view_win.h b/content/browser/renderer_host/render_widget_host_view_win.h
index 670c9f4d..4dc81b4 100644
--- a/content/browser/renderer_host/render_widget_host_view_win.h
+++ b/content/browser/renderer_host/render_widget_host_view_win.h
@@ -169,6 +169,9 @@ class RenderWidgetHostViewWin
virtual void UnhandledWheelEvent(
const WebKit::WebMouseWheelEvent& event) OVERRIDE;
virtual void SetBackground(const SkBitmap& background) OVERRIDE;
+ virtual bool CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) OVERRIDE;
// Implementation of RenderWidgetHostViewPort.
virtual void InitAsPopup(content::RenderWidgetHostView* parent_host_view,
diff --git a/content/browser/renderer_host/test_render_view_host.cc b/content/browser/renderer_host/test_render_view_host.cc
index ad23b47..e61edd1 100644
--- a/content/browser/renderer_host/test_render_view_host.cc
+++ b/content/browser/renderer_host/test_render_view_host.cc
@@ -181,6 +181,12 @@ gfx::NativeView TestRenderWidgetHostView::BuildInputMethodsGtkMenu() {
#endif // !defined(TOOLKIT_VIEWS)
#endif // defined(TOOLKIT_USES_GTK)
+bool TestRenderWidgetHostView::CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) {
+ return false;
+}
+
gfx::GLSurfaceHandle TestRenderWidgetHostView::GetCompositingSurface() {
return gfx::GLSurfaceHandle();
}
diff --git a/content/browser/renderer_host/test_render_view_host.h b/content/browser/renderer_host/test_render_view_host.h
index 354b0fe..298761e 100644
--- a/content/browser/renderer_host/test_render_view_host.h
+++ b/content/browser/renderer_host/test_render_view_host.h
@@ -76,6 +76,9 @@ class TestRenderWidgetHostView : public RenderWidgetHostViewBase {
#endif // defined(TOOLKIT_USES_GTK)
virtual void UnhandledWheelEvent(
const WebKit::WebMouseWheelEvent& event) OVERRIDE {}
+ virtual bool CopyFromCompositingSurface(
+ const gfx::Size& size,
+ skia::PlatformCanvas* output) OVERRIDE;
// RenderWidgetHostViewPort implementation.
virtual void InitAsPopup(RenderWidgetHostView* parent_host_view,
diff --git a/content/port/browser/render_widget_host_view_port.h b/content/port/browser/render_widget_host_view_port.h
index 471c427..7d84000 100644
--- a/content/port/browser/render_widget_host_view_port.h
+++ b/content/port/browser/render_widget_host_view_port.h
@@ -138,6 +138,12 @@ class CONTENT_EXPORT RenderWidgetHostViewPort : public RenderWidgetHostView {
// Allocate a backing store for this view.
virtual BackingStore* AllocBackingStore(const gfx::Size& size) = 0;
+ // Copies the contents of the compositing surface into the given
+ // (uninitialized) PlatformCanvas if any. Returns true on success, false
+ // otherwise.
+ virtual bool CopyFromCompositingSurface(const gfx::Size& size,
+ skia::PlatformCanvas* output) = 0;
+
// Called when accelerated compositing state changes.
virtual void OnAcceleratedCompositingStateChange() = 0;
// |params.window| and |params.surface_id| indicate which accelerated
diff --git a/content/public/browser/render_widget_host.h b/content/public/browser/render_widget_host.h
index e95d325..b9f5204 100644
--- a/content/public/browser/render_widget_host.h
+++ b/content/public/browser/render_widget_host.h
@@ -177,8 +177,14 @@ class CONTENT_EXPORT RenderWidgetHost : public IPC::Channel::Sender {
virtual void Blur() = 0;
// Copies the contents of the backing store into the given (uninitialized)
- // PlatformCanvas. Returns true on success, false otherwise.
- virtual bool CopyFromBackingStore(skia::PlatformCanvas* output) = 0;
+ // PlatformCanvas. Returns true on success, false otherwise. When accelerated
+ // compositing is active, the contents is copied from the compositing surface.
+ // If non empty |dest_size| is given, the content is shrinked so that it fits
+ // in |dest_size|. If |dest_size| is larger than the contens size, the
+ // content is not resized. If |dest_size| is empty, the original size of the
+ // contents is copied.
+ virtual bool CopyFromBackingStore(const gfx::Size& dest_size,
+ skia::PlatformCanvas* output) = 0;
#if defined(TOOLKIT_GTK)
// Paint the backing store into the target's |dest_rect|.
diff --git a/ui/gfx/surface/accelerated_surface_win.cc b/ui/gfx/surface/accelerated_surface_win.cc
index adff364..bf24711 100644
--- a/ui/gfx/surface/accelerated_surface_win.cc
+++ b/ui/gfx/surface/accelerated_surface_win.cc
@@ -5,6 +5,7 @@
#include "ui/gfx/surface/accelerated_surface_win.h"
#include <windows.h>
+#include <algorithm>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -38,6 +39,47 @@ UINT GetPresentationInterval() {
return D3DPRESENT_INTERVAL_ONE;
}
+// Calculate the number necessary to transform |source_size| into |dest_size|
+// by repeating downsampling of the image of |source_size| by a factor no more
+// than 2.
+int GetResampleCount(const gfx::Size& source_size, const gfx::Size& dest_size) {
+ int width_count = 0;
+ int width = source_size.width();
+ while (width > dest_size.width()) {
+ ++width_count;
+ width >>= 1;
+ }
+ int height_count = 0;
+ int height = source_size.height();
+ while (height > dest_size.height()) {
+ ++height_count;
+ height >>= 1;
+ }
+ return std::max(width_count, height_count);
+}
+
+// Returns half the size of |size| no smaller than |min_size|.
+gfx::Size GetHalfSizeNoLessThan(const gfx::Size& size,
+ const gfx::Size& min_size) {
+ return gfx::Size(std::max(min_size.width(), size.width() / 2),
+ std::max(min_size.height(), size.height() / 2));
+}
+
+bool CreateTemporarySurface(IDirect3DDevice9* device,
+ const gfx::Size& size,
+ IDirect3DSurface9** surface) {
+ HRESULT hr = device->CreateRenderTarget(
+ size.width(),
+ size.height(),
+ D3DFMT_A8R8G8B8,
+ D3DMULTISAMPLE_NONE,
+ 0,
+ TRUE,
+ surface,
+ NULL);
+ return SUCCEEDED(hr);
+}
+
} // namespace anonymous
// A PresentThread is a thread that is dedicated to presenting surfaces to a
@@ -240,6 +282,106 @@ bool AcceleratedPresenter::Present(gfx::NativeWindow window) {
return true;
}
+bool AcceleratedPresenter::CopyTo(const gfx::Size& size, void* buf) {
+ base::AutoLock locked(lock_);
+
+ if (!swap_chain_)
+ return false;
+
+ base::win::ScopedComPtr<IDirect3DSurface9> back_buffer;
+ HRESULT hr = swap_chain_->GetBackBuffer(0,
+ D3DBACKBUFFER_TYPE_MONO,
+ back_buffer.Receive());
+ if (FAILED(hr))
+ return false;
+
+ D3DSURFACE_DESC desc;
+ hr = back_buffer->GetDesc(&desc);
+ if (FAILED(hr))
+ return false;
+
+ const gfx::Size back_buffer_size(desc.Width, desc.Height);
+ if (back_buffer_size.IsEmpty())
+ return false;
+
+ // Set up intermediate buffers needed for downsampling.
+ const int resample_count =
+ GetResampleCount(gfx::Size(desc.Width, desc.Height), size);
+ base::win::ScopedComPtr<IDirect3DSurface9> final_surface;
+ base::win::ScopedComPtr<IDirect3DSurface9> temp_buffer[2];
+ if (resample_count == 0)
+ final_surface = back_buffer;
+ if (resample_count > 0) {
+ if (!CreateTemporarySurface(present_thread_->device(),
+ size,
+ final_surface.Receive()))
+ return false;
+ }
+ const gfx::Size half_size = GetHalfSizeNoLessThan(back_buffer_size, size);
+ if (resample_count > 1) {
+ if (!CreateTemporarySurface(present_thread_->device(),
+ half_size,
+ temp_buffer[0].Receive()))
+ return false;
+ }
+ if (resample_count > 2) {
+ const gfx::Size quarter_size = GetHalfSizeNoLessThan(half_size, size);
+ if (!CreateTemporarySurface(present_thread_->device(),
+ quarter_size,
+ temp_buffer[1].Receive()))
+ return false;
+ }
+
+ // Repeat downsampling the surface until its size becomes identical to
+ // |size|. We keep the factor of each downsampling no more than two because
+ // using a factor more than two can introduce aliasing.
+ gfx::Size read_size = back_buffer_size;
+ gfx::Size write_size = half_size;
+ int read_buffer_index = 1;
+ int write_buffer_index = 0;
+ for (int i = 0; i < resample_count; ++i) {
+ base::win::ScopedComPtr<IDirect3DSurface9> read_buffer =
+ (i == 0) ? back_buffer : temp_buffer[read_buffer_index];
+ base::win::ScopedComPtr<IDirect3DSurface9> write_buffer =
+ (i == resample_count - 1) ? final_surface :
+ temp_buffer[write_buffer_index];
+ RECT read_rect = {0, 0, read_size.width(), read_size.height()};
+ RECT write_rect = {0, 0, write_size.width(), write_size.height()};
+ hr = present_thread_->device()->StretchRect(read_buffer,
+ &read_rect,
+ write_buffer,
+ &write_rect,
+ D3DTEXF_LINEAR);
+ if (FAILED(hr))
+ return false;
+ read_size = write_size;
+ write_size = GetHalfSizeNoLessThan(write_size, size);
+ std::swap(read_buffer_index, write_buffer_index);
+ }
+
+ DCHECK(size == read_size);
+
+ base::win::ScopedComPtr<IDirect3DSurface9> temp_surface;
+ HANDLE handle = reinterpret_cast<HANDLE>(buf);
+ hr = present_thread_->device()->CreateOffscreenPlainSurface(
+ size.width(),
+ size.height(),
+ D3DFMT_A8R8G8B8,
+ D3DPOOL_SYSTEMMEM,
+ temp_surface.Receive(),
+ &handle);
+ if (FAILED(hr))
+ return false;
+
+ // Copy the data in the temporary buffer to the surface backed by |buf|.
+ hr = present_thread_->device()->GetRenderTargetData(final_surface,
+ temp_surface);
+ if (FAILED(hr))
+ return false;
+
+ return true;
+}
+
void AcceleratedPresenter::Suspend() {
present_thread_->message_loop()->PostTask(
FROM_HERE,
@@ -444,7 +586,10 @@ bool AcceleratedSurface::Present(HWND window) {
return presenter_->Present(window);
}
+bool AcceleratedSurface::CopyTo(const gfx::Size& size, void* buf) {
+ return presenter_->CopyTo(size, buf);
+}
+
void AcceleratedSurface::Suspend() {
presenter_->Suspend();
}
-
diff --git a/ui/gfx/surface/accelerated_surface_win.h b/ui/gfx/surface/accelerated_surface_win.h
index 9b48b36..52208d3 100644
--- a/ui/gfx/surface/accelerated_surface_win.h
+++ b/ui/gfx/surface/accelerated_surface_win.h
@@ -32,6 +32,7 @@ class AcceleratedPresenter
int64 surface_id,
const base::Callback<void(bool)>& completion_task);
bool Present(gfx::NativeWindow window);
+ bool CopyTo(const gfx::Size& size, void* buf);
void Suspend();
void WaitForPendingTasks();
@@ -85,6 +86,12 @@ class SURFACE_EXPORT AcceleratedSurface {
// Synchronously present a frame with no acknowledgement.
bool Present(gfx::NativeWindow window);
+ // Copies the surface data to |buf|. The image data is transformed so that it
+ // fits in |size|.
+ // Caller must ensure that |buf| is allocated with the size no less than
+ // |4 * size.width() * size.height()| bytes.
+ bool CopyTo(const gfx::Size& size, void* buf);
+
// Temporarily release resources until a new surface is asynchronously
// presented. Present will not be able to represent the last surface after
// calling this and will return false.