1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svtools.hxx"
26 #include <svtools/scriptedtext.hxx>
27 #include <vector>
28 #include <rtl/ustring.hxx>
29 #include <vcl/outdev.hxx>
30 #include <vcl/font.hxx>
31 #include <tools/debug.hxx>
32 #include <com/sun/star/i18n/ScriptType.hpp>
33
34
35 using namespace ::std;
36 using namespace ::rtl;
37 using namespace ::com::sun::star;
38
39
40 //_____________________________________________________________________________
41
42 class SvtScriptedTextHelper_Impl
43 {
44 private:
45 OutputDevice& mrOutDevice; /// The output device for drawing the text.
46 Font maLatinFont; /// The font for latin text portions.
47 Font maAsianFont; /// The font for asian text portions.
48 Font maCmplxFont; /// The font for complex text portions.
49 Font maDefltFont; /// The default font of the output device.
50 OUString maText; /// The text.
51
52 vector< sal_Int32 > maPosVec; /// The start position of each text portion.
53 vector< sal_Int16 > maScriptVec; /// The script type of each text portion.
54 vector< sal_Int32 > maWidthVec; /// The output width of each text portion.
55 Size maTextSize; /// The size the text will take in the current output device.
56
57 /** Assignment operator not implemented to prevent usage. */
58 SvtScriptedTextHelper_Impl& operator=( const SvtScriptedTextHelper_Impl& );
59
60 /** Gets the font of the given script type. */
61 const Font& GetFont( sal_uInt16 _nScript ) const;
62 /** Sets a font on the output device depending on the script type. */
SetOutDevFont(sal_uInt16 _nScript)63 inline void SetOutDevFont( sal_uInt16 _nScript )
64 { mrOutDevice.SetFont( GetFont( _nScript ) ); }
65 /** Fills maPosVec with positions of all changes of script type.
66 This method expects correctly initialized maPosVec and maScriptVec. */
67 void CalculateSizes();
68 /** Fills maPosVec with positions of all changes of script type and
69 maScriptVec with the script type of each portion. */
70 void CalculateBreaks(
71 const uno::Reference< i18n::XBreakIterator >& _xBreakIter );
72
73 public:
74 /** This constructor sets an output device and fonts for all script types. */
75 SvtScriptedTextHelper_Impl(
76 OutputDevice& _rOutDevice,
77 Font* _pLatinFont,
78 Font* _pAsianFont,
79 Font* _pCmplxFont );
80 /** Copy constructor. */
81 SvtScriptedTextHelper_Impl(
82 const SvtScriptedTextHelper_Impl& _rCopy );
83 /** Destructor. */
84 ~SvtScriptedTextHelper_Impl();
85
86 /** Sets new fonts and recalculates the text width. */
87 void SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont );
88 /** Sets a new text and calculates all script breaks and the text width. */
89 void SetText(
90 const OUString& _rText,
91 const uno::Reference< i18n::XBreakIterator >& _xBreakIter );
92
93 /** Returns the previously set text. */
94 const OUString& GetText() const;
95 /** Returns a size struct containing the width and height of the text in the current output device. */
96 const Size& GetTextSize() const;
97
98 /** Draws the text in the current output device. */
99 void DrawText( const Point& _rPos );
100 };
101
102
SvtScriptedTextHelper_Impl(OutputDevice & _rOutDevice,Font * _pLatinFont,Font * _pAsianFont,Font * _pCmplxFont)103 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl(
104 OutputDevice& _rOutDevice,
105 Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) :
106 mrOutDevice( _rOutDevice ),
107 maLatinFont( _pLatinFont ? *_pLatinFont : _rOutDevice.GetFont() ),
108 maAsianFont( _pAsianFont ? *_pAsianFont : _rOutDevice.GetFont() ),
109 maCmplxFont( _pCmplxFont ? *_pCmplxFont : _rOutDevice.GetFont() ),
110 maDefltFont( _rOutDevice.GetFont() )
111 {
112 }
113
SvtScriptedTextHelper_Impl(const SvtScriptedTextHelper_Impl & _rCopy)114 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( const SvtScriptedTextHelper_Impl& _rCopy ) :
115 mrOutDevice( _rCopy.mrOutDevice ),
116 maLatinFont( _rCopy.maLatinFont ),
117 maAsianFont( _rCopy.maAsianFont ),
118 maCmplxFont( _rCopy.maCmplxFont ),
119 maDefltFont( _rCopy.maDefltFont ),
120 maText( _rCopy.maText ),
121 maPosVec( _rCopy.maPosVec ),
122 maScriptVec( _rCopy.maScriptVec ),
123 maWidthVec( _rCopy.maWidthVec ),
124 maTextSize( _rCopy.maTextSize )
125 {
126 }
127
~SvtScriptedTextHelper_Impl()128 SvtScriptedTextHelper_Impl::~SvtScriptedTextHelper_Impl()
129 {
130 }
131
GetFont(sal_uInt16 _nScript) const132 const Font& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript ) const
133 {
134 switch( _nScript )
135 {
136 case i18n::ScriptType::LATIN: return maLatinFont;
137 case i18n::ScriptType::ASIAN: return maAsianFont;
138 case i18n::ScriptType::COMPLEX: return maCmplxFont;
139 }
140 return maDefltFont;
141 }
142
CalculateSizes()143 void SvtScriptedTextHelper_Impl::CalculateSizes()
144 {
145 maTextSize.Width() = maTextSize.Height() = 0;
146 maDefltFont = mrOutDevice.GetFont();
147
148 // calculate text portion widths and total width
149 maWidthVec.clear();
150 if( !maPosVec.empty() )
151 {
152 DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(),
153 "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" );
154
155 xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] );
156 xub_StrLen nNextPos;
157 sal_Int32 nPosVecSize = maPosVec.size();
158 sal_Int32 nPosVecIndex = 1;
159
160 sal_Int16 nScript;
161 sal_Int32 nScriptVecIndex = 0;
162
163 sal_Int32 nCurrWidth;
164
165 while( nPosVecIndex < nPosVecSize )
166 {
167 nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] );
168 nScript = maScriptVec[ nScriptVecIndex++ ];
169
170 SetOutDevFont( nScript );
171 nCurrWidth = mrOutDevice.GetTextWidth( maText, nThisPos, nNextPos - nThisPos );
172 maWidthVec.push_back( nCurrWidth );
173 maTextSize.Width() += nCurrWidth;
174 nThisPos = nNextPos;
175 }
176 }
177
178 // calculate maximum font height
179 SetOutDevFont( i18n::ScriptType::LATIN );
180 maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() );
181 SetOutDevFont( i18n::ScriptType::ASIAN );
182 maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() );
183 SetOutDevFont( i18n::ScriptType::COMPLEX );
184 maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() );
185
186 mrOutDevice.SetFont( maDefltFont );
187 }
188
CalculateBreaks(const uno::Reference<i18n::XBreakIterator> & _xBreakIter)189 void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
190 {
191 maPosVec.clear();
192 maScriptVec.clear();
193
194 DBG_ASSERT( _xBreakIter.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" );
195
196 sal_Int32 nLen = maText.getLength();
197 if( nLen )
198 {
199 if( _xBreakIter.is() )
200 {
201 sal_Int32 nThisPos = 0; // first position of this portion
202 sal_Int32 nNextPos = 0; // first position of next portion
203 sal_Int16 nPortScript; // script type of this portion
204 do
205 {
206 nPortScript = _xBreakIter->getScriptType( maText, nThisPos );
207 nNextPos = _xBreakIter->endOfScript( maText, nThisPos, nPortScript );
208
209 switch( nPortScript )
210 {
211 case i18n::ScriptType::LATIN:
212 case i18n::ScriptType::ASIAN:
213 case i18n::ScriptType::COMPLEX:
214 maPosVec.push_back( nThisPos );
215 maScriptVec.push_back( nPortScript );
216 break;
217 default:
218 {
219 /* *** handling of weak characters ***
220 - first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font
221 - weak portion follows another portion: Script type of preceding portion is used */
222 if( maPosVec.empty() )
223 {
224 sal_Int32 nCharIx = 0;
225 sal_Int32 nNextCharIx = 0;
226 sal_Int16 nScript;
227 do
228 {
229 nScript = i18n::ScriptType::LATIN;
230 while( (nScript != i18n::ScriptType::WEAK) && (nCharIx == nNextCharIx) )
231 {
232 nNextCharIx = mrOutDevice.HasGlyphs( GetFont( nScript ), maText, sal::static_int_cast< sal_uInt16 >(nCharIx), sal::static_int_cast< sal_uInt16 >(nNextPos - nCharIx) );
233 if( nCharIx == nNextCharIx )
234 ++nScript;
235 }
236 if( nNextCharIx == nCharIx )
237 ++nNextCharIx;
238
239 maPosVec.push_back( nCharIx );
240 maScriptVec.push_back( nScript );
241 nCharIx = nNextCharIx;
242 }
243 while( nCharIx < nNextPos );
244 }
245 // nothing to do for following portions
246 }
247 }
248 nThisPos = nNextPos;
249 }
250 while( (0 <= nThisPos) && (nThisPos < nLen) );
251 }
252 else // no break iterator: whole text LATIN
253 {
254 maPosVec.push_back( 0 );
255 maScriptVec.push_back( i18n::ScriptType::LATIN );
256 }
257
258 // push end position of last portion
259 if( !maPosVec.empty() )
260 maPosVec.push_back( nLen );
261 }
262 CalculateSizes();
263 }
264
SetFonts(Font * _pLatinFont,Font * _pAsianFont,Font * _pCmplxFont)265 void SvtScriptedTextHelper_Impl::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont )
266 {
267 maLatinFont = _pLatinFont ? *_pLatinFont : maDefltFont;
268 maAsianFont = _pAsianFont ? *_pAsianFont : maDefltFont;
269 maCmplxFont = _pCmplxFont ? *_pCmplxFont : maDefltFont;
270 CalculateSizes();
271 }
272
SetText(const OUString & _rText,const uno::Reference<i18n::XBreakIterator> & _xBreakIter)273 void SvtScriptedTextHelper_Impl::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
274 {
275 maText = _rText;
276 CalculateBreaks( _xBreakIter );
277 }
278
GetText() const279 const OUString& SvtScriptedTextHelper_Impl::GetText() const
280 {
281 return maText;
282 }
283
GetTextSize() const284 const Size& SvtScriptedTextHelper_Impl::GetTextSize() const
285 {
286 return maTextSize;
287 }
288
DrawText(const Point & _rPos)289 void SvtScriptedTextHelper_Impl::DrawText( const Point& _rPos )
290 {
291 if( !maText.getLength() || maPosVec.empty() )
292 return;
293
294 DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
295 DBG_ASSERT( maScriptVec.size() == maWidthVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
296
297 maDefltFont = mrOutDevice.GetFont();
298 Point aCurrPos( _rPos );
299 xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] );
300 xub_StrLen nNextPos;
301 sal_Int32 nPosVecSize = maPosVec.size();
302 sal_Int32 nPosVecIndex = 1;
303
304 sal_Int16 nScript;
305 sal_Int32 nVecIndex = 0;
306
307 while( nPosVecIndex < nPosVecSize )
308 {
309 nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] );
310 nScript = maScriptVec[ nVecIndex ];
311
312 SetOutDevFont( nScript );
313 mrOutDevice.DrawText( aCurrPos, maText, nThisPos, nNextPos - nThisPos );
314 aCurrPos.X() += maWidthVec[ nVecIndex++ ];
315 aCurrPos.X() += mrOutDevice.GetTextHeight() / 5; // add 20% of font height as portion spacing
316 nThisPos = nNextPos;
317 }
318 mrOutDevice.SetFont( maDefltFont );
319 }
320
321
322 //_____________________________________________________________________________
323
SvtScriptedTextHelper(OutputDevice & _rOutDevice)324 SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice& _rOutDevice ) :
325 mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, NULL, NULL, NULL ) )
326 {
327 }
328
SvtScriptedTextHelper(OutputDevice & _rOutDevice,Font * _pLatinFont,Font * _pAsianFont,Font * _pCmplxFont)329 SvtScriptedTextHelper::SvtScriptedTextHelper(
330 OutputDevice& _rOutDevice,
331 Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) :
332 mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, _pLatinFont, _pAsianFont, _pCmplxFont ) )
333 {
334 }
335
SvtScriptedTextHelper(const SvtScriptedTextHelper & _rCopy)336 SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper& _rCopy ) :
337 mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy.mpImpl ) )
338 {
339 }
340
~SvtScriptedTextHelper()341 SvtScriptedTextHelper::~SvtScriptedTextHelper()
342 {
343 delete mpImpl;
344 }
345
SetFonts(Font * _pLatinFont,Font * _pAsianFont,Font * _pCmplxFont)346 void SvtScriptedTextHelper::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont )
347 {
348 mpImpl->SetFonts( _pLatinFont, _pAsianFont, _pCmplxFont );
349 }
350
SetDefaultFont()351 void SvtScriptedTextHelper::SetDefaultFont()
352 {
353 mpImpl->SetFonts( NULL, NULL, NULL );
354 }
355
SetText(const OUString & _rText,const uno::Reference<i18n::XBreakIterator> & _xBreakIter)356 void SvtScriptedTextHelper::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
357 {
358 mpImpl->SetText( _rText, _xBreakIter );
359 }
360
GetText() const361 const OUString& SvtScriptedTextHelper::GetText() const
362 {
363 return mpImpl->GetText();
364 }
365
GetTextWidth() const366 sal_Int32 SvtScriptedTextHelper::GetTextWidth() const
367 {
368 return mpImpl->GetTextSize().Width();
369 }
370
GetTextHeight() const371 sal_Int32 SvtScriptedTextHelper::GetTextHeight() const
372 {
373 return mpImpl->GetTextSize().Height();
374 }
375
GetTextSize() const376 const Size& SvtScriptedTextHelper::GetTextSize() const
377 {
378 return mpImpl->GetTextSize();
379 }
380
DrawText(const Point & _rPos)381 void SvtScriptedTextHelper::DrawText( const Point& _rPos )
382 {
383 mpImpl->DrawText( _rPos );
384 }
385
386
387 //_____________________________________________________________________________
388
389