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
33 TextBreakupHelper::TextBreakupHelper(const TextSimplePortionPrimitive2D
& rSource
)
40 maDecTrans
= mrSource
.getTextTransform();
41 mbNoDXArray
= mrSource
.getDXArray().empty();
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());
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
82 // evaluate using TextLayouter
83 fOffset
= maTextLayouter
.getTextWidth(mrSource
.getText(), mrSource
.getTextPosition(), nIndex
);
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);
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
));
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(
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()));
166 // create a SimpleTextPrimitive
167 rTempResult
.push_back(
168 new TextSimplePortionPrimitive2D(
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*/)
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
);
208 case BreakupUnit::Character
:
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);
220 nNextCellBreak
= xBreakIterator
->nextCharacters(rTxt
, a
, rLocale
, css::i18n::CharacterIteratorMode::SKIPCELL
, 1, nDone
);
224 breakupPortion(aTempResult
, nCurrent
, a
- nCurrent
, false);
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
)
238 breakupPortion(aTempResult
, nCurrent
, a
- nCurrent
, true);
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
));
249 nCurrent
= nEndOfSpaces
;
253 nNextWordBoundary
= xBreakIterator
->getWordBoundary(rTxt
, a
+ 1, rLocale
, css::i18n::WordType::ANY_WORD
, true);
259 breakupPortion(aTempResult
, nCurrent
, a
- nCurrent
, true);
265 mxResult
= aTempResult
;
269 const Primitive2DContainer
& TextBreakupHelper::getResult(BreakupUnit aBreakupUnit
) const
273 const_cast< TextBreakupHelper
* >(this)->breakup(aBreakupUnit
);
279 } // end of namespace primitive2d
280 } // end of namespace drawinglayer
282 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */