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