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