1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_editeng.hxx"
26 
27 
28 #include <editeng/AccessibleContextBase.hxx>
29 
30 #include <com/sun/star/accessibility/AccessibleRole.hpp>
31 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
32 #include <com/sun/star/accessibility/XAccessibleEventListener.hpp>
33 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
34 #include <com/sun/star/accessibility/AccessibleRelationType.hpp>
35 
36 #include <unotools/accessiblestatesethelper.hxx>
37 #include <unotools/accessiblerelationsethelper.hxx>
38 #include <comphelper/accessibleeventnotifier.hxx>
39 #include <rtl/uuid.h>
40 #include <vos/mutex.hxx>
41 //#include <vcl/svapp.hxx>
42 
43 #include <utility>
44 
45 using namespace	::rtl;
46 using namespace	::com::sun::star;
47 using namespace	::com::sun::star::accessibility;
48 using ::com::sun::star::uno::Reference;
49 
50 namespace accessibility {
51 
52 //=====  internal  ============================================================
53 
54 // Define a shortcut for the somewhot longish base class name.
55 typedef ::cppu::WeakComponentImplHelper4<
56     ::com::sun::star::accessibility::XAccessible,
57     ::com::sun::star::accessibility::XAccessibleContext,
58     ::com::sun::star::accessibility::XAccessibleEventBroadcaster,
59     ::com::sun::star::lang::XServiceInfo> BaseClass;
60 
AccessibleContextBase(const uno::Reference<XAccessible> & rxParent,const sal_Int16 aRole)61 AccessibleContextBase::AccessibleContextBase (
62         const uno::Reference<XAccessible>& rxParent,
63 		const sal_Int16 aRole)
64 	:   BaseClass (MutexOwner::maMutex),
65         mxStateSet (NULL),
66         mxRelationSet (NULL),
67         mxParent(rxParent),
68         msDescription(),
69         meDescriptionOrigin(NotSet),
70         msName(),
71         meNameOrigin(NotSet),
72         mnClientId(0),
73         maRole(aRole)
74 {
75     // Create the state set.
76     ::utl::AccessibleStateSetHelper* pStateSet  = new ::utl::AccessibleStateSetHelper ();
77     mxStateSet = pStateSet;
78 
79     // Set some states.  Don't use the SetState method because no events
80     // shall be broadcastet (that is not yet initialized anyway).
81     if (pStateSet != NULL)
82     {
83         pStateSet->AddState (AccessibleStateType::ENABLED);
84         pStateSet->AddState (AccessibleStateType::SENSITIVE);
85         pStateSet->AddState (AccessibleStateType::SHOWING);
86         pStateSet->AddState (AccessibleStateType::VISIBLE);
87         pStateSet->AddState (AccessibleStateType::FOCUSABLE);
88         pStateSet->AddState (AccessibleStateType::SELECTABLE);
89     }
90 
91     // Create the relation set.
92     ::utl::AccessibleRelationSetHelper* pRelationSet = new ::utl::AccessibleRelationSetHelper ();
93     mxRelationSet = pRelationSet;
94 }
95 
96 
97 
98 
~AccessibleContextBase(void)99 AccessibleContextBase::~AccessibleContextBase(void)
100 {
101 }
102 
103 
104 
105 
SetState(sal_Int16 aState)106 sal_Bool AccessibleContextBase::SetState (sal_Int16 aState)
107 {
108     ::osl::ClearableMutexGuard aGuard (maMutex);
109     ::utl::AccessibleStateSetHelper* pStateSet =
110         static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
111     if ((pStateSet != NULL) && !pStateSet->contains(aState))
112     {
113         pStateSet->AddState (aState);
114         // Clear the mutex guard so that it is not locked during calls to
115         // listeners.
116         aGuard.clear();
117 
118         // Send event for all states except the DEFUNC state.
119         if (aState != AccessibleStateType::DEFUNC)
120         {
121             uno::Any aNewValue;
122             aNewValue <<= aState;
123             CommitChange(
124                 AccessibleEventId::STATE_CHANGED,
125                 aNewValue,
126                 uno::Any());
127         }
128         return sal_True;
129     }
130     else
131         return sal_False;
132 }
133 
134 
135 
136 
ResetState(sal_Int16 aState)137 sal_Bool AccessibleContextBase::ResetState (sal_Int16 aState)
138 {
139     ::osl::ClearableMutexGuard aGuard (maMutex);
140     ::utl::AccessibleStateSetHelper* pStateSet =
141         static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
142     if ((pStateSet != NULL) && pStateSet->contains(aState))
143     {
144         pStateSet->RemoveState (aState);
145         // Clear the mutex guard so that it is not locked during calls to listeners.
146         aGuard.clear();
147 
148         uno::Any aOldValue;
149         aOldValue <<= aState;
150         CommitChange(
151             AccessibleEventId::STATE_CHANGED,
152             uno::Any(),
153             aOldValue);
154         return sal_True;
155     }
156     else
157         return sal_False;
158 }
159 
160 
161 
162 
GetState(sal_Int16 aState)163 sal_Bool AccessibleContextBase::GetState (sal_Int16 aState)
164 {
165     ::osl::MutexGuard aGuard (maMutex);
166     ::utl::AccessibleStateSetHelper* pStateSet =
167         static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
168     if (pStateSet != NULL)
169         return pStateSet->contains(aState);
170     else
171         // If there is no state set then return false as a default value.
172         return sal_False;
173 }
174 
175 
176 
177 
SetRelationSet(const uno::Reference<XAccessibleRelationSet> & rxNewRelationSet)178 void AccessibleContextBase::SetRelationSet (
179     const uno::Reference<XAccessibleRelationSet>& rxNewRelationSet)
180     throw (::com::sun::star::uno::RuntimeException)
181 {
182     OSL_TRACE ("setting relation set");
183 
184     // Try to emit some meaningful events indicating differing relations in
185     // both sets.
186     typedef std::pair<short int,short int> RD;
187     const RD aRelationDescriptors[] = {
188         RD(AccessibleRelationType::CONTROLLED_BY, AccessibleEventId::CONTROLLED_BY_RELATION_CHANGED),
189         RD(AccessibleRelationType::CONTROLLER_FOR, AccessibleEventId::CONTROLLER_FOR_RELATION_CHANGED),
190         RD(AccessibleRelationType::LABELED_BY, AccessibleEventId::LABELED_BY_RELATION_CHANGED),
191         RD(AccessibleRelationType::LABEL_FOR, AccessibleEventId::LABEL_FOR_RELATION_CHANGED),
192         RD(AccessibleRelationType::MEMBER_OF, AccessibleEventId::MEMBER_OF_RELATION_CHANGED),
193         RD(AccessibleRelationType::INVALID, -1),
194     };
195     for (int i=0; aRelationDescriptors[i].first!=AccessibleRelationType::INVALID; i++)
196         if (mxRelationSet->containsRelation(aRelationDescriptors[i].first)
197         != rxNewRelationSet->containsRelation(aRelationDescriptors[i].first))
198         CommitChange (aRelationDescriptors[i].second, uno::Any(), uno::Any());
199 
200     mxRelationSet = rxNewRelationSet;
201 }
202 
203 
204 
205 
206 //=====  XAccessible  =========================================================
207 
208 uno::Reference< XAccessibleContext> SAL_CALL
getAccessibleContext(void)209     AccessibleContextBase::getAccessibleContext (void)
210     throw (uno::RuntimeException)
211 {
212     ThrowIfDisposed ();
213 	return this;
214 }
215 
216 
217 
218 
219 //=====  XAccessibleContext  ==================================================
220 
221 /** No children.
222 */
223 sal_Int32 SAL_CALL
getAccessibleChildCount(void)224    	AccessibleContextBase::getAccessibleChildCount (void)
225     throw (uno::RuntimeException)
226 {
227     ThrowIfDisposed ();
228     return 0;
229 }
230 
231 
232 
233 
234 /** Forward the request to the shape.  Return the requested shape or throw
235     an exception for a wrong index.
236 */
237 uno::Reference<XAccessible> SAL_CALL
getAccessibleChild(sal_Int32 nIndex)238     AccessibleContextBase::getAccessibleChild (sal_Int32 nIndex)
239     throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::uno::RuntimeException)
240 {
241     ThrowIfDisposed ();
242     throw lang::IndexOutOfBoundsException (
243         ::rtl::OUString::createFromAscii ("no child with index " + nIndex),
244 		NULL);
245 }
246 
247 
248 
249 
250 uno::Reference<XAccessible> SAL_CALL
getAccessibleParent(void)251    	AccessibleContextBase::getAccessibleParent (void)
252     throw (::com::sun::star::uno::RuntimeException)
253 {
254     ThrowIfDisposed ();
255 	return mxParent;
256 }
257 
258 
259 
260 
261 sal_Int32 SAL_CALL
getAccessibleIndexInParent(void)262    	AccessibleContextBase::getAccessibleIndexInParent (void)
263     throw (::com::sun::star::uno::RuntimeException)
264 {
265     ThrowIfDisposed ();
266 	//	Use a simple but slow solution for now.  Optimize later.
267 
268     //	Iterate over all the parent's children and search for this object.
269     if (mxParent.is())
270     {
271     	uno::Reference<XAccessibleContext> xParentContext (
272         	mxParent->getAccessibleContext());
273         if (xParentContext.is())
274         {
275         	sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
276             for (sal_Int32 i=0; i<nChildCount; i++)
277             {
278             	uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
279                 if (xChild.is())
280                 {
281                 	uno::Reference<XAccessibleContext> xChildContext = xChild->getAccessibleContext();
282 	            	if (xChildContext == (XAccessibleContext*)this)
283                     	return i;
284                 }
285             }
286         }
287    }
288 
289    //	Return -1 to indicate that this object's parent does not know about the
290    //	object.
291    return -1;
292 }
293 
294 
295 
296 
297 sal_Int16 SAL_CALL
getAccessibleRole(void)298 	AccessibleContextBase::getAccessibleRole (void)
299     throw (::com::sun::star::uno::RuntimeException)
300 {
301     ThrowIfDisposed ();
302 	return maRole;
303 }
304 
305 
306 
307 
308 ::rtl::OUString SAL_CALL
getAccessibleDescription(void)309    	AccessibleContextBase::getAccessibleDescription (void)
310     throw (::com::sun::star::uno::RuntimeException)
311 {
312     ThrowIfDisposed ();
313 
314     return msDescription;
315 }
316 
317 
318 
319 
320 OUString SAL_CALL
getAccessibleName(void)321    	AccessibleContextBase::getAccessibleName (void)
322     throw (::com::sun::star::uno::RuntimeException)
323 {
324     ThrowIfDisposed ();
325 
326     if (meNameOrigin == NotSet)
327     {
328         // Do not send an event because this is the first time it has been
329         // requested.
330         msName = CreateAccessibleName();
331         meNameOrigin = AutomaticallyCreated;
332     }
333 
334     return msName;
335 }
336 
337 
338 
339 
340 /**	Return a copy of the relation set.
341 */
342 uno::Reference<XAccessibleRelationSet> SAL_CALL
getAccessibleRelationSet(void)343    	AccessibleContextBase::getAccessibleRelationSet (void)
344     throw (::com::sun::star::uno::RuntimeException)
345 {
346     ThrowIfDisposed ();
347 
348     // Create a copy of the relation set and return it.
349     ::utl::AccessibleRelationSetHelper* pRelationSet =
350         static_cast< ::utl::AccessibleRelationSetHelper*>(mxRelationSet.get());
351     if (pRelationSet != NULL)
352     {
353         return uno::Reference<XAccessibleRelationSet> (
354             new ::utl::AccessibleRelationSetHelper (*pRelationSet));
355     }
356     else
357         return uno::Reference<XAccessibleRelationSet>(NULL);
358 }
359 
360 
361 
362 
363 /**	Return a copy of the state set.
364     Possible states are:
365 		ENABLED
366 		SHOWING
367 		VISIBLE
368 */
369 uno::Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet(void)370     AccessibleContextBase::getAccessibleStateSet (void)
371     throw (::com::sun::star::uno::RuntimeException)
372 {
373     ::utl::AccessibleStateSetHelper* pStateSet = NULL;
374 
375 	if (rBHelper.bDisposed)
376     {
377         // We are already disposed!
378         // Create a new state set that has only set the DEFUNC state.
379         pStateSet = new ::utl::AccessibleStateSetHelper ();
380         if (pStateSet != NULL)
381             pStateSet->AddState (AccessibleStateType::DEFUNC);
382     }
383     else
384     {
385         // Create a copy of the state set and return it.
386         pStateSet = static_cast< ::utl::AccessibleStateSetHelper*>(mxStateSet.get());
387 
388         // Merge current focused state from edit engine.
389 #if 0
390         if (aState == AccessibleStateType::FOCUSED
391             && pStateSet != NULL
392             && mpText != NULL)
393         {
394             if (mpText->GetFocusedState ())
395                 pStateSet->AddState (aState);
396             else
397                 pStateSet->RemoveState (aState);
398         }
399 #endif
400         if (pStateSet != NULL)
401             pStateSet = new ::utl::AccessibleStateSetHelper (*pStateSet);
402     }
403 
404     return uno::Reference<XAccessibleStateSet>(pStateSet);
405 }
406 
407 
408 
409 
410 lang::Locale SAL_CALL
getLocale(void)411    	AccessibleContextBase::getLocale (void)
412 	throw (IllegalAccessibleComponentStateException,
413         ::com::sun::star::uno::RuntimeException)
414 {
415     ThrowIfDisposed ();
416     // Delegate request to parent.
417 	if (mxParent.is())
418     {
419     	uno::Reference<XAccessibleContext> xParentContext (
420         	mxParent->getAccessibleContext());
421         if (xParentContext.is())
422 	    	return xParentContext->getLocale ();
423     }
424 
425     //	No locale and no parent.  Therefore throw exception to indicate this
426     //	cluelessness.
427     throw IllegalAccessibleComponentStateException ();
428 }
429 
430 
431 
432 
433 //=====  XAccessibleEventListener  ============================================
434 
435 void SAL_CALL
addEventListener(const uno::Reference<XAccessibleEventListener> & rxListener)436     AccessibleContextBase::addEventListener (
437         const uno::Reference<XAccessibleEventListener >& rxListener)
438     throw (uno::RuntimeException)
439 {
440 	if (rxListener.is())
441     {
442 	    if (rBHelper.bDisposed || rBHelper.bInDispose)
443 	    {
444             uno::Reference<uno::XInterface> x ((lang::XComponent *)this, uno::UNO_QUERY);
445 		    rxListener->disposing (lang::EventObject (x));
446 	    }
447 	    else
448 	    {
449 		    if (!mnClientId)
450                 mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
451 		    comphelper::AccessibleEventNotifier::addEventListener( mnClientId, rxListener );
452 	    }
453     }
454 }
455 
456 
457 
458 
459 void SAL_CALL
removeEventListener(const uno::Reference<XAccessibleEventListener> & rxListener)460     AccessibleContextBase::removeEventListener (
461         const uno::Reference<XAccessibleEventListener >& rxListener )
462     throw (uno::RuntimeException)
463 {
464     ThrowIfDisposed ();
465 	if (rxListener.is())
466 	{
467         sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, rxListener );
468 		if ( !nListenerCount )
469 		{
470 			// no listeners anymore
471 			// -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
472 			// and at least to us not firing any events anymore, in case somebody calls
473 			// NotifyAccessibleEvent, again
474 			comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
475 			mnClientId = 0;
476 		}
477 	}
478 }
479 
480 
481 
482 
483 //=====  XServiceInfo  ========================================================
484 
485 ::rtl::OUString SAL_CALL
getImplementationName(void)486    	AccessibleContextBase::getImplementationName (void)
487     throw (::com::sun::star::uno::RuntimeException)
488 {
489     ThrowIfDisposed ();
490 	return OUString(RTL_CONSTASCII_USTRINGPARAM("AccessibleContextBase"));
491 }
492 
493 
494 
495 
496 sal_Bool SAL_CALL
supportsService(const OUString & sServiceName)497  	AccessibleContextBase::supportsService (const OUString& sServiceName)
498     throw (::com::sun::star::uno::RuntimeException)
499 {
500     ThrowIfDisposed ();
501     //  Iterate over all supported service names and return true if on of them
502     //  matches the given name.
503     uno::Sequence< ::rtl::OUString> aSupportedServices (
504         getSupportedServiceNames ());
505     for (int i=0; i<aSupportedServices.getLength(); i++)
506         if (sServiceName == aSupportedServices[i])
507             return sal_True;
508     return sal_False;
509 }
510 
511 
512 
513 
514 uno::Sequence< ::rtl::OUString> SAL_CALL
getSupportedServiceNames(void)515    	AccessibleContextBase::getSupportedServiceNames (void)
516     throw (::com::sun::star::uno::RuntimeException)
517 {
518     ThrowIfDisposed ();
519 	static const OUString sServiceNames[2] = {
520         OUString(RTL_CONSTASCII_USTRINGPARAM(
521             "com.sun.star.accessibility.Accessible")),
522         OUString(RTL_CONSTASCII_USTRINGPARAM(
523             "com.sun.star.accessibility.AccessibleContext"))
524     };
525 	return uno::Sequence<OUString> (sServiceNames, 2);
526 }
527 
528 
529 
530 
531 //=====  XTypeProvider  =======================================================
532 
533 uno::Sequence< ::com::sun::star::uno::Type>
getTypes(void)534 	AccessibleContextBase::getTypes (void)
535     throw (::com::sun::star::uno::RuntimeException)
536 {
537     ThrowIfDisposed ();
538 
539     // This class supports no interfaces on its own.  Just return those
540     // supported by the base class.
541 	return BaseClass::getTypes();
542 }
543 
544 
545 
546 
547 uno::Sequence<sal_Int8> SAL_CALL
getImplementationId(void)548 	AccessibleContextBase::getImplementationId (void)
549     throw (::com::sun::star::uno::RuntimeException)
550 {
551     ThrowIfDisposed ();
552 	static uno::Sequence<sal_Int8> aId;
553 	if (aId.getLength() == 0)
554 	{
555         ::osl::MutexGuard aGuard (maMutex);
556 		aId.realloc (16);
557 		rtl_createUuid ((sal_uInt8 *)aId.getArray(), 0, sal_True);
558 	}
559 	return aId;
560 }
561 
562 
563 
564 
565 //=====  internal  ============================================================
566 
disposing(void)567 void SAL_CALL AccessibleContextBase::disposing (void)
568 {
569     SetState (AccessibleStateType::DEFUNC);
570 
571     ::osl::MutexGuard aGuard (maMutex);
572 
573     // Send a disposing to all listeners.
574 	if ( mnClientId )
575 	{
576         comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( mnClientId, *this );
577 		mnClientId =  0;
578 	}
579 }
580 
581 
582 
583 
SetAccessibleDescription(const::rtl::OUString & rDescription,StringOrigin eDescriptionOrigin)584 void AccessibleContextBase::SetAccessibleDescription (
585     const ::rtl::OUString& rDescription,
586     StringOrigin eDescriptionOrigin)
587     throw (uno::RuntimeException)
588 {
589     if (eDescriptionOrigin < meDescriptionOrigin
590         || (eDescriptionOrigin == meDescriptionOrigin && msDescription != rDescription))
591 	{
592 		uno::Any aOldValue, aNewValue;
593 		aOldValue <<= msDescription;
594 		aNewValue <<= rDescription;
595 
596 		msDescription = rDescription;
597         meDescriptionOrigin = eDescriptionOrigin;
598 
599         CommitChange(
600             AccessibleEventId::DESCRIPTION_CHANGED,
601             aNewValue,
602             aOldValue);
603 	}
604 }
605 
606 
607 
608 
SetAccessibleName(const::rtl::OUString & rName,StringOrigin eNameOrigin)609 void AccessibleContextBase::SetAccessibleName (
610     const ::rtl::OUString& rName,
611     StringOrigin eNameOrigin)
612     throw (uno::RuntimeException)
613 {
614     if (eNameOrigin < meNameOrigin
615         || (eNameOrigin == meNameOrigin && msName != rName))
616 	{
617 		uno::Any aOldValue, aNewValue;
618 		aOldValue <<= msName;
619 		aNewValue <<= rName;
620 
621 		msName = rName;
622         meNameOrigin = eNameOrigin;
623 
624         CommitChange(
625             AccessibleEventId::NAME_CHANGED,
626             aNewValue,
627             aOldValue);
628 	}
629 }
630 
631 
632 
633 
CreateAccessibleDescription(void)634 ::rtl::OUString AccessibleContextBase::CreateAccessibleDescription (void)
635     throw (::com::sun::star::uno::RuntimeException)
636 {
637     return ::rtl::OUString::createFromAscii ("Empty Description");
638 }
639 
640 
641 
642 
CreateAccessibleName(void)643 ::rtl::OUString AccessibleContextBase::CreateAccessibleName (void)
644     throw (::com::sun::star::uno::RuntimeException)
645 {
646     return ::rtl::OUString::createFromAscii ("Empty Name");
647 }
648 
649 
650 
651 
CommitChange(sal_Int16 nEventId,const uno::Any & rNewValue,const uno::Any & rOldValue)652 void AccessibleContextBase::CommitChange (
653     sal_Int16 nEventId,
654     const uno::Any& rNewValue,
655     const uno::Any& rOldValue)
656 {
657     // Do not call FireEvent and do not even create the event object when no
658     // listener has been registered yet.  Creating the event object can
659     // otherwise lead to a crash.  See issue 93419 for details.
660 	if (mnClientId != 0)
661     {
662         AccessibleEventObject aEvent (
663             static_cast<XAccessibleContext*>(this),
664             nEventId,
665             rNewValue,
666             rOldValue);
667 
668         FireEvent (aEvent);
669     }
670 }
671 
672 
673 
674 
FireEvent(const AccessibleEventObject & aEvent)675 void AccessibleContextBase::FireEvent (const AccessibleEventObject& aEvent)
676 {
677 	if (mnClientId)
678 		comphelper::AccessibleEventNotifier::addEvent( mnClientId, aEvent );
679 }
680 
681 
682 
683 
ThrowIfDisposed(void)684 void AccessibleContextBase::ThrowIfDisposed (void)
685     throw (::com::sun::star::lang::DisposedException)
686 {
687 	if (rBHelper.bDisposed || rBHelper.bInDispose)
688 	{
689         OSL_TRACE ("Calling disposed object. Throwing exception:");
690         throw lang::DisposedException (
691             OUString(RTL_CONSTASCII_USTRINGPARAM("object has been already disposed")),
692             static_cast<uno::XWeak*>(this));
693     }
694 }
695 
696 
697 
IsDisposed(void)698 sal_Bool AccessibleContextBase::IsDisposed (void)
699 {
700 	return (rBHelper.bDisposed || rBHelper.bInDispose);
701 }
702 
703 
704 
SetAccessibleRole(sal_Int16 _nRole)705 void AccessibleContextBase::SetAccessibleRole( sal_Int16 _nRole )
706 {
707 	maRole = _nRole;
708 }
709 
710 
711 } // end of namespace accessibility
712