xref: /trunk/main/vcl/source/gdi/outdev3.cxx (revision 059ba0598f57281fd3513a365cd47f7a6bd07d2c)
1cdf0e10cSrcweir /*************************************************************************
2cdf0e10cSrcweir  *
3cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4cdf0e10cSrcweir  *
5cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6cdf0e10cSrcweir  *
7cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8cdf0e10cSrcweir  *
9cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10cdf0e10cSrcweir  *
11cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14cdf0e10cSrcweir  *
15cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20cdf0e10cSrcweir  *
21cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25cdf0e10cSrcweir  *
26cdf0e10cSrcweir  ************************************************************************/
27cdf0e10cSrcweir 
28cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29cdf0e10cSrcweir #include "precompiled_vcl.hxx"
30cdf0e10cSrcweir 
31cdf0e10cSrcweir #include "i18npool/mslangid.hxx"
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include "rtl/tencinfo.h"
34cdf0e10cSrcweir #include "rtl/logfile.hxx"
35cdf0e10cSrcweir 
36cdf0e10cSrcweir #include "tools/debug.hxx"
37cdf0e10cSrcweir #include "tools/poly.hxx"
38cdf0e10cSrcweir 
39cdf0e10cSrcweir #include "basegfx/polygon/b2dpolygon.hxx"
40cdf0e10cSrcweir #include "basegfx/polygon/b2dpolypolygon.hxx"
41cdf0e10cSrcweir #include "basegfx/matrix/b2dhommatrix.hxx"
42cdf0e10cSrcweir 
43cdf0e10cSrcweir #include "vcl/metric.hxx"
44cdf0e10cSrcweir #include "vcl/metaact.hxx"
45cdf0e10cSrcweir #include "vcl/gdimtf.hxx"
46cdf0e10cSrcweir #include "vcl/virdev.hxx"
47cdf0e10cSrcweir #include "vcl/print.hxx"
48cdf0e10cSrcweir #include "vcl/event.hxx"
49cdf0e10cSrcweir #include "vcl/window.hxx"
50cdf0e10cSrcweir #include "vcl/svapp.hxx"
51cdf0e10cSrcweir #include "vcl/bmpacc.hxx"
52cdf0e10cSrcweir #include "vcl/outdev.hxx"
53cdf0e10cSrcweir #include "vcl/edit.hxx"
54cdf0e10cSrcweir // declare system types in sysdata.hxx
55cdf0e10cSrcweir #include <svsys.h>
56cdf0e10cSrcweir #include "vcl/sysdata.hxx"
57cdf0e10cSrcweir #include "vcl/unohelp.hxx"
58cdf0e10cSrcweir #include "vcl/controllayout.hxx"
59cdf0e10cSrcweir 
60cdf0e10cSrcweir #include "salgdi.hxx"
61cdf0e10cSrcweir #include "sallayout.hxx"
62cdf0e10cSrcweir #include "svdata.hxx"
63cdf0e10cSrcweir #include "impfont.hxx"
64cdf0e10cSrcweir #include "outdata.hxx"
65cdf0e10cSrcweir #include "outfont.hxx"
66cdf0e10cSrcweir #include "outdev.h"
67cdf0e10cSrcweir #include "textlayout.hxx"
68cdf0e10cSrcweir #include "svids.hrc"
69cdf0e10cSrcweir #include "window.h"
70cdf0e10cSrcweir 
71cdf0e10cSrcweir #include "unotools/fontcvt.hxx"
72cdf0e10cSrcweir #include "unotools/fontcfg.hxx"
73cdf0e10cSrcweir 
74cdf0e10cSrcweir #include "osl/file.h"
75cdf0e10cSrcweir 
76cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
77cdf0e10cSrcweir #include "graphite_features.hxx"
78cdf0e10cSrcweir #endif
79cdf0e10cSrcweir #ifdef USE_BUILTIN_RASTERIZER
80cdf0e10cSrcweir #include "glyphcache.hxx"
81cdf0e10cSrcweir #endif
82cdf0e10cSrcweir 
83cdf0e10cSrcweir #include "pdfwriter_impl.hxx"
84cdf0e10cSrcweir 
85cdf0e10cSrcweir #include "com/sun/star/beans/PropertyValues.hpp"
86cdf0e10cSrcweir #include "com/sun/star/i18n/XBreakIterator.hpp"
87cdf0e10cSrcweir #include "com/sun/star/i18n/WordType.hpp"
88cdf0e10cSrcweir #include "com/sun/star/linguistic2/XLinguServiceManager.hpp"
89cdf0e10cSrcweir 
90cdf0e10cSrcweir #if defined UNX
91cdf0e10cSrcweir #define GLYPH_FONT_HEIGHT   128
92cdf0e10cSrcweir #elif defined OS2
93cdf0e10cSrcweir #define GLYPH_FONT_HEIGHT   176
94cdf0e10cSrcweir #else
95cdf0e10cSrcweir #define GLYPH_FONT_HEIGHT   256
96cdf0e10cSrcweir #endif
97cdf0e10cSrcweir 
98cdf0e10cSrcweir #include "sal/alloca.h"
99cdf0e10cSrcweir 
100cdf0e10cSrcweir #include <cmath>
101cdf0e10cSrcweir #include <cstring>
102cdf0e10cSrcweir 
103cdf0e10cSrcweir #include <memory>
104cdf0e10cSrcweir #include <algorithm>
105cdf0e10cSrcweir 
106cdf0e10cSrcweir 
107cdf0e10cSrcweir // =======================================================================
108cdf0e10cSrcweir 
109cdf0e10cSrcweir DBG_NAMEEX( OutputDevice )
110cdf0e10cSrcweir DBG_NAMEEX( Font )
111cdf0e10cSrcweir 
112cdf0e10cSrcweir // =======================================================================
113cdf0e10cSrcweir 
114cdf0e10cSrcweir using namespace ::com::sun::star;
115cdf0e10cSrcweir using namespace ::com::sun::star::uno;
116cdf0e10cSrcweir using namespace ::rtl;
117cdf0e10cSrcweir using namespace ::vcl;
118cdf0e10cSrcweir using namespace ::utl;
119cdf0e10cSrcweir 
120cdf0e10cSrcweir // =======================================================================
121cdf0e10cSrcweir 
122cdf0e10cSrcweir #define TEXT_DRAW_ELLIPSIS  (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
123cdf0e10cSrcweir 
124cdf0e10cSrcweir // =======================================================================
125cdf0e10cSrcweir 
126cdf0e10cSrcweir #define UNDERLINE_LAST      UNDERLINE_BOLDWAVE
127cdf0e10cSrcweir #define STRIKEOUT_LAST      STRIKEOUT_X
128cdf0e10cSrcweir 
129cdf0e10cSrcweir // =======================================================================
130cdf0e10cSrcweir 
131cdf0e10cSrcweir static void ImplRotatePos( long nOriginX, long nOriginY, long& rX, long& rY,
132cdf0e10cSrcweir                            int nOrientation )
133cdf0e10cSrcweir {
134cdf0e10cSrcweir     if ( (nOrientation >= 0) && !(nOrientation % 900) )
135cdf0e10cSrcweir     {
136cdf0e10cSrcweir         if ( (nOrientation >= 3600) )
137cdf0e10cSrcweir             nOrientation %= 3600;
138cdf0e10cSrcweir 
139cdf0e10cSrcweir         if ( nOrientation )
140cdf0e10cSrcweir         {
141cdf0e10cSrcweir             rX -= nOriginX;
142cdf0e10cSrcweir             rY -= nOriginY;
143cdf0e10cSrcweir 
144cdf0e10cSrcweir             if ( nOrientation == 900 )
145cdf0e10cSrcweir             {
146cdf0e10cSrcweir                 long nTemp = rX;
147cdf0e10cSrcweir                 rX = rY;
148cdf0e10cSrcweir                 rY = -nTemp;
149cdf0e10cSrcweir             }
150cdf0e10cSrcweir             else if ( nOrientation == 1800 )
151cdf0e10cSrcweir             {
152cdf0e10cSrcweir                 rX = -rX;
153cdf0e10cSrcweir                 rY = -rY;
154cdf0e10cSrcweir             }
155cdf0e10cSrcweir             else /* ( nOrientation == 2700 ) */
156cdf0e10cSrcweir             {
157cdf0e10cSrcweir                 long nTemp = rX;
158cdf0e10cSrcweir                 rX = -rY;
159cdf0e10cSrcweir                 rY = nTemp;
160cdf0e10cSrcweir             }
161cdf0e10cSrcweir 
162cdf0e10cSrcweir             rX += nOriginX;
163cdf0e10cSrcweir             rY += nOriginY;
164cdf0e10cSrcweir         }
165cdf0e10cSrcweir     }
166cdf0e10cSrcweir     else
167cdf0e10cSrcweir     {
168cdf0e10cSrcweir         double nRealOrientation = nOrientation*F_PI1800;
169cdf0e10cSrcweir         double nCos = cos( nRealOrientation );
170cdf0e10cSrcweir         double nSin = sin( nRealOrientation );
171cdf0e10cSrcweir 
172cdf0e10cSrcweir         // Translation...
173cdf0e10cSrcweir         long nX = rX-nOriginX;
174cdf0e10cSrcweir         long nY = rY-nOriginY;
175cdf0e10cSrcweir 
176cdf0e10cSrcweir         // Rotation...
177cdf0e10cSrcweir         rX = +((long)(nCos*nX + nSin*nY)) + nOriginX;
178cdf0e10cSrcweir         rY = -((long)(nSin*nX - nCos*nY)) + nOriginY;
179cdf0e10cSrcweir     }
180cdf0e10cSrcweir }
181cdf0e10cSrcweir 
182cdf0e10cSrcweir // =======================================================================
183cdf0e10cSrcweir 
184cdf0e10cSrcweir void OutputDevice::ImplUpdateFontData( bool bNewFontLists )
185cdf0e10cSrcweir {
186cdf0e10cSrcweir     // the currently selected logical font is no longer needed
187cdf0e10cSrcweir     if ( mpFontEntry )
188cdf0e10cSrcweir     {
189cdf0e10cSrcweir         mpFontCache->Release( mpFontEntry );
190cdf0e10cSrcweir         mpFontEntry = NULL;
191cdf0e10cSrcweir     }
192cdf0e10cSrcweir 
193cdf0e10cSrcweir     mbInitFont = true;
194cdf0e10cSrcweir     mbNewFont = true;
195cdf0e10cSrcweir 
196cdf0e10cSrcweir     if ( bNewFontLists )
197cdf0e10cSrcweir     {
198cdf0e10cSrcweir         if ( mpGetDevFontList )
199cdf0e10cSrcweir         {
200cdf0e10cSrcweir             delete mpGetDevFontList;
201cdf0e10cSrcweir             mpGetDevFontList = NULL;
202cdf0e10cSrcweir         }
203cdf0e10cSrcweir         if ( mpGetDevSizeList )
204cdf0e10cSrcweir         {
205cdf0e10cSrcweir             delete mpGetDevSizeList;
206cdf0e10cSrcweir             mpGetDevSizeList = NULL;
207cdf0e10cSrcweir         }
208cdf0e10cSrcweir 
209cdf0e10cSrcweir         // release all physically selected fonts on this device
210cdf0e10cSrcweir     if( ImplGetGraphics() )
211cdf0e10cSrcweir          mpGraphics->ReleaseFonts();
212cdf0e10cSrcweir     }
213cdf0e10cSrcweir 
214cdf0e10cSrcweir     if ( GetOutDevType() == OUTDEV_PRINTER || mpPDFWriter )
215cdf0e10cSrcweir     {
216cdf0e10cSrcweir         ImplSVData* pSVData = ImplGetSVData();
217cdf0e10cSrcweir 
218cdf0e10cSrcweir         if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
219cdf0e10cSrcweir             mpFontCache->Invalidate();
220cdf0e10cSrcweir 
221cdf0e10cSrcweir         if ( bNewFontLists )
222cdf0e10cSrcweir         {
223cdf0e10cSrcweir             // we need a graphics
224cdf0e10cSrcweir             if ( ImplGetGraphics() )
225cdf0e10cSrcweir             {
226cdf0e10cSrcweir                 if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
227cdf0e10cSrcweir                     mpFontList->Clear();
228cdf0e10cSrcweir 
229cdf0e10cSrcweir                 if( mpPDFWriter )
230cdf0e10cSrcweir                 {
231cdf0e10cSrcweir                     if( mpFontList && mpFontList != pSVData->maGDIData.mpScreenFontList )
232cdf0e10cSrcweir                         delete mpFontList;
233cdf0e10cSrcweir                     if( mpFontCache && mpFontCache != pSVData->maGDIData.mpScreenFontCache )
234cdf0e10cSrcweir                         delete mpFontCache;
235cdf0e10cSrcweir                     mpFontList = mpPDFWriter->filterDevFontList( pSVData->maGDIData.mpScreenFontList );
236cdf0e10cSrcweir                     mpFontCache = new ImplFontCache( sal_False );
237cdf0e10cSrcweir                 }
238cdf0e10cSrcweir                 else
239cdf0e10cSrcweir                 {
240cdf0e10cSrcweir                     if( mpOutDevData )
241cdf0e10cSrcweir                         mpOutDevData->maDevFontSubst.Clear();
242cdf0e10cSrcweir                     mpGraphics->GetDevFontList( mpFontList );
243cdf0e10cSrcweir                     mpGraphics->GetDevFontSubstList( this );
244cdf0e10cSrcweir                 }
245cdf0e10cSrcweir             }
246cdf0e10cSrcweir         }
247cdf0e10cSrcweir     }
248cdf0e10cSrcweir 
249cdf0e10cSrcweir     // also update child windows if needed
250cdf0e10cSrcweir     if ( GetOutDevType() == OUTDEV_WINDOW )
251cdf0e10cSrcweir     {
252cdf0e10cSrcweir         Window* pChild = ((Window*)this)->mpWindowImpl->mpFirstChild;
253cdf0e10cSrcweir         while ( pChild )
254cdf0e10cSrcweir         {
255cdf0e10cSrcweir             pChild->ImplUpdateFontData( true );
256cdf0e10cSrcweir             pChild = pChild->mpWindowImpl->mpNext;
257cdf0e10cSrcweir         }
258cdf0e10cSrcweir     }
259cdf0e10cSrcweir }
260cdf0e10cSrcweir 
261cdf0e10cSrcweir // -----------------------------------------------------------------------
262cdf0e10cSrcweir 
263cdf0e10cSrcweir void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists )
264cdf0e10cSrcweir {
265cdf0e10cSrcweir     ImplSVData* pSVData = ImplGetSVData();
266cdf0e10cSrcweir 
267cdf0e10cSrcweir     // update all windows
268cdf0e10cSrcweir     Window* pFrame = pSVData->maWinData.mpFirstFrame;
269cdf0e10cSrcweir     while ( pFrame )
270cdf0e10cSrcweir     {
271cdf0e10cSrcweir         pFrame->ImplUpdateFontData( bNewFontLists );
272cdf0e10cSrcweir 
273cdf0e10cSrcweir         Window* pSysWin = pFrame->mpWindowImpl->mpFrameData->mpFirstOverlap;
274cdf0e10cSrcweir         while ( pSysWin )
275cdf0e10cSrcweir         {
276cdf0e10cSrcweir             pSysWin->ImplUpdateFontData( bNewFontLists );
277cdf0e10cSrcweir             pSysWin = pSysWin->mpWindowImpl->mpNextOverlap;
278cdf0e10cSrcweir         }
279cdf0e10cSrcweir 
280cdf0e10cSrcweir         pFrame = pFrame->mpWindowImpl->mpFrameData->mpNextFrame;
281cdf0e10cSrcweir     }
282cdf0e10cSrcweir 
283cdf0e10cSrcweir     // update all virtual devices
284cdf0e10cSrcweir     VirtualDevice* pVirDev = pSVData->maGDIData.mpFirstVirDev;
285cdf0e10cSrcweir     while ( pVirDev )
286cdf0e10cSrcweir     {
287cdf0e10cSrcweir         pVirDev->ImplUpdateFontData( bNewFontLists );
288cdf0e10cSrcweir         pVirDev = pVirDev->mpNext;
289cdf0e10cSrcweir     }
290cdf0e10cSrcweir 
291cdf0e10cSrcweir     // update all printers
292cdf0e10cSrcweir     Printer* pPrinter = pSVData->maGDIData.mpFirstPrinter;
293cdf0e10cSrcweir     while ( pPrinter )
294cdf0e10cSrcweir     {
295cdf0e10cSrcweir         pPrinter->ImplUpdateFontData( bNewFontLists );
296cdf0e10cSrcweir         pPrinter = pPrinter->mpNext;
297cdf0e10cSrcweir     }
298cdf0e10cSrcweir 
299cdf0e10cSrcweir     // clear global font lists to have them updated
300cdf0e10cSrcweir     pSVData->maGDIData.mpScreenFontCache->Invalidate();
301cdf0e10cSrcweir     if ( bNewFontLists )
302cdf0e10cSrcweir     {
303cdf0e10cSrcweir         pSVData->maGDIData.mpScreenFontList->Clear();
304cdf0e10cSrcweir         pFrame = pSVData->maWinData.mpFirstFrame;
305cdf0e10cSrcweir         if ( pFrame )
306cdf0e10cSrcweir         {
307cdf0e10cSrcweir             if ( pFrame->ImplGetGraphics() )
308cdf0e10cSrcweir                 // MT: Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler.
309cdf0e10cSrcweir                 ((OutputDevice*)pFrame)->mpGraphics->GetDevFontList( pFrame->mpWindowImpl->mpFrameData->mpFontList );
310cdf0e10cSrcweir         }
311cdf0e10cSrcweir     }
312cdf0e10cSrcweir }
313cdf0e10cSrcweir 
314cdf0e10cSrcweir // =======================================================================
315cdf0e10cSrcweir 
316cdf0e10cSrcweir 
317cdf0e10cSrcweir // =======================================================================
318cdf0e10cSrcweir 
319cdf0e10cSrcweir // TODO: remove this method when the CWS-gfbfcfg dust has settled
320cdf0e10cSrcweir void ImplFreeOutDevFontData()
321cdf0e10cSrcweir {}
322cdf0e10cSrcweir 
323cdf0e10cSrcweir // =======================================================================
324cdf0e10cSrcweir 
325cdf0e10cSrcweir void OutputDevice::BeginFontSubstitution()
326cdf0e10cSrcweir {
327cdf0e10cSrcweir     ImplSVData* pSVData = ImplGetSVData();
328cdf0e10cSrcweir     pSVData->maGDIData.mbFontSubChanged = sal_False;
329cdf0e10cSrcweir }
330cdf0e10cSrcweir 
331cdf0e10cSrcweir // -----------------------------------------------------------------------
332cdf0e10cSrcweir 
333cdf0e10cSrcweir void OutputDevice::EndFontSubstitution()
334cdf0e10cSrcweir {
335cdf0e10cSrcweir     ImplSVData* pSVData = ImplGetSVData();
336cdf0e10cSrcweir     if ( pSVData->maGDIData.mbFontSubChanged )
337cdf0e10cSrcweir     {
338cdf0e10cSrcweir         ImplUpdateAllFontData( false );
339cdf0e10cSrcweir 
340cdf0e10cSrcweir         Application* pApp = GetpApp();
341cdf0e10cSrcweir         DataChangedEvent aDCEvt( DATACHANGED_FONTSUBSTITUTION );
342cdf0e10cSrcweir         pApp->DataChanged( aDCEvt );
343cdf0e10cSrcweir         pApp->NotifyAllWindows( aDCEvt );
344cdf0e10cSrcweir         pSVData->maGDIData.mbFontSubChanged = sal_False;
345cdf0e10cSrcweir     }
346cdf0e10cSrcweir }
347cdf0e10cSrcweir 
348cdf0e10cSrcweir // -----------------------------------------------------------------------
349cdf0e10cSrcweir 
350cdf0e10cSrcweir void OutputDevice::AddFontSubstitute( const XubString& rFontName,
351cdf0e10cSrcweir                                       const XubString& rReplaceFontName,
352cdf0e10cSrcweir                                       sal_uInt16 nFlags )
353cdf0e10cSrcweir {
354cdf0e10cSrcweir     ImplDirectFontSubstitution*& rpSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
355cdf0e10cSrcweir     if( !rpSubst )
356cdf0e10cSrcweir         rpSubst = new ImplDirectFontSubstitution();
357cdf0e10cSrcweir     rpSubst->AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
358cdf0e10cSrcweir     ImplGetSVData()->maGDIData.mbFontSubChanged = sal_True;
359cdf0e10cSrcweir }
360cdf0e10cSrcweir 
361cdf0e10cSrcweir // -----------------------------------------------------------------------
362cdf0e10cSrcweir 
363cdf0e10cSrcweir void ImplDirectFontSubstitution::AddFontSubstitute( const String& rFontName,
364cdf0e10cSrcweir     const String& rSubstFontName, sal_uInt16 nFlags )
365cdf0e10cSrcweir {
366cdf0e10cSrcweir     maFontSubstList.push_back( ImplFontSubstEntry( rFontName, rSubstFontName, nFlags ) );
367cdf0e10cSrcweir }
368cdf0e10cSrcweir 
369cdf0e10cSrcweir // -----------------------------------------------------------------------
370cdf0e10cSrcweir 
371cdf0e10cSrcweir ImplFontSubstEntry::ImplFontSubstEntry( const String& rFontName,
372cdf0e10cSrcweir     const String& rSubstFontName, sal_uInt16 nSubstFlags )
373cdf0e10cSrcweir :   maName( rFontName )
374cdf0e10cSrcweir ,   maReplaceName( rSubstFontName )
375cdf0e10cSrcweir ,   mnFlags( nSubstFlags )
376cdf0e10cSrcweir {
377cdf0e10cSrcweir     maSearchName        = rFontName;
378cdf0e10cSrcweir     maSearchReplaceName = rSubstFontName;
379cdf0e10cSrcweir     GetEnglishSearchFontName( maSearchName );
380cdf0e10cSrcweir     GetEnglishSearchFontName( maSearchReplaceName );
381cdf0e10cSrcweir }
382cdf0e10cSrcweir 
383cdf0e10cSrcweir // -----------------------------------------------------------------------
384cdf0e10cSrcweir 
385cdf0e10cSrcweir void OutputDevice::ImplAddDevFontSubstitute( const XubString& rFontName,
386cdf0e10cSrcweir                                              const XubString& rReplaceFontName,
387cdf0e10cSrcweir                                              sal_uInt16 nFlags )
388cdf0e10cSrcweir {
389cdf0e10cSrcweir     ImplInitOutDevData();
390cdf0e10cSrcweir     mpOutDevData->maDevFontSubst.AddFontSubstitute( rFontName, rReplaceFontName, nFlags );
391cdf0e10cSrcweir }
392cdf0e10cSrcweir 
393cdf0e10cSrcweir // -----------------------------------------------------------------------
394cdf0e10cSrcweir 
395cdf0e10cSrcweir void OutputDevice::RemoveFontSubstitute( sal_uInt16 n )
396cdf0e10cSrcweir {
397cdf0e10cSrcweir     ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
398cdf0e10cSrcweir     if( pSubst )
399cdf0e10cSrcweir         pSubst->RemoveFontSubstitute( n );
400cdf0e10cSrcweir }
401cdf0e10cSrcweir 
402cdf0e10cSrcweir // -----------------------------------------------------------------------
403cdf0e10cSrcweir 
404cdf0e10cSrcweir void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex )
405cdf0e10cSrcweir {
406cdf0e10cSrcweir     FontSubstList::iterator it = maFontSubstList.begin();
407cdf0e10cSrcweir     for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
408cdf0e10cSrcweir     if( it != maFontSubstList.end() )
409cdf0e10cSrcweir         maFontSubstList.erase( it );
410cdf0e10cSrcweir }
411cdf0e10cSrcweir 
412cdf0e10cSrcweir // -----------------------------------------------------------------------
413cdf0e10cSrcweir 
414cdf0e10cSrcweir sal_uInt16 OutputDevice::GetFontSubstituteCount()
415cdf0e10cSrcweir {
416cdf0e10cSrcweir     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
417cdf0e10cSrcweir     if( !pSubst )
418cdf0e10cSrcweir     return 0;
419cdf0e10cSrcweir     int nCount =  pSubst->GetFontSubstituteCount();
420cdf0e10cSrcweir     return (sal_uInt16)nCount;
421cdf0e10cSrcweir }
422cdf0e10cSrcweir 
423cdf0e10cSrcweir // -----------------------------------------------------------------------
424cdf0e10cSrcweir 
425cdf0e10cSrcweir void OutputDevice::GetFontSubstitute( sal_uInt16 n,
426cdf0e10cSrcweir                                       XubString& rFontName,
427cdf0e10cSrcweir                                       XubString& rReplaceFontName,
428cdf0e10cSrcweir                                       sal_uInt16& rFlags )
429cdf0e10cSrcweir {
430cdf0e10cSrcweir     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
431cdf0e10cSrcweir     if( pSubst )
432cdf0e10cSrcweir         pSubst->GetFontSubstitute( n, rFontName, rReplaceFontName, rFlags );
433cdf0e10cSrcweir }
434cdf0e10cSrcweir 
435cdf0e10cSrcweir // -----------------------------------------------------------------------
436cdf0e10cSrcweir 
437cdf0e10cSrcweir bool ImplDirectFontSubstitution::GetFontSubstitute( int nIndex,
438cdf0e10cSrcweir     String& rFontName, String& rSubstFontName, sal_uInt16& rFlags ) const
439cdf0e10cSrcweir {
440cdf0e10cSrcweir     FontSubstList::const_iterator it = maFontSubstList.begin();
441cdf0e10cSrcweir     for( int nCount = 0; (it != maFontSubstList.end()) && (nCount++ != nIndex); ++it ) ;
442cdf0e10cSrcweir     if( it == maFontSubstList.end() )
443cdf0e10cSrcweir         return false;
444cdf0e10cSrcweir 
445cdf0e10cSrcweir     const ImplFontSubstEntry* pEntry = &(*it);
446cdf0e10cSrcweir     rFontName       = pEntry->maName;
447cdf0e10cSrcweir     rSubstFontName  = pEntry->maReplaceName;
448cdf0e10cSrcweir     rFlags          = pEntry->mnFlags;
449cdf0e10cSrcweir     return true;
450cdf0e10cSrcweir }
451cdf0e10cSrcweir 
452cdf0e10cSrcweir // -----------------------------------------------------------------------
453cdf0e10cSrcweir 
454cdf0e10cSrcweir bool ImplDirectFontSubstitution::FindFontSubstitute( String& rSubstName,
455cdf0e10cSrcweir     const String& rSearchName, sal_uInt16 nFlags ) const
456cdf0e10cSrcweir {
457cdf0e10cSrcweir     // TODO: get rid of O(N) searches
458cdf0e10cSrcweir     FontSubstList::const_iterator it = maFontSubstList.begin();
459cdf0e10cSrcweir     for(; it != maFontSubstList.end(); ++it )
460cdf0e10cSrcweir     {
461cdf0e10cSrcweir         const ImplFontSubstEntry& rEntry = *it;
462cdf0e10cSrcweir         if( ((rEntry.mnFlags & nFlags) || !nFlags)
463cdf0e10cSrcweir         &&   (rEntry.maSearchName == rSearchName) )
464cdf0e10cSrcweir         {
465cdf0e10cSrcweir             rSubstName = rEntry.maSearchReplaceName;
466cdf0e10cSrcweir             return true;
467cdf0e10cSrcweir         }
468cdf0e10cSrcweir     }
469cdf0e10cSrcweir 
470cdf0e10cSrcweir     return false;
471cdf0e10cSrcweir }
472cdf0e10cSrcweir 
473cdf0e10cSrcweir // -----------------------------------------------------------------------
474cdf0e10cSrcweir 
475cdf0e10cSrcweir static void ImplFontSubstitute( String& rFontName,
476cdf0e10cSrcweir     sal_uInt16 nFlags, ImplDirectFontSubstitution* pDevSpecific )
477cdf0e10cSrcweir {
478cdf0e10cSrcweir #ifdef DBG_UTIL
479cdf0e10cSrcweir     String aTempName = rFontName;
480cdf0e10cSrcweir     GetEnglishSearchFontName( aTempName );
481cdf0e10cSrcweir     DBG_ASSERT( aTempName == rFontName, "ImplFontSubstitute() called without a searchname" );
482cdf0e10cSrcweir #endif
483cdf0e10cSrcweir 
484cdf0e10cSrcweir     String aSubstFontName;
485cdf0e10cSrcweir 
486cdf0e10cSrcweir     // apply user-configurable font replacement (eg, from the list in Tools->Options)
487cdf0e10cSrcweir     const ImplDirectFontSubstitution* pSubst = ImplGetSVData()->maGDIData.mpDirectFontSubst;
488cdf0e10cSrcweir     if( pSubst && pSubst->FindFontSubstitute( aSubstFontName, rFontName, FONT_SUBSTITUTE_ALWAYS ) )
489cdf0e10cSrcweir     {
490cdf0e10cSrcweir         rFontName = aSubstFontName;
491cdf0e10cSrcweir         return;
492cdf0e10cSrcweir     }
493cdf0e10cSrcweir 
494cdf0e10cSrcweir     // apply device specific font replacement (e.g. to use printer builtin fonts)
495cdf0e10cSrcweir     if( !pDevSpecific )
496cdf0e10cSrcweir         return;
497cdf0e10cSrcweir 
498cdf0e10cSrcweir     if( pDevSpecific->FindFontSubstitute( aSubstFontName, rFontName, nFlags ) )
499cdf0e10cSrcweir     {
500cdf0e10cSrcweir         rFontName = aSubstFontName;
501cdf0e10cSrcweir         return;
502cdf0e10cSrcweir     }
503cdf0e10cSrcweir }
504cdf0e10cSrcweir 
505cdf0e10cSrcweir // -----------------------------------------------------------------------
506cdf0e10cSrcweir 
507cdf0e10cSrcweir Font OutputDevice::GetDefaultFont( sal_uInt16 nType, LanguageType eLang,
508cdf0e10cSrcweir                                    sal_uLong nFlags, const OutputDevice* pOutDev )
509cdf0e10cSrcweir {
510cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetDefaultFont()" );
511cdf0e10cSrcweir 
512cdf0e10cSrcweir     com::sun::star::lang::Locale aLocale;
513cdf0e10cSrcweir     if( eLang == LANGUAGE_NONE || eLang == LANGUAGE_SYSTEM || eLang == LANGUAGE_DONTKNOW )
514cdf0e10cSrcweir     {
515cdf0e10cSrcweir         aLocale = Application::GetSettings().GetUILocale();
516cdf0e10cSrcweir     }
517cdf0e10cSrcweir     else
518cdf0e10cSrcweir     {
519cdf0e10cSrcweir         MsLangId::convertLanguageToLocale( eLang, aLocale );
520cdf0e10cSrcweir     }
521cdf0e10cSrcweir 
522cdf0e10cSrcweir     utl::DefaultFontConfiguration& rDefaults = *utl::DefaultFontConfiguration::get();
523cdf0e10cSrcweir     String aSearch = rDefaults.getUserInterfaceFont( aLocale ); // ensure a fallback
524cdf0e10cSrcweir     String aDefault = rDefaults.getDefaultFont( aLocale, nType );
525cdf0e10cSrcweir     if( aDefault.Len() )
526cdf0e10cSrcweir         aSearch = aDefault;
527cdf0e10cSrcweir 
528cdf0e10cSrcweir     int nDefaultHeight = 12;
529cdf0e10cSrcweir 
530cdf0e10cSrcweir     Font aFont;
531cdf0e10cSrcweir     aFont.SetPitch( PITCH_VARIABLE );
532cdf0e10cSrcweir 
533cdf0e10cSrcweir     switch ( nType )
534cdf0e10cSrcweir     {
535cdf0e10cSrcweir         case DEFAULTFONT_SANS_UNICODE:
536cdf0e10cSrcweir         case DEFAULTFONT_UI_SANS:
537cdf0e10cSrcweir             aFont.SetFamily( FAMILY_SWISS );
538cdf0e10cSrcweir             break;
539cdf0e10cSrcweir 
540cdf0e10cSrcweir         case DEFAULTFONT_SANS:
541cdf0e10cSrcweir         case DEFAULTFONT_LATIN_HEADING:
542cdf0e10cSrcweir         case DEFAULTFONT_LATIN_SPREADSHEET:
543cdf0e10cSrcweir         case DEFAULTFONT_LATIN_DISPLAY:
544cdf0e10cSrcweir             aFont.SetFamily( FAMILY_SWISS );
545cdf0e10cSrcweir             break;
546cdf0e10cSrcweir 
547cdf0e10cSrcweir         case DEFAULTFONT_SERIF:
548cdf0e10cSrcweir         case DEFAULTFONT_LATIN_TEXT:
549cdf0e10cSrcweir         case DEFAULTFONT_LATIN_PRESENTATION:
550cdf0e10cSrcweir             aFont.SetFamily( FAMILY_ROMAN );
551cdf0e10cSrcweir             break;
552cdf0e10cSrcweir 
553cdf0e10cSrcweir         case DEFAULTFONT_FIXED:
554cdf0e10cSrcweir         case DEFAULTFONT_LATIN_FIXED:
555cdf0e10cSrcweir         case DEFAULTFONT_UI_FIXED:
556cdf0e10cSrcweir             aFont.SetPitch( PITCH_FIXED );
557cdf0e10cSrcweir             aFont.SetFamily( FAMILY_MODERN );
558cdf0e10cSrcweir             break;
559cdf0e10cSrcweir 
560cdf0e10cSrcweir         case DEFAULTFONT_SYMBOL:
561cdf0e10cSrcweir             aFont.SetCharSet( RTL_TEXTENCODING_SYMBOL );
562cdf0e10cSrcweir             break;
563cdf0e10cSrcweir 
564cdf0e10cSrcweir         case DEFAULTFONT_CJK_TEXT:
565cdf0e10cSrcweir         case DEFAULTFONT_CJK_PRESENTATION:
566cdf0e10cSrcweir         case DEFAULTFONT_CJK_SPREADSHEET:
567cdf0e10cSrcweir         case DEFAULTFONT_CJK_HEADING:
568cdf0e10cSrcweir         case DEFAULTFONT_CJK_DISPLAY:
569cdf0e10cSrcweir             aFont.SetFamily( FAMILY_SYSTEM );   // don't care, but don't use font subst config later...
570cdf0e10cSrcweir             break;
571cdf0e10cSrcweir 
572cdf0e10cSrcweir         case DEFAULTFONT_CTL_TEXT:
573cdf0e10cSrcweir         case DEFAULTFONT_CTL_PRESENTATION:
574cdf0e10cSrcweir         case DEFAULTFONT_CTL_SPREADSHEET:
575cdf0e10cSrcweir         case DEFAULTFONT_CTL_HEADING:
576cdf0e10cSrcweir         case DEFAULTFONT_CTL_DISPLAY:
577cdf0e10cSrcweir             aFont.SetFamily( FAMILY_SYSTEM );   // don't care, but don't use font subst config later...
578cdf0e10cSrcweir             break;
579cdf0e10cSrcweir     }
580cdf0e10cSrcweir 
581cdf0e10cSrcweir     if ( aSearch.Len() )
582cdf0e10cSrcweir     {
583cdf0e10cSrcweir         aFont.SetHeight( nDefaultHeight );
584cdf0e10cSrcweir         aFont.SetWeight( WEIGHT_NORMAL );
585cdf0e10cSrcweir         aFont.SetLanguage( eLang );
586cdf0e10cSrcweir 
587cdf0e10cSrcweir         if ( aFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW )
588cdf0e10cSrcweir             aFont.SetCharSet( gsl_getSystemTextEncoding() );
589cdf0e10cSrcweir 
590cdf0e10cSrcweir         // Should we only return available fonts on the given device
591cdf0e10cSrcweir         if ( pOutDev )
592cdf0e10cSrcweir         {
593cdf0e10cSrcweir             pOutDev->ImplInitFontList();
594cdf0e10cSrcweir 
595cdf0e10cSrcweir             // Search Font in the FontList
596cdf0e10cSrcweir             String      aName;
597cdf0e10cSrcweir             String      aSearchName;
598cdf0e10cSrcweir             xub_StrLen  nIndex = 0;
599cdf0e10cSrcweir             do
600cdf0e10cSrcweir             {
601cdf0e10cSrcweir                 aSearchName = GetNextFontToken( aSearch, nIndex );
602cdf0e10cSrcweir                 GetEnglishSearchFontName( aSearchName );
603cdf0e10cSrcweir                 ImplDevFontListData* pFontFamily = pOutDev->mpFontList->ImplFindBySearchName( aSearchName );
604cdf0e10cSrcweir                 if( pFontFamily )
605cdf0e10cSrcweir                 {
606cdf0e10cSrcweir                     AddTokenFontName( aName, pFontFamily->GetFamilyName() );
607cdf0e10cSrcweir                     if( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
608cdf0e10cSrcweir                         break;
609cdf0e10cSrcweir                 }
610cdf0e10cSrcweir             }
611cdf0e10cSrcweir             while ( nIndex != STRING_NOTFOUND );
612cdf0e10cSrcweir             aFont.SetName( aName );
613cdf0e10cSrcweir         }
614cdf0e10cSrcweir 
615cdf0e10cSrcweir         // No Name, than set all names
616cdf0e10cSrcweir         if ( !aFont.GetName().Len() )
617cdf0e10cSrcweir         {
618cdf0e10cSrcweir             xub_StrLen nIndex = 0;
619cdf0e10cSrcweir             if ( nFlags & DEFAULTFONT_FLAGS_ONLYONE )
620cdf0e10cSrcweir             {
621cdf0e10cSrcweir                 //aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
622cdf0e10cSrcweir                 if( !pOutDev )
623cdf0e10cSrcweir                     pOutDev = (const OutputDevice *)ImplGetSVData()->mpDefaultWin;
624cdf0e10cSrcweir                 if( !pOutDev )
625cdf0e10cSrcweir                     aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
626cdf0e10cSrcweir                 else
627cdf0e10cSrcweir                 {
628cdf0e10cSrcweir                     pOutDev->ImplInitFontList();
629cdf0e10cSrcweir 
630cdf0e10cSrcweir                     aFont.SetName( aSearch );
631cdf0e10cSrcweir 
632cdf0e10cSrcweir                     // convert to pixel height
633cdf0e10cSrcweir                     Size aSize = pOutDev->ImplLogicToDevicePixel( aFont.GetSize() );
634cdf0e10cSrcweir                     if ( !aSize.Height() )
635cdf0e10cSrcweir                     {
636cdf0e10cSrcweir                         // use default pixel height only when logical height is zero
637cdf0e10cSrcweir                         if ( aFont.GetHeight() )
638cdf0e10cSrcweir                             aSize.Height() = 1;
639cdf0e10cSrcweir                         else
640cdf0e10cSrcweir                             aSize.Height() = (12*pOutDev->mnDPIY)/72;
641cdf0e10cSrcweir                     }
642cdf0e10cSrcweir 
643cdf0e10cSrcweir                     // use default width only when logical width is zero
644cdf0e10cSrcweir                     if( (0 == aSize.Width()) && (0 != aFont.GetSize().Width()) )
645cdf0e10cSrcweir                         aSize.Width() = 1;
646cdf0e10cSrcweir 
647cdf0e10cSrcweir                     // get the name of the first available font
648cdf0e10cSrcweir                     float fExactHeight = static_cast<float>(aSize.Height());
649cdf0e10cSrcweir                     ImplFontEntry* pEntry = pOutDev->mpFontCache->GetFontEntry( pOutDev->mpFontList, aFont, aSize, fExactHeight, pOutDev->mpOutDevData ? &pOutDev->mpOutDevData->maDevFontSubst : NULL );
650cdf0e10cSrcweir                     if( pEntry->maFontSelData.mpFontData )
651cdf0e10cSrcweir                         aFont.SetName( pEntry->maFontSelData.mpFontData->maName );
652cdf0e10cSrcweir                     else
653cdf0e10cSrcweir                         aFont.SetName( pEntry->maFontSelData.maTargetName );
654cdf0e10cSrcweir                 }
655cdf0e10cSrcweir             }
656cdf0e10cSrcweir             else
657cdf0e10cSrcweir                 aFont.SetName( aSearch );
658cdf0e10cSrcweir         }
659cdf0e10cSrcweir     }
660cdf0e10cSrcweir 
661cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 2
662cdf0e10cSrcweir     const char* s = "DEFAULTFONT_SANS_UNKNOWN";
663cdf0e10cSrcweir     switch ( nType )
664cdf0e10cSrcweir     {
665cdf0e10cSrcweir     case DEFAULTFONT_SANS_UNICODE:  s = "DEFAULTFONT_SANS_UNICODE"; break;
666cdf0e10cSrcweir     case DEFAULTFONT_UI_SANS:   s = "DEFAULTFONT_UI_SANS"; break;
667cdf0e10cSrcweir 
668cdf0e10cSrcweir     case DEFAULTFONT_SANS:  s = "DEFAULTFONT_SANS"; break;
669cdf0e10cSrcweir     case DEFAULTFONT_LATIN_HEADING: s = "DEFAULTFONT_LATIN_HEADING"; break;
670cdf0e10cSrcweir     case DEFAULTFONT_LATIN_SPREADSHEET: s = "DEFAULTFONT_LATIN_SPREADSHEET"; break;
671cdf0e10cSrcweir     case DEFAULTFONT_LATIN_DISPLAY: s = "DEFAULTFONT_LATIN_DISPLAY"; break;
672cdf0e10cSrcweir 
673cdf0e10cSrcweir     case DEFAULTFONT_SERIF: s = "DEFAULTFONT_SERIF"; break;
674cdf0e10cSrcweir     case DEFAULTFONT_LATIN_TEXT:    s = "DEFAULTFONT_LATIN_TEXT"; break;
675cdf0e10cSrcweir     case DEFAULTFONT_LATIN_PRESENTATION:    s = "DEFAULTFONT_LATIN_PRESENTATION"; break;
676cdf0e10cSrcweir 
677cdf0e10cSrcweir     case DEFAULTFONT_FIXED: s = "DEFAULTFONT_FIXED"; break;
678cdf0e10cSrcweir     case DEFAULTFONT_LATIN_FIXED:   s = "DEFAULTFONT_LATIN_FIXED"; break;
679cdf0e10cSrcweir     case DEFAULTFONT_UI_FIXED:  s = "DEFAULTFONT_UI_FIXED"; break;
680cdf0e10cSrcweir 
681cdf0e10cSrcweir     case DEFAULTFONT_SYMBOL:    s = "DEFAULTFONT_SYMBOL"; break;
682cdf0e10cSrcweir 
683cdf0e10cSrcweir     case DEFAULTFONT_CJK_TEXT:  s = "DEFAULTFONT_CJK_TEXT"; break;
684cdf0e10cSrcweir     case DEFAULTFONT_CJK_PRESENTATION:  s = "DEFAULTFONT_CJK_PRESENTATION"; break;
685cdf0e10cSrcweir     case DEFAULTFONT_CJK_SPREADSHEET:   s = "DEFAULTFONT_CJK_SPREADSHEET"; break;
686cdf0e10cSrcweir     case DEFAULTFONT_CJK_HEADING:   s = "DEFAULTFONT_CJK_HEADING"; break;
687cdf0e10cSrcweir     case DEFAULTFONT_CJK_DISPLAY:   s = "DEFAULTFONT_CJK_DISPLAY"; break;
688cdf0e10cSrcweir 
689cdf0e10cSrcweir     case DEFAULTFONT_CTL_TEXT:  s = "DEFAULTFONT_CTL_TEXT"; break;
690cdf0e10cSrcweir     case DEFAULTFONT_CTL_PRESENTATION:  s = "DEFAULTFONT_CTL_PRESENTATION"; break;
691cdf0e10cSrcweir     case DEFAULTFONT_CTL_SPREADSHEET:   s = "DEFAULTFONT_CTL_SPREADSHEET"; break;
692cdf0e10cSrcweir     case DEFAULTFONT_CTL_HEADING:   s = "DEFAULTFONT_CTL_HEADING"; break;
693cdf0e10cSrcweir     case DEFAULTFONT_CTL_DISPLAY:   s = "DEFAULTFONT_CTL_DISPLAY"; break;
694cdf0e10cSrcweir     }
695cdf0e10cSrcweir     fprintf( stderr, "   OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
696cdf0e10cSrcweir          s, eLang, nFlags,
697cdf0e10cSrcweir          OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr()
698cdf0e10cSrcweir          );
699cdf0e10cSrcweir #endif
700cdf0e10cSrcweir 
701cdf0e10cSrcweir     return aFont;
702cdf0e10cSrcweir }
703cdf0e10cSrcweir 
704cdf0e10cSrcweir // =======================================================================
705cdf0e10cSrcweir 
706cdf0e10cSrcweir static unsigned ImplIsCJKFont( const String& rFontName )
707cdf0e10cSrcweir {
708cdf0e10cSrcweir     // Test, if Fontname includes CJK characters --> In this case we
709cdf0e10cSrcweir     // mention that it is a CJK font
710cdf0e10cSrcweir     const sal_Unicode* pStr = rFontName.GetBuffer();
711cdf0e10cSrcweir     while ( *pStr )
712cdf0e10cSrcweir     {
713cdf0e10cSrcweir         // japanese
714cdf0e10cSrcweir         if ( ((*pStr >= 0x3040) && (*pStr <= 0x30FF)) ||
715cdf0e10cSrcweir              ((*pStr >= 0x3190) && (*pStr <= 0x319F)) )
716cdf0e10cSrcweir             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_JP;
717cdf0e10cSrcweir 
718cdf0e10cSrcweir         // korean
719cdf0e10cSrcweir         if ( ((*pStr >= 0xAC00) && (*pStr <= 0xD7AF)) ||
720cdf0e10cSrcweir              ((*pStr >= 0x3130) && (*pStr <= 0x318F)) ||
721cdf0e10cSrcweir              ((*pStr >= 0x1100) && (*pStr <= 0x11FF)) )
722cdf0e10cSrcweir             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_KR;
723cdf0e10cSrcweir 
724cdf0e10cSrcweir         // chinese
725cdf0e10cSrcweir         if ( ((*pStr >= 0x3400) && (*pStr <= 0x9FFF)) )
726cdf0e10cSrcweir             return IMPL_FONT_ATTR_CJK|IMPL_FONT_ATTR_CJK_TC|IMPL_FONT_ATTR_CJK_SC;
727cdf0e10cSrcweir 
728cdf0e10cSrcweir         // cjk
729cdf0e10cSrcweir         if ( ((*pStr >= 0x3000) && (*pStr <= 0xD7AF)) ||
730cdf0e10cSrcweir              ((*pStr >= 0xFF00) && (*pStr <= 0xFFEE)) )
731cdf0e10cSrcweir             return IMPL_FONT_ATTR_CJK;
732cdf0e10cSrcweir 
733cdf0e10cSrcweir         pStr++;
734cdf0e10cSrcweir     }
735cdf0e10cSrcweir 
736cdf0e10cSrcweir     return 0;
737cdf0e10cSrcweir }
738cdf0e10cSrcweir 
739cdf0e10cSrcweir // -----------------------------------------------------------------------
740cdf0e10cSrcweir 
741cdf0e10cSrcweir static void ImplCalcType( sal_uLong& rType, FontWeight& rWeight, FontWidth& rWidth,
742cdf0e10cSrcweir                           FontFamily eFamily, const FontNameAttr* pFontAttr )
743cdf0e10cSrcweir {
744cdf0e10cSrcweir     if ( eFamily != FAMILY_DONTKNOW )
745cdf0e10cSrcweir     {
746cdf0e10cSrcweir         if ( eFamily == FAMILY_SWISS )
747cdf0e10cSrcweir             rType |= IMPL_FONT_ATTR_SANSSERIF;
748cdf0e10cSrcweir         else if ( eFamily == FAMILY_ROMAN )
749cdf0e10cSrcweir             rType |= IMPL_FONT_ATTR_SERIF;
750cdf0e10cSrcweir         else if ( eFamily == FAMILY_SCRIPT )
751cdf0e10cSrcweir             rType |= IMPL_FONT_ATTR_SCRIPT;
752cdf0e10cSrcweir         else if ( eFamily == FAMILY_MODERN )
753cdf0e10cSrcweir             rType |= IMPL_FONT_ATTR_FIXED;
754cdf0e10cSrcweir         else if ( eFamily == FAMILY_DECORATIVE )
755cdf0e10cSrcweir             rType |= IMPL_FONT_ATTR_DECORATIVE;
756cdf0e10cSrcweir     }
757cdf0e10cSrcweir 
758cdf0e10cSrcweir     if ( pFontAttr )
759cdf0e10cSrcweir     {
760cdf0e10cSrcweir         rType |= pFontAttr->Type;
761cdf0e10cSrcweir 
762cdf0e10cSrcweir         if ( ((rWeight == WEIGHT_DONTKNOW) || (rWeight == WEIGHT_NORMAL)) &&
763cdf0e10cSrcweir              (pFontAttr->Weight != WEIGHT_DONTKNOW) )
764cdf0e10cSrcweir             rWeight = pFontAttr->Weight;
765cdf0e10cSrcweir         if ( ((rWidth == WIDTH_DONTKNOW) || (rWidth == WIDTH_NORMAL)) &&
766cdf0e10cSrcweir              (pFontAttr->Width != WIDTH_DONTKNOW) )
767cdf0e10cSrcweir             rWidth = pFontAttr->Width;
768cdf0e10cSrcweir     }
769cdf0e10cSrcweir }
770cdf0e10cSrcweir 
771cdf0e10cSrcweir // =======================================================================
772cdf0e10cSrcweir 
773cdf0e10cSrcweir ImplFontData::ImplFontData( const ImplDevFontAttributes& rDFA, int nMagic )
774cdf0e10cSrcweir :   ImplDevFontAttributes( rDFA ),
775cdf0e10cSrcweir     mnWidth(0),
776cdf0e10cSrcweir     mnHeight(0),
777cdf0e10cSrcweir     mnMagic( nMagic ),
778cdf0e10cSrcweir     mpNext( NULL )
779cdf0e10cSrcweir {
780cdf0e10cSrcweir     // StarSymbol is a unicode font, but it still deserves the symbol flag
781cdf0e10cSrcweir     if( !mbSymbolFlag )
782cdf0e10cSrcweir         if( 0 == GetFamilyName().CompareIgnoreCaseToAscii( "starsymbol", 10)
783cdf0e10cSrcweir         ||  0 == GetFamilyName().CompareIgnoreCaseToAscii( "opensymbol", 10) )
784cdf0e10cSrcweir             mbSymbolFlag = true;
785cdf0e10cSrcweir }
786cdf0e10cSrcweir 
787cdf0e10cSrcweir // -----------------------------------------------------------------------
788cdf0e10cSrcweir 
789cdf0e10cSrcweir StringCompare ImplFontData::CompareIgnoreSize( const ImplFontData& rOther ) const
790cdf0e10cSrcweir {
791cdf0e10cSrcweir     // compare their width, weight, italic and style name
792cdf0e10cSrcweir     if( meWidthType < rOther.meWidthType )
793cdf0e10cSrcweir         return COMPARE_LESS;
794cdf0e10cSrcweir     else if( meWidthType > rOther.meWidthType )
795cdf0e10cSrcweir         return COMPARE_GREATER;
796cdf0e10cSrcweir 
797cdf0e10cSrcweir     if( meWeight < rOther.meWeight )
798cdf0e10cSrcweir         return COMPARE_LESS;
799cdf0e10cSrcweir     else if( meWeight > rOther.meWeight )
800cdf0e10cSrcweir         return COMPARE_GREATER;
801cdf0e10cSrcweir 
802cdf0e10cSrcweir     if( meItalic < rOther.meItalic )
803cdf0e10cSrcweir         return COMPARE_LESS;
804cdf0e10cSrcweir     else if( meItalic > rOther.meItalic )
805cdf0e10cSrcweir         return COMPARE_GREATER;
806cdf0e10cSrcweir 
807cdf0e10cSrcweir     StringCompare eCompare = maName.CompareTo( rOther.maName );
808cdf0e10cSrcweir     return eCompare;
809cdf0e10cSrcweir }
810cdf0e10cSrcweir 
811cdf0e10cSrcweir // -----------------------------------------------------------------------
812cdf0e10cSrcweir 
813cdf0e10cSrcweir StringCompare ImplFontData::CompareWithSize( const ImplFontData& rOther ) const
814cdf0e10cSrcweir {
815cdf0e10cSrcweir     StringCompare eCompare = CompareIgnoreSize( rOther );
816cdf0e10cSrcweir     if( eCompare != COMPARE_EQUAL )
817cdf0e10cSrcweir         return eCompare;
818cdf0e10cSrcweir 
819cdf0e10cSrcweir     if( mnHeight < rOther.mnHeight )
820cdf0e10cSrcweir         return COMPARE_LESS;
821cdf0e10cSrcweir     else if( mnHeight > rOther.mnHeight )
822cdf0e10cSrcweir         return COMPARE_GREATER;
823cdf0e10cSrcweir 
824cdf0e10cSrcweir     if( mnWidth < rOther.mnWidth )
825cdf0e10cSrcweir         return COMPARE_LESS;
826cdf0e10cSrcweir     else if( mnWidth > rOther.mnWidth )
827cdf0e10cSrcweir         return COMPARE_GREATER;
828cdf0e10cSrcweir 
829cdf0e10cSrcweir     return COMPARE_EQUAL;
830cdf0e10cSrcweir }
831cdf0e10cSrcweir 
832cdf0e10cSrcweir // -----------------------------------------------------------------------
833cdf0e10cSrcweir 
834cdf0e10cSrcweir struct FontMatchStatus
835cdf0e10cSrcweir {
836cdf0e10cSrcweir public:
837cdf0e10cSrcweir     int                 mnFaceMatch;
838cdf0e10cSrcweir     int                 mnHeightMatch;
839cdf0e10cSrcweir     int                 mnWidthMatch;
840cdf0e10cSrcweir     const xub_Unicode*  mpTargetStyleName;
841cdf0e10cSrcweir };
842cdf0e10cSrcweir 
843cdf0e10cSrcweir bool ImplFontData::IsBetterMatch( const ImplFontSelectData& rFSD, FontMatchStatus& rStatus ) const
844cdf0e10cSrcweir {
845cdf0e10cSrcweir     int nMatch = 0;
846cdf0e10cSrcweir 
847cdf0e10cSrcweir     const String& rFontName = rFSD.maTargetName;
848cdf0e10cSrcweir     if( (rFontName == maName) || rFontName.EqualsIgnoreCaseAscii( maName ) )
849cdf0e10cSrcweir         nMatch += 240000;
850cdf0e10cSrcweir 
851cdf0e10cSrcweir     if( rStatus.mpTargetStyleName
852cdf0e10cSrcweir     &&  maStyleName.EqualsIgnoreCaseAscii( rStatus.mpTargetStyleName ) )
853cdf0e10cSrcweir         nMatch += 120000;
854cdf0e10cSrcweir 
855cdf0e10cSrcweir     if( (rFSD.mePitch != PITCH_DONTKNOW) && (rFSD.mePitch == mePitch) )
856cdf0e10cSrcweir         nMatch += 20000;
857cdf0e10cSrcweir 
858cdf0e10cSrcweir     // prefer NORMAL font width
859cdf0e10cSrcweir     // TODO: change when the upper layers can tell their width preference
860cdf0e10cSrcweir     if( meWidthType == WIDTH_NORMAL )
861cdf0e10cSrcweir         nMatch += 400;
862cdf0e10cSrcweir     else if( (meWidthType == WIDTH_SEMI_EXPANDED) || (meWidthType == WIDTH_SEMI_CONDENSED) )
863cdf0e10cSrcweir         nMatch += 300;
864cdf0e10cSrcweir 
865cdf0e10cSrcweir     if( rFSD.meWeight != WEIGHT_DONTKNOW )
866cdf0e10cSrcweir     {
867cdf0e10cSrcweir         // if not bold prefer light fonts to bold fonts
868cdf0e10cSrcweir         int nReqWeight = (int)rFSD.meWeight;
869cdf0e10cSrcweir         if ( rFSD.meWeight > WEIGHT_MEDIUM )
870cdf0e10cSrcweir             nReqWeight += 100;
871cdf0e10cSrcweir 
872cdf0e10cSrcweir         int nGivenWeight = (int)meWeight;
873cdf0e10cSrcweir         if( meWeight > WEIGHT_MEDIUM )
874cdf0e10cSrcweir             nGivenWeight += 100;
875cdf0e10cSrcweir 
876cdf0e10cSrcweir         int nWeightDiff = nReqWeight - nGivenWeight;
877cdf0e10cSrcweir 
878cdf0e10cSrcweir         if ( nWeightDiff == 0 )
879cdf0e10cSrcweir             nMatch += 1000;
880cdf0e10cSrcweir         else if ( nWeightDiff == +1 || nWeightDiff == -1 )
881cdf0e10cSrcweir             nMatch += 700;
882cdf0e10cSrcweir         else if ( nWeightDiff < +50 && nWeightDiff > -50)
883cdf0e10cSrcweir             nMatch += 200;
884cdf0e10cSrcweir     }
885cdf0e10cSrcweir     else // requested weight == WEIGHT_DONTKNOW
886cdf0e10cSrcweir     {
887cdf0e10cSrcweir         // prefer NORMAL font weight
888cdf0e10cSrcweir         // TODO: change when the upper layers can tell their weight preference
889cdf0e10cSrcweir         if( meWeight == WEIGHT_NORMAL )
890cdf0e10cSrcweir             nMatch += 450;
891cdf0e10cSrcweir         else if( meWeight == WEIGHT_MEDIUM )
892cdf0e10cSrcweir             nMatch += 350;
893cdf0e10cSrcweir         else if( (meWeight == WEIGHT_SEMILIGHT) || (meWeight == WEIGHT_SEMIBOLD) )
894cdf0e10cSrcweir             nMatch += 200;
895cdf0e10cSrcweir         else if( meWeight == WEIGHT_LIGHT )
896cdf0e10cSrcweir             nMatch += 150;
897cdf0e10cSrcweir     }
898cdf0e10cSrcweir 
899cdf0e10cSrcweir     if ( rFSD.meItalic == ITALIC_NONE )
900cdf0e10cSrcweir     {
901cdf0e10cSrcweir         if( meItalic == ITALIC_NONE )
902cdf0e10cSrcweir             nMatch += 900;
903cdf0e10cSrcweir     }
904cdf0e10cSrcweir     else
905cdf0e10cSrcweir     {
906cdf0e10cSrcweir         if( rFSD.meItalic == meItalic )
907cdf0e10cSrcweir             nMatch += 900;
908cdf0e10cSrcweir         else if( meItalic != ITALIC_NONE )
909cdf0e10cSrcweir             nMatch += 600;
910cdf0e10cSrcweir     }
911cdf0e10cSrcweir 
912cdf0e10cSrcweir     if( mbDevice )
913cdf0e10cSrcweir         nMatch += 1;
914cdf0e10cSrcweir 
915cdf0e10cSrcweir     int nHeightMatch = 0;
916cdf0e10cSrcweir     int nWidthMatch = 0;
917cdf0e10cSrcweir 
918cdf0e10cSrcweir     if( IsScalable() )
919cdf0e10cSrcweir     {
920cdf0e10cSrcweir         if( rFSD.mnOrientation != 0 )
921cdf0e10cSrcweir             nMatch += 80;
922cdf0e10cSrcweir         else if( rFSD.mnWidth != 0 )
923cdf0e10cSrcweir             nMatch += 25;
924cdf0e10cSrcweir         else
925cdf0e10cSrcweir             nMatch += 5;
926cdf0e10cSrcweir     }
927cdf0e10cSrcweir     else
928cdf0e10cSrcweir     {
929cdf0e10cSrcweir         if( rFSD.mnHeight == mnHeight )
930cdf0e10cSrcweir         {
931cdf0e10cSrcweir             nMatch += 20;
932cdf0e10cSrcweir             if( rFSD.mnWidth == mnWidth )
933cdf0e10cSrcweir                 nMatch += 10;
934cdf0e10cSrcweir         }
935cdf0e10cSrcweir         else
936cdf0e10cSrcweir         {
937cdf0e10cSrcweir             // for non-scalable fonts the size difference is very important
938cdf0e10cSrcweir             // prefer the smaller font face because of clipping/overlapping issues
939cdf0e10cSrcweir             int nHeightDiff = (rFSD.mnHeight - mnHeight) * 1000;
940cdf0e10cSrcweir             nHeightMatch = (nHeightDiff >= 0) ? -nHeightDiff : 100+nHeightDiff;
941cdf0e10cSrcweir             if( rFSD.mnHeight )
942cdf0e10cSrcweir                 nHeightMatch /= rFSD.mnHeight;
943cdf0e10cSrcweir 
944cdf0e10cSrcweir             if( (rFSD.mnWidth != 0) && (mnWidth != 0) && (rFSD.mnWidth != mnWidth) )
945cdf0e10cSrcweir             {
946cdf0e10cSrcweir                 int nWidthDiff = (rFSD.mnWidth - mnWidth) * 100;
947cdf0e10cSrcweir                 nWidthMatch = (nWidthDiff >= 0) ? -nWidthDiff : +nWidthDiff;
948cdf0e10cSrcweir             }
949cdf0e10cSrcweir         }
950cdf0e10cSrcweir     }
951cdf0e10cSrcweir 
952cdf0e10cSrcweir     if( rStatus.mnFaceMatch > nMatch )
953cdf0e10cSrcweir         return false;
954cdf0e10cSrcweir     else if( rStatus.mnFaceMatch < nMatch )
955cdf0e10cSrcweir     {
956cdf0e10cSrcweir         rStatus.mnFaceMatch      = nMatch;
957cdf0e10cSrcweir         rStatus.mnHeightMatch    = nHeightMatch;
958cdf0e10cSrcweir         rStatus.mnWidthMatch     = nWidthMatch;
959cdf0e10cSrcweir         return true;
960cdf0e10cSrcweir     }
961cdf0e10cSrcweir 
962cdf0e10cSrcweir     // when two fonts are still competing prefer the
963cdf0e10cSrcweir     // one with the best matching height
964cdf0e10cSrcweir     if( rStatus.mnHeightMatch > nHeightMatch )
965cdf0e10cSrcweir         return false;
966cdf0e10cSrcweir     else if( rStatus.mnHeightMatch < nHeightMatch )
967cdf0e10cSrcweir     {
968cdf0e10cSrcweir         rStatus.mnHeightMatch    = nHeightMatch;
969cdf0e10cSrcweir         rStatus.mnWidthMatch     = nWidthMatch;
970cdf0e10cSrcweir         return true;
971cdf0e10cSrcweir     }
972cdf0e10cSrcweir 
973cdf0e10cSrcweir     if( rStatus.mnWidthMatch > nWidthMatch )
974cdf0e10cSrcweir         return false;
975cdf0e10cSrcweir 
976cdf0e10cSrcweir     rStatus.mnWidthMatch = nWidthMatch;
977cdf0e10cSrcweir     return true;
978cdf0e10cSrcweir }
979cdf0e10cSrcweir 
980cdf0e10cSrcweir // =======================================================================
981cdf0e10cSrcweir 
982cdf0e10cSrcweir ImplFontEntry::ImplFontEntry( const ImplFontSelectData& rFontSelData )
983cdf0e10cSrcweir :   maFontSelData( rFontSelData ),
984cdf0e10cSrcweir     maMetric( rFontSelData ),
985cdf0e10cSrcweir     mpConversion( NULL ),
986cdf0e10cSrcweir     mnRefCount( 1 ),
987cdf0e10cSrcweir     mnSetFontFlags( 0 ),
988cdf0e10cSrcweir     mnOwnOrientation( 0 ),
989cdf0e10cSrcweir     mnOrientation( 0 ),
990cdf0e10cSrcweir     mbInit( false ),
991cdf0e10cSrcweir     mpUnicodeFallbackList( NULL )
992cdf0e10cSrcweir {
993cdf0e10cSrcweir     maFontSelData.mpFontEntry = this;
994cdf0e10cSrcweir }
995cdf0e10cSrcweir 
996cdf0e10cSrcweir // -----------------------------------------------------------------------
997cdf0e10cSrcweir 
998cdf0e10cSrcweir ImplFontEntry::~ImplFontEntry()
999cdf0e10cSrcweir {
1000cdf0e10cSrcweir     delete mpUnicodeFallbackList;
1001cdf0e10cSrcweir }
1002cdf0e10cSrcweir 
1003cdf0e10cSrcweir // -----------------------------------------------------------------------
1004cdf0e10cSrcweir 
1005cdf0e10cSrcweir size_t ImplFontEntry::GFBCacheKey_Hash::operator()( const GFBCacheKey& rData ) const
1006cdf0e10cSrcweir {
1007cdf0e10cSrcweir     std::hash<sal_UCS4> a;
1008cdf0e10cSrcweir     std::hash<int > b;
1009cdf0e10cSrcweir     return a(rData.first) ^ b(rData.second);
1010cdf0e10cSrcweir }
1011cdf0e10cSrcweir 
1012cdf0e10cSrcweir inline void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
1013cdf0e10cSrcweir {
1014cdf0e10cSrcweir     if( !mpUnicodeFallbackList )
1015cdf0e10cSrcweir         mpUnicodeFallbackList = new UnicodeFallbackList;
1016cdf0e10cSrcweir     (*mpUnicodeFallbackList)[ GFBCacheKey(cChar,eWeight) ] = rFontName;
1017cdf0e10cSrcweir }
1018cdf0e10cSrcweir 
1019cdf0e10cSrcweir // -----------------------------------------------------------------------
1020cdf0e10cSrcweir 
1021cdf0e10cSrcweir inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, String* pFontName ) const
1022cdf0e10cSrcweir {
1023cdf0e10cSrcweir     if( !mpUnicodeFallbackList )
1024cdf0e10cSrcweir         return false;
1025cdf0e10cSrcweir 
1026cdf0e10cSrcweir     UnicodeFallbackList::const_iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
1027cdf0e10cSrcweir     if( it == mpUnicodeFallbackList->end() )
1028cdf0e10cSrcweir         return false;
1029cdf0e10cSrcweir 
1030cdf0e10cSrcweir     *pFontName = (*it).second;
1031cdf0e10cSrcweir     return true;
1032cdf0e10cSrcweir }
1033cdf0e10cSrcweir 
1034cdf0e10cSrcweir // -----------------------------------------------------------------------
1035cdf0e10cSrcweir 
1036cdf0e10cSrcweir inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar, FontWeight eWeight, const String& rFontName )
1037cdf0e10cSrcweir {
1038cdf0e10cSrcweir //  DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
1039cdf0e10cSrcweir     UnicodeFallbackList::iterator it = mpUnicodeFallbackList->find( GFBCacheKey(cChar,eWeight) );
1040cdf0e10cSrcweir //  DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
1041cdf0e10cSrcweir     if( it == mpUnicodeFallbackList->end() )
1042cdf0e10cSrcweir         return;
1043cdf0e10cSrcweir     if( (*it).second == rFontName )
1044cdf0e10cSrcweir         mpUnicodeFallbackList->erase( it );
1045cdf0e10cSrcweir }
1046cdf0e10cSrcweir 
1047cdf0e10cSrcweir // =======================================================================
1048cdf0e10cSrcweir 
1049cdf0e10cSrcweir ImplDevFontListData::ImplDevFontListData( const String& rSearchName )
1050cdf0e10cSrcweir :   mpFirst( NULL ),
1051cdf0e10cSrcweir     maSearchName( rSearchName ),
1052cdf0e10cSrcweir     mnTypeFaces( 0 ),
1053cdf0e10cSrcweir     mnMatchType( 0 ),
1054cdf0e10cSrcweir     meMatchWeight( WEIGHT_DONTKNOW ),
1055cdf0e10cSrcweir     meMatchWidth( WIDTH_DONTKNOW ),
1056cdf0e10cSrcweir     meFamily( FAMILY_DONTKNOW ),
1057cdf0e10cSrcweir     mePitch( PITCH_DONTKNOW ),
1058cdf0e10cSrcweir     mnMinQuality( -1 )
1059cdf0e10cSrcweir {}
1060cdf0e10cSrcweir 
1061cdf0e10cSrcweir // -----------------------------------------------------------------------
1062cdf0e10cSrcweir 
1063cdf0e10cSrcweir ImplDevFontListData::~ImplDevFontListData()
1064cdf0e10cSrcweir {
1065cdf0e10cSrcweir     // release all physical font faces
1066cdf0e10cSrcweir     while( mpFirst )
1067cdf0e10cSrcweir     {
1068cdf0e10cSrcweir         ImplFontData* pFace = mpFirst;
1069cdf0e10cSrcweir         mpFirst = pFace->GetNextFace();
1070cdf0e10cSrcweir         delete pFace;
1071cdf0e10cSrcweir     }
1072cdf0e10cSrcweir }
1073cdf0e10cSrcweir 
1074cdf0e10cSrcweir // -----------------------------------------------------------------------
1075cdf0e10cSrcweir 
1076cdf0e10cSrcweir bool ImplDevFontListData::AddFontFace( ImplFontData* pNewData )
1077cdf0e10cSrcweir {
1078cdf0e10cSrcweir     pNewData->mpNext = NULL;
1079cdf0e10cSrcweir 
1080cdf0e10cSrcweir     if( !mpFirst )
1081cdf0e10cSrcweir     {
1082cdf0e10cSrcweir         maName         = pNewData->maName;
1083cdf0e10cSrcweir         maMapNames     = pNewData->maMapNames;
1084cdf0e10cSrcweir         meFamily       = pNewData->meFamily;
1085cdf0e10cSrcweir         mePitch        = pNewData->mePitch;
1086cdf0e10cSrcweir         mnMinQuality   = pNewData->mnQuality;
1087cdf0e10cSrcweir     }
1088cdf0e10cSrcweir     else
1089cdf0e10cSrcweir     {
1090cdf0e10cSrcweir         if( meFamily == FAMILY_DONTKNOW )
1091cdf0e10cSrcweir             meFamily = pNewData->meFamily;
1092cdf0e10cSrcweir         if( mePitch == PITCH_DONTKNOW )
1093cdf0e10cSrcweir             mePitch = pNewData->mePitch;
1094cdf0e10cSrcweir         if( mnMinQuality > pNewData->mnQuality )
1095cdf0e10cSrcweir             mnMinQuality = pNewData->mnQuality;
1096cdf0e10cSrcweir     }
1097cdf0e10cSrcweir 
1098cdf0e10cSrcweir     // set attributes for attribute based font matching
1099cdf0e10cSrcweir     if( pNewData->IsScalable() )
1100cdf0e10cSrcweir         mnTypeFaces |= IMPL_DEVFONT_SCALABLE;
1101cdf0e10cSrcweir 
1102cdf0e10cSrcweir     if( pNewData->IsSymbolFont() )
1103cdf0e10cSrcweir         mnTypeFaces |= IMPL_DEVFONT_SYMBOL;
1104cdf0e10cSrcweir     else
1105cdf0e10cSrcweir         mnTypeFaces |= IMPL_DEVFONT_NONESYMBOL;
1106cdf0e10cSrcweir 
1107cdf0e10cSrcweir     if( pNewData->meWeight != WEIGHT_DONTKNOW )
1108cdf0e10cSrcweir     {
1109cdf0e10cSrcweir         if( pNewData->meWeight >= WEIGHT_SEMIBOLD )
1110cdf0e10cSrcweir             mnTypeFaces |= IMPL_DEVFONT_BOLD;
1111cdf0e10cSrcweir         else if( pNewData->meWeight <= WEIGHT_SEMILIGHT )
1112cdf0e10cSrcweir             mnTypeFaces |= IMPL_DEVFONT_LIGHT;
1113cdf0e10cSrcweir         else
1114cdf0e10cSrcweir             mnTypeFaces |= IMPL_DEVFONT_NORMAL;
1115cdf0e10cSrcweir     }
1116cdf0e10cSrcweir 
1117cdf0e10cSrcweir     if( pNewData->meItalic == ITALIC_NONE )
1118cdf0e10cSrcweir         mnTypeFaces |= IMPL_DEVFONT_NONEITALIC;
1119cdf0e10cSrcweir     else if( (pNewData->meItalic == ITALIC_NORMAL)
1120cdf0e10cSrcweir          ||  (pNewData->meItalic == ITALIC_OBLIQUE) )
1121cdf0e10cSrcweir         mnTypeFaces |= IMPL_DEVFONT_ITALIC;
1122cdf0e10cSrcweir 
1123cdf0e10cSrcweir     if( (meMatchWeight == WEIGHT_DONTKNOW)
1124cdf0e10cSrcweir     ||  (meMatchWidth  == WIDTH_DONTKNOW)
1125cdf0e10cSrcweir     ||  (mnMatchType   == 0) )
1126cdf0e10cSrcweir     {
1127cdf0e10cSrcweir         // TODO: is it cheaper to calc matching attributes now or on demand?
1128cdf0e10cSrcweir         // calc matching attributes if other entries are already initialized
1129cdf0e10cSrcweir 
1130cdf0e10cSrcweir         // MT: Perform05: Do lazy, quite expensive, not needed in start-up!
1131cdf0e10cSrcweir         // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
1132cdf0e10cSrcweir         // InitMatchData( rFontSubst, maSearchName );
1133cdf0e10cSrcweir         // mbMatchData=true; // Somewhere else???
1134cdf0e10cSrcweir     }
1135cdf0e10cSrcweir 
1136cdf0e10cSrcweir     // reassign name (sharing saves memory)
1137cdf0e10cSrcweir     if( pNewData->maName == maName )
1138cdf0e10cSrcweir         pNewData->maName = maName;
1139cdf0e10cSrcweir 
1140cdf0e10cSrcweir     // insert new physical font face into linked list
1141cdf0e10cSrcweir     // TODO: get rid of linear search?
1142cdf0e10cSrcweir     ImplFontData* pData;
1143cdf0e10cSrcweir     ImplFontData** ppHere = &mpFirst;
1144cdf0e10cSrcweir     for(; (pData=*ppHere) != NULL; ppHere=&pData->mpNext )
1145cdf0e10cSrcweir     {
1146cdf0e10cSrcweir         StringCompare eComp = pNewData->CompareWithSize( *pData );
1147cdf0e10cSrcweir         if( eComp == COMPARE_GREATER )
1148cdf0e10cSrcweir             continue;
1149cdf0e10cSrcweir         if( eComp == COMPARE_LESS )
1150cdf0e10cSrcweir             break;
1151cdf0e10cSrcweir 
1152cdf0e10cSrcweir         // ignore duplicate if its quality is worse
1153cdf0e10cSrcweir         if( pNewData->mnQuality < pData->mnQuality )
1154cdf0e10cSrcweir             return false;
1155cdf0e10cSrcweir 
1156cdf0e10cSrcweir         // keep the device font if its quality is good enough
1157cdf0e10cSrcweir         if( (pNewData->mnQuality == pData->mnQuality)
1158cdf0e10cSrcweir         &&  (pData->mbDevice || !pNewData->mbDevice) )
1159cdf0e10cSrcweir             return false;
1160cdf0e10cSrcweir 
1161cdf0e10cSrcweir         // replace existing font face with a better one
1162cdf0e10cSrcweir         pNewData->mpNext = pData->mpNext;
1163cdf0e10cSrcweir         *ppHere = pNewData;
1164cdf0e10cSrcweir         delete pData;
1165cdf0e10cSrcweir         return true;
1166cdf0e10cSrcweir     }
1167cdf0e10cSrcweir 
1168cdf0e10cSrcweir     // insert into or append to list of physical font faces
1169cdf0e10cSrcweir     pNewData->mpNext = pData;
1170cdf0e10cSrcweir     *ppHere = pNewData;
1171cdf0e10cSrcweir     return true;
1172cdf0e10cSrcweir }
1173cdf0e10cSrcweir 
1174cdf0e10cSrcweir // -----------------------------------------------------------------------
1175cdf0e10cSrcweir 
1176cdf0e10cSrcweir // get font attributes using the normalized font family name
1177cdf0e10cSrcweir void ImplDevFontListData::InitMatchData( const utl::FontSubstConfiguration& rFontSubst,
1178cdf0e10cSrcweir     const String& rSearchName )
1179cdf0e10cSrcweir {
1180cdf0e10cSrcweir     String aShortName;
1181cdf0e10cSrcweir     // get font attributes from the decorated font name
1182cdf0e10cSrcweir     rFontSubst.getMapName( rSearchName, aShortName, maMatchFamilyName,
1183cdf0e10cSrcweir                             meMatchWeight, meMatchWidth, mnMatchType );
1184cdf0e10cSrcweir     const FontNameAttr* pFontAttr = rFontSubst.getSubstInfo( rSearchName );
1185cdf0e10cSrcweir     // eventually use the stripped name
1186cdf0e10cSrcweir     if( !pFontAttr )
1187cdf0e10cSrcweir         if( aShortName != rSearchName )
1188cdf0e10cSrcweir             pFontAttr = rFontSubst.getSubstInfo( aShortName );
1189cdf0e10cSrcweir     ImplCalcType( mnMatchType, meMatchWeight, meMatchWidth, meFamily, pFontAttr );
1190cdf0e10cSrcweir     mnMatchType |= ImplIsCJKFont( maName );
1191cdf0e10cSrcweir }
1192cdf0e10cSrcweir 
1193cdf0e10cSrcweir // -----------------------------------------------------------------------
1194cdf0e10cSrcweir 
1195cdf0e10cSrcweir ImplFontData* ImplDevFontListData::FindBestFontFace( const ImplFontSelectData& rFSD ) const
1196cdf0e10cSrcweir {
1197cdf0e10cSrcweir     if( !mpFirst )
1198cdf0e10cSrcweir         return NULL;
1199cdf0e10cSrcweir     if( !mpFirst->GetNextFace() )
1200cdf0e10cSrcweir         return mpFirst;
1201cdf0e10cSrcweir 
1202cdf0e10cSrcweir     // FontName+StyleName should map to FamilyName+StyleName
1203cdf0e10cSrcweir     const String& rSearchName = rFSD.maTargetName;
1204cdf0e10cSrcweir     const xub_Unicode* pTargetStyleName = NULL;
1205cdf0e10cSrcweir     if( (rSearchName.Len() > maSearchName.Len())
1206cdf0e10cSrcweir     &&   rSearchName.Equals( maSearchName, 0, maSearchName.Len() ) )
1207cdf0e10cSrcweir         pTargetStyleName = rSearchName.GetBuffer() + maSearchName.Len() + 1;
1208cdf0e10cSrcweir 
1209cdf0e10cSrcweir     // linear search, TODO: improve?
1210cdf0e10cSrcweir     ImplFontData* pFontFace = mpFirst;
1211cdf0e10cSrcweir     ImplFontData* pBestFontFace = pFontFace;
1212cdf0e10cSrcweir     FontMatchStatus aFontMatchStatus = {0,0,0, pTargetStyleName};
1213cdf0e10cSrcweir     for(; pFontFace; pFontFace = pFontFace->GetNextFace() )
1214cdf0e10cSrcweir         if( pFontFace->IsBetterMatch( rFSD, aFontMatchStatus ) )
1215cdf0e10cSrcweir             pBestFontFace = pFontFace;
1216cdf0e10cSrcweir 
1217cdf0e10cSrcweir     return pBestFontFace;
1218cdf0e10cSrcweir }
1219cdf0e10cSrcweir 
1220cdf0e10cSrcweir // -----------------------------------------------------------------------
1221cdf0e10cSrcweir 
1222cdf0e10cSrcweir // update device font list with unique font faces, with uniqueness
1223cdf0e10cSrcweir // meaning different font attributes, but not different fonts sizes
1224cdf0e10cSrcweir void ImplDevFontListData::UpdateDevFontList( ImplGetDevFontList& rDevFontList ) const
1225cdf0e10cSrcweir {
1226cdf0e10cSrcweir     ImplFontData* pPrevFace = NULL;
1227cdf0e10cSrcweir     for( ImplFontData* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1228cdf0e10cSrcweir     {
1229cdf0e10cSrcweir         if( !pPrevFace || pFace->CompareIgnoreSize( *pPrevFace ) )
1230cdf0e10cSrcweir             rDevFontList.Add( pFace );
1231cdf0e10cSrcweir         pPrevFace = pFace;
1232cdf0e10cSrcweir     }
1233cdf0e10cSrcweir }
1234cdf0e10cSrcweir 
1235cdf0e10cSrcweir // -----------------------------------------------------------------------
1236cdf0e10cSrcweir 
1237cdf0e10cSrcweir void ImplDevFontListData::GetFontHeights( std::set<int>& rHeights ) const
1238cdf0e10cSrcweir {
1239cdf0e10cSrcweir     // add all available font heights
1240cdf0e10cSrcweir     for( const ImplFontData* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1241cdf0e10cSrcweir         rHeights.insert( pFace->GetHeight() );
1242cdf0e10cSrcweir }
1243cdf0e10cSrcweir 
1244cdf0e10cSrcweir // -----------------------------------------------------------------------
1245cdf0e10cSrcweir 
1246cdf0e10cSrcweir void ImplDevFontListData::UpdateCloneFontList( ImplDevFontList& rDevFontList,
1247cdf0e10cSrcweir     bool bScalable, bool bEmbeddable ) const
1248cdf0e10cSrcweir {
1249cdf0e10cSrcweir     for( ImplFontData* pFace = mpFirst; pFace; pFace = pFace->GetNextFace() )
1250cdf0e10cSrcweir     {
1251cdf0e10cSrcweir         if( bScalable && !pFace->IsScalable() )
1252cdf0e10cSrcweir             continue;
1253cdf0e10cSrcweir         if( bEmbeddable && !pFace->IsEmbeddable() && !pFace->IsSubsettable() )
1254cdf0e10cSrcweir             continue;
1255cdf0e10cSrcweir 
1256cdf0e10cSrcweir         ImplFontData* pClonedFace = pFace->Clone();
1257cdf0e10cSrcweir         rDevFontList.Add( pClonedFace );
1258cdf0e10cSrcweir     }
1259cdf0e10cSrcweir }
1260cdf0e10cSrcweir 
1261cdf0e10cSrcweir // =======================================================================
1262cdf0e10cSrcweir 
1263cdf0e10cSrcweir ImplDevFontList::ImplDevFontList()
1264cdf0e10cSrcweir :   mbMatchData( false )
1265cdf0e10cSrcweir ,   mbMapNames( false )
1266cdf0e10cSrcweir ,   mpPreMatchHook( NULL )
1267cdf0e10cSrcweir ,   mpFallbackHook( NULL )
1268cdf0e10cSrcweir ,   mpFallbackList( NULL )
1269cdf0e10cSrcweir ,   mnFallbackCount( -1 )
1270cdf0e10cSrcweir {}
1271cdf0e10cSrcweir 
1272cdf0e10cSrcweir // -----------------------------------------------------------------------
1273cdf0e10cSrcweir 
1274cdf0e10cSrcweir ImplDevFontList::~ImplDevFontList()
1275cdf0e10cSrcweir {
1276cdf0e10cSrcweir     Clear();
1277cdf0e10cSrcweir }
1278cdf0e10cSrcweir 
1279cdf0e10cSrcweir // -----------------------------------------------------------------------
1280cdf0e10cSrcweir 
1281cdf0e10cSrcweir void ImplDevFontList::SetPreMatchHook( ImplPreMatchFontSubstitution* pHook )
1282cdf0e10cSrcweir {
1283cdf0e10cSrcweir     mpPreMatchHook = pHook;
1284cdf0e10cSrcweir }
1285cdf0e10cSrcweir 
1286cdf0e10cSrcweir // -----------------------------------------------------------------------
1287cdf0e10cSrcweir 
1288cdf0e10cSrcweir void ImplDevFontList::SetFallbackHook( ImplGlyphFallbackFontSubstitution* pHook )
1289cdf0e10cSrcweir {
1290cdf0e10cSrcweir     mpFallbackHook = pHook;
1291cdf0e10cSrcweir }
1292cdf0e10cSrcweir 
1293cdf0e10cSrcweir // -----------------------------------------------------------------------
1294cdf0e10cSrcweir 
1295cdf0e10cSrcweir void ImplDevFontList::Clear()
1296cdf0e10cSrcweir {
1297cdf0e10cSrcweir     // remove fallback lists
1298cdf0e10cSrcweir     delete[] mpFallbackList;
1299cdf0e10cSrcweir     mpFallbackList = NULL;
1300cdf0e10cSrcweir     mnFallbackCount = -1;
1301cdf0e10cSrcweir 
1302cdf0e10cSrcweir     // clear all entries in the device font list
1303cdf0e10cSrcweir     DevFontList::iterator it = maDevFontList.begin();
1304cdf0e10cSrcweir     for(; it != maDevFontList.end(); ++it )
1305cdf0e10cSrcweir     {
1306cdf0e10cSrcweir         ImplDevFontListData* pEntry = (*it).second;
1307cdf0e10cSrcweir         delete pEntry;
1308cdf0e10cSrcweir     }
1309cdf0e10cSrcweir 
1310cdf0e10cSrcweir     maDevFontList.clear();
1311cdf0e10cSrcweir 
1312cdf0e10cSrcweir     // match data must be recalculated too
1313cdf0e10cSrcweir     mbMatchData = false;
1314cdf0e10cSrcweir }
1315cdf0e10cSrcweir 
1316cdf0e10cSrcweir 
1317cdf0e10cSrcweir // -----------------------------------------------------------------------
1318cdf0e10cSrcweir 
1319cdf0e10cSrcweir void ImplDevFontList::InitGenericGlyphFallback( void ) const
1320cdf0e10cSrcweir {
1321cdf0e10cSrcweir     // normalized family names of fonts suited for glyph fallback
1322cdf0e10cSrcweir     // if a font is available related fonts can be ignored
1323cdf0e10cSrcweir     // TODO: implement dynamic lists
1324cdf0e10cSrcweir     static const char* aGlyphFallbackList[] = {
1325cdf0e10cSrcweir         // empty strings separate the names of unrelated fonts
1326cdf0e10cSrcweir         "eudc", "",
1327cdf0e10cSrcweir         "arialunicodems", "cyberbit", "code2000", "",
1328cdf0e10cSrcweir         "andalesansui", "",
1329cdf0e10cSrcweir         "starsymbol", "opensymbol", "",
1330cdf0e10cSrcweir         "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
1331cdf0e10cSrcweir         "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
1332cdf0e10cSrcweir         "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
1333cdf0e10cSrcweir         "tahoma", "dejavusans", "timesnewroman", "liberationsans", "",
1334cdf0e10cSrcweir         "shree", "mangal", "",
1335cdf0e10cSrcweir         "raavi", "shruti", "tunga", "",
1336cdf0e10cSrcweir         "latha", "gautami", "kartika", "vrinda", "",
1337cdf0e10cSrcweir         "shayyalmt", "naskmt", "scheherazade", "",
1338cdf0e10cSrcweir         "david", "nachlieli", "lucidagrande", "",
1339cdf0e10cSrcweir         "norasi", "angsanaupc", "",
1340cdf0e10cSrcweir         "khmerossystem", "",
1341cdf0e10cSrcweir         "muktinarrow", "",
1342cdf0e10cSrcweir         "phetsarathot", "",
1343cdf0e10cSrcweir         "padauk", "pinlonmyanmar", "",
1344cdf0e10cSrcweir         "iskoolapota", "lklug", "",
1345cdf0e10cSrcweir         0
1346cdf0e10cSrcweir     };
1347cdf0e10cSrcweir 
1348cdf0e10cSrcweir     bool bHasEudc = false;
1349cdf0e10cSrcweir     int nMaxLevel = 0;
1350cdf0e10cSrcweir     int nBestQuality = 0;
1351cdf0e10cSrcweir     ImplDevFontListData** pFallbackList = NULL;
1352cdf0e10cSrcweir     for( const char** ppNames = &aGlyphFallbackList[0];; ++ppNames )
1353cdf0e10cSrcweir     {
1354cdf0e10cSrcweir         // advance to next sub-list when end-of-sublist marker
1355cdf0e10cSrcweir         if( !**ppNames )    // #i46456# check for empty string, i.e., deref string itself not only ptr to it
1356cdf0e10cSrcweir         {
1357cdf0e10cSrcweir             if( nBestQuality > 0 )
1358cdf0e10cSrcweir                 if( ++nMaxLevel >= MAX_FALLBACK )
1359cdf0e10cSrcweir                     break;
1360cdf0e10cSrcweir             if( !ppNames[1] )
1361cdf0e10cSrcweir                 break;
1362cdf0e10cSrcweir             nBestQuality = 0;
1363cdf0e10cSrcweir             continue;
1364cdf0e10cSrcweir         }
1365cdf0e10cSrcweir 
1366cdf0e10cSrcweir         // test if the glyph fallback candidate font is available and scalable
1367cdf0e10cSrcweir         String aTokenName( *ppNames, RTL_TEXTENCODING_UTF8 );
1368cdf0e10cSrcweir         ImplDevFontListData* pFallbackFont = FindFontFamily( aTokenName );
1369cdf0e10cSrcweir         if( !pFallbackFont )
1370cdf0e10cSrcweir             continue;
1371cdf0e10cSrcweir         if( !pFallbackFont->IsScalable() )
1372cdf0e10cSrcweir             continue;
1373cdf0e10cSrcweir 
1374cdf0e10cSrcweir         // keep the best font of the glyph fallback sub-list
1375cdf0e10cSrcweir         if( nBestQuality < pFallbackFont->GetMinQuality() )
1376cdf0e10cSrcweir         {
1377cdf0e10cSrcweir             nBestQuality = pFallbackFont->GetMinQuality();
1378cdf0e10cSrcweir             // store available glyph fallback fonts
1379cdf0e10cSrcweir             if( !pFallbackList )
1380cdf0e10cSrcweir                 pFallbackList = new ImplDevFontListData*[ MAX_FALLBACK ];
1381cdf0e10cSrcweir             pFallbackList[ nMaxLevel ] = pFallbackFont;
1382cdf0e10cSrcweir             if( !bHasEudc && !nMaxLevel )
1383cdf0e10cSrcweir                 bHasEudc = !strncmp( *ppNames, "eudc", 5 );
1384cdf0e10cSrcweir         }
1385cdf0e10cSrcweir     }
1386cdf0e10cSrcweir 
1387cdf0e10cSrcweir #ifdef SAL_FONTENUM_STABLE_ON_PLATFORM // #i113472#
1388cdf0e10cSrcweir     // sort the list of fonts for glyph fallback by quality (highest first)
1389cdf0e10cSrcweir     // #i33947# keep the EUDC font at the front of the list
1390cdf0e10cSrcweir     // an insertion sort is good enough for this short list
1391cdf0e10cSrcweir     const int nSortStart = bHasEudc ? 1 : 0;
1392cdf0e10cSrcweir     for( int i = nSortStart+1, j; i < nMaxLevel; ++i )
1393cdf0e10cSrcweir     {
1394cdf0e10cSrcweir         ImplDevFontListData* pTestFont = pFallbackList[ i ];
1395cdf0e10cSrcweir         int nTestQuality = pTestFont->GetMinQuality();
1396cdf0e10cSrcweir         for( j = i; --j >= nSortStart; )
1397cdf0e10cSrcweir             if( nTestQuality > pFallbackList[j]->GetMinQuality() )
1398cdf0e10cSrcweir                 pFallbackList[ j+1 ] = pFallbackList[ j ];
1399cdf0e10cSrcweir             else
1400cdf0e10cSrcweir                 break;
1401cdf0e10cSrcweir         pFallbackList[ j+1 ] = pTestFont;
1402cdf0e10cSrcweir     }
1403cdf0e10cSrcweir #endif
1404cdf0e10cSrcweir 
1405cdf0e10cSrcweir #if defined(HDU_DEBUG)
1406cdf0e10cSrcweir     for( int i = 0; i < nMaxLevel; ++i )
1407cdf0e10cSrcweir     {
1408cdf0e10cSrcweir         ImplDevFontListData* pFont = pFallbackList[ i ];
1409cdf0e10cSrcweir         ByteString aFontName( pFont->GetFamilyName(), RTL_TEXTENCODING_UTF8 );
1410cdf0e10cSrcweir         fprintf( stderr, "GlyphFallbackFont[%d] (quality=%05d): \"%s\"\n",
1411cdf0e10cSrcweir             i, pFont->GetMinQuality(), aFontName.GetBuffer() );
1412cdf0e10cSrcweir     }
1413cdf0e10cSrcweir #endif
1414cdf0e10cSrcweir 
1415cdf0e10cSrcweir     mnFallbackCount = nMaxLevel;
1416cdf0e10cSrcweir     mpFallbackList  = pFallbackList;
1417cdf0e10cSrcweir }
1418cdf0e10cSrcweir 
1419cdf0e10cSrcweir // -----------------------------------------------------------------------
1420cdf0e10cSrcweir 
1421cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::GetGlyphFallbackFont( ImplFontSelectData& rFontSelData,
1422cdf0e10cSrcweir     rtl::OUString& rMissingCodes, int nFallbackLevel ) const
1423cdf0e10cSrcweir {
1424cdf0e10cSrcweir     ImplDevFontListData* pFallbackData = NULL;
1425cdf0e10cSrcweir 
1426cdf0e10cSrcweir     // find a matching font candidate for platform specific glyph fallback
1427cdf0e10cSrcweir     if( mpFallbackHook )
1428cdf0e10cSrcweir     {
1429cdf0e10cSrcweir         // check cache for the first matching entry
1430cdf0e10cSrcweir         // to avoid calling the expensive fallback hook (#i83491#)
1431cdf0e10cSrcweir         sal_UCS4 cChar = 0;
1432cdf0e10cSrcweir         bool bCached = true;
1433cdf0e10cSrcweir         sal_Int32 nStrIndex = 0;
1434cdf0e10cSrcweir         while( nStrIndex < rMissingCodes.getLength() )
1435cdf0e10cSrcweir         {
1436cdf0e10cSrcweir             cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1437cdf0e10cSrcweir             bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName );
1438cdf0e10cSrcweir             // ignore entries which don't have a fallback
1439cdf0e10cSrcweir             if( !bCached || (rFontSelData.maSearchName.Len() != 0) )
1440cdf0e10cSrcweir                 break;
1441cdf0e10cSrcweir         }
1442cdf0e10cSrcweir 
1443cdf0e10cSrcweir         if( bCached )
1444cdf0e10cSrcweir         {
1445cdf0e10cSrcweir             // there is a matching fallback in the cache
1446cdf0e10cSrcweir             // so update rMissingCodes with codepoints not yet resolved by this fallback
1447cdf0e10cSrcweir             int nRemainingLength = 0;
1448cdf0e10cSrcweir             sal_UCS4* pRemainingCodes = (sal_UCS4*)alloca( rMissingCodes.getLength() * sizeof(sal_UCS4) );
1449cdf0e10cSrcweir             String aFontName;
1450cdf0e10cSrcweir             while( nStrIndex < rMissingCodes.getLength() )
1451cdf0e10cSrcweir             {
1452cdf0e10cSrcweir                 cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1453cdf0e10cSrcweir                 bCached = rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &aFontName );
1454cdf0e10cSrcweir                 if( !bCached || (rFontSelData.maSearchName != aFontName) )
1455cdf0e10cSrcweir                     pRemainingCodes[ nRemainingLength++ ] = cChar;
1456cdf0e10cSrcweir             }
1457cdf0e10cSrcweir             rMissingCodes = rtl::OUString( pRemainingCodes, nRemainingLength );
1458cdf0e10cSrcweir         }
1459cdf0e10cSrcweir         else
1460cdf0e10cSrcweir         {
1461cdf0e10cSrcweir             rtl::OUString aOldMissingCodes = rMissingCodes;
1462cdf0e10cSrcweir             // call the hook to query the best matching glyph fallback font
1463cdf0e10cSrcweir             if( mpFallbackHook->FindFontSubstitute( rFontSelData, rMissingCodes ) )
1464cdf0e10cSrcweir                 // apply outdev3.cxx specific fontname normalization
1465cdf0e10cSrcweir                 GetEnglishSearchFontName( rFontSelData.maSearchName );
1466cdf0e10cSrcweir             else
1467cdf0e10cSrcweir                 rFontSelData.maSearchName = String();
1468cdf0e10cSrcweir 
1469cdf0e10cSrcweir             // cache the result even if there was no match
1470cdf0e10cSrcweir             for(;;)
1471cdf0e10cSrcweir             {
1472cdf0e10cSrcweir                  if( !rFontSelData.mpFontEntry->GetFallbackForUnicode( cChar, rFontSelData.GetWeight(), &rFontSelData.maSearchName ) )
1473cdf0e10cSrcweir                      rFontSelData.mpFontEntry->AddFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
1474cdf0e10cSrcweir                  if( nStrIndex >= aOldMissingCodes.getLength() )
1475cdf0e10cSrcweir                      break;
1476cdf0e10cSrcweir                  cChar = aOldMissingCodes.iterateCodePoints( &nStrIndex );
1477cdf0e10cSrcweir             }
1478cdf0e10cSrcweir             if( rFontSelData.maSearchName.Len() != 0 )
1479cdf0e10cSrcweir             {
1480cdf0e10cSrcweir                 // remove cache entries that were still not resolved
1481cdf0e10cSrcweir                 for( nStrIndex = 0; nStrIndex < rMissingCodes.getLength(); )
1482cdf0e10cSrcweir                 {
1483cdf0e10cSrcweir                     cChar = rMissingCodes.iterateCodePoints( &nStrIndex );
1484cdf0e10cSrcweir                     rFontSelData.mpFontEntry->IgnoreFallbackForUnicode( cChar, rFontSelData.GetWeight(), rFontSelData.maSearchName );
1485cdf0e10cSrcweir                 }
1486cdf0e10cSrcweir             }
1487cdf0e10cSrcweir         }
1488cdf0e10cSrcweir 
1489cdf0e10cSrcweir         // find the matching device font
1490cdf0e10cSrcweir         if( rFontSelData.maSearchName.Len() != 0 )
1491cdf0e10cSrcweir             pFallbackData = FindFontFamily( rFontSelData.maSearchName );
1492cdf0e10cSrcweir     }
1493cdf0e10cSrcweir 
1494cdf0e10cSrcweir     // else find a matching font candidate for generic glyph fallback
1495cdf0e10cSrcweir     if( !pFallbackData )
1496cdf0e10cSrcweir     {
1497cdf0e10cSrcweir         // initialize font candidates for generic glyph fallback if needed
1498cdf0e10cSrcweir         if( mnFallbackCount < 0 )
1499cdf0e10cSrcweir             InitGenericGlyphFallback();
1500cdf0e10cSrcweir         // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
1501cdf0e10cSrcweir         if( nFallbackLevel < mnFallbackCount )
1502cdf0e10cSrcweir             pFallbackData = mpFallbackList[ nFallbackLevel ];
1503cdf0e10cSrcweir     }
1504cdf0e10cSrcweir 
1505cdf0e10cSrcweir     return pFallbackData;
1506cdf0e10cSrcweir }
1507cdf0e10cSrcweir 
1508cdf0e10cSrcweir // -----------------------------------------------------------------------
1509cdf0e10cSrcweir 
1510cdf0e10cSrcweir void ImplDevFontList::Add( ImplFontData* pNewData )
1511cdf0e10cSrcweir {
1512cdf0e10cSrcweir     int nAliasQuality = pNewData->mnQuality - 100;
1513cdf0e10cSrcweir     String aMapNames = pNewData->maMapNames;
1514cdf0e10cSrcweir     pNewData->maMapNames = String();
1515cdf0e10cSrcweir 
1516cdf0e10cSrcweir     bool bKeepNewData = false;
1517cdf0e10cSrcweir     for( xub_StrLen nMapNameIndex = 0; nMapNameIndex != STRING_NOTFOUND; )
1518cdf0e10cSrcweir     {
1519cdf0e10cSrcweir         String aSearchName = pNewData->maName;
1520cdf0e10cSrcweir         GetEnglishSearchFontName( aSearchName );
1521cdf0e10cSrcweir 
1522cdf0e10cSrcweir         DevFontList::const_iterator it = maDevFontList.find( aSearchName );
1523cdf0e10cSrcweir         ImplDevFontListData* pFoundData = NULL;
1524cdf0e10cSrcweir         if( it != maDevFontList.end() )
1525cdf0e10cSrcweir             pFoundData = (*it).second;
1526cdf0e10cSrcweir 
1527cdf0e10cSrcweir         if( !pFoundData )
1528cdf0e10cSrcweir         {
1529cdf0e10cSrcweir             pFoundData = new ImplDevFontListData( aSearchName );
1530cdf0e10cSrcweir             maDevFontList[ aSearchName ] = pFoundData;
1531cdf0e10cSrcweir         }
1532cdf0e10cSrcweir 
1533cdf0e10cSrcweir         bKeepNewData = pFoundData->AddFontFace( pNewData );
1534cdf0e10cSrcweir 
1535cdf0e10cSrcweir         // add font alias if available
1536cdf0e10cSrcweir         // a font alias should never win against an original font with similar quality
1537cdf0e10cSrcweir         if( aMapNames.Len() <= nMapNameIndex )
1538cdf0e10cSrcweir             break;
1539cdf0e10cSrcweir         if( bKeepNewData ) // try to recycle obsoleted object
1540cdf0e10cSrcweir             pNewData = pNewData->CreateAlias();
1541cdf0e10cSrcweir         bKeepNewData = false;
1542cdf0e10cSrcweir         pNewData->mnQuality = nAliasQuality;
1543cdf0e10cSrcweir         pNewData->maName = GetNextFontToken( aMapNames, nMapNameIndex );
1544cdf0e10cSrcweir     }
1545cdf0e10cSrcweir 
1546cdf0e10cSrcweir     if( !bKeepNewData )
1547cdf0e10cSrcweir         delete pNewData;
1548cdf0e10cSrcweir }
1549cdf0e10cSrcweir 
1550cdf0e10cSrcweir // -----------------------------------------------------------------------
1551cdf0e10cSrcweir 
1552cdf0e10cSrcweir // find the font from the normalized font family name
1553cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::ImplFindBySearchName( const String& rSearchName ) const
1554cdf0e10cSrcweir {
1555cdf0e10cSrcweir #ifdef DEBUG
1556cdf0e10cSrcweir     String aTempName = rSearchName;
1557cdf0e10cSrcweir     GetEnglishSearchFontName( aTempName );
1558cdf0e10cSrcweir     DBG_ASSERT( aTempName == rSearchName, "ImplDevFontList::ImplFindBySearchName() called with non-normalized name" );
1559cdf0e10cSrcweir #endif
1560cdf0e10cSrcweir 
1561cdf0e10cSrcweir     DevFontList::const_iterator it = maDevFontList.find( rSearchName );
1562cdf0e10cSrcweir     if( it == maDevFontList.end() )
1563cdf0e10cSrcweir         return NULL;
1564cdf0e10cSrcweir 
1565cdf0e10cSrcweir     ImplDevFontListData* pFoundData = (*it).second;
1566cdf0e10cSrcweir     return pFoundData;
1567cdf0e10cSrcweir }
1568cdf0e10cSrcweir 
1569cdf0e10cSrcweir // -----------------------------------------------------------------------
1570cdf0e10cSrcweir 
1571cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::ImplFindByAliasName( const String& rSearchName, const String& rShortName ) const
1572cdf0e10cSrcweir {
1573cdf0e10cSrcweir     // short circuit for impossible font name alias
1574cdf0e10cSrcweir     if( !rSearchName.Len() )
1575cdf0e10cSrcweir         return NULL;
1576cdf0e10cSrcweir 
1577cdf0e10cSrcweir     // short circuit if no alias names are available
1578cdf0e10cSrcweir     if( !mbMapNames )
1579cdf0e10cSrcweir         return NULL;
1580cdf0e10cSrcweir 
1581cdf0e10cSrcweir     // use the font's alias names to find the font
1582cdf0e10cSrcweir     // TODO: get rid of linear search
1583cdf0e10cSrcweir     DevFontList::const_iterator it = maDevFontList.begin();
1584cdf0e10cSrcweir     while( it != maDevFontList.end() )
1585cdf0e10cSrcweir     {
1586cdf0e10cSrcweir         ImplDevFontListData* pData = (*it).second;
1587cdf0e10cSrcweir         if( !pData->maMapNames.Len() )
1588cdf0e10cSrcweir             continue;
1589cdf0e10cSrcweir 
1590cdf0e10cSrcweir         // if one alias name matches we found a matching font
1591cdf0e10cSrcweir         String aTempName;
1592cdf0e10cSrcweir         xub_StrLen nIndex = 0;
1593cdf0e10cSrcweir         do
1594cdf0e10cSrcweir         {
1595cdf0e10cSrcweir            aTempName = GetNextFontToken( pData->maMapNames, nIndex );
1596cdf0e10cSrcweir            // Test, if the Font name match with one of the mapping names
1597cdf0e10cSrcweir            if ( (aTempName == rSearchName) || (aTempName == rShortName) )
1598cdf0e10cSrcweir               return pData;
1599cdf0e10cSrcweir         }
1600cdf0e10cSrcweir         while ( nIndex != STRING_NOTFOUND );
1601cdf0e10cSrcweir      }
1602cdf0e10cSrcweir 
1603cdf0e10cSrcweir      return NULL;
1604cdf0e10cSrcweir }
1605cdf0e10cSrcweir 
1606cdf0e10cSrcweir // -----------------------------------------------------------------------
1607cdf0e10cSrcweir 
1608cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::FindFontFamily( const String& rFontName ) const
1609cdf0e10cSrcweir {
1610cdf0e10cSrcweir     // normalize the font fomily name and
1611cdf0e10cSrcweir     String aName = rFontName;
1612cdf0e10cSrcweir     GetEnglishSearchFontName( aName );
1613cdf0e10cSrcweir     ImplDevFontListData* pFound = ImplFindBySearchName( aName );
1614cdf0e10cSrcweir     return pFound;
1615cdf0e10cSrcweir }
1616cdf0e10cSrcweir 
1617cdf0e10cSrcweir // -----------------------------------------------------------------------
1618cdf0e10cSrcweir 
1619cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::ImplFindByTokenNames( const String& rTokenStr ) const
1620cdf0e10cSrcweir {
1621cdf0e10cSrcweir     ImplDevFontListData* pFoundData = NULL;
1622cdf0e10cSrcweir 
1623cdf0e10cSrcweir     // use normalized font name tokens to find the font
1624cdf0e10cSrcweir     for( xub_StrLen nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
1625cdf0e10cSrcweir     {
1626cdf0e10cSrcweir         String aSearchName = GetNextFontToken( rTokenStr, nTokenPos );
1627cdf0e10cSrcweir         if( !aSearchName.Len() )
1628cdf0e10cSrcweir             continue;
1629cdf0e10cSrcweir         GetEnglishSearchFontName( aSearchName );
1630cdf0e10cSrcweir         pFoundData = ImplFindBySearchName( aSearchName );
1631cdf0e10cSrcweir         if( pFoundData )
1632cdf0e10cSrcweir             break;
1633cdf0e10cSrcweir     }
1634cdf0e10cSrcweir 
1635cdf0e10cSrcweir     return pFoundData;
1636cdf0e10cSrcweir }
1637cdf0e10cSrcweir 
1638cdf0e10cSrcweir // -----------------------------------------------------------------------
1639cdf0e10cSrcweir 
1640cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::ImplFindBySubstFontAttr( const utl::FontNameAttr& rFontAttr ) const
1641cdf0e10cSrcweir {
1642cdf0e10cSrcweir     ImplDevFontListData* pFoundData = NULL;
1643cdf0e10cSrcweir 
1644cdf0e10cSrcweir     // use the font substitutions suggested by the FontNameAttr to find the font
1645cdf0e10cSrcweir     ::std::vector< String >::const_iterator it = rFontAttr.Substitutions.begin();
1646cdf0e10cSrcweir     for(; it != rFontAttr.Substitutions.end(); ++it )
1647cdf0e10cSrcweir     {
1648cdf0e10cSrcweir         String aSearchName( *it );
1649cdf0e10cSrcweir         GetEnglishSearchFontName( aSearchName );
1650cdf0e10cSrcweir 
1651cdf0e10cSrcweir         pFoundData = ImplFindBySearchName( aSearchName );
1652cdf0e10cSrcweir         if( pFoundData )
1653cdf0e10cSrcweir             return pFoundData;
1654cdf0e10cSrcweir     }
1655cdf0e10cSrcweir 
1656cdf0e10cSrcweir     // use known attributes from the configuration to find a matching substitute
1657cdf0e10cSrcweir     const sal_uLong nSearchType = rFontAttr.Type;
1658cdf0e10cSrcweir     if( nSearchType != 0 )
1659cdf0e10cSrcweir     {
1660cdf0e10cSrcweir         const FontWeight eSearchWeight = rFontAttr.Weight;
1661cdf0e10cSrcweir         const FontWidth  eSearchWidth  = rFontAttr.Width;
1662cdf0e10cSrcweir         const FontItalic eSearchSlant  = ITALIC_DONTKNOW;
1663cdf0e10cSrcweir         const FontFamily eSearchFamily = FAMILY_DONTKNOW;
1664cdf0e10cSrcweir         const String aSearchName;
1665cdf0e10cSrcweir         pFoundData = ImplFindByAttributes( nSearchType,
1666cdf0e10cSrcweir             eSearchWeight, eSearchWidth, eSearchFamily, eSearchSlant, aSearchName );
1667cdf0e10cSrcweir         if( pFoundData )
1668cdf0e10cSrcweir             return pFoundData;
1669cdf0e10cSrcweir     }
1670cdf0e10cSrcweir 
1671cdf0e10cSrcweir     return NULL;
1672cdf0e10cSrcweir }
1673cdf0e10cSrcweir 
1674cdf0e10cSrcweir // -----------------------------------------------------------------------
1675cdf0e10cSrcweir 
1676cdf0e10cSrcweir void ImplDevFontList::InitMatchData() const
1677cdf0e10cSrcweir {
1678cdf0e10cSrcweir     // short circuit if already done
1679cdf0e10cSrcweir     if( mbMatchData )
1680cdf0e10cSrcweir         return;
1681cdf0e10cSrcweir     mbMatchData = true;
1682cdf0e10cSrcweir 
1683cdf0e10cSrcweir     // calculate MatchData for all entries
1684cdf0e10cSrcweir     const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
1685cdf0e10cSrcweir 
1686cdf0e10cSrcweir     DevFontList::const_iterator it = maDevFontList.begin();
1687cdf0e10cSrcweir     for(; it != maDevFontList.end(); ++it )
1688cdf0e10cSrcweir     {
1689cdf0e10cSrcweir         const String& rSearchName = (*it).first;
1690cdf0e10cSrcweir         ImplDevFontListData* pEntry = (*it).second;
1691cdf0e10cSrcweir 
1692cdf0e10cSrcweir         pEntry->InitMatchData( rFontSubst, rSearchName );
1693cdf0e10cSrcweir     }
1694cdf0e10cSrcweir }
1695cdf0e10cSrcweir 
1696cdf0e10cSrcweir //----------------------------------------------------------------------------
1697cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::ImplFindByLocale( com::sun::star::lang::Locale& rLocale ) const
1698cdf0e10cSrcweir {
1699cdf0e10cSrcweir     // get the default font for a specified locale
1700cdf0e10cSrcweir     const DefaultFontConfiguration& rDefaults = *DefaultFontConfiguration::get();
1701cdf0e10cSrcweir     const String aDefault = rDefaults.getUserInterfaceFont( rLocale );
1702cdf0e10cSrcweir     ImplDevFontListData* pFontData = ImplFindByTokenNames( aDefault );
1703cdf0e10cSrcweir     if( pFontData )
1704cdf0e10cSrcweir         return pFontData;
1705cdf0e10cSrcweir     return NULL;
1706cdf0e10cSrcweir }
1707cdf0e10cSrcweir 
1708cdf0e10cSrcweir // -----------------------------------------------------------------------
1709cdf0e10cSrcweir 
1710cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::ImplFindByAttributes( sal_uLong nSearchType,
1711cdf0e10cSrcweir     FontWeight eSearchWeight, FontWidth eSearchWidth, FontFamily /*eSearchFamily*/,
1712cdf0e10cSrcweir     FontItalic eSearchItalic, const String& rSearchFamilyName ) const
1713cdf0e10cSrcweir {
1714cdf0e10cSrcweir     if( (eSearchItalic != ITALIC_NONE) && (eSearchItalic != ITALIC_DONTKNOW) )
1715cdf0e10cSrcweir         nSearchType |= IMPL_FONT_ATTR_ITALIC;
1716cdf0e10cSrcweir 
1717cdf0e10cSrcweir     // don't bother to match attributes if the attributes aren't worth matching
1718cdf0e10cSrcweir     if( !nSearchType
1719cdf0e10cSrcweir     && ((eSearchWeight == WEIGHT_DONTKNOW) || (eSearchWeight == WEIGHT_NORMAL))
1720cdf0e10cSrcweir     && ((eSearchWidth == WIDTH_DONTKNOW) || (eSearchWidth == WIDTH_NORMAL)) )
1721cdf0e10cSrcweir         return NULL;
1722cdf0e10cSrcweir 
1723cdf0e10cSrcweir     InitMatchData();
1724cdf0e10cSrcweir     ImplDevFontListData* pFoundData = NULL;
1725cdf0e10cSrcweir 
1726cdf0e10cSrcweir     long    nTestMatch;
1727cdf0e10cSrcweir     long    nBestMatch = 40000;
1728cdf0e10cSrcweir     sal_uLong   nBestType = 0;
1729cdf0e10cSrcweir 
1730cdf0e10cSrcweir     DevFontList::const_iterator it = maDevFontList.begin();
1731cdf0e10cSrcweir     for(; it != maDevFontList.end(); ++it )
1732cdf0e10cSrcweir     {
1733cdf0e10cSrcweir         ImplDevFontListData* pData = (*it).second;
1734cdf0e10cSrcweir 
1735cdf0e10cSrcweir         // Get all information about the matching font
1736cdf0e10cSrcweir         sal_uLong       nMatchType  = pData->mnMatchType;
1737cdf0e10cSrcweir         FontWeight  eMatchWeight= pData->meMatchWeight;
1738cdf0e10cSrcweir         FontWidth   eMatchWidth = pData->meMatchWidth;
1739cdf0e10cSrcweir 
1740cdf0e10cSrcweir         // Calculate Match Value
1741cdf0e10cSrcweir         // 1000000000
1742cdf0e10cSrcweir         //  100000000
1743cdf0e10cSrcweir         //   10000000   CJK, CTL, None-Latin, Symbol
1744cdf0e10cSrcweir         //    1000000   FamilyName, Script, Fixed, -Special, -Decorative,
1745cdf0e10cSrcweir         //              Titling, Capitals, Outline, Shadow
1746cdf0e10cSrcweir         //     100000   Match FamilyName, Serif, SansSerif, Italic,
1747cdf0e10cSrcweir         //              Width, Weight
1748cdf0e10cSrcweir         //      10000   Scalable, Standard, Default,
1749cdf0e10cSrcweir         //              full, Normal, Knownfont,
1750cdf0e10cSrcweir         //              Otherstyle, +Special, +Decorative,
1751cdf0e10cSrcweir         //       1000   Typewriter, Rounded, Gothic, Schollbook
1752cdf0e10cSrcweir         //        100
1753cdf0e10cSrcweir         nTestMatch = 0;
1754cdf0e10cSrcweir 
1755cdf0e10cSrcweir         // test CJK script attributes
1756cdf0e10cSrcweir         if ( nSearchType & IMPL_FONT_ATTR_CJK )
1757cdf0e10cSrcweir         {
1758cdf0e10cSrcweir             // Matching language
1759cdf0e10cSrcweir             if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_CJK_ALLLANG) )
1760cdf0e10cSrcweir                 nTestMatch += 10000000*3;
1761cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_CJK )
1762cdf0e10cSrcweir                 nTestMatch += 10000000*2;
1763cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_FULL )
1764cdf0e10cSrcweir                 nTestMatch += 10000000;
1765cdf0e10cSrcweir         }
1766cdf0e10cSrcweir         else if ( nMatchType & IMPL_FONT_ATTR_CJK )
1767cdf0e10cSrcweir             nTestMatch -= 10000000;
1768cdf0e10cSrcweir 
1769cdf0e10cSrcweir         // test CTL script attributes
1770cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_CTL )
1771cdf0e10cSrcweir         {
1772cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_CTL )
1773cdf0e10cSrcweir                 nTestMatch += 10000000*2;
1774cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_FULL )
1775cdf0e10cSrcweir                 nTestMatch += 10000000;
1776cdf0e10cSrcweir         }
1777cdf0e10cSrcweir         else if ( nMatchType & IMPL_FONT_ATTR_CTL )
1778cdf0e10cSrcweir             nTestMatch -= 10000000;
1779cdf0e10cSrcweir 
1780cdf0e10cSrcweir         // test LATIN script attributes
1781cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_NONELATIN )
1782cdf0e10cSrcweir         {
1783cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_NONELATIN )
1784cdf0e10cSrcweir                 nTestMatch += 10000000*2;
1785cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_FULL )
1786cdf0e10cSrcweir                 nTestMatch += 10000000;
1787cdf0e10cSrcweir         }
1788cdf0e10cSrcweir 
1789cdf0e10cSrcweir         // test SYMBOL attributes
1790cdf0e10cSrcweir         if ( nSearchType & IMPL_FONT_ATTR_SYMBOL )
1791cdf0e10cSrcweir         {
1792cdf0e10cSrcweir             const String& rSearchName = it->first;
1793cdf0e10cSrcweir             // prefer some special known symbol fonts
1794cdf0e10cSrcweir             if ( rSearchName.EqualsAscii( "starsymbol" ) )
1795cdf0e10cSrcweir                 nTestMatch += 10000000*6+(10000*3);
1796cdf0e10cSrcweir             else if ( rSearchName.EqualsAscii( "opensymbol" ) )
1797cdf0e10cSrcweir                 nTestMatch += 10000000*6;
1798cdf0e10cSrcweir             else if ( rSearchName.EqualsAscii( "starbats" )
1799cdf0e10cSrcweir             ||        rSearchName.EqualsAscii( "wingdings" )
1800cdf0e10cSrcweir             ||        rSearchName.EqualsAscii( "monotypesorts" )
1801cdf0e10cSrcweir             ||        rSearchName.EqualsAscii( "dingbats" )
1802cdf0e10cSrcweir             ||        rSearchName.EqualsAscii( "zapfdingbats" ) )
1803cdf0e10cSrcweir                 nTestMatch += 10000000*5;
1804cdf0e10cSrcweir             else if ( pData->mnTypeFaces & IMPL_DEVFONT_SYMBOL )
1805cdf0e10cSrcweir                 nTestMatch += 10000000*4;
1806cdf0e10cSrcweir             else
1807cdf0e10cSrcweir             {
1808cdf0e10cSrcweir                 if( nMatchType & IMPL_FONT_ATTR_SYMBOL )
1809cdf0e10cSrcweir                     nTestMatch += 10000000*2;
1810cdf0e10cSrcweir                 if( nMatchType & IMPL_FONT_ATTR_FULL )
1811cdf0e10cSrcweir                     nTestMatch += 10000000;
1812cdf0e10cSrcweir             }
1813cdf0e10cSrcweir         }
1814cdf0e10cSrcweir         else if ( (pData->mnTypeFaces & (IMPL_DEVFONT_SYMBOL | IMPL_DEVFONT_NONESYMBOL)) == IMPL_DEVFONT_SYMBOL )
1815cdf0e10cSrcweir             nTestMatch -= 10000000;
1816cdf0e10cSrcweir         else if ( nMatchType & IMPL_FONT_ATTR_SYMBOL )
1817cdf0e10cSrcweir             nTestMatch -= 10000;
1818cdf0e10cSrcweir 
1819cdf0e10cSrcweir         // match stripped family name
1820cdf0e10cSrcweir         if( rSearchFamilyName.Len() && (rSearchFamilyName == pData->maMatchFamilyName) )
1821cdf0e10cSrcweir             nTestMatch += 1000000*3;
1822cdf0e10cSrcweir 
1823cdf0e10cSrcweir         // match ALLSCRIPT? attribute
1824cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_ALLSCRIPT )
1825cdf0e10cSrcweir         {
1826cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
1827cdf0e10cSrcweir                 nTestMatch += 1000000*2;
1828cdf0e10cSrcweir             if( nSearchType & IMPL_FONT_ATTR_ALLSUBSCRIPT )
1829cdf0e10cSrcweir             {
1830cdf0e10cSrcweir                 if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ALLSUBSCRIPT) )
1831cdf0e10cSrcweir                     nTestMatch += 1000000*2;
1832cdf0e10cSrcweir                 if( 0 != ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_BRUSHSCRIPT) )
1833cdf0e10cSrcweir                     nTestMatch -= 1000000;
1834cdf0e10cSrcweir             }
1835cdf0e10cSrcweir         }
1836cdf0e10cSrcweir         else if( nMatchType & IMPL_FONT_ATTR_ALLSCRIPT )
1837cdf0e10cSrcweir             nTestMatch -= 1000000;
1838cdf0e10cSrcweir 
1839cdf0e10cSrcweir         // test MONOSPACE+TYPEWRITER attributes
1840cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_FIXED )
1841cdf0e10cSrcweir         {
1842cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_FIXED )
1843cdf0e10cSrcweir                 nTestMatch += 1000000*2;
1844cdf0e10cSrcweir             // a typewriter attribute is even better
1845cdf0e10cSrcweir             if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
1846cdf0e10cSrcweir                 nTestMatch += 10000*2;
1847cdf0e10cSrcweir         }
1848cdf0e10cSrcweir         else if( nMatchType & IMPL_FONT_ATTR_FIXED )
1849cdf0e10cSrcweir             nTestMatch -= 1000000;
1850cdf0e10cSrcweir 
1851cdf0e10cSrcweir         // test SPECIAL attribute
1852cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_SPECIAL )
1853cdf0e10cSrcweir         {
1854cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_SPECIAL )
1855cdf0e10cSrcweir                 nTestMatch += 10000;
1856cdf0e10cSrcweir             else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
1857cdf0e10cSrcweir             {
1858cdf0e10cSrcweir                  if( nMatchType & IMPL_FONT_ATTR_SERIF )
1859cdf0e10cSrcweir                      nTestMatch += 1000*2;
1860cdf0e10cSrcweir                  else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1861cdf0e10cSrcweir                      nTestMatch += 1000;
1862cdf0e10cSrcweir              }
1863cdf0e10cSrcweir         }
1864cdf0e10cSrcweir         else if( (nMatchType & IMPL_FONT_ATTR_SPECIAL) && !(nSearchType & IMPL_FONT_ATTR_SYMBOL) )
1865cdf0e10cSrcweir             nTestMatch -= 1000000;
1866cdf0e10cSrcweir 
1867cdf0e10cSrcweir         // test DECORATIVE attribute
1868cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_DECORATIVE )
1869cdf0e10cSrcweir         {
1870cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
1871cdf0e10cSrcweir                 nTestMatch += 10000;
1872cdf0e10cSrcweir             else if( !(nSearchType & IMPL_FONT_ATTR_ALLSERIFSTYLE) )
1873cdf0e10cSrcweir             {
1874cdf0e10cSrcweir                 if( nMatchType & IMPL_FONT_ATTR_SERIF )
1875cdf0e10cSrcweir                     nTestMatch += 1000*2;
1876cdf0e10cSrcweir                 else if ( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1877cdf0e10cSrcweir                     nTestMatch += 1000;
1878cdf0e10cSrcweir             }
1879cdf0e10cSrcweir         }
1880cdf0e10cSrcweir         else if( nMatchType & IMPL_FONT_ATTR_DECORATIVE )
1881cdf0e10cSrcweir             nTestMatch -= 1000000;
1882cdf0e10cSrcweir 
1883cdf0e10cSrcweir         // test TITLE+CAPITALS attributes
1884cdf0e10cSrcweir         if( nSearchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1885cdf0e10cSrcweir         {
1886cdf0e10cSrcweir             if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1887cdf0e10cSrcweir                 nTestMatch += 1000000*2;
1888cdf0e10cSrcweir             if( 0 == ((nSearchType^nMatchType) & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS)))
1889cdf0e10cSrcweir                 nTestMatch += 1000000;
1890cdf0e10cSrcweir             else if( (nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS))
1891cdf0e10cSrcweir             &&       (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
1892cdf0e10cSrcweir                 nTestMatch += 1000000;
1893cdf0e10cSrcweir         }
1894cdf0e10cSrcweir         else if( nMatchType & (IMPL_FONT_ATTR_TITLING | IMPL_FONT_ATTR_CAPITALS) )
1895cdf0e10cSrcweir             nTestMatch -= 1000000;
1896cdf0e10cSrcweir 
1897cdf0e10cSrcweir         // test OUTLINE+SHADOW attributes
1898cdf0e10cSrcweir         if( nSearchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1899cdf0e10cSrcweir         {
1900cdf0e10cSrcweir             if( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1901cdf0e10cSrcweir                 nTestMatch += 1000000*2;
1902cdf0e10cSrcweir             if( 0 == ((nSearchType ^ nMatchType) & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW)) )
1903cdf0e10cSrcweir                 nTestMatch += 1000000;
1904cdf0e10cSrcweir             else if( (nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW))
1905cdf0e10cSrcweir             &&       (nMatchType & (IMPL_FONT_ATTR_STANDARD | IMPL_FONT_ATTR_DEFAULT)) )
1906cdf0e10cSrcweir                 nTestMatch += 1000000;
1907cdf0e10cSrcweir         }
1908cdf0e10cSrcweir         else if ( nMatchType & (IMPL_FONT_ATTR_OUTLINE | IMPL_FONT_ATTR_SHADOW) )
1909cdf0e10cSrcweir             nTestMatch -= 1000000;
1910cdf0e10cSrcweir 
1911cdf0e10cSrcweir         // test font name substrings
1912cdf0e10cSrcweir     // TODO: calculate name matching score using e.g. Levenstein distance
1913cdf0e10cSrcweir         if( (rSearchFamilyName.Len() >= 4) && (pData->maMatchFamilyName.Len() >= 4)
1914cdf0e10cSrcweir         &&    ((rSearchFamilyName.Search( pData->maMatchFamilyName ) != STRING_NOTFOUND)
1915cdf0e10cSrcweir             || (pData->maMatchFamilyName.Search( rSearchFamilyName ) != STRING_NOTFOUND)) )
1916cdf0e10cSrcweir                     nTestMatch += 5000;
1917cdf0e10cSrcweir 
1918cdf0e10cSrcweir         // test SERIF attribute
1919cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_SERIF )
1920cdf0e10cSrcweir         {
1921cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_SERIF )
1922cdf0e10cSrcweir                 nTestMatch += 1000000*2;
1923cdf0e10cSrcweir             else if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1924cdf0e10cSrcweir                 nTestMatch -= 1000000;
1925cdf0e10cSrcweir         }
1926cdf0e10cSrcweir 
1927cdf0e10cSrcweir         // test SANSERIF attribute
1928cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_SANSSERIF )
1929cdf0e10cSrcweir         {
1930cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
1931cdf0e10cSrcweir                 nTestMatch += 1000000;
1932cdf0e10cSrcweir             else if ( nMatchType & IMPL_FONT_ATTR_SERIF )
1933cdf0e10cSrcweir                 nTestMatch -= 1000000;
1934cdf0e10cSrcweir         }
1935cdf0e10cSrcweir 
1936cdf0e10cSrcweir         // test ITALIC attribute
1937cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_ITALIC )
1938cdf0e10cSrcweir         {
1939cdf0e10cSrcweir             if( pData->mnTypeFaces & IMPL_DEVFONT_ITALIC )
1940cdf0e10cSrcweir                 nTestMatch += 1000000*3;
1941cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_ITALIC )
1942cdf0e10cSrcweir                 nTestMatch += 1000000;
1943cdf0e10cSrcweir         }
1944cdf0e10cSrcweir         else if( !(nSearchType & IMPL_FONT_ATTR_ALLSCRIPT)
1945cdf0e10cSrcweir             &&  ((nMatchType & IMPL_FONT_ATTR_ITALIC)
1946cdf0e10cSrcweir                 || !(pData->mnTypeFaces & IMPL_DEVFONT_NONEITALIC)) )
1947cdf0e10cSrcweir             nTestMatch -= 1000000*2;
1948cdf0e10cSrcweir 
1949cdf0e10cSrcweir         // test WIDTH attribute
1950cdf0e10cSrcweir         if( (eSearchWidth != WIDTH_DONTKNOW) && (eSearchWidth != WIDTH_NORMAL) )
1951cdf0e10cSrcweir         {
1952cdf0e10cSrcweir             if( eSearchWidth < WIDTH_NORMAL )
1953cdf0e10cSrcweir             {
1954cdf0e10cSrcweir                 if( eSearchWidth == eMatchWidth )
1955cdf0e10cSrcweir                     nTestMatch += 1000000*3;
1956cdf0e10cSrcweir                 else if( (eMatchWidth < WIDTH_NORMAL) && (eMatchWidth != WIDTH_DONTKNOW) )
1957cdf0e10cSrcweir                     nTestMatch += 1000000;
1958cdf0e10cSrcweir             }
1959cdf0e10cSrcweir             else
1960cdf0e10cSrcweir             {
1961cdf0e10cSrcweir                 if( eSearchWidth == eMatchWidth )
1962cdf0e10cSrcweir                     nTestMatch += 1000000*3;
1963cdf0e10cSrcweir                 else if( eMatchWidth > WIDTH_NORMAL )
1964cdf0e10cSrcweir                     nTestMatch += 1000000;
1965cdf0e10cSrcweir             }
1966cdf0e10cSrcweir         }
1967cdf0e10cSrcweir         else if( (eMatchWidth != WIDTH_DONTKNOW) && (eMatchWidth != WIDTH_NORMAL) )
1968cdf0e10cSrcweir             nTestMatch -= 1000000;
1969cdf0e10cSrcweir 
1970cdf0e10cSrcweir         // test WEIGHT attribute
1971cdf0e10cSrcweir         if( (eSearchWeight != WEIGHT_DONTKNOW) && (eSearchWeight != WEIGHT_NORMAL) && (eSearchWeight != WEIGHT_MEDIUM) )
1972cdf0e10cSrcweir         {
1973cdf0e10cSrcweir             if( eSearchWeight < WEIGHT_NORMAL )
1974cdf0e10cSrcweir             {
1975cdf0e10cSrcweir                 if( pData->mnTypeFaces & IMPL_DEVFONT_LIGHT )
1976cdf0e10cSrcweir                     nTestMatch += 1000000;
1977cdf0e10cSrcweir                 if( (eMatchWeight < WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_DONTKNOW) )
1978cdf0e10cSrcweir                     nTestMatch += 1000000;
1979cdf0e10cSrcweir             }
1980cdf0e10cSrcweir             else
1981cdf0e10cSrcweir             {
1982cdf0e10cSrcweir                 if( pData->mnTypeFaces & IMPL_DEVFONT_BOLD )
1983cdf0e10cSrcweir                     nTestMatch += 1000000;
1984cdf0e10cSrcweir                 if( eMatchWeight > WEIGHT_BOLD )
1985cdf0e10cSrcweir                     nTestMatch += 1000000;
1986cdf0e10cSrcweir             }
1987cdf0e10cSrcweir         }
1988cdf0e10cSrcweir         else if( ((eMatchWeight != WEIGHT_DONTKNOW) && (eMatchWeight != WEIGHT_NORMAL) && (eMatchWeight != WEIGHT_MEDIUM))
1989cdf0e10cSrcweir             || !(pData->mnTypeFaces & IMPL_DEVFONT_NORMAL) )
1990cdf0e10cSrcweir             nTestMatch -= 1000000;
1991cdf0e10cSrcweir 
1992cdf0e10cSrcweir         // prefer scalable fonts
1993cdf0e10cSrcweir         if( pData->mnTypeFaces & IMPL_DEVFONT_SCALABLE )
1994cdf0e10cSrcweir             nTestMatch += 10000*4;
1995cdf0e10cSrcweir         else
1996cdf0e10cSrcweir             nTestMatch -= 10000*4;
1997cdf0e10cSrcweir 
1998cdf0e10cSrcweir         // test STANDARD+DEFAULT+FULL+NORMAL attributes
1999cdf0e10cSrcweir         if( nMatchType & IMPL_FONT_ATTR_STANDARD )
2000cdf0e10cSrcweir             nTestMatch += 10000*2;
2001cdf0e10cSrcweir         if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
2002cdf0e10cSrcweir             nTestMatch += 10000;
2003cdf0e10cSrcweir         if( nMatchType & IMPL_FONT_ATTR_FULL )
2004cdf0e10cSrcweir             nTestMatch += 10000;
2005cdf0e10cSrcweir         if( nMatchType & IMPL_FONT_ATTR_NORMAL )
2006cdf0e10cSrcweir             nTestMatch += 10000;
2007cdf0e10cSrcweir 
2008cdf0e10cSrcweir         // test OTHERSTYLE attribute
2009cdf0e10cSrcweir         if( nMatchType & IMPL_FONT_ATTR_OTHERSTYLE )
2010cdf0e10cSrcweir         {
2011cdf0e10cSrcweir             if( !(nMatchType & IMPL_FONT_ATTR_OTHERSTYLE) )
2012cdf0e10cSrcweir                 nTestMatch -= 10000;
2013cdf0e10cSrcweir         }
2014cdf0e10cSrcweir         else if( nMatchType & IMPL_FONT_ATTR_OTHERSTYLE )
2015cdf0e10cSrcweir             nTestMatch -= 10000;
2016cdf0e10cSrcweir 
2017cdf0e10cSrcweir         // test ROUNDED attribute
2018cdf0e10cSrcweir         if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_ROUNDED) )
2019cdf0e10cSrcweir             nTestMatch += 1000;
2020cdf0e10cSrcweir 
2021cdf0e10cSrcweir         // test TYPEWRITER attribute
2022cdf0e10cSrcweir         if( 0 == ((nSearchType ^ nMatchType) & IMPL_FONT_ATTR_TYPEWRITER) )
2023cdf0e10cSrcweir             nTestMatch += 1000;
2024cdf0e10cSrcweir 
2025cdf0e10cSrcweir         // test GOTHIC attribute
2026cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_GOTHIC )
2027cdf0e10cSrcweir         {
2028cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_GOTHIC )
2029cdf0e10cSrcweir                 nTestMatch += 1000*3;
2030cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_SANSSERIF )
2031cdf0e10cSrcweir                 nTestMatch += 1000*2;
2032cdf0e10cSrcweir         }
2033cdf0e10cSrcweir 
2034cdf0e10cSrcweir         // test SCHOOLBOOK attribute
2035cdf0e10cSrcweir         if( nSearchType & IMPL_FONT_ATTR_SCHOOLBOOK )
2036cdf0e10cSrcweir         {
2037cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_SCHOOLBOOK )
2038cdf0e10cSrcweir                 nTestMatch += 1000*3;
2039cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_SERIF )
2040cdf0e10cSrcweir                 nTestMatch += 1000*2;
2041cdf0e10cSrcweir         }
2042cdf0e10cSrcweir 
2043cdf0e10cSrcweir         // compare with best matching font yet
2044cdf0e10cSrcweir         if ( nTestMatch > nBestMatch )
2045cdf0e10cSrcweir         {
2046cdf0e10cSrcweir             pFoundData  = pData;
2047cdf0e10cSrcweir             nBestMatch  = nTestMatch;
2048cdf0e10cSrcweir             nBestType   = nMatchType;
2049cdf0e10cSrcweir         }
2050cdf0e10cSrcweir         else if( nTestMatch == nBestMatch )
2051cdf0e10cSrcweir         {
2052cdf0e10cSrcweir             // some fonts are more suitable defaults
2053cdf0e10cSrcweir             if( nMatchType & IMPL_FONT_ATTR_DEFAULT )
2054cdf0e10cSrcweir             {
2055cdf0e10cSrcweir                 pFoundData  = pData;
2056cdf0e10cSrcweir                 nBestType   = nMatchType;
2057cdf0e10cSrcweir             }
2058cdf0e10cSrcweir             else if( (nMatchType & IMPL_FONT_ATTR_STANDARD) &&
2059cdf0e10cSrcweir                     !(nBestType & IMPL_FONT_ATTR_DEFAULT) )
2060cdf0e10cSrcweir             {
2061cdf0e10cSrcweir                  pFoundData  = pData;
2062cdf0e10cSrcweir                  nBestType   = nMatchType;
2063cdf0e10cSrcweir             }
2064cdf0e10cSrcweir         }
2065cdf0e10cSrcweir     }
2066cdf0e10cSrcweir 
2067cdf0e10cSrcweir     return pFoundData;
2068cdf0e10cSrcweir }
2069cdf0e10cSrcweir 
2070cdf0e10cSrcweir // -----------------------------------------------------------------------
2071cdf0e10cSrcweir 
2072cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::FindDefaultFont() const
2073cdf0e10cSrcweir {
2074cdf0e10cSrcweir     // try to find one of the default fonts of the
2075cdf0e10cSrcweir     // UNICODE, SANSSERIF, SERIF or FIXED default font lists
2076cdf0e10cSrcweir     const DefaultFontConfiguration& rDefaults = *DefaultFontConfiguration::get();
2077cdf0e10cSrcweir     com::sun::star::lang::Locale aLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
2078cdf0e10cSrcweir     String aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS_UNICODE );
2079cdf0e10cSrcweir     ImplDevFontListData* pFoundData = ImplFindByTokenNames( aFontname );
2080cdf0e10cSrcweir     if( pFoundData )
2081cdf0e10cSrcweir         return pFoundData;
2082cdf0e10cSrcweir 
2083cdf0e10cSrcweir     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SANS );
2084cdf0e10cSrcweir     pFoundData = ImplFindByTokenNames( aFontname );
2085cdf0e10cSrcweir     if( pFoundData )
2086cdf0e10cSrcweir         return pFoundData;
2087cdf0e10cSrcweir 
2088cdf0e10cSrcweir     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_SERIF );
2089cdf0e10cSrcweir     pFoundData = ImplFindByTokenNames( aFontname );
2090cdf0e10cSrcweir     if( pFoundData )
2091cdf0e10cSrcweir         return pFoundData;
2092cdf0e10cSrcweir 
2093cdf0e10cSrcweir     aFontname = rDefaults.getDefaultFont( aLocale, DEFAULTFONT_FIXED );
2094cdf0e10cSrcweir     pFoundData = ImplFindByTokenNames( aFontname );
2095cdf0e10cSrcweir     if( pFoundData )
2096cdf0e10cSrcweir         return pFoundData;
2097cdf0e10cSrcweir 
2098cdf0e10cSrcweir     // now try to find a reasonable non-symbol font
2099cdf0e10cSrcweir 
2100cdf0e10cSrcweir     InitMatchData();
2101cdf0e10cSrcweir 
2102cdf0e10cSrcweir     DevFontList::const_iterator it = maDevFontList.begin();
2103cdf0e10cSrcweir     for(; it !=  maDevFontList.end(); ++it )
2104cdf0e10cSrcweir     {
2105cdf0e10cSrcweir         ImplDevFontListData* pData = (*it).second;
2106cdf0e10cSrcweir         if( pData->mnMatchType & IMPL_FONT_ATTR_SYMBOL )
2107cdf0e10cSrcweir             continue;
2108cdf0e10cSrcweir         pFoundData = pData;
2109cdf0e10cSrcweir         if( pData->mnMatchType & (IMPL_FONT_ATTR_DEFAULT|IMPL_FONT_ATTR_STANDARD) )
2110cdf0e10cSrcweir             break;
2111cdf0e10cSrcweir     }
2112cdf0e10cSrcweir     if( pFoundData )
2113cdf0e10cSrcweir         return pFoundData;
2114cdf0e10cSrcweir 
2115cdf0e10cSrcweir     // finding any font is better than finding no font at all
2116cdf0e10cSrcweir     it = maDevFontList.begin();
2117cdf0e10cSrcweir     if( it !=  maDevFontList.end() )
2118cdf0e10cSrcweir         pFoundData = (*it).second;
2119cdf0e10cSrcweir 
2120cdf0e10cSrcweir     return pFoundData;
2121cdf0e10cSrcweir }
2122cdf0e10cSrcweir 
2123cdf0e10cSrcweir // -----------------------------------------------------------------------
2124cdf0e10cSrcweir 
2125cdf0e10cSrcweir ImplDevFontList* ImplDevFontList::Clone( bool bScalable, bool bEmbeddable ) const
2126cdf0e10cSrcweir {
2127cdf0e10cSrcweir     ImplDevFontList* pClonedList = new ImplDevFontList;
2128cdf0e10cSrcweir //  pClonedList->mbMatchData    = mbMatchData;
2129cdf0e10cSrcweir     pClonedList->mbMapNames     = mbMapNames;
2130cdf0e10cSrcweir     pClonedList->mpPreMatchHook = mpPreMatchHook;
2131cdf0e10cSrcweir     pClonedList->mpFallbackHook = mpFallbackHook;
2132cdf0e10cSrcweir 
2133cdf0e10cSrcweir     // TODO: clone the config-font attributes too?
2134cdf0e10cSrcweir     pClonedList->mbMatchData    = false;
2135cdf0e10cSrcweir 
2136cdf0e10cSrcweir     DevFontList::const_iterator it = maDevFontList.begin();
2137cdf0e10cSrcweir     for(; it != maDevFontList.end(); ++it )
2138cdf0e10cSrcweir     {
2139cdf0e10cSrcweir         const ImplDevFontListData* pFontFace = (*it).second;
2140cdf0e10cSrcweir         pFontFace->UpdateCloneFontList( *pClonedList, bScalable, bEmbeddable );
2141cdf0e10cSrcweir     }
2142cdf0e10cSrcweir 
2143cdf0e10cSrcweir     return pClonedList;
2144cdf0e10cSrcweir }
2145cdf0e10cSrcweir 
2146cdf0e10cSrcweir // -----------------------------------------------------------------------
2147cdf0e10cSrcweir 
2148cdf0e10cSrcweir ImplGetDevFontList* ImplDevFontList::GetDevFontList() const
2149cdf0e10cSrcweir {
2150cdf0e10cSrcweir     ImplGetDevFontList* pGetDevFontList = new ImplGetDevFontList;
2151cdf0e10cSrcweir 
2152cdf0e10cSrcweir     DevFontList::const_iterator it = maDevFontList.begin();
2153cdf0e10cSrcweir     for(; it != maDevFontList.end(); ++it )
2154cdf0e10cSrcweir     {
2155cdf0e10cSrcweir         const ImplDevFontListData* pFontFamily = (*it).second;
2156cdf0e10cSrcweir         pFontFamily->UpdateDevFontList( *pGetDevFontList );
2157cdf0e10cSrcweir     }
2158cdf0e10cSrcweir 
2159cdf0e10cSrcweir     return pGetDevFontList;
2160cdf0e10cSrcweir }
2161cdf0e10cSrcweir 
2162cdf0e10cSrcweir // -----------------------------------------------------------------------
2163cdf0e10cSrcweir 
2164cdf0e10cSrcweir ImplGetDevSizeList* ImplDevFontList::GetDevSizeList( const String& rFontName ) const
2165cdf0e10cSrcweir {
2166cdf0e10cSrcweir     ImplGetDevSizeList* pGetDevSizeList = new ImplGetDevSizeList( rFontName );
2167cdf0e10cSrcweir 
2168cdf0e10cSrcweir     ImplDevFontListData* pFontFamily = FindFontFamily( rFontName );
2169cdf0e10cSrcweir     if( pFontFamily != NULL )
2170cdf0e10cSrcweir     {
2171cdf0e10cSrcweir         std::set<int> rHeights;
2172cdf0e10cSrcweir         pFontFamily->GetFontHeights( rHeights );
2173cdf0e10cSrcweir 
2174cdf0e10cSrcweir         std::set<int>::const_iterator it = rHeights.begin();
2175cdf0e10cSrcweir         for(; it != rHeights.begin(); ++it )
2176cdf0e10cSrcweir             pGetDevSizeList->Add( *it );
2177cdf0e10cSrcweir     }
2178cdf0e10cSrcweir 
2179cdf0e10cSrcweir     return pGetDevSizeList;
2180cdf0e10cSrcweir }
2181cdf0e10cSrcweir 
2182cdf0e10cSrcweir // =======================================================================
2183cdf0e10cSrcweir 
2184cdf0e10cSrcweir ImplFontSelectData::ImplFontSelectData( const Font& rFont,
2185cdf0e10cSrcweir     const String& rSearchName, const Size& rSize, float fExactHeight)
2186cdf0e10cSrcweir :   maSearchName( rSearchName ),
2187cdf0e10cSrcweir     mnWidth( rSize.Width() ),
2188cdf0e10cSrcweir     mnHeight( rSize.Height() ),
2189cdf0e10cSrcweir     mfExactHeight( fExactHeight),
2190cdf0e10cSrcweir     mnOrientation( rFont.GetOrientation() ),
2191cdf0e10cSrcweir     meLanguage( rFont.GetLanguage() ),
2192cdf0e10cSrcweir     mbVertical( rFont.IsVertical() ),
2193cdf0e10cSrcweir     mbNonAntialiased( false ),
2194cdf0e10cSrcweir     mpFontData( NULL ),
2195cdf0e10cSrcweir     mpFontEntry( NULL )
2196cdf0e10cSrcweir {
2197cdf0e10cSrcweir     maTargetName = maName;
2198cdf0e10cSrcweir 
2199cdf0e10cSrcweir     rFont.GetFontAttributes( *this );
2200cdf0e10cSrcweir 
2201cdf0e10cSrcweir     // normalize orientation between 0 and 3600
2202cdf0e10cSrcweir     if( 3600 <= (unsigned)mnOrientation )
2203cdf0e10cSrcweir     {
2204cdf0e10cSrcweir         if( mnOrientation >= 0 )
2205cdf0e10cSrcweir             mnOrientation %= 3600;
2206cdf0e10cSrcweir         else
2207cdf0e10cSrcweir             mnOrientation = 3600 - (-mnOrientation % 3600);
2208cdf0e10cSrcweir     }
2209cdf0e10cSrcweir 
2210cdf0e10cSrcweir     // normalize width and height
2211cdf0e10cSrcweir     if( mnHeight < 0 )
2212cdf0e10cSrcweir         mnHeight = -mnHeight;
2213cdf0e10cSrcweir     if( mnWidth < 0 )
2214cdf0e10cSrcweir         mnWidth = -mnWidth;
2215cdf0e10cSrcweir }
2216cdf0e10cSrcweir 
2217cdf0e10cSrcweir // -----------------------------------------------------------------------
2218cdf0e10cSrcweir 
2219cdf0e10cSrcweir ImplFontSelectData::ImplFontSelectData( const ImplFontData& rFontData,
2220cdf0e10cSrcweir     const Size& rSize, float fExactHeight, int nOrientation, bool bVertical )
2221cdf0e10cSrcweir :   ImplFontAttributes( rFontData ),
2222cdf0e10cSrcweir     mnWidth( rSize.Width() ),
2223cdf0e10cSrcweir     mnHeight( rSize.Height() ),
2224cdf0e10cSrcweir     mfExactHeight( fExactHeight ),
2225cdf0e10cSrcweir     mnOrientation( nOrientation ),
2226cdf0e10cSrcweir     meLanguage( 0 ),
2227cdf0e10cSrcweir     mbVertical( bVertical ),
2228cdf0e10cSrcweir     mbNonAntialiased( false ),
2229cdf0e10cSrcweir     mpFontData( &rFontData ),
2230cdf0e10cSrcweir     mpFontEntry( NULL )
2231cdf0e10cSrcweir {
2232cdf0e10cSrcweir     maTargetName = maSearchName = maName;
2233cdf0e10cSrcweir     // NOTE: no normalization for width/height/orientation
2234cdf0e10cSrcweir }
2235cdf0e10cSrcweir 
2236cdf0e10cSrcweir // =======================================================================
2237cdf0e10cSrcweir 
2238cdf0e10cSrcweir size_t ImplFontCache::IFSD_Hash::operator()( const ImplFontSelectData& rFSD ) const
2239cdf0e10cSrcweir {
2240cdf0e10cSrcweir     // TODO: does it pay off to improve this hash function?
2241cdf0e10cSrcweir     static FontNameHash aFontNameHash;
2242cdf0e10cSrcweir     size_t nHash = aFontNameHash( rFSD.maSearchName );
2243cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
2244cdf0e10cSrcweir     // check for features and generate a unique hash if necessary
2245cdf0e10cSrcweir     if (rFSD.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2246cdf0e10cSrcweir         != STRING_NOTFOUND)
2247cdf0e10cSrcweir     {
2248cdf0e10cSrcweir         nHash = aFontNameHash( rFSD.maTargetName );
2249cdf0e10cSrcweir     }
2250cdf0e10cSrcweir #endif
2251cdf0e10cSrcweir     nHash += 11 * rFSD.mnHeight;
2252cdf0e10cSrcweir     nHash += 19 * rFSD.meWeight;
2253cdf0e10cSrcweir     nHash += 29 * rFSD.meItalic;
2254cdf0e10cSrcweir     nHash += 37 * rFSD.mnOrientation;
2255cdf0e10cSrcweir     nHash += 41 * rFSD.meLanguage;
2256cdf0e10cSrcweir     if( rFSD.mbVertical )
2257cdf0e10cSrcweir         nHash += 53;
2258cdf0e10cSrcweir     return nHash;
2259cdf0e10cSrcweir }
2260cdf0e10cSrcweir 
2261cdf0e10cSrcweir // -----------------------------------------------------------------------
2262cdf0e10cSrcweir 
2263cdf0e10cSrcweir bool ImplFontCache::IFSD_Equal::operator()(const ImplFontSelectData& rA, const ImplFontSelectData& rB) const
2264cdf0e10cSrcweir {
2265cdf0e10cSrcweir     // check normalized font family name
2266cdf0e10cSrcweir     if( rA.maSearchName != rB.maSearchName )
2267cdf0e10cSrcweir         return false;
2268cdf0e10cSrcweir 
2269cdf0e10cSrcweir     // check font transformation
2270cdf0e10cSrcweir     if( (rA.mnHeight       != rB.mnHeight)
2271cdf0e10cSrcweir     ||  (rA.mnWidth        != rB.mnWidth)
2272cdf0e10cSrcweir     ||  (rA.mnOrientation  != rB.mnOrientation) )
2273cdf0e10cSrcweir         return false;
2274cdf0e10cSrcweir 
2275cdf0e10cSrcweir     // check mapping relevant attributes
2276cdf0e10cSrcweir     if( (rA.mbVertical     != rB.mbVertical)
2277cdf0e10cSrcweir     ||  (rA.meLanguage     != rB.meLanguage) )
2278cdf0e10cSrcweir         return false;
2279cdf0e10cSrcweir 
2280cdf0e10cSrcweir     // check font face attributes
2281cdf0e10cSrcweir     if( (rA.meWeight       != rB.meWeight)
2282cdf0e10cSrcweir     ||  (rA.meItalic       != rB.meItalic)
2283cdf0e10cSrcweir //    ||  (rA.meFamily       != rB.meFamily) // TODO: remove this mostly obsolete member
2284cdf0e10cSrcweir     ||  (rA.mePitch        != rB.mePitch) )
2285cdf0e10cSrcweir         return false;
2286cdf0e10cSrcweir 
2287cdf0e10cSrcweir     // check style name
2288cdf0e10cSrcweir     if( rA.maStyleName != rB.maStyleName)
2289cdf0e10cSrcweir         return false;
2290cdf0e10cSrcweir 
2291cdf0e10cSrcweir     // Symbol fonts may recode from one type to another So they are only
2292cdf0e10cSrcweir     // safely equivalent for equal targets
2293cdf0e10cSrcweir     if (
2294cdf0e10cSrcweir         (rA.mpFontData && rA.mpFontData->IsSymbolFont()) ||
2295cdf0e10cSrcweir         (rB.mpFontData && rB.mpFontData->IsSymbolFont())
2296cdf0e10cSrcweir        )
2297cdf0e10cSrcweir     {
2298cdf0e10cSrcweir         if (rA.maTargetName != rB.maTargetName)
2299cdf0e10cSrcweir             return false;
2300cdf0e10cSrcweir     }
2301cdf0e10cSrcweir 
2302cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
2303cdf0e10cSrcweir     // check for features
2304cdf0e10cSrcweir     if ((rA.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2305cdf0e10cSrcweir          != STRING_NOTFOUND ||
2306cdf0e10cSrcweir          rB.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2307cdf0e10cSrcweir          != STRING_NOTFOUND) && rA.maTargetName != rB.maTargetName)
2308cdf0e10cSrcweir         return false;
2309cdf0e10cSrcweir #endif
2310cdf0e10cSrcweir 
2311cdf0e10cSrcweir     return true;
2312cdf0e10cSrcweir }
2313cdf0e10cSrcweir 
2314cdf0e10cSrcweir // -----------------------------------------------------------------------
2315cdf0e10cSrcweir 
2316cdf0e10cSrcweir ImplFontCache::ImplFontCache( bool bPrinter )
2317cdf0e10cSrcweir :   mpFirstEntry( NULL ),
2318cdf0e10cSrcweir     mnRef0Count( 0 ),
2319cdf0e10cSrcweir     mbPrinter( bPrinter )
2320cdf0e10cSrcweir {}
2321cdf0e10cSrcweir 
2322cdf0e10cSrcweir // -----------------------------------------------------------------------
2323cdf0e10cSrcweir 
2324cdf0e10cSrcweir ImplFontCache::~ImplFontCache()
2325cdf0e10cSrcweir {
2326cdf0e10cSrcweir     FontInstanceList::iterator it = maFontInstanceList.begin();
2327cdf0e10cSrcweir     for(; it != maFontInstanceList.end(); ++it )
2328cdf0e10cSrcweir     {
2329cdf0e10cSrcweir         ImplFontEntry* pEntry = (*it).second;
2330cdf0e10cSrcweir         delete pEntry;
2331cdf0e10cSrcweir     }
2332cdf0e10cSrcweir }
2333cdf0e10cSrcweir 
2334cdf0e10cSrcweir // -----------------------------------------------------------------------
2335cdf0e10cSrcweir 
2336cdf0e10cSrcweir ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
2337cdf0e10cSrcweir     const Font& rFont, const Size& rSize, float fExactHeight, ImplDirectFontSubstitution* pDevSpecific )
2338cdf0e10cSrcweir {
2339cdf0e10cSrcweir     String aSearchName = rFont.GetName();
2340cdf0e10cSrcweir 
2341cdf0e10cSrcweir     // TODO: also add device specific name caching
2342cdf0e10cSrcweir     if( !pDevSpecific )
2343cdf0e10cSrcweir     {
2344cdf0e10cSrcweir         // check if the requested font name is already known
2345cdf0e10cSrcweir         // if it is already known get its normalized search name
2346cdf0e10cSrcweir         FontNameList::const_iterator it_name = maFontNameList.find( aSearchName );
2347cdf0e10cSrcweir         if( it_name != maFontNameList.end() )
2348cdf0e10cSrcweir             if( !(*it_name).second.EqualsAscii( "hg", 0, 2)
2349cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
2350cdf0e10cSrcweir                 && (aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX)
2351cdf0e10cSrcweir                     == STRING_NOTFOUND)
2352cdf0e10cSrcweir #endif
2353cdf0e10cSrcweir             )
2354cdf0e10cSrcweir                 aSearchName = (*it_name).second;
2355cdf0e10cSrcweir     }
2356cdf0e10cSrcweir 
2357cdf0e10cSrcweir     // initialize internal font request object
2358cdf0e10cSrcweir     ImplFontSelectData aFontSelData( rFont, aSearchName, rSize, fExactHeight );
2359cdf0e10cSrcweir     return GetFontEntry( pFontList, aFontSelData, pDevSpecific );
2360cdf0e10cSrcweir }
2361cdf0e10cSrcweir 
2362cdf0e10cSrcweir // -----------------------------------------------------------------------
2363cdf0e10cSrcweir 
2364cdf0e10cSrcweir ImplFontEntry* ImplFontCache::GetFontEntry( ImplDevFontList* pFontList,
2365cdf0e10cSrcweir     ImplFontSelectData& aFontSelData, ImplDirectFontSubstitution* pDevSpecific )
2366cdf0e10cSrcweir {
2367cdf0e10cSrcweir     // check if a directly matching logical font instance is already cached,
2368cdf0e10cSrcweir     // the most recently used font usually has a hit rate of >50%
2369cdf0e10cSrcweir     ImplFontEntry *pEntry = NULL;
2370cdf0e10cSrcweir     ImplDevFontListData* pFontFamily = NULL;
2371cdf0e10cSrcweir     IFSD_Equal aIFSD_Equal;
2372cdf0e10cSrcweir     if( mpFirstEntry && aIFSD_Equal( aFontSelData, mpFirstEntry->maFontSelData ) )
2373cdf0e10cSrcweir         pEntry = mpFirstEntry;
2374cdf0e10cSrcweir     else
2375cdf0e10cSrcweir     {
2376cdf0e10cSrcweir         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
2377cdf0e10cSrcweir         if( it != maFontInstanceList.end() )
2378cdf0e10cSrcweir             pEntry = (*it).second;
2379cdf0e10cSrcweir     }
2380cdf0e10cSrcweir 
2381cdf0e10cSrcweir     if( !pEntry ) // no direct cache hit
2382cdf0e10cSrcweir     {
2383cdf0e10cSrcweir         // find the best matching logical font family and update font selector accordingly
2384cdf0e10cSrcweir         pFontFamily = pFontList->ImplFindByFont( aFontSelData, mbPrinter, pDevSpecific );
2385cdf0e10cSrcweir         DBG_ASSERT( (pFontFamily != NULL), "ImplFontCache::Get() No logical font found!" );
2386cdf0e10cSrcweir         if( pFontFamily )
2387cdf0e10cSrcweir             aFontSelData.maSearchName = pFontFamily->GetSearchName();
2388cdf0e10cSrcweir 
2389cdf0e10cSrcweir         // check if an indirectly matching logical font instance is already cached
2390cdf0e10cSrcweir         FontInstanceList::iterator it = maFontInstanceList.find( aFontSelData );
2391cdf0e10cSrcweir         if( it != maFontInstanceList.end() )
2392cdf0e10cSrcweir         {
2393cdf0e10cSrcweir             // we have an indirect cache hit
2394cdf0e10cSrcweir             pEntry = (*it).second;
2395cdf0e10cSrcweir             // cache the requested and the selected font names
2396cdf0e10cSrcweir             // => next time there is a good chance for a direct cache hit
2397cdf0e10cSrcweir             // don't allow the cache to grow too big
2398cdf0e10cSrcweir             // TODO: implement some fancy LRU caching?
2399cdf0e10cSrcweir             if( maFontNameList.size() >= 4000 )
2400cdf0e10cSrcweir                 maFontNameList.clear();
2401cdf0e10cSrcweir             // TODO: also add device specific name caching
2402cdf0e10cSrcweir             if( !pDevSpecific )
2403cdf0e10cSrcweir                 if( aFontSelData.maName != aFontSelData.maSearchName )
2404cdf0e10cSrcweir                     maFontNameList[ aFontSelData.maName ] = aFontSelData.maSearchName;
2405cdf0e10cSrcweir         }
2406cdf0e10cSrcweir     }
2407cdf0e10cSrcweir 
2408cdf0e10cSrcweir     if( pEntry ) // cache hit => use existing font instance
2409cdf0e10cSrcweir     {
2410cdf0e10cSrcweir         // increase the font instance's reference count
2411cdf0e10cSrcweir         if( !pEntry->mnRefCount++ )
2412cdf0e10cSrcweir             --mnRef0Count;
2413cdf0e10cSrcweir     }
2414cdf0e10cSrcweir     else // no cache hit => create a new font instance
2415cdf0e10cSrcweir     {
2416cdf0e10cSrcweir         // find the best matching physical font face
2417cdf0e10cSrcweir         ImplFontData* pFontData = pFontFamily->FindBestFontFace( aFontSelData );
2418cdf0e10cSrcweir         aFontSelData.mpFontData = pFontData;
2419cdf0e10cSrcweir 
2420cdf0e10cSrcweir         // create a new logical font instance from this physical font face
2421cdf0e10cSrcweir         pEntry = pFontData->CreateFontInstance( aFontSelData );
2422cdf0e10cSrcweir 
2423cdf0e10cSrcweir         // if we found a different symbol font we need a symbol conversion table
2424cdf0e10cSrcweir         if( pFontData->IsSymbolFont() )
2425cdf0e10cSrcweir             if( aFontSelData.maTargetName != aFontSelData.maSearchName )
2426cdf0e10cSrcweir                 pEntry->mpConversion = ConvertChar::GetRecodeData( aFontSelData.maTargetName, aFontSelData.maSearchName );
2427cdf0e10cSrcweir 
2428cdf0e10cSrcweir         // add the new entry to the cache
2429cdf0e10cSrcweir         maFontInstanceList[ aFontSelData ] = pEntry;
2430cdf0e10cSrcweir     }
2431cdf0e10cSrcweir 
2432cdf0e10cSrcweir     mpFirstEntry = pEntry;
2433cdf0e10cSrcweir     return pEntry;
2434cdf0e10cSrcweir }
2435cdf0e10cSrcweir 
2436cdf0e10cSrcweir // -----------------------------------------------------------------------
2437cdf0e10cSrcweir 
2438cdf0e10cSrcweir ImplDevFontListData* ImplDevFontList::ImplFindByFont( ImplFontSelectData& rFSD,
2439cdf0e10cSrcweir     bool bPrinter, ImplDirectFontSubstitution* pDevSpecific ) const
2440cdf0e10cSrcweir {
2441cdf0e10cSrcweir     // give up if no fonts are available
2442cdf0e10cSrcweir     if( !Count() )
2443cdf0e10cSrcweir         return NULL;
2444cdf0e10cSrcweir 
2445cdf0e10cSrcweir     // test if a font in the token list is available
2446cdf0e10cSrcweir     // substitute the font if this was requested
2447cdf0e10cSrcweir     sal_uInt16 nSubstFlags = FONT_SUBSTITUTE_ALWAYS;
2448cdf0e10cSrcweir     if ( bPrinter )
2449cdf0e10cSrcweir         nSubstFlags |= FONT_SUBSTITUTE_SCREENONLY;
2450cdf0e10cSrcweir 
2451cdf0e10cSrcweir     bool bMultiToken = false;
2452cdf0e10cSrcweir     xub_StrLen nTokenPos = 0;
2453cdf0e10cSrcweir     String& aSearchName = rFSD.maSearchName; // TODO: get rid of reference
2454cdf0e10cSrcweir     for(;;)
2455cdf0e10cSrcweir     {
2456cdf0e10cSrcweir         rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
2457cdf0e10cSrcweir         aSearchName = rFSD.maTargetName;
2458cdf0e10cSrcweir 
2459cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
2460cdf0e10cSrcweir         // Until features are properly supported, they are appended to the
2461cdf0e10cSrcweir         // font name, so we need to strip them off so the font is found.
2462cdf0e10cSrcweir         xub_StrLen nFeat = aSearchName.Search(grutils::GrFeatureParser::FEAT_PREFIX);
2463cdf0e10cSrcweir         String aOrigName = rFSD.maTargetName;
2464cdf0e10cSrcweir         String aBaseFontName(aSearchName, 0, (nFeat != STRING_NOTFOUND)?nFeat:aSearchName.Len());
2465cdf0e10cSrcweir         if (nFeat != STRING_NOTFOUND && STRING_NOTFOUND !=
2466cdf0e10cSrcweir             aSearchName.Search(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR, nFeat))
2467cdf0e10cSrcweir         {
2468cdf0e10cSrcweir             aSearchName = aBaseFontName;
2469cdf0e10cSrcweir             rFSD.maTargetName = aBaseFontName;
2470cdf0e10cSrcweir         }
2471cdf0e10cSrcweir 
2472cdf0e10cSrcweir #endif
2473cdf0e10cSrcweir 
2474cdf0e10cSrcweir         GetEnglishSearchFontName( aSearchName );
2475cdf0e10cSrcweir         ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
2476cdf0e10cSrcweir         // #114999# special emboldening for Ricoh fonts
2477cdf0e10cSrcweir         // TODO: smarter check for special cases by using PreMatch infrastructure?
2478cdf0e10cSrcweir         if( (rFSD.meWeight > WEIGHT_MEDIUM)
2479cdf0e10cSrcweir         &&  aSearchName.EqualsAscii( "hg", 0, 2) )
2480cdf0e10cSrcweir         {
2481cdf0e10cSrcweir             String aBoldName;
2482cdf0e10cSrcweir             if( aSearchName.EqualsAscii( "hggothicb", 0, 9) )
2483cdf0e10cSrcweir                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hggothice"));
2484cdf0e10cSrcweir             else if( aSearchName.EqualsAscii( "hgpgothicb", 0, 10) )
2485cdf0e10cSrcweir                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpgothice"));
2486cdf0e10cSrcweir             else if( aSearchName.EqualsAscii( "hgminchol", 0, 9) )
2487cdf0e10cSrcweir                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchob"));
2488cdf0e10cSrcweir             else if( aSearchName.EqualsAscii( "hgpminchol", 0, 10) )
2489cdf0e10cSrcweir                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchob"));
2490cdf0e10cSrcweir             else if( aSearchName.EqualsAscii( "hgminchob" ) )
2491cdf0e10cSrcweir                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgminchoe"));
2492cdf0e10cSrcweir             else if( aSearchName.EqualsAscii( "hgpminchob" ) )
2493cdf0e10cSrcweir                 aBoldName = String(RTL_CONSTASCII_USTRINGPARAM("hgpminchoe"));
2494cdf0e10cSrcweir 
2495cdf0e10cSrcweir             if( aBoldName.Len() && ImplFindBySearchName( aBoldName ) )
2496cdf0e10cSrcweir             {
2497cdf0e10cSrcweir                 // the other font is available => use it
2498cdf0e10cSrcweir                 aSearchName = aBoldName;
2499cdf0e10cSrcweir                 // prevent synthetic emboldening of bold version
2500cdf0e10cSrcweir                 rFSD.meWeight = WEIGHT_DONTKNOW;
2501cdf0e10cSrcweir             }
2502cdf0e10cSrcweir         }
2503cdf0e10cSrcweir 
2504cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
2505cdf0e10cSrcweir         // restore the features to make the font selection data unique
2506cdf0e10cSrcweir         rFSD.maTargetName = aOrigName;
2507cdf0e10cSrcweir #endif
2508cdf0e10cSrcweir         // check if the current font name token or its substitute is valid
2509cdf0e10cSrcweir         ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
2510cdf0e10cSrcweir         if( pFoundData )
2511cdf0e10cSrcweir             return pFoundData;
2512cdf0e10cSrcweir 
2513cdf0e10cSrcweir         // some systems provide special customization
2514cdf0e10cSrcweir         // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
2515cdf0e10cSrcweir         //      because the system wants to map it to another font first, e.g. "Helvetica"
2516cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
2517cdf0e10cSrcweir         // use the target name to search in the prematch hook
2518cdf0e10cSrcweir         rFSD.maTargetName = aBaseFontName;
2519cdf0e10cSrcweir #endif
2520cdf0e10cSrcweir         if( mpPreMatchHook )
2521cdf0e10cSrcweir             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
2522cdf0e10cSrcweir                 GetEnglishSearchFontName( aSearchName );
2523cdf0e10cSrcweir #ifdef ENABLE_GRAPHITE
2524cdf0e10cSrcweir         // the prematch hook uses the target name to search, but we now need
2525cdf0e10cSrcweir         // to restore the features to make the font selection data unique
2526cdf0e10cSrcweir         rFSD.maTargetName = aOrigName;
2527cdf0e10cSrcweir #endif
2528cdf0e10cSrcweir         pFoundData = ImplFindBySearchName( aSearchName );
2529cdf0e10cSrcweir         if( pFoundData )
2530cdf0e10cSrcweir             return pFoundData;
2531cdf0e10cSrcweir 
2532cdf0e10cSrcweir         // break after last font name token was checked unsuccessfully
2533cdf0e10cSrcweir         if( nTokenPos == STRING_NOTFOUND)
2534cdf0e10cSrcweir             break;
2535cdf0e10cSrcweir         bMultiToken = true;
2536cdf0e10cSrcweir     }
2537cdf0e10cSrcweir 
2538cdf0e10cSrcweir     // if the first font was not available find the next available font in
2539cdf0e10cSrcweir     // the semicolon separated list of font names. A font is also considered
2540cdf0e10cSrcweir     // available when there is a matching entry in the Tools->Options->Fonts
2541cdf0e10cSrcweir     // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution
2542cdf0e10cSrcweir     // font is available
2543cdf0e10cSrcweir     for( nTokenPos = 0; nTokenPos != STRING_NOTFOUND; )
2544cdf0e10cSrcweir     {
2545cdf0e10cSrcweir         if( bMultiToken )
2546cdf0e10cSrcweir         {
2547cdf0e10cSrcweir             rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
2548cdf0e10cSrcweir             aSearchName = rFSD.maTargetName;
2549cdf0e10cSrcweir             GetEnglishSearchFontName( aSearchName );
2550cdf0e10cSrcweir         }
2551cdf0e10cSrcweir         else
2552cdf0e10cSrcweir             nTokenPos = STRING_NOTFOUND;
2553cdf0e10cSrcweir         if( mpPreMatchHook )
2554cdf0e10cSrcweir             if( mpPreMatchHook->FindFontSubstitute( rFSD ) )
2555cdf0e10cSrcweir                 GetEnglishSearchFontName( aSearchName );
2556cdf0e10cSrcweir         ImplFontSubstitute( aSearchName, nSubstFlags, pDevSpecific );
2557cdf0e10cSrcweir         ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchName );
2558cdf0e10cSrcweir         if( pFoundData )
2559cdf0e10cSrcweir             return pFoundData;
2560cdf0e10cSrcweir     }
2561cdf0e10cSrcweir 
2562cdf0e10cSrcweir     // if no font with a directly matching name is available use the
2563cdf0e10cSrcweir     // first font name token and get its attributes to find a replacement
2564cdf0e10cSrcweir     if ( bMultiToken )
2565cdf0e10cSrcweir     {
2566cdf0e10cSrcweir         nTokenPos = 0;
2567cdf0e10cSrcweir         rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
2568cdf0e10cSrcweir         aSearchName = rFSD.maTargetName;
2569cdf0e10cSrcweir         GetEnglishSearchFontName( aSearchName );
2570cdf0e10cSrcweir     }
2571cdf0e10cSrcweir 
2572cdf0e10cSrcweir     String      aSearchShortName;
2573cdf0e10cSrcweir     String      aSearchFamilyName;
2574cdf0e10cSrcweir     FontWeight  eSearchWeight   = rFSD.meWeight;
2575cdf0e10cSrcweir     FontWidth   eSearchWidth    = rFSD.meWidthType;
2576cdf0e10cSrcweir     sal_uLong       nSearchType     = 0;
2577cdf0e10cSrcweir     FontSubstConfiguration::getMapName( aSearchName, aSearchShortName, aSearchFamilyName,
2578cdf0e10cSrcweir                                         eSearchWeight, eSearchWidth, nSearchType );
2579cdf0e10cSrcweir 
2580cdf0e10cSrcweir     // note: the search name was already translated to english (if possible)
2581cdf0e10cSrcweir 
2582cdf0e10cSrcweir     // use the font's shortened name if needed
2583cdf0e10cSrcweir     if ( aSearchShortName != aSearchName )
2584cdf0e10cSrcweir     {
2585cdf0e10cSrcweir        ImplDevFontListData* pFoundData = ImplFindBySearchName( aSearchShortName );
2586cdf0e10cSrcweir        if( pFoundData )
2587cdf0e10cSrcweir        {
2588cdf0e10cSrcweir #ifdef UNX
2589cdf0e10cSrcweir             /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
2590cdf0e10cSrcweir             a korean bitmap font that is not suitable here. Use the font replacement table,
2591cdf0e10cSrcweir             that automatically leads to the desired "HG Mincho Light J". Same story for
2592cdf0e10cSrcweir             MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
2593cdf0e10cSrcweir             static String aMS_Mincho( RTL_CONSTASCII_USTRINGPARAM("msmincho") );
2594cdf0e10cSrcweir             static String aMS_Gothic( RTL_CONSTASCII_USTRINGPARAM("msgothic") );
2595cdf0e10cSrcweir             if ((aSearchName != aMS_Mincho) && (aSearchName != aMS_Gothic))
2596cdf0e10cSrcweir                 // TODO: add heuristic to only throw out the fake ms* fonts
2597cdf0e10cSrcweir #endif
2598cdf0e10cSrcweir             {
2599cdf0e10cSrcweir                 return pFoundData;
2600cdf0e10cSrcweir             }
2601cdf0e10cSrcweir         }
2602cdf0e10cSrcweir     }
2603cdf0e10cSrcweir 
2604cdf0e10cSrcweir     // use font fallback
2605cdf0e10cSrcweir     const FontNameAttr* pFontAttr = NULL;
2606cdf0e10cSrcweir     if( aSearchName.Len() )
2607cdf0e10cSrcweir     {
2608cdf0e10cSrcweir         // get fallback info using FontSubstConfiguration and
2609cdf0e10cSrcweir         // the target name, it's shortened name and family name in that order
2610cdf0e10cSrcweir         const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
2611cdf0e10cSrcweir         pFontAttr = rFontSubst.getSubstInfo( aSearchName );
2612cdf0e10cSrcweir         if ( !pFontAttr && (aSearchShortName != aSearchName) )
2613cdf0e10cSrcweir             pFontAttr = rFontSubst.getSubstInfo( aSearchShortName );
2614cdf0e10cSrcweir         if ( !pFontAttr && (aSearchFamilyName != aSearchShortName) )
2615cdf0e10cSrcweir             pFontAttr = rFontSubst.getSubstInfo( aSearchFamilyName );
2616cdf0e10cSrcweir 
2617cdf0e10cSrcweir         // try the font substitutions suggested by the fallback info
2618cdf0e10cSrcweir         if( pFontAttr )
2619cdf0e10cSrcweir         {
2620cdf0e10cSrcweir             ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pFontAttr );
2621cdf0e10cSrcweir             if( pFoundData )
2622cdf0e10cSrcweir                 return pFoundData;
2623cdf0e10cSrcweir         }
2624cdf0e10cSrcweir     }
2625cdf0e10cSrcweir 
2626cdf0e10cSrcweir     // if a target symbol font is not available use a default symbol font
2627cdf0e10cSrcweir     if( rFSD.IsSymbolFont() )
2628cdf0e10cSrcweir     {
2629cdf0e10cSrcweir         com::sun::star::lang::Locale aDefaultLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
2630cdf0e10cSrcweir         aSearchName = DefaultFontConfiguration::get()->getDefaultFont( aDefaultLocale, DEFAULTFONT_SYMBOL );
2631cdf0e10cSrcweir         ImplDevFontListData* pFoundData = ImplFindByTokenNames( aSearchName );
2632cdf0e10cSrcweir         if( pFoundData )
2633cdf0e10cSrcweir             return pFoundData;
2634cdf0e10cSrcweir     }
2635cdf0e10cSrcweir 
2636cdf0e10cSrcweir     // now try the other font name tokens
2637cdf0e10cSrcweir     while( nTokenPos != STRING_NOTFOUND )
2638cdf0e10cSrcweir     {
2639cdf0e10cSrcweir         rFSD.maTargetName = GetNextFontToken( rFSD.maName, nTokenPos );
2640cdf0e10cSrcweir         if( !rFSD.maTargetName.Len() )
2641cdf0e10cSrcweir             continue;
2642cdf0e10cSrcweir 
2643cdf0e10cSrcweir         aSearchName = rFSD.maTargetName;
2644cdf0e10cSrcweir         GetEnglishSearchFontName( aSearchName );
2645cdf0e10cSrcweir 
2646cdf0e10cSrcweir         String      aTempShortName;
2647cdf0e10cSrcweir         String      aTempFamilyName;
2648cdf0e10cSrcweir         sal_uLong       nTempType   = 0;
2649cdf0e10cSrcweir         FontWeight  eTempWeight = rFSD.meWeight;
2650cdf0e10cSrcweir         FontWidth   eTempWidth  = WIDTH_DONTKNOW;
2651cdf0e10cSrcweir         FontSubstConfiguration::getMapName( aSearchName, aTempShortName, aTempFamilyName,
2652cdf0e10cSrcweir                                             eTempWeight, eTempWidth, nTempType );
2653cdf0e10cSrcweir 
2654cdf0e10cSrcweir         // use a shortend token name if available
2655cdf0e10cSrcweir         if( aTempShortName != aSearchName )
2656cdf0e10cSrcweir         {
2657cdf0e10cSrcweir             ImplDevFontListData* pFoundData = ImplFindBySearchName( aTempShortName );
2658cdf0e10cSrcweir             if( pFoundData )
2659cdf0e10cSrcweir                 return pFoundData;
2660cdf0e10cSrcweir         }
2661cdf0e10cSrcweir 
2662cdf0e10cSrcweir         // use a font name from font fallback list to determine font attributes
2663cdf0e10cSrcweir 
2664cdf0e10cSrcweir         // get fallback info using FontSubstConfiguration and
2665cdf0e10cSrcweir         // the target name, it's shortened name and family name in that order
2666cdf0e10cSrcweir         const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
2667cdf0e10cSrcweir         const FontNameAttr* pTempFontAttr = rFontSubst.getSubstInfo( aSearchName );
2668cdf0e10cSrcweir         if ( !pTempFontAttr && (aTempShortName != aSearchName) )
2669cdf0e10cSrcweir             pTempFontAttr = rFontSubst.getSubstInfo( aTempShortName );
2670cdf0e10cSrcweir         if ( !pTempFontAttr && (aTempFamilyName != aTempShortName) )
2671cdf0e10cSrcweir             pTempFontAttr = rFontSubst.getSubstInfo( aTempFamilyName );
2672cdf0e10cSrcweir 
2673cdf0e10cSrcweir         // try the font substitutions suggested by the fallback info
2674cdf0e10cSrcweir         if( pTempFontAttr )
2675cdf0e10cSrcweir         {
2676cdf0e10cSrcweir             ImplDevFontListData* pFoundData = ImplFindBySubstFontAttr( *pTempFontAttr );
2677cdf0e10cSrcweir             if( pFoundData )
2678cdf0e10cSrcweir                 return pFoundData;
2679cdf0e10cSrcweir             if( !pFontAttr )
2680cdf0e10cSrcweir                 pFontAttr = pTempFontAttr;
2681cdf0e10cSrcweir         }
2682cdf0e10cSrcweir     }
2683cdf0e10cSrcweir 
2684cdf0e10cSrcweir     // if still needed use the alias names of the installed fonts
2685cdf0e10cSrcweir     if( mbMapNames )
2686cdf0e10cSrcweir     {
2687cdf0e10cSrcweir         ImplDevFontListData* pFoundData = ImplFindByAliasName( rFSD.maTargetName, aSearchShortName );
2688cdf0e10cSrcweir         if( pFoundData )
2689cdf0e10cSrcweir             return pFoundData;
2690cdf0e10cSrcweir     }
2691cdf0e10cSrcweir 
2692cdf0e10cSrcweir     // if still needed use the font request's attributes to find a good match
2693cdf0e10cSrcweir     switch( rFSD.meLanguage )
2694cdf0e10cSrcweir     {
2695cdf0e10cSrcweir         case LANGUAGE_CHINESE:
2696cdf0e10cSrcweir         case LANGUAGE_CHINESE_SIMPLIFIED:
2697cdf0e10cSrcweir         case LANGUAGE_CHINESE_SINGAPORE:
2698cdf0e10cSrcweir             nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_SC;
2699cdf0e10cSrcweir             break;
2700cdf0e10cSrcweir         case LANGUAGE_CHINESE_TRADITIONAL:
2701cdf0e10cSrcweir         case LANGUAGE_CHINESE_HONGKONG:
2702cdf0e10cSrcweir         case LANGUAGE_CHINESE_MACAU:
2703cdf0e10cSrcweir             nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_TC;
2704cdf0e10cSrcweir             break;
2705cdf0e10cSrcweir         case LANGUAGE_KOREAN:
2706cdf0e10cSrcweir         case LANGUAGE_KOREAN_JOHAB:
2707cdf0e10cSrcweir             nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_KR;
2708cdf0e10cSrcweir             break;
2709cdf0e10cSrcweir         case LANGUAGE_JAPANESE:
2710cdf0e10cSrcweir             nSearchType |= IMPL_FONT_ATTR_CJK | IMPL_FONT_ATTR_CJK_JP;
2711cdf0e10cSrcweir             break;
2712cdf0e10cSrcweir         default:
2713cdf0e10cSrcweir             nSearchType |= ImplIsCJKFont( rFSD.maName );
2714cdf0e10cSrcweir             if( rFSD.IsSymbolFont() )
2715cdf0e10cSrcweir                 nSearchType |= IMPL_FONT_ATTR_SYMBOL;
2716cdf0e10cSrcweir             break;
2717cdf0e10cSrcweir     }
2718cdf0e10cSrcweir 
2719cdf0e10cSrcweir     ImplCalcType( nSearchType, eSearchWeight, eSearchWidth, rFSD.meFamily, pFontAttr );
2720cdf0e10cSrcweir     ImplDevFontListData* pFoundData = ImplFindByAttributes( nSearchType,
2721cdf0e10cSrcweir         eSearchWeight, eSearchWidth, rFSD.meFamily, rFSD.meItalic, aSearchFamilyName );
2722cdf0e10cSrcweir 
2723cdf0e10cSrcweir     if( pFoundData )
2724cdf0e10cSrcweir     {
2725cdf0e10cSrcweir         // overwrite font selection attributes using info from the typeface flags
2726cdf0e10cSrcweir         if( (eSearchWeight >= WEIGHT_BOLD)
2727cdf0e10cSrcweir         &&  (eSearchWeight > rFSD.meWeight)
2728cdf0e10cSrcweir         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_BOLD) )
2729cdf0e10cSrcweir             rFSD.meWeight = eSearchWeight;
2730cdf0e10cSrcweir         else if( (eSearchWeight < WEIGHT_NORMAL)
2731cdf0e10cSrcweir         &&  (eSearchWeight < rFSD.meWeight)
2732cdf0e10cSrcweir         &&  (eSearchWeight != WEIGHT_DONTKNOW)
2733cdf0e10cSrcweir         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_LIGHT) )
2734cdf0e10cSrcweir             rFSD.meWeight = eSearchWeight;
2735cdf0e10cSrcweir 
2736cdf0e10cSrcweir         if( (nSearchType & IMPL_FONT_ATTR_ITALIC)
2737cdf0e10cSrcweir         &&  ((rFSD.meItalic == ITALIC_DONTKNOW) || (rFSD.meItalic == ITALIC_NONE))
2738cdf0e10cSrcweir         &&  (pFoundData->mnTypeFaces & IMPL_DEVFONT_ITALIC) )
2739cdf0e10cSrcweir             rFSD.meItalic = ITALIC_NORMAL;
2740cdf0e10cSrcweir     }
2741cdf0e10cSrcweir     else
2742cdf0e10cSrcweir     {
2743cdf0e10cSrcweir         // if still needed fall back to default fonts
2744cdf0e10cSrcweir         pFoundData = FindDefaultFont();
2745cdf0e10cSrcweir     }
2746cdf0e10cSrcweir 
2747cdf0e10cSrcweir     return pFoundData;
2748cdf0e10cSrcweir }
2749cdf0e10cSrcweir 
2750cdf0e10cSrcweir // -----------------------------------------------------------------------
2751cdf0e10cSrcweir 
2752cdf0e10cSrcweir ImplFontEntry* ImplFontCache::GetGlyphFallbackFont( ImplDevFontList* pFontList,
2753cdf0e10cSrcweir     ImplFontSelectData& rFontSelData, int nFallbackLevel, rtl::OUString& rMissingCodes )
2754cdf0e10cSrcweir {
2755cdf0e10cSrcweir     // get a candidate font for glyph fallback
2756cdf0e10cSrcweir     // unless the previously selected font got a device specific substitution
2757cdf0e10cSrcweir     // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
2758cdf0e10cSrcweir     if( nFallbackLevel >= 1)
2759cdf0e10cSrcweir     {
2760cdf0e10cSrcweir         ImplDevFontListData* pFallbackData = pFontList->GetGlyphFallbackFont(
2761cdf0e10cSrcweir             rFontSelData, rMissingCodes, nFallbackLevel-1 );
2762cdf0e10cSrcweir         // escape when there are no font candidates
2763cdf0e10cSrcweir         if( !pFallbackData  )
2764cdf0e10cSrcweir             return NULL;
2765cdf0e10cSrcweir         // override the font name
2766cdf0e10cSrcweir         rFontSelData.maName = pFallbackData->GetFamilyName();
2767cdf0e10cSrcweir         // clear the cached normalized name
2768cdf0e10cSrcweir         rFontSelData.maSearchName = String();
2769cdf0e10cSrcweir     }
2770cdf0e10cSrcweir 
2771cdf0e10cSrcweir     // get device font without doing device specific substitutions
2772cdf0e10cSrcweir     ImplFontEntry* pFallbackFont = GetFontEntry( pFontList, rFontSelData, NULL );
2773cdf0e10cSrcweir     return pFallbackFont;
2774cdf0e10cSrcweir }
2775cdf0e10cSrcweir 
2776cdf0e10cSrcweir // -----------------------------------------------------------------------
2777cdf0e10cSrcweir 
2778cdf0e10cSrcweir void ImplFontCache::Release( ImplFontEntry* pEntry )
2779cdf0e10cSrcweir {
2780cdf0e10cSrcweir     static const int FONTCACHE_MAX = 50;
2781cdf0e10cSrcweir 
2782cdf0e10cSrcweir     DBG_ASSERT( (pEntry->mnRefCount > 0), "ImplFontCache::Release() - font refcount underflow" );
2783cdf0e10cSrcweir     if( --pEntry->mnRefCount > 0 )
2784cdf0e10cSrcweir         return;
2785cdf0e10cSrcweir 
2786cdf0e10cSrcweir     if( ++mnRef0Count < FONTCACHE_MAX )
2787cdf0e10cSrcweir         return;
2788cdf0e10cSrcweir 
2789cdf0e10cSrcweir     // remove unused entries from font instance cache
2790cdf0e10cSrcweir     FontInstanceList::iterator it_next = maFontInstanceList.begin();
2791cdf0e10cSrcweir     while( it_next != maFontInstanceList.end() )
2792cdf0e10cSrcweir     {
2793cdf0e10cSrcweir         FontInstanceList::iterator it = it_next++;
2794cdf0e10cSrcweir         ImplFontEntry* pFontEntry = (*it).second;
2795cdf0e10cSrcweir         if( pFontEntry->mnRefCount > 0 )
2796cdf0e10cSrcweir             continue;
2797cdf0e10cSrcweir 
2798cdf0e10cSrcweir         maFontInstanceList.erase( it );
2799cdf0e10cSrcweir         delete pFontEntry;
2800cdf0e10cSrcweir         --mnRef0Count;
2801cdf0e10cSrcweir         DBG_ASSERT( (mnRef0Count>=0), "ImplFontCache::Release() - refcount0 underflow" );
2802cdf0e10cSrcweir 
2803cdf0e10cSrcweir         if( mpFirstEntry == pFontEntry )
2804cdf0e10cSrcweir             mpFirstEntry = NULL;
2805cdf0e10cSrcweir     }
2806cdf0e10cSrcweir 
2807cdf0e10cSrcweir     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Release() - refcount0 mismatch" );
2808cdf0e10cSrcweir }
2809cdf0e10cSrcweir 
2810cdf0e10cSrcweir // -----------------------------------------------------------------------
2811cdf0e10cSrcweir 
2812cdf0e10cSrcweir void ImplFontCache::Invalidate()
2813cdf0e10cSrcweir {
2814cdf0e10cSrcweir     // delete unreferenced entries
2815cdf0e10cSrcweir     FontInstanceList::iterator it = maFontInstanceList.begin();
2816cdf0e10cSrcweir     for(; it != maFontInstanceList.end(); ++it )
2817cdf0e10cSrcweir     {
2818cdf0e10cSrcweir         ImplFontEntry* pFontEntry = (*it).second;
2819cdf0e10cSrcweir         if( pFontEntry->mnRefCount > 0 )
2820cdf0e10cSrcweir             continue;
2821cdf0e10cSrcweir 
2822cdf0e10cSrcweir         delete pFontEntry;
2823cdf0e10cSrcweir         --mnRef0Count;
2824cdf0e10cSrcweir     }
2825cdf0e10cSrcweir 
2826cdf0e10cSrcweir     // #112304# make sure the font cache is really clean
2827cdf0e10cSrcweir     mpFirstEntry = NULL;
2828cdf0e10cSrcweir     maFontInstanceList.clear();
2829cdf0e10cSrcweir 
2830cdf0e10cSrcweir     DBG_ASSERT( (mnRef0Count==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
2831cdf0e10cSrcweir 
2832cdf0e10cSrcweir #ifdef USE_BUILTIN_RASTERIZER
2833cdf0e10cSrcweir     // TODO: eventually move into SalGraphics layer
2834cdf0e10cSrcweir     GlyphCache::GetInstance().InvalidateAllGlyphs();
2835cdf0e10cSrcweir #endif
2836cdf0e10cSrcweir }
2837cdf0e10cSrcweir 
2838cdf0e10cSrcweir // =======================================================================
2839cdf0e10cSrcweir 
2840cdf0e10cSrcweir ImplMultiTextLineInfo::ImplMultiTextLineInfo()
2841cdf0e10cSrcweir {
2842cdf0e10cSrcweir     mpLines = new PImplTextLineInfo[MULTITEXTLINEINFO_RESIZE];
2843cdf0e10cSrcweir     mnLines = 0;
2844cdf0e10cSrcweir     mnSize  = MULTITEXTLINEINFO_RESIZE;
2845cdf0e10cSrcweir }
2846cdf0e10cSrcweir 
2847cdf0e10cSrcweir 
2848cdf0e10cSrcweir ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
2849cdf0e10cSrcweir {
2850cdf0e10cSrcweir     for ( xub_StrLen i = 0; i < mnLines; i++ )
2851cdf0e10cSrcweir         delete mpLines[i];
2852cdf0e10cSrcweir     delete [] mpLines;
2853cdf0e10cSrcweir }
2854cdf0e10cSrcweir 
2855cdf0e10cSrcweir void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo* pLine )
2856cdf0e10cSrcweir {
2857cdf0e10cSrcweir     if ( mnSize == mnLines )
2858cdf0e10cSrcweir     {
2859cdf0e10cSrcweir         mnSize += MULTITEXTLINEINFO_RESIZE;
2860cdf0e10cSrcweir         PImplTextLineInfo* pNewLines = new PImplTextLineInfo[mnSize];
2861cdf0e10cSrcweir         memcpy( pNewLines, mpLines, mnLines*sizeof(PImplTextLineInfo) );
2862cdf0e10cSrcweir         mpLines = pNewLines;
2863cdf0e10cSrcweir     }
2864cdf0e10cSrcweir 
2865cdf0e10cSrcweir     mpLines[mnLines] = pLine;
2866cdf0e10cSrcweir     mnLines++;
2867cdf0e10cSrcweir }
2868cdf0e10cSrcweir 
2869cdf0e10cSrcweir void ImplMultiTextLineInfo::Clear()
2870cdf0e10cSrcweir {
2871cdf0e10cSrcweir     for ( xub_StrLen i = 0; i < mnLines; i++ )
2872cdf0e10cSrcweir         delete mpLines[i];
2873cdf0e10cSrcweir     mnLines = 0;
2874cdf0e10cSrcweir }
2875cdf0e10cSrcweir 
2876cdf0e10cSrcweir // =======================================================================
2877cdf0e10cSrcweir 
2878cdf0e10cSrcweir FontEmphasisMark OutputDevice::ImplGetEmphasisMarkStyle( const Font& rFont )
2879cdf0e10cSrcweir {
2880cdf0e10cSrcweir     FontEmphasisMark nEmphasisMark = rFont.GetEmphasisMark();
2881cdf0e10cSrcweir 
2882cdf0e10cSrcweir     // If no Position is set, then calculate the default position, which
2883cdf0e10cSrcweir     // depends on the language
2884cdf0e10cSrcweir     if ( !(nEmphasisMark & (EMPHASISMARK_POS_ABOVE | EMPHASISMARK_POS_BELOW)) )
2885cdf0e10cSrcweir     {
2886cdf0e10cSrcweir         LanguageType eLang = rFont.GetLanguage();
2887cdf0e10cSrcweir         // In Chinese Simplified the EmphasisMarks are below/left
2888cdf0e10cSrcweir         if ( (eLang == LANGUAGE_CHINESE_SIMPLIFIED) ||
2889cdf0e10cSrcweir              (eLang == LANGUAGE_CHINESE_SINGAPORE) )
2890cdf0e10cSrcweir             nEmphasisMark |= EMPHASISMARK_POS_BELOW;
2891cdf0e10cSrcweir         else
2892cdf0e10cSrcweir         {
2893cdf0e10cSrcweir             eLang = rFont.GetCJKContextLanguage();
2894cdf0e10cSrcweir             // In Chinese Simplified the EmphasisMarks are below/left
2895cdf0e10cSrcweir             if ( (eLang == LANGUAGE_CHINESE_SIMPLIFIED) ||
2896cdf0e10cSrcweir                  (eLang == LANGUAGE_CHINESE_SINGAPORE) )
2897cdf0e10cSrcweir                 nEmphasisMark |= EMPHASISMARK_POS_BELOW;
2898cdf0e10cSrcweir             else
2899cdf0e10cSrcweir                 nEmphasisMark |= EMPHASISMARK_POS_ABOVE;
2900cdf0e10cSrcweir         }
2901cdf0e10cSrcweir     }
2902cdf0e10cSrcweir 
2903cdf0e10cSrcweir     return nEmphasisMark;
2904cdf0e10cSrcweir }
2905cdf0e10cSrcweir 
2906cdf0e10cSrcweir // -----------------------------------------------------------------------
2907cdf0e10cSrcweir 
2908cdf0e10cSrcweir sal_Bool OutputDevice::ImplIsUnderlineAbove( const Font& rFont )
2909cdf0e10cSrcweir {
2910cdf0e10cSrcweir     if ( !rFont.IsVertical() )
2911cdf0e10cSrcweir         return sal_False;
2912cdf0e10cSrcweir 
2913cdf0e10cSrcweir     if( (LANGUAGE_JAPANESE == rFont.GetLanguage())
2914cdf0e10cSrcweir     ||  (LANGUAGE_JAPANESE == rFont.GetCJKContextLanguage()) )
2915cdf0e10cSrcweir         // the underline is right for Japanese only
2916cdf0e10cSrcweir         return sal_True;
2917cdf0e10cSrcweir 
2918cdf0e10cSrcweir     return sal_False;
2919cdf0e10cSrcweir }
2920cdf0e10cSrcweir 
2921cdf0e10cSrcweir // =======================================================================
2922cdf0e10cSrcweir 
2923cdf0e10cSrcweir void OutputDevice::ImplInitFontList() const
2924cdf0e10cSrcweir {
2925cdf0e10cSrcweir     if( ! mpFontList->Count() )
2926cdf0e10cSrcweir     {
2927cdf0e10cSrcweir         if( mpGraphics || ImplGetGraphics() )
2928cdf0e10cSrcweir         {
2929cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "OutputDevice::ImplInitFontList()" );
2930cdf0e10cSrcweir             mpGraphics->GetDevFontList( mpFontList );
2931cdf0e10cSrcweir         }
2932cdf0e10cSrcweir     }
2933cdf0e10cSrcweir     if( meOutDevType == OUTDEV_WINDOW && ! mpFontList->Count() )
2934cdf0e10cSrcweir     {
2935cdf0e10cSrcweir         String aError( RTL_CONSTASCII_USTRINGPARAM( "Application error: no fonts and no vcl resource found on your system" ) );
2936cdf0e10cSrcweir         ResMgr* pMgr = ImplGetResMgr();
2937cdf0e10cSrcweir         if( pMgr )
2938cdf0e10cSrcweir         {
2939cdf0e10cSrcweir             String aResStr( ResId( SV_ACCESSERROR_NO_FONTS, *pMgr ) );
2940cdf0e10cSrcweir             if( aResStr.Len() )
2941cdf0e10cSrcweir                 aError = aResStr;
2942cdf0e10cSrcweir         }
2943cdf0e10cSrcweir         Application::Abort( aError );
2944cdf0e10cSrcweir     }
2945cdf0e10cSrcweir }
2946cdf0e10cSrcweir 
2947cdf0e10cSrcweir // =======================================================================
2948cdf0e10cSrcweir 
2949cdf0e10cSrcweir void OutputDevice::ImplInitFont() const
2950cdf0e10cSrcweir {
2951cdf0e10cSrcweir     DBG_TESTSOLARMUTEX();
2952cdf0e10cSrcweir 
2953cdf0e10cSrcweir     if ( mbInitFont )
2954cdf0e10cSrcweir     {
2955cdf0e10cSrcweir         if ( meOutDevType != OUTDEV_PRINTER )
2956cdf0e10cSrcweir         {
2957cdf0e10cSrcweir             // decide if antialiasing is appropriate
2958cdf0e10cSrcweir             bool bNonAntialiased = (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT) != 0;
2959cdf0e10cSrcweir             const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
2960cdf0e10cSrcweir             bNonAntialiased |= ((rStyleSettings.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE) != 0);
2961cdf0e10cSrcweir             bNonAntialiased |= (int(rStyleSettings.GetAntialiasingMinPixelHeight()) > mpFontEntry->maFontSelData.mnHeight);
2962cdf0e10cSrcweir             mpFontEntry->maFontSelData.mbNonAntialiased = bNonAntialiased;
2963cdf0e10cSrcweir         }
2964cdf0e10cSrcweir 
2965cdf0e10cSrcweir         if( !mpPDFWriter || !mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
2966cdf0e10cSrcweir         {
2967cdf0e10cSrcweir             // select font in the device layers
2968cdf0e10cSrcweir             mpFontEntry->mnSetFontFlags = mpGraphics->SetFont( &(mpFontEntry->maFontSelData), 0 );
2969cdf0e10cSrcweir         }
2970cdf0e10cSrcweir         mbInitFont = false;
2971cdf0e10cSrcweir     }
2972cdf0e10cSrcweir }
2973cdf0e10cSrcweir 
2974cdf0e10cSrcweir // -----------------------------------------------------------------------
2975cdf0e10cSrcweir 
2976cdf0e10cSrcweir void OutputDevice::ImplInitTextColor()
2977cdf0e10cSrcweir {
2978cdf0e10cSrcweir     DBG_TESTSOLARMUTEX();
2979cdf0e10cSrcweir 
2980cdf0e10cSrcweir     if ( mbInitTextColor )
2981cdf0e10cSrcweir     {
2982cdf0e10cSrcweir         mpGraphics->SetTextColor( ImplColorToSal( GetTextColor() ) );
2983cdf0e10cSrcweir         mbInitTextColor = sal_False;
2984cdf0e10cSrcweir     }
2985cdf0e10cSrcweir }
2986cdf0e10cSrcweir 
2987cdf0e10cSrcweir // -----------------------------------------------------------------------
2988cdf0e10cSrcweir 
2989cdf0e10cSrcweir bool OutputDevice::ImplNewFont() const
2990cdf0e10cSrcweir {
2991cdf0e10cSrcweir     DBG_TESTSOLARMUTEX();
2992cdf0e10cSrcweir 
2993cdf0e10cSrcweir     // get correct font list on the PDF writer if necessary
2994cdf0e10cSrcweir     if( mpPDFWriter )
2995cdf0e10cSrcweir     {
2996cdf0e10cSrcweir         const ImplSVData* pSVData = ImplGetSVData();
2997cdf0e10cSrcweir         if( mpFontList == pSVData->maGDIData.mpScreenFontList
2998cdf0e10cSrcweir         ||  mpFontCache == pSVData->maGDIData.mpScreenFontCache )
2999cdf0e10cSrcweir             const_cast<OutputDevice&>(*this).ImplUpdateFontData( true );
3000cdf0e10cSrcweir     }
3001cdf0e10cSrcweir 
3002cdf0e10cSrcweir     if ( !mbNewFont )
3003cdf0e10cSrcweir         return true;
3004cdf0e10cSrcweir 
3005cdf0e10cSrcweir     // we need a graphics
3006cdf0e10cSrcweir     if ( !mpGraphics && !ImplGetGraphics() )
3007cdf0e10cSrcweir         return false;
3008cdf0e10cSrcweir     SalGraphics* pGraphics = mpGraphics;
3009cdf0e10cSrcweir     ImplInitFontList();
3010cdf0e10cSrcweir 
3011cdf0e10cSrcweir     // convert to pixel height
3012cdf0e10cSrcweir     // TODO: replace integer based aSize completely with subpixel accurate type
3013cdf0e10cSrcweir     float fExactHeight = ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont.GetHeight()) );
3014cdf0e10cSrcweir     Size aSize = ImplLogicToDevicePixel( maFont.GetSize() );
3015cdf0e10cSrcweir     if ( !aSize.Height() )
3016cdf0e10cSrcweir     {
3017cdf0e10cSrcweir         // use default pixel height only when logical height is zero
3018cdf0e10cSrcweir         if ( maFont.GetSize().Height() )
3019cdf0e10cSrcweir             aSize.Height() = 1;
3020cdf0e10cSrcweir         else
3021cdf0e10cSrcweir             aSize.Height() = (12*mnDPIY)/72;
3022cdf0e10cSrcweir         fExactHeight =  static_cast<float>(aSize.Height());
3023cdf0e10cSrcweir     }
3024cdf0e10cSrcweir 
3025cdf0e10cSrcweir     // select the default width only when logical width is zero
3026cdf0e10cSrcweir     if( (0 == aSize.Width()) && (0 != maFont.GetSize().Width()) )
3027cdf0e10cSrcweir         aSize.Width() = 1;
3028cdf0e10cSrcweir 
3029cdf0e10cSrcweir     // get font entry
3030cdf0e10cSrcweir     ImplDirectFontSubstitution* pDevSpecificSubst = NULL;
3031cdf0e10cSrcweir     if( mpOutDevData )
3032cdf0e10cSrcweir         pDevSpecificSubst = &mpOutDevData->maDevFontSubst;
3033cdf0e10cSrcweir     ImplFontEntry* pOldEntry = mpFontEntry;
3034cdf0e10cSrcweir     mpFontEntry = mpFontCache->GetFontEntry( mpFontList, maFont, aSize, fExactHeight, pDevSpecificSubst );
3035cdf0e10cSrcweir     if( pOldEntry )
3036cdf0e10cSrcweir         mpFontCache->Release( pOldEntry );
3037cdf0e10cSrcweir 
3038cdf0e10cSrcweir     ImplFontEntry* pFontEntry = mpFontEntry;
3039cdf0e10cSrcweir     // mark when lower layers need to get involved
3040cdf0e10cSrcweir     mbNewFont = sal_False;
3041cdf0e10cSrcweir     if( pFontEntry != pOldEntry )
3042cdf0e10cSrcweir         mbInitFont = sal_True;
3043cdf0e10cSrcweir 
3044cdf0e10cSrcweir     // select font when it has not been initialized yet
3045cdf0e10cSrcweir     if ( !pFontEntry->mbInit )
3046cdf0e10cSrcweir     {
3047cdf0e10cSrcweir         ImplInitFont();
3048cdf0e10cSrcweir 
3049cdf0e10cSrcweir         // get metric data from device layers
3050cdf0e10cSrcweir         if ( pGraphics )
3051cdf0e10cSrcweir         {
3052cdf0e10cSrcweir             pFontEntry->mbInit = true;
3053cdf0e10cSrcweir 
3054cdf0e10cSrcweir             pFontEntry->maMetric.mnOrientation  = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
3055cdf0e10cSrcweir             if( mpPDFWriter && mpPDFWriter->isBuiltinFont( pFontEntry->maFontSelData.mpFontData ) )
3056cdf0e10cSrcweir                 mpPDFWriter->getFontMetric( &pFontEntry->maFontSelData, &(pFontEntry->maMetric) );
3057cdf0e10cSrcweir             else
3058cdf0e10cSrcweir                 pGraphics->GetFontMetric( &(pFontEntry->maMetric) );
3059cdf0e10cSrcweir 
3060cdf0e10cSrcweir             pFontEntry->maMetric.ImplInitTextLineSize( this );
3061cdf0e10cSrcweir             pFontEntry->maMetric.ImplInitAboveTextLineSize();
3062cdf0e10cSrcweir 
3063cdf0e10cSrcweir             pFontEntry->mnLineHeight = pFontEntry->maMetric.mnAscent + pFontEntry->maMetric.mnDescent;
3064cdf0e10cSrcweir 
3065cdf0e10cSrcweir             if( pFontEntry->maFontSelData.mnOrientation
3066cdf0e10cSrcweir             && !pFontEntry->maMetric.mnOrientation
3067cdf0e10cSrcweir             && (meOutDevType != OUTDEV_PRINTER) )
3068cdf0e10cSrcweir             {
3069cdf0e10cSrcweir                 pFontEntry->mnOwnOrientation = sal::static_int_cast<short>(pFontEntry->maFontSelData.mnOrientation);
3070cdf0e10cSrcweir                 pFontEntry->mnOrientation = pFontEntry->mnOwnOrientation;
3071cdf0e10cSrcweir             }
3072cdf0e10cSrcweir             else
3073cdf0e10cSrcweir                 pFontEntry->mnOrientation = pFontEntry->maMetric.mnOrientation;
3074cdf0e10cSrcweir         }
3075cdf0e10cSrcweir     }
3076cdf0e10cSrcweir 
3077cdf0e10cSrcweir     // enable kerning array if requested
3078cdf0e10cSrcweir     if ( maFont.GetKerning() & KERNING_FONTSPECIFIC )
3079cdf0e10cSrcweir     {
3080cdf0e10cSrcweir         // TODO: test if physical font supports kerning and disable if not
3081cdf0e10cSrcweir         if( pFontEntry->maMetric.mbKernableFont )
3082cdf0e10cSrcweir             mbKerning = true;
3083cdf0e10cSrcweir     }
3084cdf0e10cSrcweir     else
3085cdf0e10cSrcweir         mbKerning = false;
3086cdf0e10cSrcweir     if ( maFont.GetKerning() & KERNING_ASIAN )
3087cdf0e10cSrcweir         mbKerning = true;
3088cdf0e10cSrcweir 
3089cdf0e10cSrcweir     // calculate EmphasisArea
3090cdf0e10cSrcweir     mnEmphasisAscent = 0;
3091cdf0e10cSrcweir     mnEmphasisDescent = 0;
3092cdf0e10cSrcweir     if ( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
3093cdf0e10cSrcweir     {
3094cdf0e10cSrcweir         FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
3095cdf0e10cSrcweir         long                nEmphasisHeight = (pFontEntry->mnLineHeight*250)/1000;
3096cdf0e10cSrcweir         if ( nEmphasisHeight < 1 )
3097cdf0e10cSrcweir             nEmphasisHeight = 1;
3098cdf0e10cSrcweir         if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
3099cdf0e10cSrcweir             mnEmphasisDescent = nEmphasisHeight;
3100cdf0e10cSrcweir         else
3101cdf0e10cSrcweir             mnEmphasisAscent = nEmphasisHeight;
3102cdf0e10cSrcweir     }
3103cdf0e10cSrcweir 
3104cdf0e10cSrcweir     // calculate text offset depending on TextAlignment
3105cdf0e10cSrcweir     TextAlign eAlign = maFont.GetAlign();
3106cdf0e10cSrcweir     if ( eAlign == ALIGN_BASELINE )
3107cdf0e10cSrcweir     {
3108cdf0e10cSrcweir         mnTextOffX = 0;
3109cdf0e10cSrcweir         mnTextOffY = 0;
3110cdf0e10cSrcweir     }
3111cdf0e10cSrcweir     else if ( eAlign == ALIGN_TOP )
3112cdf0e10cSrcweir     {
3113cdf0e10cSrcweir         mnTextOffX = 0;
3114cdf0e10cSrcweir         mnTextOffY = +pFontEntry->maMetric.mnAscent + mnEmphasisAscent;
3115cdf0e10cSrcweir         if ( pFontEntry->mnOrientation )
3116cdf0e10cSrcweir             ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
3117cdf0e10cSrcweir     }
3118cdf0e10cSrcweir     else // eAlign == ALIGN_BOTTOM
3119cdf0e10cSrcweir     {
3120cdf0e10cSrcweir         mnTextOffX = 0;
3121cdf0e10cSrcweir         mnTextOffY = -pFontEntry->maMetric.mnDescent + mnEmphasisDescent;
3122cdf0e10cSrcweir         if ( pFontEntry->mnOrientation )
3123cdf0e10cSrcweir             ImplRotatePos( 0, 0, mnTextOffX, mnTextOffY, pFontEntry->mnOrientation );
3124cdf0e10cSrcweir     }
3125cdf0e10cSrcweir 
3126cdf0e10cSrcweir     mbTextLines     = ((maFont.GetUnderline() != UNDERLINE_NONE) && (maFont.GetUnderline() != UNDERLINE_DONTKNOW)) ||
3127cdf0e10cSrcweir                       ((maFont.GetOverline()  != UNDERLINE_NONE) && (maFont.GetOverline()  != UNDERLINE_DONTKNOW)) ||
3128cdf0e10cSrcweir                       ((maFont.GetStrikeout() != STRIKEOUT_NONE) && (maFont.GetStrikeout() != STRIKEOUT_DONTKNOW));
3129cdf0e10cSrcweir     mbTextSpecial   = maFont.IsShadow() || maFont.IsOutline() ||
3130cdf0e10cSrcweir                       (maFont.GetRelief() != RELIEF_NONE);
3131cdf0e10cSrcweir 
3132cdf0e10cSrcweir     // #95414# fix for OLE objects which use scale factors very creatively
3133cdf0e10cSrcweir     if( mbMap && !aSize.Width() )
3134cdf0e10cSrcweir     {
3135cdf0e10cSrcweir         int nOrigWidth = pFontEntry->maMetric.mnWidth;
3136cdf0e10cSrcweir         float fStretch = (float)maMapRes.mnMapScNumX * maMapRes.mnMapScDenomY;
3137cdf0e10cSrcweir         fStretch /= (float)maMapRes.mnMapScNumY * maMapRes.mnMapScDenomX;
3138cdf0e10cSrcweir         int nNewWidth = (int)(nOrigWidth * fStretch + 0.5);
3139cdf0e10cSrcweir         if( (nNewWidth != nOrigWidth) && (nNewWidth != 0) )
3140cdf0e10cSrcweir         {
3141cdf0e10cSrcweir             Size aOrigSize = maFont.GetSize();
3142cdf0e10cSrcweir             const_cast<Font&>(maFont).SetSize( Size( nNewWidth, aSize.Height() ) );
3143cdf0e10cSrcweir             mbMap = sal_False;
3144cdf0e10cSrcweir             mbNewFont = sal_True;
3145cdf0e10cSrcweir             ImplNewFont();  // recurse once using stretched width
3146cdf0e10cSrcweir             mbMap = sal_True;
3147cdf0e10cSrcweir             const_cast<Font&>(maFont).SetSize( aOrigSize );
3148cdf0e10cSrcweir         }
3149cdf0e10cSrcweir     }
3150cdf0e10cSrcweir 
3151cdf0e10cSrcweir     return true;
3152cdf0e10cSrcweir }
3153cdf0e10cSrcweir 
3154cdf0e10cSrcweir // -----------------------------------------------------------------------
3155cdf0e10cSrcweir 
3156cdf0e10cSrcweir long OutputDevice::ImplGetTextWidth( const SalLayout& rSalLayout ) const
3157cdf0e10cSrcweir {
3158cdf0e10cSrcweir     long nWidth = rSalLayout.GetTextWidth();
3159cdf0e10cSrcweir     nWidth /= rSalLayout.GetUnitsPerPixel();
3160cdf0e10cSrcweir     return nWidth;
3161cdf0e10cSrcweir }
3162cdf0e10cSrcweir 
3163cdf0e10cSrcweir // -----------------------------------------------------------------------
3164cdf0e10cSrcweir 
3165cdf0e10cSrcweir void OutputDevice::ImplDrawTextRect( long nBaseX, long nBaseY,
3166cdf0e10cSrcweir                                      long nDistX, long nDistY, long nWidth, long nHeight )
3167cdf0e10cSrcweir {
3168cdf0e10cSrcweir     long nX = nDistX;
3169cdf0e10cSrcweir     long nY = nDistY;
3170cdf0e10cSrcweir 
3171cdf0e10cSrcweir     short nOrientation = mpFontEntry->mnOrientation;
3172cdf0e10cSrcweir     if ( nOrientation )
3173cdf0e10cSrcweir     {
3174cdf0e10cSrcweir         // Rotate rect without rounding problems for 90 degree rotations
3175cdf0e10cSrcweir         if ( !(nOrientation % 900) )
3176cdf0e10cSrcweir         {
3177cdf0e10cSrcweir             if ( nOrientation == 900 )
3178cdf0e10cSrcweir             {
3179cdf0e10cSrcweir                 long nTemp = nX;
3180cdf0e10cSrcweir                 nX = nY;
3181cdf0e10cSrcweir                 nY = -nTemp;
3182cdf0e10cSrcweir                 nTemp = nWidth;
3183cdf0e10cSrcweir                 nWidth = nHeight;
3184cdf0e10cSrcweir                 nHeight = nTemp;
3185cdf0e10cSrcweir                 nY -= nHeight;
3186cdf0e10cSrcweir             }
3187cdf0e10cSrcweir             else if ( nOrientation == 1800 )
3188cdf0e10cSrcweir             {
3189cdf0e10cSrcweir                 nX = -nX;
3190cdf0e10cSrcweir                 nY = -nY;
3191cdf0e10cSrcweir                 nX -= nWidth;
3192cdf0e10cSrcweir                 nY -= nHeight;
3193cdf0e10cSrcweir             }
3194cdf0e10cSrcweir             else /* ( nOrientation == 2700 ) */
3195cdf0e10cSrcweir             {
3196cdf0e10cSrcweir                 long nTemp = nX;
3197cdf0e10cSrcweir                 nX = -nY;
3198cdf0e10cSrcweir                 nY = nTemp;
3199cdf0e10cSrcweir                 nTemp = nWidth;
3200cdf0e10cSrcweir                 nWidth = nHeight;
3201cdf0e10cSrcweir                 nHeight = nTemp;
3202cdf0e10cSrcweir                 nX -= nWidth;
3203cdf0e10cSrcweir             }
3204cdf0e10cSrcweir         }
3205cdf0e10cSrcweir         else
3206cdf0e10cSrcweir         {
3207cdf0e10cSrcweir             nX += nBaseX;
3208cdf0e10cSrcweir             nY += nBaseY;
3209cdf0e10cSrcweir             // inflate because polygons are drawn smaller
3210cdf0e10cSrcweir             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
3211cdf0e10cSrcweir             Polygon   aPoly( aRect );
3212cdf0e10cSrcweir             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
3213cdf0e10cSrcweir             ImplDrawPolygon( aPoly );
3214cdf0e10cSrcweir             return;
3215cdf0e10cSrcweir         }
3216cdf0e10cSrcweir     }
3217cdf0e10cSrcweir 
3218cdf0e10cSrcweir     nX += nBaseX;
3219cdf0e10cSrcweir     nY += nBaseY;
3220cdf0e10cSrcweir     mpGraphics->DrawRect( nX, nY, nWidth, nHeight, this );
3221cdf0e10cSrcweir }
3222cdf0e10cSrcweir 
3223cdf0e10cSrcweir // -----------------------------------------------------------------------
3224cdf0e10cSrcweir 
3225cdf0e10cSrcweir void OutputDevice::ImplDrawTextBackground( const SalLayout& rSalLayout )
3226cdf0e10cSrcweir {
3227cdf0e10cSrcweir     const long nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
3228cdf0e10cSrcweir     const Point aBase = rSalLayout.DrawBase();
3229cdf0e10cSrcweir     const long nX = aBase.X();
3230cdf0e10cSrcweir     const long nY = aBase.Y();
3231cdf0e10cSrcweir 
3232cdf0e10cSrcweir     if ( mbLineColor || mbInitLineColor )
3233cdf0e10cSrcweir     {
3234cdf0e10cSrcweir         mpGraphics->SetLineColor();
3235cdf0e10cSrcweir         mbInitLineColor = sal_True;
3236cdf0e10cSrcweir     }
3237cdf0e10cSrcweir     mpGraphics->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
3238cdf0e10cSrcweir     mbInitFillColor = sal_True;
3239cdf0e10cSrcweir 
3240cdf0e10cSrcweir     ImplDrawTextRect( nX, nY, 0, -(mpFontEntry->maMetric.mnAscent + mnEmphasisAscent),
3241cdf0e10cSrcweir                       nWidth,
3242cdf0e10cSrcweir                       mpFontEntry->mnLineHeight+mnEmphasisAscent+mnEmphasisDescent );
3243cdf0e10cSrcweir }
3244cdf0e10cSrcweir 
3245cdf0e10cSrcweir // -----------------------------------------------------------------------
3246cdf0e10cSrcweir 
3247cdf0e10cSrcweir Rectangle OutputDevice::ImplGetTextBoundRect( const SalLayout& rSalLayout )
3248cdf0e10cSrcweir {
3249cdf0e10cSrcweir     Point aPoint = rSalLayout.GetDrawPosition();
3250cdf0e10cSrcweir     long nX = aPoint.X();
3251cdf0e10cSrcweir     long nY = aPoint.Y();
3252cdf0e10cSrcweir 
3253cdf0e10cSrcweir     long nWidth = rSalLayout.GetTextWidth();
3254cdf0e10cSrcweir     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
3255cdf0e10cSrcweir 
3256cdf0e10cSrcweir     nY -= mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
3257cdf0e10cSrcweir 
3258cdf0e10cSrcweir     if ( mpFontEntry->mnOrientation )
3259cdf0e10cSrcweir     {
3260cdf0e10cSrcweir         long nBaseX = nX, nBaseY = nY;
3261cdf0e10cSrcweir         if ( !(mpFontEntry->mnOrientation % 900) )
3262cdf0e10cSrcweir         {
3263cdf0e10cSrcweir             long nX2 = nX+nWidth;
3264cdf0e10cSrcweir             long nY2 = nY+nHeight;
3265cdf0e10cSrcweir             ImplRotatePos( nBaseX, nBaseY, nX, nY, mpFontEntry->mnOrientation );
3266cdf0e10cSrcweir             ImplRotatePos( nBaseX, nBaseY, nX2, nY2, mpFontEntry->mnOrientation );
3267cdf0e10cSrcweir             nWidth = nX2-nX;
3268cdf0e10cSrcweir             nHeight = nY2-nY;
3269cdf0e10cSrcweir         }
3270cdf0e10cSrcweir         else
3271cdf0e10cSrcweir         {
3272cdf0e10cSrcweir             // inflate by +1+1 because polygons are drawn smaller
3273cdf0e10cSrcweir             Rectangle aRect( Point( nX, nY ), Size( nWidth+1, nHeight+1 ) );
3274cdf0e10cSrcweir             Polygon   aPoly( aRect );
3275cdf0e10cSrcweir             aPoly.Rotate( Point( nBaseX, nBaseY ), mpFontEntry->mnOrientation );
3276cdf0e10cSrcweir             return aPoly.GetBoundRect();
3277cdf0e10cSrcweir         }
3278cdf0e10cSrcweir     }
3279cdf0e10cSrcweir 
3280cdf0e10cSrcweir     return Rectangle( Point( nX, nY ), Size( nWidth, nHeight ) );
3281cdf0e10cSrcweir }
3282cdf0e10cSrcweir 
3283cdf0e10cSrcweir // -----------------------------------------------------------------------
3284cdf0e10cSrcweir 
3285cdf0e10cSrcweir void OutputDevice::ImplInitTextLineSize()
3286cdf0e10cSrcweir {
3287cdf0e10cSrcweir     mpFontEntry->maMetric.ImplInitTextLineSize( this );
3288cdf0e10cSrcweir }
3289cdf0e10cSrcweir 
3290cdf0e10cSrcweir // -----------------------------------------------------------------------
3291cdf0e10cSrcweir 
3292cdf0e10cSrcweir void OutputDevice::ImplInitAboveTextLineSize()
3293cdf0e10cSrcweir {
3294cdf0e10cSrcweir     mpFontEntry->maMetric.ImplInitAboveTextLineSize();
3295cdf0e10cSrcweir }
3296cdf0e10cSrcweir 
3297cdf0e10cSrcweir // -----------------------------------------------------------------------
3298cdf0e10cSrcweir 
3299cdf0e10cSrcweir ImplFontMetricData::ImplFontMetricData( const ImplFontSelectData& rFontSelData )
3300cdf0e10cSrcweir :   ImplFontAttributes( rFontSelData )
3301cdf0e10cSrcweir {
3302cdf0e10cSrcweir     // initialize the members provided by the font request
3303cdf0e10cSrcweir     mnWidth        = rFontSelData.mnWidth;
3304*059ba059SHerbert Dürr     mnSlant        = rFontSelData.GetSlant();
3305cdf0e10cSrcweir     mnOrientation  = sal::static_int_cast<short>(rFontSelData.mnOrientation);
3306cdf0e10cSrcweir 
3307cdf0e10cSrcweir     // intialize the used font name
3308cdf0e10cSrcweir     if( rFontSelData.mpFontData )
3309cdf0e10cSrcweir     {
3310cdf0e10cSrcweir         maName     = rFontSelData.mpFontData->maName;
3311cdf0e10cSrcweir         maStyleName= rFontSelData.mpFontData->maStyleName;
3312cdf0e10cSrcweir         mbDevice   = rFontSelData.mpFontData->mbDevice;
3313cdf0e10cSrcweir         mbKernableFont = true;
3314cdf0e10cSrcweir     }
3315cdf0e10cSrcweir     else
3316cdf0e10cSrcweir     {
3317cdf0e10cSrcweir         xub_StrLen nTokenPos = 0;
3318cdf0e10cSrcweir         maName     = GetNextFontToken( rFontSelData.maName, nTokenPos );
3319cdf0e10cSrcweir         maStyleName= rFontSelData.maStyleName;
3320cdf0e10cSrcweir         mbDevice   = false;
3321cdf0e10cSrcweir         mbKernableFont = false;
3322cdf0e10cSrcweir     }
3323cdf0e10cSrcweir 
3324cdf0e10cSrcweir     // reset metrics that are usually measured for the font instance
3325cdf0e10cSrcweir     mnAscent       = 0;
3326cdf0e10cSrcweir     mnDescent      = 0;
3327cdf0e10cSrcweir     mnIntLeading   = 0;
3328cdf0e10cSrcweir     mnExtLeading   = 0;
3329cdf0e10cSrcweir     mnMinKashida   = 0;
3330cdf0e10cSrcweir 
3331cdf0e10cSrcweir     // reset metrics that are usually derived from the measurements
3332cdf0e10cSrcweir     mnUnderlineSize            = 0;
3333cdf0e10cSrcweir     mnUnderlineOffset          = 0;
3334cdf0e10cSrcweir     mnBUnderlineSize           = 0;
3335cdf0e10cSrcweir     mnBUnderlineOffset         = 0;
3336cdf0e10cSrcweir     mnDUnderlineSize           = 0;
3337cdf0e10cSrcweir     mnDUnderlineOffset1        = 0;
3338cdf0e10cSrcweir     mnDUnderlineOffset2        = 0;
3339cdf0e10cSrcweir     mnWUnderlineSize           = 0;
3340cdf0e10cSrcweir     mnWUnderlineOffset         = 0;
3341cdf0e10cSrcweir     mnAboveUnderlineSize       = 0;
3342cdf0e10cSrcweir     mnAboveUnderlineOffset     = 0;
3343cdf0e10cSrcweir     mnAboveBUnderlineSize      = 0;
3344cdf0e10cSrcweir     mnAboveBUnderlineOffset    = 0;
3345cdf0e10cSrcweir     mnAboveDUnderlineSize      = 0;
3346cdf0e10cSrcweir     mnAboveDUnderlineOffset1   = 0;
3347cdf0e10cSrcweir     mnAboveDUnderlineOffset2   = 0;
3348cdf0e10cSrcweir     mnAboveWUnderlineSize      = 0;
3349cdf0e10cSrcweir     mnAboveWUnderlineOffset    = 0;
3350cdf0e10cSrcweir     mnStrikeoutSize            = 0;
3351cdf0e10cSrcweir     mnStrikeoutOffset          = 0;
3352cdf0e10cSrcweir     mnBStrikeoutSize           = 0;
3353cdf0e10cSrcweir     mnBStrikeoutOffset         = 0;
3354cdf0e10cSrcweir     mnDStrikeoutSize           = 0;
3355cdf0e10cSrcweir     mnDStrikeoutOffset1        = 0;
3356cdf0e10cSrcweir     mnDStrikeoutOffset2        = 0;
3357cdf0e10cSrcweir }
3358cdf0e10cSrcweir 
3359cdf0e10cSrcweir // -----------------------------------------------------------------------
3360cdf0e10cSrcweir 
3361cdf0e10cSrcweir void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice* pDev )
3362cdf0e10cSrcweir {
3363cdf0e10cSrcweir     long nDescent = mnDescent;
3364cdf0e10cSrcweir     if ( nDescent <= 0 )
3365cdf0e10cSrcweir     {
3366cdf0e10cSrcweir         nDescent = mnAscent / 10;
3367cdf0e10cSrcweir         if ( !nDescent )
3368cdf0e10cSrcweir             nDescent = 1;
3369cdf0e10cSrcweir     }
3370cdf0e10cSrcweir 
3371cdf0e10cSrcweir     // #i55341# for some fonts it is not a good idea to calculate
3372cdf0e10cSrcweir     // their text line metrics from the real font descent
3373cdf0e10cSrcweir     // => work around this problem just for these fonts
3374cdf0e10cSrcweir     if( 3*nDescent > mnAscent )
3375cdf0e10cSrcweir         nDescent = mnAscent / 3;
3376cdf0e10cSrcweir 
3377cdf0e10cSrcweir     long nLineHeight = ((nDescent*25)+50) / 100;
3378cdf0e10cSrcweir     if ( !nLineHeight )
3379cdf0e10cSrcweir         nLineHeight = 1;
3380cdf0e10cSrcweir     long nLineHeight2 = nLineHeight / 2;
3381cdf0e10cSrcweir     if ( !nLineHeight2 )
3382cdf0e10cSrcweir         nLineHeight2 = 1;
3383cdf0e10cSrcweir 
3384cdf0e10cSrcweir     long nBLineHeight = ((nDescent*50)+50) / 100;
3385cdf0e10cSrcweir     if ( nBLineHeight == nLineHeight )
3386cdf0e10cSrcweir         nBLineHeight++;
3387cdf0e10cSrcweir     long nBLineHeight2 = nBLineHeight/2;
3388cdf0e10cSrcweir     if ( !nBLineHeight2 )
3389cdf0e10cSrcweir         nBLineHeight2 = 1;
3390cdf0e10cSrcweir 
3391cdf0e10cSrcweir     long n2LineHeight = ((nDescent*16)+50) / 100;
3392cdf0e10cSrcweir     if ( !n2LineHeight )
3393cdf0e10cSrcweir         n2LineHeight = 1;
3394cdf0e10cSrcweir     long n2LineDY = n2LineHeight;
3395cdf0e10cSrcweir      /* #117909#
3396cdf0e10cSrcweir       * add some pixels to minimum double line distance on higher resolution devices
3397cdf0e10cSrcweir       */
3398cdf0e10cSrcweir     long nMin2LineDY = 1 + pDev->ImplGetDPIY()/150;
3399cdf0e10cSrcweir     if ( n2LineDY < nMin2LineDY )
3400cdf0e10cSrcweir         n2LineDY = nMin2LineDY;
3401cdf0e10cSrcweir     long n2LineDY2 = n2LineDY/2;
3402cdf0e10cSrcweir     if ( !n2LineDY2 )
3403cdf0e10cSrcweir         n2LineDY2 = 1;
3404cdf0e10cSrcweir 
3405cdf0e10cSrcweir     long nUnderlineOffset = mnDescent/2 + 1;
3406cdf0e10cSrcweir     long nStrikeoutOffset = -((mnAscent - mnIntLeading) / 3);
3407cdf0e10cSrcweir 
3408cdf0e10cSrcweir     mnUnderlineSize        = nLineHeight;
3409cdf0e10cSrcweir     mnUnderlineOffset      = nUnderlineOffset - nLineHeight2;
3410cdf0e10cSrcweir 
3411cdf0e10cSrcweir     mnBUnderlineSize       = nBLineHeight;
3412cdf0e10cSrcweir     mnBUnderlineOffset     = nUnderlineOffset - nBLineHeight2;
3413cdf0e10cSrcweir 
3414cdf0e10cSrcweir     mnDUnderlineSize       = n2LineHeight;
3415cdf0e10cSrcweir     mnDUnderlineOffset1    = nUnderlineOffset - n2LineDY2 - n2LineHeight;
3416cdf0e10cSrcweir     mnDUnderlineOffset2    = mnDUnderlineOffset1 + n2LineDY + n2LineHeight;
3417cdf0e10cSrcweir 
3418cdf0e10cSrcweir     long nWCalcSize = mnDescent;
3419cdf0e10cSrcweir     if ( nWCalcSize < 6 )
3420cdf0e10cSrcweir     {
3421cdf0e10cSrcweir         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
3422cdf0e10cSrcweir             mnWUnderlineSize = nWCalcSize;
3423cdf0e10cSrcweir         else
3424cdf0e10cSrcweir             mnWUnderlineSize = 3;
3425cdf0e10cSrcweir     }
3426cdf0e10cSrcweir     else
3427cdf0e10cSrcweir         mnWUnderlineSize = ((nWCalcSize*50)+50) / 100;
3428cdf0e10cSrcweir 
3429cdf0e10cSrcweir     // #109280# the following line assures that wavelnes are never placed below the descent, however
3430cdf0e10cSrcweir     // for most fonts the waveline then is drawn into the text, so we better keep the old solution
3431cdf0e10cSrcweir     // pFontEntry->maMetric.mnWUnderlineOffset     = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
3432cdf0e10cSrcweir     mnWUnderlineOffset     = nUnderlineOffset;
3433cdf0e10cSrcweir 
3434cdf0e10cSrcweir     mnStrikeoutSize        = nLineHeight;
3435cdf0e10cSrcweir     mnStrikeoutOffset      = nStrikeoutOffset - nLineHeight2;
3436cdf0e10cSrcweir 
3437cdf0e10cSrcweir     mnBStrikeoutSize       = nBLineHeight;
3438cdf0e10cSrcweir     mnBStrikeoutOffset     = nStrikeoutOffset - nBLineHeight2;
3439cdf0e10cSrcweir 
3440cdf0e10cSrcweir     mnDStrikeoutSize       = n2LineHeight;
3441cdf0e10cSrcweir     mnDStrikeoutOffset1    = nStrikeoutOffset - n2LineDY2 - n2LineHeight;
3442cdf0e10cSrcweir     mnDStrikeoutOffset2    = mnDStrikeoutOffset1 + n2LineDY + n2LineHeight;
3443cdf0e10cSrcweir }
3444cdf0e10cSrcweir 
3445cdf0e10cSrcweir // -----------------------------------------------------------------------
3446cdf0e10cSrcweir 
3447cdf0e10cSrcweir void ImplFontMetricData::ImplInitAboveTextLineSize()
3448cdf0e10cSrcweir {
3449cdf0e10cSrcweir     long nIntLeading = mnIntLeading;
3450cdf0e10cSrcweir     // TODO: assess usage of nLeading below (changed in extleading CWS)
3451cdf0e10cSrcweir     // if no leading is available, we assume 15% of the ascent
3452cdf0e10cSrcweir     if ( nIntLeading <= 0 )
3453cdf0e10cSrcweir     {
3454cdf0e10cSrcweir         nIntLeading = mnAscent*15/100;
3455cdf0e10cSrcweir         if ( !nIntLeading )
3456cdf0e10cSrcweir             nIntLeading = 1;
3457cdf0e10cSrcweir     }
3458cdf0e10cSrcweir 
3459cdf0e10cSrcweir     long nLineHeight = ((nIntLeading*25)+50) / 100;
3460cdf0e10cSrcweir     if ( !nLineHeight )
3461cdf0e10cSrcweir         nLineHeight = 1;
3462cdf0e10cSrcweir 
3463cdf0e10cSrcweir     long nBLineHeight = ((nIntLeading*50)+50) / 100;
3464cdf0e10cSrcweir     if ( nBLineHeight == nLineHeight )
3465cdf0e10cSrcweir         nBLineHeight++;
3466cdf0e10cSrcweir 
3467cdf0e10cSrcweir     long n2LineHeight = ((nIntLeading*16)+50) / 100;
3468cdf0e10cSrcweir     if ( !n2LineHeight )
3469cdf0e10cSrcweir         n2LineHeight = 1;
3470cdf0e10cSrcweir 
3471cdf0e10cSrcweir     long nCeiling = -mnAscent;
3472cdf0e10cSrcweir 
3473cdf0e10cSrcweir     mnAboveUnderlineSize       = nLineHeight;
3474cdf0e10cSrcweir     mnAboveUnderlineOffset     = nCeiling + (nIntLeading - nLineHeight + 1) / 2;
3475cdf0e10cSrcweir 
3476cdf0e10cSrcweir     mnAboveBUnderlineSize      = nBLineHeight;
3477cdf0e10cSrcweir     mnAboveBUnderlineOffset    = nCeiling + (nIntLeading - nBLineHeight + 1) / 2;
3478cdf0e10cSrcweir 
3479cdf0e10cSrcweir     mnAboveDUnderlineSize      = n2LineHeight;
3480cdf0e10cSrcweir     mnAboveDUnderlineOffset1   = nCeiling + (nIntLeading - 3*n2LineHeight + 1) / 2;
3481cdf0e10cSrcweir     mnAboveDUnderlineOffset2   = nCeiling + (nIntLeading +   n2LineHeight + 1) / 2;
3482cdf0e10cSrcweir 
3483cdf0e10cSrcweir     long nWCalcSize = nIntLeading;
3484cdf0e10cSrcweir     if ( nWCalcSize < 6 )
3485cdf0e10cSrcweir     {
3486cdf0e10cSrcweir         if ( (nWCalcSize == 1) || (nWCalcSize == 2) )
3487cdf0e10cSrcweir             mnAboveWUnderlineSize = nWCalcSize;
3488cdf0e10cSrcweir         else
3489cdf0e10cSrcweir             mnAboveWUnderlineSize = 3;
3490cdf0e10cSrcweir     }
3491cdf0e10cSrcweir     else
3492cdf0e10cSrcweir         mnAboveWUnderlineSize = ((nWCalcSize*50)+50) / 100;
3493cdf0e10cSrcweir 
3494cdf0e10cSrcweir     mnAboveWUnderlineOffset = nCeiling + (nIntLeading + 1) / 2;
3495cdf0e10cSrcweir }
3496cdf0e10cSrcweir 
3497cdf0e10cSrcweir // -----------------------------------------------------------------------
3498cdf0e10cSrcweir 
3499cdf0e10cSrcweir static void ImplDrawWavePixel( long nOriginX, long nOriginY,
3500cdf0e10cSrcweir                                long nCurX, long nCurY,
3501cdf0e10cSrcweir                                short nOrientation,
3502cdf0e10cSrcweir                                SalGraphics* pGraphics,
3503cdf0e10cSrcweir                                OutputDevice* pOutDev,
3504cdf0e10cSrcweir                                sal_Bool bDrawPixAsRect,
3505cdf0e10cSrcweir 
3506cdf0e10cSrcweir                                long nPixWidth, long nPixHeight )
3507cdf0e10cSrcweir {
3508cdf0e10cSrcweir     if ( nOrientation )
3509cdf0e10cSrcweir         ImplRotatePos( nOriginX, nOriginY, nCurX, nCurY, nOrientation );
3510cdf0e10cSrcweir 
3511cdf0e10cSrcweir     if ( bDrawPixAsRect )
3512cdf0e10cSrcweir     {
3513cdf0e10cSrcweir 
3514cdf0e10cSrcweir         pGraphics->DrawRect( nCurX, nCurY, nPixWidth, nPixHeight, pOutDev );
3515cdf0e10cSrcweir     }
3516cdf0e10cSrcweir     else
3517cdf0e10cSrcweir     {
3518cdf0e10cSrcweir         pGraphics->DrawPixel( nCurX, nCurY, pOutDev );
3519cdf0e10cSrcweir     }
3520cdf0e10cSrcweir }
3521cdf0e10cSrcweir 
3522cdf0e10cSrcweir // -----------------------------------------------------------------------
3523cdf0e10cSrcweir 
3524cdf0e10cSrcweir void OutputDevice::ImplDrawWaveLine( long nBaseX, long nBaseY,
3525cdf0e10cSrcweir                                      long nDistX, long nDistY,
3526cdf0e10cSrcweir                                      long nWidth, long nHeight,
3527cdf0e10cSrcweir                                      long nLineWidth, short nOrientation,
3528cdf0e10cSrcweir                                      const Color& rColor )
3529cdf0e10cSrcweir {
3530cdf0e10cSrcweir     if ( !nHeight )
3531cdf0e10cSrcweir         return;
3532cdf0e10cSrcweir 
3533cdf0e10cSrcweir     long nStartX = nBaseX + nDistX;
3534cdf0e10cSrcweir     long nStartY = nBaseY + nDistY;
3535cdf0e10cSrcweir 
3536cdf0e10cSrcweir     // Bei Hoehe von 1 Pixel reicht es, eine Linie auszugeben
3537cdf0e10cSrcweir     if ( (nLineWidth == 1) && (nHeight == 1) )
3538cdf0e10cSrcweir     {
3539cdf0e10cSrcweir         mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
3540cdf0e10cSrcweir         mbInitLineColor = sal_True;
3541cdf0e10cSrcweir 
3542cdf0e10cSrcweir         long nEndX = nStartX+nWidth;
3543cdf0e10cSrcweir         long nEndY = nStartY;
3544cdf0e10cSrcweir         if ( nOrientation )
3545cdf0e10cSrcweir         {
3546cdf0e10cSrcweir             ImplRotatePos( nBaseX, nBaseY, nStartX, nStartY, nOrientation );
3547cdf0e10cSrcweir             ImplRotatePos( nBaseX, nBaseY, nEndX, nEndY, nOrientation );
3548cdf0e10cSrcweir         }
3549cdf0e10cSrcweir         mpGraphics->DrawLine( nStartX, nStartY, nEndX, nEndY, this );
3550cdf0e10cSrcweir     }
3551cdf0e10cSrcweir     else
3552cdf0e10cSrcweir     {
3553cdf0e10cSrcweir         long    nCurX = nStartX;
3554cdf0e10cSrcweir         long    nCurY = nStartY;
3555cdf0e10cSrcweir         long    nDiffX = 2;
3556cdf0e10cSrcweir         long    nDiffY = nHeight-1;
3557cdf0e10cSrcweir         long    nCount = nWidth;
3558cdf0e10cSrcweir         long    nOffY = -1;
3559cdf0e10cSrcweir         long    nFreq;
3560cdf0e10cSrcweir         long    i;
3561cdf0e10cSrcweir         long    nPixWidth;
3562cdf0e10cSrcweir         long    nPixHeight;
3563cdf0e10cSrcweir         sal_Bool    bDrawPixAsRect;
3564cdf0e10cSrcweir         // Auf Druckern die Pixel per DrawRect() ausgeben
3565cdf0e10cSrcweir         if ( (GetOutDevType() == OUTDEV_PRINTER) || (nLineWidth > 1) )
3566cdf0e10cSrcweir         {
3567cdf0e10cSrcweir             if ( mbLineColor || mbInitLineColor )
3568cdf0e10cSrcweir             {
3569cdf0e10cSrcweir                 mpGraphics->SetLineColor();
3570cdf0e10cSrcweir                 mbInitLineColor = sal_True;
3571cdf0e10cSrcweir             }
3572cdf0e10cSrcweir             mpGraphics->SetFillColor( ImplColorToSal( rColor ) );
3573cdf0e10cSrcweir             mbInitFillColor = sal_True;
3574cdf0e10cSrcweir             bDrawPixAsRect  = sal_True;
3575cdf0e10cSrcweir             nPixWidth       = nLineWidth;
3576cdf0e10cSrcweir             nPixHeight      = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
3577cdf0e10cSrcweir         }
3578cdf0e10cSrcweir         else
3579cdf0e10cSrcweir         {
3580cdf0e10cSrcweir             mpGraphics->SetLineColor( ImplColorToSal( rColor ) );
3581cdf0e10cSrcweir             mbInitLineColor = sal_True;
3582cdf0e10cSrcweir             nPixWidth       = 1;
3583cdf0e10cSrcweir             nPixHeight      = 1;
3584cdf0e10cSrcweir             bDrawPixAsRect  = sal_False;
3585cdf0e10cSrcweir         }
3586cdf0e10cSrcweir 
3587cdf0e10cSrcweir         if ( !nDiffY )
3588cdf0e10cSrcweir         {
3589cdf0e10cSrcweir             while ( nWidth )
3590cdf0e10cSrcweir             {
3591cdf0e10cSrcweir                 ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3592cdf0e10cSrcweir                                    mpGraphics, this,
3593cdf0e10cSrcweir                                    bDrawPixAsRect, nPixWidth, nPixHeight );
3594cdf0e10cSrcweir                 nCurX++;
3595cdf0e10cSrcweir                 nWidth--;
3596cdf0e10cSrcweir             }
3597cdf0e10cSrcweir         }
3598cdf0e10cSrcweir         else
3599cdf0e10cSrcweir         {
3600cdf0e10cSrcweir             nCurY += nDiffY;
3601cdf0e10cSrcweir             nFreq = nCount / (nDiffX+nDiffY);
3602cdf0e10cSrcweir             while ( nFreq-- )
3603cdf0e10cSrcweir             {
3604cdf0e10cSrcweir                 for( i = nDiffY; i; --i )
3605cdf0e10cSrcweir                 {
3606cdf0e10cSrcweir                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3607cdf0e10cSrcweir                                        mpGraphics, this,
3608cdf0e10cSrcweir                                        bDrawPixAsRect, nPixWidth, nPixHeight );
3609cdf0e10cSrcweir                     nCurX++;
3610cdf0e10cSrcweir                     nCurY += nOffY;
3611cdf0e10cSrcweir                 }
3612cdf0e10cSrcweir                 for( i = nDiffX; i; --i )
3613cdf0e10cSrcweir                 {
3614cdf0e10cSrcweir                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3615cdf0e10cSrcweir                                        mpGraphics, this,
3616cdf0e10cSrcweir                                        bDrawPixAsRect, nPixWidth, nPixHeight );
3617cdf0e10cSrcweir                     nCurX++;
3618cdf0e10cSrcweir                 }
3619cdf0e10cSrcweir                 nOffY = -nOffY;
3620cdf0e10cSrcweir             }
3621cdf0e10cSrcweir             nFreq = nCount % (nDiffX+nDiffY);
3622cdf0e10cSrcweir             if ( nFreq )
3623cdf0e10cSrcweir             {
3624cdf0e10cSrcweir                 for( i = nDiffY; i && nFreq; --i, --nFreq )
3625cdf0e10cSrcweir                 {
3626cdf0e10cSrcweir                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3627cdf0e10cSrcweir                                        mpGraphics, this,
3628cdf0e10cSrcweir                                        bDrawPixAsRect, nPixWidth, nPixHeight );
3629cdf0e10cSrcweir                     nCurX++;
3630cdf0e10cSrcweir                     nCurY += nOffY;
3631cdf0e10cSrcweir 
3632cdf0e10cSrcweir                 }
3633cdf0e10cSrcweir                 for( i = nDiffX; i && nFreq; --i, --nFreq )
3634cdf0e10cSrcweir                 {
3635cdf0e10cSrcweir                     ImplDrawWavePixel( nBaseX, nBaseY, nCurX, nCurY, nOrientation,
3636cdf0e10cSrcweir                                        mpGraphics, this,
3637cdf0e10cSrcweir                                        bDrawPixAsRect, nPixWidth, nPixHeight );
3638cdf0e10cSrcweir                     nCurX++;
3639cdf0e10cSrcweir                 }
3640cdf0e10cSrcweir             }
3641cdf0e10cSrcweir         }
3642cdf0e10cSrcweir 
3643cdf0e10cSrcweir     }
3644cdf0e10cSrcweir }
3645cdf0e10cSrcweir 
3646cdf0e10cSrcweir // -----------------------------------------------------------------------
3647cdf0e10cSrcweir 
3648cdf0e10cSrcweir void OutputDevice::ImplDrawWaveTextLine( long nBaseX, long nBaseY,
3649cdf0e10cSrcweir                                          long nDistX, long nDistY, long nWidth,
3650cdf0e10cSrcweir                                          FontUnderline eTextLine,
3651cdf0e10cSrcweir                                          Color aColor,
3652cdf0e10cSrcweir                                          sal_Bool bIsAbove )
3653cdf0e10cSrcweir {
3654cdf0e10cSrcweir     ImplFontEntry*  pFontEntry = mpFontEntry;
3655cdf0e10cSrcweir     long            nLineHeight;
3656cdf0e10cSrcweir     long            nLinePos;
3657cdf0e10cSrcweir 
3658cdf0e10cSrcweir     if ( bIsAbove )
3659cdf0e10cSrcweir     {
3660cdf0e10cSrcweir         nLineHeight = pFontEntry->maMetric.mnAboveWUnderlineSize;
3661cdf0e10cSrcweir         nLinePos = pFontEntry->maMetric.mnAboveWUnderlineOffset;
3662cdf0e10cSrcweir     }
3663cdf0e10cSrcweir     else
3664cdf0e10cSrcweir     {
3665cdf0e10cSrcweir         nLineHeight = pFontEntry->maMetric.mnWUnderlineSize;
3666cdf0e10cSrcweir         nLinePos = pFontEntry->maMetric.mnWUnderlineOffset;
3667cdf0e10cSrcweir     }
3668cdf0e10cSrcweir     if ( (eTextLine == UNDERLINE_SMALLWAVE) && (nLineHeight > 3) )
3669cdf0e10cSrcweir         nLineHeight = 3;
3670cdf0e10cSrcweir     long nLineWidth = (mnDPIX/300);
3671cdf0e10cSrcweir     if ( !nLineWidth )
3672cdf0e10cSrcweir         nLineWidth = 1;
3673cdf0e10cSrcweir     if ( eTextLine == UNDERLINE_BOLDWAVE )
3674cdf0e10cSrcweir         nLineWidth *= 2;
3675cdf0e10cSrcweir     nLinePos += nDistY - (nLineHeight / 2);
3676cdf0e10cSrcweir     long nLineWidthHeight = ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY;
3677cdf0e10cSrcweir     if ( eTextLine == UNDERLINE_DOUBLEWAVE )
3678cdf0e10cSrcweir     {
3679cdf0e10cSrcweir         long nOrgLineHeight = nLineHeight;
3680cdf0e10cSrcweir         nLineHeight /= 3;
3681cdf0e10cSrcweir         if ( nLineHeight < 2 )
3682cdf0e10cSrcweir         {
3683cdf0e10cSrcweir             if ( nOrgLineHeight > 1 )
3684cdf0e10cSrcweir                 nLineHeight = 2;
3685cdf0e10cSrcweir             else
3686cdf0e10cSrcweir                 nLineHeight = 1;
3687cdf0e10cSrcweir         }
3688cdf0e10cSrcweir         long nLineDY = nOrgLineHeight-(nLineHeight*2);
3689cdf0e10cSrcweir         if ( nLineDY < nLineWidthHeight )
3690cdf0e10cSrcweir             nLineDY = nLineWidthHeight;
3691cdf0e10cSrcweir         long nLineDY2 = nLineDY/2;
3692cdf0e10cSrcweir         if ( !nLineDY2 )
3693cdf0e10cSrcweir             nLineDY2 = 1;
3694cdf0e10cSrcweir 
3695cdf0e10cSrcweir         nLinePos -= nLineWidthHeight-nLineDY2;
3696cdf0e10cSrcweir         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3697cdf0e10cSrcweir                           nLineWidth, mpFontEntry->mnOrientation, aColor );
3698cdf0e10cSrcweir         nLinePos += nLineWidthHeight+nLineDY;
3699cdf0e10cSrcweir         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3700cdf0e10cSrcweir                           nLineWidth, mpFontEntry->mnOrientation, aColor );
3701cdf0e10cSrcweir     }
3702cdf0e10cSrcweir     else
3703cdf0e10cSrcweir     {
3704cdf0e10cSrcweir         nLinePos -= nLineWidthHeight/2;
3705cdf0e10cSrcweir         ImplDrawWaveLine( nBaseX, nBaseY, nDistX, nLinePos, nWidth, nLineHeight,
3706cdf0e10cSrcweir                           nLineWidth, mpFontEntry->mnOrientation, aColor );
3707cdf0e10cSrcweir     }
3708cdf0e10cSrcweir }
3709cdf0e10cSrcweir 
3710cdf0e10cSrcweir // -----------------------------------------------------------------------
3711cdf0e10cSrcweir 
3712cdf0e10cSrcweir void OutputDevice::ImplDrawStraightTextLine( long nBaseX, long nBaseY,
3713cdf0e10cSrcweir                                              long nDistX, long nDistY, long nWidth,
3714cdf0e10cSrcweir                                              FontUnderline eTextLine,
3715cdf0e10cSrcweir                                              Color aColor,
3716cdf0e10cSrcweir                                              sal_Bool bIsAbove )
3717cdf0e10cSrcweir {
3718cdf0e10cSrcweir     ImplFontEntry*  pFontEntry = mpFontEntry;
3719cdf0e10cSrcweir     long            nLineHeight = 0;
3720cdf0e10cSrcweir     long            nLinePos  = 0;
3721cdf0e10cSrcweir     long            nLinePos2 = 0;
3722cdf0e10cSrcweir 
3723cdf0e10cSrcweir     const long nY = nDistY;
3724cdf0e10cSrcweir 
3725cdf0e10cSrcweir     if ( eTextLine > UNDERLINE_LAST )
3726cdf0e10cSrcweir         eTextLine = UNDERLINE_SINGLE;
3727cdf0e10cSrcweir 
3728cdf0e10cSrcweir     switch ( eTextLine )
3729cdf0e10cSrcweir     {
3730cdf0e10cSrcweir         case UNDERLINE_SINGLE:
3731cdf0e10cSrcweir         case UNDERLINE_DOTTED:
3732cdf0e10cSrcweir         case UNDERLINE_DASH:
3733cdf0e10cSrcweir         case UNDERLINE_LONGDASH:
3734cdf0e10cSrcweir         case UNDERLINE_DASHDOT:
3735cdf0e10cSrcweir         case UNDERLINE_DASHDOTDOT:
3736cdf0e10cSrcweir             if ( bIsAbove )
3737cdf0e10cSrcweir             {
3738cdf0e10cSrcweir                 nLineHeight = pFontEntry->maMetric.mnAboveUnderlineSize;
3739cdf0e10cSrcweir                 nLinePos    = nY + pFontEntry->maMetric.mnAboveUnderlineOffset;
3740cdf0e10cSrcweir             }
3741cdf0e10cSrcweir             else
3742cdf0e10cSrcweir             {
3743cdf0e10cSrcweir                 nLineHeight = pFontEntry->maMetric.mnUnderlineSize;
3744cdf0e10cSrcweir                 nLinePos    = nY + pFontEntry->maMetric.mnUnderlineOffset;
3745cdf0e10cSrcweir             }
3746cdf0e10cSrcweir             break;
3747cdf0e10cSrcweir         case UNDERLINE_BOLD:
3748cdf0e10cSrcweir         case UNDERLINE_BOLDDOTTED:
3749cdf0e10cSrcweir         case UNDERLINE_BOLDDASH:
3750cdf0e10cSrcweir         case UNDERLINE_BOLDLONGDASH:
3751cdf0e10cSrcweir         case UNDERLINE_BOLDDASHDOT:
3752cdf0e10cSrcweir         case UNDERLINE_BOLDDASHDOTDOT:
3753cdf0e10cSrcweir             if ( bIsAbove )
3754cdf0e10cSrcweir             {
3755cdf0e10cSrcweir                 nLineHeight = pFontEntry->maMetric.mnAboveBUnderlineSize;
3756cdf0e10cSrcweir                 nLinePos    = nY + pFontEntry->maMetric.mnAboveBUnderlineOffset;
3757cdf0e10cSrcweir             }
3758cdf0e10cSrcweir             else
3759cdf0e10cSrcweir             {
3760cdf0e10cSrcweir                 nLineHeight = pFontEntry->maMetric.mnBUnderlineSize;
3761cdf0e10cSrcweir                 nLinePos    = nY + pFontEntry->maMetric.mnBUnderlineOffset;
3762cdf0e10cSrcweir             }
3763cdf0e10cSrcweir             break;
3764cdf0e10cSrcweir         case UNDERLINE_DOUBLE:
3765cdf0e10cSrcweir             if ( bIsAbove )
3766cdf0e10cSrcweir             {
3767cdf0e10cSrcweir                 nLineHeight = pFontEntry->maMetric.mnAboveDUnderlineSize;
3768cdf0e10cSrcweir                 nLinePos    = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset1;
3769cdf0e10cSrcweir                 nLinePos2   = nY + pFontEntry->maMetric.mnAboveDUnderlineOffset2;
3770cdf0e10cSrcweir             }
3771cdf0e10cSrcweir             else
3772cdf0e10cSrcweir             {
3773cdf0e10cSrcweir                 nLineHeight = pFontEntry->maMetric.mnDUnderlineSize;
3774cdf0e10cSrcweir                 nLinePos    = nY + pFontEntry->maMetric.mnDUnderlineOffset1;
3775cdf0e10cSrcweir                 nLinePos2   = nY + pFontEntry->maMetric.mnDUnderlineOffset2;
3776cdf0e10cSrcweir             }
3777cdf0e10cSrcweir             break;
3778cdf0e10cSrcweir         default:
3779cdf0e10cSrcweir             break;
3780cdf0e10cSrcweir     }
3781cdf0e10cSrcweir 
3782cdf0e10cSrcweir     if ( nLineHeight )
3783cdf0e10cSrcweir     {
3784cdf0e10cSrcweir         if ( mbLineColor || mbInitLineColor )
3785cdf0e10cSrcweir         {
3786cdf0e10cSrcweir             mpGraphics->SetLineColor();
3787cdf0e10cSrcweir             mbInitLineColor = sal_True;
3788cdf0e10cSrcweir         }
3789cdf0e10cSrcweir         mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
3790cdf0e10cSrcweir         mbInitFillColor = sal_True;
3791cdf0e10cSrcweir 
3792cdf0e10cSrcweir         long nLeft = nDistX;
3793cdf0e10cSrcweir 
3794cdf0e10cSrcweir         switch ( eTextLine )
3795cdf0e10cSrcweir         {
3796cdf0e10cSrcweir             case UNDERLINE_SINGLE:
3797cdf0e10cSrcweir             case UNDERLINE_BOLD:
3798cdf0e10cSrcweir                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
3799cdf0e10cSrcweir                 break;
3800cdf0e10cSrcweir             case UNDERLINE_DOUBLE:
3801cdf0e10cSrcweir                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos,  nWidth, nLineHeight );
3802cdf0e10cSrcweir                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
3803cdf0e10cSrcweir                 break;
3804cdf0e10cSrcweir             case UNDERLINE_DOTTED:
3805cdf0e10cSrcweir             case UNDERLINE_BOLDDOTTED:
3806cdf0e10cSrcweir                 {
3807cdf0e10cSrcweir                     long nDotWidth = nLineHeight*mnDPIY;
3808cdf0e10cSrcweir                     nDotWidth += mnDPIY/2;
3809cdf0e10cSrcweir                     nDotWidth /= mnDPIY;
3810cdf0e10cSrcweir                     long nTempWidth = nDotWidth;
3811cdf0e10cSrcweir                     long nEnd = nLeft+nWidth;
3812cdf0e10cSrcweir                     while ( nLeft < nEnd )
3813cdf0e10cSrcweir                     {
3814cdf0e10cSrcweir                         if ( nLeft+nTempWidth > nEnd )
3815cdf0e10cSrcweir                             nTempWidth = nEnd-nLeft;
3816cdf0e10cSrcweir                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
3817cdf0e10cSrcweir                         nLeft += nDotWidth*2;
3818cdf0e10cSrcweir                     }
3819cdf0e10cSrcweir                 }
3820cdf0e10cSrcweir                 break;
3821cdf0e10cSrcweir             case UNDERLINE_DASH:
3822cdf0e10cSrcweir             case UNDERLINE_LONGDASH:
3823cdf0e10cSrcweir             case UNDERLINE_BOLDDASH:
3824cdf0e10cSrcweir             case UNDERLINE_BOLDLONGDASH:
3825cdf0e10cSrcweir                 {
3826cdf0e10cSrcweir                     long nDotWidth = nLineHeight*mnDPIY;
3827cdf0e10cSrcweir                     nDotWidth += mnDPIY/2;
3828cdf0e10cSrcweir                     nDotWidth /= mnDPIY;
3829cdf0e10cSrcweir                     long nMinDashWidth;
3830cdf0e10cSrcweir                     long nMinSpaceWidth;
3831cdf0e10cSrcweir                     long nSpaceWidth;
3832cdf0e10cSrcweir                     long nDashWidth;
3833cdf0e10cSrcweir                     if ( (eTextLine == UNDERLINE_LONGDASH) ||
3834cdf0e10cSrcweir                          (eTextLine == UNDERLINE_BOLDLONGDASH) )
3835cdf0e10cSrcweir                     {
3836cdf0e10cSrcweir                         nMinDashWidth = nDotWidth*6;
3837cdf0e10cSrcweir                         nMinSpaceWidth = nDotWidth*2;
3838cdf0e10cSrcweir                         nDashWidth = 200;
3839cdf0e10cSrcweir                         nSpaceWidth = 100;
3840cdf0e10cSrcweir                     }
3841cdf0e10cSrcweir                     else
3842cdf0e10cSrcweir                     {
3843cdf0e10cSrcweir                         nMinDashWidth = nDotWidth*4;
3844cdf0e10cSrcweir                         nMinSpaceWidth = (nDotWidth*150)/100;
3845cdf0e10cSrcweir                         nDashWidth = 100;
3846cdf0e10cSrcweir                         nSpaceWidth = 50;
3847cdf0e10cSrcweir                     }
3848cdf0e10cSrcweir                     nDashWidth = ((nDashWidth*mnDPIX)+1270)/2540;
3849cdf0e10cSrcweir                     nSpaceWidth = ((nSpaceWidth*mnDPIX)+1270)/2540;
3850cdf0e10cSrcweir                     // DashWidth wird gegebenenfalls verbreitert, wenn
3851cdf0e10cSrcweir                     // die dicke der Linie im Verhaeltnis zur Laenge
3852cdf0e10cSrcweir                     // zu dick wird
3853cdf0e10cSrcweir                     if ( nDashWidth < nMinDashWidth )
3854cdf0e10cSrcweir                         nDashWidth = nMinDashWidth;
3855cdf0e10cSrcweir                     if ( nSpaceWidth < nMinSpaceWidth )
3856cdf0e10cSrcweir                         nSpaceWidth = nMinSpaceWidth;
3857cdf0e10cSrcweir                     long nTempWidth = nDashWidth;
3858cdf0e10cSrcweir                     long nEnd = nLeft+nWidth;
3859cdf0e10cSrcweir                     while ( nLeft < nEnd )
3860cdf0e10cSrcweir                     {
3861cdf0e10cSrcweir                         if ( nLeft+nTempWidth > nEnd )
3862cdf0e10cSrcweir                             nTempWidth = nEnd-nLeft;
3863cdf0e10cSrcweir                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempWidth, nLineHeight );
3864cdf0e10cSrcweir                         nLeft += nDashWidth+nSpaceWidth;
3865cdf0e10cSrcweir                     }
3866cdf0e10cSrcweir                 }
3867cdf0e10cSrcweir                 break;
3868cdf0e10cSrcweir             case UNDERLINE_DASHDOT:
3869cdf0e10cSrcweir             case UNDERLINE_BOLDDASHDOT:
3870cdf0e10cSrcweir                 {
3871cdf0e10cSrcweir                     long nDotWidth = nLineHeight*mnDPIY;
3872cdf0e10cSrcweir                     nDotWidth += mnDPIY/2;
3873cdf0e10cSrcweir                     nDotWidth /= mnDPIY;
3874cdf0e10cSrcweir                     long nDashWidth = ((100*mnDPIX)+1270)/2540;
3875cdf0e10cSrcweir                     long nMinDashWidth = nDotWidth*4;
3876cdf0e10cSrcweir                     // DashWidth wird gegebenenfalls verbreitert, wenn
3877cdf0e10cSrcweir                     // die dicke der Linie im Verhaeltnis zur Laenge
3878cdf0e10cSrcweir                     // zu dick wird
3879cdf0e10cSrcweir                     if ( nDashWidth < nMinDashWidth )
3880cdf0e10cSrcweir                         nDashWidth = nMinDashWidth;
3881cdf0e10cSrcweir                     long nTempDotWidth = nDotWidth;
3882cdf0e10cSrcweir                     long nTempDashWidth = nDashWidth;
3883cdf0e10cSrcweir                     long nEnd = nLeft+nWidth;
3884cdf0e10cSrcweir                     while ( nLeft < nEnd )
3885cdf0e10cSrcweir                     {
3886cdf0e10cSrcweir                         if ( nLeft+nTempDotWidth > nEnd )
3887cdf0e10cSrcweir                             nTempDotWidth = nEnd-nLeft;
3888cdf0e10cSrcweir                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
3889cdf0e10cSrcweir                         nLeft += nDotWidth*2;
3890cdf0e10cSrcweir                         if ( nLeft > nEnd )
3891cdf0e10cSrcweir                             break;
3892cdf0e10cSrcweir                         if ( nLeft+nTempDashWidth > nEnd )
3893cdf0e10cSrcweir                             nTempDashWidth = nEnd-nLeft;
3894cdf0e10cSrcweir                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
3895cdf0e10cSrcweir                         nLeft += nDashWidth+nDotWidth;
3896cdf0e10cSrcweir                     }
3897cdf0e10cSrcweir                 }
3898cdf0e10cSrcweir                 break;
3899cdf0e10cSrcweir             case UNDERLINE_DASHDOTDOT:
3900cdf0e10cSrcweir             case UNDERLINE_BOLDDASHDOTDOT:
3901cdf0e10cSrcweir                 {
3902cdf0e10cSrcweir                     long nDotWidth = nLineHeight*mnDPIY;
3903cdf0e10cSrcweir                     nDotWidth += mnDPIY/2;
3904cdf0e10cSrcweir                     nDotWidth /= mnDPIY;
3905cdf0e10cSrcweir                     long nDashWidth = ((100*mnDPIX)+1270)/2540;
3906cdf0e10cSrcweir                     long nMinDashWidth = nDotWidth*4;
3907cdf0e10cSrcweir                     // DashWidth wird gegebenenfalls verbreitert, wenn
3908cdf0e10cSrcweir                     // die dicke der Linie im Verhaeltnis zur Laenge
3909cdf0e10cSrcweir                     // zu dick wird
3910cdf0e10cSrcweir                     if ( nDashWidth < nMinDashWidth )
3911cdf0e10cSrcweir                         nDashWidth = nMinDashWidth;
3912cdf0e10cSrcweir                     long nTempDotWidth = nDotWidth;
3913cdf0e10cSrcweir                     long nTempDashWidth = nDashWidth;
3914cdf0e10cSrcweir                     long nEnd = nLeft+nWidth;
3915cdf0e10cSrcweir                     while ( nLeft < nEnd )
3916cdf0e10cSrcweir                     {
3917cdf0e10cSrcweir                         if ( nLeft+nTempDotWidth > nEnd )
3918cdf0e10cSrcweir                             nTempDotWidth = nEnd-nLeft;
3919cdf0e10cSrcweir                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
3920cdf0e10cSrcweir                         nLeft += nDotWidth*2;
3921cdf0e10cSrcweir                         if ( nLeft > nEnd )
3922cdf0e10cSrcweir                             break;
3923cdf0e10cSrcweir                         if ( nLeft+nTempDotWidth > nEnd )
3924cdf0e10cSrcweir                             nTempDotWidth = nEnd-nLeft;
3925cdf0e10cSrcweir                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDotWidth, nLineHeight );
3926cdf0e10cSrcweir                         nLeft += nDotWidth*2;
3927cdf0e10cSrcweir                         if ( nLeft > nEnd )
3928cdf0e10cSrcweir                             break;
3929cdf0e10cSrcweir                         if ( nLeft+nTempDashWidth > nEnd )
3930cdf0e10cSrcweir                             nTempDashWidth = nEnd-nLeft;
3931cdf0e10cSrcweir                         ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nTempDashWidth, nLineHeight );
3932cdf0e10cSrcweir                         nLeft += nDashWidth+nDotWidth;
3933cdf0e10cSrcweir                     }
3934cdf0e10cSrcweir                 }
3935cdf0e10cSrcweir                 break;
3936cdf0e10cSrcweir             default:
3937cdf0e10cSrcweir                 break;
3938cdf0e10cSrcweir         }
3939cdf0e10cSrcweir     }
3940cdf0e10cSrcweir }
3941cdf0e10cSrcweir 
3942cdf0e10cSrcweir // -----------------------------------------------------------------------
3943cdf0e10cSrcweir 
3944cdf0e10cSrcweir void OutputDevice::ImplDrawStrikeoutLine( long nBaseX, long nBaseY,
3945cdf0e10cSrcweir                                           long nDistX, long nDistY, long nWidth,
3946cdf0e10cSrcweir                                           FontStrikeout eStrikeout,
3947cdf0e10cSrcweir                                           Color aColor )
3948cdf0e10cSrcweir {
3949cdf0e10cSrcweir     ImplFontEntry*  pFontEntry = mpFontEntry;
3950cdf0e10cSrcweir     long            nLineHeight = 0;
3951cdf0e10cSrcweir     long            nLinePos  = 0;
3952cdf0e10cSrcweir     long            nLinePos2 = 0;
3953cdf0e10cSrcweir 
3954cdf0e10cSrcweir     long nY = nDistY;
3955cdf0e10cSrcweir 
3956cdf0e10cSrcweir     if ( eStrikeout > STRIKEOUT_LAST )
3957cdf0e10cSrcweir         eStrikeout = STRIKEOUT_SINGLE;
3958cdf0e10cSrcweir 
3959cdf0e10cSrcweir     switch ( eStrikeout )
3960cdf0e10cSrcweir     {
3961cdf0e10cSrcweir         case STRIKEOUT_SINGLE:
3962cdf0e10cSrcweir             nLineHeight = pFontEntry->maMetric.mnStrikeoutSize;
3963cdf0e10cSrcweir             nLinePos    = nY + pFontEntry->maMetric.mnStrikeoutOffset;
3964cdf0e10cSrcweir             break;
3965cdf0e10cSrcweir         case STRIKEOUT_BOLD:
3966cdf0e10cSrcweir             nLineHeight = pFontEntry->maMetric.mnBStrikeoutSize;
3967cdf0e10cSrcweir             nLinePos    = nY + pFontEntry->maMetric.mnBStrikeoutOffset;
3968cdf0e10cSrcweir             break;
3969cdf0e10cSrcweir         case STRIKEOUT_DOUBLE:
3970cdf0e10cSrcweir             nLineHeight = pFontEntry->maMetric.mnDStrikeoutSize;
3971cdf0e10cSrcweir             nLinePos    = nY + pFontEntry->maMetric.mnDStrikeoutOffset1;
3972cdf0e10cSrcweir             nLinePos2   = nY + pFontEntry->maMetric.mnDStrikeoutOffset2;
3973cdf0e10cSrcweir             break;
3974cdf0e10cSrcweir         default:
3975cdf0e10cSrcweir             break;
3976cdf0e10cSrcweir     }
3977cdf0e10cSrcweir 
3978cdf0e10cSrcweir     if ( nLineHeight )
3979cdf0e10cSrcweir     {
3980cdf0e10cSrcweir         if ( mbLineColor || mbInitLineColor )
3981cdf0e10cSrcweir         {
3982cdf0e10cSrcweir             mpGraphics->SetLineColor();
3983cdf0e10cSrcweir             mbInitLineColor = sal_True;
3984cdf0e10cSrcweir         }
3985cdf0e10cSrcweir         mpGraphics->SetFillColor( ImplColorToSal( aColor ) );
3986cdf0e10cSrcweir         mbInitFillColor = sal_True;
3987cdf0e10cSrcweir 
3988cdf0e10cSrcweir         const long& nLeft = nDistX;
3989cdf0e10cSrcweir 
3990cdf0e10cSrcweir         switch ( eStrikeout )
3991cdf0e10cSrcweir         {
3992cdf0e10cSrcweir             case STRIKEOUT_SINGLE:
3993cdf0e10cSrcweir             case STRIKEOUT_BOLD:
3994cdf0e10cSrcweir                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
3995cdf0e10cSrcweir                 break;
3996cdf0e10cSrcweir             case STRIKEOUT_DOUBLE:
3997cdf0e10cSrcweir                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos, nWidth, nLineHeight );
3998cdf0e10cSrcweir                 ImplDrawTextRect( nBaseX, nBaseY, nLeft, nLinePos2, nWidth, nLineHeight );
3999cdf0e10cSrcweir                 break;
4000cdf0e10cSrcweir             default:
4001cdf0e10cSrcweir                 break;
4002cdf0e10cSrcweir         }
4003cdf0e10cSrcweir     }
4004cdf0e10cSrcweir }
4005cdf0e10cSrcweir 
4006cdf0e10cSrcweir // -----------------------------------------------------------------------
4007cdf0e10cSrcweir 
4008cdf0e10cSrcweir void OutputDevice::ImplDrawStrikeoutChar( long nBaseX, long nBaseY,
4009cdf0e10cSrcweir                                           long nDistX, long nDistY, long nWidth,
4010cdf0e10cSrcweir                                           FontStrikeout eStrikeout,
4011cdf0e10cSrcweir                                           Color aColor )
4012cdf0e10cSrcweir {
4013cdf0e10cSrcweir     // PDF-export does its own strikeout drawing... why again?
4014cdf0e10cSrcweir     if( mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) )
4015cdf0e10cSrcweir         return;
4016cdf0e10cSrcweir 
4017cdf0e10cSrcweir     // prepare string for strikeout measurement
4018cdf0e10cSrcweir     static char cStrikeoutChar;
4019cdf0e10cSrcweir     if ( eStrikeout == STRIKEOUT_SLASH )
4020cdf0e10cSrcweir         cStrikeoutChar = '/';
4021cdf0e10cSrcweir     else // ( eStrikeout == STRIKEOUT_X )
4022cdf0e10cSrcweir         cStrikeoutChar = 'X';
4023cdf0e10cSrcweir     static const int nTestStrLen = 4;
4024cdf0e10cSrcweir     static const int nMaxStrikeStrLen = 2048;
4025cdf0e10cSrcweir     xub_Unicode aChars[ nMaxStrikeStrLen +1]; // +1 for valgrind...
4026cdf0e10cSrcweir     for( int i = 0; i < nTestStrLen; ++i)
4027cdf0e10cSrcweir         aChars[i] = cStrikeoutChar;
4028cdf0e10cSrcweir     const String aStrikeoutTest( aChars, nTestStrLen );
4029cdf0e10cSrcweir 
4030cdf0e10cSrcweir     // calculate approximation of strikeout atom size
4031cdf0e10cSrcweir     long nStrikeoutWidth = nWidth;
4032cdf0e10cSrcweir     SalLayout* pLayout = ImplLayout( aStrikeoutTest, 0, nTestStrLen );
4033cdf0e10cSrcweir     if( pLayout )
4034cdf0e10cSrcweir     {
4035cdf0e10cSrcweir         nStrikeoutWidth = (pLayout->GetTextWidth() +nTestStrLen/2) / (nTestStrLen * pLayout->GetUnitsPerPixel());
4036cdf0e10cSrcweir         pLayout->Release();
4037cdf0e10cSrcweir     }
4038cdf0e10cSrcweir     if( nStrikeoutWidth <= 0 ) // sanity check
4039cdf0e10cSrcweir         return;
4040cdf0e10cSrcweir 
4041cdf0e10cSrcweir     // calculate acceptable strikeout length
4042cdf0e10cSrcweir     // allow the strikeout to be one pixel larger than the text it strikes out
4043cdf0e10cSrcweir     long nMaxWidth = nStrikeoutWidth * 3 / 4;
4044cdf0e10cSrcweir     if ( nMaxWidth < 2 )
4045cdf0e10cSrcweir         nMaxWidth = 2;
4046cdf0e10cSrcweir     nMaxWidth += nWidth + 1;
4047cdf0e10cSrcweir 
4048cdf0e10cSrcweir     int nStrikeStrLen = (nMaxWidth - 1) / nStrikeoutWidth;
4049cdf0e10cSrcweir     // if the text width is smaller than the strikeout text, then do not
4050cdf0e10cSrcweir     // strike out at all. This case requires user interaction, e.g. adding
4051cdf0e10cSrcweir     // a space to the text
4052cdf0e10cSrcweir     if( nStrikeStrLen <= 0 )
4053cdf0e10cSrcweir         return;
4054cdf0e10cSrcweir     if( nStrikeStrLen > nMaxStrikeStrLen )
4055cdf0e10cSrcweir         nStrikeStrLen = nMaxStrikeStrLen;
4056cdf0e10cSrcweir 
4057cdf0e10cSrcweir     // build the strikeout string
4058cdf0e10cSrcweir     for( int i = nTestStrLen; i < nStrikeStrLen; ++i)
4059cdf0e10cSrcweir         aChars[i] = cStrikeoutChar;
4060cdf0e10cSrcweir     const String aStrikeoutText( aChars, xub_StrLen(nStrikeStrLen) );
4061cdf0e10cSrcweir 
4062cdf0e10cSrcweir     if( mpFontEntry->mnOrientation )
4063cdf0e10cSrcweir         ImplRotatePos( 0, 0, nDistX, nDistY, mpFontEntry->mnOrientation );
4064cdf0e10cSrcweir     nBaseX += nDistX;
4065cdf0e10cSrcweir     nBaseY += nDistY;
4066cdf0e10cSrcweir 
4067cdf0e10cSrcweir     // strikeout text has to be left aligned
4068cdf0e10cSrcweir     sal_uLong nOrigTLM = mnTextLayoutMode;
4069cdf0e10cSrcweir     mnTextLayoutMode = TEXT_LAYOUT_BIDI_STRONG | TEXT_LAYOUT_COMPLEX_DISABLED;
4070cdf0e10cSrcweir     pLayout = ImplLayout( aStrikeoutText, 0, STRING_LEN );
4071cdf0e10cSrcweir     mnTextLayoutMode = nOrigTLM;
4072cdf0e10cSrcweir 
4073cdf0e10cSrcweir     if( !pLayout )
4074cdf0e10cSrcweir         return;
4075cdf0e10cSrcweir 
4076cdf0e10cSrcweir     // draw the strikeout text
4077cdf0e10cSrcweir     const Color aOldColor = GetTextColor();
4078cdf0e10cSrcweir     SetTextColor( aColor );
4079cdf0e10cSrcweir     ImplInitTextColor();
4080cdf0e10cSrcweir 
4081cdf0e10cSrcweir     pLayout->DrawBase() = Point( nBaseX+mnTextOffX, nBaseY+mnTextOffY );
4082cdf0e10cSrcweir     pLayout->DrawText( *mpGraphics );
4083cdf0e10cSrcweir     pLayout->Release();
4084cdf0e10cSrcweir 
4085cdf0e10cSrcweir     SetTextColor( aOldColor );
4086cdf0e10cSrcweir     ImplInitTextColor();
4087cdf0e10cSrcweir }
4088cdf0e10cSrcweir 
4089cdf0e10cSrcweir // -----------------------------------------------------------------------
4090cdf0e10cSrcweir 
4091cdf0e10cSrcweir void OutputDevice::ImplDrawTextLine( long nX, long nY,
4092cdf0e10cSrcweir                                      long nDistX, long nWidth,
4093cdf0e10cSrcweir                                      FontStrikeout eStrikeout,
4094cdf0e10cSrcweir                                      FontUnderline eUnderline,
4095cdf0e10cSrcweir                                      FontUnderline eOverline,
4096cdf0e10cSrcweir                                      sal_Bool bUnderlineAbove )
4097cdf0e10cSrcweir {
4098cdf0e10cSrcweir     if ( !nWidth )
4099cdf0e10cSrcweir         return;
4100cdf0e10cSrcweir 
4101cdf0e10cSrcweir     Color           aStrikeoutColor = GetTextColor();
4102cdf0e10cSrcweir     Color           aUnderlineColor = GetTextLineColor();
4103cdf0e10cSrcweir     Color           aOverlineColor  = GetOverlineColor();
4104cdf0e10cSrcweir     sal_Bool            bStrikeoutDone = sal_False;
4105cdf0e10cSrcweir     sal_Bool            bUnderlineDone = sal_False;
4106cdf0e10cSrcweir     sal_Bool            bOverlineDone  = sal_False;
4107cdf0e10cSrcweir 
4108cdf0e10cSrcweir     if ( IsRTLEnabled() )
4109cdf0e10cSrcweir     {
4110cdf0e10cSrcweir         // --- RTL --- mirror at basex
4111cdf0e10cSrcweir         long nXAdd = nWidth - nDistX;
4112cdf0e10cSrcweir         if( mpFontEntry->mnOrientation )
4113cdf0e10cSrcweir             nXAdd = FRound( nXAdd * cos( mpFontEntry->mnOrientation * F_PI1800 ) );
4114cdf0e10cSrcweir         nX += nXAdd - 1;
4115cdf0e10cSrcweir     }
4116cdf0e10cSrcweir 
4117cdf0e10cSrcweir     if ( !IsTextLineColor() )
4118cdf0e10cSrcweir         aUnderlineColor = GetTextColor();
4119cdf0e10cSrcweir 
4120cdf0e10cSrcweir     if ( !IsOverlineColor() )
4121cdf0e10cSrcweir         aOverlineColor = GetTextColor();
4122cdf0e10cSrcweir 
4123cdf0e10cSrcweir     if ( (eUnderline == UNDERLINE_SMALLWAVE) ||
4124cdf0e10cSrcweir          (eUnderline == UNDERLINE_WAVE) ||
4125cdf0e10cSrcweir          (eUnderline == UNDERLINE_DOUBLEWAVE) ||
4126cdf0e10cSrcweir          (eUnderline == UNDERLINE_BOLDWAVE) )
4127cdf0e10cSrcweir     {
4128cdf0e10cSrcweir         ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
4129cdf0e10cSrcweir         bUnderlineDone = sal_True;
4130cdf0e10cSrcweir     }
4131cdf0e10cSrcweir     if ( (eOverline == UNDERLINE_SMALLWAVE) ||
4132cdf0e10cSrcweir          (eOverline == UNDERLINE_WAVE) ||
4133cdf0e10cSrcweir          (eOverline == UNDERLINE_DOUBLEWAVE) ||
4134cdf0e10cSrcweir          (eOverline == UNDERLINE_BOLDWAVE) )
4135cdf0e10cSrcweir     {
4136cdf0e10cSrcweir         ImplDrawWaveTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
4137cdf0e10cSrcweir         bOverlineDone = sal_True;
4138cdf0e10cSrcweir     }
4139cdf0e10cSrcweir 
4140cdf0e10cSrcweir     if ( (eStrikeout == STRIKEOUT_SLASH) ||
4141cdf0e10cSrcweir          (eStrikeout == STRIKEOUT_X) )
4142cdf0e10cSrcweir     {
4143cdf0e10cSrcweir         ImplDrawStrikeoutChar( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
4144cdf0e10cSrcweir         bStrikeoutDone = sal_True;
4145cdf0e10cSrcweir     }
4146cdf0e10cSrcweir 
4147cdf0e10cSrcweir     if ( !bUnderlineDone )
4148cdf0e10cSrcweir         ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eUnderline, aUnderlineColor, bUnderlineAbove );
4149cdf0e10cSrcweir 
4150cdf0e10cSrcweir     if ( !bOverlineDone )
4151cdf0e10cSrcweir         ImplDrawStraightTextLine( nX, nY, nDistX, 0, nWidth, eOverline, aOverlineColor, sal_True );
4152cdf0e10cSrcweir 
4153cdf0e10cSrcweir     if ( !bStrikeoutDone )
4154cdf0e10cSrcweir         ImplDrawStrikeoutLine( nX, nY, nDistX, 0, nWidth, eStrikeout, aStrikeoutColor );
4155cdf0e10cSrcweir }
4156cdf0e10cSrcweir 
4157cdf0e10cSrcweir // -----------------------------------------------------------------------
4158cdf0e10cSrcweir 
4159cdf0e10cSrcweir void OutputDevice::ImplDrawTextLines( SalLayout& rSalLayout,
4160cdf0e10cSrcweir     FontStrikeout eStrikeout, FontUnderline eUnderline, FontUnderline eOverline, sal_Bool bWordLine, sal_Bool bUnderlineAbove )
4161cdf0e10cSrcweir {
4162cdf0e10cSrcweir     if( bWordLine )
4163cdf0e10cSrcweir     {
4164cdf0e10cSrcweir         // draw everything relative to the layout base point
4165cdf0e10cSrcweir      const Point aStartPt = rSalLayout.DrawBase();
4166cdf0e10cSrcweir      // calculate distance of each word from the base point
4167cdf0e10cSrcweir         Point aPos;
4168cdf0e10cSrcweir         sal_Int32 nDist = 0, nWidth = 0, nAdvance=0;
4169cdf0e10cSrcweir         for( int nStart = 0;;)
4170cdf0e10cSrcweir         {
4171cdf0e10cSrcweir             // iterate through the layouted glyphs
4172cdf0e10cSrcweir             sal_GlyphId nGlyphIndex;
4173cdf0e10cSrcweir             if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart, &nAdvance ) )
4174cdf0e10cSrcweir                 break;
4175cdf0e10cSrcweir 
4176cdf0e10cSrcweir             // calculate the boundaries of each word
4177cdf0e10cSrcweir             if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
4178cdf0e10cSrcweir             {
4179cdf0e10cSrcweir                 if( !nWidth )
4180cdf0e10cSrcweir                 {
4181cdf0e10cSrcweir                     // get the distance to the base point (as projected to baseline)
4182cdf0e10cSrcweir                     nDist = aPos.X() - aStartPt.X();
4183cdf0e10cSrcweir                     if( mpFontEntry->mnOrientation )
4184cdf0e10cSrcweir                     {
4185cdf0e10cSrcweir                         const long nDY = aPos.Y() - aStartPt.Y();
4186cdf0e10cSrcweir                         const double fRad = mpFontEntry->mnOrientation * F_PI1800;
4187cdf0e10cSrcweir                         nDist = FRound( nDist*cos(fRad) - nDY*sin(fRad) );
4188cdf0e10cSrcweir                     }
4189cdf0e10cSrcweir                 }
4190cdf0e10cSrcweir 
4191cdf0e10cSrcweir                 // update the length of the textline
4192cdf0e10cSrcweir                 nWidth += nAdvance;
4193cdf0e10cSrcweir             }
4194cdf0e10cSrcweir             else if( nWidth > 0 )
4195cdf0e10cSrcweir             {
4196cdf0e10cSrcweir              // draw the textline for each word
4197cdf0e10cSrcweir                 ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
4198cdf0e10cSrcweir                     eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4199cdf0e10cSrcweir                 nWidth = 0;
4200cdf0e10cSrcweir             }
4201cdf0e10cSrcweir         }
4202cdf0e10cSrcweir 
4203cdf0e10cSrcweir         // draw textline for the last word
4204cdf0e10cSrcweir         if( nWidth > 0 )
4205cdf0e10cSrcweir         {
4206cdf0e10cSrcweir             ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), nDist, nWidth,
4207cdf0e10cSrcweir                 eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4208cdf0e10cSrcweir         }
4209cdf0e10cSrcweir     }
4210cdf0e10cSrcweir     else
4211cdf0e10cSrcweir     {
4212cdf0e10cSrcweir         Point aStartPt = rSalLayout.GetDrawPosition();
4213cdf0e10cSrcweir         int nWidth = rSalLayout.GetTextWidth() / rSalLayout.GetUnitsPerPixel();
4214cdf0e10cSrcweir         ImplDrawTextLine( aStartPt.X(), aStartPt.Y(), 0, nWidth,
4215cdf0e10cSrcweir             eStrikeout, eUnderline, eOverline, bUnderlineAbove );
4216cdf0e10cSrcweir     }
4217cdf0e10cSrcweir }
4218cdf0e10cSrcweir 
4219cdf0e10cSrcweir // -----------------------------------------------------------------------
4220cdf0e10cSrcweir 
4221cdf0e10cSrcweir void OutputDevice::ImplDrawMnemonicLine( long nX, long nY, long nWidth )
4222cdf0e10cSrcweir {
4223cdf0e10cSrcweir     long nBaseX = nX;
4224cdf0e10cSrcweir     if( /*ImplHasMirroredGraphics() &&*/ IsRTLEnabled() )
4225cdf0e10cSrcweir     {
4226cdf0e10cSrcweir         // --- RTL ---
4227cdf0e10cSrcweir         // add some strange offset
4228cdf0e10cSrcweir         nX += 2;
4229cdf0e10cSrcweir         // revert the hack that will be done later in ImplDrawTextLine
4230cdf0e10cSrcweir         nX = nBaseX - nWidth - (nX - nBaseX - 1);
4231cdf0e10cSrcweir     }
4232cdf0e10cSrcweir 
4233cdf0e10cSrcweir     ImplDrawTextLine( nX, nY, 0, nWidth, STRIKEOUT_NONE, UNDERLINE_SINGLE, UNDERLINE_NONE, sal_False );
4234cdf0e10cSrcweir }
4235cdf0e10cSrcweir 
4236cdf0e10cSrcweir // -----------------------------------------------------------------------
4237cdf0e10cSrcweir 
4238cdf0e10cSrcweir void OutputDevice::ImplGetEmphasisMark( PolyPolygon& rPolyPoly, sal_Bool& rPolyLine,
4239cdf0e10cSrcweir                                         Rectangle& rRect1, Rectangle& rRect2,
4240cdf0e10cSrcweir                                         long& rYOff, long& rWidth,
4241cdf0e10cSrcweir                                         FontEmphasisMark eEmphasis,
4242cdf0e10cSrcweir                                         long nHeight, short /*nOrient*/ )
4243cdf0e10cSrcweir {
4244cdf0e10cSrcweir     static const sal_uInt8 aAccentPolyFlags[24] =
4245cdf0e10cSrcweir     {
4246cdf0e10cSrcweir         0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
4247cdf0e10cSrcweir     };
4248cdf0e10cSrcweir 
4249cdf0e10cSrcweir     static const long aAccentPos[48] =
4250cdf0e10cSrcweir     {
4251cdf0e10cSrcweir          78,      0,
4252cdf0e10cSrcweir         348,     79,
4253cdf0e10cSrcweir         599,    235,
4254cdf0e10cSrcweir         843,    469,
4255cdf0e10cSrcweir         938,    574,
4256cdf0e10cSrcweir         990,    669,
4257cdf0e10cSrcweir         990,    773,
4258cdf0e10cSrcweir         990,    843,
4259cdf0e10cSrcweir         964,    895,
4260cdf0e10cSrcweir         921,    947,
4261cdf0e10cSrcweir         886,    982,
4262cdf0e10cSrcweir         860,    999,
4263cdf0e10cSrcweir         825,    999,
4264cdf0e10cSrcweir         764,    999,
4265cdf0e10cSrcweir         721,    964,
4266cdf0e10cSrcweir         686,    895,
4267cdf0e10cSrcweir         625,    791,
4268cdf0e10cSrcweir         556,    660,
4269cdf0e10cSrcweir         469,    504,
4270cdf0e10cSrcweir         400,    400,
4271cdf0e10cSrcweir         261,    252,
4272cdf0e10cSrcweir          61,     61,
4273cdf0e10cSrcweir           0,     27,
4274cdf0e10cSrcweir           9,      0
4275cdf0e10cSrcweir     };
4276cdf0e10cSrcweir 
4277cdf0e10cSrcweir     rWidth      = 0;
4278cdf0e10cSrcweir     rYOff       = 0;
4279cdf0e10cSrcweir     rPolyLine   = sal_False;
4280cdf0e10cSrcweir 
4281cdf0e10cSrcweir     if ( !nHeight )
4282cdf0e10cSrcweir         return;
4283cdf0e10cSrcweir 
4284cdf0e10cSrcweir     FontEmphasisMark    nEmphasisStyle = eEmphasis & EMPHASISMARK_STYLE;
4285cdf0e10cSrcweir     long                nDotSize = 0;
4286cdf0e10cSrcweir     switch ( nEmphasisStyle )
4287cdf0e10cSrcweir     {
4288cdf0e10cSrcweir         case EMPHASISMARK_DOT:
4289cdf0e10cSrcweir             // Dot has 55% of the height
4290cdf0e10cSrcweir             nDotSize = (nHeight*550)/1000;
4291cdf0e10cSrcweir             if ( !nDotSize )
4292cdf0e10cSrcweir                 nDotSize = 1;
4293cdf0e10cSrcweir             if ( nDotSize <= 2 )
4294cdf0e10cSrcweir                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4295cdf0e10cSrcweir             else
4296cdf0e10cSrcweir             {
4297cdf0e10cSrcweir                 long nRad = nDotSize/2;
4298cdf0e10cSrcweir                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4299cdf0e10cSrcweir                 rPolyPoly.Insert( aPoly );
4300cdf0e10cSrcweir             }
4301cdf0e10cSrcweir             rYOff = ((nHeight*250)/1000)/2; // Center to the anthoer EmphasisMarks
4302cdf0e10cSrcweir             rWidth = nDotSize;
4303cdf0e10cSrcweir             break;
4304cdf0e10cSrcweir 
4305cdf0e10cSrcweir         case EMPHASISMARK_CIRCLE:
4306cdf0e10cSrcweir             // Dot has 80% of the height
4307cdf0e10cSrcweir             nDotSize = (nHeight*800)/1000;
4308cdf0e10cSrcweir             if ( !nDotSize )
4309cdf0e10cSrcweir                 nDotSize = 1;
4310cdf0e10cSrcweir             if ( nDotSize <= 2 )
4311cdf0e10cSrcweir                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4312cdf0e10cSrcweir             else
4313cdf0e10cSrcweir             {
4314cdf0e10cSrcweir                 long nRad = nDotSize/2;
4315cdf0e10cSrcweir                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4316cdf0e10cSrcweir                 rPolyPoly.Insert( aPoly );
4317cdf0e10cSrcweir                 // BorderWidth is 15%
4318cdf0e10cSrcweir                 long nBorder = (nDotSize*150)/1000;
4319cdf0e10cSrcweir                 if ( nBorder <= 1 )
4320cdf0e10cSrcweir                     rPolyLine = sal_True;
4321cdf0e10cSrcweir                 else
4322cdf0e10cSrcweir                 {
4323cdf0e10cSrcweir                     Polygon aPoly2( Point( nRad, nRad ),
4324cdf0e10cSrcweir                                     nRad-nBorder, nRad-nBorder );
4325cdf0e10cSrcweir                     rPolyPoly.Insert( aPoly2 );
4326cdf0e10cSrcweir                 }
4327cdf0e10cSrcweir             }
4328cdf0e10cSrcweir             rWidth = nDotSize;
4329cdf0e10cSrcweir             break;
4330cdf0e10cSrcweir 
4331cdf0e10cSrcweir         case EMPHASISMARK_DISC:
4332cdf0e10cSrcweir             // Dot has 80% of the height
4333cdf0e10cSrcweir             nDotSize = (nHeight*800)/1000;
4334cdf0e10cSrcweir             if ( !nDotSize )
4335cdf0e10cSrcweir                 nDotSize = 1;
4336cdf0e10cSrcweir             if ( nDotSize <= 2 )
4337cdf0e10cSrcweir                 rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4338cdf0e10cSrcweir             else
4339cdf0e10cSrcweir             {
4340cdf0e10cSrcweir                 long nRad = nDotSize/2;
4341cdf0e10cSrcweir                 Polygon aPoly( Point( nRad, nRad ), nRad, nRad );
4342cdf0e10cSrcweir                 rPolyPoly.Insert( aPoly );
4343cdf0e10cSrcweir             }
4344cdf0e10cSrcweir             rWidth = nDotSize;
4345cdf0e10cSrcweir             break;
4346cdf0e10cSrcweir 
4347cdf0e10cSrcweir         case EMPHASISMARK_ACCENT:
4348cdf0e10cSrcweir             // Dot has 80% of the height
4349cdf0e10cSrcweir             nDotSize = (nHeight*800)/1000;
4350cdf0e10cSrcweir             if ( !nDotSize )
4351cdf0e10cSrcweir                 nDotSize = 1;
4352cdf0e10cSrcweir             if ( nDotSize <= 2 )
4353cdf0e10cSrcweir             {
4354cdf0e10cSrcweir                 if ( nDotSize == 1 )
4355cdf0e10cSrcweir                 {
4356cdf0e10cSrcweir                     rRect1 = Rectangle( Point(), Size( nDotSize, nDotSize ) );
4357cdf0e10cSrcweir                     rWidth = nDotSize;
4358cdf0e10cSrcweir                 }
4359cdf0e10cSrcweir                 else
4360cdf0e10cSrcweir                 {
4361cdf0e10cSrcweir                     rRect1 = Rectangle( Point(), Size( 1, 1 ) );
4362cdf0e10cSrcweir                     rRect2 = Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
4363cdf0e10cSrcweir                 }
4364cdf0e10cSrcweir             }
4365cdf0e10cSrcweir             else
4366cdf0e10cSrcweir             {
4367cdf0e10cSrcweir                 Polygon aPoly( sizeof( aAccentPos ) / sizeof( long ) / 2,
4368cdf0e10cSrcweir                                (const Point*)aAccentPos,
4369cdf0e10cSrcweir                                aAccentPolyFlags );
4370cdf0e10cSrcweir                 double dScale = ((double)nDotSize)/1000.0;
4371cdf0e10cSrcweir                 aPoly.Scale( dScale, dScale );
4372cdf0e10cSrcweir                 Polygon aTemp;
4373cdf0e10cSrcweir                 aPoly.AdaptiveSubdivide( aTemp );
4374cdf0e10cSrcweir                 Rectangle aBoundRect = aTemp.GetBoundRect();
4375cdf0e10cSrcweir                 rWidth = aBoundRect.GetWidth();
4376cdf0e10cSrcweir                 nDotSize = aBoundRect.GetHeight();
4377cdf0e10cSrcweir                 rPolyPoly.Insert( aTemp );
4378cdf0e10cSrcweir             }
4379cdf0e10cSrcweir             break;
4380cdf0e10cSrcweir     }
4381cdf0e10cSrcweir 
4382cdf0e10cSrcweir     // calculate position
4383cdf0e10cSrcweir     long nOffY = 1+(mnDPIY/300); // one visible pixel space
4384cdf0e10cSrcweir     long nSpaceY = nHeight-nDotSize;
4385cdf0e10cSrcweir     if ( nSpaceY >= nOffY*2 )
4386cdf0e10cSrcweir         rYOff += nOffY;
4387cdf0e10cSrcweir     if ( !(eEmphasis & EMPHASISMARK_POS_BELOW) )
4388cdf0e10cSrcweir         rYOff += nDotSize;
4389cdf0e10cSrcweir }
4390cdf0e10cSrcweir 
4391cdf0e10cSrcweir // -----------------------------------------------------------------------
4392cdf0e10cSrcweir 
4393cdf0e10cSrcweir void OutputDevice::ImplDrawEmphasisMark( long nBaseX, long nX, long nY,
4394cdf0e10cSrcweir                                          const PolyPolygon& rPolyPoly, sal_Bool bPolyLine,
4395cdf0e10cSrcweir                                          const Rectangle& rRect1, const Rectangle& rRect2 )
4396cdf0e10cSrcweir {
4397cdf0e10cSrcweir     // TODO: pass nWidth as width of this mark
4398cdf0e10cSrcweir     long nWidth = 0;
4399cdf0e10cSrcweir 
4400cdf0e10cSrcweir     if( IsRTLEnabled() )
4401cdf0e10cSrcweir         // --- RTL --- mirror at basex
4402cdf0e10cSrcweir         nX = nBaseX - nWidth - (nX - nBaseX - 1);
4403cdf0e10cSrcweir 
4404cdf0e10cSrcweir     nX -= mnOutOffX;
4405cdf0e10cSrcweir     nY -= mnOutOffY;
4406cdf0e10cSrcweir 
4407cdf0e10cSrcweir     if ( rPolyPoly.Count() )
4408cdf0e10cSrcweir     {
4409cdf0e10cSrcweir         if ( bPolyLine )
4410cdf0e10cSrcweir         {
4411cdf0e10cSrcweir             Polygon aPoly = rPolyPoly.GetObject( 0 );
4412cdf0e10cSrcweir             aPoly.Move( nX, nY );
4413cdf0e10cSrcweir             DrawPolyLine( aPoly );
4414cdf0e10cSrcweir         }
4415cdf0e10cSrcweir         else
4416cdf0e10cSrcweir         {
4417cdf0e10cSrcweir             PolyPolygon aPolyPoly = rPolyPoly;
4418cdf0e10cSrcweir             aPolyPoly.Move( nX, nY );
4419cdf0e10cSrcweir             DrawPolyPolygon( aPolyPoly );
4420cdf0e10cSrcweir         }
4421cdf0e10cSrcweir     }
4422cdf0e10cSrcweir 
4423cdf0e10cSrcweir     if ( !rRect1.IsEmpty() )
4424cdf0e10cSrcweir     {
4425cdf0e10cSrcweir         Rectangle aRect( Point( nX+rRect1.Left(),
4426cdf0e10cSrcweir                                 nY+rRect1.Top() ), rRect1.GetSize() );
4427cdf0e10cSrcweir         DrawRect( aRect );
4428cdf0e10cSrcweir     }
4429cdf0e10cSrcweir 
4430cdf0e10cSrcweir     if ( !rRect2.IsEmpty() )
4431cdf0e10cSrcweir     {
4432cdf0e10cSrcweir         Rectangle aRect( Point( nX+rRect2.Left(),
4433cdf0e10cSrcweir                                 nY+rRect2.Top() ), rRect2.GetSize() );
4434cdf0e10cSrcweir 
4435cdf0e10cSrcweir         DrawRect( aRect );
4436cdf0e10cSrcweir     }
4437cdf0e10cSrcweir }
4438cdf0e10cSrcweir 
4439cdf0e10cSrcweir // -----------------------------------------------------------------------
4440cdf0e10cSrcweir 
4441cdf0e10cSrcweir void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
4442cdf0e10cSrcweir {
4443cdf0e10cSrcweir     Color               aOldColor       = GetTextColor();
4444cdf0e10cSrcweir     Color               aOldLineColor   = GetLineColor();
4445cdf0e10cSrcweir     Color               aOldFillColor   = GetFillColor();
4446cdf0e10cSrcweir     sal_Bool                bOldMap         = mbMap;
4447cdf0e10cSrcweir     GDIMetaFile*        pOldMetaFile    = mpMetaFile;
4448cdf0e10cSrcweir     mpMetaFile = NULL;
4449cdf0e10cSrcweir     EnableMapMode( sal_False );
4450cdf0e10cSrcweir 
4451cdf0e10cSrcweir     FontEmphasisMark    nEmphasisMark = ImplGetEmphasisMarkStyle( maFont );
4452cdf0e10cSrcweir     PolyPolygon         aPolyPoly;
4453cdf0e10cSrcweir     Rectangle           aRect1;
4454cdf0e10cSrcweir     Rectangle           aRect2;
4455cdf0e10cSrcweir     long                nEmphasisYOff;
4456cdf0e10cSrcweir     long                nEmphasisWidth;
4457cdf0e10cSrcweir     long                nEmphasisHeight;
4458cdf0e10cSrcweir     sal_Bool                bPolyLine;
4459cdf0e10cSrcweir 
4460cdf0e10cSrcweir     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
4461cdf0e10cSrcweir         nEmphasisHeight = mnEmphasisDescent;
4462cdf0e10cSrcweir     else
4463cdf0e10cSrcweir         nEmphasisHeight = mnEmphasisAscent;
4464cdf0e10cSrcweir 
4465cdf0e10cSrcweir     ImplGetEmphasisMark( aPolyPoly, bPolyLine,
4466cdf0e10cSrcweir                          aRect1, aRect2,
4467cdf0e10cSrcweir                          nEmphasisYOff, nEmphasisWidth,
4468cdf0e10cSrcweir                          nEmphasisMark,
4469cdf0e10cSrcweir                          nEmphasisHeight, mpFontEntry->mnOrientation );
4470cdf0e10cSrcweir 
4471cdf0e10cSrcweir     if ( bPolyLine )
4472cdf0e10cSrcweir     {
4473cdf0e10cSrcweir         SetLineColor( GetTextColor() );
4474cdf0e10cSrcweir         SetFillColor();
4475cdf0e10cSrcweir     }
4476cdf0e10cSrcweir     else
4477cdf0e10cSrcweir     {
4478cdf0e10cSrcweir         SetLineColor();
4479cdf0e10cSrcweir         SetFillColor( GetTextColor() );
4480cdf0e10cSrcweir     }
4481cdf0e10cSrcweir 
4482cdf0e10cSrcweir     Point aOffset = Point(0,0);
4483cdf0e10cSrcweir 
4484cdf0e10cSrcweir     if ( nEmphasisMark & EMPHASISMARK_POS_BELOW )
4485cdf0e10cSrcweir         aOffset.Y() += mpFontEntry->maMetric.mnDescent + nEmphasisYOff;
4486cdf0e10cSrcweir     else
4487cdf0e10cSrcweir         aOffset.Y() -= mpFontEntry->maMetric.mnAscent + nEmphasisYOff;
4488cdf0e10cSrcweir 
4489cdf0e10cSrcweir     long nEmphasisWidth2  = nEmphasisWidth / 2;
4490cdf0e10cSrcweir     long nEmphasisHeight2 = nEmphasisHeight / 2;
4491cdf0e10cSrcweir     aOffset += Point( nEmphasisWidth2, nEmphasisHeight2 );
4492cdf0e10cSrcweir 
4493cdf0e10cSrcweir     Point aOutPoint;
4494cdf0e10cSrcweir     Rectangle aRectangle;
4495cdf0e10cSrcweir     for( int nStart = 0;;)
4496cdf0e10cSrcweir     {
4497cdf0e10cSrcweir         sal_GlyphId nGlyphIndex;
4498cdf0e10cSrcweir         if( !rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aOutPoint, nStart ) )
4499cdf0e10cSrcweir             break;
4500cdf0e10cSrcweir 
4501cdf0e10cSrcweir         if( !mpGraphics->GetGlyphBoundRect( nGlyphIndex, aRectangle ) )
4502cdf0e10cSrcweir             continue;
4503cdf0e10cSrcweir 
4504cdf0e10cSrcweir         if( !rSalLayout.IsSpacingGlyph( nGlyphIndex ) )
4505cdf0e10cSrcweir         {
4506cdf0e10cSrcweir             Point aAdjPoint = aOffset;
4507cdf0e10cSrcweir             aAdjPoint.X() += aRectangle.Left() + (aRectangle.GetWidth() - nEmphasisWidth) / 2;
4508cdf0e10cSrcweir             if ( mpFontEntry->mnOrientation )
4509cdf0e10cSrcweir                 ImplRotatePos( 0, 0, aAdjPoint.X(), aAdjPoint.Y(), mpFontEntry->mnOrientation );
4510cdf0e10cSrcweir             aOutPoint += aAdjPoint;
4511cdf0e10cSrcweir             aOutPoint -= Point( nEmphasisWidth2, nEmphasisHeight2 );
4512cdf0e10cSrcweir             ImplDrawEmphasisMark( rSalLayout.DrawBase().X(),
4513cdf0e10cSrcweir                                   aOutPoint.X(), aOutPoint.Y(),
4514cdf0e10cSrcweir                                   aPolyPoly, bPolyLine, aRect1, aRect2 );
4515cdf0e10cSrcweir         }
4516cdf0e10cSrcweir     }
4517cdf0e10cSrcweir 
4518cdf0e10cSrcweir     SetLineColor( aOldLineColor );
4519cdf0e10cSrcweir     SetFillColor( aOldFillColor );
4520cdf0e10cSrcweir     EnableMapMode( bOldMap );
4521cdf0e10cSrcweir     mpMetaFile = pOldMetaFile;
4522cdf0e10cSrcweir }
4523cdf0e10cSrcweir 
4524cdf0e10cSrcweir // -----------------------------------------------------------------------
4525cdf0e10cSrcweir 
4526cdf0e10cSrcweir bool OutputDevice::ImplDrawRotateText( SalLayout& rSalLayout )
4527cdf0e10cSrcweir {
4528cdf0e10cSrcweir     int nX = rSalLayout.DrawBase().X();
4529cdf0e10cSrcweir     int nY = rSalLayout.DrawBase().Y();
4530cdf0e10cSrcweir 
4531cdf0e10cSrcweir     Rectangle aBoundRect;
4532cdf0e10cSrcweir     rSalLayout.DrawBase() = Point( 0, 0 );
4533cdf0e10cSrcweir     rSalLayout.DrawOffset() = Point( 0, 0 );
4534cdf0e10cSrcweir     if( !rSalLayout.GetBoundRect( *mpGraphics, aBoundRect ) )
4535cdf0e10cSrcweir     {
4536cdf0e10cSrcweir         // guess vertical text extents if GetBoundRect failed
4537cdf0e10cSrcweir         int nRight = rSalLayout.GetTextWidth();
4538cdf0e10cSrcweir         int nTop = mpFontEntry->maMetric.mnAscent + mnEmphasisAscent;
4539cdf0e10cSrcweir         long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
4540cdf0e10cSrcweir         aBoundRect = Rectangle( 0, -nTop, nRight, nHeight - nTop );
4541cdf0e10cSrcweir     }
4542cdf0e10cSrcweir 
4543cdf0e10cSrcweir     // cache virtual device for rotation
4544cdf0e10cSrcweir     if ( !mpOutDevData )
4545cdf0e10cSrcweir         ImplInitOutDevData();
4546cdf0e10cSrcweir     if ( !mpOutDevData->mpRotateDev )
4547cdf0e10cSrcweir         mpOutDevData->mpRotateDev = new VirtualDevice( *this, 1 );
4548cdf0e10cSrcweir     VirtualDevice* pVDev = mpOutDevData->mpRotateDev;
4549cdf0e10cSrcweir 
4550cdf0e10cSrcweir     // size it accordingly
4551cdf0e10cSrcweir     if( !pVDev->SetOutputSizePixel( aBoundRect.GetSize() ) )
4552cdf0e10cSrcweir         return false;
4553cdf0e10cSrcweir 
4554cdf0e10cSrcweir     Font aFont( GetFont() );
4555cdf0e10cSrcweir     aFont.SetOrientation( 0 );
4556cdf0e10cSrcweir     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
4557cdf0e10cSrcweir     pVDev->SetFont( aFont );
4558cdf0e10cSrcweir     pVDev->SetTextColor( Color( COL_BLACK ) );
4559cdf0e10cSrcweir     pVDev->SetTextFillColor();
4560cdf0e10cSrcweir     pVDev->ImplNewFont();
4561cdf0e10cSrcweir     pVDev->ImplInitFont();
4562cdf0e10cSrcweir     pVDev->ImplInitTextColor();
4563cdf0e10cSrcweir 
4564cdf0e10cSrcweir     // draw text into upper left corner
4565cdf0e10cSrcweir     rSalLayout.DrawBase() -= aBoundRect.TopLeft();
4566cdf0e10cSrcweir     rSalLayout.DrawText( *((OutputDevice*)pVDev)->mpGraphics );
4567cdf0e10cSrcweir 
4568cdf0e10cSrcweir     Bitmap aBmp = pVDev->GetBitmap( Point(), aBoundRect.GetSize() );
4569cdf0e10cSrcweir     if ( !aBmp || !aBmp.Rotate( mpFontEntry->mnOwnOrientation, COL_WHITE ) )
4570cdf0e10cSrcweir         return false;
4571cdf0e10cSrcweir 
4572cdf0e10cSrcweir     // calculate rotation offset
4573cdf0e10cSrcweir     Polygon aPoly( aBoundRect );
4574cdf0e10cSrcweir     aPoly.Rotate( Point(), mpFontEntry->mnOwnOrientation );
4575cdf0e10cSrcweir     Point aPoint = aPoly.GetBoundRect().TopLeft();
4576cdf0e10cSrcweir     aPoint += Point( nX, nY );
4577cdf0e10cSrcweir 
4578cdf0e10cSrcweir     // mask output with text colored bitmap
4579cdf0e10cSrcweir     GDIMetaFile* pOldMetaFile = mpMetaFile;
4580cdf0e10cSrcweir     long nOldOffX = mnOutOffX;
4581cdf0e10cSrcweir     long nOldOffY = mnOutOffY;
4582cdf0e10cSrcweir     sal_Bool bOldMap = mbMap;
4583cdf0e10cSrcweir 
4584cdf0e10cSrcweir     mnOutOffX   = 0L;
4585cdf0e10cSrcweir     mnOutOffY   = 0L;
4586cdf0e10cSrcweir     mpMetaFile  = NULL;
4587cdf0e10cSrcweir     EnableMapMode( sal_False );
4588cdf0e10cSrcweir 
4589cdf0e10cSrcweir     DrawMask( aPoint, aBmp, GetTextColor() );
4590cdf0e10cSrcweir 
4591cdf0e10cSrcweir     EnableMapMode( bOldMap );
4592cdf0e10cSrcweir     mnOutOffX   = nOldOffX;
4593cdf0e10cSrcweir     mnOutOffY   = nOldOffY;
4594cdf0e10cSrcweir     mpMetaFile  = pOldMetaFile;
4595cdf0e10cSrcweir 
4596cdf0e10cSrcweir     return true;
4597cdf0e10cSrcweir }
4598cdf0e10cSrcweir 
4599cdf0e10cSrcweir // -----------------------------------------------------------------------
4600cdf0e10cSrcweir 
4601cdf0e10cSrcweir void OutputDevice::ImplDrawTextDirect( SalLayout& rSalLayout, sal_Bool bTextLines )
4602cdf0e10cSrcweir {
4603cdf0e10cSrcweir     if( mpFontEntry->mnOwnOrientation )
4604cdf0e10cSrcweir         if( ImplDrawRotateText( rSalLayout ) )
4605cdf0e10cSrcweir             return;
4606cdf0e10cSrcweir 
4607cdf0e10cSrcweir     long nOldX = rSalLayout.DrawBase().X();
4608cdf0e10cSrcweir     if( ! (mpPDFWriter && mpPDFWriter->isBuiltinFont(mpFontEntry->maFontSelData.mpFontData) ) )
4609cdf0e10cSrcweir     {
4610cdf0e10cSrcweir         if( ImplHasMirroredGraphics() )
4611cdf0e10cSrcweir         {
4612cdf0e10cSrcweir             long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
4613cdf0e10cSrcweir             long x = rSalLayout.DrawBase().X();
4614cdf0e10cSrcweir             rSalLayout.DrawBase().X() = w - 1 - x;
4615cdf0e10cSrcweir             if( !IsRTLEnabled() )
4616cdf0e10cSrcweir             {
4617cdf0e10cSrcweir                 OutputDevice *pOutDevRef = (OutputDevice *)this;
4618cdf0e10cSrcweir                 // mirror this window back
4619cdf0e10cSrcweir                 long devX = w-pOutDevRef->mnOutWidth-pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
4620cdf0e10cSrcweir                 rSalLayout.DrawBase().X() = devX + ( pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) ) ;
4621cdf0e10cSrcweir             }
4622cdf0e10cSrcweir         }
4623cdf0e10cSrcweir         else if( IsRTLEnabled() )
4624cdf0e10cSrcweir         {
4625cdf0e10cSrcweir             //long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
4626cdf0e10cSrcweir             //long x = rSalLayout.DrawBase().X();
4627cdf0e10cSrcweir             OutputDevice *pOutDevRef = (OutputDevice *)this;
4628cdf0e10cSrcweir             // mirror this window back
4629cdf0e10cSrcweir             long devX = pOutDevRef->mnOutOffX;   // re-mirrored mnOutOffX
4630cdf0e10cSrcweir             rSalLayout.DrawBase().X() = pOutDevRef->mnOutWidth - 1 - (rSalLayout.DrawBase().X() - devX) + devX;
4631cdf0e10cSrcweir         }
4632cdf0e10cSrcweir 
4633cdf0e10cSrcweir         rSalLayout.DrawText( *mpGraphics );
4634cdf0e10cSrcweir     }
4635cdf0e10cSrcweir 
4636cdf0e10cSrcweir     rSalLayout.DrawBase().X() = nOldX;
4637cdf0e10cSrcweir 
4638cdf0e10cSrcweir     if( bTextLines )
4639cdf0e10cSrcweir         ImplDrawTextLines( rSalLayout,
4640cdf0e10cSrcweir             maFont.GetStrikeout(), maFont.GetUnderline(), maFont.GetOverline(),
4641cdf0e10cSrcweir             maFont.IsWordLineMode(), ImplIsUnderlineAbove( maFont ) );
4642cdf0e10cSrcweir 
4643cdf0e10cSrcweir     // emphasis marks
4644cdf0e10cSrcweir     if( maFont.GetEmphasisMark() & EMPHASISMARK_STYLE )
4645cdf0e10cSrcweir         ImplDrawEmphasisMarks( rSalLayout );
4646cdf0e10cSrcweir }
4647cdf0e10cSrcweir 
4648cdf0e10cSrcweir // -----------------------------------------------------------------------
4649cdf0e10cSrcweir 
4650cdf0e10cSrcweir void OutputDevice::ImplDrawSpecialText( SalLayout& rSalLayout )
4651cdf0e10cSrcweir {
4652cdf0e10cSrcweir     Color       aOldColor           = GetTextColor();
4653cdf0e10cSrcweir     Color       aOldTextLineColor   = GetTextLineColor();
4654cdf0e10cSrcweir     Color       aOldOverlineColor   = GetOverlineColor();
4655cdf0e10cSrcweir     FontRelief  eRelief             = maFont.GetRelief();
4656cdf0e10cSrcweir 
4657cdf0e10cSrcweir     Point aOrigPos = rSalLayout.DrawBase();
4658cdf0e10cSrcweir     if ( eRelief != RELIEF_NONE )
4659cdf0e10cSrcweir     {
4660cdf0e10cSrcweir         Color   aReliefColor( COL_LIGHTGRAY );
4661cdf0e10cSrcweir         Color   aTextColor( aOldColor );
4662cdf0e10cSrcweir 
4663cdf0e10cSrcweir         Color   aTextLineColor( aOldTextLineColor );
4664cdf0e10cSrcweir         Color   aOverlineColor( aOldOverlineColor );
4665cdf0e10cSrcweir 
4666cdf0e10cSrcweir         // we don't have a automatic color, so black is always drawn on white
4667cdf0e10cSrcweir         if ( aTextColor.GetColor() == COL_BLACK )
4668cdf0e10cSrcweir             aTextColor = Color( COL_WHITE );
4669cdf0e10cSrcweir         if ( aTextLineColor.GetColor() == COL_BLACK )
4670cdf0e10cSrcweir             aTextLineColor = Color( COL_WHITE );
4671cdf0e10cSrcweir         if ( aOverlineColor.GetColor() == COL_BLACK )
4672cdf0e10cSrcweir             aOverlineColor = Color( COL_WHITE );
4673cdf0e10cSrcweir 
4674cdf0e10cSrcweir         // relief-color is black for white text, in all other cases
4675cdf0e10cSrcweir         // we set this to LightGray
4676cdf0e10cSrcweir         if ( aTextColor.GetColor() == COL_WHITE )
4677cdf0e10cSrcweir             aReliefColor = Color( COL_BLACK );
4678cdf0e10cSrcweir         SetTextLineColor( aReliefColor );
4679cdf0e10cSrcweir         SetOverlineColor( aReliefColor );
4680cdf0e10cSrcweir         SetTextColor( aReliefColor );
4681cdf0e10cSrcweir         ImplInitTextColor();
4682cdf0e10cSrcweir 
4683cdf0e10cSrcweir         // calculate offset - for high resolution printers the offset
4684cdf0e10cSrcweir         // should be greater so that the effect is visible
4685cdf0e10cSrcweir         long nOff = 1;
4686cdf0e10cSrcweir         nOff += mnDPIX/300;
4687cdf0e10cSrcweir 
4688cdf0e10cSrcweir         if ( eRelief == RELIEF_ENGRAVED )
4689cdf0e10cSrcweir             nOff = -nOff;
4690cdf0e10cSrcweir         rSalLayout.DrawOffset() += Point( nOff, nOff);
4691cdf0e10cSrcweir         ImplDrawTextDirect( rSalLayout, mbTextLines );
4692cdf0e10cSrcweir         rSalLayout.DrawOffset() -= Point( nOff, nOff);
4693cdf0e10cSrcweir 
4694cdf0e10cSrcweir         SetTextLineColor( aTextLineColor );
4695cdf0e10cSrcweir         SetOverlineColor( aOverlineColor );
4696cdf0e10cSrcweir         SetTextColor( aTextColor );
4697cdf0e10cSrcweir         ImplInitTextColor();
4698cdf0e10cSrcweir         ImplDrawTextDirect( rSalLayout, mbTextLines );
4699cdf0e10cSrcweir 
4700cdf0e10cSrcweir         SetTextLineColor( aOldTextLineColor );
4701cdf0e10cSrcweir         SetOverlineColor( aOldOverlineColor );
4702cdf0e10cSrcweir 
4703cdf0e10cSrcweir         if ( aTextColor != aOldColor )
4704cdf0e10cSrcweir         {
4705cdf0e10cSrcweir             SetTextColor( aOldColor );
4706cdf0e10cSrcweir             ImplInitTextColor();
4707cdf0e10cSrcweir         }
4708cdf0e10cSrcweir     }
4709cdf0e10cSrcweir     else
4710cdf0e10cSrcweir     {
4711cdf0e10cSrcweir         if ( maFont.IsShadow() )
4712cdf0e10cSrcweir         {
4713cdf0e10cSrcweir             long nOff = 1 + ((mpFontEntry->mnLineHeight-24)/24);
4714cdf0e10cSrcweir             if ( maFont.IsOutline() )
4715cdf0e10cSrcweir                 nOff++;
4716cdf0e10cSrcweir             SetTextLineColor();
4717cdf0e10cSrcweir             SetOverlineColor();
4718cdf0e10cSrcweir             if ( (GetTextColor().GetColor() == COL_BLACK)
4719cdf0e10cSrcweir             ||   (GetTextColor().GetLuminance() < 8) )
4720cdf0e10cSrcweir                 SetTextColor( Color( COL_LIGHTGRAY ) );
4721cdf0e10cSrcweir             else
4722cdf0e10cSrcweir                 SetTextColor( Color( COL_BLACK ) );
4723cdf0e10cSrcweir             ImplInitTextColor();
4724cdf0e10cSrcweir             rSalLayout.DrawBase() += Point( nOff, nOff );
4725cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4726cdf0e10cSrcweir             rSalLayout.DrawBase() -= Point( nOff, nOff );
4727cdf0e10cSrcweir             SetTextColor( aOldColor );
4728cdf0e10cSrcweir             SetTextLineColor( aOldTextLineColor );
4729cdf0e10cSrcweir             SetOverlineColor( aOldOverlineColor );
4730cdf0e10cSrcweir             ImplInitTextColor();
4731cdf0e10cSrcweir 
4732cdf0e10cSrcweir             if ( !maFont.IsOutline() )
4733cdf0e10cSrcweir                 ImplDrawTextDirect( rSalLayout, mbTextLines );
4734cdf0e10cSrcweir         }
4735cdf0e10cSrcweir 
4736cdf0e10cSrcweir         if ( maFont.IsOutline() )
4737cdf0e10cSrcweir         {
4738cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos + Point(-1,-1);
4739cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4740cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos + Point(+1,+1);
4741cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4742cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos + Point(-1,+0);
4743cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4744cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos + Point(-1,+1);
4745cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4746cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos + Point(+0,+1);
4747cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4748cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos + Point(+0,-1);
4749cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4750cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos + Point(+1,-1);
4751cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4752cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos + Point(+1,+0);
4753cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4754cdf0e10cSrcweir             rSalLayout.DrawBase() = aOrigPos;
4755cdf0e10cSrcweir 
4756cdf0e10cSrcweir             SetTextColor( Color( COL_WHITE ) );
4757cdf0e10cSrcweir             SetTextLineColor( Color( COL_WHITE ) );
4758cdf0e10cSrcweir             SetOverlineColor( Color( COL_WHITE ) );
4759cdf0e10cSrcweir             ImplInitTextColor();
4760cdf0e10cSrcweir             ImplDrawTextDirect( rSalLayout, mbTextLines );
4761cdf0e10cSrcweir             SetTextColor( aOldColor );
4762cdf0e10cSrcweir             SetTextLineColor( aOldTextLineColor );
4763cdf0e10cSrcweir             SetOverlineColor( aOldOverlineColor );
4764cdf0e10cSrcweir             ImplInitTextColor();
4765cdf0e10cSrcweir         }
4766cdf0e10cSrcweir     }
4767cdf0e10cSrcweir }
4768cdf0e10cSrcweir 
4769cdf0e10cSrcweir // -----------------------------------------------------------------------
4770cdf0e10cSrcweir 
4771cdf0e10cSrcweir void OutputDevice::ImplDrawText( SalLayout& rSalLayout )
4772cdf0e10cSrcweir {
4773cdf0e10cSrcweir     if( mbInitClipRegion )
4774cdf0e10cSrcweir         ImplInitClipRegion();
4775cdf0e10cSrcweir     if( mbOutputClipped )
4776cdf0e10cSrcweir         return;
4777cdf0e10cSrcweir     if( mbInitTextColor )
4778cdf0e10cSrcweir         ImplInitTextColor();
4779cdf0e10cSrcweir 
4780cdf0e10cSrcweir     rSalLayout.DrawBase() += Point( mnTextOffX, mnTextOffY );
4781cdf0e10cSrcweir 
4782cdf0e10cSrcweir     if( IsTextFillColor() )
4783cdf0e10cSrcweir         ImplDrawTextBackground( rSalLayout );
4784cdf0e10cSrcweir 
4785cdf0e10cSrcweir     if( mbTextSpecial )
4786cdf0e10cSrcweir         ImplDrawSpecialText( rSalLayout );
4787cdf0e10cSrcweir     else
4788cdf0e10cSrcweir         ImplDrawTextDirect( rSalLayout, mbTextLines );
4789cdf0e10cSrcweir }
4790cdf0e10cSrcweir 
4791cdf0e10cSrcweir // -----------------------------------------------------------------------
4792cdf0e10cSrcweir 
4793cdf0e10cSrcweir long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo& rLineInfo,
4794cdf0e10cSrcweir                                      long nWidth, const XubString& rStr,
4795cdf0e10cSrcweir                                      sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
4796cdf0e10cSrcweir {
4797cdf0e10cSrcweir     DBG_ASSERTWARNING( nWidth >= 0, "ImplGetTextLines: nWidth <= 0!" );
4798cdf0e10cSrcweir 
4799cdf0e10cSrcweir     if ( nWidth <= 0 )
4800cdf0e10cSrcweir         nWidth = 1;
4801cdf0e10cSrcweir 
4802cdf0e10cSrcweir     long nMaxLineWidth  = 0;
4803cdf0e10cSrcweir     rLineInfo.Clear();
4804cdf0e10cSrcweir     if ( rStr.Len() && (nWidth > 0) )
4805cdf0e10cSrcweir     {
4806cdf0e10cSrcweir         ::rtl::OUString aText( rStr );
4807cdf0e10cSrcweir         uno::Reference < i18n::XBreakIterator > xBI;
4808cdf0e10cSrcweir         // get service provider
4809cdf0e10cSrcweir         uno::Reference< lang::XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() );
4810cdf0e10cSrcweir 
4811cdf0e10cSrcweir         uno::Reference< linguistic2::XHyphenator > xHyph;
4812cdf0e10cSrcweir         if( xSMgr.is() )
4813cdf0e10cSrcweir         {
4814cdf0e10cSrcweir             uno::Reference< linguistic2::XLinguServiceManager> xLinguMgr(xSMgr->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.linguistic2.LinguServiceManager"))),uno::UNO_QUERY);
4815cdf0e10cSrcweir             if ( xLinguMgr.is() )
4816cdf0e10cSrcweir             {
4817cdf0e10cSrcweir                 xHyph = xLinguMgr->getHyphenator();
4818cdf0e10cSrcweir             }
4819cdf0e10cSrcweir         }
4820cdf0e10cSrcweir 
4821cdf0e10cSrcweir         i18n::LineBreakHyphenationOptions aHyphOptions( xHyph, uno::Sequence <beans::PropertyValue>(), 1 );
4822cdf0e10cSrcweir         i18n::LineBreakUserOptions aUserOptions;
4823cdf0e10cSrcweir 
4824cdf0e10cSrcweir         xub_StrLen nPos = 0;
4825cdf0e10cSrcweir         xub_StrLen nLen = rStr.Len();
4826cdf0e10cSrcweir         while ( nPos < nLen )
4827cdf0e10cSrcweir         {
4828cdf0e10cSrcweir             xub_StrLen nBreakPos = nPos;
4829cdf0e10cSrcweir 
4830cdf0e10cSrcweir             while ( ( nBreakPos < nLen ) && ( rStr.GetChar( nBreakPos ) != _CR ) && ( rStr.GetChar( nBreakPos ) != _LF ) )
4831cdf0e10cSrcweir                 nBreakPos++;
4832cdf0e10cSrcweir 
4833cdf0e10cSrcweir             long nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
4834cdf0e10cSrcweir             if ( ( nLineWidth > nWidth ) && ( nStyle & TEXT_DRAW_WORDBREAK ) )
4835cdf0e10cSrcweir             {
4836cdf0e10cSrcweir                 if ( !xBI.is() )
4837cdf0e10cSrcweir                     xBI = vcl::unohelper::CreateBreakIterator();
4838cdf0e10cSrcweir 
4839cdf0e10cSrcweir                 if ( xBI.is() )
4840cdf0e10cSrcweir                 {
4841cdf0e10cSrcweir                     const com::sun::star::lang::Locale& rDefLocale(Application::GetSettings().GetUILocale());
4842cdf0e10cSrcweir                     xub_StrLen nSoftBreak = _rLayout.GetTextBreak( rStr, nWidth, nPos, nBreakPos - nPos );
4843cdf0e10cSrcweir                     DBG_ASSERT( nSoftBreak < nBreakPos, "Break?!" );
4844cdf0e10cSrcweir                     //aHyphOptions.hyphenIndex = nSoftBreak;
4845cdf0e10cSrcweir                     i18n::LineBreakResults aLBR = xBI->getLineBreak( aText, nSoftBreak, rDefLocale, nPos, aHyphOptions, aUserOptions );
4846cdf0e10cSrcweir                     nBreakPos = (xub_StrLen)aLBR.breakIndex;
4847cdf0e10cSrcweir                     if ( nBreakPos <= nPos )
4848cdf0e10cSrcweir                         nBreakPos = nSoftBreak;
4849cdf0e10cSrcweir                     if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
4850cdf0e10cSrcweir                     {
4851cdf0e10cSrcweir                         // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch
4852cdf0e10cSrcweir                         // die Silbentrennung jagen...
4853cdf0e10cSrcweir                         // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt,
4854cdf0e10cSrcweir                         // nBreakPos ist der Wort-Anfang
4855cdf0e10cSrcweir                         // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort
4856cdf0e10cSrcweir                         // auf mehr als Zwei Zeilen gebrochen wird...
4857cdf0e10cSrcweir                         if ( xHyph.is() )
4858cdf0e10cSrcweir                         {
4859cdf0e10cSrcweir                             sal_Unicode cAlternateReplChar = 0;
4860cdf0e10cSrcweir                             sal_Unicode cAlternateExtraChar = 0;
4861cdf0e10cSrcweir                             i18n::Boundary aBoundary = xBI->getWordBoundary( aText, nBreakPos, rDefLocale, ::com::sun::star::i18n::WordType::DICTIONARY_WORD, sal_True );
4862cdf0e10cSrcweir                 //          sal_uInt16 nWordStart = nBreakPos;
4863cdf0e10cSrcweir                 //          sal_uInt16 nBreakPos_OLD = nBreakPos;
4864cdf0e10cSrcweir                             sal_uInt16 nWordStart = nPos;
4865cdf0e10cSrcweir                             sal_uInt16 nWordEnd = (sal_uInt16) aBoundary.endPos;
4866cdf0e10cSrcweir                             DBG_ASSERT( nWordEnd > nWordStart, "ImpBreakLine: Start >= End?" );
4867cdf0e10cSrcweir 
4868cdf0e10cSrcweir                             sal_uInt16 nWordLen = nWordEnd - nWordStart;
4869cdf0e10cSrcweir                             if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
4870cdf0e10cSrcweir                             {
4871cdf0e10cSrcweir                                 // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
4872cdf0e10cSrcweir                                 // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
4873cdf0e10cSrcweir                                 String aWord( aText, nWordStart, nWordLen );
4874cdf0e10cSrcweir                                 sal_uInt16 nMinTrail = static_cast<sal_uInt16>(nWordEnd-nSoftBreak+1);  //+1: Vor dem angeknacksten Buchstaben
4875cdf0e10cSrcweir                                 uno::Reference< linguistic2::XHyphenatedWord > xHyphWord;
4876cdf0e10cSrcweir                                 if (xHyph.is())
4877cdf0e10cSrcweir                                     xHyphWord = xHyph->hyphenate( aWord, rDefLocale, aWord.Len() - nMinTrail, uno::Sequence< beans::PropertyValue >() );
4878cdf0e10cSrcweir                                 if (xHyphWord.is())
4879cdf0e10cSrcweir                                 {
4880cdf0e10cSrcweir                                     sal_Bool bAlternate = xHyphWord->isAlternativeSpelling();
4881cdf0e10cSrcweir                                     sal_uInt16 _nWordLen = 1 + xHyphWord->getHyphenPos();
4882cdf0e10cSrcweir 
4883cdf0e10cSrcweir                                     if ( ( _nWordLen >= 2 ) && ( (nWordStart+_nWordLen) >= ( 2 ) ) )
4884cdf0e10cSrcweir                                     {
4885cdf0e10cSrcweir                                         if ( !bAlternate )
4886cdf0e10cSrcweir                                         {
4887cdf0e10cSrcweir                                             nBreakPos = nWordStart + _nWordLen;
4888cdf0e10cSrcweir                                         }
4889cdf0e10cSrcweir                                         else
4890cdf0e10cSrcweir                                         {
4891cdf0e10cSrcweir                                             String aAlt( xHyphWord->getHyphenatedWord() );
4892cdf0e10cSrcweir 
4893cdf0e10cSrcweir                                             // Wir gehen von zwei Faellen aus, die nun
4894cdf0e10cSrcweir                                             // vorliegen koennen:
4895cdf0e10cSrcweir                                             // 1) packen wird zu pak-ken
4896cdf0e10cSrcweir                                             // 2) Schiffahrt wird zu Schiff-fahrt
4897cdf0e10cSrcweir                                             // In Fall 1 muss ein Zeichen ersetzt werden,
4898cdf0e10cSrcweir                                             // in Fall 2 wird ein Zeichen hinzugefuegt.
4899cdf0e10cSrcweir                                             // Die Identifikation wird erschwert durch Worte wie
4900cdf0e10cSrcweir                                             // "Schiffahrtsbrennesseln", da der Hyphenator alle
4901cdf0e10cSrcweir                                             // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln"
4902cdf0e10cSrcweir                                             // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom
4903cdf0e10cSrcweir                                             // Index des AlternativWord auf aWord schliessen.
4904cdf0e10cSrcweir 
4905cdf0e10cSrcweir                                             // Das ganze geraffel wird durch eine Funktion am
4906cdf0e10cSrcweir                                             // Hyphenator vereinfacht werden, sobald AMA sie einbaut...
4907cdf0e10cSrcweir                                             sal_uInt16 nAltStart = _nWordLen - 1;
4908cdf0e10cSrcweir                                             sal_uInt16 nTxtStart = nAltStart - (aAlt.Len() - aWord.Len());
4909cdf0e10cSrcweir                                             sal_uInt16 nTxtEnd = nTxtStart;
4910cdf0e10cSrcweir                                             sal_uInt16 nAltEnd = nAltStart;
4911cdf0e10cSrcweir 
4912cdf0e10cSrcweir                                             // Die Bereiche zwischen den nStart und nEnd ist
4913cdf0e10cSrcweir                                             // die Differenz zwischen Alternativ- und OriginalString.
4914cdf0e10cSrcweir                                             while( nTxtEnd < aWord.Len() && nAltEnd < aAlt.Len() &&
4915cdf0e10cSrcweir                                                    aWord.GetChar(nTxtEnd) != aAlt.GetChar(nAltEnd) )
4916cdf0e10cSrcweir                                             {
4917cdf0e10cSrcweir                                                 ++nTxtEnd;
4918cdf0e10cSrcweir                                                 ++nAltEnd;
4919cdf0e10cSrcweir                                             }
4920cdf0e10cSrcweir 
4921cdf0e10cSrcweir                                             // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt:
4922cdf0e10cSrcweir                                             if( nAltEnd > nTxtEnd && nAltStart == nAltEnd &&
4923cdf0e10cSrcweir                                                 aWord.GetChar( nTxtEnd ) == aAlt.GetChar(nAltEnd) )
4924cdf0e10cSrcweir                                             {
4925cdf0e10cSrcweir                                                 ++nAltEnd;
4926cdf0e10cSrcweir                                                 ++nTxtStart;
4927cdf0e10cSrcweir                                                 ++nTxtEnd;
4928cdf0e10cSrcweir                                             }
4929cdf0e10cSrcweir 
4930cdf0e10cSrcweir                                             DBG_ASSERT( ( nAltEnd - nAltStart ) == 1, "Alternate: Falsche Annahme!" );
4931cdf0e10cSrcweir 
4932cdf0e10cSrcweir                                             if ( nTxtEnd > nTxtStart )
4933cdf0e10cSrcweir                                                 cAlternateReplChar = aAlt.GetChar( nAltStart );
4934cdf0e10cSrcweir                                             else
4935cdf0e10cSrcweir                                                 cAlternateExtraChar = aAlt.GetChar( nAltStart );
4936cdf0e10cSrcweir 
4937cdf0e10cSrcweir                                             nBreakPos = nWordStart + nTxtStart;
4938cdf0e10cSrcweir                                             if ( cAlternateReplChar )
4939cdf0e10cSrcweir                                                 nBreakPos++;
4940cdf0e10cSrcweir                                         }
4941cdf0e10cSrcweir                                     } // if (xHyphWord.is())
4942cdf0e10cSrcweir                                 } // if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
4943cdf0e10cSrcweir                             } // if ( xHyph.is() )
4944cdf0e10cSrcweir                         } // if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
4945cdf0e10cSrcweir                     }
4946cdf0e10cSrcweir                     nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
4947cdf0e10cSrcweir                 }
4948cdf0e10cSrcweir                 else
4949cdf0e10cSrcweir                 {
4950cdf0e10cSrcweir                     // fallback to something really simple
4951cdf0e10cSrcweir                     sal_uInt16 nSpacePos = STRING_LEN;
4952cdf0e10cSrcweir                     long nW = 0;
4953cdf0e10cSrcweir                     do
4954cdf0e10cSrcweir                     {
4955cdf0e10cSrcweir                         nSpacePos = rStr.SearchBackward( sal_Unicode(' '), nSpacePos );
4956cdf0e10cSrcweir                         if( nSpacePos != STRING_NOTFOUND )
4957cdf0e10cSrcweir                         {
4958cdf0e10cSrcweir                             if( nSpacePos > nPos )
4959cdf0e10cSrcweir                                 nSpacePos--;
4960cdf0e10cSrcweir                             nW = _rLayout.GetTextWidth( rStr, nPos, nSpacePos-nPos );
4961cdf0e10cSrcweir                         }
4962cdf0e10cSrcweir                     } while( nW > nWidth );
4963cdf0e10cSrcweir 
4964cdf0e10cSrcweir                     if( nSpacePos != STRING_NOTFOUND )
4965cdf0e10cSrcweir                     {
4966cdf0e10cSrcweir                         nBreakPos = nSpacePos;
4967cdf0e10cSrcweir                         nLineWidth = _rLayout.GetTextWidth( rStr, nPos, nBreakPos-nPos );
4968cdf0e10cSrcweir                         if( nBreakPos < rStr.Len()-1 )
4969cdf0e10cSrcweir                             nBreakPos++;
4970cdf0e10cSrcweir                     }
4971cdf0e10cSrcweir                 }
4972cdf0e10cSrcweir             }
4973cdf0e10cSrcweir 
4974cdf0e10cSrcweir             if ( nLineWidth > nMaxLineWidth )
4975cdf0e10cSrcweir                 nMaxLineWidth = nLineWidth;
4976cdf0e10cSrcweir 
4977cdf0e10cSrcweir             rLineInfo.AddLine( new ImplTextLineInfo( nLineWidth, nPos, nBreakPos-nPos ) );
4978cdf0e10cSrcweir 
4979cdf0e10cSrcweir             if ( nBreakPos == nPos )
4980cdf0e10cSrcweir                 nBreakPos++;
4981cdf0e10cSrcweir             nPos = nBreakPos;
4982cdf0e10cSrcweir 
4983cdf0e10cSrcweir             if ( ( rStr.GetChar( nPos ) == _CR ) || ( rStr.GetChar( nPos ) == _LF ) )
4984cdf0e10cSrcweir             {
4985cdf0e10cSrcweir                 nPos++;
4986cdf0e10cSrcweir                 // CR/LF?
4987cdf0e10cSrcweir                 if ( ( nPos < nLen ) && ( rStr.GetChar( nPos ) == _LF ) && ( rStr.GetChar( nPos-1 ) == _CR ) )
4988cdf0e10cSrcweir                     nPos++;
4989cdf0e10cSrcweir             }
4990cdf0e10cSrcweir         }
4991cdf0e10cSrcweir     }
4992cdf0e10cSrcweir #ifdef DBG_UTIL
4993cdf0e10cSrcweir     for ( sal_uInt16 nL = 0; nL < rLineInfo.Count(); nL++ )
4994cdf0e10cSrcweir     {
4995cdf0e10cSrcweir         ImplTextLineInfo* pLine = rLineInfo.GetLine( nL );
4996cdf0e10cSrcweir         String aLine( rStr, pLine->GetIndex(), pLine->GetLen() );
4997cdf0e10cSrcweir         DBG_ASSERT( aLine.Search( _CR ) == STRING_NOTFOUND, "ImplGetTextLines - Found CR!" );
4998cdf0e10cSrcweir         DBG_ASSERT( aLine.Search( _LF ) == STRING_NOTFOUND, "ImplGetTextLines - Found LF!" );
4999cdf0e10cSrcweir     }
5000cdf0e10cSrcweir #endif
5001cdf0e10cSrcweir 
5002cdf0e10cSrcweir     return nMaxLineWidth;
5003cdf0e10cSrcweir }
5004cdf0e10cSrcweir 
5005cdf0e10cSrcweir // =======================================================================
5006cdf0e10cSrcweir 
5007cdf0e10cSrcweir void OutputDevice::SetAntialiasing( sal_uInt16 nMode )
5008cdf0e10cSrcweir {
5009cdf0e10cSrcweir     if ( mnAntialiasing != nMode )
5010cdf0e10cSrcweir     {
5011cdf0e10cSrcweir         mnAntialiasing = nMode;
5012cdf0e10cSrcweir         mbInitFont = sal_True;
5013cdf0e10cSrcweir 
5014cdf0e10cSrcweir         if(mpGraphics)
5015cdf0e10cSrcweir         {
5016cdf0e10cSrcweir             mpGraphics->setAntiAliasB2DDraw(mnAntialiasing & ANTIALIASING_ENABLE_B2DDRAW);
5017cdf0e10cSrcweir         }
5018cdf0e10cSrcweir     }
5019cdf0e10cSrcweir 
5020cdf0e10cSrcweir     if( mpAlphaVDev )
5021cdf0e10cSrcweir         mpAlphaVDev->SetAntialiasing( nMode );
5022cdf0e10cSrcweir }
5023cdf0e10cSrcweir 
5024cdf0e10cSrcweir // -----------------------------------------------------------------------
5025cdf0e10cSrcweir 
5026cdf0e10cSrcweir void OutputDevice::SetFont( const Font& rNewFont )
5027cdf0e10cSrcweir {
5028cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetFont()" );
5029cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5030cdf0e10cSrcweir     DBG_CHKOBJ( &rNewFont, Font, NULL );
5031cdf0e10cSrcweir 
5032cdf0e10cSrcweir     Font aFont( rNewFont );
5033cdf0e10cSrcweir     aFont.SetLanguage(rNewFont.GetLanguage());
5034cdf0e10cSrcweir     if ( mnDrawMode & (DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT | DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT | DRAWMODE_SETTINGSTEXT |
5035cdf0e10cSrcweir                        DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL | DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
5036cdf0e10cSrcweir                        DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
5037cdf0e10cSrcweir     {
5038cdf0e10cSrcweir         Color aTextColor( aFont.GetColor() );
5039cdf0e10cSrcweir 
5040cdf0e10cSrcweir         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5041cdf0e10cSrcweir             aTextColor = Color( COL_BLACK );
5042cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5043cdf0e10cSrcweir             aTextColor = Color( COL_WHITE );
5044cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5045cdf0e10cSrcweir         {
5046cdf0e10cSrcweir             const sal_uInt8 cLum = aTextColor.GetLuminance();
5047cdf0e10cSrcweir             aTextColor = Color( cLum, cLum, cLum );
5048cdf0e10cSrcweir         }
5049cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5050cdf0e10cSrcweir             aTextColor = GetSettings().GetStyleSettings().GetFontColor();
5051cdf0e10cSrcweir 
5052cdf0e10cSrcweir         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
5053cdf0e10cSrcweir         {
5054cdf0e10cSrcweir             aTextColor = Color( (aTextColor.GetRed() >> 1 ) | 0x80,
5055cdf0e10cSrcweir                                 (aTextColor.GetGreen() >> 1 ) | 0x80,
5056cdf0e10cSrcweir                                 (aTextColor.GetBlue() >> 1 ) | 0x80 );
5057cdf0e10cSrcweir         }
5058cdf0e10cSrcweir 
5059cdf0e10cSrcweir         aFont.SetColor( aTextColor );
5060cdf0e10cSrcweir 
5061cdf0e10cSrcweir         sal_Bool bTransFill = aFont.IsTransparent();
5062cdf0e10cSrcweir         if ( !bTransFill )
5063cdf0e10cSrcweir         {
5064cdf0e10cSrcweir             Color aTextFillColor( aFont.GetFillColor() );
5065cdf0e10cSrcweir 
5066cdf0e10cSrcweir             if ( mnDrawMode & DRAWMODE_BLACKFILL )
5067cdf0e10cSrcweir                 aTextFillColor = Color( COL_BLACK );
5068cdf0e10cSrcweir             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
5069cdf0e10cSrcweir                 aTextFillColor = Color( COL_WHITE );
5070cdf0e10cSrcweir             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
5071cdf0e10cSrcweir             {
5072cdf0e10cSrcweir                 const sal_uInt8 cLum = aTextFillColor.GetLuminance();
5073cdf0e10cSrcweir                 aTextFillColor = Color( cLum, cLum, cLum );
5074cdf0e10cSrcweir             }
5075cdf0e10cSrcweir             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
5076cdf0e10cSrcweir                 aTextFillColor = GetSettings().GetStyleSettings().GetWindowColor();
5077cdf0e10cSrcweir             else if ( mnDrawMode & DRAWMODE_NOFILL )
5078cdf0e10cSrcweir             {
5079cdf0e10cSrcweir                 aTextFillColor = Color( COL_TRANSPARENT );
5080cdf0e10cSrcweir                 bTransFill = sal_True;
5081cdf0e10cSrcweir             }
5082cdf0e10cSrcweir 
5083cdf0e10cSrcweir             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
5084cdf0e10cSrcweir             {
5085cdf0e10cSrcweir                 aTextFillColor = Color( (aTextFillColor.GetRed() >> 1) | 0x80,
5086cdf0e10cSrcweir                                         (aTextFillColor.GetGreen() >> 1) | 0x80,
5087cdf0e10cSrcweir                                         (aTextFillColor.GetBlue() >> 1) | 0x80 );
5088cdf0e10cSrcweir             }
5089cdf0e10cSrcweir 
5090cdf0e10cSrcweir             aFont.SetFillColor( aTextFillColor );
5091cdf0e10cSrcweir         }
5092cdf0e10cSrcweir     }
5093cdf0e10cSrcweir 
5094cdf0e10cSrcweir     if ( mpMetaFile )
5095cdf0e10cSrcweir     {
5096cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaFontAction( aFont ) );
5097cdf0e10cSrcweir         // the color and alignment actions don't belong here
5098cdf0e10cSrcweir         // TODO: get rid of them without breaking anything...
5099cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextAlignAction( aFont.GetAlign() ) );
5100cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextFillColorAction( aFont.GetFillColor(), !aFont.IsTransparent() ) );
5101cdf0e10cSrcweir     }
5102cdf0e10cSrcweir 
5103cdf0e10cSrcweir #if (OSL_DEBUG_LEVEL > 2) || defined (HDU_DEBUG)
5104cdf0e10cSrcweir     fprintf( stderr, "   OutputDevice::SetFont( name=\"%s\", h=%ld)\n",
5105cdf0e10cSrcweir          OUStringToOString( aFont.GetName(), RTL_TEXTENCODING_UTF8 ).getStr(),
5106cdf0e10cSrcweir          aFont.GetSize().Height() );
5107cdf0e10cSrcweir #endif
5108cdf0e10cSrcweir 
5109cdf0e10cSrcweir     if ( !maFont.IsSameInstance( aFont ) )
5110cdf0e10cSrcweir     {
5111cdf0e10cSrcweir         // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
5112cdf0e10cSrcweir         // because SetTextColor() is used for this.
5113cdf0e10cSrcweir         // #i28759# maTextColor might have been changed behind our back, commit then, too.
5114cdf0e10cSrcweir         if( aFont.GetColor() != COL_TRANSPARENT
5115cdf0e10cSrcweir         && (aFont.GetColor() != maFont.GetColor() || aFont.GetColor() != maTextColor ) )
5116cdf0e10cSrcweir         {
5117cdf0e10cSrcweir             maTextColor = aFont.GetColor();
5118cdf0e10cSrcweir             mbInitTextColor = sal_True;
5119cdf0e10cSrcweir             if( mpMetaFile )
5120cdf0e10cSrcweir                 mpMetaFile->AddAction( new MetaTextColorAction( aFont.GetColor() ) );
5121cdf0e10cSrcweir         }
5122cdf0e10cSrcweir         maFont      = aFont;
5123cdf0e10cSrcweir         mbNewFont   = sal_True;
5124cdf0e10cSrcweir 
5125cdf0e10cSrcweir         if( mpAlphaVDev )
5126cdf0e10cSrcweir         {
5127cdf0e10cSrcweir             // #i30463#
5128cdf0e10cSrcweir             // Since SetFont might change the text color, apply that only
5129cdf0e10cSrcweir             // selectively to alpha vdev (which normally paints opaque text
5130cdf0e10cSrcweir             // with COL_BLACK)
5131cdf0e10cSrcweir             if( aFont.GetColor() != COL_TRANSPARENT )
5132cdf0e10cSrcweir             {
5133cdf0e10cSrcweir                 mpAlphaVDev->SetTextColor( COL_BLACK );
5134cdf0e10cSrcweir                 aFont.SetColor( COL_TRANSPARENT );
5135cdf0e10cSrcweir             }
5136cdf0e10cSrcweir 
5137cdf0e10cSrcweir             mpAlphaVDev->SetFont( aFont );
5138cdf0e10cSrcweir         }
5139cdf0e10cSrcweir     }
5140cdf0e10cSrcweir }
5141cdf0e10cSrcweir 
5142cdf0e10cSrcweir // -----------------------------------------------------------------------
5143cdf0e10cSrcweir 
5144cdf0e10cSrcweir void OutputDevice::SetLayoutMode( sal_uLong nTextLayoutMode )
5145cdf0e10cSrcweir {
5146cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetTextLayoutMode()" );
5147cdf0e10cSrcweir 
5148cdf0e10cSrcweir     if( mpMetaFile )
5149cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaLayoutModeAction( nTextLayoutMode ) );
5150cdf0e10cSrcweir 
5151cdf0e10cSrcweir     mnTextLayoutMode = nTextLayoutMode;
5152cdf0e10cSrcweir 
5153cdf0e10cSrcweir     if( mpAlphaVDev )
5154cdf0e10cSrcweir         mpAlphaVDev->SetLayoutMode( nTextLayoutMode );
5155cdf0e10cSrcweir }
5156cdf0e10cSrcweir 
5157cdf0e10cSrcweir // -----------------------------------------------------------------------
5158cdf0e10cSrcweir 
5159cdf0e10cSrcweir void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage )
5160cdf0e10cSrcweir {
5161cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetTextLanguage()" );
5162cdf0e10cSrcweir 
5163cdf0e10cSrcweir     if( mpMetaFile )
5164cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextLanguageAction( eTextLanguage ) );
5165cdf0e10cSrcweir 
5166cdf0e10cSrcweir     meTextLanguage = eTextLanguage;
5167cdf0e10cSrcweir 
5168cdf0e10cSrcweir     if( mpAlphaVDev )
5169cdf0e10cSrcweir         mpAlphaVDev->SetDigitLanguage( eTextLanguage );
5170cdf0e10cSrcweir }
5171cdf0e10cSrcweir 
5172cdf0e10cSrcweir // -----------------------------------------------------------------------
5173cdf0e10cSrcweir 
5174cdf0e10cSrcweir void OutputDevice::SetTextColor( const Color& rColor )
5175cdf0e10cSrcweir {
5176cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetTextColor()" );
5177cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5178cdf0e10cSrcweir 
5179cdf0e10cSrcweir     Color aColor( rColor );
5180cdf0e10cSrcweir 
5181cdf0e10cSrcweir     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5182cdf0e10cSrcweir                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5183cdf0e10cSrcweir                         DRAWMODE_SETTINGSTEXT ) )
5184cdf0e10cSrcweir     {
5185cdf0e10cSrcweir         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5186cdf0e10cSrcweir             aColor = Color( COL_BLACK );
5187cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5188cdf0e10cSrcweir             aColor = Color( COL_WHITE );
5189cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5190cdf0e10cSrcweir         {
5191cdf0e10cSrcweir             const sal_uInt8 cLum = aColor.GetLuminance();
5192cdf0e10cSrcweir             aColor = Color( cLum, cLum, cLum );
5193cdf0e10cSrcweir         }
5194cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5195cdf0e10cSrcweir             aColor = GetSettings().GetStyleSettings().GetFontColor();
5196cdf0e10cSrcweir 
5197cdf0e10cSrcweir         if ( mnDrawMode & DRAWMODE_GHOSTEDTEXT )
5198cdf0e10cSrcweir         {
5199cdf0e10cSrcweir             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5200cdf0e10cSrcweir                             (aColor.GetGreen() >> 1) | 0x80,
5201cdf0e10cSrcweir                             (aColor.GetBlue() >> 1) | 0x80 );
5202cdf0e10cSrcweir         }
5203cdf0e10cSrcweir     }
5204cdf0e10cSrcweir 
5205cdf0e10cSrcweir     if ( mpMetaFile )
5206cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextColorAction( aColor ) );
5207cdf0e10cSrcweir 
5208cdf0e10cSrcweir     if ( maTextColor != aColor )
5209cdf0e10cSrcweir     {
5210cdf0e10cSrcweir         maTextColor = aColor;
5211cdf0e10cSrcweir         mbInitTextColor = sal_True;
5212cdf0e10cSrcweir     }
5213cdf0e10cSrcweir 
5214cdf0e10cSrcweir     if( mpAlphaVDev )
5215cdf0e10cSrcweir         mpAlphaVDev->SetTextColor( COL_BLACK );
5216cdf0e10cSrcweir }
5217cdf0e10cSrcweir 
5218cdf0e10cSrcweir // -----------------------------------------------------------------------
5219cdf0e10cSrcweir 
5220cdf0e10cSrcweir void OutputDevice::SetTextFillColor()
5221cdf0e10cSrcweir {
5222cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetTextFillColor()" );
5223cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5224cdf0e10cSrcweir 
5225cdf0e10cSrcweir     if ( mpMetaFile )
5226cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextFillColorAction( Color(), sal_False ) );
5227cdf0e10cSrcweir 
5228cdf0e10cSrcweir     if ( maFont.GetColor() != Color( COL_TRANSPARENT ) )
5229cdf0e10cSrcweir         maFont.SetFillColor( Color( COL_TRANSPARENT ) );
5230cdf0e10cSrcweir     if ( !maFont.IsTransparent() )
5231cdf0e10cSrcweir         maFont.SetTransparent( sal_True );
5232cdf0e10cSrcweir 
5233cdf0e10cSrcweir     if( mpAlphaVDev )
5234cdf0e10cSrcweir         mpAlphaVDev->SetTextFillColor();
5235cdf0e10cSrcweir }
5236cdf0e10cSrcweir 
5237cdf0e10cSrcweir // -----------------------------------------------------------------------
5238cdf0e10cSrcweir 
5239cdf0e10cSrcweir void OutputDevice::SetTextFillColor( const Color& rColor )
5240cdf0e10cSrcweir {
5241cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetTextFillColor()" );
5242cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5243cdf0e10cSrcweir 
5244cdf0e10cSrcweir     Color aColor( rColor );
5245cdf0e10cSrcweir     sal_Bool bTransFill = ImplIsColorTransparent( aColor ) ? sal_True : sal_False;
5246cdf0e10cSrcweir 
5247cdf0e10cSrcweir     if ( !bTransFill )
5248cdf0e10cSrcweir     {
5249cdf0e10cSrcweir         if ( mnDrawMode & ( DRAWMODE_BLACKFILL | DRAWMODE_WHITEFILL |
5250cdf0e10cSrcweir                             DRAWMODE_GRAYFILL | DRAWMODE_NOFILL |
5251cdf0e10cSrcweir                             DRAWMODE_GHOSTEDFILL | DRAWMODE_SETTINGSFILL ) )
5252cdf0e10cSrcweir         {
5253cdf0e10cSrcweir             if ( mnDrawMode & DRAWMODE_BLACKFILL )
5254cdf0e10cSrcweir                 aColor = Color( COL_BLACK );
5255cdf0e10cSrcweir             else if ( mnDrawMode & DRAWMODE_WHITEFILL )
5256cdf0e10cSrcweir                 aColor = Color( COL_WHITE );
5257cdf0e10cSrcweir             else if ( mnDrawMode & DRAWMODE_GRAYFILL )
5258cdf0e10cSrcweir             {
5259cdf0e10cSrcweir                 const sal_uInt8 cLum = aColor.GetLuminance();
5260cdf0e10cSrcweir                 aColor = Color( cLum, cLum, cLum );
5261cdf0e10cSrcweir             }
5262cdf0e10cSrcweir             else if( mnDrawMode & DRAWMODE_SETTINGSFILL )
5263cdf0e10cSrcweir                 aColor = GetSettings().GetStyleSettings().GetWindowColor();
5264cdf0e10cSrcweir             else if ( mnDrawMode & DRAWMODE_NOFILL )
5265cdf0e10cSrcweir             {
5266cdf0e10cSrcweir                 aColor = Color( COL_TRANSPARENT );
5267cdf0e10cSrcweir                 bTransFill = sal_True;
5268cdf0e10cSrcweir             }
5269cdf0e10cSrcweir 
5270cdf0e10cSrcweir             if ( !bTransFill && (mnDrawMode & DRAWMODE_GHOSTEDFILL) )
5271cdf0e10cSrcweir             {
5272cdf0e10cSrcweir                 aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5273cdf0e10cSrcweir                                 (aColor.GetGreen() >> 1) | 0x80,
5274cdf0e10cSrcweir                                 (aColor.GetBlue() >> 1) | 0x80 );
5275cdf0e10cSrcweir             }
5276cdf0e10cSrcweir         }
5277cdf0e10cSrcweir     }
5278cdf0e10cSrcweir 
5279cdf0e10cSrcweir     if ( mpMetaFile )
5280cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextFillColorAction( aColor, sal_True ) );
5281cdf0e10cSrcweir 
5282cdf0e10cSrcweir     if ( maFont.GetFillColor() != aColor )
5283cdf0e10cSrcweir         maFont.SetFillColor( aColor );
5284cdf0e10cSrcweir     if ( maFont.IsTransparent() != bTransFill )
5285cdf0e10cSrcweir         maFont.SetTransparent( bTransFill );
5286cdf0e10cSrcweir 
5287cdf0e10cSrcweir     if( mpAlphaVDev )
5288cdf0e10cSrcweir         mpAlphaVDev->SetTextFillColor( COL_BLACK );
5289cdf0e10cSrcweir }
5290cdf0e10cSrcweir 
5291cdf0e10cSrcweir // -----------------------------------------------------------------------
5292cdf0e10cSrcweir 
5293cdf0e10cSrcweir Color OutputDevice::GetTextFillColor() const
5294cdf0e10cSrcweir {
5295cdf0e10cSrcweir     if ( maFont.IsTransparent() )
5296cdf0e10cSrcweir         return Color( COL_TRANSPARENT );
5297cdf0e10cSrcweir     else
5298cdf0e10cSrcweir         return maFont.GetFillColor();
5299cdf0e10cSrcweir }
5300cdf0e10cSrcweir 
5301cdf0e10cSrcweir // -----------------------------------------------------------------------
5302cdf0e10cSrcweir 
5303cdf0e10cSrcweir void OutputDevice::SetTextLineColor()
5304cdf0e10cSrcweir {
5305cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetTextLineColor()" );
5306cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5307cdf0e10cSrcweir 
5308cdf0e10cSrcweir     if ( mpMetaFile )
5309cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextLineColorAction( Color(), sal_False ) );
5310cdf0e10cSrcweir 
5311cdf0e10cSrcweir     maTextLineColor = Color( COL_TRANSPARENT );
5312cdf0e10cSrcweir 
5313cdf0e10cSrcweir     if( mpAlphaVDev )
5314cdf0e10cSrcweir         mpAlphaVDev->SetTextLineColor();
5315cdf0e10cSrcweir }
5316cdf0e10cSrcweir 
5317cdf0e10cSrcweir // -----------------------------------------------------------------------
5318cdf0e10cSrcweir 
5319cdf0e10cSrcweir void OutputDevice::SetTextLineColor( const Color& rColor )
5320cdf0e10cSrcweir {
5321cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetTextLineColor()" );
5322cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5323cdf0e10cSrcweir 
5324cdf0e10cSrcweir     Color aColor( rColor );
5325cdf0e10cSrcweir 
5326cdf0e10cSrcweir     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5327cdf0e10cSrcweir                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5328cdf0e10cSrcweir                         DRAWMODE_SETTINGSTEXT ) )
5329cdf0e10cSrcweir     {
5330cdf0e10cSrcweir         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5331cdf0e10cSrcweir             aColor = Color( COL_BLACK );
5332cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5333cdf0e10cSrcweir             aColor = Color( COL_WHITE );
5334cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5335cdf0e10cSrcweir         {
5336cdf0e10cSrcweir             const sal_uInt8 cLum = aColor.GetLuminance();
5337cdf0e10cSrcweir             aColor = Color( cLum, cLum, cLum );
5338cdf0e10cSrcweir         }
5339cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5340cdf0e10cSrcweir             aColor = GetSettings().GetStyleSettings().GetFontColor();
5341cdf0e10cSrcweir 
5342cdf0e10cSrcweir         if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
5343cdf0e10cSrcweir         &&  (aColor.GetColor() != COL_TRANSPARENT) )
5344cdf0e10cSrcweir         {
5345cdf0e10cSrcweir             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5346cdf0e10cSrcweir                             (aColor.GetGreen() >> 1) | 0x80,
5347cdf0e10cSrcweir                             (aColor.GetBlue() >> 1) | 0x80 );
5348cdf0e10cSrcweir         }
5349cdf0e10cSrcweir     }
5350cdf0e10cSrcweir 
5351cdf0e10cSrcweir     if ( mpMetaFile )
5352cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextLineColorAction( aColor, sal_True ) );
5353cdf0e10cSrcweir 
5354cdf0e10cSrcweir     maTextLineColor = aColor;
5355cdf0e10cSrcweir 
5356cdf0e10cSrcweir     if( mpAlphaVDev )
5357cdf0e10cSrcweir         mpAlphaVDev->SetTextLineColor( COL_BLACK );
5358cdf0e10cSrcweir }
5359cdf0e10cSrcweir 
5360cdf0e10cSrcweir // -----------------------------------------------------------------------
5361cdf0e10cSrcweir 
5362cdf0e10cSrcweir void OutputDevice::SetOverlineColor()
5363cdf0e10cSrcweir {
5364cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetOverlineColor()" );
5365cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5366cdf0e10cSrcweir 
5367cdf0e10cSrcweir     if ( mpMetaFile )
5368cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaOverlineColorAction( Color(), sal_False ) );
5369cdf0e10cSrcweir 
5370cdf0e10cSrcweir     maOverlineColor = Color( COL_TRANSPARENT );
5371cdf0e10cSrcweir 
5372cdf0e10cSrcweir     if( mpAlphaVDev )
5373cdf0e10cSrcweir         mpAlphaVDev->SetOverlineColor();
5374cdf0e10cSrcweir }
5375cdf0e10cSrcweir 
5376cdf0e10cSrcweir // -----------------------------------------------------------------------
5377cdf0e10cSrcweir 
5378cdf0e10cSrcweir void OutputDevice::SetOverlineColor( const Color& rColor )
5379cdf0e10cSrcweir {
5380cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetOverlineColor()" );
5381cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5382cdf0e10cSrcweir 
5383cdf0e10cSrcweir     Color aColor( rColor );
5384cdf0e10cSrcweir 
5385cdf0e10cSrcweir     if ( mnDrawMode & ( DRAWMODE_BLACKTEXT | DRAWMODE_WHITETEXT |
5386cdf0e10cSrcweir                         DRAWMODE_GRAYTEXT | DRAWMODE_GHOSTEDTEXT |
5387cdf0e10cSrcweir                         DRAWMODE_SETTINGSTEXT ) )
5388cdf0e10cSrcweir     {
5389cdf0e10cSrcweir         if ( mnDrawMode & DRAWMODE_BLACKTEXT )
5390cdf0e10cSrcweir             aColor = Color( COL_BLACK );
5391cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_WHITETEXT )
5392cdf0e10cSrcweir             aColor = Color( COL_WHITE );
5393cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_GRAYTEXT )
5394cdf0e10cSrcweir         {
5395cdf0e10cSrcweir             const sal_uInt8 cLum = aColor.GetLuminance();
5396cdf0e10cSrcweir             aColor = Color( cLum, cLum, cLum );
5397cdf0e10cSrcweir         }
5398cdf0e10cSrcweir         else if ( mnDrawMode & DRAWMODE_SETTINGSTEXT )
5399cdf0e10cSrcweir             aColor = GetSettings().GetStyleSettings().GetFontColor();
5400cdf0e10cSrcweir 
5401cdf0e10cSrcweir         if( (mnDrawMode & DRAWMODE_GHOSTEDTEXT)
5402cdf0e10cSrcweir         &&  (aColor.GetColor() != COL_TRANSPARENT) )
5403cdf0e10cSrcweir         {
5404cdf0e10cSrcweir             aColor = Color( (aColor.GetRed() >> 1) | 0x80,
5405cdf0e10cSrcweir                             (aColor.GetGreen() >> 1) | 0x80,
5406cdf0e10cSrcweir                             (aColor.GetBlue() >> 1) | 0x80 );
5407cdf0e10cSrcweir         }
5408cdf0e10cSrcweir     }
5409cdf0e10cSrcweir 
5410cdf0e10cSrcweir     if ( mpMetaFile )
5411cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaOverlineColorAction( aColor, sal_True ) );
5412cdf0e10cSrcweir 
5413cdf0e10cSrcweir     maOverlineColor = aColor;
5414cdf0e10cSrcweir 
5415cdf0e10cSrcweir     if( mpAlphaVDev )
5416cdf0e10cSrcweir         mpAlphaVDev->SetOverlineColor( COL_BLACK );
5417cdf0e10cSrcweir }
5418cdf0e10cSrcweir 
5419cdf0e10cSrcweir // -----------------------------------------------------------------------
5420cdf0e10cSrcweir 
5421cdf0e10cSrcweir 
5422cdf0e10cSrcweir void OutputDevice::SetTextAlign( TextAlign eAlign )
5423cdf0e10cSrcweir {
5424cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::SetTextAlign()" );
5425cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5426cdf0e10cSrcweir 
5427cdf0e10cSrcweir     if ( mpMetaFile )
5428cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextAlignAction( eAlign ) );
5429cdf0e10cSrcweir 
5430cdf0e10cSrcweir     if ( maFont.GetAlign() != eAlign )
5431cdf0e10cSrcweir     {
5432cdf0e10cSrcweir         maFont.SetAlign( eAlign );
5433cdf0e10cSrcweir         mbNewFont = sal_True;
5434cdf0e10cSrcweir     }
5435cdf0e10cSrcweir 
5436cdf0e10cSrcweir     if( mpAlphaVDev )
5437cdf0e10cSrcweir         mpAlphaVDev->SetTextAlign( eAlign );
5438cdf0e10cSrcweir }
5439cdf0e10cSrcweir 
5440cdf0e10cSrcweir // -----------------------------------------------------------------------
5441cdf0e10cSrcweir 
5442cdf0e10cSrcweir void OutputDevice::DrawTextLine( const Point& rPos, long nWidth,
5443cdf0e10cSrcweir                                  FontStrikeout eStrikeout,
5444cdf0e10cSrcweir                                  FontUnderline eUnderline,
5445cdf0e10cSrcweir                                  FontUnderline eOverline,
5446cdf0e10cSrcweir                                  sal_Bool bUnderlineAbove )
5447cdf0e10cSrcweir {
5448cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::DrawTextLine()" );
5449cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5450cdf0e10cSrcweir 
5451cdf0e10cSrcweir     if ( mpMetaFile )
5452cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextLineAction( rPos, nWidth, eStrikeout, eUnderline, eOverline ) );
5453cdf0e10cSrcweir 
5454cdf0e10cSrcweir     if ( ((eUnderline == UNDERLINE_NONE) || (eUnderline == UNDERLINE_DONTKNOW)) &&
5455cdf0e10cSrcweir          ((eOverline  == UNDERLINE_NONE) || (eOverline  == UNDERLINE_DONTKNOW)) &&
5456cdf0e10cSrcweir          ((eStrikeout == STRIKEOUT_NONE) || (eStrikeout == STRIKEOUT_DONTKNOW)) )
5457cdf0e10cSrcweir         return;
5458cdf0e10cSrcweir 
5459cdf0e10cSrcweir     if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
5460cdf0e10cSrcweir         return;
5461cdf0e10cSrcweir 
5462cdf0e10cSrcweir     // we need a graphics
5463cdf0e10cSrcweir     if( !mpGraphics && !ImplGetGraphics() )
5464cdf0e10cSrcweir         return;
5465cdf0e10cSrcweir     if( mbInitClipRegion )
5466cdf0e10cSrcweir         ImplInitClipRegion();
5467cdf0e10cSrcweir     if( mbOutputClipped )
5468cdf0e10cSrcweir         return;
5469cdf0e10cSrcweir 
5470cdf0e10cSrcweir     // initialize font if needed to get text offsets
5471cdf0e10cSrcweir     // TODO: only needed for mnTextOff!=(0,0)
5472cdf0e10cSrcweir     if( mbNewFont )
5473cdf0e10cSrcweir         if( !ImplNewFont() )
5474cdf0e10cSrcweir             return;
5475cdf0e10cSrcweir     if( mbInitFont )
5476cdf0e10cSrcweir         ImplInitFont();
5477cdf0e10cSrcweir 
5478cdf0e10cSrcweir     Point aPos = ImplLogicToDevicePixel( rPos );
5479cdf0e10cSrcweir     nWidth = ImplLogicWidthToDevicePixel( nWidth );
5480cdf0e10cSrcweir     aPos += Point( mnTextOffX, mnTextOffY );
5481cdf0e10cSrcweir     ImplDrawTextLine( aPos.X(), aPos.X(), 0, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
5482cdf0e10cSrcweir 
5483cdf0e10cSrcweir     if( mpAlphaVDev )
5484cdf0e10cSrcweir         mpAlphaVDev->DrawTextLine( rPos, nWidth, eStrikeout, eUnderline, eOverline, bUnderlineAbove );
5485cdf0e10cSrcweir }
5486cdf0e10cSrcweir 
5487cdf0e10cSrcweir // ------------------------------------------------------------------------
5488cdf0e10cSrcweir 
5489cdf0e10cSrcweir sal_Bool OutputDevice::IsTextUnderlineAbove( const Font& rFont )
5490cdf0e10cSrcweir {
5491cdf0e10cSrcweir     return ImplIsUnderlineAbove( rFont );
5492cdf0e10cSrcweir }
5493cdf0e10cSrcweir 
5494cdf0e10cSrcweir // ------------------------------------------------------------------------
5495cdf0e10cSrcweir 
5496cdf0e10cSrcweir void OutputDevice::DrawWaveLine( const Point& rStartPos, const Point& rEndPos,
5497cdf0e10cSrcweir                                  sal_uInt16 nStyle )
5498cdf0e10cSrcweir {
5499cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::DrawWaveLine()" );
5500cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5501cdf0e10cSrcweir 
5502cdf0e10cSrcweir     if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
5503cdf0e10cSrcweir         return;
5504cdf0e10cSrcweir 
5505cdf0e10cSrcweir     // we need a graphics
5506cdf0e10cSrcweir     if( !mpGraphics )
5507cdf0e10cSrcweir         if( !ImplGetGraphics() )
5508cdf0e10cSrcweir             return;
5509cdf0e10cSrcweir 
5510cdf0e10cSrcweir     if ( mbInitClipRegion )
5511cdf0e10cSrcweir         ImplInitClipRegion();
5512cdf0e10cSrcweir     if ( mbOutputClipped )
5513cdf0e10cSrcweir         return;
5514cdf0e10cSrcweir 
5515cdf0e10cSrcweir     if( mbNewFont )
5516cdf0e10cSrcweir         if( !ImplNewFont() )
5517cdf0e10cSrcweir             return;
5518cdf0e10cSrcweir 
5519cdf0e10cSrcweir     Point   aStartPt = ImplLogicToDevicePixel( rStartPos );
5520cdf0e10cSrcweir     Point   aEndPt = ImplLogicToDevicePixel( rEndPos );
5521cdf0e10cSrcweir     long    nStartX = aStartPt.X();
5522cdf0e10cSrcweir     long    nStartY = aStartPt.Y();
5523cdf0e10cSrcweir     long    nEndX = aEndPt.X();
5524cdf0e10cSrcweir     long    nEndY = aEndPt.Y();
5525cdf0e10cSrcweir     short   nOrientation = 0;
5526cdf0e10cSrcweir 
5527cdf0e10cSrcweir     // when rotated
5528cdf0e10cSrcweir     if ( (nStartY != nEndY) || (nStartX > nEndX) )
5529cdf0e10cSrcweir     {
5530cdf0e10cSrcweir         long nDX = nEndX - nStartX;
5531cdf0e10cSrcweir         double nO = atan2( -nEndY + nStartY, ((nDX == 0L) ? 0.000000001 : nDX) );
5532cdf0e10cSrcweir         nO /= F_PI1800;
5533cdf0e10cSrcweir         nOrientation = (short)nO;
5534cdf0e10cSrcweir         ImplRotatePos( nStartX, nStartY, nEndX, nEndY, -nOrientation );
5535cdf0e10cSrcweir     }
5536cdf0e10cSrcweir 
5537cdf0e10cSrcweir     long nWaveHeight;
5538cdf0e10cSrcweir     if ( nStyle == WAVE_NORMAL )
5539cdf0e10cSrcweir     {
5540cdf0e10cSrcweir         nWaveHeight = 3;
5541cdf0e10cSrcweir         nStartY++;
5542cdf0e10cSrcweir         nEndY++;
5543cdf0e10cSrcweir     }
5544cdf0e10cSrcweir     else if( nStyle == WAVE_SMALL )
5545cdf0e10cSrcweir     {
5546cdf0e10cSrcweir         nWaveHeight = 2;
5547cdf0e10cSrcweir         nStartY++;
5548cdf0e10cSrcweir         nEndY++;
5549cdf0e10cSrcweir     }
5550cdf0e10cSrcweir     else // WAVE_FLAT
5551cdf0e10cSrcweir         nWaveHeight = 1;
5552cdf0e10cSrcweir 
5553cdf0e10cSrcweir      // #109280# make sure the waveline does not exceed the descent to avoid paint problems
5554cdf0e10cSrcweir      ImplFontEntry* pFontEntry = mpFontEntry;
5555cdf0e10cSrcweir      if( nWaveHeight > pFontEntry->maMetric.mnWUnderlineSize )
5556cdf0e10cSrcweir          nWaveHeight = pFontEntry->maMetric.mnWUnderlineSize;
5557cdf0e10cSrcweir 
5558cdf0e10cSrcweir      ImplDrawWaveLine( nStartX, nStartY, 0, 0,
5559cdf0e10cSrcweir                       nEndX-nStartX, nWaveHeight, 1,
5560cdf0e10cSrcweir                       nOrientation, GetLineColor() );
5561cdf0e10cSrcweir     if( mpAlphaVDev )
5562cdf0e10cSrcweir         mpAlphaVDev->DrawWaveLine( rStartPos, rEndPos, nStyle );
5563cdf0e10cSrcweir }
5564cdf0e10cSrcweir 
5565cdf0e10cSrcweir // -----------------------------------------------------------------------
5566cdf0e10cSrcweir 
5567cdf0e10cSrcweir void OutputDevice::DrawText( const Point& rStartPt, const String& rStr,
5568cdf0e10cSrcweir                              xub_StrLen nIndex, xub_StrLen nLen,
5569cdf0e10cSrcweir                              MetricVector* pVector, String* pDisplayText
5570cdf0e10cSrcweir                              )
5571cdf0e10cSrcweir {
5572cdf0e10cSrcweir     if( mpOutDevData && mpOutDevData->mpRecordLayout )
5573cdf0e10cSrcweir     {
5574cdf0e10cSrcweir         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
5575cdf0e10cSrcweir         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
5576cdf0e10cSrcweir     }
5577cdf0e10cSrcweir 
5578cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::DrawText()" );
5579cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5580cdf0e10cSrcweir 
5581cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 2
5582cdf0e10cSrcweir     fprintf( stderr, "   OutputDevice::DrawText(\"%s\")\n",
5583cdf0e10cSrcweir          OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ).getStr() );
5584cdf0e10cSrcweir #endif
5585cdf0e10cSrcweir 
5586cdf0e10cSrcweir     if ( mpMetaFile )
5587cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
5588cdf0e10cSrcweir     if( pVector )
5589cdf0e10cSrcweir     {
5590cdf0e10cSrcweir         Region aClip( GetClipRegion() );
5591cdf0e10cSrcweir         if( meOutDevType == OUTDEV_WINDOW )
5592cdf0e10cSrcweir             aClip.Intersect( Rectangle( Point(), GetOutputSize() ) );
5593cdf0e10cSrcweir         if( mpOutDevData && mpOutDevData->mpRecordLayout )
5594cdf0e10cSrcweir         {
5595cdf0e10cSrcweir             mpOutDevData->mpRecordLayout->m_aLineIndices.push_back( mpOutDevData->mpRecordLayout->m_aDisplayText.Len() );
5596cdf0e10cSrcweir             aClip.Intersect( mpOutDevData->maRecordRect );
5597cdf0e10cSrcweir         }
5598cdf0e10cSrcweir         if( ! aClip.IsNull() )
5599cdf0e10cSrcweir         {
5600cdf0e10cSrcweir             MetricVector aTmp;
5601cdf0e10cSrcweir             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, aTmp );
5602cdf0e10cSrcweir 
5603cdf0e10cSrcweir             bool bInserted = false;
5604cdf0e10cSrcweir             for( MetricVector::const_iterator it = aTmp.begin(); it != aTmp.end(); ++it, nIndex++ )
5605cdf0e10cSrcweir             {
5606cdf0e10cSrcweir                 bool bAppend = false;
5607cdf0e10cSrcweir 
5608cdf0e10cSrcweir                 if( aClip.IsOver( *it ) )
5609cdf0e10cSrcweir                     bAppend = true;
5610cdf0e10cSrcweir                 else if( rStr.GetChar( nIndex ) == ' ' && bInserted )
5611cdf0e10cSrcweir                 {
5612cdf0e10cSrcweir                     MetricVector::const_iterator next = it;
5613cdf0e10cSrcweir                     ++next;
5614cdf0e10cSrcweir                     if( next != aTmp.end() && aClip.IsOver( *next ) )
5615cdf0e10cSrcweir                         bAppend = true;
5616cdf0e10cSrcweir                 }
5617cdf0e10cSrcweir 
5618cdf0e10cSrcweir                 if( bAppend )
5619cdf0e10cSrcweir                 {
5620cdf0e10cSrcweir                     pVector->push_back( *it );
5621cdf0e10cSrcweir                     if( pDisplayText )
5622cdf0e10cSrcweir                         pDisplayText->Append( rStr.GetChar( nIndex ) );
5623cdf0e10cSrcweir                     bInserted = true;
5624cdf0e10cSrcweir                 }
5625cdf0e10cSrcweir             }
5626cdf0e10cSrcweir         }
5627cdf0e10cSrcweir         else
5628cdf0e10cSrcweir         {
5629cdf0e10cSrcweir             GetGlyphBoundRects( rStartPt, rStr, nIndex, nLen, nIndex, *pVector );
5630cdf0e10cSrcweir             if( pDisplayText )
5631cdf0e10cSrcweir                 pDisplayText->Append( rStr.Copy( nIndex, nLen ) );
5632cdf0e10cSrcweir         }
5633cdf0e10cSrcweir     }
5634cdf0e10cSrcweir 
5635cdf0e10cSrcweir     if ( !IsDeviceOutputNecessary() || pVector )
5636cdf0e10cSrcweir         return;
5637cdf0e10cSrcweir 
5638cdf0e10cSrcweir     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, NULL, true );
5639cdf0e10cSrcweir     if( pSalLayout )
5640cdf0e10cSrcweir     {
5641cdf0e10cSrcweir         ImplDrawText( *pSalLayout );
5642cdf0e10cSrcweir         pSalLayout->Release();
5643cdf0e10cSrcweir     }
5644cdf0e10cSrcweir 
5645cdf0e10cSrcweir     if( mpAlphaVDev )
5646cdf0e10cSrcweir         mpAlphaVDev->DrawText( rStartPt, rStr, nIndex, nLen, pVector, pDisplayText );
5647cdf0e10cSrcweir }
5648cdf0e10cSrcweir 
5649cdf0e10cSrcweir // -----------------------------------------------------------------------
5650cdf0e10cSrcweir 
5651cdf0e10cSrcweir long OutputDevice::GetTextWidth( const String& rStr,
5652cdf0e10cSrcweir                                  xub_StrLen nIndex, xub_StrLen nLen ) const
5653cdf0e10cSrcweir {
5654cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetTextWidth()" );
5655cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5656cdf0e10cSrcweir 
5657cdf0e10cSrcweir     long nWidth = GetTextArray( rStr, NULL, nIndex, nLen );
5658cdf0e10cSrcweir     return nWidth;
5659cdf0e10cSrcweir }
5660cdf0e10cSrcweir 
5661cdf0e10cSrcweir // -----------------------------------------------------------------------
5662cdf0e10cSrcweir 
5663cdf0e10cSrcweir long OutputDevice::GetTextHeight() const
5664cdf0e10cSrcweir {
5665cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetTextHeight()" );
5666cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5667cdf0e10cSrcweir 
5668cdf0e10cSrcweir     if( mbNewFont )
5669cdf0e10cSrcweir         if( !ImplNewFont() )
5670cdf0e10cSrcweir             return 0;
5671cdf0e10cSrcweir     if( mbInitFont )
5672cdf0e10cSrcweir         if( !ImplNewFont() )
5673cdf0e10cSrcweir             return 0;
5674cdf0e10cSrcweir 
5675cdf0e10cSrcweir     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
5676cdf0e10cSrcweir 
5677cdf0e10cSrcweir     if ( mbMap )
5678cdf0e10cSrcweir         nHeight = ImplDevicePixelToLogicHeight( nHeight );
5679cdf0e10cSrcweir 
5680cdf0e10cSrcweir     return nHeight;
5681cdf0e10cSrcweir }
5682cdf0e10cSrcweir 
5683cdf0e10cSrcweir // -----------------------------------------------------------------------
5684cdf0e10cSrcweir 
5685cdf0e10cSrcweir void OutputDevice::DrawTextArray( const Point& rStartPt, const String& rStr,
5686cdf0e10cSrcweir                                   const sal_Int32* pDXAry,
5687cdf0e10cSrcweir                                   xub_StrLen nIndex, xub_StrLen nLen )
5688cdf0e10cSrcweir {
5689cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::DrawTextArray()" );
5690cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5691cdf0e10cSrcweir 
5692cdf0e10cSrcweir     if ( mpMetaFile )
5693cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
5694cdf0e10cSrcweir 
5695cdf0e10cSrcweir     if ( !IsDeviceOutputNecessary() )
5696cdf0e10cSrcweir         return;
5697cdf0e10cSrcweir     if( !mpGraphics && !ImplGetGraphics() )
5698cdf0e10cSrcweir         return;
5699cdf0e10cSrcweir     if( mbInitClipRegion )
5700cdf0e10cSrcweir         ImplInitClipRegion();
5701cdf0e10cSrcweir     if( mbOutputClipped )
5702cdf0e10cSrcweir         return;
5703cdf0e10cSrcweir 
5704cdf0e10cSrcweir     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
5705cdf0e10cSrcweir     if( pSalLayout )
5706cdf0e10cSrcweir     {
5707cdf0e10cSrcweir         ImplDrawText( *pSalLayout );
5708cdf0e10cSrcweir         pSalLayout->Release();
5709cdf0e10cSrcweir     }
5710cdf0e10cSrcweir 
5711cdf0e10cSrcweir     if( mpAlphaVDev )
5712cdf0e10cSrcweir         mpAlphaVDev->DrawTextArray( rStartPt, rStr, pDXAry, nIndex, nLen );
5713cdf0e10cSrcweir }
5714cdf0e10cSrcweir 
5715cdf0e10cSrcweir // -----------------------------------------------------------------------
5716cdf0e10cSrcweir 
5717cdf0e10cSrcweir long OutputDevice::GetTextArray( const String& rStr, sal_Int32* pDXAry,
5718cdf0e10cSrcweir                                  xub_StrLen nIndex, xub_StrLen nLen ) const
5719cdf0e10cSrcweir {
5720cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetTextArray()" );
5721cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5722cdf0e10cSrcweir 
5723cdf0e10cSrcweir     if( nIndex >= rStr.Len() )
5724cdf0e10cSrcweir         return 0;
5725cdf0e10cSrcweir     if( (sal_uLong)nIndex+nLen >= rStr.Len() )
5726cdf0e10cSrcweir         nLen = rStr.Len() - nIndex;
5727cdf0e10cSrcweir 
5728cdf0e10cSrcweir     // do layout
5729cdf0e10cSrcweir     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
5730cdf0e10cSrcweir     if( !pSalLayout )
5731cdf0e10cSrcweir         return 0;
5732cdf0e10cSrcweir 
5733cdf0e10cSrcweir     long nWidth = pSalLayout->FillDXArray( pDXAry );
5734cdf0e10cSrcweir     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
5735cdf0e10cSrcweir     pSalLayout->Release();
5736cdf0e10cSrcweir 
5737cdf0e10cSrcweir     // convert virtual char widths to virtual absolute positions
5738cdf0e10cSrcweir     if( pDXAry )
5739cdf0e10cSrcweir         for( int i = 1; i < nLen; ++i )
5740cdf0e10cSrcweir             pDXAry[ i ] += pDXAry[ i-1 ];
5741cdf0e10cSrcweir 
5742cdf0e10cSrcweir     // convert from font units to logical units
5743cdf0e10cSrcweir     if( mbMap )
5744cdf0e10cSrcweir     {
5745cdf0e10cSrcweir         if( pDXAry )
5746cdf0e10cSrcweir             for( int i = 0; i < nLen; ++i )
5747cdf0e10cSrcweir                 pDXAry[i] = ImplDevicePixelToLogicWidth( pDXAry[i] );
5748cdf0e10cSrcweir         nWidth = ImplDevicePixelToLogicWidth( nWidth );
5749cdf0e10cSrcweir     }
5750cdf0e10cSrcweir 
5751cdf0e10cSrcweir     if( nWidthFactor > 1 )
5752cdf0e10cSrcweir     {
5753cdf0e10cSrcweir         if( pDXAry )
5754cdf0e10cSrcweir             for( int i = 0; i < nLen; ++i )
5755cdf0e10cSrcweir                 pDXAry[i] /= nWidthFactor;
5756cdf0e10cSrcweir         nWidth /= nWidthFactor;
5757cdf0e10cSrcweir     }
5758cdf0e10cSrcweir 
5759cdf0e10cSrcweir     return nWidth;
5760cdf0e10cSrcweir }
5761cdf0e10cSrcweir 
5762cdf0e10cSrcweir // -----------------------------------------------------------------------
5763cdf0e10cSrcweir 
5764cdf0e10cSrcweir bool OutputDevice::GetCaretPositions( const XubString& rStr, sal_Int32* pCaretXArray,
5765cdf0e10cSrcweir     xub_StrLen nIndex, xub_StrLen nLen,
5766cdf0e10cSrcweir     sal_Int32* pDXAry, long nLayoutWidth,
5767cdf0e10cSrcweir     sal_Bool bCellBreaking ) const
5768cdf0e10cSrcweir {
5769cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetCaretPositions()" );
5770cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5771cdf0e10cSrcweir 
5772cdf0e10cSrcweir     if( nIndex >= rStr.Len() )
5773cdf0e10cSrcweir         return false;
5774cdf0e10cSrcweir     if( (sal_uLong)nIndex+nLen >= rStr.Len() )
5775cdf0e10cSrcweir         nLen = rStr.Len() - nIndex;
5776cdf0e10cSrcweir 
5777cdf0e10cSrcweir     // layout complex text
5778cdf0e10cSrcweir     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen,
5779cdf0e10cSrcweir         Point(0,0), nLayoutWidth, pDXAry );
5780cdf0e10cSrcweir     if( !pSalLayout )
5781cdf0e10cSrcweir         return false;
5782cdf0e10cSrcweir 
5783cdf0e10cSrcweir     int nWidthFactor = pSalLayout->GetUnitsPerPixel();
5784cdf0e10cSrcweir     pSalLayout->GetCaretPositions( 2*nLen, pCaretXArray );
5785cdf0e10cSrcweir     long nWidth = pSalLayout->GetTextWidth();
5786cdf0e10cSrcweir     pSalLayout->Release();
5787cdf0e10cSrcweir 
5788cdf0e10cSrcweir     // fixup unknown caret positions
5789cdf0e10cSrcweir     int i;
5790cdf0e10cSrcweir     for( i = 0; i < 2 * nLen; ++i )
5791cdf0e10cSrcweir         if( pCaretXArray[ i ] >= 0 )
5792cdf0e10cSrcweir             break;
5793cdf0e10cSrcweir     long nXPos = pCaretXArray[ i ];
5794cdf0e10cSrcweir     for( i = 0; i < 2 * nLen; ++i )
5795cdf0e10cSrcweir     {
5796cdf0e10cSrcweir         if( pCaretXArray[ i ] >= 0 )
5797cdf0e10cSrcweir             nXPos = pCaretXArray[ i ];
5798cdf0e10cSrcweir         else
5799cdf0e10cSrcweir             pCaretXArray[ i ] = nXPos;
5800cdf0e10cSrcweir     }
5801cdf0e10cSrcweir 
5802cdf0e10cSrcweir     // handle window mirroring
5803cdf0e10cSrcweir     if( IsRTLEnabled() )
5804cdf0e10cSrcweir     {
5805cdf0e10cSrcweir         for( i = 0; i < 2 * nLen; ++i )
5806cdf0e10cSrcweir             pCaretXArray[i] = nWidth - pCaretXArray[i] - 1;
5807cdf0e10cSrcweir     }
5808cdf0e10cSrcweir 
5809cdf0e10cSrcweir     // convert from font units to logical units
5810cdf0e10cSrcweir     if( mbMap )
5811cdf0e10cSrcweir     {
5812cdf0e10cSrcweir         for( i = 0; i < 2*nLen; ++i )
5813cdf0e10cSrcweir             pCaretXArray[i] = ImplDevicePixelToLogicWidth( pCaretXArray[i] );
5814cdf0e10cSrcweir     }
5815cdf0e10cSrcweir 
5816cdf0e10cSrcweir     if( nWidthFactor != 1 )
5817cdf0e10cSrcweir     {
5818cdf0e10cSrcweir         for( i = 0; i < 2*nLen; ++i )
5819cdf0e10cSrcweir             pCaretXArray[i] /= nWidthFactor;
5820cdf0e10cSrcweir     }
5821cdf0e10cSrcweir 
5822cdf0e10cSrcweir     // if requested move caret position to cell limits
5823cdf0e10cSrcweir     if( bCellBreaking )
5824cdf0e10cSrcweir     {
5825cdf0e10cSrcweir         ; // TODO
5826cdf0e10cSrcweir     }
5827cdf0e10cSrcweir 
5828cdf0e10cSrcweir     return true;
5829cdf0e10cSrcweir }
5830cdf0e10cSrcweir 
5831cdf0e10cSrcweir // -----------------------------------------------------------------------
5832cdf0e10cSrcweir 
5833cdf0e10cSrcweir void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
5834cdf0e10cSrcweir                                     const String& rStr,
5835cdf0e10cSrcweir                                     xub_StrLen nIndex, xub_StrLen nLen )
5836cdf0e10cSrcweir {
5837cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::DrawStretchText()" );
5838cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
5839cdf0e10cSrcweir 
5840cdf0e10cSrcweir     if ( mpMetaFile )
5841cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaStretchTextAction( rStartPt, nWidth, rStr, nIndex, nLen ) );
5842cdf0e10cSrcweir 
5843cdf0e10cSrcweir     if ( !IsDeviceOutputNecessary() )
5844cdf0e10cSrcweir         return;
5845cdf0e10cSrcweir 
5846cdf0e10cSrcweir     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, nWidth, NULL, true );
5847cdf0e10cSrcweir     if( pSalLayout )
5848cdf0e10cSrcweir     {
5849cdf0e10cSrcweir         ImplDrawText( *pSalLayout );
5850cdf0e10cSrcweir         pSalLayout->Release();
5851cdf0e10cSrcweir     }
5852cdf0e10cSrcweir 
5853cdf0e10cSrcweir     if( mpAlphaVDev )
5854cdf0e10cSrcweir         mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
5855cdf0e10cSrcweir }
5856cdf0e10cSrcweir 
5857cdf0e10cSrcweir // -----------------------------------------------------------------------
5858cdf0e10cSrcweir 
5859cdf0e10cSrcweir ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( String& rStr,
5860cdf0e10cSrcweir                                        xub_StrLen nMinIndex, xub_StrLen nLen,
5861cdf0e10cSrcweir                                        long nPixelWidth, const sal_Int32* pDXArray ) const
5862cdf0e10cSrcweir {
5863cdf0e10cSrcweir     // get string length for calculating extents
5864cdf0e10cSrcweir     xub_StrLen nEndIndex = rStr.Len();
5865cdf0e10cSrcweir     if( (sal_uLong)nMinIndex + nLen < nEndIndex )
5866cdf0e10cSrcweir         nEndIndex = nMinIndex + nLen;
5867cdf0e10cSrcweir 
5868cdf0e10cSrcweir     // don't bother if there is nothing to do
5869cdf0e10cSrcweir     if( nEndIndex < nMinIndex )
5870cdf0e10cSrcweir         nEndIndex = nMinIndex;
5871cdf0e10cSrcweir 
5872cdf0e10cSrcweir     int nLayoutFlags = 0;
5873cdf0e10cSrcweir     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL )
5874cdf0e10cSrcweir         nLayoutFlags |= SAL_LAYOUT_BIDI_RTL;
5875cdf0e10cSrcweir     if( mnTextLayoutMode & TEXT_LAYOUT_BIDI_STRONG )
5876cdf0e10cSrcweir         nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
5877cdf0e10cSrcweir     else if( 0 == (mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) )
5878cdf0e10cSrcweir     {
5879cdf0e10cSrcweir         // disable Bidi if no RTL hint and no RTL codes used
5880cdf0e10cSrcweir         const xub_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
5881cdf0e10cSrcweir         const xub_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
5882cdf0e10cSrcweir         for( ; pStr < pEnd; ++pStr )
5883cdf0e10cSrcweir             if( ((*pStr >= 0x0580) && (*pStr < 0x0800))   // middle eastern scripts
5884cdf0e10cSrcweir             ||  ((*pStr >= 0xFB18) && (*pStr < 0xFE00))   // hebrew + arabic A presentation forms
5885cdf0e10cSrcweir             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation forms B
5886cdf0e10cSrcweir                 break;
5887cdf0e10cSrcweir         if( pStr >= pEnd )
5888cdf0e10cSrcweir             nLayoutFlags |= SAL_LAYOUT_BIDI_STRONG;
5889cdf0e10cSrcweir     }
5890cdf0e10cSrcweir 
5891cdf0e10cSrcweir     if( mbKerning )
5892cdf0e10cSrcweir         nLayoutFlags |= SAL_LAYOUT_KERNING_PAIRS;
5893cdf0e10cSrcweir     if( maFont.GetKerning() & KERNING_ASIAN )
5894cdf0e10cSrcweir         nLayoutFlags |= SAL_LAYOUT_KERNING_ASIAN;
5895cdf0e10cSrcweir     if( maFont.IsVertical() )
5896cdf0e10cSrcweir         nLayoutFlags |= SAL_LAYOUT_VERTICAL;
5897cdf0e10cSrcweir 
5898cdf0e10cSrcweir     if( mnTextLayoutMode & TEXT_LAYOUT_ENABLE_LIGATURES )
5899cdf0e10cSrcweir         nLayoutFlags |= SAL_LAYOUT_ENABLE_LIGATURES;
5900cdf0e10cSrcweir     else if( mnTextLayoutMode & TEXT_LAYOUT_COMPLEX_DISABLED )
5901cdf0e10cSrcweir         nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
5902cdf0e10cSrcweir     else
5903cdf0e10cSrcweir     {
5904cdf0e10cSrcweir         // disable CTL for non-CTL text
5905cdf0e10cSrcweir         const sal_Unicode* pStr = rStr.GetBuffer() + nMinIndex;
5906cdf0e10cSrcweir         const sal_Unicode* pEnd = rStr.GetBuffer() + nEndIndex;
5907cdf0e10cSrcweir         for( ; pStr < pEnd; ++pStr )
5908cdf0e10cSrcweir             if( ((*pStr >= 0x0300) && (*pStr < 0x0370))   // diacritical marks
5909cdf0e10cSrcweir             ||  ((*pStr >= 0x0590) && (*pStr < 0x10A0))   // many CTL scripts
5910cdf0e10cSrcweir             ||  ((*pStr >= 0x1100) && (*pStr < 0x1200))   // hangul jamo
5911cdf0e10cSrcweir             ||  ((*pStr >= 0x1700) && (*pStr < 0x1900))   // many CTL scripts
5912cdf0e10cSrcweir             ||  ((*pStr >= 0xFB1D) && (*pStr < 0xFE00))   // middle east presentation
5913cdf0e10cSrcweir             ||  ((*pStr >= 0xFE70) && (*pStr < 0xFEFF)) ) // arabic presentation B
5914cdf0e10cSrcweir                 break;
5915cdf0e10cSrcweir         if( pStr >= pEnd )
5916cdf0e10cSrcweir             nLayoutFlags |= SAL_LAYOUT_COMPLEX_DISABLED;
5917cdf0e10cSrcweir     }
5918cdf0e10cSrcweir 
5919cdf0e10cSrcweir     if( meTextLanguage ) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
5920cdf0e10cSrcweir     {
5921cdf0e10cSrcweir         // disable character localization when no digits used
5922cdf0e10cSrcweir         const sal_Unicode* pBase = rStr.GetBuffer();
5923cdf0e10cSrcweir         const sal_Unicode* pStr = pBase + nMinIndex;
5924cdf0e10cSrcweir         const sal_Unicode* pEnd = pBase + nEndIndex;
5925cdf0e10cSrcweir         for( ; pStr < pEnd; ++pStr )
5926cdf0e10cSrcweir         {
5927cdf0e10cSrcweir             // TODO: are there non-digit localizations?
5928cdf0e10cSrcweir             if( (*pStr >= '0') && (*pStr <= '9') )
5929cdf0e10cSrcweir             {
5930cdf0e10cSrcweir                 // translate characters to local preference
5931cdf0e10cSrcweir                 sal_UCS4 cChar = GetLocalizedChar( *pStr, meTextLanguage );
5932cdf0e10cSrcweir                 if( cChar != *pStr )
5933cdf0e10cSrcweir                     // TODO: are the localized digit surrogates?
5934cdf0e10cSrcweir                     rStr.SetChar( static_cast<sal_uInt16>(pStr - pBase),
5935cdf0e10cSrcweir                                  static_cast<sal_Unicode>(cChar) );
5936cdf0e10cSrcweir             }
5937cdf0e10cSrcweir         }
5938cdf0e10cSrcweir     }
5939cdf0e10cSrcweir 
5940cdf0e10cSrcweir     // right align for RTL text, DRAWPOS_REVERSED, RTL window style
5941cdf0e10cSrcweir     bool bRightAlign = ((mnTextLayoutMode & TEXT_LAYOUT_BIDI_RTL) != 0);
5942cdf0e10cSrcweir     if( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT )
5943cdf0e10cSrcweir         bRightAlign = false;
5944cdf0e10cSrcweir     else if ( mnTextLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT )
5945cdf0e10cSrcweir         bRightAlign = true;
5946cdf0e10cSrcweir     // SSA: hack for western office, ie text get right aligned
5947cdf0e10cSrcweir     //      for debugging purposes of mirrored UI
5948cdf0e10cSrcweir     //static const char* pEnv = getenv( "SAL_RTL_MIRRORTEXT" );
5949cdf0e10cSrcweir     bool bRTLWindow = IsRTLEnabled();
5950cdf0e10cSrcweir     bRightAlign ^= bRTLWindow;
5951cdf0e10cSrcweir     if( bRightAlign )
5952cdf0e10cSrcweir         nLayoutFlags |= SAL_LAYOUT_RIGHT_ALIGN;
5953cdf0e10cSrcweir 
5954cdf0e10cSrcweir     // set layout options
5955cdf0e10cSrcweir     ImplLayoutArgs aLayoutArgs( rStr.GetBuffer(), rStr.Len(), nMinIndex, nEndIndex, nLayoutFlags );
5956cdf0e10cSrcweir 
5957cdf0e10cSrcweir     int nOrientation = mpFontEntry ? mpFontEntry->mnOrientation : 0;
5958cdf0e10cSrcweir     aLayoutArgs.SetOrientation( nOrientation );
5959cdf0e10cSrcweir 
5960cdf0e10cSrcweir     aLayoutArgs.SetLayoutWidth( nPixelWidth );
5961cdf0e10cSrcweir     aLayoutArgs.SetDXArray( pDXArray );
5962cdf0e10cSrcweir 
5963cdf0e10cSrcweir     return aLayoutArgs;
5964cdf0e10cSrcweir }
5965cdf0e10cSrcweir 
5966cdf0e10cSrcweir // -----------------------------------------------------------------------
5967cdf0e10cSrcweir 
5968cdf0e10cSrcweir SalLayout* OutputDevice::ImplLayout( const String& rOrigStr,
5969cdf0e10cSrcweir                                      xub_StrLen nMinIndex,
5970cdf0e10cSrcweir                                      xub_StrLen nLen,
5971cdf0e10cSrcweir                                      const Point& rLogicalPos,
5972cdf0e10cSrcweir                                      long nLogicalWidth,
5973cdf0e10cSrcweir                                      const sal_Int32* pDXArray,
5974cdf0e10cSrcweir                                      bool bFilter ) const
5975cdf0e10cSrcweir {
5976cdf0e10cSrcweir     // we need a graphics
5977cdf0e10cSrcweir     if( !mpGraphics )
5978cdf0e10cSrcweir         if( !ImplGetGraphics() )
5979cdf0e10cSrcweir             return NULL;
5980cdf0e10cSrcweir 
5981cdf0e10cSrcweir     // initialize font if needed
5982cdf0e10cSrcweir     if( mbNewFont )
5983cdf0e10cSrcweir         if( !ImplNewFont() )
5984cdf0e10cSrcweir             return NULL;
5985cdf0e10cSrcweir     if( mbInitFont )
5986cdf0e10cSrcweir         ImplInitFont();
5987cdf0e10cSrcweir 
5988cdf0e10cSrcweir     // check string index and length
5989cdf0e10cSrcweir     if( (unsigned)nMinIndex + nLen > rOrigStr.Len() )
5990cdf0e10cSrcweir     {
5991cdf0e10cSrcweir         const int nNewLen = (int)rOrigStr.Len() - nMinIndex;
5992cdf0e10cSrcweir         if( nNewLen <= 0 )
5993cdf0e10cSrcweir             return NULL;
5994cdf0e10cSrcweir         nLen = static_cast<xub_StrLen>(nNewLen);
5995cdf0e10cSrcweir     }
5996cdf0e10cSrcweir 
5997cdf0e10cSrcweir     String aStr = rOrigStr;
5998cdf0e10cSrcweir 
5999cdf0e10cSrcweir     // filter out special markers
6000cdf0e10cSrcweir     if( bFilter )
6001cdf0e10cSrcweir     {
6002cdf0e10cSrcweir         xub_StrLen nCutStart, nCutStop, nOrgLen = nLen;
6003cdf0e10cSrcweir         bool bFiltered = mpGraphics->filterText( rOrigStr, aStr, nMinIndex, nLen, nCutStart, nCutStop );
6004cdf0e10cSrcweir         if( !nLen )
6005cdf0e10cSrcweir             return NULL;
6006cdf0e10cSrcweir 
6007cdf0e10cSrcweir         if( bFiltered && nCutStop != nCutStart && pDXArray )
6008cdf0e10cSrcweir         {
6009cdf0e10cSrcweir             if( !nLen )
6010cdf0e10cSrcweir                 pDXArray = NULL;
6011cdf0e10cSrcweir             else
6012cdf0e10cSrcweir             {
6013cdf0e10cSrcweir                 sal_Int32* pAry = (sal_Int32*)alloca(sizeof(sal_Int32)*nLen);
6014cdf0e10cSrcweir                 if( nCutStart > nMinIndex )
6015cdf0e10cSrcweir                     memcpy( pAry, pDXArray, sizeof(sal_Int32)*(nCutStart-nMinIndex) );
6016cdf0e10cSrcweir                 // note: nCutStart will never be smaller than nMinIndex
6017cdf0e10cSrcweir                 memcpy( pAry+nCutStart-nMinIndex,
6018cdf0e10cSrcweir                         pDXArray + nOrgLen - (nCutStop-nMinIndex),
6019cdf0e10cSrcweir                         sizeof(sal_Int32)*(nLen - (nCutStart-nMinIndex)) );
6020cdf0e10cSrcweir                 pDXArray = pAry;
6021cdf0e10cSrcweir             }
6022cdf0e10cSrcweir         }
6023cdf0e10cSrcweir     }
6024cdf0e10cSrcweir 
6025cdf0e10cSrcweir     // convert from logical units to physical units
6026cdf0e10cSrcweir     // recode string if needed
6027cdf0e10cSrcweir     if( mpFontEntry->mpConversion )
6028cdf0e10cSrcweir         mpFontEntry->mpConversion->RecodeString( aStr, 0, aStr.Len() );
6029cdf0e10cSrcweir 
6030cdf0e10cSrcweir     long nPixelWidth = nLogicalWidth;
6031cdf0e10cSrcweir     if( nLogicalWidth && mbMap )
6032cdf0e10cSrcweir         nPixelWidth = ImplLogicWidthToDevicePixel( nLogicalWidth );
6033cdf0e10cSrcweir     if( pDXArray && mbMap )
6034cdf0e10cSrcweir     {
6035cdf0e10cSrcweir         // convert from logical units to font units using a temporary array
6036cdf0e10cSrcweir         sal_Int32* pTempDXAry = (sal_Int32*)alloca( nLen * sizeof(sal_Int32) );
6037cdf0e10cSrcweir         // using base position for better rounding a.k.a. "dancing characters"
6038cdf0e10cSrcweir         int nPixelXOfs = ImplLogicWidthToDevicePixel( rLogicalPos.X() );
6039cdf0e10cSrcweir         for( int i = 0; i < nLen; ++i )
6040cdf0e10cSrcweir             pTempDXAry[i] = ImplLogicWidthToDevicePixel( rLogicalPos.X() + pDXArray[i] ) - nPixelXOfs;
6041cdf0e10cSrcweir 
6042cdf0e10cSrcweir         pDXArray = pTempDXAry;
6043cdf0e10cSrcweir     }
6044cdf0e10cSrcweir 
6045cdf0e10cSrcweir     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen, nPixelWidth, pDXArray );
6046cdf0e10cSrcweir 
6047cdf0e10cSrcweir     // get matching layout object for base font
6048cdf0e10cSrcweir     SalLayout* pSalLayout = NULL;
6049cdf0e10cSrcweir     if( mpPDFWriter )
6050cdf0e10cSrcweir         pSalLayout = mpPDFWriter->GetTextLayout( aLayoutArgs, &mpFontEntry->maFontSelData );
6051cdf0e10cSrcweir 
6052cdf0e10cSrcweir     if( !pSalLayout )
6053cdf0e10cSrcweir         pSalLayout = mpGraphics->GetTextLayout( aLayoutArgs, 0 );
6054cdf0e10cSrcweir 
6055cdf0e10cSrcweir     // layout text
6056cdf0e10cSrcweir     if( pSalLayout && !pSalLayout->LayoutText( aLayoutArgs ) )
6057cdf0e10cSrcweir     {
6058cdf0e10cSrcweir         pSalLayout->Release();
6059cdf0e10cSrcweir         pSalLayout = NULL;
6060cdf0e10cSrcweir     }
6061cdf0e10cSrcweir 
6062cdf0e10cSrcweir     if( !pSalLayout )
6063cdf0e10cSrcweir         return NULL;
6064cdf0e10cSrcweir 
6065cdf0e10cSrcweir     // do glyph fallback if needed
6066cdf0e10cSrcweir     // #105768# avoid fallback for very small font sizes
6067cdf0e10cSrcweir     if( aLayoutArgs.NeedFallback() )
6068cdf0e10cSrcweir         if( mpFontEntry && (mpFontEntry->maFontSelData.mnHeight >= 3) )
6069cdf0e10cSrcweir             pSalLayout = ImplGlyphFallbackLayout( pSalLayout, aLayoutArgs );
6070cdf0e10cSrcweir 
6071cdf0e10cSrcweir     // position, justify, etc. the layout
6072cdf0e10cSrcweir     pSalLayout->AdjustLayout( aLayoutArgs );
6073cdf0e10cSrcweir     pSalLayout->DrawBase() = ImplLogicToDevicePixel( rLogicalPos );
6074cdf0e10cSrcweir     // adjust to right alignment if necessary
6075cdf0e10cSrcweir     if( aLayoutArgs.mnFlags & SAL_LAYOUT_RIGHT_ALIGN )
6076cdf0e10cSrcweir     {
6077cdf0e10cSrcweir         long nRTLOffset;
6078cdf0e10cSrcweir         if( pDXArray )
6079cdf0e10cSrcweir             nRTLOffset = pDXArray[ nLen - 1 ];
6080cdf0e10cSrcweir         else if( nPixelWidth )
6081cdf0e10cSrcweir             nRTLOffset = nPixelWidth;
6082cdf0e10cSrcweir         else
6083cdf0e10cSrcweir             nRTLOffset = pSalLayout->GetTextWidth() / pSalLayout->GetUnitsPerPixel();
6084cdf0e10cSrcweir         pSalLayout->DrawOffset().X() = 1 - nRTLOffset;
6085cdf0e10cSrcweir     }
6086cdf0e10cSrcweir 
6087cdf0e10cSrcweir     return pSalLayout;
6088cdf0e10cSrcweir }
6089cdf0e10cSrcweir 
6090cdf0e10cSrcweir // -----------------------------------------------------------------------
6091cdf0e10cSrcweir 
6092cdf0e10cSrcweir SalLayout* OutputDevice::ImplGlyphFallbackLayout( SalLayout* pSalLayout, ImplLayoutArgs& rLayoutArgs ) const
6093cdf0e10cSrcweir {
6094cdf0e10cSrcweir     // prepare multi level glyph fallback
6095cdf0e10cSrcweir     MultiSalLayout* pMultiSalLayout = NULL;
6096cdf0e10cSrcweir     ImplLayoutRuns aLayoutRuns = rLayoutArgs.maRuns;
6097cdf0e10cSrcweir     rLayoutArgs.PrepareFallback();
6098cdf0e10cSrcweir     rLayoutArgs.mnFlags |= SAL_LAYOUT_FOR_FALLBACK;
6099cdf0e10cSrcweir 
6100cdf0e10cSrcweir #if defined(HDU_DEBUG)
6101cdf0e10cSrcweir     {
6102cdf0e10cSrcweir         int nCharPos = -1;
6103cdf0e10cSrcweir         bool bRTL = false;
6104cdf0e10cSrcweir         fprintf(stderr,"OD:ImplLayout Glyph Fallback for");
6105cdf0e10cSrcweir         for( int i=0; i<8 && rLayoutArgs.GetNextPos( &nCharPos, &bRTL); ++i )
6106cdf0e10cSrcweir             fprintf(stderr," U+%04X", rLayoutArgs.mpStr[ nCharPos ] );
6107cdf0e10cSrcweir         fprintf(stderr,"\n");
6108cdf0e10cSrcweir         rLayoutArgs.ResetPos();
6109cdf0e10cSrcweir     }
6110cdf0e10cSrcweir #endif
6111cdf0e10cSrcweir     // get list of unicodes that need glyph fallback
6112cdf0e10cSrcweir     int nCharPos = -1;
6113cdf0e10cSrcweir     bool bRTL = false;
6114cdf0e10cSrcweir     rtl::OUStringBuffer aMissingCodeBuf;
6115cdf0e10cSrcweir     while( rLayoutArgs.GetNextPos( &nCharPos, &bRTL) )
6116cdf0e10cSrcweir         aMissingCodeBuf.append( rLayoutArgs.mpStr[ nCharPos ] );
6117cdf0e10cSrcweir     rLayoutArgs.ResetPos();
6118cdf0e10cSrcweir     rtl::OUString aMissingCodes = aMissingCodeBuf.makeStringAndClear();
6119cdf0e10cSrcweir 
6120cdf0e10cSrcweir     ImplFontSelectData aFontSelData = mpFontEntry->maFontSelData;
6121cdf0e10cSrcweir 
6122cdf0e10cSrcweir     ImplFontMetricData aOrigMetric( aFontSelData );
6123cdf0e10cSrcweir     // TODO: use cached metric in fontentry
6124cdf0e10cSrcweir     mpGraphics->GetFontMetric( &aOrigMetric );
6125cdf0e10cSrcweir 
6126cdf0e10cSrcweir     // when device specific font substitution may have been performed for
6127cdf0e10cSrcweir     // the originally selected font then make sure that a fallback to that
6128cdf0e10cSrcweir     // font is performed first
6129cdf0e10cSrcweir     int nDevSpecificFallback = 0;
6130cdf0e10cSrcweir     if( mpOutDevData && !mpOutDevData->maDevFontSubst.Empty() )
6131cdf0e10cSrcweir         nDevSpecificFallback = 1;
6132cdf0e10cSrcweir 
6133cdf0e10cSrcweir     // try if fallback fonts support the missing unicodes
6134cdf0e10cSrcweir     for( int nFallbackLevel = 1; nFallbackLevel < MAX_FALLBACK; ++nFallbackLevel )
6135cdf0e10cSrcweir     {
6136cdf0e10cSrcweir         // find a font family suited for glyph fallback
6137cdf0e10cSrcweir #ifndef FONTFALLBACK_HOOKS_DISABLED
6138cdf0e10cSrcweir         // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
6139cdf0e10cSrcweir         // if the system-specific glyph fallback is active
6140cdf0e10cSrcweir         aFontSelData.mpFontEntry = mpFontEntry; // reset the fontentry to base-level
6141cdf0e10cSrcweir #endif
6142cdf0e10cSrcweir         ImplFontEntry* pFallbackFont = mpFontCache->GetGlyphFallbackFont( mpFontList,
6143cdf0e10cSrcweir             aFontSelData, nFallbackLevel-nDevSpecificFallback, aMissingCodes );
6144cdf0e10cSrcweir         if( !pFallbackFont )
6145cdf0e10cSrcweir             break;
6146cdf0e10cSrcweir 
6147cdf0e10cSrcweir         aFontSelData.mpFontEntry = pFallbackFont;
6148cdf0e10cSrcweir         aFontSelData.mpFontData = pFallbackFont->maFontSelData.mpFontData;
6149cdf0e10cSrcweir         if( mpFontEntry && nFallbackLevel < MAX_FALLBACK-1)
6150cdf0e10cSrcweir         {
6151cdf0e10cSrcweir             // ignore fallback font if it is the same as the original font
6152cdf0e10cSrcweir             if( mpFontEntry->maFontSelData.mpFontData == aFontSelData.mpFontData )
6153cdf0e10cSrcweir             {
6154cdf0e10cSrcweir                 mpFontCache->Release( pFallbackFont );
6155cdf0e10cSrcweir                 continue;
6156cdf0e10cSrcweir             }
6157cdf0e10cSrcweir         }
6158cdf0e10cSrcweir 
6159cdf0e10cSrcweir #if defined(HDU_DEBUG)
6160cdf0e10cSrcweir         {
6161cdf0e10cSrcweir             ByteString aOrigFontName( maFont.GetName(), RTL_TEXTENCODING_UTF8);
6162cdf0e10cSrcweir             ByteString aFallbackName( aFontSelData.mpFontData->GetFamilyName(),
6163cdf0e10cSrcweir                 RTL_TEXTENCODING_UTF8);
6164cdf0e10cSrcweir             fprintf(stderr,"\tGlyphFallback[lvl=%d] \"%s\" -> \"%s\" (q=%d)\n",
6165cdf0e10cSrcweir                 nFallbackLevel, aOrigFontName.GetBuffer(), aFallbackName.GetBuffer(),
6166cdf0e10cSrcweir                 aFontSelData.mpFontData->GetQuality());
6167cdf0e10cSrcweir         }
6168cdf0e10cSrcweir #endif
6169cdf0e10cSrcweir 
6170cdf0e10cSrcweir         // TODO: try to get the metric data from the GFB's mpFontEntry
6171cdf0e10cSrcweir         ImplFontMetricData aSubstituteMetric( aFontSelData );
6172cdf0e10cSrcweir         pFallbackFont->mnSetFontFlags = mpGraphics->SetFont( &aFontSelData, nFallbackLevel );
6173cdf0e10cSrcweir         mpGraphics->GetFontMetric( &aSubstituteMetric, nFallbackLevel );
6174cdf0e10cSrcweir 
6175cdf0e10cSrcweir         const long nOriginalHeight = aOrigMetric.mnAscent + aOrigMetric.mnDescent;
6176cdf0e10cSrcweir         const long nSubstituteHeight = aSubstituteMetric.mnAscent + aSubstituteMetric.mnDescent;
6177cdf0e10cSrcweir         // Too tall, shrink it a bit. Need a better calculation to include extra
6178cdf0e10cSrcweir         // factors and any extra wriggle room we might have available?
6179cdf0e10cSrcweir     // TODO: should we scale by max-ascent/max-descent instead of design height?
6180cdf0e10cSrcweir         if( nSubstituteHeight > nOriginalHeight )
6181cdf0e10cSrcweir         {
6182cdf0e10cSrcweir             const float fScale = nOriginalHeight / (float)nSubstituteHeight;
6183cdf0e10cSrcweir             const float fOrigHeight = aFontSelData.mfExactHeight;
6184cdf0e10cSrcweir             const int nOrigHeight = aFontSelData.mnHeight;
6185cdf0e10cSrcweir             aFontSelData.mfExactHeight *= fScale;
6186cdf0e10cSrcweir             aFontSelData.mnHeight = static_cast<int>(aFontSelData.mfExactHeight);
6187cdf0e10cSrcweir             pFallbackFont->mnSetFontFlags = mpGraphics->SetFont( &aFontSelData, nFallbackLevel );
6188cdf0e10cSrcweir             aFontSelData.mnHeight = nOrigHeight;
6189cdf0e10cSrcweir             aFontSelData.mfExactHeight = fOrigHeight;
6190cdf0e10cSrcweir         }
6191cdf0e10cSrcweir 
6192cdf0e10cSrcweir         // create and add glyph fallback layout to multilayout
6193cdf0e10cSrcweir         rLayoutArgs.ResetPos();
6194cdf0e10cSrcweir         SalLayout* pFallback = mpGraphics->GetTextLayout( rLayoutArgs, nFallbackLevel );
6195cdf0e10cSrcweir         if( pFallback )
6196cdf0e10cSrcweir         {
6197cdf0e10cSrcweir             if( pFallback->LayoutText( rLayoutArgs ) )
6198cdf0e10cSrcweir             {
6199cdf0e10cSrcweir                 if( !pMultiSalLayout )
6200cdf0e10cSrcweir                     pMultiSalLayout = new MultiSalLayout( *pSalLayout );
6201cdf0e10cSrcweir                 pMultiSalLayout->AddFallback( *pFallback,
6202cdf0e10cSrcweir                     rLayoutArgs.maRuns, aFontSelData.mpFontData );
6203cdf0e10cSrcweir                 if (nFallbackLevel == MAX_FALLBACK-1)
6204cdf0e10cSrcweir                     pMultiSalLayout->SetInComplete();
6205cdf0e10cSrcweir             }
6206cdf0e10cSrcweir             else
6207cdf0e10cSrcweir             {
6208cdf0e10cSrcweir                 // there is no need for a font that couldn't resolve anything
6209cdf0e10cSrcweir                 pFallback->Release();
6210cdf0e10cSrcweir             }
6211cdf0e10cSrcweir         }
6212cdf0e10cSrcweir 
6213cdf0e10cSrcweir         mpFontCache->Release( pFallbackFont );
6214cdf0e10cSrcweir 
6215cdf0e10cSrcweir         // break when this fallback was sufficient
6216cdf0e10cSrcweir         if( !rLayoutArgs.PrepareFallback() )
6217cdf0e10cSrcweir             break;
6218cdf0e10cSrcweir     }
6219cdf0e10cSrcweir 
6220cdf0e10cSrcweir     if( pMultiSalLayout && pMultiSalLayout->LayoutText( rLayoutArgs ) )
6221cdf0e10cSrcweir         pSalLayout = pMultiSalLayout;
6222cdf0e10cSrcweir 
6223cdf0e10cSrcweir     // restore orig font settings
6224cdf0e10cSrcweir     pSalLayout->InitFont();
6225cdf0e10cSrcweir     rLayoutArgs.maRuns = aLayoutRuns;
6226cdf0e10cSrcweir 
6227cdf0e10cSrcweir     return pSalLayout;
6228cdf0e10cSrcweir }
6229cdf0e10cSrcweir 
6230cdf0e10cSrcweir // -----------------------------------------------------------------------
6231cdf0e10cSrcweir 
6232cdf0e10cSrcweir sal_Bool OutputDevice::GetTextIsRTL(
6233cdf0e10cSrcweir             const String& rString,
6234cdf0e10cSrcweir             xub_StrLen nIndex, xub_StrLen nLen ) const
6235cdf0e10cSrcweir {
6236cdf0e10cSrcweir     String aStr( rString );
6237cdf0e10cSrcweir     ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
6238cdf0e10cSrcweir     bool bRTL = false;
6239cdf0e10cSrcweir     int nCharPos = -1;
6240cdf0e10cSrcweir     aArgs.GetNextPos( &nCharPos, &bRTL );
6241cdf0e10cSrcweir     return (nCharPos != nIndex) ? sal_True : sal_False;
6242cdf0e10cSrcweir }
6243cdf0e10cSrcweir 
6244cdf0e10cSrcweir // -----------------------------------------------------------------------
6245cdf0e10cSrcweir 
6246cdf0e10cSrcweir xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
6247cdf0e10cSrcweir                                        xub_StrLen nIndex, xub_StrLen nLen,
6248cdf0e10cSrcweir                                        long nCharExtra, sal_Bool /*TODO: bCellBreaking*/ ) const
6249cdf0e10cSrcweir {
6250cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetTextBreak()" );
6251cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6252cdf0e10cSrcweir 
6253cdf0e10cSrcweir     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
6254cdf0e10cSrcweir     xub_StrLen nRetVal = STRING_LEN;
6255cdf0e10cSrcweir     if( pSalLayout )
6256cdf0e10cSrcweir     {
6257cdf0e10cSrcweir         // convert logical widths into layout units
6258cdf0e10cSrcweir         // NOTE: be very careful to avoid rounding errors for nCharExtra case
6259cdf0e10cSrcweir         // problem with rounding errors especially for small nCharExtras
6260cdf0e10cSrcweir         // TODO: remove when layout units have subpixel granularity
6261cdf0e10cSrcweir         long nWidthFactor = pSalLayout->GetUnitsPerPixel();
6262cdf0e10cSrcweir         long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
6263cdf0e10cSrcweir         nTextWidth *= nWidthFactor * nSubPixelFactor;
6264cdf0e10cSrcweir         long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
6265cdf0e10cSrcweir         long nExtraPixelWidth = 0;
6266cdf0e10cSrcweir         if( nCharExtra != 0 )
6267cdf0e10cSrcweir         {
6268cdf0e10cSrcweir             nCharExtra *= nWidthFactor * nSubPixelFactor;
6269cdf0e10cSrcweir             nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
6270cdf0e10cSrcweir         }
6271cdf0e10cSrcweir         nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6272cdf0e10cSrcweir 
6273cdf0e10cSrcweir         pSalLayout->Release();
6274cdf0e10cSrcweir     }
6275cdf0e10cSrcweir 
6276cdf0e10cSrcweir     return nRetVal;
6277cdf0e10cSrcweir }
6278cdf0e10cSrcweir 
6279cdf0e10cSrcweir // -----------------------------------------------------------------------
6280cdf0e10cSrcweir 
6281cdf0e10cSrcweir xub_StrLen OutputDevice::GetTextBreak( const String& rStr, long nTextWidth,
6282cdf0e10cSrcweir                                        sal_Unicode nHyphenatorChar, xub_StrLen& rHyphenatorPos,
6283cdf0e10cSrcweir                                        xub_StrLen nIndex, xub_StrLen nLen,
6284cdf0e10cSrcweir                                        long nCharExtra ) const
6285cdf0e10cSrcweir {
6286cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetTextBreak()" );
6287cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6288cdf0e10cSrcweir 
6289cdf0e10cSrcweir     rHyphenatorPos = STRING_LEN;
6290cdf0e10cSrcweir 
6291cdf0e10cSrcweir     SalLayout* pSalLayout = ImplLayout( rStr, nIndex, nLen );
6292cdf0e10cSrcweir     if( !pSalLayout )
6293cdf0e10cSrcweir         return STRING_LEN;
6294cdf0e10cSrcweir 
6295cdf0e10cSrcweir     // convert logical widths into layout units
6296cdf0e10cSrcweir     // NOTE: be very careful to avoid rounding errors for nCharExtra case
6297cdf0e10cSrcweir     // problem with rounding errors especially for small nCharExtras
6298cdf0e10cSrcweir     // TODO: remove when layout units have subpixel granularity
6299cdf0e10cSrcweir     long nWidthFactor = pSalLayout->GetUnitsPerPixel();
6300cdf0e10cSrcweir     long nSubPixelFactor = (nWidthFactor < 64 ) ? 64 : 1;
6301cdf0e10cSrcweir 
6302cdf0e10cSrcweir     nTextWidth *= nWidthFactor * nSubPixelFactor;
6303cdf0e10cSrcweir     long nTextPixelWidth = ImplLogicWidthToDevicePixel( nTextWidth );
6304cdf0e10cSrcweir     long nExtraPixelWidth = 0;
6305cdf0e10cSrcweir     if( nCharExtra != 0 )
6306cdf0e10cSrcweir     {
6307cdf0e10cSrcweir         nCharExtra *= nWidthFactor * nSubPixelFactor;
6308cdf0e10cSrcweir         nExtraPixelWidth = ImplLogicWidthToDevicePixel( nCharExtra );
6309cdf0e10cSrcweir     }
6310cdf0e10cSrcweir 
6311cdf0e10cSrcweir     // calculate un-hyphenated break position
6312cdf0e10cSrcweir     xub_StrLen nRetVal = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6313cdf0e10cSrcweir 
6314cdf0e10cSrcweir     // calculate hyphenated break position
6315cdf0e10cSrcweir     String aHyphenatorStr( &nHyphenatorChar, 1 );
6316cdf0e10cSrcweir     xub_StrLen nTempLen = 1;
6317cdf0e10cSrcweir     SalLayout* pHyphenatorLayout = ImplLayout( aHyphenatorStr, 0, nTempLen );
6318cdf0e10cSrcweir     if( pHyphenatorLayout )
6319cdf0e10cSrcweir     {
6320cdf0e10cSrcweir         // calculate subpixel width of hyphenation character
6321cdf0e10cSrcweir         long nHyphenatorPixelWidth = pHyphenatorLayout->GetTextWidth() * nSubPixelFactor;
6322cdf0e10cSrcweir         pHyphenatorLayout->Release();
6323cdf0e10cSrcweir 
6324cdf0e10cSrcweir         // calculate hyphenated break position
6325cdf0e10cSrcweir         nTextPixelWidth -= nHyphenatorPixelWidth;
6326cdf0e10cSrcweir         if( nExtraPixelWidth > 0 )
6327cdf0e10cSrcweir             nTextPixelWidth -= nExtraPixelWidth;
6328cdf0e10cSrcweir 
6329cdf0e10cSrcweir         rHyphenatorPos = sal::static_int_cast<xub_StrLen>(pSalLayout->GetTextBreak( nTextPixelWidth, nExtraPixelWidth, nSubPixelFactor ));
6330cdf0e10cSrcweir 
6331cdf0e10cSrcweir         if( rHyphenatorPos > nRetVal )
6332cdf0e10cSrcweir             rHyphenatorPos = nRetVal;
6333cdf0e10cSrcweir     }
6334cdf0e10cSrcweir 
6335cdf0e10cSrcweir     pSalLayout->Release();
6336cdf0e10cSrcweir     return nRetVal;
6337cdf0e10cSrcweir }
6338cdf0e10cSrcweir 
6339cdf0e10cSrcweir // -----------------------------------------------------------------------
6340cdf0e10cSrcweir 
6341cdf0e10cSrcweir void OutputDevice::ImplDrawText( OutputDevice& rTargetDevice, const Rectangle& rRect,
6342cdf0e10cSrcweir                                  const String& rOrigStr, sal_uInt16 nStyle,
6343cdf0e10cSrcweir                                  MetricVector* pVector, String* pDisplayText,
6344cdf0e10cSrcweir                                  ::vcl::ITextLayout& _rLayout )
6345cdf0e10cSrcweir {
6346cdf0e10cSrcweir     Color aOldTextColor;
6347cdf0e10cSrcweir     Color aOldTextFillColor;
6348cdf0e10cSrcweir     sal_Bool  bRestoreFillColor = false;
6349cdf0e10cSrcweir     if ( (nStyle & TEXT_DRAW_DISABLE) && ! pVector )
6350cdf0e10cSrcweir     {
6351cdf0e10cSrcweir         sal_Bool  bHighContrastBlack = sal_False;
6352cdf0e10cSrcweir         sal_Bool  bHighContrastWhite = sal_False;
6353cdf0e10cSrcweir         const StyleSettings& rStyleSettings( rTargetDevice.GetSettings().GetStyleSettings() );
6354cdf0e10cSrcweir         if( rStyleSettings.GetHighContrastMode() )
6355cdf0e10cSrcweir         {
6356cdf0e10cSrcweir             Color aCol;
6357cdf0e10cSrcweir             if( rTargetDevice.IsBackground() )
6358cdf0e10cSrcweir                 aCol = rTargetDevice.GetBackground().GetColor();
6359cdf0e10cSrcweir             else
6360cdf0e10cSrcweir                 // best guess is the face color here
6361cdf0e10cSrcweir                 // but it may be totally wrong. the background color
6362cdf0e10cSrcweir                 // was typically already reset
6363cdf0e10cSrcweir                 aCol = rStyleSettings.GetFaceColor();
6364cdf0e10cSrcweir 
6365cdf0e10cSrcweir             bHighContrastBlack = aCol.IsDark();
6366cdf0e10cSrcweir             bHighContrastWhite = aCol.IsBright();
6367cdf0e10cSrcweir         }
6368cdf0e10cSrcweir 
6369cdf0e10cSrcweir         aOldTextColor = rTargetDevice.GetTextColor();
6370cdf0e10cSrcweir         if ( rTargetDevice.IsTextFillColor() )
6371cdf0e10cSrcweir         {
6372cdf0e10cSrcweir             bRestoreFillColor = sal_True;
6373cdf0e10cSrcweir             aOldTextFillColor = rTargetDevice.GetTextFillColor();
6374cdf0e10cSrcweir         }
6375cdf0e10cSrcweir         if( bHighContrastBlack )
6376cdf0e10cSrcweir             rTargetDevice.SetTextColor( COL_GREEN );
6377cdf0e10cSrcweir         else if( bHighContrastWhite )
6378cdf0e10cSrcweir             rTargetDevice.SetTextColor( COL_LIGHTGREEN );
6379cdf0e10cSrcweir         else
6380cdf0e10cSrcweir         {
6381cdf0e10cSrcweir             // draw disabled text always without shadow
6382cdf0e10cSrcweir             // as it fits better with native look
6383cdf0e10cSrcweir             /*
6384cdf0e10cSrcweir             SetTextColor( GetSettings().GetStyleSettings().GetLightColor() );
6385cdf0e10cSrcweir             Rectangle aRect = rRect;
6386cdf0e10cSrcweir             aRect.Move( 1, 1 );
6387cdf0e10cSrcweir             DrawText( aRect, rOrigStr, nStyle & ~TEXT_DRAW_DISABLE );
6388cdf0e10cSrcweir             */
6389cdf0e10cSrcweir             rTargetDevice.SetTextColor( rTargetDevice.GetSettings().GetStyleSettings().GetDisableColor() );
6390cdf0e10cSrcweir         }
6391cdf0e10cSrcweir     }
6392cdf0e10cSrcweir 
6393cdf0e10cSrcweir     long        nWidth          = rRect.GetWidth();
6394cdf0e10cSrcweir     long        nHeight         = rRect.GetHeight();
6395cdf0e10cSrcweir 
6396cdf0e10cSrcweir     if ( ((nWidth <= 0) || (nHeight <= 0)) && (nStyle & TEXT_DRAW_CLIP) )
6397cdf0e10cSrcweir         return;
6398cdf0e10cSrcweir 
6399cdf0e10cSrcweir     Point       aPos            = rRect.TopLeft();
6400cdf0e10cSrcweir 
6401cdf0e10cSrcweir     long        nTextHeight     = rTargetDevice.GetTextHeight();
6402cdf0e10cSrcweir     TextAlign   eAlign          = rTargetDevice.GetTextAlign();
6403cdf0e10cSrcweir     xub_StrLen  nMnemonicPos    = STRING_NOTFOUND;
6404cdf0e10cSrcweir 
6405cdf0e10cSrcweir     String aStr = rOrigStr;
6406cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MNEMONIC )
6407cdf0e10cSrcweir         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
6408cdf0e10cSrcweir 
6409cdf0e10cSrcweir     const bool bDrawMnemonics = !(rTargetDevice.GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector;
6410cdf0e10cSrcweir 
6411cdf0e10cSrcweir     // Mehrzeiligen Text behandeln wir anders
6412cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MULTILINE )
6413cdf0e10cSrcweir     {
6414cdf0e10cSrcweir 
6415cdf0e10cSrcweir         XubString               aLastLine;
6416cdf0e10cSrcweir         ImplMultiTextLineInfo   aMultiLineInfo;
6417cdf0e10cSrcweir         ImplTextLineInfo*       pLineInfo;
6418cdf0e10cSrcweir         long                    nMaxTextWidth;
6419cdf0e10cSrcweir         xub_StrLen              i;
6420cdf0e10cSrcweir         xub_StrLen              nLines;
6421cdf0e10cSrcweir         xub_StrLen              nFormatLines;
6422cdf0e10cSrcweir 
6423cdf0e10cSrcweir         if ( nTextHeight )
6424cdf0e10cSrcweir         {
6425cdf0e10cSrcweir             nMaxTextWidth = ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _rLayout );
6426cdf0e10cSrcweir             nLines = (xub_StrLen)(nHeight/nTextHeight);
6427cdf0e10cSrcweir             nFormatLines = aMultiLineInfo.Count();
6428cdf0e10cSrcweir             if ( !nLines )
6429cdf0e10cSrcweir                 nLines = 1;
6430cdf0e10cSrcweir             if ( nFormatLines > nLines )
6431cdf0e10cSrcweir             {
6432cdf0e10cSrcweir                 if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
6433cdf0e10cSrcweir                 {
6434cdf0e10cSrcweir                     // Letzte Zeile zusammenbauen und kuerzen
6435cdf0e10cSrcweir                     nFormatLines = nLines-1;
6436cdf0e10cSrcweir 
6437cdf0e10cSrcweir                     pLineInfo = aMultiLineInfo.GetLine( nFormatLines );
6438cdf0e10cSrcweir                     aLastLine = aStr.Copy( pLineInfo->GetIndex() );
6439cdf0e10cSrcweir                     aLastLine.ConvertLineEnd( LINEEND_LF );
6440cdf0e10cSrcweir                     // Alle LineFeed's durch Spaces ersetzen
6441cdf0e10cSrcweir                     xub_StrLen nLastLineLen = aLastLine.Len();
6442cdf0e10cSrcweir                     for ( i = 0; i < nLastLineLen; i++ )
6443cdf0e10cSrcweir                     {
6444cdf0e10cSrcweir                         if ( aLastLine.GetChar( i ) == _LF )
6445cdf0e10cSrcweir                             aLastLine.SetChar( i, ' ' );
6446cdf0e10cSrcweir                     }
6447cdf0e10cSrcweir                     aLastLine = ImplGetEllipsisString( rTargetDevice, aLastLine, nWidth, nStyle, _rLayout );
6448cdf0e10cSrcweir                     nStyle &= ~(TEXT_DRAW_VCENTER | TEXT_DRAW_BOTTOM);
6449cdf0e10cSrcweir                     nStyle |= TEXT_DRAW_TOP;
6450cdf0e10cSrcweir                 }
6451cdf0e10cSrcweir             }
6452cdf0e10cSrcweir             else
6453cdf0e10cSrcweir             {
6454cdf0e10cSrcweir                 if ( nMaxTextWidth <= nWidth )
6455cdf0e10cSrcweir                     nStyle &= ~TEXT_DRAW_CLIP;
6456cdf0e10cSrcweir             }
6457cdf0e10cSrcweir 
6458cdf0e10cSrcweir             // Muss in der Hoehe geclippt werden?
6459cdf0e10cSrcweir             if ( nFormatLines*nTextHeight > nHeight )
6460cdf0e10cSrcweir                 nStyle |= TEXT_DRAW_CLIP;
6461cdf0e10cSrcweir 
6462cdf0e10cSrcweir             // Clipping setzen
6463cdf0e10cSrcweir             if ( nStyle & TEXT_DRAW_CLIP )
6464cdf0e10cSrcweir             {
6465cdf0e10cSrcweir                 rTargetDevice.Push( PUSH_CLIPREGION );
6466cdf0e10cSrcweir                 rTargetDevice.IntersectClipRegion( rRect );
6467cdf0e10cSrcweir             }
6468cdf0e10cSrcweir 
6469cdf0e10cSrcweir             // Vertikales Alignment
6470cdf0e10cSrcweir             if ( nStyle & TEXT_DRAW_BOTTOM )
6471cdf0e10cSrcweir                 aPos.Y() += nHeight-(nFormatLines*nTextHeight);
6472cdf0e10cSrcweir             else if ( nStyle & TEXT_DRAW_VCENTER )
6473cdf0e10cSrcweir                 aPos.Y() += (nHeight-(nFormatLines*nTextHeight))/2;
6474cdf0e10cSrcweir 
6475cdf0e10cSrcweir             // Font Alignment
6476cdf0e10cSrcweir             if ( eAlign == ALIGN_BOTTOM )
6477cdf0e10cSrcweir                 aPos.Y() += nTextHeight;
6478cdf0e10cSrcweir             else if ( eAlign == ALIGN_BASELINE )
6479cdf0e10cSrcweir                 aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
6480cdf0e10cSrcweir 
6481cdf0e10cSrcweir             // Alle Zeilen ausgeben, bis auf die letzte
6482cdf0e10cSrcweir             for ( i = 0; i < nFormatLines; i++ )
6483cdf0e10cSrcweir             {
6484cdf0e10cSrcweir                 pLineInfo = aMultiLineInfo.GetLine( i );
6485cdf0e10cSrcweir                 if ( nStyle & TEXT_DRAW_RIGHT )
6486cdf0e10cSrcweir                     aPos.X() += nWidth-pLineInfo->GetWidth();
6487cdf0e10cSrcweir                 else if ( nStyle & TEXT_DRAW_CENTER )
6488cdf0e10cSrcweir                     aPos.X() += (nWidth-pLineInfo->GetWidth())/2;
6489cdf0e10cSrcweir                 xub_StrLen nIndex   = pLineInfo->GetIndex();
6490cdf0e10cSrcweir                 xub_StrLen nLineLen = pLineInfo->GetLen();
6491cdf0e10cSrcweir                 _rLayout.DrawText( aPos, aStr, nIndex, nLineLen, pVector, pDisplayText );
6492cdf0e10cSrcweir                 if ( bDrawMnemonics )
6493cdf0e10cSrcweir                 {
6494cdf0e10cSrcweir                     if ( (nMnemonicPos >= nIndex) && (nMnemonicPos < nIndex+nLineLen) )
6495cdf0e10cSrcweir                     {
6496cdf0e10cSrcweir                         long        nMnemonicX;
6497cdf0e10cSrcweir                         long        nMnemonicY;
6498cdf0e10cSrcweir                         long        nMnemonicWidth;
6499cdf0e10cSrcweir 
6500cdf0e10cSrcweir                         sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * nLineLen );
6501cdf0e10cSrcweir                         /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray,
6502cdf0e10cSrcweir                                                 nIndex, nLineLen );
6503cdf0e10cSrcweir                         long lc_x1 = pCaretXArray[2*(nMnemonicPos - nIndex)];
6504cdf0e10cSrcweir                         long lc_x2 = pCaretXArray[2*(nMnemonicPos - nIndex)+1];
6505cdf0e10cSrcweir                         nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
6506cdf0e10cSrcweir 
6507cdf0e10cSrcweir                         Point       aTempPos = rTargetDevice.LogicToPixel( aPos );
6508cdf0e10cSrcweir                         nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min( lc_x1, lc_x2 ) );
6509cdf0e10cSrcweir                         nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
6510cdf0e10cSrcweir                         rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6511cdf0e10cSrcweir                     }
6512cdf0e10cSrcweir                 }
6513cdf0e10cSrcweir                 aPos.Y() += nTextHeight;
6514cdf0e10cSrcweir                 aPos.X() = rRect.Left();
6515cdf0e10cSrcweir             }
6516cdf0e10cSrcweir 
6517cdf0e10cSrcweir 
6518cdf0e10cSrcweir             // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
6519cdf0e10cSrcweir             // da die Zeile gekuerzt wurde
6520cdf0e10cSrcweir             if ( aLastLine.Len() )
6521cdf0e10cSrcweir                 _rLayout.DrawText( aPos, aLastLine, 0, STRING_LEN, pVector, pDisplayText );
6522cdf0e10cSrcweir 
6523cdf0e10cSrcweir             // Clipping zuruecksetzen
6524cdf0e10cSrcweir             if ( nStyle & TEXT_DRAW_CLIP )
6525cdf0e10cSrcweir                 rTargetDevice.Pop();
6526cdf0e10cSrcweir         }
6527cdf0e10cSrcweir     }
6528cdf0e10cSrcweir     else
6529cdf0e10cSrcweir     {
6530cdf0e10cSrcweir         long nTextWidth = _rLayout.GetTextWidth( aStr, 0, STRING_LEN );
6531cdf0e10cSrcweir 
6532cdf0e10cSrcweir         // Evt. Text kuerzen
6533cdf0e10cSrcweir         if ( nTextWidth > nWidth )
6534cdf0e10cSrcweir         {
6535cdf0e10cSrcweir             if ( nStyle & TEXT_DRAW_ELLIPSIS )
6536cdf0e10cSrcweir             {
6537cdf0e10cSrcweir                 aStr = ImplGetEllipsisString( rTargetDevice, aStr, nWidth, nStyle, _rLayout );
6538cdf0e10cSrcweir                 nStyle &= ~(TEXT_DRAW_CENTER | TEXT_DRAW_RIGHT);
6539cdf0e10cSrcweir                 nStyle |= TEXT_DRAW_LEFT;
6540cdf0e10cSrcweir                 nTextWidth = _rLayout.GetTextWidth( aStr, 0, aStr.Len() );
6541cdf0e10cSrcweir             }
6542cdf0e10cSrcweir         }
6543cdf0e10cSrcweir         else
6544cdf0e10cSrcweir         {
6545cdf0e10cSrcweir             if ( nTextHeight <= nHeight )
6546cdf0e10cSrcweir                 nStyle &= ~TEXT_DRAW_CLIP;
6547cdf0e10cSrcweir         }
6548cdf0e10cSrcweir 
6549cdf0e10cSrcweir         // horizontal text alignment
6550cdf0e10cSrcweir         if ( nStyle & TEXT_DRAW_RIGHT )
6551cdf0e10cSrcweir             aPos.X() += nWidth-nTextWidth;
6552cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_CENTER )
6553cdf0e10cSrcweir             aPos.X() += (nWidth-nTextWidth)/2;
6554cdf0e10cSrcweir 
6555cdf0e10cSrcweir         // vertical font alignment
6556cdf0e10cSrcweir         if ( eAlign == ALIGN_BOTTOM )
6557cdf0e10cSrcweir             aPos.Y() += nTextHeight;
6558cdf0e10cSrcweir         else if ( eAlign == ALIGN_BASELINE )
6559cdf0e10cSrcweir             aPos.Y() += rTargetDevice.GetFontMetric().GetAscent();
6560cdf0e10cSrcweir 
6561cdf0e10cSrcweir         if ( nStyle & TEXT_DRAW_BOTTOM )
6562cdf0e10cSrcweir             aPos.Y() += nHeight-nTextHeight;
6563cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_VCENTER )
6564cdf0e10cSrcweir             aPos.Y() += (nHeight-nTextHeight)/2;
6565cdf0e10cSrcweir 
6566cdf0e10cSrcweir         long        nMnemonicX = 0;
6567cdf0e10cSrcweir         long        nMnemonicY = 0;
6568cdf0e10cSrcweir         long        nMnemonicWidth = 0;
6569cdf0e10cSrcweir         if ( nMnemonicPos != STRING_NOTFOUND )
6570cdf0e10cSrcweir         {
6571cdf0e10cSrcweir             sal_Int32* pCaretXArray = (sal_Int32*) alloca( 2 * sizeof(sal_Int32) * aStr.Len() );
6572cdf0e10cSrcweir             /*sal_Bool bRet =*/ _rLayout.GetCaretPositions( aStr, pCaretXArray, 0, aStr.Len() );
6573cdf0e10cSrcweir             long lc_x1 = pCaretXArray[2*(nMnemonicPos)];
6574cdf0e10cSrcweir             long lc_x2 = pCaretXArray[2*(nMnemonicPos)+1];
6575cdf0e10cSrcweir             nMnemonicWidth = rTargetDevice.ImplLogicWidthToDevicePixel( ::abs((int)(lc_x1 - lc_x2)) );
6576cdf0e10cSrcweir 
6577cdf0e10cSrcweir             Point aTempPos = rTargetDevice.LogicToPixel( aPos );
6578cdf0e10cSrcweir             nMnemonicX = rTargetDevice.GetOutOffXPixel() + aTempPos.X() + rTargetDevice.ImplLogicWidthToDevicePixel( Min(lc_x1, lc_x2) );
6579cdf0e10cSrcweir             nMnemonicY = rTargetDevice.GetOutOffYPixel() + aTempPos.Y() + rTargetDevice.ImplLogicWidthToDevicePixel( rTargetDevice.GetFontMetric().GetAscent() );
6580cdf0e10cSrcweir         }
6581cdf0e10cSrcweir 
6582cdf0e10cSrcweir         if ( nStyle & TEXT_DRAW_CLIP )
6583cdf0e10cSrcweir         {
6584cdf0e10cSrcweir             rTargetDevice.Push( PUSH_CLIPREGION );
6585cdf0e10cSrcweir             rTargetDevice.IntersectClipRegion( rRect );
6586cdf0e10cSrcweir             _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
6587cdf0e10cSrcweir             if ( bDrawMnemonics )
6588cdf0e10cSrcweir             {
6589cdf0e10cSrcweir                 if ( nMnemonicPos != STRING_NOTFOUND )
6590cdf0e10cSrcweir                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6591cdf0e10cSrcweir             }
6592cdf0e10cSrcweir             rTargetDevice.Pop();
6593cdf0e10cSrcweir         }
6594cdf0e10cSrcweir         else
6595cdf0e10cSrcweir         {
6596cdf0e10cSrcweir             _rLayout.DrawText( aPos, aStr, 0, STRING_LEN, pVector, pDisplayText );
6597cdf0e10cSrcweir             if ( bDrawMnemonics )
6598cdf0e10cSrcweir             {
6599cdf0e10cSrcweir                 if ( nMnemonicPos != STRING_NOTFOUND )
6600cdf0e10cSrcweir                     rTargetDevice.ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
6601cdf0e10cSrcweir             }
6602cdf0e10cSrcweir         }
6603cdf0e10cSrcweir     }
6604cdf0e10cSrcweir 
6605cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_DISABLE && !pVector )
6606cdf0e10cSrcweir     {
6607cdf0e10cSrcweir         rTargetDevice.SetTextColor( aOldTextColor );
6608cdf0e10cSrcweir         if ( bRestoreFillColor )
6609cdf0e10cSrcweir             rTargetDevice.SetTextFillColor( aOldTextFillColor );
6610cdf0e10cSrcweir     }
6611cdf0e10cSrcweir }
6612cdf0e10cSrcweir 
6613cdf0e10cSrcweir // -----------------------------------------------------------------------
6614cdf0e10cSrcweir 
6615cdf0e10cSrcweir void OutputDevice::AddTextRectActions( const Rectangle& rRect,
6616cdf0e10cSrcweir                                        const String&    rOrigStr,
6617cdf0e10cSrcweir                                        sal_uInt16           nStyle,
6618cdf0e10cSrcweir                                        GDIMetaFile&     rMtf )
6619cdf0e10cSrcweir {
6620cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::AddTextRectActions( const Rectangle& )" );
6621cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6622cdf0e10cSrcweir 
6623cdf0e10cSrcweir     if ( !rOrigStr.Len() || rRect.IsEmpty() )
6624cdf0e10cSrcweir         return;
6625cdf0e10cSrcweir 
6626cdf0e10cSrcweir     // we need a graphics
6627cdf0e10cSrcweir     if( !mpGraphics && !ImplGetGraphics() )
6628cdf0e10cSrcweir         return;
6629cdf0e10cSrcweir     if( mbInitClipRegion )
6630cdf0e10cSrcweir         ImplInitClipRegion();
6631cdf0e10cSrcweir 
6632cdf0e10cSrcweir     // temporarily swap in passed mtf for action generation, and
6633cdf0e10cSrcweir     // disable output generation.
6634cdf0e10cSrcweir     const sal_Bool bOutputEnabled( IsOutputEnabled() );
6635cdf0e10cSrcweir     GDIMetaFile* pMtf = mpMetaFile;
6636cdf0e10cSrcweir 
6637cdf0e10cSrcweir     mpMetaFile = &rMtf;
6638cdf0e10cSrcweir     EnableOutput( sal_False );
6639cdf0e10cSrcweir 
6640cdf0e10cSrcweir     // #i47157# Factored out to ImplDrawTextRect(), to be shared
6641cdf0e10cSrcweir     // between us and DrawText()
6642cdf0e10cSrcweir     DefaultTextLayout aLayout( *this );
6643cdf0e10cSrcweir     ImplDrawText( *this, rRect, rOrigStr, nStyle, NULL, NULL, aLayout );
6644cdf0e10cSrcweir 
6645cdf0e10cSrcweir     // and restore again
6646cdf0e10cSrcweir     EnableOutput( bOutputEnabled );
6647cdf0e10cSrcweir     mpMetaFile = pMtf;
6648cdf0e10cSrcweir }
6649cdf0e10cSrcweir 
6650cdf0e10cSrcweir // -----------------------------------------------------------------------
6651cdf0e10cSrcweir 
6652cdf0e10cSrcweir void OutputDevice::DrawText( const Rectangle& rRect, const String& rOrigStr, sal_uInt16 nStyle,
6653cdf0e10cSrcweir                              MetricVector* pVector, String* pDisplayText,
6654cdf0e10cSrcweir                              ::vcl::ITextLayout* _pTextLayout )
6655cdf0e10cSrcweir {
6656cdf0e10cSrcweir     if( mpOutDevData && mpOutDevData->mpRecordLayout )
6657cdf0e10cSrcweir     {
6658cdf0e10cSrcweir         pVector = &mpOutDevData->mpRecordLayout->m_aUnicodeBoundRects;
6659cdf0e10cSrcweir         pDisplayText = &mpOutDevData->mpRecordLayout->m_aDisplayText;
6660cdf0e10cSrcweir     }
6661cdf0e10cSrcweir 
6662cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::DrawText( const Rectangle& )" );
6663cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6664cdf0e10cSrcweir 
6665cdf0e10cSrcweir     bool bDecomposeTextRectAction = ( _pTextLayout != NULL ) && _pTextLayout->DecomposeTextRectAction();
6666cdf0e10cSrcweir     if ( mpMetaFile && !bDecomposeTextRectAction )
6667cdf0e10cSrcweir         mpMetaFile->AddAction( new MetaTextRectAction( rRect, rOrigStr, nStyle ) );
6668cdf0e10cSrcweir 
6669cdf0e10cSrcweir     if ( ( !IsDeviceOutputNecessary() && !pVector && !bDecomposeTextRectAction ) || !rOrigStr.Len() || rRect.IsEmpty() )
6670cdf0e10cSrcweir         return;
6671cdf0e10cSrcweir 
6672cdf0e10cSrcweir     // we need a graphics
6673cdf0e10cSrcweir     if( !mpGraphics && !ImplGetGraphics() )
6674cdf0e10cSrcweir         return;
6675cdf0e10cSrcweir     if( mbInitClipRegion )
6676cdf0e10cSrcweir         ImplInitClipRegion();
6677cdf0e10cSrcweir     if( mbOutputClipped && !bDecomposeTextRectAction )
6678cdf0e10cSrcweir         return;
6679cdf0e10cSrcweir 
6680cdf0e10cSrcweir     // temporarily disable mtf action generation (ImplDrawText _does_
6681cdf0e10cSrcweir     // create META_TEXT_ACTIONs otherwise)
6682cdf0e10cSrcweir     GDIMetaFile* pMtf = mpMetaFile;
6683cdf0e10cSrcweir     if ( !bDecomposeTextRectAction )
6684cdf0e10cSrcweir         mpMetaFile = NULL;
6685cdf0e10cSrcweir 
6686cdf0e10cSrcweir     // #i47157# Factored out to ImplDrawText(), to be used also
6687cdf0e10cSrcweir     // from AddTextRectActions()
6688cdf0e10cSrcweir     DefaultTextLayout aDefaultLayout( *this );
6689cdf0e10cSrcweir     ImplDrawText( *this, rRect, rOrigStr, nStyle, pVector, pDisplayText, _pTextLayout ? *_pTextLayout : aDefaultLayout );
6690cdf0e10cSrcweir 
6691cdf0e10cSrcweir     // and enable again
6692cdf0e10cSrcweir     mpMetaFile = pMtf;
6693cdf0e10cSrcweir 
6694cdf0e10cSrcweir     if( mpAlphaVDev )
6695cdf0e10cSrcweir         mpAlphaVDev->DrawText( rRect, rOrigStr, nStyle, pVector, pDisplayText );
6696cdf0e10cSrcweir }
6697cdf0e10cSrcweir 
6698cdf0e10cSrcweir // -----------------------------------------------------------------------
6699cdf0e10cSrcweir 
6700cdf0e10cSrcweir Rectangle OutputDevice::GetTextRect( const Rectangle& rRect,
6701cdf0e10cSrcweir                                      const XubString& rStr, sal_uInt16 nStyle,
6702cdf0e10cSrcweir                                      TextRectInfo* pInfo,
6703cdf0e10cSrcweir                                      const ::vcl::ITextLayout* _pTextLayout ) const
6704cdf0e10cSrcweir {
6705cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetTextRect()" );
6706cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6707cdf0e10cSrcweir 
6708cdf0e10cSrcweir     Rectangle           aRect = rRect;
6709cdf0e10cSrcweir     xub_StrLen          nLines;
6710cdf0e10cSrcweir     long                nWidth = rRect.GetWidth();
6711cdf0e10cSrcweir     long                nMaxWidth;
6712cdf0e10cSrcweir     long                nTextHeight = GetTextHeight();
6713cdf0e10cSrcweir 
6714cdf0e10cSrcweir     String aStr = rStr;
6715cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MNEMONIC )
6716cdf0e10cSrcweir         aStr = GetNonMnemonicString( aStr );
6717cdf0e10cSrcweir 
6718cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MULTILINE )
6719cdf0e10cSrcweir     {
6720cdf0e10cSrcweir         ImplMultiTextLineInfo   aMultiLineInfo;
6721cdf0e10cSrcweir         ImplTextLineInfo*       pLineInfo;
6722cdf0e10cSrcweir         xub_StrLen              nFormatLines;
6723cdf0e10cSrcweir         xub_StrLen              i;
6724cdf0e10cSrcweir 
6725cdf0e10cSrcweir         nMaxWidth = 0;
6726cdf0e10cSrcweir         DefaultTextLayout aDefaultLayout( *const_cast< OutputDevice* >( this ) );
6727cdf0e10cSrcweir         ImplGetTextLines( aMultiLineInfo, nWidth, aStr, nStyle, _pTextLayout ? *_pTextLayout : aDefaultLayout );
6728cdf0e10cSrcweir         nFormatLines = aMultiLineInfo.Count();
6729cdf0e10cSrcweir         if ( !nTextHeight )
6730cdf0e10cSrcweir             nTextHeight = 1;
6731cdf0e10cSrcweir         nLines = (sal_uInt16)(aRect.GetHeight()/nTextHeight);
6732cdf0e10cSrcweir         if ( pInfo )
6733cdf0e10cSrcweir             pInfo->mnLineCount = nFormatLines;
6734cdf0e10cSrcweir         if ( !nLines )
6735cdf0e10cSrcweir             nLines = 1;
6736cdf0e10cSrcweir         if ( nFormatLines <= nLines )
6737cdf0e10cSrcweir             nLines = nFormatLines;
6738cdf0e10cSrcweir         else
6739cdf0e10cSrcweir         {
6740cdf0e10cSrcweir             if ( !(nStyle & TEXT_DRAW_ENDELLIPSIS) )
6741cdf0e10cSrcweir                 nLines = nFormatLines;
6742cdf0e10cSrcweir             else
6743cdf0e10cSrcweir             {
6744cdf0e10cSrcweir                 if ( pInfo )
6745cdf0e10cSrcweir                     pInfo->mbEllipsis = sal_True;
6746cdf0e10cSrcweir                 nMaxWidth = nWidth;
6747cdf0e10cSrcweir             }
6748cdf0e10cSrcweir         }
6749cdf0e10cSrcweir         if ( pInfo )
6750cdf0e10cSrcweir         {
6751cdf0e10cSrcweir             sal_Bool bMaxWidth = nMaxWidth == 0;
6752cdf0e10cSrcweir             pInfo->mnMaxWidth = 0;
6753cdf0e10cSrcweir             for ( i = 0; i < nLines; i++ )
6754cdf0e10cSrcweir             {
6755cdf0e10cSrcweir                 pLineInfo = aMultiLineInfo.GetLine( i );
6756cdf0e10cSrcweir                 if ( bMaxWidth && (pLineInfo->GetWidth() > nMaxWidth) )
6757cdf0e10cSrcweir                     nMaxWidth = pLineInfo->GetWidth();
6758cdf0e10cSrcweir                 if ( pLineInfo->GetWidth() > pInfo->mnMaxWidth )
6759cdf0e10cSrcweir                     pInfo->mnMaxWidth = pLineInfo->GetWidth();
6760cdf0e10cSrcweir             }
6761cdf0e10cSrcweir         }
6762cdf0e10cSrcweir         else if ( !nMaxWidth )
6763cdf0e10cSrcweir         {
6764cdf0e10cSrcweir             for ( i = 0; i < nLines; i++ )
6765cdf0e10cSrcweir             {
6766cdf0e10cSrcweir                 pLineInfo = aMultiLineInfo.GetLine( i );
6767cdf0e10cSrcweir                 if ( pLineInfo->GetWidth() > nMaxWidth )
6768cdf0e10cSrcweir                     nMaxWidth = pLineInfo->GetWidth();
6769cdf0e10cSrcweir             }
6770cdf0e10cSrcweir         }
6771cdf0e10cSrcweir     }
6772cdf0e10cSrcweir     else
6773cdf0e10cSrcweir     {
6774cdf0e10cSrcweir         nLines      = 1;
6775cdf0e10cSrcweir         nMaxWidth   = _pTextLayout ? _pTextLayout->GetTextWidth( aStr, 0, aStr.Len() ) : GetTextWidth( aStr );
6776cdf0e10cSrcweir 
6777cdf0e10cSrcweir         if ( pInfo )
6778cdf0e10cSrcweir         {
6779cdf0e10cSrcweir             pInfo->mnLineCount  = 1;
6780cdf0e10cSrcweir             pInfo->mnMaxWidth   = nMaxWidth;
6781cdf0e10cSrcweir         }
6782cdf0e10cSrcweir 
6783cdf0e10cSrcweir         if ( (nMaxWidth > nWidth) && (nStyle & TEXT_DRAW_ELLIPSIS) )
6784cdf0e10cSrcweir         {
6785cdf0e10cSrcweir             if ( pInfo )
6786cdf0e10cSrcweir                 pInfo->mbEllipsis = sal_True;
6787cdf0e10cSrcweir             nMaxWidth = nWidth;
6788cdf0e10cSrcweir         }
6789cdf0e10cSrcweir     }
6790cdf0e10cSrcweir 
6791cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_RIGHT )
6792cdf0e10cSrcweir         aRect.Left() = aRect.Right()-nMaxWidth+1;
6793cdf0e10cSrcweir     else if ( nStyle & TEXT_DRAW_CENTER )
6794cdf0e10cSrcweir     {
6795cdf0e10cSrcweir         aRect.Left() += (nWidth-nMaxWidth)/2;
6796cdf0e10cSrcweir         aRect.Right() = aRect.Left()+nMaxWidth-1;
6797cdf0e10cSrcweir     }
6798cdf0e10cSrcweir     else
6799cdf0e10cSrcweir         aRect.Right() = aRect.Left()+nMaxWidth-1;
6800cdf0e10cSrcweir 
6801cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_BOTTOM )
6802cdf0e10cSrcweir         aRect.Top() = aRect.Bottom()-(nTextHeight*nLines)+1;
6803cdf0e10cSrcweir     else if ( nStyle & TEXT_DRAW_VCENTER )
6804cdf0e10cSrcweir     {
6805cdf0e10cSrcweir         aRect.Top()   += (aRect.GetHeight()-(nTextHeight*nLines))/2;
6806cdf0e10cSrcweir         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
6807cdf0e10cSrcweir     }
6808cdf0e10cSrcweir     else
6809cdf0e10cSrcweir         aRect.Bottom() = aRect.Top()+(nTextHeight*nLines)-1;
6810cdf0e10cSrcweir 
6811cdf0e10cSrcweir     aRect.Right()++; // #99188# get rid of rounding problems when using this rect later
6812cdf0e10cSrcweir     return aRect;
6813cdf0e10cSrcweir }
6814cdf0e10cSrcweir 
6815cdf0e10cSrcweir // -----------------------------------------------------------------------
6816cdf0e10cSrcweir 
6817cdf0e10cSrcweir static sal_Bool ImplIsCharIn( xub_Unicode c, const sal_Char* pStr )
6818cdf0e10cSrcweir {
6819cdf0e10cSrcweir     while ( *pStr )
6820cdf0e10cSrcweir     {
6821cdf0e10cSrcweir         if ( *pStr == c )
6822cdf0e10cSrcweir             return sal_True;
6823cdf0e10cSrcweir         pStr++;
6824cdf0e10cSrcweir     }
6825cdf0e10cSrcweir 
6826cdf0e10cSrcweir     return sal_False;
6827cdf0e10cSrcweir }
6828cdf0e10cSrcweir 
6829cdf0e10cSrcweir // -----------------------------------------------------------------------
6830cdf0e10cSrcweir 
6831cdf0e10cSrcweir String OutputDevice::GetEllipsisString( const String& rOrigStr, long nMaxWidth,
6832cdf0e10cSrcweir                                         sal_uInt16 nStyle ) const
6833cdf0e10cSrcweir {
6834cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6835cdf0e10cSrcweir     DefaultTextLayout aTextLayout( *const_cast< OutputDevice* >( this ) );
6836cdf0e10cSrcweir     return ImplGetEllipsisString( *this, rOrigStr, nMaxWidth, nStyle, aTextLayout );
6837cdf0e10cSrcweir }
6838cdf0e10cSrcweir 
6839cdf0e10cSrcweir // -----------------------------------------------------------------------
6840cdf0e10cSrcweir 
6841cdf0e10cSrcweir String OutputDevice::ImplGetEllipsisString( const OutputDevice& rTargetDevice, const XubString& rOrigStr, long nMaxWidth,
6842cdf0e10cSrcweir                                                sal_uInt16 nStyle, const ::vcl::ITextLayout& _rLayout )
6843cdf0e10cSrcweir {
6844cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::ImplGetEllipsisString()" );
6845cdf0e10cSrcweir 
6846cdf0e10cSrcweir     String aStr = rOrigStr;
6847cdf0e10cSrcweir     xub_StrLen nIndex = _rLayout.GetTextBreak( aStr, nMaxWidth, 0, aStr.Len() );
6848cdf0e10cSrcweir 
6849cdf0e10cSrcweir 
6850cdf0e10cSrcweir     if ( nIndex != STRING_LEN )
6851cdf0e10cSrcweir     {
6852cdf0e10cSrcweir         if( (nStyle & TEXT_DRAW_CENTERELLIPSIS) == TEXT_DRAW_CENTERELLIPSIS )
6853cdf0e10cSrcweir         {
6854cdf0e10cSrcweir             String aTmpStr( aStr );
6855cdf0e10cSrcweir             xub_StrLen nEraseChars = 4;
6856cdf0e10cSrcweir             while( nEraseChars < aStr.Len() && _rLayout.GetTextWidth( aTmpStr, 0, aTmpStr.Len() ) > nMaxWidth )
6857cdf0e10cSrcweir             {
6858cdf0e10cSrcweir                 aTmpStr = aStr;
6859cdf0e10cSrcweir                 xub_StrLen i = (aTmpStr.Len() - nEraseChars)/2;
6860cdf0e10cSrcweir                 aTmpStr.Erase( i, nEraseChars++ );
6861cdf0e10cSrcweir                 aTmpStr.InsertAscii( "...", i );
6862cdf0e10cSrcweir             }
6863cdf0e10cSrcweir             aStr = aTmpStr;
6864cdf0e10cSrcweir         }
6865cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_ENDELLIPSIS )
6866cdf0e10cSrcweir         {
6867cdf0e10cSrcweir             aStr.Erase( nIndex );
6868cdf0e10cSrcweir             if ( nIndex > 1 )
6869cdf0e10cSrcweir             {
6870cdf0e10cSrcweir                 aStr.AppendAscii( "..." );
6871cdf0e10cSrcweir                 while ( aStr.Len() && (_rLayout.GetTextWidth( aStr, 0, aStr.Len() ) > nMaxWidth) )
6872cdf0e10cSrcweir                 {
6873cdf0e10cSrcweir                     if ( (nIndex > 1) || (nIndex == aStr.Len()) )
6874cdf0e10cSrcweir                         nIndex--;
6875cdf0e10cSrcweir                     aStr.Erase( nIndex, 1 );
6876cdf0e10cSrcweir                 }
6877cdf0e10cSrcweir             }
6878cdf0e10cSrcweir 
6879cdf0e10cSrcweir             if ( !aStr.Len() && (nStyle & TEXT_DRAW_CLIP) )
6880cdf0e10cSrcweir                 aStr += rOrigStr.GetChar( 0 );
6881cdf0e10cSrcweir         }
6882cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_PATHELLIPSIS )
6883cdf0e10cSrcweir         {
6884cdf0e10cSrcweir             rtl::OUString aPath( rOrigStr );
6885cdf0e10cSrcweir             rtl::OUString aAbbreviatedPath;
6886cdf0e10cSrcweir             osl_abbreviateSystemPath( aPath.pData, &aAbbreviatedPath.pData, nIndex, NULL );
6887cdf0e10cSrcweir             aStr = aAbbreviatedPath;
6888cdf0e10cSrcweir         }
6889cdf0e10cSrcweir         else if ( nStyle & TEXT_DRAW_NEWSELLIPSIS )
6890cdf0e10cSrcweir         {
6891cdf0e10cSrcweir             static sal_Char const   pSepChars[] = ".";
6892cdf0e10cSrcweir             // Letztes Teilstueck ermitteln
6893cdf0e10cSrcweir             xub_StrLen nLastContent = aStr.Len();
6894cdf0e10cSrcweir             while ( nLastContent )
6895cdf0e10cSrcweir             {
6896cdf0e10cSrcweir                 nLastContent--;
6897cdf0e10cSrcweir                 if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
6898cdf0e10cSrcweir                     break;
6899cdf0e10cSrcweir             }
6900cdf0e10cSrcweir             while ( nLastContent &&
6901cdf0e10cSrcweir                     ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
6902cdf0e10cSrcweir                 nLastContent--;
6903cdf0e10cSrcweir 
6904cdf0e10cSrcweir             XubString aLastStr( aStr, nLastContent, aStr.Len() );
6905cdf0e10cSrcweir             XubString aTempLastStr1( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
6906cdf0e10cSrcweir             aTempLastStr1 += aLastStr;
6907cdf0e10cSrcweir             if ( _rLayout.GetTextWidth( aTempLastStr1, 0, aTempLastStr1.Len() ) > nMaxWidth )
6908cdf0e10cSrcweir                 aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
6909cdf0e10cSrcweir             else
6910cdf0e10cSrcweir             {
6911cdf0e10cSrcweir                 sal_uInt16 nFirstContent = 0;
6912cdf0e10cSrcweir                 while ( nFirstContent < nLastContent )
6913cdf0e10cSrcweir                 {
6914cdf0e10cSrcweir                     nFirstContent++;
6915cdf0e10cSrcweir                     if ( ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
6916cdf0e10cSrcweir                         break;
6917cdf0e10cSrcweir                 }
6918cdf0e10cSrcweir                 while ( (nFirstContent < nLastContent) &&
6919cdf0e10cSrcweir                         ImplIsCharIn( aStr.GetChar( nFirstContent ), pSepChars ) )
6920cdf0e10cSrcweir                     nFirstContent++;
6921cdf0e10cSrcweir 
6922cdf0e10cSrcweir                 if ( nFirstContent >= nLastContent )
6923cdf0e10cSrcweir                     aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
6924cdf0e10cSrcweir                 else
6925cdf0e10cSrcweir                 {
6926cdf0e10cSrcweir                     if ( nFirstContent > 4 )
6927cdf0e10cSrcweir                         nFirstContent = 4;
6928cdf0e10cSrcweir                     XubString aFirstStr( aStr, 0, nFirstContent );
6929cdf0e10cSrcweir                     aFirstStr.AppendAscii( "..." );
6930cdf0e10cSrcweir                     XubString aTempStr = aFirstStr;
6931cdf0e10cSrcweir                     aTempStr += aLastStr;
6932cdf0e10cSrcweir                     if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
6933cdf0e10cSrcweir                         aStr = OutputDevice::ImplGetEllipsisString( rTargetDevice, aStr, nMaxWidth, nStyle | TEXT_DRAW_ENDELLIPSIS, _rLayout );
6934cdf0e10cSrcweir                     else
6935cdf0e10cSrcweir                     {
6936cdf0e10cSrcweir                         do
6937cdf0e10cSrcweir                         {
6938cdf0e10cSrcweir                             aStr = aTempStr;
6939cdf0e10cSrcweir                             if( nLastContent > aStr.Len() )
6940cdf0e10cSrcweir                                 nLastContent = aStr.Len();
6941cdf0e10cSrcweir                             while ( nFirstContent < nLastContent )
6942cdf0e10cSrcweir                             {
6943cdf0e10cSrcweir                                 nLastContent--;
6944cdf0e10cSrcweir                                 if ( ImplIsCharIn( aStr.GetChar( nLastContent ), pSepChars ) )
6945cdf0e10cSrcweir                                     break;
6946cdf0e10cSrcweir 
6947cdf0e10cSrcweir                             }
6948cdf0e10cSrcweir                             while ( (nFirstContent < nLastContent) &&
6949cdf0e10cSrcweir                                     ImplIsCharIn( aStr.GetChar( nLastContent-1 ), pSepChars ) )
6950cdf0e10cSrcweir                                 nLastContent--;
6951cdf0e10cSrcweir 
6952cdf0e10cSrcweir                             if ( nFirstContent < nLastContent )
6953cdf0e10cSrcweir                             {
6954cdf0e10cSrcweir                                 XubString aTempLastStr( aStr, nLastContent, aStr.Len() );
6955cdf0e10cSrcweir                                 aTempStr = aFirstStr;
6956cdf0e10cSrcweir                                 aTempStr += aTempLastStr;
6957cdf0e10cSrcweir                                 if ( _rLayout.GetTextWidth( aTempStr, 0, aTempStr.Len() ) > nMaxWidth )
6958cdf0e10cSrcweir                                     break;
6959cdf0e10cSrcweir                             }
6960cdf0e10cSrcweir                         }
6961cdf0e10cSrcweir                         while ( nFirstContent < nLastContent );
6962cdf0e10cSrcweir                     }
6963cdf0e10cSrcweir                 }
6964cdf0e10cSrcweir             }
6965cdf0e10cSrcweir         }
6966cdf0e10cSrcweir     }
6967cdf0e10cSrcweir 
6968cdf0e10cSrcweir     return aStr;
6969cdf0e10cSrcweir }
6970cdf0e10cSrcweir 
6971cdf0e10cSrcweir // -----------------------------------------------------------------------
6972cdf0e10cSrcweir 
6973cdf0e10cSrcweir void OutputDevice::DrawCtrlText( const Point& rPos, const XubString& rStr,
6974cdf0e10cSrcweir                                  xub_StrLen nIndex, xub_StrLen nLen,
6975cdf0e10cSrcweir                                  sal_uInt16 nStyle, MetricVector* pVector, String* pDisplayText )
6976cdf0e10cSrcweir {
6977cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::DrawCtrlText()" );
6978cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
6979cdf0e10cSrcweir 
6980cdf0e10cSrcweir     if ( !IsDeviceOutputNecessary() || (nIndex >= rStr.Len()) )
6981cdf0e10cSrcweir         return;
6982cdf0e10cSrcweir 
6983cdf0e10cSrcweir     // better get graphics here because ImplDrawMnemonicLine() will not
6984cdf0e10cSrcweir     // we need a graphics
6985cdf0e10cSrcweir     if( !mpGraphics && !ImplGetGraphics() )
6986cdf0e10cSrcweir         return;
6987cdf0e10cSrcweir     if( mbInitClipRegion )
6988cdf0e10cSrcweir         ImplInitClipRegion();
6989cdf0e10cSrcweir     if ( mbOutputClipped )
6990cdf0e10cSrcweir         return;
6991cdf0e10cSrcweir 
6992cdf0e10cSrcweir     if( nIndex >= rStr.Len() )
6993cdf0e10cSrcweir         return;
6994cdf0e10cSrcweir     if( (sal_uLong)nIndex+nLen >= rStr.Len() )
6995cdf0e10cSrcweir         nLen = rStr.Len() - nIndex;
6996cdf0e10cSrcweir 
6997cdf0e10cSrcweir     XubString   aStr = rStr;
6998cdf0e10cSrcweir     xub_StrLen  nMnemonicPos = STRING_NOTFOUND;
6999cdf0e10cSrcweir 
7000cdf0e10cSrcweir     long        nMnemonicX = 0;
7001cdf0e10cSrcweir     long        nMnemonicY = 0;
7002cdf0e10cSrcweir     long        nMnemonicWidth = 0;
7003cdf0e10cSrcweir     if ( (nStyle & TEXT_DRAW_MNEMONIC) && nLen > 1 )
7004cdf0e10cSrcweir     {
7005cdf0e10cSrcweir         aStr = GetNonMnemonicString( aStr, nMnemonicPos );
7006cdf0e10cSrcweir         if ( nMnemonicPos != STRING_NOTFOUND )
7007cdf0e10cSrcweir         {
7008cdf0e10cSrcweir             if( nMnemonicPos < nIndex )
7009cdf0e10cSrcweir                 --nIndex;
7010cdf0e10cSrcweir             else if( nLen < STRING_LEN )
7011cdf0e10cSrcweir             {
7012cdf0e10cSrcweir                 if( nMnemonicPos < (nIndex+nLen) )
7013cdf0e10cSrcweir                     --nLen;
7014cdf0e10cSrcweir                 DBG_ASSERT( nMnemonicPos < (nIndex+nLen), "Mnemonic underline marker after last character" );
7015cdf0e10cSrcweir             }
7016cdf0e10cSrcweir             sal_Bool bInvalidPos = sal_False;
7017cdf0e10cSrcweir 
7018cdf0e10cSrcweir             if( nMnemonicPos >= nLen )
7019cdf0e10cSrcweir             {
7020cdf0e10cSrcweir                 // #106952#
7021cdf0e10cSrcweir                 // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
7022cdf0e10cSrcweir                 // due to some strange BiDi text editors
7023cdf0e10cSrcweir                 // ->place the underline behind the string to indicate a failure
7024cdf0e10cSrcweir                 bInvalidPos = sal_True;
7025cdf0e10cSrcweir                 nMnemonicPos = nLen-1;
7026cdf0e10cSrcweir             }
7027cdf0e10cSrcweir 
7028cdf0e10cSrcweir             sal_Int32* pCaretXArray = (sal_Int32*)alloca( 2 * sizeof(sal_Int32) * nLen );
7029cdf0e10cSrcweir             /*sal_Bool bRet =*/ GetCaretPositions( aStr, pCaretXArray, nIndex, nLen );
7030cdf0e10cSrcweir             long lc_x1 = pCaretXArray[ 2*(nMnemonicPos - nIndex) ];
7031cdf0e10cSrcweir             long lc_x2 = pCaretXArray[ 2*(nMnemonicPos - nIndex)+1 ];
7032cdf0e10cSrcweir             nMnemonicWidth = ::abs((int)(lc_x1 - lc_x2));
7033cdf0e10cSrcweir 
7034cdf0e10cSrcweir             Point aTempPos( Min(lc_x1,lc_x2), GetFontMetric().GetAscent() );
7035cdf0e10cSrcweir             if( bInvalidPos )  // #106952#, place behind the (last) character
7036cdf0e10cSrcweir                 aTempPos = Point( Max(lc_x1,lc_x2), GetFontMetric().GetAscent() );
7037cdf0e10cSrcweir 
7038cdf0e10cSrcweir             aTempPos += rPos;
7039cdf0e10cSrcweir             aTempPos = LogicToPixel( aTempPos );
7040cdf0e10cSrcweir             nMnemonicX = mnOutOffX + aTempPos.X();
7041cdf0e10cSrcweir             nMnemonicY = mnOutOffY + aTempPos.Y();
7042cdf0e10cSrcweir         }
7043cdf0e10cSrcweir     }
7044cdf0e10cSrcweir 
7045cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_DISABLE && ! pVector )
7046cdf0e10cSrcweir     {
7047cdf0e10cSrcweir         Color aOldTextColor;
7048cdf0e10cSrcweir         Color aOldTextFillColor;
7049cdf0e10cSrcweir         sal_Bool  bRestoreFillColor;
7050cdf0e10cSrcweir         sal_Bool  bHighContrastBlack = sal_False;
7051cdf0e10cSrcweir         sal_Bool  bHighContrastWhite = sal_False;
7052cdf0e10cSrcweir         const StyleSettings& rStyleSettings( GetSettings().GetStyleSettings() );
7053cdf0e10cSrcweir         if( rStyleSettings.GetHighContrastMode() )
7054cdf0e10cSrcweir         {
7055cdf0e10cSrcweir             if( IsBackground() )
7056cdf0e10cSrcweir             {
7057cdf0e10cSrcweir                 Wallpaper aWall = GetBackground();
7058cdf0e10cSrcweir                 Color aCol = aWall.GetColor();
7059cdf0e10cSrcweir                 bHighContrastBlack = aCol.IsDark();
7060cdf0e10cSrcweir                 bHighContrastWhite = aCol.IsBright();
7061cdf0e10cSrcweir             }
7062cdf0e10cSrcweir         }
7063cdf0e10cSrcweir 
7064cdf0e10cSrcweir         aOldTextColor = GetTextColor();
7065cdf0e10cSrcweir         if ( IsTextFillColor() )
7066cdf0e10cSrcweir         {
7067cdf0e10cSrcweir             bRestoreFillColor = sal_True;
7068cdf0e10cSrcweir             aOldTextFillColor = GetTextFillColor();
7069cdf0e10cSrcweir         }
7070cdf0e10cSrcweir         else
7071cdf0e10cSrcweir             bRestoreFillColor = sal_False;
7072cdf0e10cSrcweir 
7073cdf0e10cSrcweir         if( bHighContrastBlack )
7074cdf0e10cSrcweir             SetTextColor( COL_GREEN );
7075cdf0e10cSrcweir         else if( bHighContrastWhite )
7076cdf0e10cSrcweir             SetTextColor( COL_LIGHTGREEN );
7077cdf0e10cSrcweir         else
7078cdf0e10cSrcweir             SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
7079cdf0e10cSrcweir 
7080cdf0e10cSrcweir         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
7081cdf0e10cSrcweir         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
7082cdf0e10cSrcweir         {
7083cdf0e10cSrcweir             if ( nMnemonicPos != STRING_NOTFOUND )
7084cdf0e10cSrcweir                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
7085cdf0e10cSrcweir         }
7086cdf0e10cSrcweir         SetTextColor( aOldTextColor );
7087cdf0e10cSrcweir         if ( bRestoreFillColor )
7088cdf0e10cSrcweir             SetTextFillColor( aOldTextFillColor );
7089cdf0e10cSrcweir     }
7090cdf0e10cSrcweir     else
7091cdf0e10cSrcweir     {
7092cdf0e10cSrcweir         DrawText( rPos, aStr, nIndex, nLen, pVector, pDisplayText );
7093cdf0e10cSrcweir         if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS) && !pVector )
7094cdf0e10cSrcweir         {
7095cdf0e10cSrcweir             if ( nMnemonicPos != STRING_NOTFOUND )
7096cdf0e10cSrcweir                 ImplDrawMnemonicLine( nMnemonicX, nMnemonicY, nMnemonicWidth );
7097cdf0e10cSrcweir         }
7098cdf0e10cSrcweir     }
7099cdf0e10cSrcweir 
7100cdf0e10cSrcweir     if( mpAlphaVDev )
7101cdf0e10cSrcweir         mpAlphaVDev->DrawCtrlText( rPos, rStr, nIndex, nLen, nStyle, pVector, pDisplayText );
7102cdf0e10cSrcweir }
7103cdf0e10cSrcweir 
7104cdf0e10cSrcweir // -----------------------------------------------------------------------
7105cdf0e10cSrcweir 
7106cdf0e10cSrcweir long OutputDevice::GetCtrlTextWidth( const String& rStr,
7107cdf0e10cSrcweir                                      xub_StrLen nIndex, xub_StrLen nLen,
7108cdf0e10cSrcweir                                      sal_uInt16 nStyle ) const
7109cdf0e10cSrcweir {
7110cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetCtrlTextSize()" );
7111cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7112cdf0e10cSrcweir 
7113cdf0e10cSrcweir     if ( nStyle & TEXT_DRAW_MNEMONIC )
7114cdf0e10cSrcweir     {
7115cdf0e10cSrcweir         xub_StrLen  nMnemonicPos;
7116cdf0e10cSrcweir         XubString   aStr = GetNonMnemonicString( rStr, nMnemonicPos );
7117cdf0e10cSrcweir         if ( nMnemonicPos != STRING_NOTFOUND )
7118cdf0e10cSrcweir         {
7119cdf0e10cSrcweir             if ( nMnemonicPos < nIndex )
7120cdf0e10cSrcweir                 nIndex--;
7121cdf0e10cSrcweir             else if ( (nLen < STRING_LEN) &&
7122cdf0e10cSrcweir                       (nMnemonicPos >= nIndex) && (nMnemonicPos < (sal_uLong)(nIndex+nLen)) )
7123cdf0e10cSrcweir                 nLen--;
7124cdf0e10cSrcweir         }
7125cdf0e10cSrcweir         return GetTextWidth( aStr, nIndex, nLen );
7126cdf0e10cSrcweir     }
7127cdf0e10cSrcweir     else
7128cdf0e10cSrcweir         return GetTextWidth( rStr, nIndex, nLen );
7129cdf0e10cSrcweir }
7130cdf0e10cSrcweir 
7131cdf0e10cSrcweir // -----------------------------------------------------------------------
7132cdf0e10cSrcweir 
7133cdf0e10cSrcweir String OutputDevice::GetNonMnemonicString( const String& rStr, xub_StrLen& rMnemonicPos )
7134cdf0e10cSrcweir {
7135cdf0e10cSrcweir     String   aStr    = rStr;
7136cdf0e10cSrcweir     xub_StrLen  nLen    = aStr.Len();
7137cdf0e10cSrcweir     xub_StrLen  i       = 0;
7138cdf0e10cSrcweir 
7139cdf0e10cSrcweir     rMnemonicPos = STRING_NOTFOUND;
7140cdf0e10cSrcweir     while ( i < nLen )
7141cdf0e10cSrcweir     {
7142cdf0e10cSrcweir         if ( aStr.GetChar( i ) == '~' )
7143cdf0e10cSrcweir         {
7144cdf0e10cSrcweir             if ( aStr.GetChar( i+1 ) != '~' )
7145cdf0e10cSrcweir             {
7146cdf0e10cSrcweir                 if ( rMnemonicPos == STRING_NOTFOUND )
7147cdf0e10cSrcweir                     rMnemonicPos = i;
7148cdf0e10cSrcweir                 aStr.Erase( i, 1 );
7149cdf0e10cSrcweir                 nLen--;
7150cdf0e10cSrcweir             }
7151cdf0e10cSrcweir             else
7152cdf0e10cSrcweir             {
7153cdf0e10cSrcweir                 aStr.Erase( i, 1 );
7154cdf0e10cSrcweir                 nLen--;
7155cdf0e10cSrcweir                 i++;
7156cdf0e10cSrcweir             }
7157cdf0e10cSrcweir         }
7158cdf0e10cSrcweir         else
7159cdf0e10cSrcweir             i++;
7160cdf0e10cSrcweir     }
7161cdf0e10cSrcweir 
7162cdf0e10cSrcweir     return aStr;
7163cdf0e10cSrcweir }
7164cdf0e10cSrcweir 
7165cdf0e10cSrcweir // -----------------------------------------------------------------------
7166cdf0e10cSrcweir 
7167cdf0e10cSrcweir int OutputDevice::GetDevFontCount() const
7168cdf0e10cSrcweir {
7169cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetDevFontCount()" );
7170cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7171cdf0e10cSrcweir 
7172cdf0e10cSrcweir     if( !mpGetDevFontList )
7173cdf0e10cSrcweir         mpGetDevFontList = mpFontList->GetDevFontList();
7174cdf0e10cSrcweir     return mpGetDevFontList->Count();
7175cdf0e10cSrcweir }
7176cdf0e10cSrcweir 
7177cdf0e10cSrcweir // -----------------------------------------------------------------------
7178cdf0e10cSrcweir 
7179cdf0e10cSrcweir FontInfo OutputDevice::GetDevFont( int nDevFontIndex ) const
7180cdf0e10cSrcweir {
7181cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetDevFont()" );
7182cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7183cdf0e10cSrcweir 
7184cdf0e10cSrcweir     FontInfo aFontInfo;
7185cdf0e10cSrcweir 
7186cdf0e10cSrcweir     ImplInitFontList();
7187cdf0e10cSrcweir 
7188cdf0e10cSrcweir     int nCount = GetDevFontCount();
7189cdf0e10cSrcweir     if( nDevFontIndex < nCount )
7190cdf0e10cSrcweir     {
7191cdf0e10cSrcweir         const ImplFontData& rData = *mpGetDevFontList->Get( nDevFontIndex );
7192cdf0e10cSrcweir         aFontInfo.SetName( rData.maName );
7193cdf0e10cSrcweir         aFontInfo.SetStyleName( rData.maStyleName );
7194cdf0e10cSrcweir         aFontInfo.SetCharSet( rData.mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
7195cdf0e10cSrcweir         aFontInfo.SetFamily( rData.meFamily );
7196cdf0e10cSrcweir         aFontInfo.SetPitch( rData.mePitch );
7197cdf0e10cSrcweir         aFontInfo.SetWeight( rData.meWeight );
7198cdf0e10cSrcweir         aFontInfo.SetItalic( rData.meItalic );
7199cdf0e10cSrcweir         aFontInfo.SetWidthType( rData.meWidthType );
7200cdf0e10cSrcweir         if( rData.IsScalable() )
7201cdf0e10cSrcweir             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
7202cdf0e10cSrcweir         if( rData.mbDevice )
7203cdf0e10cSrcweir             aFontInfo.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
7204cdf0e10cSrcweir     }
7205cdf0e10cSrcweir 
7206cdf0e10cSrcweir     return aFontInfo;
7207cdf0e10cSrcweir }
7208cdf0e10cSrcweir 
7209cdf0e10cSrcweir // -----------------------------------------------------------------------
7210cdf0e10cSrcweir 
7211cdf0e10cSrcweir sal_Bool OutputDevice::AddTempDevFont( const String& rFileURL, const String& rFontName )
7212cdf0e10cSrcweir {
7213cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::AddTempDevFont()" );
7214cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7215cdf0e10cSrcweir 
7216cdf0e10cSrcweir     ImplInitFontList();
7217cdf0e10cSrcweir 
7218cdf0e10cSrcweir     if( !mpGraphics && !ImplGetGraphics() )
7219cdf0e10cSrcweir         return sal_False;
7220cdf0e10cSrcweir 
7221cdf0e10cSrcweir     bool bRC = mpGraphics->AddTempDevFont( mpFontList, rFileURL, rFontName );
7222cdf0e10cSrcweir     if( !bRC )
7223cdf0e10cSrcweir         return sal_False;
7224cdf0e10cSrcweir 
7225cdf0e10cSrcweir     if( mpAlphaVDev )
7226cdf0e10cSrcweir         mpAlphaVDev->AddTempDevFont( rFileURL, rFontName );
7227cdf0e10cSrcweir 
7228cdf0e10cSrcweir     mpFontCache->Invalidate();
7229cdf0e10cSrcweir     return sal_True;
7230cdf0e10cSrcweir }
7231cdf0e10cSrcweir 
7232cdf0e10cSrcweir // -----------------------------------------------------------------------
7233cdf0e10cSrcweir 
7234cdf0e10cSrcweir int OutputDevice::GetDevFontSizeCount( const Font& rFont ) const
7235cdf0e10cSrcweir {
7236cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetDevFontSizeCount()" );
7237cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7238cdf0e10cSrcweir 
7239cdf0e10cSrcweir     delete mpGetDevSizeList;
7240cdf0e10cSrcweir 
7241cdf0e10cSrcweir     ImplInitFontList();
7242cdf0e10cSrcweir     mpGetDevSizeList = mpFontList->GetDevSizeList( rFont.GetName() );
7243cdf0e10cSrcweir     return mpGetDevSizeList->Count();
7244cdf0e10cSrcweir }
7245cdf0e10cSrcweir 
7246cdf0e10cSrcweir // -----------------------------------------------------------------------
7247cdf0e10cSrcweir 
7248cdf0e10cSrcweir Size OutputDevice::GetDevFontSize( const Font& rFont, int nSizeIndex ) const
7249cdf0e10cSrcweir {
7250cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetDevFontSize()" );
7251cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7252cdf0e10cSrcweir 
7253cdf0e10cSrcweir     // check range
7254cdf0e10cSrcweir     int nCount = GetDevFontSizeCount( rFont );
7255cdf0e10cSrcweir     if ( nSizeIndex >= nCount )
7256cdf0e10cSrcweir         return Size();
7257cdf0e10cSrcweir 
7258cdf0e10cSrcweir     // when mapping is enabled round to .5 points
7259cdf0e10cSrcweir     Size aSize( 0, mpGetDevSizeList->Get( nSizeIndex ) );
7260cdf0e10cSrcweir     if ( mbMap )
7261cdf0e10cSrcweir     {
7262cdf0e10cSrcweir         aSize.Height() *= 10;
7263cdf0e10cSrcweir         MapMode aMap( MAP_10TH_INCH, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
7264cdf0e10cSrcweir         aSize = PixelToLogic( aSize, aMap );
7265cdf0e10cSrcweir         aSize.Height() += 5;
7266cdf0e10cSrcweir         aSize.Height() /= 10;
7267cdf0e10cSrcweir         long nRound = aSize.Height() % 5;
7268cdf0e10cSrcweir         if ( nRound >= 3 )
7269cdf0e10cSrcweir             aSize.Height() += (5-nRound);
7270cdf0e10cSrcweir         else
7271cdf0e10cSrcweir             aSize.Height() -= nRound;
7272cdf0e10cSrcweir         aSize.Height() *= 10;
7273cdf0e10cSrcweir         aSize = LogicToPixel( aSize, aMap );
7274cdf0e10cSrcweir         aSize = PixelToLogic( aSize );
7275cdf0e10cSrcweir         aSize.Height() += 5;
7276cdf0e10cSrcweir         aSize.Height() /= 10;
7277cdf0e10cSrcweir     }
7278cdf0e10cSrcweir     return aSize;
7279cdf0e10cSrcweir }
7280cdf0e10cSrcweir 
7281cdf0e10cSrcweir // -----------------------------------------------------------------------
7282cdf0e10cSrcweir 
7283cdf0e10cSrcweir sal_Bool OutputDevice::IsFontAvailable( const String& rFontName ) const
7284cdf0e10cSrcweir {
7285cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::IsFontAvailable()" );
7286cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7287cdf0e10cSrcweir 
7288cdf0e10cSrcweir     ImplDevFontListData* pFound = mpFontList->FindFontFamily( rFontName );
7289cdf0e10cSrcweir     return (pFound != NULL);
7290cdf0e10cSrcweir }
7291cdf0e10cSrcweir 
7292cdf0e10cSrcweir // -----------------------------------------------------------------------
7293cdf0e10cSrcweir 
7294cdf0e10cSrcweir FontMetric OutputDevice::GetFontMetric() const
7295cdf0e10cSrcweir {
7296cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetFontMetric()" );
7297cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7298cdf0e10cSrcweir 
7299cdf0e10cSrcweir     FontMetric aMetric;
7300cdf0e10cSrcweir     if( mbNewFont && !ImplNewFont() )
7301cdf0e10cSrcweir         return aMetric;
7302cdf0e10cSrcweir 
7303cdf0e10cSrcweir     ImplFontEntry*      pEntry = mpFontEntry;
7304cdf0e10cSrcweir     ImplFontMetricData* pMetric = &(pEntry->maMetric);
7305cdf0e10cSrcweir 
7306cdf0e10cSrcweir     // prepare metric
7307cdf0e10cSrcweir     aMetric.Font::operator=( maFont );
7308cdf0e10cSrcweir 
7309cdf0e10cSrcweir     // set aMetric with info from font
7310cdf0e10cSrcweir     aMetric.SetName( maFont.GetName() );
7311cdf0e10cSrcweir     aMetric.SetStyleName( pMetric->maStyleName );
7312cdf0e10cSrcweir     aMetric.SetSize( PixelToLogic( Size( pMetric->mnWidth, pMetric->mnAscent+pMetric->mnDescent-pMetric->mnIntLeading ) ) );
7313cdf0e10cSrcweir     aMetric.SetCharSet( pMetric->mbSymbolFlag ? RTL_TEXTENCODING_SYMBOL : RTL_TEXTENCODING_UNICODE );
7314cdf0e10cSrcweir     aMetric.SetFamily( pMetric->meFamily );
7315cdf0e10cSrcweir     aMetric.SetPitch( pMetric->mePitch );
7316cdf0e10cSrcweir     aMetric.SetWeight( pMetric->meWeight );
7317cdf0e10cSrcweir     aMetric.SetItalic( pMetric->meItalic );
7318cdf0e10cSrcweir     aMetric.SetWidthType( pMetric->meWidthType );
7319cdf0e10cSrcweir     if ( pEntry->mnOwnOrientation )
7320cdf0e10cSrcweir         aMetric.SetOrientation( pEntry->mnOwnOrientation );
7321cdf0e10cSrcweir     else
7322cdf0e10cSrcweir         aMetric.SetOrientation( pMetric->mnOrientation );
7323cdf0e10cSrcweir     if( !pEntry->maMetric.mbKernableFont )
7324cdf0e10cSrcweir          aMetric.SetKerning( maFont.GetKerning() & ~KERNING_FONTSPECIFIC );
7325cdf0e10cSrcweir 
7326cdf0e10cSrcweir     // set remaining metric fields
7327cdf0e10cSrcweir     aMetric.mpImplMetric->mnMiscFlags   = 0;
7328cdf0e10cSrcweir     if( pMetric->mbDevice )
7329cdf0e10cSrcweir             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::DEVICE_FLAG;
7330cdf0e10cSrcweir     if( pMetric->mbScalableFont )
7331cdf0e10cSrcweir             aMetric.mpImplMetric->mnMiscFlags |= ImplFontMetric::SCALABLE_FLAG;
7332cdf0e10cSrcweir     aMetric.mpImplMetric->mnAscent      = ImplDevicePixelToLogicHeight( pMetric->mnAscent+mnEmphasisAscent );
7333cdf0e10cSrcweir     aMetric.mpImplMetric->mnDescent     = ImplDevicePixelToLogicHeight( pMetric->mnDescent+mnEmphasisDescent );
7334cdf0e10cSrcweir     aMetric.mpImplMetric->mnIntLeading  = ImplDevicePixelToLogicHeight( pMetric->mnIntLeading+mnEmphasisAscent );
7335cdf0e10cSrcweir     aMetric.mpImplMetric->mnExtLeading  = ImplDevicePixelToLogicHeight( pMetric->mnExtLeading );
7336cdf0e10cSrcweir     aMetric.mpImplMetric->mnLineHeight  = ImplDevicePixelToLogicHeight( pMetric->mnAscent+pMetric->mnDescent+mnEmphasisAscent+mnEmphasisDescent );
7337cdf0e10cSrcweir     aMetric.mpImplMetric->mnSlant       = ImplDevicePixelToLogicHeight( pMetric->mnSlant );
7338cdf0e10cSrcweir 
7339cdf0e10cSrcweir #ifdef UNX
7340cdf0e10cSrcweir     // backwards compatible line metrics after fixing #i60945#
7341cdf0e10cSrcweir     if( (meOutDevType == OUTDEV_VIRDEV)
7342cdf0e10cSrcweir     &&  static_cast<const VirtualDevice*>(this)->ForceZeroExtleadBug() )
7343cdf0e10cSrcweir         aMetric.mpImplMetric->mnExtLeading = 0;
7344cdf0e10cSrcweir #endif
7345cdf0e10cSrcweir 
7346cdf0e10cSrcweir     return aMetric;
7347cdf0e10cSrcweir }
7348cdf0e10cSrcweir 
7349cdf0e10cSrcweir // -----------------------------------------------------------------------
7350cdf0e10cSrcweir 
7351cdf0e10cSrcweir FontMetric OutputDevice::GetFontMetric( const Font& rFont ) const
7352cdf0e10cSrcweir {
7353cdf0e10cSrcweir     // select font, query metrics, select original font again
7354cdf0e10cSrcweir     Font aOldFont = GetFont();
7355cdf0e10cSrcweir     const_cast<OutputDevice*>(this)->SetFont( rFont );
7356cdf0e10cSrcweir     FontMetric aMetric( GetFontMetric() );
7357cdf0e10cSrcweir     const_cast<OutputDevice*>(this)->SetFont( aOldFont );
7358cdf0e10cSrcweir     return aMetric;
7359cdf0e10cSrcweir }
7360cdf0e10cSrcweir 
7361cdf0e10cSrcweir // -----------------------------------------------------------------------
7362cdf0e10cSrcweir 
7363cdf0e10cSrcweir /** OutputDevice::GetSysFontData
7364cdf0e10cSrcweir  *
7365cdf0e10cSrcweir  * @param nFallbacklevel Fallback font level (0 = best matching font)
7366cdf0e10cSrcweir  *
7367cdf0e10cSrcweir  * Retrieve detailed font information in platform independent structure
7368cdf0e10cSrcweir  *
7369cdf0e10cSrcweir  * @return SystemFontData
7370cdf0e10cSrcweir  **/
7371cdf0e10cSrcweir SystemFontData OutputDevice::GetSysFontData(int nFallbacklevel) const
7372cdf0e10cSrcweir {
7373cdf0e10cSrcweir     SystemFontData aSysFontData;
7374cdf0e10cSrcweir     aSysFontData.nSize = sizeof(aSysFontData);
7375cdf0e10cSrcweir 
7376cdf0e10cSrcweir     if (!mpGraphics) ImplGetGraphics();
7377cdf0e10cSrcweir     if (mpGraphics) aSysFontData = mpGraphics->GetSysFontData(nFallbacklevel);
7378cdf0e10cSrcweir 
7379cdf0e10cSrcweir     return aSysFontData;
7380cdf0e10cSrcweir }
7381cdf0e10cSrcweir 
7382cdf0e10cSrcweir 
7383cdf0e10cSrcweir // -----------------------------------------------------------------------
7384cdf0e10cSrcweir 
7385cdf0e10cSrcweir /** OutputDevice::GetSysTextLayoutData
7386cdf0e10cSrcweir  *
7387cdf0e10cSrcweir  * @param rStartPt Start point of the text
7388cdf0e10cSrcweir  * @param rStr Text string that will be transformed into layout of glyphs
7389cdf0e10cSrcweir  * @param nIndex Position in the string from where layout will be done
7390cdf0e10cSrcweir  * @param nLen Length of the string
7391cdf0e10cSrcweir  * @param pDXAry Custom layout adjustment data
7392cdf0e10cSrcweir  *
7393cdf0e10cSrcweir  * Export finalized glyph layout data as platform independent SystemTextLayoutData
7394cdf0e10cSrcweir  * (see vcl/inc/vcl/sysdata.hxx)
7395cdf0e10cSrcweir  *
7396cdf0e10cSrcweir  * Only parameters rStartPt and rStr are mandatory, the rest is optional
7397cdf0e10cSrcweir  * (default values will be used)
7398cdf0e10cSrcweir  *
7399cdf0e10cSrcweir  * @return SystemTextLayoutData
7400cdf0e10cSrcweir  **/
7401cdf0e10cSrcweir SystemTextLayoutData OutputDevice::GetSysTextLayoutData(const Point& rStartPt, const XubString& rStr, xub_StrLen nIndex, xub_StrLen nLen,
7402cdf0e10cSrcweir                                                         const sal_Int32* pDXAry) const
7403cdf0e10cSrcweir {
7404cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetSysTextLayoutData()" );
7405cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7406cdf0e10cSrcweir 
7407cdf0e10cSrcweir     SystemTextLayoutData aSysLayoutData;
7408cdf0e10cSrcweir     aSysLayoutData.nSize = sizeof(aSysLayoutData);
7409cdf0e10cSrcweir     aSysLayoutData.rGlyphData.reserve( 256 );
7410cdf0e10cSrcweir 
7411cdf0e10cSrcweir     if ( mpMetaFile ) {
7412cdf0e10cSrcweir         if (pDXAry)
7413cdf0e10cSrcweir             mpMetaFile->AddAction( new MetaTextArrayAction( rStartPt, rStr, pDXAry, nIndex, nLen ) );
7414cdf0e10cSrcweir         else
7415cdf0e10cSrcweir             mpMetaFile->AddAction( new MetaTextAction( rStartPt, rStr, nIndex, nLen ) );
7416cdf0e10cSrcweir     }
7417cdf0e10cSrcweir 
7418cdf0e10cSrcweir     if ( !IsDeviceOutputNecessary() ) return aSysLayoutData;
7419cdf0e10cSrcweir 
7420cdf0e10cSrcweir     SalLayout* rLayout = ImplLayout( rStr, nIndex, nLen, rStartPt, 0, pDXAry, true );
7421cdf0e10cSrcweir 
7422cdf0e10cSrcweir     // setup glyphs
7423cdf0e10cSrcweir     Point aPos;
7424cdf0e10cSrcweir     sal_GlyphId aGlyphId;
7425cdf0e10cSrcweir     for( int nStart = 0; rLayout->GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
7426cdf0e10cSrcweir     {
7427cdf0e10cSrcweir         // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
7428cdf0e10cSrcweir         //       ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
7429cdf0e10cSrcweir 
7430cdf0e10cSrcweir         SystemGlyphData aGlyph;
7431cdf0e10cSrcweir         aGlyph.index = static_cast<unsigned long> (aGlyphId & GF_IDXMASK);
7432cdf0e10cSrcweir         aGlyph.x = aPos.X();
7433cdf0e10cSrcweir         aGlyph.y = aPos.Y();
7434cdf0e10cSrcweir         int nLevel = (aGlyphId & GF_FONTMASK) >> GF_FONTSHIFT;
7435cdf0e10cSrcweir         aGlyph.fallbacklevel = nLevel < MAX_FALLBACK ? nLevel : 0;
7436cdf0e10cSrcweir         aSysLayoutData.rGlyphData.push_back(aGlyph);
7437cdf0e10cSrcweir     }
7438cdf0e10cSrcweir 
7439cdf0e10cSrcweir     // Get font data
7440cdf0e10cSrcweir     aSysLayoutData.orientation = rLayout->GetOrientation();
7441cdf0e10cSrcweir 
7442cdf0e10cSrcweir     rLayout->Release();
7443cdf0e10cSrcweir 
7444cdf0e10cSrcweir     return aSysLayoutData;
7445cdf0e10cSrcweir }
7446cdf0e10cSrcweir 
7447cdf0e10cSrcweir // -----------------------------------------------------------------------
7448cdf0e10cSrcweir 
7449cdf0e10cSrcweir 
7450cdf0e10cSrcweir long OutputDevice::GetMinKashida() const
7451cdf0e10cSrcweir {
7452cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetMinKashida()" );
7453cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7454cdf0e10cSrcweir     if( mbNewFont && !ImplNewFont() )
7455cdf0e10cSrcweir         return 0;
7456cdf0e10cSrcweir 
7457cdf0e10cSrcweir     ImplFontEntry*      pEntry = mpFontEntry;
7458cdf0e10cSrcweir     ImplFontMetricData* pMetric = &(pEntry->maMetric);
7459cdf0e10cSrcweir     return ImplDevicePixelToLogicWidth( pMetric->mnMinKashida );
7460cdf0e10cSrcweir }
7461cdf0e10cSrcweir // -----------------------------------------------------------------------
7462cdf0e10cSrcweir 
7463cdf0e10cSrcweir long OutputDevice::GetMinKashida( const Font& rFont ) const
7464cdf0e10cSrcweir {
7465cdf0e10cSrcweir     // select font, query Kashida, select original font again
7466cdf0e10cSrcweir     Font aOldFont = GetFont();
7467cdf0e10cSrcweir     const_cast<OutputDevice*>(this)->SetFont( rFont );
7468cdf0e10cSrcweir     long aKashida = GetMinKashida();
7469cdf0e10cSrcweir     const_cast<OutputDevice*>(this)->SetFont( aOldFont );
7470cdf0e10cSrcweir     return aKashida;
7471cdf0e10cSrcweir }
7472cdf0e10cSrcweir 
7473cdf0e10cSrcweir // -----------------------------------------------------------------------
7474cdf0e10cSrcweir xub_StrLen OutputDevice::ValidateKashidas ( const String& rTxt,
7475cdf0e10cSrcweir                                             xub_StrLen nIdx, xub_StrLen nLen,
7476cdf0e10cSrcweir                                             xub_StrLen nKashCount,
7477cdf0e10cSrcweir                                             const xub_StrLen* pKashidaPos,
7478cdf0e10cSrcweir                                             xub_StrLen* pKashidaPosDropped ) const
7479cdf0e10cSrcweir {
7480cdf0e10cSrcweir    // do layout
7481cdf0e10cSrcweir     SalLayout* pSalLayout = ImplLayout( rTxt, nIdx, nLen );
7482cdf0e10cSrcweir     if( !pSalLayout )
7483cdf0e10cSrcweir         return 0;
7484cdf0e10cSrcweir     xub_StrLen nDropped = 0;
7485cdf0e10cSrcweir     for( int i = 0; i < nKashCount; ++i )
7486cdf0e10cSrcweir     {
7487cdf0e10cSrcweir         if( !pSalLayout->IsKashidaPosValid( pKashidaPos[ i ] ))
7488cdf0e10cSrcweir         {
7489cdf0e10cSrcweir             pKashidaPosDropped[ nDropped ] = pKashidaPos [ i ];
7490cdf0e10cSrcweir             ++nDropped;
7491cdf0e10cSrcweir         }
7492cdf0e10cSrcweir     }
7493cdf0e10cSrcweir     pSalLayout->Release();
7494cdf0e10cSrcweir     return nDropped;
7495cdf0e10cSrcweir }
7496cdf0e10cSrcweir 
7497cdf0e10cSrcweir 
7498cdf0e10cSrcweir 
7499cdf0e10cSrcweir // -----------------------------------------------------------------------
7500cdf0e10cSrcweir 
7501cdf0e10cSrcweir 
7502cdf0e10cSrcweir // TODO: best is to get rid of this method completely
7503cdf0e10cSrcweir sal_uLong OutputDevice::GetKerningPairCount() const
7504cdf0e10cSrcweir {
7505cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetKerningPairCount()" );
7506cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7507cdf0e10cSrcweir 
7508cdf0e10cSrcweir     if( mbNewFont && !ImplNewFont() )
7509cdf0e10cSrcweir         return 0;
7510cdf0e10cSrcweir     if( mbInitFont )
7511cdf0e10cSrcweir         ImplInitFont();
7512cdf0e10cSrcweir 
7513cdf0e10cSrcweir     if( mpPDFWriter && mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
7514cdf0e10cSrcweir         return 0;
7515cdf0e10cSrcweir 
7516cdf0e10cSrcweir     // get the kerning pair count from the device layer
7517cdf0e10cSrcweir     int nKernPairs = mpGraphics->GetKernPairs( 0, NULL );
7518cdf0e10cSrcweir     return nKernPairs;
7519cdf0e10cSrcweir }
7520cdf0e10cSrcweir 
7521cdf0e10cSrcweir // -----------------------------------------------------------------------
7522cdf0e10cSrcweir 
7523cdf0e10cSrcweir inline bool CmpKernData( const KerningPair& a, const KerningPair& b )
7524cdf0e10cSrcweir {
7525cdf0e10cSrcweir     return (a.nChar1 < b.nChar1) || ((a.nChar1 == a.nChar2) && (a.nChar2 < a.nChar2));
7526cdf0e10cSrcweir }
7527cdf0e10cSrcweir 
7528cdf0e10cSrcweir // TODO: best is to get rid of this method completely
7529cdf0e10cSrcweir void OutputDevice::GetKerningPairs( sal_uLong nRequestedPairs, KerningPair* pKernPairs ) const
7530cdf0e10cSrcweir {
7531cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetKerningPairs()" );
7532cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7533cdf0e10cSrcweir 
7534cdf0e10cSrcweir     if( mbNewFont && !ImplNewFont() )
7535cdf0e10cSrcweir         return;
7536cdf0e10cSrcweir     if( mbInitFont )
7537cdf0e10cSrcweir         ImplInitFont();
7538cdf0e10cSrcweir 
7539cdf0e10cSrcweir     if( mpPDFWriter && mpPDFWriter->isBuiltinFont( mpFontEntry->maFontSelData.mpFontData ) )
7540cdf0e10cSrcweir         return;
7541cdf0e10cSrcweir 
7542cdf0e10cSrcweir     // get the kerning pairs directly from the device layer
7543cdf0e10cSrcweir     int nKernPairs = mpGraphics->GetKernPairs( nRequestedPairs, (ImplKernPairData*)pKernPairs );
7544cdf0e10cSrcweir 
7545cdf0e10cSrcweir     // sort kerning pairs
7546cdf0e10cSrcweir     std::sort( pKernPairs, pKernPairs+nKernPairs, CmpKernData );
7547cdf0e10cSrcweir }
7548cdf0e10cSrcweir 
7549cdf0e10cSrcweir // -----------------------------------------------------------------------
7550cdf0e10cSrcweir 
7551cdf0e10cSrcweir sal_Bool OutputDevice::GetGlyphBoundRects( const Point& rOrigin, const String& rStr,
7552cdf0e10cSrcweir     int nIndex, int nLen, int nBase, MetricVector& rVector )
7553cdf0e10cSrcweir {
7554cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetGlyphBoundRect_CTL()" );
7555cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7556cdf0e10cSrcweir 
7557cdf0e10cSrcweir     rVector.clear();
7558cdf0e10cSrcweir 
7559cdf0e10cSrcweir     if( nLen == STRING_LEN )
7560cdf0e10cSrcweir         nLen = rStr.Len() - nIndex;
7561cdf0e10cSrcweir 
7562cdf0e10cSrcweir     Rectangle aRect;
7563cdf0e10cSrcweir     for( int i = 0; i < nLen; i++ )
7564cdf0e10cSrcweir     {
7565cdf0e10cSrcweir         if( !GetTextBoundRect( aRect, rStr, sal::static_int_cast<xub_StrLen>(nBase), sal::static_int_cast<xub_StrLen>(nIndex+i), 1 ) )
7566cdf0e10cSrcweir             break;
7567cdf0e10cSrcweir         aRect.Move( rOrigin.X(), rOrigin.Y() );
7568cdf0e10cSrcweir         rVector.push_back( aRect );
7569cdf0e10cSrcweir     }
7570cdf0e10cSrcweir 
7571cdf0e10cSrcweir     return (nLen == (int)rVector.size());
7572cdf0e10cSrcweir }
7573cdf0e10cSrcweir 
7574cdf0e10cSrcweir // -----------------------------------------------------------------------
7575cdf0e10cSrcweir 
7576cdf0e10cSrcweir sal_Bool OutputDevice::GetTextBoundRect( Rectangle& rRect,
7577cdf0e10cSrcweir     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
7578cdf0e10cSrcweir     sal_uLong nLayoutWidth, const sal_Int32* pDXAry ) const
7579cdf0e10cSrcweir {
7580cdf0e10cSrcweir     DBG_TRACE( "OutputDevice::GetTextBoundRect()" );
7581cdf0e10cSrcweir     DBG_CHKTHIS( OutputDevice, ImplDbgCheckOutputDevice );
7582cdf0e10cSrcweir 
7583cdf0e10cSrcweir     sal_Bool bRet = sal_False;
7584cdf0e10cSrcweir     rRect.SetEmpty();
7585cdf0e10cSrcweir 
7586cdf0e10cSrcweir     SalLayout* pSalLayout = NULL;
7587cdf0e10cSrcweir     const Point aPoint;
7588cdf0e10cSrcweir     // calculate offset when nBase!=nIndex
7589cdf0e10cSrcweir     long nXOffset = 0;
7590cdf0e10cSrcweir     if( nBase != nIndex )
7591cdf0e10cSrcweir     {
7592cdf0e10cSrcweir         xub_StrLen nStart = Min( nBase, nIndex );
7593cdf0e10cSrcweir         xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
7594cdf0e10cSrcweir         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, aPoint, nLayoutWidth, pDXAry );
7595cdf0e10cSrcweir         if( pSalLayout )
7596cdf0e10cSrcweir         {
7597cdf0e10cSrcweir             nXOffset = pSalLayout->GetTextWidth();
7598cdf0e10cSrcweir             nXOffset /= pSalLayout->GetUnitsPerPixel();
7599cdf0e10cSrcweir             pSalLayout->Release();
7600cdf0e10cSrcweir             // TODO: fix offset calculation for Bidi case
7601cdf0e10cSrcweir             if( nBase < nIndex)
7602cdf0e10cSrcweir                 nXOffset = -nXOffset;
7603cdf0e10cSrcweir         }
7604cdf0e10cSrcweir     }
7605cdf0e10cSrcweir 
7606cdf0e10cSrcweir     pSalLayout = ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
7607cdf0e10cSrcweir     Rectangle aPixelRect;
7608cdf0e10cSrcweir     if( pSalLayout )
7609cdf0e10cSrcweir     {
7610cdf0e10cSrcweir         bRet = pSalLayout->GetBoundRect( *mpGraphics, aPixelRect );
7611cdf0e10cSrcweir 
7612cdf0e10cSrcweir         if( bRet )
7613cdf0e10cSrcweir         {
7614cdf0e10cSrcweir             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
7615cdf0e10cSrcweir 
7616cdf0e10cSrcweir             if( nWidthFactor > 1 )
7617cdf0e10cSrcweir             {
7618cdf0e10cSrcweir                 double fFactor = 1.0 / nWidthFactor;
7619cdf0e10cSrcweir                 aPixelRect.Left()
7620cdf0e10cSrcweir                     = static_cast< long >(aPixelRect.Left() * fFactor);
7621cdf0e10cSrcweir                 aPixelRect.Right()
7622cdf0e10cSrcweir                     = static_cast< long >(aPixelRect.Right() * fFactor);
7623cdf0e10cSrcweir                 aPixelRect.Top()
7624cdf0e10cSrcweir                     = static_cast< long >(aPixelRect.Top() * fFactor);
7625cdf0e10cSrcweir                 aPixelRect.Bottom()
7626cdf0e10cSrcweir                     = static_cast< long >(aPixelRect.Bottom() * fFactor);
7627cdf0e10cSrcweir             }
7628cdf0e10cSrcweir 
7629cdf0e10cSrcweir             Point aRotatedOfs( mnTextOffX, mnTextOffY );
7630cdf0e10cSrcweir             aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
7631cdf0e10cSrcweir             aPixelRect += aRotatedOfs;
7632cdf0e10cSrcweir             rRect = PixelToLogic( aPixelRect );
7633cdf0e10cSrcweir             if( mbMap )
7634cdf0e10cSrcweir                 rRect += Point( maMapRes.mnMapOfsX, maMapRes.mnMapOfsY );
7635cdf0e10cSrcweir         }
7636cdf0e10cSrcweir 
7637cdf0e10cSrcweir         pSalLayout->Release();
7638cdf0e10cSrcweir     }
7639cdf0e10cSrcweir 
7640cdf0e10cSrcweir     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
7641cdf0e10cSrcweir         return bRet;
7642cdf0e10cSrcweir 
7643cdf0e10cSrcweir     // fall back to bitmap method to get the bounding rectangle,
7644cdf0e10cSrcweir     // so we need a monochrome virtual device with matching font
7645cdf0e10cSrcweir     VirtualDevice aVDev( 1 );
7646cdf0e10cSrcweir     Font aFont( GetFont() );
7647cdf0e10cSrcweir     aFont.SetShadow( sal_False );
7648cdf0e10cSrcweir     aFont.SetOutline( sal_False );
7649cdf0e10cSrcweir     aFont.SetRelief( RELIEF_NONE );
7650cdf0e10cSrcweir     aFont.SetOrientation( 0 );
7651cdf0e10cSrcweir     aFont.SetSize( Size( mpFontEntry->maFontSelData.mnWidth, mpFontEntry->maFontSelData.mnHeight ) );
7652cdf0e10cSrcweir     aVDev.SetFont( aFont );
7653cdf0e10cSrcweir     aVDev.SetTextAlign( ALIGN_TOP );
7654cdf0e10cSrcweir 
7655cdf0e10cSrcweir     // layout the text on the virtual device
7656cdf0e10cSrcweir     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, aPoint, nLayoutWidth, pDXAry );
7657cdf0e10cSrcweir     if( !pSalLayout )
7658cdf0e10cSrcweir         return false;
7659cdf0e10cSrcweir 
7660cdf0e10cSrcweir     // make the bitmap big enough
7661cdf0e10cSrcweir     // TODO: use factors when it would get too big
7662cdf0e10cSrcweir     long nWidth = pSalLayout->GetTextWidth();
7663cdf0e10cSrcweir     long nHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent + mnEmphasisDescent;
7664cdf0e10cSrcweir     Point aOffset( nWidth/2, 8 );
7665cdf0e10cSrcweir     Size aOutSize( nWidth + 2*aOffset.X(), nHeight + 2*aOffset.Y() );
7666cdf0e10cSrcweir     if( !nWidth || !aVDev.SetOutputSizePixel( aOutSize ) )
7667cdf0e10cSrcweir         return false;
7668cdf0e10cSrcweir 
7669cdf0e10cSrcweir     // draw text in black
7670cdf0e10cSrcweir     pSalLayout->DrawBase() = aOffset;
7671cdf0e10cSrcweir     aVDev.SetTextColor( Color( COL_BLACK ) );
7672cdf0e10cSrcweir     aVDev.SetTextFillColor();
7673cdf0e10cSrcweir     aVDev.ImplInitTextColor();
7674cdf0e10cSrcweir     aVDev.ImplDrawText( *pSalLayout );
7675cdf0e10cSrcweir     pSalLayout->Release();
7676cdf0e10cSrcweir 
7677cdf0e10cSrcweir     // find extents using the bitmap
7678cdf0e10cSrcweir     Bitmap aBmp = aVDev.GetBitmap( Point(), aOutSize );
7679cdf0e10cSrcweir     BitmapReadAccess* pAcc = aBmp.AcquireReadAccess();
7680cdf0e10cSrcweir     if( !pAcc )
7681cdf0e10cSrcweir         return sal_False;
7682cdf0e10cSrcweir     const BitmapColor aBlack( pAcc->GetBestMatchingColor( Color( COL_BLACK ) ) );
7683cdf0e10cSrcweir     const long nW = pAcc->Width();
7684cdf0e10cSrcweir     const long nH = pAcc->Height();
7685cdf0e10cSrcweir     long nLeft = 0;
7686cdf0e10cSrcweir     long nRight = 0;
7687cdf0e10cSrcweir 
7688cdf0e10cSrcweir     // find top left point
7689cdf0e10cSrcweir     long nTop = 0;
7690cdf0e10cSrcweir     for(; nTop < nH; ++nTop )
7691cdf0e10cSrcweir     {
7692cdf0e10cSrcweir         for( nLeft = 0; nLeft < nW; ++nLeft )
7693cdf0e10cSrcweir             if( pAcc->GetPixel( nTop, nLeft ) == aBlack )
7694cdf0e10cSrcweir                 break;
7695cdf0e10cSrcweir         if( nLeft < nW )
7696cdf0e10cSrcweir             break;
7697cdf0e10cSrcweir     }
7698cdf0e10cSrcweir 
7699cdf0e10cSrcweir     // find bottom right point
7700cdf0e10cSrcweir     long nBottom = nH;
7701cdf0e10cSrcweir     while( --nBottom >= nTop )
7702cdf0e10cSrcweir     {
7703cdf0e10cSrcweir         for( nRight = nW; --nRight >= 0; )
7704cdf0e10cSrcweir             if( pAcc->GetPixel( nBottom, nRight ) == aBlack )
7705cdf0e10cSrcweir                 break;
7706cdf0e10cSrcweir         if( nRight >= 0 )
7707cdf0e10cSrcweir             break;
7708cdf0e10cSrcweir     }
7709cdf0e10cSrcweir     if( nRight < nLeft )
7710cdf0e10cSrcweir     {
7711cdf0e10cSrcweir         long nX = nRight;
7712cdf0e10cSrcweir         nRight = nLeft;
7713cdf0e10cSrcweir         nLeft  = nX;
7714cdf0e10cSrcweir     }
7715cdf0e10cSrcweir 
7716cdf0e10cSrcweir     for( long nY = nTop; nY <= nBottom; ++nY )
7717cdf0e10cSrcweir     {
7718cdf0e10cSrcweir         // find leftmost point
7719cdf0e10cSrcweir         long nX;
7720cdf0e10cSrcweir         for( nX = 0; nX < nLeft; ++nX )
7721cdf0e10cSrcweir             if( pAcc->GetPixel( nY, nX ) == aBlack )
7722cdf0e10cSrcweir                 break;
7723cdf0e10cSrcweir         nLeft = nX;
7724cdf0e10cSrcweir 
7725cdf0e10cSrcweir         // find rightmost point
7726cdf0e10cSrcweir         for( nX = nW; --nX > nRight; )
7727cdf0e10cSrcweir             if( pAcc->GetPixel( nY, nX ) == aBlack )
7728cdf0e10cSrcweir                 break;
7729cdf0e10cSrcweir         nRight = nX;
7730cdf0e10cSrcweir     }
7731cdf0e10cSrcweir 
7732cdf0e10cSrcweir     aBmp.ReleaseAccess( pAcc );
7733cdf0e10cSrcweir 
7734cdf0e10cSrcweir     if( nTop <= nBottom )
7735cdf0e10cSrcweir     {
7736cdf0e10cSrcweir         Size aSize( nRight - nLeft + 1, nBottom - nTop + 1 );
7737cdf0e10cSrcweir         Point aTopLeft( nLeft, nTop );
7738cdf0e10cSrcweir         aTopLeft -= aOffset;
7739cdf0e10cSrcweir         // adjust to text alignment
7740cdf0e10cSrcweir         aTopLeft.Y()+= mnTextOffY - (mpFontEntry->maMetric.mnAscent + mnEmphasisAscent);
7741cdf0e10cSrcweir         // convert to logical coordinates
7742cdf0e10cSrcweir         aSize = PixelToLogic( aSize );
7743cdf0e10cSrcweir         aTopLeft.X() = ImplDevicePixelToLogicWidth( aTopLeft.X() );
7744cdf0e10cSrcweir         aTopLeft.Y() = ImplDevicePixelToLogicHeight( aTopLeft.Y() );
7745cdf0e10cSrcweir         rRect = Rectangle( aTopLeft, aSize );
7746cdf0e10cSrcweir         return sal_True;
7747cdf0e10cSrcweir     }
7748cdf0e10cSrcweir 
7749cdf0e10cSrcweir     return sal_False;
7750cdf0e10cSrcweir }
7751cdf0e10cSrcweir 
7752cdf0e10cSrcweir // -----------------------------------------------------------------------
7753cdf0e10cSrcweir 
7754cdf0e10cSrcweir sal_Bool OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector& rVector,
7755cdf0e10cSrcweir     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
7756cdf0e10cSrcweir     sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
7757cdf0e10cSrcweir {
7758cdf0e10cSrcweir     // the fonts need to be initialized
7759cdf0e10cSrcweir     if( mbNewFont )
7760cdf0e10cSrcweir         ImplNewFont();
7761cdf0e10cSrcweir     if( mbInitFont )
7762cdf0e10cSrcweir         ImplInitFont();
7763cdf0e10cSrcweir     if( !mpFontEntry )
7764cdf0e10cSrcweir         return sal_False;
7765cdf0e10cSrcweir 
7766cdf0e10cSrcweir     sal_Bool bRet = sal_False;
7767cdf0e10cSrcweir     rVector.clear();
7768cdf0e10cSrcweir     if( nLen == STRING_LEN )
7769cdf0e10cSrcweir         nLen = rStr.Len() - nIndex;
7770cdf0e10cSrcweir     rVector.reserve( nLen );
7771cdf0e10cSrcweir 
7772cdf0e10cSrcweir     // we want to get the Rectangle in logical units, so to
7773cdf0e10cSrcweir     // avoid rounding errors we just size the font in logical units
7774cdf0e10cSrcweir     sal_Bool bOldMap = mbMap;
7775cdf0e10cSrcweir     if( bOldMap )
7776cdf0e10cSrcweir     {
7777cdf0e10cSrcweir         const_cast<OutputDevice&>(*this).mbMap = sal_False;
7778cdf0e10cSrcweir         const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
7779cdf0e10cSrcweir     }
7780cdf0e10cSrcweir 
7781cdf0e10cSrcweir     SalLayout* pSalLayout = NULL;
7782cdf0e10cSrcweir 
7783cdf0e10cSrcweir     // calculate offset when nBase!=nIndex
7784cdf0e10cSrcweir     long nXOffset = 0;
7785cdf0e10cSrcweir     if( nBase != nIndex )
7786cdf0e10cSrcweir     {
7787cdf0e10cSrcweir         xub_StrLen nStart = Min( nBase, nIndex );
7788cdf0e10cSrcweir         xub_StrLen nOfsLen = Max( nBase, nIndex ) - nStart;
7789cdf0e10cSrcweir         pSalLayout = ImplLayout( rStr, nStart, nOfsLen, Point(0,0), nTWidth, pDXArray );
7790cdf0e10cSrcweir         if( pSalLayout )
7791cdf0e10cSrcweir         {
7792cdf0e10cSrcweir             nXOffset = pSalLayout->GetTextWidth();
7793cdf0e10cSrcweir             pSalLayout->Release();
7794cdf0e10cSrcweir             // TODO: fix offset calculation for Bidi case
7795cdf0e10cSrcweir             if( nBase > nIndex)
7796cdf0e10cSrcweir                 nXOffset = -nXOffset;
7797cdf0e10cSrcweir         }
7798cdf0e10cSrcweir     }
7799cdf0e10cSrcweir 
7800cdf0e10cSrcweir     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
7801cdf0e10cSrcweir     if( pSalLayout )
7802cdf0e10cSrcweir     {
7803cdf0e10cSrcweir         bRet = pSalLayout->GetOutline( *mpGraphics, rVector );
7804cdf0e10cSrcweir         if( bRet )
7805cdf0e10cSrcweir         {
7806cdf0e10cSrcweir             // transform polygon to pixel units
7807cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aMatrix;
7808cdf0e10cSrcweir 
7809cdf0e10cSrcweir             int nWidthFactor = pSalLayout->GetUnitsPerPixel();
7810cdf0e10cSrcweir             if( nXOffset | mnTextOffX | mnTextOffY )
7811cdf0e10cSrcweir             {
7812cdf0e10cSrcweir                 Point aRotatedOfs( mnTextOffX*nWidthFactor, mnTextOffY*nWidthFactor );
7813cdf0e10cSrcweir                 aRotatedOfs -= pSalLayout->GetDrawPosition( Point( nXOffset, 0 ) );
7814cdf0e10cSrcweir                 aMatrix.translate( aRotatedOfs.X(), aRotatedOfs.Y() );
7815cdf0e10cSrcweir             }
7816cdf0e10cSrcweir 
7817cdf0e10cSrcweir             if( nWidthFactor > 1 )
7818cdf0e10cSrcweir             {
7819cdf0e10cSrcweir                 double fFactor = 1.0 / nWidthFactor;
7820cdf0e10cSrcweir                 aMatrix.scale( fFactor, fFactor );
7821cdf0e10cSrcweir             }
7822cdf0e10cSrcweir 
7823cdf0e10cSrcweir             if( !aMatrix.isIdentity() )
7824cdf0e10cSrcweir             {
7825cdf0e10cSrcweir                 ::basegfx::B2DPolyPolygonVector::iterator aIt = rVector.begin();
7826cdf0e10cSrcweir                 for(; aIt != rVector.end(); ++aIt )
7827cdf0e10cSrcweir                     (*aIt).transform( aMatrix );
7828cdf0e10cSrcweir             }
7829cdf0e10cSrcweir         }
7830cdf0e10cSrcweir 
7831cdf0e10cSrcweir         pSalLayout->Release();
7832cdf0e10cSrcweir     }
7833cdf0e10cSrcweir 
7834cdf0e10cSrcweir     if( bOldMap )
7835cdf0e10cSrcweir     {
7836cdf0e10cSrcweir         // restore original font size and map mode
7837cdf0e10cSrcweir         const_cast<OutputDevice&>(*this).mbMap = bOldMap;
7838cdf0e10cSrcweir         const_cast<OutputDevice&>(*this).mbNewFont = sal_True;
7839cdf0e10cSrcweir     }
7840cdf0e10cSrcweir 
7841cdf0e10cSrcweir     if( bRet || (OUTDEV_PRINTER == meOutDevType) || !mpFontEntry )
7842cdf0e10cSrcweir         return bRet;
7843cdf0e10cSrcweir 
7844cdf0e10cSrcweir     // fall back to bitmap conversion ------------------------------------------
7845cdf0e10cSrcweir 
7846cdf0e10cSrcweir     // Here, we can savely assume that the mapping between characters and glyphs
7847cdf0e10cSrcweir     // is one-to-one. This is most probably valid for the old bitmap fonts.
7848cdf0e10cSrcweir 
7849cdf0e10cSrcweir     // fall back to bitmap method to get the bounding rectangle,
7850cdf0e10cSrcweir     // so we need a monochrome virtual device with matching font
7851cdf0e10cSrcweir     pSalLayout = ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
7852cdf0e10cSrcweir     if (pSalLayout == 0)
7853cdf0e10cSrcweir         return false;
7854cdf0e10cSrcweir     long nOrgWidth = pSalLayout->GetTextWidth();
7855cdf0e10cSrcweir     long nOrgHeight = mpFontEntry->mnLineHeight + mnEmphasisAscent
7856cdf0e10cSrcweir         + mnEmphasisDescent;
7857cdf0e10cSrcweir     pSalLayout->Release();
7858cdf0e10cSrcweir 
7859cdf0e10cSrcweir     VirtualDevice aVDev(1);
7860cdf0e10cSrcweir 
7861cdf0e10cSrcweir     Font aFont(GetFont());
7862cdf0e10cSrcweir     aFont.SetShadow(false);
7863cdf0e10cSrcweir     aFont.SetOutline(false);
7864cdf0e10cSrcweir     aFont.SetRelief(RELIEF_NONE);
7865cdf0e10cSrcweir     aFont.SetOrientation(0);
7866cdf0e10cSrcweir     if( bOptimize )
7867cdf0e10cSrcweir     {
7868cdf0e10cSrcweir         aFont.SetSize( Size( 0, GLYPH_FONT_HEIGHT ) );
7869cdf0e10cSrcweir         aVDev.SetMapMode( MAP_PIXEL );
7870cdf0e10cSrcweir     }
7871cdf0e10cSrcweir     aVDev.SetFont( aFont );
7872cdf0e10cSrcweir     aVDev.SetTextAlign( ALIGN_TOP );
7873cdf0e10cSrcweir     aVDev.SetTextColor( Color(COL_BLACK) );
7874cdf0e10cSrcweir     aVDev.SetTextFillColor();
7875cdf0e10cSrcweir 
7876cdf0e10cSrcweir     pSalLayout = aVDev.ImplLayout( rStr, nIndex, nLen, Point(0,0), nTWidth, pDXArray );
7877cdf0e10cSrcweir     if (pSalLayout == 0)
7878cdf0e10cSrcweir         return false;
7879cdf0e10cSrcweir     long nWidth = pSalLayout->GetTextWidth();
7880cdf0e10cSrcweir     long nHeight = ((OutputDevice*)&aVDev)->mpFontEntry->mnLineHeight + ((OutputDevice*)&aVDev)->mnEmphasisAscent
7881cdf0e10cSrcweir         + ((OutputDevice*)&aVDev)->mnEmphasisDescent;
7882cdf0e10cSrcweir     pSalLayout->Release();
7883cdf0e10cSrcweir 
7884cdf0e10cSrcweir     if( !nWidth || !nHeight )
7885cdf0e10cSrcweir         return sal_True;
7886cdf0e10cSrcweir     double fScaleX = static_cast< double >(nOrgWidth) / nWidth;
7887cdf0e10cSrcweir     double fScaleY = static_cast< double >(nOrgHeight) / nHeight;
7888cdf0e10cSrcweir 
7889cdf0e10cSrcweir     // calculate offset when nBase!=nIndex
7890cdf0e10cSrcweir     // TODO: fix offset calculation for Bidi case
7891cdf0e10cSrcweir     nXOffset = 0;
7892cdf0e10cSrcweir     if( nBase != nIndex )
7893cdf0e10cSrcweir     {
7894cdf0e10cSrcweir         xub_StrLen nStart  = ((nBase < nIndex) ? nBase : nIndex);
7895cdf0e10cSrcweir         xub_StrLen nLength = ((nBase > nIndex) ? nBase : nIndex) - nStart;
7896cdf0e10cSrcweir         pSalLayout = aVDev.ImplLayout( rStr, nStart, nLength, Point(0,0), nTWidth, pDXArray );
7897cdf0e10cSrcweir         if( pSalLayout )
7898cdf0e10cSrcweir         {
7899cdf0e10cSrcweir             nXOffset = pSalLayout->GetTextWidth();
7900cdf0e10cSrcweir             pSalLayout->Release();
7901cdf0e10cSrcweir             if( nBase > nIndex)
7902cdf0e10cSrcweir                 nXOffset = -nXOffset;
7903cdf0e10cSrcweir         }
7904cdf0e10cSrcweir     }
7905cdf0e10cSrcweir 
7906cdf0e10cSrcweir     bRet = true;
7907cdf0e10cSrcweir     bool bRTL = false;
7908cdf0e10cSrcweir     String aStr( rStr ); // prepare for e.g. localized digits
7909cdf0e10cSrcweir     ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, NULL );
7910cdf0e10cSrcweir     for( int nCharPos = -1; aLayoutArgs.GetNextPos( &nCharPos, &bRTL);)
7911cdf0e10cSrcweir     {
7912cdf0e10cSrcweir         bool bSuccess = false;
7913cdf0e10cSrcweir 
7914cdf0e10cSrcweir         // draw character into virtual device
7915cdf0e10cSrcweir         pSalLayout = aVDev.ImplLayout( rStr, static_cast< xub_StrLen >(nCharPos), 1, Point(0,0), nTWidth, pDXArray );
7916cdf0e10cSrcweir         if (pSalLayout == 0)
7917cdf0e10cSrcweir             return false;
7918cdf0e10cSrcweir         long nCharWidth = pSalLayout->GetTextWidth();
7919cdf0e10cSrcweir 
7920cdf0e10cSrcweir         Point aOffset(nCharWidth / 2, 8);
7921cdf0e10cSrcweir         Size aSize(nCharWidth + 2 * aOffset.X(), nHeight + 2 * aOffset.Y());
7922cdf0e10cSrcweir         bSuccess = (bool)aVDev.SetOutputSizePixel(aSize);
7923cdf0e10cSrcweir         if( bSuccess )
7924cdf0e10cSrcweir         {
7925cdf0e10cSrcweir             // draw glyph into virtual device
7926cdf0e10cSrcweir             aVDev.Erase();
7927cdf0e10cSrcweir             pSalLayout->DrawBase() += aOffset;
7928cdf0e10cSrcweir             pSalLayout->DrawBase() += Point( ((OutputDevice*)&aVDev)->mnTextOffX, ((OutputDevice*)&aVDev)->mnTextOffY );
7929cdf0e10cSrcweir             pSalLayout->DrawText( *((OutputDevice*)&aVDev)->mpGraphics );
7930cdf0e10cSrcweir             pSalLayout->Release();
7931cdf0e10cSrcweir 
7932cdf0e10cSrcweir             // convert character image into outline
7933cdf0e10cSrcweir             Bitmap aBmp( aVDev.GetBitmap(Point(0, 0), aSize));
7934cdf0e10cSrcweir 
7935cdf0e10cSrcweir             PolyPolygon aPolyPoly;
7936cdf0e10cSrcweir             bool bVectorized = aBmp.Vectorize(aPolyPoly, BMP_VECTORIZE_OUTER | BMP_VECTORIZE_REDUCE_EDGES);
7937cdf0e10cSrcweir             if( !bVectorized )
7938cdf0e10cSrcweir                 bSuccess = false;
7939cdf0e10cSrcweir             else
7940cdf0e10cSrcweir             {
7941cdf0e10cSrcweir                 // convert units to logical width
7942cdf0e10cSrcweir                 for (sal_uInt16 j = 0; j < aPolyPoly.Count(); ++j)
7943cdf0e10cSrcweir                 {
7944cdf0e10cSrcweir                     Polygon& rPoly = aPolyPoly[j];
7945cdf0e10cSrcweir                     for (sal_uInt16 k = 0; k < rPoly.GetSize(); ++k)
7946cdf0e10cSrcweir                     {
7947cdf0e10cSrcweir                         Point& rPt = rPoly[k];
7948cdf0e10cSrcweir                         rPt -= aOffset;
7949cdf0e10cSrcweir                         int nPixelX = rPt.X() - ((OutputDevice&)aVDev).mnTextOffX + nXOffset;
7950cdf0e10cSrcweir                         int nPixelY = rPt.Y() - ((OutputDevice&)aVDev).mnTextOffY;
7951cdf0e10cSrcweir                         rPt.X() = ImplDevicePixelToLogicWidth( nPixelX );
7952cdf0e10cSrcweir                         rPt.Y() = ImplDevicePixelToLogicHeight( nPixelY );
7953cdf0e10cSrcweir                     }
7954cdf0e10cSrcweir                 }
7955cdf0e10cSrcweir 
7956cdf0e10cSrcweir 
7957cdf0e10cSrcweir                 // ignore "empty" glyphs:
7958cdf0e10cSrcweir                 if( aPolyPoly.Count() > 0 )
7959cdf0e10cSrcweir                 {
7960cdf0e10cSrcweir                     // convert  to B2DPolyPolygon
7961cdf0e10cSrcweir                     // TODO: get rid of intermediate tool's PolyPolygon
7962cdf0e10cSrcweir                     ::basegfx::B2DPolyPolygon aB2DPolyPoly = aPolyPoly.getB2DPolyPolygon();
7963cdf0e10cSrcweir                     ::basegfx::B2DHomMatrix aMatrix;
7964cdf0e10cSrcweir                     aMatrix.scale( fScaleX, fScaleY );
7965cdf0e10cSrcweir                     int nAngle = GetFont().GetOrientation();
7966cdf0e10cSrcweir                     if( nAngle )
7967cdf0e10cSrcweir                         aMatrix.rotate( nAngle * F_PI1800 );
7968cdf0e10cSrcweir                     aB2DPolyPoly.transform( aMatrix );
7969cdf0e10cSrcweir                     rVector.push_back( aB2DPolyPoly );
7970cdf0e10cSrcweir                 }
7971cdf0e10cSrcweir             }
7972cdf0e10cSrcweir         }
7973cdf0e10cSrcweir 
7974cdf0e10cSrcweir         nXOffset += nCharWidth;
7975cdf0e10cSrcweir         bRet = bRet && bSuccess;
7976cdf0e10cSrcweir     }
7977cdf0e10cSrcweir 
7978cdf0e10cSrcweir     return bRet;
7979cdf0e10cSrcweir }
7980cdf0e10cSrcweir 
7981cdf0e10cSrcweir // -----------------------------------------------------------------------
7982cdf0e10cSrcweir 
7983cdf0e10cSrcweir sal_Bool OutputDevice::GetTextOutlines( PolyPolyVector& rResultVector,
7984cdf0e10cSrcweir     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex,
7985cdf0e10cSrcweir     xub_StrLen nLen, sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
7986cdf0e10cSrcweir {
7987cdf0e10cSrcweir     rResultVector.clear();
7988cdf0e10cSrcweir 
7989cdf0e10cSrcweir     // get the basegfx polypolygon vector
7990cdf0e10cSrcweir     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
7991cdf0e10cSrcweir     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
7992cdf0e10cSrcweir                          bOptimize, nTWidth, pDXArray ) )
7993cdf0e10cSrcweir     return sal_False;
7994cdf0e10cSrcweir 
7995cdf0e10cSrcweir     // convert to a tool polypolygon vector
7996cdf0e10cSrcweir     rResultVector.reserve( aB2DPolyPolyVector.size() );
7997cdf0e10cSrcweir     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
7998cdf0e10cSrcweir     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
7999cdf0e10cSrcweir         rResultVector.push_back(PolyPolygon(*aIt)); // #i76339#
8000cdf0e10cSrcweir 
8001cdf0e10cSrcweir     return sal_True;
8002cdf0e10cSrcweir }
8003cdf0e10cSrcweir 
8004cdf0e10cSrcweir // -----------------------------------------------------------------------
8005cdf0e10cSrcweir 
8006cdf0e10cSrcweir sal_Bool OutputDevice::GetTextOutline( PolyPolygon& rPolyPoly,
8007cdf0e10cSrcweir     const String& rStr, xub_StrLen nBase, xub_StrLen nIndex, xub_StrLen nLen,
8008cdf0e10cSrcweir     sal_Bool bOptimize, sal_uLong nTWidth, const sal_Int32* pDXArray ) const
8009cdf0e10cSrcweir {
8010cdf0e10cSrcweir     rPolyPoly.Clear();
8011cdf0e10cSrcweir 
8012cdf0e10cSrcweir     // get the basegfx polypolygon vector
8013cdf0e10cSrcweir     ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector;
8014cdf0e10cSrcweir     if( !GetTextOutlines( aB2DPolyPolyVector, rStr, nBase, nIndex, nLen,
8015cdf0e10cSrcweir                          bOptimize, nTWidth, pDXArray ) )
8016cdf0e10cSrcweir     return sal_False;
8017cdf0e10cSrcweir 
8018cdf0e10cSrcweir     // convert and merge into a tool polypolygon
8019cdf0e10cSrcweir     ::basegfx::B2DPolyPolygonVector::const_iterator aIt = aB2DPolyPolyVector.begin();
8020cdf0e10cSrcweir     for(; aIt != aB2DPolyPolyVector.end(); ++aIt )
8021cdf0e10cSrcweir         for( unsigned int i = 0; i < aIt->count(); ++i )
8022cdf0e10cSrcweir             rPolyPoly.Insert(Polygon((*aIt).getB2DPolygon( i ))); // #i76339#
8023cdf0e10cSrcweir 
8024cdf0e10cSrcweir     return sal_True;
8025cdf0e10cSrcweir }
8026cdf0e10cSrcweir 
8027cdf0e10cSrcweir // -----------------------------------------------------------------------
8028cdf0e10cSrcweir 
8029cdf0e10cSrcweir sal_Bool OutputDevice::GetFontCharMap( FontCharMap& rFontCharMap ) const
8030cdf0e10cSrcweir {
8031cdf0e10cSrcweir     rFontCharMap.Reset();
8032cdf0e10cSrcweir 
8033cdf0e10cSrcweir     // we need a graphics
8034cdf0e10cSrcweir     if( !mpGraphics && !ImplGetGraphics() )
8035cdf0e10cSrcweir         return sal_False;
8036cdf0e10cSrcweir 
8037cdf0e10cSrcweir     if( mbNewFont )
8038cdf0e10cSrcweir         ImplNewFont();
8039cdf0e10cSrcweir     if( mbInitFont )
8040cdf0e10cSrcweir         ImplInitFont();
8041cdf0e10cSrcweir     if( !mpFontEntry )
8042cdf0e10cSrcweir         return sal_False;
8043cdf0e10cSrcweir 
8044cdf0e10cSrcweir #ifdef ENABLE_IFC_CACHE    // a little font charmap cache helps considerably
8045cdf0e10cSrcweir     static const int NMAXITEMS = 16;
8046cdf0e10cSrcweir     static int nUsedItems = 0, nCurItem = 0;
8047cdf0e10cSrcweir 
8048cdf0e10cSrcweir     struct CharMapCacheItem { const ImplFontData* mpFontData; FontCharMap maCharMap; };
8049cdf0e10cSrcweir     static CharMapCacheItem aCache[ NMAXITEMS ];
8050cdf0e10cSrcweir 
8051cdf0e10cSrcweir     const ImplFontData* pFontData = mpFontEntry->maFontSelData.mpFontData;
8052cdf0e10cSrcweir 
8053cdf0e10cSrcweir     int i;
8054cdf0e10cSrcweir     for( i = nUsedItems; --i >= 0; )
8055cdf0e10cSrcweir         if( pFontData == aCache[i].mpFontData )
8056cdf0e10cSrcweir             break;
8057cdf0e10cSrcweir     if( i >= 0 )    // found in cache
8058cdf0e10cSrcweir     {
8059cdf0e10cSrcweir         rFontCharMap.Reset( aCache[i].maCharMap.mpImpl );
8060cdf0e10cSrcweir     }
8061cdf0e10cSrcweir     else            // need to cache
8062cdf0e10cSrcweir #endif // ENABLE_IFC_CACHE
8063cdf0e10cSrcweir     {
8064cdf0e10cSrcweir         const ImplFontCharMap* pNewMap = mpGraphics->GetImplFontCharMap();
8065cdf0e10cSrcweir         rFontCharMap.Reset( pNewMap );
8066cdf0e10cSrcweir 
8067cdf0e10cSrcweir #ifdef ENABLE_IFC_CACHE
8068cdf0e10cSrcweir         // manage cache round-robin and insert data
8069cdf0e10cSrcweir         CharMapCacheItem& rItem = aCache[ nCurItem ];
8070cdf0e10cSrcweir         rItem.mpFontData = pFontData;
8071cdf0e10cSrcweir         rItem.maCharMap.Reset( pNewMap );
8072cdf0e10cSrcweir 
8073cdf0e10cSrcweir         if( ++nCurItem >= NMAXITEMS )
8074cdf0e10cSrcweir             nCurItem = 0;
8075cdf0e10cSrcweir 
8076cdf0e10cSrcweir         if( ++nUsedItems >= NMAXITEMS )
8077cdf0e10cSrcweir             nUsedItems = NMAXITEMS;
8078cdf0e10cSrcweir #endif // ENABLE_IFC_CACHE
8079cdf0e10cSrcweir     }
8080cdf0e10cSrcweir 
8081cdf0e10cSrcweir     if( rFontCharMap.IsDefaultMap() )
8082cdf0e10cSrcweir         return sal_False;
8083cdf0e10cSrcweir     return sal_True;
8084cdf0e10cSrcweir }
8085cdf0e10cSrcweir 
8086cdf0e10cSrcweir // -----------------------------------------------------------------------
8087cdf0e10cSrcweir 
8088cdf0e10cSrcweir xub_StrLen OutputDevice::HasGlyphs( const Font& rTempFont, const String& rStr,
8089cdf0e10cSrcweir     xub_StrLen nIndex, xub_StrLen nLen ) const
8090cdf0e10cSrcweir {
8091cdf0e10cSrcweir     if( nIndex >= rStr.Len() )
8092cdf0e10cSrcweir         return nIndex;
8093cdf0e10cSrcweir     xub_StrLen nEnd = nIndex + nLen;
8094cdf0e10cSrcweir     if( (sal_uLong)nIndex+nLen > rStr.Len() )
8095cdf0e10cSrcweir         nEnd = rStr.Len();
8096cdf0e10cSrcweir 
8097cdf0e10cSrcweir     DBG_ASSERT( nIndex < nEnd, "StartPos >= EndPos?" );
8098cdf0e10cSrcweir     DBG_ASSERT( nEnd <= rStr.Len(), "String too short" );
8099cdf0e10cSrcweir 
8100cdf0e10cSrcweir     // to get the map temporarily set font
8101cdf0e10cSrcweir     const Font aOrigFont = GetFont();
8102cdf0e10cSrcweir     const_cast<OutputDevice&>(*this).SetFont( rTempFont );
8103cdf0e10cSrcweir     FontCharMap aFontCharMap;
8104cdf0e10cSrcweir     sal_Bool bRet = GetFontCharMap( aFontCharMap );
8105cdf0e10cSrcweir     const_cast<OutputDevice&>(*this).SetFont( aOrigFont );
8106cdf0e10cSrcweir 
8107cdf0e10cSrcweir     // if fontmap is unknown assume it doesn't have the glyphs
8108cdf0e10cSrcweir     if( bRet == sal_False )
8109cdf0e10cSrcweir         return nIndex;
8110cdf0e10cSrcweir 
8111cdf0e10cSrcweir     const sal_Unicode* pStr = rStr.GetBuffer();
8112cdf0e10cSrcweir     for( pStr += nIndex; nIndex < nEnd; ++pStr, ++nIndex )
8113cdf0e10cSrcweir         if( ! aFontCharMap.HasChar( *pStr ) )
8114cdf0e10cSrcweir             return nIndex;
8115cdf0e10cSrcweir 
8116cdf0e10cSrcweir     return STRING_LEN;
8117cdf0e10cSrcweir }
8118cdf0e10cSrcweir 
8119cdf0e10cSrcweir // -----------------------------------------------------------------------
8120