1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_accessibility.hxx"
26 
27 #ifndef _TOOLKIT_AWT_VCLXACCESSIBLECOMPONENT_HXX_
28 #include <accessibility/extended/textwindowaccessibility.hxx>
29 #endif
30 #include "comphelper/accessibleeventnotifier.hxx"
31 #include "unotools/accessiblerelationsethelper.hxx"
32 #include <unotools/accessiblestatesethelper.hxx>
33 #include <vcl/window.hxx>
34 #include <toolkit/helper/convert.hxx>
35 
36 #include <algorithm>
37 #include <vector>
38 #include <hash_map>
39 
40 namespace css = ::com::sun::star;
41 
42 namespace accessibility
43 {
44 
45 // Both ::osl::Mutex and ParagraphBase implement acquire and release, and thus
46 // ::rtl::Reference< Paragraph > does not work.  So ParagraphImpl was factored
47 // out and ::rtl::Reference< ParagraphImpl > is used instead.
48 class Paragraph: private ::osl::Mutex, public ParagraphImpl
49 {
50 public:
51     inline Paragraph(::rtl::Reference< Document > const & rDocument,
52                      Paragraphs::size_type nNumber):
53         ParagraphImpl(rDocument, nNumber, *this) {}
54 };
55 
56 void SfxListenerGuard::startListening(::SfxBroadcaster & rNotifier)
57 {
58     OSL_ENSURE(m_pNotifier == 0, "called more than once");
59     m_pNotifier = &rNotifier;
60     m_rListener.StartListening(*m_pNotifier, true);
61 }
62 
63 void SfxListenerGuard::endListening()
64 {
65     if (m_pNotifier != 0)
66     {
67         m_rListener.EndListening(*m_pNotifier);
68         m_pNotifier = 0;
69     }
70 }
71 
72 void WindowListenerGuard::startListening(::Window & rNotifier)
73 {
74     OSL_ENSURE(m_pNotifier == 0, "called more than once");
75     m_pNotifier = &rNotifier;
76     m_pNotifier->AddEventListener(m_aListener);
77 }
78 
79 void WindowListenerGuard::endListening()
80 {
81     if (m_pNotifier != 0)
82     {
83         m_pNotifier->RemoveEventListener(m_aListener);
84         m_pNotifier = 0;
85     }
86 }
87 
88 ParagraphImpl::ParagraphImpl(::rtl::Reference< Document > const & rDocument,
89                              Paragraphs::size_type nNumber,
90                              ::osl::Mutex & rMutex):
91     ParagraphBase(rMutex),
92     m_xDocument(rDocument),
93     m_nNumber(nNumber),
94     m_nClientId(0)
95 {
96     m_aParagraphText = m_xDocument->retrieveParagraphText(this);
97 }
98 
99 void
100 ParagraphImpl::numberChanged(bool bIncremented)
101 {
102     if (bIncremented)
103         ++m_nNumber;
104     else
105         --m_nNumber;
106 }
107 
108 void ParagraphImpl::textChanged()
109 {
110     ::rtl::OUString aParagraphText = implGetText();
111 	::css::uno::Any aOldValue, aNewValue;
112     if ( implInitTextChangedEvent( m_aParagraphText, aParagraphText, aOldValue, aNewValue ) )
113     {
114         m_aParagraphText = aParagraphText;
115         notifyEvent(::css::accessibility::AccessibleEventId::
116                     TEXT_CHANGED,
117                     aOldValue, aNewValue);
118     }
119 }
120 
121 void ParagraphImpl::notifyEvent(::sal_Int16 nEventId,
122                                 ::css::uno::Any const & rOldValue,
123                                 ::css::uno::Any const & rNewValue)
124 {
125 	if (m_nClientId)
126 		comphelper::AccessibleEventNotifier::addEvent( m_nClientId, ::css::accessibility::AccessibleEventObject(
127                              static_cast< ::cppu::OWeakObject * >(this),
128                              nEventId, rNewValue, rOldValue) );
129 }
130 
131 // virtual
132 ::css::uno::Reference< ::css::accessibility::XAccessibleContext > SAL_CALL
133 ParagraphImpl::getAccessibleContext() throw (::css::uno::RuntimeException)
134 {
135     checkDisposed();
136     return this;
137 }
138 
139 // virtual
140 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleChildCount()
141     throw (::css::uno::RuntimeException)
142 {
143     checkDisposed();
144     return 0;
145 }
146 
147 // virtual
148 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
149 ParagraphImpl::getAccessibleChild(::sal_Int32)
150     throw (::css::lang::IndexOutOfBoundsException,
151            ::css::uno::RuntimeException)
152 {
153     checkDisposed();
154     throw ::css::lang::IndexOutOfBoundsException(
155         ::rtl::OUString(
156             RTL_CONSTASCII_USTRINGPARAM(
157                 "textwindowaccessibility.cxx:"
158                 " ParagraphImpl::getAccessibleChild")),
159         static_cast< ::css::uno::XWeak * >(this));
160 }
161 
162 // virtual
163 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
164 ParagraphImpl::getAccessibleParent()
165     throw (::css::uno::RuntimeException)
166 {
167     checkDisposed();
168     return m_xDocument->getAccessible();
169 }
170 
171 // virtual
172 ::sal_Int32 SAL_CALL ParagraphImpl::getAccessibleIndexInParent()
173     throw (::css::uno::RuntimeException)
174 {
175     checkDisposed();
176     return m_xDocument->retrieveParagraphIndex(this);
177 }
178 
179 // virtual
180 ::sal_Int16 SAL_CALL ParagraphImpl::getAccessibleRole()
181     throw (::css::uno::RuntimeException)
182 {
183     checkDisposed();
184     return ::css::accessibility::AccessibleRole::PARAGRAPH;
185 }
186 
187 // virtual
188 ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleDescription()
189     throw (::css::uno::RuntimeException)
190 {
191     checkDisposed();
192     return ::rtl::OUString();
193 }
194 
195 // virtual
196 ::rtl::OUString SAL_CALL ParagraphImpl::getAccessibleName()
197     throw (::css::uno::RuntimeException)
198 {
199     checkDisposed();
200     return ::rtl::OUString();
201 }
202 
203 // virtual
204 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
205 SAL_CALL ParagraphImpl::getAccessibleRelationSet()
206     throw (::css::uno::RuntimeException)
207 {
208     checkDisposed();
209     return m_xDocument->retrieveParagraphRelationSet( this );
210 }
211 
212 // virtual
213 ::css::uno::Reference< ::css::accessibility::XAccessibleStateSet >
214 SAL_CALL ParagraphImpl::getAccessibleStateSet()
215     throw (::css::uno::RuntimeException)
216 {
217     checkDisposed();
218 
219     // FIXME  Notification of changes (STATE_CHANGED) missing when
220     // m_rView.IsReadOnly() changes:
221     return new ::utl::AccessibleStateSetHelper(
222         m_xDocument->retrieveParagraphState(this));
223 }
224 
225 // virtual
226 ::css::lang::Locale SAL_CALL ParagraphImpl::getLocale()
227     throw (::css::accessibility::IllegalAccessibleComponentStateException,
228            ::css::uno::RuntimeException)
229 {
230     checkDisposed();
231     return m_xDocument->retrieveLocale();
232 }
233 
234 // virtual
235 ::sal_Bool SAL_CALL ParagraphImpl::containsPoint(::css::awt::Point const & rPoint)
236     throw (::css::uno::RuntimeException)
237 {
238     checkDisposed();
239     ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
240                                                                      false));
241     return rPoint.X >= 0 && rPoint.X < aRect.Width
242         && rPoint.Y >= 0 && rPoint.Y < aRect.Height;
243 }
244 
245 // virtual
246 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
247 ParagraphImpl::getAccessibleAtPoint(::css::awt::Point const &)
248     throw (::css::uno::RuntimeException)
249 {
250     checkDisposed();
251     return 0;
252 }
253 
254 // virtual
255 ::css::awt::Rectangle SAL_CALL ParagraphImpl::getBounds()
256     throw (::css::uno::RuntimeException)
257 {
258     checkDisposed();
259     return m_xDocument->retrieveParagraphBounds(this, false);
260 }
261 
262 // virtual
263 ::css::awt::Point SAL_CALL ParagraphImpl::getLocation()
264     throw (::css::uno::RuntimeException)
265 {
266     checkDisposed();
267     ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
268                                                                      false));
269     return ::css::awt::Point(aRect.X, aRect.Y);
270 }
271 
272 // virtual
273 ::css::awt::Point SAL_CALL ParagraphImpl::getLocationOnScreen()
274     throw (::css::uno::RuntimeException)
275 {
276     checkDisposed();
277     ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
278                                                                      true));
279     return ::css::awt::Point(aRect.X, aRect.Y);
280 }
281 
282 // virtual
283 ::css::awt::Size SAL_CALL ParagraphImpl::getSize()
284     throw (::css::uno::RuntimeException)
285 {
286     checkDisposed();
287     ::css::awt::Rectangle aRect(m_xDocument->retrieveParagraphBounds(this,
288                                                                      false));
289     return ::css::awt::Size(aRect.Width, aRect.Height);
290 }
291 
292 // virtual
293 void SAL_CALL ParagraphImpl::grabFocus() throw (::css::uno::RuntimeException)
294 {
295     checkDisposed();
296     Window* pWindow = m_xDocument->GetWindow();
297     if ( pWindow )
298     {
299         pWindow->GrabFocus();
300     }
301     try
302     {
303         m_xDocument->changeParagraphSelection(this, 0, 0);
304     }
305     catch (::css::lang::IndexOutOfBoundsException & rEx)
306     {
307         OSL_TRACE(
308             "textwindowaccessibility.cxx: ParagraphImpl::grabFocus:"
309             " caught unexpected %s\n",
310             ::rtl::OUStringToOString(rEx.Message, RTL_TEXTENCODING_UTF8).
311             getStr());
312     }
313 }
314 
315 // virtual
316 ::css::uno::Any SAL_CALL ParagraphImpl::getAccessibleKeyBinding()
317     throw (::css::uno::RuntimeException)
318 {
319     checkDisposed();
320     return ::css::uno::Any();
321 }
322 
323 // virtual
324 ::css::util::Color SAL_CALL ParagraphImpl::getForeground()
325     throw (::css::uno::RuntimeException)
326 {
327     return 0; // TODO
328 }
329 
330 // virtual
331 ::css::util::Color SAL_CALL ParagraphImpl::getBackground()
332     throw (::css::uno::RuntimeException)
333 {
334     return 0; // TODO
335 }
336 
337 // virtual
338 ::sal_Int32 SAL_CALL ParagraphImpl::getCaretPosition()
339     throw (::css::uno::RuntimeException)
340 {
341     checkDisposed();
342     return m_xDocument->retrieveParagraphCaretPosition(this);
343 }
344 
345 // virtual
346 ::sal_Bool SAL_CALL ParagraphImpl::setCaretPosition(::sal_Int32 nIndex)
347     throw (::css::lang::IndexOutOfBoundsException,
348            ::css::uno::RuntimeException)
349 {
350     checkDisposed();
351     m_xDocument->changeParagraphSelection(this, nIndex, nIndex);
352     return true;
353 }
354 
355 // virtual
356 ::sal_Unicode SAL_CALL ParagraphImpl::getCharacter(::sal_Int32 nIndex)
357     throw (::css::lang::IndexOutOfBoundsException,
358            ::css::uno::RuntimeException)
359 {
360     checkDisposed();
361     return OCommonAccessibleText::getCharacter(nIndex);
362 }
363 
364 // virtual
365 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
366 ParagraphImpl::getCharacterAttributes(::sal_Int32 nIndex, const ::com::sun::star::uno::Sequence< ::rtl::OUString >& aRequestedAttributes)
367     throw (::css::lang::IndexOutOfBoundsException,
368            ::css::uno::RuntimeException)
369 {
370     checkDisposed();
371     return m_xDocument->retrieveCharacterAttributes( this, nIndex, aRequestedAttributes );
372 }
373 
374 // virtual
375 ::css::awt::Rectangle SAL_CALL
376 ParagraphImpl::getCharacterBounds(::sal_Int32 nIndex)
377     throw (::css::lang::IndexOutOfBoundsException,
378            ::css::uno::RuntimeException)
379 {
380     checkDisposed();
381     ::css::awt::Rectangle aBounds(m_xDocument->retrieveCharacterBounds(this, nIndex));
382     ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false));
383 	aBounds.X -= aParaBounds.X;
384 	aBounds.Y -= aParaBounds.Y;
385 	return aBounds;
386 }
387 
388 // virtual
389 ::sal_Int32 SAL_CALL ParagraphImpl::getCharacterCount()
390     throw (::css::uno::RuntimeException)
391 {
392     checkDisposed();
393     return OCommonAccessibleText::getCharacterCount();
394 }
395 
396 // virtual
397 ::sal_Int32 SAL_CALL
398 ParagraphImpl::getIndexAtPoint(::css::awt::Point const & rPoint)
399     throw (::css::uno::RuntimeException)
400 {
401     checkDisposed();
402 	::css::awt::Point aPoint(rPoint);
403     ::css::awt::Rectangle aParaBounds(m_xDocument->retrieveParagraphBounds(this, false));
404 	aPoint.X += aParaBounds.X;
405 	aPoint.Y += aParaBounds.Y;
406     return m_xDocument->retrieveCharacterIndex(this, aPoint);
407 }
408 
409 // virtual
410 ::rtl::OUString SAL_CALL ParagraphImpl::getSelectedText()
411     throw (::css::uno::RuntimeException)
412 {
413     checkDisposed();
414 
415     return OCommonAccessibleText::getSelectedText();
416 }
417 
418 // virtual
419 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionStart()
420     throw (::css::uno::RuntimeException)
421 {
422     checkDisposed();
423     return OCommonAccessibleText::getSelectionStart();
424 }
425 
426 // virtual
427 ::sal_Int32 SAL_CALL ParagraphImpl::getSelectionEnd()
428     throw (::css::uno::RuntimeException)
429 {
430     checkDisposed();
431     return OCommonAccessibleText::getSelectionEnd();
432 }
433 
434 // virtual
435 ::sal_Bool SAL_CALL ParagraphImpl::setSelection(::sal_Int32 nStartIndex,
436                                                 ::sal_Int32 nEndIndex)
437     throw (::css::lang::IndexOutOfBoundsException,
438            ::css::uno::RuntimeException)
439 {
440     checkDisposed();
441     m_xDocument->changeParagraphSelection(this, nStartIndex, nEndIndex);
442     return true;
443 }
444 
445 // virtual
446 ::rtl::OUString SAL_CALL ParagraphImpl::getText()
447     throw (::css::uno::RuntimeException)
448 {
449     checkDisposed();
450     return OCommonAccessibleText::getText();
451 }
452 
453 // virtual
454 ::rtl::OUString SAL_CALL ParagraphImpl::getTextRange(::sal_Int32 nStartIndex,
455                                                      ::sal_Int32 nEndIndex)
456     throw (::css::lang::IndexOutOfBoundsException,
457            ::css::uno::RuntimeException)
458 {
459     checkDisposed();
460     return OCommonAccessibleText::getTextRange(nStartIndex, nEndIndex);
461 }
462 
463 // virtual
464 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
465 {
466     checkDisposed();
467     return OCommonAccessibleText::getTextAtIndex(nIndex, aTextType);
468 }
469 
470 // virtual
471 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
472 {
473     checkDisposed();
474     return OCommonAccessibleText::getTextBeforeIndex(nIndex, aTextType);
475 }
476 
477 // virtual
478 ::com::sun::star::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) throw (::com::sun::star::lang::IndexOutOfBoundsException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::uno::RuntimeException)
479 {
480     checkDisposed();
481     return OCommonAccessibleText::getTextBehindIndex(nIndex, aTextType);
482 }
483 
484 // virtual
485 ::sal_Bool SAL_CALL ParagraphImpl::copyText(::sal_Int32 nStartIndex,
486                                             ::sal_Int32 nEndIndex)
487     throw (::css::lang::IndexOutOfBoundsException,
488            ::css::uno::RuntimeException)
489 {
490     checkDisposed();
491     m_xDocument->copyParagraphText(this, nStartIndex, nEndIndex);
492     return true;
493 }
494 
495 // virtual
496 ::sal_Bool SAL_CALL ParagraphImpl::cutText(::sal_Int32 nStartIndex,
497                                            ::sal_Int32 nEndIndex)
498     throw (::css::lang::IndexOutOfBoundsException,
499            ::css::uno::RuntimeException)
500 {
501     checkDisposed();
502     m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, true, false,
503                                      ::rtl::OUString());
504     return true;
505 }
506 
507 // virtual
508 ::sal_Bool SAL_CALL ParagraphImpl::pasteText(::sal_Int32 nIndex)
509     throw (::css::lang::IndexOutOfBoundsException,
510            ::css::uno::RuntimeException)
511 {
512     checkDisposed();
513     m_xDocument->changeParagraphText(this, nIndex, nIndex, false, true,
514                                      ::rtl::OUString());
515     return true;
516 }
517 
518 // virtual
519 ::sal_Bool SAL_CALL ParagraphImpl::deleteText(::sal_Int32 nStartIndex,
520                                           ::sal_Int32 nEndIndex)
521     throw (::css::lang::IndexOutOfBoundsException,
522            ::css::uno::RuntimeException)
523 {
524     checkDisposed();
525     m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
526                                      ::rtl::OUString());
527     return true;
528 }
529 
530 // virtual
531 ::sal_Bool SAL_CALL ParagraphImpl::insertText(::rtl::OUString const & rText,
532                                               ::sal_Int32 nIndex)
533     throw (::css::lang::IndexOutOfBoundsException,
534            ::css::uno::RuntimeException)
535 {
536     checkDisposed();
537     m_xDocument->changeParagraphText(this, nIndex, nIndex, false, false, rText);
538     return true;
539 }
540 
541 // virtual
542 ::sal_Bool SAL_CALL
543 ParagraphImpl::replaceText(::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
544                            ::rtl::OUString const & rReplacement)
545     throw (::css::lang::IndexOutOfBoundsException,
546            ::css::uno::RuntimeException)
547 {
548     checkDisposed();
549     m_xDocument->changeParagraphText(this, nStartIndex, nEndIndex, false, false,
550                                      rReplacement);
551     return true;
552 }
553 
554 // virtual
555 ::sal_Bool SAL_CALL ParagraphImpl::setAttributes(
556     ::sal_Int32 nStartIndex, ::sal_Int32 nEndIndex,
557     ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
558     throw (::css::lang::IndexOutOfBoundsException,
559            ::css::uno::RuntimeException)
560 {
561     checkDisposed();
562     m_xDocument->changeParagraphAttributes(this, nStartIndex, nEndIndex,
563                                            rAttributeSet);
564     return true;
565 }
566 
567 // virtual
568 ::sal_Bool SAL_CALL ParagraphImpl::setText(::rtl::OUString const & rText)
569     throw (::css::uno::RuntimeException)
570 {
571     checkDisposed();
572     m_xDocument->changeParagraphText(this, rText);
573     return true;
574 }
575 
576 // virtual
577 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
578 ParagraphImpl::getDefaultAttributes(const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
579     throw (::css::uno::RuntimeException)
580 {
581     checkDisposed();
582     return m_xDocument->retrieveDefaultAttributes( this, RequestedAttributes );
583 }
584 
585 // virtual
586 ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL
587 ParagraphImpl::getRunAttributes(::sal_Int32 Index, const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
588     throw (::css::lang::IndexOutOfBoundsException,
589            ::css::uno::RuntimeException)
590 {
591     checkDisposed();
592     return m_xDocument->retrieveRunAttributes( this, Index, RequestedAttributes );
593 }
594 
595 // virtual
596 ::sal_Int32 SAL_CALL ParagraphImpl::getLineNumberAtIndex( ::sal_Int32 nIndex )
597     throw (::css::lang::IndexOutOfBoundsException,
598            ::css::uno::RuntimeException)
599 {
600     checkDisposed();
601 
602     ::sal_Int32 nLineNo = -1;
603     ::css::i18n::Boundary aBoundary =
604         m_xDocument->retrieveParagraphLineBoundary( this, nIndex, &nLineNo );
605 
606     return nLineNo;
607 }
608 
609 // virtual
610 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineNumber( ::sal_Int32 nLineNo )
611     throw (::css::lang::IndexOutOfBoundsException,
612            ::css::uno::RuntimeException)
613 {
614     checkDisposed();
615 
616     ::css::i18n::Boundary aBoundary =
617         m_xDocument->retrieveParagraphBoundaryOfLine( this, nLineNo );
618 
619     return ::css::accessibility::TextSegment( getTextRange(aBoundary.startPos, aBoundary.endPos),
620         aBoundary.startPos, aBoundary.endPos);
621 }
622 
623 // virtual
624 ::css::accessibility::TextSegment SAL_CALL ParagraphImpl::getTextAtLineWithCaret(  )
625     throw (::css::uno::RuntimeException)
626 {
627     checkDisposed();
628 
629     sal_Int32 nLineNo = getNumberOfLineWithCaret();
630 
631     try {
632         return ( nLineNo >= 0 ) ?
633             getTextAtLineNumber( nLineNo ) :
634             ::css::accessibility::TextSegment();
635     } catch (const ::css::lang::IndexOutOfBoundsException&) {
636         throw ::css::uno::RuntimeException(
637             ::rtl::OUString(
638                 RTL_CONSTASCII_USTRINGPARAM(
639                     "textwindowaccessibility.cxx:"
640                     " ParagraphImpl::getTextAtLineWithCaret") ),
641             static_cast< ::css::uno::XWeak * >( this ) );
642     }
643 }
644 
645 // virtual
646 ::sal_Int32 SAL_CALL ParagraphImpl::getNumberOfLineWithCaret(  )
647     throw (::css::uno::RuntimeException)
648 {
649     checkDisposed();
650     return m_xDocument->retrieveParagraphLineWithCursor(this);
651 }
652 
653 
654 // virtual
655 void SAL_CALL ParagraphImpl::addEventListener(
656     ::css::uno::Reference<
657     ::css::accessibility::XAccessibleEventListener > const & rListener)
658     throw (::css::uno::RuntimeException)
659 {
660     if (rListener.is())
661     {
662         ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
663         if (rBHelper.bDisposed || rBHelper.bInDispose)
664         {
665             aGuard.clear();
666             rListener->disposing(::css::lang::EventObject(
667                                     static_cast< ::cppu::OWeakObject * >(this)));
668         }
669         else
670         {
671 			if (!m_nClientId)
672                 m_nClientId = comphelper::AccessibleEventNotifier::registerClient( );
673 			comphelper::AccessibleEventNotifier::addEventListener( m_nClientId, rListener );
674 		}
675     }
676 }
677 
678 // virtual
679 void SAL_CALL ParagraphImpl::removeEventListener(
680     ::css::uno::Reference<
681     ::css::accessibility::XAccessibleEventListener > const & rListener)
682     throw (::css::uno::RuntimeException)
683 {
684 	comphelper::AccessibleEventNotifier::TClientId nId = 0;
685 	{
686         ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
687 		if (rListener.is() && m_nClientId != 0
688 			&& comphelper::AccessibleEventNotifier::removeEventListener( m_nClientId, rListener ) == 0)
689 		{
690 			nId = m_nClientId;
691 			m_nClientId = 0;
692 		}
693 	}
694 	if (nId != 0)
695 	{
696 		// no listeners anymore
697 		// -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
698 		// and at least to us not firing any events anymore, in case somebody calls
699 		// NotifyAccessibleEvent, again
700 		comphelper::AccessibleEventNotifier::revokeClient(nId);
701 	}
702 }
703 
704 // virtual
705 void SAL_CALL ParagraphImpl::disposing()
706 {
707 	comphelper::AccessibleEventNotifier::TClientId nId = 0;
708 	{
709         ::osl::ClearableMutexGuard aGuard(rBHelper.rMutex);
710 		nId = m_nClientId;
711 		m_nClientId = 0;
712 	}
713 	if (nId != 0)
714         comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing(nId, *this);
715 }
716 
717 // virtual
718 ::rtl::OUString ParagraphImpl::implGetText()
719 {
720     return m_xDocument->retrieveParagraphText(this);
721 }
722 
723 // virtual
724 ::css::lang::Locale ParagraphImpl::implGetLocale()
725 {
726     return m_xDocument->retrieveLocale();
727 }
728 
729 // virtual
730 void ParagraphImpl::implGetSelection(::sal_Int32 & rStartIndex,
731                                      ::sal_Int32 & rEndIndex)
732 {
733     m_xDocument->retrieveParagraphSelection(this, &rStartIndex, &rEndIndex);
734 }
735 
736 // virtual
737 void ParagraphImpl::implGetParagraphBoundary( ::css::i18n::Boundary& rBoundary,
738                                               ::sal_Int32 nIndex )
739 {
740     ::rtl::OUString sText( implGetText() );
741     ::sal_Int32 nLength = sText.getLength();
742 
743     if ( implIsValidIndex( nIndex, nLength ) )
744     {
745         rBoundary.startPos = 0;
746         rBoundary.endPos = nLength;
747     }
748     else
749     {
750         rBoundary.startPos = nIndex;
751         rBoundary.endPos = nIndex;
752     }
753 }
754 
755 // virtual
756 void ParagraphImpl::implGetLineBoundary( ::css::i18n::Boundary& rBoundary,
757                                          ::sal_Int32 nIndex )
758 {
759     ::rtl::OUString sText( implGetText() );
760     ::sal_Int32 nLength = sText.getLength();
761 
762     if ( implIsValidIndex( nIndex, nLength ) || nIndex == nLength )
763     {
764         ::css::i18n::Boundary aBoundary =
765             m_xDocument->retrieveParagraphLineBoundary( this, nIndex );
766         rBoundary.startPos = aBoundary.startPos;
767         rBoundary.endPos = aBoundary.endPos;
768     }
769     else
770     {
771         rBoundary.startPos = nIndex;
772         rBoundary.endPos = nIndex;
773     }
774 }
775 
776 
777 void ParagraphImpl::checkDisposed()
778 {
779     ::osl::MutexGuard aGuard(rBHelper.rMutex);
780     if (!(rBHelper.bDisposed || rBHelper.bInDispose))
781         return;
782     throw ::css::lang::DisposedException(
783         ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this));
784 }
785 
786 Document::Document(::VCLXWindow * pVclXWindow, ::TextEngine & rEngine,
787                    ::TextView & rView, bool bCompoundControlChild):
788     VCLXAccessibleComponent(pVclXWindow),
789     m_xAccessible(pVclXWindow),
790     m_rEngine(rEngine),
791     m_rView(rView),
792     m_aEngineListener(*this),
793     m_aViewListener(LINK(this, Document, WindowEventHandler)),
794 	m_bCompoundControlChild(bCompoundControlChild)
795 {}
796 
797 ::css::lang::Locale Document::retrieveLocale()
798 {
799     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
800     return m_rEngine.GetLocale();
801 }
802 
803 ::sal_Int32 Document::retrieveParagraphIndex(ParagraphImpl const * pParagraph)
804 {
805     ::osl::MutexGuard aInternalGuard(GetMutex());
806 
807     // If a client holds on to a Paragraph that is no longer visible, it can
808     // happen that this Paragraph lies outside the range from m_aVisibleBegin
809     // to m_aVisibleEnd.  In that case, return -1 instead of a valid index:
810     Paragraphs::iterator aPara(m_xParagraphs->begin()
811                                + pParagraph->getNumber());
812     return aPara < m_aVisibleBegin || aPara >= m_aVisibleEnd
813         ? -1 : static_cast< ::sal_Int32 >(aPara - m_aVisibleBegin);
814         // XXX  numeric overflow
815 }
816 
817 ::sal_Int64 Document::retrieveParagraphState(ParagraphImpl const * pParagraph)
818 {
819     ::osl::MutexGuard aInternalGuard(GetMutex());
820 
821     // If a client holds on to a Paragraph that is no longer visible, it can
822     // happen that this Paragraph lies outside the range from m_aVisibleBegin
823     // to m_aVisibleEnd.  In that case, it is neither VISIBLE nor SHOWING:
824     ::sal_Int64 nState
825           = (static_cast< ::sal_Int64 >(1)
826              << ::css::accessibility::AccessibleStateType::ENABLED)
827           | (static_cast< ::sal_Int64 >(1)
828              << ::css::accessibility::AccessibleStateType::SENSITIVE)
829           | (static_cast< ::sal_Int64 >(1)
830              << ::css::accessibility::AccessibleStateType::FOCUSABLE)
831           | (static_cast< ::sal_Int64 >(1)
832              << ::css::accessibility::AccessibleStateType::MULTI_LINE);
833     if (!m_rView.IsReadOnly())
834         nState |= (static_cast< ::sal_Int64 >(1)
835                    << ::css::accessibility::AccessibleStateType::EDITABLE);
836     Paragraphs::iterator aPara(m_xParagraphs->begin()
837                                + pParagraph->getNumber());
838     if (aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd)
839     {
840         nState
841             |= (static_cast< ::sal_Int64 >(1)
842                 << ::css::accessibility::AccessibleStateType::VISIBLE)
843             | (static_cast< ::sal_Int64 >(1)
844                << ::css::accessibility::AccessibleStateType::SHOWING);
845         if (aPara == m_aFocused)
846             nState |= (static_cast< ::sal_Int64 >(1)
847                        << ::css::accessibility::AccessibleStateType::FOCUSED);
848     }
849     return nState;
850 };
851 
852 ::css::awt::Rectangle
853 Document::retrieveParagraphBounds(ParagraphImpl const * pParagraph,
854                                   bool bAbsolute)
855 {
856     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
857     ::osl::MutexGuard aInternalGuard(GetMutex());
858 
859     // If a client holds on to a Paragraph that is no longer visible (as it
860     // scrolled out the top of the view), it can happen that this Paragraph
861     // lies before m_aVisibleBegin.  In that case, calculate the vertical
862     // position of the Paragraph starting at paragraph 0, otherwise optimize
863     // and start at m_aVisibleBegin:
864     Paragraphs::iterator aPara(m_xParagraphs->begin()
865                                + pParagraph->getNumber());
866     ::sal_Int32 nPos;
867     Paragraphs::iterator aIt;
868     if (aPara < m_aVisibleBegin)
869     {
870         nPos = 0;
871         aIt = m_xParagraphs->begin();
872     }
873     else
874     {
875         nPos = m_nViewOffset - m_nVisibleBeginOffset;
876         aIt = m_aVisibleBegin;
877     }
878     for (; aIt != aPara; ++aIt)
879         nPos += aIt->getHeight();
880 
881     Point aOrig(0, 0);
882     if (bAbsolute)
883         aOrig = m_rView.GetWindow()->OutputToAbsoluteScreenPixel(aOrig);
884 
885     return ::css::awt::Rectangle(
886         static_cast< ::sal_Int32 >(aOrig.X()),
887         static_cast< ::sal_Int32 >(aOrig.Y()) + nPos - m_nViewOffset,
888         m_rView.GetWindow()->GetOutputSizePixel().Width(), aPara->getHeight());
889         // XXX  numeric overflow (3x)
890 }
891 
892 ::rtl::OUString
893 Document::retrieveParagraphText(ParagraphImpl const * pParagraph)
894 {
895     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
896     ::osl::MutexGuard aInternalGuard(GetMutex());
897     return m_rEngine.GetText(static_cast< ::sal_uLong >(pParagraph->getNumber()));
898         // numeric overflow cannot happen here
899 }
900 
901 void Document::retrieveParagraphSelection(ParagraphImpl const * pParagraph,
902                                           ::sal_Int32 * pBegin,
903                                           ::sal_Int32 * pEnd)
904 {
905     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
906     ::osl::MutexGuard aInternalGuard(GetMutex());
907     ::TextSelection const & rSelection = m_rView.GetSelection();
908     Paragraphs::size_type nNumber = pParagraph->getNumber();
909     TextPaM aStartPaM( rSelection.GetStart() );
910     TextPaM aEndPaM( rSelection.GetEnd() );
911     TextPaM aMinPaM( ::std::min( aStartPaM, aEndPaM ) );
912     TextPaM aMaxPaM( ::std::max( aStartPaM, aEndPaM ) );
913 
914     if ( nNumber >= aMinPaM.GetPara() && nNumber <= aMaxPaM.GetPara() )
915     {
916         *pBegin = nNumber > aMinPaM.GetPara()
917             ? 0
918             : static_cast< ::sal_Int32 >( aMinPaM.GetIndex() );
919             // XXX numeric overflow
920         *pEnd = nNumber < aMaxPaM.GetPara()
921             ? static_cast< ::sal_Int32 >( m_rEngine.GetText(static_cast< ::sal_uLong >(nNumber)).Len() )
922             : static_cast< ::sal_Int32 >( aMaxPaM.GetIndex() );
923             // XXX  numeric overflow (3x)
924 
925         if ( aStartPaM > aEndPaM )
926             ::std::swap( *pBegin, *pEnd );
927     }
928     else
929     {
930         *pBegin = 0;
931         *pEnd = 0;
932     }
933 }
934 
935 ::sal_Int32 Document::retrieveParagraphCaretPosition(ParagraphImpl const * pParagraph)
936 {
937     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
938     ::osl::MutexGuard aInternalGuard(GetMutex());
939     ::TextSelection const & rSelection = m_rView.GetSelection();
940     Paragraphs::size_type nNumber = pParagraph->getNumber();
941     TextPaM aEndPaM( rSelection.GetEnd() );
942 
943     return aEndPaM.GetPara() == nNumber
944         ? static_cast< ::sal_Int32 >(aEndPaM.GetIndex()) : -1;
945 }
946 
947 ::css::awt::Rectangle
948 Document::retrieveCharacterBounds(ParagraphImpl const * pParagraph,
949                                   ::sal_Int32 nIndex)
950 {
951     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
952     ::osl::MutexGuard aInternalGuard(GetMutex());
953     ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
954     sal_Int32 nLength = m_rEngine.GetText(nNumber).Len();
955         // XXX  numeric overflow
956     if (nIndex < 0 || nIndex > nLength)
957         throw ::css::lang::IndexOutOfBoundsException(
958             ::rtl::OUString(
959                 RTL_CONSTASCII_USTRINGPARAM(
960                     "textwindowaccessibility.cxx:"
961                     " Document::retrieveCharacterAttributes")),
962             static_cast< ::css::uno::XWeak * >(this));
963     ::css::awt::Rectangle aBounds( 0, 0, 0, 0 );
964     if ( nIndex == nLength )
965     {
966         aBounds = AWTRectangle(
967             m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
968                                                 static_cast< ::sal_uInt16 >(nIndex))));
969     }
970     else
971     {
972         ::Rectangle aLeft(
973             m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
974                                                 static_cast< ::sal_uInt16 >(nIndex))));
975             // XXX  numeric overflow
976         ::Rectangle aRight(
977             m_rEngine.PaMtoEditCursor(::TextPaM(nNumber,
978                                                 static_cast< ::sal_uInt16 >(nIndex)
979                                                 + 1)));
980             // XXX  numeric overflow (2x)
981         // FIXME  If the vertical extends of the two cursors do not match, assume
982         // nIndex is the last character on the line; the bounding box will then
983         // extend to m_rEnginge.GetMaxTextWidth():
984         ::sal_Int32 nWidth = (aLeft.Top() == aRight.Top()
985                             && aLeft.Bottom() == aRight.Bottom())
986             ? static_cast< ::sal_Int32 >(aRight.Left() - aLeft.Left())
987             : static_cast< ::sal_Int32 >(m_rEngine.GetMaxTextWidth()
988                                         - aLeft.Left());
989             // XXX  numeric overflow (4x)
990         aBounds = ::css::awt::Rectangle(static_cast< ::sal_Int32 >(aLeft.Left()),
991                                         static_cast< ::sal_Int32 >(aLeft.Top() - m_nViewOffset),
992                                         nWidth,
993                                         static_cast< ::sal_Int32 >(aLeft.Bottom()
994                                                                     - aLeft.Top()));
995             // XXX  numeric overflow (4x)
996     }
997     return aBounds;
998 }
999 
1000 ::sal_Int32 Document::retrieveCharacterIndex(ParagraphImpl const * pParagraph,
1001                                              ::css::awt::Point const & rPoint)
1002 {
1003     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1004     ::osl::MutexGuard aInternalGuard(GetMutex());
1005     ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1006         // XXX  numeric overflow
1007     ::TextPaM aPaM(m_rEngine.GetPaM(::Point(static_cast< long >(rPoint.X),
1008                                             static_cast< long >(rPoint.Y))));
1009         // XXX  numeric overflow (2x)
1010     return aPaM.GetPara() == nNumber
1011         ? static_cast< ::sal_Int32 >(aPaM.GetIndex()) : -1;
1012         // XXX  numeric overflow
1013 }
1014 
1015 ::css::uno::Sequence< ::css::beans::PropertyValue >
1016 Document::retrieveCharacterAttributes(
1017     ParagraphImpl const * pParagraph, ::sal_Int32 nIndex,
1018     const ::css::uno::Sequence< ::rtl::OUString >& aRequestedAttributes)
1019 {
1020     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1021     ::osl::MutexGuard aInternalGuard(GetMutex());
1022     ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1023         // XXX  numeric overflow
1024     if (nIndex < 0 || nIndex >= m_rEngine.GetText(nNumber).Len())
1025         throw ::css::lang::IndexOutOfBoundsException(
1026             ::rtl::OUString(
1027                 RTL_CONSTASCII_USTRINGPARAM(
1028                     "textwindowaccessibility.cxx:"
1029                     " Document::retrieveCharacterAttributes")),
1030             static_cast< ::css::uno::XWeak * >(this));
1031 
1032     // retrieve default attributes
1033     tPropValMap aCharAttrSeq;
1034     retrieveDefaultAttributesImpl( pParagraph, aRequestedAttributes, aCharAttrSeq );
1035 
1036     // retrieve run attributes
1037     tPropValMap aRunAttrSeq;
1038     retrieveRunAttributesImpl( pParagraph, nIndex, aRequestedAttributes, aRunAttrSeq );
1039 
1040     // merge default and run attributes
1041     for ( tPropValMap::const_iterator aRunIter  = aRunAttrSeq.begin();
1042           aRunIter != aRunAttrSeq.end();
1043           ++aRunIter )
1044     {
1045         aCharAttrSeq[ aRunIter->first ] = aRunIter->second;
1046     }
1047 
1048     return convertHashMapToSequence( aCharAttrSeq );
1049 }
1050 
1051 void Document::retrieveDefaultAttributesImpl(
1052     ParagraphImpl const * pParagraph,
1053     const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes,
1054     tPropValMap& rDefAttrSeq)
1055 {
1056     // default attributes are not supported by text engine
1057     (void) pParagraph;
1058     (void) RequestedAttributes;
1059     (void) rDefAttrSeq;
1060 }
1061 
1062 ::css::uno::Sequence< ::css::beans::PropertyValue >
1063 Document::retrieveDefaultAttributes(
1064     ParagraphImpl const * pParagraph,
1065     const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
1066 {
1067     ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1068     ::osl::MutexGuard aInternalGuard( GetMutex() );
1069 
1070     tPropValMap aDefAttrSeq;
1071     retrieveDefaultAttributesImpl( pParagraph, RequestedAttributes, aDefAttrSeq );
1072     return convertHashMapToSequence( aDefAttrSeq );
1073 }
1074 
1075 // static
1076 ::css::uno::Sequence< ::css::beans::PropertyValue >
1077 Document::convertHashMapToSequence(tPropValMap& rAttrSeq)
1078 {
1079     ::css::uno::Sequence< ::css::beans::PropertyValue > aValues( rAttrSeq.size() );
1080     ::css::beans::PropertyValue* pValues = aValues.getArray();
1081     ::sal_Int32 i = 0;
1082     for ( tPropValMap::const_iterator aIter  = rAttrSeq.begin();
1083           aIter != rAttrSeq.end();
1084           ++aIter )
1085     {
1086         pValues[i] = aIter->second;
1087         ++i;
1088     }
1089     return aValues;
1090 }
1091 
1092 void Document::retrieveRunAttributesImpl(
1093     ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1094     const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes,
1095     tPropValMap& rRunAttrSeq)
1096 {
1097     ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1098     ::TextPaM aPaM( nNumber, static_cast< ::sal_uInt16 >( Index ) );
1099         // XXX  numeric overflow
1100     // FIXME  TEXTATTR_HYPERLINK ignored:
1101     ::TextAttribFontColor const * pColor
1102           = static_cast< ::TextAttribFontColor const * >(
1103               m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTCOLOR ) );
1104     ::TextAttribFontWeight const * pWeight
1105           = static_cast< ::TextAttribFontWeight const * >(
1106               m_rEngine.FindAttrib( aPaM, TEXTATTR_FONTWEIGHT ) );
1107     tPropValMap aRunAttrSeq;
1108     if ( pColor )
1109     {
1110         ::css::beans::PropertyValue aPropVal;
1111         aPropVal.Name =
1112             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharColor" ) );
1113         aPropVal.Handle = -1;
1114         aPropVal.Value = mapFontColor( pColor->GetColor() );
1115         aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1116         aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1117     }
1118     if ( pWeight )
1119     {
1120         ::css::beans::PropertyValue aPropVal;
1121         aPropVal.Name =
1122             ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "CharWeight" ) );
1123         aPropVal.Handle = -1;
1124         aPropVal.Value = mapFontWeight( pWeight->getFontWeight() );
1125         aPropVal.State = ::css::beans::PropertyState_DIRECT_VALUE;
1126         aRunAttrSeq[ aPropVal.Name ] = aPropVal;
1127     }
1128     if ( RequestedAttributes.getLength() == 0 )
1129     {
1130         rRunAttrSeq = aRunAttrSeq;
1131     }
1132     else
1133     {
1134         const ::rtl::OUString* pReqAttrs = RequestedAttributes.getConstArray();
1135         const ::sal_Int32 nLength = RequestedAttributes.getLength();
1136         for ( ::sal_Int32 i = 0; i < nLength; ++i )
1137         {
1138             tPropValMap::iterator aIter = aRunAttrSeq.find( pReqAttrs[i] );
1139             if ( aIter != aRunAttrSeq.end() )
1140             {
1141                 rRunAttrSeq[ (*aIter).first ] = (*aIter).second;
1142             }
1143         }
1144     }
1145 }
1146 
1147 ::css::uno::Sequence< ::css::beans::PropertyValue >
1148 Document::retrieveRunAttributes(
1149     ParagraphImpl const * pParagraph, ::sal_Int32 Index,
1150     const ::css::uno::Sequence< ::rtl::OUString >& RequestedAttributes)
1151 {
1152     ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1153     ::osl::MutexGuard aInternalGuard( GetMutex() );
1154     ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1155         // XXX  numeric overflow
1156     if ( Index < 0 || Index >= m_rEngine.GetText(nNumber).Len() )
1157         throw ::css::lang::IndexOutOfBoundsException(
1158             ::rtl::OUString(
1159                 RTL_CONSTASCII_USTRINGPARAM(
1160                     "textwindowaccessibility.cxx:"
1161                     " Document::retrieveRunAttributes") ),
1162             static_cast< ::css::uno::XWeak * >( this ) );
1163 
1164     tPropValMap aRunAttrSeq;
1165     retrieveRunAttributesImpl( pParagraph, Index, RequestedAttributes, aRunAttrSeq );
1166     return convertHashMapToSequence( aRunAttrSeq );
1167 }
1168 
1169 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1170                                    ::rtl::OUString const & rText)
1171 {
1172     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1173     {
1174         ::osl::MutexGuard aInternalGuard(GetMutex());
1175         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1176             // XXX  numeric overflow
1177         changeParagraphText(nNumber, 0, m_rEngine.GetTextLen(nNumber), false,
1178                             false, rText);
1179     }
1180 }
1181 
1182 void Document::changeParagraphText(ParagraphImpl * pParagraph,
1183                                    ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1184                                    bool bCut, bool bPaste,
1185                                    ::rtl::OUString const & rText)
1186 {
1187     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1188     {
1189         ::osl::MutexGuard aInternalGuard(GetMutex());
1190         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1191             // XXX  numeric overflow
1192         if (nBegin < 0 || nBegin > nEnd
1193             || nEnd > m_rEngine.GetText(nNumber).Len())
1194             throw ::css::lang::IndexOutOfBoundsException(
1195                 ::rtl::OUString(
1196                     RTL_CONSTASCII_USTRINGPARAM(
1197                         "textwindowaccessibility.cxx:"
1198                         " Document::changeParagraphText")),
1199                 static_cast< ::css::uno::XWeak * >(this));
1200         changeParagraphText(nNumber, static_cast< ::sal_uInt16 >(nBegin),
1201                             static_cast< ::sal_uInt16 >(nEnd), bCut, bPaste, rText);
1202             // XXX  numeric overflow (2x)
1203     }
1204 }
1205 
1206 void Document::copyParagraphText(ParagraphImpl const * pParagraph,
1207                                  ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1208 {
1209     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1210     {
1211         ::osl::MutexGuard aInternalGuard(GetMutex());
1212         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1213             // XXX  numeric overflow
1214         if (nBegin < 0 || nBegin > nEnd
1215             || nEnd > m_rEngine.GetText(nNumber).Len())
1216             throw ::css::lang::IndexOutOfBoundsException(
1217                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1218                                     "textwindowaccessibility.cxx:"
1219                                     " Document::copyParagraphText")),
1220                 static_cast< ::css::uno::XWeak * >(this));
1221         m_rView.SetSelection(
1222             ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)),
1223                             ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd))));
1224             // XXX  numeric overflow (2x)
1225         m_rView.Copy();
1226     }
1227 }
1228 
1229 void Document::changeParagraphAttributes(
1230     ParagraphImpl * pParagraph, ::sal_Int32 nBegin, ::sal_Int32 nEnd,
1231     ::css::uno::Sequence< ::css::beans::PropertyValue > const & rAttributeSet)
1232 {
1233     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1234     {
1235         ::osl::MutexGuard aInternalGuard(GetMutex());
1236         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1237         // XXX  numeric overflow
1238         if (nBegin < 0 || nBegin > nEnd
1239             || nEnd > m_rEngine.GetText(nNumber).Len())
1240             throw ::css::lang::IndexOutOfBoundsException(
1241                 ::rtl::OUString(
1242                     RTL_CONSTASCII_USTRINGPARAM(
1243                         "textwindowaccessibility.cxx:"
1244                         " Document::changeParagraphAttributes")),
1245                 static_cast< ::css::uno::XWeak * >(this));
1246 
1247         // FIXME  The new attributes are added to any attributes already set,
1248         // they do not replace the old attributes as required by
1249         // XAccessibleEditableText.setAttributes:
1250         for (::sal_Int32 i = 0; i < rAttributeSet.getLength(); ++i)
1251             if (rAttributeSet[i].Name.equalsAsciiL(
1252                     RTL_CONSTASCII_STRINGPARAM("CharColor")))
1253                 m_rEngine.SetAttrib(::TextAttribFontColor(
1254                                         mapFontColor(rAttributeSet[i].Value)),
1255                                     nNumber, static_cast< ::sal_uInt16 >(nBegin),
1256                                     static_cast< ::sal_uInt16 >(nEnd));
1257                     // XXX  numeric overflow (2x)
1258             else if (rAttributeSet[i].Name.equalsAsciiL(
1259                          RTL_CONSTASCII_STRINGPARAM("CharWeight")))
1260                 m_rEngine.SetAttrib(::TextAttribFontWeight(
1261                                         mapFontWeight(rAttributeSet[i].Value)),
1262                                     nNumber, static_cast< ::sal_uInt16 >(nBegin),
1263                                     static_cast< ::sal_uInt16 >(nEnd));
1264                     // XXX  numeric overflow (2x)
1265     }
1266 }
1267 
1268 void Document::changeParagraphSelection(ParagraphImpl * pParagraph,
1269                                         ::sal_Int32 nBegin, ::sal_Int32 nEnd)
1270 {
1271     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1272     {
1273         ::osl::MutexGuard aInternalGuard(GetMutex());
1274         ::sal_uLong nNumber = static_cast< ::sal_uLong >(pParagraph->getNumber());
1275             // XXX  numeric overflow
1276         if (nBegin < 0 || nBegin > nEnd
1277             || nEnd > m_rEngine.GetText(nNumber).Len())
1278             throw ::css::lang::IndexOutOfBoundsException(
1279                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
1280                                     "textwindowaccessibility.cxx:"
1281                                     " Document::changeParagraphSelection")),
1282                 static_cast< ::css::uno::XWeak * >(this));
1283         m_rView.SetSelection(
1284             ::TextSelection(::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nBegin)),
1285                             ::TextPaM(nNumber, static_cast< ::sal_uInt16 >(nEnd))));
1286             // XXX  numeric overflow (2x)
1287     }
1288 }
1289 
1290 ::css::i18n::Boundary
1291 Document::retrieveParagraphLineBoundary( ParagraphImpl const * pParagraph,
1292                                          ::sal_Int32 nIndex, ::sal_Int32 *pLineNo )
1293 {
1294     ::css::i18n::Boundary aBoundary;
1295     aBoundary.startPos = nIndex;
1296     aBoundary.endPos = nIndex;
1297 
1298     ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1299     {
1300         ::osl::MutexGuard aInternalGuard( GetMutex() );
1301         ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1302         if ( nIndex < 0 || nIndex > m_rEngine.GetText( nNumber ).Len() )
1303             throw ::css::lang::IndexOutOfBoundsException(
1304                 ::rtl::OUString(
1305                     RTL_CONSTASCII_USTRINGPARAM(
1306                         "textwindowaccessibility.cxx:"
1307                         " Document::retrieveParagraphLineBoundary" ) ),
1308                 static_cast< ::css::uno::XWeak * >( this ) );
1309         ::sal_Int32 nLineStart = 0;
1310         ::sal_Int32 nLineEnd = 0;
1311         ::sal_uInt16 nLineCount = m_rEngine.GetLineCount( nNumber );
1312         for ( ::sal_uInt16 nLine = 0; nLine < nLineCount; ++nLine )
1313         {
1314             ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1315                 m_rEngine.GetLineLen( nNumber, nLine ) );
1316             nLineStart = nLineEnd;
1317             nLineEnd += nLineLength;
1318             if ( nIndex >= nLineStart && ( ( nLine == nLineCount - 1 ) ? nIndex <= nLineEnd : nIndex < nLineEnd ) )
1319             {
1320                 aBoundary.startPos = nLineStart;
1321                 aBoundary.endPos = nLineEnd;
1322                 if( pLineNo )
1323                     pLineNo[0] = nLine;
1324                 break;
1325             }
1326         }
1327     }
1328 
1329     return aBoundary;
1330 }
1331 
1332 ::css::i18n::Boundary
1333 Document::retrieveParagraphBoundaryOfLine( ParagraphImpl const * pParagraph,
1334                                            ::sal_Int32 nLineNo )
1335 {
1336     ::css::i18n::Boundary aBoundary;
1337     aBoundary.startPos = 0;
1338     aBoundary.endPos = 0;
1339 
1340     ::osl::Guard< ::comphelper::IMutex > aExternalGuard( getExternalLock() );
1341     {
1342         ::osl::MutexGuard aInternalGuard( GetMutex() );
1343         ::sal_uLong nNumber = static_cast< ::sal_uLong >( pParagraph->getNumber() );
1344         if ( nLineNo >= m_rEngine.GetLineCount( nNumber ) )
1345             throw ::css::lang::IndexOutOfBoundsException(
1346                 ::rtl::OUString(
1347                     RTL_CONSTASCII_USTRINGPARAM(
1348                         "textwindowaccessibility.cxx:"
1349                         " Document::retrieveParagraphBoundaryOfLine" ) ),
1350                 static_cast< ::css::uno::XWeak * >( this ) );
1351         ::sal_Int32 nLineStart = 0;
1352         ::sal_Int32 nLineEnd = 0;
1353         for ( ::sal_uInt16 nLine = 0; nLine <= nLineNo; ++nLine )
1354         {
1355             ::sal_Int32 nLineLength = static_cast< ::sal_Int32 >(
1356                 m_rEngine.GetLineLen( nNumber, nLine ) );
1357             nLineStart = nLineEnd;
1358             nLineEnd += nLineLength;
1359         }
1360 
1361         aBoundary.startPos = nLineStart;
1362         aBoundary.endPos = nLineEnd;
1363     }
1364 
1365     return aBoundary;
1366 }
1367 
1368 sal_Int32 Document::retrieveParagraphLineWithCursor( ParagraphImpl const * pParagraph )
1369 {
1370     ::osl::Guard< ::comphelper::IMutex > aExternalGuard(getExternalLock());
1371     ::osl::MutexGuard aInternalGuard(GetMutex());
1372     ::TextSelection const & rSelection = m_rView.GetSelection();
1373     Paragraphs::size_type nNumber = pParagraph->getNumber();
1374     TextPaM aEndPaM( rSelection.GetEnd() );
1375 
1376     return aEndPaM.GetPara() == nNumber
1377         ? m_rView.GetLineNumberOfCursorInSelection() : -1;
1378 }
1379 
1380 
1381 ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet >
1382 Document::retrieveParagraphRelationSet( ParagraphImpl const * pParagraph )
1383 {
1384     ::osl::MutexGuard aInternalGuard( GetMutex() );
1385 
1386     ::utl::AccessibleRelationSetHelper* pRelationSetHelper = new ::utl::AccessibleRelationSetHelper();
1387     ::css::uno::Reference< ::css::accessibility::XAccessibleRelationSet > xSet = pRelationSetHelper;
1388 
1389     Paragraphs::iterator aPara( m_xParagraphs->begin() + pParagraph->getNumber() );
1390 
1391     if ( aPara > m_aVisibleBegin && aPara < m_aVisibleEnd )
1392     {
1393         ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1394         aSequence[0] = getAccessibleChild( aPara - 1 );
1395         ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_FROM, aSequence );
1396         pRelationSetHelper->AddRelation( aRelation );
1397     }
1398 
1399     if ( aPara >= m_aVisibleBegin && aPara < m_aVisibleEnd -1 )
1400     {
1401         ::css::uno::Sequence< ::css::uno::Reference< ::css::uno::XInterface > > aSequence(1);
1402         aSequence[0] = getAccessibleChild( aPara + 1 );
1403         ::css::accessibility::AccessibleRelation aRelation( ::css::accessibility::AccessibleRelationType::CONTENT_FLOWS_TO, aSequence );
1404         pRelationSetHelper->AddRelation( aRelation );
1405     }
1406 
1407     return xSet;
1408 }
1409 
1410 void Document::ProcessWindowEvent( const VclWindowEvent& rVclWindowEvent )
1411 {
1412 	switch ( rVclWindowEvent.GetId() )
1413 	{
1414 		case VCLEVENT_WINDOW_GETFOCUS:
1415 		case VCLEVENT_WINDOW_LOSEFOCUS:
1416 		{
1417 			// #107179# if our parent is a compound control (e.g. MultiLineEdit),
1418 			// suppress the window focus events here
1419 			if ( !m_bCompoundControlChild )
1420 				VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1421 		}
1422 		break;
1423 		default:
1424 			VCLXAccessibleComponent::ProcessWindowEvent( rVclWindowEvent );
1425 	}
1426 }
1427 
1428 // virtual
1429 ::sal_Int32 SAL_CALL Document::getAccessibleChildCount()
1430     throw (::css::uno::RuntimeException)
1431 {
1432     ::comphelper::OExternalLockGuard aGuard(this);
1433     init();
1434     return m_aVisibleEnd - m_aVisibleBegin;
1435 }
1436 
1437 // virtual
1438 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1439 Document::getAccessibleChild(::sal_Int32 i)
1440     throw (::css::lang::IndexOutOfBoundsException,
1441            ::css::uno::RuntimeException)
1442 {
1443     ::comphelper::OExternalLockGuard aGuard(this);
1444     init();
1445     if (i < 0 || i >= m_aVisibleEnd - m_aVisibleBegin)
1446         throw ::css::lang::IndexOutOfBoundsException(
1447             ::rtl::OUString(
1448                 RTL_CONSTASCII_USTRINGPARAM(
1449                     "textwindowaccessibility.cxx:"
1450                     " Document::getAccessibleChild")),
1451             static_cast< ::css::uno::XWeak * >(this));
1452     return getAccessibleChild(m_aVisibleBegin
1453                               + static_cast< Paragraphs::size_type >(i));
1454 }
1455 
1456 // virtual
1457 ::sal_Int16 SAL_CALL Document::getAccessibleRole()
1458     throw (::css::uno::RuntimeException)
1459 {
1460     return ::css::accessibility::AccessibleRole::TEXT_FRAME;
1461 }
1462 
1463 // virtual
1464 ::css::uno::Reference< ::css::accessibility::XAccessible > SAL_CALL
1465 Document::getAccessibleAtPoint(::css::awt::Point const & rPoint)
1466     throw (::css::uno::RuntimeException)
1467 {
1468     ::comphelper::OExternalLockGuard aGuard(this);
1469     init();
1470     if (rPoint.X >= 0
1471         && rPoint.X < m_rView.GetWindow()->GetOutputSizePixel().Width()
1472         && rPoint.Y >= 0 && rPoint.Y < m_nViewHeight)
1473     {
1474         ::sal_Int32 nOffset = m_nViewOffset + rPoint.Y; // XXX  numeric overflow
1475         ::sal_Int32 nPos = m_nViewOffset - m_nVisibleBeginOffset;
1476         for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1477              ++aIt)
1478         {
1479             nPos += aIt->getHeight(); // XXX  numeric overflow
1480             if (nOffset < nPos)
1481                 return getAccessibleChild(aIt);
1482         }
1483     }
1484     return 0;
1485 }
1486 
1487 // virtual
1488 void SAL_CALL Document::disposing()
1489 {
1490     m_aEngineListener.endListening();
1491     m_aViewListener.endListening();
1492     if (m_xParagraphs.get() != 0)
1493         disposeParagraphs();
1494     VCLXAccessibleComponent::disposing();
1495 }
1496 
1497 // virtual
1498 void Document::Notify(::SfxBroadcaster &, ::SfxHint const & rHint)
1499 {
1500     if (rHint.ISA(::TextHint))
1501     {
1502         ::TextHint const & rTextHint
1503               = static_cast< ::TextHint const & >(rHint);
1504         switch (rTextHint.GetId())
1505         {
1506         case TEXT_HINT_PARAINSERTED:
1507         case TEXT_HINT_PARAREMOVED:
1508             // TEXT_HINT_PARAINSERTED and TEXT_HINT_PARAREMOVED are sent at
1509             // "unsafe" times (when the text engine has not yet re-formatted its
1510             // content), so that for example calling ::TextEngine::GetTextHeight
1511             // from within the code that handles TEXT_HINT_PARAINSERTED causes
1512             // trouble within the text engine.  Therefore, these hints are just
1513             // buffered until a following ::TextEngine::FormatDoc causes a
1514             // TEXT_HINT_TEXTFORMATTED to come in:
1515         case TEXT_HINT_FORMATPARA:
1516             // ::TextEngine::FormatDoc sends a sequence of
1517             // TEXT_HINT_FORMATPARAs, followed by an optional
1518             // TEXT_HINT_TEXTHEIGHTCHANGED, followed in all cases by one
1519             // TEXT_HINT_TEXTFORMATTED.  Only the TEXT_HINT_FORMATPARAs contain
1520             // the the numbers of the affected paragraphs, but they are sent
1521             // before the changes are applied.  Therefore, TEXT_HINT_FORMATPARAs
1522             // are just buffered until another hint comes in:
1523             {
1524                 ::osl::MutexGuard aInternalGuard(GetMutex());
1525                 if (!isAlive())
1526                     break;
1527 
1528                 m_aParagraphNotifications.push(rTextHint);
1529                 break;
1530             }
1531         case TEXT_HINT_TEXTFORMATTED:
1532         case TEXT_HINT_TEXTHEIGHTCHANGED:
1533         case TEXT_HINT_MODIFIED:
1534             {
1535                 ::osl::MutexGuard aInternalGuard(GetMutex());
1536                 if (!isAlive())
1537                     break;
1538                 handleParagraphNotifications();
1539                 break;
1540             }
1541         case TEXT_HINT_VIEWSCROLLED:
1542             {
1543                 ::osl::MutexGuard aInternalGuard(GetMutex());
1544                 if (!isAlive())
1545                     break;
1546                 handleParagraphNotifications();
1547 
1548                 ::sal_Int32 nOffset = static_cast< ::sal_Int32 >(
1549                     m_rView.GetStartDocPos().Y());
1550                     // XXX  numeric overflow
1551                 if (nOffset != m_nViewOffset)
1552                 {
1553                     m_nViewOffset = nOffset;
1554 
1555                     Paragraphs::iterator aOldVisibleBegin(
1556                         m_aVisibleBegin);
1557                     Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1558 
1559                     determineVisibleRange();
1560 
1561                     notifyVisibleRangeChanges(aOldVisibleBegin,
1562                                                 aOldVisibleEnd,
1563                                                 m_xParagraphs->end());
1564                 }
1565                 break;
1566             }
1567         case TEXT_HINT_VIEWSELECTIONCHANGED:
1568             {
1569                 ::osl::MutexGuard aInternalGuard(GetMutex());
1570                 if (!isAlive())
1571                     break;
1572 
1573                 if (m_aParagraphNotifications.empty())
1574                 {
1575                     handleSelectionChangeNotification();
1576                 }
1577                 else
1578                 {
1579                     // TEXT_HINT_VIEWSELECTIONCHANGED is sometimes sent at
1580                     // "unsafe" times (when the text engine has not yet re-
1581                     // formatted its content), so that for example calling
1582                     // ::TextEngine::GetTextHeight from within the code that
1583                     // handles a previous TEXT_HINT_PARAINSERTED causes
1584                     // trouble within the text engine.  Therefore, these
1585                     // hints are just buffered (along with
1586                     // TEXT_HINT_PARAINSERTED/REMOVED/FORMATPARA) until a
1587                     // following ::TextEngine::FormatDoc causes a
1588                     // TEXT_HINT_TEXTFORMATTED to come in:
1589                     m_bSelectionChangedNotification = true;
1590                 }
1591                 break;
1592             }
1593         }
1594     }
1595 }
1596 
1597 IMPL_LINK(Document, WindowEventHandler, ::VclSimpleEvent *, pEvent)
1598 {
1599     switch (pEvent->GetId())
1600     {
1601     case VCLEVENT_WINDOW_RESIZE:
1602         {
1603             ::osl::MutexGuard aInternalGuard(GetMutex());
1604             if (!isAlive())
1605                 break;
1606 
1607             ::sal_Int32 nHeight = static_cast< ::sal_Int32 >(
1608                 m_rView.GetWindow()->GetOutputSizePixel().Height());
1609                 // XXX  numeric overflow
1610             if (nHeight != m_nViewHeight)
1611             {
1612                 m_nViewHeight = nHeight;
1613 
1614                 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1615                 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1616 
1617                 determineVisibleRange();
1618 
1619                 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1620                                             m_xParagraphs->end());
1621             }
1622             break;
1623         }
1624     case VCLEVENT_WINDOW_GETFOCUS:
1625         {
1626             ::osl::MutexGuard aInternalGuard(GetMutex());
1627             if (!isAlive())
1628                 break;
1629 
1630             if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1631             {
1632                 ::rtl::Reference< ParagraphImpl > xParagraph(
1633                     getParagraph(m_aFocused));
1634                 if (xParagraph.is())
1635                     xParagraph->notifyEvent(
1636                         ::css::accessibility::AccessibleEventId::
1637                         STATE_CHANGED,
1638                         ::css::uno::Any(),
1639                         ::css::uno::makeAny(
1640                             ::css::accessibility::AccessibleStateType::
1641                             FOCUSED));
1642             }
1643             break;
1644         }
1645     case VCLEVENT_WINDOW_LOSEFOCUS:
1646         {
1647             ::osl::MutexGuard aInternalGuard(GetMutex());
1648             if (!isAlive())
1649                 break;
1650 
1651             if (m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
1652             {
1653                 ::rtl::Reference< ParagraphImpl > xParagraph(
1654                     getParagraph(m_aFocused));
1655                 if (xParagraph.is())
1656                     xParagraph->notifyEvent(
1657                         ::css::accessibility::AccessibleEventId::
1658                         STATE_CHANGED,
1659                         ::css::uno::makeAny(
1660                             ::css::accessibility::AccessibleStateType::
1661                             FOCUSED),
1662                         ::css::uno::Any());
1663             }
1664             break;
1665         }
1666     }
1667     return 0;
1668 }
1669 
1670 void Document::init()
1671 {
1672     if (m_xParagraphs.get() == 0)
1673     {
1674         ::sal_uLong nCount = m_rEngine.GetParagraphCount();
1675         ::std::auto_ptr< Paragraphs > p(new Paragraphs);
1676         p->reserve(static_cast< Paragraphs::size_type >(nCount));
1677             // numeric overflow is harmless here
1678         for (::sal_uLong i = 0; i < nCount; ++i)
1679             p->push_back(ParagraphInfo(static_cast< ::sal_Int32 >(
1680                                            m_rEngine.GetTextHeight(i))));
1681                 // XXX  numeric overflow
1682         m_nViewOffset = static_cast< ::sal_Int32 >(
1683             m_rView.GetStartDocPos().Y()); // XXX  numeric overflow
1684         m_nViewHeight = static_cast< ::sal_Int32 >(
1685             m_rView.GetWindow()->GetOutputSizePixel().Height());
1686             // XXX  numeric overflow
1687         m_xParagraphs = p;
1688         determineVisibleRange();
1689         m_nSelectionFirstPara = -1;
1690         m_nSelectionFirstPos = -1;
1691         m_nSelectionLastPara = -1;
1692         m_nSelectionLastPos = -1;
1693         m_aFocused = m_xParagraphs->end();
1694         m_bSelectionChangedNotification = false;
1695         m_aEngineListener.startListening(m_rEngine);
1696         m_aViewListener.startListening(*m_rView.GetWindow());
1697     }
1698 }
1699 
1700 ::rtl::Reference< ParagraphImpl >
1701 Document::getParagraph(Paragraphs::iterator const & rIt)
1702 {
1703     return static_cast< ParagraphImpl * >(
1704         ::css::uno::Reference< ::css::accessibility::XAccessible >(
1705             rIt->getParagraph()).get());
1706 }
1707 
1708 ::css::uno::Reference< ::css::accessibility::XAccessible >
1709 Document::getAccessibleChild(Paragraphs::iterator const & rIt)
1710 {
1711     ::css::uno::Reference< ::css::accessibility::XAccessible > xParagraph(
1712         rIt->getParagraph());
1713     if (!xParagraph.is())
1714     {
1715         xParagraph = new Paragraph(this, rIt - m_xParagraphs->begin());
1716         rIt->setParagraph(xParagraph);
1717     }
1718     return xParagraph;
1719 }
1720 
1721 void Document::determineVisibleRange()
1722 {
1723     m_aVisibleBegin = m_xParagraphs->end();
1724     m_aVisibleEnd = m_aVisibleBegin;
1725     ::sal_Int32 nPos = 0;
1726     for (Paragraphs::iterator aIt = m_xParagraphs->begin();;)
1727     {
1728         if (aIt == m_xParagraphs->end())
1729         {
1730             m_nVisibleBeginOffset = 0;
1731             break;
1732         }
1733         ::sal_Int32 nOldPos = nPos;
1734         nPos += aIt->getHeight(); // XXX  numeric overflow
1735         if (m_aVisibleBegin == m_xParagraphs->end() && nPos >= m_nViewOffset)
1736         {
1737             m_aVisibleBegin = aIt;
1738             m_nVisibleBeginOffset = m_nViewOffset - nOldPos;
1739         }
1740         ++aIt;
1741         if (m_aVisibleBegin != m_xParagraphs->end()
1742             && (aIt == m_xParagraphs->end()
1743                 || nPos >= m_nViewOffset + m_nViewHeight))
1744             // XXX  numeric overflow
1745         {
1746             m_aVisibleEnd = aIt;
1747             break;
1748         }
1749     }
1750 }
1751 
1752 void Document::notifyVisibleRangeChanges(
1753     Paragraphs::iterator const & rOldVisibleBegin,
1754     Paragraphs::iterator const & rOldVisibleEnd,
1755     Paragraphs::iterator const & rInserted)
1756 {
1757     // XXX  Replace this code that determines which paragraphs have changed from
1758     // invisible to visible or vice versa with a better algorithm.
1759     {for (Paragraphs::iterator aIt(rOldVisibleBegin); aIt != rOldVisibleEnd;
1760           ++aIt)
1761         if (aIt != rInserted
1762             && (aIt < m_aVisibleBegin || aIt >= m_aVisibleEnd))
1763             NotifyAccessibleEvent(
1764                 ::css::accessibility::AccessibleEventId::
1765                 CHILD,
1766                 ::css::uno::makeAny(getAccessibleChild(aIt)),
1767                 ::css::uno::Any());
1768     }
1769     {for (Paragraphs::iterator aIt(m_aVisibleBegin); aIt != m_aVisibleEnd;
1770           ++aIt)
1771         if (aIt == rInserted
1772             || aIt < rOldVisibleBegin || aIt >= rOldVisibleEnd)
1773             NotifyAccessibleEvent(
1774                 ::css::accessibility::AccessibleEventId::
1775                 CHILD,
1776                 ::css::uno::Any(),
1777                 ::css::uno::makeAny(getAccessibleChild(aIt)));
1778     }
1779 }
1780 
1781 void
1782 Document::changeParagraphText(::sal_uLong nNumber, ::sal_uInt16 nBegin, ::sal_uInt16 nEnd,
1783                               bool bCut, bool bPaste,
1784                               ::rtl::OUString const & rText)
1785 {
1786     m_rView.SetSelection(::TextSelection(::TextPaM(nNumber, nBegin),
1787                                          ::TextPaM(nNumber, nEnd)));
1788     if (bCut)
1789         m_rView.Cut();
1790     else if (nBegin != nEnd)
1791         m_rView.DeleteSelected();
1792     if (bPaste)
1793         m_rView.Paste();
1794     else if (rText.getLength() != 0)
1795         m_rView.InsertText(rText);
1796 }
1797 
1798 void Document::handleParagraphNotifications()
1799 {
1800     while (!m_aParagraphNotifications.empty())
1801     {
1802         ::TextHint aHint(m_aParagraphNotifications.front());
1803         m_aParagraphNotifications.pop();
1804         switch (aHint.GetId())
1805         {
1806         case TEXT_HINT_PARAINSERTED:
1807             {
1808                 ::sal_uLong n = aHint.GetValue();
1809                 OSL_ENSURE(n <= m_xParagraphs->size(),
1810                            "bad TEXT_HINT_PARAINSERTED event");
1811 
1812                 // Save the values of old iterators (the iterators themselves
1813                 // will get invalidated), and adjust the old values so that they
1814                 // reflect the insertion of the new paragraph:
1815                 Paragraphs::size_type nOldVisibleBegin
1816                     = m_aVisibleBegin - m_xParagraphs->begin();
1817                 Paragraphs::size_type nOldVisibleEnd
1818                     = m_aVisibleEnd - m_xParagraphs->begin();
1819                 Paragraphs::size_type nOldFocused
1820                     = m_aFocused - m_xParagraphs->begin();
1821                 if (n <= nOldVisibleBegin)
1822                     ++nOldVisibleBegin; // XXX  numeric overflow
1823                 if (n <= nOldVisibleEnd)
1824                     ++nOldVisibleEnd; // XXX  numeric overflow
1825                 if (n <= nOldFocused)
1826                     ++nOldFocused; // XXX  numeric overflow
1827                 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionFirstPara)
1828                     ++m_nSelectionFirstPara; // XXX  numeric overflow
1829                 if (sal::static_int_cast<sal_Int32>(n) <= m_nSelectionLastPara)
1830                     ++m_nSelectionLastPara; // XXX  numeric overflow
1831 
1832                 Paragraphs::iterator aIns(
1833                     m_xParagraphs->insert(
1834                         m_xParagraphs->begin() + n,
1835                         ParagraphInfo(static_cast< ::sal_Int32 >(
1836                                           m_rEngine.GetTextHeight(n)))));
1837                     // XXX  numeric overflow (2x)
1838 
1839                 determineVisibleRange();
1840                 m_aFocused = m_xParagraphs->begin() + nOldFocused;
1841 
1842                 for (Paragraphs::iterator aIt(aIns);;)
1843                 {
1844                     ++aIt;
1845                     if (aIt == m_xParagraphs->end())
1846                         break;
1847                     ::rtl::Reference< ParagraphImpl > xParagraph(
1848                         getParagraph(aIt));
1849                     if (xParagraph.is())
1850                         xParagraph->numberChanged(true);
1851                 }
1852 
1853                 notifyVisibleRangeChanges(
1854                     m_xParagraphs->begin() + nOldVisibleBegin,
1855                     m_xParagraphs->begin() + nOldVisibleEnd, aIns);
1856                 break;
1857             }
1858         case TEXT_HINT_PARAREMOVED:
1859             {
1860                 ::sal_uLong n = aHint.GetValue();
1861                 if (n == TEXT_PARA_ALL)
1862                 {
1863                     {for (Paragraphs::iterator aIt(m_aVisibleBegin);
1864                           aIt != m_aVisibleEnd; ++aIt)
1865                         NotifyAccessibleEvent(
1866                             ::css::accessibility::AccessibleEventId::
1867                             CHILD,
1868                             ::css::uno::makeAny(getAccessibleChild(aIt)),
1869                             ::css::uno::Any());
1870                     }
1871                     disposeParagraphs();
1872                     m_xParagraphs->clear();
1873                     determineVisibleRange();
1874                     m_nSelectionFirstPara = -1;
1875                     m_nSelectionFirstPos = -1;
1876                     m_nSelectionLastPara = -1;
1877                     m_nSelectionLastPos = -1;
1878                     m_aFocused = m_xParagraphs->end();
1879                 }
1880                 else
1881                 {
1882                     OSL_ENSURE(n < m_xParagraphs->size(),
1883                                "Bad TEXT_HINT_PARAREMOVED event");
1884 
1885                     Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1886                         // numeric overflow cannot occur
1887 
1888                     // Save the values of old iterators (the iterators
1889                     // themselves will get invalidated), and adjust the old
1890                     // values so that they reflect the removal of the paragraph:
1891                     Paragraphs::size_type nOldVisibleBegin
1892                         = m_aVisibleBegin - m_xParagraphs->begin();
1893                     Paragraphs::size_type nOldVisibleEnd
1894                         = m_aVisibleEnd - m_xParagraphs->begin();
1895                     bool bWasVisible
1896                         = nOldVisibleBegin <= n && n < nOldVisibleEnd;
1897                     Paragraphs::size_type nOldFocused
1898                         = m_aFocused - m_xParagraphs->begin();
1899                     bool bWasFocused = aIt == m_aFocused;
1900                     if (n < nOldVisibleBegin)
1901                         --nOldVisibleBegin;
1902                     if (n < nOldVisibleEnd)
1903                         --nOldVisibleEnd;
1904                     if (n < nOldFocused)
1905                         --nOldFocused;
1906                     if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionFirstPara)
1907                         --m_nSelectionFirstPara;
1908                     else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionFirstPara)
1909                     {
1910                         if (m_nSelectionFirstPara == m_nSelectionLastPara)
1911                         {
1912                             m_nSelectionFirstPara = -1;
1913                             m_nSelectionFirstPos = -1;
1914                             m_nSelectionLastPara = -1;
1915                             m_nSelectionLastPos = -1;
1916                         }
1917                         else
1918                         {
1919                             ++m_nSelectionFirstPara;
1920                             m_nSelectionFirstPos = 0;
1921                         }
1922                     }
1923                     if (sal::static_int_cast<sal_Int32>(n) < m_nSelectionLastPara)
1924                         --m_nSelectionLastPara;
1925                     else if (sal::static_int_cast<sal_Int32>(n) == m_nSelectionLastPara)
1926                     {
1927                         OSL_ENSURE(m_nSelectionFirstPara < m_nSelectionLastPara,
1928                                    "logic error");
1929                         --m_nSelectionLastPara;
1930                         m_nSelectionLastPos = 0x7FFFFFFF;
1931                     }
1932 
1933                     ::css::uno::Reference< ::css::accessibility::XAccessible >
1934                           xStrong;
1935                     if (bWasVisible)
1936                         xStrong = getAccessibleChild(aIt);
1937                     ::css::uno::WeakReference<
1938                           ::css::accessibility::XAccessible > xWeak(
1939                               aIt->getParagraph());
1940                     aIt = m_xParagraphs->erase(aIt);
1941 
1942                     determineVisibleRange();
1943                     m_aFocused = bWasFocused ? m_xParagraphs->end()
1944                         : m_xParagraphs->begin() + nOldFocused;
1945 
1946                     for (; aIt != m_xParagraphs->end(); ++aIt)
1947                     {
1948                         ::rtl::Reference< ParagraphImpl > xParagraph(
1949                             getParagraph(aIt));
1950                         if (xParagraph.is())
1951                             xParagraph->numberChanged(false);
1952                     }
1953 
1954                     if (bWasVisible)
1955                         NotifyAccessibleEvent(
1956                             ::css::accessibility::AccessibleEventId::
1957                             CHILD,
1958                             ::css::uno::makeAny(getAccessibleChild(aIt)),
1959                             ::css::uno::Any());
1960 
1961                     ::css::uno::Reference< ::css::lang::XComponent > xComponent(
1962                         xWeak.get(), ::css::uno::UNO_QUERY);
1963                     if (xComponent.is())
1964                         xComponent->dispose();
1965 
1966                     notifyVisibleRangeChanges(
1967                         m_xParagraphs->begin() + nOldVisibleBegin,
1968                         m_xParagraphs->begin() + nOldVisibleEnd,
1969                         m_xParagraphs->end());
1970                 }
1971                 break;
1972             }
1973         case TEXT_HINT_FORMATPARA:
1974             {
1975                 ::sal_uLong n = aHint.GetValue();
1976                 OSL_ENSURE(n < m_xParagraphs->size(),
1977                            "Bad TEXT_HINT_FORMATPARA event");
1978 
1979                 (*m_xParagraphs)[static_cast< Paragraphs::size_type >(n)].
1980                     changeHeight(static_cast< ::sal_Int32 >(
1981                                      m_rEngine.GetTextHeight(n)));
1982                     // XXX  numeric overflow
1983                 Paragraphs::iterator aOldVisibleBegin(m_aVisibleBegin);
1984                 Paragraphs::iterator aOldVisibleEnd(m_aVisibleEnd);
1985                 determineVisibleRange();
1986                 notifyVisibleRangeChanges(aOldVisibleBegin, aOldVisibleEnd,
1987                                           m_xParagraphs->end());
1988 
1989                 if (n < m_xParagraphs->size())
1990                 {
1991                     Paragraphs::iterator aIt(m_xParagraphs->begin() + n);
1992                     ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
1993                     if (xParagraph.is())
1994                         xParagraph->textChanged();
1995                 }
1996                 break;
1997             }
1998         default:
1999             OSL_ENSURE(false, "bad buffered hint");
2000             break;
2001         }
2002     }
2003     if (m_bSelectionChangedNotification)
2004     {
2005         m_bSelectionChangedNotification = false;
2006         handleSelectionChangeNotification();
2007     }
2008 }
2009 
2010 void Document::handleSelectionChangeNotification()
2011 {
2012     ::TextSelection const & rSelection = m_rView.GetSelection();
2013     OSL_ENSURE(rSelection.GetStart().GetPara() < m_xParagraphs->size()
2014                && rSelection.GetEnd().GetPara() < m_xParagraphs->size(),
2015                "bad TEXT_HINT_VIEWSELECTIONCHANGED event");
2016     ::sal_Int32 nNewFirstPara
2017           = static_cast< ::sal_Int32 >(rSelection.GetStart().GetPara());
2018     ::sal_Int32 nNewFirstPos
2019           = static_cast< ::sal_Int32 >(rSelection.GetStart().GetIndex());
2020         // XXX  numeric overflow
2021     ::sal_Int32 nNewLastPara
2022           = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetPara());
2023     ::sal_Int32 nNewLastPos
2024           = static_cast< ::sal_Int32 >(rSelection.GetEnd().GetIndex());
2025         // XXX  numeric overflow
2026 
2027     // Lose focus:
2028     Paragraphs::iterator aIt(m_xParagraphs->begin() + nNewLastPara);
2029     if (m_aFocused != m_xParagraphs->end() && m_aFocused != aIt
2030         && m_aFocused >= m_aVisibleBegin && m_aFocused < m_aVisibleEnd)
2031     {
2032         ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(m_aFocused));
2033         if (xParagraph.is())
2034             xParagraph->notifyEvent(
2035                 ::css::accessibility::AccessibleEventId::
2036                 STATE_CHANGED,
2037                 ::css::uno::makeAny(
2038                     ::css::accessibility::AccessibleStateType::FOCUSED),
2039                 ::css::uno::Any());
2040     }
2041 
2042     // Gain focus and update cursor position:
2043     if (aIt >= m_aVisibleBegin && aIt < m_aVisibleEnd
2044         && (aIt != m_aFocused
2045             || nNewLastPara != m_nSelectionLastPara
2046             || nNewLastPos != m_nSelectionLastPos))
2047     {
2048         ::rtl::Reference< ParagraphImpl > xParagraph(getParagraph(aIt));
2049         if (xParagraph.is())
2050         {
2051             if (aIt != m_aFocused)
2052                 xParagraph->notifyEvent(
2053                     ::css::accessibility::AccessibleEventId::
2054                     STATE_CHANGED,
2055                     ::css::uno::Any(),
2056                     ::css::uno::makeAny(
2057                         ::css::accessibility::AccessibleStateType::FOCUSED));
2058             if (nNewLastPara != m_nSelectionLastPara
2059                 || nNewLastPos != m_nSelectionLastPos)
2060                 xParagraph->notifyEvent(
2061                     ::css::accessibility::AccessibleEventId::
2062                     CARET_CHANGED,
2063                     ::css::uno::makeAny< ::sal_Int32 >(
2064                         nNewLastPara == m_nSelectionLastPara
2065                         ? m_nSelectionLastPos : 0),
2066                     ::css::uno::makeAny(nNewLastPos));
2067         }
2068     }
2069     m_aFocused = aIt;
2070 
2071     // Update both old and new selection.  (Regardless of how the two selections
2072     // look like, there will always be two ranges to the left and right of the
2073     // overlap---the overlap and/or the range to the right of it possibly being
2074     // empty.  Only for these two ranges notifications have to be sent.)
2075 
2076     TextPaM aOldTextStart( static_cast< sal_uLong >( m_nSelectionFirstPara ), static_cast< sal_uInt16 >( m_nSelectionFirstPos ) );
2077     TextPaM aOldTextEnd( static_cast< sal_uLong >( m_nSelectionLastPara ), static_cast< sal_uInt16 >( m_nSelectionLastPos ) );
2078     TextPaM aNewTextStart( static_cast< sal_uLong >( nNewFirstPara ), static_cast< sal_uInt16 >( nNewFirstPos ) );
2079     TextPaM aNewTextEnd( static_cast< sal_uLong >( nNewLastPara ), static_cast< sal_uInt16 >( nNewLastPos ) );
2080 
2081     // justify selections
2082     justifySelection( aOldTextStart, aOldTextEnd );
2083     justifySelection( aNewTextStart, aNewTextEnd );
2084 
2085     sal_Int32 nFirst1;
2086     sal_Int32 nLast1;
2087     sal_Int32 nFirst2;
2088     sal_Int32 nLast2;
2089 
2090     if ( m_nSelectionFirstPara == -1 )
2091     {
2092         // old selection not initialized yet => notify events only for new selection (if not empty)
2093         nFirst1 = aNewTextStart.GetPara();
2094         nLast1 = aNewTextEnd.GetPara() + ( aNewTextStart != aNewTextEnd ? 1 : 0 );
2095         nFirst2 = 0;
2096         nLast2 = 0;
2097     }
2098     else if ( aOldTextStart == aOldTextEnd && aNewTextStart == aNewTextEnd )
2099     {
2100         // old an new selection empty => no events
2101         nFirst1 = 0;
2102         nLast1 = 0;
2103         nFirst2 = 0;
2104         nLast2 = 0;
2105     }
2106     else if ( aOldTextStart != aOldTextEnd && aNewTextStart == aNewTextEnd )
2107     {
2108         // old selection not empty + new selection empty => notify events only for old selection
2109         nFirst1 = aOldTextStart.GetPara();
2110         nLast1 = aOldTextEnd.GetPara() + 1;
2111         nFirst2 = 0;
2112         nLast2 = 0;
2113     }
2114     else if ( aOldTextStart == aOldTextEnd && aNewTextStart != aNewTextEnd )
2115     {
2116         // old selection empty + new selection not empty => notify events only for new selection
2117         nFirst1 = aNewTextStart.GetPara();
2118         nLast1 = aNewTextEnd.GetPara() + 1;
2119         nFirst2 = 0;
2120         nLast2 = 0;
2121     }
2122     else
2123     {
2124         // old and new selection not empty => notify events for the two ranges left and right of the overlap
2125         ::std::vector< TextPaM > aTextPaMs(4);
2126         aTextPaMs[0] = aOldTextStart;
2127         aTextPaMs[1] = aOldTextEnd;
2128         aTextPaMs[2] = aNewTextStart;
2129         aTextPaMs[3] = aNewTextEnd;
2130         ::std::sort( aTextPaMs.begin(), aTextPaMs.end() );
2131 
2132         nFirst1 = aTextPaMs[0].GetPara();
2133         nLast1 = aTextPaMs[1].GetPara() + ( aTextPaMs[0] != aTextPaMs[1] ? 1 : 0 );
2134 
2135         nFirst2 = aTextPaMs[2].GetPara();
2136         nLast2 = aTextPaMs[3].GetPara() + ( aTextPaMs[2] != aTextPaMs[3] ? 1 : 0 );
2137 
2138         // adjust overlapping ranges
2139         if ( nLast1 > nFirst2 )
2140             nLast1 = nFirst2;
2141     }
2142 
2143     // notify selection changes
2144     notifySelectionChange( nFirst1, nLast1 );
2145     notifySelectionChange( nFirst2, nLast2 );
2146 
2147     m_nSelectionFirstPara = nNewFirstPara;
2148     m_nSelectionFirstPos = nNewFirstPos;
2149     m_nSelectionLastPara = nNewLastPara;
2150     m_nSelectionLastPos = nNewLastPos;
2151 }
2152 
2153 void Document::notifySelectionChange( sal_Int32 nFirst, sal_Int32 nLast )
2154 {
2155     if ( nFirst < nLast )
2156     {
2157         Paragraphs::iterator aEnd( ::std::min( m_xParagraphs->begin() + nLast, m_aVisibleEnd ) );
2158         for ( Paragraphs::iterator aIt = ::std::max( m_xParagraphs->begin() + nFirst, m_aVisibleBegin ); aIt < aEnd; ++aIt )
2159         {
2160             ::rtl::Reference< ParagraphImpl > xParagraph( getParagraph( aIt ) );
2161             if ( xParagraph.is() )
2162             {
2163                 xParagraph->notifyEvent(
2164                     ::css::accessibility::AccessibleEventId::SELECTION_CHANGED,
2165                     ::css::uno::Any(), ::css::uno::Any() );
2166                 xParagraph->notifyEvent(
2167                     ::css::accessibility::AccessibleEventId::TEXT_SELECTION_CHANGED,
2168                     ::css::uno::Any(), ::css::uno::Any() );
2169             }
2170         }
2171     }
2172 }
2173 
2174 void Document::justifySelection( TextPaM& rTextStart, TextPaM& rTextEnd )
2175 {
2176     if ( rTextStart > rTextEnd )
2177     {
2178         TextPaM aTextPaM( rTextStart );
2179         rTextStart = rTextEnd;
2180         rTextEnd = aTextPaM;
2181     }
2182 }
2183 
2184 void Document::disposeParagraphs()
2185 {
2186     for (Paragraphs::iterator aIt(m_xParagraphs->begin());
2187          aIt != m_xParagraphs->end(); ++aIt)
2188     {
2189         ::css::uno::Reference< ::css::lang::XComponent > xComponent(
2190             aIt->getParagraph().get(), ::css::uno::UNO_QUERY);
2191         if (xComponent.is())
2192             xComponent->dispose();
2193     }
2194 }
2195 
2196 // static
2197 ::css::uno::Any Document::mapFontColor(::Color const & rColor)
2198 {
2199     return ::css::uno::makeAny(
2200         static_cast< ::sal_Int32 >(COLORDATA_RGB(rColor.GetColor())));
2201         // FIXME  keep transparency?
2202 }
2203 
2204 // static
2205 ::Color Document::mapFontColor(::css::uno::Any const & rColor)
2206 {
2207     ::sal_Int32 nColor = 0;
2208     rColor >>= nColor;
2209     return ::Color(static_cast< ::ColorData >(nColor));
2210 }
2211 
2212 // static
2213 ::css::uno::Any Document::mapFontWeight(::FontWeight nWeight)
2214 {
2215     // Map from ::FontWeight to ::css:awt::FontWeight, depends on order of
2216     // elements in ::FontWeight (vcl/vclenum.hxx):
2217     static float const aWeight[]
2218         = { ::css::awt::FontWeight::DONTKNOW, // WEIGHT_DONTKNOW
2219             ::css::awt::FontWeight::THIN, // WEIGHT_THIN
2220             ::css::awt::FontWeight::ULTRALIGHT, // WEIGHT_ULTRALIGHT
2221             ::css::awt::FontWeight::LIGHT, // WEIGHT_LIGHT
2222             ::css::awt::FontWeight::SEMILIGHT, // WEIGHT_SEMILIGHT
2223             ::css::awt::FontWeight::NORMAL, // WEIGHT_NORMAL
2224             ::css::awt::FontWeight::NORMAL, // WEIGHT_MEDIUM
2225             ::css::awt::FontWeight::SEMIBOLD, // WEIGHT_SEMIBOLD
2226             ::css::awt::FontWeight::BOLD, // WEIGHT_BOLD
2227             ::css::awt::FontWeight::ULTRABOLD, // WEIGHT_ULTRABOLD
2228             ::css::awt::FontWeight::BLACK }; // WEIGHT_BLACK
2229     return ::css::uno::makeAny(aWeight[nWeight]);
2230 }
2231 
2232 // static
2233 ::FontWeight Document::mapFontWeight(::css::uno::Any const & rWeight)
2234 {
2235     float nWeight = ::css::awt::FontWeight::NORMAL;
2236     rWeight >>= nWeight;
2237     return nWeight <= ::css::awt::FontWeight::DONTKNOW ? WEIGHT_DONTKNOW
2238         : nWeight <= ::css::awt::FontWeight::THIN ? WEIGHT_THIN
2239         : nWeight <= ::css::awt::FontWeight::ULTRALIGHT ? WEIGHT_ULTRALIGHT
2240         : nWeight <= ::css::awt::FontWeight::LIGHT ? WEIGHT_LIGHT
2241         : nWeight <= ::css::awt::FontWeight::SEMILIGHT ? WEIGHT_SEMILIGHT
2242         : nWeight <= ::css::awt::FontWeight::NORMAL ? WEIGHT_NORMAL
2243         : nWeight <= ::css::awt::FontWeight::SEMIBOLD ? WEIGHT_SEMIBOLD
2244         : nWeight <= ::css::awt::FontWeight::BOLD ? WEIGHT_BOLD
2245         : nWeight <= ::css::awt::FontWeight::ULTRABOLD ? WEIGHT_ULTRABOLD
2246         : WEIGHT_BLACK;
2247 }
2248 
2249 }
2250 
2251