xref: /AOO41X/main/sdext/source/presenter/PresenterTextView.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir #include "precompiled_sdext.hxx"
29*cdf0e10cSrcweir 
30*cdf0e10cSrcweir #include "PresenterTextView.hxx"
31*cdf0e10cSrcweir #include "PresenterCanvasHelper.hxx"
32*cdf0e10cSrcweir #include "PresenterGeometryHelper.hxx"
33*cdf0e10cSrcweir #include "PresenterTimer.hxx"
34*cdf0e10cSrcweir 
35*cdf0e10cSrcweir #include <cmath>
36*cdf0e10cSrcweir 
37*cdf0e10cSrcweir #include <com/sun/star/accessibility/AccessibleTextType.hpp>
38*cdf0e10cSrcweir #include <com/sun/star/container/XEnumerationAccess.hpp>
39*cdf0e10cSrcweir #include <com/sun/star/i18n/CharType.hpp>
40*cdf0e10cSrcweir #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
41*cdf0e10cSrcweir #include <com/sun/star/i18n/CTLScriptType.hpp>
42*cdf0e10cSrcweir #include <com/sun/star/i18n/ScriptDirection.hpp>
43*cdf0e10cSrcweir #include <com/sun/star/i18n/WordType.hpp>
44*cdf0e10cSrcweir #include <com/sun/star/rendering/CompositeOperation.hpp>
45*cdf0e10cSrcweir #include <com/sun/star/rendering/TextDirection.hpp>
46*cdf0e10cSrcweir #include <com/sun/star/text/WritingMode2.hpp>
47*cdf0e10cSrcweir #include <boost/bind.hpp>
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir using namespace ::com::sun::star;
50*cdf0e10cSrcweir using namespace ::com::sun::star::accessibility;
51*cdf0e10cSrcweir using namespace ::com::sun::star::uno;
52*cdf0e10cSrcweir 
53*cdf0e10cSrcweir #define A2S(pString) (::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(pString)))
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir const static sal_Int64 CaretBlinkIntervall = 500 * 1000 * 1000;
56*cdf0e10cSrcweir 
57*cdf0e10cSrcweir //#define SHOW_CHARACTER_BOXES
58*cdf0e10cSrcweir 
59*cdf0e10cSrcweir namespace {
60*cdf0e10cSrcweir     sal_Int32 Signum (const sal_Int32 nValue)
61*cdf0e10cSrcweir     {
62*cdf0e10cSrcweir         if (nValue < 0)
63*cdf0e10cSrcweir             return -1;
64*cdf0e10cSrcweir         else if (nValue > 0)
65*cdf0e10cSrcweir             return +1;
66*cdf0e10cSrcweir         else
67*cdf0e10cSrcweir             return 0;
68*cdf0e10cSrcweir     }
69*cdf0e10cSrcweir }
70*cdf0e10cSrcweir 
71*cdf0e10cSrcweir namespace sdext { namespace presenter {
72*cdf0e10cSrcweir 
73*cdf0e10cSrcweir 
74*cdf0e10cSrcweir //===== PresenterTextView =====================================================
75*cdf0e10cSrcweir 
76*cdf0e10cSrcweir PresenterTextView::PresenterTextView (
77*cdf0e10cSrcweir     const Reference<XComponentContext>& rxContext,
78*cdf0e10cSrcweir     const Reference<rendering::XCanvas>& rxCanvas,
79*cdf0e10cSrcweir     const ::boost::function<void(const ::css::awt::Rectangle&)>& rInvalidator)
80*cdf0e10cSrcweir     : mxCanvas(rxCanvas),
81*cdf0e10cSrcweir       mbDoOuput(true),
82*cdf0e10cSrcweir       mxBreakIterator(),
83*cdf0e10cSrcweir       mxScriptTypeDetector(),
84*cdf0e10cSrcweir       maLocation(0,0),
85*cdf0e10cSrcweir       maSize(0,0),
86*cdf0e10cSrcweir       mpFont(),
87*cdf0e10cSrcweir       maParagraphs(),
88*cdf0e10cSrcweir       mpCaret(new PresenterTextCaret(
89*cdf0e10cSrcweir           ::boost::bind(&PresenterTextView::GetCaretBounds, this, _1, _2),
90*cdf0e10cSrcweir           rInvalidator)),
91*cdf0e10cSrcweir       mnLeftOffset(0),
92*cdf0e10cSrcweir       mnTopOffset(0),
93*cdf0e10cSrcweir       maInvalidator(rInvalidator),
94*cdf0e10cSrcweir       mbIsFormatPending(false),
95*cdf0e10cSrcweir       mnCharacterCount(-1),
96*cdf0e10cSrcweir       maTextChangeBroadcaster()
97*cdf0e10cSrcweir {
98*cdf0e10cSrcweir     Reference<lang::XMultiComponentFactory> xFactory (
99*cdf0e10cSrcweir         rxContext->getServiceManager(), UNO_QUERY);
100*cdf0e10cSrcweir     if ( ! xFactory.is())
101*cdf0e10cSrcweir         return;
102*cdf0e10cSrcweir 
103*cdf0e10cSrcweir     // Create the break iterator that we use to break text into lines.
104*cdf0e10cSrcweir     mxBreakIterator = Reference<i18n::XBreakIterator>(
105*cdf0e10cSrcweir         xFactory->createInstanceWithContext(
106*cdf0e10cSrcweir             A2S("com.sun.star.i18n.BreakIterator"),
107*cdf0e10cSrcweir             rxContext),
108*cdf0e10cSrcweir         UNO_QUERY_THROW);
109*cdf0e10cSrcweir 
110*cdf0e10cSrcweir     // Create the script type detector that is used to split paragraphs into
111*cdf0e10cSrcweir     // portions of the same text direction.
112*cdf0e10cSrcweir     mxScriptTypeDetector = Reference<i18n::XScriptTypeDetector>(
113*cdf0e10cSrcweir         xFactory->createInstanceWithContext(
114*cdf0e10cSrcweir             A2S("com.sun.star.i18n.ScriptTypeDetector"),
115*cdf0e10cSrcweir             rxContext),
116*cdf0e10cSrcweir         UNO_QUERY_THROW);
117*cdf0e10cSrcweir }
118*cdf0e10cSrcweir 
119*cdf0e10cSrcweir 
120*cdf0e10cSrcweir 
121*cdf0e10cSrcweir 
122*cdf0e10cSrcweir PresenterTextView::PresenterTextView (
123*cdf0e10cSrcweir     const Reference<XComponentContext>& rxContext,
124*cdf0e10cSrcweir     const Reference<rendering::XCanvas>& rxCanvas)
125*cdf0e10cSrcweir     : mxCanvas(rxCanvas),
126*cdf0e10cSrcweir       mbDoOuput(false),
127*cdf0e10cSrcweir       mxBreakIterator(),
128*cdf0e10cSrcweir       mxScriptTypeDetector(),
129*cdf0e10cSrcweir       maLocation(0,0),
130*cdf0e10cSrcweir       maSize(0,0),
131*cdf0e10cSrcweir       mpFont(),
132*cdf0e10cSrcweir       maParagraphs(),
133*cdf0e10cSrcweir       mpCaret(new PresenterTextCaret(
134*cdf0e10cSrcweir           ::boost::bind(&PresenterTextView::GetCaretBounds, this, _1, _2),
135*cdf0e10cSrcweir           ::boost::function<void(const css::awt::Rectangle&)>())),
136*cdf0e10cSrcweir       mnLeftOffset(0),
137*cdf0e10cSrcweir       mnTopOffset(0),
138*cdf0e10cSrcweir       maInvalidator(),
139*cdf0e10cSrcweir       mbIsFormatPending(false),
140*cdf0e10cSrcweir       mnCharacterCount(-1),
141*cdf0e10cSrcweir       maTextChangeBroadcaster()
142*cdf0e10cSrcweir {
143*cdf0e10cSrcweir     Reference<lang::XMultiComponentFactory> xFactory (
144*cdf0e10cSrcweir         rxContext->getServiceManager(), UNO_QUERY);
145*cdf0e10cSrcweir     if ( ! xFactory.is())
146*cdf0e10cSrcweir         return;
147*cdf0e10cSrcweir 
148*cdf0e10cSrcweir     // Create the break iterator that we use to break text into lines.
149*cdf0e10cSrcweir     mxBreakIterator = Reference<i18n::XBreakIterator>(
150*cdf0e10cSrcweir         xFactory->createInstanceWithContext(
151*cdf0e10cSrcweir             A2S("com.sun.star.i18n.BreakIterator"),
152*cdf0e10cSrcweir             rxContext),
153*cdf0e10cSrcweir         UNO_QUERY_THROW);
154*cdf0e10cSrcweir 
155*cdf0e10cSrcweir     // Create the script type detector that is used to split paragraphs into
156*cdf0e10cSrcweir     // portions of the same text direction.
157*cdf0e10cSrcweir     mxScriptTypeDetector = Reference<i18n::XScriptTypeDetector>(
158*cdf0e10cSrcweir         xFactory->createInstanceWithContext(
159*cdf0e10cSrcweir             A2S("com.sun.star.i18n.ScriptTypeDetector"),
160*cdf0e10cSrcweir             rxContext),
161*cdf0e10cSrcweir         UNO_QUERY_THROW);
162*cdf0e10cSrcweir }
163*cdf0e10cSrcweir 
164*cdf0e10cSrcweir 
165*cdf0e10cSrcweir 
166*cdf0e10cSrcweir 
167*cdf0e10cSrcweir void PresenterTextView::SetText (const Reference<text::XText>& rxText)
168*cdf0e10cSrcweir {
169*cdf0e10cSrcweir     maParagraphs.clear();
170*cdf0e10cSrcweir     mnCharacterCount = -1;
171*cdf0e10cSrcweir 
172*cdf0e10cSrcweir     Reference<container::XEnumerationAccess> xParagraphAccess (rxText, UNO_QUERY);
173*cdf0e10cSrcweir     if ( ! xParagraphAccess.is())
174*cdf0e10cSrcweir         return;
175*cdf0e10cSrcweir 
176*cdf0e10cSrcweir     Reference<container::XEnumeration> xParagraphs (
177*cdf0e10cSrcweir         xParagraphAccess->createEnumeration() , UNO_QUERY);
178*cdf0e10cSrcweir     if ( ! xParagraphs.is())
179*cdf0e10cSrcweir         return;
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir     if ( ! mpFont || ! mpFont->PrepareFont(mxCanvas))
182*cdf0e10cSrcweir         return;
183*cdf0e10cSrcweir 
184*cdf0e10cSrcweir     sal_Int32 nCharacterCount (0);
185*cdf0e10cSrcweir     while (xParagraphs->hasMoreElements())
186*cdf0e10cSrcweir     {
187*cdf0e10cSrcweir         SharedPresenterTextParagraph pParagraph (new PresenterTextParagraph(
188*cdf0e10cSrcweir             maParagraphs.size(),
189*cdf0e10cSrcweir             mxBreakIterator,
190*cdf0e10cSrcweir             mxScriptTypeDetector,
191*cdf0e10cSrcweir             Reference<text::XTextRange>(xParagraphs->nextElement(), UNO_QUERY),
192*cdf0e10cSrcweir             mpCaret));
193*cdf0e10cSrcweir         pParagraph->SetupCellArray(mpFont);
194*cdf0e10cSrcweir         pParagraph->SetCharacterOffset(nCharacterCount);
195*cdf0e10cSrcweir         nCharacterCount += pParagraph->GetCharacterCount();
196*cdf0e10cSrcweir         maParagraphs.push_back(pParagraph);
197*cdf0e10cSrcweir     }
198*cdf0e10cSrcweir 
199*cdf0e10cSrcweir     if (mpCaret)
200*cdf0e10cSrcweir         mpCaret->HideCaret();
201*cdf0e10cSrcweir 
202*cdf0e10cSrcweir     RequestFormat();
203*cdf0e10cSrcweir }
204*cdf0e10cSrcweir 
205*cdf0e10cSrcweir 
206*cdf0e10cSrcweir 
207*cdf0e10cSrcweir 
208*cdf0e10cSrcweir void PresenterTextView::SetText (const ::rtl::OUString& rsText)
209*cdf0e10cSrcweir {
210*cdf0e10cSrcweir     maParagraphs.clear();
211*cdf0e10cSrcweir     mnCharacterCount = -1;
212*cdf0e10cSrcweir 
213*cdf0e10cSrcweir     if ( ! mpFont || ! mpFont->PrepareFont(mxCanvas))
214*cdf0e10cSrcweir         return;
215*cdf0e10cSrcweir 
216*cdf0e10cSrcweir     sal_Int32 nCharacterCount (0);
217*cdf0e10cSrcweir 
218*cdf0e10cSrcweir     SharedPresenterTextParagraph pParagraph (new PresenterTextParagraph(
219*cdf0e10cSrcweir         0,
220*cdf0e10cSrcweir         mxBreakIterator,
221*cdf0e10cSrcweir         mxScriptTypeDetector,
222*cdf0e10cSrcweir         rsText,
223*cdf0e10cSrcweir         mpCaret));
224*cdf0e10cSrcweir     pParagraph->SetupCellArray(mpFont);
225*cdf0e10cSrcweir     pParagraph->SetCharacterOffset(nCharacterCount);
226*cdf0e10cSrcweir     nCharacterCount += pParagraph->GetCharacterCount();
227*cdf0e10cSrcweir     maParagraphs.push_back(pParagraph);
228*cdf0e10cSrcweir 
229*cdf0e10cSrcweir     if (mpCaret)
230*cdf0e10cSrcweir         mpCaret->HideCaret();
231*cdf0e10cSrcweir 
232*cdf0e10cSrcweir     RequestFormat();
233*cdf0e10cSrcweir }
234*cdf0e10cSrcweir 
235*cdf0e10cSrcweir 
236*cdf0e10cSrcweir 
237*cdf0e10cSrcweir 
238*cdf0e10cSrcweir void PresenterTextView::SetTextChangeBroadcaster (
239*cdf0e10cSrcweir     const ::boost::function<void(void)>& rBroadcaster)
240*cdf0e10cSrcweir {
241*cdf0e10cSrcweir     maTextChangeBroadcaster = rBroadcaster;
242*cdf0e10cSrcweir }
243*cdf0e10cSrcweir 
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir 
246*cdf0e10cSrcweir 
247*cdf0e10cSrcweir void PresenterTextView::SetLocation (const css::geometry::RealPoint2D& rLocation)
248*cdf0e10cSrcweir {
249*cdf0e10cSrcweir     maLocation = rLocation;
250*cdf0e10cSrcweir 
251*cdf0e10cSrcweir     for (::std::vector<SharedPresenterTextParagraph>::iterator
252*cdf0e10cSrcweir              iParagraph(maParagraphs.begin()),
253*cdf0e10cSrcweir              iEnd(maParagraphs.end());
254*cdf0e10cSrcweir          iParagraph!=iEnd;
255*cdf0e10cSrcweir          ++iParagraph)
256*cdf0e10cSrcweir     {
257*cdf0e10cSrcweir         (*iParagraph)->SetOrigin(
258*cdf0e10cSrcweir             maLocation.X - mnLeftOffset,
259*cdf0e10cSrcweir             maLocation.Y - mnTopOffset);
260*cdf0e10cSrcweir     }
261*cdf0e10cSrcweir }
262*cdf0e10cSrcweir 
263*cdf0e10cSrcweir 
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir 
266*cdf0e10cSrcweir void PresenterTextView::SetSize (const css::geometry::RealSize2D& rSize)
267*cdf0e10cSrcweir {
268*cdf0e10cSrcweir     maSize = rSize;
269*cdf0e10cSrcweir     RequestFormat();
270*cdf0e10cSrcweir }
271*cdf0e10cSrcweir 
272*cdf0e10cSrcweir 
273*cdf0e10cSrcweir 
274*cdf0e10cSrcweir 
275*cdf0e10cSrcweir double PresenterTextView::GetTotalTextHeight (void)
276*cdf0e10cSrcweir {
277*cdf0e10cSrcweir     double nTotalHeight (0);
278*cdf0e10cSrcweir 
279*cdf0e10cSrcweir     if (mbIsFormatPending)
280*cdf0e10cSrcweir     {
281*cdf0e10cSrcweir         if ( ! mpFont->PrepareFont(mxCanvas))
282*cdf0e10cSrcweir             return 0;
283*cdf0e10cSrcweir         Format();
284*cdf0e10cSrcweir     }
285*cdf0e10cSrcweir 
286*cdf0e10cSrcweir     for (::std::vector<SharedPresenterTextParagraph>::iterator
287*cdf0e10cSrcweir              iParagraph(maParagraphs.begin()),
288*cdf0e10cSrcweir              iEnd(maParagraphs.end());
289*cdf0e10cSrcweir          iParagraph!=iEnd;
290*cdf0e10cSrcweir          ++iParagraph)
291*cdf0e10cSrcweir     {
292*cdf0e10cSrcweir         nTotalHeight += (*iParagraph)->GetTotalTextHeight();
293*cdf0e10cSrcweir     }
294*cdf0e10cSrcweir 
295*cdf0e10cSrcweir     return nTotalHeight;
296*cdf0e10cSrcweir }
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir 
299*cdf0e10cSrcweir 
300*cdf0e10cSrcweir 
301*cdf0e10cSrcweir void PresenterTextView::SetFont (const PresenterTheme::SharedFontDescriptor& rpFont)
302*cdf0e10cSrcweir {
303*cdf0e10cSrcweir     mpFont = rpFont;
304*cdf0e10cSrcweir     RequestFormat();
305*cdf0e10cSrcweir }
306*cdf0e10cSrcweir 
307*cdf0e10cSrcweir 
308*cdf0e10cSrcweir 
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir void PresenterTextView::SetOffset(
311*cdf0e10cSrcweir     const double nLeft,
312*cdf0e10cSrcweir     const double nTop)
313*cdf0e10cSrcweir {
314*cdf0e10cSrcweir     mnLeftOffset = nLeft;
315*cdf0e10cSrcweir     mnTopOffset = nTop;
316*cdf0e10cSrcweir 
317*cdf0e10cSrcweir     // Trigger an update of the text origin stored at the individual paragraphs.
318*cdf0e10cSrcweir     SetLocation(maLocation);
319*cdf0e10cSrcweir }
320*cdf0e10cSrcweir 
321*cdf0e10cSrcweir 
322*cdf0e10cSrcweir 
323*cdf0e10cSrcweir void PresenterTextView::MoveCaret (
324*cdf0e10cSrcweir     const sal_Int32 nDistance,
325*cdf0e10cSrcweir     const sal_Int16 nTextType)
326*cdf0e10cSrcweir {
327*cdf0e10cSrcweir     if ( ! mpCaret)
328*cdf0e10cSrcweir         return;
329*cdf0e10cSrcweir 
330*cdf0e10cSrcweir     // When the caret has not been visible yet then move it to the beginning
331*cdf0e10cSrcweir     // of the text.
332*cdf0e10cSrcweir     if (mpCaret->GetParagraphIndex() < 0)
333*cdf0e10cSrcweir     {
334*cdf0e10cSrcweir         mpCaret->SetPosition(0,0);
335*cdf0e10cSrcweir         return;
336*cdf0e10cSrcweir     }
337*cdf0e10cSrcweir 
338*cdf0e10cSrcweir     sal_Int32 nParagraphIndex (mpCaret->GetParagraphIndex());
339*cdf0e10cSrcweir     sal_Int32 nCharacterIndex (mpCaret->GetCharacterIndex());
340*cdf0e10cSrcweir     switch (nTextType)
341*cdf0e10cSrcweir     {
342*cdf0e10cSrcweir         default:
343*cdf0e10cSrcweir         case AccessibleTextType::CHARACTER:
344*cdf0e10cSrcweir             nCharacterIndex += nDistance;
345*cdf0e10cSrcweir             break;
346*cdf0e10cSrcweir 
347*cdf0e10cSrcweir         case AccessibleTextType::WORD:
348*cdf0e10cSrcweir         {
349*cdf0e10cSrcweir             sal_Int32 nRemainingDistance (nDistance);
350*cdf0e10cSrcweir             while (nRemainingDistance != 0)
351*cdf0e10cSrcweir             {
352*cdf0e10cSrcweir                 SharedPresenterTextParagraph pParagraph (GetParagraph(nParagraphIndex));
353*cdf0e10cSrcweir                 if (pParagraph)
354*cdf0e10cSrcweir                 {
355*cdf0e10cSrcweir                     const sal_Int32 nDelta (Signum(nDistance));
356*cdf0e10cSrcweir                     nCharacterIndex = pParagraph->GetWordBoundary(nCharacterIndex, nDelta);
357*cdf0e10cSrcweir                     if (nCharacterIndex < 0)
358*cdf0e10cSrcweir                     {
359*cdf0e10cSrcweir                         // Go to previous or next paragraph.
360*cdf0e10cSrcweir                         nParagraphIndex += nDelta;
361*cdf0e10cSrcweir                         if (nParagraphIndex < 0)
362*cdf0e10cSrcweir                         {
363*cdf0e10cSrcweir                             nParagraphIndex = 0;
364*cdf0e10cSrcweir                             nCharacterIndex = 0;
365*cdf0e10cSrcweir                             nRemainingDistance = 0;
366*cdf0e10cSrcweir                         }
367*cdf0e10cSrcweir                         else if (sal_uInt32(nParagraphIndex) >= maParagraphs.size())
368*cdf0e10cSrcweir                         {
369*cdf0e10cSrcweir                             nParagraphIndex = maParagraphs.size()-1;
370*cdf0e10cSrcweir                             pParagraph = GetParagraph(nParagraphIndex);
371*cdf0e10cSrcweir                             if (pParagraph)
372*cdf0e10cSrcweir                                 nCharacterIndex = pParagraph->GetCharacterCount();
373*cdf0e10cSrcweir                             nRemainingDistance = 0;
374*cdf0e10cSrcweir                         }
375*cdf0e10cSrcweir                         else
376*cdf0e10cSrcweir                         {
377*cdf0e10cSrcweir                             nRemainingDistance -= nDelta;
378*cdf0e10cSrcweir 
379*cdf0e10cSrcweir                             // Move caret one character to the end of
380*cdf0e10cSrcweir                             // the previous or the start of the next paragraph.
381*cdf0e10cSrcweir                             pParagraph = GetParagraph(nParagraphIndex);
382*cdf0e10cSrcweir                             if (pParagraph)
383*cdf0e10cSrcweir                             {
384*cdf0e10cSrcweir                                 if (nDistance<0)
385*cdf0e10cSrcweir                                     nCharacterIndex = pParagraph->GetCharacterCount();
386*cdf0e10cSrcweir                                 else
387*cdf0e10cSrcweir                                     nCharacterIndex = 0;
388*cdf0e10cSrcweir                             }
389*cdf0e10cSrcweir                         }
390*cdf0e10cSrcweir                     }
391*cdf0e10cSrcweir                     else
392*cdf0e10cSrcweir                         nRemainingDistance -= nDelta;
393*cdf0e10cSrcweir                 }
394*cdf0e10cSrcweir                 else
395*cdf0e10cSrcweir                     break;
396*cdf0e10cSrcweir             }
397*cdf0e10cSrcweir             break;
398*cdf0e10cSrcweir         }
399*cdf0e10cSrcweir     }
400*cdf0e10cSrcweir 
401*cdf0e10cSrcweir     // Move the caret to the new position.
402*cdf0e10cSrcweir     mpCaret->SetPosition(nParagraphIndex, nCharacterIndex);
403*cdf0e10cSrcweir }
404*cdf0e10cSrcweir 
405*cdf0e10cSrcweir 
406*cdf0e10cSrcweir 
407*cdf0e10cSrcweir 
408*cdf0e10cSrcweir void PresenterTextView::Paint (
409*cdf0e10cSrcweir     const css::awt::Rectangle& rUpdateBox)
410*cdf0e10cSrcweir {
411*cdf0e10cSrcweir     if ( ! mbDoOuput)
412*cdf0e10cSrcweir         return;
413*cdf0e10cSrcweir     if ( ! mxCanvas.is())
414*cdf0e10cSrcweir         return;
415*cdf0e10cSrcweir     if ( ! mpFont->PrepareFont(mxCanvas))
416*cdf0e10cSrcweir         return;
417*cdf0e10cSrcweir 
418*cdf0e10cSrcweir     if (mbIsFormatPending)
419*cdf0e10cSrcweir         Format();
420*cdf0e10cSrcweir 
421*cdf0e10cSrcweir     // Setup the clipping rectangle.  Horizontally we make it a little
422*cdf0e10cSrcweir     // larger to allow characters (and the caret) to stick out of their
423*cdf0e10cSrcweir     // bounding boxes.  This can happen on some characters (like the
424*cdf0e10cSrcweir     // uppercase J) for typographical reasons.
425*cdf0e10cSrcweir     const sal_Int32 nAdditionalLeftBorder (10);
426*cdf0e10cSrcweir     const sal_Int32 nAdditionalRightBorder (5);
427*cdf0e10cSrcweir     double nX (maLocation.X - mnLeftOffset);
428*cdf0e10cSrcweir     double nY (maLocation.Y - mnTopOffset);
429*cdf0e10cSrcweir     const sal_Int32 nClipLeft (::std::max(
430*cdf0e10cSrcweir         PresenterGeometryHelper::Round(maLocation.X)-nAdditionalLeftBorder, rUpdateBox.X));
431*cdf0e10cSrcweir     const sal_Int32 nClipTop (::std::max(
432*cdf0e10cSrcweir         PresenterGeometryHelper::Round(maLocation.Y), rUpdateBox.Y));
433*cdf0e10cSrcweir     const sal_Int32 nClipRight (::std::min(
434*cdf0e10cSrcweir         PresenterGeometryHelper::Round(maLocation.X+maSize.Width)+nAdditionalRightBorder, rUpdateBox.X+rUpdateBox.Width));
435*cdf0e10cSrcweir     const sal_Int32 nClipBottom (::std::min(
436*cdf0e10cSrcweir         PresenterGeometryHelper::Round(maLocation.Y+maSize.Height), rUpdateBox.Y+rUpdateBox.Height));
437*cdf0e10cSrcweir     if (nClipLeft>=nClipRight || nClipTop>=nClipBottom)
438*cdf0e10cSrcweir         return;
439*cdf0e10cSrcweir 
440*cdf0e10cSrcweir     const awt::Rectangle aClipBox(
441*cdf0e10cSrcweir         nClipLeft,
442*cdf0e10cSrcweir         nClipTop,
443*cdf0e10cSrcweir         nClipRight - nClipLeft,
444*cdf0e10cSrcweir         nClipBottom - nClipTop);
445*cdf0e10cSrcweir     Reference<rendering::XPolyPolygon2D> xClipPolygon (
446*cdf0e10cSrcweir         PresenterGeometryHelper::CreatePolygon(aClipBox, mxCanvas->getDevice()));
447*cdf0e10cSrcweir 
448*cdf0e10cSrcweir     const rendering::ViewState aViewState(
449*cdf0e10cSrcweir         geometry::AffineMatrix2D(1,0,0, 0,1,0),
450*cdf0e10cSrcweir         xClipPolygon);
451*cdf0e10cSrcweir 
452*cdf0e10cSrcweir     rendering::RenderState aRenderState (
453*cdf0e10cSrcweir         geometry::AffineMatrix2D(1,0,nX, 0,1,nY),
454*cdf0e10cSrcweir         NULL,
455*cdf0e10cSrcweir         Sequence<double>(4),
456*cdf0e10cSrcweir         rendering::CompositeOperation::SOURCE);
457*cdf0e10cSrcweir     PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
458*cdf0e10cSrcweir 
459*cdf0e10cSrcweir     for (::std::vector<SharedPresenterTextParagraph>::const_iterator
460*cdf0e10cSrcweir              iParagraph(maParagraphs.begin()),
461*cdf0e10cSrcweir              iEnd(maParagraphs.end());
462*cdf0e10cSrcweir          iParagraph!=iEnd;
463*cdf0e10cSrcweir          ++iParagraph)
464*cdf0e10cSrcweir     {
465*cdf0e10cSrcweir         (*iParagraph)->Paint(
466*cdf0e10cSrcweir             mxCanvas,
467*cdf0e10cSrcweir             maSize,
468*cdf0e10cSrcweir             mpFont,
469*cdf0e10cSrcweir             aViewState,
470*cdf0e10cSrcweir             aRenderState,
471*cdf0e10cSrcweir             mnTopOffset,
472*cdf0e10cSrcweir             nClipTop,
473*cdf0e10cSrcweir             nClipBottom);
474*cdf0e10cSrcweir     }
475*cdf0e10cSrcweir 
476*cdf0e10cSrcweir     aRenderState.AffineTransform.m02 = 0;
477*cdf0e10cSrcweir     aRenderState.AffineTransform.m12 = 0;
478*cdf0e10cSrcweir 
479*cdf0e10cSrcweir #ifdef SHOW_CHARACTER_BOXES
480*cdf0e10cSrcweir     PresenterCanvasHelper::SetDeviceColor(aRenderState, 0x00808080);
481*cdf0e10cSrcweir     for (sal_Int32 nParagraphIndex(0), nParagraphCount(GetParagraphCount());
482*cdf0e10cSrcweir          nParagraphIndex<nParagraphCount;
483*cdf0e10cSrcweir          ++nParagraphIndex)
484*cdf0e10cSrcweir     {
485*cdf0e10cSrcweir         const SharedPresenterTextParagraph pParagraph (GetParagraph(nParagraphIndex));
486*cdf0e10cSrcweir         if ( ! pParagraph)
487*cdf0e10cSrcweir             continue;
488*cdf0e10cSrcweir         for (sal_Int32 nCharacterIndex(0),nCharacterCount(pParagraph->GetCharacterCount());
489*cdf0e10cSrcweir              nCharacterIndex<nCharacterCount; ++nCharacterIndex)
490*cdf0e10cSrcweir         {
491*cdf0e10cSrcweir             const awt::Rectangle aBox (pParagraph->GetCharacterBounds(nCharacterIndex, false));
492*cdf0e10cSrcweir             mxCanvas->drawPolyPolygon (
493*cdf0e10cSrcweir                 PresenterGeometryHelper::CreatePolygon(
494*cdf0e10cSrcweir                     aBox,
495*cdf0e10cSrcweir                     mxCanvas->getDevice()),
496*cdf0e10cSrcweir                 aViewState,
497*cdf0e10cSrcweir                 aRenderState);
498*cdf0e10cSrcweir         }
499*cdf0e10cSrcweir     }
500*cdf0e10cSrcweir     PresenterCanvasHelper::SetDeviceColor(aRenderState, mpFont->mnColor);
501*cdf0e10cSrcweir #endif
502*cdf0e10cSrcweir 
503*cdf0e10cSrcweir     if (mpCaret && mpCaret->IsVisible())
504*cdf0e10cSrcweir     {
505*cdf0e10cSrcweir         mxCanvas->fillPolyPolygon (
506*cdf0e10cSrcweir             PresenterGeometryHelper::CreatePolygon(
507*cdf0e10cSrcweir                 mpCaret->GetBounds(),
508*cdf0e10cSrcweir                 mxCanvas->getDevice()),
509*cdf0e10cSrcweir             aViewState,
510*cdf0e10cSrcweir             aRenderState);
511*cdf0e10cSrcweir     }
512*cdf0e10cSrcweir }
513*cdf0e10cSrcweir 
514*cdf0e10cSrcweir 
515*cdf0e10cSrcweir 
516*cdf0e10cSrcweir 
517*cdf0e10cSrcweir SharedPresenterTextCaret PresenterTextView::GetCaret (void) const
518*cdf0e10cSrcweir {
519*cdf0e10cSrcweir     return mpCaret;
520*cdf0e10cSrcweir }
521*cdf0e10cSrcweir 
522*cdf0e10cSrcweir 
523*cdf0e10cSrcweir 
524*cdf0e10cSrcweir 
525*cdf0e10cSrcweir sal_Int32 PresenterTextView::GetCharacterOffset (const sal_Int32 nParagraphIndex) const
526*cdf0e10cSrcweir {
527*cdf0e10cSrcweir     sal_Int32 nCharacterOffset (0);
528*cdf0e10cSrcweir     for (sal_Int32 nIndex=0; nIndex<nParagraphIndex; ++nIndex)
529*cdf0e10cSrcweir         nCharacterOffset += maParagraphs[nIndex]->GetCharacterCount();
530*cdf0e10cSrcweir     return nCharacterOffset;
531*cdf0e10cSrcweir }
532*cdf0e10cSrcweir 
533*cdf0e10cSrcweir 
534*cdf0e10cSrcweir 
535*cdf0e10cSrcweir 
536*cdf0e10cSrcweir awt::Rectangle PresenterTextView::GetCaretBounds (
537*cdf0e10cSrcweir     sal_Int32 nParagraphIndex,
538*cdf0e10cSrcweir     const sal_Int32 nCharacterIndex) const
539*cdf0e10cSrcweir {
540*cdf0e10cSrcweir     SharedPresenterTextParagraph pParagraph (GetParagraph(nParagraphIndex));
541*cdf0e10cSrcweir 
542*cdf0e10cSrcweir     if (pParagraph)
543*cdf0e10cSrcweir         return pParagraph->GetCharacterBounds(nCharacterIndex, true);
544*cdf0e10cSrcweir     else
545*cdf0e10cSrcweir         return awt::Rectangle(0,0,0,0);
546*cdf0e10cSrcweir }
547*cdf0e10cSrcweir 
548*cdf0e10cSrcweir 
549*cdf0e10cSrcweir 
550*cdf0e10cSrcweir 
551*cdf0e10cSrcweir //----- private ---------------------------------------------------------------
552*cdf0e10cSrcweir 
553*cdf0e10cSrcweir void PresenterTextView::RequestFormat (void)
554*cdf0e10cSrcweir {
555*cdf0e10cSrcweir     mbIsFormatPending = true;
556*cdf0e10cSrcweir }
557*cdf0e10cSrcweir 
558*cdf0e10cSrcweir 
559*cdf0e10cSrcweir 
560*cdf0e10cSrcweir 
561*cdf0e10cSrcweir void PresenterTextView::Format (void)
562*cdf0e10cSrcweir {
563*cdf0e10cSrcweir     mbIsFormatPending = false;
564*cdf0e10cSrcweir 
565*cdf0e10cSrcweir     double nY (0);
566*cdf0e10cSrcweir     for (::std::vector<SharedPresenterTextParagraph>::const_iterator
567*cdf0e10cSrcweir              iParagraph(maParagraphs.begin()),
568*cdf0e10cSrcweir              iEnd(maParagraphs.end());
569*cdf0e10cSrcweir          iParagraph!=iEnd;
570*cdf0e10cSrcweir          ++iParagraph)
571*cdf0e10cSrcweir     {
572*cdf0e10cSrcweir         (*iParagraph)->Format(nY, maSize.Width, mpFont);
573*cdf0e10cSrcweir         nY += (*iParagraph)->GetTotalTextHeight();
574*cdf0e10cSrcweir     }
575*cdf0e10cSrcweir 
576*cdf0e10cSrcweir     if (maTextChangeBroadcaster)
577*cdf0e10cSrcweir         maTextChangeBroadcaster();
578*cdf0e10cSrcweir }
579*cdf0e10cSrcweir 
580*cdf0e10cSrcweir 
581*cdf0e10cSrcweir 
582*cdf0e10cSrcweir 
583*cdf0e10cSrcweir sal_Int32 PresenterTextView::GetParagraphCount (void) const
584*cdf0e10cSrcweir {
585*cdf0e10cSrcweir     return maParagraphs.size();
586*cdf0e10cSrcweir }
587*cdf0e10cSrcweir 
588*cdf0e10cSrcweir 
589*cdf0e10cSrcweir 
590*cdf0e10cSrcweir 
591*cdf0e10cSrcweir SharedPresenterTextParagraph PresenterTextView::GetParagraph (
592*cdf0e10cSrcweir     const sal_Int32 nParagraphIndex) const
593*cdf0e10cSrcweir {
594*cdf0e10cSrcweir     if (nParagraphIndex < 0)
595*cdf0e10cSrcweir         return SharedPresenterTextParagraph();
596*cdf0e10cSrcweir     else if (nParagraphIndex>=sal_Int32(maParagraphs.size()))
597*cdf0e10cSrcweir         return SharedPresenterTextParagraph();
598*cdf0e10cSrcweir     else
599*cdf0e10cSrcweir         return maParagraphs[nParagraphIndex];
600*cdf0e10cSrcweir }
601*cdf0e10cSrcweir 
602*cdf0e10cSrcweir 
603*cdf0e10cSrcweir 
604*cdf0e10cSrcweir 
605*cdf0e10cSrcweir //===== PresenterTextParagraph ================================================
606*cdf0e10cSrcweir 
607*cdf0e10cSrcweir PresenterTextParagraph::PresenterTextParagraph (
608*cdf0e10cSrcweir     const sal_Int32 nParagraphIndex,
609*cdf0e10cSrcweir     const Reference<i18n::XBreakIterator>& rxBreakIterator,
610*cdf0e10cSrcweir     const Reference<i18n::XScriptTypeDetector>& rxScriptTypeDetector,
611*cdf0e10cSrcweir     const Reference<text::XTextRange>& rxTextRange,
612*cdf0e10cSrcweir     const SharedPresenterTextCaret& rpCaret)
613*cdf0e10cSrcweir     : msParagraphText(),
614*cdf0e10cSrcweir       mnParagraphIndex(nParagraphIndex),
615*cdf0e10cSrcweir       mpCaret(rpCaret),
616*cdf0e10cSrcweir       mxBreakIterator(rxBreakIterator),
617*cdf0e10cSrcweir       mxScriptTypeDetector(rxScriptTypeDetector),
618*cdf0e10cSrcweir       maLines(),
619*cdf0e10cSrcweir       mnVerticalOffset(0),
620*cdf0e10cSrcweir       mnXOrigin(0),
621*cdf0e10cSrcweir       mnYOrigin(0),
622*cdf0e10cSrcweir       mnWidth(0),
623*cdf0e10cSrcweir       mnAscent(0),
624*cdf0e10cSrcweir       mnDescent(0),
625*cdf0e10cSrcweir       mnLineHeight(-1),
626*cdf0e10cSrcweir       meAdjust(style::ParagraphAdjust_LEFT),
627*cdf0e10cSrcweir       mnWritingMode (text::WritingMode2::LR_TB),
628*cdf0e10cSrcweir       mnCharacterOffset(0),
629*cdf0e10cSrcweir       maCells()
630*cdf0e10cSrcweir {
631*cdf0e10cSrcweir     if (rxTextRange.is())
632*cdf0e10cSrcweir     {
633*cdf0e10cSrcweir         Reference<beans::XPropertySet> xProperties (rxTextRange, UNO_QUERY);
634*cdf0e10cSrcweir         lang::Locale aLocale;
635*cdf0e10cSrcweir         try
636*cdf0e10cSrcweir         {
637*cdf0e10cSrcweir             xProperties->getPropertyValue(A2S("CharLocale")) >>= aLocale;
638*cdf0e10cSrcweir         }
639*cdf0e10cSrcweir         catch(beans::UnknownPropertyException&)
640*cdf0e10cSrcweir         {
641*cdf0e10cSrcweir             // Ignore the exception.  Use the default value.
642*cdf0e10cSrcweir         }
643*cdf0e10cSrcweir         try
644*cdf0e10cSrcweir         {
645*cdf0e10cSrcweir             xProperties->getPropertyValue(A2S("ParaAdjust")) >>= meAdjust;
646*cdf0e10cSrcweir         }
647*cdf0e10cSrcweir         catch(beans::UnknownPropertyException&)
648*cdf0e10cSrcweir         {
649*cdf0e10cSrcweir             // Ignore the exception.  Use the default value.
650*cdf0e10cSrcweir         }
651*cdf0e10cSrcweir         try
652*cdf0e10cSrcweir         {
653*cdf0e10cSrcweir             xProperties->getPropertyValue(A2S("WritingMode")) >>= mnWritingMode;
654*cdf0e10cSrcweir         }
655*cdf0e10cSrcweir         catch(beans::UnknownPropertyException&)
656*cdf0e10cSrcweir         {
657*cdf0e10cSrcweir             // Ignore the exception.  Use the default value.
658*cdf0e10cSrcweir         }
659*cdf0e10cSrcweir 
660*cdf0e10cSrcweir         msParagraphText = rxTextRange->getString();
661*cdf0e10cSrcweir     }
662*cdf0e10cSrcweir }
663*cdf0e10cSrcweir 
664*cdf0e10cSrcweir 
665*cdf0e10cSrcweir 
666*cdf0e10cSrcweir 
667*cdf0e10cSrcweir PresenterTextParagraph::PresenterTextParagraph (
668*cdf0e10cSrcweir     const sal_Int32 nParagraphIndex,
669*cdf0e10cSrcweir     const Reference<i18n::XBreakIterator>& rxBreakIterator,
670*cdf0e10cSrcweir     const Reference<i18n::XScriptTypeDetector>& rxScriptTypeDetector,
671*cdf0e10cSrcweir     const ::rtl::OUString& rsText,
672*cdf0e10cSrcweir     const SharedPresenterTextCaret& rpCaret)
673*cdf0e10cSrcweir     : msParagraphText(rsText),
674*cdf0e10cSrcweir       mnParagraphIndex(nParagraphIndex),
675*cdf0e10cSrcweir       mpCaret(rpCaret),
676*cdf0e10cSrcweir       mxBreakIterator(rxBreakIterator),
677*cdf0e10cSrcweir       mxScriptTypeDetector(rxScriptTypeDetector),
678*cdf0e10cSrcweir       maLines(),
679*cdf0e10cSrcweir       mnVerticalOffset(0),
680*cdf0e10cSrcweir       mnXOrigin(0),
681*cdf0e10cSrcweir       mnYOrigin(0),
682*cdf0e10cSrcweir       mnWidth(0),
683*cdf0e10cSrcweir       mnAscent(0),
684*cdf0e10cSrcweir       mnDescent(0),
685*cdf0e10cSrcweir       mnLineHeight(-1),
686*cdf0e10cSrcweir       meAdjust(style::ParagraphAdjust_LEFT),
687*cdf0e10cSrcweir       mnWritingMode (text::WritingMode2::LR_TB),
688*cdf0e10cSrcweir       mnCharacterOffset(0),
689*cdf0e10cSrcweir       maCells()
690*cdf0e10cSrcweir {
691*cdf0e10cSrcweir }
692*cdf0e10cSrcweir 
693*cdf0e10cSrcweir 
694*cdf0e10cSrcweir 
695*cdf0e10cSrcweir 
696*cdf0e10cSrcweir void PresenterTextParagraph::Paint (
697*cdf0e10cSrcweir     const Reference<rendering::XCanvas>& rxCanvas,
698*cdf0e10cSrcweir     const geometry::RealSize2D& rSize,
699*cdf0e10cSrcweir     const PresenterTheme::SharedFontDescriptor& rpFont,
700*cdf0e10cSrcweir     const rendering::ViewState& rViewState,
701*cdf0e10cSrcweir     rendering::RenderState& rRenderState,
702*cdf0e10cSrcweir     const double nTopOffset,
703*cdf0e10cSrcweir     const double nClipTop,
704*cdf0e10cSrcweir     const double nClipBottom)
705*cdf0e10cSrcweir {
706*cdf0e10cSrcweir     if (mnLineHeight <= 0)
707*cdf0e10cSrcweir         return;
708*cdf0e10cSrcweir 
709*cdf0e10cSrcweir     sal_Int8 nTextDirection (GetTextDirection());
710*cdf0e10cSrcweir 
711*cdf0e10cSrcweir     const double nSavedM12 (rRenderState.AffineTransform.m12);
712*cdf0e10cSrcweir 
713*cdf0e10cSrcweir     if ( ! IsTextReferencePointLeft())
714*cdf0e10cSrcweir         rRenderState.AffineTransform.m02 += rSize.Width;
715*cdf0e10cSrcweir 
716*cdf0e10cSrcweir 
717*cdf0e10cSrcweir #ifdef SHOW_CHARACTER_BOXES
718*cdf0e10cSrcweir     for (sal_Int32 nIndex=0,nCount=maLines.size();
719*cdf0e10cSrcweir          nIndex<nCount;
720*cdf0e10cSrcweir          ++nIndex)
721*cdf0e10cSrcweir     {
722*cdf0e10cSrcweir         Line& rLine (maLines[nIndex]);
723*cdf0e10cSrcweir         rLine.ProvideLayoutedLine(msParagraphText, rpFont, nTextDirection);
724*cdf0e10cSrcweir     }
725*cdf0e10cSrcweir #endif
726*cdf0e10cSrcweir 
727*cdf0e10cSrcweir     for (sal_Int32 nIndex=0,nCount=maLines.size();
728*cdf0e10cSrcweir          nIndex<nCount;
729*cdf0e10cSrcweir          ++nIndex, rRenderState.AffineTransform.m12 += mnLineHeight)
730*cdf0e10cSrcweir     {
731*cdf0e10cSrcweir         Line& rLine (maLines[nIndex]);
732*cdf0e10cSrcweir 
733*cdf0e10cSrcweir         // Paint only visible lines.
734*cdf0e10cSrcweir         const double nLineTop = rLine.mnBaseLine - mnAscent - nTopOffset;
735*cdf0e10cSrcweir         if (nLineTop + mnLineHeight< nClipTop)
736*cdf0e10cSrcweir             continue;
737*cdf0e10cSrcweir         else if (nLineTop > nClipBottom)
738*cdf0e10cSrcweir             break;
739*cdf0e10cSrcweir         rLine.ProvideLayoutedLine(msParagraphText, rpFont, nTextDirection);
740*cdf0e10cSrcweir 
741*cdf0e10cSrcweir         rRenderState.AffineTransform.m12 = nSavedM12 + rLine.mnBaseLine;
742*cdf0e10cSrcweir 
743*cdf0e10cSrcweir         rxCanvas->drawTextLayout (
744*cdf0e10cSrcweir             rLine.mxLayoutedLine,
745*cdf0e10cSrcweir             rViewState,
746*cdf0e10cSrcweir             rRenderState);
747*cdf0e10cSrcweir     }
748*cdf0e10cSrcweir     rRenderState.AffineTransform.m12 = nSavedM12;
749*cdf0e10cSrcweir 
750*cdf0e10cSrcweir     if ( ! IsTextReferencePointLeft())
751*cdf0e10cSrcweir         rRenderState.AffineTransform.m02 -= rSize.Width;
752*cdf0e10cSrcweir }
753*cdf0e10cSrcweir 
754*cdf0e10cSrcweir 
755*cdf0e10cSrcweir 
756*cdf0e10cSrcweir 
757*cdf0e10cSrcweir void PresenterTextParagraph::Format (
758*cdf0e10cSrcweir     const double nY,
759*cdf0e10cSrcweir     const double nWidth,
760*cdf0e10cSrcweir     const PresenterTheme::SharedFontDescriptor& rpFont)
761*cdf0e10cSrcweir {
762*cdf0e10cSrcweir     // Make sure that the text view is in a valid and sane state.
763*cdf0e10cSrcweir     if ( ! mxBreakIterator.is() || ! mxScriptTypeDetector.is())
764*cdf0e10cSrcweir         return;
765*cdf0e10cSrcweir     if (nWidth<=0)
766*cdf0e10cSrcweir         return;
767*cdf0e10cSrcweir     if ( ! rpFont || ! rpFont->mxFont.is())
768*cdf0e10cSrcweir         return;
769*cdf0e10cSrcweir 
770*cdf0e10cSrcweir     sal_Int32 nPosition (0);
771*cdf0e10cSrcweir 
772*cdf0e10cSrcweir     mnWidth = nWidth;
773*cdf0e10cSrcweir     maLines.clear();
774*cdf0e10cSrcweir     mnLineHeight = 0;
775*cdf0e10cSrcweir     mnAscent = 0;
776*cdf0e10cSrcweir     mnDescent = 0;
777*cdf0e10cSrcweir     mnVerticalOffset = nY;
778*cdf0e10cSrcweir     maWordBoundaries.clear();
779*cdf0e10cSrcweir     maWordBoundaries.push_back(0);
780*cdf0e10cSrcweir 
781*cdf0e10cSrcweir     const rendering::FontMetrics aMetrics (rpFont->mxFont->getFontMetrics());
782*cdf0e10cSrcweir     mnAscent = aMetrics.Ascent;
783*cdf0e10cSrcweir     mnDescent = aMetrics.Descent;
784*cdf0e10cSrcweir     mnLineHeight = aMetrics.Ascent + aMetrics.Descent + aMetrics.ExternalLeading;
785*cdf0e10cSrcweir     nPosition = 0;
786*cdf0e10cSrcweir     i18n::Boundary aCurrentLine(0,0);
787*cdf0e10cSrcweir     while (true)
788*cdf0e10cSrcweir     {
789*cdf0e10cSrcweir         const i18n::Boundary aWordBoundary = mxBreakIterator->nextWord(
790*cdf0e10cSrcweir             msParagraphText,
791*cdf0e10cSrcweir             nPosition,
792*cdf0e10cSrcweir             lang::Locale(),
793*cdf0e10cSrcweir             i18n::WordType::ANYWORD_IGNOREWHITESPACES);
794*cdf0e10cSrcweir         AddWord(nWidth, aCurrentLine, aWordBoundary.startPos, rpFont);
795*cdf0e10cSrcweir 
796*cdf0e10cSrcweir         // Remember the new word boundary for caret travelling by words.
797*cdf0e10cSrcweir         // Prevent duplicates.
798*cdf0e10cSrcweir         if (aWordBoundary.startPos > maWordBoundaries.back())
799*cdf0e10cSrcweir             maWordBoundaries.push_back(aWordBoundary.startPos);
800*cdf0e10cSrcweir 
801*cdf0e10cSrcweir         if (aWordBoundary.endPos>aWordBoundary.startPos)
802*cdf0e10cSrcweir             AddWord(nWidth, aCurrentLine, aWordBoundary.endPos, rpFont);
803*cdf0e10cSrcweir 
804*cdf0e10cSrcweir         if (aWordBoundary.startPos<0 || aWordBoundary.endPos<0)
805*cdf0e10cSrcweir             break;
806*cdf0e10cSrcweir         if (nPosition >= aWordBoundary.endPos)
807*cdf0e10cSrcweir             break;
808*cdf0e10cSrcweir         nPosition = aWordBoundary.endPos;
809*cdf0e10cSrcweir     }
810*cdf0e10cSrcweir 
811*cdf0e10cSrcweir     if (aCurrentLine.endPos>aCurrentLine.startPos)
812*cdf0e10cSrcweir         AddLine(aCurrentLine);
813*cdf0e10cSrcweir 
814*cdf0e10cSrcweir }
815*cdf0e10cSrcweir 
816*cdf0e10cSrcweir 
817*cdf0e10cSrcweir 
818*cdf0e10cSrcweir 
819*cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetWordBoundary(
820*cdf0e10cSrcweir     const sal_Int32 nLocalCharacterIndex,
821*cdf0e10cSrcweir     const sal_Int32 nDistance)
822*cdf0e10cSrcweir {
823*cdf0e10cSrcweir     OSL_ASSERT(nDistance==-1 || nDistance==+1);
824*cdf0e10cSrcweir 
825*cdf0e10cSrcweir     if (nLocalCharacterIndex < 0)
826*cdf0e10cSrcweir     {
827*cdf0e10cSrcweir         // The caller asked for the start or end position of the paragraph.
828*cdf0e10cSrcweir         if (nDistance < 0)
829*cdf0e10cSrcweir             return 0;
830*cdf0e10cSrcweir         else
831*cdf0e10cSrcweir             return GetCharacterCount();
832*cdf0e10cSrcweir     }
833*cdf0e10cSrcweir 
834*cdf0e10cSrcweir     sal_Int32 nIndex (0);
835*cdf0e10cSrcweir     for (sal_Int32 nCount (maWordBoundaries.size()); nIndex<nCount; ++nIndex)
836*cdf0e10cSrcweir     {
837*cdf0e10cSrcweir         if (maWordBoundaries[nIndex] >= nLocalCharacterIndex)
838*cdf0e10cSrcweir         {
839*cdf0e10cSrcweir             // When inside the word (not at its start or end) then
840*cdf0e10cSrcweir             // first move to the start or end before going the previous or
841*cdf0e10cSrcweir             // next word.
842*cdf0e10cSrcweir             if (maWordBoundaries[nIndex] > nLocalCharacterIndex)
843*cdf0e10cSrcweir                 if (nDistance > 0)
844*cdf0e10cSrcweir                     --nIndex;
845*cdf0e10cSrcweir             break;
846*cdf0e10cSrcweir         }
847*cdf0e10cSrcweir     }
848*cdf0e10cSrcweir 
849*cdf0e10cSrcweir     nIndex += nDistance;
850*cdf0e10cSrcweir 
851*cdf0e10cSrcweir     if (nIndex < 0)
852*cdf0e10cSrcweir         return -1;
853*cdf0e10cSrcweir     else if (sal_uInt32(nIndex)>=maWordBoundaries.size())
854*cdf0e10cSrcweir         return -1;
855*cdf0e10cSrcweir     else
856*cdf0e10cSrcweir         return maWordBoundaries[nIndex];
857*cdf0e10cSrcweir }
858*cdf0e10cSrcweir 
859*cdf0e10cSrcweir 
860*cdf0e10cSrcweir 
861*cdf0e10cSrcweir 
862*cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetCaretPosition (void) const
863*cdf0e10cSrcweir {
864*cdf0e10cSrcweir     if (mpCaret && mpCaret->GetParagraphIndex()==mnParagraphIndex)
865*cdf0e10cSrcweir         return mpCaret->GetCharacterIndex();
866*cdf0e10cSrcweir     else
867*cdf0e10cSrcweir         return -1;
868*cdf0e10cSrcweir }
869*cdf0e10cSrcweir 
870*cdf0e10cSrcweir 
871*cdf0e10cSrcweir 
872*cdf0e10cSrcweir 
873*cdf0e10cSrcweir void PresenterTextParagraph::SetCaretPosition (const sal_Int32 nPosition) const
874*cdf0e10cSrcweir {
875*cdf0e10cSrcweir     if (mpCaret && mpCaret->GetParagraphIndex()==mnParagraphIndex)
876*cdf0e10cSrcweir         return mpCaret->SetPosition(mnParagraphIndex, nPosition);
877*cdf0e10cSrcweir }
878*cdf0e10cSrcweir 
879*cdf0e10cSrcweir 
880*cdf0e10cSrcweir 
881*cdf0e10cSrcweir 
882*cdf0e10cSrcweir void PresenterTextParagraph::SetOrigin (const double nXOrigin, const double nYOrigin)
883*cdf0e10cSrcweir {
884*cdf0e10cSrcweir     mnXOrigin = nXOrigin;
885*cdf0e10cSrcweir     mnYOrigin = nYOrigin;
886*cdf0e10cSrcweir }
887*cdf0e10cSrcweir 
888*cdf0e10cSrcweir 
889*cdf0e10cSrcweir 
890*cdf0e10cSrcweir 
891*cdf0e10cSrcweir awt::Point PresenterTextParagraph::GetRelativeLocation (void) const
892*cdf0e10cSrcweir {
893*cdf0e10cSrcweir     return awt::Point(
894*cdf0e10cSrcweir         sal_Int32(mnXOrigin),
895*cdf0e10cSrcweir         sal_Int32(mnYOrigin + mnVerticalOffset));
896*cdf0e10cSrcweir }
897*cdf0e10cSrcweir 
898*cdf0e10cSrcweir 
899*cdf0e10cSrcweir 
900*cdf0e10cSrcweir 
901*cdf0e10cSrcweir awt::Size PresenterTextParagraph::GetSize (void)
902*cdf0e10cSrcweir {
903*cdf0e10cSrcweir     return awt::Size(
904*cdf0e10cSrcweir         sal_Int32(mnWidth),
905*cdf0e10cSrcweir         sal_Int32(GetTotalTextHeight()));
906*cdf0e10cSrcweir }
907*cdf0e10cSrcweir 
908*cdf0e10cSrcweir 
909*cdf0e10cSrcweir 
910*cdf0e10cSrcweir 
911*cdf0e10cSrcweir void PresenterTextParagraph::AddWord (
912*cdf0e10cSrcweir     const double nWidth,
913*cdf0e10cSrcweir     i18n::Boundary& rCurrentLine,
914*cdf0e10cSrcweir     const sal_Int32 nWordBoundary,
915*cdf0e10cSrcweir     const PresenterTheme::SharedFontDescriptor& rpFont)
916*cdf0e10cSrcweir {
917*cdf0e10cSrcweir     sal_Int32 nLineStart (0);
918*cdf0e10cSrcweir     sal_Int32 nLineEnd (0);
919*cdf0e10cSrcweir     if ( ! maLines.empty())
920*cdf0e10cSrcweir     {
921*cdf0e10cSrcweir         nLineStart = rCurrentLine.startPos;
922*cdf0e10cSrcweir         nLineEnd = rCurrentLine.endPos;
923*cdf0e10cSrcweir     }
924*cdf0e10cSrcweir 
925*cdf0e10cSrcweir     const ::rtl::OUString sLineCandidate (
926*cdf0e10cSrcweir         msParagraphText.copy(nLineStart, nWordBoundary-nLineStart));
927*cdf0e10cSrcweir 
928*cdf0e10cSrcweir     css::geometry::RealRectangle2D aLineBox (
929*cdf0e10cSrcweir         PresenterCanvasHelper::GetTextBoundingBox (
930*cdf0e10cSrcweir             rpFont->mxFont,
931*cdf0e10cSrcweir             sLineCandidate,
932*cdf0e10cSrcweir             mnWritingMode));
933*cdf0e10cSrcweir     const double nLineWidth (aLineBox.X2 - aLineBox.X1);
934*cdf0e10cSrcweir 
935*cdf0e10cSrcweir     if (nLineWidth >= nWidth)
936*cdf0e10cSrcweir     {
937*cdf0e10cSrcweir         // Add new line with a single word (so far).
938*cdf0e10cSrcweir         AddLine(rCurrentLine);
939*cdf0e10cSrcweir     }
940*cdf0e10cSrcweir     rCurrentLine.endPos = nWordBoundary;
941*cdf0e10cSrcweir }
942*cdf0e10cSrcweir 
943*cdf0e10cSrcweir 
944*cdf0e10cSrcweir 
945*cdf0e10cSrcweir 
946*cdf0e10cSrcweir void PresenterTextParagraph::AddLine (
947*cdf0e10cSrcweir     i18n::Boundary& rCurrentLine)
948*cdf0e10cSrcweir {
949*cdf0e10cSrcweir     Line aLine (rCurrentLine.startPos, rCurrentLine.endPos);
950*cdf0e10cSrcweir 
951*cdf0e10cSrcweir     // Find the start and end of the line with respect to cells.
952*cdf0e10cSrcweir     if (maLines.size() > 0)
953*cdf0e10cSrcweir     {
954*cdf0e10cSrcweir         aLine.mnLineStartCellIndex = maLines.back().mnLineEndCellIndex;
955*cdf0e10cSrcweir         aLine.mnBaseLine = maLines.back().mnBaseLine + mnLineHeight;
956*cdf0e10cSrcweir     }
957*cdf0e10cSrcweir     else
958*cdf0e10cSrcweir     {
959*cdf0e10cSrcweir         aLine.mnLineStartCellIndex = 0;
960*cdf0e10cSrcweir         aLine.mnBaseLine = mnVerticalOffset + mnAscent;
961*cdf0e10cSrcweir     }
962*cdf0e10cSrcweir     sal_Int32 nCellIndex (aLine.mnLineStartCellIndex);
963*cdf0e10cSrcweir     double nWidth (0);
964*cdf0e10cSrcweir     for ( ; nCellIndex<sal_Int32(maCells.size()); ++nCellIndex)
965*cdf0e10cSrcweir     {
966*cdf0e10cSrcweir         const Cell& rCell (maCells[nCellIndex]);
967*cdf0e10cSrcweir         if (rCell.mnCharacterIndex+rCell.mnCharacterCount > aLine.mnLineEndCharacterIndex)
968*cdf0e10cSrcweir             break;
969*cdf0e10cSrcweir         nWidth += rCell.mnCellWidth;
970*cdf0e10cSrcweir     }
971*cdf0e10cSrcweir     aLine.mnLineEndCellIndex = nCellIndex;
972*cdf0e10cSrcweir     aLine.mnWidth = nWidth;
973*cdf0e10cSrcweir 
974*cdf0e10cSrcweir     maLines.push_back(aLine);
975*cdf0e10cSrcweir 
976*cdf0e10cSrcweir     rCurrentLine.startPos = rCurrentLine.endPos;
977*cdf0e10cSrcweir }
978*cdf0e10cSrcweir 
979*cdf0e10cSrcweir 
980*cdf0e10cSrcweir 
981*cdf0e10cSrcweir 
982*cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetParagraphIndex (void) const
983*cdf0e10cSrcweir {
984*cdf0e10cSrcweir     return mnParagraphIndex;
985*cdf0e10cSrcweir }
986*cdf0e10cSrcweir 
987*cdf0e10cSrcweir 
988*cdf0e10cSrcweir 
989*cdf0e10cSrcweir 
990*cdf0e10cSrcweir double PresenterTextParagraph::GetTotalTextHeight (void)
991*cdf0e10cSrcweir {
992*cdf0e10cSrcweir     return maLines.size() * mnLineHeight;
993*cdf0e10cSrcweir }
994*cdf0e10cSrcweir 
995*cdf0e10cSrcweir 
996*cdf0e10cSrcweir 
997*cdf0e10cSrcweir 
998*cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetCharacterOffset (void) const
999*cdf0e10cSrcweir {
1000*cdf0e10cSrcweir     return mnCharacterOffset;
1001*cdf0e10cSrcweir }
1002*cdf0e10cSrcweir 
1003*cdf0e10cSrcweir 
1004*cdf0e10cSrcweir 
1005*cdf0e10cSrcweir 
1006*cdf0e10cSrcweir void PresenterTextParagraph::SetCharacterOffset (const sal_Int32 nCharacterOffset)
1007*cdf0e10cSrcweir {
1008*cdf0e10cSrcweir     mnCharacterOffset = nCharacterOffset;
1009*cdf0e10cSrcweir }
1010*cdf0e10cSrcweir 
1011*cdf0e10cSrcweir 
1012*cdf0e10cSrcweir 
1013*cdf0e10cSrcweir 
1014*cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetCharacterCount (void) const
1015*cdf0e10cSrcweir {
1016*cdf0e10cSrcweir     return msParagraphText.getLength();
1017*cdf0e10cSrcweir }
1018*cdf0e10cSrcweir 
1019*cdf0e10cSrcweir 
1020*cdf0e10cSrcweir 
1021*cdf0e10cSrcweir 
1022*cdf0e10cSrcweir sal_Unicode PresenterTextParagraph::GetCharacter (
1023*cdf0e10cSrcweir     const sal_Int32 nGlobalCharacterIndex) const
1024*cdf0e10cSrcweir {
1025*cdf0e10cSrcweir     if (nGlobalCharacterIndex<mnCharacterOffset
1026*cdf0e10cSrcweir         || nGlobalCharacterIndex>=mnCharacterOffset+msParagraphText.getLength())
1027*cdf0e10cSrcweir     {
1028*cdf0e10cSrcweir         return sal_Unicode();
1029*cdf0e10cSrcweir     }
1030*cdf0e10cSrcweir     else
1031*cdf0e10cSrcweir     {
1032*cdf0e10cSrcweir         return msParagraphText.getStr()[nGlobalCharacterIndex - mnCharacterOffset];
1033*cdf0e10cSrcweir     }
1034*cdf0e10cSrcweir }
1035*cdf0e10cSrcweir 
1036*cdf0e10cSrcweir 
1037*cdf0e10cSrcweir 
1038*cdf0e10cSrcweir 
1039*cdf0e10cSrcweir ::rtl::OUString PresenterTextParagraph::GetText (void) const
1040*cdf0e10cSrcweir {
1041*cdf0e10cSrcweir     return msParagraphText;
1042*cdf0e10cSrcweir }
1043*cdf0e10cSrcweir 
1044*cdf0e10cSrcweir 
1045*cdf0e10cSrcweir 
1046*cdf0e10cSrcweir 
1047*cdf0e10cSrcweir TextSegment PresenterTextParagraph::GetTextSegment (
1048*cdf0e10cSrcweir     const sal_Int32 nOffset,
1049*cdf0e10cSrcweir     const sal_Int32 nIndex,
1050*cdf0e10cSrcweir     const sal_Int16 nTextType) const
1051*cdf0e10cSrcweir {
1052*cdf0e10cSrcweir     switch(nTextType)
1053*cdf0e10cSrcweir     {
1054*cdf0e10cSrcweir         case AccessibleTextType::PARAGRAPH:
1055*cdf0e10cSrcweir             return TextSegment(
1056*cdf0e10cSrcweir                 msParagraphText,
1057*cdf0e10cSrcweir                 mnCharacterOffset,
1058*cdf0e10cSrcweir                 mnCharacterOffset+msParagraphText.getLength());
1059*cdf0e10cSrcweir 
1060*cdf0e10cSrcweir         case AccessibleTextType::SENTENCE:
1061*cdf0e10cSrcweir             if (mxBreakIterator.is())
1062*cdf0e10cSrcweir             {
1063*cdf0e10cSrcweir                 const sal_Int32 nStart (mxBreakIterator->beginOfSentence(
1064*cdf0e10cSrcweir                     msParagraphText, nIndex-mnCharacterOffset, lang::Locale()));
1065*cdf0e10cSrcweir                 const sal_Int32 nEnd (mxBreakIterator->endOfSentence(
1066*cdf0e10cSrcweir                     msParagraphText, nIndex-mnCharacterOffset, lang::Locale()));
1067*cdf0e10cSrcweir                 if (nStart < nEnd)
1068*cdf0e10cSrcweir                     return TextSegment(
1069*cdf0e10cSrcweir                         msParagraphText.copy(nStart, nEnd-nStart),
1070*cdf0e10cSrcweir                         nStart+mnCharacterOffset,
1071*cdf0e10cSrcweir                         nEnd+mnCharacterOffset);
1072*cdf0e10cSrcweir             }
1073*cdf0e10cSrcweir             break;
1074*cdf0e10cSrcweir 
1075*cdf0e10cSrcweir         case AccessibleTextType::WORD:
1076*cdf0e10cSrcweir             if (mxBreakIterator.is())
1077*cdf0e10cSrcweir                 return GetWordTextSegment(nOffset, nIndex);
1078*cdf0e10cSrcweir             break;
1079*cdf0e10cSrcweir 
1080*cdf0e10cSrcweir         case AccessibleTextType::LINE:
1081*cdf0e10cSrcweir         {
1082*cdf0e10cSrcweir             for (::std::vector<Line>::const_iterator
1083*cdf0e10cSrcweir                      iLine(maLines.begin()),
1084*cdf0e10cSrcweir                      iEnd(maLines.end());
1085*cdf0e10cSrcweir                  iLine!=iEnd;
1086*cdf0e10cSrcweir                  ++iLine)
1087*cdf0e10cSrcweir             {
1088*cdf0e10cSrcweir                 if (nIndex < iLine->mnLineEndCharacterIndex)
1089*cdf0e10cSrcweir                 {
1090*cdf0e10cSrcweir                     return TextSegment(
1091*cdf0e10cSrcweir                         msParagraphText.copy(
1092*cdf0e10cSrcweir                             iLine->mnLineStartCharacterIndex,
1093*cdf0e10cSrcweir                             iLine->mnLineEndCharacterIndex - iLine->mnLineStartCharacterIndex),
1094*cdf0e10cSrcweir                         iLine->mnLineStartCharacterIndex,
1095*cdf0e10cSrcweir                         iLine->mnLineEndCharacterIndex);
1096*cdf0e10cSrcweir                 }
1097*cdf0e10cSrcweir             }
1098*cdf0e10cSrcweir         }
1099*cdf0e10cSrcweir         break;
1100*cdf0e10cSrcweir 
1101*cdf0e10cSrcweir         // Handle GLYPH and ATTRIBUTE_RUN like CHARACTER because we can not
1102*cdf0e10cSrcweir         // do better at the moment.
1103*cdf0e10cSrcweir         case AccessibleTextType::CHARACTER:
1104*cdf0e10cSrcweir         case AccessibleTextType::GLYPH:
1105*cdf0e10cSrcweir         case AccessibleTextType::ATTRIBUTE_RUN:
1106*cdf0e10cSrcweir             return CreateTextSegment(nIndex+nOffset, nIndex+nOffset+1);
1107*cdf0e10cSrcweir     }
1108*cdf0e10cSrcweir 
1109*cdf0e10cSrcweir     return TextSegment(::rtl::OUString(), 0,0);
1110*cdf0e10cSrcweir }
1111*cdf0e10cSrcweir 
1112*cdf0e10cSrcweir 
1113*cdf0e10cSrcweir 
1114*cdf0e10cSrcweir 
1115*cdf0e10cSrcweir TextSegment PresenterTextParagraph::GetWordTextSegment (
1116*cdf0e10cSrcweir     const sal_Int32 nOffset,
1117*cdf0e10cSrcweir     const sal_Int32 nIndex) const
1118*cdf0e10cSrcweir {
1119*cdf0e10cSrcweir     sal_Int32 nCurrentOffset (nOffset);
1120*cdf0e10cSrcweir     sal_Int32 nCurrentIndex (nIndex);
1121*cdf0e10cSrcweir 
1122*cdf0e10cSrcweir     i18n::Boundary aWordBoundary;
1123*cdf0e10cSrcweir     if (nCurrentOffset == 0)
1124*cdf0e10cSrcweir         aWordBoundary = mxBreakIterator->getWordBoundary(
1125*cdf0e10cSrcweir             msParagraphText,
1126*cdf0e10cSrcweir             nIndex,
1127*cdf0e10cSrcweir             lang::Locale(),
1128*cdf0e10cSrcweir             i18n::WordType::ANYWORD_IGNOREWHITESPACES,
1129*cdf0e10cSrcweir             sal_True);
1130*cdf0e10cSrcweir     else if (nCurrentOffset < 0)
1131*cdf0e10cSrcweir     {
1132*cdf0e10cSrcweir         while (nCurrentOffset<0 && nCurrentIndex>0)
1133*cdf0e10cSrcweir         {
1134*cdf0e10cSrcweir             aWordBoundary = mxBreakIterator->previousWord(
1135*cdf0e10cSrcweir                 msParagraphText,
1136*cdf0e10cSrcweir                 nCurrentIndex,
1137*cdf0e10cSrcweir                 lang::Locale(),
1138*cdf0e10cSrcweir                 i18n::WordType::ANYWORD_IGNOREWHITESPACES);
1139*cdf0e10cSrcweir             nCurrentIndex = aWordBoundary.startPos;
1140*cdf0e10cSrcweir             ++nCurrentOffset;
1141*cdf0e10cSrcweir         }
1142*cdf0e10cSrcweir     }
1143*cdf0e10cSrcweir     else
1144*cdf0e10cSrcweir     {
1145*cdf0e10cSrcweir         while (nCurrentOffset>0 && nCurrentIndex<=GetCharacterCount())
1146*cdf0e10cSrcweir         {
1147*cdf0e10cSrcweir             aWordBoundary = mxBreakIterator->nextWord(
1148*cdf0e10cSrcweir                 msParagraphText,
1149*cdf0e10cSrcweir                 nCurrentIndex,
1150*cdf0e10cSrcweir                 lang::Locale(),
1151*cdf0e10cSrcweir                 i18n::WordType::ANYWORD_IGNOREWHITESPACES);
1152*cdf0e10cSrcweir             nCurrentIndex = aWordBoundary.endPos;
1153*cdf0e10cSrcweir             --nCurrentOffset;
1154*cdf0e10cSrcweir         }
1155*cdf0e10cSrcweir     }
1156*cdf0e10cSrcweir 
1157*cdf0e10cSrcweir     return CreateTextSegment(aWordBoundary.startPos, aWordBoundary.endPos);
1158*cdf0e10cSrcweir }
1159*cdf0e10cSrcweir 
1160*cdf0e10cSrcweir 
1161*cdf0e10cSrcweir 
1162*cdf0e10cSrcweir 
1163*cdf0e10cSrcweir TextSegment PresenterTextParagraph::CreateTextSegment (
1164*cdf0e10cSrcweir     sal_Int32 nStartIndex,
1165*cdf0e10cSrcweir     sal_Int32 nEndIndex) const
1166*cdf0e10cSrcweir {
1167*cdf0e10cSrcweir     if (nEndIndex <= nStartIndex)
1168*cdf0e10cSrcweir         return TextSegment(
1169*cdf0e10cSrcweir             ::rtl::OUString(),
1170*cdf0e10cSrcweir             nStartIndex,
1171*cdf0e10cSrcweir             nEndIndex);
1172*cdf0e10cSrcweir     else
1173*cdf0e10cSrcweir         return TextSegment(
1174*cdf0e10cSrcweir             msParagraphText.copy(nStartIndex, nEndIndex-nStartIndex),
1175*cdf0e10cSrcweir             nStartIndex,
1176*cdf0e10cSrcweir             nEndIndex);
1177*cdf0e10cSrcweir }
1178*cdf0e10cSrcweir 
1179*cdf0e10cSrcweir 
1180*cdf0e10cSrcweir 
1181*cdf0e10cSrcweir 
1182*cdf0e10cSrcweir awt::Rectangle PresenterTextParagraph::GetCharacterBounds (
1183*cdf0e10cSrcweir     sal_Int32 nGlobalCharacterIndex,
1184*cdf0e10cSrcweir     const bool bCaretBox)
1185*cdf0e10cSrcweir {
1186*cdf0e10cSrcweir     // Find the line that contains the requested character and accumulate
1187*cdf0e10cSrcweir     // the previous line heights.
1188*cdf0e10cSrcweir     sal_Int32 nFirstCharacterIndex (0);
1189*cdf0e10cSrcweir     sal_Int32 nEndCharacterIndex (0);
1190*cdf0e10cSrcweir     double nX (mnXOrigin);
1191*cdf0e10cSrcweir     double nY (mnYOrigin + mnVerticalOffset + mnAscent);
1192*cdf0e10cSrcweir     const sal_Int8 nTextDirection (GetTextDirection());
1193*cdf0e10cSrcweir     for (sal_Int32 nLineIndex=0,nLineCount=maLines.size();
1194*cdf0e10cSrcweir          nLineIndex<nLineCount;
1195*cdf0e10cSrcweir          ++nLineIndex, nFirstCharacterIndex=nEndCharacterIndex, nY+=mnLineHeight)
1196*cdf0e10cSrcweir     {
1197*cdf0e10cSrcweir         Line& rLine (maLines[nLineIndex]);
1198*cdf0e10cSrcweir         // Skip lines before the indexed character.
1199*cdf0e10cSrcweir         if (nGlobalCharacterIndex >= rLine.mnLineEndCharacterIndex)
1200*cdf0e10cSrcweir             // When in the last line then allow the index past the last char.
1201*cdf0e10cSrcweir             if (nLineIndex<nLineCount-1)
1202*cdf0e10cSrcweir                 continue;
1203*cdf0e10cSrcweir 
1204*cdf0e10cSrcweir         rLine.ProvideCellBoxes();
1205*cdf0e10cSrcweir 
1206*cdf0e10cSrcweir         const sal_Int32 nCellIndex (nGlobalCharacterIndex - rLine.mnLineStartCharacterIndex);
1207*cdf0e10cSrcweir 
1208*cdf0e10cSrcweir         // The cell bounding box is defined relative to the origin of
1209*cdf0e10cSrcweir         // the current line.  Therefore we have to add the absolute
1210*cdf0e10cSrcweir         // position of the line.
1211*cdf0e10cSrcweir         geometry::RealRectangle2D rCellBox (rLine.maCellBoxes[
1212*cdf0e10cSrcweir             ::std::min(nCellIndex, rLine.maCellBoxes.getLength()-1)]);
1213*cdf0e10cSrcweir 
1214*cdf0e10cSrcweir         double nLeft = nX + rCellBox.X1;
1215*cdf0e10cSrcweir         double nRight = nX + rCellBox.X2;
1216*cdf0e10cSrcweir         if (nTextDirection == rendering::TextDirection::WEAK_RIGHT_TO_LEFT)
1217*cdf0e10cSrcweir         {
1218*cdf0e10cSrcweir             const double nOldRight (nRight);
1219*cdf0e10cSrcweir             nRight = rLine.mnWidth - nLeft;
1220*cdf0e10cSrcweir             nLeft = rLine.mnWidth - nOldRight;
1221*cdf0e10cSrcweir         }
1222*cdf0e10cSrcweir         double nTop (nY + rCellBox.Y1);
1223*cdf0e10cSrcweir         double nBottom (nY + rCellBox.Y2);
1224*cdf0e10cSrcweir         if (bCaretBox)
1225*cdf0e10cSrcweir         {
1226*cdf0e10cSrcweir             nTop = nTop - rCellBox.Y1 - mnAscent;
1227*cdf0e10cSrcweir             nBottom = nTop + mnLineHeight;
1228*cdf0e10cSrcweir             if (nCellIndex >= rLine.maCellBoxes.getLength())
1229*cdf0e10cSrcweir                 nLeft = nRight-2;
1230*cdf0e10cSrcweir             if (nLeft < nX)
1231*cdf0e10cSrcweir                 nLeft = nX;
1232*cdf0e10cSrcweir             nRight = nLeft+2;
1233*cdf0e10cSrcweir         }
1234*cdf0e10cSrcweir         else
1235*cdf0e10cSrcweir         {
1236*cdf0e10cSrcweir             nTop = nTop - rCellBox.Y1 - mnAscent;
1237*cdf0e10cSrcweir             nBottom = nTop + mnAscent + mnDescent;
1238*cdf0e10cSrcweir         }
1239*cdf0e10cSrcweir         const sal_Int32 nX1 = sal_Int32(floor(nLeft));
1240*cdf0e10cSrcweir         const sal_Int32 nY1 = sal_Int32(floor(nTop));
1241*cdf0e10cSrcweir         const sal_Int32 nX2 = sal_Int32(ceil(nRight));
1242*cdf0e10cSrcweir         const sal_Int32 nY2 = sal_Int32(ceil(nBottom));
1243*cdf0e10cSrcweir 
1244*cdf0e10cSrcweir         return awt::Rectangle(nX1,nY1,nX2-nX1+1,nY2-nY1+1);
1245*cdf0e10cSrcweir     }
1246*cdf0e10cSrcweir 
1247*cdf0e10cSrcweir     // We are still here.  That means that the given index lies past the
1248*cdf0e10cSrcweir     // last character in the paragraph.
1249*cdf0e10cSrcweir     // Return an empty box that lies past the last character.  Better than nothing.
1250*cdf0e10cSrcweir     return awt::Rectangle(sal_Int32(nX+0.5), sal_Int32(nY+0.5), 0, 0);
1251*cdf0e10cSrcweir }
1252*cdf0e10cSrcweir 
1253*cdf0e10cSrcweir 
1254*cdf0e10cSrcweir 
1255*cdf0e10cSrcweir 
1256*cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::GetIndexAtPoint (const awt::Point& rPoint) const
1257*cdf0e10cSrcweir {
1258*cdf0e10cSrcweir     (void)rPoint;
1259*cdf0e10cSrcweir     return -1;
1260*cdf0e10cSrcweir }
1261*cdf0e10cSrcweir 
1262*cdf0e10cSrcweir 
1263*cdf0e10cSrcweir 
1264*cdf0e10cSrcweir 
1265*cdf0e10cSrcweir sal_Int8 PresenterTextParagraph::GetTextDirection (void) const
1266*cdf0e10cSrcweir {
1267*cdf0e10cSrcweir     // Find first portion that has a non-neutral text direction.
1268*cdf0e10cSrcweir     sal_Int32 nPosition (0);
1269*cdf0e10cSrcweir     sal_Int32 nTextLength (msParagraphText.getLength());
1270*cdf0e10cSrcweir     while (nPosition < nTextLength)
1271*cdf0e10cSrcweir     {
1272*cdf0e10cSrcweir         const sal_Int16 nScriptDirection (
1273*cdf0e10cSrcweir             mxScriptTypeDetector->getScriptDirection(
1274*cdf0e10cSrcweir                 msParagraphText, nPosition, i18n::ScriptDirection::NEUTRAL));
1275*cdf0e10cSrcweir         switch (nScriptDirection)
1276*cdf0e10cSrcweir         {
1277*cdf0e10cSrcweir             case i18n::ScriptDirection::NEUTRAL:
1278*cdf0e10cSrcweir                 // continue looping.
1279*cdf0e10cSrcweir                 break;
1280*cdf0e10cSrcweir             case i18n::ScriptDirection::LEFT_TO_RIGHT:
1281*cdf0e10cSrcweir                 return rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
1282*cdf0e10cSrcweir 
1283*cdf0e10cSrcweir             case i18n::ScriptDirection::RIGHT_TO_LEFT:
1284*cdf0e10cSrcweir                 return rendering::TextDirection::WEAK_RIGHT_TO_LEFT;
1285*cdf0e10cSrcweir         }
1286*cdf0e10cSrcweir 
1287*cdf0e10cSrcweir         nPosition = mxScriptTypeDetector->endOfScriptDirection(
1288*cdf0e10cSrcweir             msParagraphText, nPosition, nScriptDirection);
1289*cdf0e10cSrcweir     }
1290*cdf0e10cSrcweir 
1291*cdf0e10cSrcweir     // All text in paragraph is neutral.  Fall back on writing mode taken
1292*cdf0e10cSrcweir     // from the XText (which may not be properly initialized.)
1293*cdf0e10cSrcweir     sal_Int8 nTextDirection(rendering::TextDirection::WEAK_LEFT_TO_RIGHT);
1294*cdf0e10cSrcweir     switch(mnWritingMode)
1295*cdf0e10cSrcweir     {
1296*cdf0e10cSrcweir         case text::WritingMode2::LR_TB:
1297*cdf0e10cSrcweir             nTextDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
1298*cdf0e10cSrcweir             break;
1299*cdf0e10cSrcweir 
1300*cdf0e10cSrcweir         case text::WritingMode2::RL_TB:
1301*cdf0e10cSrcweir             nTextDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT;
1302*cdf0e10cSrcweir             break;
1303*cdf0e10cSrcweir 
1304*cdf0e10cSrcweir         default:
1305*cdf0e10cSrcweir         case text::WritingMode2::TB_RL:
1306*cdf0e10cSrcweir         case text::WritingMode2::TB_LR:
1307*cdf0e10cSrcweir             // Can not handle this.  Use default and hope for the best.
1308*cdf0e10cSrcweir             break;
1309*cdf0e10cSrcweir     }
1310*cdf0e10cSrcweir     return nTextDirection;
1311*cdf0e10cSrcweir }
1312*cdf0e10cSrcweir 
1313*cdf0e10cSrcweir 
1314*cdf0e10cSrcweir 
1315*cdf0e10cSrcweir 
1316*cdf0e10cSrcweir bool PresenterTextParagraph::IsTextReferencePointLeft (void) const
1317*cdf0e10cSrcweir {
1318*cdf0e10cSrcweir     return mnWritingMode != text::WritingMode2::RL_TB;
1319*cdf0e10cSrcweir }
1320*cdf0e10cSrcweir 
1321*cdf0e10cSrcweir 
1322*cdf0e10cSrcweir 
1323*cdf0e10cSrcweir 
1324*cdf0e10cSrcweir void PresenterTextParagraph::SetupCellArray (
1325*cdf0e10cSrcweir     const PresenterTheme::SharedFontDescriptor& rpFont)
1326*cdf0e10cSrcweir {
1327*cdf0e10cSrcweir     maCells.clear();
1328*cdf0e10cSrcweir 
1329*cdf0e10cSrcweir     if ( ! rpFont || ! rpFont->mxFont.is())
1330*cdf0e10cSrcweir         return;
1331*cdf0e10cSrcweir 
1332*cdf0e10cSrcweir     sal_Int32 nPosition (0);
1333*cdf0e10cSrcweir     sal_Int32 nIndex (0);
1334*cdf0e10cSrcweir     const sal_Int32 nTextLength (msParagraphText.getLength());
1335*cdf0e10cSrcweir     const sal_Int8 nTextDirection (GetTextDirection());
1336*cdf0e10cSrcweir     while (nPosition < nTextLength)
1337*cdf0e10cSrcweir     {
1338*cdf0e10cSrcweir         const sal_Int32 nNewPosition (mxBreakIterator->nextCharacters(
1339*cdf0e10cSrcweir             msParagraphText,
1340*cdf0e10cSrcweir             nPosition,
1341*cdf0e10cSrcweir             lang::Locale(),
1342*cdf0e10cSrcweir             i18n::CharacterIteratorMode::SKIPCELL,
1343*cdf0e10cSrcweir             1,
1344*cdf0e10cSrcweir             nIndex));
1345*cdf0e10cSrcweir 
1346*cdf0e10cSrcweir         rendering::StringContext aContext (msParagraphText, nPosition, nNewPosition-nPosition);
1347*cdf0e10cSrcweir         Reference<rendering::XTextLayout> xLayout (
1348*cdf0e10cSrcweir             rpFont->mxFont->createTextLayout(aContext, nTextDirection, 0));
1349*cdf0e10cSrcweir         css::geometry::RealRectangle2D aCharacterBox (xLayout->queryTextBounds());
1350*cdf0e10cSrcweir 
1351*cdf0e10cSrcweir         maCells.push_back(Cell(
1352*cdf0e10cSrcweir             nPosition,
1353*cdf0e10cSrcweir             nNewPosition-nPosition,
1354*cdf0e10cSrcweir             aCharacterBox.X2-aCharacterBox.X1));
1355*cdf0e10cSrcweir 
1356*cdf0e10cSrcweir         nPosition = nNewPosition;
1357*cdf0e10cSrcweir     }
1358*cdf0e10cSrcweir }
1359*cdf0e10cSrcweir 
1360*cdf0e10cSrcweir 
1361*cdf0e10cSrcweir 
1362*cdf0e10cSrcweir 
1363*cdf0e10cSrcweir //===== PresenterTextCaret ================================================----
1364*cdf0e10cSrcweir 
1365*cdf0e10cSrcweir PresenterTextCaret::PresenterTextCaret (
1366*cdf0e10cSrcweir     const ::boost::function<css::awt::Rectangle(const sal_Int32,const sal_Int32)>& rCharacterBoundsAccess,
1367*cdf0e10cSrcweir     const ::boost::function<void(const css::awt::Rectangle&)>& rInvalidator)
1368*cdf0e10cSrcweir     : mnParagraphIndex(-1),
1369*cdf0e10cSrcweir       mnCharacterIndex(-1),
1370*cdf0e10cSrcweir       mnCaretBlinkTaskId(0),
1371*cdf0e10cSrcweir       mbIsCaretVisible(false),
1372*cdf0e10cSrcweir       maCharacterBoundsAccess(rCharacterBoundsAccess),
1373*cdf0e10cSrcweir       maInvalidator(rInvalidator),
1374*cdf0e10cSrcweir       maBroadcaster(),
1375*cdf0e10cSrcweir       maCaretBounds()
1376*cdf0e10cSrcweir {
1377*cdf0e10cSrcweir }
1378*cdf0e10cSrcweir 
1379*cdf0e10cSrcweir 
1380*cdf0e10cSrcweir 
1381*cdf0e10cSrcweir 
1382*cdf0e10cSrcweir PresenterTextCaret::~PresenterTextCaret (void)
1383*cdf0e10cSrcweir {
1384*cdf0e10cSrcweir     HideCaret();
1385*cdf0e10cSrcweir }
1386*cdf0e10cSrcweir 
1387*cdf0e10cSrcweir 
1388*cdf0e10cSrcweir 
1389*cdf0e10cSrcweir 
1390*cdf0e10cSrcweir void PresenterTextCaret::ShowCaret (void)
1391*cdf0e10cSrcweir {
1392*cdf0e10cSrcweir     if (mnCaretBlinkTaskId == 0)
1393*cdf0e10cSrcweir     {
1394*cdf0e10cSrcweir         mnCaretBlinkTaskId = PresenterTimer::ScheduleRepeatedTask (
1395*cdf0e10cSrcweir             ::boost::bind(&PresenterTextCaret::InvertCaret, this),
1396*cdf0e10cSrcweir             CaretBlinkIntervall,
1397*cdf0e10cSrcweir             CaretBlinkIntervall);
1398*cdf0e10cSrcweir     }
1399*cdf0e10cSrcweir     mbIsCaretVisible = true;
1400*cdf0e10cSrcweir }
1401*cdf0e10cSrcweir 
1402*cdf0e10cSrcweir 
1403*cdf0e10cSrcweir 
1404*cdf0e10cSrcweir 
1405*cdf0e10cSrcweir void PresenterTextCaret::HideCaret (void)
1406*cdf0e10cSrcweir {
1407*cdf0e10cSrcweir     if (mnCaretBlinkTaskId != 0)
1408*cdf0e10cSrcweir     {
1409*cdf0e10cSrcweir         PresenterTimer::CancelTask(mnCaretBlinkTaskId);
1410*cdf0e10cSrcweir         mnCaretBlinkTaskId = 0;
1411*cdf0e10cSrcweir     }
1412*cdf0e10cSrcweir     mbIsCaretVisible = false;
1413*cdf0e10cSrcweir     // Reset the caret position.
1414*cdf0e10cSrcweir     mnParagraphIndex = -1;
1415*cdf0e10cSrcweir     mnCharacterIndex = -1;
1416*cdf0e10cSrcweir }
1417*cdf0e10cSrcweir 
1418*cdf0e10cSrcweir 
1419*cdf0e10cSrcweir 
1420*cdf0e10cSrcweir 
1421*cdf0e10cSrcweir sal_Int32 PresenterTextCaret::GetParagraphIndex (void) const
1422*cdf0e10cSrcweir {
1423*cdf0e10cSrcweir     return mnParagraphIndex;
1424*cdf0e10cSrcweir }
1425*cdf0e10cSrcweir 
1426*cdf0e10cSrcweir 
1427*cdf0e10cSrcweir 
1428*cdf0e10cSrcweir 
1429*cdf0e10cSrcweir sal_Int32 PresenterTextCaret::GetCharacterIndex (void) const
1430*cdf0e10cSrcweir {
1431*cdf0e10cSrcweir     return mnCharacterIndex;
1432*cdf0e10cSrcweir }
1433*cdf0e10cSrcweir 
1434*cdf0e10cSrcweir 
1435*cdf0e10cSrcweir 
1436*cdf0e10cSrcweir 
1437*cdf0e10cSrcweir void PresenterTextCaret::SetPosition (
1438*cdf0e10cSrcweir     const sal_Int32 nParagraphIndex,
1439*cdf0e10cSrcweir     const sal_Int32 nCharacterIndex)
1440*cdf0e10cSrcweir {
1441*cdf0e10cSrcweir     if (mnParagraphIndex != nParagraphIndex
1442*cdf0e10cSrcweir         || mnCharacterIndex != nCharacterIndex)
1443*cdf0e10cSrcweir     {
1444*cdf0e10cSrcweir         if (mnParagraphIndex >= 0)
1445*cdf0e10cSrcweir             maInvalidator(maCaretBounds);
1446*cdf0e10cSrcweir 
1447*cdf0e10cSrcweir         const sal_Int32 nOldParagraphIndex (mnParagraphIndex);
1448*cdf0e10cSrcweir         const sal_Int32 nOldCharacterIndex (mnCharacterIndex);
1449*cdf0e10cSrcweir         mnParagraphIndex = nParagraphIndex;
1450*cdf0e10cSrcweir         mnCharacterIndex = nCharacterIndex;
1451*cdf0e10cSrcweir         maCaretBounds = maCharacterBoundsAccess(mnParagraphIndex, mnCharacterIndex);
1452*cdf0e10cSrcweir         if (mnParagraphIndex >= 0)
1453*cdf0e10cSrcweir             ShowCaret();
1454*cdf0e10cSrcweir         else
1455*cdf0e10cSrcweir             HideCaret();
1456*cdf0e10cSrcweir 
1457*cdf0e10cSrcweir         if (mnParagraphIndex >= 0)
1458*cdf0e10cSrcweir             maInvalidator(maCaretBounds);
1459*cdf0e10cSrcweir 
1460*cdf0e10cSrcweir         if (maBroadcaster)
1461*cdf0e10cSrcweir             maBroadcaster(
1462*cdf0e10cSrcweir                 nOldParagraphIndex,
1463*cdf0e10cSrcweir                 nOldCharacterIndex,
1464*cdf0e10cSrcweir                 mnParagraphIndex,
1465*cdf0e10cSrcweir                 mnCharacterIndex);
1466*cdf0e10cSrcweir 
1467*cdf0e10cSrcweir     }
1468*cdf0e10cSrcweir }
1469*cdf0e10cSrcweir 
1470*cdf0e10cSrcweir 
1471*cdf0e10cSrcweir 
1472*cdf0e10cSrcweir 
1473*cdf0e10cSrcweir bool PresenterTextCaret::IsVisible (void) const
1474*cdf0e10cSrcweir {
1475*cdf0e10cSrcweir     return mbIsCaretVisible;
1476*cdf0e10cSrcweir }
1477*cdf0e10cSrcweir 
1478*cdf0e10cSrcweir 
1479*cdf0e10cSrcweir 
1480*cdf0e10cSrcweir 
1481*cdf0e10cSrcweir void PresenterTextCaret::SetCaretMotionBroadcaster (
1482*cdf0e10cSrcweir     const ::boost::function<void(sal_Int32,sal_Int32,sal_Int32,sal_Int32)>& rBroadcaster)
1483*cdf0e10cSrcweir {
1484*cdf0e10cSrcweir     maBroadcaster = rBroadcaster;
1485*cdf0e10cSrcweir }
1486*cdf0e10cSrcweir 
1487*cdf0e10cSrcweir 
1488*cdf0e10cSrcweir 
1489*cdf0e10cSrcweir 
1490*cdf0e10cSrcweir css::awt::Rectangle PresenterTextCaret::GetBounds (void) const
1491*cdf0e10cSrcweir {
1492*cdf0e10cSrcweir     return maCaretBounds;
1493*cdf0e10cSrcweir }
1494*cdf0e10cSrcweir 
1495*cdf0e10cSrcweir 
1496*cdf0e10cSrcweir 
1497*cdf0e10cSrcweir 
1498*cdf0e10cSrcweir void PresenterTextCaret::InvertCaret (void)
1499*cdf0e10cSrcweir {
1500*cdf0e10cSrcweir     mbIsCaretVisible = !mbIsCaretVisible;
1501*cdf0e10cSrcweir     if (mnParagraphIndex >= 0)
1502*cdf0e10cSrcweir         maInvalidator(maCaretBounds);
1503*cdf0e10cSrcweir }
1504*cdf0e10cSrcweir 
1505*cdf0e10cSrcweir 
1506*cdf0e10cSrcweir 
1507*cdf0e10cSrcweir 
1508*cdf0e10cSrcweir 
1509*cdf0e10cSrcweir 
1510*cdf0e10cSrcweir 
1511*cdf0e10cSrcweir //===== PresenterTextParagraph::Cell ==========================================
1512*cdf0e10cSrcweir 
1513*cdf0e10cSrcweir PresenterTextParagraph::Cell::Cell (
1514*cdf0e10cSrcweir     const sal_Int32 nCharacterIndex,
1515*cdf0e10cSrcweir     const sal_Int32 nCharacterCount,
1516*cdf0e10cSrcweir     const double nCellWidth)
1517*cdf0e10cSrcweir     : mnCharacterIndex(nCharacterIndex),
1518*cdf0e10cSrcweir       mnCharacterCount(nCharacterCount),
1519*cdf0e10cSrcweir       mnCellWidth(nCellWidth)
1520*cdf0e10cSrcweir {
1521*cdf0e10cSrcweir }
1522*cdf0e10cSrcweir 
1523*cdf0e10cSrcweir 
1524*cdf0e10cSrcweir 
1525*cdf0e10cSrcweir 
1526*cdf0e10cSrcweir //===== PresenterTextParagraph::Line ==========================================
1527*cdf0e10cSrcweir 
1528*cdf0e10cSrcweir PresenterTextParagraph::Line::Line (
1529*cdf0e10cSrcweir     const sal_Int32 nLineStartCharacterIndex,
1530*cdf0e10cSrcweir     const sal_Int32 nLineEndCharacterIndex)
1531*cdf0e10cSrcweir     : mnLineStartCharacterIndex(nLineStartCharacterIndex),
1532*cdf0e10cSrcweir       mnLineEndCharacterIndex(nLineEndCharacterIndex),
1533*cdf0e10cSrcweir       mnLineStartCellIndex(-1), mnLineEndCellIndex(-1),
1534*cdf0e10cSrcweir       mxLayoutedLine(),
1535*cdf0e10cSrcweir       mnBaseLine(0), mnWidth(0),
1536*cdf0e10cSrcweir       maCellBoxes()
1537*cdf0e10cSrcweir {
1538*cdf0e10cSrcweir }
1539*cdf0e10cSrcweir 
1540*cdf0e10cSrcweir 
1541*cdf0e10cSrcweir 
1542*cdf0e10cSrcweir 
1543*cdf0e10cSrcweir sal_Int32 PresenterTextParagraph::Line::GetLength (void) const
1544*cdf0e10cSrcweir {
1545*cdf0e10cSrcweir     return mnLineEndCharacterIndex-mnLineStartCharacterIndex;
1546*cdf0e10cSrcweir }
1547*cdf0e10cSrcweir 
1548*cdf0e10cSrcweir 
1549*cdf0e10cSrcweir 
1550*cdf0e10cSrcweir 
1551*cdf0e10cSrcweir void PresenterTextParagraph::Line::ProvideCellBoxes (void)
1552*cdf0e10cSrcweir {
1553*cdf0e10cSrcweir     if ( ! IsEmpty() && maCellBoxes.getLength()==0)
1554*cdf0e10cSrcweir     {
1555*cdf0e10cSrcweir         if (mxLayoutedLine.is())
1556*cdf0e10cSrcweir             maCellBoxes = mxLayoutedLine->queryInkMeasures();
1557*cdf0e10cSrcweir         else
1558*cdf0e10cSrcweir         {
1559*cdf0e10cSrcweir             OSL_ASSERT(mxLayoutedLine.is());
1560*cdf0e10cSrcweir         }
1561*cdf0e10cSrcweir     }
1562*cdf0e10cSrcweir }
1563*cdf0e10cSrcweir 
1564*cdf0e10cSrcweir 
1565*cdf0e10cSrcweir 
1566*cdf0e10cSrcweir 
1567*cdf0e10cSrcweir void PresenterTextParagraph::Line::ProvideLayoutedLine (
1568*cdf0e10cSrcweir     const ::rtl::OUString& rsParagraphText,
1569*cdf0e10cSrcweir     const PresenterTheme::SharedFontDescriptor& rpFont,
1570*cdf0e10cSrcweir     const sal_Int8 nTextDirection)
1571*cdf0e10cSrcweir {
1572*cdf0e10cSrcweir     if ( ! mxLayoutedLine.is())
1573*cdf0e10cSrcweir     {
1574*cdf0e10cSrcweir         const rendering::StringContext aContext (
1575*cdf0e10cSrcweir             rsParagraphText,
1576*cdf0e10cSrcweir             mnLineStartCharacterIndex,
1577*cdf0e10cSrcweir             mnLineEndCharacterIndex - mnLineStartCharacterIndex);
1578*cdf0e10cSrcweir 
1579*cdf0e10cSrcweir         mxLayoutedLine = rpFont->mxFont->createTextLayout(
1580*cdf0e10cSrcweir             aContext,
1581*cdf0e10cSrcweir             nTextDirection,
1582*cdf0e10cSrcweir             0);
1583*cdf0e10cSrcweir     }
1584*cdf0e10cSrcweir }
1585*cdf0e10cSrcweir 
1586*cdf0e10cSrcweir 
1587*cdf0e10cSrcweir 
1588*cdf0e10cSrcweir 
1589*cdf0e10cSrcweir bool PresenterTextParagraph::Line::IsEmpty (void) const
1590*cdf0e10cSrcweir {
1591*cdf0e10cSrcweir     return mnLineStartCharacterIndex >= mnLineEndCharacterIndex;
1592*cdf0e10cSrcweir }
1593*cdf0e10cSrcweir 
1594*cdf0e10cSrcweir 
1595*cdf0e10cSrcweir 
1596*cdf0e10cSrcweir 
1597*cdf0e10cSrcweir } } // end of namespace ::sdext::presenter
1598