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