Commit e407679d authored by Adam Ettenberger's avatar Adam Ettenberger Committed by Commit Bot

Initial standup of ITextRangeProvider::GetAttributeValue

1. Add AXPlatformNodeWin::GetTextAttributeValue which is used to query the
   TEXTATTRIBUTEID

2. Implement AXPlatformNodeTextRangeProviderWin::GetAttributeValue
   a) Get all anchors in the range
   b) Query the TEXTATTRIBUTEID on each anchor
     b.1) If all the same value, return that value
     b.2) If there's multiple values, return a reserved mixed value
     b.3) If none support it, return a reserved not supported value

3. Implement UIA_IsHiddenAttributeId

Bug: 847971
Change-Id: I7e315ab8ec2c01de62aa8cce51a697464424fc7c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1542575Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Commit-Queue: Adam Ettenberger <adettenb@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#645380}
parent a10dd1dc
......@@ -278,7 +278,10 @@ test("accessibility_unittests") {
if (is_win) {
deps += [ "//third_party/iaccessible2" ]
libs = [ "oleacc.lib" ]
libs = [
"oleacc.lib",
"uiautomationcore.lib",
]
}
if (use_atk) {
sources += [
......
......@@ -7,6 +7,7 @@
#include <utility>
#include <vector>
#include "base/win/scoped_variant.h"
#include "ui/accessibility/platform/ax_platform_node_delegate.h"
#define UIA_VALIDATE_TEXTRANGEPROVIDER_CALL() \
......@@ -134,7 +135,44 @@ STDMETHODIMP AXPlatformNodeTextRangeProviderWin::GetAttributeValue(
TEXTATTRIBUTEID attribute_id,
VARIANT* value) {
WIN_ACCESSIBILITY_API_HISTOGRAM(UMA_API_TEXTRANGE_GETATTRIBUTEVALUE);
return E_NOTIMPL;
AXNodeRange range(start_->Clone(), end_->Clone());
std::vector<AXNodeRange> anchors = range.GetAnchors();
if (anchors.empty())
return UIA_E_ELEMENTNOTAVAILABLE;
base::win::ScopedVariant attribute_value_variant;
AXPlatformNodeDelegate* delegate = owner()->GetDelegate();
for (auto&& current_range : anchors) {
DCHECK(current_range.anchor()->GetAnchor() ==
current_range.focus()->GetAnchor());
AXPlatformNodeWin* platform_node = static_cast<AXPlatformNodeWin*>(
delegate->GetFromNodeID(current_range.anchor()->GetAnchor()->id()));
DCHECK(platform_node);
if (!platform_node)
continue;
base::win::ScopedVariant current_variant;
HRESULT hr = platform_node->GetTextAttributeValue(
attribute_id, current_variant.Receive());
if (FAILED(hr))
return E_FAIL;
if (attribute_value_variant.type() == VT_EMPTY) {
attribute_value_variant.Reset(current_variant);
} else if (0 != attribute_value_variant.Compare(current_variant)) {
V_VT(value) = VT_UNKNOWN;
return ::UiaGetReservedMixedAttributeValue(&V_UNKNOWN(value));
}
}
*value = attribute_value_variant.Release();
return S_OK;
}
STDMETHODIMP AXPlatformNodeTextRangeProviderWin::GetBoundingRectangles(
......
......@@ -10,6 +10,7 @@
#include "base/win/atl.h"
#include "base/win/scoped_bstr.h"
#include "base/win/scoped_safearray.h"
#include "base/win/scoped_variant.h"
#include "ui/accessibility/ax_tree_manager_map.h"
#include "ui/accessibility/platform/ax_fragment_root_win.h"
#include "ui/accessibility/platform/ax_platform_node_textrangeprovider_win.h"
......@@ -81,6 +82,14 @@ namespace ui {
EXPECT_HRESULT_SUCCEEDED(::SafeArrayUnaccessData(safearray)); \
}
#define EXPECT_UIA_TEXTATTRIBUTE_EQ(provider, attribute, variant) \
{ \
base::win::ScopedVariant scoped_variant; \
EXPECT_HRESULT_SUCCEEDED( \
provider->GetAttributeValue(attribute, scoped_variant.Receive())); \
EXPECT_EQ(0, scoped_variant.Compare(variant)); \
}
class AXPlatformNodeTextRangeProviderTest : public ui::AXPlatformNodeWinTest {
public:
const AXNodePosition::AXPositionInstance& GetStart(
......@@ -1206,4 +1215,76 @@ TEST_F(AXPlatformNodeTextRangeProviderTest, TestITextRangeProviderGetChildren) {
AXNodePosition::SetTreeForTesting(nullptr);
}
TEST_F(AXPlatformNodeTextRangeProviderTest,
TestITextRangeProviderGetAttributeValue) {
ui::AXNodeData text_data;
text_data.id = 2;
text_data.role = ax::mojom::Role::kStaticText;
text_data.SetName("some text");
ui::AXNodeData more_text_data;
more_text_data.id = 3;
more_text_data.role = ax::mojom::Role::kStaticText;
more_text_data.AddState(ax::mojom::State::kInvisible);
more_text_data.SetName("more text");
ui::AXNodeData root_data;
root_data.id = 1;
root_data.role = ax::mojom::Role::kRootWebArea;
root_data.child_ids = {2, 3};
ui::AXTreeUpdate update;
ui::AXTreeData tree_data;
tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
update.tree_data = tree_data;
update.has_tree_data = true;
update.root_id = root_data.id;
update.nodes.push_back(root_data);
update.nodes.push_back(text_data);
update.nodes.push_back(more_text_data);
Init(update);
AXNodePosition::SetTreeForTesting(tree_.get());
AXNode* text_node = GetRootNode()->children()[0];
ComPtr<ITextProvider> document_provider;
EXPECT_HRESULT_SUCCEEDED(
GetRootIRawElementProviderSimple()->GetPatternProvider(
UIA_TextPatternId, &document_provider));
ComPtr<ITextProvider> text_provider;
EXPECT_HRESULT_SUCCEEDED(
QueryInterfaceFromNode<IRawElementProviderSimple>(text_node)
->GetPatternProvider(UIA_TextPatternId, &text_provider));
ComPtr<ITextRangeProvider> document_range_provider;
EXPECT_HRESULT_SUCCEEDED(
document_provider->get_DocumentRange(&document_range_provider));
ComPtr<ITextRangeProvider> text_range_provider;
EXPECT_HRESULT_SUCCEEDED(
text_provider->get_DocumentRange(&text_range_provider));
base::win::ScopedVariant expected_mixed_variant;
{
VARIANT var;
V_VT(&var) = VT_UNKNOWN;
EXPECT_HRESULT_SUCCEEDED(
::UiaGetReservedMixedAttributeValue(&V_UNKNOWN(&var)));
expected_mixed_variant.Reset(var);
}
base::win::ScopedVariant expected_variant;
expected_variant.Set(false);
EXPECT_UIA_TEXTATTRIBUTE_EQ(text_range_provider, UIA_IsHiddenAttributeId,
expected_variant);
expected_variant.Reset();
EXPECT_UIA_TEXTATTRIBUTE_EQ(document_range_provider, UIA_IsHiddenAttributeId,
expected_mixed_variant);
}
} // namespace ui
......@@ -4079,6 +4079,32 @@ IFACEMETHODIMP AXPlatformNodeWin::QueryService(REFGUID guidService,
return E_FAIL;
}
HRESULT AXPlatformNodeWin::GetTextAttributeValue(TEXTATTRIBUTEID attribute_id,
VARIANT* result) {
// Text attributes of kInlineTextBox nodes are stored on the parent node
// (which is typically a kStaticText or kLineBreak node).
if (GetData().role == ax::mojom::Role::kInlineTextBox) {
AXPlatformNodeWin* parent_platform_node =
static_cast<AXPlatformNodeWin*>(FromNativeViewAccessible(GetParent()));
if (!parent_platform_node)
return UIA_E_ELEMENTNOTAVAILABLE;
return parent_platform_node->GetTextAttributeValue(attribute_id, result);
}
switch (attribute_id) {
case UIA_IsHiddenAttributeId:
V_VT(result) = VT_BOOL;
V_BOOL(result) = IsInvisibleOrIgnored() ? VARIANT_TRUE : VARIANT_FALSE;
break;
default:
V_VT(result) = VT_UNKNOWN;
return ::UiaGetReservedNotSupportedValue(&V_UNKNOWN(result));
}
return S_OK;
}
//
// Private member functions.
//
......
......@@ -993,6 +993,10 @@ class AX_EXPORT __declspec(uuid("26f5641a-246d-457b-a96d-07f3fae6acf2"))
REFIID riid,
void** object) override;
public:
// Support method for ITextRangeProvider::GetAttributeValue
HRESULT GetTextAttributeValue(TEXTATTRIBUTEID attribute_id, VARIANT* result);
protected:
// This is hard-coded; all products based on the Chromium engine will have the
// same framework name, so that assistive technology can detect any
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment