xref: /AOO41X/main/drawinglayer/source/primitive2d/textbreakuphelper.cxx (revision ddde725d65c83fe3ba1186d46f6e3e08f12ba47e)
1*ddde725dSArmin Le Grand /**************************************************************
2*ddde725dSArmin Le Grand  *
3*ddde725dSArmin Le Grand  * Licensed to the Apache Software Foundation (ASF) under one
4*ddde725dSArmin Le Grand  * or more contributor license agreements.  See the NOTICE file
5*ddde725dSArmin Le Grand  * distributed with this work for additional information
6*ddde725dSArmin Le Grand  * regarding copyright ownership.  The ASF licenses this file
7*ddde725dSArmin Le Grand  * to you under the Apache License, Version 2.0 (the
8*ddde725dSArmin Le Grand  * "License"); you may not use this file except in compliance
9*ddde725dSArmin Le Grand  * with the License.  You may obtain a copy of the License at
10*ddde725dSArmin Le Grand  *
11*ddde725dSArmin Le Grand  *   http:\\www.apache.org\licenses\LICENSE-2.0
12*ddde725dSArmin Le Grand  *
13*ddde725dSArmin Le Grand  * Unless required by applicable law or agreed to in writing,
14*ddde725dSArmin Le Grand  * software distributed under the License is distributed on an
15*ddde725dSArmin Le Grand  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*ddde725dSArmin Le Grand  * KIND, either express or implied.  See the License for the
17*ddde725dSArmin Le Grand  * specific language governing permissions and limitations
18*ddde725dSArmin Le Grand  * under the License.
19*ddde725dSArmin Le Grand  *
20*ddde725dSArmin Le Grand  *************************************************************/
21*ddde725dSArmin Le Grand 
22*ddde725dSArmin Le Grand // MARKER(update_precomp.py): autogen include statement, do not remove
23*ddde725dSArmin Le Grand #include "precompiled_drawinglayer.hxx"
24*ddde725dSArmin Le Grand 
25*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/textbreakuphelper.hxx>
26*ddde725dSArmin Le Grand #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
27*ddde725dSArmin Le Grand #include <com/sun/star/i18n/XBreakIterator.hpp>
28*ddde725dSArmin Le Grand #include <comphelper/processfactory.hxx>
29*ddde725dSArmin Le Grand #include <com/sun/star/i18n/CharacterIteratorMode.hdl>
30*ddde725dSArmin Le Grand #include <com/sun/star/i18n/WordType.hpp>
31*ddde725dSArmin Le Grand 
32*ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
33*ddde725dSArmin Le Grand 
34*ddde725dSArmin Le Grand namespace drawinglayer
35*ddde725dSArmin Le Grand {
36*ddde725dSArmin Le Grand 	namespace primitive2d
37*ddde725dSArmin Le Grand 	{
38*ddde725dSArmin Le Grand         TextBreakupHelper::TextBreakupHelper(const Primitive2DReference& rxSource)
39*ddde725dSArmin Le Grand         :   mxSource(rxSource),
40*ddde725dSArmin Le Grand             mxResult(),
41*ddde725dSArmin Le Grand             mpSource(dynamic_cast< const TextSimplePortionPrimitive2D* >(rxSource.get())),
42*ddde725dSArmin Le Grand             maTextLayouter(),
43*ddde725dSArmin Le Grand             maDecTrans(),
44*ddde725dSArmin Le Grand             mbNoDXArray()
45*ddde725dSArmin Le Grand         {
46*ddde725dSArmin Le Grand             if(mpSource)
47*ddde725dSArmin Le Grand             {
48*ddde725dSArmin Le Grand                 maDecTrans = mpSource->getTextTransform();
49*ddde725dSArmin Le Grand                 mbNoDXArray = mpSource->getDXArray().empty();
50*ddde725dSArmin Le Grand 
51*ddde725dSArmin Le Grand                 if(mbNoDXArray)
52*ddde725dSArmin Le Grand                 {
53*ddde725dSArmin Le Grand                     // init TextLayouter when no dxarray
54*ddde725dSArmin Le Grand 				    maTextLayouter.setFontAttribute(
55*ddde725dSArmin Le Grand                         mpSource->getFontAttribute(),
56*ddde725dSArmin Le Grand                         maDecTrans.getScale().getX(),
57*ddde725dSArmin Le Grand                         maDecTrans.getScale().getY(),
58*ddde725dSArmin Le Grand                         mpSource->getLocale());
59*ddde725dSArmin Le Grand                 }
60*ddde725dSArmin Le Grand             }
61*ddde725dSArmin Le Grand         }
62*ddde725dSArmin Le Grand 
63*ddde725dSArmin Le Grand         TextBreakupHelper::~TextBreakupHelper()
64*ddde725dSArmin Le Grand         {
65*ddde725dSArmin Le Grand         }
66*ddde725dSArmin Le Grand 
67*ddde725dSArmin Le Grand         void TextBreakupHelper::breakupPortion(Primitive2DVector& rTempResult, sal_uInt32 nIndex, sal_uInt32 nLength)
68*ddde725dSArmin Le Grand         {
69*ddde725dSArmin Le Grand             if(mpSource && nLength && !(nIndex == mpSource->getTextPosition() && nLength == mpSource->getTextLength()))
70*ddde725dSArmin Le Grand             {
71*ddde725dSArmin Le Grand  				// prepare values for new portion
72*ddde725dSArmin Le Grand 				basegfx::B2DHomMatrix aNewTransform;
73*ddde725dSArmin Le Grand 				::std::vector< double > aNewDXArray;
74*ddde725dSArmin Le Grand 				const bool bNewStartIsNotOldStart(nIndex > mpSource->getTextPosition());
75*ddde725dSArmin Le Grand 
76*ddde725dSArmin Le Grand 				if(!mbNoDXArray)
77*ddde725dSArmin Le Grand 				{
78*ddde725dSArmin Le Grand 					// prepare new DXArray for the single word
79*ddde725dSArmin Le Grand 					aNewDXArray = ::std::vector< double >(
80*ddde725dSArmin Le Grand 						mpSource->getDXArray().begin() + (nIndex - mpSource->getTextPosition()),
81*ddde725dSArmin Le Grand 						mpSource->getDXArray().begin() + ((nIndex + nLength) - mpSource->getTextPosition()));
82*ddde725dSArmin Le Grand 				}
83*ddde725dSArmin Le Grand 
84*ddde725dSArmin Le Grand 				if(bNewStartIsNotOldStart)
85*ddde725dSArmin Le Grand 				{
86*ddde725dSArmin Le Grand 					// needs to be moved to a new start position
87*ddde725dSArmin Le Grand 					double fOffset(0.0);
88*ddde725dSArmin Le Grand 
89*ddde725dSArmin Le Grand 					if(mbNoDXArray)
90*ddde725dSArmin Le Grand 					{
91*ddde725dSArmin Le Grand 						// evaluate using TextLayouter
92*ddde725dSArmin Le Grand 						fOffset = maTextLayouter.getTextWidth(mpSource->getText(), mpSource->getTextPosition(), nIndex);
93*ddde725dSArmin Le Grand 					}
94*ddde725dSArmin Le Grand 					else
95*ddde725dSArmin Le Grand 					{
96*ddde725dSArmin Le Grand 						// get from DXArray
97*ddde725dSArmin Le Grand 						const sal_uInt32 nIndex(static_cast< sal_uInt32 >(nIndex - mpSource->getTextPosition()));
98*ddde725dSArmin Le Grand 						fOffset = mpSource->getDXArray()[nIndex - 1];
99*ddde725dSArmin Le Grand 					}
100*ddde725dSArmin Le Grand 
101*ddde725dSArmin Le Grand                     // need offset without FontScale for building the new transformation. The
102*ddde725dSArmin Le Grand                     // new transformation will be multiplied with the current text transformation
103*ddde725dSArmin Le Grand                     // so FontScale would be double
104*ddde725dSArmin Le Grand 					double fOffsetNoScale(fOffset);
105*ddde725dSArmin Le Grand                     const double fFontScaleX(maDecTrans.getScale().getX());
106*ddde725dSArmin Le Grand 
107*ddde725dSArmin Le Grand                     if(!basegfx::fTools::equal(fFontScaleX, 1.0)
108*ddde725dSArmin Le Grand                         && !basegfx::fTools::equalZero(fFontScaleX))
109*ddde725dSArmin Le Grand                     {
110*ddde725dSArmin Le Grand                         fOffsetNoScale /= fFontScaleX;
111*ddde725dSArmin Le Grand                     }
112*ddde725dSArmin Le Grand 
113*ddde725dSArmin Le Grand 					// apply needed offset to transformation
114*ddde725dSArmin Le Grand                     aNewTransform.translate(fOffsetNoScale, 0.0);
115*ddde725dSArmin Le Grand 
116*ddde725dSArmin Le Grand 					if(!mbNoDXArray)
117*ddde725dSArmin Le Grand 					{
118*ddde725dSArmin Le Grand 						// DXArray values need to be corrected with the offset, too. Here,
119*ddde725dSArmin Le Grand                         // take the scaled offset since the DXArray is scaled
120*ddde725dSArmin Le Grand 						const sal_uInt32 nArraySize(aNewDXArray.size());
121*ddde725dSArmin Le Grand 
122*ddde725dSArmin Le Grand 						for(sal_uInt32 a(0); a < nArraySize; a++)
123*ddde725dSArmin Le Grand 						{
124*ddde725dSArmin Le Grand 							aNewDXArray[a] -= fOffset;
125*ddde725dSArmin Le Grand 						}
126*ddde725dSArmin Le Grand 					}
127*ddde725dSArmin Le Grand 				}
128*ddde725dSArmin Le Grand 
129*ddde725dSArmin Le Grand 				// add text transformation to new transformation
130*ddde725dSArmin Le Grand 				aNewTransform = maDecTrans.getB2DHomMatrix() * aNewTransform;
131*ddde725dSArmin Le Grand 
132*ddde725dSArmin Le Grand                 // callback to allow evtl. changes
133*ddde725dSArmin Le Grand                 const bool bCreate(allowChange(rTempResult.size(), aNewTransform, nIndex, nLength));
134*ddde725dSArmin Le Grand 
135*ddde725dSArmin Le Grand                 if(bCreate)
136*ddde725dSArmin Le Grand                 {
137*ddde725dSArmin Le Grand                     // check if we have a decorated primitive as source
138*ddde725dSArmin Le Grand                     const TextDecoratedPortionPrimitive2D* pTextDecoratedPortionPrimitive2D =
139*ddde725dSArmin Le Grand                         dynamic_cast< const TextDecoratedPortionPrimitive2D* >(mpSource);
140*ddde725dSArmin Le Grand 
141*ddde725dSArmin Le Grand                     if(pTextDecoratedPortionPrimitive2D)
142*ddde725dSArmin Le Grand                     {
143*ddde725dSArmin Le Grand                         // create a TextDecoratedPortionPrimitive2D
144*ddde725dSArmin Le Grand 	                    rTempResult.push_back(
145*ddde725dSArmin Le Grand                             new TextDecoratedPortionPrimitive2D(
146*ddde725dSArmin Le Grand                                 aNewTransform,
147*ddde725dSArmin Le Grand                                 mpSource->getText(),
148*ddde725dSArmin Le Grand 				                nIndex,
149*ddde725dSArmin Le Grand 				                nLength,
150*ddde725dSArmin Le Grand                                 aNewDXArray,
151*ddde725dSArmin Le Grand                                 mpSource->getFontAttribute(),
152*ddde725dSArmin Le Grand                                 mpSource->getLocale(),
153*ddde725dSArmin Le Grand                                 mpSource->getFontColor(),
154*ddde725dSArmin Le Grand 
155*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getOverlineColor(),
156*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getTextlineColor(),
157*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getFontOverline(),
158*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getFontUnderline(),
159*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getUnderlineAbove(),
160*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getTextStrikeout(),
161*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getWordLineMode(),
162*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getTextEmphasisMark(),
163*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getEmphasisMarkAbove(),
164*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getEmphasisMarkBelow(),
165*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getTextRelief(),
166*ddde725dSArmin Le Grand                                 pTextDecoratedPortionPrimitive2D->getShadow()));
167*ddde725dSArmin Le Grand                     }
168*ddde725dSArmin Le Grand                     else
169*ddde725dSArmin Le Grand                     {
170*ddde725dSArmin Le Grand                         // create a SimpleTextPrimitive
171*ddde725dSArmin Le Grand 	                    rTempResult.push_back(
172*ddde725dSArmin Le Grand                             new TextSimplePortionPrimitive2D(
173*ddde725dSArmin Le Grand                                 aNewTransform,
174*ddde725dSArmin Le Grand                                 mpSource->getText(),
175*ddde725dSArmin Le Grand 				                nIndex,
176*ddde725dSArmin Le Grand 				                nLength,
177*ddde725dSArmin Le Grand                                 aNewDXArray,
178*ddde725dSArmin Le Grand                                 mpSource->getFontAttribute(),
179*ddde725dSArmin Le Grand                                 mpSource->getLocale(),
180*ddde725dSArmin Le Grand                                 mpSource->getFontColor()));
181*ddde725dSArmin Le Grand                     }
182*ddde725dSArmin Le Grand                 }
183*ddde725dSArmin Le Grand             }
184*ddde725dSArmin Le Grand         }
185*ddde725dSArmin Le Grand 
186*ddde725dSArmin Le Grand         bool TextBreakupHelper::allowChange(sal_uInt32 nCount, basegfx::B2DHomMatrix& rNewTransform, sal_uInt32 nIndex, sal_uInt32 nLength)
187*ddde725dSArmin Le Grand         {
188*ddde725dSArmin Le Grand             return true;
189*ddde725dSArmin Le Grand         }
190*ddde725dSArmin Le Grand 
191*ddde725dSArmin Le Grand         void TextBreakupHelper::breakup(BreakupUnit aBreakupUnit)
192*ddde725dSArmin Le Grand         {
193*ddde725dSArmin Le Grand             if(mpSource && mpSource->getTextLength())
194*ddde725dSArmin Le Grand             {
195*ddde725dSArmin Le Grand                 Primitive2DVector aTempResult;
196*ddde725dSArmin Le Grand                 static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBreakIterator;
197*ddde725dSArmin Le Grand 
198*ddde725dSArmin Le Grand                 if(!xBreakIterator.is())
199*ddde725dSArmin Le Grand                 {
200*ddde725dSArmin Le Grand                     ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
201*ddde725dSArmin Le Grand                     xBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY);
202*ddde725dSArmin Le Grand                 }
203*ddde725dSArmin Le Grand 
204*ddde725dSArmin Le Grand                 if(xBreakIterator.is())
205*ddde725dSArmin Le Grand                 {
206*ddde725dSArmin Le Grand                     const rtl::OUString& rTxt = mpSource->getText();
207*ddde725dSArmin Le Grand                     const sal_Int32 nTextLength(mpSource->getTextLength());
208*ddde725dSArmin Le Grand                     const ::com::sun::star::lang::Locale& rLocale = mpSource->getLocale();
209*ddde725dSArmin Le Grand                     const sal_Int32 nTextPosition(mpSource->getTextPosition());
210*ddde725dSArmin Le Grand                     sal_Int32 nCurrent(nTextPosition);
211*ddde725dSArmin Le Grand 
212*ddde725dSArmin Le Grand                     switch(aBreakupUnit)
213*ddde725dSArmin Le Grand                     {
214*ddde725dSArmin Le Grand                         case BreakupUnit_character:
215*ddde725dSArmin Le Grand                         {
216*ddde725dSArmin Le Grand                             sal_Int32 nDone;
217*ddde725dSArmin Le Grand                             sal_Int32 nNextCellBreak(xBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
218*ddde725dSArmin Le Grand                             sal_Int32 a(nTextPosition);
219*ddde725dSArmin Le Grand 
220*ddde725dSArmin Le Grand                             for(; a < nTextPosition + nTextLength; a++)
221*ddde725dSArmin Le Grand                             {
222*ddde725dSArmin Le Grand                                 if(a == nNextCellBreak)
223*ddde725dSArmin Le Grand                                 {
224*ddde725dSArmin Le Grand                                     breakupPortion(aTempResult, nCurrent, a - nCurrent);
225*ddde725dSArmin Le Grand                                     nCurrent = a;
226*ddde725dSArmin Le Grand                                     nNextCellBreak = xBreakIterator->nextCharacters(rTxt, a, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
227*ddde725dSArmin Le Grand                                 }
228*ddde725dSArmin Le Grand                             }
229*ddde725dSArmin Le Grand 
230*ddde725dSArmin Le Grand                             breakupPortion(aTempResult, nCurrent, a - nCurrent);
231*ddde725dSArmin Le Grand                             break;
232*ddde725dSArmin Le Grand                         }
233*ddde725dSArmin Le Grand                         case BreakupUnit_word:
234*ddde725dSArmin Le Grand                         {
235*ddde725dSArmin Le Grand                             ::com::sun::star::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
236*ddde725dSArmin Le Grand                             sal_Int32 a(nTextPosition);
237*ddde725dSArmin Le Grand 
238*ddde725dSArmin Le Grand                             for(; a < nTextPosition + nTextLength; a++)
239*ddde725dSArmin Le Grand                             {
240*ddde725dSArmin Le Grand                                 if(a == nNextWordBoundary.endPos)
241*ddde725dSArmin Le Grand                                 {
242*ddde725dSArmin Le Grand                                     breakupPortion(aTempResult, nCurrent, a - nCurrent);
243*ddde725dSArmin Le Grand                                     nCurrent = a;
244*ddde725dSArmin Le Grand                                     nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
245*ddde725dSArmin Le Grand                                 }
246*ddde725dSArmin Le Grand                             }
247*ddde725dSArmin Le Grand 
248*ddde725dSArmin Le Grand                             breakupPortion(aTempResult, nCurrent, a - nCurrent);
249*ddde725dSArmin Le Grand                             break;
250*ddde725dSArmin Le Grand                         }
251*ddde725dSArmin Le Grand                         case BreakupUnit_sentence:
252*ddde725dSArmin Le Grand                         {
253*ddde725dSArmin Le Grand                             sal_Int32 nNextSentenceBreak(xBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
254*ddde725dSArmin Le Grand                             sal_Int32 a(nTextPosition);
255*ddde725dSArmin Le Grand 
256*ddde725dSArmin Le Grand                             for(; a < nTextPosition + nTextLength; a++)
257*ddde725dSArmin Le Grand                             {
258*ddde725dSArmin Le Grand                                 if(a == nNextSentenceBreak)
259*ddde725dSArmin Le Grand                                 {
260*ddde725dSArmin Le Grand                                     breakupPortion(aTempResult, nCurrent, a - nCurrent);
261*ddde725dSArmin Le Grand                                     nCurrent = a;
262*ddde725dSArmin Le Grand                                     nNextSentenceBreak = xBreakIterator->endOfSentence(rTxt, a + 1, rLocale);
263*ddde725dSArmin Le Grand                                 }
264*ddde725dSArmin Le Grand                             }
265*ddde725dSArmin Le Grand 
266*ddde725dSArmin Le Grand                             breakupPortion(aTempResult, nCurrent, a - nCurrent);
267*ddde725dSArmin Le Grand                             break;
268*ddde725dSArmin Le Grand                         }
269*ddde725dSArmin Le Grand                     }
270*ddde725dSArmin Le Grand                 }
271*ddde725dSArmin Le Grand 
272*ddde725dSArmin Le Grand                 mxResult = Primitive2DVectorToPrimitive2DSequence(aTempResult);
273*ddde725dSArmin Le Grand             }
274*ddde725dSArmin Le Grand         }
275*ddde725dSArmin Le Grand 
276*ddde725dSArmin Le Grand         const Primitive2DSequence& TextBreakupHelper::getResult(BreakupUnit aBreakupUnit) const
277*ddde725dSArmin Le Grand         {
278*ddde725dSArmin Le Grand             if(mxResult.hasElements())
279*ddde725dSArmin Le Grand             {
280*ddde725dSArmin Le Grand                 return mxResult;
281*ddde725dSArmin Le Grand             }
282*ddde725dSArmin Le Grand             else if(mpSource)
283*ddde725dSArmin Le Grand             {
284*ddde725dSArmin Le Grand                 const_cast< TextBreakupHelper* >(this)->breakup(aBreakupUnit);
285*ddde725dSArmin Le Grand             }
286*ddde725dSArmin Le Grand 
287*ddde725dSArmin Le Grand             return mxResult;
288*ddde725dSArmin Le Grand         }
289*ddde725dSArmin Le Grand 
290*ddde725dSArmin Le Grand 	} // end of namespace primitive2d
291*ddde725dSArmin Le Grand } // end of namespace drawinglayer
292*ddde725dSArmin Le Grand 
293*ddde725dSArmin Le Grand //////////////////////////////////////////////////////////////////////////////
294*ddde725dSArmin Le Grand // eof
295