diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/aura/remote_root_window_host_win.cc | 4 | ||||
-rw-r--r-- | ui/aura/remote_root_window_host_win.h | 1 | ||||
-rw-r--r-- | ui/aura/root_window.cc | 1 | ||||
-rw-r--r-- | ui/aura/root_window_host.h | 3 | ||||
-rw-r--r-- | ui/aura/root_window_host_linux.cc | 32 | ||||
-rw-r--r-- | ui/aura/root_window_host_linux.h | 1 | ||||
-rw-r--r-- | ui/aura/root_window_host_win.cc | 4 | ||||
-rw-r--r-- | ui/aura/root_window_host_win.h | 1 | ||||
-rw-r--r-- | ui/base/touch/touch_factory.cc | 26 | ||||
-rw-r--r-- | ui/base/x/device_list_cache_x.cc | 61 | ||||
-rw-r--r-- | ui/base/x/device_list_cache_x.h | 63 | ||||
-rw-r--r-- | ui/base/x/events_x.cc | 24 | ||||
-rw-r--r-- | ui/base/x/valuators.cc | 12 | ||||
-rw-r--r-- | ui/ui.gyp | 2 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc | 4 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_root_window_host_linux.h | 1 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_root_window_host_win.cc | 3 | ||||
-rw-r--r-- | ui/views/widget/desktop_aura/desktop_root_window_host_win.h | 1 |
18 files changed, 209 insertions, 35 deletions
diff --git a/ui/aura/remote_root_window_host_win.cc b/ui/aura/remote_root_window_host_win.cc index fefb127..773e4fe 100644 --- a/ui/aura/remote_root_window_host_win.cc +++ b/ui/aura/remote_root_window_host_win.cc @@ -126,6 +126,10 @@ bool RemoteRootWindowHostWin::GrabSnapshot( void RemoteRootWindowHostWin::UnConfineCursor() { } +void RemoteRootWindowHostWin::OnCursorVisibilityChanged(bool show) { + NOTIMPLEMENTED(); +} + void RemoteRootWindowHostWin::MoveCursorTo(const gfx::Point& location) { } diff --git a/ui/aura/remote_root_window_host_win.h b/ui/aura/remote_root_window_host_win.h index 7227d7b0..a01d489 100644 --- a/ui/aura/remote_root_window_host_win.h +++ b/ui/aura/remote_root_window_host_win.h @@ -60,6 +60,7 @@ class AURA_EXPORT RemoteRootWindowHostWin : public RootWindowHost { virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; virtual bool ConfineCursorToRootWindow() OVERRIDE; virtual void UnConfineCursor() OVERRIDE; + virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE; virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds, diff --git a/ui/aura/root_window.cc b/ui/aura/root_window.cc index 33347cb..4c7c6dd 100644 --- a/ui/aura/root_window.cc +++ b/ui/aura/root_window.cc @@ -210,6 +210,7 @@ void RootWindow::OnCursorVisibilityChanged(bool show) { // cursor state. Env::GetInstance()->SetCursorShown(show); PostMouseMoveEventAfterWindowChange(); + host_->OnCursorVisibilityChanged(show); } void RootWindow::MoveCursorTo(const gfx::Point& location_in_dip) { diff --git a/ui/aura/root_window_host.h b/ui/aura/root_window_host.h index 0766a6a..168f2d6 100644 --- a/ui/aura/root_window_host.h +++ b/ui/aura/root_window_host.h @@ -83,6 +83,9 @@ class AURA_EXPORT RootWindowHost { virtual bool ConfineCursorToRootWindow() = 0; virtual void UnConfineCursor() = 0; + // Called when the cursor visibility has changed. + virtual void OnCursorVisibilityChanged(bool show) = 0; + // Moves the cursor to the specified location relative to the root window. virtual void MoveCursorTo(const gfx::Point& location) = 0; diff --git a/ui/aura/root_window_host_linux.cc b/ui/aura/root_window_host_linux.cc index ce51c6d..90d2512 100644 --- a/ui/aura/root_window_host_linux.cc +++ b/ui/aura/root_window_host_linux.cc @@ -35,6 +35,7 @@ #include "ui/base/touch/touch_factory.h" #include "ui/base/ui_base_switches.h" #include "ui/base/view_prop.h" +#include "ui/base/x/device_list_cache_x.h" #include "ui/base/x/valuators.h" #include "ui/base/x/x11_util.h" #include "ui/compositor/dip_util.h" @@ -70,6 +71,9 @@ const char* kAtomsToCache[] = { "_NET_WM_PING", "_NET_WM_PID", "WM_S0", +#if defined(OS_CHROMEOS) + "Tap Paused", // Defined in the gestures library. +#endif NULL }; @@ -607,6 +611,34 @@ void RootWindowHostLinux::UnConfineCursor() { #endif } +void RootWindowHostLinux::OnCursorVisibilityChanged(bool show) { +#if defined(OS_CHROMEOS) + // Temporarily pause tap-to-click when the cursor is hidden. + Atom prop = atom_cache_.GetAtom("Tap Paused"); + unsigned char value = !show; + XIDeviceList dev_list = + ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(xdisplay_); + + // Only slave pointer devices could possibly have tap-paused property. + for (int i = 0; i < dev_list.count; i++) { + if (dev_list[i].use == XISlavePointer) { + Atom old_type; + int old_format; + uint64 old_nvalues, bytes; + unsigned char* data; + int result = XIGetProperty(xdisplay_, dev_list[i].deviceid, prop, 0, 0, + False, AnyPropertyType, &old_type, &old_format, + &old_nvalues, &bytes, &data); + if (result != Success) + continue; + XFree(data); + XIChangeProperty(xdisplay_, dev_list[i].deviceid, prop, XA_INTEGER, 8, + PropModeReplace, &value, 1); + } + } +#endif +} + void RootWindowHostLinux::MoveCursorTo(const gfx::Point& location) { XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0, bounds_.x() + location.x(), diff --git a/ui/aura/root_window_host_linux.h b/ui/aura/root_window_host_linux.h index 220ec7f..7e52e1f 100644 --- a/ui/aura/root_window_host_linux.h +++ b/ui/aura/root_window_host_linux.h @@ -52,6 +52,7 @@ class RootWindowHostLinux : public RootWindowHost, virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; virtual bool ConfineCursorToRootWindow() OVERRIDE; virtual void UnConfineCursor() OVERRIDE; + virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE; virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds, diff --git a/ui/aura/root_window_host_win.cc b/ui/aura/root_window_host_win.cc index e8d50f9..0aa04fd 100644 --- a/ui/aura/root_window_host_win.cc +++ b/ui/aura/root_window_host_win.cc @@ -212,6 +212,10 @@ void RootWindowHostWin::UnConfineCursor() { ClipCursor(NULL); } +void RootWindowHostWin::OnCursorVisibilityChanged(bool show) { + NOTIMPLEMENTED(); +} + void RootWindowHostWin::MoveCursorTo(const gfx::Point& location) { POINT pt; ClientToScreen(hwnd(), &pt); diff --git a/ui/aura/root_window_host_win.h b/ui/aura/root_window_host_win.h index 5b1a368..d5319ad 100644 --- a/ui/aura/root_window_host_win.h +++ b/ui/aura/root_window_host_win.h @@ -32,6 +32,7 @@ class RootWindowHostWin : public RootWindowHost, public ui::WindowImpl { virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; virtual bool ConfineCursorToRootWindow() OVERRIDE; virtual void UnConfineCursor() OVERRIDE; + virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE; virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds, diff --git a/ui/base/touch/touch_factory.cc b/ui/base/touch/touch_factory.cc index 14c5b96..ed8b3f0 100644 --- a/ui/base/touch/touch_factory.cc +++ b/ui/base/touch/touch_factory.cc @@ -18,6 +18,7 @@ #include "base/string_number_conversions.h" #include "base/string_split.h" #include "ui/base/ui_base_switches.h" +#include "ui/base/x/device_list_cache_x.h" #include "ui/base/x/x11_util.h" namespace { @@ -108,7 +109,6 @@ void TouchFactory::SetTouchDeviceListFromCommandLine() { void TouchFactory::UpdateDeviceList(Display* display) { // Detect touch devices. - int count = 0; touch_device_available_ = false; touch_device_lookup_.reset(); touch_device_list_.clear(); @@ -120,19 +120,18 @@ void TouchFactory::UpdateDeviceList(Display* display) { // If XInput2 is not supported, this will return null (with count of -1) so // we assume there cannot be any touch devices. // With XI2.1 or older, we allow only single touch devices. - XDeviceInfo* devlist = XListInputDevices(display, &count); - for (int i = 0; i < count; i++) { - if (devlist[i].type) { - XScopedString devtype(XGetAtomName(display, devlist[i].type)); + XDeviceList dev_list = + DeviceListCacheX::GetInstance()->GetXDeviceList(display); + for (int i = 0; i < dev_list.count; i++) { + if (dev_list[i].type) { + XScopedString devtype(XGetAtomName(display, dev_list[i].type)); if (devtype.string() && !strcmp(devtype.string(), XI_TOUCHSCREEN)) { - touch_device_lookup_[devlist[i].id] = true; - touch_device_list_[devlist[i].id] = false; + touch_device_lookup_[dev_list[i].id] = true; + touch_device_list_[dev_list[i].id] = false; touch_device_available_ = true; } } } - if (devlist) - XFreeDeviceList(devlist); #endif // Instead of asking X for the list of devices all the time, let's maintain a @@ -148,9 +147,10 @@ void TouchFactory::UpdateDeviceList(Display* display) { // floating device is not connected to a master device. So it is necessary to // also select on the floating devices. pointer_device_lookup_.reset(); - XIDeviceInfo* devices = XIQueryDevice(display, XIAllDevices, &count); - for (int i = 0; i < count; i++) { - XIDeviceInfo* devinfo = devices + i; + XIDeviceList xi_dev_list = + DeviceListCacheX::GetInstance()->GetXI2DeviceList(display); + for (int i = 0; i < xi_dev_list.count; i++) { + XIDeviceInfo* devinfo = xi_dev_list.devices + i; if (devinfo->use == XIFloatingSlave || devinfo->use == XIMasterPointer) { #if defined(USE_XI2_MT) for (int k = 0; k < devinfo->num_classes; ++k) { @@ -170,8 +170,6 @@ void TouchFactory::UpdateDeviceList(Display* display) { pointer_device_lookup_[devinfo->deviceid] = true; } } - if (devices) - XIFreeDeviceInfo(devices); } bool TouchFactory::ShouldProcessXI2Event(XEvent* xev) { diff --git a/ui/base/x/device_list_cache_x.cc b/ui/base/x/device_list_cache_x.cc new file mode 100644 index 0000000..9fcb9db --- /dev/null +++ b/ui/base/x/device_list_cache_x.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2012 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 "ui/base/x/device_list_cache_x.h" + +#include <algorithm> + +#include "base/memory/singleton.h" +#include "ui/base/x/x11_util.h" + +namespace ui { + +DeviceListCacheX::DeviceListCacheX() { +} + +DeviceListCacheX::~DeviceListCacheX() { + std::map<Display*, XDeviceList>::iterator xp; + for (xp = x_dev_list_map_.begin(); xp != x_dev_list_map_.end(); xp++) + XFreeDeviceList(xp->second.devices); + std::map<Display*, XIDeviceList>::iterator xip; + for (xip = xi_dev_list_map_.begin(); xip != xi_dev_list_map_.end(); xip++) + XIFreeDeviceInfo(xip->second.devices); +} + +DeviceListCacheX* DeviceListCacheX::GetInstance() { + return Singleton<DeviceListCacheX>::get(); +} + +void DeviceListCacheX::UpdateDeviceList(Display* display) { + XDeviceList& new_x_dev_list = x_dev_list_map_[display]; + if (new_x_dev_list.devices) + XFreeDeviceList(new_x_dev_list.devices); + new_x_dev_list.devices = XListInputDevices(display, &new_x_dev_list.count); + + XIDeviceList& new_xi_dev_list = xi_dev_list_map_[display]; + if (new_xi_dev_list.devices) + XIFreeDeviceInfo(new_xi_dev_list.devices); + new_xi_dev_list.devices = XIQueryDevice(display, XIAllDevices, + &new_xi_dev_list.count); +} + +const XDeviceList& DeviceListCacheX::GetXDeviceList(Display* display) { + XDeviceList& x_dev_list = x_dev_list_map_[display]; + // Note that the function can be called before any update has taken place. + if (!x_dev_list.devices && !x_dev_list.count) + x_dev_list.devices = XListInputDevices(display, &x_dev_list.count); + return x_dev_list; +} + +const XIDeviceList& DeviceListCacheX::GetXI2DeviceList(Display* display) { + XIDeviceList& xi_dev_list = xi_dev_list_map_[display]; + if (!xi_dev_list.devices && !xi_dev_list.count) { + xi_dev_list.devices = XIQueryDevice(display, XIAllDevices, + &xi_dev_list.count); + } + return xi_dev_list; +} + +} // namespace ui + diff --git a/ui/base/x/device_list_cache_x.h b/ui/base/x/device_list_cache_x.h new file mode 100644 index 0000000..2b3cefa --- /dev/null +++ b/ui/base/x/device_list_cache_x.h @@ -0,0 +1,63 @@ +// Copyright (c) 2012 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 UI_BASE_X_DEVICE_LIST_CACHE_X_H_ +#define UI_BASE_X_DEVICE_LIST_CACHE_X_H_ + +#include <X11/extensions/XInput.h> +#include <X11/extensions/XInput2.h> + +#include <map> + +#include "base/basictypes.h" +#include "ui/base/ui_export.h" + +template <typename T> struct DefaultSingletonTraits; + +typedef struct _XDisplay Display; + +template <typename T> +struct DeviceList { + DeviceList() : devices(NULL), count(0) { + } + T& operator[] (int x) { + return devices[x]; + } + T* devices; + int count; +}; + +typedef struct DeviceList<XDeviceInfo> XDeviceList; +typedef struct DeviceList<XIDeviceInfo> XIDeviceList; + +namespace ui { + +// A class to cache the current XInput device list. This minimized the +// round-trip time to the X server whenever such a device list is needed. The +// update function will be called on each incoming XI_HierarchyChanged event. +class UI_EXPORT DeviceListCacheX { + public: + static DeviceListCacheX* GetInstance(); + + void UpdateDeviceList(Display* display); + + const XDeviceList& GetXDeviceList(Display* display); + const XIDeviceList& GetXI2DeviceList(Display* display); + + private: + friend struct DefaultSingletonTraits<DeviceListCacheX>; + + DeviceListCacheX(); + ~DeviceListCacheX(); + + std::map<Display*, XDeviceList> x_dev_list_map_; + std::map<Display*, XIDeviceList> xi_dev_list_map_; + + DISALLOW_COPY_AND_ASSIGN(DeviceListCacheX); +}; + +} // namespace ui + +#endif // UI_BASE_X_DEVICE_LIST_CACHE_X_H_ + diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc index 9aa84d7..116b867 100644 --- a/ui/base/x/events_x.cc +++ b/ui/base/x/events_x.cc @@ -19,6 +19,7 @@ #include "ui/base/keycodes/keyboard_code_conversion_x.h" #include "ui/base/touch/touch_factory.h" #include "ui/base/ui_base_switches.h" +#include "ui/base/x/device_list_cache_x.h" #include "ui/base/x/valuators.h" #include "ui/base/x/x11_atom_cache.h" #include "ui/base/x/x11_util.h" @@ -98,20 +99,16 @@ class CMTEventData { device_to_valuators_.clear(); #if defined(USE_XI2_MT) - int count = 0; - // Find all the touchpad devices. - XDeviceInfo* dev_list = XListInputDevices(display, &count); + XDeviceList dev_list = + ui::DeviceListCacheX::GetInstance()->GetXDeviceList(display); Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false); - for (int i = 0; i < count; ++i) { - XDeviceInfo* dev = dev_list + i; - if (dev->type == xi_touchpad) + for (int i = 0; i < dev_list.count; ++i) + if (dev_list[i].type == xi_touchpad) touchpads_[dev_list[i].id] = true; - } - if (dev_list) - XFreeDeviceList(dev_list); - XIDeviceInfo* info_list = XIQueryDevice(display, XIAllDevices, &count); + XIDeviceList info_list = + ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(display); Atom x_axis = atom_cache_.GetAtom(AXIS_LABEL_PROP_REL_HWHEEL); Atom y_axis = atom_cache_.GetAtom(AXIS_LABEL_PROP_REL_WHEEL); Atom start_time = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_START_TIME); @@ -126,8 +123,8 @@ class CMTEventData { Atom fling_state = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_FLING_STATE); Atom finger_count = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_FINGER_COUNT); - for (int i = 0; i < count; ++i) { - XIDeviceInfo* info = info_list + i; + for (int i = 0; i < info_list.count; ++i) { + XIDeviceInfo* info = info_list.devices + i; if (info->use != XISlavePointer && info->use != XIFloatingSlave) continue; @@ -199,8 +196,6 @@ class CMTEventData { cmt_devices_[info->deviceid] = true; } } - if (info_list) - XIFreeDeviceInfo(info_list); #endif // defined(USE_XI2_MT) } @@ -704,6 +699,7 @@ namespace ui { void UpdateDeviceList() { Display* display = GetXDisplay(); + DeviceListCacheX::GetInstance()->UpdateDeviceList(display); CMTEventData::GetInstance()->UpdateDeviceList(display); TouchFactory::GetInstance()->UpdateDeviceList(display); ValuatorTracker::GetInstance()->SetupValuator(); diff --git a/ui/base/x/valuators.cc b/ui/base/x/valuators.cc index 2380d84..4008b36 100644 --- a/ui/base/x/valuators.cc +++ b/ui/base/x/valuators.cc @@ -8,6 +8,7 @@ #include "base/memory/singleton.h" #include "ui/base/touch/touch_factory.h" +#include "ui/base/x/device_list_cache_x.h" #include "ui/base/x/x11_util.h" namespace { @@ -158,12 +159,12 @@ void ValuatorTracker::SetupValuator() { memset(last_seen_valuator_, 0, sizeof(last_seen_valuator_)); Display* display = GetXDisplay(); - int ndevice; - XIDeviceInfo* info_list = XIQueryDevice(display, XIAllDevices, &ndevice); + XIDeviceList info_list = + DeviceListCacheX::GetInstance()->GetXI2DeviceList(display); TouchFactory* factory = TouchFactory::GetInstance(); - for (int i = 0; i < ndevice; i++) { - XIDeviceInfo* info = info_list + i; + for (int i = 0; i < info_list.count; i++) { + XIDeviceInfo* info = info_list.devices + i; if (!factory->IsTouchDevice(info->deviceid)) continue; @@ -178,9 +179,6 @@ void ValuatorTracker::SetupValuator() { } } } - - if (info_list) - XIFreeDeviceInfo(info_list); } } // namespace ui @@ -328,6 +328,8 @@ 'base/x/active_window_watcher_x.cc', 'base/x/active_window_watcher_x.h', 'base/x/active_window_watcher_x_observer.h', + 'base/x/device_list_cache_x.cc', + 'base/x/device_list_cache_x.h', 'base/x/events_x.cc', 'base/x/root_window_property_watcher_x.cc', 'base/x/root_window_property_watcher_x.h', diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc index 815d2e2..280c67a 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_linux.cc @@ -775,6 +775,10 @@ void DesktopRootWindowHostLinux::UnConfineCursor() { NOTIMPLEMENTED(); } +void DesktopRootWindowHostLinux::OnCursorVisibilityChanged(bool show) { + NOTIMPLEMENTED(); +} + void DesktopRootWindowHostLinux::MoveCursorTo(const gfx::Point& location) { NOTIMPLEMENTED(); } diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_linux.h b/ui/views/widget/desktop_aura/desktop_root_window_host_linux.h index e8748f5..982e790 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_linux.h +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_linux.h @@ -162,6 +162,7 @@ class VIEWS_EXPORT DesktopRootWindowHostLinux virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; virtual bool ConfineCursorToRootWindow() OVERRIDE; virtual void UnConfineCursor() OVERRIDE; + virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE; virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds, diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc index 829b1a1..f05f610 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc @@ -431,6 +431,9 @@ bool DesktopRootWindowHostWin::ConfineCursorToRootWindow() { void DesktopRootWindowHostWin::UnConfineCursor() { } +void DesktopRootWindowHostWin::OnCursorVisibilityChanged(bool show) { +} + void DesktopRootWindowHostWin::MoveCursorTo(const gfx::Point& location) { } diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.h b/ui/views/widget/desktop_aura/desktop_root_window_host_win.h index 927123b..705ecf3 100644 --- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.h +++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.h @@ -113,6 +113,7 @@ class VIEWS_EXPORT DesktopRootWindowHostWin virtual bool QueryMouseLocation(gfx::Point* location_return) OVERRIDE; virtual bool ConfineCursorToRootWindow() OVERRIDE; virtual void UnConfineCursor() OVERRIDE; + virtual void OnCursorVisibilityChanged(bool show) OVERRIDE; virtual void MoveCursorTo(const gfx::Point& location) OVERRIDE; virtual void SetFocusWhenShown(bool focus_when_shown) OVERRIDE; virtual bool CopyAreaToSkCanvas(const gfx::Rect& source_bounds, |