LibreOffice Module drawinglayer (master) 1
textbreakuphelper.cxx
Go to the documentation of this file.
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
22#include <com/sun/star/i18n/BreakIterator.hpp>
24#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
25#include <com/sun/star/i18n/WordType.hpp>
26#include <com/sun/star/i18n/CharType.hpp>
27
28
30{
32 : mrSource(rSource),
33 mbNoDXArray(false)
34 {
37
38 if(mbNoDXArray)
39 {
40 // init TextLayouter when no dxarray
46 }
47 }
48
50 {
51 }
52
53 void TextBreakupHelper::breakupPortion(Primitive2DContainer& rTempResult, sal_Int32 nIndex, sal_Int32 nLength, bool bWordLineMode)
54 {
56 return;
57
58 // prepare values for new portion
59 basegfx::B2DHomMatrix aNewTransform;
60 std::vector< double > aNewDXArray;
61 std::vector< sal_Bool > aNewKashidaArray;
62 const bool bNewStartIsNotOldStart(nIndex > mrSource.getTextPosition());
63
64 if(!mbNoDXArray)
65 {
66 // prepare new DXArray for the single word
67 aNewDXArray = std::vector< double >(
70 }
71
72 if(!mbNoDXArray && !mrSource.getKashidaArray().empty())
73 {
74 aNewKashidaArray = std::vector< sal_Bool >(
77 }
78
79 if(bNewStartIsNotOldStart)
80 {
81 // needs to be moved to a new start position
82 double fOffset(0.0);
83
84 if(mbNoDXArray)
85 {
86 // evaluate using TextLayouter
88 }
89 else
90 {
91 // get from DXArray
92 const sal_Int32 nIndex2(nIndex - mrSource.getTextPosition());
93 fOffset = mrSource.getDXArray()[nIndex2 - 1];
94 }
95
96 // need offset without FontScale for building the new transformation. The
97 // new transformation will be multiplied with the current text transformation
98 // so FontScale would be double
99 double fOffsetNoScale(fOffset);
100 const double fFontScaleX(maDecTrans.getScale().getX());
101
102 if(!basegfx::fTools::equal(fFontScaleX, 1.0)
103 && !basegfx::fTools::equalZero(fFontScaleX))
104 {
105 fOffsetNoScale /= fFontScaleX;
106 }
107
108 // apply needed offset to transformation
109 aNewTransform.translate(fOffsetNoScale, 0.0);
110
111 if(!mbNoDXArray)
112 {
113 // DXArray values need to be corrected with the offset, too. Here,
114 // take the scaled offset since the DXArray is scaled
115 const sal_uInt32 nArraySize(aNewDXArray.size());
116
117 for(sal_uInt32 a(0); a < nArraySize; a++)
118 {
119 aNewDXArray[a] -= fOffset;
120 }
121 }
122 }
123
124 // add text transformation to new transformation
125 // coverity[swapped_arguments : FALSE] - this is in the correct order
126 aNewTransform *= maDecTrans.getB2DHomMatrix();
127
128 // callback to allow evtl. changes
129 const bool bCreate(allowChange(rTempResult.size(), aNewTransform, nIndex, nLength));
130
131 if(!bCreate)
132 return;
133
134 // check if we have a decorated primitive as source
135 const TextDecoratedPortionPrimitive2D* pTextDecoratedPortionPrimitive2D =
136 dynamic_cast< const TextDecoratedPortionPrimitive2D* >(&mrSource);
137
138 if(pTextDecoratedPortionPrimitive2D)
139 {
140 // create a TextDecoratedPortionPrimitive2D
141 rTempResult.push_back(
143 aNewTransform,
145 nIndex,
146 nLength,
147 std::move(aNewDXArray),
148 std::move(aNewKashidaArray),
153
154 pTextDecoratedPortionPrimitive2D->getOverlineColor(),
155 pTextDecoratedPortionPrimitive2D->getTextlineColor(),
156 pTextDecoratedPortionPrimitive2D->getFontOverline(),
157 pTextDecoratedPortionPrimitive2D->getFontUnderline(),
158 pTextDecoratedPortionPrimitive2D->getUnderlineAbove(),
159 pTextDecoratedPortionPrimitive2D->getTextStrikeout(),
160
161 // reset WordLineMode when BreakupUnit::Word is executed; else copy original
162 !bWordLineMode && pTextDecoratedPortionPrimitive2D->getWordLineMode(),
163
164 pTextDecoratedPortionPrimitive2D->getTextEmphasisMark(),
165 pTextDecoratedPortionPrimitive2D->getEmphasisMarkAbove(),
166 pTextDecoratedPortionPrimitive2D->getEmphasisMarkBelow(),
167 pTextDecoratedPortionPrimitive2D->getTextRelief(),
168 pTextDecoratedPortionPrimitive2D->getShadow()));
169 }
170 else
171 {
172 // create a SimpleTextPrimitive
173 rTempResult.push_back(
175 aNewTransform,
177 nIndex,
178 nLength,
179 std::move(aNewDXArray),
180 std::move(aNewKashidaArray),
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
193 {
195 return;
196
197 Primitive2DContainer aTempResult;
198 static css::uno::Reference< css::i18n::XBreakIterator > xBreakIterator;
199
200 if(!xBreakIterator.is())
201 {
202 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
203 xBreakIterator = css::i18n::BreakIterator::create(xContext);
204 }
205
206 const OUString& rTxt = mrSource.getText();
207 const sal_Int32 nTextLength(mrSource.getTextLength());
208 const css::lang::Locale& rLocale = mrSource.getLocale();
209 const sal_Int32 nTextPosition(mrSource.getTextPosition());
210 sal_Int32 nCurrent(nTextPosition);
211
212 switch(aBreakupUnit)
213 {
215 {
216 sal_Int32 nDone;
217 sal_Int32 nNextCellBreak(xBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
218 sal_Int32 a(nTextPosition);
219
220 for(; a < nTextPosition + nTextLength; a++)
221 {
222 if(a == nNextCellBreak)
223 {
224 breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
225 nCurrent = a;
226 nNextCellBreak = xBreakIterator->nextCharacters(rTxt, a, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
227 }
228 }
229
230 breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
231 break;
232 }
234 {
235 css::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, true));
236 sal_Int32 a(nTextPosition);
237
238 for(; a < nTextPosition + nTextLength; a++)
239 {
240 if(a == nNextWordBoundary.endPos)
241 {
242 if(a > nCurrent)
243 {
244 breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
245 }
246
247 nCurrent = a;
248
249 // skip spaces (maybe enhanced with a bool later if needed)
250 {
251 const sal_Int32 nEndOfSpaces(xBreakIterator->endOfCharBlock(rTxt, a, rLocale, css::i18n::CharType::SPACE_SEPARATOR));
252
253 if(nEndOfSpaces > a)
254 {
255 nCurrent = nEndOfSpaces;
256 }
257 }
258
259 nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, css::i18n::WordType::ANY_WORD, true);
260 }
261 }
262
263 if(a > nCurrent)
264 {
265 breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
266 }
267 break;
268 }
269 }
270
271 mxResult = aTempResult;
272 }
273
275 {
276 if(mxResult.empty())
277 {
278 breakup(aBreakupUnit);
279 }
280
281 return std::move(mxResult);
282 }
283
284} // end of namespace
285
286/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void translate(double fX, double fY)
TYPE getX() const
TYPE getY() const
Primitive2DContainer extractResult(BreakupUnit aBreakupUnit=BreakupUnit::Character)
get result
const TextSimplePortionPrimitive2D & mrSource
TextBreakupHelper(const TextSimplePortionPrimitive2D &rSource)
void breakup(BreakupUnit aBreakupUnit)
breakup complete primitive
void breakupPortion(Primitive2DContainer &rTempResult, sal_Int32 nIndex, sal_Int32 nLength, bool bWordLineMode)
create a portion from nIndex to nLength and append to rTempResult
virtual bool allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix &rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength)
allow user callback to allow changes to the new TextTransformation.
basegfx::utils::B2DHomMatrixBufferedOnDemandDecompose maDecTrans
void setFontAttribute(const attribute::FontAttribute &rFontAttribute, double fFontScaleX, double fFontScaleY, const css::lang::Locale &rLocale)
double getTextWidth(const OUString &rText, sal_uInt32 nIndex, sal_uInt32 nLength) const
const ::std::vector< sal_Bool > & getKashidaArray() const
const ::std::vector< double > & getDXArray() const
const attribute::FontAttribute & getFontAttribute() const
const basegfx::B2DHomMatrix & getTextTransform() const
data read access
sal_Int32 nIndex
uno_Any a
bool equalZero(const T &rfVal)
bool equal(T const &rfValA, T const &rfValB)
sal_Int32 nLength