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