LCOV - code coverage report
Current view: top level - drawinglayer/source/primitive2d - textbreakuphelper.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 84 111 75.7 %
Date: 2015-06-13 12:38:46 Functions: 6 7 85.7 %
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 <drawinglayer/primitive2d/textbreakuphelper.hxx>
      21             : #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
      22             : #include <com/sun/star/i18n/BreakIterator.hpp>
      23             : #include <comphelper/processfactory.hxx>
      24             : #include <com/sun/star/i18n/CharacterIteratorMode.hdl>
      25             : #include <com/sun/star/i18n/WordType.hpp>
      26             : #include <com/sun/star/i18n/CharType.hpp>
      27             : 
      28             : 
      29             : 
      30             : namespace drawinglayer
      31             : {
      32             :     namespace primitive2d
      33             :     {
      34         929 :         TextBreakupHelper::TextBreakupHelper(const TextSimplePortionPrimitive2D& rSource)
      35             :         :   mrSource(rSource),
      36             :             mxResult(),
      37             :             maTextLayouter(),
      38             :             maDecTrans(),
      39         929 :             mbNoDXArray(false)
      40             :         {
      41             :             OSL_ENSURE(dynamic_cast< const TextSimplePortionPrimitive2D* >(&mrSource), "TextBreakupHelper with illegal primitive created (!)");
      42         929 :             maDecTrans = mrSource.getTextTransform();
      43         929 :             mbNoDXArray = mrSource.getDXArray().empty();
      44             : 
      45         929 :             if(mbNoDXArray)
      46             :             {
      47             :                 // init TextLayouter when no dxarray
      48             :                 maTextLayouter.setFontAttribute(
      49           0 :                     mrSource.getFontAttribute(),
      50           0 :                     maDecTrans.getScale().getX(),
      51           0 :                     maDecTrans.getScale().getY(),
      52           0 :                     mrSource.getLocale());
      53             :             }
      54         929 :         }
      55             : 
      56         929 :         TextBreakupHelper::~TextBreakupHelper()
      57             :         {
      58         929 :         }
      59             : 
      60        1274 :         void TextBreakupHelper::breakupPortion(Primitive2DVector& rTempResult, sal_Int32 nIndex, sal_Int32 nLength, bool bWordLineMode)
      61             :         {
      62        1274 :             if(nLength && !(nIndex == mrSource.getTextPosition() && nLength == mrSource.getTextLength()))
      63             :             {
      64             :                 // prepare values for new portion
      65         636 :                 basegfx::B2DHomMatrix aNewTransform;
      66        1272 :                 ::std::vector< double > aNewDXArray;
      67         636 :                 const bool bNewStartIsNotOldStart(nIndex > mrSource.getTextPosition());
      68             : 
      69         636 :                 if(!mbNoDXArray)
      70             :                 {
      71             :                     // prepare new DXArray for the single word
      72        3816 :                     aNewDXArray = ::std::vector< double >(
      73        1272 :                         mrSource.getDXArray().begin() + (nIndex - mrSource.getTextPosition()),
      74        1908 :                         mrSource.getDXArray().begin() + ((nIndex + nLength) - mrSource.getTextPosition()));
      75             :                 }
      76             : 
      77         636 :                 if(bNewStartIsNotOldStart)
      78             :                 {
      79             :                     // needs to be moved to a new start position
      80         345 :                     double fOffset(0.0);
      81             : 
      82         345 :                     if(mbNoDXArray)
      83             :                     {
      84             :                         // evaluate using TextLayouter
      85           0 :                         fOffset = maTextLayouter.getTextWidth(mrSource.getText(), mrSource.getTextPosition(), nIndex);
      86             :                     }
      87             :                     else
      88             :                     {
      89             :                         // get from DXArray
      90         345 :                         const sal_Int32 nIndex2(nIndex - mrSource.getTextPosition());
      91         345 :                         fOffset = mrSource.getDXArray()[nIndex2 - 1];
      92             :                     }
      93             : 
      94             :                     // need offset without FontScale for building the new transformation. The
      95             :                     // new transformation will be multiplied with the current text transformation
      96             :                     // so FontScale would be double
      97         345 :                     double fOffsetNoScale(fOffset);
      98         345 :                     const double fFontScaleX(maDecTrans.getScale().getX());
      99             : 
     100        1035 :                     if(!basegfx::fTools::equal(fFontScaleX, 1.0)
     101        1035 :                         && !basegfx::fTools::equalZero(fFontScaleX))
     102             :                     {
     103         345 :                         fOffsetNoScale /= fFontScaleX;
     104             :                     }
     105             : 
     106             :                     // apply needed offset to transformation
     107         345 :                     aNewTransform.translate(fOffsetNoScale, 0.0);
     108             : 
     109         345 :                     if(!mbNoDXArray)
     110             :                     {
     111             :                         // DXArray values need to be corrected with the offset, too. Here,
     112             :                         // take the scaled offset since the DXArray is scaled
     113         345 :                         const sal_uInt32 nArraySize(aNewDXArray.size());
     114             : 
     115        1380 :                         for(sal_uInt32 a(0); a < nArraySize; a++)
     116             :                         {
     117        1035 :                             aNewDXArray[a] -= fOffset;
     118             :                         }
     119             :                     }
     120             :                 }
     121             : 
     122             :                 // add text transformation to new transformation
     123         636 :                 aNewTransform = maDecTrans.getB2DHomMatrix() * aNewTransform;
     124             : 
     125             :                 // callback to allow evtl. changes
     126         636 :                 const bool bCreate(allowChange(rTempResult.size(), aNewTransform, nIndex, nLength));
     127             : 
     128         636 :                 if(bCreate)
     129             :                 {
     130             :                     // check if we have a decorated primitive as source
     131             :                     const TextDecoratedPortionPrimitive2D* pTextDecoratedPortionPrimitive2D =
     132         636 :                         dynamic_cast< const TextDecoratedPortionPrimitive2D* >(&mrSource);
     133             : 
     134         636 :                     if(pTextDecoratedPortionPrimitive2D)
     135             :                     {
     136             :                         // create a TextDecoratedPortionPrimitive2D
     137             :                         rTempResult.push_back(
     138             :                             new TextDecoratedPortionPrimitive2D(
     139             :                                 aNewTransform,
     140         636 :                                 mrSource.getText(),
     141             :                                 nIndex,
     142             :                                 nLength,
     143             :                                 aNewDXArray,
     144         636 :                                 mrSource.getFontAttribute(),
     145         636 :                                 mrSource.getLocale(),
     146         636 :                                 mrSource.getFontColor(),
     147         636 :                                 mrSource.getTextFillColor(),
     148             : 
     149             :                                 pTextDecoratedPortionPrimitive2D->getOverlineColor(),
     150             :                                 pTextDecoratedPortionPrimitive2D->getTextlineColor(),
     151             :                                 pTextDecoratedPortionPrimitive2D->getFontOverline(),
     152             :                                 pTextDecoratedPortionPrimitive2D->getFontUnderline(),
     153         636 :                                 pTextDecoratedPortionPrimitive2D->getUnderlineAbove(),
     154             :                                 pTextDecoratedPortionPrimitive2D->getTextStrikeout(),
     155             : 
     156             :                                 // reset WordLineMode when BreakupUnit_word is executed; else copy original
     157         636 :                                 !bWordLineMode && pTextDecoratedPortionPrimitive2D->getWordLineMode(),
     158             : 
     159             :                                 pTextDecoratedPortionPrimitive2D->getTextEmphasisMark(),
     160         636 :                                 pTextDecoratedPortionPrimitive2D->getEmphasisMarkAbove(),
     161         636 :                                 pTextDecoratedPortionPrimitive2D->getEmphasisMarkBelow(),
     162             :                                 pTextDecoratedPortionPrimitive2D->getTextRelief(),
     163        5724 :                                 pTextDecoratedPortionPrimitive2D->getShadow()));
     164             :                     }
     165             :                     else
     166             :                     {
     167             :                         // create a SimpleTextPrimitive
     168             :                         rTempResult.push_back(
     169             :                             new TextSimplePortionPrimitive2D(
     170             :                                 aNewTransform,
     171           0 :                                 mrSource.getText(),
     172             :                                 nIndex,
     173             :                                 nLength,
     174             :                                 aNewDXArray,
     175           0 :                                 mrSource.getFontAttribute(),
     176           0 :                                 mrSource.getLocale(),
     177           0 :                                 mrSource.getFontColor()));
     178             :                     }
     179         636 :                 }
     180             :             }
     181        1274 :         }
     182             : 
     183         636 :         bool TextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& /*rNewTransform*/, sal_uInt32 /*nIndex*/, sal_uInt32 /*nLength*/)
     184             :         {
     185         636 :             return true;
     186             :         }
     187             : 
     188         929 :         void TextBreakupHelper::breakup(BreakupUnit aBreakupUnit)
     189             :         {
     190         929 :             if(mrSource.getTextLength())
     191             :             {
     192         929 :                 Primitive2DVector aTempResult;
     193         929 :                 static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBreakIterator;
     194             : 
     195         929 :                 if(!xBreakIterator.is())
     196             :                 {
     197           2 :                     ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
     198           2 :                     xBreakIterator = ::com::sun::star::i18n::BreakIterator::create(xContext);
     199             :                 }
     200             : 
     201         929 :                 const OUString& rTxt = mrSource.getText();
     202         929 :                 const sal_Int32 nTextLength(mrSource.getTextLength());
     203         929 :                 const ::com::sun::star::lang::Locale& rLocale = mrSource.getLocale();
     204         929 :                 const sal_Int32 nTextPosition(mrSource.getTextPosition());
     205         929 :                 sal_Int32 nCurrent(nTextPosition);
     206             : 
     207         929 :                 switch(aBreakupUnit)
     208             :                 {
     209             :                     case BreakupUnit_character:
     210             :                     {
     211             :                         sal_Int32 nDone;
     212           0 :                         sal_Int32 nNextCellBreak(xBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
     213           0 :                         sal_Int32 a(nTextPosition);
     214             : 
     215           0 :                         for(; a < nTextPosition + nTextLength; a++)
     216             :                         {
     217           0 :                             if(a == nNextCellBreak)
     218             :                             {
     219           0 :                                 breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
     220           0 :                                 nCurrent = a;
     221           0 :                                 nNextCellBreak = xBreakIterator->nextCharacters(rTxt, a, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
     222             :                             }
     223             :                         }
     224             : 
     225           0 :                         breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
     226           0 :                         break;
     227             :                     }
     228             :                     case BreakupUnit_word:
     229             :                     {
     230         929 :                         ::com::sun::star::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
     231         929 :                         sal_Int32 a(nTextPosition);
     232             : 
     233        4875 :                         for(; a < nTextPosition + nTextLength; a++)
     234             :                         {
     235        3946 :                             if(a == nNextWordBoundary.endPos)
     236             :                             {
     237         459 :                                 if(a > nCurrent)
     238             :                                 {
     239         459 :                                     breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
     240             :                                 }
     241             : 
     242         459 :                                 nCurrent = a;
     243             : 
     244             :                                 // skip spaces (maybe enhanced with a bool later if needed)
     245             :                                 {
     246         459 :                                     const sal_Int32 nEndOfSpaces(xBreakIterator->endOfCharBlock(rTxt, a, rLocale, ::com::sun::star::i18n::CharType::SPACE_SEPARATOR));
     247             : 
     248         459 :                                     if(nEndOfSpaces > a)
     249             :                                     {
     250         416 :                                         nCurrent = nEndOfSpaces;
     251             :                                     }
     252             :                                 }
     253             : 
     254         459 :                                 nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
     255             :                             }
     256             :                         }
     257             : 
     258         929 :                         if(a > nCurrent)
     259             :                         {
     260         815 :                             breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
     261             :                         }
     262         929 :                         break;
     263             :                     }
     264             :                     case BreakupUnit_sentence:
     265             :                     {
     266           0 :                         sal_Int32 nNextSentenceBreak(xBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
     267           0 :                         sal_Int32 a(nTextPosition);
     268             : 
     269           0 :                         for(; a < nTextPosition + nTextLength; a++)
     270             :                         {
     271           0 :                             if(a == nNextSentenceBreak)
     272             :                             {
     273           0 :                                 breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
     274           0 :                                 nCurrent = a;
     275           0 :                                 nNextSentenceBreak = xBreakIterator->endOfSentence(rTxt, a + 1, rLocale);
     276             :                             }
     277             :                         }
     278             : 
     279           0 :                         breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
     280           0 :                         break;
     281             :                     }
     282             :                 }
     283             : 
     284         929 :                 mxResult = Primitive2DVectorToPrimitive2DSequence(aTempResult);
     285             :             }
     286         929 :         }
     287             : 
     288         929 :         const Primitive2DSequence& TextBreakupHelper::getResult(BreakupUnit aBreakupUnit) const
     289             :         {
     290         929 :             if(!mxResult.hasElements())
     291             :             {
     292         929 :                 const_cast< TextBreakupHelper* >(this)->breakup(aBreakupUnit);
     293             :             }
     294             : 
     295         929 :             return mxResult;
     296             :         }
     297             : 
     298             :     } // end of namespace primitive2d
     299             : } // end of namespace drawinglayer
     300             : 
     301             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11