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 <rtl/ref.hxx>
21 #include <cppuhelper/weakref.hxx>
22 #include <vcl/window.hxx>
23 #include <svx/svdmodel.hxx>
24 #include <svx/unomod.hxx>
25 #include <algorithm>
26 #include <map>
27 #include <list>
28 #include <vector>
29 #include <accmap.hxx>
30 #include "acccontext.hxx"
31 #include "accdoc.hxx"
32 #include <strings.hrc>
33 #include "accpreview.hxx"
34 #include "accpage.hxx"
35 #include "accpara.hxx"
36 #include "accheaderfooter.hxx"
37 #include "accfootnote.hxx"
38 #include "acctextframe.hxx"
39 #include "accgraphic.hxx"
40 #include "accembedded.hxx"
41 #include "acccell.hxx"
42 #include "acctable.hxx"
43 #include <fesh.hxx>
44 #include <rootfrm.hxx>
45 #include <txtfrm.hxx>
46 #include <hffrm.hxx>
47 #include <ftnfrm.hxx>
48 #include <cellfrm.hxx>
49 #include <tabfrm.hxx>
50 #include <pagefrm.hxx>
51 #include <flyfrm.hxx>
52 #include <ndtyp.hxx>
53 #include <IDocumentDrawModelAccess.hxx>
54 #include <svx/AccessibleShapeInfo.hxx>
55 #include <svx/ShapeTypeHandler.hxx>
56 #include <svx/SvxShapeTypes.hxx>
57 #include <svx/svdpage.hxx>
58 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
59 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
60 #include <com/sun/star/accessibility/AccessibleRole.hpp>
61 #include <com/sun/star/beans/XPropertySet.hpp>
62 #include <com/sun/star/document/XShapeEventBroadcaster.hpp>
63 #include <cppuhelper/implbase.hxx>
64 #include <comphelper/interfacecontainer2.hxx>
65 #include <pagepreviewlayout.hxx>
66 #include <dcontact.hxx>
67 #include <svx/unoapi.hxx>
68 #include <svx/svdmark.hxx>
69 #include <doc.hxx>
70 #include <drawdoc.hxx>
71 #include <pam.hxx>
72 #include <ndtxt.hxx>
73 #include <dflyobj.hxx>
74 #include <prevwpage.hxx>
75 #include <calbck.hxx>
76 #include <undobj.hxx>
77 #include <tools/diagnose_ex.h>
78 #include <tools/debug.hxx>
79 
80 using namespace ::com::sun::star;
81 using namespace ::com::sun::star::accessibility;
82 using namespace ::sw::access;
83 
84 struct SwFrameFunc
85 {
operator ()SwFrameFunc86     bool operator()( const SwFrame * p1, const SwFrame * p2) const
87     {
88         return p1 < p2;
89     }
90 };
91 
92 class SwAccessibleContextMap_Impl
93 {
94 public:
95     typedef const SwFrame *                                               key_type;
96     typedef uno::WeakReference < XAccessible >                          mapped_type;
97     typedef std::pair<const key_type,mapped_type>                       value_type;
98     typedef SwFrameFunc                                                   key_compare;
99     typedef std::map<key_type,mapped_type,key_compare>::iterator        iterator;
100     typedef std::map<key_type,mapped_type,key_compare>::const_iterator  const_iterator;
101 private:
102     std::map <key_type,mapped_type,key_compare> maMap;
103 public:
104 
105 #if OSL_DEBUG_LEVEL > 0
106     bool mbLocked;
107 #endif
108 
SwAccessibleContextMap_Impl()109     SwAccessibleContextMap_Impl()
110 #if OSL_DEBUG_LEVEL > 0
111         : mbLocked( false )
112 #endif
113     {}
114 
begin()115     iterator begin() { return maMap.begin(); }
end()116     iterator end() { return maMap.end(); }
empty() const117     bool empty() const { return maMap.empty(); }
clear()118     void clear() { maMap.clear(); }
find(const key_type & key)119     iterator find(const key_type& key) { return maMap.find(key); }
120     template<class... Args>
emplace(Args &&...args)121     std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
erase(const_iterator const & pos)122     iterator erase(const_iterator const & pos) { return maMap.erase(pos); }
123 };
124 
125 class SwDrawModellListener_Impl : public SfxListener,
126     public ::cppu::WeakImplHelper< document::XShapeEventBroadcaster >
127 {
128     mutable ::osl::Mutex maListenerMutex;
129     ::comphelper::OInterfaceContainerHelper2 maEventListeners;
130     std::unordered_map<css::uno::Reference< css::drawing::XShape >, css::uno::Reference< css::document::XShapeEventListener >> maShapeListeners;
131     SdrModel *mpDrawModel;
132 protected:
133     virtual ~SwDrawModellListener_Impl() override;
134 
135 public:
136     explicit SwDrawModellListener_Impl( SdrModel *pDrawModel );
137 
138     // css::document::XEventBroadcaster
139     virtual void SAL_CALL addEventListener( const uno::Reference< document::XEventListener >& xListener ) override;
140     virtual void SAL_CALL removeEventListener( const uno::Reference< document::XEventListener >& xListener ) override;
141     // css::document::XShapeEventBroadcaster
142     virtual void SAL_CALL addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;
143     virtual void SAL_CALL removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;
144 
145     virtual void        Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
146     void Dispose();
147 };
148 
SwDrawModellListener_Impl(SdrModel * pDrawModel)149 SwDrawModellListener_Impl::SwDrawModellListener_Impl( SdrModel *pDrawModel ) :
150     maEventListeners( maListenerMutex ),
151     mpDrawModel( pDrawModel )
152 {
153     StartListening( *mpDrawModel );
154 }
155 
~SwDrawModellListener_Impl()156 SwDrawModellListener_Impl::~SwDrawModellListener_Impl()
157 {
158     Dispose();
159 }
160 
addEventListener(const uno::Reference<document::XEventListener> & xListener)161 void SAL_CALL SwDrawModellListener_Impl::addEventListener( const uno::Reference< document::XEventListener >& xListener )
162 {
163     maEventListeners.addInterface( xListener );
164 }
165 
removeEventListener(const uno::Reference<document::XEventListener> & xListener)166 void SAL_CALL SwDrawModellListener_Impl::removeEventListener( const uno::Reference< document::XEventListener >& xListener )
167 {
168     maEventListeners.removeInterface( xListener );
169 }
170 
addShapeEventListener(const css::uno::Reference<css::drawing::XShape> & xShape,const uno::Reference<document::XShapeEventListener> & xListener)171 void SAL_CALL SwDrawModellListener_Impl::addShapeEventListener(
172                 const css::uno::Reference< css::drawing::XShape >& xShape,
173                 const uno::Reference< document::XShapeEventListener >& xListener )
174 {
175     assert(xShape.is() && "no shape?");
176     osl::MutexGuard aGuard(maListenerMutex);
177     auto rv = maShapeListeners.emplace(xShape, xListener);
178     assert(rv.second && "duplicate listener?");
179     (void)rv;
180 }
181 
removeShapeEventListener(const css::uno::Reference<css::drawing::XShape> & xShape,const uno::Reference<document::XShapeEventListener> & xListener)182 void SAL_CALL SwDrawModellListener_Impl::removeShapeEventListener(
183                 const css::uno::Reference< css::drawing::XShape >& xShape,
184                 const uno::Reference< document::XShapeEventListener >& xListener )
185 {
186     osl::MutexGuard aGuard(maListenerMutex);
187     auto it = maShapeListeners.find(xShape);
188     if (it != maShapeListeners.end())
189     {
190         assert(it->second == xListener);
191         (void)xListener;
192         maShapeListeners.erase(it);
193     }
194 }
195 
Notify(SfxBroadcaster &,const SfxHint & rHint)196 void SwDrawModellListener_Impl::Notify( SfxBroadcaster& /*rBC*/,
197         const SfxHint& rHint )
198 {
199     // do not broadcast notifications for writer fly frames, because there
200     // are no shapes that need to know about them.
201     if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
202         return;
203     const SdrHint *pSdrHint = static_cast<const SdrHint*>( &rHint );
204     if (pSdrHint->GetObject() &&
205            ( dynamic_cast< const SwFlyDrawObj* >(pSdrHint->GetObject()) !=  nullptr ||
206               dynamic_cast< const SwVirtFlyDrawObj* >(pSdrHint->GetObject()) !=  nullptr ||
207              typeid(SdrObject) == typeid(pSdrHint->GetObject()) ) )
208     {
209         return;
210     }
211 
212     OSL_ENSURE( mpDrawModel, "draw model listener is disposed" );
213     if( !mpDrawModel )
214         return;
215 
216     document::EventObject aEvent;
217     if( !SvxUnoDrawMSFactory::createEvent( mpDrawModel, pSdrHint, aEvent ) )
218         return;
219 
220     ::comphelper::OInterfaceIteratorHelper2 aIter( maEventListeners );
221     while( aIter.hasMoreElements() )
222     {
223         uno::Reference < document::XEventListener > xListener( aIter.next(),
224                                                 uno::UNO_QUERY );
225         try
226         {
227             xListener->notifyEvent( aEvent );
228         }
229         catch( uno::RuntimeException const & )
230         {
231             TOOLS_WARN_EXCEPTION("sw.a11y", "Runtime exception caught while notifying shape");
232         }
233     }
234 
235     // right now, we're only handling the specific event necessary to fix this performance problem
236     if (pSdrHint->GetKind() == SdrHintKind::ObjectChange)
237     {
238         auto pSdrObject = const_cast<SdrObject*>(pSdrHint->GetObject());
239         uno::Reference<drawing::XShape> xShape(pSdrObject->getUnoShape(), uno::UNO_QUERY);
240         osl::MutexGuard aGuard(maListenerMutex);
241         auto it = maShapeListeners.find(xShape);
242         if (it != maShapeListeners.end())
243             it->second->notifyShapeEvent(aEvent);
244     }
245 }
246 
Dispose()247 void SwDrawModellListener_Impl::Dispose()
248 {
249     if (mpDrawModel != nullptr) {
250         EndListening( *mpDrawModel );
251     }
252     mpDrawModel = nullptr;
253 }
254 
255 struct SwShapeFunc
256 {
operator ()SwShapeFunc257     bool operator()( const SdrObject * p1, const SdrObject * p2) const
258     {
259         return p1 < p2;
260     }
261 };
262 typedef std::pair < const SdrObject *, ::rtl::Reference < ::accessibility::AccessibleShape > > SwAccessibleObjShape_Impl;
263 
264 class SwAccessibleShapeMap_Impl
265 {
266 public:
267 
268     typedef const SdrObject *                                           key_type;
269     typedef uno::WeakReference<XAccessible>                             mapped_type;
270     typedef std::pair<const key_type,mapped_type>                       value_type;
271     typedef SwShapeFunc                                                 key_compare;
272     typedef std::map<key_type,mapped_type,key_compare>::iterator        iterator;
273     typedef std::map<key_type,mapped_type,key_compare>::const_iterator  const_iterator;
274 
275 private:
276 
277     ::accessibility::AccessibleShapeTreeInfo    maInfo;
278     std::map<key_type,mapped_type,SwShapeFunc>  maMap;
279 
280 public:
281 
SwAccessibleShapeMap_Impl(SwAccessibleMap const * pMap)282     explicit SwAccessibleShapeMap_Impl( SwAccessibleMap const *pMap )
283         : maMap()
284     {
285         maInfo.SetSdrView( pMap->GetShell()->GetDrawView() );
286         maInfo.SetDevice( pMap->GetShell()->GetWin() );
287         maInfo.SetViewForwarder( pMap );
288         uno::Reference < document::XShapeEventBroadcaster > xModelBroadcaster =
289             new SwDrawModellListener_Impl(
290                     pMap->GetShell()->getIDocumentDrawModelAccess().GetOrCreateDrawModel() );
291         maInfo.SetModelBroadcaster( xModelBroadcaster );
292     }
293 
294     ~SwAccessibleShapeMap_Impl();
295 
GetInfo() const296     const ::accessibility::AccessibleShapeTreeInfo& GetInfo() const { return maInfo; }
297 
298     std::unique_ptr<SwAccessibleObjShape_Impl[]> Copy( size_t& rSize,
299         const SwFEShell *pFESh,
300         SwAccessibleObjShape_Impl  **pSelShape ) const;
301 
end()302     iterator end() { return maMap.end(); }
cbegin() const303     const_iterator cbegin() const { return maMap.cbegin(); }
cend() const304     const_iterator cend() const { return maMap.cend(); }
empty() const305     bool empty() const { return maMap.empty(); }
find(const key_type & key)306     iterator find(const key_type& key) { return maMap.find(key); }
307     template<class... Args>
emplace(Args &&...args)308     std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
erase(const_iterator const & pos)309     iterator erase(const_iterator const & pos) { return maMap.erase(pos); }
310 };
311 
~SwAccessibleShapeMap_Impl()312 SwAccessibleShapeMap_Impl::~SwAccessibleShapeMap_Impl()
313 {
314     uno::Reference < document::XEventBroadcaster > xBrd( maInfo.GetModelBroadcaster() );
315     if( xBrd.is() )
316         static_cast < SwDrawModellListener_Impl * >( xBrd.get() )->Dispose();
317 }
318 
319 std::unique_ptr<SwAccessibleObjShape_Impl[]>
Copy(size_t & rSize,const SwFEShell * pFESh,SwAccessibleObjShape_Impl ** pSelStart) const320     SwAccessibleShapeMap_Impl::Copy(
321             size_t& rSize, const SwFEShell *pFESh,
322             SwAccessibleObjShape_Impl **pSelStart ) const
323 {
324     std::unique_ptr<SwAccessibleObjShape_Impl[]> pShapes;
325     SwAccessibleObjShape_Impl *pSelShape = nullptr;
326 
327     size_t nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
328     rSize = maMap.size();
329 
330     if( rSize > 0 )
331     {
332         pShapes.reset(new SwAccessibleObjShape_Impl[rSize]);
333 
334         SwAccessibleObjShape_Impl *pShape = pShapes.get();
335         pSelShape = &(pShapes[rSize]);
336         for( const auto& rEntry : maMap )
337         {
338             const SdrObject *pObj = rEntry.first;
339             uno::Reference < XAccessible > xAcc( rEntry.second );
340             if( nSelShapes && pFESh && pFESh->IsObjSelected( *pObj ) )
341             {
342                 // selected objects are inserted from the back
343                 --pSelShape;
344                 pSelShape->first = pObj;
345                 pSelShape->second =
346                     static_cast < ::accessibility::AccessibleShape* >(
347                                                     xAcc.get() );
348                 --nSelShapes;
349             }
350             else
351             {
352                 pShape->first = pObj;
353                 pShape->second =
354                     static_cast < ::accessibility::AccessibleShape* >(
355                                                     xAcc.get() );
356                 ++pShape;
357             }
358         }
359         assert(pSelShape == pShape);
360     }
361 
362     if( pSelStart )
363         *pSelStart = pSelShape;
364 
365     return pShapes;
366 }
367 
368 struct SwAccessibleEvent_Impl
369 {
370 public:
371     enum EventType { CARET_OR_STATES,
372                      INVALID_CONTENT,
373                      POS_CHANGED,
374                      CHILD_POS_CHANGED,
375                      SHAPE_SELECTION,
376                      DISPOSE,
377                      INVALID_ATTR };
378 
379 private:
380     SwRect      maOldBox;                       // the old bounds for CHILD_POS_CHANGED
381                                                 // and POS_CHANGED
382     uno::WeakReference < XAccessible > mxAcc;   // The object that fires the event
383     SwAccessibleChild const maFrameOrObj;       // the child for CHILD_POS_CHANGED and
384                                                 // the same as xAcc for any other
385                                                 // event type
386     EventType   meType;                         // The event type
387     AccessibleStates mnStates;                 // check states or update caret pos
388 
389 public:
390     const SwFrame* mpParentFrame;   // The object that fires the event
IsNoXaccParentFrameSwAccessibleEvent_Impl391     bool IsNoXaccParentFrame() const
392     {
393         return CHILD_POS_CHANGED == meType && mpParentFrame != nullptr;
394     }
395 
396 public:
SwAccessibleEvent_ImplSwAccessibleEvent_Impl397     SwAccessibleEvent_Impl( EventType eT,
398                             SwAccessibleContext *pA,
399                             const SwAccessibleChild& rFrameOrObj )
400         : mxAcc( pA ),
401           maFrameOrObj( rFrameOrObj ),
402           meType( eT ),
403           mnStates( AccessibleStates::NONE ),
404           mpParentFrame( nullptr )
405     {}
406 
SwAccessibleEvent_ImplSwAccessibleEvent_Impl407     SwAccessibleEvent_Impl( EventType eT,
408                             const SwAccessibleChild& rFrameOrObj )
409         : maFrameOrObj( rFrameOrObj ),
410           meType( eT ),
411           mnStates( AccessibleStates::NONE ),
412           mpParentFrame( nullptr )
413     {
414         assert(SwAccessibleEvent_Impl::DISPOSE == meType &&
415                 "wrong event constructor, DISPOSE only");
416     }
417 
SwAccessibleEvent_ImplSwAccessibleEvent_Impl418     explicit SwAccessibleEvent_Impl( EventType eT )
419         : meType( eT ),
420           mnStates( AccessibleStates::NONE ),
421           mpParentFrame( nullptr )
422     {
423         assert(SwAccessibleEvent_Impl::SHAPE_SELECTION == meType &&
424                 "wrong event constructor, SHAPE_SELECTION only" );
425     }
426 
SwAccessibleEvent_ImplSwAccessibleEvent_Impl427     SwAccessibleEvent_Impl( EventType eT,
428                             SwAccessibleContext *pA,
429                             const SwAccessibleChild& rFrameOrObj,
430                             const SwRect& rR )
431         : maOldBox( rR ),
432           mxAcc( pA ),
433           maFrameOrObj( rFrameOrObj ),
434           meType( eT ),
435           mnStates( AccessibleStates::NONE ),
436           mpParentFrame( nullptr )
437     {
438         assert((SwAccessibleEvent_Impl::CHILD_POS_CHANGED == meType ||
439                 SwAccessibleEvent_Impl::POS_CHANGED == meType) &&
440                 "wrong event constructor, (CHILD_)POS_CHANGED only" );
441     }
442 
SwAccessibleEvent_ImplSwAccessibleEvent_Impl443     SwAccessibleEvent_Impl( EventType eT,
444                             SwAccessibleContext *pA,
445                             const SwAccessibleChild& rFrameOrObj,
446                             const AccessibleStates _nStates )
447         : mxAcc( pA ),
448           maFrameOrObj( rFrameOrObj ),
449           meType( eT ),
450           mnStates( _nStates ),
451           mpParentFrame( nullptr )
452     {
453         assert( SwAccessibleEvent_Impl::CARET_OR_STATES == meType &&
454                 "wrong event constructor, CARET_OR_STATES only" );
455     }
456 
SwAccessibleEvent_ImplSwAccessibleEvent_Impl457     SwAccessibleEvent_Impl( EventType eT, const SwFrame *pParentFrame,
458                 const SwAccessibleChild& rFrameOrObj, const SwRect& rR ) :
459         maOldBox( rR ),
460         maFrameOrObj( rFrameOrObj ),
461         meType( eT ),
462         mnStates( AccessibleStates::NONE ),
463         mpParentFrame( pParentFrame )
464     {
465         assert( SwAccessibleEvent_Impl::CHILD_POS_CHANGED == meType &&
466             "wrong event constructor, CHILD_POS_CHANGED only" );
467     }
468 
469     // <SetType(..)> only used in method <SwAccessibleMap::AppendEvent(..)>
SetTypeSwAccessibleEvent_Impl470     void SetType( EventType eT )
471     {
472         meType = eT;
473     }
GetTypeSwAccessibleEvent_Impl474     EventType GetType() const
475     {
476         return meType;
477     }
478 
GetContextSwAccessibleEvent_Impl479     ::rtl::Reference < SwAccessibleContext > GetContext() const
480     {
481         uno::Reference < XAccessible > xTmp( mxAcc );
482         ::rtl::Reference < SwAccessibleContext > xAccImpl(
483                             static_cast<SwAccessibleContext*>( xTmp.get() ) );
484 
485         return xAccImpl;
486     }
487 
GetOldBoxSwAccessibleEvent_Impl488     const SwRect& GetOldBox() const
489     {
490         return maOldBox;
491     }
492     // <SetOldBox(..)> only used in method <SwAccessibleMap::AppendEvent(..)>
SetOldBoxSwAccessibleEvent_Impl493     void SetOldBox( const SwRect& rOldBox )
494     {
495         maOldBox = rOldBox;
496     }
497 
GetFrameOrObjSwAccessibleEvent_Impl498     const SwAccessibleChild& GetFrameOrObj() const
499     {
500         return maFrameOrObj;
501     }
502 
503     // <SetStates(..)> only used in method <SwAccessibleMap::AppendEvent(..)>
SetStatesSwAccessibleEvent_Impl504     void SetStates( AccessibleStates _nStates )
505     {
506         mnStates |= _nStates;
507     }
508 
IsUpdateCursorPosSwAccessibleEvent_Impl509     bool IsUpdateCursorPos() const
510     {
511         return bool(mnStates & AccessibleStates::CARET);
512     }
IsInvalidateStatesSwAccessibleEvent_Impl513     bool IsInvalidateStates() const
514     {
515         return bool(mnStates & (AccessibleStates::EDITABLE | AccessibleStates::OPAQUE));
516     }
IsInvalidateRelationSwAccessibleEvent_Impl517     bool IsInvalidateRelation() const
518     {
519         return bool(mnStates & (AccessibleStates::RELATION_FROM | AccessibleStates::RELATION_TO));
520     }
IsInvalidateTextSelectionSwAccessibleEvent_Impl521     bool IsInvalidateTextSelection() const
522     {
523         return bool( mnStates & AccessibleStates::TEXT_SELECTION_CHANGED );
524     }
525 
IsInvalidateTextAttrsSwAccessibleEvent_Impl526     bool IsInvalidateTextAttrs() const
527     {
528         return bool( mnStates & AccessibleStates::TEXT_ATTRIBUTE_CHANGED );
529     }
530 
GetStatesSwAccessibleEvent_Impl531     AccessibleStates GetStates() const
532     {
533         return mnStates;
534     }
535 
GetAllStatesSwAccessibleEvent_Impl536     AccessibleStates GetAllStates() const
537     {
538         return mnStates;
539     }
540 };
541 
542 class SwAccessibleEventList_Impl
543 {
544     std::list<SwAccessibleEvent_Impl> maEvents;
545     bool mbFiring;
546 
547 public:
SwAccessibleEventList_Impl()548     SwAccessibleEventList_Impl()
549         : mbFiring( false )
550     {}
551 
SetFiring()552     void SetFiring()
553     {
554         mbFiring = true;
555     }
IsFiring() const556     bool IsFiring() const
557     {
558         return mbFiring;
559     }
560 
561     void MoveMissingXAccToEnd();
562 
size() const563     size_t size() const { return maEvents.size(); }
begin()564     std::list<SwAccessibleEvent_Impl>::iterator begin() { return maEvents.begin(); }
end()565     std::list<SwAccessibleEvent_Impl>::iterator end() { return maEvents.end(); }
insert(const std::list<SwAccessibleEvent_Impl>::iterator & aIter,const SwAccessibleEvent_Impl & rEvent)566     std::list<SwAccessibleEvent_Impl>::iterator insert( const std::list<SwAccessibleEvent_Impl>::iterator& aIter,
567                                                         const SwAccessibleEvent_Impl& rEvent )
568     {
569         return maEvents.insert( aIter, rEvent );
570     }
erase(const std::list<SwAccessibleEvent_Impl>::iterator & aPos)571     std::list<SwAccessibleEvent_Impl>::iterator erase( const std::list<SwAccessibleEvent_Impl>::iterator& aPos )
572     {
573         return maEvents.erase( aPos );
574     }
575 };
576 
577 // see comment in SwAccessibleMap::InvalidatePosOrSize()
578 // last case "else if(pParent)" for why this surprising hack exists
MoveMissingXAccToEnd()579 void SwAccessibleEventList_Impl::MoveMissingXAccToEnd()
580 {
581     size_t nSize = size();
582     if (nSize < 2 )
583     {
584         return;
585     }
586     SwAccessibleEventList_Impl lstEvent;
587     for (auto li = begin(); li != end(); )
588     {
589         if (li->IsNoXaccParentFrame())
590         {
591             lstEvent.insert(lstEvent.end(), *li);
592             li = erase(li);
593         }
594         else
595             ++li;
596     }
597     assert(size() + lstEvent.size() == nSize);
598     maEvents.insert(end(),lstEvent.begin(),lstEvent.end());
599     assert(size() == nSize);
600 }
601 
602 struct SwAccessibleChildFunc
603 {
operator ()SwAccessibleChildFunc604     bool operator()( const SwAccessibleChild& r1,
605                          const SwAccessibleChild& r2 ) const
606     {
607         const void *p1 = r1.GetSwFrame()
608                          ? static_cast < const void * >( r1.GetSwFrame())
609                          : ( r1.GetDrawObject()
610                              ? static_cast < const void * >( r1.GetDrawObject() )
611                              : static_cast < const void * >( r1.GetWindow() ) );
612         const void *p2 = r2.GetSwFrame()
613                          ? static_cast < const void * >( r2.GetSwFrame())
614                          : ( r2.GetDrawObject()
615                              ? static_cast < const void * >( r2.GetDrawObject() )
616                              : static_cast < const void * >( r2.GetWindow() ) );
617         return p1 < p2;
618     }
619 };
620 
621 class SwAccessibleEventMap_Impl
622 {
623 public:
624     typedef SwAccessibleChild                                           key_type;
625     typedef std::list<SwAccessibleEvent_Impl>::iterator                 mapped_type;
626     typedef std::pair<const key_type,mapped_type>                       value_type;
627     typedef SwAccessibleChildFunc                                       key_compare;
628     typedef std::map<key_type,mapped_type,key_compare>::iterator        iterator;
629     typedef std::map<key_type,mapped_type,key_compare>::const_iterator  const_iterator;
630 private:
631     std::map <key_type,mapped_type,key_compare> maMap;
632 public:
end()633     iterator end() { return maMap.end(); }
find(const key_type & key)634     iterator find(const key_type& key) { return maMap.find(key); }
635     template<class... Args>
emplace(Args &&...args)636     std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
erase(const_iterator const & pos)637     iterator erase(const_iterator const & pos) { return maMap.erase(pos); }
638 };
639 
640 struct SwAccessibleParaSelection
641 {
642     TextFrameIndex const nStartOfSelection;
643     TextFrameIndex const nEndOfSelection;
644 
SwAccessibleParaSelectionSwAccessibleParaSelection645     SwAccessibleParaSelection(const TextFrameIndex nStartOfSelection_,
646                               const TextFrameIndex nEndOfSelection_)
647         : nStartOfSelection(nStartOfSelection_)
648         , nEndOfSelection(nEndOfSelection_)
649     {}
650 };
651 
652 struct SwXAccWeakRefComp
653 {
operator ()SwXAccWeakRefComp654     bool operator()( const uno::WeakReference<XAccessible>& _rXAccWeakRef1,
655                          const uno::WeakReference<XAccessible>& _rXAccWeakRef2 ) const
656     {
657         return _rXAccWeakRef1.get() < _rXAccWeakRef2.get();
658     }
659 };
660 
661 class SwAccessibleSelectedParas_Impl
662 {
663 public:
664     typedef uno::WeakReference < XAccessible >                          key_type;
665     typedef SwAccessibleParaSelection                                   mapped_type;
666     typedef std::pair<const key_type,mapped_type>                       value_type;
667     typedef SwXAccWeakRefComp                                           key_compare;
668     typedef std::map<key_type,mapped_type,key_compare>::iterator        iterator;
669     typedef std::map<key_type,mapped_type,key_compare>::const_iterator  const_iterator;
670 private:
671     std::map<key_type,mapped_type,key_compare> maMap;
672 public:
begin()673     iterator begin() { return maMap.begin(); }
end()674     iterator end() { return maMap.end(); }
find(const key_type & key)675     iterator find(const key_type& key) { return maMap.find(key); }
676     template<class... Args>
emplace(Args &&...args)677     std::pair<iterator,bool> emplace(Args&&... args) { return maMap.emplace(std::forward<Args>(args)...); }
erase(const_iterator const & pos)678     iterator erase(const_iterator const & pos) { return maMap.erase(pos); }
679 };
680 
681 // helper class that stores preview data
682 class SwAccPreviewData
683 {
684     typedef std::vector<tools::Rectangle> Rectangles;
685     Rectangles maPreviewRects;
686     Rectangles maLogicRects;
687 
688     SwRect maVisArea;
689     Fraction maScale;
690 
691     const SwPageFrame *mpSelPage;
692 
693     /** adjust logic page rectangle to its visible part
694 
695         @param _iorLogicPgSwRect
696         input/output parameter - reference to the logic page rectangle, which
697         has to be adjusted.
698 
699         @param _rPreviewPgSwRect
700         input parameter - constant reference to the corresponding preview page
701         rectangle; needed to determine the visible part of the logic page rectangle.
702 
703         @param _rPreviewWinSize
704         input parameter - constant reference to the preview window size in TWIP;
705         needed to determine the visible part of the logic page rectangle
706     */
707     static void AdjustLogicPgRectToVisibleArea( SwRect&         _iorLogicPgSwRect,
708                                          const SwRect&   _rPreviewPgSwRect,
709                                          const Size&     _rPreviewWinSize );
710 
711 public:
712     SwAccPreviewData();
713 
714     void Update( const SwAccessibleMap& rAccMap,
715                  const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
716                  const Fraction&  _rScale,
717                  const SwPageFrame* _pSelectedPageFrame,
718                  const Size&      _rPreviewWinSize );
719 
720     void InvalidateSelection( const SwPageFrame* _pSelectedPageFrame );
721 
GetVisArea() const722     const SwRect& GetVisArea() const { return maVisArea;}
723 
724     /** Adjust the MapMode so that the preview page appears at the
725      * proper position. rPoint identifies the page for which the
726      * MapMode should be adjusted. If bFromPreview is true, rPoint is
727      * a preview coordinate; else it's a document coordinate. */
728     void AdjustMapMode( MapMode& rMapMode,
729                         const Point& rPoint ) const;
730 
GetSelPage() const731     const SwPageFrame *GetSelPage() const { return mpSelPage; }
732 
733     void DisposePage(const SwPageFrame *pPageFrame );
734 };
735 
SwAccPreviewData()736 SwAccPreviewData::SwAccPreviewData() :
737     mpSelPage( nullptr )
738 {
739 }
740 
Update(const SwAccessibleMap & rAccMap,const std::vector<std::unique_ptr<PreviewPage>> & _rPreviewPages,const Fraction & _rScale,const SwPageFrame * _pSelectedPageFrame,const Size & _rPreviewWinSize)741 void SwAccPreviewData::Update( const SwAccessibleMap& rAccMap,
742                                const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
743                                const Fraction&  _rScale,
744                                const SwPageFrame* _pSelectedPageFrame,
745                                const Size&      _rPreviewWinSize )
746 {
747     // store preview scaling, maximal preview page size and selected page
748     maScale = _rScale;
749     mpSelPage = _pSelectedPageFrame;
750 
751     // prepare loop on preview pages
752     maPreviewRects.clear();
753     maLogicRects.clear();
754     SwAccessibleChild aPage;
755     maVisArea.Clear();
756 
757     // loop on preview pages to calculate <maPreviewRects>, <maLogicRects> and
758     // <maVisArea>
759     for ( auto & rpPreviewPage : _rPreviewPages )
760     {
761         aPage = rpPreviewPage->pPage;
762 
763         // add preview page rectangle to <maPreviewRects>
764         tools::Rectangle aPreviewPgRect( rpPreviewPage->aPreviewWinPos, rpPreviewPage->aPageSize );
765         maPreviewRects.push_back( aPreviewPgRect );
766 
767         // add logic page rectangle to <maLogicRects>
768         SwRect aLogicPgSwRect( aPage.GetBox( rAccMap ) );
769         tools::Rectangle aLogicPgRect( aLogicPgSwRect.SVRect() );
770         maLogicRects.push_back( aLogicPgRect );
771         // union visible area with visible part of logic page rectangle
772         if ( rpPreviewPage->bVisible )
773         {
774             if ( !rpPreviewPage->pPage->IsEmptyPage() )
775             {
776                 AdjustLogicPgRectToVisibleArea( aLogicPgSwRect,
777                                                 SwRect( aPreviewPgRect ),
778                                                 _rPreviewWinSize );
779             }
780             if ( maVisArea.IsEmpty() )
781                 maVisArea = aLogicPgSwRect;
782             else
783                 maVisArea.Union( aLogicPgSwRect );
784         }
785     }
786 }
787 
InvalidateSelection(const SwPageFrame * _pSelectedPageFrame)788 void SwAccPreviewData::InvalidateSelection( const SwPageFrame* _pSelectedPageFrame )
789 {
790     mpSelPage = _pSelectedPageFrame;
791     assert(mpSelPage);
792 }
793 
794 struct ContainsPredicate
795 {
796     const Point& mrPoint;
ContainsPredicateContainsPredicate797     explicit ContainsPredicate( const Point& rPoint ) : mrPoint(rPoint) {}
operator ()ContainsPredicate798     bool operator() ( const tools::Rectangle& rRect ) const
799     {
800         return rRect.IsInside( mrPoint );
801     }
802 };
803 
804 
AdjustMapMode(MapMode & rMapMode,const Point & rPoint) const805 void SwAccPreviewData::AdjustMapMode( MapMode& rMapMode,
806                                       const Point& rPoint ) const
807 {
808     // adjust scale
809     rMapMode.SetScaleX( maScale );
810     rMapMode.SetScaleY( maScale );
811 
812     // find proper rectangle
813     Rectangles::const_iterator aBegin = maLogicRects.begin();
814     Rectangles::const_iterator aEnd = maLogicRects.end();
815     Rectangles::const_iterator aFound = std::find_if( aBegin, aEnd,
816                                                  ContainsPredicate( rPoint ) );
817 
818     if( aFound != aEnd )
819     {
820         // found! set new origin
821         Point aPoint = (maPreviewRects.begin() + (aFound - aBegin))->TopLeft();
822         aPoint -= (maLogicRects.begin() + (aFound-aBegin))->TopLeft();
823         rMapMode.SetOrigin( aPoint );
824     }
825     // else: don't adjust MapMode
826 }
827 
DisposePage(const SwPageFrame * pPageFrame)828 void SwAccPreviewData::DisposePage(const SwPageFrame *pPageFrame )
829 {
830     if( mpSelPage == pPageFrame )
831         mpSelPage = nullptr;
832 }
833 
834 // adjust logic page rectangle to its visible part
AdjustLogicPgRectToVisibleArea(SwRect & _iorLogicPgSwRect,const SwRect & _rPreviewPgSwRect,const Size & _rPreviewWinSize)835 void SwAccPreviewData::AdjustLogicPgRectToVisibleArea(
836                             SwRect&         _iorLogicPgSwRect,
837                             const SwRect&   _rPreviewPgSwRect,
838                             const Size&     _rPreviewWinSize )
839 {
840     // determine preview window rectangle
841     const SwRect aPreviewWinSwRect( Point( 0, 0 ), _rPreviewWinSize );
842     // calculate visible preview page rectangle
843     SwRect aVisPreviewPgSwRect( _rPreviewPgSwRect );
844     aVisPreviewPgSwRect.Intersection( aPreviewWinSwRect );
845     // adjust logic page rectangle
846     SwTwips nTmpDiff;
847     // left
848     nTmpDiff = aVisPreviewPgSwRect.Left() - _rPreviewPgSwRect.Left();
849     if ( nTmpDiff > 0 )
850         _iorLogicPgSwRect.Left( _iorLogicPgSwRect.Left() + nTmpDiff );
851     // top
852     nTmpDiff = aVisPreviewPgSwRect.Top() - _rPreviewPgSwRect.Top();
853     if ( nTmpDiff > 0 )
854         _iorLogicPgSwRect.Top( _iorLogicPgSwRect.Top() + nTmpDiff );
855     // right
856     nTmpDiff = _rPreviewPgSwRect.Right() - aVisPreviewPgSwRect.Right();
857     if ( nTmpDiff > 0 )
858         _iorLogicPgSwRect.Right( _iorLogicPgSwRect.Right() - nTmpDiff );
859     // bottom
860     nTmpDiff = _rPreviewPgSwRect.Bottom() - aVisPreviewPgSwRect.Bottom();
861     if ( nTmpDiff > 0 )
862         _iorLogicPgSwRect.Bottom( _iorLogicPgSwRect.Bottom() - nTmpDiff );
863 }
864 
AreInSameTable(const uno::Reference<XAccessible> & rAcc,const SwFrame * pFrame)865 static bool AreInSameTable( const uno::Reference< XAccessible >& rAcc,
866                                   const SwFrame *pFrame )
867 {
868     bool bRet = false;
869 
870     if( pFrame && pFrame->IsCellFrame() && rAcc.is() )
871     {
872         // Is it in the same table? We check that
873         // by comparing the last table frame in the
874         // follow chain, because that's cheaper than
875         // searching the first one.
876         SwAccessibleContext *pAccImpl =
877             static_cast< SwAccessibleContext *>( rAcc.get() );
878         if( pAccImpl->GetFrame()->IsCellFrame() )
879         {
880             const SwTabFrame *pTabFrame1 = pAccImpl->GetFrame()->FindTabFrame();
881             if (pTabFrame1)
882             {
883                 while (pTabFrame1->GetFollow())
884                     pTabFrame1 = pTabFrame1->GetFollow();
885             }
886 
887             const SwTabFrame *pTabFrame2 = pFrame->FindTabFrame();
888             if (pTabFrame2)
889             {
890                 while (pTabFrame2->GetFollow())
891                     pTabFrame2 = pTabFrame2->GetFollow();
892             }
893 
894             bRet = (pTabFrame1 == pTabFrame2);
895         }
896     }
897 
898     return bRet;
899 }
900 
FireEvent(const SwAccessibleEvent_Impl & rEvent)901 void SwAccessibleMap::FireEvent( const SwAccessibleEvent_Impl& rEvent )
902 {
903     ::rtl::Reference < SwAccessibleContext > xAccImpl( rEvent.GetContext() );
904     if (!xAccImpl.is() && rEvent.mpParentFrame != nullptr)
905     {
906         SwAccessibleContextMap_Impl::iterator aIter =
907             mpFrameMap->find( rEvent.mpParentFrame );
908         if( aIter != mpFrameMap->end() )
909         {
910             uno::Reference < XAccessible > xAcc( (*aIter).second );
911             if (xAcc.is())
912             {
913                 uno::Reference < XAccessibleContext >  xContext(xAcc,uno::UNO_QUERY);
914                 if (xContext.is() && xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH)
915                 {
916                     xAccImpl = static_cast< SwAccessibleContext *>( xAcc.get() );
917                 }
918             }
919         }
920     }
921     if( SwAccessibleEvent_Impl::SHAPE_SELECTION == rEvent.GetType() )
922     {
923         DoInvalidateShapeSelection();
924     }
925     else if( xAccImpl.is() && xAccImpl->GetFrame() )
926     {
927         if ( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE &&
928              rEvent.IsInvalidateTextAttrs() )
929         {
930             xAccImpl->InvalidateAttr();
931         }
932         switch( rEvent.GetType() )
933         {
934         case SwAccessibleEvent_Impl::INVALID_CONTENT:
935             xAccImpl->InvalidateContent();
936             break;
937         case SwAccessibleEvent_Impl::POS_CHANGED:
938             xAccImpl->InvalidatePosOrSize( rEvent.GetOldBox() );
939             break;
940         case SwAccessibleEvent_Impl::CHILD_POS_CHANGED:
941             xAccImpl->InvalidateChildPosOrSize( rEvent.GetFrameOrObj(),
942                                        rEvent.GetOldBox() );
943             break;
944         case SwAccessibleEvent_Impl::DISPOSE:
945             assert(!"dispose event has been stored");
946             break;
947         case SwAccessibleEvent_Impl::INVALID_ATTR:
948             // nothing to do here - handled above
949             break;
950         default:
951             break;
952         }
953         if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() )
954         {
955             if( rEvent.IsUpdateCursorPos() )
956                 xAccImpl->InvalidateCursorPos();
957             if( rEvent.IsInvalidateStates() )
958                 xAccImpl->InvalidateStates( rEvent.GetStates() );
959             if( rEvent.IsInvalidateRelation() )
960             {
961                 // both events CONTENT_FLOWS_FROM_RELATION_CHANGED and
962                 // CONTENT_FLOWS_TO_RELATION_CHANGED are possible
963                 if ( rEvent.GetAllStates() & AccessibleStates::RELATION_FROM )
964                 {
965                     xAccImpl->InvalidateRelation(
966                         AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED );
967                 }
968                 if ( rEvent.GetAllStates() & AccessibleStates::RELATION_TO )
969                 {
970                     xAccImpl->InvalidateRelation(
971                         AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED );
972                 }
973             }
974 
975             if ( rEvent.IsInvalidateTextSelection() )
976             {
977                 xAccImpl->InvalidateTextSelection();
978             }
979         }
980     }
981 }
982 
AppendEvent(const SwAccessibleEvent_Impl & rEvent)983 void SwAccessibleMap::AppendEvent( const SwAccessibleEvent_Impl& rEvent )
984 {
985     osl::MutexGuard aGuard( maEventMutex );
986 
987     if( !mpEvents )
988         mpEvents.reset(new SwAccessibleEventList_Impl);
989     if( !mpEventMap )
990         mpEventMap.reset(new SwAccessibleEventMap_Impl);
991 
992     if( mpEvents->IsFiring() )
993     {
994         // While events are fired new ones are generated. They have to be fired
995         // now. This does not work for DISPOSE events!
996         OSL_ENSURE( rEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE,
997                 "dispose event while firing events" );
998         FireEvent( rEvent );
999     }
1000     else
1001     {
1002 
1003         SwAccessibleEventMap_Impl::iterator aIter =
1004                                         mpEventMap->find( rEvent.GetFrameOrObj() );
1005         if( aIter != mpEventMap->end() )
1006         {
1007             SwAccessibleEvent_Impl aEvent( *(*aIter).second );
1008             assert( aEvent.GetType() != SwAccessibleEvent_Impl::DISPOSE &&
1009                     "dispose events should not be stored" );
1010             bool bAppendEvent = true;
1011             switch( rEvent.GetType() )
1012             {
1013             case SwAccessibleEvent_Impl::CARET_OR_STATES:
1014                 // A CARET_OR_STATES event is added to any other
1015                 // event only. It is broadcasted after any other event, so the
1016                 // event should be put to the back.
1017                 OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
1018                         "invalid event combination" );
1019                 aEvent.SetStates( rEvent.GetAllStates() );
1020                 break;
1021             case SwAccessibleEvent_Impl::INVALID_CONTENT:
1022                 // An INVALID_CONTENT event overwrites a CARET_OR_STATES
1023                 // event (but keeps its flags) and it is contained in a
1024                 // POS_CHANGED event.
1025                 // Therefore, the event's type has to be adapted and the event
1026                 // has to be put at the end.
1027                 //
1028                 // fdo#56031 An INVALID_CONTENT event overwrites a INVALID_ATTR
1029                 // event and overwrites its flags
1030                 OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
1031                         "invalid event combination" );
1032                 if( aEvent.GetType() == SwAccessibleEvent_Impl::CARET_OR_STATES )
1033                     aEvent.SetType( SwAccessibleEvent_Impl::INVALID_CONTENT );
1034                 else if ( aEvent.GetType() == SwAccessibleEvent_Impl::INVALID_ATTR )
1035                 {
1036                     aEvent.SetType( SwAccessibleEvent_Impl::INVALID_CONTENT );
1037                     aEvent.SetStates( rEvent.GetAllStates() );
1038                 }
1039 
1040                 break;
1041             case SwAccessibleEvent_Impl::POS_CHANGED:
1042                 // A pos changed event overwrites CARET_STATES (keeping its
1043                 // flags) as well as INVALID_CONTENT. The old box position
1044                 // has to be stored however if the old event is not a
1045                 // POS_CHANGED itself.
1046                 OSL_ENSURE( aEvent.GetType() != SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
1047                         "invalid event combination" );
1048                 if( aEvent.GetType() != SwAccessibleEvent_Impl::POS_CHANGED )
1049                     aEvent.SetOldBox( rEvent.GetOldBox() );
1050                 aEvent.SetType( SwAccessibleEvent_Impl::POS_CHANGED );
1051                 break;
1052             case SwAccessibleEvent_Impl::CHILD_POS_CHANGED:
1053                 // CHILD_POS_CHANGED events can only follow CHILD_POS_CHANGED
1054                 // events. The only action that needs to be done again is
1055                 // to put the old event to the back. The new one cannot be used,
1056                 // because we are interested in the old frame bounds.
1057                 OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
1058                         "invalid event combination" );
1059                 break;
1060             case SwAccessibleEvent_Impl::SHAPE_SELECTION:
1061                 OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::SHAPE_SELECTION,
1062                         "invalid event combination" );
1063                 break;
1064             case SwAccessibleEvent_Impl::DISPOSE:
1065                 // DISPOSE events overwrite all others. They are not stored
1066                 // but executed immediately to avoid broadcasting of
1067                 // nonfunctional objects. So what needs to be done here is to
1068                 // remove all events for the frame in question.
1069                 bAppendEvent = false;
1070                 break;
1071             case SwAccessibleEvent_Impl::INVALID_ATTR:
1072                 OSL_ENSURE( aEvent.GetType() == SwAccessibleEvent_Impl::INVALID_ATTR,
1073                         "invalid event combination" );
1074                 break;
1075             }
1076             if( bAppendEvent )
1077             {
1078                 mpEvents->erase( (*aIter).second );
1079                 (*aIter).second = mpEvents->insert( mpEvents->end(), aEvent );
1080             }
1081             else
1082             {
1083                 mpEvents->erase( (*aIter).second );
1084                 mpEventMap->erase( aIter );
1085             }
1086         }
1087         else if( SwAccessibleEvent_Impl::DISPOSE != rEvent.GetType() )
1088         {
1089             mpEventMap->emplace( rEvent.GetFrameOrObj(),
1090                     mpEvents->insert( mpEvents->end(), rEvent ) );
1091         }
1092     }
1093 }
1094 
InvalidateCursorPosition(const uno::Reference<XAccessible> & rAcc)1095 void SwAccessibleMap::InvalidateCursorPosition(
1096         const uno::Reference< XAccessible >& rAcc )
1097 {
1098     SwAccessibleContext *pAccImpl =
1099         static_cast< SwAccessibleContext *>( rAcc.get() );
1100     assert(pAccImpl);
1101     assert(pAccImpl->GetFrame());
1102     if( GetShell()->ActionPend() )
1103     {
1104         SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES,
1105                                        pAccImpl,
1106                                        SwAccessibleChild(pAccImpl->GetFrame()),
1107                                        AccessibleStates::CARET );
1108         AppendEvent( aEvent );
1109     }
1110     else
1111     {
1112         FireEvents();
1113         // While firing events the current frame might have
1114         // been disposed because it moved out of the visible area.
1115         // Setting the cursor for such frames is useless and even
1116         // causes asserts.
1117         if( pAccImpl->GetFrame() )
1118             pAccImpl->InvalidateCursorPos();
1119     }
1120 }
1121 
InvalidateShapeSelection()1122 void SwAccessibleMap::InvalidateShapeSelection()
1123 {
1124     if( GetShell()->ActionPend() )
1125     {
1126         SwAccessibleEvent_Impl aEvent(
1127             SwAccessibleEvent_Impl::SHAPE_SELECTION );
1128         AppendEvent( aEvent );
1129     }
1130     else
1131     {
1132         FireEvents();
1133         DoInvalidateShapeSelection();
1134     }
1135 }
1136 
1137 //This method should implement the following functions:
1138 //1.find the shape objects and set the selected state.
1139 //2.find the Swframe objects and set the selected state.
1140 //3.find the paragraph objects and set the selected state.
InvalidateShapeInParaSelection()1141 void SwAccessibleMap::InvalidateShapeInParaSelection()
1142 {
1143     std::unique_ptr<SwAccessibleObjShape_Impl[]> pShapes;
1144     SwAccessibleObjShape_Impl *pSelShape = nullptr;
1145     size_t nShapes = 0;
1146 
1147     const SwViewShell *pVSh = GetShell();
1148     const SwFEShell *pFESh = dynamic_cast<const SwFEShell*>( pVSh) !=  nullptr ?
1149                             static_cast< const SwFEShell * >( pVSh ) : nullptr;
1150     SwPaM* pCursor = pFESh ? pFESh->GetCursor( false /* ??? */ ) : nullptr;
1151 
1152     //const size_t nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
1153 
1154     {
1155         osl::MutexGuard aGuard( maMutex );
1156         if( mpShapeMap )
1157             pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape );
1158     }
1159 
1160     bool bIsSelAll =IsDocumentSelAll();
1161 
1162     if( mpShapeMap )
1163     {
1164         //Checked for shapes.
1165         SwAccessibleShapeMap_Impl::const_iterator aIter = mpShapeMap->cbegin();
1166         SwAccessibleShapeMap_Impl::const_iterator aEndIter = mpShapeMap->cend();
1167         ::rtl::Reference< SwAccessibleContext > xParentAccImpl;
1168 
1169         if( bIsSelAll)
1170         {
1171             while( aIter != aEndIter )
1172             {
1173                 uno::Reference < XAccessible > xAcc( (*aIter).second );
1174                 if( xAcc.is() )
1175                     static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->SetState( AccessibleStateType::SELECTED );
1176 
1177                 ++aIter;
1178             }
1179         }
1180         else
1181         {
1182             while( aIter != aEndIter )
1183             {
1184                 SwAccessibleChild aFrame( (*aIter).first );
1185 
1186                 const SwFrameFormat *pFrameFormat = (*aIter).first ? ::FindFrameFormat( (*aIter).first ) : nullptr;
1187                 if( !pFrameFormat )
1188                 {
1189                     ++aIter;
1190                     continue;
1191                 }
1192                 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
1193                 const SwPosition *pPos = rAnchor.GetContentAnchor();
1194 
1195                 if(rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE)
1196                 {
1197                     uno::Reference < XAccessible > xAcc( (*aIter).second );
1198                     if(xAcc.is())
1199                         static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1200 
1201                     ++aIter;
1202                     continue;
1203                 }
1204 
1205                 if( !pPos )
1206                 {
1207                     ++aIter;
1208                     continue;
1209                 }
1210                 if( pPos->nNode.GetNode().GetTextNode() )
1211                 {
1212                     int nIndex = pPos->nContent.GetIndex();
1213                     bool bMarked = false;
1214                     if( pCursor != nullptr )
1215                     {
1216                         const SwTextNode* pNode = pPos->nNode.GetNode().GetTextNode();
1217                         SwTextFrame const*const pFrame(static_cast<SwTextFrame*>(pNode->getLayoutFrame(pVSh->GetLayout())));
1218                         sal_uLong nFirstNode(pFrame->GetTextNodeFirst()->GetIndex());
1219                         sal_uLong nLastNode;
1220                         if (sw::MergedPara const*const pMerged = pFrame->GetMergedPara())
1221                         {
1222                             nLastNode = pMerged->pLastNode->GetIndex();
1223                         }
1224                         else
1225                         {
1226                             nLastNode = nFirstNode;
1227                         }
1228 
1229                         sal_uLong nHere = pNode->GetIndex();
1230 
1231                         for(SwPaM& rTmpCursor : pCursor->GetRingContainer())
1232                         {
1233                             // ignore, if no mark
1234                             if( rTmpCursor.HasMark() )
1235                             {
1236                                 bMarked = true;
1237                                 // check whether nHere is 'inside' pCursor
1238                                 SwPosition* pStart = rTmpCursor.Start();
1239                                 sal_uLong nStartIndex = pStart->nNode.GetIndex();
1240                                 SwPosition* pEnd = rTmpCursor.End();
1241                                 sal_uLong nEndIndex = pEnd->nNode.GetIndex();
1242                                 if ((nStartIndex <= nLastNode) && (nFirstNode <= nEndIndex))
1243                                 {
1244                                     if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1245                                     {
1246                                         if( ( ((nHere == nStartIndex) && (nIndex >= pStart->nContent.GetIndex())) || (nHere > nStartIndex) )
1247                                             &&( ((nHere == nEndIndex) && (nIndex < pEnd->nContent.GetIndex())) || (nHere < nEndIndex) ) )
1248                                         {
1249                                             uno::Reference < XAccessible > xAcc( (*aIter).second );
1250                                             if( xAcc.is() )
1251                                                 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->SetState( AccessibleStateType::SELECTED );
1252                                         }
1253                                         else
1254                                         {
1255                                             uno::Reference < XAccessible > xAcc( (*aIter).second );
1256                                             if( xAcc.is() )
1257                                                 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1258                                         }
1259                                     }
1260                                     else if( rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA )
1261                                     {
1262                                         uno::Reference<XAccessible> const xAcc((*aIter).second);
1263                                         if (xAcc.is())
1264                                         {
1265                                             if (IsSelectFrameAnchoredAtPara(*pPos, *pStart, *pEnd))
1266                                             {
1267                                                 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->SetState( AccessibleStateType::SELECTED );
1268                                             }
1269                                             else
1270                                             {
1271                                                 static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1272                                             }
1273                                         }
1274                                     }
1275                                     else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
1276                                     {
1277                                         uno::Reference<XAccessible> const xAcc((*aIter).second);
1278                                         if (xAcc.is())
1279                                         {
1280                                             if (IsDestroyFrameAnchoredAtChar(*pPos, *pStart, *pEnd))
1281                                             {
1282                                                 static_cast<::accessibility::AccessibleShape*>(xAcc.get())->SetState( AccessibleStateType::SELECTED );
1283                                             }
1284                                             else
1285                                             {
1286                                                 static_cast<::accessibility::AccessibleShape*>(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1287                                             }
1288                                         }
1289                                     }
1290                                 }
1291                             }
1292                         }
1293                     }
1294                     if( !bMarked )
1295                     {
1296                         SwAccessibleObjShape_Impl  *pShape = pShapes.get();
1297                         size_t nNumShapes = nShapes;
1298                         while( nNumShapes )
1299                         {
1300                             if( pShape < pSelShape && (pShape->first==(*aIter).first) )
1301                             {
1302                                 uno::Reference < XAccessible > xAcc( (*aIter).second );
1303                                 if(xAcc.is())
1304                                     static_cast < ::accessibility::AccessibleShape* >(xAcc.get())->ResetState( AccessibleStateType::SELECTED );
1305                             }
1306                             --nNumShapes;
1307                             ++pShape;
1308                         }
1309                     }
1310                 }
1311 
1312                 ++aIter;
1313             }//while( aIter != aEndIter )
1314         }//else
1315     }
1316 
1317     pShapes.reset();
1318 
1319     //Checked for FlyFrame
1320     if (mpFrameMap)
1321     {
1322         SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->begin();
1323         while( aIter != mpFrameMap->end() )
1324         {
1325             const SwFrame *pFrame = (*aIter).first;
1326             if(pFrame->IsFlyFrame())
1327             {
1328                 uno::Reference < XAccessible > xAcc = (*aIter).second;
1329 
1330                 if(xAcc.is())
1331                 {
1332                     SwAccessibleFrameBase *pAccFrame = static_cast< SwAccessibleFrameBase * >(xAcc.get());
1333                     bool bFrameChanged = pAccFrame->SetSelectedState( true );
1334                     if (bFrameChanged)
1335                     {
1336                         const SwFlyFrame *pFlyFrame = static_cast< const SwFlyFrame * >( pFrame );
1337                         const SwFrameFormat *pFrameFormat = pFlyFrame->GetFormat();
1338                         if (pFrameFormat)
1339                         {
1340                             const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
1341                             if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1342                             {
1343                                 uno::Reference< XAccessible > xAccParent = pAccFrame->getAccessibleParent();
1344                                 if (xAccParent.is())
1345                                 {
1346                                     uno::Reference< XAccessibleContext > xAccContext = xAccParent->getAccessibleContext();
1347                                     if(xAccContext.is() && xAccContext->getAccessibleRole() == AccessibleRole::PARAGRAPH)
1348                                     {
1349                                         SwAccessibleParagraph* pAccPara = static_cast< SwAccessibleParagraph *>(xAccContext.get());
1350                                         if(pAccFrame->IsSeletedInDoc())
1351                                         {
1352                                             m_setParaAdd.insert(pAccPara);
1353                                         }
1354                                         else if(m_setParaAdd.count(pAccPara) == 0)
1355                                         {
1356                                             m_setParaRemove.insert(pAccPara);
1357                                         }
1358                                     }
1359                                 }
1360                             }
1361                         }
1362                     }
1363                 }
1364             }
1365             ++aIter;
1366         }
1367     }
1368 
1369     typedef std::vector< SwAccessibleContext* > VEC_PARA;
1370     VEC_PARA vecAdd;
1371     VEC_PARA vecRemove;
1372     //Checked for Paras.
1373     bool bMarkChanged = false;
1374     SwAccessibleContextMap_Impl mapTemp;
1375     if( pCursor != nullptr )
1376     {
1377         for(SwPaM& rTmpCursor : pCursor->GetRingContainer())
1378         {
1379             if( rTmpCursor.HasMark() )
1380             {
1381                 SwNodeIndex nStartIndex( rTmpCursor.Start()->nNode );
1382                 SwNodeIndex nEndIndex( rTmpCursor.End()->nNode );
1383                 for (; nStartIndex <= nEndIndex; ++nStartIndex)
1384                 {
1385                     SwFrame *pFrame = nullptr;
1386                     if(nStartIndex.GetNode().IsContentNode())
1387                     {
1388                         SwContentNode* pCNd = static_cast<SwContentNode*>(&(nStartIndex.GetNode()));
1389                         pFrame = SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First();
1390                         if (mapTemp.find(pFrame) != mapTemp.end())
1391                         {
1392                             continue; // sw_redlinehide: once is enough
1393                         }
1394                     }
1395                     else if( nStartIndex.GetNode().IsTableNode() )
1396                     {
1397                         SwTableNode * pTable = static_cast<SwTableNode *>(&(nStartIndex.GetNode()));
1398                         SwTableFormat* pFormat = pTable->GetTable().GetFrameFormat();
1399                         pFrame = SwIterator<SwFrame, SwTableFormat>(*pFormat).First();
1400                     }
1401 
1402                     if( pFrame && mpFrameMap)
1403                     {
1404                         SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pFrame );
1405                         if( aIter != mpFrameMap->end() )
1406                         {
1407                             uno::Reference < XAccessible > xAcc = (*aIter).second;
1408                             bool isChanged = false;
1409                             if( xAcc.is() )
1410                             {
1411                                 isChanged = static_cast< SwAccessibleContext * >(xAcc.get())->SetSelectedState( true );
1412                             }
1413                             if(!isChanged)
1414                             {
1415                                 SwAccessibleContextMap_Impl::iterator aEraseIter = mpSeletedFrameMap->find( pFrame );
1416                                 if(aEraseIter != mpSeletedFrameMap->end())
1417                                     mpSeletedFrameMap->erase(aEraseIter);
1418                             }
1419                             else
1420                             {
1421                                 bMarkChanged = true;
1422                                 vecAdd.push_back(static_cast< SwAccessibleContext * >(xAcc.get()));
1423                             }
1424 
1425                             mapTemp.emplace( pFrame, xAcc );
1426                         }
1427                     }
1428                 }
1429             }
1430         }
1431     }
1432     if( !mpSeletedFrameMap )
1433         mpSeletedFrameMap.reset( new SwAccessibleContextMap_Impl );
1434     if( !mpSeletedFrameMap->empty() )
1435     {
1436         SwAccessibleContextMap_Impl::iterator aIter = mpSeletedFrameMap->begin();
1437         while( aIter != mpSeletedFrameMap->end() )
1438         {
1439             uno::Reference < XAccessible > xAcc = (*aIter).second;
1440             if(xAcc.is())
1441                 static_cast< SwAccessibleContext * >(xAcc.get())->SetSelectedState( false );
1442             ++aIter;
1443             vecRemove.push_back(static_cast< SwAccessibleContext * >(xAcc.get()));
1444         }
1445         bMarkChanged = true;
1446         mpSeletedFrameMap->clear();
1447     }
1448 
1449     SwAccessibleContextMap_Impl::iterator aIter = mapTemp.begin();
1450     while( aIter != mapTemp.end() )
1451     {
1452         mpSeletedFrameMap->emplace( (*aIter).first, (*aIter).second );
1453         ++aIter;
1454     }
1455     mapTemp.clear();
1456 
1457     if( bMarkChanged && mpFrameMap)
1458     {
1459         for (SwAccessibleContext* pAccPara : vecAdd)
1460         {
1461             AccessibleEventObject aEvent;
1462             aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
1463             if (pAccPara)
1464             {
1465                 pAccPara->FireAccessibleEvent( aEvent );
1466             }
1467         }
1468         for (SwAccessibleContext* pAccPara : vecRemove)
1469         {
1470             AccessibleEventObject aEvent;
1471             aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
1472             if (pAccPara)
1473             {
1474                 pAccPara->FireAccessibleEvent( aEvent );
1475             }
1476         }
1477     }
1478 }
1479 
1480 //Merge with DoInvalidateShapeFocus
DoInvalidateShapeSelection(bool bInvalidateFocusMode)1481 void SwAccessibleMap::DoInvalidateShapeSelection(bool bInvalidateFocusMode /*=false*/)
1482 {
1483     std::unique_ptr<SwAccessibleObjShape_Impl[]> pShapes;
1484     SwAccessibleObjShape_Impl *pSelShape = nullptr;
1485     size_t nShapes = 0;
1486 
1487     const SwViewShell *pVSh = GetShell();
1488     const SwFEShell *pFESh = dynamic_cast<const SwFEShell*>( pVSh) !=  nullptr ?
1489                             static_cast< const SwFEShell * >( pVSh ) : nullptr;
1490     const size_t nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
1491 
1492     //when InvalidateFocus Call this function ,and the current selected shape count is not 1 ,
1493     //return
1494     if (bInvalidateFocusMode && nSelShapes != 1)
1495     {
1496         return;
1497     }
1498     {
1499         osl::MutexGuard aGuard( maMutex );
1500         if( mpShapeMap )
1501             pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape );
1502     }
1503 
1504     if( !pShapes )
1505         return;
1506 
1507     typedef std::vector< ::rtl::Reference < ::accessibility::AccessibleShape >  >  VEC_SHAPE;
1508     VEC_SHAPE vecxShapeAdd;
1509     VEC_SHAPE vecxShapeRemove;
1510     int nCountSelectedShape=0;
1511 
1512     vcl::Window *pWin = GetShell()->GetWin();
1513     bool bFocused = pWin && pWin->HasFocus();
1514     SwAccessibleObjShape_Impl *pShape = pShapes.get();
1515     int nShapeCount = nShapes;
1516     while( nShapeCount )
1517     {
1518         if (pShape->second.is() && IsInSameLevel(pShape->first, pFESh))
1519         {
1520             if( pShape < pSelShape )
1521             {
1522                 if(pShape->second->ResetState( AccessibleStateType::SELECTED ))
1523                 {
1524                     vecxShapeRemove.push_back(pShape->second);
1525                 }
1526                 pShape->second->ResetState( AccessibleStateType::FOCUSED );
1527             }
1528         }
1529         --nShapeCount;
1530         ++pShape;
1531     }
1532 
1533     for (const auto& rpShape : vecxShapeRemove)
1534     {
1535         ::accessibility::AccessibleShape *pAccShape = rpShape.get();
1536         if (pAccShape)
1537         {
1538             pAccShape->CommitChange(AccessibleEventId::SELECTION_CHANGED_REMOVE, uno::Any(), uno::Any());
1539         }
1540     }
1541 
1542     pShape = pShapes.get();
1543 
1544     while( nShapes )
1545     {
1546         if (pShape->second.is() && IsInSameLevel(pShape->first, pFESh))
1547         {
1548             if( pShape >= pSelShape )
1549             {
1550                 //first fire focus event
1551                 if( bFocused && 1 == nSelShapes )
1552                     pShape->second->SetState( AccessibleStateType::FOCUSED );
1553                 else
1554                     pShape->second->ResetState( AccessibleStateType::FOCUSED );
1555 
1556                 if(pShape->second->SetState( AccessibleStateType::SELECTED ))
1557                 {
1558                     vecxShapeAdd.push_back(pShape->second);
1559                 }
1560                 ++nCountSelectedShape;
1561             }
1562         }
1563 
1564         --nShapes;
1565         ++pShape;
1566     }
1567 
1568     const unsigned int SELECTION_WITH_NUM = 10;
1569     if (vecxShapeAdd.size() > SELECTION_WITH_NUM )
1570     {
1571          uno::Reference< XAccessible > xDoc = GetDocumentView( );
1572          SwAccessibleContext * pCont = static_cast<SwAccessibleContext *>(xDoc.get());
1573          if (pCont)
1574          {
1575              AccessibleEventObject aEvent;
1576              aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
1577              pCont->FireAccessibleEvent(aEvent);
1578          }
1579     }
1580     else
1581     {
1582         short nEventID = AccessibleEventId::SELECTION_CHANGED_ADD;
1583         if (nCountSelectedShape <= 1 && vecxShapeAdd.size() == 1 )
1584         {
1585             nEventID = AccessibleEventId::SELECTION_CHANGED;
1586         }
1587         for (const auto& rpShape : vecxShapeAdd)
1588         {
1589             ::accessibility::AccessibleShape *pAccShape = rpShape.get();
1590             if (pAccShape)
1591             {
1592                 pAccShape->CommitChange(nEventID, uno::Any(), uno::Any());
1593             }
1594         }
1595     }
1596 
1597     for (const auto& rpShape : vecxShapeAdd)
1598     {
1599         ::accessibility::AccessibleShape *pAccShape = rpShape.get();
1600         if (pAccShape)
1601         {
1602             SdrObject *pObj = GetSdrObjectFromXShape(pAccShape->GetXShape());
1603             SwFrameFormat *pFrameFormat = pObj ? FindFrameFormat( pObj ) : nullptr;
1604             if (pFrameFormat)
1605             {
1606                 const SwFormatAnchor& rAnchor = pFrameFormat->GetAnchor();
1607                 if( rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1608                 {
1609                     uno::Reference< XAccessible > xPara = pAccShape->getAccessibleParent();
1610                     if (xPara.is())
1611                     {
1612                         uno::Reference< XAccessibleContext > xParaContext = xPara->getAccessibleContext();
1613                         if (xParaContext.is() && xParaContext->getAccessibleRole() == AccessibleRole::PARAGRAPH)
1614                         {
1615                             SwAccessibleParagraph* pAccPara = static_cast< SwAccessibleParagraph *>(xPara.get());
1616                             if (pAccPara)
1617                             {
1618                                 m_setParaAdd.insert(pAccPara);
1619                             }
1620                         }
1621                     }
1622                 }
1623             }
1624         }
1625     }
1626     for (const auto& rpShape : vecxShapeRemove)
1627     {
1628         ::accessibility::AccessibleShape *pAccShape = rpShape.get();
1629         if (pAccShape)
1630         {
1631             uno::Reference< XAccessible > xPara = pAccShape->getAccessibleParent();
1632             uno::Reference< XAccessibleContext > xParaContext = xPara->getAccessibleContext();
1633             if (xParaContext.is() && xParaContext->getAccessibleRole() == AccessibleRole::PARAGRAPH)
1634             {
1635                 SwAccessibleParagraph* pAccPara = static_cast< SwAccessibleParagraph *>(xPara.get());
1636                 if (m_setParaAdd.count(pAccPara) == 0 )
1637                 {
1638                     m_setParaRemove.insert(pAccPara);
1639                 }
1640             }
1641         }
1642     }
1643 }
1644 
1645 //Merge with DoInvalidateShapeSelection
1646 /*
1647 void SwAccessibleMap::DoInvalidateShapeFocus()
1648 {
1649     const SwViewShell *pVSh = GetShell();
1650     const SwFEShell *pFESh = dynamic_cast<const SwFEShell*>( pVSh) !=  nullptr ?
1651                             static_cast< const SwFEShell * >( pVSh ) : nullptr;
1652     const size_t nSelShapes = pFESh ? pFESh->IsObjSelected() : 0;
1653 
1654     if( nSelShapes != 1 )
1655         return;
1656 
1657     SwAccessibleObjShape_Impl *pShapes = nullptr;
1658     SwAccessibleObjShape_Impl *pSelShape = nullptr;
1659     size_t nShapes = 0;
1660 
1661     {
1662         osl::MutexGuard aGuard( maMutex );
1663         if( mpShapeMap )
1664             pShapes = mpShapeMap->Copy( nShapes, pFESh, &pSelShape );
1665     }
1666 
1667     if( pShapes )
1668     {
1669         vcl::Window *pWin = GetShell()->GetWin();
1670         bool bFocused = pWin && pWin->HasFocus();
1671         SwAccessibleObjShape_Impl  *pShape = pShapes;
1672         while( nShapes )
1673         {
1674             if( pShape->second.is() )
1675             {
1676                 if( bFocused && pShape >= pSelShape )
1677                     pShape->second->SetState( AccessibleStateType::FOCUSED );
1678                 else
1679                     pShape->second->ResetState( AccessibleStateType::FOCUSED );
1680             }
1681 
1682             --nShapes;
1683             ++pShape;
1684         }
1685 
1686         delete[] pShapes;
1687     }
1688 }
1689 
1690 */
1691 
SwAccessibleMap(SwViewShell * pSh)1692 SwAccessibleMap::SwAccessibleMap( SwViewShell *pSh ) :
1693     mpVSh( pSh ),
1694     mbShapeSelected( false ),
1695     maDocName(SwAccessibleContext::GetResource(STR_ACCESS_DOC_NAME))
1696 {
1697     pSh->GetLayout()->AddAccessibleShell();
1698 }
1699 
~SwAccessibleMap()1700 SwAccessibleMap::~SwAccessibleMap()
1701 {
1702     DBG_TESTSOLARMUTEX();
1703     uno::Reference < XAccessible > xAcc;
1704     {
1705         osl::MutexGuard aGuard( maMutex );
1706         if( mpFrameMap )
1707         {
1708             const SwRootFrame *pRootFrame = GetShell()->GetLayout();
1709             SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pRootFrame );
1710             if( aIter != mpFrameMap->end() )
1711                 xAcc = (*aIter).second;
1712             if( !xAcc.is() )
1713                 assert(false); // let's hope this can't happen? the vcl::Window apparently owns the top-level
1714                 //xAcc = new SwAccessibleDocument(shared_from_this());
1715         }
1716     }
1717 
1718     if(xAcc.is())
1719     {
1720         SwAccessibleDocumentBase *const pAcc =
1721             static_cast<SwAccessibleDocumentBase *>(xAcc.get());
1722         pAcc->Dispose( true );
1723     }
1724 #if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
1725     if( mpFrameMap )
1726     {
1727         SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->begin();
1728         while( aIter != mpFrameMap->end() )
1729         {
1730             uno::Reference < XAccessible > xTmp = (*aIter).second;
1731             if( xTmp.is() )
1732             {
1733                 SwAccessibleContext *pTmp = static_cast< SwAccessibleContext * >( xTmp.get() );
1734                 assert(pTmp->GetMap() == nullptr); // must be disposed
1735             }
1736             ++aIter;
1737         }
1738     }
1739 #endif
1740     {
1741         osl::MutexGuard aGuard( maMutex );
1742         assert((!mpFrameMap || mpFrameMap->empty()) &&
1743                 "Frame map should be empty after disposing the root frame");
1744         assert((!mpShapeMap || mpShapeMap->empty()) &&
1745                 "Object map should be empty after disposing the root frame");
1746         mpFrameMap.reset();
1747         mpShapeMap.reset();
1748         mvShapes.clear();
1749         mpSelectedParas.reset();
1750     }
1751 
1752     mpPreview.reset();
1753 
1754     {
1755         osl::MutexGuard aGuard( maEventMutex );
1756         assert(!mpEvents);
1757         assert(!mpEventMap);
1758         mpEventMap.reset();
1759         mpEvents.reset();
1760     }
1761     mpVSh->GetLayout()->RemoveAccessibleShell();
1762 }
1763 
GetDocumentView_(bool bPagePreview)1764 uno::Reference< XAccessible > SwAccessibleMap::GetDocumentView_(
1765     bool bPagePreview )
1766 {
1767     uno::Reference < XAccessible > xAcc;
1768     bool bSetVisArea = false;
1769 
1770     {
1771         osl::MutexGuard aGuard( maMutex );
1772 
1773         if( !mpFrameMap )
1774         {
1775             mpFrameMap.reset(new SwAccessibleContextMap_Impl);
1776 #if OSL_DEBUG_LEVEL > 0
1777             mpFrameMap->mbLocked = false;
1778 #endif
1779         }
1780 
1781 #if OSL_DEBUG_LEVEL > 0
1782         assert(!mpFrameMap->mbLocked);
1783         mpFrameMap->mbLocked = true;
1784 #endif
1785 
1786         const SwRootFrame *pRootFrame = GetShell()->GetLayout();
1787         SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pRootFrame );
1788         if( aIter != mpFrameMap->end() )
1789             xAcc = (*aIter).second;
1790         if( xAcc.is() )
1791         {
1792             bSetVisArea = true; // Set VisArea when map mutex is not locked
1793         }
1794         else
1795         {
1796             if( bPagePreview )
1797                 xAcc = new SwAccessiblePreview(shared_from_this());
1798             else
1799                 xAcc = new SwAccessibleDocument(shared_from_this());
1800 
1801             if( aIter != mpFrameMap->end() )
1802             {
1803                 (*aIter).second = xAcc;
1804             }
1805             else
1806             {
1807                 mpFrameMap->emplace( pRootFrame, xAcc );
1808             }
1809         }
1810 
1811 #if OSL_DEBUG_LEVEL > 0
1812         mpFrameMap->mbLocked = false;
1813 #endif
1814     }
1815 
1816     if( bSetVisArea )
1817     {
1818         SwAccessibleDocumentBase *pAcc =
1819             static_cast< SwAccessibleDocumentBase * >( xAcc.get() );
1820         pAcc->SetVisArea();
1821     }
1822 
1823     return xAcc;
1824 }
1825 
GetDocumentView()1826 uno::Reference< XAccessible > SwAccessibleMap::GetDocumentView( )
1827 {
1828     return GetDocumentView_( false );
1829 }
1830 
GetDocumentPreview(const std::vector<std::unique_ptr<PreviewPage>> & _rPreviewPages,const Fraction & _rScale,const SwPageFrame * _pSelectedPageFrame,const Size & _rPreviewWinSize)1831 uno::Reference<XAccessible> SwAccessibleMap::GetDocumentPreview(
1832                                     const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
1833                                     const Fraction&  _rScale,
1834                                     const SwPageFrame* _pSelectedPageFrame,
1835                                     const Size&      _rPreviewWinSize )
1836 {
1837     // create & update preview data object
1838     if( mpPreview == nullptr )
1839         mpPreview.reset( new SwAccPreviewData() );
1840     mpPreview->Update( *this, _rPreviewPages, _rScale, _pSelectedPageFrame, _rPreviewWinSize );
1841 
1842     uno::Reference<XAccessible> xAcc = GetDocumentView_( true );
1843     return xAcc;
1844 }
1845 
GetContext(const SwFrame * pFrame,bool bCreate)1846 uno::Reference< XAccessible> SwAccessibleMap::GetContext( const SwFrame *pFrame,
1847                                                      bool bCreate )
1848 {
1849     DBG_TESTSOLARMUTEX();
1850     uno::Reference < XAccessible > xAcc;
1851     uno::Reference < XAccessible > xOldCursorAcc;
1852     bool bOldShapeSelected = false;
1853 
1854     {
1855         osl::MutexGuard aGuard( maMutex );
1856 
1857         if( !mpFrameMap && bCreate )
1858             mpFrameMap.reset(new SwAccessibleContextMap_Impl);
1859         if( mpFrameMap )
1860         {
1861             SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pFrame );
1862             if( aIter != mpFrameMap->end() )
1863                 xAcc = (*aIter).second;
1864 
1865             if( !xAcc.is() && bCreate )
1866             {
1867                 SwAccessibleContext *pAcc = nullptr;
1868                 switch( pFrame->GetType() )
1869                 {
1870                 case SwFrameType::Txt:
1871                     pAcc = new SwAccessibleParagraph(shared_from_this(),
1872                                     static_cast< const SwTextFrame& >( *pFrame ) );
1873                     break;
1874                 case SwFrameType::Header:
1875                     pAcc = new SwAccessibleHeaderFooter(shared_from_this(),
1876                                     static_cast< const SwHeaderFrame *>( pFrame ) );
1877                     break;
1878                 case SwFrameType::Footer:
1879                     pAcc = new SwAccessibleHeaderFooter(shared_from_this(),
1880                                     static_cast< const SwFooterFrame *>( pFrame ) );
1881                     break;
1882                 case SwFrameType::Ftn:
1883                     {
1884                         const SwFootnoteFrame *pFootnoteFrame =
1885                             static_cast < const SwFootnoteFrame * >( pFrame );
1886                         bool bIsEndnote =
1887                             SwAccessibleFootnote::IsEndnote( pFootnoteFrame );
1888                         pAcc = new SwAccessibleFootnote(shared_from_this(), bIsEndnote,
1889                                     /*(bIsEndnote ? mnEndnote++ : mnFootnote++),*/
1890                                     pFootnoteFrame );
1891                     }
1892                     break;
1893                 case SwFrameType::Fly:
1894                     {
1895                         const SwFlyFrame *pFlyFrame =
1896                             static_cast < const SwFlyFrame * >( pFrame );
1897                         switch( SwAccessibleFrameBase::GetNodeType( pFlyFrame ) )
1898                         {
1899                         case SwNodeType::Grf:
1900                             pAcc = new SwAccessibleGraphic(shared_from_this(), pFlyFrame );
1901                             break;
1902                         case SwNodeType::Ole:
1903                             pAcc = new SwAccessibleEmbeddedObject(shared_from_this(), pFlyFrame );
1904                             break;
1905                         default:
1906                             pAcc = new SwAccessibleTextFrame(shared_from_this(), *pFlyFrame );
1907                             break;
1908                         }
1909                     }
1910                     break;
1911                 case SwFrameType::Cell:
1912                     pAcc = new SwAccessibleCell(shared_from_this(),
1913                                     static_cast< const SwCellFrame *>( pFrame ) );
1914                     break;
1915                 case SwFrameType::Tab:
1916                     pAcc = new SwAccessibleTable(shared_from_this(),
1917                                     static_cast< const SwTabFrame *>( pFrame ) );
1918                     break;
1919                 case SwFrameType::Page:
1920                     OSL_ENSURE( GetShell()->IsPreview(),
1921                                 "accessible page frames only in PagePreview" );
1922                     pAcc = new SwAccessiblePage(shared_from_this(), pFrame);
1923                     break;
1924                 default: break;
1925                 }
1926                 xAcc = pAcc;
1927                 assert(xAcc.is());
1928 
1929                 if( aIter != mpFrameMap->end() )
1930                 {
1931                     (*aIter).second = xAcc;
1932                 }
1933                 else
1934                 {
1935                     mpFrameMap->emplace( pFrame, xAcc );
1936                 }
1937 
1938                 if( pAcc->HasCursor() &&
1939                     !AreInSameTable( mxCursorContext, pFrame ) )
1940                 {
1941                     // If the new context has the focus, and if we know
1942                     // another context that had the focus, then the focus
1943                     // just moves from the old context to the new one. We
1944                     // then have to send a focus event and a caret event for
1945                     // the old context. We have to do that now,
1946                     // because after we have left this method, anyone might
1947                     // call getStates for the new context and will get a
1948                     // focused state then. Sending the focus changes event
1949                     // after that seems to be strange. However, we cannot
1950                     // send a focus event for the new context now, because
1951                     // no one except us knows it. In any case, we remember
1952                     // the new context as the one that has the focus
1953                     // currently.
1954 
1955                     xOldCursorAcc = mxCursorContext;
1956                     mxCursorContext = xAcc;
1957 
1958                     bOldShapeSelected = mbShapeSelected;
1959                     mbShapeSelected = false;
1960                 }
1961             }
1962         }
1963     }
1964 
1965     // Invalidate focus for old object when map is not locked
1966     if( xOldCursorAcc.is() )
1967         InvalidateCursorPosition( xOldCursorAcc );
1968     if( bOldShapeSelected )
1969         InvalidateShapeSelection();
1970 
1971     return xAcc;
1972 }
1973 
GetContextImpl(const SwFrame * pFrame,bool bCreate)1974 ::rtl::Reference < SwAccessibleContext > SwAccessibleMap::GetContextImpl(
1975             const SwFrame *pFrame,
1976             bool bCreate )
1977 {
1978     uno::Reference < XAccessible > xAcc( GetContext( pFrame, bCreate ) );
1979 
1980     ::rtl::Reference < SwAccessibleContext > xAccImpl(
1981          static_cast< SwAccessibleContext * >( xAcc.get() ) );
1982 
1983     return xAccImpl;
1984 }
1985 
GetContext(const SdrObject * pObj,SwAccessibleContext * pParentImpl,bool bCreate)1986 uno::Reference< XAccessible> SwAccessibleMap::GetContext(
1987         const SdrObject *pObj,
1988         SwAccessibleContext *pParentImpl,
1989         bool bCreate )
1990 {
1991     uno::Reference < XAccessible > xAcc;
1992     uno::Reference < XAccessible > xOldCursorAcc;
1993 
1994     {
1995         osl::MutexGuard aGuard( maMutex );
1996 
1997         if( !mpShapeMap && bCreate )
1998             mpShapeMap.reset(new SwAccessibleShapeMap_Impl( this ));
1999         if( mpShapeMap )
2000         {
2001             SwAccessibleShapeMap_Impl::iterator aIter = mpShapeMap->find( pObj );
2002             if( aIter != mpShapeMap->end() )
2003                 xAcc = (*aIter).second;
2004 
2005             if( !xAcc.is() && bCreate )
2006             {
2007                 rtl::Reference< ::accessibility::AccessibleShape> pAcc;
2008                 uno::Reference < drawing::XShape > xShape(
2009                     const_cast< SdrObject * >( pObj )->getUnoShape(),
2010                     uno::UNO_QUERY );
2011                 if( xShape.is() )
2012                 {
2013                     ::accessibility::ShapeTypeHandler& rShapeTypeHandler =
2014                                 ::accessibility::ShapeTypeHandler::Instance();
2015                     uno::Reference < XAccessible > xParent( pParentImpl );
2016                     ::accessibility::AccessibleShapeInfo aShapeInfo(
2017                             xShape, xParent, this );
2018 
2019                     pAcc = rShapeTypeHandler.CreateAccessibleObject(
2020                                 aShapeInfo, mpShapeMap->GetInfo() );
2021                 }
2022                 xAcc = pAcc.get();
2023                 assert(xAcc.is());
2024                 pAcc->Init();
2025                 if( aIter != mpShapeMap->end() )
2026                 {
2027                     (*aIter).second = xAcc;
2028                 }
2029                 else
2030                 {
2031                     mpShapeMap->emplace( pObj, xAcc );
2032                 }
2033                 // TODO: focus!!!
2034                 AddGroupContext(pObj, xAcc);
2035             }
2036         }
2037     }
2038 
2039     // Invalidate focus for old object when map is not locked
2040     if( xOldCursorAcc.is() )
2041         InvalidateCursorPosition( xOldCursorAcc );
2042 
2043     return xAcc;
2044 }
2045 
IsInSameLevel(const SdrObject * pObj,const SwFEShell * pFESh)2046 bool SwAccessibleMap::IsInSameLevel(const SdrObject* pObj, const SwFEShell* pFESh)
2047 {
2048     if (pFESh)
2049         return pFESh->IsObjSameLevelWithMarked(pObj);
2050     return false;
2051 }
2052 
AddShapeContext(const SdrObject * pObj,uno::Reference<XAccessible> const & xAccShape)2053 void SwAccessibleMap::AddShapeContext(const SdrObject *pObj, uno::Reference < XAccessible > const & xAccShape)
2054 {
2055     osl::MutexGuard aGuard( maMutex );
2056 
2057     if( mpShapeMap )
2058     {
2059         mpShapeMap->emplace( pObj, xAccShape );
2060     }
2061 
2062 }
2063 
2064 //Added by yanjun for sym2_6407
RemoveGroupContext(const SdrObject * pParentObj)2065 void SwAccessibleMap::RemoveGroupContext(const SdrObject *pParentObj)
2066 {
2067     osl::MutexGuard aGuard( maMutex );
2068     // TODO: Why are sub-shapes of group shapes even added to our map?
2069     //       Doesn't the AccessibleShape of the top-level shape create them
2070     //       on demand anyway? Why does SwAccessibleMap need to know them?
2071     // We cannot rely on getAccessibleChild here to remove the sub-shapes
2072     // from mpShapes because the top-level shape may not only be disposed here
2073     // but also by visibility checks in svx, then it doesn't return children.
2074     if (mpShapeMap && pParentObj && pParentObj->IsGroupObject())
2075     {
2076         SdrObjList *const pChildren(pParentObj->GetSubList());
2077         for (size_t i = 0; pChildren && i < pChildren->GetObjCount(); ++i)
2078         {
2079             SdrObject *const pChild(pChildren->GetObj(i));
2080             assert(pChild);
2081             RemoveContext(pChild);
2082         }
2083     }
2084 }
2085 //End
2086 
AddGroupContext(const SdrObject * pParentObj,uno::Reference<XAccessible> const & xAccParent)2087 void SwAccessibleMap::AddGroupContext(const SdrObject *pParentObj, uno::Reference < XAccessible > const & xAccParent)
2088 {
2089     osl::MutexGuard aGuard( maMutex );
2090     if( mpShapeMap )
2091     {
2092         //here get all the sub list.
2093         if (pParentObj->IsGroupObject())
2094         {
2095             if (xAccParent.is())
2096             {
2097                 uno::Reference < XAccessibleContext > xContext = xAccParent->getAccessibleContext();
2098                 if (xContext.is())
2099                 {
2100                     sal_Int32 nChildren = xContext->getAccessibleChildCount();
2101                     for(sal_Int32 i = 0; i<nChildren; i++)
2102                     {
2103                         uno::Reference < XAccessible > xChild = xContext->getAccessibleChild(i);
2104                         if (xChild.is())
2105                         {
2106                             uno::Reference < XAccessibleContext > xChildContext = xChild->getAccessibleContext();
2107                             if (xChildContext.is())
2108                             {
2109                                 short nRole = xChildContext->getAccessibleRole();
2110                                 if (nRole == AccessibleRole::SHAPE)
2111                                 {
2112                                     ::accessibility::AccessibleShape* pAccShape = static_cast < ::accessibility::AccessibleShape* >( xChild.get());
2113                                     uno::Reference < drawing::XShape > xShape = pAccShape->GetXShape();
2114                                     if (xShape.is())
2115                                     {
2116                                         SdrObject* pObj = GetSdrObjectFromXShape(xShape);
2117                                         AddShapeContext(pObj, xChild);
2118                                         AddGroupContext(pObj,xChild);
2119                                     }
2120                                 }
2121                             }
2122                         }
2123                     }
2124                 }
2125             }
2126         }
2127     }
2128 }
2129 
GetContextImpl(const SdrObject * pObj,SwAccessibleContext * pParentImpl,bool bCreate)2130 ::rtl::Reference < ::accessibility::AccessibleShape > SwAccessibleMap::GetContextImpl(
2131             const SdrObject *pObj,
2132             SwAccessibleContext *pParentImpl,
2133             bool bCreate )
2134 {
2135     uno::Reference < XAccessible > xAcc( GetContext( pObj, pParentImpl, bCreate ) );
2136 
2137     ::rtl::Reference < ::accessibility::AccessibleShape > xAccImpl(
2138          static_cast< ::accessibility::AccessibleShape* >( xAcc.get() ) );
2139 
2140     return xAccImpl;
2141 }
2142 
RemoveContext(const SwFrame * pFrame)2143 void SwAccessibleMap::RemoveContext( const SwFrame *pFrame )
2144 {
2145     osl::MutexGuard aGuard( maMutex );
2146 
2147     if( mpFrameMap )
2148     {
2149         SwAccessibleContextMap_Impl::iterator aIter =
2150             mpFrameMap->find( pFrame );
2151         if( aIter != mpFrameMap->end() )
2152         {
2153             mpFrameMap->erase( aIter );
2154 
2155             // Remove reference to old caret object. Though mxCursorContext
2156             // is a weak reference and cleared automatically, clearing it
2157             // directly makes sure to not keep a non-functional object.
2158             uno::Reference < XAccessible > xOldAcc( mxCursorContext );
2159             if( xOldAcc.is() )
2160             {
2161                 SwAccessibleContext *pOldAccImpl =
2162                     static_cast< SwAccessibleContext *>( xOldAcc.get() );
2163                 OSL_ENSURE( pOldAccImpl->GetFrame(), "old caret context is disposed" );
2164                 if( pOldAccImpl->GetFrame() == pFrame )
2165                 {
2166                     xOldAcc.clear();    // get an empty ref
2167                     mxCursorContext = xOldAcc;
2168                 }
2169             }
2170 
2171             if( mpFrameMap->empty() )
2172             {
2173                 mpFrameMap.reset();
2174             }
2175         }
2176     }
2177 }
2178 
RemoveContext(const SdrObject * pObj)2179 void SwAccessibleMap::RemoveContext( const SdrObject *pObj )
2180 {
2181     osl::MutexGuard aGuard( maMutex );
2182 
2183     if( mpShapeMap )
2184     {
2185         SwAccessibleShapeMap_Impl::iterator aIter = mpShapeMap->find( pObj );
2186         if( aIter != mpShapeMap->end() )
2187         {
2188             uno::Reference < XAccessible > xAcc( (*aIter).second );
2189             mpShapeMap->erase( aIter );
2190             RemoveGroupContext(pObj);
2191             // The shape selection flag is not cleared, but one might do
2192             // so but has to make sure that the removed context is the one
2193             // that is selected.
2194 
2195             if( mpShapeMap && mpShapeMap->empty() )
2196             {
2197                 mpShapeMap.reset();
2198             }
2199         }
2200     }
2201 }
2202 
Contains(const SwFrame * pFrame) const2203 bool SwAccessibleMap::Contains(const SwFrame *pFrame) const
2204 {
2205     return (pFrame && mpFrameMap && mpFrameMap->find(pFrame) != mpFrameMap->end());
2206 }
2207 
A11yDispose(const SwFrame * pFrame,const SdrObject * pObj,vcl::Window * pWindow,bool bRecursive,bool bCanSkipInvisible)2208 void SwAccessibleMap::A11yDispose( const SwFrame *pFrame,
2209                                    const SdrObject *pObj,
2210                                    vcl::Window* pWindow,
2211                                    bool bRecursive,
2212                                    bool bCanSkipInvisible )
2213 {
2214     SwAccessibleChild aFrameOrObj( pFrame, pObj, pWindow );
2215 
2216     // Indeed, the following assert checks the frame's accessible flag,
2217     // because that's the one that is evaluated in the layout. The frame
2218     // might not be accessible anyway. That's the case for cell frames that
2219     // contain further cells.
2220     OSL_ENSURE( !aFrameOrObj.GetSwFrame() || aFrameOrObj.GetSwFrame()->IsAccessibleFrame(),
2221             "non accessible frame should be disposed" );
2222 
2223     if (aFrameOrObj.IsAccessible(GetShell()->IsPreview())
2224                // fdo#87199 dispose the darn thing if it ever was accessible
2225             || Contains(pFrame))
2226     {
2227         ::rtl::Reference< SwAccessibleContext > xAccImpl;
2228         ::rtl::Reference< SwAccessibleContext > xParentAccImpl;
2229         ::rtl::Reference< ::accessibility::AccessibleShape > xShapeAccImpl;
2230         // get accessible context for frame
2231         {
2232             osl::MutexGuard aGuard( maMutex );
2233 
2234             // First of all look for an accessible context for a frame
2235             if( aFrameOrObj.GetSwFrame() && mpFrameMap )
2236             {
2237                 SwAccessibleContextMap_Impl::iterator aIter =
2238                     mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2239                 if( aIter != mpFrameMap->end() )
2240                 {
2241                     uno::Reference < XAccessible > xAcc( (*aIter).second );
2242                     xAccImpl = static_cast< SwAccessibleContext *>( xAcc.get() );
2243                 }
2244             }
2245             if( !xAccImpl.is() && mpFrameMap )
2246             {
2247                 // If there is none, look if the parent is accessible.
2248                 const SwFrame *pParent =
2249                         SwAccessibleFrame::GetParent( aFrameOrObj,
2250                                                       GetShell()->IsPreview());
2251 
2252                 if( pParent )
2253                 {
2254                     SwAccessibleContextMap_Impl::iterator aIter =
2255                         mpFrameMap->find( pParent );
2256                     if( aIter != mpFrameMap->end() )
2257                     {
2258                         uno::Reference < XAccessible > xAcc( (*aIter).second );
2259                         xParentAccImpl =
2260                             static_cast< SwAccessibleContext *>( xAcc.get() );
2261                     }
2262                 }
2263             }
2264             if( !xParentAccImpl.is() && !aFrameOrObj.GetSwFrame() && mpShapeMap )
2265             {
2266                 SwAccessibleShapeMap_Impl::iterator aIter =
2267                     mpShapeMap->find( aFrameOrObj.GetDrawObject() );
2268                 if( aIter != mpShapeMap->end() )
2269                 {
2270                     uno::Reference < XAccessible > xAcc( (*aIter).second );
2271                     xShapeAccImpl =
2272                         static_cast< ::accessibility::AccessibleShape *>( xAcc.get() );
2273                 }
2274             }
2275             if( pObj && GetShell()->ActionPend() &&
2276                 (xParentAccImpl.is() || xShapeAccImpl.is()) )
2277             {
2278                 // Keep a reference to the XShape to avoid that it
2279                 // is deleted with a SwFrameFormat::Modify.
2280                 uno::Reference < drawing::XShape > xShape(
2281                     const_cast< SdrObject * >( pObj )->getUnoShape(),
2282                     uno::UNO_QUERY );
2283                 if( xShape.is() )
2284                 {
2285                     mvShapes.push_back( xShape );
2286                 }
2287             }
2288         }
2289 
2290         // remove events stored for the frame
2291         {
2292             osl::MutexGuard aGuard( maEventMutex );
2293             if( mpEvents )
2294             {
2295                 SwAccessibleEventMap_Impl::iterator aIter =
2296                     mpEventMap->find( aFrameOrObj );
2297                 if( aIter != mpEventMap->end() )
2298                 {
2299                     SwAccessibleEvent_Impl aEvent(
2300                             SwAccessibleEvent_Impl::DISPOSE, aFrameOrObj );
2301                     AppendEvent( aEvent );
2302                 }
2303             }
2304         }
2305 
2306         // If the frame is accessible and there is a context for it, dispose
2307         // the frame. If the frame is no context for it but disposing should
2308         // take place recursive, the frame's children have to be disposed
2309         // anyway, so we have to create the context then.
2310         if( xAccImpl.is() )
2311         {
2312             xAccImpl->Dispose( bRecursive );
2313         }
2314         else if( xParentAccImpl.is() )
2315         {
2316             // If the frame is a cell frame, the table must be notified.
2317             // If we are in an action, a table model change event will
2318             // be broadcasted at the end of the action to give the table
2319             // a chance to generate a single table change event.
2320 
2321             xParentAccImpl->DisposeChild( aFrameOrObj, bRecursive, bCanSkipInvisible );
2322         }
2323         else if( xShapeAccImpl.is() )
2324         {
2325             RemoveContext( aFrameOrObj.GetDrawObject() );
2326             xShapeAccImpl->dispose();
2327         }
2328 
2329         if( mpPreview && pFrame && pFrame->IsPageFrame() )
2330             mpPreview->DisposePage( static_cast< const SwPageFrame *>( pFrame ) );
2331     }
2332 }
2333 
InvalidatePosOrSize(const SwFrame * pFrame,const SdrObject * pObj,vcl::Window * pWindow,const SwRect & rOldBox)2334 void SwAccessibleMap::InvalidatePosOrSize( const SwFrame *pFrame,
2335                                            const SdrObject *pObj,
2336                                            vcl::Window* pWindow,
2337                                            const SwRect& rOldBox )
2338 {
2339     SwAccessibleChild aFrameOrObj( pFrame, pObj, pWindow );
2340     if( aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2341     {
2342         ::rtl::Reference< SwAccessibleContext > xAccImpl;
2343         ::rtl::Reference< SwAccessibleContext > xParentAccImpl;
2344         const SwFrame *pParent =nullptr;
2345         {
2346             osl::MutexGuard aGuard( maMutex );
2347 
2348             if( mpFrameMap )
2349             {
2350                 if( aFrameOrObj.GetSwFrame() )
2351                 {
2352                     SwAccessibleContextMap_Impl::iterator aIter =
2353                         mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2354                     if( aIter != mpFrameMap->end() )
2355                     {
2356                         // If there is an accessible object already it is
2357                         // notified directly.
2358                         uno::Reference < XAccessible > xAcc( (*aIter).second );
2359                         xAccImpl =
2360                             static_cast< SwAccessibleContext *>( xAcc.get() );
2361                     }
2362                 }
2363                 if( !xAccImpl.is() )
2364                 {
2365                     // Otherwise we look if the parent is accessible.
2366                     // If not, there is nothing to do.
2367                     pParent =
2368                         SwAccessibleFrame::GetParent( aFrameOrObj,
2369                                                       GetShell()->IsPreview());
2370 
2371                     if( pParent )
2372                     {
2373                         SwAccessibleContextMap_Impl::iterator aIter =
2374                             mpFrameMap->find( pParent );
2375                         if( aIter != mpFrameMap->end() )
2376                         {
2377                             uno::Reference < XAccessible > xAcc( (*aIter).second );
2378                             xParentAccImpl =
2379                                 static_cast< SwAccessibleContext *>( xAcc.get() );
2380                         }
2381                     }
2382                 }
2383             }
2384         }
2385 
2386         if( xAccImpl.is() )
2387         {
2388             if( GetShell()->ActionPend() )
2389             {
2390                 SwAccessibleEvent_Impl aEvent(
2391                     SwAccessibleEvent_Impl::POS_CHANGED, xAccImpl.get(),
2392                     aFrameOrObj, rOldBox );
2393                 AppendEvent( aEvent );
2394             }
2395             else
2396             {
2397                 FireEvents();
2398                 if (xAccImpl->GetFrame()) // not if disposed by FireEvents()
2399                 {
2400                     xAccImpl->InvalidatePosOrSize(rOldBox);
2401                 }
2402             }
2403         }
2404         else if( xParentAccImpl.is() )
2405         {
2406             if( GetShell()->ActionPend() )
2407             {
2408                 assert(pParent);
2409                 // tdf#99722 faster not to buffer events that won't be sent
2410                 if (!SwAccessibleChild(pParent).IsVisibleChildrenOnly()
2411                     || xParentAccImpl->IsShowing(rOldBox)
2412                     || xParentAccImpl->IsShowing(*this, aFrameOrObj))
2413                 {
2414                     SwAccessibleEvent_Impl aEvent(
2415                         SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
2416                         xParentAccImpl.get(), aFrameOrObj, rOldBox );
2417                     AppendEvent( aEvent );
2418                 }
2419             }
2420             else
2421             {
2422                 FireEvents();
2423                 xParentAccImpl->InvalidateChildPosOrSize( aFrameOrObj,
2424                                                           rOldBox );
2425             }
2426         }
2427         else if(pParent)
2428         {
2429 /*
2430 For child graphic and its parent paragraph,if split 2 graphic to 2 paragraph,
2431 will delete one graphic swfrm and new create 1 graphic swfrm ,
2432 then the new paragraph and the new graphic SwFrame will add .
2433 but when add graphic SwFrame ,the accessible of the new Paragraph is not created yet.
2434 so the new graphic accessible 'parent is NULL,
2435 so run here: save the parent's SwFrame not the accessible object parent,
2436 */
2437             bool bIsValidFrame = false;
2438             bool bIsTextParent = false;
2439             if (aFrameOrObj.GetSwFrame())
2440             {
2441                 if (SwFrameType::Fly == pFrame->GetType())
2442                 {
2443                     bIsValidFrame =true;
2444                 }
2445             }
2446             else if(pObj)
2447             {
2448                 if (SwFrameType::Txt == pParent->GetType())
2449                 {
2450                     bIsTextParent =true;
2451                 }
2452             }
2453             if( bIsValidFrame || bIsTextParent )
2454             {
2455                 if( GetShell()->ActionPend() )
2456                 {
2457                     SwAccessibleEvent_Impl aEvent(
2458                         SwAccessibleEvent_Impl::CHILD_POS_CHANGED,
2459                         pParent, aFrameOrObj, rOldBox );
2460                     AppendEvent( aEvent );
2461                 }
2462                 else
2463                 {
2464                     OSL_ENSURE(false,"");
2465                 }
2466             }
2467         }
2468     }
2469 }
2470 
InvalidateContent(const SwFrame * pFrame)2471 void SwAccessibleMap::InvalidateContent( const SwFrame *pFrame )
2472 {
2473     SwAccessibleChild aFrameOrObj( pFrame );
2474     if( aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2475     {
2476         uno::Reference < XAccessible > xAcc;
2477         {
2478             osl::MutexGuard aGuard( maMutex );
2479 
2480             if( mpFrameMap )
2481             {
2482                 SwAccessibleContextMap_Impl::iterator aIter =
2483                     mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2484                 if( aIter != mpFrameMap->end() )
2485                     xAcc = (*aIter).second;
2486             }
2487         }
2488 
2489         if( xAcc.is() )
2490         {
2491             SwAccessibleContext *pAccImpl =
2492                 static_cast< SwAccessibleContext *>( xAcc.get() );
2493             if( GetShell()->ActionPend() )
2494             {
2495                 SwAccessibleEvent_Impl aEvent(
2496                     SwAccessibleEvent_Impl::INVALID_CONTENT, pAccImpl,
2497                     aFrameOrObj );
2498                 AppendEvent( aEvent );
2499             }
2500             else
2501             {
2502                 FireEvents();
2503                 pAccImpl->InvalidateContent();
2504             }
2505         }
2506     }
2507 }
2508 
InvalidateAttr(const SwTextFrame & rTextFrame)2509 void SwAccessibleMap::InvalidateAttr( const SwTextFrame& rTextFrame )
2510 {
2511     SwAccessibleChild aFrameOrObj( &rTextFrame );
2512     if( aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2513     {
2514         uno::Reference < XAccessible > xAcc;
2515         {
2516             osl::MutexGuard aGuard( maMutex );
2517 
2518             if( mpFrameMap )
2519             {
2520                 SwAccessibleContextMap_Impl::iterator aIter =
2521                     mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2522                 if( aIter != mpFrameMap->end() )
2523                     xAcc = (*aIter).second;
2524             }
2525         }
2526 
2527         if( xAcc.is() )
2528         {
2529             SwAccessibleContext *pAccImpl =
2530                 static_cast< SwAccessibleContext *>( xAcc.get() );
2531             if( GetShell()->ActionPend() )
2532             {
2533                 SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::INVALID_ATTR,
2534                                                pAccImpl, aFrameOrObj );
2535                 aEvent.SetStates( AccessibleStates::TEXT_ATTRIBUTE_CHANGED );
2536                 AppendEvent( aEvent );
2537             }
2538             else
2539             {
2540                 FireEvents();
2541                 pAccImpl->InvalidateAttr();
2542             }
2543         }
2544     }
2545 }
2546 
InvalidateCursorPosition(const SwFrame * pFrame)2547 void SwAccessibleMap::InvalidateCursorPosition( const SwFrame *pFrame )
2548 {
2549     SwAccessibleChild aFrameOrObj( pFrame );
2550     bool bShapeSelected = false;
2551     const SwViewShell *pVSh = GetShell();
2552     if( auto pCSh = dynamic_cast<const SwCursorShell*>(pVSh) )
2553     {
2554         if( pCSh->IsTableMode() )
2555         {
2556             while( aFrameOrObj.GetSwFrame() && !aFrameOrObj.GetSwFrame()->IsCellFrame() )
2557                 aFrameOrObj = aFrameOrObj.GetSwFrame()->GetUpper();
2558         }
2559         else if( auto pFESh = dynamic_cast<const SwFEShell*>(pVSh) )
2560         {
2561             const SwFrame *pFlyFrame = pFESh->GetSelectedFlyFrame();
2562             if( pFlyFrame )
2563             {
2564                 OSL_ENSURE( !pFrame || pFrame->FindFlyFrame() == pFlyFrame,
2565                         "cursor is not contained in fly frame" );
2566                 aFrameOrObj = pFlyFrame;
2567             }
2568             else if( pFESh->IsObjSelected() > 0 )
2569             {
2570                 bShapeSelected = true;
2571                 aFrameOrObj = static_cast<const SwFrame *>( nullptr );
2572             }
2573         }
2574     }
2575 
2576     OSL_ENSURE( bShapeSelected || aFrameOrObj.IsAccessible(GetShell()->IsPreview()),
2577             "frame is not accessible" );
2578 
2579     uno::Reference < XAccessible > xOldAcc;
2580     uno::Reference < XAccessible > xAcc;
2581     bool bOldShapeSelected = false;
2582 
2583     {
2584         osl::MutexGuard aGuard( maMutex );
2585 
2586         xOldAcc = mxCursorContext;
2587         mxCursorContext = xAcc; // clear reference
2588 
2589         bOldShapeSelected = mbShapeSelected;
2590         mbShapeSelected = bShapeSelected;
2591 
2592         if( aFrameOrObj.GetSwFrame() && mpFrameMap )
2593         {
2594             SwAccessibleContextMap_Impl::iterator aIter =
2595                 mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2596             if( aIter != mpFrameMap->end() )
2597                 xAcc = (*aIter).second;
2598             else
2599             {
2600                 SwRect rcEmpty;
2601                 const SwTabFrame* pTabFrame = aFrameOrObj.GetSwFrame()->FindTabFrame();
2602                 if (pTabFrame)
2603                 {
2604                     InvalidatePosOrSize(pTabFrame, nullptr, nullptr, rcEmpty);
2605                 }
2606                 else
2607                 {
2608                     InvalidatePosOrSize(aFrameOrObj.GetSwFrame(), nullptr, nullptr, rcEmpty);
2609                 }
2610 
2611                 aIter = mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2612                 if( aIter != mpFrameMap->end() )
2613                 {
2614                     xAcc = (*aIter).second;
2615                 }
2616             }
2617 
2618             // For cells, some extra thoughts are necessary,
2619             // because invalidating the cursor for one cell
2620             // invalidates the cursor for all cells of the same
2621             // table. For this reason, we don't want to
2622             // invalidate the cursor for the old cursor object
2623             // and the new one if they are within the same table,
2624             // because this would result in doing the work twice.
2625             // Moreover, we have to make sure to invalidate the
2626             // cursor even if the current cell has no accessible object.
2627             // If the old cursor objects exists and is in the same
2628             // table, it's the best choice, because using it avoids
2629             // an unnecessary cursor invalidation cycle when creating
2630             // a new object for the current cell.
2631             if( aFrameOrObj.GetSwFrame()->IsCellFrame() )
2632             {
2633                 if( xOldAcc.is() &&
2634                     AreInSameTable( xOldAcc, aFrameOrObj.GetSwFrame() ) )
2635                 {
2636                     if( xAcc.is() )
2637                         xOldAcc = xAcc; // avoid extra invalidation
2638                     else
2639                         xAcc = xOldAcc; // make sure at least one
2640                 }
2641                 if( !xAcc.is() )
2642                     xAcc = GetContext( aFrameOrObj.GetSwFrame() );
2643             }
2644         }
2645         else if (bShapeSelected)
2646         {
2647             const SwFEShell *pFESh = static_cast< const SwFEShell * >( pVSh );
2648             const SdrMarkList *pMarkList = pFESh->GetMarkList();
2649             if (pMarkList != nullptr && pMarkList->GetMarkCount() == 1)
2650             {
2651                 SdrObject *pObj = pMarkList->GetMark( 0 )->GetMarkedSdrObj();
2652                 ::rtl::Reference < ::accessibility::AccessibleShape > pAccShapeImpl = GetContextImpl(pObj,nullptr,false);
2653                 if (!pAccShapeImpl.is())
2654                 {
2655                     while (pObj && pObj->getParentSdrObjectFromSdrObject())
2656                     {
2657                         pObj = pObj->getParentSdrObjectFromSdrObject();
2658                     }
2659                     if (pObj != nullptr)
2660                     {
2661                         const SwFrame *pParent = SwAccessibleFrame::GetParent( SwAccessibleChild(pObj), GetShell()->IsPreview() );
2662                         if( pParent )
2663                         {
2664                             ::rtl::Reference< SwAccessibleContext > xParentAccImpl = GetContextImpl(pParent,false);
2665                             if (!xParentAccImpl.is())
2666                             {
2667                                 const SwTabFrame* pTabFrame = pParent->FindTabFrame();
2668                                 if (pTabFrame)
2669                                 {
2670                                     //The Table should not add in acc.because the "pParent" is not add to acc .
2671                                     uno::Reference< XAccessible>  xAccParentTab = GetContext(pTabFrame);//Should Create.
2672 
2673                                     const SwFrame *pParentRoot = SwAccessibleFrame::GetParent( SwAccessibleChild(pTabFrame), GetShell()->IsPreview() );
2674                                     if (pParentRoot)
2675                                     {
2676                                         ::rtl::Reference< SwAccessibleContext > xParentAccImplRoot = GetContextImpl(pParentRoot,false);
2677                                         if(xParentAccImplRoot.is())
2678                                         {
2679                                             AccessibleEventObject aEvent;
2680                                             aEvent.EventId = AccessibleEventId::CHILD;
2681                                             aEvent.NewValue <<= xAccParentTab;
2682                                             xParentAccImplRoot->FireAccessibleEvent( aEvent );
2683                                         }
2684                                     }
2685 
2686                                     //Get "pParent" acc again.
2687                                     xParentAccImpl = GetContextImpl(pParent,false);
2688                                 }
2689                                 else
2690                                 {
2691                                     //directly create this acc para .
2692                                     xParentAccImpl = GetContextImpl(pParent);//Should Create.
2693 
2694                                     const SwFrame *pParentRoot = SwAccessibleFrame::GetParent( SwAccessibleChild(pParent), GetShell()->IsPreview() );
2695 
2696                                     ::rtl::Reference< SwAccessibleContext > xParentAccImplRoot = GetContextImpl(pParentRoot,false);
2697                                     if(xParentAccImplRoot.is())
2698                                     {
2699                                         AccessibleEventObject aEvent;
2700                                         aEvent.EventId = AccessibleEventId::CHILD;
2701                                         aEvent.NewValue <<= uno::Reference< XAccessible>(xParentAccImpl.get());
2702                                         xParentAccImplRoot->FireAccessibleEvent( aEvent );
2703                                     }
2704                                 }
2705                             }
2706                             if (xParentAccImpl.is())
2707                             {
2708                                 uno::Reference< XAccessible>  xAccShape =
2709                                     GetContext(pObj,xParentAccImpl.get());
2710 
2711                                 AccessibleEventObject aEvent;
2712                                 aEvent.EventId = AccessibleEventId::CHILD;
2713                                 aEvent.NewValue <<= xAccShape;
2714                                 xParentAccImpl->FireAccessibleEvent( aEvent );
2715                             }
2716                         }
2717                     }
2718                 }
2719             }
2720         }
2721     }
2722 
2723     m_setParaAdd.clear();
2724     m_setParaRemove.clear();
2725     if( xOldAcc.is() && xOldAcc != xAcc )
2726         InvalidateCursorPosition( xOldAcc );
2727     if( bOldShapeSelected || bShapeSelected )
2728         InvalidateShapeSelection();
2729     if( xAcc.is() )
2730         InvalidateCursorPosition( xAcc );
2731 
2732     InvalidateShapeInParaSelection();
2733 
2734     for (SwAccessibleParagraph* pAccPara : m_setParaRemove)
2735     {
2736         if(pAccPara && pAccPara->getSelectedAccessibleChildCount() == 0 && pAccPara->getSelectedText().getLength() == 0)
2737         {
2738             if(pAccPara->SetSelectedState(false))
2739             {
2740                 AccessibleEventObject aEvent;
2741                 aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
2742                 pAccPara->FireAccessibleEvent( aEvent );
2743             }
2744         }
2745     }
2746     for (SwAccessibleParagraph* pAccPara : m_setParaAdd)
2747     {
2748         if(pAccPara && pAccPara->SetSelectedState(true))
2749         {
2750             AccessibleEventObject aEvent;
2751             aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
2752             pAccPara->FireAccessibleEvent( aEvent );
2753         }
2754     }
2755 }
2756 
InvalidateFocus()2757 void SwAccessibleMap::InvalidateFocus()
2758 {
2759     if(GetShell()->IsPreview())
2760     {
2761         uno::Reference<XAccessible> xAcc = GetDocumentView_( true );
2762         if (xAcc.get())
2763         {
2764             SwAccessiblePreview *pAccPreview = static_cast<SwAccessiblePreview *>(xAcc.get());
2765             if (pAccPreview)
2766             {
2767                 pAccPreview->InvalidateFocus();
2768                 return ;
2769             }
2770         }
2771     }
2772     uno::Reference < XAccessible > xAcc;
2773     {
2774         osl::MutexGuard aGuard( maMutex );
2775 
2776         xAcc = mxCursorContext;
2777     }
2778 
2779     if( xAcc.is() )
2780     {
2781         SwAccessibleContext *pAccImpl = static_cast< SwAccessibleContext *>( xAcc.get() );
2782         pAccImpl->InvalidateFocus();
2783     }
2784     else
2785     {
2786         DoInvalidateShapeSelection(true);
2787     }
2788 }
2789 
SetCursorContext(const::rtl::Reference<SwAccessibleContext> & rCursorContext)2790 void SwAccessibleMap::SetCursorContext(
2791         const ::rtl::Reference < SwAccessibleContext >& rCursorContext )
2792 {
2793     osl::MutexGuard aGuard( maMutex );
2794     uno::Reference < XAccessible > xAcc( rCursorContext.get() );
2795     mxCursorContext = xAcc;
2796 }
2797 
InvalidateEditableStates(const SwFrame * _pFrame)2798 void SwAccessibleMap::InvalidateEditableStates( const SwFrame* _pFrame )
2799 {
2800     // Start with the frame or the first upper that is accessible
2801     SwAccessibleChild aFrameOrObj( _pFrame );
2802     while( aFrameOrObj.GetSwFrame() &&
2803             !aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2804         aFrameOrObj = aFrameOrObj.GetSwFrame()->GetUpper();
2805     if( !aFrameOrObj.GetSwFrame() )
2806         aFrameOrObj = GetShell()->GetLayout();
2807 
2808     uno::Reference< XAccessible > xAcc( GetContext( aFrameOrObj.GetSwFrame() ) );
2809     SwAccessibleContext *pAccImpl = static_cast< SwAccessibleContext *>( xAcc.get() );
2810     if( GetShell()->ActionPend() )
2811     {
2812         SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES,
2813                                        pAccImpl,
2814                                        SwAccessibleChild(pAccImpl->GetFrame()),
2815                                        AccessibleStates::EDITABLE );
2816         AppendEvent( aEvent );
2817     }
2818     else
2819     {
2820         FireEvents();
2821         pAccImpl->InvalidateStates( AccessibleStates::EDITABLE );
2822     }
2823 }
2824 
InvalidateRelationSet_(const SwFrame * pFrame,bool bFrom)2825 void SwAccessibleMap::InvalidateRelationSet_( const SwFrame* pFrame,
2826                                               bool bFrom )
2827 {
2828     // first, see if this frame is accessible, and if so, get the respective
2829     SwAccessibleChild aFrameOrObj( pFrame );
2830     if( aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2831     {
2832         uno::Reference < XAccessible > xAcc;
2833         {
2834             osl::MutexGuard aGuard( maMutex );
2835 
2836             if( mpFrameMap )
2837             {
2838                 SwAccessibleContextMap_Impl::iterator aIter =
2839                                         mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2840                 if( aIter != mpFrameMap->end() )
2841                 {
2842                     xAcc = (*aIter).second;
2843                 }
2844             }
2845         }
2846 
2847         // deliver event directly, or queue event
2848         if( xAcc.is() )
2849         {
2850             SwAccessibleContext *pAccImpl =
2851                             static_cast< SwAccessibleContext *>( xAcc.get() );
2852             if( GetShell()->ActionPend() )
2853             {
2854                 SwAccessibleEvent_Impl aEvent( SwAccessibleEvent_Impl::CARET_OR_STATES,
2855                                                pAccImpl, SwAccessibleChild(pFrame),
2856                                                ( bFrom
2857                                                  ? AccessibleStates::RELATION_FROM
2858                                                  : AccessibleStates::RELATION_TO ) );
2859                 AppendEvent( aEvent );
2860             }
2861             else
2862             {
2863                 FireEvents();
2864                 pAccImpl->InvalidateRelation( bFrom
2865                         ? AccessibleEventId::CONTENT_FLOWS_FROM_RELATION_CHANGED
2866                         : AccessibleEventId::CONTENT_FLOWS_TO_RELATION_CHANGED );
2867             }
2868         }
2869     }
2870 }
2871 
InvalidateRelationSet(const SwFrame * pMaster,const SwFrame * pFollow)2872 void SwAccessibleMap::InvalidateRelationSet( const SwFrame* pMaster,
2873                                              const SwFrame* pFollow )
2874 {
2875     InvalidateRelationSet_( pMaster, false );
2876     InvalidateRelationSet_( pFollow, true );
2877 }
2878 
2879 // invalidation of CONTENT_FLOW_FROM/_TO relation of a paragraph
InvalidateParaFlowRelation(const SwTextFrame & _rTextFrame,const bool _bFrom)2880 void SwAccessibleMap::InvalidateParaFlowRelation( const SwTextFrame& _rTextFrame,
2881                                                   const bool _bFrom )
2882 {
2883     InvalidateRelationSet_( &_rTextFrame, _bFrom );
2884 }
2885 
2886 // invalidation of text selection of a paragraph
InvalidateParaTextSelection(const SwTextFrame & _rTextFrame)2887 void SwAccessibleMap::InvalidateParaTextSelection( const SwTextFrame& _rTextFrame )
2888 {
2889     // first, see if this frame is accessible, and if so, get the respective
2890     SwAccessibleChild aFrameOrObj( &_rTextFrame );
2891     if( aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2892     {
2893         uno::Reference < XAccessible > xAcc;
2894         {
2895             osl::MutexGuard aGuard( maMutex );
2896 
2897             if( mpFrameMap )
2898             {
2899                 SwAccessibleContextMap_Impl::iterator aIter =
2900                                         mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2901                 if( aIter != mpFrameMap->end() )
2902                 {
2903                     xAcc = (*aIter).second;
2904                 }
2905             }
2906         }
2907 
2908         // deliver event directly, or queue event
2909         if( xAcc.is() )
2910         {
2911             SwAccessibleContext *pAccImpl =
2912                             static_cast< SwAccessibleContext *>( xAcc.get() );
2913             if( GetShell()->ActionPend() )
2914             {
2915                 SwAccessibleEvent_Impl aEvent(
2916                     SwAccessibleEvent_Impl::CARET_OR_STATES,
2917                     pAccImpl,
2918                     SwAccessibleChild( &_rTextFrame ),
2919                     AccessibleStates::TEXT_SELECTION_CHANGED );
2920                 AppendEvent( aEvent );
2921             }
2922             else
2923             {
2924                 FireEvents();
2925                 pAccImpl->InvalidateTextSelection();
2926             }
2927         }
2928     }
2929 }
2930 
GetChildIndex(const SwFrame & rParentFrame,vcl::Window & rChild) const2931 sal_Int32 SwAccessibleMap::GetChildIndex( const SwFrame& rParentFrame,
2932                                           vcl::Window& rChild ) const
2933 {
2934     sal_Int32 nIndex( -1 );
2935 
2936     SwAccessibleChild aFrameOrObj( &rParentFrame );
2937     if( aFrameOrObj.IsAccessible( GetShell()->IsPreview() ) )
2938     {
2939         uno::Reference < XAccessible > xAcc;
2940         {
2941             osl::MutexGuard aGuard( maMutex );
2942 
2943             if( mpFrameMap )
2944             {
2945                 SwAccessibleContextMap_Impl::iterator aIter =
2946                                         mpFrameMap->find( aFrameOrObj.GetSwFrame() );
2947                 if( aIter != mpFrameMap->end() )
2948                 {
2949                     xAcc = (*aIter).second;
2950                 }
2951             }
2952         }
2953 
2954         if( xAcc.is() )
2955         {
2956             SwAccessibleContext *pAccImpl =
2957                             static_cast< SwAccessibleContext *>( xAcc.get() );
2958 
2959             nIndex = pAccImpl->GetChildIndex( const_cast<SwAccessibleMap&>(*this),
2960                                               SwAccessibleChild( &rChild ) );
2961         }
2962     }
2963 
2964     return nIndex;
2965 }
2966 
UpdatePreview(const std::vector<std::unique_ptr<PreviewPage>> & _rPreviewPages,const Fraction & _rScale,const SwPageFrame * _pSelectedPageFrame,const Size & _rPreviewWinSize)2967 void SwAccessibleMap::UpdatePreview( const std::vector<std::unique_ptr<PreviewPage>>& _rPreviewPages,
2968                                      const Fraction&  _rScale,
2969                                      const SwPageFrame* _pSelectedPageFrame,
2970                                      const Size&      _rPreviewWinSize )
2971 {
2972     assert(GetShell()->IsPreview() && "no preview?");
2973     assert(mpPreview != nullptr && "no preview data?");
2974 
2975     mpPreview->Update( *this, _rPreviewPages, _rScale, _pSelectedPageFrame, _rPreviewWinSize );
2976 
2977     // propagate change of VisArea through the document's
2978     // accessibility tree; this will also send appropriate scroll
2979     // events
2980     SwAccessibleContext* pDoc =
2981         GetContextImpl( GetShell()->GetLayout() ).get();
2982     static_cast<SwAccessibleDocumentBase*>( pDoc )->SetVisArea();
2983 
2984     uno::Reference < XAccessible > xOldAcc;
2985     uno::Reference < XAccessible > xAcc;
2986     {
2987         osl::MutexGuard aGuard( maMutex );
2988 
2989         xOldAcc = mxCursorContext;
2990 
2991         const SwPageFrame *pSelPage = mpPreview->GetSelPage();
2992         if( pSelPage && mpFrameMap )
2993         {
2994             SwAccessibleContextMap_Impl::iterator aIter =
2995                 mpFrameMap->find( pSelPage );
2996             if( aIter != mpFrameMap->end() )
2997                 xAcc = (*aIter).second;
2998         }
2999     }
3000 
3001     if( xOldAcc.is() && xOldAcc != xAcc )
3002         InvalidateCursorPosition( xOldAcc );
3003     if( xAcc.is() )
3004         InvalidateCursorPosition( xAcc );
3005 }
3006 
InvalidatePreviewSelection(sal_uInt16 nSelPage)3007 void SwAccessibleMap::InvalidatePreviewSelection( sal_uInt16 nSelPage )
3008 {
3009     assert(GetShell()->IsPreview());
3010     assert(mpPreview != nullptr);
3011 
3012     mpPreview->InvalidateSelection( GetShell()->GetLayout()->GetPageByPageNum( nSelPage ) );
3013 
3014     uno::Reference < XAccessible > xOldAcc;
3015     uno::Reference < XAccessible > xAcc;
3016     {
3017         osl::MutexGuard aGuard( maMutex );
3018 
3019         xOldAcc = mxCursorContext;
3020 
3021         const SwPageFrame *pSelPage = mpPreview->GetSelPage();
3022         if( pSelPage && mpFrameMap )
3023         {
3024             SwAccessibleContextMap_Impl::iterator aIter = mpFrameMap->find( pSelPage );
3025             if( aIter != mpFrameMap->end() )
3026                 xAcc = (*aIter).second;
3027         }
3028     }
3029 
3030     if( xOldAcc.is() && xOldAcc != xAcc )
3031         InvalidateCursorPosition( xOldAcc );
3032     if( xAcc.is() )
3033         InvalidateCursorPosition( xAcc );
3034 }
3035 
IsPageSelected(const SwPageFrame * pPageFrame) const3036 bool SwAccessibleMap::IsPageSelected( const SwPageFrame *pPageFrame ) const
3037 {
3038     return mpPreview && mpPreview->GetSelPage() == pPageFrame;
3039 }
3040 
FireEvents()3041 void SwAccessibleMap::FireEvents()
3042 {
3043     {
3044         osl::MutexGuard aGuard( maEventMutex );
3045         if( mpEvents )
3046         {
3047             if (mpEvents->IsFiring())
3048             {
3049                 return; // prevent recursive FireEvents()
3050             }
3051 
3052             mpEvents->SetFiring();
3053             mpEvents->MoveMissingXAccToEnd();
3054             for( auto const& aEvent : *mpEvents )
3055                  FireEvent(aEvent);
3056 
3057             mpEventMap.reset();
3058             mpEvents.reset();
3059         }
3060     }
3061     {
3062         osl::MutexGuard aGuard( maMutex );
3063         mvShapes.clear();
3064     }
3065 
3066 }
3067 
GetVisibleArea() const3068 tools::Rectangle SwAccessibleMap::GetVisibleArea() const
3069 {
3070     MapMode aSrc( MapUnit::MapTwip );
3071     MapMode aDest( MapUnit::Map100thMM );
3072     return OutputDevice::LogicToLogic( GetVisArea().SVRect(), aSrc, aDest );
3073 }
3074 
3075 // Convert a MM100 value relative to the document root into a pixel value
3076 // relative to the screen!
LogicToPixel(const Point & rPoint) const3077 Point SwAccessibleMap::LogicToPixel( const Point& rPoint ) const
3078 {
3079     MapMode aSrc( MapUnit::Map100thMM );
3080     MapMode aDest( MapUnit::MapTwip );
3081 
3082     Point aPoint = OutputDevice::LogicToLogic( rPoint, aSrc, aDest );
3083     vcl::Window *pWin = GetShell()->GetWin();
3084     if( pWin )
3085     {
3086         MapMode aMapMode;
3087         GetMapMode( aPoint, aMapMode );
3088         aPoint = pWin->LogicToPixel( aPoint, aMapMode );
3089         aPoint = pWin->OutputToAbsoluteScreenPixel( aPoint );
3090     }
3091 
3092     return aPoint;
3093 }
3094 
LogicToPixel(const Size & rSize) const3095 Size SwAccessibleMap::LogicToPixel( const Size& rSize ) const
3096 {
3097     MapMode aSrc( MapUnit::Map100thMM );
3098     MapMode aDest( MapUnit::MapTwip );
3099     Size aSize( OutputDevice::LogicToLogic( rSize, aSrc, aDest ) );
3100     if( GetShell()->GetWin() )
3101     {
3102         MapMode aMapMode;
3103         GetMapMode( Point(0,0), aMapMode );
3104         aSize = GetShell()->GetWin()->LogicToPixel( aSize, aMapMode );
3105     }
3106 
3107     return aSize;
3108 }
3109 
ReplaceChild(::accessibility::AccessibleShape * pCurrentChild,const uno::Reference<drawing::XShape> & _rxShape,const long,const::accessibility::AccessibleShapeTreeInfo &)3110 bool SwAccessibleMap::ReplaceChild (
3111         ::accessibility::AccessibleShape* pCurrentChild,
3112         const uno::Reference< drawing::XShape >& _rxShape,
3113         const long /*_nIndex*/,
3114         const ::accessibility::AccessibleShapeTreeInfo& /*_rShapeTreeInfo*/
3115     )
3116 {
3117     const SdrObject *pObj = nullptr;
3118     {
3119         osl::MutexGuard aGuard( maMutex );
3120         if( mpShapeMap )
3121         {
3122             SwAccessibleShapeMap_Impl::const_iterator aIter = mpShapeMap->cbegin();
3123             SwAccessibleShapeMap_Impl::const_iterator aEndIter = mpShapeMap->cend();
3124             while( aIter != aEndIter && !pObj )
3125             {
3126                 uno::Reference < XAccessible > xAcc( (*aIter).second );
3127                 ::accessibility::AccessibleShape *pAccShape =
3128                     static_cast < ::accessibility::AccessibleShape* >( xAcc.get() );
3129                 if( pAccShape == pCurrentChild )
3130                 {
3131                     pObj = (*aIter).first;
3132                 }
3133                 ++aIter;
3134             }
3135         }
3136     }
3137     if( !pObj )
3138         return false;
3139 
3140     uno::Reference < drawing::XShape > xShape( _rxShape );  // keep reference to shape, because
3141                                                             // we might be the only one that
3142                                                             // holds it.
3143     // Also get keep parent.
3144     uno::Reference < XAccessible > xParent( pCurrentChild->getAccessibleParent() );
3145     pCurrentChild = nullptr;  // will be released by dispose
3146     A11yDispose( nullptr, pObj, nullptr );
3147 
3148     {
3149         osl::MutexGuard aGuard( maMutex );
3150 
3151         if( !mpShapeMap )
3152             mpShapeMap.reset(new SwAccessibleShapeMap_Impl( this ));
3153 
3154         // create the new child
3155         ::accessibility::ShapeTypeHandler& rShapeTypeHandler =
3156                         ::accessibility::ShapeTypeHandler::Instance();
3157         ::accessibility::AccessibleShapeInfo aShapeInfo(
3158                                             xShape, xParent, this );
3159         rtl::Reference< ::accessibility::AccessibleShape> pReplacement(
3160             rShapeTypeHandler.CreateAccessibleObject (
3161                 aShapeInfo, mpShapeMap->GetInfo() ));
3162 
3163         uno::Reference < XAccessible > xAcc( pReplacement.get() );
3164         if( xAcc.is() )
3165         {
3166             pReplacement->Init();
3167 
3168             SwAccessibleShapeMap_Impl::iterator aIter = mpShapeMap->find( pObj );
3169             if( aIter != mpShapeMap->end() )
3170             {
3171                 (*aIter).second = xAcc;
3172             }
3173             else
3174             {
3175                 mpShapeMap->emplace( pObj, xAcc );
3176             }
3177         }
3178     }
3179 
3180     SwRect aEmptyRect;
3181     InvalidatePosOrSize( nullptr, pObj, nullptr, aEmptyRect );
3182 
3183     return true;
3184 }
3185 
3186 //Get the accessible control shape from the model object, here model object is with XPropertySet type
GetAccControlShapeFromModel(css::beans::XPropertySet * pSet)3187 ::accessibility::AccessibleControlShape * SwAccessibleMap::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet)
3188 {
3189     if( mpShapeMap )
3190     {
3191         SwAccessibleShapeMap_Impl::const_iterator aIter = mpShapeMap->cbegin();
3192         SwAccessibleShapeMap_Impl::const_iterator aEndIter = mpShapeMap->cend();
3193         while( aIter != aEndIter)
3194         {
3195             uno::Reference < XAccessible > xAcc( (*aIter).second );
3196             ::accessibility::AccessibleShape *pAccShape =
3197                 static_cast < ::accessibility::AccessibleShape* >( xAcc.get() );
3198             if(pAccShape && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == ::accessibility::DRAWING_CONTROL)
3199             {
3200                 ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape);
3201                 if (pCtlAccShape->GetControlModel() == pSet)
3202                     return pCtlAccShape;
3203             }
3204             ++aIter;
3205         }
3206     }
3207     return nullptr;
3208 }
3209 
3210 css::uno::Reference< XAccessible >
GetAccessibleCaption(const css::uno::Reference<css::drawing::XShape> &)3211     SwAccessibleMap::GetAccessibleCaption (const css::uno::Reference< css::drawing::XShape >&)
3212 {
3213     return nullptr;
3214 }
3215 
PixelToCore(const Point & rPoint) const3216 Point SwAccessibleMap::PixelToCore( const Point& rPoint ) const
3217 {
3218     Point aPoint;
3219     if( GetShell()->GetWin() )
3220     {
3221         MapMode aMapMode;
3222         GetMapMode( rPoint, aMapMode );
3223         aPoint = GetShell()->GetWin()->PixelToLogic( rPoint, aMapMode );
3224     }
3225     return aPoint;
3226 }
3227 
lcl_CorrectCoarseValue(long aCoarseValue,long aFineValue,long aRefValue,bool bToLower)3228 static long lcl_CorrectCoarseValue(long aCoarseValue, long aFineValue,
3229                                           long aRefValue, bool bToLower)
3230 {
3231     long aResult = aCoarseValue;
3232 
3233     if (bToLower)
3234     {
3235         if (aFineValue < aRefValue)
3236             aResult -= 1;
3237     }
3238     else
3239     {
3240         if (aFineValue > aRefValue)
3241             aResult += 1;
3242     }
3243 
3244     return aResult;
3245 }
3246 
lcl_CorrectRectangle(tools::Rectangle & rRect,const tools::Rectangle & rSource,const tools::Rectangle & rInGrid)3247 static void lcl_CorrectRectangle(tools::Rectangle & rRect,
3248                                         const tools::Rectangle & rSource,
3249                                         const tools::Rectangle & rInGrid)
3250 {
3251     rRect.SetLeft( lcl_CorrectCoarseValue(rRect.Left(), rSource.Left(),
3252                                           rInGrid.Left(), false) );
3253     rRect.SetTop( lcl_CorrectCoarseValue(rRect.Top(), rSource.Top(),
3254                                          rInGrid.Top(), false) );
3255     rRect.SetRight( lcl_CorrectCoarseValue(rRect.Right(), rSource.Right(),
3256                                            rInGrid.Right(), true) );
3257     rRect.SetBottom( lcl_CorrectCoarseValue(rRect.Bottom(), rSource.Bottom(),
3258                                             rInGrid.Bottom(), true) );
3259 }
3260 
CoreToPixel(const tools::Rectangle & rRect) const3261 tools::Rectangle SwAccessibleMap::CoreToPixel( const tools::Rectangle& rRect ) const
3262 {
3263     tools::Rectangle aRect;
3264     if( GetShell()->GetWin() )
3265     {
3266         MapMode aMapMode;
3267         GetMapMode( rRect.TopLeft(), aMapMode );
3268         aRect = GetShell()->GetWin()->LogicToPixel( rRect, aMapMode );
3269 
3270         tools::Rectangle aTmpRect = GetShell()->GetWin()->PixelToLogic( aRect, aMapMode );
3271         lcl_CorrectRectangle(aRect, rRect, aTmpRect);
3272     }
3273 
3274     return aRect;
3275 }
3276 
3277 /** get mapping mode for LogicToPixel and PixelToLogic conversions
3278 
3279     Method returns mapping mode of current output device and adjusts it,
3280     if the shell is in page/print preview.
3281     Necessary, because <PreviewAdjust(..)> changes mapping mode at current
3282     output device for mapping logic document positions to page preview window
3283     positions and vice versa and doesn't take care to recover its changes.
3284 */
GetMapMode(const Point & _rPoint,MapMode & _orMapMode) const3285 void SwAccessibleMap::GetMapMode( const Point& _rPoint,
3286                                   MapMode&     _orMapMode ) const
3287 {
3288     MapMode aMapMode = GetShell()->GetWin()->GetMapMode();
3289     if( GetShell()->IsPreview() )
3290     {
3291         assert(mpPreview != nullptr);
3292         mpPreview->AdjustMapMode( aMapMode, _rPoint );
3293     }
3294     _orMapMode = aMapMode;
3295 }
3296 
GetPreviewPageSize(sal_uInt16 const nPreviewPageNum) const3297 Size SwAccessibleMap::GetPreviewPageSize(sal_uInt16 const nPreviewPageNum) const
3298 {
3299     assert(mpVSh->IsPreview());
3300     assert(mpPreview != nullptr);
3301     return mpVSh->PagePreviewLayout()->GetPreviewPageSizeByPageNum(nPreviewPageNum);
3302 }
3303 
3304 /** method to build up a new data structure of the accessible paragraphs,
3305     which have a selection
3306     Important note: method has to be used inside a mutual exclusive section
3307 */
BuildSelectedParas()3308 std::unique_ptr<SwAccessibleSelectedParas_Impl> SwAccessibleMap::BuildSelectedParas()
3309 {
3310     // no accessible contexts, no selection
3311     if ( !mpFrameMap )
3312     {
3313         return nullptr;
3314     }
3315 
3316     // get cursor as an instance of its base class <SwPaM>
3317     SwPaM* pCursor( nullptr );
3318     {
3319         SwCursorShell* pCursorShell = dynamic_cast<SwCursorShell*>(GetShell());
3320         if ( pCursorShell )
3321         {
3322             SwFEShell* pFEShell = dynamic_cast<SwFEShell*>(pCursorShell);
3323             if ( !pFEShell ||
3324                  ( !pFEShell->IsFrameSelected() &&
3325                    pFEShell->IsObjSelected() == 0 ) )
3326             {
3327                 // get cursor without updating an existing table cursor.
3328                 pCursor = pCursorShell->GetCursor( false );
3329             }
3330         }
3331     }
3332     // no cursor, no selection
3333     if ( !pCursor )
3334     {
3335         return nullptr;
3336     }
3337 
3338     std::unique_ptr<SwAccessibleSelectedParas_Impl> pRetSelectedParas;
3339 
3340     // loop on all cursors
3341     SwPaM* pRingStart = pCursor;
3342     do {
3343 
3344         // for a selection the cursor has to have a mark.
3345         // for safety reasons assure that point and mark are in text nodes
3346         if ( pCursor->HasMark() &&
3347              pCursor->GetPoint()->nNode.GetNode().IsTextNode() &&
3348              pCursor->GetMark()->nNode.GetNode().IsTextNode() )
3349         {
3350             SwPosition* pStartPos = pCursor->Start();
3351             SwPosition* pEndPos = pCursor->End();
3352             // loop on all text nodes inside the selection
3353             SwNodeIndex aIdx( pStartPos->nNode );
3354             for ( ; aIdx.GetIndex() <= pEndPos->nNode.GetIndex(); ++aIdx )
3355             {
3356                 SwTextNode* pTextNode( aIdx.GetNode().GetTextNode() );
3357                 if ( pTextNode )
3358                 {
3359                     // loop on all text frames registered at the text node.
3360                     SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pTextNode);
3361                     for( SwTextFrame* pTextFrame = aIter.First(); pTextFrame; pTextFrame = aIter.Next() )
3362                         {
3363                             uno::WeakReference < XAccessible > xWeakAcc;
3364                             SwAccessibleContextMap_Impl::iterator aMapIter =
3365                                                     mpFrameMap->find( pTextFrame );
3366                             if( aMapIter != mpFrameMap->end() )
3367                             {
3368                                 xWeakAcc = (*aMapIter).second;
3369                                 SwAccessibleParaSelection aDataEntry(
3370                                     sw::FrameContainsNode(*pTextFrame, pStartPos->nNode.GetIndex())
3371                                         ? pTextFrame->MapModelToViewPos(*pStartPos)
3372                                         : TextFrameIndex(0),
3373 
3374                                     sw::FrameContainsNode(*pTextFrame, pEndPos->nNode.GetIndex())
3375                                         ? pTextFrame->MapModelToViewPos(*pEndPos)
3376                                         : TextFrameIndex(COMPLETE_STRING));
3377                                 if ( !pRetSelectedParas )
3378                                 {
3379                                     pRetSelectedParas.reset(
3380                                             new SwAccessibleSelectedParas_Impl);
3381                                 }
3382                                 // sw_redlinehide: should be idempotent for multiple nodes in a merged para
3383                                 pRetSelectedParas->emplace( xWeakAcc, aDataEntry );
3384                             }
3385                         }
3386                     }
3387                 }
3388             }
3389 
3390         // prepare next turn: get next cursor in ring
3391         pCursor = pCursor->GetNext();
3392     } while ( pCursor != pRingStart );
3393 
3394     return pRetSelectedParas;
3395 }
3396 
InvalidateTextSelectionOfAllParas()3397 void SwAccessibleMap::InvalidateTextSelectionOfAllParas()
3398 {
3399     osl::MutexGuard aGuard( maMutex );
3400 
3401     // keep previously known selected paragraphs
3402     std::unique_ptr<SwAccessibleSelectedParas_Impl> pPrevSelectedParas( std::move(mpSelectedParas) );
3403 
3404     // determine currently selected paragraphs
3405     mpSelectedParas = BuildSelectedParas();
3406 
3407     // compare currently selected paragraphs with the previously selected
3408     // paragraphs and submit corresponding TEXT_SELECTION_CHANGED events.
3409     // first, search for new and changed selections.
3410     // on the run remove selections from previously known ones, if they are
3411     // also in the current ones.
3412     if ( mpSelectedParas )
3413     {
3414         SwAccessibleSelectedParas_Impl::iterator aIter = mpSelectedParas->begin();
3415         for ( ; aIter != mpSelectedParas->end(); ++aIter )
3416         {
3417             bool bSubmitEvent( false );
3418             if ( !pPrevSelectedParas )
3419             {
3420                 // new selection
3421                 bSubmitEvent = true;
3422             }
3423             else
3424             {
3425                 SwAccessibleSelectedParas_Impl::iterator aPrevSelected =
3426                                         pPrevSelectedParas->find( (*aIter).first );
3427                 if ( aPrevSelected != pPrevSelectedParas->end() )
3428                 {
3429                     // check, if selection has changed
3430                     if ( (*aIter).second.nStartOfSelection !=
3431                                     (*aPrevSelected).second.nStartOfSelection ||
3432                          (*aIter).second.nEndOfSelection !=
3433                                     (*aPrevSelected).second.nEndOfSelection )
3434                     {
3435                         // changed selection
3436                         bSubmitEvent = true;
3437                     }
3438                     pPrevSelectedParas->erase( aPrevSelected );
3439                 }
3440                 else
3441                 {
3442                     // new selection
3443                     bSubmitEvent = true;
3444                 }
3445             }
3446 
3447             if ( bSubmitEvent )
3448             {
3449                 uno::Reference < XAccessible > xAcc( (*aIter).first );
3450                 if ( xAcc.is() )
3451                 {
3452                     ::rtl::Reference < SwAccessibleContext > xAccImpl(
3453                                 static_cast<SwAccessibleContext*>( xAcc.get() ) );
3454                     if ( xAccImpl.is() && xAccImpl->GetFrame() )
3455                     {
3456                         const SwTextFrame* pTextFrame(
3457                             dynamic_cast<const SwTextFrame*>(xAccImpl->GetFrame()) );
3458                         OSL_ENSURE( pTextFrame,
3459                                 "<SwAccessibleMap::_SubmitTextSelectionChangedEvents()> - unexpected type of frame" );
3460                         if ( pTextFrame )
3461                         {
3462                             InvalidateParaTextSelection( *pTextFrame );
3463                         }
3464                     }
3465                 }
3466             }
3467         }
3468     }
3469 
3470     // second, handle previous selections - after the first step the data
3471     // structure of the previously known only contains the 'old' selections
3472     if ( pPrevSelectedParas )
3473     {
3474         SwAccessibleSelectedParas_Impl::iterator aIter = pPrevSelectedParas->begin();
3475         for ( ; aIter != pPrevSelectedParas->end(); ++aIter )
3476         {
3477             uno::Reference < XAccessible > xAcc( (*aIter).first );
3478             if ( xAcc.is() )
3479             {
3480                 ::rtl::Reference < SwAccessibleContext > xAccImpl(
3481                             static_cast<SwAccessibleContext*>( xAcc.get() ) );
3482                 if ( xAccImpl.is() && xAccImpl->GetFrame() )
3483                 {
3484                     const SwTextFrame* pTextFrame(
3485                             dynamic_cast<const SwTextFrame*>(xAccImpl->GetFrame()) );
3486                     OSL_ENSURE( pTextFrame,
3487                             "<SwAccessibleMap::_SubmitTextSelectionChangedEvents()> - unexpected type of frame" );
3488                     if ( pTextFrame )
3489                     {
3490                         InvalidateParaTextSelection( *pTextFrame );
3491                     }
3492                 }
3493             }
3494         }
3495     }
3496 }
3497 
GetVisArea() const3498 const SwRect& SwAccessibleMap::GetVisArea() const
3499 {
3500     assert(!GetShell()->IsPreview() || (mpPreview != nullptr));
3501 
3502     return GetShell()->IsPreview()
3503            ? mpPreview->GetVisArea()
3504            : GetShell()->VisArea();
3505 }
3506 
IsDocumentSelAll()3507 bool SwAccessibleMap::IsDocumentSelAll()
3508 {
3509     return GetShell()->GetDoc()->IsPrepareSelAll();
3510 }
3511 
3512 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3513