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>
28 #include <com/sun/star/i18n/XBreakIterator.hpp>
31 using namespace ::com::sun::star
;
34 class SvtScriptedTextHelper_Impl
37 OutputDevice
& mrOutDevice
; /// The output device for drawing the text.
38 vcl::Font maLatinFont
; /// The font for latin text portions.
39 vcl::Font maAsianFont
; /// The font for asian text portions.
40 vcl::Font maCmplxFont
; /// The font for complex text portions.
41 vcl::Font maDefltFont
; /// The default font of the output device.
42 OUString maText
; /// The text.
44 std::vector
< sal_Int32
> maPosVec
; /// The start position of each text portion.
45 std::vector
< sal_Int16
> maScriptVec
; /// The script type of each text portion.
46 std::vector
< sal_Int32
> maWidthVec
; /// The output width of each text portion.
47 Size maTextSize
; /// The size the text will take in the current output device.
49 /** Gets the font of the given script type. */
50 const vcl::Font
& GetFont( sal_uInt16 _nScript
) const;
51 /** Sets a font on the output device depending on the script type. */
52 void SetOutDevFont( sal_uInt16 _nScript
)
53 { mrOutDevice
.SetFont( GetFont( _nScript
) ); }
54 /** Fills maPosVec with positions of all changes of script type.
55 This method expects correctly initialized maPosVec and maScriptVec. */
56 void CalculateSizes();
57 /** Fills maPosVec with positions of all changes of script type and
58 maScriptVec with the script type of each portion. */
60 const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
);
63 /** This constructor sets an output device and fonts for all script types. */
64 explicit SvtScriptedTextHelper_Impl(
65 OutputDevice
& _rOutDevice
);
67 /** Sets new fonts and recalculates the text width. */
68 void SetFonts( vcl::Font
const * _pLatinFont
, vcl::Font
const * _pAsianFont
, vcl::Font
const * _pCmplxFont
);
69 /** Sets a new text and calculates all script breaks and the text width. */
71 const OUString
& _rText
,
72 const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
);
74 /** Returns a size struct containing the width and height of the text in the current output device. */
75 const Size
& GetTextSize() const { return maTextSize
;}
77 /** Draws the text in the current output device. */
78 void DrawText( const Point
& _rPos
);
82 SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl(
83 OutputDevice
& _rOutDevice
) :
84 mrOutDevice( _rOutDevice
),
85 maLatinFont( _rOutDevice
.GetFont() ),
86 maAsianFont( _rOutDevice
.GetFont() ),
87 maCmplxFont( _rOutDevice
.GetFont() ),
88 maDefltFont( _rOutDevice
.GetFont() )
92 const vcl::Font
& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript
) const
96 case i18n::ScriptType::LATIN
: return maLatinFont
;
97 case i18n::ScriptType::ASIAN
: return maAsianFont
;
98 case i18n::ScriptType::COMPLEX
: return maCmplxFont
;
103 void SvtScriptedTextHelper_Impl::CalculateSizes()
105 maTextSize
.setWidth(0);
106 maTextSize
.setHeight(0);
107 mrOutDevice
.Push(vcl::PushFlags::FONT
| vcl::PushFlags::TEXTCOLOR
);
109 // calculate text portion widths and total width
111 if( !maPosVec
.empty() )
113 DBG_ASSERT( maPosVec
.size() - 1 == maScriptVec
.size(),
114 "SvtScriptedTextHelper_Impl::CalculateWidth - invalid std::vectors" );
116 sal_Int32 nThisPos
= maPosVec
[ 0 ];
118 sal_Int32 nPosVecSize
= maPosVec
.size();
119 sal_Int32 nPosVecIndex
= 1;
122 sal_Int32 nScriptVecIndex
= 0;
124 sal_Int32 nCurrWidth
;
126 while( nPosVecIndex
< nPosVecSize
)
128 nNextPos
= maPosVec
[ nPosVecIndex
++ ];
129 nScript
= maScriptVec
[ nScriptVecIndex
++ ];
131 SetOutDevFont( nScript
);
132 nCurrWidth
= mrOutDevice
.GetTextWidth( maText
, nThisPos
, nNextPos
- nThisPos
);
133 maWidthVec
.push_back( nCurrWidth
);
134 maTextSize
.AdjustWidth(nCurrWidth
);
139 // calculate maximum font height
140 SetOutDevFont( i18n::ScriptType::LATIN
);
141 maTextSize
.setHeight( std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() ) );
142 SetOutDevFont( i18n::ScriptType::ASIAN
);
143 maTextSize
.setHeight( std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() ) );
144 SetOutDevFont( i18n::ScriptType::COMPLEX
);
145 maTextSize
.setHeight( std::max( maTextSize
.Height(), mrOutDevice
.GetTextHeight() ) );
150 void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
155 DBG_ASSERT( _xBreakIter
.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" );
157 sal_Int32 nLen
= maText
.getLength();
160 if( _xBreakIter
.is() )
162 sal_Int32 nThisPos
= 0; // first position of this portion
163 sal_Int32 nNextPos
= 0; // first position of next portion
164 sal_Int16 nPortScript
; // script type of this portion
167 nPortScript
= _xBreakIter
->getScriptType( maText
, nThisPos
);
168 nNextPos
= _xBreakIter
->endOfScript( maText
, nThisPos
, nPortScript
);
170 switch( nPortScript
)
172 case i18n::ScriptType::LATIN
:
173 case i18n::ScriptType::ASIAN
:
174 case i18n::ScriptType::COMPLEX
:
175 maPosVec
.push_back( nThisPos
);
176 maScriptVec
.push_back( nPortScript
);
180 /* *** handling of weak characters ***
181 - first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font
182 - weak portion follows another portion: Script type of preceding portion is used */
183 if( maPosVec
.empty() )
185 sal_Int32 nCharIx
= 0;
186 sal_Int32 nNextCharIx
= 0;
190 nScript
= i18n::ScriptType::LATIN
;
191 while( (nScript
!= i18n::ScriptType::WEAK
) && (nCharIx
== nNextCharIx
) )
193 nNextCharIx
= mrOutDevice
.HasGlyphs( GetFont( nScript
), maText
, nCharIx
, nNextPos
- nCharIx
);
194 if( nCharIx
== nNextCharIx
)
197 if( nNextCharIx
== nCharIx
)
200 maPosVec
.push_back( nCharIx
);
201 maScriptVec
.push_back( nScript
);
202 nCharIx
= nNextCharIx
;
204 while( nCharIx
< nNextPos
&& nCharIx
!= -1 );
206 // nothing to do for following portions
211 while( (0 <= nThisPos
) && (nThisPos
< nLen
) );
213 else // no break iterator: whole text LATIN
215 maPosVec
.push_back( 0 );
216 maScriptVec
.push_back( i18n::ScriptType::LATIN
);
219 // push end position of last portion
220 if( !maPosVec
.empty() )
221 maPosVec
.push_back( nLen
);
226 void SvtScriptedTextHelper_Impl::SetFonts( vcl::Font
const * _pLatinFont
, vcl::Font
const * _pAsianFont
, vcl::Font
const * _pCmplxFont
)
228 maLatinFont
= _pLatinFont
? *_pLatinFont
: maDefltFont
;
229 maAsianFont
= _pAsianFont
? *_pAsianFont
: maDefltFont
;
230 maCmplxFont
= _pCmplxFont
? *_pCmplxFont
: maDefltFont
;
234 void SvtScriptedTextHelper_Impl::SetText( const OUString
& _rText
, const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
237 CalculateBreaks( _xBreakIter
);
241 void SvtScriptedTextHelper_Impl::DrawText( const Point
& _rPos
)
243 if( maText
.isEmpty() || maPosVec
.empty() )
246 DBG_ASSERT( maPosVec
.size() - 1 == maScriptVec
.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid std::vectors" );
247 DBG_ASSERT( maScriptVec
.size() == maWidthVec
.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid std::vectors" );
249 mrOutDevice
.Push(vcl::PushFlags::FONT
| vcl::PushFlags::TEXTCOLOR
);
251 Point
aCurrPos( _rPos
);
252 sal_Int32 nThisPos
= maPosVec
[ 0 ];
254 sal_Int32 nPosVecSize
= maPosVec
.size();
255 sal_Int32 nPosVecIndex
= 1;
258 sal_Int32 nVecIndex
= 0;
260 while( nPosVecIndex
< nPosVecSize
)
262 nNextPos
= maPosVec
[ nPosVecIndex
++ ];
263 nScript
= maScriptVec
[ nVecIndex
];
264 vcl::Font aFont
= GetFont( nScript
);
265 mrOutDevice
.SetFont( aFont
);
266 if (aFont
.GetColor() == COL_AUTO
)
267 mrOutDevice
.SetTextColor( mrOutDevice
.GetFillColor().IsDark() ? COL_WHITE
: COL_BLACK
);
268 mrOutDevice
.DrawText( aCurrPos
, maText
, nThisPos
, nNextPos
- nThisPos
);
269 aCurrPos
.AdjustX(maWidthVec
[ nVecIndex
++ ] );
270 aCurrPos
.AdjustX(mrOutDevice
.GetTextHeight() / 5 ); // add 20% of font height as portion spacing
278 SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice
& _rOutDevice
) :
279 mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice
) )
283 SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper
& _rCopy
) :
284 mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy
.mpImpl
) )
288 SvtScriptedTextHelper::~SvtScriptedTextHelper()
292 void SvtScriptedTextHelper::SetFonts( vcl::Font
const * _pLatinFont
, vcl::Font
const * _pAsianFont
, vcl::Font
const * _pCmplxFont
)
294 mpImpl
->SetFonts( _pLatinFont
, _pAsianFont
, _pCmplxFont
);
297 void SvtScriptedTextHelper::SetDefaultFont()
299 mpImpl
->SetFonts( nullptr, nullptr, nullptr );
302 void SvtScriptedTextHelper::SetText( const OUString
& _rText
, const uno::Reference
< i18n::XBreakIterator
>& _xBreakIter
)
304 mpImpl
->SetText( _rText
, _xBreakIter
);
307 const Size
& SvtScriptedTextHelper::GetTextSize() const
309 return mpImpl
->GetTextSize();
312 void SvtScriptedTextHelper::DrawText( const Point
& _rPos
)
314 mpImpl
->DrawText( _rPos
);
318 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */