Changeset 284675 in webkit
- Timestamp:
- Oct 22, 2021, 1:51:03 AM (5 years ago)
- Location:
- trunk
- Files:
-
- 1 added
- 17 edited
-
Source/WebCore/ChangeLog (modified) (1 diff)
-
Source/WebCore/SourcesGTK.txt (modified) (1 diff)
-
Source/WebCore/accessibility/AXObjectCache.cpp (modified) (10 diffs)
-
Source/WebCore/accessibility/AXObjectCache.h (modified) (1 diff)
-
Source/WebCore/accessibility/AccessibilityObject.cpp (modified) (1 diff)
-
Source/WebCore/accessibility/AccessibilityObject.h (modified) (1 diff)
-
Source/WebCore/accessibility/AccessibilityRenderObject.cpp (modified) (1 diff)
-
Source/WebCore/accessibility/atspi/AXObjectCacheAtspi.cpp (modified) (2 diffs)
-
Source/WebCore/accessibility/atspi/AccessibilityAtspi.cpp (modified) (1 diff)
-
Source/WebCore/accessibility/atspi/AccessibilityAtspi.h (modified) (1 diff)
-
Source/WebCore/accessibility/atspi/AccessibilityAtspiEnums.h (modified) (1 diff)
-
Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp (modified) (5 diffs)
-
Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h (modified) (3 diffs)
-
Source/WebCore/accessibility/atspi/AccessibilityObjectTextAtspi.cpp (added)
-
Source/WebCore/editing/atspi/FrameSelectionAtspi.cpp (modified) (1 diff)
-
Source/WebCore/html/HTMLTextFormControlElement.cpp (modified) (1 diff)
-
Tools/ChangeLog (modified) (1 diff)
-
Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r284674 r284675 1 2021-10-22 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 [GTK][a11y] Add implementation of text interface when building with ATSPI 4 https://bugs.webkit.org/show_bug.cgi?id=230258 5 6 Reviewed by Adrian Perez de Castro. 7 8 * SourcesGTK.txt: 9 * accessibility/AXObjectCache.cpp: 10 (WebCore::AXObjectCache::postTextStateChangeNotification): 11 (WebCore::AXObjectCache::postTextReplacementNotification): 12 (WebCore::AXObjectCache::postTextReplacementNotificationForTextControl): 13 (WebCore::AXObjectCache::enqueuePasswordValueChangeNotification): 14 * accessibility/AXObjectCache.h: 15 * accessibility/AccessibilityObject.cpp: 16 (WebCore::AccessibilityObject::textIteratorBehaviorForTextRange const): 17 * accessibility/AccessibilityObject.h: 18 * accessibility/AccessibilityRenderObject.cpp: 19 (WebCore::AccessibilityRenderObject::indexForVisiblePosition const): 20 * accessibility/atspi/AXObjectCacheAtspi.cpp: 21 (WebCore::AXObjectCache::postTextStateChangePlatformNotification): 22 (WebCore::AXObjectCache::postTextReplacementPlatformNotificationForTextControl): 23 (WebCore::AXObjectCache::postTextReplacementPlatformNotification): 24 (WebCore::AXObjectCache::nodeTextChangePlatformNotification): Deleted. 25 * accessibility/atspi/AccessibilityAtspi.cpp: 26 (WebCore::AccessibilityAtspi::textChanged): 27 (WebCore::AccessibilityAtspi::textAttributesChanged): 28 (WebCore::AccessibilityAtspi::textCaretMoved): 29 (WebCore::AccessibilityAtspi::textSelectionChanged): 30 * accessibility/atspi/AccessibilityAtspi.h: 31 * accessibility/atspi/AccessibilityAtspiEnums.h: 32 * accessibility/atspi/AccessibilityObjectAtspi.cpp: 33 (WebCore::roleIsTextType): 34 (WebCore::AccessibilityObjectAtspi::interfacesForObject): 35 (WebCore::AccessibilityObjectAtspi::path): 36 (WebCore::AccessibilityObjectAtspi::buildInterfaces const): 37 * accessibility/atspi/AccessibilityObjectAtspi.h: 38 * accessibility/atspi/AccessibilityObjectTextAtspi.cpp: Added. 39 (WebCore::AccessibilityObjectAtspi::atspiBoundaryToTextGranularity): 40 (WebCore::AccessibilityObjectAtspi::atspiGranularityToTextGranularity): 41 (WebCore::offsetMapping): 42 (WebCore::UTF16OffsetToUTF8): 43 (WebCore::UTF8OffsetToUTF16): 44 (WebCore::AccessibilityObjectAtspi::text const): 45 (WebCore::AccessibilityObject::getLengthForTextRange const): 46 (WebCore::AccessibilityObject::allowsTextRanges const): 47 (WebCore::AccessibilityObjectAtspi::textInserted): 48 (WebCore::AccessibilityObjectAtspi::textDeleted): 49 (WebCore::AccessibilityObjectAtspi::boundaryOffset const): 50 (WebCore::AccessibilityObjectAtspi::textAtOffset const): 51 (WebCore::AccessibilityObjectAtspi::characterAtOffset const): 52 (WebCore::AccessibilityObjectAtspi::boundsForRange const): 53 (WebCore::AccessibilityObjectAtspi::textExtents const): 54 (WebCore::AccessibilityObjectAtspi::offsetAtPoint const): 55 (WebCore::AccessibilityObjectAtspi::boundsForSelection const): 56 (WebCore::AccessibilityObjectAtspi::selectedRange const): 57 (WebCore::AccessibilityObjectAtspi::selectionBounds const): 58 (WebCore::AccessibilityObjectAtspi::setSelectedRange): 59 (WebCore::AccessibilityObjectAtspi::selectRange): 60 (WebCore::AccessibilityObjectAtspi::selectionChanged): 61 (WebCore::AccessibilityObjectAtspi::textAttributes const): 62 (WebCore::AccessibilityObjectAtspi::textAttributesWithUTF8Offset const): 63 (WebCore::AccessibilityObjectAtspi::textAttributesChanged): 64 (WebCore::AccessibilityObjectAtspi::scrollToMakeVisible const): 65 (WebCore::AccessibilityObjectAtspi::scrollToPoint const): 66 * editing/atspi/FrameSelectionAtspi.cpp: 67 (WebCore::FrameSelection::notifyAccessibilityForSelectionChange): 68 * html/HTMLTextFormControlElement.cpp: 69 (WebCore::HTMLTextFormControlElement::setInnerTextValue): 70 1 71 2021-10-22 Youenn Fablet <youenn@apple.com> 2 72 -
trunk/Source/WebCore/SourcesGTK.txt
r284367 r284675 43 43 accessibility/atspi/AccessibilityObjectAtspi.cpp 44 44 accessibility/atspi/AccessibilityObjectComponentAtspi.cpp 45 accessibility/atspi/AccessibilityObjectTextAtspi.cpp 45 46 accessibility/atspi/AccessibilityRootAtspi.cpp 46 47 accessibility/atspi/AXObjectCacheAtspi.cpp -
trunk/Source/WebCore/accessibility/AXObjectCache.cpp
r284142 r284675 1410 1410 return; 1411 1411 1412 #if PLATFORM(COCOA) 1412 #if PLATFORM(COCOA) || USE(ATSPI) 1413 1413 stopCachingComputedObjectAttributes(); 1414 1414 … … 1429 1429 stopCachingComputedObjectAttributes(); 1430 1430 1431 #if PLATFORM(COCOA) 1431 #if PLATFORM(COCOA) || USE(ATSPI) 1432 1432 AccessibilityObject* object = getOrCreate(node); 1433 1433 if (object && object->accessibilityIsIgnored()) { 1434 #if PLATFORM(COCOA) 1434 1435 if (position.atLastEditingPositionForNode()) { 1435 1436 if (AccessibilityObject* nextSibling = object->nextSiblingUnignored(1)) … … 1439 1440 object = previousSibling; 1440 1441 } 1442 #elif USE(ATSPI) 1443 // ATSPI doesn't expose text nodes, so we need the parent 1444 // object which is the one implementing the text interface. 1445 auto* parent = object->parentObjectUnignored(); 1446 if (is<AccessibilityObject>(parent)) 1447 object = downcast<AccessibilityObject>(parent); 1448 #endif 1441 1449 } 1442 1450 … … 1452 1460 stopCachingComputedObjectAttributes(); 1453 1461 1454 #if PLATFORM(COCOA) 1462 #if PLATFORM(COCOA) || USE(ATSPI) 1455 1463 if (object) { 1456 1464 if (isPasswordFieldOrContainedByPasswordField(object)) … … 1491 1499 1492 1500 AccessibilityObject* object = getOrCreate(node); 1493 #if PLATFORM(COCOA) 1501 #if PLATFORM(COCOA) || USE(ATSPI) 1494 1502 if (object) { 1495 1503 if (enqueuePasswordValueChangeNotification(object)) … … 1526 1534 1527 1535 AccessibilityObject* object = getOrCreate(node); 1528 #if PLATFORM(COCOA) 1536 #if PLATFORM(COCOA) || USE(ATSPI) 1529 1537 if (object) { 1530 1538 if (enqueuePasswordValueChangeNotification(object)) … … 1545 1553 1546 1554 AccessibilityObject* object = getOrCreate(&textControl); 1547 #if PLATFORM(COCOA) 1555 #if PLATFORM(COCOA) || USE(ATSPI) 1548 1556 if (object) { 1549 1557 if (enqueuePasswordValueChangeNotification(object)) … … 1561 1569 bool AXObjectCache::enqueuePasswordValueChangeNotification(AccessibilityObject* object) 1562 1570 { 1571 #if PLATFORM(COCOA) 1563 1572 if (!isPasswordFieldOrContainedByPasswordField(object)) 1564 1573 return false; … … 1576 1585 1577 1586 return true; 1587 #else 1588 UNUSED_PARAM(object); 1589 return false; 1590 #endif 1578 1591 } 1579 1592 … … 3464 3477 } 3465 3478 3466 #if !PLATFORM(COCOA) 3479 #if !PLATFORM(COCOA) && !USE(ATSPI) 3467 3480 AXTextChange AXObjectCache::textChangeForEditType(AXTextEditType type) 3468 3481 { -
trunk/Source/WebCore/accessibility/AXObjectCache.h
r284080 r284675 399 399 void platformPerformDeferredCacheUpdate(); 400 400 401 #if PLATFORM(COCOA) 401 #if PLATFORM(COCOA) || USE(ATSPI) 402 402 void postTextStateChangePlatformNotification(AXCoreObject*, const AXTextStateChangeIntent&, const VisibleSelection&); 403 403 void postTextStateChangePlatformNotification(AccessibilityObject*, AXTextEditType, const String&, const VisiblePosition&); -
trunk/Source/WebCore/accessibility/AccessibilityObject.cpp
r284606 r284675 3274 3274 { 3275 3275 TextIteratorBehaviors behaviors { TextIteratorBehavior::IgnoresStyleVisibility }; 3276 3277 #if USE(ATK) 3276 3277 #if USE(ATK) || USE(ATSPI) 3278 3278 // We need to emit replaced elements for GTK, and present 3279 3279 // them with the 'object replacement character' (0xFFFC). -
trunk/Source/WebCore/accessibility/AccessibilityObject.h
r284529 r284675 834 834 #endif 835 835 836 #if !(ENABLE(ACCESSIBILITY) && USE(ATK))836 #if !(ENABLE(ACCESSIBILITY) && (USE(ATK) || USE(ATSPI))) 837 837 inline bool AccessibilityObject::allowsTextRanges() const { return true; } 838 838 inline unsigned AccessibilityObject::getLengthForTextRange() const { return text().length(); } -
trunk/Source/WebCore/accessibility/AccessibilityRenderObject.cpp
r284612 r284675 2161 2161 return 0; 2162 2162 2163 #if USE(ATK) 2163 #if USE(ATK) || USE(ATSPI) 2164 2164 // We need to consider replaced elements for GTK, as they will be 2165 2165 // presented with the 'object replacement character' (0xFFFC). -
trunk/Source/WebCore/accessibility/atspi/AXObjectCacheAtspi.cpp
r283361 r284675 22 22 23 23 #if ENABLE(ACCESSIBILITY) && USE(ATSPI) 24 #include "AXTextStateChangeIntent.h" 24 25 #include "AccessibilityObject.h" 25 26 #include "AccessibilityObjectAtspi.h" … … 186 187 } 187 188 188 void AXObjectCache::nodeTextChangePlatformNotification(AccessibilityObject* object, AXTextChange textChange, unsigned offset, const String& text) 189 { 189 void AXObjectCache::postTextStateChangePlatformNotification(AXCoreObject* coreObject, const AXTextStateChangeIntent&, const VisibleSelection& selection) 190 { 191 RELEASE_ASSERT(isMainThread()); 192 if (!coreObject) 193 coreObject = rootWebArea(); 194 195 if (!coreObject) 196 return; 197 198 auto* wrapper = coreObject->wrapper(); 199 if (!wrapper) 200 return; 201 202 wrapper->selectionChanged(selection); 203 } 204 205 void AXObjectCache::postTextStateChangePlatformNotification(AccessibilityObject* coreObject, AXTextEditType editType, const String& text, const VisiblePosition& position) 206 { 207 RELEASE_ASSERT(isMainThread()); 208 if (text.isEmpty()) 209 return; 210 211 auto* wrapper = coreObject->wrapper(); 212 if (!wrapper) 213 return; 214 215 switch (editType) { 216 case AXTextEditTypeDelete: 217 case AXTextEditTypeCut: 218 wrapper->textDeleted(text, position); 219 break; 220 case AXTextEditTypeInsert: 221 case AXTextEditTypeTyping: 222 case AXTextEditTypeDictation: 223 case AXTextEditTypePaste: 224 wrapper->textInserted(text, position); 225 break; 226 case AXTextEditTypeAttributesChange: 227 wrapper->textAttributesChanged(); 228 break; 229 case AXTextEditTypeUnknown: 230 break; 231 } 232 } 233 234 void AXObjectCache::postTextReplacementPlatformNotificationForTextControl(AXCoreObject* coreObject, const String& deletedText, const String& insertedText, HTMLTextFormControlElement&) 235 { 236 RELEASE_ASSERT(isMainThread()); 237 if (!coreObject) 238 coreObject = rootWebArea(); 239 240 if (!coreObject) 241 return; 242 243 if (deletedText.isEmpty() && insertedText.isEmpty()) 244 return; 245 246 auto* wrapper = coreObject->wrapper(); 247 if (!wrapper) 248 return; 249 250 if (!deletedText.isEmpty()) 251 wrapper->textDeleted(deletedText, coreObject->visiblePositionForIndex(0)); 252 if (!insertedText.isEmpty()) 253 wrapper->textInserted(insertedText, coreObject->visiblePositionForIndex(insertedText.length())); 254 } 255 256 void AXObjectCache::postTextReplacementPlatformNotification(AXCoreObject* coreObject, AXTextEditType, const String& deletedText, AXTextEditType, const String& insertedText, const VisiblePosition& position) 257 { 258 RELEASE_ASSERT(isMainThread()); 259 if (!coreObject) 260 coreObject = rootWebArea(); 261 262 if (!coreObject) 263 return; 264 265 if (deletedText.isEmpty() && insertedText.isEmpty()) 266 return; 267 268 auto* wrapper = coreObject->wrapper(); 269 if (!wrapper) 270 return; 271 272 if (!deletedText.isEmpty()) 273 wrapper->textDeleted(deletedText, position); 274 if (!insertedText.isEmpty()) 275 wrapper->textInserted(insertedText, position); 190 276 } 191 277 -
trunk/Source/WebCore/accessibility/atspi/AccessibilityAtspi.cpp
r283361 r284675 165 165 g_dbus_connection_emit_signal(m_connection.get(), nullptr, atspiObject->path().utf8().data(), "org.a11y.atspi.Event.Object", "StateChanged", 166 166 g_variant_new("(siiva{sv})", name.data(), value, 0, g_variant_new_string("0"), nullptr), nullptr); 167 }); 168 } 169 170 void AccessibilityAtspi::textChanged(AccessibilityObjectAtspi& atspiObject, const char* changeType, CString&& text, unsigned offset, unsigned length) 171 { 172 RELEASE_ASSERT(isMainThread()); 173 m_queue->dispatch([this, atspiObject = Ref { atspiObject }, changeType = CString(changeType), text = WTFMove(text), offset, length] { 174 if (!m_connection) 175 return; 176 177 g_dbus_connection_emit_signal(m_connection.get(), nullptr, atspiObject->path().utf8().data(), "org.a11y.atspi.Event.Object", "TextChanged", 178 g_variant_new("(siiva{sv})", changeType.data(), offset, length, g_variant_new_string(text.data()), nullptr), nullptr); 179 }); 180 } 181 182 void AccessibilityAtspi::textAttributesChanged(AccessibilityObjectAtspi& atspiObject) 183 { 184 RELEASE_ASSERT(isMainThread()); 185 m_queue->dispatch([this, atspiObject = Ref { atspiObject }] { 186 if (!m_connection) 187 return; 188 189 g_dbus_connection_emit_signal(m_connection.get(), nullptr, atspiObject->path().utf8().data(), "org.a11y.atspi.Event.Object", "TextAttributesChanged", 190 g_variant_new("(siiva{sv})", "", 0, 0, g_variant_new_string(""), nullptr), nullptr); 191 }); 192 } 193 194 void AccessibilityAtspi::textCaretMoved(AccessibilityObjectAtspi& atspiObject, unsigned caretOffset) 195 { 196 RELEASE_ASSERT(isMainThread()); 197 m_queue->dispatch([this, atspiObject = Ref { atspiObject }, caretOffset] { 198 if (!m_connection) 199 return; 200 201 g_dbus_connection_emit_signal(m_connection.get(), nullptr, atspiObject->path().utf8().data(), "org.a11y.atspi.Event.Object", "TextCaretMoved", 202 g_variant_new("(siiva{sv})", "", caretOffset, 0, g_variant_new_string(""), nullptr), nullptr); 203 }); 204 } 205 206 void AccessibilityAtspi::textSelectionChanged(AccessibilityObjectAtspi& atspiObject) 207 { 208 RELEASE_ASSERT(isMainThread()); 209 m_queue->dispatch([this, atspiObject = Ref { atspiObject }] { 210 if (!m_connection) 211 return; 212 213 g_dbus_connection_emit_signal(m_connection.get(), nullptr, atspiObject->path().utf8().data(), "org.a11y.atspi.Event.Object", "TextSelectionChanged", 214 g_variant_new("(siiva{sv})", "", 0, 0, g_variant_new_string(""), nullptr), nullptr); 167 215 }); 168 216 } -
trunk/Source/WebCore/accessibility/atspi/AccessibilityAtspi.h
r283361 r284675 57 57 void stateChanged(AccessibilityObjectAtspi&, const char*, bool); 58 58 59 void textChanged(AccessibilityObjectAtspi&, const char*, CString&&, unsigned, unsigned); 60 void textAttributesChanged(AccessibilityObjectAtspi&); 61 void textCaretMoved(AccessibilityObjectAtspi&, unsigned); 62 void textSelectionChanged(AccessibilityObjectAtspi&); 63 59 64 static const char* localizedRoleName(AccessibilityRole); 60 65 -
trunk/Source/WebCore/accessibility/atspi/AccessibilityAtspiEnums.h
r284367 r284675 259 259 }; 260 260 261 enum TextBoundaryType { 262 CharBoundary, 263 WordStartBoundary, 264 WordEndBoundary, 265 SentenceStartBoundary, 266 SentenceEndBoundary, 267 LineStartBoundary, 268 LineEndBoundary 269 }; 270 271 enum TextGranularityType { 272 CharGranularity, 273 WordGranularity, 274 SentenceGranularity, 275 LineGranularity, 276 ParagraphGranularity 277 }; 278 261 279 } // namespace Atspi 262 280 } // namespace WebCore -
trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.cpp
r284367 r284675 22 22 23 23 #if ENABLE(ACCESSIBILITY) && USE(ATSPI) 24 #include "AXIsolatedObject.h" 24 25 #include "AccessibilityAtspiEnums.h" 25 26 #include "AccessibilityObjectInterface.h" … … 29 30 #include "RenderAncestorIterator.h" 30 31 #include "RenderBlock.h" 32 #include "RenderObject.h" 31 33 #include <glib/gi18n-lib.h> 32 34 #include <wtf/MainThread.h> … … 40 42 } 41 43 44 static inline bool roleIsTextType(AccessibilityRole role) 45 { 46 return role == AccessibilityRole::Paragraph 47 || role == AccessibilityRole::Heading 48 || role == AccessibilityRole::Div 49 || role == AccessibilityRole::Cell 50 || role == AccessibilityRole::Link 51 || role == AccessibilityRole::WebCoreLink 52 || role == AccessibilityRole::ListItem 53 || role == AccessibilityRole::Pre 54 || role == AccessibilityRole::GridCell 55 || role == AccessibilityRole::TextGroup 56 || role == AccessibilityRole::ApplicationTextGroup 57 || role == AccessibilityRole::ApplicationGroup; 58 } 59 42 60 OptionSet<AccessibilityObjectAtspi::Interface> AccessibilityObjectAtspi::interfacesForObject(AXCoreObject& coreObject) 43 61 { 44 62 OptionSet<Interface> interfaces = { Interface::Accessible, Interface::Component }; 63 64 RenderObject* renderer = coreObject.isAccessibilityRenderObject() ? coreObject.renderer() : nullptr; 65 if (coreObject.roleValue() == AccessibilityRole::StaticText || coreObject.roleValue() == AccessibilityRole::ColorWell) 66 interfaces.add(Interface::Text); 67 else if (coreObject.isTextControl() || coreObject.isNonNativeTextControl()) 68 interfaces.add(Interface::Text); 69 else if (!coreObject.isWebArea()) { 70 if (coreObject.roleValue() != AccessibilityRole::Table) { 71 if ((renderer && renderer->childrenInline()) || roleIsTextType(coreObject.roleValue()) || coreObject.isMathToken()) 72 interfaces.add(Interface::Text); 73 } 74 75 // Add the Text interface for list items whose first accessible child has a text renderer. 76 if (coreObject.roleValue() == AccessibilityRole::ListItem) { 77 const auto& children = coreObject.children(); 78 if (!children.isEmpty()) { 79 auto childInterfaces = interfacesForObject(*children[0]); 80 if (childInterfaces.contains(Interface::Text)) 81 interfaces.add(Interface::Text); 82 } 83 } 84 } 45 85 46 86 return interfaces; … … 428 468 if (m_interfaces.contains(Interface::Component)) 429 469 interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_component_interface), &s_componentFunctions }); 470 if (m_interfaces.contains(Interface::Text)) 471 interfaces.append({ const_cast<GDBusInterfaceInfo*>(&webkit_text_interface), &s_textFunctions }); 430 472 m_path = atspiRoot->atspi().registerObject(*this, WTFMove(interfaces)); 431 473 } … … 1041 1083 if (m_interfaces.contains(Interface::Component)) 1042 1084 g_variant_builder_add(builder, "s", webkit_component_interface.name); 1085 if (m_interfaces.contains(Interface::Text)) 1086 g_variant_builder_add(builder, "s", webkit_text_interface.name); 1043 1087 } 1044 1088 -
trunk/Source/WebCore/accessibility/atspi/AccessibilityObjectAtspi.h
r284367 r284675 45 45 enum class Interface : uint8_t { 46 46 Accessible = 1 << 0, 47 Component = 1 << 1 47 Component = 1 << 1, 48 Text = 1 << 2 48 49 }; 49 50 const OptionSet<Interface>& interfaces() const { return m_interfaces; } … … 83 84 void scrollToPoint(const IntPoint&, uint32_t) const; 84 85 86 String text() const; 87 enum class TextGranularity { 88 Character, 89 WordStart, 90 WordEnd, 91 SentenceStart, 92 SentenceEnd, 93 LineStart, 94 LineEnd, 95 Paragraph 96 }; 97 IntPoint boundaryOffset(unsigned, TextGranularity) const; 98 IntRect boundsForRange(unsigned, unsigned, uint32_t) const; 99 struct TextAttributes { 100 HashMap<String, String> attributes; 101 int startOffset; 102 int endOffset; 103 }; 104 TextAttributes textAttributes(std::optional<unsigned> = std::nullopt, bool = false) const; 105 IntPoint selectedRange() const; 106 void setSelectedRange(unsigned, unsigned); 107 void textInserted(const String&, const VisiblePosition&); 108 void textDeleted(const String&, const VisiblePosition&); 109 void textAttributesChanged(); 110 void selectionChanged(const VisibleSelection&); 111 85 112 private: 86 113 explicit AccessibilityObjectAtspi(AXCoreObject*); … … 100 127 float opacity() const; 101 128 129 static TextGranularity atspiBoundaryToTextGranularity(uint32_t); 130 static TextGranularity atspiGranularityToTextGranularity(uint32_t); 131 CString text(int, int) const; 132 CString textAtOffset(int, TextGranularity, int&, int&) const; 133 int characterAtOffset(int) const; 134 IntRect textExtents(int, int, uint32_t) const; 135 int offsetAtPoint(const IntPoint&, uint32_t) const; 136 IntPoint boundsForSelection(const VisibleSelection&) const; 137 bool selectionBounds(int&, int&) const; 138 bool selectRange(int, int); 139 TextAttributes textAttributesWithUTF8Offset(std::optional<int> = std::nullopt, bool = false) const; 140 bool scrollToMakeVisible(int, int, uint32_t) const; 141 bool scrollToPoint(int, int, uint32_t, int, int) const; 142 102 143 static OptionSet<Interface> interfacesForObject(AXCoreObject&); 103 144 104 145 static GDBusInterfaceVTable s_accessibleFunctions; 105 146 static GDBusInterfaceVTable s_componentFunctions; 147 static GDBusInterfaceVTable s_textFunctions; 106 148 107 149 AXCoreObject* m_axObject { nullptr }; -
trunk/Source/WebCore/editing/atspi/FrameSelectionAtspi.cpp
r282643 r284675 24 24 25 25 #include "AXObjectCache.h" 26 #include "DocumentInlines.h" 26 27 27 28 namespace WebCore { 28 29 29 void FrameSelection::notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent& )30 void FrameSelection::notifyAccessibilityForSelectionChange(const AXTextStateChangeIntent& intent) 30 31 { 31 32 if (!AXObjectCache::accessibilityEnabled()) 32 33 return; 34 35 if (!m_selection.start().isNotNull() || !m_selection.end().isNotNull()) 36 return; 37 38 if (AXObjectCache* cache = m_document->existingAXObjectCache()) 39 cache->postTextStateChangeNotification(m_selection.start(), intent, m_selection); 33 40 } 34 41 -
trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp
r284080 r284675 604 604 } 605 605 606 #if ENABLE(ACCESSIBILITY) && PLATFORM(COCOA)606 #if ENABLE(ACCESSIBILITY) && (PLATFORM(COCOA) || USE(ATSPI)) 607 607 if (textIsChanged && renderer()) { 608 608 if (AXObjectCache* cache = document().existingAXObjectCache()) -
trunk/Tools/ChangeLog
r284669 r284675 1 2021-10-22 Carlos Garcia Campos <cgarcia@igalia.com> 2 3 [GTK][a11y] Add implementation of text interface when building with ATSPI 4 https://bugs.webkit.org/show_bug.cgi?id=230258 5 6 Reviewed by Adrian Perez de Castro. 7 8 Add unit tests for the text interface. 9 10 * TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp: 11 (AtspiTextRangeDeleter::operator() const): 12 (AccessibilityTest::startEventMonitor): 13 (AccessibilityTest::stopEventMonitor): 14 (AccessibilityTest::findEvent): 15 (testTextBasic): 16 (testTextSurrogatePair): 17 (testTextIterator): 18 (testTextExtents): 19 (testTextSelections): 20 (testTextAttributes): 21 (testTextStateChanged): 22 (beforeAll): 23 1 24 2021-10-22 Kimmo Kinnunen <kkinnunen@apple.com> 2 25 -
trunk/Tools/TestWebKitAPI/Tests/WebKitGtk/TestWebKitAccessibility.cpp
r284592 r284675 35 35 }; 36 36 37 struct AtspiTextRangeDeleter { 38 void operator()(AtspiTextRange* range) const 39 { 40 g_boxed_free(ATSPI_TYPE_TEXT_RANGE, range); 41 } 42 }; 43 37 44 using UniqueAtspiEvent = std::unique_ptr<AtspiEvent, AtspiEventDeleter>; 45 using UniqueAtspiTextRange = std::unique_ptr<AtspiTextRange, AtspiTextRangeDeleter>; 38 46 39 47 class AccessibilityTest : public WebViewTest { … … 99 107 } 100 108 101 void startEventMonitor(AtspiAccessible* source, const Vector<const char*>& events)109 void startEventMonitor(AtspiAccessible* source, Vector<CString>&& events) 102 110 { 103 111 m_eventMonitor.source = source; 112 m_eventMonitor.eventTypes = WTFMove(events); 104 113 m_eventMonitor.listener = adoptGRef(atspi_event_listener_new([](AtspiEvent* event, gpointer userData) { 105 114 auto* test = static_cast<AccessibilityTest*>(userData); … … 108 117 }, this, nullptr)); 109 118 110 for (const auto * event : events)111 atspi_event_listener_register(m_eventMonitor.listener.get(), event , nullptr);119 for (const auto& event : m_eventMonitor.eventTypes) 120 atspi_event_listener_register(m_eventMonitor.listener.get(), event.data(), nullptr); 112 121 } 113 122 … … 120 129 121 130 auto events = WTFMove(m_eventMonitor.events); 122 m_eventMonitor = { nullptr, { }, nullptr }; 131 for (const auto& event : m_eventMonitor.eventTypes) 132 atspi_event_listener_deregister(m_eventMonitor.listener.get(), event.data(), nullptr); 133 m_eventMonitor = { nullptr, { }, { }, nullptr }; 123 134 return events; 135 } 136 137 static AtspiEvent* findEvent(const Vector<UniqueAtspiEvent>& events, const char* eventType) 138 { 139 for (const auto& event : events) { 140 if (!g_strcmp0(event->type, eventType)) 141 return event.get(); 142 } 143 144 return nullptr; 124 145 } 125 146 … … 137 158 struct { 138 159 GRefPtr<AtspiEventListener> listener; 160 Vector<CString> eventTypes; 139 161 Vector<UniqueAtspiEvent> events; 140 162 AtspiAccessible* source { nullptr }; … … 806 828 #endif 807 829 830 static void testTextBasic(AccessibilityTest* test, gconstpointer) 831 { 832 test->showInWindow(); 833 test->loadHtml( 834 "<html>" 835 " <body>" 836 " <p>This is a line of text</p>" 837 " </body>" 838 "</html>", 839 nullptr); 840 test->waitUntilLoadFinished(); 841 842 auto testApp = test->findTestApplication(); 843 g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get())); 844 845 auto documentWeb = test->findDocumentWeb(testApp.get()); 846 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 847 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1); 848 849 auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 850 g_assert_true(ATSPI_IS_TEXT(p.get())); 851 auto length = atspi_text_get_character_count(ATSPI_TEXT(p.get()), nullptr); 852 g_assert_cmpint(length, ==, 22); 853 GUniquePtr<char> text(atspi_text_get_text(ATSPI_TEXT(p.get()), 0, length, nullptr)); 854 g_assert_cmpstr(text.get(), ==, "This is a line of text"); 855 text.reset(atspi_text_get_text(ATSPI_TEXT(p.get()), 0, -1, nullptr)); 856 g_assert_cmpstr(text.get(), ==, "This is a line of text"); 857 text.reset(atspi_text_get_text(ATSPI_TEXT(p.get()), 5, 7, nullptr)); 858 g_assert_cmpstr(text.get(), ==, "is"); 859 text.reset(atspi_text_get_text(ATSPI_TEXT(p.get()), 0, -2, nullptr)); 860 g_assert_cmpstr(text.get(), ==, ""); 861 text.reset(atspi_text_get_text(ATSPI_TEXT(p.get()), -5, 23, nullptr)); 862 g_assert_cmpstr(text.get(), ==, ""); 863 } 864 865 static void testTextSurrogatePair(AccessibilityTest* test, gconstpointer) 866 { 867 #if USE(ATK) 868 g_test_skip("Surrogate pairs are not correctly handled by WebKit when using ATK"); 869 return; 870 #endif 871 872 test->showInWindow(); 873 test->loadHtml( 874 "<html>" 875 " <body>" 876 " <p>This contains a 𝌆 symbol</p>" 877 " <input value='This contains a 𝌆 symbol'/>" 878 " </body>" 879 "</html>", 880 nullptr); 881 test->waitUntilLoadFinished(); 882 883 auto testApp = test->findTestApplication(); 884 g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get())); 885 886 auto documentWeb = test->findDocumentWeb(testApp.get()); 887 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 888 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 2); 889 890 auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 891 g_assert_true(ATSPI_IS_TEXT(p.get())); 892 auto length = atspi_text_get_character_count(ATSPI_TEXT(p.get()), nullptr); 893 g_assert_cmpint(length, ==, 24); 894 GUniquePtr<char> text(atspi_text_get_text(ATSPI_TEXT(p.get()), 0, length, nullptr)); 895 g_assert_cmpstr(text.get(), ==, "This contains a 𝌆 symbol"); 896 text.reset(atspi_text_get_text(ATSPI_TEXT(p.get()), 16, 17, nullptr)); 897 g_assert_cmpstr(text.get(), ==, "𝌆"); 898 899 auto section = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 1, nullptr)); 900 g_assert_true(ATSPI_IS_ACCESSIBLE(section.get())); 901 g_assert_cmpint(atspi_accessible_get_child_count(section.get(), nullptr), ==, 1); 902 auto input = adoptGRef(atspi_accessible_get_child_at_index(section.get(), 0, nullptr)); 903 g_assert_true(ATSPI_IS_TEXT(input.get())); 904 length = atspi_text_get_character_count(ATSPI_TEXT(input.get()), nullptr); 905 g_assert_cmpint(length, ==, 24); 906 text.reset(atspi_text_get_text(ATSPI_TEXT(input.get()), 0, length, nullptr)); 907 g_assert_cmpstr(text.get(), ==, "This contains a 𝌆 symbol"); 908 text.reset(atspi_text_get_text(ATSPI_TEXT(input.get()), 16, 17, nullptr)); 909 g_assert_cmpstr(text.get(), ==, "𝌆"); 910 } 911 912 static void testTextIterator(AccessibilityTest* test, gconstpointer) 913 { 914 test->showInWindow(800, 600); 915 test->loadHtml( 916 "<html>" 917 " <body>" 918 " <p>Text of first sentence. This is the second sentence.<br>And this is the next paragraph.</p>" 919 " </body>" 920 "</html>", 921 nullptr); 922 test->waitUntilLoadFinished(); 923 924 auto testApp = test->findTestApplication(); 925 g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get())); 926 927 auto documentWeb = test->findDocumentWeb(testApp.get()); 928 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 929 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1); 930 931 auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 932 g_assert_true(ATSPI_IS_TEXT(p.get())); 933 auto length = atspi_text_get_character_count(ATSPI_TEXT(p.get()), nullptr); 934 g_assert_cmpint(length, ==, 84); 935 GUniquePtr<char> text(atspi_text_get_text(ATSPI_TEXT(p.get()), 0, length, nullptr)); 936 g_assert_cmpstr(text.get(), ==, "Text of first sentence. This is the second sentence.\nAnd this is the next paragraph."); 937 938 // Character granularity. 939 UniqueAtspiTextRange range(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 0, ATSPI_TEXT_GRANULARITY_CHAR, nullptr)); 940 g_assert_cmpstr(range->content, ==, "T"); 941 g_assert_cmpint(range->start_offset, ==, 0); 942 g_assert_cmpint(range->end_offset, ==, 1); 943 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 83, ATSPI_TEXT_GRANULARITY_CHAR, nullptr)); 944 g_assert_cmpstr(range->content, ==, "."); 945 g_assert_cmpint(range->start_offset, ==, 83); 946 g_assert_cmpint(range->end_offset, ==, 84); 947 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 84, ATSPI_TEXT_GRANULARITY_CHAR, nullptr)); 948 g_assert_cmpstr(range->content, ==, ""); 949 g_assert_cmpint(range->start_offset, ==, 84); 950 g_assert_cmpint(range->end_offset, ==, 84); 951 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 85, ATSPI_TEXT_GRANULARITY_CHAR, nullptr)); 952 g_assert_cmpstr(range->content, ==, ""); 953 #if USE(ATSPI) 954 g_assert_cmpint(range->start_offset, ==, 0); 955 g_assert_cmpint(range->end_offset, ==, 0); 956 #else 957 // FIXME: ATK returns wrong offsets in this case. 958 g_assert_cmpint(range->start_offset, ==, 84); 959 g_assert_cmpint(range->end_offset, ==, 84); 960 #endif 961 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), -1, ATSPI_TEXT_GRANULARITY_CHAR, nullptr)); 962 g_assert_cmpstr(range->content, ==, ""); 963 g_assert_cmpint(range->start_offset, ==, 0); 964 g_assert_cmpint(range->end_offset, ==, 0); 965 966 // Word granularity. 967 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 0, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 968 g_assert_cmpstr(range->content, ==, "Text "); 969 g_assert_cmpint(range->start_offset, ==, 0); 970 g_assert_cmpint(range->end_offset, ==, 5); 971 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 4, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 972 g_assert_cmpstr(range->content, ==, "Text "); 973 g_assert_cmpint(range->start_offset, ==, 0); 974 g_assert_cmpint(range->end_offset, ==, 5); 975 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 5, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 976 g_assert_cmpstr(range->content, ==, "of "); 977 g_assert_cmpint(range->start_offset, ==, 5); 978 g_assert_cmpint(range->end_offset, ==, 8); 979 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 40, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 980 g_assert_cmpstr(range->content, ==, "second "); 981 g_assert_cmpint(range->start_offset, ==, 36); 982 g_assert_cmpint(range->end_offset, ==, 43); 983 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 16, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 984 g_assert_cmpstr(range->content, ==, "sentence. "); 985 g_assert_cmpint(range->start_offset, ==, 14); 986 g_assert_cmpint(range->end_offset, ==, 24); 987 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 74, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 988 g_assert_cmpstr(range->content, ==, "paragraph."); 989 g_assert_cmpint(range->start_offset, ==, 74); 990 g_assert_cmpint(range->end_offset, ==, 84); 991 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 83, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 992 g_assert_cmpstr(range->content, ==, "paragraph."); 993 g_assert_cmpint(range->start_offset, ==, 74); 994 g_assert_cmpint(range->end_offset, ==, 84); 995 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 80, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 996 g_assert_cmpstr(range->content, ==, "paragraph."); 997 g_assert_cmpint(range->start_offset, ==, 74); 998 g_assert_cmpint(range->end_offset, ==, 84); 999 1000 // Sentence granularity. 1001 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 0, ATSPI_TEXT_GRANULARITY_SENTENCE, nullptr)); 1002 g_assert_cmpstr(range->content, ==, "Text of first sentence. "); 1003 g_assert_cmpint(range->start_offset, ==, 0); 1004 g_assert_cmpint(range->end_offset, ==, 24); 1005 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 23, ATSPI_TEXT_GRANULARITY_SENTENCE, nullptr)); 1006 g_assert_cmpstr(range->content, ==, "Text of first sentence. "); 1007 g_assert_cmpint(range->start_offset, ==, 0); 1008 g_assert_cmpint(range->end_offset, ==, 24); 1009 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 24, ATSPI_TEXT_GRANULARITY_SENTENCE, nullptr)); 1010 g_assert_cmpstr(range->content, ==, "This is the second sentence.\n"); 1011 g_assert_cmpint(range->start_offset, ==, 24); 1012 g_assert_cmpint(range->end_offset, ==, 53); 1013 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 40, ATSPI_TEXT_GRANULARITY_SENTENCE, nullptr)); 1014 g_assert_cmpstr(range->content, ==, "This is the second sentence.\n"); 1015 g_assert_cmpint(range->start_offset, ==, 24); 1016 g_assert_cmpint(range->end_offset, ==, 53); 1017 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 53, ATSPI_TEXT_GRANULARITY_SENTENCE, nullptr)); 1018 g_assert_cmpstr(range->content, ==, "And this is the next paragraph."); 1019 g_assert_cmpint(range->start_offset, ==, 53); 1020 g_assert_cmpint(range->end_offset, ==, 84); 1021 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 83, ATSPI_TEXT_GRANULARITY_SENTENCE, nullptr)); 1022 g_assert_cmpstr(range->content, ==, "And this is the next paragraph."); 1023 g_assert_cmpint(range->start_offset, ==, 53); 1024 g_assert_cmpint(range->end_offset, ==, 84); 1025 1026 // Line granularity. 1027 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 0, ATSPI_TEXT_GRANULARITY_LINE, nullptr)); 1028 g_assert_cmpstr(range->content, ==, "Text of first sentence. This is the second sentence.\n"); 1029 g_assert_cmpint(range->start_offset, ==, 0); 1030 g_assert_cmpint(range->end_offset, ==, 53); 1031 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 83, ATSPI_TEXT_GRANULARITY_LINE, nullptr)); 1032 g_assert_cmpstr(range->content, ==, "And this is the next paragraph."); 1033 g_assert_cmpint(range->start_offset, ==, 53); 1034 g_assert_cmpint(range->end_offset, ==, 84); 1035 1036 #if USE(ATSPI) // ATK doesn't implement paragraph granularity. 1037 // Paragraph granularity. 1038 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 0, ATSPI_TEXT_GRANULARITY_PARAGRAPH, nullptr)); 1039 g_assert_cmpstr(range->content, ==, "Text of first sentence. This is the second sentence."); 1040 g_assert_cmpint(range->start_offset, ==, 0); 1041 g_assert_cmpint(range->end_offset, ==, 52); 1042 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(p.get()), 83, ATSPI_TEXT_GRANULARITY_PARAGRAPH, nullptr)); 1043 g_assert_cmpstr(range->content, ==, "And this is the next paragraph."); 1044 g_assert_cmpint(range->start_offset, ==, 53); 1045 g_assert_cmpint(range->end_offset, ==, 84); 1046 #endif 1047 1048 // Using a text control now. 1049 test->loadHtml( 1050 "<html>" 1051 " <body>" 1052 " <input value='Text of input field'/>" 1053 " </body>" 1054 "</html>", 1055 nullptr); 1056 test->waitUntilLoadFinished(); 1057 1058 documentWeb = test->findDocumentWeb(testApp.get()); 1059 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 1060 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1); 1061 1062 auto section = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 1063 g_assert_true(ATSPI_IS_ACCESSIBLE(section.get())); 1064 g_assert_cmpint(atspi_accessible_get_child_count(section.get(), nullptr), ==, 1); 1065 auto input = adoptGRef(atspi_accessible_get_child_at_index(section.get(), 0, nullptr)); 1066 g_assert_true(ATSPI_IS_TEXT(input.get())); 1067 length = atspi_text_get_character_count(ATSPI_TEXT(input.get()), nullptr); 1068 g_assert_cmpint(length, ==, 19); 1069 text.reset(atspi_text_get_text(ATSPI_TEXT(input.get()), 0, length, nullptr)); 1070 g_assert_cmpstr(text.get(), ==, "Text of input field"); 1071 1072 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(input.get()), 0, ATSPI_TEXT_GRANULARITY_CHAR, nullptr)); 1073 g_assert_cmpstr(range->content, ==, "T"); 1074 g_assert_cmpint(range->start_offset, ==, 0); 1075 g_assert_cmpint(range->end_offset, ==, 1); 1076 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(input.get()), 18, ATSPI_TEXT_GRANULARITY_CHAR, nullptr)); 1077 g_assert_cmpstr(range->content, ==, "d"); 1078 g_assert_cmpint(range->start_offset, ==, 18); 1079 g_assert_cmpint(range->end_offset, ==, 19); 1080 1081 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(input.get()), 0, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 1082 g_assert_cmpstr(range->content, ==, "Text "); 1083 g_assert_cmpint(range->start_offset, ==, 0); 1084 g_assert_cmpint(range->end_offset, ==, 5); 1085 range.reset(atspi_text_get_string_at_offset(ATSPI_TEXT(input.get()), 16, ATSPI_TEXT_GRANULARITY_WORD, nullptr)); 1086 g_assert_cmpstr(range->content, ==, "field"); 1087 g_assert_cmpint(range->start_offset, ==, 14); 1088 g_assert_cmpint(range->end_offset, ==, 19); 1089 } 1090 1091 static void testTextExtents(AccessibilityTest* test, gconstpointer) 1092 { 1093 test->showInWindow(); 1094 test->loadHtml( 1095 "<html>" 1096 " <body>" 1097 " <p>Text</p>" 1098 " </body>" 1099 "</html>", 1100 nullptr); 1101 test->waitUntilLoadFinished(); 1102 1103 auto testApp = test->findTestApplication(); 1104 g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get())); 1105 1106 auto documentWeb = test->findDocumentWeb(testApp.get()); 1107 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 1108 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1); 1109 1110 auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 1111 g_assert_true(ATSPI_IS_TEXT(p.get())); 1112 GUniquePtr<AtspiRect> firstCharRect(atspi_text_get_character_extents(ATSPI_TEXT(p.get()), 0, ATSPI_COORD_TYPE_WINDOW, nullptr)); 1113 g_assert_nonnull(firstCharRect.get()); 1114 g_assert_cmpuint(firstCharRect->x, >, 0); 1115 g_assert_cmpuint(firstCharRect->y, >, 0); 1116 g_assert_cmpuint(firstCharRect->width, >, 0); 1117 g_assert_cmpuint(firstCharRect->height, >, 0); 1118 GUniquePtr<AtspiRect> lastCharRect(atspi_text_get_character_extents(ATSPI_TEXT(p.get()), 3, ATSPI_COORD_TYPE_WINDOW, nullptr)); 1119 g_assert_nonnull(lastCharRect.get()); 1120 g_assert_cmpuint(lastCharRect->x, >, firstCharRect->x); 1121 g_assert_cmpuint(lastCharRect->y, ==, firstCharRect->y); 1122 g_assert_cmpuint(lastCharRect->width, >, 0); 1123 g_assert_cmpuint(lastCharRect->height, >, 0); 1124 GUniquePtr<AtspiRect> rangeRect(atspi_text_get_range_extents(ATSPI_TEXT(p.get()), 0, 4, ATSPI_COORD_TYPE_WINDOW, nullptr)); 1125 g_assert_nonnull(rangeRect.get()); 1126 g_assert_cmpuint(rangeRect->x, ==, firstCharRect->x); 1127 g_assert_cmpuint(rangeRect->y, ==, firstCharRect->y); 1128 g_assert_cmpuint(rangeRect->width, >, 0); 1129 g_assert_cmpuint(rangeRect->height, >, 0); 1130 #if USE(ATSPI) // Offset at point is broken with ATK. 1131 auto offset = atspi_text_get_offset_at_point(ATSPI_TEXT(p.get()), firstCharRect->x, firstCharRect->y, ATSPI_COORD_TYPE_WINDOW, nullptr); 1132 g_assert_cmpint(offset, ==, 0); 1133 offset = atspi_text_get_offset_at_point(ATSPI_TEXT(p.get()), firstCharRect->x + firstCharRect->width, firstCharRect->y, ATSPI_COORD_TYPE_WINDOW, nullptr); 1134 g_assert_cmpint(offset, ==, 1); 1135 offset = atspi_text_get_offset_at_point(ATSPI_TEXT(p.get()), lastCharRect->x, lastCharRect->y, ATSPI_COORD_TYPE_WINDOW, nullptr); 1136 g_assert_cmpint(offset, ==, 3); 1137 offset = atspi_text_get_offset_at_point(ATSPI_TEXT(p.get()), lastCharRect->x + lastCharRect->width, lastCharRect->y, ATSPI_COORD_TYPE_WINDOW, nullptr); 1138 g_assert_cmpint(offset, ==, 4); 1139 #endif 1140 } 1141 1142 static void testTextSelections(AccessibilityTest* test, gconstpointer) 1143 { 1144 test->showInWindow(800, 600); 1145 test->loadHtml( 1146 "<html>" 1147 " <body>" 1148 " <p>This is a line of text</p>" 1149 " <input value='This is text input value'/>" 1150 " </body>" 1151 "</html>", 1152 nullptr); 1153 test->waitUntilLoadFinished(); 1154 1155 auto testApp = test->findTestApplication(); 1156 g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get())); 1157 1158 auto documentWeb = test->findDocumentWeb(testApp.get()); 1159 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 1160 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 2); 1161 1162 auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 1163 g_assert_true(ATSPI_IS_TEXT(p.get())); 1164 1165 auto selectionCount = atspi_text_get_n_selections(ATSPI_TEXT(p.get()), nullptr); 1166 g_assert_cmpuint(selectionCount, ==, 0); 1167 auto caretOffset = atspi_text_get_caret_offset(ATSPI_TEXT(p.get()), nullptr); 1168 #if USE(ATSPI) 1169 g_assert_cmpint(caretOffset, ==, -1); 1170 #else 1171 g_assert_cmpint(caretOffset, ==, 0); 1172 #endif 1173 1174 GUniquePtr<AtspiRange> selection(atspi_text_get_selection(ATSPI_TEXT(p.get()), 0, nullptr)); 1175 g_assert_nonnull(selection.get()); 1176 g_assert_cmpint(selection->start_offset, ==, 0); 1177 g_assert_cmpint(selection->end_offset, ==, 0); 1178 1179 g_assert_true(atspi_text_set_selection(ATSPI_TEXT(p.get()), 0, 5, 14, nullptr)); 1180 selectionCount = atspi_text_get_n_selections(ATSPI_TEXT(p.get()), nullptr); 1181 g_assert_cmpuint(selectionCount, ==, 1); 1182 caretOffset = atspi_text_get_caret_offset(ATSPI_TEXT(p.get()), nullptr); 1183 g_assert_cmpint(caretOffset, ==, 14); 1184 selection.reset(atspi_text_get_selection(ATSPI_TEXT(p.get()), 0, nullptr)); 1185 g_assert_nonnull(selection.get()); 1186 g_assert_cmpint(selection->start_offset, ==, 5); 1187 g_assert_cmpint(selection->end_offset, ==, 14); 1188 GUniquePtr<char> text(atspi_text_get_text(ATSPI_TEXT(p.get()), selection->start_offset, selection->end_offset, nullptr)); 1189 g_assert_cmpstr(text.get(), ==, "is a line"); 1190 1191 g_assert_true(atspi_text_remove_selection(ATSPI_TEXT(p.get()), 0, nullptr)); 1192 selectionCount = atspi_text_get_n_selections(ATSPI_TEXT(p.get()), nullptr); 1193 g_assert_cmpuint(selectionCount, ==, 0); 1194 caretOffset = atspi_text_get_caret_offset(ATSPI_TEXT(p.get()), nullptr); 1195 g_assert_cmpint(caretOffset, ==, 14); 1196 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(p.get()), 0, nullptr)); 1197 caretOffset = atspi_text_get_caret_offset(ATSPI_TEXT(p.get()), nullptr); 1198 g_assert_cmpint(caretOffset, ==, 0); 1199 1200 auto section = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 1, nullptr)); 1201 g_assert_true(ATSPI_IS_ACCESSIBLE(section.get())); 1202 g_assert_cmpint(atspi_accessible_get_child_count(section.get(), nullptr), ==, 1); 1203 auto input = adoptGRef(atspi_accessible_get_child_at_index(section.get(), 0, nullptr)); 1204 g_assert_true(ATSPI_IS_TEXT(input.get())); 1205 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(input.get()), 5, nullptr)); 1206 caretOffset = atspi_text_get_caret_offset(ATSPI_TEXT(input.get()), nullptr); 1207 g_assert_cmpint(caretOffset, ==, 5); 1208 g_assert_true(atspi_text_set_selection(ATSPI_TEXT(input.get()), 0, 5, 12, nullptr)); 1209 selectionCount = atspi_text_get_n_selections(ATSPI_TEXT(input.get()), nullptr); 1210 g_assert_cmpuint(selectionCount, ==, 1); 1211 caretOffset = atspi_text_get_caret_offset(ATSPI_TEXT(input.get()), nullptr); 1212 g_assert_cmpint(caretOffset, ==, 12); 1213 selection.reset(atspi_text_get_selection(ATSPI_TEXT(input.get()), 0, nullptr)); 1214 g_assert_nonnull(selection.get()); 1215 g_assert_cmpint(selection->start_offset, ==, 5); 1216 g_assert_cmpint(selection->end_offset, ==, 12); 1217 text.reset(atspi_text_get_text(ATSPI_TEXT(input.get()), selection->start_offset, selection->end_offset, nullptr)); 1218 g_assert_cmpstr(text.get(), ==, "is text"); 1219 } 1220 1221 static void testTextAttributes(AccessibilityTest* test, gconstpointer) 1222 { 1223 test->showInWindow(800, 600); 1224 test->loadHtml( 1225 "<html>" 1226 " <body>" 1227 " <p>This is a <b>line</b> of text</p>" 1228 " </body>" 1229 "</html>", 1230 nullptr); 1231 test->waitUntilLoadFinished(); 1232 1233 auto testApp = test->findTestApplication(); 1234 g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get())); 1235 1236 auto documentWeb = test->findDocumentWeb(testApp.get()); 1237 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 1238 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1); 1239 1240 auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 1241 g_assert_true(ATSPI_IS_TEXT(p.get())); 1242 1243 // Including default attributes. 1244 int startOffset, endOffset; 1245 GRefPtr<GHashTable> attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 0, TRUE, &startOffset, &endOffset, nullptr)); 1246 g_assert_nonnull(attributes.get()); 1247 g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 1); 1248 g_assert_cmpstr(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "weight")), ==, "400"); 1249 g_assert_cmpint(startOffset, ==, 0); 1250 g_assert_cmpint(endOffset, ==, 10); 1251 1252 attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 12, TRUE, &startOffset, &endOffset, nullptr)); 1253 g_assert_nonnull(attributes.get()); 1254 g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 1); 1255 g_assert_cmpstr(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "weight")), ==, "700"); 1256 GUniquePtr<char> value(atspi_text_get_attribute_value(ATSPI_TEXT(p.get()), 11, const_cast<char*>("weight"), nullptr)); 1257 g_assert_cmpstr(value.get(), ==, "700"); 1258 g_assert_cmpint(startOffset, ==, 10); 1259 g_assert_cmpint(endOffset, ==, 14); 1260 1261 attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 16, TRUE, &startOffset, &endOffset, nullptr)); 1262 g_assert_nonnull(attributes.get()); 1263 g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 1); 1264 g_assert_cmpstr(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "weight")), ==, "400"); 1265 g_assert_cmpint(startOffset, ==, 14); 1266 g_assert_cmpint(endOffset, ==, 22); 1267 1268 // Without default attributes. 1269 attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 0, FALSE, &startOffset, &endOffset, nullptr)); 1270 g_assert_nonnull(attributes.get()); 1271 g_assert_cmpuint(g_hash_table_size(attributes.get()), ==, 0); 1272 g_assert_cmpint(startOffset, ==, 0); 1273 g_assert_cmpint(endOffset, ==, 10); 1274 1275 attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 12, FALSE, &startOffset, &endOffset, nullptr)); 1276 g_assert_nonnull(attributes.get()); 1277 g_assert_cmpuint(g_hash_table_size(attributes.get()), ==, 1); 1278 g_assert_cmpstr(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "weight")), ==, "700"); 1279 g_assert_cmpint(startOffset, ==, 10); 1280 g_assert_cmpint(endOffset, ==, 14); 1281 1282 attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 16, FALSE, &startOffset, &endOffset, nullptr)); 1283 g_assert_nonnull(attributes.get()); 1284 g_assert_cmpuint(g_hash_table_size(attributes.get()), ==, 0); 1285 g_assert_cmpint(startOffset, ==, 14); 1286 g_assert_cmpint(endOffset, ==, 22); 1287 1288 // Only default attributes. 1289 attributes = adoptGRef(atspi_text_get_default_attributes(ATSPI_TEXT(p.get()), nullptr)); 1290 g_assert_nonnull(attributes.get()); 1291 g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 1); 1292 g_assert_cmpstr(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "weight")), ==, "400"); 1293 1294 #if USE(ATSPI) 1295 // Atspi implementation handles ranges with the same attributes as one run. 1296 test->loadHtml( 1297 "<html>" 1298 " <body>" 1299 " <p>This is a <b>li</b><b>ne</b> of text</p>" 1300 " </body>" 1301 "</html>", 1302 nullptr); 1303 test->waitUntilLoadFinished(); 1304 1305 documentWeb = test->findDocumentWeb(testApp.get()); 1306 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 1307 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 1); 1308 1309 p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 1310 g_assert_true(ATSPI_IS_TEXT(p.get())); 1311 1312 attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 0, TRUE, &startOffset, &endOffset, nullptr)); 1313 g_assert_nonnull(attributes.get()); 1314 g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 1); 1315 g_assert_cmpstr(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "weight")), ==, "400"); 1316 g_assert_cmpint(startOffset, ==, 0); 1317 g_assert_cmpint(endOffset, ==, 10); 1318 1319 attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 12, TRUE, &startOffset, &endOffset, nullptr)); 1320 g_assert_nonnull(attributes.get()); 1321 g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 1); 1322 g_assert_cmpstr(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "weight")), ==, "700"); 1323 g_assert_cmpint(startOffset, ==, 10); 1324 g_assert_cmpint(endOffset, ==, 14); 1325 1326 attributes = adoptGRef(atspi_text_get_attribute_run(ATSPI_TEXT(p.get()), 16, TRUE, &startOffset, &endOffset, nullptr)); 1327 g_assert_nonnull(attributes.get()); 1328 g_assert_cmpuint(g_hash_table_size(attributes.get()), >, 1); 1329 g_assert_cmpstr(static_cast<const char*>(g_hash_table_lookup(attributes.get(), "weight")), ==, "400"); 1330 g_assert_cmpint(startOffset, ==, 14); 1331 g_assert_cmpint(endOffset, ==, 22); 1332 1333 #endif 1334 } 1335 1336 static void testTextStateChanged(AccessibilityTest* test, gconstpointer) 1337 { 1338 test->showInWindow(800, 600); 1339 test->loadHtml( 1340 "<html>" 1341 " <body>" 1342 " <p>This is a line of text</p>" 1343 " <input value='This is a text field'/>" 1344 " <div contenteditable=true>This is content editable</div>" 1345 " </body>" 1346 "</html>", 1347 nullptr); 1348 test->waitUntilLoadFinished(); 1349 1350 auto testApp = test->findTestApplication(); 1351 g_assert_true(ATSPI_IS_ACCESSIBLE(testApp.get())); 1352 1353 auto documentWeb = test->findDocumentWeb(testApp.get()); 1354 g_assert_true(ATSPI_IS_ACCESSIBLE(documentWeb.get())); 1355 g_assert_cmpint(atspi_accessible_get_child_count(documentWeb.get(), nullptr), ==, 3); 1356 1357 // Text caret moved. 1358 auto p = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 0, nullptr)); 1359 g_assert_true(ATSPI_IS_TEXT(p.get())); 1360 test->startEventMonitor(p.get(), { "object:text-caret-moved" }); 1361 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(p.get()), 10, nullptr)); 1362 auto events = test->stopEventMonitor(1); 1363 g_assert_cmpuint(events.size(), ==, 1); 1364 g_assert_cmpstr(events[0]->type, ==, "object:text-caret-moved"); 1365 g_assert_cmpuint(events[0]->detail1, ==, 10); 1366 1367 auto section = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 1, nullptr)); 1368 g_assert_true(ATSPI_IS_ACCESSIBLE(section.get())); 1369 g_assert_cmpint(atspi_accessible_get_child_count(section.get(), nullptr), ==, 1); 1370 auto input = adoptGRef(atspi_accessible_get_child_at_index(section.get(), 0, nullptr)); 1371 g_assert_true(ATSPI_IS_TEXT(input.get())); 1372 test->startEventMonitor(input.get(), { "object:text-caret-moved" }); 1373 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(input.get()), 5, nullptr)); 1374 events = test->stopEventMonitor(1); 1375 g_assert_cmpuint(events.size(), ==, 1); 1376 g_assert_cmpstr(events[0]->type, ==, "object:text-caret-moved"); 1377 g_assert_cmpuint(events[0]->detail1, ==, 5); 1378 1379 auto div = adoptGRef(atspi_accessible_get_child_at_index(documentWeb.get(), 2, nullptr)); 1380 g_assert_true(ATSPI_IS_TEXT(div.get())); 1381 test->startEventMonitor(div.get(), { "object:text-caret-moved" }); 1382 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(div.get()), 15, nullptr)); 1383 events = test->stopEventMonitor(1); 1384 g_assert_cmpuint(events.size(), ==, 1); 1385 g_assert_cmpstr(events[0]->type, ==, "object:text-caret-moved"); 1386 g_assert_cmpuint(events[0]->detail1, ==, 15); 1387 1388 #if USE(ATSPI) // Selection changed seems to be broken with ATK. 1389 // Selection changed. 1390 test->startEventMonitor(p.get(), { "object:text-selection-changed", "object:text-caret-moved" }); 1391 g_assert_true(atspi_text_set_selection(ATSPI_TEXT(p.get()), 0, 10, 15, nullptr)); 1392 events = test->stopEventMonitor(2); 1393 g_assert_cmpuint(events.size(), ==, 2); 1394 auto* event = AccessibilityTest::findEvent(events, "object:text-caret-moved"); 1395 g_assert_nonnull(event); 1396 g_assert_cmpuint(event->detail1, ==, 15); 1397 g_assert_nonnull(AccessibilityTest::findEvent(events, "object:text-selection-changed")); 1398 1399 test->startEventMonitor(input.get(), { "object:text-selection-changed", "object:text-caret-moved" }); 1400 g_assert_true(atspi_text_set_selection(ATSPI_TEXT(input.get()), 0, 5, 10, nullptr)); 1401 events = test->stopEventMonitor(2); 1402 g_assert_cmpuint(events.size(), ==, 2); 1403 event = AccessibilityTest::findEvent(events, "object:text-caret-moved"); 1404 g_assert_nonnull(event); 1405 g_assert_cmpuint(event->detail1, ==, 10); 1406 g_assert_nonnull(AccessibilityTest::findEvent(events, "object:text-selection-changed")); 1407 1408 test->startEventMonitor(div.get(), { "object:text-selection-changed", "object:text-caret-moved" }); 1409 g_assert_true(atspi_text_set_selection(ATSPI_TEXT(div.get()), 0, 15, 18, nullptr)); 1410 events = test->stopEventMonitor(2); 1411 g_assert_cmpuint(events.size(), ==, 2); 1412 event = AccessibilityTest::findEvent(events, "object:text-caret-moved"); 1413 g_assert_nonnull(event); 1414 g_assert_cmpuint(event->detail1, ==, 18); 1415 g_assert_nonnull(AccessibilityTest::findEvent(events, "object:text-selection-changed")); 1416 #endif 1417 1418 // Text changed. 1419 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(input.get()), 5, nullptr)); 1420 test->startEventMonitor(input.get(), { "object:text-changed:insert", "object:text-changed:delete" }); 1421 test->keyStroke(GDK_KEY_a); 1422 events = test->stopEventMonitor(1); 1423 g_assert_cmpuint(events.size(), ==, 1); 1424 g_assert_cmpstr(events[0]->type, ==, "object:text-changed:insert"); 1425 #if USE(ATSPI) 1426 g_assert_cmpuint(events[0]->detail1, ==, 5); 1427 #endif 1428 g_assert_cmpuint(events[0]->detail2, ==, 1); 1429 g_assert_true(G_VALUE_HOLDS_STRING(&events[0]->any_data)); 1430 g_assert_cmpstr(g_value_get_string(&events[0]->any_data), ==, "a"); 1431 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(input.get()), 0, nullptr)); 1432 test->startEventMonitor(input.get(), { "object:text-changed:insert", "object:text-changed:delete" }); 1433 test->keyStroke(GDK_KEY_Delete); 1434 events = test->stopEventMonitor(1); 1435 g_assert_cmpuint(events.size(), ==, 1); 1436 g_assert_cmpstr(events[0]->type, ==, "object:text-changed:delete"); 1437 g_assert_cmpuint(events[0]->detail1, ==, 0); 1438 g_assert_cmpuint(events[0]->detail2, ==, 1); 1439 g_assert_true(G_VALUE_HOLDS_STRING(&events[0]->any_data)); 1440 g_assert_cmpstr(g_value_get_string(&events[0]->any_data), ==, "T"); 1441 1442 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(div.get()), 10, nullptr)); 1443 test->startEventMonitor(div.get(), { "object:text-changed:insert", "object:text-changed:delete" }); 1444 test->keyStroke(GDK_KEY_b); 1445 events = test->stopEventMonitor(1); 1446 g_assert_cmpuint(events.size(), ==, 1); 1447 g_assert_cmpstr(events[0]->type, ==, "object:text-changed:insert"); 1448 #if USE(ATSPI) 1449 g_assert_cmpuint(events[0]->detail1, ==, 10); 1450 #endif 1451 g_assert_cmpuint(events[0]->detail2, ==, 1); 1452 g_assert_true(G_VALUE_HOLDS_STRING(&events[0]->any_data)); 1453 g_assert_cmpstr(g_value_get_string(&events[0]->any_data), ==, "b"); 1454 g_assert_true(atspi_text_set_caret_offset(ATSPI_TEXT(div.get()), 15, nullptr)); 1455 test->startEventMonitor(div.get(), { "object:text-changed:insert", "object:text-changed:delete" }); 1456 test->keyStroke(GDK_KEY_BackSpace); 1457 events = test->stopEventMonitor(1); 1458 g_assert_cmpuint(events.size(), ==, 1); 1459 g_assert_cmpstr(events[0]->type, ==, "object:text-changed:delete"); 1460 #if USE(ATSPI) 1461 g_assert_cmpuint(events[0]->detail1, ==, 14); 1462 #endif 1463 g_assert_cmpuint(events[0]->detail2, ==, 1); 1464 g_assert_true(G_VALUE_HOLDS_STRING(&events[0]->any_data)); 1465 g_assert_cmpstr(g_value_get_string(&events[0]->any_data), ==, "n"); 1466 1467 // Text replaced. 1468 g_assert_true(atspi_text_set_selection(ATSPI_TEXT(input.get()), 0, 5, 10, nullptr)); 1469 test->startEventMonitor(input.get(), { "object:text-changed:insert", "object:text-changed:delete" }); 1470 test->keyStroke(GDK_KEY_c); 1471 events = test->stopEventMonitor(2); 1472 g_assert_cmpuint(events.size(), ==, 2); 1473 g_assert_cmpstr(events[0]->type, ==, "object:text-changed:delete"); 1474 g_assert_cmpuint(events[0]->detail1, ==, 6); 1475 g_assert_cmpuint(events[0]->detail2, ==, 5); 1476 g_assert_true(G_VALUE_HOLDS_STRING(&events[0]->any_data)); 1477 g_assert_cmpstr(g_value_get_string(&events[0]->any_data), ==, "is a "); 1478 g_assert_cmpstr(events[1]->type, ==, "object:text-changed:insert"); 1479 #if USE(ATSPI) 1480 g_assert_cmpuint(events[1]->detail1, ==, 5); 1481 #endif 1482 g_assert_cmpuint(events[1]->detail2, ==, 1); 1483 g_assert_true(G_VALUE_HOLDS_STRING(&events[1]->any_data)); 1484 g_assert_cmpstr(g_value_get_string(&events[1]->any_data), ==, "c"); 1485 1486 g_assert_true(atspi_text_set_selection(ATSPI_TEXT(div.get()), 0, 10, 18, nullptr)); 1487 test->startEventMonitor(div.get(), { "object:text-changed:insert", "object:text-changed:delete" }); 1488 test->keyStroke(GDK_KEY_Delete); 1489 events = test->stopEventMonitor(1); 1490 g_assert_cmpuint(events.size(), ==, 1); 1491 g_assert_cmpstr(events[0]->type, ==, "object:text-changed:delete"); 1492 #if USE(ATSPI) 1493 g_assert_cmpuint(events[0]->detail1, ==, 10); 1494 #endif 1495 g_assert_cmpuint(events[0]->detail2, ==, 8); 1496 g_assert_true(G_VALUE_HOLDS_STRING(&events[0]->any_data)); 1497 g_assert_cmpstr(g_value_get_string(&events[0]->any_data), ==, "bntet ed"); 1498 1499 #if USE(ATSPI) 1500 // Text input value changed. 1501 test->startEventMonitor(input.get(), { "object:text-changed:insert", "object:text-changed:delete" }); 1502 test->runJavaScriptAndWaitUntilFinished("document.getElementsByTagName('input')[0].value = 'foo';", nullptr); 1503 events = test->stopEventMonitor(2); 1504 g_assert_cmpuint(events.size(), ==, 2); 1505 g_assert_cmpstr(events[0]->type, ==, "object:text-changed:delete"); 1506 g_assert_cmpuint(events[0]->detail1, ==, 0); 1507 g_assert_cmpuint(events[0]->detail2, ==, 16); 1508 g_assert_true(G_VALUE_HOLDS_STRING(&events[0]->any_data)); 1509 g_assert_cmpstr(g_value_get_string(&events[0]->any_data), ==, "his actext field"); 1510 g_assert_cmpstr(events[1]->type, ==, "object:text-changed:insert"); 1511 g_assert_cmpuint(events[1]->detail1, ==, 0); 1512 g_assert_cmpuint(events[1]->detail2, ==, 3); 1513 g_assert_true(G_VALUE_HOLDS_STRING(&events[1]->any_data)); 1514 g_assert_cmpstr(g_value_get_string(&events[1]->any_data), ==, "foo"); 1515 #endif 1516 } 1517 808 1518 void beforeAll() 809 1519 { … … 818 1528 AccessibilityTest::add("WebKitAccessibility", "component/scroll-to", testComponentScrollTo); 819 1529 #endif 1530 AccessibilityTest::add("WebKitAccessibility", "text/basic", testTextBasic); 1531 AccessibilityTest::add("WebKitAccessibility", "text/surrogate-pair", testTextSurrogatePair); 1532 AccessibilityTest::add("WebKitAccessibility", "text/iterator", testTextIterator); 1533 AccessibilityTest::add("WebKitAccessibility", "text/extents", testTextExtents); 1534 AccessibilityTest::add("WebKitAccessibility", "text/selections", testTextSelections); 1535 AccessibilityTest::add("WebKitAccessibility", "text/attributes", testTextAttributes); 1536 AccessibilityTest::add("WebKitAccessibility", "text/state-changed", testTextStateChanged); 820 1537 } 821 1538
Note:
See TracChangeset
for help on using the changeset viewer.