Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / drawinglayer / source / primitive2d / textbreakuphelper.cxx
blob82d5fcac7bb790b2827b07f7abb59eb9da986873
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <drawinglayer/primitive2d/textbreakuphelper.hxx>
21 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
22 #include <com/sun/star/i18n/BreakIterator.hpp>
23 #include <comphelper/processfactory.hxx>
24 #include <com/sun/star/i18n/CharacterIteratorMode.hpp>
25 #include <com/sun/star/i18n/WordType.hpp>
26 #include <com/sun/star/i18n/CharType.hpp>
29 namespace drawinglayer
31 namespace primitive2d
33 TextBreakupHelper::TextBreakupHelper(const TextSimplePortionPrimitive2D& rSource)
34 : mrSource(rSource),
35 mxResult(),
36 maTextLayouter(),
37 maDecTrans(),
38 mbNoDXArray(false)
40 maDecTrans = mrSource.getTextTransform();
41 mbNoDXArray = mrSource.getDXArray().empty();
43 if(mbNoDXArray)
45 // init TextLayouter when no dxarray
46 maTextLayouter.setFontAttribute(
47 mrSource.getFontAttribute(),
48 maDecTrans.getScale().getX(),
49 maDecTrans.getScale().getY(),
50 mrSource.getLocale());
54 TextBreakupHelper::~TextBreakupHelper()
58 void TextBreakupHelper::breakupPortion(Primitive2DContainer& rTempResult, sal_Int32 nIndex, sal_Int32 nLength, bool bWordLineMode)
60 if(nLength && !(nIndex == mrSource.getTextPosition() && nLength == mrSource.getTextLength()))
62 // prepare values for new portion
63 basegfx::B2DHomMatrix aNewTransform;
64 std::vector< double > aNewDXArray;
65 const bool bNewStartIsNotOldStart(nIndex > mrSource.getTextPosition());
67 if(!mbNoDXArray)
69 // prepare new DXArray for the single word
70 aNewDXArray = std::vector< double >(
71 mrSource.getDXArray().begin() + (nIndex - mrSource.getTextPosition()),
72 mrSource.getDXArray().begin() + ((nIndex + nLength) - mrSource.getTextPosition()));
75 if(bNewStartIsNotOldStart)
77 // needs to be moved to a new start position
78 double fOffset(0.0);
80 if(mbNoDXArray)
82 // evaluate using TextLayouter
83 fOffset = maTextLayouter.getTextWidth(mrSource.getText(), mrSource.getTextPosition(), nIndex);
85 else
87 // get from DXArray
88 const sal_Int32 nIndex2(nIndex - mrSource.getTextPosition());
89 fOffset = mrSource.getDXArray()[nIndex2 - 1];
92 // need offset without FontScale for building the new transformation. The
93 // new transformation will be multiplied with the current text transformation
94 // so FontScale would be double
95 double fOffsetNoScale(fOffset);
96 const double fFontScaleX(maDecTrans.getScale().getX());
98 if(!basegfx::fTools::equal(fFontScaleX, 1.0)
99 && !basegfx::fTools::equalZero(fFontScaleX))
101 fOffsetNoScale /= fFontScaleX;
104 // apply needed offset to transformation
105 aNewTransform.translate(fOffsetNoScale, 0.0);
107 if(!mbNoDXArray)
109 // DXArray values need to be corrected with the offset, too. Here,
110 // take the scaled offset since the DXArray is scaled
111 const sal_uInt32 nArraySize(aNewDXArray.size());
113 for(sal_uInt32 a(0); a < nArraySize; a++)
115 aNewDXArray[a] -= fOffset;
120 // add text transformation to new transformation
121 // coverity[swapped_arguments : FALSE] - this is in the correct order
122 aNewTransform *= maDecTrans.getB2DHomMatrix();
124 // callback to allow evtl. changes
125 const bool bCreate(allowChange(rTempResult.size(), aNewTransform, nIndex, nLength));
127 if(bCreate)
129 // check if we have a decorated primitive as source
130 const TextDecoratedPortionPrimitive2D* pTextDecoratedPortionPrimitive2D =
131 dynamic_cast< const TextDecoratedPortionPrimitive2D* >(&mrSource);
133 if(pTextDecoratedPortionPrimitive2D)
135 // create a TextDecoratedPortionPrimitive2D
136 rTempResult.push_back(
137 new TextDecoratedPortionPrimitive2D(
138 aNewTransform,
139 mrSource.getText(),
140 nIndex,
141 nLength,
142 aNewDXArray,
143 mrSource.getFontAttribute(),
144 mrSource.getLocale(),
145 mrSource.getFontColor(),
146 mrSource.getTextFillColor(),
148 pTextDecoratedPortionPrimitive2D->getOverlineColor(),
149 pTextDecoratedPortionPrimitive2D->getTextlineColor(),
150 pTextDecoratedPortionPrimitive2D->getFontOverline(),
151 pTextDecoratedPortionPrimitive2D->getFontUnderline(),
152 pTextDecoratedPortionPrimitive2D->getUnderlineAbove(),
153 pTextDecoratedPortionPrimitive2D->getTextStrikeout(),
155 // reset WordLineMode when BreakupUnit::Word is executed; else copy original
156 !bWordLineMode && pTextDecoratedPortionPrimitive2D->getWordLineMode(),
158 pTextDecoratedPortionPrimitive2D->getTextEmphasisMark(),
159 pTextDecoratedPortionPrimitive2D->getEmphasisMarkAbove(),
160 pTextDecoratedPortionPrimitive2D->getEmphasisMarkBelow(),
161 pTextDecoratedPortionPrimitive2D->getTextRelief(),
162 pTextDecoratedPortionPrimitive2D->getShadow()));
164 else
166 // create a SimpleTextPrimitive
167 rTempResult.push_back(
168 new TextSimplePortionPrimitive2D(
169 aNewTransform,
170 mrSource.getText(),
171 nIndex,
172 nLength,
173 aNewDXArray,
174 mrSource.getFontAttribute(),
175 mrSource.getLocale(),
176 mrSource.getFontColor()));
182 bool TextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& /*rNewTransform*/, sal_uInt32 /*nIndex*/, sal_uInt32 /*nLength*/)
184 return true;
187 void TextBreakupHelper::breakup(BreakupUnit aBreakupUnit)
189 if(mrSource.getTextLength())
191 Primitive2DContainer aTempResult;
192 static css::uno::Reference< css::i18n::XBreakIterator > xBreakIterator;
194 if(!xBreakIterator.is())
196 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
197 xBreakIterator = css::i18n::BreakIterator::create(xContext);
200 const OUString& rTxt = mrSource.getText();
201 const sal_Int32 nTextLength(mrSource.getTextLength());
202 const css::lang::Locale& rLocale = mrSource.getLocale();
203 const sal_Int32 nTextPosition(mrSource.getTextPosition());
204 sal_Int32 nCurrent(nTextPosition);
206 switch(aBreakupUnit)
208 case BreakupUnit::Character:
210 sal_Int32 nDone;
211 sal_Int32 nNextCellBreak(xBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
212 sal_Int32 a(nTextPosition);
214 for(; a < nTextPosition + nTextLength; a++)
216 if(a == nNextCellBreak)
218 breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
219 nCurrent = a;
220 nNextCellBreak = xBreakIterator->nextCharacters(rTxt, a, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
224 breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
225 break;
227 case BreakupUnit::Word:
229 css::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, true));
230 sal_Int32 a(nTextPosition);
232 for(; a < nTextPosition + nTextLength; a++)
234 if(a == nNextWordBoundary.endPos)
236 if(a > nCurrent)
238 breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
241 nCurrent = a;
243 // skip spaces (maybe enhanced with a bool later if needed)
245 const sal_Int32 nEndOfSpaces(xBreakIterator->endOfCharBlock(rTxt, a, rLocale, css::i18n::CharType::SPACE_SEPARATOR));
247 if(nEndOfSpaces > a)
249 nCurrent = nEndOfSpaces;
253 nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, css::i18n::WordType::ANY_WORD, true);
257 if(a > nCurrent)
259 breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
261 break;
265 mxResult = aTempResult;
269 const Primitive2DContainer& TextBreakupHelper::getResult(BreakupUnit aBreakupUnit) const
271 if(mxResult.empty())
273 const_cast< TextBreakupHelper* >(this)->breakup(aBreakupUnit);
276 return mxResult;
279 } // end of namespace primitive2d
280 } // end of namespace drawinglayer
282 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */