update emoji autocorrect entries from po-files
[LibreOffice.git] / svtools / source / control / scriptedtext.cxx
blob565a5b551141674adab5c357679866d163b2817d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
21 #include <vector>
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
38 private:
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. */
64 void CalculateBreaks(
65 const uno::Reference< i18n::XBreakIterator >& _xBreakIter );
67 public:
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 );
77 /** Destructor. */
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. */
83 void SetText(
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
126 switch( _nScript )
128 case i18n::ScriptType::LATIN: return maLatinFont;
129 case i18n::ScriptType::ASIAN: return maAsianFont;
130 case i18n::ScriptType::COMPLEX: return maCmplxFont;
132 return maDefltFont;
135 void SvtScriptedTextHelper_Impl::CalculateSizes()
137 maTextSize.Width() = maTextSize.Height() = 0;
138 maDefltFont = mrOutDevice.GetFont();
140 // calculate text portion widths and total width
141 maWidthVec.clear();
142 if( !maPosVec.empty() )
144 DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(),
145 "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" );
147 sal_Int32 nThisPos = maPosVec[ 0 ];
148 sal_Int32 nNextPos;
149 sal_Int32 nPosVecSize = maPosVec.size();
150 sal_Int32 nPosVecIndex = 1;
152 sal_Int16 nScript;
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;
166 nThisPos = nNextPos;
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 )
183 maPosVec.clear();
184 maScriptVec.clear();
186 DBG_ASSERT( _xBreakIter.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" );
188 sal_Int32 nLen = maText.getLength();
189 if( nLen )
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 );
208 break;
209 default:
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;
218 sal_Int16 nScript;
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 )
226 ++nScript;
228 if( nNextCharIx == nCharIx )
229 ++nNextCharIx;
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
240 nThisPos = nNextPos;
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 );
254 CalculateSizes();
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;
262 CalculateSizes();
265 void SvtScriptedTextHelper_Impl::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
267 maText = _rText;
268 CalculateBreaks( _xBreakIter );
272 void SvtScriptedTextHelper_Impl::DrawText( const Point& _rPos )
274 if( maText.isEmpty() || maPosVec.empty() )
275 return;
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 ];
283 sal_Int32 nNextPos;
284 sal_Int32 nPosVecSize = maPosVec.size();
285 sal_Int32 nPosVecIndex = 1;
287 sal_Int16 nScript;
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
299 nThisPos = nNextPos;
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()
319 delete mpImpl;
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: */