Commit 00d1887a authored by Nektarios Paisios's avatar Nektarios Paisios Committed by Commit Bot

Introduces SelectionDeserializer that receives an HTML snippet and creates a...

Introduces SelectionDeserializer that receives an HTML snippet and creates a selection in the AX tree

Will help with automated testing using HTML files that include selection markers.
R=dmazzoni@chromium.org

Change-Id: I7dd23b980b6966c87e09c12bdb27b8ad27c9cc15
Reviewed-on: https://chromium-review.googlesource.com/1106901
Commit-Queue: Nektarios Paisios <nektar@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575194}
parent 5ced600f
...@@ -44,6 +44,7 @@ ...@@ -44,6 +44,7 @@
#include "third_party/blink/renderer/platform/geometry/float_quad.h" #include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h" #include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/graphics/color.h" #include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/blink/renderer/platform/wtf/vector.h"
......
...@@ -176,7 +176,6 @@ const AXPosition AXPosition::FromPosition( ...@@ -176,7 +176,6 @@ const AXPosition AXPosition::FromPosition(
position_with_affinity.Affinity()); position_with_affinity.Affinity());
} }
// Only for use by |AXSelection| to represent empty selection ranges.
AXPosition::AXPosition() AXPosition::AXPosition()
: container_object_(nullptr), : container_object_(nullptr),
text_offset_or_child_index_(0), text_offset_or_child_index_(0),
......
...@@ -53,6 +53,9 @@ class MODULES_EXPORT AXPosition final { ...@@ -53,6 +53,9 @@ class MODULES_EXPORT AXPosition final {
const TextAffinity = TextAffinity::kDownstream); const TextAffinity = TextAffinity::kDownstream);
static const AXPosition FromPosition(const PositionWithAffinity&); static const AXPosition FromPosition(const PositionWithAffinity&);
// Creates an empty position. |IsValid| will return false.
AXPosition();
AXPosition(const AXPosition&) = default; AXPosition(const AXPosition&) = default;
AXPosition& operator=(const AXPosition&) = default; AXPosition& operator=(const AXPosition&) = default;
~AXPosition() = default; ~AXPosition() = default;
...@@ -115,7 +118,6 @@ class MODULES_EXPORT AXPosition final { ...@@ -115,7 +118,6 @@ class MODULES_EXPORT AXPosition final {
AXPositionAdjustmentBehavior::kMoveLeft) const; AXPositionAdjustmentBehavior::kMoveLeft) const;
private: private:
AXPosition();
// Only used by static Create... methods. // Only used by static Create... methods.
explicit AXPosition(const AXObject& container); explicit AXPosition(const AXObject& container);
...@@ -141,12 +143,6 @@ class MODULES_EXPORT AXPosition final { ...@@ -141,12 +143,6 @@ class MODULES_EXPORT AXPosition final {
uint64_t dom_tree_version_; uint64_t dom_tree_version_;
uint64_t style_version_; uint64_t style_version_;
#endif #endif
// For access to our constructor for use when creating empty AX selections.
// There is no sense in creating empty positions in other circomstances so we
// disallow it.
friend class AXRange;
friend class AXSelection;
}; };
MODULES_EXPORT bool operator==(const AXPosition&, const AXPosition&); MODULES_EXPORT bool operator==(const AXPosition&, const AXPosition&);
......
...@@ -4,10 +4,15 @@ ...@@ -4,10 +4,15 @@
#include "third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.h" #include "third_party/blink/renderer/modules/accessibility/testing/accessibility_selection_test.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object.h" #include "third_party/blink/renderer/modules/accessibility/ax_object.h"
#include "third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h"
#include "third_party/blink/renderer/modules/accessibility/ax_position.h" #include "third_party/blink/renderer/modules/accessibility/ax_position.h"
#include "third_party/blink/renderer/modules/accessibility/ax_selection.h" #include "third_party/blink/renderer/modules/accessibility/ax_selection.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink { namespace blink {
...@@ -136,6 +141,90 @@ class AXSelectionSerializer final { ...@@ -136,6 +141,90 @@ class AXSelectionSerializer final {
AXSelection selection_; AXSelection selection_;
}; };
// Deserializes an HTML snippet with or without selection markers to an
// accessibility tree. A '^' could be present at the selection anchor offset and
// a '|' at the focus offset. If multiple markers are present, the deserializer
// will DCHECK. If there are no markers, no selection will be made.
class AXSelectionDeserializer final {
STACK_ALLOCATED();
public:
AXSelectionDeserializer(AXObjectCacheImpl& cache)
: ax_object_cache_(&cache), base_(), extent_() {}
~AXSelectionDeserializer() = default;
// Creates an accessibility tree rooted at the given HTML element from the
// provided HTML snippet, selects the part of the tree indicated by the
// selection markers in the snippet if present, and returns the tree's root.
AXObject* Deserialize(const std::string& html_snippet, HTMLElement& element) {
element.SetInnerHTMLFromString(String::FromUTF8(html_snippet.c_str()));
AXObject* root = ax_object_cache_->GetOrCreate(&element);
if (!root)
return nullptr;
FindSelectionMarkers(*root);
if (base_ && extent_) {
AXSelection::Builder builder;
AXSelection ax_selection =
builder.SetBase(base_).SetExtent(extent_).Build();
ax_selection.Select();
}
return root;
}
private:
void HandleCharacterData(const AXObject& text_object) {
int base_offset = -1;
int extent_offset = -1;
String name = text_object.ComputedName();
for (unsigned i = 0; i < name.length(); ++i) {
const UChar character = name[i];
if (character == '^') {
DCHECK_EQ(base_offset, -1) << text_object;
base_offset = static_cast<int>(i);
continue;
}
if (character == '|') {
DCHECK_EQ(extent_offset, -1) << text_object;
extent_offset = static_cast<int>(i);
continue;
}
}
if (base_offset == -1 && extent_offset == -1)
return;
if (base_offset >= 0)
base_ = AXPosition::CreatePositionInTextObject(text_object, base_offset);
if (extent_offset >= 0) {
extent_ =
AXPosition::CreatePositionInTextObject(text_object, extent_offset);
}
}
void HandleObject(const AXObject& object) {
for (const Member<AXObject>& child : object.Children()) {
if (!child)
continue;
FindSelectionMarkers(*child);
}
}
void FindSelectionMarkers(const AXObject& root) {
const Node* node = root.GetNode();
if (node && node->IsCharacterDataNode()) {
HandleCharacterData(root);
return;
}
HandleObject(root);
}
Member<AXObjectCacheImpl> const ax_object_cache_;
AXPosition base_;
AXPosition extent_;
};
} // namespace } // namespace
AccessibilitySelectionTest::AccessibilitySelectionTest( AccessibilitySelectionTest::AccessibilitySelectionTest(
...@@ -156,4 +245,20 @@ std::string AccessibilitySelectionTest::GetSelectionText( ...@@ -156,4 +245,20 @@ std::string AccessibilitySelectionTest::GetSelectionText(
return AXSelectionSerializer(selection).Serialize(subtree); return AXSelectionSerializer(selection).Serialize(subtree);
} }
AXObject* AccessibilitySelectionTest::SetSelectionText(
const std::string& selection_text) const {
HTMLElement* body = GetDocument().body();
if (!body)
return nullptr;
return AXSelectionDeserializer(GetAXObjectCache())
.Deserialize(selection_text, *body);
}
AXObject* AccessibilitySelectionTest::SetSelectionText(
const std::string& selection_text,
HTMLElement& element) const {
return AXSelectionDeserializer(GetAXObjectCache())
.Deserialize(selection_text, element);
}
} // namespace blink } // namespace blink
...@@ -24,9 +24,23 @@ class AccessibilitySelectionTest : public AccessibilityTest { ...@@ -24,9 +24,23 @@ class AccessibilitySelectionTest : public AccessibilityTest {
AccessibilitySelectionTest(LocalFrameClient* local_frame_client = nullptr); AccessibilitySelectionTest(LocalFrameClient* local_frame_client = nullptr);
protected: protected:
// Gets the inner HTML of the accessibility tree and annotates it with markers
// indicating the anchor and focus of |selection|.
std::string GetSelectionText(const AXSelection& selection) const; std::string GetSelectionText(const AXSelection& selection) const;
// Gets the inner HTML of the accessibility subtree rooted at |subtree| and
// annotates it with markers indicating the anchor and focus of |selection|.
std::string GetSelectionText(const AXSelection& selection, std::string GetSelectionText(const AXSelection& selection,
const AXObject& subtree) const; const AXObject& subtree) const;
// Sets |selection_text| as inner HTML of the document body and returns the
// root of the accessibility tree at body.
AXObject* SetSelectionText(const std::string& selection_text) const;
// Sets |selection_text| as inner HTML of |element| and returns the root of
// the accessibility subtree at |element|.
AXObject* SetSelectionText(const std::string& selection_text,
HTMLElement& element) const;
}; };
} // namespace blink } // namespace blink
......
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