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