tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / svtools / source / control / scriptedtext.cxx
blobe47924687bab2ec264188131faec3ee05fecfeba
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>
28 #include <com/sun/star/i18n/XBreakIterator.hpp>
31 using namespace ::com::sun::star;
34 class SvtScriptedTextHelper_Impl
36 private:
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. */
59 void CalculateBreaks(
60 const uno::Reference< i18n::XBreakIterator >& _xBreakIter );
62 public:
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. */
70 void SetText(
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
94 switch( _nScript )
96 case i18n::ScriptType::LATIN: return maLatinFont;
97 case i18n::ScriptType::ASIAN: return maAsianFont;
98 case i18n::ScriptType::COMPLEX: return maCmplxFont;
100 return maDefltFont;
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
110 maWidthVec.clear();
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 ];
117 sal_Int32 nNextPos;
118 sal_Int32 nPosVecSize = maPosVec.size();
119 sal_Int32 nPosVecIndex = 1;
121 sal_Int16 nScript;
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 );
135 nThisPos = nNextPos;
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() ) );
147 mrOutDevice.Pop();
150 void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
152 maPosVec.clear();
153 maScriptVec.clear();
155 DBG_ASSERT( _xBreakIter.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" );
157 sal_Int32 nLen = maText.getLength();
158 if( nLen )
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 );
177 break;
178 default:
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;
187 sal_Int16 nScript;
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 )
195 ++nScript;
197 if( nNextCharIx == nCharIx )
198 ++nNextCharIx;
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
209 nThisPos = nNextPos;
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 );
223 CalculateSizes();
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;
231 CalculateSizes();
234 void SvtScriptedTextHelper_Impl::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
236 maText = _rText;
237 CalculateBreaks( _xBreakIter );
241 void SvtScriptedTextHelper_Impl::DrawText( const Point& _rPos )
243 if( maText.isEmpty() || maPosVec.empty() )
244 return;
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 ];
253 sal_Int32 nNextPos;
254 sal_Int32 nPosVecSize = maPosVec.size();
255 sal_Int32 nPosVecIndex = 1;
257 sal_Int16 nScript;
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
271 nThisPos = nNextPos;
274 mrOutDevice.Pop();
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: */