1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
|
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/accessibility/platform/ax_system_caret_win.h"
#include <windows.h>
#include "base/check.h"
#include "base/notreached.h"
#include "ui/accessibility/ax_enums.mojom.h"
#include "ui/accessibility/platform/ax_platform_node_win.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/rect_f.h"
namespace ui {
AXSystemCaretWin::AXSystemCaretWin(gfx::AcceleratedWidget event_target)
: event_target_(event_target), caret_(AXPlatformNode::Create(*this)) {
// The caret object is not part of the accessibility tree and so doesn't need
// a node ID. A globally unique ID is used when firing Win events, retrieved
// via |unique_id|.
data_.id = -1;
data_.role = ax::mojom::Role::kCaret;
// |get_accState| should return 0 which means that the caret is visible.
data_.state = 0;
data_.AddState(ax::mojom::State::kInvisible);
// According to MSDN, "Edit" should be the name of the caret object.
data_.SetName(u"Edit");
data_.relative_bounds.offset_container_id = -1;
if (event_target_) {
::NotifyWinEvent(EVENT_OBJECT_CREATE, event_target_, OBJID_CARET,
-caret_->GetUniqueId());
}
}
AXSystemCaretWin::~AXSystemCaretWin() {
if (event_target_) {
::NotifyWinEvent(EVENT_OBJECT_DESTROY, event_target_, OBJID_CARET,
-caret_->GetUniqueId());
}
}
Microsoft::WRL::ComPtr<IAccessible> AXSystemCaretWin::GetCaret() const {
Microsoft::WRL::ComPtr<IAccessible> caret_accessible;
HRESULT hr = static_cast<AXPlatformNodeWin&>(*caret_).QueryInterface(
IID_PPV_ARGS(&caret_accessible));
DCHECK(SUCCEEDED(hr));
return caret_accessible;
}
void AXSystemCaretWin::MoveCaretTo(const gfx::Rect& bounds_physical_pixels) {
if (bounds_physical_pixels.IsEmpty())
return;
// If the caret has non-empty bounds, assume it has been made visible.
bool newly_visible = false;
if (data_.HasState(ax::mojom::State::kInvisible)) {
newly_visible = true;
data_.RemoveState(ax::mojom::State::kInvisible);
}
if (!event_target_)
return;
if (newly_visible) {
::NotifyWinEvent(EVENT_OBJECT_SHOW, event_target_, OBJID_CARET,
-caret_->GetUniqueId());
}
gfx::RectF new_location(bounds_physical_pixels);
// Avoid redundant caret move events (if the location stays the same), but
// always fire when it's made visible again.
if (data_.relative_bounds.bounds != new_location || newly_visible) {
data_.relative_bounds.bounds = new_location;
::NotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, event_target_, OBJID_CARET,
-caret_->GetUniqueId());
}
}
void AXSystemCaretWin::Hide() {
if (!data_.HasState(ax::mojom::State::kInvisible)) {
data_.AddState(ax::mojom::State::kInvisible);
data_.relative_bounds.bounds.set_width(0);
if (event_target_) {
::NotifyWinEvent(EVENT_OBJECT_HIDE, event_target_, OBJID_CARET,
-caret_->GetUniqueId());
}
}
}
const AXNodeData& AXSystemCaretWin::GetData() const {
return data_;
}
gfx::NativeViewAccessible AXSystemCaretWin::GetParent() const {
if (!event_target_)
return nullptr;
gfx::NativeViewAccessible parent;
HRESULT hr =
::AccessibleObjectFromWindow(event_target_, OBJID_WINDOW, IID_IAccessible,
reinterpret_cast<void**>(&parent));
if (SUCCEEDED(hr))
return parent;
return nullptr;
}
gfx::Rect AXSystemCaretWin::GetBoundsRect(
const AXCoordinateSystem coordinate_system,
const AXClippingBehavior clipping_behavior,
AXOffscreenResult* offscreen_result) const {
switch (coordinate_system) {
case AXCoordinateSystem::kScreenPhysicalPixels:
// We could optionally add clipping here if ever needed.
return ToEnclosingRect(data_.relative_bounds.bounds);
case AXCoordinateSystem::kScreenDIPs:
return display::win::GetScreenWin()->ScreenToDIPRect(
event_target_, ToEnclosingRect(data_.relative_bounds.bounds));
case AXCoordinateSystem::kRootFrame:
case AXCoordinateSystem::kFrame:
NOTIMPLEMENTED();
return gfx::Rect();
}
}
gfx::AcceleratedWidget
AXSystemCaretWin::GetTargetForNativeAccessibilityEvent() {
return event_target_;
}
bool AXSystemCaretWin::ShouldIgnoreHoveredStateForTesting() {
return false;
}
AXPlatformNodeId AXSystemCaretWin::GetUniqueId() const {
return unique_id_;
}
} // namespace ui
|