Implement the Windows screen capturer using the Magnification API.
The original ScreenCapturerWin is renamed ScreenCapturerWinGdi.

BUG=2789
TESTED=full desktop cast and single monitor cast works on win7 and win8 desktop mode. Have to use GDI capturer on win8 metro mode. Changing display configuration work on the fly.
R=sergeyu@chromium.org, wez@chromium.org

Committed: https://code.google.com/p/webrtc/source/detail?r=6048

Review URL: https://webrtc-codereview.appspot.com/12149004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6053 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/tools/valgrind-webrtc/drmemory/suppressions.txt b/tools/valgrind-webrtc/drmemory/suppressions.txt
index 5bfc865..8b75653 100644
--- a/tools/valgrind-webrtc/drmemory/suppressions.txt
+++ b/tools/valgrind-webrtc/drmemory/suppressions.txt
@@ -29,28 +29,37 @@
 *!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void>
 
 UNINITIALIZED READ
-name=https://code.google.com/p/webrtc/issues/detail?id=2323 (2)
+name=<https://code.google.com/p/webrtc/issues/detail?id=2323 (2)>
 system call NtUserGetThreadDesktop parameter value #1
 *!webrtc::Desktop::GetThreadDesktop
 *!webrtc::ScopedThreadDesktop::ScopedThreadDesktop
-*!webrtc::`anonymous namespace'::ScreenCapturerWin::ScreenCapturerWin
-*!webrtc::ScreenCapturer::CreateWithDisableAero
-*!webrtc::ScreenCapturer::Create
-...
-*!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void>
-
-UNINITIALIZED READ
-name=https://code.google.com/p/webrtc/issues/detail?id=2323 (3)
-system call NtUserGetThreadDesktop parameter value #1
-*!webrtc::Desktop::GetThreadDesktop
-*!webrtc::ScopedThreadDesktop::ScopedThreadDesktop
-*!webrtc::`anonymous namespace'::ScreenCapturerWin::ScreenCapturerWin
+*!webrtc::ScreenCapturerWinGdi::ScreenCapturerWinGdi
 *!webrtc::ScreenCapturer::Create
 *!webrtc::ScreenCapturerTest::SetUp
 *!testing::internal::HandleSehExceptionsInMethodIfSupported<>
 
 UNINITIALIZED READ
-name=https://code.google.com/p/webrtc/issues/detail?id=2323 (4)
+name=<https://code.google.com/p/webrtc/issues/detail?id=2323 (3)>
+system call NtUserGetThreadDesktop parameter value #1
+*!webrtc::Desktop::GetThreadDesktop
+*!webrtc::ScopedThreadDesktop::ScopedThreadDesktop
+*!webrtc::ScreenCapturerWinGdi::ScreenCapturerWinGdi
+*!webrtc::ScreenCapturer::Create
+*!webrtc::ScreenCapturerTest_UseMagnifier_Test::TestBody
+*!testing::internal::HandleSehExceptionsInMethodIfSupported<>
+
+UNINITIALIZED READ
+name=<https://code.google.com/p/webrtc/issues/detail?id=2323 (4)>
+system call NtUserGetThreadDesktop parameter value #1
+*!webrtc::Desktop::GetThreadDesktop
+*!webrtc::ScopedThreadDesktop::ScopedThreadDesktop
+*!webrtc::ScreenCapturerWinMagnifier::ScreenCapturerWinMagnifier
+*!webrtc::ScreenCapturer::Create
+*!webrtc::ScreenCapturerTest_UseMagnifier_Test::TestBody
+*!testing::internal::HandleSehExceptionsInMethodIfSupported<>
+
+UNINITIALIZED READ
+name=https://code.google.com/p/webrtc/issues/detail?id=2323 (5)
 system call NtUserGetIconInfo parameter value #0
 USER32.dll!GetIconInfo
 *!webrtc::CreateMouseCursorFromHCursor
@@ -60,7 +69,7 @@
 *!testing::internal::HandleSehExceptionsInMethodIfSupported<>
 
 UNINITIALIZED READ
-name=https://code.google.com/p/webrtc/issues/detail?id=2323 (5)
+name=https://code.google.com/p/webrtc/issues/detail?id=2323 (6)
 system call NtUserGetWindowPlacement
 *!webrtc::GetCroppedWindowRect
 *!webrtc::`anonymous namespace'::WindowCapturerWin::Capture
@@ -68,7 +77,7 @@
 *!testing::internal::HandleSehExceptionsInMethodIfSupported<>
 
 UNADDRESSABLE ACCESS
-name=https://code.google.com/p/webrtc/issues/detail?id=2323 (6)
+name=https://code.google.com/p/webrtc/issues/detail?id=2323 (7)
 system call NtUserGetWindowPlacement parameter #1
 *!webrtc::GetCroppedWindowRect
 *!webrtc::`anonymous namespace'::WindowCapturerWin::Capture
diff --git a/webrtc/modules/desktop_capture/desktop_capture.gypi b/webrtc/modules/desktop_capture/desktop_capture.gypi
index 5f96745..6f4a083 100644
--- a/webrtc/modules/desktop_capture/desktop_capture.gypi
+++ b/webrtc/modules/desktop_capture/desktop_capture.gypi
@@ -69,6 +69,12 @@
         "win/scoped_gdi_object.h",
         "win/scoped_thread_desktop.cc",
         "win/scoped_thread_desktop.h",
+        "win/screen_capturer_win_gdi.cc",
+        "win/screen_capturer_win_gdi.h",
+        "win/screen_capturer_win_magnifier.cc",
+        "win/screen_capturer_win_magnifier.h",
+        "win/screen_capture_utils.cc",
+        "win/screen_capture_utils.h",
         "win/window_capture_utils.cc",
         "win/window_capture_utils.h",
         "window_capturer.cc",
diff --git a/webrtc/modules/desktop_capture/desktop_capture_options.cc b/webrtc/modules/desktop_capture/desktop_capture_options.cc
index 26044e1..105853b 100644
--- a/webrtc/modules/desktop_capture/desktop_capture_options.cc
+++ b/webrtc/modules/desktop_capture/desktop_capture_options.cc
@@ -19,6 +19,10 @@
   // XDamage is often broken, so don't use it by default.
   use_update_notifications_ = false;
 #endif
+
+#if defined(WEBRTC_WIN)
+  allow_use_magnification_api_ = false;
+#endif
 }
 
 DesktopCaptureOptions::~DesktopCaptureOptions() {}
diff --git a/webrtc/modules/desktop_capture/desktop_capture_options.h b/webrtc/modules/desktop_capture/desktop_capture_options.h
index 2a188a0..c01d3d2 100644
--- a/webrtc/modules/desktop_capture/desktop_capture_options.h
+++ b/webrtc/modules/desktop_capture/desktop_capture_options.h
@@ -66,6 +66,15 @@
     disable_effects_ = disable_effects;
   }
 
+#if defined(WEBRTC_WIN)
+  bool allow_use_magnification_api() const {
+    return allow_use_magnification_api_;
+  }
+  void set_allow_use_magnification_api(bool allow) {
+    allow_use_magnification_api_ = allow;
+  }
+#endif
+
  private:
 #if defined(USE_X11)
   scoped_refptr<SharedXDisplay> x_display_;
@@ -74,6 +83,10 @@
 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
   scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_;
 #endif
+
+#if defined(WEBRTC_WIN)
+  bool allow_use_magnification_api_;
+#endif
   bool use_update_notifications_;
   bool disable_effects_;
 };
diff --git a/webrtc/modules/desktop_capture/screen_capturer_unittest.cc b/webrtc/modules/desktop_capture/screen_capturer_unittest.cc
index 94c1f70..50ff7a2 100644
--- a/webrtc/modules/desktop_capture/screen_capturer_unittest.cc
+++ b/webrtc/modules/desktop_capture/screen_capturer_unittest.cc
@@ -106,7 +106,7 @@
   delete frame;
 }
 
-#if defined(OS_WIN)
+#if defined(WEBRTC_WIN)
 
 TEST_F(ScreenCapturerTest, UseSharedBuffers) {
   DesktopFrame* frame = NULL;
@@ -129,6 +129,20 @@
   delete frame;
 }
 
-#endif  // defined(OS_WIN)
+TEST_F(ScreenCapturerTest, UseMagnifier) {
+  DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault());
+  options.set_allow_use_magnification_api(true);
+  capturer_.reset(ScreenCapturer::Create(options));
+
+  DesktopFrame* frame = NULL;
+  EXPECT_CALL(callback_, OnCaptureCompleted(_)).WillOnce(SaveArg<0>(&frame));
+
+  capturer_->Start(&callback_);
+  capturer_->Capture(DesktopRegion());
+  ASSERT_TRUE(frame);
+  delete frame;
+}
+
+#endif  // defined(WEBRTC_WIN)
 
 }  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/screen_capturer_win.cc b/webrtc/modules/desktop_capture/screen_capturer_win.cc
index fc6ce508..5950795 100644
--- a/webrtc/modules/desktop_capture/screen_capturer_win.cc
+++ b/webrtc/modules/desktop_capture/screen_capturer_win.cc
@@ -10,451 +10,20 @@
 
 #include "webrtc/modules/desktop_capture/screen_capturer.h"
 
-#include <windows.h>
-
 #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
-#include "webrtc/modules/desktop_capture/desktop_frame.h"
-#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
-#include "webrtc/modules/desktop_capture/desktop_region.h"
-#include "webrtc/modules/desktop_capture/differ.h"
-#include "webrtc/modules/desktop_capture/mouse_cursor.h"
-#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
-#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
-#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
-#include "webrtc/modules/desktop_capture/win/cursor.h"
-#include "webrtc/modules/desktop_capture/win/desktop.h"
-#include "webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
-#include "webrtc/system_wrappers/interface/logging.h"
-#include "webrtc/system_wrappers/interface/scoped_ptr.h"
-#include "webrtc/system_wrappers/interface/tick_util.h"
+#include "webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h"
+#include "webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h"
 
 namespace webrtc {
 
-namespace {
-
-// Constants from dwmapi.h.
-const UINT DWM_EC_DISABLECOMPOSITION = 0;
-const UINT DWM_EC_ENABLECOMPOSITION = 1;
-
-typedef HRESULT (WINAPI * DwmEnableCompositionFunc)(UINT);
-
-const wchar_t kDwmapiLibraryName[] = L"dwmapi.dll";
-
-// ScreenCapturerWin captures 32bit RGB using GDI.
-//
-// ScreenCapturerWin is double-buffered as required by ScreenCapturer.
-class ScreenCapturerWin : public ScreenCapturer {
- public:
-  ScreenCapturerWin(const DesktopCaptureOptions& options);
-  virtual ~ScreenCapturerWin();
-
-  // Overridden from ScreenCapturer:
-  virtual void Start(Callback* callback) OVERRIDE;
-  virtual void Capture(const DesktopRegion& region) OVERRIDE;
-  virtual void SetMouseShapeObserver(
-      MouseShapeObserver* mouse_shape_observer) OVERRIDE;
-  virtual bool GetScreenList(ScreenList* screens) OVERRIDE;
-  virtual bool SelectScreen(ScreenId id) OVERRIDE;
-
- private:
-  // Make sure that the device contexts match the screen configuration.
-  void PrepareCaptureResources();
-
-  // Captures the current screen contents into the current buffer. Returns true
-  // if succeeded.
-  bool CaptureImage();
-
-  // Capture the current cursor shape.
-  void CaptureCursor();
-
-  // Get the rect of the currently selected screen, relative to the primary
-  // display's top-left. If the screen is disabled or disconnected, or any error
-  // happens, an empty rect is returned.
-  DesktopRect GetScreenRect();
-
-  Callback* callback_;
-  MouseShapeObserver* mouse_shape_observer_;
-  ScreenId current_screen_id_;
-  std::wstring current_device_key_;
-
-  // A thread-safe list of invalid rectangles, and the size of the most
-  // recently captured screen.
-  ScreenCapturerHelper helper_;
-
-  // Snapshot of the last cursor bitmap we sent to the client. This is used
-  // to diff against the current cursor so we only send a cursor-change
-  // message when the shape has changed.
-  MouseCursorShape last_cursor_;
-
-  ScopedThreadDesktop desktop_;
-
-  // GDI resources used for screen capture.
-  HDC desktop_dc_;
-  HDC memory_dc_;
-
-  // Queue of the frames buffers.
-  ScreenCaptureFrameQueue queue_;
-
-  // Rectangle describing the bounds of the desktop device context, relative to
-  // the primary display's top-left.
-  DesktopRect desktop_dc_rect_;
-
-  // Class to calculate the difference between two screen bitmaps.
-  scoped_ptr<Differ> differ_;
-
-  HMODULE dwmapi_library_;
-  DwmEnableCompositionFunc composition_func_;
-
-  // Used to suppress duplicate logging of SetThreadExecutionState errors.
-  bool set_thread_execution_state_failed_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWin);
-};
-
-ScreenCapturerWin::ScreenCapturerWin(const DesktopCaptureOptions& options)
-    : callback_(NULL),
-      mouse_shape_observer_(NULL),
-      current_screen_id_(kFullDesktopScreenId),
-      desktop_dc_(NULL),
-      memory_dc_(NULL),
-      dwmapi_library_(NULL),
-      composition_func_(NULL),
-      set_thread_execution_state_failed_(false) {
-  if (options.disable_effects()) {
-    // Load dwmapi.dll dynamically since it is not available on XP.
-    if (!dwmapi_library_)
-      dwmapi_library_ = LoadLibrary(kDwmapiLibraryName);
-
-    if (dwmapi_library_) {
-      composition_func_ = reinterpret_cast<DwmEnableCompositionFunc>(
-          GetProcAddress(dwmapi_library_, "DwmEnableComposition"));
-    }
-  }
-}
-
-ScreenCapturerWin::~ScreenCapturerWin() {
-  if (desktop_dc_)
-    ReleaseDC(NULL, desktop_dc_);
-  if (memory_dc_)
-    DeleteDC(memory_dc_);
-
-  // Restore Aero.
-  if (composition_func_)
-    (*composition_func_)(DWM_EC_ENABLECOMPOSITION);
-
-  if (dwmapi_library_)
-    FreeLibrary(dwmapi_library_);
-}
-
-void ScreenCapturerWin::Capture(const DesktopRegion& region) {
-  TickTime capture_start_time = TickTime::Now();
-
-  queue_.MoveToNextFrame();
-
-  // Request that the system not power-down the system, or the display hardware.
-  if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) {
-    if (!set_thread_execution_state_failed_) {
-      set_thread_execution_state_failed_ = true;
-      LOG_F(LS_WARNING) << "Failed to make system & display power assertion: "
-                        << GetLastError();
-    }
-  }
-
-  // Make sure the GDI capture resources are up-to-date.
-  PrepareCaptureResources();
-
-  // Copy screen bits to the current buffer.
-  if (!CaptureImage()) {
-    callback_->OnCaptureCompleted(NULL);
-    return;
-  }
-
-  const DesktopFrame* current_frame = queue_.current_frame();
-  const DesktopFrame* last_frame = queue_.previous_frame();
-  if (last_frame && last_frame->size().equals(current_frame->size())) {
-    // Make sure the differencer is set up correctly for these previous and
-    // current screens.
-    if (!differ_.get() ||
-        (differ_->width() != current_frame->size().width()) ||
-        (differ_->height() != current_frame->size().height()) ||
-        (differ_->bytes_per_row() != current_frame->stride())) {
-      differ_.reset(new Differ(current_frame->size().width(),
-                               current_frame->size().height(),
-                               DesktopFrame::kBytesPerPixel,
-                               current_frame->stride()));
-    }
-
-    // Calculate difference between the two last captured frames.
-    DesktopRegion region;
-    differ_->CalcDirtyRegion(last_frame->data(), current_frame->data(),
-                             &region);
-    helper_.InvalidateRegion(region);
-  } else {
-    // No previous frame is available, or the screen is resized. Invalidate the
-    // whole screen.
-    helper_.InvalidateScreen(current_frame->size());
-  }
-
-  helper_.set_size_most_recent(current_frame->size());
-
-  // Emit the current frame.
-  DesktopFrame* frame = queue_.current_frame()->Share();
-  frame->set_dpi(DesktopVector(
-      GetDeviceCaps(desktop_dc_, LOGPIXELSX),
-      GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
-  frame->mutable_updated_region()->Clear();
-  helper_.TakeInvalidRegion(frame->mutable_updated_region());
-  frame->set_capture_time_ms(
-      (TickTime::Now() - capture_start_time).Milliseconds());
-  callback_->OnCaptureCompleted(frame);
-
-  // Check for cursor shape update.
-  CaptureCursor();
-}
-
-void ScreenCapturerWin::SetMouseShapeObserver(
-      MouseShapeObserver* mouse_shape_observer) {
-  assert(!mouse_shape_observer_);
-  assert(mouse_shape_observer);
-
-  mouse_shape_observer_ = mouse_shape_observer;
-}
-
-bool ScreenCapturerWin::GetScreenList(ScreenList* screens) {
-  assert(screens->size() == 0);
-  BOOL enum_result = TRUE;
-  for (int device_index = 0; ; ++device_index) {
-    DISPLAY_DEVICE device;
-    device.cb = sizeof(device);
-    enum_result = EnumDisplayDevices(NULL, device_index, &device, 0);
-    // |enum_result| is 0 if we have enumerated all devices.
-    if (!enum_result)
-      break;
-
-    // We only care about active displays.
-    if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE))
-      continue;
-    Screen screen;
-    screen.id = device_index;
-    screens->push_back(screen);
-  }
-  return true;
-}
-
-bool ScreenCapturerWin::SelectScreen(ScreenId id) {
-  if (id == kFullDesktopScreenId) {
-    current_screen_id_ = id;
-    return true;
-  }
-  DISPLAY_DEVICE device;
-  device.cb = sizeof(device);
-  BOOL enum_result = EnumDisplayDevices(NULL, id, &device, 0);
-  if (!enum_result)
-    return false;
-
-  current_device_key_ = device.DeviceKey;
-  current_screen_id_ = id;
-  return true;
-}
-
-void ScreenCapturerWin::Start(Callback* callback) {
-  assert(!callback_);
-  assert(callback);
-
-  callback_ = callback;
-
-  // Vote to disable Aero composited desktop effects while capturing. Windows
-  // will restore Aero automatically if the process exits. This has no effect
-  // under Windows 8 or higher.  See crbug.com/124018.
-  if (composition_func_)
-    (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
-}
-
-void ScreenCapturerWin::PrepareCaptureResources() {
-  // Switch to the desktop receiving user input if different from the current
-  // one.
-  scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
-  if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
-    // Release GDI resources otherwise SetThreadDesktop will fail.
-    if (desktop_dc_) {
-      ReleaseDC(NULL, desktop_dc_);
-      desktop_dc_ = NULL;
-    }
-
-    if (memory_dc_) {
-      DeleteDC(memory_dc_);
-      memory_dc_ = NULL;
-    }
-
-    // If SetThreadDesktop() fails, the thread is still assigned a desktop.
-    // So we can continue capture screen bits, just from the wrong desktop.
-    desktop_.SetThreadDesktop(input_desktop.release());
-
-    // Re-assert our vote to disable Aero.
-    // See crbug.com/124018 and crbug.com/129906.
-    if (composition_func_ != NULL) {
-      (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
-    }
-  }
-
-  // If the display bounds have changed then recreate GDI resources.
-  // TODO(wez): Also check for pixel format changes.
-  DesktopRect screen_rect(DesktopRect::MakeXYWH(
-      GetSystemMetrics(SM_XVIRTUALSCREEN),
-      GetSystemMetrics(SM_YVIRTUALSCREEN),
-      GetSystemMetrics(SM_CXVIRTUALSCREEN),
-      GetSystemMetrics(SM_CYVIRTUALSCREEN)));
-  if (!screen_rect.equals(desktop_dc_rect_)) {
-    if (desktop_dc_) {
-      ReleaseDC(NULL, desktop_dc_);
-      desktop_dc_ = NULL;
-    }
-    if (memory_dc_) {
-      DeleteDC(memory_dc_);
-      memory_dc_ = NULL;
-    }
-    desktop_dc_rect_ = DesktopRect();
-  }
-
-  if (desktop_dc_ == NULL) {
-    assert(memory_dc_ == NULL);
-
-    // Create GDI device contexts to capture from the desktop into memory.
-    desktop_dc_ = GetDC(NULL);
-    if (!desktop_dc_)
-      abort();
-    memory_dc_ = CreateCompatibleDC(desktop_dc_);
-    if (!memory_dc_)
-      abort();
-    desktop_dc_rect_ = screen_rect;
-
-    // Make sure the frame buffers will be reallocated.
-    queue_.Reset();
-
-    helper_.ClearInvalidRegion();
-  }
-}
-
-bool ScreenCapturerWin::CaptureImage() {
-  DesktopRect screen_rect = GetScreenRect();
-  if (screen_rect.is_empty())
-    return false;
-  DesktopSize size = screen_rect.size();
-  // If the current buffer is from an older generation then allocate a new one.
-  // Note that we can't reallocate other buffers at this point, since the caller
-  // may still be reading from them.
-  if (!queue_.current_frame() ||
-      !queue_.current_frame()->size().equals(size)) {
-    assert(desktop_dc_ != NULL);
-    assert(memory_dc_ != NULL);
-
-    size_t buffer_size = size.width() * size.height() *
-        DesktopFrame::kBytesPerPixel;
-    SharedMemory* shared_memory =
-        callback_->CreateSharedMemory(buffer_size);
-    scoped_ptr<DesktopFrameWin> buffer(
-        DesktopFrameWin::Create(size, shared_memory, desktop_dc_));
-    queue_.ReplaceCurrentFrame(buffer.release());
-  }
-
-  // Select the target bitmap into the memory dc and copy the rect from desktop
-  // to memory.
-  DesktopFrameWin* current = static_cast<DesktopFrameWin*>(
-      queue_.current_frame()->GetUnderlyingFrame());
-  HGDIOBJ previous_object = SelectObject(memory_dc_, current->bitmap());
-  if (previous_object != NULL) {
-    BitBlt(memory_dc_,
-           0, 0, screen_rect.width(), screen_rect.height(),
-           desktop_dc_,
-           screen_rect.left(), screen_rect.top(),
-           SRCCOPY | CAPTUREBLT);
-
-    // Select back the previously selected object to that the device contect
-    // could be destroyed independently of the bitmap if needed.
-    SelectObject(memory_dc_, previous_object);
-  }
-  return true;
-}
-
-void ScreenCapturerWin::CaptureCursor() {
-  CURSORINFO cursor_info;
-  cursor_info.cbSize = sizeof(CURSORINFO);
-  if (!GetCursorInfo(&cursor_info)) {
-    LOG_F(LS_ERROR) << "Unable to get cursor info. Error = " << GetLastError();
-    return;
-  }
-
-  // Note that |cursor_info.hCursor| does not need to be freed.
-  scoped_ptr<MouseCursor> cursor_image(
-      CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor));
-  if (!cursor_image.get())
-    return;
-
-  scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape);
-  cursor->hotspot = cursor_image->hotspot();
-  cursor->size = cursor_image->image()->size();
-  uint8_t* current_row = cursor_image->image()->data();
-  for (int y = 0; y < cursor_image->image()->size().height(); ++y) {
-    cursor->data.append(current_row,
-                        current_row + cursor_image->image()->size().width() *
-                                        DesktopFrame::kBytesPerPixel);
-    current_row += cursor_image->image()->stride();
-  }
-
-  // Compare the current cursor with the last one we sent to the client. If
-  // they're the same, then don't bother sending the cursor again.
-  if (last_cursor_.size.equals(cursor->size) &&
-      last_cursor_.hotspot.equals(cursor->hotspot) &&
-      last_cursor_.data == cursor->data) {
-    return;
-  }
-
-  LOG(LS_VERBOSE) << "Sending updated cursor: " << cursor->size.width() << "x"
-                  << cursor->size.height();
-
-  // Record the last cursor image that we sent to the client.
-  last_cursor_ = *cursor;
-
-  if (mouse_shape_observer_)
-    mouse_shape_observer_->OnCursorShapeChanged(cursor.release());
-}
-
-DesktopRect ScreenCapturerWin::GetScreenRect() {
-  DesktopRect rect = desktop_dc_rect_;
-  if (current_screen_id_ == kFullDesktopScreenId)
-    return rect;
-
-  DISPLAY_DEVICE device;
-  device.cb = sizeof(device);
-  BOOL result = EnumDisplayDevices(NULL, current_screen_id_, &device, 0);
-  if (!result)
-    return DesktopRect();
-
-  // Verifies the device index still maps to the same display device. DeviceKey
-  // is documented as reserved, but it actually contains the registry key for
-  // the device and is unique for each monitor, while DeviceID is not.
-  if (current_device_key_ != device.DeviceKey)
-    return DesktopRect();
-
-  DEVMODE device_mode;
-  device_mode.dmSize = sizeof(device_mode);
-  device_mode.dmDriverExtra = 0;
-  result = EnumDisplaySettingsEx(
-      device.DeviceName, ENUM_CURRENT_SETTINGS, &device_mode, 0);
-  if (!result)
-    return DesktopRect();
-
-  rect = DesktopRect::MakeXYWH(device_mode.dmPosition.x,
-                               device_mode.dmPosition.y,
-                               device_mode.dmPelsWidth,
-                               device_mode.dmPelsHeight);
-  return rect;
-}
-}  // namespace
-
 // static
 ScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
-  return new ScreenCapturerWin(options);
+  scoped_ptr<ScreenCapturer> gdi_capturer(new ScreenCapturerWinGdi(options));
+
+  if (options.allow_use_magnification_api())
+    return new ScreenCapturerWinMagnifier(gdi_capturer.Pass());
+
+  return gdi_capturer.release();
 }
 
 }  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils.cc b/webrtc/modules/desktop_capture/win/screen_capture_utils.cc
new file mode 100644
index 0000000..4487e6d
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/screen_capture_utils.cc
@@ -0,0 +1,91 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
+
+#include <windows.h>
+
+namespace webrtc {
+
+bool GetScreenList(ScreenCapturer::ScreenList* screens) {
+  assert(screens->size() == 0);
+
+  BOOL enum_result = TRUE;
+  for (int device_index = 0;; ++device_index) {
+    DISPLAY_DEVICE device;
+    device.cb = sizeof(device);
+    enum_result = EnumDisplayDevices(NULL, device_index, &device, 0);
+
+    // |enum_result| is 0 if we have enumerated all devices.
+    if (!enum_result)
+      break;
+
+    // We only care about active displays.
+    if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE))
+      continue;
+
+    ScreenCapturer::Screen screen;
+    screen.id = device_index;
+    screens->push_back(screen);
+  }
+  return true;
+}
+
+bool IsScreenValid(ScreenId screen, std::wstring* device_key) {
+  if (screen == kFullDesktopScreenId) {
+    *device_key = L"";
+    return true;
+  }
+
+  DISPLAY_DEVICE device;
+  device.cb = sizeof(device);
+  BOOL enum_result = EnumDisplayDevices(NULL, screen, &device, 0);
+  if (enum_result)
+    *device_key = device.DeviceKey;
+
+  return !!enum_result;
+}
+
+DesktopRect GetScreenRect(ScreenId screen, const std::wstring& device_key) {
+  if (screen == kFullDesktopScreenId) {
+    return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN),
+                                 GetSystemMetrics(SM_YVIRTUALSCREEN),
+                                 GetSystemMetrics(SM_CXVIRTUALSCREEN),
+                                 GetSystemMetrics(SM_CYVIRTUALSCREEN));
+  }
+
+  DISPLAY_DEVICE device;
+  device.cb = sizeof(device);
+  BOOL result = EnumDisplayDevices(NULL, screen, &device, 0);
+  if (!result)
+    return DesktopRect();
+
+  // Verifies the device index still maps to the same display device, to make
+  // sure we are capturing the same device when devices are added or removed.
+  // DeviceKey is documented as reserved, but it actually contains the registry
+  // key for the device and is unique for each monitor, while DeviceID is not.
+  if (device_key != device.DeviceKey)
+    return DesktopRect();
+
+  DEVMODE device_mode;
+  device_mode.dmSize = sizeof(device_mode);
+  device_mode.dmDriverExtra = 0;
+  result = EnumDisplaySettingsEx(
+      device.DeviceName, ENUM_CURRENT_SETTINGS, &device_mode, 0);
+  if (!result)
+    return DesktopRect();
+
+  return DesktopRect::MakeXYWH(device_mode.dmPosition.x,
+                               device_mode.dmPosition.y,
+                               device_mode.dmPelsWidth,
+                               device_mode.dmPelsHeight);
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/win/screen_capture_utils.h b/webrtc/modules/desktop_capture/win/screen_capture_utils.h
new file mode 100644
index 0000000..42473e0
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/screen_capture_utils.h
@@ -0,0 +1,35 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURE_UTILS_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURE_UTILS_H_
+
+#include "webrtc/modules/desktop_capture/screen_capturer.h"
+
+namespace webrtc {
+
+// Output the list of active screens into |screens|. Returns true if succeeded,
+// or false if it fails to enumerate the display devices.
+bool GetScreenList(ScreenCapturer::ScreenList* screens);
+
+// Returns true if |screen| is a valid screen. The screen device key is
+// returned through |device_key| if the screen is valid. The device key can be
+// used in GetScreenRect to verify the screen matches the previously obtained
+// id.
+bool IsScreenValid(ScreenId screen, std::wstring* device_key);
+
+// Get the rect of the screen identified by |screen|, relative to the primary
+// display's top-left. If the screen device key does not match |device_key|, or
+// the screen does not exist, or any error happens, an empty rect is returned.
+DesktopRect GetScreenRect(ScreenId screen, const std::wstring& device_key);
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURE_UTILS_H_
diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc
new file mode 100644
index 0000000..5ab2553
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.cc
@@ -0,0 +1,322 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h"
+
+#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
+#include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
+#include "webrtc/modules/desktop_capture/desktop_region.h"
+#include "webrtc/modules/desktop_capture/differ.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor.h"
+#include "webrtc/modules/desktop_capture/win/cursor.h"
+#include "webrtc/modules/desktop_capture/win/desktop.h"
+#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
+#include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
+
+namespace webrtc {
+
+namespace {
+
+// Constants from dwmapi.h.
+const UINT DWM_EC_DISABLECOMPOSITION = 0;
+const UINT DWM_EC_ENABLECOMPOSITION = 1;
+
+const wchar_t kDwmapiLibraryName[] = L"dwmapi.dll";
+
+}  // namespace
+
+ScreenCapturerWinGdi::ScreenCapturerWinGdi(const DesktopCaptureOptions& options)
+    : callback_(NULL),
+      mouse_shape_observer_(NULL),
+      current_screen_id_(kFullDesktopScreenId),
+      desktop_dc_(NULL),
+      memory_dc_(NULL),
+      dwmapi_library_(NULL),
+      composition_func_(NULL),
+      set_thread_execution_state_failed_(false) {
+  if (options.disable_effects()) {
+    // Load dwmapi.dll dynamically since it is not available on XP.
+    if (!dwmapi_library_)
+      dwmapi_library_ = LoadLibrary(kDwmapiLibraryName);
+
+    if (dwmapi_library_) {
+      composition_func_ = reinterpret_cast<DwmEnableCompositionFunc>(
+          GetProcAddress(dwmapi_library_, "DwmEnableComposition"));
+    }
+  }
+}
+
+ScreenCapturerWinGdi::~ScreenCapturerWinGdi() {
+  if (desktop_dc_)
+    ReleaseDC(NULL, desktop_dc_);
+  if (memory_dc_)
+    DeleteDC(memory_dc_);
+
+  // Restore Aero.
+  if (composition_func_)
+    (*composition_func_)(DWM_EC_ENABLECOMPOSITION);
+
+  if (dwmapi_library_)
+    FreeLibrary(dwmapi_library_);
+}
+
+void ScreenCapturerWinGdi::Capture(const DesktopRegion& region) {
+  TickTime capture_start_time = TickTime::Now();
+
+  queue_.MoveToNextFrame();
+
+  // Request that the system not power-down the system, or the display hardware.
+  if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) {
+    if (!set_thread_execution_state_failed_) {
+      set_thread_execution_state_failed_ = true;
+      LOG_F(LS_WARNING) << "Failed to make system & display power assertion: "
+                        << GetLastError();
+    }
+  }
+
+  // Make sure the GDI capture resources are up-to-date.
+  PrepareCaptureResources();
+
+  if (!CaptureImage()) {
+    callback_->OnCaptureCompleted(NULL);
+    return;
+  }
+
+  const DesktopFrame* current_frame = queue_.current_frame();
+  const DesktopFrame* last_frame = queue_.previous_frame();
+  if (last_frame && last_frame->size().equals(current_frame->size())) {
+    // Make sure the differencer is set up correctly for these previous and
+    // current screens.
+    if (!differ_.get() ||
+        (differ_->width() != current_frame->size().width()) ||
+        (differ_->height() != current_frame->size().height()) ||
+        (differ_->bytes_per_row() != current_frame->stride())) {
+      differ_.reset(new Differ(current_frame->size().width(),
+                               current_frame->size().height(),
+                               DesktopFrame::kBytesPerPixel,
+                               current_frame->stride()));
+    }
+
+    // Calculate difference between the two last captured frames.
+    DesktopRegion region;
+    differ_->CalcDirtyRegion(last_frame->data(), current_frame->data(),
+                             &region);
+    helper_.InvalidateRegion(region);
+  } else {
+    // No previous frame is available, or the screen is resized. Invalidate the
+    // whole screen.
+    helper_.InvalidateScreen(current_frame->size());
+  }
+
+  helper_.set_size_most_recent(current_frame->size());
+
+  // Emit the current frame.
+  DesktopFrame* frame = queue_.current_frame()->Share();
+  frame->set_dpi(DesktopVector(
+      GetDeviceCaps(desktop_dc_, LOGPIXELSX),
+      GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
+  frame->mutable_updated_region()->Clear();
+  helper_.TakeInvalidRegion(frame->mutable_updated_region());
+  frame->set_capture_time_ms(
+      (TickTime::Now() - capture_start_time).Milliseconds());
+  callback_->OnCaptureCompleted(frame);
+
+  // Check for cursor shape update.
+  CaptureCursor();
+}
+
+void ScreenCapturerWinGdi::SetMouseShapeObserver(
+    MouseShapeObserver* mouse_shape_observer) {
+  assert(!mouse_shape_observer_);
+  assert(mouse_shape_observer);
+
+  mouse_shape_observer_ = mouse_shape_observer;
+}
+
+bool ScreenCapturerWinGdi::GetScreenList(ScreenList* screens) {
+  return webrtc::GetScreenList(screens);
+}
+
+bool ScreenCapturerWinGdi::SelectScreen(ScreenId id) {
+  bool valid = IsScreenValid(id, &current_device_key_);
+  if (valid)
+    current_screen_id_ = id;
+  return valid;
+}
+
+void ScreenCapturerWinGdi::Start(Callback* callback) {
+  assert(!callback_);
+  assert(callback);
+
+  callback_ = callback;
+
+  // Vote to disable Aero composited desktop effects while capturing. Windows
+  // will restore Aero automatically if the process exits. This has no effect
+  // under Windows 8 or higher.  See crbug.com/124018.
+  if (composition_func_)
+    (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
+}
+
+void ScreenCapturerWinGdi::PrepareCaptureResources() {
+  // Switch to the desktop receiving user input if different from the current
+  // one.
+  scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
+  if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
+    // Release GDI resources otherwise SetThreadDesktop will fail.
+    if (desktop_dc_) {
+      ReleaseDC(NULL, desktop_dc_);
+      desktop_dc_ = NULL;
+    }
+
+    if (memory_dc_) {
+      DeleteDC(memory_dc_);
+      memory_dc_ = NULL;
+    }
+
+    // If SetThreadDesktop() fails, the thread is still assigned a desktop.
+    // So we can continue capture screen bits, just from the wrong desktop.
+    desktop_.SetThreadDesktop(input_desktop.release());
+
+    // Re-assert our vote to disable Aero.
+    // See crbug.com/124018 and crbug.com/129906.
+    if (composition_func_ != NULL) {
+      (*composition_func_)(DWM_EC_DISABLECOMPOSITION);
+    }
+  }
+
+  // If the display bounds have changed then recreate GDI resources.
+  // TODO(wez): Also check for pixel format changes.
+  DesktopRect screen_rect(DesktopRect::MakeXYWH(
+      GetSystemMetrics(SM_XVIRTUALSCREEN),
+      GetSystemMetrics(SM_YVIRTUALSCREEN),
+      GetSystemMetrics(SM_CXVIRTUALSCREEN),
+      GetSystemMetrics(SM_CYVIRTUALSCREEN)));
+  if (!screen_rect.equals(desktop_dc_rect_)) {
+    if (desktop_dc_) {
+      ReleaseDC(NULL, desktop_dc_);
+      desktop_dc_ = NULL;
+    }
+    if (memory_dc_) {
+      DeleteDC(memory_dc_);
+      memory_dc_ = NULL;
+    }
+    desktop_dc_rect_ = DesktopRect();
+  }
+
+  if (desktop_dc_ == NULL) {
+    assert(memory_dc_ == NULL);
+
+    // Create GDI device contexts to capture from the desktop into memory.
+    desktop_dc_ = GetDC(NULL);
+    if (!desktop_dc_)
+      abort();
+    memory_dc_ = CreateCompatibleDC(desktop_dc_);
+    if (!memory_dc_)
+      abort();
+
+    desktop_dc_rect_ = screen_rect;
+
+    // Make sure the frame buffers will be reallocated.
+    queue_.Reset();
+
+    helper_.ClearInvalidRegion();
+  }
+}
+
+bool ScreenCapturerWinGdi::CaptureImage() {
+  DesktopRect screen_rect =
+      GetScreenRect(current_screen_id_, current_device_key_);
+  if (screen_rect.is_empty())
+    return false;
+
+  DesktopSize size = screen_rect.size();
+  // If the current buffer is from an older generation then allocate a new one.
+  // Note that we can't reallocate other buffers at this point, since the caller
+  // may still be reading from them.
+  if (!queue_.current_frame() ||
+      !queue_.current_frame()->size().equals(screen_rect.size())) {
+    assert(desktop_dc_ != NULL);
+    assert(memory_dc_ != NULL);
+
+    size_t buffer_size = size.width() * size.height() *
+        DesktopFrame::kBytesPerPixel;
+    SharedMemory* shared_memory = callback_->CreateSharedMemory(buffer_size);
+
+    scoped_ptr<DesktopFrame> buffer;
+    buffer.reset(
+        DesktopFrameWin::Create(size, shared_memory, desktop_dc_));
+    queue_.ReplaceCurrentFrame(buffer.release());
+  }
+
+  // Select the target bitmap into the memory dc and copy the rect from desktop
+  // to memory.
+  DesktopFrameWin* current = static_cast<DesktopFrameWin*>(
+      queue_.current_frame()->GetUnderlyingFrame());
+  HGDIOBJ previous_object = SelectObject(memory_dc_, current->bitmap());
+  if (previous_object != NULL) {
+    BitBlt(memory_dc_,
+           0, 0, screen_rect.width(), screen_rect.height(),
+           desktop_dc_,
+           screen_rect.left(), screen_rect.top(),
+           SRCCOPY | CAPTUREBLT);
+
+    // Select back the previously selected object to that the device contect
+    // could be destroyed independently of the bitmap if needed.
+    SelectObject(memory_dc_, previous_object);
+  }
+  return true;
+}
+
+void ScreenCapturerWinGdi::CaptureCursor() {
+  CURSORINFO cursor_info;
+  cursor_info.cbSize = sizeof(CURSORINFO);
+  if (!GetCursorInfo(&cursor_info)) {
+    LOG_F(LS_ERROR) << "Unable to get cursor info. Error = " << GetLastError();
+    return;
+  }
+
+  // Note that |cursor_info.hCursor| does not need to be freed.
+  scoped_ptr<MouseCursor> cursor_image(
+      CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor));
+  if (!cursor_image.get())
+    return;
+
+  scoped_ptr<MouseCursorShape> cursor(new MouseCursorShape);
+  cursor->hotspot = cursor_image->hotspot();
+  cursor->size = cursor_image->image()->size();
+  uint8_t* current_row = cursor_image->image()->data();
+  for (int y = 0; y < cursor_image->image()->size().height(); ++y) {
+    cursor->data.append(current_row,
+                        current_row + cursor_image->image()->size().width() *
+                                        DesktopFrame::kBytesPerPixel);
+    current_row += cursor_image->image()->stride();
+  }
+
+  // Compare the current cursor with the last one we sent to the client. If
+  // they're the same, then don't bother sending the cursor again.
+  if (last_cursor_.size.equals(cursor->size) &&
+      last_cursor_.hotspot.equals(cursor->hotspot) &&
+      last_cursor_.data == cursor->data) {
+    return;
+  }
+
+  LOG(LS_VERBOSE) << "Sending updated cursor: " << cursor->size.width() << "x"
+                  << cursor->size.height();
+
+  // Record the last cursor image that we sent to the client.
+  last_cursor_ = *cursor;
+
+  if (mouse_shape_observer_)
+    mouse_shape_observer_->OnCursorShapeChanged(cursor.release());
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h
new file mode 100644
index 0000000..2db87d0
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_gdi.h
@@ -0,0 +1,99 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_GDI_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_GDI_H_
+
+#include "webrtc/modules/desktop_capture/screen_capturer.h"
+
+#include <windows.h>
+
+#include "webrtc/modules/desktop_capture/mouse_cursor_shape.h"
+#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
+#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
+#include "webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+
+namespace webrtc {
+
+class Differ;
+class MouseShapeObserver;
+
+// ScreenCapturerWinGdi captures 32bit RGB using GDI.
+//
+// ScreenCapturerWinGdi is double-buffered as required by ScreenCapturer.
+class ScreenCapturerWinGdi : public ScreenCapturer {
+ public:
+  explicit ScreenCapturerWinGdi(const DesktopCaptureOptions& options);
+  virtual ~ScreenCapturerWinGdi();
+
+  // Overridden from ScreenCapturer:
+  virtual void Start(Callback* callback) OVERRIDE;
+  virtual void Capture(const DesktopRegion& region) OVERRIDE;
+  virtual void SetMouseShapeObserver(
+      MouseShapeObserver* mouse_shape_observer) OVERRIDE;
+  virtual bool GetScreenList(ScreenList* screens) OVERRIDE;
+  virtual bool SelectScreen(ScreenId id) OVERRIDE;
+
+ private:
+  typedef HRESULT (WINAPI * DwmEnableCompositionFunc)(UINT);
+
+  // Make sure that the device contexts match the screen configuration.
+  void PrepareCaptureResources();
+
+  // Captures the current screen contents into the current buffer. Returns true
+  // if succeeded.
+  bool CaptureImage();
+
+  // Capture the current cursor shape.
+  void CaptureCursor();
+
+  Callback* callback_;
+  MouseShapeObserver* mouse_shape_observer_;
+  ScreenId current_screen_id_;
+  std::wstring current_device_key_;
+
+  // A thread-safe list of invalid rectangles, and the size of the most
+  // recently captured screen.
+  ScreenCapturerHelper helper_;
+
+  // Snapshot of the last cursor bitmap we sent to the client. This is used
+  // to diff against the current cursor so we only send a cursor-change
+  // message when the shape has changed.
+  MouseCursorShape last_cursor_;
+
+  ScopedThreadDesktop desktop_;
+
+  // GDI resources used for screen capture.
+  HDC desktop_dc_;
+  HDC memory_dc_;
+
+  // Queue of the frames buffers.
+  ScreenCaptureFrameQueue queue_;
+
+  // Rectangle describing the bounds of the desktop device context, relative to
+  // the primary display's top-left.
+  DesktopRect desktop_dc_rect_;
+
+  // Class to calculate the difference between two screen bitmaps.
+  scoped_ptr<Differ> differ_;
+
+  HMODULE dwmapi_library_;
+  DwmEnableCompositionFunc composition_func_;
+
+  // Used to suppress duplicate logging of SetThreadExecutionState errors.
+  bool set_thread_execution_state_failed_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinGdi);
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_GDI_H_
diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.cc b/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
new file mode 100644
index 0000000..4ce0073
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.cc
@@ -0,0 +1,459 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h"
+
+#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
+#include "webrtc/modules/desktop_capture/desktop_frame.h"
+#include "webrtc/modules/desktop_capture/desktop_frame_win.h"
+#include "webrtc/modules/desktop_capture/desktop_region.h"
+#include "webrtc/modules/desktop_capture/differ.h"
+#include "webrtc/modules/desktop_capture/mouse_cursor.h"
+#include "webrtc/modules/desktop_capture/win/cursor.h"
+#include "webrtc/modules/desktop_capture/win/desktop.h"
+#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
+#include "webrtc/system_wrappers/interface/logging.h"
+#include "webrtc/system_wrappers/interface/tick_util.h"
+
+namespace webrtc {
+
+// kMagnifierWindowClass has to be "Magnifier" according to the Magnification
+// API. The other strings can be anything.
+static LPCTSTR kMagnifierHostClass = L"ScreenCapturerWinMagnifierHost";
+static LPCTSTR kHostWindowName = L"MagnifierHost";
+static LPCTSTR kMagnifierWindowClass = L"Magnifier";
+static LPCTSTR kMagnifierWindowName = L"MagnifierWindow";
+
+Atomic32 ScreenCapturerWinMagnifier::tls_index_(TLS_OUT_OF_INDEXES);
+
+ScreenCapturerWinMagnifier::ScreenCapturerWinMagnifier(
+    scoped_ptr<ScreenCapturer> fallback_capturer)
+    : fallback_capturer_(fallback_capturer.Pass()),
+      fallback_capturer_started_(false),
+      callback_(NULL),
+      current_screen_id_(kFullDesktopScreenId),
+      excluded_window_(NULL),
+      set_thread_execution_state_failed_(false),
+      desktop_dc_(NULL),
+      mag_lib_handle_(NULL),
+      mag_initialize_func_(NULL),
+      mag_uninitialize_func_(NULL),
+      set_window_source_func_(NULL),
+      set_window_filter_list_func_(NULL),
+      set_image_scaling_callback_func_(NULL),
+      host_window_(NULL),
+      magnifier_window_(NULL),
+      magnifier_initialized_(false),
+      magnifier_capture_succeeded_(true) {
+}
+
+ScreenCapturerWinMagnifier::~ScreenCapturerWinMagnifier() {
+  // DestroyWindow must be called before MagUninitialize. magnifier_window_ is
+  // destroyed automatically when host_window_ is destroyed.
+  if (host_window_)
+    DestroyWindow(host_window_);
+
+  if (magnifier_initialized_)
+    mag_uninitialize_func_();
+
+  if (mag_lib_handle_)
+    FreeLibrary(mag_lib_handle_);
+
+  if (desktop_dc_)
+    ReleaseDC(NULL, desktop_dc_);
+}
+
+void ScreenCapturerWinMagnifier::Start(Callback* callback) {
+  assert(!callback_);
+  assert(callback);
+  callback_ = callback;
+
+  InitializeMagnifier();
+}
+
+void ScreenCapturerWinMagnifier::Capture(const DesktopRegion& region) {
+  TickTime capture_start_time = TickTime::Now();
+
+  queue_.MoveToNextFrame();
+
+  // Request that the system not power-down the system, or the display hardware.
+  if (!SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED)) {
+    if (!set_thread_execution_state_failed_) {
+      set_thread_execution_state_failed_ = true;
+      LOG_F(LS_WARNING) << "Failed to make system & display power assertion: "
+                        << GetLastError();
+    }
+  }
+  // Switch to the desktop receiving user input if different from the current
+  // one.
+  scoped_ptr<Desktop> input_desktop(Desktop::GetInputDesktop());
+  if (input_desktop.get() != NULL && !desktop_.IsSame(*input_desktop)) {
+    // Release GDI resources otherwise SetThreadDesktop will fail.
+    if (desktop_dc_) {
+      ReleaseDC(NULL, desktop_dc_);
+      desktop_dc_ = NULL;
+    }
+    // If SetThreadDesktop() fails, the thread is still assigned a desktop.
+    // So we can continue capture screen bits, just from the wrong desktop.
+    desktop_.SetThreadDesktop(input_desktop.release());
+  }
+
+  bool succeeded = false;
+
+  // Do not try to use the magnfiier if it's capturing non-primary screen, or it
+  // failed before.
+  if (magnifier_initialized_ && IsCapturingPrimaryScreenOnly() &&
+      magnifier_capture_succeeded_) {
+    DesktopRect rect = GetScreenRect(current_screen_id_, current_device_key_);
+    CreateCurrentFrameIfNecessary(rect.size());
+
+    // CaptureImage may fail in some situations, e.g. windows8 metro mode.
+    succeeded = CaptureImage(rect);
+  }
+
+  // Defer to the fallback capturer if magnifier capturer did not work.
+  if (!succeeded) {
+    LOG_F(LS_WARNING) << "Switching to the fallback screen capturer.";
+    StartFallbackCapturer();
+    fallback_capturer_->Capture(region);
+    return;
+  }
+
+  const DesktopFrame* current_frame = queue_.current_frame();
+  const DesktopFrame* last_frame = queue_.previous_frame();
+  if (last_frame && last_frame->size().equals(current_frame->size())) {
+    // Make sure the differencer is set up correctly for these previous and
+    // current screens.
+    if (!differ_.get() || (differ_->width() != current_frame->size().width()) ||
+        (differ_->height() != current_frame->size().height()) ||
+        (differ_->bytes_per_row() != current_frame->stride())) {
+      differ_.reset(new Differ(current_frame->size().width(),
+                               current_frame->size().height(),
+                               DesktopFrame::kBytesPerPixel,
+                               current_frame->stride()));
+    }
+
+    // Calculate difference between the two last captured frames.
+    DesktopRegion region;
+    differ_->CalcDirtyRegion(
+        last_frame->data(), current_frame->data(), &region);
+    helper_.InvalidateRegion(region);
+  } else {
+    // No previous frame is available, or the screen is resized. Invalidate the
+    // whole screen.
+    helper_.InvalidateScreen(current_frame->size());
+  }
+
+  helper_.set_size_most_recent(current_frame->size());
+
+  // Emit the current frame.
+  DesktopFrame* frame = queue_.current_frame()->Share();
+  frame->set_dpi(DesktopVector(GetDeviceCaps(desktop_dc_, LOGPIXELSX),
+                               GetDeviceCaps(desktop_dc_, LOGPIXELSY)));
+  frame->mutable_updated_region()->Clear();
+  helper_.TakeInvalidRegion(frame->mutable_updated_region());
+  frame->set_capture_time_ms(
+      (TickTime::Now() - capture_start_time).Milliseconds());
+  callback_->OnCaptureCompleted(frame);
+}
+
+void ScreenCapturerWinMagnifier::SetMouseShapeObserver(
+    MouseShapeObserver* mouse_shape_observer) {
+  assert(false);  // NOTREACHED();
+}
+
+bool ScreenCapturerWinMagnifier::GetScreenList(ScreenList* screens) {
+  return webrtc::GetScreenList(screens);
+}
+
+bool ScreenCapturerWinMagnifier::SelectScreen(ScreenId id) {
+  bool valid = IsScreenValid(id, &current_device_key_);
+
+  // Set current_screen_id_ even if the fallback capturer is being used, so we
+  // can switch back to the magnifier when possible.
+  if (valid)
+    current_screen_id_ = id;
+
+  if (fallback_capturer_started_)
+    fallback_capturer_->SelectScreen(id);
+
+  return valid;
+}
+
+void ScreenCapturerWinMagnifier::SetExcludedWindow(WindowId excluded_window) {
+  excluded_window_ = (HWND)excluded_window;
+  if (excluded_window_ && magnifier_initialized_) {
+    set_window_filter_list_func_(
+        magnifier_window_, MW_FILTERMODE_EXCLUDE, 1, &excluded_window_);
+  }
+}
+
+bool ScreenCapturerWinMagnifier::CaptureImage(const DesktopRect& rect) {
+  assert(magnifier_initialized_);
+
+  // Set the magnifier control to cover the captured rect. The content of the
+  // magnifier control will be the captured image.
+  BOOL result = SetWindowPos(magnifier_window_,
+                             NULL,
+                             rect.left(), rect.top(),
+                             rect.width(), rect.height(),
+                             0);
+  if (!result) {
+    LOG_F(LS_WARNING) << "Failed to call SetWindowPos: " << GetLastError()
+                      << ". Rect = {" << rect.left() << ", " << rect.top()
+                      << ", " << rect.right() << ", " << rect.bottom() << "}";
+    return false;
+  }
+
+  magnifier_capture_succeeded_ = false;
+
+  RECT native_rect = {rect.left(), rect.top(), rect.right(), rect.bottom()};
+
+  // OnCaptured will be called via OnMagImageScalingCallback and fill in the
+  // frame before set_window_source_func_ returns.
+  result = set_window_source_func_(magnifier_window_, native_rect);
+
+  if (!result) {
+    LOG_F(LS_WARNING) << "Failed to call MagSetWindowSource: " << GetLastError()
+                      << ". Rect = {" << rect.left() << ", " << rect.top()
+                      << ", " << rect.right() << ", " << rect.bottom() << "}";
+    return false;
+  }
+
+  return magnifier_capture_succeeded_;
+}
+
+BOOL ScreenCapturerWinMagnifier::OnMagImageScalingCallback(
+    HWND hwnd,
+    void* srcdata,
+    MAGIMAGEHEADER srcheader,
+    void* destdata,
+    MAGIMAGEHEADER destheader,
+    RECT unclipped,
+    RECT clipped,
+    HRGN dirty) {
+  assert(tls_index_.Value() != TLS_OUT_OF_INDEXES);
+
+  ScreenCapturerWinMagnifier* owner =
+      reinterpret_cast<ScreenCapturerWinMagnifier*>(
+          TlsGetValue(tls_index_.Value()));
+
+  owner->OnCaptured(srcdata, srcheader);
+
+  return TRUE;
+}
+
+bool ScreenCapturerWinMagnifier::InitializeMagnifier() {
+  assert(!magnifier_initialized_);
+
+  desktop_dc_ = GetDC(NULL);
+
+  mag_lib_handle_ = LoadLibrary(L"Magnification.dll");
+  if (!mag_lib_handle_)
+    return false;
+
+  // Initialize Magnification API function pointers.
+  mag_initialize_func_ = reinterpret_cast<MagInitializeFunc>(
+      GetProcAddress(mag_lib_handle_, "MagInitialize"));
+  mag_uninitialize_func_ = reinterpret_cast<MagUninitializeFunc>(
+      GetProcAddress(mag_lib_handle_, "MagUninitialize"));
+  set_window_source_func_ = reinterpret_cast<MagSetWindowSourceFunc>(
+      GetProcAddress(mag_lib_handle_, "MagSetWindowSource"));
+  set_window_filter_list_func_ = reinterpret_cast<MagSetWindowFilterListFunc>(
+      GetProcAddress(mag_lib_handle_, "MagSetWindowFilterList"));
+  set_image_scaling_callback_func_ =
+      reinterpret_cast<MagSetImageScalingCallbackFunc>(
+          GetProcAddress(mag_lib_handle_, "MagSetImageScalingCallback"));
+
+  if (!mag_initialize_func_ || !mag_uninitialize_func_ ||
+      !set_window_source_func_ || !set_window_filter_list_func_ ||
+      !set_image_scaling_callback_func_) {
+    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
+                      << "library functions missing.";
+    return false;
+  }
+
+  BOOL result = mag_initialize_func_();
+  if (!result) {
+    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
+                      << "error from MagInitialize " << GetLastError();
+    return false;
+  }
+
+  HMODULE hInstance = NULL;
+  result = GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
+                                  GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+                              reinterpret_cast<char*>(&DefWindowProc),
+                              &hInstance);
+  if (!result) {
+    mag_uninitialize_func_();
+    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
+                      << "error from GetModulehandleExA " << GetLastError();
+    return false;
+  }
+
+  // Register the host window class. See the MSDN documentation of the
+  // Magnification API for more infomation.
+  WNDCLASSEX wcex = {};
+  wcex.cbSize = sizeof(WNDCLASSEX);
+  wcex.lpfnWndProc = &DefWindowProc;
+  wcex.hInstance = hInstance;
+  wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+  wcex.lpszClassName = kMagnifierHostClass;
+
+  // Ignore the error which may happen when the class is already registered.
+  RegisterClassEx(&wcex);
+
+  // Create the host window.
+  host_window_ = CreateWindowEx(WS_EX_LAYERED,
+                                kMagnifierHostClass,
+                                kHostWindowName,
+                                0,
+                                0, 0, 0, 0,
+                                NULL,
+                                NULL,
+                                hInstance,
+                                NULL);
+  if (!host_window_) {
+    mag_uninitialize_func_();
+    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
+                      << "error from creating host window " << GetLastError();
+    return false;
+  }
+
+  // Create the magnifier control.
+  magnifier_window_ = CreateWindow(kMagnifierWindowClass,
+                                   kMagnifierWindowName,
+                                   WS_CHILD | WS_VISIBLE,
+                                   0, 0, 0, 0,
+                                   host_window_,
+                                   NULL,
+                                   hInstance,
+                                   NULL);
+  if (!magnifier_window_) {
+    mag_uninitialize_func_();
+    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
+                      << "error from creating magnifier window "
+                      << GetLastError();
+    return false;
+  }
+
+  // Hide the host window.
+  ShowWindow(host_window_, SW_HIDE);
+
+  // Set the scaling callback to receive captured image.
+  result = set_image_scaling_callback_func_(
+      magnifier_window_,
+      &ScreenCapturerWinMagnifier::OnMagImageScalingCallback);
+  if (!result) {
+    mag_uninitialize_func_();
+    LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
+                      << "error from MagSetImageScalingCallback "
+                      << GetLastError();
+    return false;
+  }
+
+  if (excluded_window_) {
+    result = set_window_filter_list_func_(
+        magnifier_window_, MW_FILTERMODE_EXCLUDE, 1, &excluded_window_);
+    if (!result) {
+      mag_uninitialize_func_();
+      LOG_F(LS_WARNING) << "Failed to initialize ScreenCapturerWinMagnifier: "
+                        << "error from MagSetWindowFilterList "
+                        << GetLastError();
+      return false;
+    }
+  }
+
+  if (tls_index_.Value() == TLS_OUT_OF_INDEXES) {
+    // More than one threads may get here at the same time, but only one will
+    // write to tls_index_ using CompareExchange.
+    DWORD new_tls_index = TlsAlloc();
+    if (!tls_index_.CompareExchange(new_tls_index, TLS_OUT_OF_INDEXES))
+      TlsFree(new_tls_index);
+  }
+
+  assert(tls_index_.Value() != TLS_OUT_OF_INDEXES);
+  TlsSetValue(tls_index_.Value(), this);
+
+  magnifier_initialized_ = true;
+  return true;
+}
+
+void ScreenCapturerWinMagnifier::OnCaptured(void* data,
+                                            const MAGIMAGEHEADER& header) {
+  DesktopFrame* current_frame = queue_.current_frame();
+
+  // Verify the format.
+  // TODO(jiayl): support capturing sources with pixel formats other than RGBA.
+  int captured_bytes_per_pixel = header.cbSize / header.width / header.height;
+  if (header.format != GUID_WICPixelFormat32bppRGBA ||
+      header.width != static_cast<UINT>(current_frame->size().width()) ||
+      header.height != static_cast<UINT>(current_frame->size().height()) ||
+      header.stride != static_cast<UINT>(current_frame->stride()) ||
+      captured_bytes_per_pixel != DesktopFrame::kBytesPerPixel) {
+    LOG_F(LS_WARNING) << "Output format does not match the captured format: "
+                      << "width = " << header.width << ", "
+                      << "height = " << header.height << ", "
+                      << "stride = " << header.stride << ", "
+                      << "bpp = " << captured_bytes_per_pixel << ", "
+                      << "pixel format RGBA ? "
+                      << (header.format == GUID_WICPixelFormat32bppRGBA) << ".";
+    return;
+  }
+
+  // Copy the data into the frame.
+  current_frame->CopyPixelsFrom(
+      reinterpret_cast<uint8_t*>(data),
+      header.stride,
+      DesktopRect::MakeXYWH(0, 0, header.width, header.height));
+
+  magnifier_capture_succeeded_ = true;
+}
+
+void ScreenCapturerWinMagnifier::CreateCurrentFrameIfNecessary(
+    const DesktopSize& size) {
+  // If the current buffer is from an older generation then allocate a new one.
+  // Note that we can't reallocate other buffers at this point, since the caller
+  // may still be reading from them.
+  if (!queue_.current_frame() || !queue_.current_frame()->size().equals(size)) {
+    size_t buffer_size =
+        size.width() * size.height() * DesktopFrame::kBytesPerPixel;
+    SharedMemory* shared_memory = callback_->CreateSharedMemory(buffer_size);
+
+    scoped_ptr<DesktopFrame> buffer;
+    if (shared_memory) {
+      buffer.reset(new SharedMemoryDesktopFrame(
+          size, size.width() * DesktopFrame::kBytesPerPixel, shared_memory));
+    } else {
+      buffer.reset(new BasicDesktopFrame(size));
+    }
+    queue_.ReplaceCurrentFrame(buffer.release());
+  }
+}
+
+bool ScreenCapturerWinMagnifier::IsCapturingPrimaryScreenOnly() const {
+  if (current_screen_id_ != kFullDesktopScreenId)
+    return current_screen_id_ == 0;  // the primary screen is always '0'.
+
+  return GetSystemMetrics(SM_CMONITORS) == 1;
+}
+
+void ScreenCapturerWinMagnifier::StartFallbackCapturer() {
+  assert(fallback_capturer_);
+  if (!fallback_capturer_started_) {
+    fallback_capturer_started_ = true;
+
+    fallback_capturer_->Start(callback_);
+    fallback_capturer_->SelectScreen(current_screen_id_);
+  }
+}
+
+}  // namespace webrtc
diff --git a/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h b/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h
new file mode 100644
index 0000000..618386a
--- /dev/null
+++ b/webrtc/modules/desktop_capture/win/screen_capturer_win_magnifier.h
@@ -0,0 +1,159 @@
+/*
+ *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_MAGNIFIER_H_
+#define WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_MAGNIFIER_H_
+
+#include <magnification.h>
+#include <wincodec.h>
+#include <windows.h>
+
+#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
+#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
+#include "webrtc/modules/desktop_capture/screen_capturer.h"
+#include "webrtc/modules/desktop_capture/win/scoped_thread_desktop.h"
+#include "webrtc/system_wrappers/interface/atomic32.h"
+#include "webrtc/system_wrappers/interface/constructor_magic.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+
+namespace webrtc {
+
+class DesktopFrame;
+class DesktopRect;
+class Differ;
+class MouseShapeObserver;
+
+// Captures the screen using the Magnification API to support window exclusion.
+// Each capturer must run on a dedicated thread because it uses thread local
+// storage for redirecting the library callback. Also the thread must have a UI
+// message loop to handle the window messages for the magnifier window.
+class ScreenCapturerWinMagnifier : public ScreenCapturer {
+ public:
+  // |fallback_capturer| will be used to capture the screen if a non-primary
+  // screen is being captured, or the OS does not support Magnification API, or
+  // the magnifier capturer fails (e.g. in Windows8 Metro mode).
+  explicit ScreenCapturerWinMagnifier(
+      scoped_ptr<ScreenCapturer> fallback_capturer);
+  virtual ~ScreenCapturerWinMagnifier();
+
+  // Overridden from ScreenCapturer:
+  virtual void Start(Callback* callback) OVERRIDE;
+  virtual void Capture(const DesktopRegion& region) OVERRIDE;
+  virtual void SetMouseShapeObserver(
+      MouseShapeObserver* mouse_shape_observer) OVERRIDE;
+  virtual bool GetScreenList(ScreenList* screens) OVERRIDE;
+  virtual bool SelectScreen(ScreenId id) OVERRIDE;
+  virtual void SetExcludedWindow(WindowId window) OVERRIDE;
+
+ private:
+  typedef BOOL(WINAPI* MagImageScalingCallback)(HWND hwnd,
+                                                void* srcdata,
+                                                MAGIMAGEHEADER srcheader,
+                                                void* destdata,
+                                                MAGIMAGEHEADER destheader,
+                                                RECT unclipped,
+                                                RECT clipped,
+                                                HRGN dirty);
+  typedef BOOL(WINAPI* MagInitializeFunc)(void);
+  typedef BOOL(WINAPI* MagUninitializeFunc)(void);
+  typedef BOOL(WINAPI* MagSetWindowSourceFunc)(HWND hwnd, RECT rect);
+  typedef BOOL(WINAPI* MagSetWindowFilterListFunc)(HWND hwnd,
+                                                   DWORD dwFilterMode,
+                                                   int count,
+                                                   HWND* pHWND);
+  typedef BOOL(WINAPI* MagSetImageScalingCallbackFunc)(
+      HWND hwnd,
+      MagImageScalingCallback callback);
+
+  static BOOL WINAPI OnMagImageScalingCallback(HWND hwnd,
+                                               void* srcdata,
+                                               MAGIMAGEHEADER srcheader,
+                                               void* destdata,
+                                               MAGIMAGEHEADER destheader,
+                                               RECT unclipped,
+                                               RECT clipped,
+                                               HRGN dirty);
+
+  // Captures the screen within |rect| in the desktop coordinates. Returns true
+  // if succeeded.
+  // It can only capture the primary screen for now. The magnification library
+  // crashes under some screen configurations (e.g. secondary screen on top of
+  // primary screen) if it tries to capture a non-primary screen. The caller
+  // must make sure not calling it on non-primary screens.
+  bool CaptureImage(const DesktopRect& rect);
+
+  // Helper method for setting up the magnifier control. Returns true if
+  // succeeded.
+  bool InitializeMagnifier();
+
+  // Called by OnMagImageScalingCallback to output captured data.
+  void OnCaptured(void* data, const MAGIMAGEHEADER& header);
+
+  // Makes sure the current frame exists and matches |size|.
+  void CreateCurrentFrameIfNecessary(const DesktopSize& size);
+
+  // Returns true if we are capturing the primary screen only.
+  bool IsCapturingPrimaryScreenOnly() const;
+
+  // Start the fallback capturer and select the screen.
+  void StartFallbackCapturer();
+
+  static Atomic32 tls_index_;
+
+  scoped_ptr<ScreenCapturer> fallback_capturer_;
+  bool fallback_capturer_started_;
+  Callback* callback_;
+  ScreenId current_screen_id_;
+  std::wstring current_device_key_;
+  HWND excluded_window_;
+
+  // A thread-safe list of invalid rectangles, and the size of the most
+  // recently captured screen.
+  ScreenCapturerHelper helper_;
+
+  // Queue of the frames buffers.
+  ScreenCaptureFrameQueue queue_;
+
+  // Class to calculate the difference between two screen bitmaps.
+  scoped_ptr<Differ> differ_;
+
+  // Used to suppress duplicate logging of SetThreadExecutionState errors.
+  bool set_thread_execution_state_failed_;
+
+  ScopedThreadDesktop desktop_;
+
+  // Used for getting the screen dpi.
+  HDC desktop_dc_;
+
+  HMODULE mag_lib_handle_;
+  MagInitializeFunc mag_initialize_func_;
+  MagUninitializeFunc mag_uninitialize_func_;
+  MagSetWindowSourceFunc set_window_source_func_;
+  MagSetWindowFilterListFunc set_window_filter_list_func_;
+  MagSetImageScalingCallbackFunc set_image_scaling_callback_func_;
+
+  // The hidden window hosting the magnifier control.
+  HWND host_window_;
+  // The magnifier control that captures the screen.
+  HWND magnifier_window_;
+
+  // True if the magnifier control has been successfully initialized.
+  bool magnifier_initialized_;
+
+  // True if the last OnMagImageScalingCallback was called and handled
+  // successfully. Reset at the beginning of each CaptureImage call.
+  bool magnifier_capture_succeeded_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScreenCapturerWinMagnifier);
+};
+
+}  // namespace webrtc
+
+#endif  // WEBRTC_MODULES_DESKTOP_CAPTURE_WIN_SCREEN_CAPTURER_WIN_MAGNIFIER_H_