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 <svtools/scriptedtext.hxx>
22 #include <rtl/ustring.hxx>
23 #include <vcl/outdev.hxx>
24 #include <vcl/font.hxx>
25 #include <tools/debug.hxx>
26 #include <tools/gen.hxx>
27 #include <com/sun/star/i18n/ScriptType.hpp>
30 using namespace ::std
;
31 using namespace ::rtl
;
32 using namespace ::com::sun::star
;
35 //_____________________________________________________________________________
37 class SvtScriptedTextHelper_Impl
40 OutputDevice
& mrOutDevice
; /// The output device for drawing the text.
41 Font maLatinFont
; /// The font for latin text portions.
42 Font maAsianFont
; /// The font for asian text portions.
43 Font maCmplxFont
; /// The font for complex text portions.
44 Font maDefltFont
; /// The default font of the output device.
45 OUString maText
; /// The text.
47 vector
< sal_Int32
> maPosVec
; /// The start position of each text portion.
48 vector
< sal_Int16
> maScriptVec
; /// The script type of each text portion.
49 vector
< sal_Int32
> maWidthVec
; /// The output width of each text portion.
50 Size maTextSize
; /// The size the text will take in the current output device.
52 /** Assignment operator not implemented to prevent usage. */
53 SvtScriptedTextHelper_Impl
& operator=( const SvtScriptedTextHelper_Impl
& );
55 /** Gets the font of the given script type. */
56 const Font
& GetFont( sal_uInt16 _nScript
) const;
57 /** Sets a font on the output device depending on the script type. */
58 inline void SetOutDevFont( sal_uInt16 _nScript
)
59 { mrOutDevice
.SetFont( GetFont( _nScript
) ); }
60 /** Fills maPosVec with positions of all changes of script type.
61 This method expects correctly initialized maPosVec and maScriptVec. */
62 void CalculateSizes();
63 /** Fills maPosVec with positions of all changes of script type and
64 maScriptVec with the script type of each portion. */
66 const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
);
69 /** This constructor sets an output device and fonts for all script types. */
70 SvtScriptedTextHelper_Impl(
71 OutputDevice
& _rOutDevice
,
75 /** Copy constructor. */
76 SvtScriptedTextHelper_Impl(
77 const SvtScriptedTextHelper_Impl
& _rCopy
);
79 ~SvtScriptedTextHelper_Impl();
81 /** Sets new fonts and recalculates the text width. */
82 void SetFonts( Font
* _pLatinFont
, Font
* _pAsianFont
, Font
* _pCmplxFont
);
83 /** Sets a new text and calculates all script breaks and the text width. */
85 const OUString
& _rText
,
86 const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
);
88 /** Returns a size struct containing the width and height of the text in the current output device. */
89 const Size
& GetTextSize() const;
91 /** Draws the text in the current output device. */
92 void DrawText( const Point
& _rPos
);
96 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl(
97 OutputDevice
& _rOutDevice
,
98 Font
* _pLatinFont
, Font
* _pAsianFont
, Font
* _pCmplxFont
) :
99 mrOutDevice( _rOutDevice
),
100 maLatinFont( _pLatinFont
? *_pLatinFont
: _rOutDevice
.GetFont() ),
101 maAsianFont( _pAsianFont
? *_pAsianFont
: _rOutDevice
.GetFont() ),
102 maCmplxFont( _pCmplxFont
? *_pCmplxFont
: _rOutDevice
.GetFont() ),
103 maDefltFont( _rOutDevice
.GetFont() )
107 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( const SvtScriptedTextHelper_Impl
& _rCopy
) :
108 mrOutDevice( _rCopy
.mrOutDevice
),
109 maLatinFont( _rCopy
.maLatinFont
),
110 maAsianFont( _rCopy
.maAsianFont
),
111 maCmplxFont( _rCopy
.maCmplxFont
),
112 maDefltFont( _rCopy
.maDefltFont
),
113 maText( _rCopy
.maText
),
114 maPosVec( _rCopy
.maPosVec
),
115 maScriptVec( _rCopy
.maScriptVec
),
116 maWidthVec( _rCopy
.maWidthVec
),
117 maTextSize( _rCopy
.maTextSize
)
121 SvtScriptedTextHelper_Impl::~SvtScriptedTextHelper_Impl()
125 const Font
& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript
) const
129 case i18n::ScriptType::LATIN
: return maLatinFont
;
130 case i18n::ScriptType::ASIAN
: return maAsianFont
;
131 case i18n::ScriptType::COMPLEX
: return maCmplxFont
;
136 void SvtScriptedTextHelper_Impl::CalculateSizes()
138 maTextSize
.Width() = maTextSize
.Height() = 0;
139 maDefltFont
= mrOutDevice
.GetFont();
141 // calculate text portion widths and total width
143 if( !maPosVec
.empty() )
145 DBG_ASSERT( maPosVec
.size() - 1 == maScriptVec
.size(),
146 "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" );
148 sal_Int32 nThisPos
= maPosVec
[ 0 ];
150 sal_Int32 nPosVecSize
= maPosVec
.size();
151 sal_Int32 nPosVecIndex
= 1;
154 sal_Int32 nScriptVecIndex
= 0;
156 sal_Int32 nCurrWidth
;
158 while( nPosVecIndex
< nPosVecSize
)
160 nNextPos
= maPosVec
[ nPosVecIndex
++ ];
161 nScript
= maScriptVec
[ nScriptVecIndex
++ ];
163 SetOutDevFont( nScript
);
164 nCurrWidth
= mrOutDevice
.GetTextWidth( maText
, nThisPos
, nNextPos
- nThisPos
);
165 maWidthVec
.push_back( nCurrWidth
);
166 maTextSize
.Width() += nCurrWidth
;
171 // calculate maximum font height
172 SetOutDevFont( i18n::ScriptType::LATIN
);
173 maTextSize
.Height() = std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() );
174 SetOutDevFont( i18n::ScriptType::ASIAN
);
175 maTextSize
.Height() = std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() );
176 SetOutDevFont( i18n::ScriptType::COMPLEX
);
177 maTextSize
.Height() = std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() );
179 mrOutDevice
.SetFont( maDefltFont
);
182 void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
187 DBG_ASSERT( _xBreakIter
.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" );
189 sal_Int32 nLen
= maText
.getLength();
192 if( _xBreakIter
.is() )
194 sal_Int32 nThisPos
= 0; // first position of this portion
195 sal_Int32 nNextPos
= 0; // first position of next portion
196 sal_Int16 nPortScript
; // script type of this portion
199 nPortScript
= _xBreakIter
->getScriptType( maText
, nThisPos
);
200 nNextPos
= _xBreakIter
->endOfScript( maText
, nThisPos
, nPortScript
);
202 switch( nPortScript
)
204 case i18n::ScriptType::LATIN
:
205 case i18n::ScriptType::ASIAN
:
206 case i18n::ScriptType::COMPLEX
:
207 maPosVec
.push_back( nThisPos
);
208 maScriptVec
.push_back( nPortScript
);
212 /* *** handling of weak characters ***
213 - first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font
214 - weak portion follows another portion: Script type of preceding portion is used */
215 if( maPosVec
.empty() )
217 sal_Int32 nCharIx
= 0;
218 sal_Int32 nNextCharIx
= 0;
222 nScript
= i18n::ScriptType::LATIN
;
223 while( (nScript
!= i18n::ScriptType::WEAK
) && (nCharIx
== nNextCharIx
) )
225 nNextCharIx
= mrOutDevice
.HasGlyphs( GetFont( nScript
), maText
, sal::static_int_cast
< sal_uInt16
>(nCharIx
), sal::static_int_cast
< sal_uInt16
>(nNextPos
- nCharIx
) );
226 if( nCharIx
== nNextCharIx
)
229 if( nNextCharIx
== nCharIx
)
232 maPosVec
.push_back( nCharIx
);
233 maScriptVec
.push_back( nScript
);
234 nCharIx
= nNextCharIx
;
236 while( nCharIx
< nNextPos
);
238 // nothing to do for following portions
243 while( (0 <= nThisPos
) && (nThisPos
< nLen
) );
245 else // no break iterator: whole text LATIN
247 maPosVec
.push_back( 0 );
248 maScriptVec
.push_back( i18n::ScriptType::LATIN
);
251 // push end position of last portion
252 if( !maPosVec
.empty() )
253 maPosVec
.push_back( nLen
);
258 void SvtScriptedTextHelper_Impl::SetFonts( Font
* _pLatinFont
, Font
* _pAsianFont
, Font
* _pCmplxFont
)
260 maLatinFont
= _pLatinFont
? *_pLatinFont
: maDefltFont
;
261 maAsianFont
= _pAsianFont
? *_pAsianFont
: maDefltFont
;
262 maCmplxFont
= _pCmplxFont
? *_pCmplxFont
: maDefltFont
;
266 void SvtScriptedTextHelper_Impl::SetText( const OUString
& _rText
, const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
269 CalculateBreaks( _xBreakIter
);
272 const Size
& SvtScriptedTextHelper_Impl::GetTextSize() const
277 void SvtScriptedTextHelper_Impl::DrawText( const Point
& _rPos
)
279 if( maText
.isEmpty() || maPosVec
.empty() )
282 DBG_ASSERT( maPosVec
.size() - 1 == maScriptVec
.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
283 DBG_ASSERT( maScriptVec
.size() == maWidthVec
.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
285 maDefltFont
= mrOutDevice
.GetFont();
286 Point
aCurrPos( _rPos
);
287 sal_Int32 nThisPos
= maPosVec
[ 0 ];
289 sal_Int32 nPosVecSize
= maPosVec
.size();
290 sal_Int32 nPosVecIndex
= 1;
293 sal_Int32 nVecIndex
= 0;
295 while( nPosVecIndex
< nPosVecSize
)
297 nNextPos
= maPosVec
[ nPosVecIndex
++ ];
298 nScript
= maScriptVec
[ nVecIndex
];
300 SetOutDevFont( nScript
);
301 mrOutDevice
.DrawText( aCurrPos
, maText
, nThisPos
, nNextPos
- nThisPos
);
302 aCurrPos
.X() += maWidthVec
[ nVecIndex
++ ];
303 aCurrPos
.X() += mrOutDevice
.GetTextHeight() / 5; // add 20% of font height as portion spacing
306 mrOutDevice
.SetFont( maDefltFont
);
310 //_____________________________________________________________________________
312 SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice
& _rOutDevice
) :
313 mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice
, NULL
, NULL
, NULL
) )
317 SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper
& _rCopy
) :
318 mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy
.mpImpl
) )
322 SvtScriptedTextHelper::~SvtScriptedTextHelper()
327 void SvtScriptedTextHelper::SetFonts( Font
* _pLatinFont
, Font
* _pAsianFont
, Font
* _pCmplxFont
)
329 mpImpl
->SetFonts( _pLatinFont
, _pAsianFont
, _pCmplxFont
);
332 void SvtScriptedTextHelper::SetDefaultFont()
334 mpImpl
->SetFonts( NULL
, NULL
, NULL
);
337 void SvtScriptedTextHelper::SetText( const OUString
& _rText
, const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
339 mpImpl
->SetText( _rText
, _xBreakIter
);
342 const Size
& SvtScriptedTextHelper::GetTextSize() const
344 return mpImpl
->GetTextSize();
347 void SvtScriptedTextHelper::DrawText( const Point
& _rPos
)
349 mpImpl
->DrawText( _rPos
);
353 //_____________________________________________________________________________
355 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */