Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <svtools/scriptedtext.hxx>
30 : : #include <vector>
31 : : #include <rtl/ustring.hxx>
32 : : #include <vcl/outdev.hxx>
33 : : #include <vcl/font.hxx>
34 : : #include <tools/debug.hxx>
35 : : #include <com/sun/star/i18n/ScriptType.hpp>
36 : :
37 : :
38 : : using namespace ::std;
39 : : using namespace ::rtl;
40 : : using namespace ::com::sun::star;
41 : :
42 : :
43 : : //_____________________________________________________________________________
44 : :
45 : : class SvtScriptedTextHelper_Impl
46 : : {
47 : : private:
48 : : OutputDevice& mrOutDevice; /// The output device for drawing the text.
49 : : Font maLatinFont; /// The font for latin text portions.
50 : : Font maAsianFont; /// The font for asian text portions.
51 : : Font maCmplxFont; /// The font for complex text portions.
52 : : Font maDefltFont; /// The default font of the output device.
53 : : OUString maText; /// The text.
54 : :
55 : : vector< sal_Int32 > maPosVec; /// The start position of each text portion.
56 : : vector< sal_Int16 > maScriptVec; /// The script type of each text portion.
57 : : vector< sal_Int32 > maWidthVec; /// The output width of each text portion.
58 : : Size maTextSize; /// The size the text will take in the current output device.
59 : :
60 : : /** Assignment operator not implemented to prevent usage. */
61 : : SvtScriptedTextHelper_Impl& operator=( const SvtScriptedTextHelper_Impl& );
62 : :
63 : : /** Gets the font of the given script type. */
64 : : const Font& GetFont( sal_uInt16 _nScript ) const;
65 : : /** Sets a font on the output device depending on the script type. */
66 : 0 : inline void SetOutDevFont( sal_uInt16 _nScript )
67 : 0 : { mrOutDevice.SetFont( GetFont( _nScript ) ); }
68 : : /** Fills maPosVec with positions of all changes of script type.
69 : : This method expects correctly initialized maPosVec and maScriptVec. */
70 : : void CalculateSizes();
71 : : /** Fills maPosVec with positions of all changes of script type and
72 : : maScriptVec with the script type of each portion. */
73 : : void CalculateBreaks(
74 : : const uno::Reference< i18n::XBreakIterator >& _xBreakIter );
75 : :
76 : : public:
77 : : /** This constructor sets an output device and fonts for all script types. */
78 : : SvtScriptedTextHelper_Impl(
79 : : OutputDevice& _rOutDevice,
80 : : Font* _pLatinFont,
81 : : Font* _pAsianFont,
82 : : Font* _pCmplxFont );
83 : : /** Copy constructor. */
84 : : SvtScriptedTextHelper_Impl(
85 : : const SvtScriptedTextHelper_Impl& _rCopy );
86 : : /** Destructor. */
87 : : ~SvtScriptedTextHelper_Impl();
88 : :
89 : : /** Sets new fonts and recalculates the text width. */
90 : : void SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont );
91 : : /** Sets a new text and calculates all script breaks and the text width. */
92 : : void SetText(
93 : : const OUString& _rText,
94 : : const uno::Reference< i18n::XBreakIterator >& _xBreakIter );
95 : :
96 : : /** Returns a size struct containing the width and height of the text in the current output device. */
97 : : const Size& GetTextSize() const;
98 : :
99 : : /** Draws the text in the current output device. */
100 : : void DrawText( const Point& _rPos );
101 : : };
102 : :
103 : :
104 : 0 : SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl(
105 : : OutputDevice& _rOutDevice,
106 : : Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont ) :
107 : : mrOutDevice( _rOutDevice ),
108 : : maLatinFont( _pLatinFont ? *_pLatinFont : _rOutDevice.GetFont() ),
109 : : maAsianFont( _pAsianFont ? *_pAsianFont : _rOutDevice.GetFont() ),
110 : : maCmplxFont( _pCmplxFont ? *_pCmplxFont : _rOutDevice.GetFont() ),
111 [ # # ][ # # ]: 0 : maDefltFont( _rOutDevice.GetFont() )
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
112 : : {
113 : 0 : }
114 : :
115 : 0 : SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( const SvtScriptedTextHelper_Impl& _rCopy ) :
116 : : mrOutDevice( _rCopy.mrOutDevice ),
117 : : maLatinFont( _rCopy.maLatinFont ),
118 : : maAsianFont( _rCopy.maAsianFont ),
119 : : maCmplxFont( _rCopy.maCmplxFont ),
120 : : maDefltFont( _rCopy.maDefltFont ),
121 : : maText( _rCopy.maText ),
122 : : maPosVec( _rCopy.maPosVec ),
123 : : maScriptVec( _rCopy.maScriptVec ),
124 : : maWidthVec( _rCopy.maWidthVec ),
125 [ # # ][ # # ]: 0 : maTextSize( _rCopy.maTextSize )
[ # # ][ # # ]
[ # # ][ # # ]
126 : : {
127 : 0 : }
128 : :
129 [ # # ][ # # ]: 0 : SvtScriptedTextHelper_Impl::~SvtScriptedTextHelper_Impl()
[ # # ]
130 : : {
131 : 0 : }
132 : :
133 : 0 : const Font& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript ) const
134 : : {
135 [ # # # # ]: 0 : switch( _nScript )
136 : : {
137 : 0 : case i18n::ScriptType::LATIN: return maLatinFont;
138 : 0 : case i18n::ScriptType::ASIAN: return maAsianFont;
139 : 0 : case i18n::ScriptType::COMPLEX: return maCmplxFont;
140 : : }
141 : 0 : return maDefltFont;
142 : : }
143 : :
144 : 0 : void SvtScriptedTextHelper_Impl::CalculateSizes()
145 : : {
146 : 0 : maTextSize.Width() = maTextSize.Height() = 0;
147 : 0 : maDefltFont = mrOutDevice.GetFont();
148 : :
149 : : // calculate text portion widths and total width
150 : 0 : maWidthVec.clear();
151 [ # # ]: 0 : if( !maPosVec.empty() )
152 : : {
153 : : DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(),
154 : : "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" );
155 : :
156 [ # # ]: 0 : xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] );
157 : : xub_StrLen nNextPos;
158 : 0 : sal_Int32 nPosVecSize = maPosVec.size();
159 : 0 : sal_Int32 nPosVecIndex = 1;
160 : :
161 : : sal_Int16 nScript;
162 : 0 : sal_Int32 nScriptVecIndex = 0;
163 : :
164 : : sal_Int32 nCurrWidth;
165 : :
166 [ # # ]: 0 : while( nPosVecIndex < nPosVecSize )
167 : : {
168 [ # # ]: 0 : nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] );
169 [ # # ]: 0 : nScript = maScriptVec[ nScriptVecIndex++ ];
170 : :
171 [ # # ]: 0 : SetOutDevFont( nScript );
172 [ # # ][ # # ]: 0 : nCurrWidth = mrOutDevice.GetTextWidth( maText, nThisPos, nNextPos - nThisPos );
[ # # ]
173 [ # # ]: 0 : maWidthVec.push_back( nCurrWidth );
174 : 0 : maTextSize.Width() += nCurrWidth;
175 : 0 : nThisPos = nNextPos;
176 : : }
177 : : }
178 : :
179 : : // calculate maximum font height
180 : 0 : SetOutDevFont( i18n::ScriptType::LATIN );
181 : 0 : maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() );
182 : 0 : SetOutDevFont( i18n::ScriptType::ASIAN );
183 : 0 : maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() );
184 : 0 : SetOutDevFont( i18n::ScriptType::COMPLEX );
185 : 0 : maTextSize.Height() = Max( maTextSize.Height(), mrOutDevice.GetTextHeight() );
186 : :
187 : 0 : mrOutDevice.SetFont( maDefltFont );
188 : 0 : }
189 : :
190 : 0 : void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
191 : : {
192 : 0 : maPosVec.clear();
193 : 0 : maScriptVec.clear();
194 : :
195 : : DBG_ASSERT( _xBreakIter.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" );
196 : :
197 : 0 : sal_Int32 nLen = maText.getLength();
198 [ # # ]: 0 : if( nLen )
199 : : {
200 [ # # ]: 0 : if( _xBreakIter.is() )
201 : : {
202 : 0 : sal_Int32 nThisPos = 0; // first position of this portion
203 : 0 : sal_Int32 nNextPos = 0; // first position of next portion
204 : : sal_Int16 nPortScript; // script type of this portion
205 [ # # ][ # # ]: 0 : do
[ # # ]
206 : : {
207 [ # # ][ # # ]: 0 : nPortScript = _xBreakIter->getScriptType( maText, nThisPos );
208 [ # # ][ # # ]: 0 : nNextPos = _xBreakIter->endOfScript( maText, nThisPos, nPortScript );
209 : :
210 [ # # ]: 0 : switch( nPortScript )
211 : : {
212 : : case i18n::ScriptType::LATIN:
213 : : case i18n::ScriptType::ASIAN:
214 : : case i18n::ScriptType::COMPLEX:
215 [ # # ]: 0 : maPosVec.push_back( nThisPos );
216 [ # # ]: 0 : maScriptVec.push_back( nPortScript );
217 : 0 : break;
218 : : default:
219 : : {
220 : : /* *** handling of weak characters ***
221 : : - first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font
222 : : - weak portion follows another portion: Script type of preceding portion is used */
223 [ # # ]: 0 : if( maPosVec.empty() )
224 : : {
225 : 0 : sal_Int32 nCharIx = 0;
226 : 0 : sal_Int32 nNextCharIx = 0;
227 : : sal_Int16 nScript;
228 [ # # ]: 0 : do
229 : : {
230 : 0 : nScript = i18n::ScriptType::LATIN;
231 [ # # ][ # # ]: 0 : while( (nScript != i18n::ScriptType::WEAK) && (nCharIx == nNextCharIx) )
[ # # ]
232 : : {
233 [ # # ][ # # ]: 0 : nNextCharIx = mrOutDevice.HasGlyphs( GetFont( nScript ), maText, sal::static_int_cast< sal_uInt16 >(nCharIx), sal::static_int_cast< sal_uInt16 >(nNextPos - nCharIx) );
[ # # ]
234 [ # # ]: 0 : if( nCharIx == nNextCharIx )
235 : 0 : ++nScript;
236 : : }
237 [ # # ]: 0 : if( nNextCharIx == nCharIx )
238 : 0 : ++nNextCharIx;
239 : :
240 [ # # ]: 0 : maPosVec.push_back( nCharIx );
241 [ # # ]: 0 : maScriptVec.push_back( nScript );
242 : 0 : nCharIx = nNextCharIx;
243 : : }
244 : : while( nCharIx < nNextPos );
245 : : }
246 : : // nothing to do for following portions
247 : : }
248 : : }
249 : 0 : nThisPos = nNextPos;
250 : : }
251 : : while( (0 <= nThisPos) && (nThisPos < nLen) );
252 : : }
253 : : else // no break iterator: whole text LATIN
254 : : {
255 [ # # ]: 0 : maPosVec.push_back( 0 );
256 [ # # ]: 0 : maScriptVec.push_back( i18n::ScriptType::LATIN );
257 : : }
258 : :
259 : : // push end position of last portion
260 [ # # ]: 0 : if( !maPosVec.empty() )
261 [ # # ]: 0 : maPosVec.push_back( nLen );
262 : : }
263 [ # # ]: 0 : CalculateSizes();
264 : 0 : }
265 : :
266 : 0 : void SvtScriptedTextHelper_Impl::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont )
267 : : {
268 [ # # ]: 0 : maLatinFont = _pLatinFont ? *_pLatinFont : maDefltFont;
269 [ # # ]: 0 : maAsianFont = _pAsianFont ? *_pAsianFont : maDefltFont;
270 [ # # ]: 0 : maCmplxFont = _pCmplxFont ? *_pCmplxFont : maDefltFont;
271 : 0 : CalculateSizes();
272 : 0 : }
273 : :
274 : 0 : void SvtScriptedTextHelper_Impl::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
275 : : {
276 : 0 : maText = _rText;
277 : 0 : CalculateBreaks( _xBreakIter );
278 : 0 : }
279 : :
280 : 0 : const Size& SvtScriptedTextHelper_Impl::GetTextSize() const
281 : : {
282 : 0 : return maTextSize;
283 : : }
284 : :
285 : 0 : void SvtScriptedTextHelper_Impl::DrawText( const Point& _rPos )
286 : : {
287 [ # # ][ # # ]: 0 : if( maText.isEmpty() || maPosVec.empty() )
[ # # ]
288 : 0 : return;
289 : :
290 : : DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
291 : : DBG_ASSERT( maScriptVec.size() == maWidthVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
292 : :
293 [ # # ]: 0 : maDefltFont = mrOutDevice.GetFont();
294 : 0 : Point aCurrPos( _rPos );
295 [ # # ]: 0 : xub_StrLen nThisPos = static_cast< xub_StrLen >( maPosVec[ 0 ] );
296 : : xub_StrLen nNextPos;
297 : 0 : sal_Int32 nPosVecSize = maPosVec.size();
298 : 0 : sal_Int32 nPosVecIndex = 1;
299 : :
300 : : sal_Int16 nScript;
301 : 0 : sal_Int32 nVecIndex = 0;
302 : :
303 [ # # ]: 0 : while( nPosVecIndex < nPosVecSize )
304 : : {
305 [ # # ]: 0 : nNextPos = static_cast< xub_StrLen >( maPosVec[ nPosVecIndex++ ] );
306 [ # # ]: 0 : nScript = maScriptVec[ nVecIndex ];
307 : :
308 [ # # ]: 0 : SetOutDevFont( nScript );
309 [ # # ][ # # ]: 0 : mrOutDevice.DrawText( aCurrPos, maText, nThisPos, nNextPos - nThisPos );
[ # # ]
310 [ # # ]: 0 : aCurrPos.X() += maWidthVec[ nVecIndex++ ];
311 [ # # ]: 0 : aCurrPos.X() += mrOutDevice.GetTextHeight() / 5; // add 20% of font height as portion spacing
312 : 0 : nThisPos = nNextPos;
313 : : }
314 [ # # ]: 0 : mrOutDevice.SetFont( maDefltFont );
315 : : }
316 : :
317 : :
318 : : //_____________________________________________________________________________
319 : :
320 : 0 : SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice& _rOutDevice ) :
321 [ # # ]: 0 : mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice, NULL, NULL, NULL ) )
322 : : {
323 : 0 : }
324 : :
325 : 0 : SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper& _rCopy ) :
326 [ # # ]: 0 : mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy.mpImpl ) )
327 : : {
328 : 0 : }
329 : :
330 : 0 : SvtScriptedTextHelper::~SvtScriptedTextHelper()
331 : : {
332 [ # # ]: 0 : delete mpImpl;
333 [ # # ]: 0 : }
334 : :
335 : 0 : void SvtScriptedTextHelper::SetFonts( Font* _pLatinFont, Font* _pAsianFont, Font* _pCmplxFont )
336 : : {
337 : 0 : mpImpl->SetFonts( _pLatinFont, _pAsianFont, _pCmplxFont );
338 : 0 : }
339 : :
340 : 0 : void SvtScriptedTextHelper::SetDefaultFont()
341 : : {
342 : 0 : mpImpl->SetFonts( NULL, NULL, NULL );
343 : 0 : }
344 : :
345 : 0 : void SvtScriptedTextHelper::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
346 : : {
347 : 0 : mpImpl->SetText( _rText, _xBreakIter );
348 : 0 : }
349 : :
350 : 0 : const Size& SvtScriptedTextHelper::GetTextSize() const
351 : : {
352 : 0 : return mpImpl->GetTextSize();
353 : : }
354 : :
355 : 0 : void SvtScriptedTextHelper::DrawText( const Point& _rPos )
356 : : {
357 : 0 : mpImpl->DrawText( _rPos );
358 : 0 : }
359 : :
360 : :
361 : : //_____________________________________________________________________________
362 : :
363 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|