calc: on editing invalidation of view with different zoom is wrong
[LibreOffice.git] / drawinglayer / source / primitive2d / textbreakuphelper.cxx
blob8f92d9817a0e6c825cbf462624b7e501cbca1dfd
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::primitive2d
31 TextBreakupHelper::TextBreakupHelper(const TextSimplePortionPrimitive2D& rSource)
32 : mrSource(rSource),
33 mbNoDXArray(false)
35 maDecTrans = mrSource.getTextTransform();
36 mbNoDXArray = mrSource.getDXArray().empty();
38 if(mbNoDXArray)
40 // init TextLayouter when no dxarray
41 maTextLayouter.setFontAttribute(
42 mrSource.getFontAttribute(),
43 maDecTrans.getScale().getX(),
44 maDecTrans.getScale().getY(),
45 mrSource.getLocale());
49 TextBreakupHelper::~TextBreakupHelper()
53 void TextBreakupHelper::breakupPortion(Primitive2DContainer& rTempResult, sal_Int32 nIndex, sal_Int32 nLength, bool bWordLineMode)
55 if(!(nLength && (nIndex != mrSource.getTextPosition() || nLength != mrSource.getTextLength())))
56 return;
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());
64 if(!mbNoDXArray)
66 // prepare new DXArray for the single word
67 aNewDXArray = std::vector< double >(
68 mrSource.getDXArray().begin() + (nIndex - mrSource.getTextPosition()),
69 mrSource.getDXArray().begin() + ((nIndex + nLength) - mrSource.getTextPosition()));
72 if(!mbNoDXArray && !mrSource.getKashidaArray().empty())
74 aNewKashidaArray = std::vector< sal_Bool >(
75 mrSource.getKashidaArray().begin() + (nIndex - mrSource.getTextPosition()),
76 mrSource.getKashidaArray().begin() + ((nIndex + nLength) - mrSource.getTextPosition()));
79 if(bNewStartIsNotOldStart)
81 // needs to be moved to a new start position
82 double fOffset(0.0);
84 if(mbNoDXArray)
86 // evaluate using TextLayouter
87 fOffset = maTextLayouter.getTextWidth(mrSource.getText(), mrSource.getTextPosition(), nIndex);
89 else
91 // get from DXArray
92 const sal_Int32 nIndex2(nIndex - mrSource.getTextPosition());
93 fOffset = mrSource.getDXArray()[nIndex2 - 1];
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());
102 if(!basegfx::fTools::equal(fFontScaleX, 1.0)
103 && !basegfx::fTools::equalZero(fFontScaleX))
105 fOffsetNoScale /= fFontScaleX;
108 // apply needed offset to transformation
109 aNewTransform.translate(fOffsetNoScale, 0.0);
111 if(!mbNoDXArray)
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());
117 for(sal_uInt32 a(0); a < nArraySize; a++)
119 aNewDXArray[a] -= fOffset;
124 // add text transformation to new transformation
125 // coverity[swapped_arguments : FALSE] - this is in the correct order
126 aNewTransform *= maDecTrans.getB2DHomMatrix();
128 // callback to allow evtl. changes
129 const bool bCreate(allowChange(rTempResult.size(), aNewTransform, nIndex, nLength));
131 if(!bCreate)
132 return;
134 // check if we have a decorated primitive as source
135 const TextDecoratedPortionPrimitive2D* pTextDecoratedPortionPrimitive2D =
136 dynamic_cast< const TextDecoratedPortionPrimitive2D* >(&mrSource);
138 if(pTextDecoratedPortionPrimitive2D)
140 // create a TextDecoratedPortionPrimitive2D
141 rTempResult.push_back(
142 new TextDecoratedPortionPrimitive2D(
143 aNewTransform,
144 mrSource.getText(),
145 nIndex,
146 nLength,
147 std::move(aNewDXArray),
148 std::move(aNewKashidaArray),
149 mrSource.getFontAttribute(),
150 mrSource.getLocale(),
151 mrSource.getFontColor(),
152 mrSource.getTextFillColor(),
154 pTextDecoratedPortionPrimitive2D->getOverlineColor(),
155 pTextDecoratedPortionPrimitive2D->getTextlineColor(),
156 pTextDecoratedPortionPrimitive2D->getFontOverline(),
157 pTextDecoratedPortionPrimitive2D->getFontUnderline(),
158 pTextDecoratedPortionPrimitive2D->getUnderlineAbove(),
159 pTextDecoratedPortionPrimitive2D->getTextStrikeout(),
161 // reset WordLineMode when BreakupUnit::Word is executed; else copy original
162 !bWordLineMode && pTextDecoratedPortionPrimitive2D->getWordLineMode(),
164 pTextDecoratedPortionPrimitive2D->getTextEmphasisMark(),
165 pTextDecoratedPortionPrimitive2D->getEmphasisMarkAbove(),
166 pTextDecoratedPortionPrimitive2D->getEmphasisMarkBelow(),
167 pTextDecoratedPortionPrimitive2D->getTextRelief(),
168 pTextDecoratedPortionPrimitive2D->getShadow()));
170 else
172 // create a SimpleTextPrimitive
173 rTempResult.push_back(
174 new TextSimplePortionPrimitive2D(
175 aNewTransform,
176 mrSource.getText(),
177 nIndex,
178 nLength,
179 std::move(aNewDXArray),
180 std::move(aNewKashidaArray),
181 mrSource.getFontAttribute(),
182 mrSource.getLocale(),
183 mrSource.getFontColor()));
187 bool TextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& /*rNewTransform*/, sal_uInt32 /*nIndex*/, sal_uInt32 /*nLength*/)
189 return true;
192 void TextBreakupHelper::breakup(BreakupUnit aBreakupUnit)
194 if(!mrSource.getTextLength())
195 return;
197 Primitive2DContainer aTempResult;
198 static css::uno::Reference< css::i18n::XBreakIterator > xBreakIterator;
200 if(!xBreakIterator.is())
202 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
203 xBreakIterator = css::i18n::BreakIterator::create(xContext);
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);
212 switch(aBreakupUnit)
214 case BreakupUnit::Character:
216 sal_Int32 nDone;
217 sal_Int32 nNextCellBreak(xBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
218 sal_Int32 a(nTextPosition);
220 for(; a < nTextPosition + nTextLength; a++)
222 if(a == nNextCellBreak)
224 breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
225 nCurrent = a;
226 nNextCellBreak = xBreakIterator->nextCharacters(rTxt, a, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
230 breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
231 break;
233 case BreakupUnit::Word:
235 css::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, true));
236 sal_Int32 a(nTextPosition);
238 for(; a < nTextPosition + nTextLength; a++)
240 if(a == nNextWordBoundary.endPos)
242 if(a > nCurrent)
244 breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
247 nCurrent = a;
249 // skip spaces (maybe enhanced with a bool later if needed)
251 const sal_Int32 nEndOfSpaces(xBreakIterator->endOfCharBlock(rTxt, a, rLocale, css::i18n::CharType::SPACE_SEPARATOR));
253 if(nEndOfSpaces > a)
255 nCurrent = nEndOfSpaces;
259 nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, css::i18n::WordType::ANY_WORD, true);
263 if(a > nCurrent)
265 breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
267 break;
271 mxResult = aTempResult;
274 Primitive2DContainer TextBreakupHelper::extractResult(BreakupUnit aBreakupUnit)
276 if(mxResult.empty())
278 breakup(aBreakupUnit);
281 return std::move(mxResult);
284 } // end of namespace
286 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */