LCOV - code coverage report
Current view: top level - sdext/source/presenter - PresenterTextView.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1 521 0.2 %
Date: 2015-06-13 12:38:46 Functions: 2 55 3.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11