1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/window.hxx>
21 #include <swtypes.hxx>
22 
23 #include <com/sun/star/accessibility/XAccessible.hpp>
24 #include <com/sun/star/accessibility/XAccessibleStateSet.hpp>
25 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
26 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
27 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
28 #include <osl/mutex.hxx>
29 #include <sal/log.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/settings.hxx>
32 #include <i18nlangtag/languagetag.hxx>
33 #include <unotools/accessiblestatesethelper.hxx>
34 #include <unotools/accessiblerelationsethelper.hxx>
35 #include <viewsh.hxx>
36 #include <crsrsh.hxx>
37 #include <fesh.hxx>
38 #include <wrtsh.hxx>
39 #include <txtfrm.hxx>
40 #include <ndtxt.hxx>
41 #include <pagefrm.hxx>
42 #include <flyfrm.hxx>
43 #include <dflyobj.hxx>
44 #include <pam.hxx>
45 #include <accmap.hxx>
46 #include "accfrmobjslist.hxx"
47 #include "acccontext.hxx"
48 #include <svx/AccessibleShape.hxx>
49 #include <comphelper/accessibleeventnotifier.hxx>
50 #include <cppuhelper/supportsservice.hxx>
51 #include <PostItMgr.hxx>
52 
53 using namespace sw::access;
54 using namespace ::com::sun::star;
55 using namespace ::com::sun::star::accessibility;
56 
InitStates()57 void SwAccessibleContext::InitStates()
58 {
59     m_isShowingState = GetMap() && IsShowing( *(GetMap()) );
60 
61     SwViewShell *pVSh = GetMap()->GetShell();
62     m_isEditableState = pVSh && IsEditable( pVSh );
63     m_isOpaqueState = pVSh && IsOpaque( pVSh );
64     m_isDefuncState = false;
65 }
66 
SetParent(SwAccessibleContext * pParent)67 void SwAccessibleContext::SetParent( SwAccessibleContext *pParent )
68 {
69     osl::MutexGuard aGuard( m_Mutex );
70 
71     uno::Reference < XAccessible > xParent( pParent );
72     m_xWeakParent = xParent;
73 }
74 
GetWeakParent() const75 uno::Reference< XAccessible > SwAccessibleContext::GetWeakParent() const
76 {
77     osl::MutexGuard aGuard( m_Mutex );
78 
79     uno::Reference< XAccessible > xParent( m_xWeakParent );
80     return xParent;
81 }
82 
GetWindow()83 vcl::Window *SwAccessibleContext::GetWindow()
84 {
85     vcl::Window *pWin = nullptr;
86 
87     if( GetMap() )
88     {
89         const SwViewShell *pVSh = GetMap()->GetShell();
90         OSL_ENSURE( pVSh, "no view shell" );
91         if( pVSh )
92             pWin = pVSh->GetWin();
93 
94         OSL_ENSURE( pWin, "no window" );
95     }
96 
97     return pWin;
98 }
99 
100 // get SwViewShell from accessibility map, and cast to cursor shell
GetCursorShell()101 SwCursorShell* SwAccessibleContext::GetCursorShell()
102 {
103     SwViewShell* pViewShell = GetMap() ? GetMap()->GetShell() : nullptr;
104     OSL_ENSURE( pViewShell, "no view shell" );
105     return dynamic_cast<SwCursorShell*>( pViewShell);
106 }
107 
GetCursorShell() const108 const SwCursorShell* SwAccessibleContext::GetCursorShell() const
109 {
110     // just like non-const GetCursorShell
111     const SwViewShell* pViewShell = GetMap() ? GetMap()->GetShell() : nullptr;
112     OSL_ENSURE( pViewShell, "no view shell" );
113     return dynamic_cast<const SwCursorShell*>( pViewShell);
114 }
115 
116 namespace {
117 
118 enum class Action { NONE, SCROLLED, SCROLLED_WITHIN,
119                           SCROLLED_IN, SCROLLED_OUT };
120 
121 }
122 
ChildrenScrolled(const SwFrame * pFrame,const SwRect & rOldVisArea)123 void SwAccessibleContext::ChildrenScrolled( const SwFrame *pFrame,
124                                             const SwRect& rOldVisArea )
125 {
126     const SwRect& rNewVisArea = GetVisArea();
127     const bool bVisibleChildrenOnly = SwAccessibleChild( pFrame ).IsVisibleChildrenOnly();
128 
129     const SwAccessibleChildSList aList( *pFrame, *(GetMap()) );
130     SwAccessibleChildSList::const_iterator aIter( aList.begin() );
131     while( aIter != aList.end() )
132     {
133         const SwAccessibleChild& rLower = *aIter;
134         const SwRect aBox( rLower.GetBox( *(GetMap()) ) );
135         if( rLower.IsAccessible( GetShell()->IsPreview() ) )
136         {
137             Action eAction = Action::NONE;
138             if( aBox.IsOver( rNewVisArea ) )
139             {
140                 if( aBox.IsOver( rOldVisArea ) )
141                 {
142                     eAction = Action::SCROLLED_WITHIN;
143                 }
144                 else
145                 {
146                     if ( bVisibleChildrenOnly &&
147                          !rLower.AlwaysIncludeAsChild() )
148                     {
149                         eAction = Action::SCROLLED_IN;
150                     }
151                     else
152                     {
153                         eAction = Action::SCROLLED;
154                     }
155                 }
156             }
157             else if( aBox.IsOver( rOldVisArea ) )
158             {
159                 if ( bVisibleChildrenOnly &&
160                      !rLower.AlwaysIncludeAsChild() )
161                 {
162                     eAction = Action::SCROLLED_OUT;
163                 }
164                 else
165                 {
166                     eAction = Action::SCROLLED;
167                 }
168             }
169             else if( !bVisibleChildrenOnly ||
170                      rLower.AlwaysIncludeAsChild() )
171             {
172                 // This wouldn't be required if the SwAccessibleFrame,
173                 // wouldn't know about the visible area.
174                 eAction = Action::SCROLLED;
175             }
176             if( Action::NONE != eAction )
177             {
178                 if ( rLower.GetSwFrame() )
179                 {
180                     OSL_ENSURE( !rLower.AlwaysIncludeAsChild(),
181                             "<SwAccessibleContext::ChildrenScrolled(..)> - always included child not considered!" );
182                     const SwFrame* pLower( rLower.GetSwFrame() );
183                     ::rtl::Reference< SwAccessibleContext > xAccImpl =
184                         GetMap()->GetContextImpl( pLower );
185                     if( xAccImpl.is() )
186                     {
187                         switch( eAction )
188                         {
189                         case Action::SCROLLED:
190                             xAccImpl->Scrolled( rOldVisArea );
191                             break;
192                         case Action::SCROLLED_WITHIN:
193                             xAccImpl->ScrolledWithin( rOldVisArea );
194                             break;
195                         case Action::SCROLLED_IN:
196                             xAccImpl->ScrolledIn();
197                             break;
198                         case Action::SCROLLED_OUT:
199                             xAccImpl->ScrolledOut( rOldVisArea );
200                             break;
201                         case Action::NONE:
202                             break;
203                         }
204                     }
205                     else
206                     {
207                         ChildrenScrolled( pLower, rOldVisArea );
208                     }
209                 }
210                 else if ( rLower.GetDrawObject() )
211                 {
212                     OSL_ENSURE( !rLower.AlwaysIncludeAsChild(),
213                             "<SwAccessibleContext::ChildrenScrolled(..)> - always included child not considered!" );
214                     ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl =
215                         GetMap()->GetContextImpl( rLower.GetDrawObject(),
216                                                   this );
217                     if( xAccImpl.is() )
218                     {
219                         switch( eAction )
220                         {
221                         case Action::SCROLLED:
222                         case Action::SCROLLED_WITHIN:
223                             xAccImpl->ViewForwarderChanged();
224                             break;
225                         case Action::SCROLLED_IN:
226                             ScrolledInShape( xAccImpl.get() );
227                             break;
228                         case Action::SCROLLED_OUT:
229                             {
230                                 xAccImpl->ViewForwarderChanged();
231                                 // this DisposeShape call was removed by
232                                 // IAccessibility2 implementation
233                                 // without giving any reason why
234                                 DisposeShape( rLower.GetDrawObject(),
235                                           xAccImpl.get() );
236                             }
237                             break;
238                         // coverity[dead_error_begin] - following conditions exist to avoid compiler warning
239                         case Action::NONE:
240                             break;
241                         }
242                     }
243                 }
244                 else if ( rLower.GetWindow() )
245                 {
246                     // nothing to do - as such children are always included as children.
247                     OSL_ENSURE( rLower.AlwaysIncludeAsChild(),
248                             "<SwAccessibleContext::ChildrenScrolled(..)> - not always included child not considered!" );
249                 }
250             }
251         }
252         else if ( rLower.GetSwFrame() &&
253                   ( !bVisibleChildrenOnly ||
254                     aBox.IsOver( rOldVisArea ) ||
255                     aBox.IsOver( rNewVisArea ) ) )
256         {
257             // There are no unaccessible SdrObjects that need to be notified
258             ChildrenScrolled( rLower.GetSwFrame(), rOldVisArea );
259         }
260         ++aIter;
261     }
262 }
263 
Scrolled(const SwRect & rOldVisArea)264 void SwAccessibleContext::Scrolled( const SwRect& rOldVisArea )
265 {
266     SetVisArea( GetMap()->GetVisArea() );
267 
268     ChildrenScrolled( GetFrame(), rOldVisArea );
269 
270     bool bIsOldShowingState;
271     bool bIsNewShowingState = IsShowing( *(GetMap()) );
272     {
273         osl::MutexGuard aGuard( m_Mutex );
274         bIsOldShowingState = m_isShowingState;
275         m_isShowingState = bIsNewShowingState;
276     }
277 
278     if( bIsOldShowingState != bIsNewShowingState )
279         FireStateChangedEvent( AccessibleStateType::SHOWING,
280                                bIsNewShowingState  );
281 }
282 
ScrolledWithin(const SwRect & rOldVisArea)283 void SwAccessibleContext::ScrolledWithin( const SwRect& rOldVisArea )
284 {
285     SetVisArea( GetMap()->GetVisArea() );
286 
287     ChildrenScrolled( GetFrame(), rOldVisArea );
288 
289     FireVisibleDataEvent();
290 }
291 
ScrolledIn()292 void SwAccessibleContext::ScrolledIn()
293 {
294     // This accessible should be freshly created, because it
295     // was not visible before. Therefore, its visible area must already
296     // reflect the scrolling.
297     OSL_ENSURE( GetVisArea() == GetMap()->GetVisArea(),
298             "Visible area of child is wrong. Did it exist already?" );
299 
300     // Send child event at parent. That's all we have to do here.
301     const SwFrame* pParent = GetParent();
302     ::rtl::Reference< SwAccessibleContext > xParentImpl(
303          GetMap()->GetContextImpl( pParent, false ) );
304     uno::Reference < XAccessibleContext > xThis( this );
305     if( !xParentImpl.is() )
306         return;
307 
308     SetParent( xParentImpl.get() );
309 
310     AccessibleEventObject aEvent;
311     aEvent.EventId = AccessibleEventId::CHILD;
312     aEvent.NewValue <<= xThis;
313 
314     xParentImpl->FireAccessibleEvent( aEvent );
315 
316     if( HasCursor() )
317     {
318         vcl::Window *pWin = GetWindow();
319         if( pWin && pWin->HasFocus() )
320         {
321             FireStateChangedEvent( AccessibleStateType::FOCUSED, true );
322         }
323     }
324 }
325 
ScrolledOut(const SwRect & rOldVisArea)326 void SwAccessibleContext::ScrolledOut( const SwRect& rOldVisArea )
327 {
328     SetVisArea( GetMap()->GetVisArea() );
329 
330     // First of all, update the children. That's required to dispose
331     // all children that are existing only if they are visible. They
332     // are not disposed by the recursive Dispose call that follows later on,
333     // because this call will only dispose children that are in the
334     // new visible area. The children we want to dispose however are in the
335     // old visible area all.
336     ChildrenScrolled( GetFrame(), rOldVisArea );
337 
338     // Broadcast a state changed event for the showing state.
339     // It might be that the child is freshly created just to send
340     // the child event. In this case no listener will exist.
341     FireStateChangedEvent( AccessibleStateType::SHOWING, false );
342 
343     // this Dispose call was removed by IAccessibility2 implementation
344     // without giving any reason why - without it we get stale
345     // entries in SwAccessibleMap::mpFrameMap.
346     Dispose(true);
347 }
348 
349 // #i27301# - use new type definition for <_nStates>
InvalidateChildrenStates(const SwFrame * _pFrame,AccessibleStates _nStates)350 void SwAccessibleContext::InvalidateChildrenStates( const SwFrame* _pFrame,
351                                                     AccessibleStates _nStates )
352 {
353     const SwAccessibleChildSList aVisList( GetVisArea(), *_pFrame, *(GetMap()) );
354 
355     SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
356     while( aIter != aVisList.end() )
357     {
358         const SwAccessibleChild& rLower = *aIter;
359         const SwFrame* pLower = rLower.GetSwFrame();
360         if( pLower )
361         {
362             ::rtl::Reference< SwAccessibleContext > xAccImpl;
363             if( rLower.IsAccessible( GetShell()->IsPreview() ) )
364                 xAccImpl = GetMap()->GetContextImpl( pLower, false );
365             if( xAccImpl.is() )
366                 xAccImpl->InvalidateStates( _nStates );
367             else
368                 InvalidateChildrenStates( pLower, _nStates );
369         }
370         else if ( rLower.GetDrawObject() )
371         {
372             // TODO: SdrObjects
373         }
374         else if ( rLower.GetWindow() )
375         {
376             // nothing to do ?
377         }
378 
379         ++aIter;
380     }
381 }
382 
DisposeChildren(const SwFrame * pFrame,bool bRecursive,bool bCanSkipInvisible)383 void SwAccessibleContext::DisposeChildren(const SwFrame *pFrame,
384                                           bool bRecursive,
385                                           bool bCanSkipInvisible)
386 {
387     const SwAccessibleChildSList aVisList( GetVisArea(), *pFrame, *(GetMap()) );
388     SwAccessibleChildSList::const_iterator aIter( aVisList.begin() );
389     while( aIter != aVisList.end() )
390     {
391         const SwAccessibleChild& rLower = *aIter;
392         const SwFrame* pLower = rLower.GetSwFrame();
393         if( pLower )
394         {
395             // tdf#117601 dispose the darn thing if it ever was accessible
396             ::rtl::Reference<SwAccessibleContext> xAccImpl = GetMap()->GetContextImpl(pLower, false);
397             if( xAccImpl.is() )
398                 xAccImpl->Dispose( bRecursive );
399             else
400             {
401                 // it's possible that the xAccImpl *does* exist with a
402                 // ref-count of 0 and blocked in its dtor in another thread -
403                 // this call here could be from SwAccessibleMap dtor so
404                 // remove it from any maps now!
405                 GetMap()->RemoveContext(pLower);
406                 // in this case the context will check with a weak_ptr
407                 // that the map is still alive so it's not necessary
408                 // to clear its m_pMap here.
409                 if (bRecursive)
410                 {
411                     DisposeChildren(pLower, bRecursive, bCanSkipInvisible);
412                 }
413             }
414         }
415         else if ( rLower.GetDrawObject() )
416         {
417             ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl(
418                     GetMap()->GetContextImpl( rLower.GetDrawObject(),
419                                           this, false )  );
420             if( xAccImpl.is() )
421                 DisposeShape( rLower.GetDrawObject(), xAccImpl.get() );
422         }
423         else if ( rLower.GetWindow() )
424         {
425             DisposeChild(rLower, false, bCanSkipInvisible);
426         }
427         ++aIter;
428     }
429 }
430 
InvalidateContent_(bool)431 void SwAccessibleContext::InvalidateContent_( bool )
432 {
433 }
434 
InvalidateCursorPos_()435 void SwAccessibleContext::InvalidateCursorPos_()
436 {
437 }
438 
InvalidateFocus_()439 void SwAccessibleContext::InvalidateFocus_()
440 {
441 }
442 
FireAccessibleEvent(AccessibleEventObject & rEvent)443 void SwAccessibleContext::FireAccessibleEvent( AccessibleEventObject& rEvent )
444 {
445     OSL_ENSURE( GetFrame(), "fire event for disposed frame?" );
446     if( !GetFrame() )
447         return;
448 
449     if( !rEvent.Source.is() )
450     {
451         uno::Reference < XAccessibleContext > xThis( this );
452         rEvent.Source = xThis;
453     }
454 
455     if (m_nClientId)
456         comphelper::AccessibleEventNotifier::addEvent( m_nClientId, rEvent );
457 }
458 
FireVisibleDataEvent()459 void SwAccessibleContext::FireVisibleDataEvent()
460 {
461     AccessibleEventObject aEvent;
462     aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
463 
464     FireAccessibleEvent( aEvent );
465 }
466 
FireStateChangedEvent(sal_Int16 nState,bool bNewState)467 void SwAccessibleContext::FireStateChangedEvent( sal_Int16 nState,
468                                                  bool bNewState )
469 {
470     AccessibleEventObject aEvent;
471 
472     aEvent.EventId = AccessibleEventId::STATE_CHANGED;
473     if( bNewState )
474         aEvent.NewValue <<= nState;
475     else
476         aEvent.OldValue <<= nState;
477 
478     FireAccessibleEvent( aEvent );
479 }
480 
GetStates(::utl::AccessibleStateSetHelper & rStateSet)481 void SwAccessibleContext::GetStates(
482         ::utl::AccessibleStateSetHelper& rStateSet )
483 {
484     SolarMutexGuard aGuard;
485 
486     // SHOWING
487     if (m_isShowingState)
488         rStateSet.AddState( AccessibleStateType::SHOWING );
489 
490     // EDITABLE
491     if (m_isEditableState)
492     //Set editable state to graphic and other object when the document is editable
493     {
494         rStateSet.AddState( AccessibleStateType::EDITABLE );
495         rStateSet.AddState( AccessibleStateType::RESIZABLE );
496         rStateSet.AddState( AccessibleStateType::MOVEABLE );
497     }
498     // ENABLED
499     rStateSet.AddState( AccessibleStateType::ENABLED );
500 
501     // OPAQUE
502     if (m_isOpaqueState)
503         rStateSet.AddState( AccessibleStateType::OPAQUE );
504 
505     // VISIBLE
506     rStateSet.AddState( AccessibleStateType::VISIBLE );
507 
508     if (m_isDefuncState)
509         rStateSet.AddState( AccessibleStateType::DEFUNC );
510 }
511 
IsEditableState()512 bool SwAccessibleContext::IsEditableState()
513 {
514     bool bRet;
515     {
516         osl::MutexGuard aGuard( m_Mutex );
517         bRet = m_isEditableState;
518     }
519 
520     return bRet;
521 }
522 
ThrowIfDisposed()523 void SwAccessibleContext::ThrowIfDisposed()
524 {
525     if (!(GetFrame() && GetMap()))
526     {
527         throw lang::DisposedException("object is nonfunctional",
528                 static_cast<cppu::OWeakObject*>(this));
529     }
530 }
531 
SwAccessibleContext(std::shared_ptr<SwAccessibleMap> const & pMap,sal_Int16 const nRole,const SwFrame * pF)532 SwAccessibleContext::SwAccessibleContext(std::shared_ptr<SwAccessibleMap> const& pMap,
533                                           sal_Int16 const nRole,
534                                           const SwFrame *pF )
535     : SwAccessibleFrame( pMap->GetVisArea(), pF,
536                          pMap->GetShell()->IsPreview() )
537     , m_pMap(pMap.get())
538     , m_wMap(pMap)
539     , m_nClientId(0)
540     , m_nRole(nRole)
541     , m_isDisposing( false )
542     , m_isRegisteredAtAccessibleMap( true )
543     , m_isSelectedInDoc(false)
544 {
545     InitStates();
546 }
547 
~SwAccessibleContext()548 SwAccessibleContext::~SwAccessibleContext()
549 {
550     // must have for 2 reasons: 2. as long as this thread has SolarMutex
551     // another thread cannot destroy the SwAccessibleMap so our temporary
552     // taking a hard ref to SwAccessibleMap won't delay its destruction
553     SolarMutexGuard aGuard;
554     // must check with weak_ptr that m_pMap is still alive
555     std::shared_ptr<SwAccessibleMap> pMap(m_wMap.lock());
556     if (m_isRegisteredAtAccessibleMap && GetFrame() && pMap)
557     {
558         pMap->RemoveContext( GetFrame() );
559     }
560 }
561 
562 uno::Reference< XAccessibleContext > SAL_CALL
getAccessibleContext()563     SwAccessibleContext::getAccessibleContext()
564 {
565     uno::Reference < XAccessibleContext > xRet( this );
566     return xRet;
567 }
568 
getAccessibleChildCount()569 sal_Int32 SAL_CALL SwAccessibleContext::getAccessibleChildCount()
570 {
571     SolarMutexGuard aGuard;
572 
573     ThrowIfDisposed();
574 
575     return m_isDisposing ? 0 : GetChildCount( *(GetMap()) );
576 }
577 
578 uno::Reference< XAccessible> SAL_CALL
getAccessibleChild(sal_Int32 nIndex)579     SwAccessibleContext::getAccessibleChild( sal_Int32 nIndex )
580 {
581     SolarMutexGuard aGuard;
582 
583     ThrowIfDisposed();
584 
585     const SwAccessibleChild aChild( GetChild( *(GetMap()), nIndex ) );
586     if( !aChild.IsValid() )
587     {
588         uno::Reference < XAccessibleContext > xThis( this );
589         lang::IndexOutOfBoundsException aExcept(
590                 "index out of bounds",
591                 xThis );
592         throw aExcept;
593     }
594 
595     uno::Reference< XAccessible > xChild;
596     if( aChild.GetSwFrame() )
597     {
598         ::rtl::Reference < SwAccessibleContext > xChildImpl(
599                 GetMap()->GetContextImpl( aChild.GetSwFrame(), !m_isDisposing )  );
600         if( xChildImpl.is() )
601         {
602             xChildImpl->SetParent( this );
603             xChild = xChildImpl.get();
604         }
605     }
606     else if ( aChild.GetDrawObject() )
607     {
608         ::rtl::Reference < ::accessibility::AccessibleShape > xChildImpl(
609                 GetMap()->GetContextImpl( aChild.GetDrawObject(),
610                                           this, !m_isDisposing) );
611         if( xChildImpl.is() )
612             xChild = xChildImpl.get();
613     }
614     else if ( aChild.GetWindow() )
615     {
616         xChild = aChild.GetWindow()->GetAccessible();
617     }
618 
619     return xChild;
620 }
621 
622 css::uno::Sequence<uno::Reference<XAccessible>> SAL_CALL
getAccessibleChildren()623     SwAccessibleContext::getAccessibleChildren()
624 {
625     SolarMutexGuard aGuard;
626 
627     ThrowIfDisposed();
628 
629     std::list< sw::access::SwAccessibleChild > aChildren;
630     GetChildren( *GetMap(), aChildren );
631 
632     std::vector<uno::Reference<XAccessible>> aRet;
633     aRet.reserve(aChildren.size());
634     for (const auto & rSwChild : aChildren)
635     {
636         uno::Reference< XAccessible > xChild;
637         if( rSwChild.GetSwFrame() )
638         {
639             ::rtl::Reference < SwAccessibleContext > xChildImpl(
640                     GetMap()->GetContextImpl( rSwChild.GetSwFrame(), !m_isDisposing )  );
641             if( xChildImpl.is() )
642             {
643                 xChildImpl->SetParent( this );
644                 xChild = xChildImpl.get();
645             }
646         }
647         else if ( rSwChild.GetDrawObject() )
648         {
649             ::rtl::Reference < ::accessibility::AccessibleShape > xChildImpl(
650                     GetMap()->GetContextImpl( rSwChild.GetDrawObject(),
651                                               this, !m_isDisposing) );
652             if( xChildImpl.is() )
653                 xChild = xChildImpl.get();
654         }
655         else if ( rSwChild.GetWindow() )
656         {
657             xChild = rSwChild.GetWindow()->GetAccessible();
658         }
659         aRet.push_back(xChild);
660     }
661     return comphelper::containerToSequence(aRet);
662 }
663 
getAccessibleParentImpl()664 uno::Reference< XAccessible> SwAccessibleContext::getAccessibleParentImpl()
665 {
666     SolarMutexGuard aGuard;
667 
668     const SwFrame *pUpper = GetParent();
669     OSL_ENSURE( pUpper != nullptr || m_isDisposing, "no upper found" );
670 
671     uno::Reference< XAccessible > xAcc;
672     if( pUpper )
673         xAcc = GetMap()->GetContext( pUpper, !m_isDisposing );
674 
675     OSL_ENSURE( xAcc.is() || m_isDisposing, "no parent found" );
676 
677     // Remember the parent as weak ref.
678     {
679         osl::MutexGuard aWeakParentGuard( m_Mutex );
680         m_xWeakParent = xAcc;
681     }
682 
683     return xAcc;
684 }
685 
getAccessibleParent()686 uno::Reference< XAccessible> SAL_CALL SwAccessibleContext::getAccessibleParent()
687 {
688     SolarMutexGuard aGuard;
689 
690     ThrowIfDisposed();
691 
692     return getAccessibleParentImpl();
693 }
694 
getAccessibleIndexInParent()695 sal_Int32 SAL_CALL SwAccessibleContext::getAccessibleIndexInParent()
696 {
697     SolarMutexGuard aGuard;
698 
699     ThrowIfDisposed();
700 
701     const SwFrame *pUpper = GetParent();
702     OSL_ENSURE( pUpper != nullptr || m_isDisposing, "no upper found" );
703 
704     sal_Int32 nIndex = -1;
705     if( pUpper )
706     {
707         ::rtl::Reference < SwAccessibleContext > xAccImpl(
708             GetMap()->GetContextImpl(pUpper, !m_isDisposing) );
709         OSL_ENSURE( xAccImpl.is() || m_isDisposing, "no parent found" );
710         if( xAccImpl.is() )
711             nIndex = xAccImpl->GetChildIndex( *(GetMap()), SwAccessibleChild(GetFrame()) );
712     }
713 
714     return nIndex;
715 }
716 
getAccessibleRole()717 sal_Int16 SAL_CALL SwAccessibleContext::getAccessibleRole()
718 {
719     return m_nRole;
720 }
721 
getAccessibleName()722 OUString SAL_CALL SwAccessibleContext::getAccessibleName()
723 {
724     return m_sName;
725 }
726 
727 uno::Reference< XAccessibleRelationSet> SAL_CALL
getAccessibleRelationSet()728     SwAccessibleContext::getAccessibleRelationSet()
729 {
730     // by default there are no relations
731     uno::Reference< XAccessibleRelationSet> xRet( new utl::AccessibleRelationSetHelper() );
732     return xRet;
733 }
734 
735 uno::Reference<XAccessibleStateSet> SAL_CALL
getAccessibleStateSet()736     SwAccessibleContext::getAccessibleStateSet()
737 {
738     SolarMutexGuard aGuard;
739 
740     ThrowIfDisposed();
741 
742     rtl::Reference<::utl::AccessibleStateSetHelper> pStateSet =
743         new ::utl::AccessibleStateSetHelper;
744 
745     if (m_isSelectedInDoc)
746         pStateSet->AddState( AccessibleStateType::SELECTED );
747 
748     GetStates( *pStateSet );
749 
750     return pStateSet;
751 }
752 
getLocale()753 lang::Locale SAL_CALL SwAccessibleContext::getLocale()
754 {
755     SolarMutexGuard aGuard;
756 
757     lang::Locale aLoc( Application::GetSettings().GetLanguageTag().getLocale() );
758     return aLoc;
759 }
760 
addAccessibleEventListener(const uno::Reference<XAccessibleEventListener> & xListener)761 void SAL_CALL SwAccessibleContext::addAccessibleEventListener(
762             const uno::Reference< XAccessibleEventListener >& xListener )
763 {
764     if (xListener.is())
765     {
766         SolarMutexGuard aGuard;
767         if (!m_nClientId)
768             m_nClientId = comphelper::AccessibleEventNotifier::registerClient( );
769         comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, xListener );
770     }
771 }
772 
removeAccessibleEventListener(const uno::Reference<XAccessibleEventListener> & xListener)773 void SAL_CALL SwAccessibleContext::removeAccessibleEventListener(
774             const uno::Reference< XAccessibleEventListener >& xListener )
775 {
776     if (!(xListener.is() && m_nClientId))
777         return;
778 
779     SolarMutexGuard aGuard;
780     sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, xListener );
781     if ( !nListenerCount )
782     {
783         // no listeners anymore
784         // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
785         // and at least to us not firing any events anymore, in case somebody calls
786         // NotifyAccessibleEvent, again
787         comphelper::AccessibleEventNotifier::revokeClient( m_nClientId );
788         m_nClientId = 0;
789     }
790 }
791 
lcl_PointInRectangle(const awt::Point & aPoint,const awt::Rectangle & aRect)792 static bool lcl_PointInRectangle(const awt::Point & aPoint,
793                                      const awt::Rectangle & aRect)
794 {
795     tools::Long nDiffX = aPoint.X - aRect.X;
796     tools::Long nDiffY = aPoint.Y - aRect.Y;
797 
798     return
799         nDiffX >= 0 && nDiffX < aRect.Width && nDiffY >= 0 &&
800         nDiffY < aRect.Height;
801 
802 }
803 
containsPoint(const awt::Point & aPoint)804 sal_Bool SAL_CALL SwAccessibleContext::containsPoint(
805             const awt::Point& aPoint )
806 {
807     awt::Rectangle aPixBounds = getBoundsImpl(true);
808     aPixBounds.X = 0;
809     aPixBounds.Y = 0;
810 
811     return lcl_PointInRectangle(aPoint, aPixBounds);
812 }
813 
getAccessibleAtPoint(const awt::Point & aPoint)814 uno::Reference< XAccessible > SAL_CALL SwAccessibleContext::getAccessibleAtPoint(
815                 const awt::Point& aPoint )
816 {
817     SolarMutexGuard aGuard;
818 
819     ThrowIfDisposed();
820 
821     uno::Reference< XAccessible > xAcc;
822 
823     vcl::Window *pWin = GetWindow();
824     if (!pWin)
825     {
826         throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
827     }
828 
829     Point aPixPoint( aPoint.X, aPoint.Y ); // px rel to parent
830     if( !GetFrame()->IsRootFrame() )
831     {
832         SwRect aLogBounds( GetBounds( *(GetMap()), GetFrame() ) ); // twip rel to doc root
833         Point aPixPos( GetMap()->CoreToPixel( aLogBounds ).TopLeft() );
834         aPixPoint.setX(aPixPoint.getX() + aPixPos.getX());
835         aPixPoint.setY(aPixPoint.getY() + aPixPos.getY());
836     }
837 
838     const SwAccessibleChild aChild( GetChildAtPixel( aPixPoint, *(GetMap()) ) );
839     if( aChild.GetSwFrame() )
840     {
841         xAcc = GetMap()->GetContext( aChild.GetSwFrame() );
842     }
843     else if( aChild.GetDrawObject() )
844     {
845         xAcc = GetMap()->GetContext( aChild.GetDrawObject(), this );
846     }
847     else if ( aChild.GetWindow() )
848     {
849         xAcc = aChild.GetWindow()->GetAccessible();
850     }
851 
852     return xAcc;
853 }
854 
855 /**
856    Get bounding box.
857 
858    There are two modes.
859 
860    - relative
861 
862      Return bounding box relative to parent if parent is no root
863      frame. Otherwise return the absolute bounding box.
864 
865    - absolute
866 
867      Return the absolute bounding box.
868 
869    @param bRelative
870    true: Use relative mode.
871    false: Use absolute mode.
872 */
getBoundsImpl(bool bRelative)873 awt::Rectangle SwAccessibleContext::getBoundsImpl(bool bRelative)
874 {
875     SolarMutexGuard aGuard;
876 
877     ThrowIfDisposed();
878 
879     const SwFrame *pParent = GetParent();
880     OSL_ENSURE( pParent, "no Parent found" );
881     vcl::Window *pWin = GetWindow();
882 
883     if (!pParent)
884     {
885         throw uno::RuntimeException("no Parent", static_cast<cppu::OWeakObject*>(this));
886     }
887     if (!pWin)
888     {
889         throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
890     }
891 
892     SwRect aLogBounds( GetBounds( *(GetMap()), GetFrame() ) ); // twip relative to document root
893     tools::Rectangle aPixBounds( 0, 0, 0, 0 );
894     if( GetFrame()->IsPageFrame() &&
895         static_cast < const SwPageFrame * >( GetFrame() )->IsEmptyPage() )
896     {
897         OSL_ENSURE( GetShell()->IsPreview(), "empty page accessible?" );
898         if( GetShell()->IsPreview() )
899         {
900             // adjust method call <GetMap()->GetPreviewPageSize()>
901             sal_uInt16 nPageNum =
902                 static_cast < const SwPageFrame * >( GetFrame() )->GetPhyPageNum();
903             aLogBounds.SSize( GetMap()->GetPreviewPageSize( nPageNum ) );
904         }
905     }
906     if( !aLogBounds.IsEmpty() )
907     {
908         aPixBounds = GetMap()->CoreToPixel( aLogBounds );
909         if( !pParent->IsRootFrame() && bRelative)
910         {
911             SwRect aParentLogBounds( GetBounds( *(GetMap()), pParent ) ); // twip rel to doc root
912             Point aParentPixPos( GetMap()->CoreToPixel( aParentLogBounds ).TopLeft() );
913             aPixBounds.Move( -aParentPixPos.getX(), -aParentPixPos.getY() );
914         }
915     }
916 
917     awt::Rectangle aBox( aPixBounds.Left(), aPixBounds.Top(),
918                          aPixBounds.GetWidth(), aPixBounds.GetHeight() );
919 
920     return aBox;
921 }
922 
getBounds()923 awt::Rectangle SAL_CALL SwAccessibleContext::getBounds()
924 {
925     return getBoundsImpl(true);
926 }
927 
getLocation()928 awt::Point SAL_CALL SwAccessibleContext::getLocation()
929 {
930     awt::Rectangle aRect = getBoundsImpl(true);
931     awt::Point aPoint(aRect.X, aRect.Y);
932 
933     return aPoint;
934 }
935 
getLocationOnScreen()936 awt::Point SAL_CALL SwAccessibleContext::getLocationOnScreen()
937 {
938     awt::Rectangle aRect = getBoundsImpl(false);
939 
940     Point aPixPos(aRect.X, aRect.Y);
941 
942     vcl::Window *pWin = GetWindow();
943     if (!pWin)
944     {
945         throw uno::RuntimeException("no Window", static_cast<cppu::OWeakObject*>(this));
946     }
947 
948     aPixPos = pWin->OutputToAbsoluteScreenPixel(aPixPos);
949     awt::Point aPoint(aPixPos.getX(), aPixPos.getY());
950 
951     return aPoint;
952 }
953 
getSize()954 awt::Size SAL_CALL SwAccessibleContext::getSize()
955 {
956     awt::Rectangle aRect = getBoundsImpl(false);
957     awt::Size aSize( aRect.Width, aRect.Height );
958 
959     return aSize;
960 }
961 
grabFocus()962 void SAL_CALL SwAccessibleContext::grabFocus()
963 {
964     SolarMutexGuard aGuard;
965 
966     ThrowIfDisposed();
967 
968     if( GetFrame()->IsFlyFrame() )
969     {
970         const SdrObject *pObj =
971             static_cast < const SwFlyFrame * >( GetFrame() )->GetVirtDrawObj();
972         if( pObj )
973             Select( const_cast < SdrObject * >( pObj ), false );
974     }
975     else
976     {
977         const SwContentFrame *pCFrame = nullptr;
978         if( GetFrame()->IsContentFrame() )
979             pCFrame = static_cast< const SwContentFrame * >( GetFrame() );
980         else if( GetFrame()->IsLayoutFrame() )
981             pCFrame = static_cast< const SwLayoutFrame * >( GetFrame() )->ContainsContent();
982 
983         if( pCFrame && pCFrame->IsTextFrame() )
984         {
985             const SwTextFrame *pTextFrame = static_cast< const SwTextFrame * >( pCFrame );
986             const SwTextNode *pTextNd = pTextFrame->GetTextNodeFirst();
987             assert(pTextNd); // can it actually be null? probably not=>simplify
988             if( pTextNd )
989             {
990                 // create pam for selection
991                 SwPosition const aStartPos(pTextFrame->MapViewToModelPos(pTextFrame->GetOffset()));
992                 SwPaM aPaM( aStartPos );
993 
994                 // set PaM at cursor shell
995                 Select( aPaM );
996             }
997         }
998     }
999 }
1000 
getForeground()1001 sal_Int32 SAL_CALL SwAccessibleContext::getForeground()
1002 {
1003     return sal_Int32(COL_BLACK);
1004 }
1005 
getBackground()1006 sal_Int32 SAL_CALL SwAccessibleContext::getBackground()
1007 {
1008     return sal_Int32(COL_WHITE);
1009 }
1010 
supportsService(const OUString & ServiceName)1011 sal_Bool SAL_CALL SwAccessibleContext::supportsService (const OUString& ServiceName)
1012 {
1013     return cppu::supportsService(this, ServiceName);
1014 }
1015 
DisposeShape(const SdrObject * pObj,::accessibility::AccessibleShape * pAccImpl)1016 void SwAccessibleContext::DisposeShape( const SdrObject *pObj,
1017                                 ::accessibility::AccessibleShape *pAccImpl )
1018 {
1019     ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl( pAccImpl );
1020     if( !xAccImpl.is() )
1021         xAccImpl = GetMap()->GetContextImpl( pObj, this );
1022 
1023     AccessibleEventObject aEvent;
1024     aEvent.EventId = AccessibleEventId::CHILD;
1025     uno::Reference< XAccessible > xAcc( xAccImpl );
1026     aEvent.OldValue <<= xAcc;
1027     FireAccessibleEvent( aEvent );
1028 
1029     GetMap()->RemoveContext( pObj );
1030     xAccImpl->dispose();
1031 }
1032 
ScrolledInShape(::accessibility::AccessibleShape * pAccImpl)1033 void SwAccessibleContext::ScrolledInShape( ::accessibility::AccessibleShape *pAccImpl )
1034 {
1035     if(nullptr == pAccImpl)
1036     {
1037         return ;
1038     }
1039     AccessibleEventObject aEvent;
1040     aEvent.EventId = AccessibleEventId::CHILD;
1041     uno::Reference< XAccessible > xAcc( pAccImpl );
1042     aEvent.NewValue <<= xAcc;
1043     FireAccessibleEvent( aEvent );
1044 
1045     if( !pAccImpl->GetState( AccessibleStateType::FOCUSED ) )
1046         return;
1047 
1048     vcl::Window *pWin = GetWindow();
1049     if( pWin && pWin->HasFocus() )
1050     {
1051         AccessibleEventObject aStateChangedEvent;
1052         aStateChangedEvent.EventId = AccessibleEventId::STATE_CHANGED;
1053         aStateChangedEvent.NewValue <<= AccessibleStateType::FOCUSED;
1054         aStateChangedEvent.Source = xAcc;
1055 
1056         FireAccessibleEvent( aStateChangedEvent );
1057     }
1058 }
1059 
Dispose(bool bRecursive,bool bCanSkipInvisible)1060 void SwAccessibleContext::Dispose(bool bRecursive, bool bCanSkipInvisible)
1061 {
1062     SolarMutexGuard aGuard;
1063 
1064     OSL_ENSURE( GetFrame() && GetMap(), "already disposed" );
1065     OSL_ENSURE( GetMap()->GetVisArea() == GetVisArea(),
1066                 "invalid visible area for dispose" );
1067 
1068     m_isDisposing = true;
1069 
1070     // dispose children
1071     if( bRecursive )
1072         DisposeChildren(GetFrame(), bRecursive, bCanSkipInvisible);
1073 
1074     // get parent
1075     uno::Reference< XAccessible > xParent( GetWeakParent() );
1076     uno::Reference < XAccessibleContext > xThis( this );
1077 
1078     // send child event at parent
1079     if( xParent.is() )
1080     {
1081         SwAccessibleContext *pAcc = static_cast<SwAccessibleContext *>(xParent.get());
1082 
1083         AccessibleEventObject aEvent;
1084         aEvent.EventId = AccessibleEventId::CHILD;
1085         aEvent.OldValue <<= xThis;
1086         pAcc->FireAccessibleEvent( aEvent );
1087     }
1088 
1089     // set defunc state (it's not required to broadcast a state changed
1090     // event if the object is disposed afterwards)
1091     {
1092         osl::MutexGuard aDefuncStateGuard( m_Mutex );
1093         m_isDefuncState = true;
1094     }
1095 
1096     // broadcast dispose event
1097     if (m_nClientId)
1098     {
1099         comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( m_nClientId, *this );
1100         m_nClientId =  0;
1101     }
1102 
1103     RemoveFrameFromAccessibleMap();
1104     ClearFrame();
1105     m_pMap = nullptr;
1106     m_wMap.reset();
1107 
1108     m_isDisposing = false;
1109 }
1110 
DisposeChild(const SwAccessibleChild & rChildFrameOrObj,bool bRecursive,bool bCanSkipInvisible)1111 void SwAccessibleContext::DisposeChild( const SwAccessibleChild& rChildFrameOrObj,
1112                                         bool bRecursive, bool bCanSkipInvisible )
1113 {
1114     SolarMutexGuard aGuard;
1115 
1116     if ( !bCanSkipInvisible ||
1117          rChildFrameOrObj.AlwaysIncludeAsChild() ||
1118          IsShowing( *(GetMap()), rChildFrameOrObj ) ||
1119          !SwAccessibleChild( GetFrame() ).IsVisibleChildrenOnly() )
1120     {
1121         // If the object could have existed before, then there is nothing to do,
1122         // because no wrapper exists now and therefore no one is interested to
1123         // get notified of the movement.
1124         if( rChildFrameOrObj.GetSwFrame() )
1125         {
1126             ::rtl::Reference< SwAccessibleContext > xAccImpl =
1127                     GetMap()->GetContextImpl( rChildFrameOrObj.GetSwFrame(), false );
1128             if (xAccImpl)
1129                 xAccImpl->Dispose( bRecursive );
1130         }
1131         else if ( rChildFrameOrObj.GetDrawObject() )
1132         {
1133             ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl =
1134                     GetMap()->GetContextImpl( rChildFrameOrObj.GetDrawObject(),
1135                                               this, false );
1136             if (xAccImpl)
1137                 DisposeShape( rChildFrameOrObj.GetDrawObject(),
1138                               xAccImpl.get() );
1139         }
1140         else if ( rChildFrameOrObj.GetWindow() )
1141         {
1142             AccessibleEventObject aEvent;
1143             aEvent.EventId = AccessibleEventId::CHILD;
1144             uno::Reference< XAccessible > xAcc =
1145                                     rChildFrameOrObj.GetWindow()->GetAccessible();
1146             aEvent.OldValue <<= xAcc;
1147             FireAccessibleEvent( aEvent );
1148         }
1149     }
1150     else if( bRecursive && rChildFrameOrObj.GetSwFrame() )
1151         DisposeChildren(rChildFrameOrObj.GetSwFrame(), bRecursive, bCanSkipInvisible);
1152 }
1153 
InvalidatePosOrSize(const SwRect &)1154 void SwAccessibleContext::InvalidatePosOrSize( const SwRect& )
1155 {
1156     SolarMutexGuard aGuard;
1157 
1158     OSL_ENSURE( GetFrame() && !GetFrame()->getFrameArea().IsEmpty(), "context should have a size" );
1159 
1160     bool bIsOldShowingState;
1161     bool bIsNewShowingState = IsShowing( *(GetMap()) );
1162     {
1163         osl::MutexGuard aShowingStateGuard( m_Mutex );
1164         bIsOldShowingState = m_isShowingState;
1165         m_isShowingState = bIsNewShowingState;
1166     }
1167 
1168     if( bIsOldShowingState != bIsNewShowingState )
1169     {
1170         FireStateChangedEvent( AccessibleStateType::SHOWING,
1171                                bIsNewShowingState  );
1172     }
1173     else if( bIsNewShowingState )
1174     {
1175         // The frame stays visible -> broadcast event
1176         FireVisibleDataEvent();
1177     }
1178 
1179     // note: InvalidatePosOrSize must call InvalidateContent_ so that
1180     // SwAccessibleParagraph updates its portions, or dispose it
1181     // (see accmap.cxx: INVALID_CONTENT is contained in POS_CHANGED)
1182     if( !bIsNewShowingState &&
1183         SwAccessibleChild( GetParent() ).IsVisibleChildrenOnly() )
1184     {
1185         // this Dispose call was removed by IAccessibility2 implementation
1186         // without giving any reason why - without it we get stale
1187         // entries in SwAccessibleMap::mpFrameMap.
1188         Dispose(true);
1189     }
1190     else
1191     {
1192         InvalidateContent_( true );
1193     }
1194 }
1195 
InvalidateChildPosOrSize(const SwAccessibleChild & rChildFrameOrObj,const SwRect & rOldFrame)1196 void SwAccessibleContext::InvalidateChildPosOrSize(
1197                     const SwAccessibleChild& rChildFrameOrObj,
1198                     const SwRect& rOldFrame )
1199 {
1200     SolarMutexGuard aGuard;
1201 
1202     // this happens during layout, e.g. when a page is deleted and next page's
1203     // header/footer moves backward such an event is generated
1204     SAL_INFO_IF(rChildFrameOrObj.GetSwFrame() &&
1205             rChildFrameOrObj.GetSwFrame()->getFrameArea().IsEmpty(),
1206             "sw.a11y", "child context should have a size");
1207 
1208     if ( rChildFrameOrObj.AlwaysIncludeAsChild() )
1209     {
1210         // nothing to do;
1211         return;
1212     }
1213 
1214     const bool bVisibleChildrenOnly = SwAccessibleChild( GetFrame() ).IsVisibleChildrenOnly();
1215     const bool bNew = rOldFrame.IsEmpty() ||
1216                      ( rOldFrame.Left() == 0 && rOldFrame.Top() == 0 );
1217     if( IsShowing( *(GetMap()), rChildFrameOrObj ) )
1218     {
1219         // If the object could have existed before, then there is nothing to do,
1220         // because no wrapper exists now and therefore no one is interested to
1221         // get notified of the movement.
1222         if( bNew || (bVisibleChildrenOnly && !IsShowing( rOldFrame )) )
1223         {
1224             if( rChildFrameOrObj.GetSwFrame() )
1225             {
1226                 // The frame becomes visible. A child event must be send.
1227                 ::rtl::Reference< SwAccessibleContext > xAccImpl =
1228                     GetMap()->GetContextImpl( rChildFrameOrObj.GetSwFrame() );
1229                 xAccImpl->ScrolledIn();
1230             }
1231             else if ( rChildFrameOrObj.GetDrawObject() )
1232             {
1233                 ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl =
1234                         GetMap()->GetContextImpl( rChildFrameOrObj.GetDrawObject(),
1235                                                   this );
1236                 // #i37790#
1237                 if ( xAccImpl.is() )
1238                 {
1239                     ScrolledInShape( xAccImpl.get() );
1240                 }
1241                 else
1242                 {
1243                     OSL_FAIL( "<SwAccessibleContext::InvalidateChildPosOrSize(..)> - no accessible shape found." );
1244                 }
1245             }
1246             else if ( rChildFrameOrObj.GetWindow() )
1247             {
1248                 AccessibleEventObject aEvent;
1249                 aEvent.EventId = AccessibleEventId::CHILD;
1250                 aEvent.NewValue <<= rChildFrameOrObj.GetWindow()->GetAccessible();
1251                 FireAccessibleEvent( aEvent );
1252             }
1253         }
1254     }
1255     else
1256     {
1257         // If the frame was visible before, then a child event for the parent
1258         // needs to be send. However, there is no wrapper existing, and so
1259         // no notifications for grandchildren are required. If the are
1260         // grandgrandchildren, they would be notified by the layout.
1261         if( bVisibleChildrenOnly &&
1262             !bNew && IsShowing( rOldFrame ) )
1263         {
1264             if( rChildFrameOrObj.GetSwFrame() )
1265             {
1266                 ::rtl::Reference< SwAccessibleContext > xAccImpl =
1267                     GetMap()->GetContextImpl( rChildFrameOrObj.GetSwFrame() );
1268                 xAccImpl->SetParent( this );
1269                 xAccImpl->Dispose( true );
1270             }
1271             else if ( rChildFrameOrObj.GetDrawObject() )
1272             {
1273                 ::rtl::Reference< ::accessibility::AccessibleShape > xAccImpl =
1274                         GetMap()->GetContextImpl( rChildFrameOrObj.GetDrawObject(),
1275                                                   this );
1276                 DisposeShape( rChildFrameOrObj.GetDrawObject(),
1277                           xAccImpl.get() );
1278             }
1279             else if ( rChildFrameOrObj.GetWindow() )
1280             {
1281                 OSL_FAIL( "<SwAccessibleContext::InvalidateChildPosOrSize(..)> - not expected to handle dispose of child of type <vcl::Window>." );
1282             }
1283         }
1284     }
1285 }
1286 
InvalidateContent()1287 void SwAccessibleContext::InvalidateContent()
1288 {
1289     SolarMutexGuard aGuard;
1290 
1291     InvalidateContent_( false );
1292 }
1293 
InvalidateCursorPos()1294 void SwAccessibleContext::InvalidateCursorPos()
1295 {
1296     SolarMutexGuard aGuard;
1297 
1298     InvalidateCursorPos_();
1299 }
1300 
InvalidateFocus()1301 void SwAccessibleContext::InvalidateFocus()
1302 {
1303     SolarMutexGuard aGuard;
1304 
1305     InvalidateFocus_();
1306 }
1307 
1308 // #i27301# - use new type definition for <_nStates>
InvalidateStates(AccessibleStates _nStates)1309 void SwAccessibleContext::InvalidateStates( AccessibleStates _nStates )
1310 {
1311     if( !GetMap() )
1312         return;
1313 
1314     SwViewShell *pVSh = GetMap()->GetShell();
1315     if( pVSh )
1316     {
1317         if( _nStates & AccessibleStates::EDITABLE )
1318         {
1319             bool bIsOldEditableState;
1320             bool bIsNewEditableState = IsEditable( pVSh );
1321             {
1322                 osl::MutexGuard aGuard( m_Mutex );
1323                 bIsOldEditableState = m_isEditableState;
1324                 m_isEditableState = bIsNewEditableState;
1325             }
1326 
1327             if( bIsOldEditableState != bIsNewEditableState )
1328                 FireStateChangedEvent( AccessibleStateType::EDITABLE,
1329                                        bIsNewEditableState  );
1330         }
1331         if( _nStates & AccessibleStates::OPAQUE )
1332         {
1333             bool bIsOldOpaqueState;
1334             bool bIsNewOpaqueState = IsOpaque( pVSh );
1335             {
1336                 osl::MutexGuard aGuard( m_Mutex );
1337                 bIsOldOpaqueState = m_isOpaqueState;
1338                 m_isOpaqueState = bIsNewOpaqueState;
1339             }
1340 
1341             if( bIsOldOpaqueState != bIsNewOpaqueState )
1342                 FireStateChangedEvent( AccessibleStateType::OPAQUE,
1343                                        bIsNewOpaqueState  );
1344         }
1345     }
1346 
1347     InvalidateChildrenStates( GetFrame(), _nStates );
1348 }
1349 
InvalidateRelation(sal_uInt16 nType)1350 void SwAccessibleContext::InvalidateRelation( sal_uInt16 nType )
1351 {
1352     AccessibleEventObject aEvent;
1353     aEvent.EventId = nType;
1354 
1355     FireAccessibleEvent( aEvent );
1356 }
1357 
1358 /** #i27301# - text selection has changed */
InvalidateTextSelection()1359 void SwAccessibleContext::InvalidateTextSelection()
1360 {
1361     AccessibleEventObject aEvent;
1362     aEvent.EventId = AccessibleEventId::TEXT_SELECTION_CHANGED;
1363 
1364     FireAccessibleEvent( aEvent );
1365 }
1366 
1367 /** #i88069# - attributes has changed */
InvalidateAttr()1368 void SwAccessibleContext::InvalidateAttr()
1369 {
1370     AccessibleEventObject aEvent;
1371     aEvent.EventId = AccessibleEventId::TEXT_ATTRIBUTE_CHANGED;
1372 
1373     FireAccessibleEvent( aEvent );
1374 }
1375 
HasCursor()1376 bool SwAccessibleContext::HasCursor()
1377 {
1378     return false;
1379 }
1380 
Select(SwPaM * pPaM,SdrObject * pObj,bool bAdd)1381 bool SwAccessibleContext::Select( SwPaM *pPaM, SdrObject *pObj,
1382                                   bool bAdd )
1383 {
1384     SwCursorShell* pCursorShell = GetCursorShell();
1385     if( !pCursorShell )
1386         return false;
1387 
1388     SwFEShell* pFEShell = dynamic_cast<SwFEShell*>(pCursorShell);
1389     // Get rid of activated OLE object
1390     if( pFEShell )
1391         pFEShell->FinishOLEObj();
1392 
1393     SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(pCursorShell);
1394 
1395     bool bRet = false;
1396     if( pObj )
1397     {
1398         if( pFEShell )
1399         {
1400             sal_uInt8 nFlags = bAdd ? SW_ADD_SELECT : 0;
1401             pFEShell->SelectObj( Point(), nFlags, pObj );
1402             bRet = true;
1403         }
1404     }
1405     else if( pPaM )
1406     {
1407         // Get rid of frame selection. If there is one, make text cursor
1408         // visible again.
1409         bool bCallShowCursor = false;
1410         if( pFEShell && (pFEShell->IsFrameSelected() ||
1411                          pFEShell->IsObjSelected()) )
1412         {
1413             Point aPt( LONG_MIN, LONG_MIN );
1414             pFEShell->SelectObj( aPt );
1415             bCallShowCursor = true;
1416         }
1417         pCursorShell->KillPams();
1418         if( pWrtShell && pPaM->HasMark() )
1419             // We have to do this or SwWrtShell can't figure out that it needs
1420             // to kill the selection later, when the user moves the cursor.
1421             pWrtShell->SttSelect();
1422         pCursorShell->SetSelection( *pPaM );
1423         if( pPaM->HasMark() && *pPaM->GetPoint() == *pPaM->GetMark())
1424             // Setting a "Selection" that starts and ends at the same spot
1425             // should remove the selection rather than create an empty one, so
1426             // that we get defined behavior if accessibility sets the cursor
1427             // later.
1428             pCursorShell->ClearMark();
1429         if( bCallShowCursor )
1430             pCursorShell->ShowCursor();
1431         bRet = true;
1432     }
1433 
1434     return bRet;
1435 }
1436 
GetResource(const char * pResId,const OUString * pArg1,const OUString * pArg2)1437 OUString SwAccessibleContext::GetResource(const char* pResId,
1438                                           const OUString *pArg1,
1439                                           const OUString *pArg2)
1440 {
1441     OUString sStr = SwResId(pResId);
1442 
1443     if( pArg1 )
1444     {
1445         sStr = sStr.replaceFirst( "$(ARG1)", *pArg1 );
1446     }
1447     if( pArg2 )
1448     {
1449         sStr = sStr.replaceFirst( "$(ARG2)", *pArg2 );
1450     }
1451 
1452     return sStr;
1453 }
1454 
RemoveFrameFromAccessibleMap()1455 void SwAccessibleContext::RemoveFrameFromAccessibleMap()
1456 {
1457     assert(m_refCount > 0); // must be alive to do this without using m_wMap
1458     if (m_isRegisteredAtAccessibleMap && GetFrame() && GetMap())
1459         GetMap()->RemoveContext( GetFrame() );
1460 }
1461 
HasAdditionalAccessibleChildren()1462 bool SwAccessibleContext::HasAdditionalAccessibleChildren()
1463 {
1464     bool bRet( false );
1465 
1466     if ( GetFrame()->IsTextFrame() )
1467     {
1468         SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr();
1469         if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
1470         {
1471             bRet = pPostItMgr->HasFrameConnectedSidebarWins( *(GetFrame()) );
1472         }
1473     }
1474 
1475     return bRet;
1476 }
1477 
1478 /** #i88070# - get additional accessible child by index */
GetAdditionalAccessibleChild(const sal_Int32 nIndex)1479 vcl::Window* SwAccessibleContext::GetAdditionalAccessibleChild( const sal_Int32 nIndex )
1480 {
1481     vcl::Window* pAdditionalAccessibleChild( nullptr );
1482 
1483     if ( GetFrame()->IsTextFrame() )
1484     {
1485         SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr();
1486         if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
1487         {
1488             pAdditionalAccessibleChild =
1489                     pPostItMgr->GetSidebarWinForFrameByIndex( *(GetFrame()), nIndex );
1490         }
1491     }
1492 
1493     return pAdditionalAccessibleChild;
1494 }
1495 
1496 /** #i88070# - get all additional accessible children */
GetAdditionalAccessibleChildren(std::vector<vcl::Window * > * pChildren)1497 void SwAccessibleContext::GetAdditionalAccessibleChildren( std::vector< vcl::Window* >* pChildren )
1498 {
1499     if ( GetFrame()->IsTextFrame() )
1500     {
1501         SwPostItMgr* pPostItMgr = GetMap()->GetShell()->GetPostItMgr();
1502         if ( pPostItMgr && pPostItMgr->HasNotes() && pPostItMgr->ShowNotes() )
1503         {
1504             pPostItMgr->GetAllSidebarWinForFrame( *(GetFrame()), pChildren );
1505         }
1506     }
1507 }
1508 
SetSelectedState(bool const bSelected)1509 bool SwAccessibleContext::SetSelectedState(bool const bSelected)
1510 {
1511     if (m_isSelectedInDoc != bSelected)
1512     {
1513         m_isSelectedInDoc = bSelected;
1514         FireStateChangedEvent( AccessibleStateType::SELECTED, bSelected );
1515         return true;
1516     }
1517     return false;
1518 };
1519 
1520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1521