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

Generated by: LCOV version 1.10