summaryrefslogtreecommitdiffstats
path: root/app/win
diff options
context:
space:
mode:
authorbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-31 20:39:02 +0000
committerbrettw@google.com <brettw@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-31 20:39:02 +0000
commitfd85ad650d68309b965dbc9f3d6823cf2754349c (patch)
tree28b98629e02b2e05ec74272146f249ca62a164da /app/win
parentce072a7181ea5d58133e33654133236f5d9f5551 (diff)
downloadchromium_src-fd85ad650d68309b965dbc9f3d6823cf2754349c.zip
chromium_src-fd85ad650d68309b965dbc9f3d6823cf2754349c.tar.gz
chromium_src-fd85ad650d68309b965dbc9f3d6823cf2754349c.tar.bz2
Move app/win_util to app/win and fix the namespace usage.
Split out the two classes: ScopedComInitializer and ScopedCOMem (which I renamed) to separate files. I removed the win_util_path file which had one function in it and moved the function to win_util. Somehow, this was getting picked up by the nacl64 build and the call in sandbox_policy was then not being defined. I just implemented the function in-plcae since it's just a simple wrapper around a Windows API call. TEST=it compiles BUG=none Review URL: http://codereview.chromium.org/6013009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@70343 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'app/win')
-rw-r--r--app/win/scoped_co_mem.h49
-rw-r--r--app/win/scoped_com_initializer.h60
-rw-r--r--app/win/win_util.cc326
-rw-r--r--app/win/win_util.h114
-rw-r--r--app/win/win_util_unittest.cc59
5 files changed, 608 insertions, 0 deletions
diff --git a/app/win/scoped_co_mem.h b/app/win/scoped_co_mem.h
new file mode 100644
index 0000000..a6017fa
--- /dev/null
+++ b/app/win/scoped_co_mem.h
@@ -0,0 +1,49 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef APP_WIN_SCOPED_CO_MEM_H_
+#define APP_WIN_SCOPED_CO_MEM_H_
+#pragma once
+
+#include <objbase.h>
+
+#include "base/basictypes.h"
+
+namespace app {
+namespace win {
+
+// Simple scoped memory releaser class for COM allocated memory.
+// Example:
+// app::win::ScopedCoMem<ITEMIDLIST> file_item;
+// SHGetSomeInfo(&file_item, ...);
+// ...
+// return; <-- memory released
+template<typename T>
+class ScopedCoMem {
+ public:
+ explicit ScopedCoMem() : mem_ptr_(NULL) {}
+
+ ~ScopedCoMem() {
+ if (mem_ptr_)
+ CoTaskMemFree(mem_ptr_);
+ }
+
+ T** operator&() { // NOLINT
+ return &mem_ptr_;
+ }
+
+ operator T*() {
+ return mem_ptr_;
+ }
+
+ private:
+ T* mem_ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCoMem);
+};
+
+} // namespace win
+} // namespace app
+
+#endif // APP_WIN_SCOPED_CO_MEM_H_
diff --git a/app/win/scoped_com_initializer.h b/app/win/scoped_com_initializer.h
new file mode 100644
index 0000000..3a2cf55
--- /dev/null
+++ b/app/win/scoped_com_initializer.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef APP_WIN_SCOPED_COM_INITIALIZER_H_
+#define APP_WIN_SCOPED_COM_INITIALIZER_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+
+#if defined(OS_WIN)
+
+#include <objbase.h>
+
+namespace app {
+namespace win {
+
+// Initializes COM in the constructor (STA), and uninitializes COM in the
+// destructor.
+class ScopedCOMInitializer {
+ public:
+ ScopedCOMInitializer() : hr_(CoInitialize(NULL)) {
+ }
+
+ ScopedCOMInitializer::~ScopedCOMInitializer() {
+ if (SUCCEEDED(hr_))
+ CoUninitialize();
+ }
+
+ private:
+ HRESULT hr_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer);
+};
+
+} // namespace win
+} // namespace app
+
+#else
+
+namespace app {
+namespace win {
+
+// Do-nothing class for other platforms.
+class ScopedCOMInitializer {
+ public:
+ ScopedCOMInitializer() {}
+ ~ScopedCOMInitializer() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedCOMInitializer);
+};
+
+} // namespace win
+} // namespace app
+
+#endif
+
+#endif // APP_WIN_SCOPED_COM_INITIALIZER_H_
diff --git a/app/win/win_util.cc b/app/win/win_util.cc
new file mode 100644
index 0000000..f1ac107
--- /dev/null
+++ b/app/win/win_util.cc
@@ -0,0 +1,326 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "app/win/win_util.h"
+
+#include <commdlg.h>
+#include <shellapi.h>
+
+#include <algorithm>
+
+#include "app/l10n_util.h"
+#include "app/l10n_util_win.h"
+#include "base/base_switches.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/i18n/rtl.h"
+#include "base/logging.h"
+#include "base/scoped_handle.h"
+#include "base/scoped_handle_win.h"
+#include "base/string_util.h"
+#include "base/win/scoped_gdi_object.h"
+#include "base/win/scoped_hdc.h"
+#include "base/win/win_util.h"
+#include "gfx/codec/png_codec.h"
+#include "gfx/font.h"
+#include "gfx/gdi_util.h"
+
+namespace app {
+namespace win {
+
+const int kAutoHideTaskbarThicknessPx = 2;
+
+string16 FormatSystemTime(const SYSTEMTIME& time, const string16& format) {
+ // If the format string is empty, just use the default format.
+ LPCTSTR format_ptr = NULL;
+ if (!format.empty())
+ format_ptr = format.c_str();
+
+ int buffer_size = GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &time, format_ptr,
+ NULL, 0);
+
+ string16 output;
+ GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &time, format_ptr,
+ WriteInto(&output, buffer_size), buffer_size);
+
+ return output;
+}
+
+string16 FormatSystemDate(const SYSTEMTIME& date, const string16& format) {
+ // If the format string is empty, just use the default format.
+ LPCTSTR format_ptr = NULL;
+ if (!format.empty())
+ format_ptr = format.c_str();
+
+ int buffer_size = GetDateFormat(LOCALE_USER_DEFAULT, NULL, &date, format_ptr,
+ NULL, 0);
+
+ string16 output;
+ GetDateFormat(LOCALE_USER_DEFAULT, NULL, &date, format_ptr,
+ WriteInto(&output, buffer_size), buffer_size);
+
+ return output;
+}
+
+bool ConvertToLongPath(const string16& short_path,
+ string16* long_path) {
+ wchar_t long_path_buf[MAX_PATH];
+ DWORD return_value = GetLongPathName(short_path.c_str(), long_path_buf,
+ MAX_PATH);
+ if (return_value != 0 && return_value < MAX_PATH) {
+ *long_path = long_path_buf;
+ return true;
+ }
+
+ return false;
+}
+
+bool IsDoubleClick(const POINT& origin,
+ const POINT& current,
+ DWORD elapsed_time) {
+ // The CXDOUBLECLK and CYDOUBLECLK system metrics describe the width and
+ // height of a rectangle around the origin position, inside of which clicks
+ // within the double click time are considered double clicks.
+ return (elapsed_time <= GetDoubleClickTime()) &&
+ (abs(current.x - origin.x) <= (GetSystemMetrics(SM_CXDOUBLECLK) / 2)) &&
+ (abs(current.y - origin.y) <= (GetSystemMetrics(SM_CYDOUBLECLK) / 2));
+}
+
+bool IsDrag(const POINT& origin, const POINT& current) {
+ // The CXDRAG and CYDRAG system metrics describe the width and height of a
+ // rectangle around the origin position, inside of which motion is not
+ // considered a drag.
+ return (abs(current.x - origin.x) > (GetSystemMetrics(SM_CXDRAG) / 2)) ||
+ (abs(current.y - origin.y) > (GetSystemMetrics(SM_CYDRAG) / 2));
+}
+
+bool EdgeHasTopmostAutoHideTaskbar(UINT edge, HMONITOR monitor) {
+ APPBARDATA taskbar_data = { 0 };
+ taskbar_data.cbSize = sizeof APPBARDATA;
+ taskbar_data.uEdge = edge;
+ HWND taskbar = reinterpret_cast<HWND>(SHAppBarMessage(ABM_GETAUTOHIDEBAR,
+ &taskbar_data));
+ return ::IsWindow(taskbar) && (monitor != NULL) &&
+ (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONULL) == monitor) &&
+ (GetWindowLong(taskbar, GWL_EXSTYLE) & WS_EX_TOPMOST);
+}
+
+HANDLE GetSectionFromProcess(HANDLE section, HANDLE process, bool read_only) {
+ HANDLE valid_section = NULL;
+ DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ;
+ if (!read_only)
+ access |= FILE_MAP_WRITE;
+ DuplicateHandle(process, section, GetCurrentProcess(), &valid_section, access,
+ FALSE, 0);
+ return valid_section;
+}
+
+HANDLE GetSectionForProcess(HANDLE section, HANDLE process, bool read_only) {
+ HANDLE valid_section = NULL;
+ DWORD access = STANDARD_RIGHTS_REQUIRED | FILE_MAP_READ;
+ if (!read_only)
+ access |= FILE_MAP_WRITE;
+ DuplicateHandle(GetCurrentProcess(), section, process, &valid_section, access,
+ FALSE, 0);
+ return valid_section;
+}
+
+void EnsureRectIsVisibleInRect(const gfx::Rect& parent_rect,
+ gfx::Rect* child_rect,
+ int padding) {
+ DCHECK(child_rect);
+
+ // We use padding here because it allows some of the original web page to
+ // bleed through around the edges.
+ int twice_padding = padding * 2;
+
+ // FIRST, clamp width and height so we don't open child windows larger than
+ // the containing parent.
+ if (child_rect->width() > (parent_rect.width() + twice_padding))
+ child_rect->set_width(std::max(0, parent_rect.width() - twice_padding));
+ if (child_rect->height() > parent_rect.height() + twice_padding)
+ child_rect->set_height(std::max(0, parent_rect.height() - twice_padding));
+
+ // SECOND, clamp x,y position to padding,padding so we don't position child
+ // windows in hyperspace.
+ // TODO(mpcomplete): I don't see what the second check in each 'if' does that
+ // isn't handled by the LAST set of 'ifs'. Maybe we can remove it.
+ if (child_rect->x() < parent_rect.x() ||
+ child_rect->x() > parent_rect.right()) {
+ child_rect->set_x(parent_rect.x() + padding);
+ }
+ if (child_rect->y() < parent_rect.y() ||
+ child_rect->y() > parent_rect.bottom()) {
+ child_rect->set_y(parent_rect.y() + padding);
+ }
+
+ // LAST, nudge the window back up into the client area if its x,y position is
+ // within the parent bounds but its width/height place it off-screen.
+ if (child_rect->bottom() > parent_rect.bottom())
+ child_rect->set_y(parent_rect.bottom() - child_rect->height() - padding);
+ if (child_rect->right() > parent_rect.right())
+ child_rect->set_x(parent_rect.right() - child_rect->width() - padding);
+}
+
+gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect) {
+ RECT p_rect = rect.ToRECT();
+ HMONITOR monitor = MonitorFromRect(&p_rect, MONITOR_DEFAULTTONEAREST);
+ if (monitor) {
+ MONITORINFO mi = {0};
+ mi.cbSize = sizeof(mi);
+ GetMonitorInfo(monitor, &mi);
+ return gfx::Rect(mi.rcWork);
+ }
+ NOTREACHED();
+ return gfx::Rect();
+}
+
+bool IsNumPadDigit(int key_code, bool extended_key) {
+ if (key_code >= VK_NUMPAD0 && key_code <= VK_NUMPAD9)
+ return true;
+
+ // Check for num pad keys without NumLock.
+ // Note: there is no easy way to know if a the key that was pressed comes from
+ // the num pad or the rest of the keyboard. Investigating how
+ // TranslateMessage() generates the WM_KEYCHAR from an
+ // ALT + <NumPad sequences> it appears it looks at the extended key flag
+ // (which is on if the key pressed comes from one of the 3 clusters to
+ // the left of the numeric keypad). So we use it as well.
+ return !extended_key &&
+ ((key_code >= VK_PRIOR && key_code <= VK_DOWN) || // All keys but 5
+ // and 0.
+ (key_code == VK_CLEAR) || // Key 5.
+ (key_code == VK_INSERT)); // Key 0.
+}
+
+void GrabWindowSnapshot(HWND window_handle,
+ std::vector<unsigned char>* png_representation) {
+ // Create a memory DC that's compatible with the window.
+ HDC window_hdc = GetWindowDC(window_handle);
+ base::win::ScopedHDC mem_hdc(CreateCompatibleDC(window_hdc));
+
+ // Create a DIB that's the same size as the window.
+ RECT content_rect = {0, 0, 0, 0};
+ ::GetWindowRect(window_handle, &content_rect);
+ content_rect.right++; // Match what PrintWindow wants.
+ int width = content_rect.right - content_rect.left;
+ int height = content_rect.bottom - content_rect.top;
+ BITMAPINFOHEADER hdr;
+ gfx::CreateBitmapHeader(width, height, &hdr);
+ unsigned char *bit_ptr = NULL;
+ ScopedBitmap bitmap(CreateDIBSection(mem_hdc,
+ reinterpret_cast<BITMAPINFO*>(&hdr),
+ DIB_RGB_COLORS,
+ reinterpret_cast<void **>(&bit_ptr),
+ NULL, 0));
+
+ SelectObject(mem_hdc, bitmap);
+ // Clear the bitmap to white (so that rounded corners on windows
+ // show up on a white background, and strangely-shaped windows
+ // look reasonable). Not capturing an alpha mask saves a
+ // bit of space.
+ PatBlt(mem_hdc, 0, 0, width, height, WHITENESS);
+ // Grab a copy of the window
+ // First, see if PrintWindow is defined (it's not in Windows 2000).
+ typedef BOOL (WINAPI *PrintWindowPointer)(HWND, HDC, UINT);
+ PrintWindowPointer print_window =
+ reinterpret_cast<PrintWindowPointer>(
+ GetProcAddress(GetModuleHandle(L"User32.dll"), "PrintWindow"));
+
+ // If PrintWindow is defined, use it. It will work on partially
+ // obscured windows, and works better for out of process sub-windows.
+ // Otherwise grab the bits we can get with BitBlt; it's better
+ // than nothing and will work fine in the average case (window is
+ // completely on screen).
+ if (print_window)
+ (*print_window)(window_handle, mem_hdc, 0);
+ else
+ BitBlt(mem_hdc, 0, 0, width, height, window_hdc, 0, 0, SRCCOPY);
+
+ // We now have a copy of the window contents in a DIB, so
+ // encode it into a useful format for posting to the bug report
+ // server.
+ gfx::PNGCodec::Encode(bit_ptr, gfx::PNGCodec::FORMAT_BGRA,
+ width, height, width * 4, true,
+ png_representation);
+
+ ReleaseDC(window_handle, window_hdc);
+}
+
+bool IsWindowActive(HWND hwnd) {
+ WINDOWINFO info;
+ return ::GetWindowInfo(hwnd, &info) &&
+ ((info.dwWindowStatus & WS_ACTIVECAPTION) != 0);
+}
+
+bool IsReservedName(const string16& filename) {
+ // This list is taken from the MSDN article "Naming a file"
+ // http://msdn2.microsoft.com/en-us/library/aa365247(VS.85).aspx
+ // I also added clock$ because GetSaveFileName seems to consider it as a
+ // reserved name too.
+ static const wchar_t* const known_devices[] = {
+ L"con", L"prn", L"aux", L"nul", L"com1", L"com2", L"com3", L"com4", L"com5",
+ L"com6", L"com7", L"com8", L"com9", L"lpt1", L"lpt2", L"lpt3", L"lpt4",
+ L"lpt5", L"lpt6", L"lpt7", L"lpt8", L"lpt9", L"clock$"
+ };
+ string16 filename_lower = StringToLowerASCII(filename);
+
+ for (int i = 0; i < arraysize(known_devices); ++i) {
+ // Exact match.
+ if (filename_lower == known_devices[i])
+ return true;
+ // Starts with "DEVICE.".
+ if (filename_lower.find(string16(known_devices[i]) + L".") == 0)
+ return true;
+ }
+
+ static const wchar_t* const magic_names[] = {
+ // These file names are used by the "Customize folder" feature of the shell.
+ L"desktop.ini",
+ L"thumbs.db",
+ };
+
+ for (int i = 0; i < arraysize(magic_names); ++i) {
+ if (filename_lower == magic_names[i])
+ return true;
+ }
+
+ return false;
+}
+
+// In addition to passing the RTL flags to ::MessageBox if we are running in an
+// RTL locale, we need to make sure that LTR strings are rendered correctly by
+// adding the appropriate Unicode directionality marks.
+int MessageBox(HWND hwnd,
+ const string16& text,
+ const string16& caption,
+ UINT flags) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoMessageBox))
+ return IDOK;
+
+ UINT actual_flags = flags;
+ if (base::i18n::IsRTL())
+ actual_flags |= MB_RIGHT | MB_RTLREADING;
+
+ string16 localized_text = text;
+ base::i18n::AdjustStringForLocaleDirection(&localized_text);
+ const wchar_t* text_ptr = localized_text.c_str();
+
+ string16 localized_caption = caption;
+ base::i18n::AdjustStringForLocaleDirection(&localized_caption);
+ const wchar_t* caption_ptr = localized_caption.c_str();
+
+ return ::MessageBox(hwnd, text_ptr, caption_ptr, actual_flags);
+}
+
+gfx::Font GetWindowTitleFont() {
+ NONCLIENTMETRICS ncm;
+ base::win::GetNonClientMetrics(&ncm);
+ l10n_util::AdjustUIFont(&(ncm.lfCaptionFont));
+ base::win::ScopedHFONT caption_font(CreateFontIndirect(&(ncm.lfCaptionFont)));
+ return gfx::Font(caption_font);
+}
+
+} // namespace win
+} // namespace app
diff --git a/app/win/win_util.h b/app/win/win_util.h
new file mode 100644
index 0000000..71b0f78
--- /dev/null
+++ b/app/win/win_util.h
@@ -0,0 +1,114 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef APP_WIN_WIN_UTIL_H_
+#define APP_WIN_WIN_UTIL_H_
+#pragma once
+
+#include <windows.h>
+
+#include <vector>
+
+#include "base/string16.h"
+
+class FilePath;
+
+namespace gfx {
+class Font;
+class Rect;
+}
+
+namespace app {
+namespace win {
+
+// Creates a string interpretation of the time of day represented by the given
+// SYSTEMTIME that's appropriate for the user's default locale.
+// Format can be an empty string (for the default format), or a "format picture"
+// as specified in the Windows documentation for GetTimeFormat().
+string16 FormatSystemTime(const SYSTEMTIME& time,
+ const string16& format);
+
+// Creates a string interpretation of the date represented by the given
+// SYSTEMTIME that's appropriate for the user's default locale.
+// Format can be an empty string (for the default format), or a "format picture"
+// as specified in the Windows documentation for GetDateFormat().
+string16 FormatSystemDate(const SYSTEMTIME& date,
+ const string16& format);
+
+// Returns the long path name given a short path name. A short path name
+// is a path that follows the 8.3 convention and has ~x in it. If the
+// path is already a long path name, the function returns the current
+// path without modification.
+bool ConvertToLongPath(const string16& short_path, string16* long_path);
+
+// Returns true if the current point is close enough to the origin point in
+// space and time that it would be considered a double click.
+bool IsDoubleClick(const POINT& origin,
+ const POINT& current,
+ DWORD elapsed_time);
+
+// Returns true if the current point is far enough from the origin that it
+// would be considered a drag.
+bool IsDrag(const POINT& origin, const POINT& current);
+
+// Returns true if edge |edge| (one of ABE_LEFT, TOP, RIGHT, or BOTTOM) of
+// monitor |monitor| has an auto-hiding taskbar that's always-on-top.
+bool EdgeHasTopmostAutoHideTaskbar(UINT edge, HMONITOR monitor);
+
+// Duplicates a section handle from another process to the current process.
+// Returns the new valid handle if the function succeed. NULL otherwise.
+HANDLE GetSectionFromProcess(HANDLE section, HANDLE process, bool read_only);
+
+// Duplicates a section handle from the current process for use in another
+// process. Returns the new valid handle or NULL on failure.
+HANDLE GetSectionForProcess(HANDLE section, HANDLE process, bool read_only);
+
+// Adjusts the value of |child_rect| if necessary to ensure that it is
+// completely visible within |parent_rect|.
+void EnsureRectIsVisibleInRect(const gfx::Rect& parent_rect,
+ gfx::Rect* child_rect,
+ int padding);
+
+// Returns the bounds for the monitor that contains the largest area of
+// intersection with the specified rectangle.
+gfx::Rect GetMonitorBoundsForRect(const gfx::Rect& rect);
+
+// Returns true if the virtual key code is a digit coming from the numeric
+// keypad (with or without NumLock on). |extended_key| should be set to the
+// extended key flag specified in the WM_KEYDOWN/UP where the |key_code|
+// originated.
+bool IsNumPadDigit(int key_code, bool extended_key);
+
+// Grabs a snapshot of the designated window and stores a PNG representation
+// into a byte vector.
+void GrabWindowSnapshot(HWND window_handle,
+ std::vector<unsigned char>* png_representation);
+
+// Returns whether the specified window is the current active window.
+bool IsWindowActive(HWND hwnd);
+
+// Returns whether the specified file name is a reserved name on windows.
+// This includes names like "com2.zip" (which correspond to devices) and
+// desktop.ini and thumbs.db which have special meaning to the windows shell.
+bool IsReservedName(const string16& filename);
+
+// A wrapper around Windows' MessageBox function. Using a Chrome specific
+// MessageBox function allows us to control certain RTL locale flags so that
+// callers don't have to worry about adding these flags when running in a
+// right-to-left locale.
+int MessageBox(HWND hwnd,
+ const string16& text,
+ const string16& caption,
+ UINT flags);
+
+// Returns the system set window title font.
+gfx::Font GetWindowTitleFont();
+
+// The thickness of an auto-hide taskbar in pixels.
+extern const int kAutoHideTaskbarThicknessPx;
+
+} // namespace win
+} // namespace app
+
+#endif // APP_WIN_WIN_UTIL_H_
diff --git a/app/win/win_util_unittest.cc b/app/win/win_util_unittest.cc
new file mode 100644
index 0000000..0dc4568
--- /dev/null
+++ b/app/win/win_util_unittest.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "app/win/win_util.h"
+#include "gfx/rect.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace app {
+namespace win {
+
+TEST(WinUtilTest, EnsureRectIsVisibleInRect) {
+ gfx::Rect parent_rect(0, 0, 500, 400);
+
+ {
+ // Child rect x < 0
+ gfx::Rect child_rect(-50, 20, 100, 100);
+ EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
+ EXPECT_EQ(gfx::Rect(10, 20, 100, 100), child_rect);
+ }
+
+ {
+ // Child rect y < 0
+ gfx::Rect child_rect(20, -50, 100, 100);
+ EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
+ EXPECT_EQ(gfx::Rect(20, 10, 100, 100), child_rect);
+ }
+
+ {
+ // Child rect right > parent_rect.right
+ gfx::Rect child_rect(450, 20, 100, 100);
+ EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
+ EXPECT_EQ(gfx::Rect(390, 20, 100, 100), child_rect);
+ }
+
+ {
+ // Child rect bottom > parent_rect.bottom
+ gfx::Rect child_rect(20, 350, 100, 100);
+ EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
+ EXPECT_EQ(gfx::Rect(20, 290, 100, 100), child_rect);
+ }
+
+ {
+ // Child rect width > parent_rect.width
+ gfx::Rect child_rect(20, 20, 700, 100);
+ EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
+ EXPECT_EQ(gfx::Rect(20, 20, 480, 100), child_rect);
+ }
+
+ {
+ // Child rect height > parent_rect.height
+ gfx::Rect child_rect(20, 20, 100, 700);
+ EnsureRectIsVisibleInRect(parent_rect, &child_rect, 10);
+ EXPECT_EQ(gfx::Rect(20, 20, 100, 380), child_rect);
+ }
+}
+
+} // namespace win
+} // namespace app