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