/*
 *  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/include/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:
  bool ShouldUseScreenCapturer() override;
  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_;

  AeroChecker aero_checker_;
};

bool CroppingWindowCapturerWin::ShouldUseScreenCapturer() {
  if (!rtc::IsWindows8OrLater() && aero_checker_.IsAeroEnabled())
    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
