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