/*
 *  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/cropping_window_capturer.h"

#include "webrtc/base/win32.h"
#include "webrtc/modules/desktop_capture/win/scoped_gdi_object.h"
#include "webrtc/modules/desktop_capture/win/screen_capture_utils.h"
#include "webrtc/modules/desktop_capture/win/window_capture_utils.h"
#include "webrtc/system_wrappers/interface/logging.h"

namespace webrtc {

namespace {

// Used to pass input/output data during the EnumWindow call for verifying if
// the selected window is on top.
struct TopWindowVerifierContext {
  TopWindowVerifierContext(HWND selected_window, HWND excluded_window)
      : selected_window(selected_window),
        excluded_window(excluded_window),
        is_top_window(false),
        selected_window_process_id(0) {}

  HWND selected_window;
  HWND excluded_window;
  bool is_top_window;
  DWORD selected_window_process_id;
  DesktopRect selected_window_rect;
};

// The function is called during EnumWindow for every window enumerated and is
// responsible for verifying if the selected window is on top.
BOOL CALLBACK TopWindowVerifier(HWND hwnd, LPARAM param) {
  TopWindowVerifierContext* context =
      reinterpret_cast<TopWindowVerifierContext*>(param);

  if (hwnd == context->selected_window) {
    context->is_top_window = true;
    return FALSE;
  }

  // Ignore the excluded window.
  if (hwnd == context->excluded_window) {
    return TRUE;
  }

  // Ignore hidden or minimized window.
  if (IsIconic(hwnd) || !IsWindowVisible(hwnd)) {
    return TRUE;
  }

  // Ignore descendant/owned windows since we want to capture them.
  // This check does not work for tooltips and context menus. Drop down menus
  // and popup windows are fine.
  if (GetAncestor(hwnd, GA_ROOTOWNER) == context->selected_window) {
    return TRUE;
  }

  // If |hwnd| has no title and belongs to the same process, assume it's a
  // tooltip or context menu from the selected window and ignore it.
  const size_t kTitleLength = 32;
  WCHAR window_title[kTitleLength];
  GetWindowText(hwnd, window_title, kTitleLength);
  if (wcsnlen_s(window_title, kTitleLength) == 0) {
    DWORD enumerated_process;
    GetWindowThreadProcessId(hwnd, &enumerated_process);
    if (!context->selected_window_process_id) {
      GetWindowThreadProcessId(context->selected_window,
                               &context->selected_window_process_id);
    }
    if (context->selected_window_process_id == enumerated_process) {
      return TRUE;
    }
  }

  // Check if the enumerated window intersects with the selected window.
  RECT enumerated_rect;
  if (!GetWindowRect(hwnd, &enumerated_rect)) {
    // Bail out if failed to get the window area.
    context->is_top_window = false;
    return FALSE;
  }

  DesktopRect intersect_rect = context->selected_window_rect;
  DesktopRect enumerated_desktop_rect =
      DesktopRect::MakeLTRB(enumerated_rect.left,
                            enumerated_rect.top,
                            enumerated_rect.right,
                            enumerated_rect.bottom);
  intersect_rect.IntersectWith(enumerated_desktop_rect);

  // If intersection is not empty, the selected window is not on top.
  if (!intersect_rect.is_empty()) {
    context->is_top_window = false;
    return FALSE;
  }
  // Otherwise, keep enumerating.
  return TRUE;
}

class CroppingWindowCapturerWin : public CroppingWindowCapturer {
 public:
  CroppingWindowCapturerWin(
      const DesktopCaptureOptions& options)
      : CroppingWindowCapturer(options) {}

 private:
  virtual bool ShouldUseScreenCapturer() OVERRIDE;
  virtual DesktopRect GetWindowRectInVirtualScreen() OVERRIDE;

  // The region from GetWindowRgn in the desktop coordinate if the region is
  // rectangular, or the rect from GetWindowRect if the region is not set.
  DesktopRect window_region_rect_;
};

bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() {
  if (!rtc::IsWindows8OrLater())
    return false;

  // Check if the window is a translucent layered window.
  HWND selected = reinterpret_cast<HWND>(selected_window());
  LONG window_ex_style = GetWindowLong(selected, GWL_EXSTYLE);
  if (window_ex_style & WS_EX_LAYERED) {
    COLORREF color_ref_key = 0;
    BYTE alpha = 0;
    DWORD flags = 0;

    // GetLayeredWindowAttributes fails if the window was setup with
    // UpdateLayeredWindow. We have no way to know the opacity of the window in
    // that case. This happens for Stiky Note (crbug/412726).
    if (!GetLayeredWindowAttributes(selected, &color_ref_key, &alpha, &flags))
      return false;

    // UpdateLayeredWindow is the only way to set per-pixel alpha and will cause
    // the previous GetLayeredWindowAttributes to fail. So we only need to check
    // the window wide color key or alpha.
    if ((flags & LWA_COLORKEY) || ((flags & LWA_ALPHA) && (alpha < 255)))
      return false;
  }

  TopWindowVerifierContext context(
      selected, reinterpret_cast<HWND>(excluded_window()));

  RECT selected_window_rect;
  if (!GetWindowRect(selected, &selected_window_rect)) {
    return false;
  }
  context.selected_window_rect = DesktopRect::MakeLTRB(
      selected_window_rect.left,
      selected_window_rect.top,
      selected_window_rect.right,
      selected_window_rect.bottom);

  // Get the window region and check if it is rectangular.
  win::ScopedGDIObject<HRGN, win::DeleteObjectTraits<HRGN> >
      scoped_hrgn(CreateRectRgn(0, 0, 0, 0));
  int region_type = GetWindowRgn(selected, scoped_hrgn.Get());

  // Do not use the screen capturer if the region is empty or not rectangular.
  if (region_type == COMPLEXREGION || region_type == NULLREGION)
    return false;

  if (region_type == SIMPLEREGION) {
    RECT region_rect;
    GetRgnBox(scoped_hrgn.Get(), &region_rect);
    DesktopRect rgn_rect =
        DesktopRect::MakeLTRB(region_rect.left,
                              region_rect.top,
                              region_rect.right,
                              region_rect.bottom);
    rgn_rect.Translate(context.selected_window_rect.left(),
                       context.selected_window_rect.top());
    context.selected_window_rect.IntersectWith(rgn_rect);
  }
  window_region_rect_ = context.selected_window_rect;

  // Check if the window is occluded by any other window, excluding the child
  // windows, context menus, and |excluded_window_|.
  EnumWindows(&TopWindowVerifier, reinterpret_cast<LPARAM>(&context));
  return context.is_top_window;
}

DesktopRect CroppingWindowCapturerWin::GetWindowRectInVirtualScreen() {
  DesktopRect original_rect;
  DesktopRect window_rect;
  HWND hwnd = reinterpret_cast<HWND>(selected_window());
  if (!GetCroppedWindowRect(hwnd, &window_rect, &original_rect)) {
    LOG(LS_WARNING) << "Failed to get window info: " << GetLastError();
    return window_rect;
  }
  window_rect.IntersectWith(window_region_rect_);

  // Convert |window_rect| to be relative to the top-left of the virtual screen.
  DesktopRect screen_rect(GetScreenRect(kFullDesktopScreenId, L""));
  window_rect.IntersectWith(screen_rect);
  window_rect.Translate(-screen_rect.left(), -screen_rect.top());
  return window_rect;
}

}  // namespace

// static
WindowCapturer*
CroppingWindowCapturer::Create(const DesktopCaptureOptions& options) {
  return new CroppingWindowCapturerWin(options);
}

}  // namespace webrtc
