c5e5e6c032e29c4cf1c4282d4e4969820a1d2ce7
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / ios / AccessibilityUIElementIOS.mm
1 /*
2  * Copyright (C) 2014 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "AccessibilityCommonMac.h"
28 #import "AccessibilityNotificationHandler.h"
29 #import "AccessibilityUIElement.h"
30 #import "InjectedBundle.h"
31 #import "InjectedBundlePage.h"
32 #import <Foundation/Foundation.h>
33 #import <JavaScriptCore/JSRetainPtr.h>
34 #import <JavaScriptCore/JSStringRef.h>
35 #import <JavaScriptCore/JSStringRefCF.h>
36 #import <UIKit/UIKit.h>
37 #import <WebCore/TextGranularity.h>
38 #import <WebKit/WKBundleFrame.h>
39 #import <wtf/RetainPtr.h>
40 #import <wtf/Vector.h>
41
42 typedef void (*AXPostedNotificationCallback)(id element, NSString* notification, void* context);
43
44 @interface NSObject (UIAccessibilityHidden)
45 - (id)accessibilityHitTest:(CGPoint)point;
46 - (id)accessibilityLinkedElement;
47 - (NSRange)accessibilityColumnRange;
48 - (NSRange)accessibilityRowRange;
49 - (id)accessibilityElementForRow:(NSInteger)row andColumn:(NSInteger)column;
50 - (NSURL *)accessibilityURL;
51 - (NSArray *)accessibilityHeaderElements;
52 - (NSString *)accessibilityPlaceholderValue;
53 - (NSString *)stringForRange:(NSRange)range;
54 - (NSAttributedString *)attributedStringForRange:(NSRange)range;
55 - (NSAttributedString *)attributedStringForElement;
56 - (NSArray *)elementsForRange:(NSRange)range;
57 - (NSString *)selectionRangeString;
58 - (CGPoint)accessibilityClickPoint;
59 - (void)accessibilityModifySelection:(WebCore::TextGranularity)granularity increase:(BOOL)increase;
60 - (void)accessibilitySetPostedNotificationCallback:(AXPostedNotificationCallback)function withContext:(void*)context;
61 - (CGFloat)_accessibilityMinValue;
62 - (CGFloat)_accessibilityMaxValue;
63 - (void)_accessibilitySetValue:(NSString *)value;
64 - (void)_accessibilityActivate;
65 - (UIAccessibilityTraits)_axSelectedTrait;
66 - (UIAccessibilityTraits)_axTextAreaTrait;
67 - (UIAccessibilityTraits)_axSearchFieldTrait;
68 - (NSString *)accessibilityARIACurrentStatus;
69 - (NSUInteger)accessibilityRowCount;
70 - (NSUInteger)accessibilityColumnCount;
71 - (NSUInteger)accessibilityARIARowCount;
72 - (NSUInteger)accessibilityARIAColumnCount;
73 - (NSUInteger)accessibilityARIARowIndex;
74 - (NSUInteger)accessibilityARIAColumnIndex;
75 - (UIAccessibilityTraits)_axContainedByFieldsetTrait;
76 - (id)_accessibilityFieldsetAncestor;
77 - (BOOL)_accessibilityHasTouchEventListener;
78 - (NSString *)accessibilityExpandedTextValue;
79 - (NSString *)accessibilitySortDirection;
80 - (BOOL)accessibilityIsExpanded;
81 - (NSUInteger)accessibilityBlockquoteLevel;
82 - (NSArray *)accessibilityFindMatchingObjects:(NSDictionary *)parameters;
83 - (NSArray<NSString *> *)accessibilitySpeechHint;
84 - (BOOL)_accessibilityIsStrongPasswordField;
85 - (CGRect)accessibilityVisibleContentRect;
86
87 // TextMarker related
88 - (NSArray *)textMarkerRange;
89 - (NSInteger)lengthForTextMarkers:(NSArray *)textMarkers;
90 - (NSString *)stringForTextMarkers:(NSArray *)markers;
91 - (id)startOrEndTextMarkerForTextMarkers:(NSArray*)textMarkers isStart:(BOOL)isStart;
92 - (NSArray *)textMarkerRangeForMarkers:(NSArray *)textMarkers;
93 - (id)nextMarkerForMarker:(id)marker;
94 - (id)previousMarkerForMarker:(id)marker;
95 - (id)accessibilityObjectForTextMarker:(id)marker;
96 - (id)lineStartMarkerForMarker:(id)marker;
97 - (id)lineEndMarkerForMarker:(id)marker;
98 - (NSArray *)textMarkerRangeFromMarkers:(NSArray *)markers withText:(NSString *)text;
99 @end
100
101 @interface NSObject (WebAccessibilityObjectWrapperPrivate)
102 - (CGPathRef)_accessibilityPath;
103 @end
104
105 @implementation NSString (JSStringRefAdditions)
106
107 + (NSString *)stringWithJSStringRef:(JSStringRef)jsStringRef
108 {
109     if (!jsStringRef)
110         return nil;
111     
112     return CFBridgingRelease(JSStringCopyCFString(kCFAllocatorDefault, jsStringRef));
113 }
114
115 - (JSStringRef)createJSStringRef
116 {
117     return JSStringCreateWithCFString((__bridge CFStringRef)self);
118 }
119
120 @end
121
122 namespace WTR {
123
124 static void convertNSArrayToVector(NSArray* array, Vector<RefPtr<AccessibilityUIElement> >& elementVector)
125 {
126     NSUInteger count = [array count];
127     for (NSUInteger i = 0; i < count; ++i)
128         elementVector.append(AccessibilityUIElement::create([array objectAtIndex:i]));
129 }    
130
131 static JSStringRef concatenateAttributeAndValue(NSString* attribute, NSString* value)
132 {
133     Vector<UniChar> buffer([attribute length]);
134     [attribute getCharacters:buffer.data()];
135     buffer.append(':');
136     buffer.append(' ');
137     
138     Vector<UniChar> valueBuffer([value length]);
139     [value getCharacters:valueBuffer.data()];
140     buffer.appendVector(valueBuffer);
141     
142     return JSStringCreateWithCharacters(buffer.data(), buffer.size());
143 }
144     
145 AccessibilityUIElement::AccessibilityUIElement(PlatformUIElement element)
146     : m_element(element)
147     , m_notificationHandler(0)
148 {
149     // FIXME: ap@webkit.org says ObjC objects need to be CFRetained/CFRelease to be GC-compliant on the mac.
150     [m_element retain];
151 }
152
153 AccessibilityUIElement::AccessibilityUIElement(const AccessibilityUIElement& other)
154     : JSWrappable()
155     , m_element(other.m_element)
156     , m_notificationHandler(0)
157 {
158     [m_element retain];
159 }
160
161 AccessibilityUIElement::~AccessibilityUIElement()
162 {
163     [m_element release];
164 }
165
166 bool AccessibilityUIElement::isEqual(AccessibilityUIElement* otherElement)
167 {
168     if (!otherElement)
169         return false;
170     return platformUIElement() == otherElement->platformUIElement();
171 }
172
173 RefPtr<AccessibilityUIElement> AccessibilityUIElement::headerElementAtIndex(unsigned index)
174 {
175     NSArray *headers = [m_element accessibilityHeaderElements];
176     if (index < [headers count])
177         return AccessibilityUIElement::create([headers objectAtIndex:index]);
178     
179     return nullptr;
180 }
181
182 RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedElement()
183 {
184     id linkedElement = [m_element accessibilityLinkedElement];
185     if (linkedElement)
186         return AccessibilityUIElement::create(linkedElement);
187     
188     return nullptr;
189 }
190
191 void AccessibilityUIElement::getLinkedUIElements(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
192 {
193 }
194
195 void AccessibilityUIElement::getDocumentLinks(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
196 {
197 }
198
199 void AccessibilityUIElement::getChildren(Vector<RefPtr<AccessibilityUIElement> >& elementVector)
200 {
201     NSInteger childCount = [m_element accessibilityElementCount];
202     for (NSInteger k = 0; k < childCount; ++k)
203         elementVector.append(AccessibilityUIElement::create([m_element accessibilityElementAtIndex:k]));
204 }
205
206 void AccessibilityUIElement::getChildrenWithRange(Vector<RefPtr<AccessibilityUIElement> >& elementVector, unsigned location, unsigned length)
207 {
208     NSUInteger childCount = [m_element accessibilityElementCount];
209     for (NSUInteger k = location; k < childCount && k < (location+length); ++k)
210         elementVector.append(AccessibilityUIElement::create([m_element accessibilityElementAtIndex:k]));
211 }
212
213 int AccessibilityUIElement::childrenCount()
214 {
215     Vector<RefPtr<AccessibilityUIElement>> children;
216     getChildren(children);
217
218     return children.size();
219 }
220
221 RefPtr<AccessibilityUIElement> AccessibilityUIElement::elementAtPoint(int x, int y)
222 {
223     id element = [m_element accessibilityHitTest:CGPointMake(x, y)];
224     if (!element)
225         return nil;
226     
227     return AccessibilityUIElement::create(element);
228 }
229     
230 static JSValueRef convertElementsToObjectArray(JSContextRef context, Vector<RefPtr<AccessibilityUIElement>>& elements)
231 {
232     JSValueRef arrayResult = JSObjectMakeArray(context, 0, nullptr, nullptr);
233     JSObjectRef arrayObj = JSValueToObject(context, arrayResult, nullptr);
234     size_t elementCount = elements.size();
235     for (size_t i = 0; i < elementCount; ++i)
236         JSObjectSetPropertyAtIndex(context, arrayObj, i, JSObjectMake(context, elements[i]->wrapperClass(), elements[i].get()), nullptr);
237     
238     return arrayResult;
239 }
240
241 JSValueRef AccessibilityUIElement::elementsForRange(unsigned location, unsigned length)
242 {
243     WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::singleton().page()->page());
244     JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
245
246     NSArray *elementsForRange = [m_element elementsForRange:NSMakeRange(location, length)];
247     Vector<RefPtr<AccessibilityUIElement>> elements;
248     convertNSArrayToVector(elementsForRange, elements);
249     return convertElementsToObjectArray(context, elements);
250 }
251
252 unsigned AccessibilityUIElement::indexOfChild(AccessibilityUIElement* element)
253 {
254     return 0;
255 }
256
257 RefPtr<AccessibilityUIElement> AccessibilityUIElement::childAtIndex(unsigned index)
258 {
259     Vector<RefPtr<AccessibilityUIElement> > children;
260     getChildrenWithRange(children, index, 1);
261
262     if (children.size() == 1)
263         return children[0];
264     return nullptr;
265 }
266
267 RefPtr<AccessibilityUIElement> AccessibilityUIElement::linkedUIElementAtIndex(unsigned index)
268 {
269     return nullptr;
270 }
271
272 RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaOwnsElementAtIndex(unsigned index)
273 {
274     return nullptr;
275 }
276
277 RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaFlowToElementAtIndex(unsigned index)
278 {
279     return 0;
280 }
281
282 RefPtr<AccessibilityUIElement> AccessibilityUIElement::ariaControlsElementAtIndex(unsigned index)
283 {
284     return 0;
285 }
286
287 RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedRowAtIndex(unsigned index)
288 {
289     return 0;
290 }
291
292 RefPtr<AccessibilityUIElement> AccessibilityUIElement::rowAtIndex(unsigned index)
293 {
294     return 0;
295 }
296
297 RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedChildAtIndex(unsigned index) const
298 {
299     return nullptr;
300 }
301
302 unsigned AccessibilityUIElement::selectedChildrenCount() const
303 {
304     return 0;
305 }
306
307 RefPtr<AccessibilityUIElement> AccessibilityUIElement::selectedRowAtIndex(unsigned index)
308 {
309     return nullptr;
310 }
311
312 RefPtr<AccessibilityUIElement> AccessibilityUIElement::titleUIElement()
313 {
314     return nullptr;
315 }
316
317 RefPtr<AccessibilityUIElement> AccessibilityUIElement::parentElement()
318 {
319     return nil;
320 }
321
322 RefPtr<AccessibilityUIElement> AccessibilityUIElement::disclosedByRow()
323 {
324     return nullptr;
325 }
326
327 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfLinkedUIElements()
328 {
329     return JSStringCreateWithCharacters(0, 0);
330 }
331
332 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfDocumentLinks()
333 {
334     return JSStringCreateWithCharacters(0, 0);
335 }
336
337 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfChildren()
338 {
339     return JSStringCreateWithCharacters(0, 0);
340 }
341
342 JSRetainPtr<JSStringRef> AccessibilityUIElement::allAttributes()
343 {
344     return JSStringCreateWithCharacters(0, 0);
345 }
346
347 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringAttributeValue(JSStringRef attribute)
348 {
349     if (JSStringIsEqualToUTF8CString(attribute, "AXPlaceholderValue"))
350         return [[m_element accessibilityPlaceholderValue] createJSStringRef];
351     
352     if (JSStringIsEqualToUTF8CString(attribute, "AXARIACurrent"))
353         return [[m_element accessibilityARIACurrentStatus] createJSStringRef];
354
355     if (JSStringIsEqualToUTF8CString(attribute, "AXExpandedTextValue"))
356         return [[m_element accessibilityExpandedTextValue] createJSStringRef];
357     
358     if (JSStringIsEqualToUTF8CString(attribute, "AXSortDirection"))
359         return [[m_element accessibilitySortDirection] createJSStringRef];
360     
361     if (JSStringIsEqualToUTF8CString(attribute, "AXVisibleContentRect")) {
362         CGRect screenRect = [m_element accessibilityVisibleContentRect];
363         NSString *rectStr = [NSString stringWithFormat:@"{%.2f, %.2f, %.2f, %.2f}", screenRect.origin.x, screenRect.origin.y, screenRect.size.width, screenRect.size.height];
364         return [rectStr createJSStringRef];
365     }
366
367     return JSStringCreateWithCharacters(0, 0);
368 }
369
370 double AccessibilityUIElement::numberAttributeValue(JSStringRef attribute)
371 {
372     // Support test for table related attributes.
373     if (JSStringIsEqualToUTF8CString(attribute, "AXARIAColumnCount"))
374         return [m_element accessibilityARIAColumnCount];
375     if (JSStringIsEqualToUTF8CString(attribute, "AXARIARowCount"))
376         return [m_element accessibilityARIARowCount];
377     if (JSStringIsEqualToUTF8CString(attribute, "AXARIAColumnIndex"))
378         return [m_element accessibilityARIAColumnIndex];
379     if (JSStringIsEqualToUTF8CString(attribute, "AXARIARowIndex"))
380         return [m_element accessibilityARIARowIndex];
381     if (JSStringIsEqualToUTF8CString(attribute, "AXBlockquoteLevel"))
382         return [m_element accessibilityBlockquoteLevel];
383     
384     return 0;
385 }
386
387 JSValueRef AccessibilityUIElement::uiElementArrayAttributeValue(JSStringRef attribute) const
388 {
389     return nullptr;
390 }
391
392 JSValueRef AccessibilityUIElement::rowHeaders() const
393 {
394     return nullptr;
395 }
396
397 JSValueRef AccessibilityUIElement::columnHeaders() const
398 {
399     return nullptr;
400 }
401
402 RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementAttributeValue(JSStringRef attribute) const
403 {
404     return nullptr;
405 }
406
407 bool AccessibilityUIElement::boolAttributeValue(JSStringRef attribute)
408 {
409     if (JSStringIsEqualToUTF8CString(attribute, "AXHasTouchEventListener"))
410         return [m_element _accessibilityHasTouchEventListener];
411     if (JSStringIsEqualToUTF8CString(attribute, "AXIsStrongPasswordField"))
412         return [m_element _accessibilityIsStrongPasswordField];
413     return false;
414 }
415
416 bool AccessibilityUIElement::isAttributeSettable(JSStringRef attribute)
417 {
418     return false;
419 }
420
421 bool AccessibilityUIElement::isAttributeSupported(JSStringRef attribute)
422 {
423     return false;
424 }
425
426 JSRetainPtr<JSStringRef> AccessibilityUIElement::parameterizedAttributeNames()
427 {
428     return JSStringCreateWithCharacters(0, 0);
429 }
430
431 JSRetainPtr<JSStringRef> AccessibilityUIElement::role()
432 {
433     return JSStringCreateWithCharacters(0, 0);
434 }
435
436 JSRetainPtr<JSStringRef> AccessibilityUIElement::subrole()
437 {
438     return JSStringCreateWithCharacters(0, 0);
439 }
440
441 JSRetainPtr<JSStringRef> AccessibilityUIElement::roleDescription()
442 {
443     return JSStringCreateWithCharacters(0, 0);
444 }
445
446 JSRetainPtr<JSStringRef> AccessibilityUIElement::computedRoleString()
447 {
448     // FIXME: implement
449     return JSStringCreateWithCharacters(0, 0);
450 }
451
452 JSRetainPtr<JSStringRef> AccessibilityUIElement::title()
453 {
454     return JSStringCreateWithCharacters(0, 0);
455 }
456
457 JSRetainPtr<JSStringRef> AccessibilityUIElement::description()
458 {
459     return concatenateAttributeAndValue(@"AXLabel", [m_element accessibilityLabel]);
460 }
461
462 JSRetainPtr<JSStringRef> AccessibilityUIElement::orientation() const
463 {
464     return JSStringCreateWithCharacters(0, 0);
465 }
466
467 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringValue()
468 {
469     return concatenateAttributeAndValue(@"AXValue", [m_element accessibilityValue]);
470 }
471
472 JSRetainPtr<JSStringRef> AccessibilityUIElement::language()
473 {
474     return JSStringCreateWithCharacters(0, 0);
475 }
476
477 JSRetainPtr<JSStringRef> AccessibilityUIElement::helpText() const
478 {
479     return concatenateAttributeAndValue(@"AXHint", [m_element accessibilityHint]);
480 }
481
482 double AccessibilityUIElement::x()
483 {
484     CGRect frame = [m_element accessibilityFrame];
485     return frame.origin.x;
486 }
487
488 double AccessibilityUIElement::y()
489 {
490     CGRect frame = [m_element accessibilityFrame];
491     return frame.origin.y;
492 }
493
494 double AccessibilityUIElement::width()
495 {
496     CGRect frame = [m_element accessibilityFrame];
497     return frame.size.width;
498 }
499
500 double AccessibilityUIElement::height()
501 {
502     CGRect frame = [m_element accessibilityFrame];
503     return frame.size.height;
504 }
505
506 double AccessibilityUIElement::clickPointX()
507 {
508     return [m_element accessibilityClickPoint].x;
509 }
510
511 double AccessibilityUIElement::clickPointY()
512 {
513     return [m_element accessibilityClickPoint].y;
514 }
515
516 double AccessibilityUIElement::intValue() const
517 {
518     return 0;
519 }
520
521 double AccessibilityUIElement::minValue()
522 {
523     return [m_element _accessibilityMinValue];
524 }
525
526 double AccessibilityUIElement::maxValue()
527 {
528     return [m_element _accessibilityMaxValue];
529 }
530
531
532 JSRetainPtr<JSStringRef> AccessibilityUIElement::valueDescription()
533 {
534     return JSStringCreateWithCharacters(0, 0);
535 }
536
537 int AccessibilityUIElement::insertionPointLineNumber()
538 {
539     return -1;
540 }
541
542 bool AccessibilityUIElement::isPressActionSupported()
543 {
544     return false;
545 }
546
547 bool AccessibilityUIElement::isIncrementActionSupported()
548 {
549     return false;
550 }
551
552 bool AccessibilityUIElement::isDecrementActionSupported()
553 {
554     return false;
555 }
556
557 bool AccessibilityUIElement::isEnabled()
558 {
559     return false;
560 }
561
562 bool AccessibilityUIElement::isRequired() const
563 {
564     return false;
565 }
566
567 bool AccessibilityUIElement::isFocused() const
568 {
569     // FIXME: implement
570     return false;
571 }
572
573 bool AccessibilityUIElement::isSelected() const
574 {
575     UIAccessibilityTraits traits = [m_element accessibilityTraits];
576     return (traits & [m_element _axSelectedTrait]) == [m_element _axSelectedTrait];
577 }
578
579 bool AccessibilityUIElement::isSelectedOptionActive() const
580 {
581     // FIXME: implement
582     return false;
583 }
584
585 bool AccessibilityUIElement::isIndeterminate() const
586 {
587     // FIXME: implement
588     return false;
589 }
590
591 bool AccessibilityUIElement::isExpanded() const
592 {
593     return [m_element accessibilityIsExpanded];
594 }
595
596 bool AccessibilityUIElement::isChecked() const
597 {
598     return false;
599 }
600
601 int AccessibilityUIElement::hierarchicalLevel() const
602 {
603     return 0;
604 }
605
606 JSRetainPtr<JSStringRef> AccessibilityUIElement::classList() const
607 {
608     return nullptr;
609 }
610
611 JSRetainPtr<JSStringRef> AccessibilityUIElement::speakAs()
612 {
613     return [[[m_element accessibilitySpeechHint] componentsJoinedByString:@", "] createJSStringRef];
614 }
615
616 bool AccessibilityUIElement::ariaIsGrabbed() const
617 {
618     return false;
619 }
620
621 JSRetainPtr<JSStringRef> AccessibilityUIElement::ariaDropEffects() const
622 {
623     return JSStringCreateWithCharacters(0, 0);
624 }
625
626 // parameterized attributes
627 int AccessibilityUIElement::lineForIndex(int index)
628 {
629     return -1;
630 }
631
632 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForLine(int line)
633 {
634     return nullptr;
635 }
636
637 JSRetainPtr<JSStringRef> AccessibilityUIElement::rangeForPosition(int x, int y)
638 {
639     return nullptr;
640 }
641
642 JSRetainPtr<JSStringRef> AccessibilityUIElement::boundsForRange(unsigned location, unsigned length)
643 {
644     return JSStringCreateWithCharacters(0, 0);
645 }
646
647 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForRange(unsigned location, unsigned length)
648 {
649     NSString *stringForRange = [m_element stringForRange:NSMakeRange(location, length)];
650     if (!stringForRange)
651         return nullptr;
652     
653     return [stringForRange createJSStringRef];
654 }
655
656 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForRange(unsigned location, unsigned length)
657 {
658     NSAttributedString *stringForRange = [m_element attributedStringForRange:NSMakeRange(location, length)];
659     if (!stringForRange)
660         return nullptr;
661     
662     return [[stringForRange description] createJSStringRef];
663 }
664
665 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForElement()
666 {
667     NSAttributedString *string = [m_element attributedStringForElement];
668     if (![string isKindOfClass:[NSAttributedString class]])
669         return nullptr;
670     
671     return [[string description] createJSStringRef];
672 }
673
674 bool AccessibilityUIElement::attributedStringRangeIsMisspelled(unsigned location, unsigned length)
675 {
676     return false;
677 }
678
679 unsigned AccessibilityUIElement::uiElementCountForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
680 {
681     return 0;
682 }
683
684 RefPtr<AccessibilityUIElement> AccessibilityUIElement::uiElementForSearchPredicate(JSContextRef context, AccessibilityUIElement *startElement, bool isDirectionNext, JSValueRef searchKey, JSStringRef searchText, bool visibleOnly, bool immediateDescendantsOnly)
685 {
686     NSDictionary *parameterizedAttribute = searchPredicateParameterizedAttributeForSearchCriteria(context, startElement, isDirectionNext, 5, searchKey, searchText, visibleOnly, immediateDescendantsOnly);
687     id value = [m_element accessibilityFindMatchingObjects:parameterizedAttribute];
688     if (![value isKindOfClass:[NSArray class]])
689         return nullptr;
690     for (id element in value) {
691         if ([element isAccessibilityElement])
692             return AccessibilityUIElement::create(element);
693     }
694     return AccessibilityUIElement::create([value firstObject]);
695 }
696
697 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectTextWithCriteria(JSContextRef, JSStringRef ambiguityResolution, JSValueRef searchStrings, JSStringRef replacementString, JSStringRef activity)
698 {
699     return nullptr;
700 }
701
702 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumnHeaders()
703 {
704     return JSStringCreateWithCharacters(0, 0);
705 }
706
707 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRowHeaders()
708 {
709     return JSStringCreateWithCharacters(0, 0);
710 }
711
712 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfColumns()
713 {
714     return JSStringCreateWithCharacters(0, 0);
715 }
716
717 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfRows()
718 {
719     return JSStringCreateWithCharacters(0, 0);
720 }
721
722 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfVisibleCells()
723 {
724     return JSStringCreateWithCharacters(0, 0);
725 }
726
727 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributesOfHeader()
728 {
729     return JSStringCreateWithCharacters(0, 0);
730 }
731
732 JSRetainPtr<JSStringRef> AccessibilityUIElement::traits()
733 {
734     return concatenateAttributeAndValue(@"AXTraits", [NSString stringWithFormat:@"%qu", [m_element accessibilityTraits]]);
735 }
736
737 JSRetainPtr<JSStringRef> AccessibilityUIElement::identifier()
738 {
739     return concatenateAttributeAndValue(@"AXIdentifier", [m_element accessibilityIdentifier]);
740 }
741
742 bool AccessibilityUIElement::hasContainedByFieldsetTrait()
743 {
744     UIAccessibilityTraits traits = [m_element accessibilityTraits];
745     return (traits & [m_element _axContainedByFieldsetTrait]) == [m_element _axContainedByFieldsetTrait];
746 }
747
748 RefPtr<AccessibilityUIElement> AccessibilityUIElement::fieldsetAncestorElement()
749 {
750     id ancestorElement = [m_element _accessibilityFieldsetAncestor];
751     if (ancestorElement)
752         return AccessibilityUIElement::create(ancestorElement);
753     
754     return nullptr;
755 }
756
757 bool AccessibilityUIElement::isTextArea() const
758 {
759     return ([m_element accessibilityTraits] & [m_element _axTextAreaTrait]) == [m_element _axTextAreaTrait];
760 }
761
762 bool AccessibilityUIElement::isSearchField() const
763 {
764     return ([m_element accessibilityTraits] & [m_element _axSearchFieldTrait]) == [m_element _axSearchFieldTrait];
765 }
766     
767 int AccessibilityUIElement::rowCount()
768 {
769     return [m_element accessibilityRowCount];
770 }
771
772 int AccessibilityUIElement::columnCount()
773 {
774     return [m_element accessibilityColumnCount];
775 }
776
777 int AccessibilityUIElement::indexInTable()
778 {
779     return -1;
780 }
781
782 JSRetainPtr<JSStringRef> AccessibilityUIElement::rowIndexRange()
783 {
784     NSRange range = [m_element accessibilityRowRange];
785     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length];
786     return [rangeDescription createJSStringRef];
787 }
788
789 JSRetainPtr<JSStringRef> AccessibilityUIElement::columnIndexRange()
790 {
791     NSRange range = [m_element accessibilityColumnRange];
792     NSMutableString* rangeDescription = [NSMutableString stringWithFormat:@"{%lu, %lu}", (unsigned long)range.location, (unsigned long)range.length];
793     return [rangeDescription createJSStringRef];
794 }
795
796 RefPtr<AccessibilityUIElement> AccessibilityUIElement::cellForColumnAndRow(unsigned col, unsigned row)
797 {
798     return AccessibilityUIElement::create([m_element accessibilityElementForRow:row andColumn:col]);
799 }
800
801 RefPtr<AccessibilityUIElement> AccessibilityUIElement::horizontalScrollbar() const
802 {
803     return nullptr;
804 }
805
806 RefPtr<AccessibilityUIElement> AccessibilityUIElement::verticalScrollbar() const
807 {
808     return nullptr;
809 }
810
811 void AccessibilityUIElement::scrollToMakeVisible()
812 {
813 }
814     
815 void AccessibilityUIElement::scrollToGlobalPoint(int x, int y)
816 {
817 }
818     
819 void AccessibilityUIElement::scrollToMakeVisibleWithSubFocus(int x, int y, int width, int height)
820 {
821 }
822
823 JSRetainPtr<JSStringRef> AccessibilityUIElement::selectedTextRange()
824 {
825     return JSStringCreateWithCharacters(0, 0);
826 }
827
828 bool AccessibilityUIElement::setSelectedVisibleTextRange(AccessibilityTextMarkerRange*)
829 {
830     return false;
831 }
832
833 bool AccessibilityUIElement::setSelectedTextRange(unsigned location, unsigned length)
834 {
835     return false;
836 }
837
838 void AccessibilityUIElement::increment()
839 {
840     [m_element accessibilityIncrement];
841 }
842
843 void AccessibilityUIElement::decrement()
844 {
845     [m_element accessibilityDecrement];
846 }
847
848 void AccessibilityUIElement::showMenu()
849 {
850 }
851
852 void AccessibilityUIElement::press()
853 {
854     [m_element _accessibilityActivate];
855 }
856     
857 bool AccessibilityUIElement::dismiss()
858 {
859     return [m_element accessibilityPerformEscape];
860 }
861
862 void AccessibilityUIElement::setSelectedChild(AccessibilityUIElement* element) const
863 {
864 }
865
866 void AccessibilityUIElement::setSelectedChildAtIndex(unsigned index) const
867 {
868 }
869
870 void AccessibilityUIElement::removeSelectionAtIndex(unsigned index) const
871 {
872 }
873
874 void AccessibilityUIElement::clearSelectedChildren() const
875 {
876     // FIXME: implement
877 }
878
879 JSRetainPtr<JSStringRef> AccessibilityUIElement::accessibilityValue() const
880 {
881     // FIXME: implement
882     return JSStringCreateWithCharacters(0, 0);
883 }
884
885 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentEncoding()
886 {
887     return JSStringCreateWithCharacters(0, 0);
888 }
889
890 JSRetainPtr<JSStringRef> AccessibilityUIElement::documentURI()
891 {
892     return JSStringCreateWithCharacters(0, 0);
893 }
894
895 void AccessibilityUIElement::assistiveTechnologySimulatedFocus()
896 {
897     [m_element accessibilityElementDidBecomeFocused];
898 }
899     
900 bool AccessibilityUIElement::scrollPageUp()
901 {
902     return [m_element accessibilityScroll:UIAccessibilityScrollDirectionUp];
903 }
904
905 bool AccessibilityUIElement::scrollPageDown()
906 {
907     return [m_element accessibilityScroll:UIAccessibilityScrollDirectionDown];
908 }
909 bool AccessibilityUIElement::scrollPageLeft()
910 {
911     return [m_element accessibilityScroll:UIAccessibilityScrollDirectionLeft];
912 }
913
914 bool AccessibilityUIElement::scrollPageRight()
915 {
916     return [m_element accessibilityScroll:UIAccessibilityScrollDirectionRight];
917 }
918
919 void AccessibilityUIElement::increaseTextSelection()
920 {
921     [m_element accessibilityModifySelection:WebCore::CharacterGranularity increase:YES];
922 }
923
924 void AccessibilityUIElement::decreaseTextSelection()
925 {
926     [m_element accessibilityModifySelection:WebCore::CharacterGranularity increase:NO];
927 }
928
929 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForSelection()
930 {
931     NSString *stringForRange = [m_element selectionRangeString];
932     if (!stringForRange)
933         return nullptr;
934     
935     return [stringForRange createJSStringRef];
936 }
937     
938 int AccessibilityUIElement::elementTextPosition()
939 {
940     NSRange range = [[m_element valueForKey:@"elementTextRange"] rangeValue];
941     return range.location;
942 }
943
944 int AccessibilityUIElement::elementTextLength()
945 {
946     NSRange range = [[m_element valueForKey:@"elementTextRange"] rangeValue];
947     return range.length;    
948 }
949     
950 JSRetainPtr<JSStringRef> AccessibilityUIElement::url()
951 {
952     NSURL *url = [m_element accessibilityURL];
953     return [[url absoluteString] createJSStringRef];
954 }
955
956 bool AccessibilityUIElement::addNotificationListener(JSValueRef functionCallback)
957 {
958     if (!functionCallback)
959         return false;
960     
961     // iOS programmers should not be adding more than one notification listener per element.
962     // Other platforms may be different.
963     if (m_notificationHandler)
964         return false;
965     m_notificationHandler = [[AccessibilityNotificationHandler alloc] init];
966     [m_notificationHandler setPlatformElement:platformUIElement()];
967     [m_notificationHandler setCallback:functionCallback];
968     [m_notificationHandler startObserving];
969     
970     return true;
971 }
972
973 bool AccessibilityUIElement::removeNotificationListener()
974 {
975     // iOS programmers should not be trying to remove a listener that's already removed.
976     ASSERT(m_notificationHandler);
977     
978     [m_notificationHandler stopObserving];
979     [m_notificationHandler release];
980     m_notificationHandler = nil;
981     
982     return true;
983 }
984
985 bool AccessibilityUIElement::isFocusable() const
986 {
987     return false;
988 }
989
990 bool AccessibilityUIElement::isSelectable() const
991 {
992     // FIXME: implement
993     return false;
994 }
995
996 bool AccessibilityUIElement::isMultiSelectable() const
997 {
998     // FIXME: implement
999     return false;
1000 }
1001
1002 bool AccessibilityUIElement::isVisible() const
1003 {
1004     // FIXME: implement
1005     return false;
1006 }
1007
1008 bool AccessibilityUIElement::isOffScreen() const
1009 {
1010     // FIXME: implement
1011     return false;
1012 }
1013
1014 bool AccessibilityUIElement::isCollapsed() const
1015 {
1016     // FIXME: implement
1017     return false;
1018 }
1019
1020 bool AccessibilityUIElement::isIgnored() const
1021 {
1022     bool isAccessibilityElement = [m_element isAccessibilityElement];
1023     return !isAccessibilityElement;
1024 }
1025
1026 bool AccessibilityUIElement::isSingleLine() const
1027 {
1028     // FIXME: implement
1029     return false;
1030 }
1031
1032 bool AccessibilityUIElement::isMultiLine() const
1033 {
1034     // FIXME: implement
1035     return false;
1036 }
1037
1038 bool AccessibilityUIElement::hasPopup() const
1039 {
1040     return false;
1041 }
1042
1043 void AccessibilityUIElement::takeFocus()
1044 {
1045     // FIXME: implement
1046 }
1047
1048 void AccessibilityUIElement::takeSelection()
1049 {
1050     // FIXME: implement
1051 }
1052
1053 void AccessibilityUIElement::addSelection()
1054 {
1055     // FIXME: implement
1056 }
1057
1058 void AccessibilityUIElement::removeSelection()
1059 {
1060     // FIXME: implement
1061 }
1062
1063 // Text markers
1064 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::lineTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1065 {
1066     id startTextMarker = [m_element lineStartMarkerForMarker:(id)textMarker->platformTextMarker()];
1067     id endTextMarker = [m_element lineEndMarkerForMarker:(id)textMarker->platformTextMarker()];
1068     NSArray *textMarkers = [NSArray arrayWithObjects:startTextMarker, endTextMarker, nil];
1069     
1070     id textMarkerRange = [m_element textMarkerRangeForMarkers:textMarkers];
1071     return AccessibilityTextMarkerRange::create(textMarkerRange);
1072 }
1073
1074 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForElement(AccessibilityUIElement* element)
1075 {
1076     id textMarkerRange = [element->platformUIElement() textMarkerRange];
1077     return AccessibilityTextMarkerRange::create(textMarkerRange);
1078 }
1079
1080 int AccessibilityUIElement::textMarkerRangeLength(AccessibilityTextMarkerRange* range)
1081 {
1082     id textMarkers = (id)range->platformTextMarkerRange();    
1083     return [m_element lengthForTextMarkers:textMarkers];
1084 }
1085
1086 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousTextMarker(AccessibilityTextMarker* textMarker)
1087 {
1088     id previousMarker = [m_element previousMarkerForMarker:(id)textMarker->platformTextMarker()];
1089     return AccessibilityTextMarker::create(previousMarker);
1090 }
1091
1092 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextTextMarker(AccessibilityTextMarker* textMarker)
1093 {
1094     id nextMarker = [m_element nextMarkerForMarker:(id)textMarker->platformTextMarker()];
1095     return AccessibilityTextMarker::create(nextMarker);
1096 }
1097
1098 JSRetainPtr<JSStringRef> AccessibilityUIElement::stringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
1099 {
1100     id textMarkers = (id)markerRange->platformTextMarkerRange();
1101     if (!textMarkers || ![textMarkers isKindOfClass:[NSArray class]])
1102         return JSStringCreateWithCharacters(0, 0);
1103     return [[m_element stringForTextMarkers:textMarkers] createJSStringRef];
1104 }
1105
1106 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
1107 {
1108     NSArray *textMarkers = [NSArray arrayWithObjects:(id)startMarker->platformTextMarker(), (id)endMarker->platformTextMarker(), nil];
1109     id textMarkerRange = [m_element textMarkerRangeForMarkers:textMarkers];
1110     return AccessibilityTextMarkerRange::create(textMarkerRange);
1111 }
1112
1113 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1114 {
1115     id textMarkers = (id)range->platformTextMarkerRange();
1116     id textMarker = [m_element startOrEndTextMarkerForTextMarkers:textMarkers isStart:YES];
1117     return AccessibilityTextMarker::create(textMarker);
1118 }
1119
1120 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange* range)
1121 {
1122     id textMarkers = (id)range->platformTextMarkerRange();
1123     id textMarker = [m_element startOrEndTextMarkerForTextMarkers:textMarkers isStart:NO];
1124     return AccessibilityTextMarker::create(textMarker);
1125 }
1126
1127 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarkerForBounds(int x, int y, int width, int height)
1128 {
1129     return nullptr;
1130 }
1131
1132 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarkerForBounds(int x, int y, int width, int height)
1133 {
1134     return nullptr;
1135 }
1136
1137 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForPoint(int x, int y)
1138 {
1139     return nullptr;
1140 }
1141
1142 RefPtr<AccessibilityUIElement> AccessibilityUIElement::accessibilityElementForTextMarker(AccessibilityTextMarker* marker)
1143 {
1144     id obj = [m_element accessibilityObjectForTextMarker:(id)marker->platformTextMarker()];
1145     if (obj)
1146         return AccessibilityUIElement::create(obj);
1147     return nullptr;
1148 }
1149
1150 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForTextMarkerRange(AccessibilityTextMarkerRange* markerRange)
1151 {
1152     return nullptr;
1153 }
1154
1155 JSRetainPtr<JSStringRef> AccessibilityUIElement::attributedStringForTextMarkerRangeWithOptions(AccessibilityTextMarkerRange* markerRange, bool)
1156 {
1157     return nullptr;
1158 }
1159
1160 bool AccessibilityUIElement::attributedStringForTextMarkerRangeContainsAttribute(JSStringRef attribute, AccessibilityTextMarkerRange* range)
1161 {
1162     return false;
1163 }
1164
1165 int AccessibilityUIElement::indexForTextMarker(AccessibilityTextMarker* marker)
1166 {
1167     return -1;
1168 }
1169
1170 bool AccessibilityUIElement::isTextMarkerValid(AccessibilityTextMarker* textMarker)
1171 {
1172     return false;
1173 }
1174
1175 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::textMarkerForIndex(int textIndex)
1176 {
1177     return nullptr;
1178 }
1179
1180 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::startTextMarker()
1181 {
1182     return nullptr;
1183 }
1184
1185 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::endTextMarker()
1186 {
1187     return nullptr;
1188 }
1189
1190 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::leftWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1191 {
1192     return nullptr;
1193 }
1194
1195 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::rightWordTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1196 {
1197     return nullptr;
1198 }
1199
1200 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousWordStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1201 {
1202     return nullptr;
1203 }
1204
1205 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextWordEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1206 {
1207     return nullptr;
1208 }
1209
1210 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::paragraphTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1211 {
1212     return nullptr;
1213 }
1214
1215 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextParagraphEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1216 {
1217     return nullptr;
1218 }
1219
1220 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousParagraphStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1221 {
1222     return nullptr;
1223 }
1224
1225 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::sentenceTextMarkerRangeForTextMarker(AccessibilityTextMarker* textMarker)
1226 {
1227     return nullptr;
1228 }
1229
1230 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::nextSentenceEndTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1231 {
1232     return nullptr;
1233 }
1234
1235 RefPtr<AccessibilityTextMarker> AccessibilityUIElement::previousSentenceStartTextMarkerForTextMarker(AccessibilityTextMarker* textMarker)
1236 {
1237     return nullptr;
1238 }
1239     
1240 RefPtr<AccessibilityTextMarkerRange> AccessibilityUIElement::textMarkerRangeMatchesTextNearMarkers(JSStringRef text, AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker)
1241 {
1242     NSArray *textMarkers = nil;
1243     if (startMarker->platformTextMarker() && endMarker->platformTextMarker())
1244         textMarkers = [NSArray arrayWithObjects:(id)startMarker->platformTextMarker(), (id)endMarker->platformTextMarker(), nil];
1245     id textMarkerRange = [m_element textMarkerRangeFromMarkers:textMarkers withText:[NSString stringWithJSStringRef:text]];
1246     return AccessibilityTextMarkerRange::create(textMarkerRange);
1247 }
1248
1249 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPostscriptsDescription() const
1250 {
1251     return nullptr;
1252 }
1253
1254 JSRetainPtr<JSStringRef> AccessibilityUIElement::mathPrescriptsDescription() const
1255 {
1256     return nullptr;
1257 }
1258
1259 static void _CGPathEnumerationIteration(void *info, const CGPathElement *element)
1260 {
1261     NSMutableString *result = (NSMutableString *)info;
1262     switch (element->type) {
1263     case kCGPathElementMoveToPoint:
1264         [result appendString:@"\tMove to point\n"];
1265         break;
1266     case kCGPathElementAddLineToPoint:
1267         [result appendString:@"\tLine to\n"];
1268         break;
1269     case kCGPathElementAddQuadCurveToPoint:
1270         [result appendString:@"\tQuad curve to\n"];
1271         break;
1272     case kCGPathElementAddCurveToPoint:
1273         [result appendString:@"\tCurve to\n"];
1274         break;
1275     case kCGPathElementCloseSubpath:
1276         [result appendString:@"\tClose\n"];
1277         break;
1278     }
1279 }
1280
1281 JSRetainPtr<JSStringRef> AccessibilityUIElement::pathDescription() const
1282 {
1283     NSMutableString *result = [NSMutableString stringWithString:@"\nStart Path\n"];
1284     CGPathRef pathRef = [m_element _accessibilityPath];
1285     
1286     CGPathApply(pathRef, result, _CGPathEnumerationIteration);
1287     
1288     return [result createJSStringRef];
1289 }
1290
1291 JSRetainPtr<JSStringRef> AccessibilityUIElement::supportedActions() const
1292 {
1293     return nullptr;
1294 }
1295
1296 } // namespace WTR
1297