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