1*ddde725dSArmin Le Grand /************************************************************** 2*ddde725dSArmin Le Grand * 3*ddde725dSArmin Le Grand * Licensed to the Apache Software Foundation (ASF) under one 4*ddde725dSArmin Le Grand * or more contributor license agreements. See the NOTICE file 5*ddde725dSArmin Le Grand * distributed with this work for additional information 6*ddde725dSArmin Le Grand * regarding copyright ownership. The ASF licenses this file 7*ddde725dSArmin Le Grand * to you under the Apache License, Version 2.0 (the 8*ddde725dSArmin Le Grand * "License"); you may not use this file except in compliance 9*ddde725dSArmin Le Grand * with the License. You may obtain a copy of the License at 10*ddde725dSArmin Le Grand * 11*ddde725dSArmin Le Grand * http:\\www.apache.org\licenses\LICENSE-2.0 12*ddde725dSArmin Le Grand * 13*ddde725dSArmin Le Grand * Unless required by applicable law or agreed to in writing, 14*ddde725dSArmin Le Grand * software distributed under the License is distributed on an 15*ddde725dSArmin Le Grand * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*ddde725dSArmin Le Grand * KIND, either express or implied. See the License for the 17*ddde725dSArmin Le Grand * specific language governing permissions and limitations 18*ddde725dSArmin Le Grand * under the License. 19*ddde725dSArmin Le Grand * 20*ddde725dSArmin Le Grand *************************************************************/ 21*ddde725dSArmin Le Grand 22*ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove 23*ddde725dSArmin Le Grand #include "precompiled_drawinglayer.hxx" 24*ddde725dSArmin Le Grand 25*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/textbreakuphelper.hxx> 26*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx> 27*ddde725dSArmin Le Grand #include <com/sun/star/i18n/XBreakIterator.hpp> 28*ddde725dSArmin Le Grand #include <comphelper/processfactory.hxx> 29*ddde725dSArmin Le Grand #include <com/sun/star/i18n/CharacterIteratorMode.hdl> 30*ddde725dSArmin Le Grand #include <com/sun/star/i18n/WordType.hpp> 31*ddde725dSArmin Le Grand 32*ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 33*ddde725dSArmin Le Grand 34*ddde725dSArmin Le Grand namespace drawinglayer 35*ddde725dSArmin Le Grand { 36*ddde725dSArmin Le Grand namespace primitive2d 37*ddde725dSArmin Le Grand { 38*ddde725dSArmin Le Grand TextBreakupHelper::TextBreakupHelper(const Primitive2DReference& rxSource) 39*ddde725dSArmin Le Grand : mxSource(rxSource), 40*ddde725dSArmin Le Grand mxResult(), 41*ddde725dSArmin Le Grand mpSource(dynamic_cast< const TextSimplePortionPrimitive2D* >(rxSource.get())), 42*ddde725dSArmin Le Grand maTextLayouter(), 43*ddde725dSArmin Le Grand maDecTrans(), 44*ddde725dSArmin Le Grand mbNoDXArray() 45*ddde725dSArmin Le Grand { 46*ddde725dSArmin Le Grand if(mpSource) 47*ddde725dSArmin Le Grand { 48*ddde725dSArmin Le Grand maDecTrans = mpSource->getTextTransform(); 49*ddde725dSArmin Le Grand mbNoDXArray = mpSource->getDXArray().empty(); 50*ddde725dSArmin Le Grand 51*ddde725dSArmin Le Grand if(mbNoDXArray) 52*ddde725dSArmin Le Grand { 53*ddde725dSArmin Le Grand // init TextLayouter when no dxarray 54*ddde725dSArmin Le Grand maTextLayouter.setFontAttribute( 55*ddde725dSArmin Le Grand mpSource->getFontAttribute(), 56*ddde725dSArmin Le Grand maDecTrans.getScale().getX(), 57*ddde725dSArmin Le Grand maDecTrans.getScale().getY(), 58*ddde725dSArmin Le Grand mpSource->getLocale()); 59*ddde725dSArmin Le Grand } 60*ddde725dSArmin Le Grand } 61*ddde725dSArmin Le Grand } 62*ddde725dSArmin Le Grand 63*ddde725dSArmin Le Grand TextBreakupHelper::~TextBreakupHelper() 64*ddde725dSArmin Le Grand { 65*ddde725dSArmin Le Grand } 66*ddde725dSArmin Le Grand 67*ddde725dSArmin Le Grand void TextBreakupHelper::breakupPortion(Primitive2DVector& rTempResult, sal_uInt32 nIndex, sal_uInt32 nLength) 68*ddde725dSArmin Le Grand { 69*ddde725dSArmin Le Grand if(mpSource && nLength && !(nIndex == mpSource->getTextPosition() && nLength == mpSource->getTextLength())) 70*ddde725dSArmin Le Grand { 71*ddde725dSArmin Le Grand // prepare values for new portion 72*ddde725dSArmin Le Grand basegfx::B2DHomMatrix aNewTransform; 73*ddde725dSArmin Le Grand ::std::vector< double > aNewDXArray; 74*ddde725dSArmin Le Grand const bool bNewStartIsNotOldStart(nIndex > mpSource->getTextPosition()); 75*ddde725dSArmin Le Grand 76*ddde725dSArmin Le Grand if(!mbNoDXArray) 77*ddde725dSArmin Le Grand { 78*ddde725dSArmin Le Grand // prepare new DXArray for the single word 79*ddde725dSArmin Le Grand aNewDXArray = ::std::vector< double >( 80*ddde725dSArmin Le Grand mpSource->getDXArray().begin() + (nIndex - mpSource->getTextPosition()), 81*ddde725dSArmin Le Grand mpSource->getDXArray().begin() + ((nIndex + nLength) - mpSource->getTextPosition())); 82*ddde725dSArmin Le Grand } 83*ddde725dSArmin Le Grand 84*ddde725dSArmin Le Grand if(bNewStartIsNotOldStart) 85*ddde725dSArmin Le Grand { 86*ddde725dSArmin Le Grand // needs to be moved to a new start position 87*ddde725dSArmin Le Grand double fOffset(0.0); 88*ddde725dSArmin Le Grand 89*ddde725dSArmin Le Grand if(mbNoDXArray) 90*ddde725dSArmin Le Grand { 91*ddde725dSArmin Le Grand // evaluate using TextLayouter 92*ddde725dSArmin Le Grand fOffset = maTextLayouter.getTextWidth(mpSource->getText(), mpSource->getTextPosition(), nIndex); 93*ddde725dSArmin Le Grand } 94*ddde725dSArmin Le Grand else 95*ddde725dSArmin Le Grand { 96*ddde725dSArmin Le Grand // get from DXArray 97*ddde725dSArmin Le Grand const sal_uInt32 nIndex(static_cast< sal_uInt32 >(nIndex - mpSource->getTextPosition())); 98*ddde725dSArmin Le Grand fOffset = mpSource->getDXArray()[nIndex - 1]; 99*ddde725dSArmin Le Grand } 100*ddde725dSArmin Le Grand 101*ddde725dSArmin Le Grand // need offset without FontScale for building the new transformation. The 102*ddde725dSArmin Le Grand // new transformation will be multiplied with the current text transformation 103*ddde725dSArmin Le Grand // so FontScale would be double 104*ddde725dSArmin Le Grand double fOffsetNoScale(fOffset); 105*ddde725dSArmin Le Grand const double fFontScaleX(maDecTrans.getScale().getX()); 106*ddde725dSArmin Le Grand 107*ddde725dSArmin Le Grand if(!basegfx::fTools::equal(fFontScaleX, 1.0) 108*ddde725dSArmin Le Grand && !basegfx::fTools::equalZero(fFontScaleX)) 109*ddde725dSArmin Le Grand { 110*ddde725dSArmin Le Grand fOffsetNoScale /= fFontScaleX; 111*ddde725dSArmin Le Grand } 112*ddde725dSArmin Le Grand 113*ddde725dSArmin Le Grand // apply needed offset to transformation 114*ddde725dSArmin Le Grand aNewTransform.translate(fOffsetNoScale, 0.0); 115*ddde725dSArmin Le Grand 116*ddde725dSArmin Le Grand if(!mbNoDXArray) 117*ddde725dSArmin Le Grand { 118*ddde725dSArmin Le Grand // DXArray values need to be corrected with the offset, too. Here, 119*ddde725dSArmin Le Grand // take the scaled offset since the DXArray is scaled 120*ddde725dSArmin Le Grand const sal_uInt32 nArraySize(aNewDXArray.size()); 121*ddde725dSArmin Le Grand 122*ddde725dSArmin Le Grand for(sal_uInt32 a(0); a < nArraySize; a++) 123*ddde725dSArmin Le Grand { 124*ddde725dSArmin Le Grand aNewDXArray[a] -= fOffset; 125*ddde725dSArmin Le Grand } 126*ddde725dSArmin Le Grand } 127*ddde725dSArmin Le Grand } 128*ddde725dSArmin Le Grand 129*ddde725dSArmin Le Grand // add text transformation to new transformation 130*ddde725dSArmin Le Grand aNewTransform = maDecTrans.getB2DHomMatrix() * aNewTransform; 131*ddde725dSArmin Le Grand 132*ddde725dSArmin Le Grand // callback to allow evtl. changes 133*ddde725dSArmin Le Grand const bool bCreate(allowChange(rTempResult.size(), aNewTransform, nIndex, nLength)); 134*ddde725dSArmin Le Grand 135*ddde725dSArmin Le Grand if(bCreate) 136*ddde725dSArmin Le Grand { 137*ddde725dSArmin Le Grand // check if we have a decorated primitive as source 138*ddde725dSArmin Le Grand const TextDecoratedPortionPrimitive2D* pTextDecoratedPortionPrimitive2D = 139*ddde725dSArmin Le Grand dynamic_cast< const TextDecoratedPortionPrimitive2D* >(mpSource); 140*ddde725dSArmin Le Grand 141*ddde725dSArmin Le Grand if(pTextDecoratedPortionPrimitive2D) 142*ddde725dSArmin Le Grand { 143*ddde725dSArmin Le Grand // create a TextDecoratedPortionPrimitive2D 144*ddde725dSArmin Le Grand rTempResult.push_back( 145*ddde725dSArmin Le Grand new TextDecoratedPortionPrimitive2D( 146*ddde725dSArmin Le Grand aNewTransform, 147*ddde725dSArmin Le Grand mpSource->getText(), 148*ddde725dSArmin Le Grand nIndex, 149*ddde725dSArmin Le Grand nLength, 150*ddde725dSArmin Le Grand aNewDXArray, 151*ddde725dSArmin Le Grand mpSource->getFontAttribute(), 152*ddde725dSArmin Le Grand mpSource->getLocale(), 153*ddde725dSArmin Le Grand mpSource->getFontColor(), 154*ddde725dSArmin Le Grand 155*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getOverlineColor(), 156*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getTextlineColor(), 157*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getFontOverline(), 158*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getFontUnderline(), 159*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getUnderlineAbove(), 160*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getTextStrikeout(), 161*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getWordLineMode(), 162*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getTextEmphasisMark(), 163*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getEmphasisMarkAbove(), 164*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getEmphasisMarkBelow(), 165*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getTextRelief(), 166*ddde725dSArmin Le Grand pTextDecoratedPortionPrimitive2D->getShadow())); 167*ddde725dSArmin Le Grand } 168*ddde725dSArmin Le Grand else 169*ddde725dSArmin Le Grand { 170*ddde725dSArmin Le Grand // create a SimpleTextPrimitive 171*ddde725dSArmin Le Grand rTempResult.push_back( 172*ddde725dSArmin Le Grand new TextSimplePortionPrimitive2D( 173*ddde725dSArmin Le Grand aNewTransform, 174*ddde725dSArmin Le Grand mpSource->getText(), 175*ddde725dSArmin Le Grand nIndex, 176*ddde725dSArmin Le Grand nLength, 177*ddde725dSArmin Le Grand aNewDXArray, 178*ddde725dSArmin Le Grand mpSource->getFontAttribute(), 179*ddde725dSArmin Le Grand mpSource->getLocale(), 180*ddde725dSArmin Le Grand mpSource->getFontColor())); 181*ddde725dSArmin Le Grand } 182*ddde725dSArmin Le Grand } 183*ddde725dSArmin Le Grand } 184*ddde725dSArmin Le Grand } 185*ddde725dSArmin Le Grand 186*ddde725dSArmin Le Grand bool TextBreakupHelper::allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength) 187*ddde725dSArmin Le Grand { 188*ddde725dSArmin Le Grand return true; 189*ddde725dSArmin Le Grand } 190*ddde725dSArmin Le Grand 191*ddde725dSArmin Le Grand void TextBreakupHelper::breakup(BreakupUnit aBreakupUnit) 192*ddde725dSArmin Le Grand { 193*ddde725dSArmin Le Grand if(mpSource && mpSource->getTextLength()) 194*ddde725dSArmin Le Grand { 195*ddde725dSArmin Le Grand Primitive2DVector aTempResult; 196*ddde725dSArmin Le Grand static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBreakIterator; 197*ddde725dSArmin Le Grand 198*ddde725dSArmin Le Grand if(!xBreakIterator.is()) 199*ddde725dSArmin Le Grand { 200*ddde725dSArmin Le Grand ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory()); 201*ddde725dSArmin Le Grand xBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY); 202*ddde725dSArmin Le Grand } 203*ddde725dSArmin Le Grand 204*ddde725dSArmin Le Grand if(xBreakIterator.is()) 205*ddde725dSArmin Le Grand { 206*ddde725dSArmin Le Grand const rtl::OUString& rTxt = mpSource->getText(); 207*ddde725dSArmin Le Grand const sal_Int32 nTextLength(mpSource->getTextLength()); 208*ddde725dSArmin Le Grand const ::com::sun::star::lang::Locale& rLocale = mpSource->getLocale(); 209*ddde725dSArmin Le Grand const sal_Int32 nTextPosition(mpSource->getTextPosition()); 210*ddde725dSArmin Le Grand sal_Int32 nCurrent(nTextPosition); 211*ddde725dSArmin Le Grand 212*ddde725dSArmin Le Grand switch(aBreakupUnit) 213*ddde725dSArmin Le Grand { 214*ddde725dSArmin Le Grand case BreakupUnit_character: 215*ddde725dSArmin Le Grand { 216*ddde725dSArmin Le Grand sal_Int32 nDone; 217*ddde725dSArmin Le Grand sal_Int32 nNextCellBreak(xBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone)); 218*ddde725dSArmin Le Grand sal_Int32 a(nTextPosition); 219*ddde725dSArmin Le Grand 220*ddde725dSArmin Le Grand for(; a < nTextPosition + nTextLength; a++) 221*ddde725dSArmin Le Grand { 222*ddde725dSArmin Le Grand if(a == nNextCellBreak) 223*ddde725dSArmin Le Grand { 224*ddde725dSArmin Le Grand breakupPortion(aTempResult, nCurrent, a - nCurrent); 225*ddde725dSArmin Le Grand nCurrent = a; 226*ddde725dSArmin Le Grand nNextCellBreak = xBreakIterator->nextCharacters(rTxt, a, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone); 227*ddde725dSArmin Le Grand } 228*ddde725dSArmin Le Grand } 229*ddde725dSArmin Le Grand 230*ddde725dSArmin Le Grand breakupPortion(aTempResult, nCurrent, a - nCurrent); 231*ddde725dSArmin Le Grand break; 232*ddde725dSArmin Le Grand } 233*ddde725dSArmin Le Grand case BreakupUnit_word: 234*ddde725dSArmin Le Grand { 235*ddde725dSArmin Le Grand ::com::sun::star::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True)); 236*ddde725dSArmin Le Grand sal_Int32 a(nTextPosition); 237*ddde725dSArmin Le Grand 238*ddde725dSArmin Le Grand for(; a < nTextPosition + nTextLength; a++) 239*ddde725dSArmin Le Grand { 240*ddde725dSArmin Le Grand if(a == nNextWordBoundary.endPos) 241*ddde725dSArmin Le Grand { 242*ddde725dSArmin Le Grand breakupPortion(aTempResult, nCurrent, a - nCurrent); 243*ddde725dSArmin Le Grand nCurrent = a; 244*ddde725dSArmin Le Grand nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True); 245*ddde725dSArmin Le Grand } 246*ddde725dSArmin Le Grand } 247*ddde725dSArmin Le Grand 248*ddde725dSArmin Le Grand breakupPortion(aTempResult, nCurrent, a - nCurrent); 249*ddde725dSArmin Le Grand break; 250*ddde725dSArmin Le Grand } 251*ddde725dSArmin Le Grand case BreakupUnit_sentence: 252*ddde725dSArmin Le Grand { 253*ddde725dSArmin Le Grand sal_Int32 nNextSentenceBreak(xBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale)); 254*ddde725dSArmin Le Grand sal_Int32 a(nTextPosition); 255*ddde725dSArmin Le Grand 256*ddde725dSArmin Le Grand for(; a < nTextPosition + nTextLength; a++) 257*ddde725dSArmin Le Grand { 258*ddde725dSArmin Le Grand if(a == nNextSentenceBreak) 259*ddde725dSArmin Le Grand { 260*ddde725dSArmin Le Grand breakupPortion(aTempResult, nCurrent, a - nCurrent); 261*ddde725dSArmin Le Grand nCurrent = a; 262*ddde725dSArmin Le Grand nNextSentenceBreak = xBreakIterator->endOfSentence(rTxt, a + 1, rLocale); 263*ddde725dSArmin Le Grand } 264*ddde725dSArmin Le Grand } 265*ddde725dSArmin Le Grand 266*ddde725dSArmin Le Grand breakupPortion(aTempResult, nCurrent, a - nCurrent); 267*ddde725dSArmin Le Grand break; 268*ddde725dSArmin Le Grand } 269*ddde725dSArmin Le Grand } 270*ddde725dSArmin Le Grand } 271*ddde725dSArmin Le Grand 272*ddde725dSArmin Le Grand mxResult = Primitive2DVectorToPrimitive2DSequence(aTempResult); 273*ddde725dSArmin Le Grand } 274*ddde725dSArmin Le Grand } 275*ddde725dSArmin Le Grand 276*ddde725dSArmin Le Grand const Primitive2DSequence& TextBreakupHelper::getResult(BreakupUnit aBreakupUnit) const 277*ddde725dSArmin Le Grand { 278*ddde725dSArmin Le Grand if(mxResult.hasElements()) 279*ddde725dSArmin Le Grand { 280*ddde725dSArmin Le Grand return mxResult; 281*ddde725dSArmin Le Grand } 282*ddde725dSArmin Le Grand else if(mpSource) 283*ddde725dSArmin Le Grand { 284*ddde725dSArmin Le Grand const_cast< TextBreakupHelper* >(this)->breakup(aBreakupUnit); 285*ddde725dSArmin Le Grand } 286*ddde725dSArmin Le Grand 287*ddde725dSArmin Le Grand return mxResult; 288*ddde725dSArmin Le Grand } 289*ddde725dSArmin Le Grand 290*ddde725dSArmin Le Grand } // end of namespace primitive2d 291*ddde725dSArmin Le Grand } // end of namespace drawinglayer 292*ddde725dSArmin Le Grand 293*ddde725dSArmin Le Grand ////////////////////////////////////////////////////////////////////////////// 294*ddde725dSArmin Le Grand // eof 295