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 ::com::sun::star
;
36 class SvtScriptedTextHelper_Impl
39 OutputDevice
& mrOutDevice
; /// The output device for drawing the text.
40 vcl::Font maLatinFont
; /// The font for latin text portions.
41 vcl::Font maAsianFont
; /// The font for asian text portions.
42 vcl::Font maCmplxFont
; /// The font for complex text portions.
43 vcl::Font maDefltFont
; /// The default font of the output device.
44 OUString maText
; /// The text.
46 vector
< sal_Int32
> maPosVec
; /// The start position of each text portion.
47 vector
< sal_Int16
> maScriptVec
; /// The script type of each text portion.
48 vector
< sal_Int32
> maWidthVec
; /// The output width of each text portion.
49 Size maTextSize
; /// The size the text will take in the current output device.
51 /** Assignment operator not implemented to prevent usage. */
52 SvtScriptedTextHelper_Impl
& operator=( const SvtScriptedTextHelper_Impl
& ) SAL_DELETED_FUNCTION
;
54 /** Gets the font of the given script type. */
55 const vcl::Font
& GetFont( sal_uInt16 _nScript
) const;
56 /** Sets a font on the output device depending on the script type. */
57 inline void SetOutDevFont( sal_uInt16 _nScript
)
58 { mrOutDevice
.SetFont( GetFont( _nScript
) ); }
59 /** Fills maPosVec with positions of all changes of script type.
60 This method expects correctly initialized maPosVec and maScriptVec. */
61 void CalculateSizes();
62 /** Fills maPosVec with positions of all changes of script type and
63 maScriptVec with the script type of each portion. */
65 const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
);
68 /** This constructor sets an output device and fonts for all script types. */
69 SvtScriptedTextHelper_Impl(
70 OutputDevice
& _rOutDevice
,
71 vcl::Font
* _pLatinFont
,
72 vcl::Font
* _pAsianFont
,
73 vcl::Font
* _pCmplxFont
);
74 /** Copy constructor. */
75 SvtScriptedTextHelper_Impl(
76 const SvtScriptedTextHelper_Impl
& _rCopy
);
78 ~SvtScriptedTextHelper_Impl();
80 /** Sets new fonts and recalculates the text width. */
81 void SetFonts( vcl::Font
* _pLatinFont
, vcl::Font
* _pAsianFont
, vcl::Font
* _pCmplxFont
);
82 /** Sets a new text and calculates all script breaks and the text width. */
84 const OUString
& _rText
,
85 const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
);
87 /** Returns a size struct containing the width and height of the text in the current output device. */
88 const Size
& GetTextSize() const { return maTextSize
;}
90 /** Draws the text in the current output device. */
91 void DrawText( const Point
& _rPos
);
95 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl(
96 OutputDevice
& _rOutDevice
,
97 vcl::Font
* _pLatinFont
, vcl::Font
* _pAsianFont
, vcl::Font
* _pCmplxFont
) :
98 mrOutDevice( _rOutDevice
),
99 maLatinFont( _pLatinFont
? *_pLatinFont
: _rOutDevice
.GetFont() ),
100 maAsianFont( _pAsianFont
? *_pAsianFont
: _rOutDevice
.GetFont() ),
101 maCmplxFont( _pCmplxFont
? *_pCmplxFont
: _rOutDevice
.GetFont() ),
102 maDefltFont( _rOutDevice
.GetFont() )
106 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl( const SvtScriptedTextHelper_Impl
& _rCopy
) :
107 mrOutDevice( _rCopy
.mrOutDevice
),
108 maLatinFont( _rCopy
.maLatinFont
),
109 maAsianFont( _rCopy
.maAsianFont
),
110 maCmplxFont( _rCopy
.maCmplxFont
),
111 maDefltFont( _rCopy
.maDefltFont
),
112 maText( _rCopy
.maText
),
113 maPosVec( _rCopy
.maPosVec
),
114 maScriptVec( _rCopy
.maScriptVec
),
115 maWidthVec( _rCopy
.maWidthVec
),
116 maTextSize( _rCopy
.maTextSize
)
120 SvtScriptedTextHelper_Impl::~SvtScriptedTextHelper_Impl()
124 const vcl::Font
& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript
) const
128 case i18n::ScriptType::LATIN
: return maLatinFont
;
129 case i18n::ScriptType::ASIAN
: return maAsianFont
;
130 case i18n::ScriptType::COMPLEX
: return maCmplxFont
;
135 void SvtScriptedTextHelper_Impl::CalculateSizes()
137 maTextSize
.Width() = maTextSize
.Height() = 0;
138 maDefltFont
= mrOutDevice
.GetFont();
140 // calculate text portion widths and total width
142 if( !maPosVec
.empty() )
144 DBG_ASSERT( maPosVec
.size() - 1 == maScriptVec
.size(),
145 "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" );
147 sal_Int32 nThisPos
= maPosVec
[ 0 ];
149 sal_Int32 nPosVecSize
= maPosVec
.size();
150 sal_Int32 nPosVecIndex
= 1;
153 sal_Int32 nScriptVecIndex
= 0;
155 sal_Int32 nCurrWidth
;
157 while( nPosVecIndex
< nPosVecSize
)
159 nNextPos
= maPosVec
[ nPosVecIndex
++ ];
160 nScript
= maScriptVec
[ nScriptVecIndex
++ ];
162 SetOutDevFont( nScript
);
163 nCurrWidth
= mrOutDevice
.GetTextWidth( maText
, nThisPos
, nNextPos
- nThisPos
);
164 maWidthVec
.push_back( nCurrWidth
);
165 maTextSize
.Width() += nCurrWidth
;
170 // calculate maximum font height
171 SetOutDevFont( i18n::ScriptType::LATIN
);
172 maTextSize
.Height() = std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() );
173 SetOutDevFont( i18n::ScriptType::ASIAN
);
174 maTextSize
.Height() = std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() );
175 SetOutDevFont( i18n::ScriptType::COMPLEX
);
176 maTextSize
.Height() = std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() );
178 mrOutDevice
.SetFont( maDefltFont
);
181 void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
186 DBG_ASSERT( _xBreakIter
.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" );
188 sal_Int32 nLen
= maText
.getLength();
191 if( _xBreakIter
.is() )
193 sal_Int32 nThisPos
= 0; // first position of this portion
194 sal_Int32 nNextPos
= 0; // first position of next portion
195 sal_Int16 nPortScript
; // script type of this portion
198 nPortScript
= _xBreakIter
->getScriptType( maText
, nThisPos
);
199 nNextPos
= _xBreakIter
->endOfScript( maText
, nThisPos
, nPortScript
);
201 switch( nPortScript
)
203 case i18n::ScriptType::LATIN
:
204 case i18n::ScriptType::ASIAN
:
205 case i18n::ScriptType::COMPLEX
:
206 maPosVec
.push_back( nThisPos
);
207 maScriptVec
.push_back( nPortScript
);
211 /* *** handling of weak characters ***
212 - first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font
213 - weak portion follows another portion: Script type of preceding portion is used */
214 if( maPosVec
.empty() )
216 sal_Int32 nCharIx
= 0;
217 sal_Int32 nNextCharIx
= 0;
221 nScript
= i18n::ScriptType::LATIN
;
222 while( (nScript
!= i18n::ScriptType::WEAK
) && (nCharIx
== nNextCharIx
) )
224 nNextCharIx
= mrOutDevice
.HasGlyphs( GetFont( nScript
), maText
, nCharIx
, nNextPos
- nCharIx
);
225 if( nCharIx
== nNextCharIx
)
228 if( nNextCharIx
== nCharIx
)
231 maPosVec
.push_back( nCharIx
);
232 maScriptVec
.push_back( nScript
);
233 nCharIx
= nNextCharIx
;
235 while( nCharIx
< nNextPos
&& nCharIx
!= -1 );
237 // nothing to do for following portions
242 while( (0 <= nThisPos
) && (nThisPos
< nLen
) );
244 else // no break iterator: whole text LATIN
246 maPosVec
.push_back( 0 );
247 maScriptVec
.push_back( i18n::ScriptType::LATIN
);
250 // push end position of last portion
251 if( !maPosVec
.empty() )
252 maPosVec
.push_back( nLen
);
257 void SvtScriptedTextHelper_Impl::SetFonts( vcl::Font
* _pLatinFont
, vcl::Font
* _pAsianFont
, vcl::Font
* _pCmplxFont
)
259 maLatinFont
= _pLatinFont
? *_pLatinFont
: maDefltFont
;
260 maAsianFont
= _pAsianFont
? *_pAsianFont
: maDefltFont
;
261 maCmplxFont
= _pCmplxFont
? *_pCmplxFont
: maDefltFont
;
265 void SvtScriptedTextHelper_Impl::SetText( const OUString
& _rText
, const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
268 CalculateBreaks( _xBreakIter
);
272 void SvtScriptedTextHelper_Impl::DrawText( const Point
& _rPos
)
274 if( maText
.isEmpty() || maPosVec
.empty() )
277 DBG_ASSERT( maPosVec
.size() - 1 == maScriptVec
.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
278 DBG_ASSERT( maScriptVec
.size() == maWidthVec
.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
280 maDefltFont
= mrOutDevice
.GetFont();
281 Point
aCurrPos( _rPos
);
282 sal_Int32 nThisPos
= maPosVec
[ 0 ];
284 sal_Int32 nPosVecSize
= maPosVec
.size();
285 sal_Int32 nPosVecIndex
= 1;
288 sal_Int32 nVecIndex
= 0;
290 while( nPosVecIndex
< nPosVecSize
)
292 nNextPos
= maPosVec
[ nPosVecIndex
++ ];
293 nScript
= maScriptVec
[ nVecIndex
];
295 SetOutDevFont( nScript
);
296 mrOutDevice
.DrawText( aCurrPos
, maText
, nThisPos
, nNextPos
- nThisPos
);
297 aCurrPos
.X() += maWidthVec
[ nVecIndex
++ ];
298 aCurrPos
.X() += mrOutDevice
.GetTextHeight() / 5; // add 20% of font height as portion spacing
301 mrOutDevice
.SetFont( maDefltFont
);
307 SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice
& _rOutDevice
) :
308 mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice
, NULL
, NULL
, NULL
) )
312 SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper
& _rCopy
) :
313 mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy
.mpImpl
) )
317 SvtScriptedTextHelper::~SvtScriptedTextHelper()
322 void SvtScriptedTextHelper::SetFonts( vcl::Font
* _pLatinFont
, vcl::Font
* _pAsianFont
, vcl::Font
* _pCmplxFont
)
324 mpImpl
->SetFonts( _pLatinFont
, _pAsianFont
, _pCmplxFont
);
327 void SvtScriptedTextHelper::SetDefaultFont()
329 mpImpl
->SetFonts( NULL
, NULL
, NULL
);
332 void SvtScriptedTextHelper::SetText( const OUString
& _rText
, const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
334 mpImpl
->SetText( _rText
, _xBreakIter
);
337 const Size
& SvtScriptedTextHelper::GetTextSize() const
339 return mpImpl
->GetTextSize();
342 void SvtScriptedTextHelper::DrawText( const Point
& _rPos
)
344 mpImpl
->DrawText( _rPos
);
350 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */