1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
)
35 maDecTrans
= mrSource
.getTextTransform();
36 mbNoDXArray
= mrSource
.getDXArray().empty();
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())))
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());
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
86 // evaluate using TextLayouter
87 fOffset
= maTextLayouter
.getTextWidth(mrSource
.getText(), mrSource
.getTextPosition(), nIndex
);
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);
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
));
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(
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()));
172 // create a SimpleTextPrimitive
173 rTempResult
.push_back(
174 new TextSimplePortionPrimitive2D(
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*/)
192 void TextBreakupHelper::breakup(BreakupUnit aBreakupUnit
)
194 if(!mrSource
.getTextLength())
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
);
214 case BreakupUnit::Character
:
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);
226 nNextCellBreak
= xBreakIterator
->nextCharacters(rTxt
, a
, rLocale
, css::i18n::CharacterIteratorMode::SKIPCELL
, 1, nDone
);
230 breakupPortion(aTempResult
, nCurrent
, a
- nCurrent
, false);
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
)
244 breakupPortion(aTempResult
, nCurrent
, a
- nCurrent
, true);
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
));
255 nCurrent
= nEndOfSpaces
;
259 nNextWordBoundary
= xBreakIterator
->getWordBoundary(rTxt
, a
+ 1, rLocale
, css::i18n::WordType::ANY_WORD
, true);
265 breakupPortion(aTempResult
, nCurrent
, a
- nCurrent
, true);
271 mxResult
= aTempResult
;
274 Primitive2DContainer
TextBreakupHelper::extractResult(BreakupUnit aBreakupUnit
)
278 breakup(aBreakupUnit
);
281 return std::move(mxResult
);
284 } // end of namespace
286 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */