1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
31 #include <i18npool/mslangid.hxx>
36 #include <vcl/salgdi.hxx>
37 #include <vcl/sallayout.hxx>
38 #include <rtl/tencinfo.h>
39 #include <tools/debug.hxx>
40 #include <vcl/svdata.hxx>
41 #include <vcl/metric.hxx>
42 #include <vcl/impfont.hxx>
43 #include <vcl/metaact.hxx>
44 #include <vcl/gdimtf.hxx>
45 #include <vcl/outdata.hxx>
46 #include <vcl/outfont.hxx>
47 #include <basegfx/polygon/b2dpolygon.hxx>
48 #include <basegfx/polygon/b2dpolypolygon.hxx>
49 #include <basegfx/matrix/b2dhommatrix.hxx>
50 #include <tools/poly.hxx>
51 #include <vcl/outdev.h>
52 #include <vcl/virdev.hxx>
53 #include <vcl/print.hxx>
54 #include <vcl/event.hxx>
55 #include <vcl/window.h>
56 #include <vcl/window.hxx>
57 #include <vcl/svapp.hxx>
58 #include <vcl/bmpacc.hxx>
59 #include <vcl/fontcvt.hxx>
60 #include <vcl/outdev.hxx>
61 #include <vcl/edit.hxx>
62 #include <vcl/fontcfg.hxx>
63 #include <vcl/sysdata.hxx>
67 #ifdef ENABLE_GRAPHITE
68 #include <vcl/graphite_features.hxx>
71 #include <vcl/unohelp.hxx>
72 #include <pdfwriter_impl.hxx>
73 #include <vcl/controllayout.hxx>
74 #include <rtl/logfile.hxx>
76 #ifndef _COM_SUN_STAR_BEANS_PROPERTYVALUES_HDL_
77 #include <com/sun/star/beans/PropertyValues.hdl>
79 #include <com/sun/star/i18n/XBreakIterator.hpp>
80 #include <com/sun/star/i18n/WordType.hpp>
81 #include <com/sun/star/linguistic2/XLinguServiceManager.hpp>
84 #define GLYPH_FONT_HEIGHT 128
86 #define GLYPH_FONT_HEIGHT 176
88 #define GLYPH_FONT_HEIGHT 256
91 #include <sal/alloca.h>
99 // =======================================================================
101 DBG_NAMEEX( OutputDevice
)
104 // =======================================================================
106 using namespace ::com::sun::star
;
107 using namespace ::com::sun::star::uno
;
108 using namespace ::rtl
;
109 using namespace ::vcl
;
111 // =======================================================================
113 #define TEXT_DRAW_ELLIPSIS (TEXT_DRAW_ENDELLIPSIS | TEXT_DRAW_PATHELLIPSIS | TEXT_DRAW_NEWSELLIPSIS)
115 // =======================================================================
117 #define UNDERLINE_LAST UNDERLINE_BOLDWAVE
118 #define STRIKEOUT_LAST STRIKEOUT_X
120 // =======================================================================
122 static void ImplRotatePos( long nOriginX
, long nOriginY
, long& rX
, long& rY
,
125 if ( (nOrientation
>= 0) && !(nOrientation
% 900) )
127 if ( (nOrientation
>= 3600) )
128 nOrientation
%= 3600;
135 if ( nOrientation
== 900 )
141 else if ( nOrientation
== 1800 )
146 else /* ( nOrientation == 2700 ) */
159 double nRealOrientation
= nOrientation
*F_PI1800
;
160 double nCos
= cos( nRealOrientation
);
161 double nSin
= sin( nRealOrientation
);
164 long nX
= rX
-nOriginX
;
165 long nY
= rY
-nOriginY
;
168 rX
= +((long)(nCos
*nX
+ nSin
*nY
)) + nOriginX
;
169 rY
= -((long)(nSin
*nX
- nCos
*nY
)) + nOriginY
;
173 // =======================================================================
175 void OutputDevice::ImplUpdateFontData( bool bNewFontLists
)
177 // the currently selected logical font is no longer needed
180 mpFontCache
->Release( mpFontEntry
);
189 if ( mpGetDevFontList
)
191 delete mpGetDevFontList
;
192 mpGetDevFontList
= NULL
;
194 if ( mpGetDevSizeList
)
196 delete mpGetDevSizeList
;
197 mpGetDevSizeList
= NULL
;
200 // release all physically selected fonts on this device
201 if( ImplGetGraphics() )
202 mpGraphics
->ReleaseFonts();
205 if ( GetOutDevType() == OUTDEV_PRINTER
|| mpPDFWriter
)
207 ImplSVData
* pSVData
= ImplGetSVData();
209 if( mpFontCache
&& mpFontCache
!= pSVData
->maGDIData
.mpScreenFontCache
)
210 mpFontCache
->Invalidate();
214 // we need a graphics
215 if ( ImplGetGraphics() )
217 if( mpFontList
&& mpFontList
!= pSVData
->maGDIData
.mpScreenFontList
)
222 if( mpFontList
&& mpFontList
!= pSVData
->maGDIData
.mpScreenFontList
)
224 if( mpFontCache
&& mpFontCache
!= pSVData
->maGDIData
.mpScreenFontCache
)
226 mpFontList
= mpPDFWriter
->filterDevFontList( pSVData
->maGDIData
.mpScreenFontList
);
227 mpFontCache
= new ImplFontCache( FALSE
);
232 mpOutDevData
->maDevFontSubst
.Clear();
233 mpGraphics
->GetDevFontList( mpFontList
);
234 mpGraphics
->GetDevFontSubstList( this );
240 // also update child windows if needed
241 if ( GetOutDevType() == OUTDEV_WINDOW
)
243 Window
* pChild
= ((Window
*)this)->mpWindowImpl
->mpFirstChild
;
246 pChild
->ImplUpdateFontData( true );
247 pChild
= pChild
->mpWindowImpl
->mpNext
;
252 // -----------------------------------------------------------------------
254 void OutputDevice::ImplUpdateAllFontData( bool bNewFontLists
)
256 ImplSVData
* pSVData
= ImplGetSVData();
258 // update all windows
259 Window
* pFrame
= pSVData
->maWinData
.mpFirstFrame
;
262 pFrame
->ImplUpdateFontData( bNewFontLists
);
264 Window
* pSysWin
= pFrame
->mpWindowImpl
->mpFrameData
->mpFirstOverlap
;
267 pSysWin
->ImplUpdateFontData( bNewFontLists
);
268 pSysWin
= pSysWin
->mpWindowImpl
->mpNextOverlap
;
271 pFrame
= pFrame
->mpWindowImpl
->mpFrameData
->mpNextFrame
;
274 // update all virtual devices
275 VirtualDevice
* pVirDev
= pSVData
->maGDIData
.mpFirstVirDev
;
278 pVirDev
->ImplUpdateFontData( bNewFontLists
);
279 pVirDev
= pVirDev
->mpNext
;
282 // update all printers
283 Printer
* pPrinter
= pSVData
->maGDIData
.mpFirstPrinter
;
286 pPrinter
->ImplUpdateFontData( bNewFontLists
);
287 pPrinter
= pPrinter
->mpNext
;
290 // clear global font lists to have them updated
291 pSVData
->maGDIData
.mpScreenFontCache
->Invalidate();
294 pSVData
->maGDIData
.mpScreenFontList
->Clear();
295 pFrame
= pSVData
->maWinData
.mpFirstFrame
;
298 if ( pFrame
->ImplGetGraphics() )
299 // MT: Stupid typecast here and somewhere ((OutputDevice*)&aVDev)->, because bug in .NET2002 compiler.
300 ((OutputDevice
*)pFrame
)->mpGraphics
->GetDevFontList( pFrame
->mpWindowImpl
->mpFrameData
->mpFontList
);
305 // =======================================================================
307 struct ImplLocalizedFontName
309 const char* mpEnglishName
;
310 const sal_Unicode
* mpLocalizedNames
;
313 static sal_Unicode
const aBatang
[] = { 0xBC14, 0xD0D5, 0, 0 };
314 static sal_Unicode
const aBatangChe
[] = { 0xBC14, 0xD0D5, 0xCCB4, 0, 0 };
315 static sal_Unicode
const aGungsuh
[] = { 0xAD81, 0xC11C, 0, 0 };
316 static sal_Unicode
const aGungsuhChe
[] = { 0xAD81, 0xC11C, 0xCCB4, 0, 0 };
317 static sal_Unicode
const aGulim
[] = { 0xAD74, 0xB9BC, 0, 0 };
318 static sal_Unicode
const aGulimChe
[] = { 0xAD74, 0xB9BC, 0xCCB4, 0, 0 };
319 static sal_Unicode
const aDotum
[] = { 0xB3CB, 0xC6C0, 0, 0 };
320 static sal_Unicode
const aDotumChe
[] = { 0xB3CB, 0xC6C0, 0xCCB4, 0, 0 };
321 static sal_Unicode
const aSimSun
[] = { 0x5B8B, 0x4F53, 0, 0 };
322 static sal_Unicode
const aNSimSun
[] = { 0x65B0, 0x5B8B, 0x4F53, 0, 0 };
323 static sal_Unicode
const aSimHei
[] = { 0x9ED1, 0x4F53, 0, 0 };
324 static sal_Unicode
const aSimKai
[] = { 0x6977, 0x4F53, 0, 0 };
325 static sal_Unicode
const azycjkSun
[] = { 0x4E2D, 0x6613, 0x5B8B, 0x4F53, 0, 0 };
326 static sal_Unicode
const azycjkHei
[] = { 0x4E2D, 0x6613, 0x9ED1, 0x4F53, 0, 0 };
327 static sal_Unicode
const azycjkKai
[] = { 0x4E2D, 0x6613, 0x6977, 0x4F53, 0, 0 };
328 static sal_Unicode
const aFZHei
[] = { 0x65B9, 0x6B63, 0x9ED1, 0x4F53, 0, 0 };
329 static sal_Unicode
const aFZKai
[] = { 0x65B9, 0x6B63, 0x6977, 0x4F53, 0, 0 };
330 static sal_Unicode
const aFZSongYI
[] = { 0x65B9, 0x6B63, 0x5B8B, 0x4E00, 0, 0 };
331 static sal_Unicode
const aFZShuSong
[] = { 0x65B9, 0x6B63, 0x4E66, 0x5B8B, 0, 0 };
332 static sal_Unicode
const aFZFangSong
[] = { 0x65B9, 0x6B63, 0x4EFF, 0x5B8B, 0, 0 };
333 // Attention: this fonts includes the wrong encoding vector - so we double the names with correct and wrong encoding
334 // First one is the GB-Encoding (we think the correct one), second is the big5 encoded name
335 static sal_Unicode
const aMHei
[] = { 'm', 0x7B80, 0x9ED1, 0, 'm', 0x6F60, 0x7AAA, 0, 0 };
336 static sal_Unicode
const aMKai
[] = { 'm', 0x7B80, 0x6977, 0x566C, 0, 'm', 0x6F60, 0x7FF1, 0x628E, 0, 0 };
337 static sal_Unicode
const aMSong
[] = { 'm', 0x7B80, 0x5B8B, 0, 'm', 0x6F60, 0x51BC, 0, 0 };
338 static sal_Unicode
const aCFangSong
[] = { 'm', 0x7B80, 0x592B, 0x5B8B, 0, 'm', 0x6F60, 0x6E98, 0x51BC, 0, 0 };
339 static sal_Unicode
const aMingLiU
[] = { 0x7D30, 0x660E, 0x9AD4, 0, 0 };
340 static sal_Unicode
const aPMingLiU
[] = { 0x65B0, 0x7D30, 0x660E, 0x9AD4, 0, 0 };
341 static sal_Unicode
const aHei
[] = { 0x6865, 0, 0 };
342 static sal_Unicode
const aKai
[] = { 0x6B61, 0, 0 };
343 static sal_Unicode
const aMing
[] = { 0x6D69, 0x6E67, 0, 0 };
344 static sal_Unicode
const aMSGothic
[] = { 'm','s', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 };
345 static sal_Unicode
const aMSPGothic
[] = { 'm','s','p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 };
346 static sal_Unicode
const aMSMincho
[] = { 'm', 's', 0x660E, 0x671D, 0 };
347 static sal_Unicode
const aMSPMincho
[] = { 'm','s','p', 0x660E, 0x671D, 0 };
348 static sal_Unicode
const aMeiryo
[] = { 0x30e1, 0x30a4, 0x30ea, 0x30aa, 0 };
349 static sal_Unicode
const aHGMinchoL
[] = { 'h','g', 0x660E, 0x671D, 'l', 0, 0 };
350 static sal_Unicode
const aHGGothicB
[] = { 'h','g', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 0 };
351 static sal_Unicode
const aHGPMinchoL
[] = { 'h','g','p', 0x660E, 0x671D, 'l', 0 };
352 static sal_Unicode
const aHGPGothicB
[] = { 'h','g','p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 0 };
353 static sal_Unicode
const aHGMinchoLSun
[] = { 'h','g', 0x660E, 0x671D, 'l', 's', 'u', 'n', 0 };
354 static sal_Unicode
const aHGPMinchoLSun
[] = { 'h','g','p', 0x660E, 0x671D, 'l', 's', 'u', 'n', 0 };
355 static sal_Unicode
const aHGGothicBSun
[] = { 'h', 'g', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 's', 'u', 'n', 0 };
356 static sal_Unicode
const aHGPGothicBSun
[] = { 'h', 'g', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 'b', 's', 'u', 'n', 0 };
357 static sal_Unicode
const aHGHeiseiMin
[] = { 'h', 'g', 0x5E73, 0x6210, 0x660E, 0x671D, 0x4F53, 0, 'h', 'g', 0x5E73, 0x6210, 0x660E, 0x671D, 0x4F53, 'w', '3', 'x', '1', '2', 0, 0 };
358 static sal_Unicode
const aIPAMincho
[] = { 'i', 'p', 'a', 0x660E, 0x671D, 0 };
359 static sal_Unicode
const aIPAPMincho
[] = { 'i', 'p', 'a', 'p', 0x660E, 0x671D, 0 };
360 static sal_Unicode
const aIPAGothic
[] = { 'i', 'p', 'a', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
361 static sal_Unicode
const aIPAPGothic
[] = { 'i', 'p', 'a', 'p', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
362 static sal_Unicode
const aIPAUIGothic
[] = { 'i', 'p', 'a', 'u', 'i', 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0 };
363 static sal_Unicode
const aSazanamiMincho
[] = { 0x3055, 0x3056, 0x306A, 0x307F, 0x660E, 0x671D, 0, 0 };
364 static sal_Unicode
const aSazanamiGothic
[] = { 0x3055, 0x3056, 0x306A, 0x307F, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 };
365 static sal_Unicode
const aKochiMincho
[] = { 0x6771, 0x98A8, 0x660E, 0x671D, 0, 0 };
366 static sal_Unicode
const aKochiGothic
[] = { 0x6771, 0x98A8, 0x30B4, 0x30B7, 0x30C3, 0x30AF, 0, 0 };
367 static sal_Unicode
const aSunDotum
[] = { 0xC36C, 0xB3CB, 0xC6C0, 0, 0 };
368 static sal_Unicode
const aSunGulim
[] = { 0xC36C, 0xAD74, 0xB9BC, 0, 0 };
369 static sal_Unicode
const aSunBatang
[] = { 0xC36C, 0xBC14, 0xD0D5, 0, 0 };
370 static sal_Unicode
const aBaekmukDotum
[] = { 0xBC31, 0xBB35, 0xB3CB, 0xC6C0, 0, 0 };
371 static sal_Unicode
const aBaekmukGulim
[] = { 0xBC31, 0xBB35, 0xAD74, 0xB9BC, 0, 0 };
372 static sal_Unicode
const aBaekmukBatang
[] = { 0xBC31, 0xBB35, 0xBC14, 0xD0D5, 0, 0 };
373 static sal_Unicode
const aFzMingTi
[] = { 0x65B9, 0x6B63, 0x660E, 0x9AD4, 0, 0 };
374 static sal_Unicode
const aFzHeiTiTW
[]= { 0x65B9, 0x6B63, 0x9ED1, 0x9AD4, 0, 0 };
375 static sal_Unicode
const aFzKaiTiTW
[]= { 0x65B9, 0x6B63, 0x6977, 0x9AD4, 0, 0 };
376 static sal_Unicode
const aFzHeiTiCN
[]= { 0x65B9, 0x6B63, 0x9ED1, 0x4F53, 0, 0 };
377 static sal_Unicode
const aFzKaiTiCN
[]= { 0x65B9, 0x6B63, 0x6977, 0x4F53, 0, 0 };
378 static sal_Unicode
const aFzSongTi
[] = { 0x65B9, 0x6B63, 0x5B8B, 0x4F53, 0, 0 };
379 static sal_Unicode
const aHYMyeongJoExtra
[] = { 'h', 'y', 0xACAC, 0xBA85, 0xC870, 0, 0 };
380 static sal_Unicode
const aHYSinMyeongJoMedium
[] = { 'h', 'y', 0xC2E0, 0xBA85, 0xC870, 0, 0 };
381 static sal_Unicode
const aHYGothicMedium
[] = { 'h', 'y', 0xC911, 0xACE0, 0xB515, 0, 0 };
382 static sal_Unicode
const aHYGraphicMedium
[] = { 'h', 'y', 0xADF8, 0xB798, 0xD53D, 'm', 0, 0 };
383 static sal_Unicode
const aHYGraphic
[] = { 'h', 'y', 0xADF8, 0xB798, 0xD53D, 0, 0 };
384 static sal_Unicode
const aNewGulim
[] = { 0xC0C8, 0xAD74, 0xB9BC, 0, 0 };
385 static sal_Unicode
const aSunGungseo
[] = { 0xC36C, 0xAD81, 0xC11C, 0, 0 };
386 static sal_Unicode
const aHYGungSoBold
[] = { 'h','y', 0xAD81, 0xC11C, 'b', 0, 0 };
387 static sal_Unicode
const aHYGungSo
[] = { 'h','y', 0xAD81, 0xC11C, 0, 0 };
388 static sal_Unicode
const aSunHeadLine
[] = { 0xC36C, 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 0, 0 };
389 static sal_Unicode
const aHYHeadLineMedium
[] = { 'h', 'y', 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 'm', 0, 0 };
390 static sal_Unicode
const aHYHeadLine
[] = { 'h', 'y', 0xD5E4, 0xB4DC, 0xB77C, 0xC778, 0, 0 };
391 static sal_Unicode
const aYetR
[] = { 0xD734, 0xBA3C, 0xC61B, 0xCCB4, 0, 0 };
392 static sal_Unicode
const aHYGothicExtra
[] = { 'h', 'y', 0xACAC, 0xACE0, 0xB515, 0, 0 };
393 static sal_Unicode
const aSunMokPan
[] = { 0xC36C, 0xBAA9, 0xD310, 0, 0 };
394 static sal_Unicode
const aSunYeopseo
[] = { 0xC36C, 0xC5FD, 0xC11C, 0, 0 };
395 static sal_Unicode
const aSunBaekSong
[] = { 0xC36C, 0xBC31, 0xC1A1, 0, 0 };
396 static sal_Unicode
const aHYPostLight
[] = { 'h', 'y', 0xC5FD, 0xC11C, 'l', 0, 0 };
397 static sal_Unicode
const aHYPost
[] = { 'h', 'y', 0xC5FD, 0xC11C, 0, 0 };
398 static sal_Unicode
const aMagicR
[] = { 0xD734, 0xBA3C, 0xB9E4, 0xC9C1, 0xCCB4, 0, 0 };
399 static sal_Unicode
const aSunCrystal
[] = { 0xC36C, 0xD06C, 0xB9AC, 0xC2A4, 0xD0C8, 0, 0 };
400 static sal_Unicode
const aSunSaemmul
[] = { 0xC36C, 0xC0D8, 0xBB3C, 0, 0 };
401 static sal_Unicode
const aHaansoftBatang
[] = { 0xD55C, 0xCEF4, 0xBC14, 0xD0D5, 0, 0 };
402 static sal_Unicode
const aHaansoftDotum
[] = { 0xD55C, 0xCEF4, 0xB3CB, 0xC6C0, 0, 0 };
403 static sal_Unicode
const aHyhaeseo
[] = { 0xD55C, 0xC591, 0xD574, 0xC11C, 0, 0 };
404 static sal_Unicode
const aMDSol
[] = { 'm', 'd', 0xC194, 0xCCB4, 0, 0 };
405 static sal_Unicode
const aMDGaesung
[] = { 'm', 'd', 0xAC1C, 0xC131, 0xCCB4, 0, 0 };
406 static sal_Unicode
const aMDArt
[] = { 'm', 'd', 0xC544, 0xD2B8, 0xCCB4, 0, 0 };
407 static sal_Unicode
const aMDAlong
[] = { 'm', 'd', 0xC544, 0xB871, 0xCCB4, 0, 0 };
408 static sal_Unicode
const aMDEasop
[] = { 'm', 'd', 0xC774, 0xC19D, 0xCCB4, 0, 0 };
409 static sal_Unicode
const aHYShortSamulMedium
[] = { 'h', 'y', 0xC595, 0xC740, 0xC0D8, 0xBB3C, 'm', 0 };
410 static sal_Unicode
const aHYShortSamul
[] = { 'h', 'y', 0xC595, 0xC740, 0xC0D8, 0xBB3C, 0 };
411 static sal_Unicode
const aHGGothicE
[] = { 'h','g', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
412 static sal_Unicode
const aHGPGothicE
[] = { 'h','g','p', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
413 static sal_Unicode
const aHGSGothicE
[] = { 'h','g','s', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'e', 0 };
414 static sal_Unicode
const aHGGothicM
[] = { 'h','g', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
415 static sal_Unicode
const aHGPGothicM
[] = { 'h','g','p', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
416 static sal_Unicode
const aHGSGothicM
[] = { 'h','g','s', 0xFF7A, 0xFF9E, 0xFF7C, 0xFF6F, 0xFF78, 'm', 0 };
417 static sal_Unicode
const aHGGyoshotai
[] = { 'h','g', 0x884C, 0x66F8, 0x4F53, 0 };
418 static sal_Unicode
const aHGPGyoshotai
[] = { 'h','g','p', 0x884C, 0x66F8, 0x4F53, 0 };
419 static sal_Unicode
const aHGSGyoshotai
[] = { 'h','g','s', 0x884C, 0x66F8, 0x4F53, 0 };
420 static sal_Unicode
const aHGKyokashotai
[] = { 'h','g', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
421 static sal_Unicode
const aHGPKyokashotai
[] = { 'h','g','p', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
422 static sal_Unicode
const aHGSKyokashotai
[] = { 'h','g','s', 0x6559, 0x79D1, 0x66F8, 0x4F53, 0 };
423 static sal_Unicode
const aHGMinchoB
[] = { 'h','g', 0x660E, 0x671D, 'b', 0 };
424 static sal_Unicode
const aHGPMinchoB
[] = { 'h','g','p', 0x660E, 0x671D, 'b', 0 };
425 static sal_Unicode
const aHGSMinchoB
[] = { 'h','g','s', 0x660E, 0x671D, 'b', 0 };
426 static sal_Unicode
const aHGMinchoE
[] = { 'h','g', 0x660E, 0x671D, 'e', 0 };
427 static sal_Unicode
const aHGPMinchoE
[] = { 'h','g','p', 0x660E, 0x671D, 'e', 0 };
428 static sal_Unicode
const aHGSMinchoE
[] = { 'h','g','s', 0x660E, 0x671D, 'e', 0 };
429 static sal_Unicode
const aHGSoeiKakupoptai
[] = { 'h','g', 0x5275,0x82F1,0x89D2,0xFF8E,
430 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
431 static sal_Unicode
const aHGPSoeiKakupoptai
[] = { 'h','g', 'p', 0x5275,0x82F1,0x89D2,0xFF8E,
432 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
433 static sal_Unicode
const aHGSSoeiKakupoptai
[] = { 'h','g', 's', 0x5275,0x82F1,0x89D2,0xFF8E,
434 0xFF9F,0xFF6F,0xFF8C,0xFF9F,0x4F53,0};
435 static sal_Unicode
const aHGSoeiPresenceEB
[] = { 'h','g', 0x5275,0x82F1,0xFF8C,0xFF9F,
436 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
437 static sal_Unicode
const aHGPSoeiPresenceEB
[] = { 'h','g','p', 0x5275,0x82F1,0xFF8C,0xFF9F,
438 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
439 static sal_Unicode
const aHGSSoeiPresenceEB
[] = { 'h','g','s', 0x5275,0x82F1,0xFF8C,0xFF9F,
440 0xFF9A,0xFF7E,0xFF9E,0xFF9D,0xFF7D, 'e','b',0};
441 static sal_Unicode
const aHGSoeiKakugothicUB
[] = { 'h','g', 0x5275,0x82F1,0x89D2,0xFF7A,
442 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
443 static sal_Unicode
const aHGPSoeiKakugothicUB
[] = { 'h','g','p', 0x5275,0x82F1,0x89D2,0xFF7A,
444 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
445 static sal_Unicode
const aHGSSoeiKakugothicUB
[] = { 'h','g','s', 0x5275,0x82F1,0x89D2,0xFF7A,
446 0xFF9E,0xFF7C,0xFF6F,0xFF78,'u','b',0};
447 static sal_Unicode
const aHGSeikaishotaiPRO
[] = { 'h','g', 0x6B63,0x6977,0x66F8,0x4F53, '-','p','r','o',0};
448 static sal_Unicode
const aHGMaruGothicMPRO
[] = { 'h','g', 0x4E38,0xFF7A,0xFF9E,0xFF7C,0xFF6F,0xFF78, '-','p','r','o',0};
449 static sal_Unicode
const aHiraginoMinchoPro
[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x660E, 0x671D, 'p','r','o',0};
450 static sal_Unicode
const aHiraginoMinchoProN
[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x660E, 0x671D, 'p','r','o','n',0};
451 static sal_Unicode
const aHiraginoKakuGothicPro
[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 'p','r','o',0};
452 static sal_Unicode
const aHiraginoKakuGothicProN
[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x89D2, 0x30B4, 'p','r','o','n',0};
453 static sal_Unicode
const aHiraginoMaruGothicPro
[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x4E38, 0x30B4, 'p','r','o',0};
454 static sal_Unicode
const aHiraginoMaruGothicProN
[] = { 0x30D2, 0x30E9, 0x30AE, 0x30CE, 0x4E38, 0x30B4, 'p','r','o','n',0};
457 static ImplLocalizedFontName aImplLocalizedNamesList
[] =
459 { "batang", aBatang
},
460 { "batangche", aBatangChe
},
461 { "gungshu", aGungsuh
},
462 { "gungshuche", aGungsuhChe
},
464 { "gulimche", aGulimChe
},
466 { "dotumche", aDotumChe
},
467 { "simsun", aSimSun
},
468 { "nsimsun", aNSimSun
},
469 { "simhei", aSimHei
},
470 { "simkai", aSimKai
},
471 { "zycjksun", azycjkSun
},
472 { "zycjkhei", azycjkHei
},
473 { "zycjkkai", azycjkKai
},
476 { "fzsong", aFZSongYI
},
477 { "fzshusong", aFZShuSong
},
478 { "fzfangsong", aFZFangSong
},
482 { "cfangsong", aCFangSong
},
483 { "mingliu", aMingLiU
},
484 { "pmingliu", aPMingLiU
},
488 { "msgothic", aMSGothic
},
489 { "mspgothic", aMSPGothic
},
490 { "msmincho", aMSMincho
},
491 { "mspmincho", aMSPMincho
},
492 { "meiryo", aMeiryo
},
493 { "hgminchol", aHGMinchoL
},
494 { "hggothicb", aHGGothicB
},
495 { "hgpminchol", aHGPMinchoL
},
496 { "hgpgothicb", aHGPGothicB
},
497 { "hgmincholsun", aHGMinchoLSun
},
498 { "hggothicbsun", aHGGothicBSun
},
499 { "hgpmincholsun", aHGPMinchoLSun
},
500 { "hgpgothicbsun", aHGPGothicBSun
},
501 { "hgheiseimin", aHGHeiseiMin
},
502 { "ipamincho", aIPAMincho
},
503 { "ipapmincho", aIPAPMincho
},
504 { "ipagothic", aIPAGothic
},
505 { "ipapgothic", aIPAPGothic
},
506 { "ipauigothic", aIPAUIGothic
},
507 { "sazanamimincho", aSazanamiMincho
},
508 { "sazanamigothic", aSazanamiGothic
},
509 { "kochimincho", aKochiMincho
},
510 { "kochigothic", aKochiGothic
},
511 { "sundotum", aSunDotum
},
512 { "sungulim", aSunGulim
},
513 { "sunbatang", aSunBatang
},
514 { "baekmukdotum", aBaekmukDotum
},
515 { "baekmukgulim", aBaekmukGulim
},
516 { "baekmukbatang", aBaekmukBatang
},
517 { "fzheiti", aFzHeiTiCN
},
518 { "fzheiti", aFzHeiTiTW
},
519 { "fzkaiti", aFzKaiTiCN
},
520 { "fzkaitib", aFzKaiTiTW
},
521 { "fzmingtib", aFzMingTi
},
522 { "fzsongti", aFzSongTi
},
523 { "hymyeongjoextra", aHYMyeongJoExtra
},
524 { "hysinmyeongjomedium", aHYSinMyeongJoMedium
},
525 { "hygothicmedium", aHYGothicMedium
},
526 { "hygraphicmedium", aHYGraphicMedium
},
527 { "hygraphic", aHYGraphic
},
528 { "newgulim", aNewGulim
},
529 { "sungungseo", aSunGungseo
},
530 { "hygungsobold", aHYGungSoBold
},
531 { "hygungso", aHYGungSo
},
532 { "sunheadline", aSunHeadLine
},
533 { "hyheadlinemedium", aHYHeadLineMedium
},
534 { "hyheadline", aHYHeadLine
},
536 { "hygothicextra", aHYGothicExtra
},
537 { "sunmokpan", aSunMokPan
},
538 { "sunyeopseo", aSunYeopseo
},
539 { "sunbaeksong", aSunBaekSong
},
540 { "hypostlight", aHYPostLight
},
541 { "hypost", aHYPost
},
542 { "magicr", aMagicR
},
543 { "suncrystal", aSunCrystal
},
544 { "sunsaemmul", aSunSaemmul
},
545 { "hyshortsamulmedium", aHYShortSamulMedium
},
546 { "hyshortsamul", aHYShortSamul
},
547 { "haansoftbatang", aHaansoftBatang
},
548 { "haansoftdotum", aHaansoftDotum
},
549 { "hyhaeseo", aHyhaeseo
},
551 { "mdgaesung", aMDGaesung
},
553 { "mdalong", aMDAlong
},
554 { "mdeasop", aMDEasop
},
555 { "hggothice", aHGGothicE
},
556 { "hgpgothice", aHGPGothicE
},
557 { "hgpothice", aHGSGothicE
},
558 { "hggothicm", aHGGothicM
},
559 { "hgpgothicm", aHGPGothicM
},
560 { "hgpgothicm", aHGSGothicM
},
561 { "hggyoshotai", aHGGyoshotai
},
562 { "hgpgyoshotai", aHGPGyoshotai
},
563 { "hgsgyoshotai", aHGSGyoshotai
},
564 { "hgkyokashotai", aHGKyokashotai
},
565 { "hgpkyokashotai", aHGPKyokashotai
},
566 { "hgskyokashotai", aHGSKyokashotai
},
567 { "hgminchob", aHGMinchoB
},
568 { "hgpminchob", aHGPMinchoB
},
569 { "hgsminchob", aHGSMinchoB
},
570 { "hgminchoe", aHGMinchoE
},
571 { "hgpminchoe", aHGPMinchoE
},
572 { "hgsminchoe", aHGSMinchoE
},
573 { "hgsoeikakupoptai", aHGSoeiKakupoptai
},
574 { "hgpsoeikakupopta", aHGPSoeiKakupoptai
},
575 { "hgssoeikakupopta", aHGSSoeiKakupoptai
},
576 { "hgsoeipresenceeb", aHGSoeiPresenceEB
},
577 { "hgpsoeipresenceeb", aHGPSoeiPresenceEB
},
578 { "hgssoeipresenceeb", aHGSSoeiPresenceEB
},
579 { "hgsoeikakugothicub", aHGSoeiKakugothicUB
},
580 { "hgpsoeikakugothicub", aHGPSoeiKakugothicUB
},
581 { "hgssoeikakugothicub", aHGSSoeiKakugothicUB
},
582 { "hgseikaishotaipro", aHGSeikaishotaiPRO
},
583 { "hgmarugothicmpro", aHGMaruGothicMPRO
},
584 { "hiraginominchopro", aHiraginoMinchoPro
},
585 { "hiraginominchopron", aHiraginoMinchoProN
},
586 { "hiraginokakugothicpro", aHiraginoKakuGothicPro
},
587 { "hiraginokakugothicpron", aHiraginoKakuGothicProN
},
588 { "hiraginomarugothicpro", aHiraginoMaruGothicPro
},
589 { "hiraginomarugothicpron", aHiraginoMaruGothicProN
},
593 // -----------------------------------------------------------------------
595 void ImplGetEnglishSearchFontName( String
& rName
)
597 bool bNeedTranslation
= false;
598 xub_StrLen nLen
= rName
.Len();
600 // Remove trailing whitespaces
602 while ( i
&& (rName
.GetChar( i
-1 ) < 32) )
607 // Remove Script at the end
608 // Scriptname must be the last part of the fontname and
609 // looks like "fontname (scriptname)". So there can only be a
610 // script name at the and of the fontname, when the last char is ')'
611 if ( (nLen
>= 3) && rName
.GetChar( nLen
-1 ) == ')' )
614 xub_StrLen nTempLen
= nLen
-2;
617 if ( rName
.GetChar( nTempLen
) == '(' )
622 // Remove Space at the end
623 if ( nTempLen
&& (rName
.GetChar( nTempLen
-1 ) == ' ') )
625 rName
.Erase( nTempLen
);
630 if ( rName
.GetChar( nTempLen
) == ')' )
636 // remove all whitespaces and converts to lower case ASCII
637 // TODO: better transliteration to ASCII e.g. all digits
641 sal_Unicode c
= rName
.GetChar( i
);
644 // Translate to Lowercase-ASCII
645 // FullWidth-ASCII to half ASCII
646 if ( (c
>= 0xFF00) && (c
<= 0xFF5E) )
650 if ( (c
>= 'A') && (c
<= 'Z') )
652 rName
.SetChar( i
, c
);
656 // Only Fontnames with None-Ascii-Characters must be translated
657 bNeedTranslation
= true;
660 // not lowercase Ascii
661 else if ( !((c
>= 'a') && (c
<= 'z')) )
663 // To Lowercase-Ascii
664 if ( (c
>= 'A') && (c
<= 'Z') )
667 rName
.SetChar( i
, c
);
669 else if( ((c
< '0') || (c
> '9')) && (c
!= ';') ) // not 0-9 or semicolon
671 // Remove white spaces and special characters
681 // translate normalized localized name to its normalized English ASCII name
682 if( bNeedTranslation
)
684 typedef std::hash_map
<const String
, const char*,FontNameHash
> FontNameDictionary
;
685 static FontNameDictionary
aDictionary( sizeof(aImplLocalizedNamesList
) / sizeof(*aImplLocalizedNamesList
) );
686 // the font name dictionary needs to be intialized once
687 if( aDictionary
.empty() )
689 // TODO: check if all dictionary entries are already normalized?
690 const ImplLocalizedFontName
* pList
= aImplLocalizedNamesList
;
691 for(; pList
->mpEnglishName
; ++pList
)
692 aDictionary
[ pList
->mpLocalizedNames
] = pList
->mpEnglishName
;
695 FontNameDictionary::const_iterator it
= aDictionary
.find( rName
);
696 if( it
!= aDictionary
.end() )
697 rName
.AssignAscii( it
->second
);
701 // -----------------------------------------------------------------------
703 static String
GetNextFontToken( const String
& rTokenStr
, xub_StrLen
& rIndex
)
705 // check for valid start index
706 int nStringLen
= rTokenStr
.Len();
707 if( rIndex
>= nStringLen
)
709 rIndex
= STRING_NOTFOUND
;
713 // find the next token delimiter and return the token substring
714 const sal_Unicode
* pStr
= rTokenStr
.GetBuffer() + rIndex
;
715 const sal_Unicode
* pEnd
= rTokenStr
.GetBuffer() + nStringLen
;
716 for(; pStr
< pEnd
; ++pStr
)
717 if( (*pStr
== ';') || (*pStr
== ',') )
720 xub_StrLen nTokenStart
= rIndex
;
721 xub_StrLen nTokenLen
;
724 rIndex
= sal::static_int_cast
<xub_StrLen
>(pStr
- rTokenStr
.GetBuffer());
725 nTokenLen
= rIndex
- nTokenStart
;
726 ++rIndex
; // skip over token separator
730 // no token delimiter found => handle last token
731 rIndex
= STRING_NOTFOUND
;
732 nTokenLen
= STRING_LEN
;
734 // optimize if the token string consists of just one token
739 return String( rTokenStr
, nTokenStart
, nTokenLen
);
742 // TODO: get rid of this in another incompatible build with SW project.
743 // SW's WW8 and RTF filters still use this (from fontcvt.hxx)
744 String
GetFontToken( const String
& rTokenStr
, xub_StrLen nToken
, xub_StrLen
& rIndex
)
746 // skip nToken Tokens
747 for( xub_StrLen i
= 0; (i
< nToken
) && (rIndex
!= STRING_NOTFOUND
); ++i
)
748 GetNextFontToken( rTokenStr
, rIndex
);
750 return GetNextFontToken( rTokenStr
, rIndex
);
753 // =======================================================================
755 // TODO: remove this method when the CWS-gfbfcfg dust has settled
756 void ImplFreeOutDevFontData()
759 // =======================================================================
761 void OutputDevice::BeginFontSubstitution()
763 ImplSVData
* pSVData
= ImplGetSVData();
764 pSVData
->maGDIData
.mbFontSubChanged
= FALSE
;
767 // -----------------------------------------------------------------------
769 void OutputDevice::EndFontSubstitution()
771 ImplSVData
* pSVData
= ImplGetSVData();
772 if ( pSVData
->maGDIData
.mbFontSubChanged
)
774 ImplUpdateAllFontData( false );
776 Application
* pApp
= GetpApp();
777 DataChangedEvent
aDCEvt( DATACHANGED_FONTSUBSTITUTION
);
778 pApp
->DataChanged( aDCEvt
);
779 pApp
->NotifyAllWindows( aDCEvt
);
780 pSVData
->maGDIData
.mbFontSubChanged
= FALSE
;
784 // -----------------------------------------------------------------------
786 void OutputDevice::AddFontSubstitute( const XubString
& rFontName
,
787 const XubString
& rReplaceFontName
,
790 ImplDirectFontSubstitution
*& rpSubst
= ImplGetSVData()->maGDIData
.mpDirectFontSubst
;
792 rpSubst
= new ImplDirectFontSubstitution();
793 rpSubst
->AddFontSubstitute( rFontName
, rReplaceFontName
, nFlags
);
794 ImplGetSVData()->maGDIData
.mbFontSubChanged
= TRUE
;
797 // -----------------------------------------------------------------------
799 void ImplDirectFontSubstitution::AddFontSubstitute( const String
& rFontName
,
800 const String
& rSubstFontName
, USHORT nFlags
)
802 maFontSubstList
.push_back( ImplFontSubstEntry( rFontName
, rSubstFontName
, nFlags
) );
805 // -----------------------------------------------------------------------
807 ImplFontSubstEntry::ImplFontSubstEntry( const String
& rFontName
,
808 const String
& rSubstFontName
, USHORT nSubstFlags
)
809 : maName( rFontName
)
810 , maReplaceName( rSubstFontName
)
811 , mnFlags( nSubstFlags
)
813 maSearchName
= rFontName
;
814 maSearchReplaceName
= rSubstFontName
;
815 ImplGetEnglishSearchFontName( maSearchName
);
816 ImplGetEnglishSearchFontName( maSearchReplaceName
);
819 // -----------------------------------------------------------------------
821 void OutputDevice::ImplAddDevFontSubstitute( const XubString
& rFontName
,
822 const XubString
& rReplaceFontName
,
825 ImplInitOutDevData();
826 mpOutDevData
->maDevFontSubst
.AddFontSubstitute( rFontName
, rReplaceFontName
, nFlags
);
829 // -----------------------------------------------------------------------
831 void OutputDevice::RemoveFontSubstitute( USHORT n
)
833 ImplDirectFontSubstitution
* pSubst
= ImplGetSVData()->maGDIData
.mpDirectFontSubst
;
835 pSubst
->RemoveFontSubstitute( n
);
838 // -----------------------------------------------------------------------
840 void ImplDirectFontSubstitution::RemoveFontSubstitute( int nIndex
)
842 FontSubstList::iterator it
= maFontSubstList
.begin();
843 for( int nCount
= 0; (it
!= maFontSubstList
.end()) && (nCount
++ != nIndex
); ++it
) ;
844 if( it
!= maFontSubstList
.end() )
845 maFontSubstList
.erase( it
);
848 // -----------------------------------------------------------------------
850 USHORT
OutputDevice::GetFontSubstituteCount()
852 const ImplDirectFontSubstitution
* pSubst
= ImplGetSVData()->maGDIData
.mpDirectFontSubst
;
855 int nCount
= pSubst
->GetFontSubstituteCount();
856 return (USHORT
)nCount
;
859 // -----------------------------------------------------------------------
861 void OutputDevice::GetFontSubstitute( USHORT n
,
862 XubString
& rFontName
,
863 XubString
& rReplaceFontName
,
866 const ImplDirectFontSubstitution
* pSubst
= ImplGetSVData()->maGDIData
.mpDirectFontSubst
;
868 pSubst
->GetFontSubstitute( n
, rFontName
, rReplaceFontName
, rFlags
);
871 // -----------------------------------------------------------------------
873 bool ImplDirectFontSubstitution::GetFontSubstitute( int nIndex
,
874 String
& rFontName
, String
& rSubstFontName
, USHORT
& rFlags
) const
876 FontSubstList::const_iterator it
= maFontSubstList
.begin();
877 for( int nCount
= 0; (it
!= maFontSubstList
.end()) && (nCount
++ != nIndex
); ++it
) ;
878 if( it
== maFontSubstList
.end() )
881 const ImplFontSubstEntry
* pEntry
= &(*it
);
882 rFontName
= pEntry
->maName
;
883 rSubstFontName
= pEntry
->maReplaceName
;
884 rFlags
= pEntry
->mnFlags
;
888 // -----------------------------------------------------------------------
890 bool ImplDirectFontSubstitution::FindFontSubstitute( String
& rSubstName
,
891 const String
& rSearchName
, USHORT nFlags
) const
893 // TODO: get rid of O(N) searches
894 FontSubstList::const_iterator it
= maFontSubstList
.begin();
895 for(; it
!= maFontSubstList
.end(); ++it
)
897 const ImplFontSubstEntry
& rEntry
= *it
;
898 if( ((rEntry
.mnFlags
& nFlags
) || !nFlags
)
899 && (rEntry
.maSearchName
== rSearchName
) )
901 rSubstName
= rEntry
.maSearchReplaceName
;
909 // -----------------------------------------------------------------------
911 static void ImplFontSubstitute( String
& rFontName
,
912 USHORT nFlags
, ImplDirectFontSubstitution
* pDevSpecific
)
915 String aTempName
= rFontName
;
916 ImplGetEnglishSearchFontName( aTempName
);
917 DBG_ASSERT( aTempName
== rFontName
, "ImplFontSubstitute() called without a searchname" );
920 String aSubstFontName
;
922 // apply user-configurable font replacement (eg, from the list in Tools->Options)
923 const ImplDirectFontSubstitution
* pSubst
= ImplGetSVData()->maGDIData
.mpDirectFontSubst
;
924 if( pSubst
&& pSubst
->FindFontSubstitute( aSubstFontName
, rFontName
, FONT_SUBSTITUTE_ALWAYS
) )
926 rFontName
= aSubstFontName
;
930 // apply device specific font replacement (e.g. to use printer builtin fonts)
934 if( pDevSpecific
->FindFontSubstitute( aSubstFontName
, rFontName
, nFlags
) )
936 rFontName
= aSubstFontName
;
941 // =======================================================================
943 static bool ImplIsFontToken( const String
& rName
, const String
& rToken
)
946 xub_StrLen nIndex
= 0;
949 aTempName
= GetNextFontToken( rName
, nIndex
);
950 if ( rToken
== aTempName
)
953 while ( nIndex
!= STRING_NOTFOUND
);
958 // -----------------------------------------------------------------------
960 static void ImplAppendFontToken( String
& rName
, const String
& rNewToken
)
965 rName
.Append( rNewToken
);
971 // -----------------------------------------------------------------------
973 static void ImplAddTokenFontName( String
& rName
, const String
& rNewToken
)
975 if ( !ImplIsFontToken( rName
, rNewToken
) )
976 ImplAppendFontToken( rName
, rNewToken
);
979 // -----------------------------------------------------------------------
981 Font
OutputDevice::GetDefaultFont( USHORT nType
, LanguageType eLang
,
982 ULONG nFlags
, const OutputDevice
* pOutDev
)
984 DBG_TRACE( "OutputDevice::GetDefaultFont()" );
986 com::sun::star::lang::Locale aLocale
;
987 if( eLang
== LANGUAGE_NONE
|| eLang
== LANGUAGE_SYSTEM
|| eLang
== LANGUAGE_DONTKNOW
)
989 aLocale
= Application::GetSettings().GetUILocale();
993 MsLangId::convertLanguageToLocale( eLang
, aLocale
);
996 DefaultFontConfiguration
& rDefaults
= *DefaultFontConfiguration::get();
997 String aSearch
= rDefaults
.getUserInterfaceFont( aLocale
); // ensure a fallback
998 String aDefault
= rDefaults
.getDefaultFont( aLocale
, nType
);
1002 int nDefaultHeight
= 12;
1005 aFont
.SetPitch( PITCH_VARIABLE
);
1009 case DEFAULTFONT_SANS_UNICODE
:
1010 case DEFAULTFONT_UI_SANS
:
1011 aFont
.SetFamily( FAMILY_SWISS
);
1014 case DEFAULTFONT_SANS
:
1015 case DEFAULTFONT_LATIN_HEADING
:
1016 case DEFAULTFONT_LATIN_SPREADSHEET
:
1017 case DEFAULTFONT_LATIN_DISPLAY
:
1018 aFont
.SetFamily( FAMILY_SWISS
);
1021 case DEFAULTFONT_SERIF
:
1022 case DEFAULTFONT_LATIN_TEXT
:
1023 case DEFAULTFONT_LATIN_PRESENTATION
:
1024 aFont
.SetFamily( FAMILY_ROMAN
);
1027 case DEFAULTFONT_FIXED
:
1028 case DEFAULTFONT_LATIN_FIXED
:
1029 case DEFAULTFONT_UI_FIXED
:
1030 aFont
.SetPitch( PITCH_FIXED
);
1031 aFont
.SetFamily( FAMILY_MODERN
);
1034 case DEFAULTFONT_SYMBOL
:
1035 aFont
.SetCharSet( RTL_TEXTENCODING_SYMBOL
);
1038 case DEFAULTFONT_CJK_TEXT
:
1039 case DEFAULTFONT_CJK_PRESENTATION
:
1040 case DEFAULTFONT_CJK_SPREADSHEET
:
1041 case DEFAULTFONT_CJK_HEADING
:
1042 case DEFAULTFONT_CJK_DISPLAY
:
1043 aFont
.SetFamily( FAMILY_SYSTEM
); // don't care, but don't use font subst config later...
1046 case DEFAULTFONT_CTL_TEXT
:
1047 case DEFAULTFONT_CTL_PRESENTATION
:
1048 case DEFAULTFONT_CTL_SPREADSHEET
:
1049 case DEFAULTFONT_CTL_HEADING
:
1050 case DEFAULTFONT_CTL_DISPLAY
:
1051 aFont
.SetFamily( FAMILY_SYSTEM
); // don't care, but don't use font subst config later...
1055 if ( aSearch
.Len() )
1057 aFont
.SetHeight( nDefaultHeight
);
1058 aFont
.SetWeight( WEIGHT_NORMAL
);
1060 if ( aFont
.GetCharSet() == RTL_TEXTENCODING_DONTKNOW
)
1061 aFont
.SetCharSet( gsl_getSystemTextEncoding() );
1063 // Should we only return available fonts on the given device
1066 pOutDev
->ImplInitFontList();
1068 // Search Font in the FontList
1071 xub_StrLen nIndex
= 0;
1074 aSearchName
= GetNextFontToken( aSearch
, nIndex
);
1075 ImplGetEnglishSearchFontName( aSearchName
);
1076 ImplDevFontListData
* pFontFamily
= pOutDev
->mpFontList
->ImplFindBySearchName( aSearchName
);
1079 ImplAddTokenFontName( aName
, pFontFamily
->GetFamilyName() );
1080 if( nFlags
& DEFAULTFONT_FLAGS_ONLYONE
)
1084 while ( nIndex
!= STRING_NOTFOUND
);
1085 aFont
.SetName( aName
);
1088 // No Name, than set all names
1089 if ( !aFont
.GetName().Len() )
1091 xub_StrLen nIndex
= 0;
1092 if ( nFlags
& DEFAULTFONT_FLAGS_ONLYONE
)
1094 //aFont.SetName( aSearch.GetToken( 0, ';', nIndex ) );
1096 pOutDev
= (const OutputDevice
*)ImplGetSVData()->mpDefaultWin
;
1098 aFont
.SetName( aSearch
.GetToken( 0, ';', nIndex
) );
1101 pOutDev
->ImplInitFontList();
1103 aFont
.SetName( aSearch
);
1105 // convert to pixel height
1106 Size aSize
= pOutDev
->ImplLogicToDevicePixel( aFont
.GetSize() );
1107 if ( !aSize
.Height() )
1109 // use default pixel height only when logical height is zero
1110 if ( aFont
.GetHeight() )
1113 aSize
.Height() = (12*pOutDev
->mnDPIY
)/72;
1116 // use default width only when logical width is zero
1117 if( (0 == aSize
.Width()) && (0 != aFont
.GetSize().Width()) )
1120 // get the name of the first available font
1121 float fExactHeight
= static_cast<float>(aSize
.Height());
1122 ImplFontEntry
* pEntry
= pOutDev
->mpFontCache
->GetFontEntry( pOutDev
->mpFontList
, aFont
, aSize
, fExactHeight
, pOutDev
->mpOutDevData
? &pOutDev
->mpOutDevData
->maDevFontSubst
: NULL
);
1123 if( pEntry
->maFontSelData
.mpFontData
)
1124 aFont
.SetName( pEntry
->maFontSelData
.mpFontData
->maName
);
1126 aFont
.SetName( pEntry
->maFontSelData
.maTargetName
);
1130 aFont
.SetName( aSearch
);
1134 #if OSL_DEBUG_LEVEL > 2
1135 const char* s
= "DEFAULTFONT_SANS_UNKNOWN";
1138 case DEFAULTFONT_SANS_UNICODE
: s
= "DEFAULTFONT_SANS_UNICODE"; break;
1139 case DEFAULTFONT_UI_SANS
: s
= "DEFAULTFONT_UI_SANS"; break;
1141 case DEFAULTFONT_SANS
: s
= "DEFAULTFONT_SANS"; break;
1142 case DEFAULTFONT_LATIN_HEADING
: s
= "DEFAULTFONT_LATIN_HEADING"; break;
1143 case DEFAULTFONT_LATIN_SPREADSHEET
: s
= "DEFAULTFONT_LATIN_SPREADSHEET"; break;
1144 case DEFAULTFONT_LATIN_DISPLAY
: s
= "DEFAULTFONT_LATIN_DISPLAY"; break;
1146 case DEFAULTFONT_SERIF
: s
= "DEFAULTFONT_SERIF"; break;
1147 case DEFAULTFONT_LATIN_TEXT
: s
= "DEFAULTFONT_LATIN_TEXT"; break;
1148 case DEFAULTFONT_LATIN_PRESENTATION
: s
= "DEFAULTFONT_LATIN_PRESENTATION"; break;
1150 case DEFAULTFONT_FIXED
: s
= "DEFAULTFONT_FIXED"; break;
1151 case DEFAULTFONT_LATIN_FIXED
: s
= "DEFAULTFONT_LATIN_FIXED"; break;
1152 case DEFAULTFONT_UI_FIXED
: s
= "DEFAULTFONT_UI_FIXED"; break;
1154 case DEFAULTFONT_SYMBOL
: s
= "DEFAULTFONT_SYMBOL"; break;
1156 case DEFAULTFONT_CJK_TEXT
: s
= "DEFAULTFONT_CJK_TEXT"; break;
1157 case DEFAULTFONT_CJK_PRESENTATION
: s
= "DEFAULTFONT_CJK_PRESENTATION"; break;
1158 case DEFAULTFONT_CJK_SPREADSHEET
: s
= "DEFAULTFONT_CJK_SPREADSHEET"; break;
1159 case DEFAULTFONT_CJK_HEADING
: s
= "DEFAULTFONT_CJK_HEADING"; break;
1160 case DEFAULTFONT_CJK_DISPLAY
: s
= "DEFAULTFONT_CJK_DISPLAY"; break;
1162 case DEFAULTFONT_CTL_TEXT
: s
= "DEFAULTFONT_CTL_TEXT"; break;
1163 case DEFAULTFONT_CTL_PRESENTATION
: s
= "DEFAULTFONT_CTL_PRESENTATION"; break;
1164 case DEFAULTFONT_CTL_SPREADSHEET
: s
= "DEFAULTFONT_CTL_SPREADSHEET"; break;
1165 case DEFAULTFONT_CTL_HEADING
: s
= "DEFAULTFONT_CTL_HEADING"; break;
1166 case DEFAULTFONT_CTL_DISPLAY
: s
= "DEFAULTFONT_CTL_DISPLAY"; break;
1168 fprintf( stderr
, " OutputDevice::GetDefaultFont() Type=\"%s\" lang=%d flags=%ld FontName=\"%s\"\n",
1170 OUStringToOString( aFont
.GetName(), RTL_TEXTENCODING_UTF8
).getStr()
1177 // =======================================================================
1179 String
GetSubsFontName( const String
& rName
, ULONG nFlags
)
1183 xub_StrLen nIndex
= 0;
1184 String aOrgName
= GetNextFontToken( rName
, nIndex
);
1185 ImplGetEnglishSearchFontName( aOrgName
);
1187 // #93662# do not try to replace StarSymbol with MS only font
1188 if( nFlags
== (SUBSFONT_MS
|SUBSFONT_ONLYONE
)
1189 && ( aOrgName
.EqualsAscii( "starsymbol" )
1190 || aOrgName
.EqualsAscii( "opensymbol" ) ) )
1193 const FontNameAttr
* pAttr
= FontSubstConfiguration::get()->getSubstInfo( aOrgName
);
1196 for( int i
= 0; i
< 3; i
++ )
1198 const ::std::vector
< String
>* pVector
= NULL
;
1202 if( nFlags
& SUBSFONT_MS
&& pAttr
->MSSubstitutions
.size() )
1203 pVector
= &pAttr
->MSSubstitutions
;
1206 if( nFlags
& SUBSFONT_PS
&& pAttr
->PSSubstitutions
.size() )
1207 pVector
= &pAttr
->PSSubstitutions
;
1210 if( nFlags
& SUBSFONT_HTML
&& pAttr
->HTMLSubstitutions
.size() )
1211 pVector
= &pAttr
->HTMLSubstitutions
;
1216 for( ::std::vector
< String
>::const_iterator it
= pVector
->begin(); it
!= pVector
->end(); ++it
)
1217 if( ! ImplIsFontToken( rName
, *it
) )
1219 ImplAppendFontToken( aName
, *it
);
1220 if( nFlags
& SUBSFONT_ONLYONE
)
1232 // =======================================================================
1234 static unsigned ImplIsCJKFont( const String
& rFontName
)
1236 // Test, if Fontname includes CJK characters --> In this case we
1237 // mention that it is a CJK font
1238 const sal_Unicode
* pStr
= rFontName
.GetBuffer();
1242 if ( ((*pStr
>= 0x3040) && (*pStr
<= 0x30FF)) ||
1243 ((*pStr
>= 0x3190) && (*pStr
<= 0x319F)) )
1244 return IMPL_FONT_ATTR_CJK
|IMPL_FONT_ATTR_CJK_JP
;
1247 if ( ((*pStr
>= 0xAC00) && (*pStr
<= 0xD7AF)) ||
1248 ((*pStr
>= 0x3130) && (*pStr
<= 0x318F)) ||
1249 ((*pStr
>= 0x1100) && (*pStr
<= 0x11FF)) )
1250 return IMPL_FONT_ATTR_CJK
|IMPL_FONT_ATTR_CJK_KR
;
1253 if ( ((*pStr
>= 0x3400) && (*pStr
<= 0x9FFF)) )
1254 return IMPL_FONT_ATTR_CJK
|IMPL_FONT_ATTR_CJK_TC
|IMPL_FONT_ATTR_CJK_SC
;
1257 if ( ((*pStr
>= 0x3000) && (*pStr
<= 0xD7AF)) ||
1258 ((*pStr
>= 0xFF00) && (*pStr
<= 0xFFEE)) )
1259 return IMPL_FONT_ATTR_CJK
;
1267 // -----------------------------------------------------------------------
1269 static void ImplCalcType( ULONG
& rType
, FontWeight
& rWeight
, FontWidth
& rWidth
,
1270 FontFamily eFamily
, const FontNameAttr
* pFontAttr
)
1272 if ( eFamily
!= FAMILY_DONTKNOW
)
1274 if ( eFamily
== FAMILY_SWISS
)
1275 rType
|= IMPL_FONT_ATTR_SANSSERIF
;
1276 else if ( eFamily
== FAMILY_ROMAN
)
1277 rType
|= IMPL_FONT_ATTR_SERIF
;
1278 else if ( eFamily
== FAMILY_SCRIPT
)
1279 rType
|= IMPL_FONT_ATTR_SCRIPT
;
1280 else if ( eFamily
== FAMILY_MODERN
)
1281 rType
|= IMPL_FONT_ATTR_FIXED
;
1282 else if ( eFamily
== FAMILY_DECORATIVE
)
1283 rType
|= IMPL_FONT_ATTR_DECORATIVE
;
1288 rType
|= pFontAttr
->Type
;
1290 if ( ((rWeight
== WEIGHT_DONTKNOW
) || (rWeight
== WEIGHT_NORMAL
)) &&
1291 (pFontAttr
->Weight
!= WEIGHT_DONTKNOW
) )
1292 rWeight
= pFontAttr
->Weight
;
1293 if ( ((rWidth
== WIDTH_DONTKNOW
) || (rWidth
== WIDTH_NORMAL
)) &&
1294 (pFontAttr
->Width
!= WIDTH_DONTKNOW
) )
1295 rWidth
= pFontAttr
->Width
;
1299 // =======================================================================
1301 ImplFontData::ImplFontData( const ImplDevFontAttributes
& rDFA
, int nMagic
)
1302 : ImplDevFontAttributes( rDFA
),
1308 // StarSymbol is a unicode font, but it still deserves the symbol flag
1310 if( 0 == GetFamilyName().CompareIgnoreCaseToAscii( "starsymbol", 10)
1311 || 0 == GetFamilyName().CompareIgnoreCaseToAscii( "opensymbol", 10) )
1312 mbSymbolFlag
= true;
1315 // -----------------------------------------------------------------------
1317 StringCompare
ImplFontData::CompareIgnoreSize( const ImplFontData
& rOther
) const
1319 // compare their width, weight, italic and style name
1320 if( meWidthType
< rOther
.meWidthType
)
1321 return COMPARE_LESS
;
1322 else if( meWidthType
> rOther
.meWidthType
)
1323 return COMPARE_GREATER
;
1325 if( meWeight
< rOther
.meWeight
)
1326 return COMPARE_LESS
;
1327 else if( meWeight
> rOther
.meWeight
)
1328 return COMPARE_GREATER
;
1330 if( meItalic
< rOther
.meItalic
)
1331 return COMPARE_LESS
;
1332 else if( meItalic
> rOther
.meItalic
)
1333 return COMPARE_GREATER
;
1335 StringCompare eCompare
= maName
.CompareTo( rOther
.maName
);
1339 // -----------------------------------------------------------------------
1341 StringCompare
ImplFontData::CompareWithSize( const ImplFontData
& rOther
) const
1343 StringCompare eCompare
= CompareIgnoreSize( rOther
);
1344 if( eCompare
!= COMPARE_EQUAL
)
1347 if( mnHeight
< rOther
.mnHeight
)
1348 return COMPARE_LESS
;
1349 else if( mnHeight
> rOther
.mnHeight
)
1350 return COMPARE_GREATER
;
1352 if( mnWidth
< rOther
.mnWidth
)
1353 return COMPARE_LESS
;
1354 else if( mnWidth
> rOther
.mnWidth
)
1355 return COMPARE_GREATER
;
1357 return COMPARE_EQUAL
;
1360 // -----------------------------------------------------------------------
1362 struct FontMatchStatus
1368 const xub_Unicode
* mpTargetStyleName
;
1371 bool ImplFontData::IsBetterMatch( const ImplFontSelectData
& rFSD
, FontMatchStatus
& rStatus
) const
1375 const String
& rFontName
= rFSD
.maTargetName
;
1376 if( (rFontName
== maName
) || rFontName
.EqualsIgnoreCaseAscii( maName
) )
1379 if( rStatus
.mpTargetStyleName
1380 && maStyleName
.EqualsIgnoreCaseAscii( rStatus
.mpTargetStyleName
) )
1383 if( (rFSD
.mePitch
!= PITCH_DONTKNOW
) && (rFSD
.mePitch
== mePitch
) )
1386 // prefer NORMAL font width
1387 // TODO: change when the upper layers can tell their width preference
1388 if( meWidthType
== WIDTH_NORMAL
)
1390 else if( (meWidthType
== WIDTH_SEMI_EXPANDED
) || (meWidthType
== WIDTH_SEMI_CONDENSED
) )
1393 if( rFSD
.meWeight
!= WEIGHT_DONTKNOW
)
1395 // if not bold prefer light fonts to bold fonts
1396 int nReqWeight
= (int)rFSD
.meWeight
;
1397 if ( rFSD
.meWeight
> WEIGHT_MEDIUM
)
1400 int nGivenWeight
= (int)meWeight
;
1401 if( meWeight
> WEIGHT_MEDIUM
)
1402 nGivenWeight
+= 100;
1404 int nWeightDiff
= nReqWeight
- nGivenWeight
;
1406 if ( nWeightDiff
== 0 )
1408 else if ( nWeightDiff
== +1 || nWeightDiff
== -1 )
1410 else if ( nWeightDiff
< +50 && nWeightDiff
> -50)
1413 else // requested weight == WEIGHT_DONTKNOW
1415 // prefer NORMAL font weight
1416 // TODO: change when the upper layers can tell their weight preference
1417 if( meWeight
== WEIGHT_NORMAL
)
1419 else if( meWeight
== WEIGHT_MEDIUM
)
1421 else if( (meWeight
== WEIGHT_SEMILIGHT
) || (meWeight
== WEIGHT_SEMIBOLD
) )
1423 else if( meWeight
== WEIGHT_LIGHT
)
1427 if ( rFSD
.meItalic
== ITALIC_NONE
)
1429 if( meItalic
== ITALIC_NONE
)
1434 if( rFSD
.meItalic
== meItalic
)
1436 else if( meItalic
!= ITALIC_NONE
)
1443 int nHeightMatch
= 0;
1444 int nWidthMatch
= 0;
1448 if( rFSD
.mnOrientation
!= 0 )
1450 else if( rFSD
.mnWidth
!= 0 )
1457 if( rFSD
.mnHeight
== mnHeight
)
1460 if( rFSD
.mnWidth
== mnWidth
)
1465 // for non-scalable fonts the size difference is very important
1466 // prefer the smaller font face because of clipping/overlapping issues
1467 int nHeightDiff
= (rFSD
.mnHeight
- mnHeight
) * 1000;
1468 nHeightMatch
= (nHeightDiff
>= 0) ? -nHeightDiff
: 100+nHeightDiff
;
1470 nHeightMatch
/= rFSD
.mnHeight
;
1472 if( (rFSD
.mnWidth
!= 0) && (mnWidth
!= 0) && (rFSD
.mnWidth
!= mnWidth
) )
1474 int nWidthDiff
= (rFSD
.mnWidth
- mnWidth
) * 100;
1475 nWidthMatch
= (nWidthDiff
>= 0) ? -nWidthDiff
: +nWidthDiff
;
1480 if( rStatus
.mnFaceMatch
> nMatch
)
1482 else if( rStatus
.mnFaceMatch
< nMatch
)
1484 rStatus
.mnFaceMatch
= nMatch
;
1485 rStatus
.mnHeightMatch
= nHeightMatch
;
1486 rStatus
.mnWidthMatch
= nWidthMatch
;
1490 // when two fonts are still competing prefer the
1491 // one with the best matching height
1492 if( rStatus
.mnHeightMatch
> nHeightMatch
)
1494 else if( rStatus
.mnHeightMatch
< nHeightMatch
)
1496 rStatus
.mnHeightMatch
= nHeightMatch
;
1497 rStatus
.mnWidthMatch
= nWidthMatch
;
1501 if( rStatus
.mnWidthMatch
> nWidthMatch
)
1504 rStatus
.mnWidthMatch
= nWidthMatch
;
1508 // =======================================================================
1510 ImplFontEntry::ImplFontEntry( const ImplFontSelectData
& rFontSelData
)
1511 : maFontSelData( rFontSelData
),
1512 maMetric( rFontSelData
),
1513 mpConversion( NULL
),
1515 mnSetFontFlags( 0 ),
1516 mnOwnOrientation( 0 ),
1519 mpUnicodeFallbackList( NULL
)
1521 maFontSelData
.mpFontEntry
= this;
1524 // -----------------------------------------------------------------------
1526 ImplFontEntry::~ImplFontEntry()
1528 delete mpUnicodeFallbackList
;
1531 // -----------------------------------------------------------------------
1533 inline void ImplFontEntry::AddFallbackForUnicode( sal_UCS4 cChar
, const String
& rFontName
)
1535 if( !mpUnicodeFallbackList
)
1536 mpUnicodeFallbackList
= new UnicodeFallbackList
;
1537 (*mpUnicodeFallbackList
)[cChar
] = rFontName
;
1540 // -----------------------------------------------------------------------
1542 inline bool ImplFontEntry::GetFallbackForUnicode( sal_UCS4 cChar
, String
* pFontName
) const
1544 if( !mpUnicodeFallbackList
)
1547 UnicodeFallbackList::const_iterator it
= mpUnicodeFallbackList
->find( cChar
);
1548 if( it
== mpUnicodeFallbackList
->end() )
1551 *pFontName
= (*it
).second
;
1555 // -----------------------------------------------------------------------
1557 inline void ImplFontEntry::IgnoreFallbackForUnicode( sal_UCS4 cChar
, const String
& rFontName
)
1559 // DBG_ASSERT( mpUnicodeFallbackList, "ImplFontEntry::IgnoreFallbackForUnicode no list" );
1560 UnicodeFallbackList::iterator it
= mpUnicodeFallbackList
->find( cChar
);
1561 // DBG_ASSERT( it != mpUnicodeFallbackList->end(), "ImplFontEntry::IgnoreFallbackForUnicode no match" );
1562 if( it
== mpUnicodeFallbackList
->end() )
1564 if( (*it
).second
== rFontName
)
1565 mpUnicodeFallbackList
->erase( it
);
1568 // =======================================================================
1570 ImplDevFontListData::ImplDevFontListData( const String
& rSearchName
)
1572 maSearchName( rSearchName
),
1575 meMatchWeight( WEIGHT_DONTKNOW
),
1576 meMatchWidth( WIDTH_DONTKNOW
),
1577 meFamily( FAMILY_DONTKNOW
),
1578 mePitch( PITCH_DONTKNOW
),
1582 // -----------------------------------------------------------------------
1584 ImplDevFontListData::~ImplDevFontListData()
1586 // release all physical font faces
1589 ImplFontData
* pFace
= mpFirst
;
1590 mpFirst
= pFace
->GetNextFace();
1595 // -----------------------------------------------------------------------
1597 bool ImplDevFontListData::AddFontFace( ImplFontData
* pNewData
)
1599 pNewData
->mpNext
= NULL
;
1603 maName
= pNewData
->maName
;
1604 maMapNames
= pNewData
->maMapNames
;
1605 meFamily
= pNewData
->meFamily
;
1606 mePitch
= pNewData
->mePitch
;
1607 mnMinQuality
= pNewData
->mnQuality
;
1611 if( meFamily
== FAMILY_DONTKNOW
)
1612 meFamily
= pNewData
->meFamily
;
1613 if( mePitch
== PITCH_DONTKNOW
)
1614 mePitch
= pNewData
->mePitch
;
1615 if( mnMinQuality
> pNewData
->mnQuality
)
1616 mnMinQuality
= pNewData
->mnQuality
;
1619 // set attributes for attribute based font matching
1620 if( pNewData
->IsScalable() )
1621 mnTypeFaces
|= IMPL_DEVFONT_SCALABLE
;
1623 if( pNewData
->IsSymbolFont() )
1624 mnTypeFaces
|= IMPL_DEVFONT_SYMBOL
;
1626 mnTypeFaces
|= IMPL_DEVFONT_NONESYMBOL
;
1628 if( pNewData
->meWeight
!= WEIGHT_DONTKNOW
)
1630 if( pNewData
->meWeight
>= WEIGHT_SEMIBOLD
)
1631 mnTypeFaces
|= IMPL_DEVFONT_BOLD
;
1632 else if( pNewData
->meWeight
<= WEIGHT_SEMILIGHT
)
1633 mnTypeFaces
|= IMPL_DEVFONT_LIGHT
;
1635 mnTypeFaces
|= IMPL_DEVFONT_NORMAL
;
1638 if( pNewData
->meItalic
== ITALIC_NONE
)
1639 mnTypeFaces
|= IMPL_DEVFONT_NONEITALIC
;
1640 else if( (pNewData
->meItalic
== ITALIC_NORMAL
)
1641 || (pNewData
->meItalic
== ITALIC_OBLIQUE
) )
1642 mnTypeFaces
|= IMPL_DEVFONT_ITALIC
;
1644 if( (meMatchWeight
== WEIGHT_DONTKNOW
)
1645 || (meMatchWidth
== WIDTH_DONTKNOW
)
1646 || (mnMatchType
== 0) )
1648 // TODO: is it cheaper to calc matching attributes now or on demand?
1649 // calc matching attributes if other entries are already initialized
1651 // MT: Perform05: Do lazy, quite expensive, not needed in start-up!
1652 // const FontSubstConfiguration& rFontSubst = *FontSubstConfiguration::get();
1653 // InitMatchData( rFontSubst, maSearchName );
1654 // mbMatchData=true; // Somewhere else???
1657 // reassign name (sharing saves memory)
1658 if( pNewData
->maName
== maName
)
1659 pNewData
->maName
= maName
;
1661 // insert new physical font face into linked list
1662 // TODO: get rid of linear search?
1663 ImplFontData
* pData
;
1664 ImplFontData
** ppHere
= &mpFirst
;
1665 for(; (pData
=*ppHere
) != NULL
; ppHere
=&pData
->mpNext
)
1667 StringCompare eComp
= pNewData
->CompareWithSize( *pData
);
1668 if( eComp
== COMPARE_GREATER
)
1670 if( eComp
== COMPARE_LESS
)
1673 // ignore duplicate if its quality is worse
1674 if( pNewData
->mnQuality
< pData
->mnQuality
)
1677 // keep the device font if its quality is good enough
1678 if( (pNewData
->mnQuality
== pData
->mnQuality
)
1679 && (pData
->mbDevice
|| !pNewData
->mbDevice
) )
1682 // replace existing font face with a better one
1683 pNewData
->mpNext
= pData
->mpNext
;
1689 // insert into or append to list of physical font faces
1690 pNewData
->mpNext
= pData
;
1695 // -----------------------------------------------------------------------
1697 // get font attributes using the normalized font family name
1698 void ImplDevFontListData::InitMatchData( const vcl::FontSubstConfiguration
& rFontSubst
,
1699 const String
& rSearchName
)
1702 // get font attributes from the decorated font name
1703 rFontSubst
.getMapName( rSearchName
, aShortName
, maMatchFamilyName
,
1704 meMatchWeight
, meMatchWidth
, mnMatchType
);
1705 const FontNameAttr
* pFontAttr
= rFontSubst
.getSubstInfo( rSearchName
);
1706 // eventually use the stripped name
1708 if( aShortName
!= rSearchName
)
1709 pFontAttr
= rFontSubst
.getSubstInfo( aShortName
);
1710 ImplCalcType( mnMatchType
, meMatchWeight
, meMatchWidth
, meFamily
, pFontAttr
);
1711 mnMatchType
|= ImplIsCJKFont( maName
);
1714 // -----------------------------------------------------------------------
1716 ImplFontData
* ImplDevFontListData::FindBestFontFace( const ImplFontSelectData
& rFSD
) const
1720 if( !mpFirst
->GetNextFace() )
1723 // FontName+StyleName should map to FamilyName+StyleName
1724 const String
& rSearchName
= rFSD
.maTargetName
;
1725 const xub_Unicode
* pTargetStyleName
= NULL
;
1726 if( (rSearchName
.Len() > maSearchName
.Len())
1727 && rSearchName
.Equals( maSearchName
, 0, maSearchName
.Len() ) )
1728 pTargetStyleName
= rSearchName
.GetBuffer() + maSearchName
.Len() + 1;
1730 // linear search, TODO: improve?
1731 ImplFontData
* pFontFace
= mpFirst
;
1732 ImplFontData
* pBestFontFace
= pFontFace
;
1733 FontMatchStatus aFontMatchStatus
= {0,0,0, pTargetStyleName
};
1734 for(; pFontFace
; pFontFace
= pFontFace
->GetNextFace() )
1735 if( pFontFace
->IsBetterMatch( rFSD
, aFontMatchStatus
) )
1736 pBestFontFace
= pFontFace
;
1738 return pBestFontFace
;
1741 // -----------------------------------------------------------------------
1743 // update device font list with unique font faces, with uniqueness
1744 // meaning different font attributes, but not different fonts sizes
1745 void ImplDevFontListData::UpdateDevFontList( ImplGetDevFontList
& rDevFontList
) const
1747 ImplFontData
* pPrevFace
= NULL
;
1748 for( ImplFontData
* pFace
= mpFirst
; pFace
; pFace
= pFace
->GetNextFace() )
1750 if( !pPrevFace
|| pFace
->CompareIgnoreSize( *pPrevFace
) )
1751 rDevFontList
.Add( pFace
);
1756 // -----------------------------------------------------------------------
1758 void ImplDevFontListData::GetFontHeights( std::set
<int>& rHeights
) const
1760 // add all available font heights
1761 for( const ImplFontData
* pFace
= mpFirst
; pFace
; pFace
= pFace
->GetNextFace() )
1762 rHeights
.insert( pFace
->GetHeight() );
1765 // -----------------------------------------------------------------------
1767 void ImplDevFontListData::UpdateCloneFontList( ImplDevFontList
& rDevFontList
,
1768 bool bScalable
, bool bEmbeddable
) const
1770 for( ImplFontData
* pFace
= mpFirst
; pFace
; pFace
= pFace
->GetNextFace() )
1772 if( bScalable
&& !pFace
->IsScalable() )
1774 if( bEmbeddable
&& !pFace
->IsEmbeddable() && !pFace
->IsSubsettable() )
1777 ImplFontData
* pClonedFace
= pFace
->Clone();
1778 rDevFontList
.Add( pClonedFace
);
1782 // =======================================================================
1784 ImplDevFontList::ImplDevFontList()
1785 : mbMatchData( false )
1786 , mbMapNames( false )
1787 , mpPreMatchHook( NULL
)
1788 , mpFallbackHook( NULL
)
1789 , mpFallbackList( NULL
)
1790 , mnFallbackCount( -1 )
1793 // -----------------------------------------------------------------------
1795 ImplDevFontList::~ImplDevFontList()
1800 // -----------------------------------------------------------------------
1802 void ImplDevFontList::SetPreMatchHook( ImplPreMatchFontSubstitution
* pHook
)
1804 mpPreMatchHook
= pHook
;
1807 // -----------------------------------------------------------------------
1809 void ImplDevFontList::SetFallbackHook( ImplGlyphFallbackFontSubstitution
* pHook
)
1811 mpFallbackHook
= pHook
;
1814 // -----------------------------------------------------------------------
1816 void ImplDevFontList::Clear()
1818 // remove fallback lists
1819 delete[] mpFallbackList
;
1820 mpFallbackList
= NULL
;
1821 mnFallbackCount
= -1;
1823 // clear all entries in the device font list
1824 DevFontList::iterator it
= maDevFontList
.begin();
1825 for(; it
!= maDevFontList
.end(); ++it
)
1827 ImplDevFontListData
* pEntry
= (*it
).second
;
1831 maDevFontList
.clear();
1833 // match data must be recalculated too
1834 mbMatchData
= false;
1837 // -----------------------------------------------------------------------
1839 // TODO: use a more generic String hash
1840 int FontNameHash::operator()( const String
& rStr
) const
1842 // this simple hash just has to be good enough for font names
1844 const int nLen
= rStr
.Len();
1845 const sal_Unicode
* p
= rStr
.GetBuffer();
1848 default: nHash
= (p
[0]<<16) - (p
[1]<<8) + p
[2];
1852 case 3: nHash
+= (p
[2]<<16); // fall through
1853 case 2: nHash
+= (p
[1]<<8); // fall through
1854 case 1: nHash
+= p
[0]; // fall through
1861 // -----------------------------------------------------------------------
1863 void ImplDevFontList::InitGenericGlyphFallback( void ) const
1865 // normalized family names of fonts suited for glyph fallback
1866 // if a font is available related fonts can be ignored
1867 // TODO: implement dynamic lists
1868 static const char* aGlyphFallbackList
[] = {
1869 // empty strings separate the names of unrelated fonts
1871 "arialunicodems", "cyberbit", "code2000", "",
1873 "starsymbol", "opensymbol", "",
1874 "msmincho", "fzmingti", "fzheiti", "ipamincho", "sazanamimincho", "kochimincho", "",
1875 "sunbatang", "sundotum", "baekmukdotum", "gulim", "batang", "dotum", "",
1876 "hgmincholightj", "msunglightsc", "msunglighttc", "hymyeongjolightk", "",
1877 "tahoma", "dejavusans", "timesnewroman", "lucidatypewriter", "lucidasans", "nimbussansl", "",
1878 "shree", "mangal", "",
1879 "raavi", "shruti", "tunga", "",
1880 "latha", "gautami", "kartika", "vrinda", "",
1881 "shayyalmt", "naskmt", "",
1882 "david", "nachlieli", "lucidagrande", "",
1883 "norasi", "angsanaupc", "",
1884 "khmerossystem", "",
1887 "padauk", "pinlonmyanmar", "",
1891 bool bHasEudc
= false;
1893 int nBestQuality
= 0;
1894 ImplDevFontListData
** pFallbackList
= NULL
;
1895 for( const char** ppNames
= &aGlyphFallbackList
[0];; ++ppNames
)
1897 // advance to next sub-list when end-of-sublist marker
1898 if( !**ppNames
) // #i46456# check for empty string, i.e., deref string itself not only ptr to it
1900 if( nBestQuality
> 0 )
1901 if( ++nMaxLevel
>= MAX_FALLBACK
)
1909 // test if the glyph fallback candidate font is available and scalable
1910 String
aTokenName( *ppNames
, RTL_TEXTENCODING_UTF8
);
1911 ImplDevFontListData
* pFallbackFont
= FindFontFamily( aTokenName
);
1912 if( !pFallbackFont
)
1914 if( !pFallbackFont
->IsScalable() )
1917 // keep the best font of the glyph fallback sub-list
1918 if( nBestQuality
< pFallbackFont
->GetMinQuality() )
1920 nBestQuality
= pFallbackFont
->GetMinQuality();
1921 // store available glyph fallback fonts
1922 if( !pFallbackList
)
1923 pFallbackList
= new ImplDevFontListData
*[ MAX_FALLBACK
];
1924 pFallbackList
[ nMaxLevel
] = pFallbackFont
;
1925 if( !bHasEudc
&& !nMaxLevel
)
1926 bHasEudc
= !strncmp( *ppNames
, "eudc", 5 );
1930 // sort the list of fonts for glyph fallback by quality (highest first)
1931 // #i33947# keep the EUDC font at the front of the list
1932 // an insertion sort is good enough for this short list
1933 const int nSortStart
= bHasEudc
? 1 : 0;
1934 for( int i
= nSortStart
+1, j
; i
< nMaxLevel
; ++i
)
1936 ImplDevFontListData
* pTestFont
= pFallbackList
[ i
];
1937 int nTestQuality
= pTestFont
->GetMinQuality();
1938 for( j
= i
; --j
>= nSortStart
; )
1939 if( nTestQuality
> pFallbackList
[j
]->GetMinQuality() )
1940 pFallbackList
[ j
+1 ] = pFallbackList
[ j
];
1943 pFallbackList
[ j
+1 ] = pTestFont
;
1946 #if defined(HDU_DEBUG)
1947 for( int i
= 0; i
< nMaxLevel
; ++i
)
1949 ImplDevFontListData
* pFont
= pFallbackList
[ i
];
1950 ByteString
aFontName( pFont
->GetFamilyName(), RTL_TEXTENCODING_UTF8
);
1951 fprintf( stderr
, "GlyphFallbackFont[%d] (quality=%05d): \"%s\"\n",
1952 i
, pFont
->GetMinQuality(), aFontName
.GetBuffer() );
1956 mnFallbackCount
= nMaxLevel
;
1957 mpFallbackList
= pFallbackList
;
1960 // -----------------------------------------------------------------------
1962 ImplDevFontListData
* ImplDevFontList::GetGlyphFallbackFont( ImplFontSelectData
& rFontSelData
,
1963 rtl::OUString
& rMissingCodes
, int nFallbackLevel
) const
1965 ImplDevFontListData
* pFallbackData
= NULL
;
1967 // find a matching font candidate for platform specific glyph fallback
1968 if( mpFallbackHook
)
1970 // check cache for the first matching entry
1971 // to avoid calling the expensive fallback hook (#i83491#)
1973 bool bCached
= true;
1974 sal_Int32 nStrIndex
= 0;
1975 while( nStrIndex
< rMissingCodes
.getLength() )
1977 cChar
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
1978 bCached
= rFontSelData
.mpFontEntry
->GetFallbackForUnicode( cChar
, &rFontSelData
.maSearchName
);
1979 // ignore entries which don't have a fallback
1980 if( !bCached
|| (rFontSelData
.maSearchName
.Len() != 0) )
1986 // there is a matching fallback in the cache
1987 // so update rMissingCodes with codepoints not yet resolved by this fallback
1988 int nRemainingLength
= 0;
1989 sal_UCS4
* pRemainingCodes
= (sal_UCS4
*)alloca( rMissingCodes
.getLength() * sizeof(sal_UCS4
) );
1991 while( nStrIndex
< rMissingCodes
.getLength() )
1993 cChar
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
1994 bCached
= rFontSelData
.mpFontEntry
->GetFallbackForUnicode( cChar
, &aFontName
);
1995 if( !bCached
|| (rFontSelData
.maSearchName
!= aFontName
) )
1996 pRemainingCodes
[ nRemainingLength
++ ] = cChar
;
1998 rMissingCodes
= rtl::OUString( pRemainingCodes
, nRemainingLength
);
2002 rtl::OUString aOldMissingCodes
= rMissingCodes
;
2003 // call the hook to query the best matching glyph fallback font
2004 if( mpFallbackHook
->FindFontSubstitute( rFontSelData
, rMissingCodes
) )
2005 // apply outdev3.cxx specific fontname normalization
2006 ImplGetEnglishSearchFontName( rFontSelData
.maSearchName
);
2008 rFontSelData
.maSearchName
= String();
2010 // cache the result even if there was no match
2013 if( !rFontSelData
.mpFontEntry
->GetFallbackForUnicode( cChar
, &rFontSelData
.maSearchName
) )
2014 rFontSelData
.mpFontEntry
->AddFallbackForUnicode( cChar
, rFontSelData
.maSearchName
);
2015 if( nStrIndex
>= aOldMissingCodes
.getLength() )
2017 cChar
= aOldMissingCodes
.iterateCodePoints( &nStrIndex
);
2019 if( rFontSelData
.maSearchName
.Len() != 0 )
2021 // remove cache entries that were still not resolved
2022 for( nStrIndex
= 0; nStrIndex
< rMissingCodes
.getLength(); )
2024 cChar
= rMissingCodes
.iterateCodePoints( &nStrIndex
);
2025 rFontSelData
.mpFontEntry
->IgnoreFallbackForUnicode( cChar
, rFontSelData
.maSearchName
);
2030 // find the matching device font
2031 if( rFontSelData
.maSearchName
.Len() != 0 )
2032 pFallbackData
= FindFontFamily( rFontSelData
.maSearchName
);
2035 // else find a matching font candidate for generic glyph fallback
2036 if( !pFallbackData
)
2038 // initialize font candidates for generic glyph fallback if needed
2039 if( mnFallbackCount
< 0 )
2040 InitGenericGlyphFallback();
2041 // TODO: adjust nFallbackLevel by number of levels resolved by the fallback hook
2042 if( nFallbackLevel
< mnFallbackCount
)
2043 pFallbackData
= mpFallbackList
[ nFallbackLevel
];
2046 return pFallbackData
;
2049 // -----------------------------------------------------------------------
2051 void ImplDevFontList::Add( ImplFontData
* pNewData
)
2053 int nAliasQuality
= pNewData
->mnQuality
- 100;
2054 String aMapNames
= pNewData
->maMapNames
;
2055 pNewData
->maMapNames
= String();
2057 bool bKeepNewData
= false;
2058 for( xub_StrLen nMapNameIndex
= 0; nMapNameIndex
!= STRING_NOTFOUND
; )
2060 String aSearchName
= pNewData
->maName
;
2061 ImplGetEnglishSearchFontName( aSearchName
);
2063 DevFontList::const_iterator it
= maDevFontList
.find( aSearchName
);
2064 ImplDevFontListData
* pFoundData
= NULL
;
2065 if( it
!= maDevFontList
.end() )
2066 pFoundData
= (*it
).second
;
2070 pFoundData
= new ImplDevFontListData( aSearchName
);
2071 maDevFontList
[ aSearchName
] = pFoundData
;
2074 bKeepNewData
= pFoundData
->AddFontFace( pNewData
);
2076 // add font alias if available
2077 // a font alias should never win against an original font with similar quality
2078 if( aMapNames
.Len() >= nMapNameIndex
)
2080 if( bKeepNewData
) // try to recycle obsoleted object
2081 pNewData
= pNewData
->CreateAlias();
2082 bKeepNewData
= false;
2083 pNewData
->mnQuality
= nAliasQuality
;
2084 pNewData
->maName
= GetNextFontToken( aMapNames
, nMapNameIndex
);
2091 // -----------------------------------------------------------------------
2093 // find the font from the normalized font family name
2094 ImplDevFontListData
* ImplDevFontList::ImplFindBySearchName( const String
& rSearchName
) const
2097 String aTempName
= rSearchName
;
2098 ImplGetEnglishSearchFontName( aTempName
);
2099 DBG_ASSERT( aTempName
== rSearchName
, "ImplDevFontList::ImplFindBySearchName() called with non-normalized name" );
2102 DevFontList::const_iterator it
= maDevFontList
.find( rSearchName
);
2103 if( it
== maDevFontList
.end() )
2106 ImplDevFontListData
* pFoundData
= (*it
).second
;
2110 // -----------------------------------------------------------------------
2112 ImplDevFontListData
* ImplDevFontList::ImplFindByAliasName( const String
& rSearchName
, const String
& rShortName
) const
2114 // short circuit for impossible font name alias
2115 if( !rSearchName
.Len() )
2118 // short circuit if no alias names are available
2122 // use the font's alias names to find the font
2123 // TODO: get rid of linear search
2124 DevFontList::const_iterator it
= maDevFontList
.begin();
2125 while( it
!= maDevFontList
.end() )
2127 ImplDevFontListData
* pData
= (*it
).second
;
2128 if( !pData
->maMapNames
.Len() )
2131 // if one alias name matches we found a matching font
2133 xub_StrLen nIndex
= 0;
2136 aTempName
= GetNextFontToken( pData
->maMapNames
, nIndex
);
2137 // Test, if the Font name match with one of the mapping names
2138 if ( (aTempName
== rSearchName
) || (aTempName
== rShortName
) )
2141 while ( nIndex
!= STRING_NOTFOUND
);
2147 // -----------------------------------------------------------------------
2149 ImplDevFontListData
* ImplDevFontList::FindFontFamily( const String
& rFontName
) const
2151 // normalize the font fomily name and
2152 String aName
= rFontName
;
2153 ImplGetEnglishSearchFontName( aName
);
2154 ImplDevFontListData
* pFound
= ImplFindBySearchName( aName
);
2158 // -----------------------------------------------------------------------
2160 ImplDevFontListData
* ImplDevFontList::ImplFindByTokenNames( const String
& rTokenStr
) const
2162 ImplDevFontListData
* pFoundData
= NULL
;
2164 // use normalized font name tokens to find the font
2165 for( xub_StrLen nTokenPos
= 0; nTokenPos
!= STRING_NOTFOUND
; )
2167 String aSearchName
= GetNextFontToken( rTokenStr
, nTokenPos
);
2168 if( !aSearchName
.Len() )
2170 ImplGetEnglishSearchFontName( aSearchName
);
2171 pFoundData
= ImplFindBySearchName( aSearchName
);
2179 // -----------------------------------------------------------------------
2181 ImplDevFontListData
* ImplDevFontList::ImplFindBySubstFontAttr( const vcl::FontNameAttr
& rFontAttr
) const
2183 ImplDevFontListData
* pFoundData
= NULL
;
2185 // use the font substitutions suggested by the FontNameAttr to find the font
2186 ::std::vector
< String
>::const_iterator it
= rFontAttr
.Substitutions
.begin();
2187 for(; it
!= rFontAttr
.Substitutions
.end(); ++it
)
2189 String
aSearchName( *it
);
2190 ImplGetEnglishSearchFontName( aSearchName
);
2192 pFoundData
= ImplFindBySearchName( aSearchName
);
2200 // -----------------------------------------------------------------------
2202 void ImplDevFontList::InitMatchData() const
2204 // short circuit if already done
2209 // calculate MatchData for all entries
2210 const FontSubstConfiguration
& rFontSubst
= *FontSubstConfiguration::get();
2212 DevFontList::const_iterator it
= maDevFontList
.begin();
2213 for(; it
!= maDevFontList
.end(); ++it
)
2215 const String
& rSearchName
= (*it
).first
;
2216 ImplDevFontListData
* pEntry
= (*it
).second
;
2218 pEntry
->InitMatchData( rFontSubst
, rSearchName
);
2222 // -----------------------------------------------------------------------
2224 ImplDevFontListData
* ImplDevFontList::ImplFindByAttributes( ULONG nSearchType
,
2225 FontWeight eSearchWeight
, FontWidth eSearchWidth
, FontFamily
/*eSearchFamily*/,
2226 FontItalic eSearchItalic
, const String
& rSearchFamilyName
) const
2228 if( (eSearchItalic
!= ITALIC_NONE
) && (eSearchItalic
!= ITALIC_DONTKNOW
) )
2229 nSearchType
|= IMPL_FONT_ATTR_ITALIC
;
2231 // don't bother to match attributes if the attributes aren't worth matching
2233 && ((eSearchWeight
== WEIGHT_DONTKNOW
) || (eSearchWeight
== WEIGHT_NORMAL
))
2234 && ((eSearchWidth
== WIDTH_DONTKNOW
) || (eSearchWidth
== WIDTH_NORMAL
)) )
2238 ImplDevFontListData
* pFoundData
= NULL
;
2241 long nBestMatch
= 40000;
2242 ULONG nBestType
= 0;
2244 DevFontList::const_iterator it
= maDevFontList
.begin();
2245 for(; it
!= maDevFontList
.end(); ++it
)
2247 ImplDevFontListData
* pData
= (*it
).second
;
2249 // Get all information about the matching font
2250 ULONG nMatchType
= pData
->mnMatchType
;
2251 FontWeight eMatchWeight
= pData
->meMatchWeight
;
2252 FontWidth eMatchWidth
= pData
->meMatchWidth
;
2254 // Calculate Match Value
2257 // 10000000 CJK, CTL, None-Latin, Symbol
2258 // 1000000 FamilyName, Script, Fixed, -Special, -Decorative,
2259 // Titling, Capitals, Outline, Shadow
2260 // 100000 Match FamilyName, Serif, SansSerif, Italic,
2262 // 10000 Scalable, Standard, Default,
2263 // full, Normal, Knownfont,
2264 // Otherstyle, +Special, +Decorative,
2265 // 1000 Typewriter, Rounded, Gothic, Schollbook
2269 // test CJK script attributes
2270 if ( nSearchType
& IMPL_FONT_ATTR_CJK
)
2272 // Matching language
2273 if( 0 == ((nSearchType
^ nMatchType
) & IMPL_FONT_ATTR_CJK_ALLLANG
) )
2274 nTestMatch
+= 10000000*3;
2275 if( nMatchType
& IMPL_FONT_ATTR_CJK
)
2276 nTestMatch
+= 10000000*2;
2277 if( nMatchType
& IMPL_FONT_ATTR_FULL
)
2278 nTestMatch
+= 10000000;
2280 else if ( nMatchType
& IMPL_FONT_ATTR_CJK
)
2281 nTestMatch
-= 10000000;
2283 // test CTL script attributes
2284 if( nSearchType
& IMPL_FONT_ATTR_CTL
)
2286 if( nMatchType
& IMPL_FONT_ATTR_CTL
)
2287 nTestMatch
+= 10000000*2;
2288 if( nMatchType
& IMPL_FONT_ATTR_FULL
)
2289 nTestMatch
+= 10000000;
2291 else if ( nMatchType
& IMPL_FONT_ATTR_CTL
)
2292 nTestMatch
-= 10000000;
2294 // test LATIN script attributes
2295 if( nSearchType
& IMPL_FONT_ATTR_NONELATIN
)
2297 if( nMatchType
& IMPL_FONT_ATTR_NONELATIN
)
2298 nTestMatch
+= 10000000*2;
2299 if( nMatchType
& IMPL_FONT_ATTR_FULL
)
2300 nTestMatch
+= 10000000;
2303 // test SYMBOL attributes
2304 if ( nSearchType
& IMPL_FONT_ATTR_SYMBOL
)
2306 const String
& rSearchName
= it
->first
;
2307 // prefer some special known symbol fonts
2308 if ( rSearchName
.EqualsAscii( "starsymbol" ) )
2309 nTestMatch
+= 10000000*6+(10000*3);
2310 else if ( rSearchName
.EqualsAscii( "opensymbol" ) )
2311 nTestMatch
+= 10000000*6;
2312 else if ( rSearchName
.EqualsAscii( "starbats" )
2313 || rSearchName
.EqualsAscii( "wingdings" )
2314 || rSearchName
.EqualsAscii( "monotypesorts" )
2315 || rSearchName
.EqualsAscii( "dingbats" )
2316 || rSearchName
.EqualsAscii( "zapfdingbats" ) )
2317 nTestMatch
+= 10000000*5;
2318 else if ( pData
->mnTypeFaces
& IMPL_DEVFONT_SYMBOL
)
2319 nTestMatch
+= 10000000*4;
2322 if( nMatchType
& IMPL_FONT_ATTR_SYMBOL
)
2323 nTestMatch
+= 10000000*2;
2324 if( nMatchType
& IMPL_FONT_ATTR_FULL
)
2325 nTestMatch
+= 10000000;
2328 else if ( (pData
->mnTypeFaces
& (IMPL_DEVFONT_SYMBOL
| IMPL_DEVFONT_NONESYMBOL
)) == IMPL_DEVFONT_SYMBOL
)
2329 nTestMatch
-= 10000000;
2330 else if ( nMatchType
& IMPL_FONT_ATTR_SYMBOL
)
2331 nTestMatch
-= 10000;
2333 // match stripped family name
2334 if( rSearchFamilyName
.Len() && (rSearchFamilyName
== pData
->maMatchFamilyName
) )
2335 nTestMatch
+= 1000000*3;
2337 // match ALLSCRIPT? attribute
2338 if( nSearchType
& IMPL_FONT_ATTR_ALLSCRIPT
)
2340 if( nMatchType
& IMPL_FONT_ATTR_ALLSCRIPT
)
2341 nTestMatch
+= 1000000*2;
2342 if( nSearchType
& IMPL_FONT_ATTR_ALLSUBSCRIPT
)
2344 if( 0 == ((nSearchType
^ nMatchType
) & IMPL_FONT_ATTR_ALLSUBSCRIPT
) )
2345 nTestMatch
+= 1000000*2;
2346 if( 0 != ((nSearchType
^ nMatchType
) & IMPL_FONT_ATTR_BRUSHSCRIPT
) )
2347 nTestMatch
-= 1000000;
2350 else if( nMatchType
& IMPL_FONT_ATTR_ALLSCRIPT
)
2351 nTestMatch
-= 1000000;
2353 // test MONOSPACE+TYPEWRITER attributes
2354 if( nSearchType
& IMPL_FONT_ATTR_FIXED
)
2356 if( nMatchType
& IMPL_FONT_ATTR_FIXED
)
2357 nTestMatch
+= 1000000*2;
2358 // a typewriter attribute is even better
2359 if( 0 == ((nSearchType
^ nMatchType
) & IMPL_FONT_ATTR_TYPEWRITER
) )
2360 nTestMatch
+= 10000*2;
2362 else if( nMatchType
& IMPL_FONT_ATTR_FIXED
)
2363 nTestMatch
-= 1000000;
2365 // test SPECIAL attribute
2366 if( nSearchType
& IMPL_FONT_ATTR_SPECIAL
)
2368 if( nMatchType
& IMPL_FONT_ATTR_SPECIAL
)
2369 nTestMatch
+= 10000;
2370 else if( !(nSearchType
& IMPL_FONT_ATTR_ALLSERIFSTYLE
) )
2372 if( nMatchType
& IMPL_FONT_ATTR_SERIF
)
2373 nTestMatch
+= 1000*2;
2374 else if( nMatchType
& IMPL_FONT_ATTR_SANSSERIF
)
2378 else if( (nMatchType
& IMPL_FONT_ATTR_SPECIAL
) && !(nSearchType
& IMPL_FONT_ATTR_SYMBOL
) )
2379 nTestMatch
-= 1000000;
2381 // test DECORATIVE attribute
2382 if( nSearchType
& IMPL_FONT_ATTR_DECORATIVE
)
2384 if( nMatchType
& IMPL_FONT_ATTR_DECORATIVE
)
2385 nTestMatch
+= 10000;
2386 else if( !(nSearchType
& IMPL_FONT_ATTR_ALLSERIFSTYLE
) )
2388 if( nMatchType
& IMPL_FONT_ATTR_SERIF
)
2389 nTestMatch
+= 1000*2;
2390 else if ( nMatchType
& IMPL_FONT_ATTR_SANSSERIF
)
2394 else if( nMatchType
& IMPL_FONT_ATTR_DECORATIVE
)
2395 nTestMatch
-= 1000000;
2397 // test TITLE+CAPITALS attributes
2398 if( nSearchType
& (IMPL_FONT_ATTR_TITLING
| IMPL_FONT_ATTR_CAPITALS
) )
2400 if( nMatchType
& (IMPL_FONT_ATTR_TITLING
| IMPL_FONT_ATTR_CAPITALS
) )
2401 nTestMatch
+= 1000000*2;
2402 if( 0 == ((nSearchType
^nMatchType
) & (IMPL_FONT_ATTR_TITLING
| IMPL_FONT_ATTR_CAPITALS
)))
2403 nTestMatch
+= 1000000;
2404 else if( (nMatchType
& (IMPL_FONT_ATTR_TITLING
| IMPL_FONT_ATTR_CAPITALS
))
2405 && (nMatchType
& (IMPL_FONT_ATTR_STANDARD
| IMPL_FONT_ATTR_DEFAULT
)) )
2406 nTestMatch
+= 1000000;
2408 else if( nMatchType
& (IMPL_FONT_ATTR_TITLING
| IMPL_FONT_ATTR_CAPITALS
) )
2409 nTestMatch
-= 1000000;
2411 // test OUTLINE+SHADOW attributes
2412 if( nSearchType
& (IMPL_FONT_ATTR_OUTLINE
| IMPL_FONT_ATTR_SHADOW
) )
2414 if( nMatchType
& (IMPL_FONT_ATTR_OUTLINE
| IMPL_FONT_ATTR_SHADOW
) )
2415 nTestMatch
+= 1000000*2;
2416 if( 0 == ((nSearchType
^ nMatchType
) & (IMPL_FONT_ATTR_OUTLINE
| IMPL_FONT_ATTR_SHADOW
)) )
2417 nTestMatch
+= 1000000;
2418 else if( (nMatchType
& (IMPL_FONT_ATTR_OUTLINE
| IMPL_FONT_ATTR_SHADOW
))
2419 && (nMatchType
& (IMPL_FONT_ATTR_STANDARD
| IMPL_FONT_ATTR_DEFAULT
)) )
2420 nTestMatch
+= 1000000;
2422 else if ( nMatchType
& (IMPL_FONT_ATTR_OUTLINE
| IMPL_FONT_ATTR_SHADOW
) )
2423 nTestMatch
-= 1000000;
2425 // test font name substrings
2426 if( (rSearchFamilyName
.Len() && pData
->maMatchFamilyName
.Len())
2427 && ((rSearchFamilyName
.Search( pData
->maMatchFamilyName
) != STRING_NOTFOUND
)
2428 || (pData
->maMatchFamilyName
.Search( rSearchFamilyName
) != STRING_NOTFOUND
)) )
2429 nTestMatch
+= 100000*2;
2431 // test SERIF attribute
2432 if( nSearchType
& IMPL_FONT_ATTR_SERIF
)
2434 if( nMatchType
& IMPL_FONT_ATTR_SERIF
)
2435 nTestMatch
+= 1000000*2;
2436 else if( nMatchType
& IMPL_FONT_ATTR_SANSSERIF
)
2437 nTestMatch
-= 1000000;
2440 // test SANSERIF attribute
2441 if( nSearchType
& IMPL_FONT_ATTR_SANSSERIF
)
2443 if( nMatchType
& IMPL_FONT_ATTR_SANSSERIF
)
2444 nTestMatch
+= 1000000;
2445 else if ( nMatchType
& IMPL_FONT_ATTR_SERIF
)
2446 nTestMatch
-= 1000000;
2449 // test ITALIC attribute
2450 if( nSearchType
& IMPL_FONT_ATTR_ITALIC
)
2452 if( pData
->mnTypeFaces
& IMPL_DEVFONT_ITALIC
)
2453 nTestMatch
+= 1000000*3;
2454 if( nMatchType
& IMPL_FONT_ATTR_ITALIC
)
2455 nTestMatch
+= 1000000;
2457 else if( !(nSearchType
& IMPL_FONT_ATTR_ALLSCRIPT
)
2458 && ((nMatchType
& IMPL_FONT_ATTR_ITALIC
)
2459 || !(pData
->mnTypeFaces
& IMPL_DEVFONT_NONEITALIC
)) )
2460 nTestMatch
-= 1000000*2;
2462 // test WIDTH attribute
2463 if( (eSearchWidth
!= WIDTH_DONTKNOW
) && (eSearchWidth
!= WIDTH_NORMAL
) )
2465 if( eSearchWidth
< WIDTH_NORMAL
)
2467 if( eSearchWidth
== eMatchWidth
)
2468 nTestMatch
+= 1000000*3;
2469 else if( (eMatchWidth
< WIDTH_NORMAL
) && (eMatchWidth
!= WIDTH_DONTKNOW
) )
2470 nTestMatch
+= 1000000;
2474 if( eSearchWidth
== eMatchWidth
)
2475 nTestMatch
+= 1000000*3;
2476 else if( eMatchWidth
> WIDTH_NORMAL
)
2477 nTestMatch
+= 1000000;
2480 else if( (eMatchWidth
!= WIDTH_DONTKNOW
) && (eMatchWidth
!= WIDTH_NORMAL
) )
2481 nTestMatch
-= 1000000;
2483 // test WEIGHT attribute
2484 if( (eSearchWeight
!= WEIGHT_DONTKNOW
) && (eSearchWeight
!= WEIGHT_NORMAL
) && (eSearchWeight
!= WEIGHT_MEDIUM
) )
2486 if( eSearchWeight
< WEIGHT_NORMAL
)
2488 if( pData
->mnTypeFaces
& IMPL_DEVFONT_LIGHT
)
2489 nTestMatch
+= 1000000;
2490 if( (eMatchWeight
< WEIGHT_NORMAL
) && (eMatchWeight
!= WEIGHT_DONTKNOW
) )
2491 nTestMatch
+= 1000000;
2495 if( pData
->mnTypeFaces
& IMPL_DEVFONT_BOLD
)
2496 nTestMatch
+= 1000000;
2497 if( eMatchWeight
> WEIGHT_BOLD
)
2498 nTestMatch
+= 1000000;
2501 else if( ((eMatchWeight
!= WEIGHT_DONTKNOW
) && (eMatchWeight
!= WEIGHT_NORMAL
) && (eMatchWeight
!= WEIGHT_MEDIUM
))
2502 || !(pData
->mnTypeFaces
& IMPL_DEVFONT_NORMAL
) )
2503 nTestMatch
-= 1000000;
2505 // prefer scalable fonts
2506 if( pData
->mnTypeFaces
& IMPL_DEVFONT_SCALABLE
)
2507 nTestMatch
+= 10000*4;
2509 nTestMatch
-= 10000*4;
2511 // test STANDARD+DEFAULT+FULL+NORMAL attributes
2512 if( nMatchType
& IMPL_FONT_ATTR_STANDARD
)
2513 nTestMatch
+= 10000*2;
2514 if( nMatchType
& IMPL_FONT_ATTR_DEFAULT
)
2515 nTestMatch
+= 10000;
2516 if( nMatchType
& IMPL_FONT_ATTR_FULL
)
2517 nTestMatch
+= 10000;
2518 if( nMatchType
& IMPL_FONT_ATTR_NORMAL
)
2519 nTestMatch
+= 10000;
2521 // test OTHERSTYLE attribute
2522 if( nMatchType
& IMPL_FONT_ATTR_OTHERSTYLE
)
2524 if( !(nMatchType
& IMPL_FONT_ATTR_OTHERSTYLE
) )
2525 nTestMatch
-= 10000;
2527 else if( nMatchType
& IMPL_FONT_ATTR_OTHERSTYLE
)
2528 nTestMatch
-= 10000;
2530 // test ROUNDED attribute
2531 if( 0 == ((nSearchType
^ nMatchType
) & IMPL_FONT_ATTR_ROUNDED
) )
2534 // test TYPEWRITER attribute
2535 if( 0 == ((nSearchType
^ nMatchType
) & IMPL_FONT_ATTR_TYPEWRITER
) )
2538 // test GOTHIC attribute
2539 if( nSearchType
& IMPL_FONT_ATTR_GOTHIC
)
2541 if( nMatchType
& IMPL_FONT_ATTR_GOTHIC
)
2542 nTestMatch
+= 1000*3;
2543 if( nMatchType
& IMPL_FONT_ATTR_SANSSERIF
)
2544 nTestMatch
+= 1000*2;
2547 // test SCHOOLBOOK attribute
2548 if( nSearchType
& IMPL_FONT_ATTR_SCHOOLBOOK
)
2550 if( nMatchType
& IMPL_FONT_ATTR_SCHOOLBOOK
)
2551 nTestMatch
+= 1000*3;
2552 if( nMatchType
& IMPL_FONT_ATTR_SERIF
)
2553 nTestMatch
+= 1000*2;
2556 // compare with best matching font yet
2557 if ( nTestMatch
> nBestMatch
)
2560 nBestMatch
= nTestMatch
;
2561 nBestType
= nMatchType
;
2563 else if( nTestMatch
== nBestMatch
)
2565 // some fonts are more suitable defaults
2566 if( nMatchType
& IMPL_FONT_ATTR_DEFAULT
)
2569 nBestType
= nMatchType
;
2571 else if( (nMatchType
& IMPL_FONT_ATTR_STANDARD
) &&
2572 !(nBestType
& IMPL_FONT_ATTR_DEFAULT
) )
2575 nBestType
= nMatchType
;
2583 // -----------------------------------------------------------------------
2585 ImplDevFontListData
* ImplDevFontList::FindDefaultFont() const
2587 // try to find one of the default fonts of the
2588 // UNICODE, SANSSERIF, SERIF or FIXED default font lists
2589 const DefaultFontConfiguration
& rDefaults
= *DefaultFontConfiguration::get();
2590 com::sun::star::lang::Locale
aLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
2591 String aFontname
= rDefaults
.getDefaultFont( aLocale
, DEFAULTFONT_SANS_UNICODE
);
2592 ImplDevFontListData
* pFoundData
= ImplFindByTokenNames( aFontname
);
2596 aFontname
= rDefaults
.getDefaultFont( aLocale
, DEFAULTFONT_SANS
);
2597 pFoundData
= ImplFindByTokenNames( aFontname
);
2601 aFontname
= rDefaults
.getDefaultFont( aLocale
, DEFAULTFONT_SERIF
);
2602 pFoundData
= ImplFindByTokenNames( aFontname
);
2606 aFontname
= rDefaults
.getDefaultFont( aLocale
, DEFAULTFONT_FIXED
);
2607 pFoundData
= ImplFindByTokenNames( aFontname
);
2611 // now try to find a reasonable non-symbol font
2615 DevFontList::const_iterator it
= maDevFontList
.begin();
2616 for(; it
!= maDevFontList
.end(); ++it
)
2618 ImplDevFontListData
* pData
= (*it
).second
;
2619 if( pData
->mnMatchType
& IMPL_FONT_ATTR_SYMBOL
)
2622 if( pData
->mnMatchType
& (IMPL_FONT_ATTR_DEFAULT
|IMPL_FONT_ATTR_STANDARD
) )
2628 // finding any font is better than finding no font at all
2629 it
= maDevFontList
.begin();
2630 if( it
!= maDevFontList
.end() )
2631 pFoundData
= (*it
).second
;
2636 // -----------------------------------------------------------------------
2638 ImplDevFontList
* ImplDevFontList::Clone( bool bScalable
, bool bEmbeddable
) const
2640 ImplDevFontList
* pClonedList
= new ImplDevFontList
;
2641 pClonedList
->mbMatchData
= mbMatchData
;
2642 pClonedList
->mbMapNames
= mbMapNames
;
2643 pClonedList
->mpPreMatchHook
= mpPreMatchHook
;
2644 pClonedList
->mpFallbackHook
= mpFallbackHook
;
2646 DevFontList::const_iterator it
= maDevFontList
.begin();
2647 for(; it
!= maDevFontList
.end(); ++it
)
2649 const ImplDevFontListData
* pFontFace
= (*it
).second
;
2650 pFontFace
->UpdateCloneFontList( *pClonedList
, bScalable
, bEmbeddable
);
2656 // -----------------------------------------------------------------------
2658 ImplGetDevFontList
* ImplDevFontList::GetDevFontList() const
2660 ImplGetDevFontList
* pGetDevFontList
= new ImplGetDevFontList
;
2662 DevFontList::const_iterator it
= maDevFontList
.begin();
2663 for(; it
!= maDevFontList
.end(); ++it
)
2665 const ImplDevFontListData
* pFontFamily
= (*it
).second
;
2666 pFontFamily
->UpdateDevFontList( *pGetDevFontList
);
2669 return pGetDevFontList
;
2672 // -----------------------------------------------------------------------
2674 ImplGetDevSizeList
* ImplDevFontList::GetDevSizeList( const String
& rFontName
) const
2676 ImplGetDevSizeList
* pGetDevSizeList
= new ImplGetDevSizeList( rFontName
);
2678 ImplDevFontListData
* pFontFamily
= FindFontFamily( rFontName
);
2679 if( pFontFamily
!= NULL
)
2681 std::set
<int> rHeights
;
2682 pFontFamily
->GetFontHeights( rHeights
);
2684 std::set
<int>::const_iterator it
= rHeights
.begin();
2685 for(; it
!= rHeights
.begin(); ++it
)
2686 pGetDevSizeList
->Add( *it
);
2689 return pGetDevSizeList
;
2692 // =======================================================================
2694 ImplFontSelectData::ImplFontSelectData( const Font
& rFont
,
2695 const String
& rSearchName
, const Size
& rSize
, float fExactHeight
)
2696 : maSearchName( rSearchName
),
2697 mnWidth( rSize
.Width() ),
2698 mnHeight( rSize
.Height() ),
2699 mfExactHeight( fExactHeight
),
2700 mnOrientation( rFont
.GetOrientation() ),
2701 meLanguage( rFont
.GetLanguage() ),
2702 mbVertical( rFont
.IsVertical() ),
2703 mbNonAntialiased( false ),
2707 maTargetName
= maName
;
2709 rFont
.GetFontAttributes( *this );
2711 // normalize orientation between 0 and 3600
2712 if( 3600 <= (unsigned)mnOrientation
)
2714 if( mnOrientation
>= 0 )
2715 mnOrientation
%= 3600;
2717 mnOrientation
= 3600 - (-mnOrientation
% 3600);
2720 // normalize width and height
2722 mnHeight
= -mnHeight
;
2727 // -----------------------------------------------------------------------
2729 ImplFontSelectData::ImplFontSelectData( const ImplFontData
& rFontData
,
2730 const Size
& rSize
, float fExactHeight
, int nOrientation
, bool bVertical
)
2731 : ImplFontAttributes( rFontData
),
2732 mnWidth( rSize
.Width() ),
2733 mnHeight( rSize
.Height() ),
2734 mfExactHeight( fExactHeight
),
2735 mnOrientation( nOrientation
),
2737 mbVertical( bVertical
),
2738 mbNonAntialiased( false ),
2739 mpFontData( &rFontData
),
2742 maTargetName
= maSearchName
= maName
;
2743 // NOTE: no normalization for width/height/orientation
2746 // =======================================================================
2748 size_t ImplFontCache::IFSD_Hash::operator()( const ImplFontSelectData
& rFSD
) const
2750 // TODO: does it pay off to improve this hash function?
2751 static FontNameHash aFontNameHash
;
2752 size_t nHash
= aFontNameHash( rFSD
.maSearchName
);
2753 #ifdef ENABLE_GRAPHITE
2754 // check for features and generate a unique hash if necessary
2755 if (rFSD
.maTargetName
.Search(grutils::GrFeatureParser::FEAT_PREFIX
)
2758 nHash
= aFontNameHash( rFSD
.maTargetName
);
2761 nHash
+= 11 * rFSD
.mnHeight
;
2762 nHash
+= 19 * rFSD
.meWeight
;
2763 nHash
+= 29 * rFSD
.meItalic
;
2764 nHash
+= 37 * rFSD
.mnOrientation
;
2765 nHash
+= 41 * rFSD
.meLanguage
;
2766 if( rFSD
.mbVertical
)
2771 // -----------------------------------------------------------------------
2773 bool ImplFontCache::IFSD_Equal::operator()(const ImplFontSelectData
& rA
, const ImplFontSelectData
& rB
) const
2775 // check normalized font family name
2776 if( rA
.maSearchName
!= rB
.maSearchName
)
2779 // check font transformation
2780 if( (rA
.mnHeight
!= rB
.mnHeight
)
2781 || (rA
.mnWidth
!= rB
.mnWidth
)
2782 || (rA
.mnOrientation
!= rB
.mnOrientation
) )
2785 // check mapping relevant attributes
2786 if( (rA
.mbVertical
!= rB
.mbVertical
)
2787 || (rA
.meLanguage
!= rB
.meLanguage
) )
2790 // check font face attributes
2791 if( (rA
.meWeight
!= rB
.meWeight
)
2792 || (rA
.meItalic
!= rB
.meItalic
)
2793 // || (rA.meFamily != rB.meFamily) // TODO: remove this mostly obsolete member
2794 || (rA
.mePitch
!= rB
.mePitch
) )
2798 if( rA
.maStyleName
!= rB
.maStyleName
)
2801 // Symbol fonts may recode from one type to another So they are only
2802 // safely equivalent for equal targets
2804 (rA
.mpFontData
&& rA
.mpFontData
->IsSymbolFont()) ||
2805 (rB
.mpFontData
&& rB
.mpFontData
->IsSymbolFont())
2808 if (rA
.maTargetName
!= rB
.maTargetName
)
2812 #ifdef ENABLE_GRAPHITE
2813 // check for features
2814 if ((rA
.maTargetName
.Search(grutils::GrFeatureParser::FEAT_PREFIX
)
2815 != STRING_NOTFOUND
||
2816 rB
.maTargetName
.Search(grutils::GrFeatureParser::FEAT_PREFIX
)
2817 != STRING_NOTFOUND
) && rA
.maTargetName
!= rB
.maTargetName
)
2824 // -----------------------------------------------------------------------
2826 ImplFontCache::ImplFontCache( bool bPrinter
)
2827 : mpFirstEntry( NULL
),
2829 mbPrinter( bPrinter
)
2832 // -----------------------------------------------------------------------
2834 ImplFontCache::~ImplFontCache()
2836 FontInstanceList::iterator it
= maFontInstanceList
.begin();
2837 for(; it
!= maFontInstanceList
.end(); ++it
)
2839 ImplFontEntry
* pEntry
= (*it
).second
;
2844 // -----------------------------------------------------------------------
2846 ImplFontEntry
* ImplFontCache::GetFontEntry( ImplDevFontList
* pFontList
,
2847 const Font
& rFont
, const Size
& rSize
, float fExactHeight
, ImplDirectFontSubstitution
* pDevSpecific
)
2849 String aSearchName
= rFont
.GetName();
2851 // TODO: also add device specific name caching
2854 // check if the requested font name is already known
2855 // if it is already known get its normalized search name
2856 FontNameList::const_iterator it_name
= maFontNameList
.find( aSearchName
);
2857 if( it_name
!= maFontNameList
.end() )
2858 if( !(*it_name
).second
.EqualsAscii( "hg", 0, 2)
2859 #ifdef ENABLE_GRAPHITE
2860 && (aSearchName
.Search(grutils::GrFeatureParser::FEAT_PREFIX
)
2864 aSearchName
= (*it_name
).second
;
2867 // initialize internal font request object
2868 ImplFontSelectData
aFontSelData( rFont
, aSearchName
, rSize
, fExactHeight
);
2869 return GetFontEntry( pFontList
, aFontSelData
, pDevSpecific
);
2872 // -----------------------------------------------------------------------
2874 ImplFontEntry
* ImplFontCache::GetFontEntry( ImplDevFontList
* pFontList
,
2875 ImplFontSelectData
& aFontSelData
, ImplDirectFontSubstitution
* pDevSpecific
)
2877 // check if a directly matching logical font instance is already cached,
2878 // the most recently used font usually has a hit rate of >50%
2879 ImplFontEntry
*pEntry
= NULL
;
2880 ImplDevFontListData
* pFontFamily
= NULL
;
2881 IFSD_Equal aIFSD_Equal
;
2882 if( mpFirstEntry
&& aIFSD_Equal( aFontSelData
, mpFirstEntry
->maFontSelData
) )
2883 pEntry
= mpFirstEntry
;
2886 FontInstanceList::iterator it
= maFontInstanceList
.find( aFontSelData
);
2887 if( it
!= maFontInstanceList
.end() )
2888 pEntry
= (*it
).second
;
2891 if( !pEntry
) // no direct cache hit
2893 // find the best matching logical font family and update font selector accordingly
2894 pFontFamily
= pFontList
->ImplFindByFont( aFontSelData
, mbPrinter
, pDevSpecific
);
2895 DBG_ASSERT( (pFontFamily
!= NULL
), "ImplFontCache::Get() No logical font found!" );
2897 aFontSelData
.maSearchName
= pFontFamily
->GetSearchName();
2899 // check if an indirectly matching logical font instance is already cached
2900 FontInstanceList::iterator it
= maFontInstanceList
.find( aFontSelData
);
2901 if( it
!= maFontInstanceList
.end() )
2903 // we have an indirect cache hit
2904 pEntry
= (*it
).second
;
2905 // cache the requested and the selected font names
2906 // => next time there is a good chance for a direct cache hit
2907 // don't allow the cache to grow too big
2908 // TODO: implement some fancy LRU caching?
2909 if( maFontNameList
.size() >= 4000 )
2910 maFontNameList
.clear();
2911 // TODO: also add device specific name caching
2913 if( aFontSelData
.maName
!= aFontSelData
.maSearchName
)
2914 maFontNameList
[ aFontSelData
.maName
] = aFontSelData
.maSearchName
;
2918 if( pEntry
) // cache hit => use existing font instance
2920 // increase the font instance's reference count
2921 if( !pEntry
->mnRefCount
++ )
2924 else // no cache hit => create a new font instance
2926 // find the best matching physical font face
2927 ImplFontData
* pFontData
= pFontFamily
->FindBestFontFace( aFontSelData
);
2928 aFontSelData
.mpFontData
= pFontData
;
2930 // create a new logical font instance from this physical font face
2931 pEntry
= pFontData
->CreateFontInstance( aFontSelData
);
2933 // if we found a different symbol font we need a symbol conversion table
2934 if( pFontData
->IsSymbolFont() )
2935 if( aFontSelData
.maTargetName
!= aFontSelData
.maSearchName
)
2936 pEntry
->mpConversion
= ImplGetRecodeData( aFontSelData
.maTargetName
, aFontSelData
.maSearchName
);
2938 // add the new entry to the cache
2939 maFontInstanceList
[ aFontSelData
] = pEntry
;
2942 mpFirstEntry
= pEntry
;
2946 // -----------------------------------------------------------------------
2948 ImplDevFontListData
* ImplDevFontList::ImplFindByFont( ImplFontSelectData
& rFSD
,
2949 bool bPrinter
, ImplDirectFontSubstitution
* pDevSpecific
) const
2951 // give up if no fonts are available
2955 // test if a font in the token list is available
2956 // substitute the font if this was requested
2957 USHORT nSubstFlags
= FONT_SUBSTITUTE_ALWAYS
;
2959 nSubstFlags
|= FONT_SUBSTITUTE_SCREENONLY
;
2961 bool bMultiToken
= false;
2962 xub_StrLen nTokenPos
= 0;
2963 String
& aSearchName
= rFSD
.maSearchName
; // TODO: get rid of reference
2966 rFSD
.maTargetName
= GetNextFontToken( rFSD
.maName
, nTokenPos
);
2967 aSearchName
= rFSD
.maTargetName
;
2969 #ifdef ENABLE_GRAPHITE
2970 // Until features are properly supported, they are appended to the
2971 // font name, so we need to strip them off so the font is found.
2972 xub_StrLen nFeat
= aSearchName
.Search(grutils::GrFeatureParser::FEAT_PREFIX
);
2973 String aOrigName
= rFSD
.maTargetName
;
2974 String
aBaseFontName(aSearchName
, 0, (nFeat
!= STRING_NOTFOUND
)?nFeat
:aSearchName
.Len());
2975 if (nFeat
!= STRING_NOTFOUND
&& STRING_NOTFOUND
!=
2976 aSearchName
.Search(grutils::GrFeatureParser::FEAT_ID_VALUE_SEPARATOR
, nFeat
))
2978 aSearchName
= aBaseFontName
;
2979 rFSD
.maTargetName
= aBaseFontName
;
2984 ImplGetEnglishSearchFontName( aSearchName
);
2985 ImplFontSubstitute( aSearchName
, nSubstFlags
, pDevSpecific
);
2986 // #114999# special emboldening for Ricoh fonts
2987 // TODO: smarter check for special cases by using PreMatch infrastructure?
2988 if( (rFSD
.meWeight
> WEIGHT_MEDIUM
)
2989 && aSearchName
.EqualsAscii( "hg", 0, 2) )
2992 if( aSearchName
.EqualsAscii( "hggothicb", 0, 9) )
2993 aBoldName
= String(RTL_CONSTASCII_USTRINGPARAM("hggothice"));
2994 else if( aSearchName
.EqualsAscii( "hgpgothicb", 0, 10) )
2995 aBoldName
= String(RTL_CONSTASCII_USTRINGPARAM("hgpgothice"));
2996 else if( aSearchName
.EqualsAscii( "hgminchol", 0, 9) )
2997 aBoldName
= String(RTL_CONSTASCII_USTRINGPARAM("hgminchob"));
2998 else if( aSearchName
.EqualsAscii( "hgpminchol", 0, 10) )
2999 aBoldName
= String(RTL_CONSTASCII_USTRINGPARAM("hgpminchob"));
3000 else if( aSearchName
.EqualsAscii( "hgminchob" ) )
3001 aBoldName
= String(RTL_CONSTASCII_USTRINGPARAM("hgminchoe"));
3002 else if( aSearchName
.EqualsAscii( "hgpminchob" ) )
3003 aBoldName
= String(RTL_CONSTASCII_USTRINGPARAM("hgpminchoe"));
3005 if( aBoldName
.Len() && ImplFindBySearchName( aBoldName
) )
3007 // the other font is available => use it
3008 aSearchName
= aBoldName
;
3009 // prevent synthetic emboldening of bold version
3010 rFSD
.meWeight
= WEIGHT_DONTKNOW
;
3014 #ifdef ENABLE_GRAPHITE
3015 // restore the features to make the font selection data unique
3016 rFSD
.maTargetName
= aOrigName
;
3018 // check if the current font name token or its substitute is valid
3019 ImplDevFontListData
* pFoundData
= ImplFindBySearchName( aSearchName
);
3023 // some systems provide special customization
3024 // e.g. they suggest "serif" as UI-font, but this name cannot be used directly
3025 // because the system wants to map it to another font first, e.g. "Helvetica"
3026 #ifdef ENABLE_GRAPHITE
3027 // use the target name to search in the prematch hook
3028 rFSD
.maTargetName
= aBaseFontName
;
3030 if( mpPreMatchHook
)
3031 if( mpPreMatchHook
->FindFontSubstitute( rFSD
) )
3032 ImplGetEnglishSearchFontName( aSearchName
);
3033 #ifdef ENABLE_GRAPHITE
3034 // the prematch hook uses the target name to search, but we now need
3035 // to restore the features to make the font selection data unique
3036 rFSD
.maTargetName
= aOrigName
;
3038 pFoundData
= ImplFindBySearchName( aSearchName
);
3042 // break after last font name token was checked unsuccessfully
3043 if( nTokenPos
== STRING_NOTFOUND
)
3048 // if the first font was not available find the next available font in
3049 // the semicolon separated list of font names. A font is also considered
3050 // available when there is a matching entry in the Tools->Options->Fonts
3051 // dialog witho neither ALWAYS nor SCREENONLY flags set and the substitution
3052 // font is available
3053 for( nTokenPos
= 0; nTokenPos
!= STRING_NOTFOUND
; )
3057 rFSD
.maTargetName
= GetNextFontToken( rFSD
.maName
, nTokenPos
);
3058 aSearchName
= rFSD
.maTargetName
;
3059 ImplGetEnglishSearchFontName( aSearchName
);
3062 nTokenPos
= STRING_NOTFOUND
;
3063 if( mpPreMatchHook
)
3064 if( mpPreMatchHook
->FindFontSubstitute( rFSD
) )
3065 ImplGetEnglishSearchFontName( aSearchName
);
3066 ImplFontSubstitute( aSearchName
, nSubstFlags
, pDevSpecific
);
3067 ImplDevFontListData
* pFoundData
= ImplFindBySearchName( aSearchName
);
3072 // if no font with a directly matching name is available use the
3073 // first font name token and get its attributes to find a replacement
3077 rFSD
.maTargetName
= GetNextFontToken( rFSD
.maName
, nTokenPos
);
3078 aSearchName
= rFSD
.maTargetName
;
3079 ImplGetEnglishSearchFontName( aSearchName
);
3082 String aSearchShortName
;
3083 String aSearchFamilyName
;
3084 FontWeight eSearchWeight
= rFSD
.meWeight
;
3085 FontWidth eSearchWidth
= rFSD
.meWidthType
;
3086 ULONG nSearchType
= 0;
3087 FontSubstConfiguration::getMapName( aSearchName
, aSearchShortName
, aSearchFamilyName
,
3088 eSearchWeight
, eSearchWidth
, nSearchType
);
3090 // note: the search name was already translated to english (if possible)
3092 // use the font's shortened name if needed
3093 if ( aSearchShortName
!= aSearchName
)
3095 ImplDevFontListData
* pFoundData
= ImplFindBySearchName( aSearchShortName
);
3099 /* #96738# don't use mincho as an replacement for "MS Mincho" on X11: Mincho is
3100 a korean bitmap font that is not suitable here. Use the font replacement table,
3101 that automatically leads to the desired "HG Mincho Light J". Same story for
3102 MS Gothic, there are thai and korean "Gothic" fonts, so we even prefer Andale */
3103 static String
aMS_Mincho( RTL_CONSTASCII_USTRINGPARAM("msmincho") );
3104 static String
aMS_Gothic( RTL_CONSTASCII_USTRINGPARAM("msgothic") );
3105 if ((aSearchName
!= aMS_Mincho
) && (aSearchName
!= aMS_Gothic
))
3106 // TODO: add heuristic to only throw out the fake ms* fonts
3114 // use font fallback
3115 const FontNameAttr
* pFontAttr
= NULL
;
3116 if( aSearchName
.Len() )
3118 // get fallback info using FontSubstConfiguration and
3119 // the target name, it's shortened name and family name in that order
3120 const FontSubstConfiguration
& rFontSubst
= *FontSubstConfiguration::get();
3121 pFontAttr
= rFontSubst
.getSubstInfo( aSearchName
);
3122 if ( !pFontAttr
&& (aSearchShortName
!= aSearchName
) )
3123 pFontAttr
= rFontSubst
.getSubstInfo( aSearchShortName
);
3124 if ( !pFontAttr
&& (aSearchFamilyName
!= aSearchShortName
) )
3125 pFontAttr
= rFontSubst
.getSubstInfo( aSearchFamilyName
);
3127 // try the font substitutions suggested by the fallback info
3130 ImplDevFontListData
* pFoundData
= ImplFindBySubstFontAttr( *pFontAttr
);
3136 // if a target symbol font is not available use a default symbol font
3137 if( rFSD
.IsSymbolFont() )
3139 com::sun::star::lang::Locale
aDefaultLocale( OUString( RTL_CONSTASCII_USTRINGPARAM("en") ), OUString(), OUString() );
3140 aSearchName
= DefaultFontConfiguration::get()->getDefaultFont( aDefaultLocale
, DEFAULTFONT_SYMBOL
);
3141 ImplDevFontListData
* pFoundData
= ImplFindByTokenNames( aSearchName
);
3146 // now try the other font name tokens
3147 while( nTokenPos
!= STRING_NOTFOUND
)
3149 rFSD
.maTargetName
= GetNextFontToken( rFSD
.maName
, nTokenPos
);
3150 if( !rFSD
.maTargetName
.Len() )
3153 aSearchName
= rFSD
.maTargetName
;
3154 ImplGetEnglishSearchFontName( aSearchName
);
3156 String aTempShortName
;
3157 String aTempFamilyName
;
3158 ULONG nTempType
= 0;
3159 FontWeight eTempWeight
= rFSD
.meWeight
;
3160 FontWidth eTempWidth
= WIDTH_DONTKNOW
;
3161 FontSubstConfiguration::getMapName( aSearchName
, aTempShortName
, aTempFamilyName
,
3162 eTempWeight
, eTempWidth
, nTempType
);
3164 // use a shortend token name if available
3165 if( aTempShortName
!= aSearchName
)
3167 ImplDevFontListData
* pFoundData
= ImplFindBySearchName( aTempShortName
);
3172 // use a font name from font fallback list to determine font attributes
3174 // get fallback info using FontSubstConfiguration and
3175 // the target name, it's shortened name and family name in that order
3176 const FontSubstConfiguration
& rFontSubst
= *FontSubstConfiguration::get();
3177 const FontNameAttr
* pTempFontAttr
= rFontSubst
.getSubstInfo( aSearchName
);
3178 if ( !pTempFontAttr
&& (aTempShortName
!= aSearchName
) )
3179 pTempFontAttr
= rFontSubst
.getSubstInfo( aTempShortName
);
3180 if ( !pTempFontAttr
&& (aTempFamilyName
!= aTempShortName
) )
3181 pTempFontAttr
= rFontSubst
.getSubstInfo( aTempFamilyName
);
3183 // try the font substitutions suggested by the fallback info
3186 ImplDevFontListData
* pFoundData
= ImplFindBySubstFontAttr( *pTempFontAttr
);
3190 pFontAttr
= pTempFontAttr
;
3194 // if still needed use the alias names of the installed fonts
3197 ImplDevFontListData
* pFoundData
= ImplFindByAliasName( rFSD
.maTargetName
, aSearchShortName
);
3202 // if still needed use the font request's attributes to find a good match
3203 switch( rFSD
.meLanguage
)
3205 case LANGUAGE_CHINESE
:
3206 case LANGUAGE_CHINESE_SIMPLIFIED
:
3207 case LANGUAGE_CHINESE_SINGAPORE
:
3208 nSearchType
|= IMPL_FONT_ATTR_CJK
| IMPL_FONT_ATTR_CJK_SC
;
3210 case LANGUAGE_CHINESE_TRADITIONAL
:
3211 case LANGUAGE_CHINESE_HONGKONG
:
3212 case LANGUAGE_CHINESE_MACAU
:
3213 nSearchType
|= IMPL_FONT_ATTR_CJK
| IMPL_FONT_ATTR_CJK_TC
;
3215 case LANGUAGE_KOREAN
:
3216 case LANGUAGE_KOREAN_JOHAB
:
3217 nSearchType
|= IMPL_FONT_ATTR_CJK
| IMPL_FONT_ATTR_CJK_KR
;
3219 case LANGUAGE_JAPANESE
:
3220 nSearchType
|= IMPL_FONT_ATTR_CJK
| IMPL_FONT_ATTR_CJK_JP
;
3223 nSearchType
|= ImplIsCJKFont( rFSD
.maName
);
3224 if( rFSD
.IsSymbolFont() )
3225 nSearchType
|= IMPL_FONT_ATTR_SYMBOL
;
3229 ImplCalcType( nSearchType
, eSearchWeight
, eSearchWidth
, rFSD
.meFamily
, pFontAttr
);
3230 ImplDevFontListData
* pFoundData
= ImplFindByAttributes( nSearchType
,
3231 eSearchWeight
, eSearchWidth
, rFSD
.meFamily
, rFSD
.meItalic
, aSearchFamilyName
);
3235 // overwrite font selection attributes using info from the typeface flags
3236 if( (eSearchWeight
>= WEIGHT_BOLD
)
3237 && (eSearchWeight
> rFSD
.meWeight
)
3238 && (pFoundData
->mnTypeFaces
& IMPL_DEVFONT_BOLD
) )
3239 rFSD
.meWeight
= eSearchWeight
;
3240 else if( (eSearchWeight
< WEIGHT_NORMAL
)
3241 && (eSearchWeight
< rFSD
.meWeight
)
3242 && (eSearchWeight
!= WEIGHT_DONTKNOW
)
3243 && (pFoundData
->mnTypeFaces
& IMPL_DEVFONT_LIGHT
) )
3244 rFSD
.meWeight
= eSearchWeight
;
3246 if( (nSearchType
& IMPL_FONT_ATTR_ITALIC
)
3247 && ((rFSD
.meItalic
== ITALIC_DONTKNOW
) || (rFSD
.meItalic
== ITALIC_NONE
))
3248 && (pFoundData
->mnTypeFaces
& IMPL_DEVFONT_ITALIC
) )
3249 rFSD
.meItalic
= ITALIC_NORMAL
;
3253 // if still needed fall back to default fonts
3254 pFoundData
= FindDefaultFont();
3260 // -----------------------------------------------------------------------
3262 ImplFontEntry
* ImplFontCache::GetGlyphFallbackFont( ImplDevFontList
* pFontList
,
3263 ImplFontSelectData
& rFontSelData
, int nFallbackLevel
, rtl::OUString
& rMissingCodes
)
3265 // get a candidate font for glyph fallback
3266 // unless the previously selected font got a device specific substitution
3267 // e.g. PsPrint Arial->Helvetica for udiaeresis when Helvetica doesn't support it
3268 if( nFallbackLevel
>= 1)
3270 ImplDevFontListData
* pFallbackData
= pFontList
->GetGlyphFallbackFont(
3271 rFontSelData
, rMissingCodes
, nFallbackLevel
-1 );
3272 // escape when there are no font candidates
3273 if( !pFallbackData
)
3275 // override the font name
3276 rFontSelData
.maName
= pFallbackData
->GetFamilyName();
3277 // clear the cached normalized name
3278 rFontSelData
.maSearchName
= String();
3281 // get device font without doing device specific substitutions
3282 ImplFontEntry
* pFallbackFont
= GetFontEntry( pFontList
, rFontSelData
, NULL
);
3283 return pFallbackFont
;
3286 // -----------------------------------------------------------------------
3288 void ImplFontCache::Release( ImplFontEntry
* pEntry
)
3290 static const int FONTCACHE_MAX
= 50;
3292 DBG_ASSERT( (pEntry
->mnRefCount
> 0), "ImplFontCache::Release() - font refcount underflow" );
3293 if( --pEntry
->mnRefCount
> 0 )
3296 if( ++mnRef0Count
< FONTCACHE_MAX
)
3299 // remove unused entries from font instance cache
3300 FontInstanceList::iterator it_next
= maFontInstanceList
.begin();
3301 while( it_next
!= maFontInstanceList
.end() )
3303 FontInstanceList::iterator it
= it_next
++;
3304 ImplFontEntry
* pFontEntry
= (*it
).second
;
3305 if( pFontEntry
->mnRefCount
> 0 )
3308 maFontInstanceList
.erase( it
);
3311 DBG_ASSERT( (mnRef0Count
>=0), "ImplFontCache::Release() - refcount0 underflow" );
3313 if( mpFirstEntry
== pFontEntry
)
3314 mpFirstEntry
= NULL
;
3317 DBG_ASSERT( (mnRef0Count
==0), "ImplFontCache::Release() - refcount0 mismatch" );
3320 // -----------------------------------------------------------------------
3322 void ImplFontCache::Invalidate()
3324 // delete unreferenced entries
3325 FontInstanceList::iterator it
= maFontInstanceList
.begin();
3326 for(; it
!= maFontInstanceList
.end(); ++it
)
3328 ImplFontEntry
* pFontEntry
= (*it
).second
;
3329 if( pFontEntry
->mnRefCount
> 0 )
3336 // #112304# make sure the font cache is really clean
3337 mpFirstEntry
= NULL
;
3338 maFontInstanceList
.clear();
3340 DBG_ASSERT( (mnRef0Count
==0), "ImplFontCache::Invalidate() - mnRef0Count non-zero" );
3343 // =======================================================================
3345 ImplMultiTextLineInfo::ImplMultiTextLineInfo()
3347 mpLines
= new PImplTextLineInfo
[MULTITEXTLINEINFO_RESIZE
];
3349 mnSize
= MULTITEXTLINEINFO_RESIZE
;
3353 ImplMultiTextLineInfo::~ImplMultiTextLineInfo()
3355 for ( xub_StrLen i
= 0; i
< mnLines
; i
++ )
3360 void ImplMultiTextLineInfo::AddLine( ImplTextLineInfo
* pLine
)
3362 if ( mnSize
== mnLines
)
3364 mnSize
+= MULTITEXTLINEINFO_RESIZE
;
3365 PImplTextLineInfo
* pNewLines
= new PImplTextLineInfo
[mnSize
];
3366 memcpy( pNewLines
, mpLines
, mnLines
*sizeof(PImplTextLineInfo
) );
3367 mpLines
= pNewLines
;
3370 mpLines
[mnLines
] = pLine
;
3374 void ImplMultiTextLineInfo::Clear()
3376 for ( xub_StrLen i
= 0; i
< mnLines
; i
++ )
3381 // =======================================================================
3383 FontEmphasisMark
OutputDevice::ImplGetEmphasisMarkStyle( const Font
& rFont
)
3385 FontEmphasisMark nEmphasisMark
= rFont
.GetEmphasisMark();
3387 // If no Position is set, then calculate the default position, which
3388 // depends on the language
3389 if ( !(nEmphasisMark
& (EMPHASISMARK_POS_ABOVE
| EMPHASISMARK_POS_BELOW
)) )
3391 LanguageType eLang
= rFont
.GetLanguage();
3392 // In Chinese Simplified the EmphasisMarks are below/left
3393 if ( (eLang
== LANGUAGE_CHINESE_SIMPLIFIED
) ||
3394 (eLang
== LANGUAGE_CHINESE_SINGAPORE
) )
3395 nEmphasisMark
|= EMPHASISMARK_POS_BELOW
;
3398 eLang
= rFont
.GetCJKContextLanguage();
3399 // In Chinese Simplified the EmphasisMarks are below/left
3400 if ( (eLang
== LANGUAGE_CHINESE_SIMPLIFIED
) ||
3401 (eLang
== LANGUAGE_CHINESE_SINGAPORE
) )
3402 nEmphasisMark
|= EMPHASISMARK_POS_BELOW
;
3404 nEmphasisMark
|= EMPHASISMARK_POS_ABOVE
;
3408 return nEmphasisMark
;
3411 // -----------------------------------------------------------------------
3413 BOOL
OutputDevice::ImplIsUnderlineAbove( const Font
& rFont
)
3415 if ( !rFont
.IsVertical() )
3418 if( (LANGUAGE_JAPANESE
== rFont
.GetLanguage())
3419 || (LANGUAGE_JAPANESE
== rFont
.GetCJKContextLanguage()) )
3420 // the underline is right for Japanese only
3426 // =======================================================================
3428 void OutputDevice::ImplInitFontList() const
3430 if( ! mpFontList
->Count() )
3432 if( mpGraphics
|| ImplGetGraphics() )
3434 RTL_LOGFILE_CONTEXT( aLog
, "OutputDevice::ImplInitFontList()" );
3435 mpGraphics
->GetDevFontList( mpFontList
);
3440 // =======================================================================
3442 void OutputDevice::ImplInitFont() const
3444 DBG_TESTSOLARMUTEX();
3448 if ( meOutDevType
!= OUTDEV_PRINTER
)
3450 // decide if antialiasing is appropriate
3451 bool bNonAntialiased
= (GetAntialiasing() & ANTIALIASING_DISABLE_TEXT
) != 0;
3452 const StyleSettings
& rStyleSettings
= GetSettings().GetStyleSettings();
3453 bNonAntialiased
|= ((rStyleSettings
.GetDisplayOptions() & DISPLAY_OPTION_AA_DISABLE
) != 0);
3454 bNonAntialiased
|= (int(rStyleSettings
.GetAntialiasingMinPixelHeight()) > mpFontEntry
->maFontSelData
.mnHeight
);
3455 mpFontEntry
->maFontSelData
.mbNonAntialiased
= bNonAntialiased
;
3458 if( !mpPDFWriter
|| !mpPDFWriter
->isBuiltinFont( mpFontEntry
->maFontSelData
.mpFontData
) )
3460 // select font in the device layers
3461 mpFontEntry
->mnSetFontFlags
= mpGraphics
->SetFont( &(mpFontEntry
->maFontSelData
), 0 );
3467 // -----------------------------------------------------------------------
3469 void OutputDevice::ImplInitTextColor()
3471 DBG_TESTSOLARMUTEX();
3473 if ( mbInitTextColor
)
3475 mpGraphics
->SetTextColor( ImplColorToSal( GetTextColor() ) );
3476 mbInitTextColor
= FALSE
;
3480 // -----------------------------------------------------------------------
3482 bool OutputDevice::ImplNewFont() const
3484 DBG_TESTSOLARMUTEX();
3486 // get correct font list on the PDF writer if necessary
3489 const ImplSVData
* pSVData
= ImplGetSVData();
3490 if( mpFontList
== pSVData
->maGDIData
.mpScreenFontList
3491 || mpFontCache
== pSVData
->maGDIData
.mpScreenFontCache
)
3492 const_cast<OutputDevice
&>(*this).ImplUpdateFontData( true );
3498 // we need a graphics
3499 if ( !mpGraphics
&& !ImplGetGraphics() )
3501 SalGraphics
* pGraphics
= mpGraphics
;
3504 // convert to pixel height
3505 // TODO: replace integer based aSize completely with subpixel accurate type
3506 float fExactHeight
= ImplFloatLogicHeightToDevicePixel( static_cast<float>(maFont
.GetHeight()) );
3507 Size aSize
= ImplLogicToDevicePixel( maFont
.GetSize() );
3508 if ( !aSize
.Height() )
3510 // use default pixel height only when logical height is zero
3511 if ( maFont
.GetSize().Height() )
3514 aSize
.Height() = (12*mnDPIY
)/72;
3515 fExactHeight
= static_cast<float>(aSize
.Height());
3518 // select the default width only when logical width is zero
3519 if( (0 == aSize
.Width()) && (0 != maFont
.GetSize().Width()) )
3523 ImplDirectFontSubstitution
* pDevSpecificSubst
= NULL
;
3525 pDevSpecificSubst
= &mpOutDevData
->maDevFontSubst
;
3526 ImplFontEntry
* pOldEntry
= mpFontEntry
;
3527 mpFontEntry
= mpFontCache
->GetFontEntry( mpFontList
, maFont
, aSize
, fExactHeight
, pDevSpecificSubst
);
3529 mpFontCache
->Release( pOldEntry
);
3531 ImplFontEntry
* pFontEntry
= mpFontEntry
;
3532 // mark when lower layers need to get involved
3534 if( pFontEntry
!= pOldEntry
)
3537 // select font when it has not been initialized yet
3538 if ( !pFontEntry
->mbInit
)
3542 // get metric data from device layers
3545 pFontEntry
->mbInit
= true;
3547 pFontEntry
->maMetric
.mnOrientation
= sal::static_int_cast
<short>(pFontEntry
->maFontSelData
.mnOrientation
);
3548 if( mpPDFWriter
&& mpPDFWriter
->isBuiltinFont( pFontEntry
->maFontSelData
.mpFontData
) )
3549 mpPDFWriter
->getFontMetric( &pFontEntry
->maFontSelData
, &(pFontEntry
->maMetric
) );
3551 pGraphics
->GetFontMetric( &(pFontEntry
->maMetric
) );
3553 pFontEntry
->maMetric
.ImplInitTextLineSize( this );
3554 pFontEntry
->maMetric
.ImplInitAboveTextLineSize();
3556 pFontEntry
->mnLineHeight
= pFontEntry
->maMetric
.mnAscent
+ pFontEntry
->maMetric
.mnDescent
;
3558 if( pFontEntry
->maFontSelData
.mnOrientation
3559 && !pFontEntry
->maMetric
.mnOrientation
3560 && (meOutDevType
!= OUTDEV_PRINTER
) )
3562 pFontEntry
->mnOwnOrientation
= sal::static_int_cast
<short>(pFontEntry
->maFontSelData
.mnOrientation
);
3563 pFontEntry
->mnOrientation
= pFontEntry
->mnOwnOrientation
;
3566 pFontEntry
->mnOrientation
= pFontEntry
->maMetric
.mnOrientation
;
3570 // enable kerning array if requested
3571 if ( maFont
.GetKerning() & KERNING_FONTSPECIFIC
)
3573 // TODO: test if physical font supports kerning and disable if not
3574 if( pFontEntry
->maMetric
.mbKernableFont
)
3579 if ( maFont
.GetKerning() & KERNING_ASIAN
)
3582 // calculate EmphasisArea
3583 mnEmphasisAscent
= 0;
3584 mnEmphasisDescent
= 0;
3585 if ( maFont
.GetEmphasisMark() & EMPHASISMARK_STYLE
)
3587 FontEmphasisMark nEmphasisMark
= ImplGetEmphasisMarkStyle( maFont
);
3588 long nEmphasisHeight
= (pFontEntry
->mnLineHeight
*250)/1000;
3589 if ( nEmphasisHeight
< 1 )
3590 nEmphasisHeight
= 1;
3591 if ( nEmphasisMark
& EMPHASISMARK_POS_BELOW
)
3592 mnEmphasisDescent
= nEmphasisHeight
;
3594 mnEmphasisAscent
= nEmphasisHeight
;
3597 // calculate text offset depending on TextAlignment
3598 TextAlign eAlign
= maFont
.GetAlign();
3599 if ( eAlign
== ALIGN_BASELINE
)
3604 else if ( eAlign
== ALIGN_TOP
)
3607 mnTextOffY
= +pFontEntry
->maMetric
.mnAscent
+ mnEmphasisAscent
;
3608 if ( pFontEntry
->mnOrientation
)
3609 ImplRotatePos( 0, 0, mnTextOffX
, mnTextOffY
, pFontEntry
->mnOrientation
);
3611 else // eAlign == ALIGN_BOTTOM
3614 mnTextOffY
= -pFontEntry
->maMetric
.mnDescent
+ mnEmphasisDescent
;
3615 if ( pFontEntry
->mnOrientation
)
3616 ImplRotatePos( 0, 0, mnTextOffX
, mnTextOffY
, pFontEntry
->mnOrientation
);
3619 mbTextLines
= ((maFont
.GetUnderline() != UNDERLINE_NONE
) && (maFont
.GetUnderline() != UNDERLINE_DONTKNOW
)) ||
3620 ((maFont
.GetOverline() != UNDERLINE_NONE
) && (maFont
.GetOverline() != UNDERLINE_DONTKNOW
)) ||
3621 ((maFont
.GetStrikeout() != STRIKEOUT_NONE
) && (maFont
.GetStrikeout() != STRIKEOUT_DONTKNOW
));
3622 mbTextSpecial
= maFont
.IsShadow() || maFont
.IsOutline() ||
3623 (maFont
.GetRelief() != RELIEF_NONE
);
3625 // #95414# fix for OLE objects which use scale factors very creatively
3626 if( mbMap
&& !aSize
.Width() )
3628 int nOrigWidth
= pFontEntry
->maMetric
.mnWidth
;
3629 float fStretch
= (float)maMapRes
.mnMapScNumX
* maMapRes
.mnMapScDenomY
;
3630 fStretch
/= (float)maMapRes
.mnMapScNumY
* maMapRes
.mnMapScDenomX
;
3631 int nNewWidth
= (int)(nOrigWidth
* fStretch
+ 0.5);
3632 if( (nNewWidth
!= nOrigWidth
) && (nNewWidth
!= 0) )
3634 Size aOrigSize
= maFont
.GetSize();
3635 const_cast<Font
&>(maFont
).SetSize( Size( nNewWidth
, aSize
.Height() ) );
3638 ImplNewFont(); // recurse once using stretched width
3640 const_cast<Font
&>(maFont
).SetSize( aOrigSize
);
3647 // -----------------------------------------------------------------------
3649 long OutputDevice::ImplGetTextWidth( const SalLayout
& rSalLayout
) const
3651 long nWidth
= rSalLayout
.GetTextWidth();
3652 nWidth
/= rSalLayout
.GetUnitsPerPixel();
3656 // -----------------------------------------------------------------------
3658 void OutputDevice::ImplDrawTextRect( long nBaseX
, long nBaseY
,
3659 long nX
, long nY
, long nWidth
, long nHeight
)
3661 short nOrientation
= mpFontEntry
->mnOrientation
;
3664 // Rotate rect without rounding problems for 90 degree rotations
3665 if ( !(nOrientation
% 900) )
3670 if ( nOrientation
== 900 )
3680 else if ( nOrientation
== 1800 )
3687 else /* ( nOrientation == 2700 ) */
3703 // inflate because polygons are drawn smaller
3704 Rectangle
aRect( Point( nX
, nY
), Size( nWidth
+1, nHeight
+1 ) );
3705 Polygon
aPoly( aRect
);
3706 aPoly
.Rotate( Point( nBaseX
, nBaseY
), mpFontEntry
->mnOrientation
);
3707 ImplDrawPolygon( aPoly
);
3712 mpGraphics
->DrawRect( nX
, nY
, nWidth
, nHeight
, this );
3715 // -----------------------------------------------------------------------
3717 void OutputDevice::ImplDrawTextBackground( const SalLayout
& rSalLayout
)
3719 const long nWidth
= rSalLayout
.GetTextWidth() / rSalLayout
.GetUnitsPerPixel();
3720 const Point aBase
= rSalLayout
.DrawBase();
3721 const long nX
= aBase
.X();
3722 const long nY
= aBase
.Y();
3724 if ( mbLineColor
|| mbInitLineColor
)
3726 mpGraphics
->SetLineColor();
3727 mbInitLineColor
= TRUE
;
3729 mpGraphics
->SetFillColor( ImplColorToSal( GetTextFillColor() ) );
3730 mbInitFillColor
= TRUE
;
3732 ImplDrawTextRect( nX
, nY
, nX
, nY
-mpFontEntry
->maMetric
.mnAscent
-mnEmphasisAscent
,
3734 mpFontEntry
->mnLineHeight
+mnEmphasisAscent
+mnEmphasisDescent
);
3737 // -----------------------------------------------------------------------
3739 Rectangle
OutputDevice::ImplGetTextBoundRect( const SalLayout
& rSalLayout
)
3741 Point aPoint
= rSalLayout
.GetDrawPosition();
3742 long nX
= aPoint
.X();
3743 long nY
= aPoint
.Y();
3745 long nWidth
= rSalLayout
.GetTextWidth();
3746 long nHeight
= mpFontEntry
->mnLineHeight
+ mnEmphasisAscent
+ mnEmphasisDescent
;
3748 nY
-= mpFontEntry
->maMetric
.mnAscent
+ mnEmphasisAscent
;
3750 if ( mpFontEntry
->mnOrientation
)
3752 long nBaseX
= nX
, nBaseY
= nY
;
3753 if ( !(mpFontEntry
->mnOrientation
% 900) )
3755 long nX2
= nX
+nWidth
;
3756 long nY2
= nY
+nHeight
;
3757 ImplRotatePos( nBaseX
, nBaseY
, nX
, nY
, mpFontEntry
->mnOrientation
);
3758 ImplRotatePos( nBaseX
, nBaseY
, nX2
, nY2
, mpFontEntry
->mnOrientation
);
3764 // inflate by +1+1 because polygons are drawn smaller
3765 Rectangle
aRect( Point( nX
, nY
), Size( nWidth
+1, nHeight
+1 ) );
3766 Polygon
aPoly( aRect
);
3767 aPoly
.Rotate( Point( nBaseX
, nBaseY
), mpFontEntry
->mnOrientation
);
3768 return aPoly
.GetBoundRect();
3772 return Rectangle( Point( nX
, nY
), Size( nWidth
, nHeight
) );
3775 // -----------------------------------------------------------------------
3777 void OutputDevice::ImplInitTextLineSize()
3779 mpFontEntry
->maMetric
.ImplInitTextLineSize( this );
3782 // -----------------------------------------------------------------------
3784 void OutputDevice::ImplInitAboveTextLineSize()
3786 mpFontEntry
->maMetric
.ImplInitAboveTextLineSize();
3789 // -----------------------------------------------------------------------
3791 ImplFontMetricData::ImplFontMetricData( const ImplFontSelectData
& rFontSelData
)
3792 : ImplFontAttributes( rFontSelData
)
3794 // initialize the members provided by the font request
3795 mnWidth
= rFontSelData
.mnWidth
;
3796 mnOrientation
= sal::static_int_cast
<short>(rFontSelData
.mnOrientation
);
3798 // intialize the used font name
3799 if( rFontSelData
.mpFontData
)
3801 maName
= rFontSelData
.mpFontData
->maName
;
3802 maStyleName
= rFontSelData
.mpFontData
->maStyleName
;
3803 mbDevice
= rFontSelData
.mpFontData
->mbDevice
;
3804 mbKernableFont
= true;
3808 xub_StrLen nTokenPos
= 0;
3809 maName
= GetNextFontToken( rFontSelData
.maName
, nTokenPos
);
3810 maStyleName
= rFontSelData
.maStyleName
;
3812 mbKernableFont
= false;
3815 // reset metrics that are usually measured for the font instance
3823 // reset metrics that are usually derived from the measurements
3824 mnUnderlineSize
= 0;
3825 mnUnderlineOffset
= 0;
3826 mnBUnderlineSize
= 0;
3827 mnBUnderlineOffset
= 0;
3828 mnDUnderlineSize
= 0;
3829 mnDUnderlineOffset1
= 0;
3830 mnDUnderlineOffset2
= 0;
3831 mnWUnderlineSize
= 0;
3832 mnWUnderlineOffset
= 0;
3833 mnAboveUnderlineSize
= 0;
3834 mnAboveUnderlineOffset
= 0;
3835 mnAboveBUnderlineSize
= 0;
3836 mnAboveBUnderlineOffset
= 0;
3837 mnAboveDUnderlineSize
= 0;
3838 mnAboveDUnderlineOffset1
= 0;
3839 mnAboveDUnderlineOffset2
= 0;
3840 mnAboveWUnderlineSize
= 0;
3841 mnAboveWUnderlineOffset
= 0;
3842 mnStrikeoutSize
= 0;
3843 mnStrikeoutOffset
= 0;
3844 mnBStrikeoutSize
= 0;
3845 mnBStrikeoutOffset
= 0;
3846 mnDStrikeoutSize
= 0;
3847 mnDStrikeoutOffset1
= 0;
3848 mnDStrikeoutOffset2
= 0;
3851 // -----------------------------------------------------------------------
3853 void ImplFontMetricData::ImplInitTextLineSize( const OutputDevice
* pDev
)
3855 long nDescent
= mnDescent
;
3856 if ( nDescent
<= 0 )
3858 nDescent
= mnAscent
/ 10;
3863 // #i55341# for some fonts it is not a good idea to calculate
3864 // their text line metrics from the real font descent
3865 // => work around this problem just for these fonts
3866 if( 3*nDescent
> mnAscent
)
3867 nDescent
= mnAscent
/ 3;
3869 long nLineHeight
= ((nDescent
*25)+50) / 100;
3872 long nLineHeight2
= nLineHeight
/ 2;
3873 if ( !nLineHeight2
)
3876 long nBLineHeight
= ((nDescent
*50)+50) / 100;
3877 if ( nBLineHeight
== nLineHeight
)
3879 long nBLineHeight2
= nBLineHeight
/2;
3880 if ( !nBLineHeight2
)
3883 long n2LineHeight
= ((nDescent
*16)+50) / 100;
3884 if ( !n2LineHeight
)
3886 long n2LineDY
= n2LineHeight
;
3888 * add some pixels to minimum double line distance on higher resolution devices
3890 long nMin2LineDY
= 1 + pDev
->ImplGetDPIY()/150;
3891 if ( n2LineDY
< nMin2LineDY
)
3892 n2LineDY
= nMin2LineDY
;
3893 long n2LineDY2
= n2LineDY
/2;
3897 long nUnderlineOffset
= mnDescent
/2 + 1;
3898 long nStrikeoutOffset
= -((mnAscent
- mnIntLeading
) / 3);
3900 mnUnderlineSize
= nLineHeight
;
3901 mnUnderlineOffset
= nUnderlineOffset
- nLineHeight2
;
3903 mnBUnderlineSize
= nBLineHeight
;
3904 mnBUnderlineOffset
= nUnderlineOffset
- nBLineHeight2
;
3906 mnDUnderlineSize
= n2LineHeight
;
3907 mnDUnderlineOffset1
= nUnderlineOffset
- n2LineDY2
- n2LineHeight
;
3908 mnDUnderlineOffset2
= mnDUnderlineOffset1
+ n2LineDY
+ n2LineHeight
;
3910 long nWCalcSize
= mnDescent
;
3911 if ( nWCalcSize
< 6 )
3913 if ( (nWCalcSize
== 1) || (nWCalcSize
== 2) )
3914 mnWUnderlineSize
= nWCalcSize
;
3916 mnWUnderlineSize
= 3;
3919 mnWUnderlineSize
= ((nWCalcSize
*50)+50) / 100;
3921 // #109280# the following line assures that wavelnes are never placed below the descent, however
3922 // for most fonts the waveline then is drawn into the text, so we better keep the old solution
3923 // pFontEntry->maMetric.mnWUnderlineOffset = pFontEntry->maMetric.mnDescent + 1 - pFontEntry->maMetric.mnWUnderlineSize;
3924 mnWUnderlineOffset
= nUnderlineOffset
;
3926 mnStrikeoutSize
= nLineHeight
;
3927 mnStrikeoutOffset
= nStrikeoutOffset
- nLineHeight2
;
3929 mnBStrikeoutSize
= nBLineHeight
;
3930 mnBStrikeoutOffset
= nStrikeoutOffset
- nBLineHeight2
;
3932 mnDStrikeoutSize
= n2LineHeight
;
3933 mnDStrikeoutOffset1
= nStrikeoutOffset
- n2LineDY2
- n2LineHeight
;
3934 mnDStrikeoutOffset2
= mnDStrikeoutOffset1
+ n2LineDY
+ n2LineHeight
;
3937 // -----------------------------------------------------------------------
3939 void ImplFontMetricData::ImplInitAboveTextLineSize()
3941 long nIntLeading
= mnIntLeading
;
3942 // TODO: assess usage of nLeading below (changed in extleading CWS)
3943 // if no leading is available, we assume 15% of the ascent
3944 if ( nIntLeading
<= 0 )
3946 nIntLeading
= mnAscent
*15/100;
3951 long nLineHeight
= ((nIntLeading
*25)+50) / 100;
3955 long nBLineHeight
= ((nIntLeading
*50)+50) / 100;
3956 if ( nBLineHeight
== nLineHeight
)
3959 long n2LineHeight
= ((nIntLeading
*16)+50) / 100;
3960 if ( !n2LineHeight
)
3963 long nCeiling
= -mnAscent
;
3965 mnAboveUnderlineSize
= nLineHeight
;
3966 mnAboveUnderlineOffset
= nCeiling
+ (nIntLeading
- nLineHeight
+ 1) / 2;
3968 mnAboveBUnderlineSize
= nBLineHeight
;
3969 mnAboveBUnderlineOffset
= nCeiling
+ (nIntLeading
- nBLineHeight
+ 1) / 2;
3971 mnAboveDUnderlineSize
= n2LineHeight
;
3972 mnAboveDUnderlineOffset1
= nCeiling
+ (nIntLeading
- 3*n2LineHeight
+ 1) / 2;
3973 mnAboveDUnderlineOffset2
= nCeiling
+ (nIntLeading
+ n2LineHeight
+ 1) / 2;
3975 long nWCalcSize
= nIntLeading
;
3976 if ( nWCalcSize
< 6 )
3978 if ( (nWCalcSize
== 1) || (nWCalcSize
== 2) )
3979 mnAboveWUnderlineSize
= nWCalcSize
;
3981 mnAboveWUnderlineSize
= 3;
3984 mnAboveWUnderlineSize
= ((nWCalcSize
*50)+50) / 100;
3986 mnAboveWUnderlineOffset
= nCeiling
+ (nIntLeading
+ 1) / 2;
3989 // -----------------------------------------------------------------------
3991 static void ImplDrawWavePixel( long nOriginX
, long nOriginY
,
3992 long nCurX
, long nCurY
,
3994 SalGraphics
* pGraphics
,
3995 OutputDevice
* pOutDev
,
3996 BOOL bDrawPixAsRect
,
3998 long nPixWidth
, long nPixHeight
)
4001 ImplRotatePos( nOriginX
, nOriginY
, nCurX
, nCurY
, nOrientation
);
4003 if ( bDrawPixAsRect
)
4006 pGraphics
->DrawRect( nCurX
, nCurY
, nPixWidth
, nPixHeight
, pOutDev
);
4010 pGraphics
->DrawPixel( nCurX
, nCurY
, pOutDev
);
4014 // -----------------------------------------------------------------------
4016 void OutputDevice::ImplDrawWaveLine( long nBaseX
, long nBaseY
,
4017 long nStartX
, long nStartY
,
4018 long nWidth
, long nHeight
,
4019 long nLineWidth
, short nOrientation
,
4020 const Color
& rColor
)
4025 // Bei Hoehe von 1 Pixel reicht es, eine Linie auszugeben
4026 if ( (nLineWidth
== 1) && (nHeight
== 1) )
4028 mpGraphics
->SetLineColor( ImplColorToSal( rColor
) );
4029 mbInitLineColor
= TRUE
;
4031 long nEndX
= nStartX
+nWidth
;
4032 long nEndY
= nStartY
;
4035 ImplRotatePos( nBaseX
, nBaseY
, nStartX
, nStartY
, nOrientation
);
4036 ImplRotatePos( nBaseX
, nBaseY
, nEndX
, nEndY
, nOrientation
);
4038 mpGraphics
->DrawLine( nStartX
, nStartY
, nEndX
, nEndY
, this );
4043 long nCurX
= nStartX
;
4044 long nCurY
= nStartY
;
4046 long nDiffY
= nHeight
-1;
4047 long nCount
= nWidth
;
4053 BOOL bDrawPixAsRect
;
4054 // Auf Druckern die Pixel per DrawRect() ausgeben
4055 if ( (GetOutDevType() == OUTDEV_PRINTER
) || (nLineWidth
> 1) )
4057 if ( mbLineColor
|| mbInitLineColor
)
4059 mpGraphics
->SetLineColor();
4060 mbInitLineColor
= TRUE
;
4062 mpGraphics
->SetFillColor( ImplColorToSal( rColor
) );
4063 mbInitFillColor
= TRUE
;
4064 bDrawPixAsRect
= TRUE
;
4065 nPixWidth
= nLineWidth
;
4066 nPixHeight
= ((nLineWidth
*mnDPIX
)+(mnDPIY
/2))/mnDPIY
;
4070 mpGraphics
->SetLineColor( ImplColorToSal( rColor
) );
4071 mbInitLineColor
= TRUE
;
4074 bDrawPixAsRect
= FALSE
;
4081 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
4083 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
4091 nFreq
= nCount
/ (nDiffX
+nDiffY
);
4094 for( i
= nDiffY
; i
; --i
)
4096 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
4098 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
4102 for( i
= nDiffX
; i
; --i
)
4104 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
4106 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
4111 nFreq
= nCount
% (nDiffX
+nDiffY
);
4114 for( i
= nDiffY
; i
&& nFreq
; --i
, --nFreq
)
4116 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
4118 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
4123 for( i
= nDiffX
; i
&& nFreq
; --i
, --nFreq
)
4125 ImplDrawWavePixel( nBaseX
, nBaseY
, nCurX
, nCurY
, nOrientation
,
4127 bDrawPixAsRect
, nPixWidth
, nPixHeight
);
4136 // -----------------------------------------------------------------------
4138 void OutputDevice::ImplDrawWaveTextLine( long nBaseX
, long nBaseY
,
4139 long nX
, long nY
, long nWidth
,
4140 FontUnderline eTextLine
,
4144 ImplFontEntry
* pFontEntry
= mpFontEntry
;
4150 nLineHeight
= pFontEntry
->maMetric
.mnAboveWUnderlineSize
;
4151 nLinePos
= pFontEntry
->maMetric
.mnAboveWUnderlineOffset
;
4155 nLineHeight
= pFontEntry
->maMetric
.mnWUnderlineSize
;
4156 nLinePos
= pFontEntry
->maMetric
.mnWUnderlineOffset
;
4158 if ( (eTextLine
== UNDERLINE_SMALLWAVE
) && (nLineHeight
> 3) )
4160 long nLineWidth
= (mnDPIX
/300);
4163 if ( eTextLine
== UNDERLINE_BOLDWAVE
)
4165 nLinePos
+= nY
- (nLineHeight
/ 2);
4166 long nLineWidthHeight
= ((nLineWidth
*mnDPIX
)+(mnDPIY
/2))/mnDPIY
;
4167 if ( eTextLine
== UNDERLINE_DOUBLEWAVE
)
4169 long nOrgLineHeight
= nLineHeight
;
4171 if ( nLineHeight
< 2 )
4173 if ( nOrgLineHeight
> 1 )
4178 long nLineDY
= nOrgLineHeight
-(nLineHeight
*2);
4179 if ( nLineDY
< nLineWidthHeight
)
4180 nLineDY
= nLineWidthHeight
;
4181 long nLineDY2
= nLineDY
/2;
4185 nLinePos
-= nLineWidthHeight
-nLineDY2
;
4186 ImplDrawWaveLine( nBaseX
, nBaseY
, nX
, nLinePos
, nWidth
, nLineHeight
,
4187 nLineWidth
, mpFontEntry
->mnOrientation
, aColor
);
4188 nLinePos
+= nLineWidthHeight
+nLineDY
;
4189 ImplDrawWaveLine( nBaseX
, nBaseY
, nX
, nLinePos
, nWidth
, nLineHeight
,
4190 nLineWidth
, mpFontEntry
->mnOrientation
, aColor
);
4194 nLinePos
-= nLineWidthHeight
/2;
4195 ImplDrawWaveLine( nBaseX
, nBaseY
, nX
, nLinePos
, nWidth
, nLineHeight
,
4196 nLineWidth
, mpFontEntry
->mnOrientation
, aColor
);
4200 // -----------------------------------------------------------------------
4202 void OutputDevice::ImplDrawStraightTextLine( long nBaseX
, long nBaseY
,
4203 long nX
, long nY
, long nWidth
,
4204 FontUnderline eTextLine
,
4208 ImplFontEntry
* pFontEntry
= mpFontEntry
;
4209 long nLineHeight
= 0;
4213 if ( eTextLine
> UNDERLINE_LAST
)
4214 eTextLine
= UNDERLINE_SINGLE
;
4216 switch ( eTextLine
)
4218 case UNDERLINE_SINGLE
:
4219 case UNDERLINE_DOTTED
:
4220 case UNDERLINE_DASH
:
4221 case UNDERLINE_LONGDASH
:
4222 case UNDERLINE_DASHDOT
:
4223 case UNDERLINE_DASHDOTDOT
:
4226 nLineHeight
= pFontEntry
->maMetric
.mnAboveUnderlineSize
;
4227 nLinePos
= nY
+ pFontEntry
->maMetric
.mnAboveUnderlineOffset
;
4231 nLineHeight
= pFontEntry
->maMetric
.mnUnderlineSize
;
4232 nLinePos
= nY
+ pFontEntry
->maMetric
.mnUnderlineOffset
;
4235 case UNDERLINE_BOLD
:
4236 case UNDERLINE_BOLDDOTTED
:
4237 case UNDERLINE_BOLDDASH
:
4238 case UNDERLINE_BOLDLONGDASH
:
4239 case UNDERLINE_BOLDDASHDOT
:
4240 case UNDERLINE_BOLDDASHDOTDOT
:
4243 nLineHeight
= pFontEntry
->maMetric
.mnAboveBUnderlineSize
;
4244 nLinePos
= nY
+ pFontEntry
->maMetric
.mnAboveBUnderlineOffset
;
4248 nLineHeight
= pFontEntry
->maMetric
.mnBUnderlineSize
;
4249 nLinePos
= nY
+ pFontEntry
->maMetric
.mnBUnderlineOffset
;
4252 case UNDERLINE_DOUBLE
:
4255 nLineHeight
= pFontEntry
->maMetric
.mnAboveDUnderlineSize
;
4256 nLinePos
= nY
+ pFontEntry
->maMetric
.mnAboveDUnderlineOffset1
;
4257 nLinePos2
= nY
+ pFontEntry
->maMetric
.mnAboveDUnderlineOffset2
;
4261 nLineHeight
= pFontEntry
->maMetric
.mnDUnderlineSize
;
4262 nLinePos
= nY
+ pFontEntry
->maMetric
.mnDUnderlineOffset1
;
4263 nLinePos2
= nY
+ pFontEntry
->maMetric
.mnDUnderlineOffset2
;
4272 if ( mbLineColor
|| mbInitLineColor
)
4274 mpGraphics
->SetLineColor();
4275 mbInitLineColor
= TRUE
;
4277 mpGraphics
->SetFillColor( ImplColorToSal( aColor
) );
4278 mbInitFillColor
= TRUE
;
4282 switch ( eTextLine
)
4284 case UNDERLINE_SINGLE
:
4285 case UNDERLINE_BOLD
:
4286 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nWidth
, nLineHeight
);
4288 case UNDERLINE_DOUBLE
:
4289 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nWidth
, nLineHeight
);
4290 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos2
, nWidth
, nLineHeight
);
4292 case UNDERLINE_DOTTED
:
4293 case UNDERLINE_BOLDDOTTED
:
4295 long nDotWidth
= nLineHeight
*mnDPIY
;
4296 nDotWidth
+= mnDPIY
/2;
4297 nDotWidth
/= mnDPIY
;
4298 long nTempWidth
= nDotWidth
;
4299 long nEnd
= nLeft
+nWidth
;
4300 while ( nLeft
< nEnd
)
4302 if ( nLeft
+nTempWidth
> nEnd
)
4303 nTempWidth
= nEnd
-nLeft
;
4304 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempWidth
, nLineHeight
);
4305 nLeft
+= nDotWidth
*2;
4309 case UNDERLINE_DASH
:
4310 case UNDERLINE_LONGDASH
:
4311 case UNDERLINE_BOLDDASH
:
4312 case UNDERLINE_BOLDLONGDASH
:
4314 long nDotWidth
= nLineHeight
*mnDPIY
;
4315 nDotWidth
+= mnDPIY
/2;
4316 nDotWidth
/= mnDPIY
;
4318 long nMinSpaceWidth
;
4321 if ( (eTextLine
== UNDERLINE_LONGDASH
) ||
4322 (eTextLine
== UNDERLINE_BOLDLONGDASH
) )
4324 nMinDashWidth
= nDotWidth
*6;
4325 nMinSpaceWidth
= nDotWidth
*2;
4331 nMinDashWidth
= nDotWidth
*4;
4332 nMinSpaceWidth
= (nDotWidth
*150)/100;
4336 nDashWidth
= ((nDashWidth
*mnDPIX
)+1270)/2540;
4337 nSpaceWidth
= ((nSpaceWidth
*mnDPIX
)+1270)/2540;
4338 // DashWidth wird gegebenenfalls verbreitert, wenn
4339 // die dicke der Linie im Verhaeltnis zur Laenge
4341 if ( nDashWidth
< nMinDashWidth
)
4342 nDashWidth
= nMinDashWidth
;
4343 if ( nSpaceWidth
< nMinSpaceWidth
)
4344 nSpaceWidth
= nMinSpaceWidth
;
4345 long nTempWidth
= nDashWidth
;
4346 long nEnd
= nLeft
+nWidth
;
4347 while ( nLeft
< nEnd
)
4349 if ( nLeft
+nTempWidth
> nEnd
)
4350 nTempWidth
= nEnd
-nLeft
;
4351 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempWidth
, nLineHeight
);
4352 nLeft
+= nDashWidth
+nSpaceWidth
;
4356 case UNDERLINE_DASHDOT
:
4357 case UNDERLINE_BOLDDASHDOT
:
4359 long nDotWidth
= nLineHeight
*mnDPIY
;
4360 nDotWidth
+= mnDPIY
/2;
4361 nDotWidth
/= mnDPIY
;
4362 long nDashWidth
= ((100*mnDPIX
)+1270)/2540;
4363 long nMinDashWidth
= nDotWidth
*4;
4364 // DashWidth wird gegebenenfalls verbreitert, wenn
4365 // die dicke der Linie im Verhaeltnis zur Laenge
4367 if ( nDashWidth
< nMinDashWidth
)
4368 nDashWidth
= nMinDashWidth
;
4369 long nTempDotWidth
= nDotWidth
;
4370 long nTempDashWidth
= nDashWidth
;
4371 long nEnd
= nLeft
+nWidth
;
4372 while ( nLeft
< nEnd
)
4374 if ( nLeft
+nTempDotWidth
> nEnd
)
4375 nTempDotWidth
= nEnd
-nLeft
;
4376 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDotWidth
, nLineHeight
);
4377 nLeft
+= nDotWidth
*2;
4380 if ( nLeft
+nTempDashWidth
> nEnd
)
4381 nTempDashWidth
= nEnd
-nLeft
;
4382 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDashWidth
, nLineHeight
);
4383 nLeft
+= nDashWidth
+nDotWidth
;
4387 case UNDERLINE_DASHDOTDOT
:
4388 case UNDERLINE_BOLDDASHDOTDOT
:
4390 long nDotWidth
= nLineHeight
*mnDPIY
;
4391 nDotWidth
+= mnDPIY
/2;
4392 nDotWidth
/= mnDPIY
;
4393 long nDashWidth
= ((100*mnDPIX
)+1270)/2540;
4394 long nMinDashWidth
= nDotWidth
*4;
4395 // DashWidth wird gegebenenfalls verbreitert, wenn
4396 // die dicke der Linie im Verhaeltnis zur Laenge
4398 if ( nDashWidth
< nMinDashWidth
)
4399 nDashWidth
= nMinDashWidth
;
4400 long nTempDotWidth
= nDotWidth
;
4401 long nTempDashWidth
= nDashWidth
;
4402 long nEnd
= nLeft
+nWidth
;
4403 while ( nLeft
< nEnd
)
4405 if ( nLeft
+nTempDotWidth
> nEnd
)
4406 nTempDotWidth
= nEnd
-nLeft
;
4407 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDotWidth
, nLineHeight
);
4408 nLeft
+= nDotWidth
*2;
4411 if ( nLeft
+nTempDotWidth
> nEnd
)
4412 nTempDotWidth
= nEnd
-nLeft
;
4413 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDotWidth
, nLineHeight
);
4414 nLeft
+= nDotWidth
*2;
4417 if ( nLeft
+nTempDashWidth
> nEnd
)
4418 nTempDashWidth
= nEnd
-nLeft
;
4419 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nTempDashWidth
, nLineHeight
);
4420 nLeft
+= nDashWidth
+nDotWidth
;
4430 // -----------------------------------------------------------------------
4432 void OutputDevice::ImplDrawStrikeoutLine( long nBaseX
, long nBaseY
,
4433 long nX
, long nY
, long nWidth
,
4434 FontStrikeout eStrikeout
,
4437 ImplFontEntry
* pFontEntry
= mpFontEntry
;
4438 long nLineHeight
= 0;
4442 if ( eStrikeout
> STRIKEOUT_LAST
)
4443 eStrikeout
= STRIKEOUT_SINGLE
;
4445 switch ( eStrikeout
)
4447 case STRIKEOUT_SINGLE
:
4448 nLineHeight
= pFontEntry
->maMetric
.mnStrikeoutSize
;
4449 nLinePos
= nY
+ pFontEntry
->maMetric
.mnStrikeoutOffset
;
4451 case STRIKEOUT_BOLD
:
4452 nLineHeight
= pFontEntry
->maMetric
.mnBStrikeoutSize
;
4453 nLinePos
= nY
+ pFontEntry
->maMetric
.mnBStrikeoutOffset
;
4455 case STRIKEOUT_DOUBLE
:
4456 nLineHeight
= pFontEntry
->maMetric
.mnDStrikeoutSize
;
4457 nLinePos
= nY
+ pFontEntry
->maMetric
.mnDStrikeoutOffset1
;
4458 nLinePos2
= nY
+ pFontEntry
->maMetric
.mnDStrikeoutOffset2
;
4466 if ( mbLineColor
|| mbInitLineColor
)
4468 mpGraphics
->SetLineColor();
4469 mbInitLineColor
= TRUE
;
4471 mpGraphics
->SetFillColor( ImplColorToSal( aColor
) );
4472 mbInitFillColor
= TRUE
;
4476 switch ( eStrikeout
)
4478 case STRIKEOUT_SINGLE
:
4479 case STRIKEOUT_BOLD
:
4480 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nWidth
, nLineHeight
);
4482 case STRIKEOUT_DOUBLE
:
4483 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos
, nWidth
, nLineHeight
);
4484 ImplDrawTextRect( nBaseX
, nBaseY
, nLeft
, nLinePos2
, nWidth
, nLineHeight
);
4492 // -----------------------------------------------------------------------
4494 void OutputDevice::ImplDrawStrikeoutChar( long nBaseX
, long nBaseY
,
4495 long nX
, long nY
, long nWidth
,
4496 FontStrikeout eStrikeout
,
4499 // PDF-export does its own strikeout drawing... why again?
4500 if( mpPDFWriter
&& mpPDFWriter
->isBuiltinFont(mpFontEntry
->maFontSelData
.mpFontData
) )
4503 // prepare string for strikeout measurement
4504 static char cStrikeoutChar
;
4505 if ( eStrikeout
== STRIKEOUT_SLASH
)
4506 cStrikeoutChar
= '/';
4507 else // ( eStrikeout == STRIKEOUT_X )
4508 cStrikeoutChar
= 'X';
4509 static const int nTestStrLen
= 4;
4510 static const int nMaxStrikeStrLen
= 2048;
4511 xub_Unicode aChars
[ nMaxStrikeStrLen
+1]; // +1 for valgrind...
4512 for( int i
= 0; i
< nTestStrLen
; ++i
)
4513 aChars
[i
] = cStrikeoutChar
;
4514 const String
aStrikeoutTest( aChars
, nTestStrLen
);
4516 // calculate approximation of strikeout atom size
4517 long nStrikeoutWidth
= nWidth
;
4518 SalLayout
* pLayout
= ImplLayout( aStrikeoutTest
, 0, nTestStrLen
);
4521 nStrikeoutWidth
= (pLayout
->GetTextWidth() +nTestStrLen
/2) / (nTestStrLen
* pLayout
->GetUnitsPerPixel());
4524 if( nStrikeoutWidth
<= 0 ) // sanity check
4527 // calculate acceptable strikeout length
4528 // allow the strikeout to be one pixel larger than the text it strikes out
4529 long nMaxWidth
= nStrikeoutWidth
/ 2;
4530 if ( nMaxWidth
< 2 )
4532 nMaxWidth
+= nWidth
+ 1;
4534 int nStrikeStrLen
= (nMaxWidth
+ nStrikeoutWidth
- 1) / nStrikeoutWidth
;
4535 // if the text width is smaller than the strikeout text, then do not
4536 // strike out at all. This case requires user interaction, e.g. adding
4537 // a space to the text
4538 if( nStrikeStrLen
<= 0 )
4540 if( nStrikeStrLen
> nMaxStrikeStrLen
)
4541 nStrikeStrLen
= nMaxStrikeStrLen
;
4543 // build the strikeout string
4544 for( int i
= nTestStrLen
; i
< nStrikeStrLen
; ++i
)
4545 aChars
[i
] = cStrikeoutChar
;
4546 const String
aStrikeoutText( aChars
, xub_StrLen(nStrikeStrLen
) );
4548 if( mpFontEntry
->mnOrientation
)
4549 ImplRotatePos( nBaseX
, nBaseY
, nX
, nY
, mpFontEntry
->mnOrientation
);
4551 // strikeout text has to be left aligned
4552 ULONG nOrigTLM
= mnTextLayoutMode
;
4553 mnTextLayoutMode
= TEXT_LAYOUT_BIDI_STRONG
| TEXT_LAYOUT_COMPLEX_DISABLED
;
4554 pLayout
= ImplLayout( aStrikeoutText
, 0, STRING_LEN
);
4555 mnTextLayoutMode
= nOrigTLM
;
4560 // draw the strikeout text
4561 const Color aOldColor
= GetTextColor();
4562 SetTextColor( aColor
);
4563 ImplInitTextColor();
4565 pLayout
->DrawBase() = Point( nX
+mnTextOffX
, nY
+mnTextOffY
);
4566 pLayout
->DrawText( *mpGraphics
);
4569 SetTextColor( aOldColor
);
4570 ImplInitTextColor();
4573 // -----------------------------------------------------------------------
4575 void OutputDevice::ImplDrawTextLine( long nBaseX
,
4576 long nX
, long nY
, long nWidth
,
4577 FontStrikeout eStrikeout
,
4578 FontUnderline eUnderline
,
4579 FontUnderline eOverline
,
4580 BOOL bUnderlineAbove
)
4585 Color aStrikeoutColor
= GetTextColor();
4586 Color aUnderlineColor
= GetTextLineColor();
4587 Color aOverlineColor
= GetOverlineColor();
4588 BOOL bStrikeoutDone
= FALSE
;
4589 BOOL bUnderlineDone
= FALSE
;
4590 BOOL bOverlineDone
= FALSE
;
4592 // TODO: fix rotated text
4593 if ( IsRTLEnabled() )
4594 // --- RTL --- mirror at basex
4595 nX
= nBaseX
- nWidth
- (nX
- nBaseX
- 1);
4597 if ( !IsTextLineColor() )
4598 aUnderlineColor
= GetTextColor();
4600 if ( !IsOverlineColor() )
4601 aOverlineColor
= GetTextColor();
4603 if ( (eUnderline
== UNDERLINE_SMALLWAVE
) ||
4604 (eUnderline
== UNDERLINE_WAVE
) ||
4605 (eUnderline
== UNDERLINE_DOUBLEWAVE
) ||
4606 (eUnderline
== UNDERLINE_BOLDWAVE
) )
4608 ImplDrawWaveTextLine( nBaseX
, nY
, nX
, nY
, nWidth
, eUnderline
, aUnderlineColor
, bUnderlineAbove
);
4609 bUnderlineDone
= TRUE
;
4611 if ( (eOverline
== UNDERLINE_SMALLWAVE
) ||
4612 (eOverline
== UNDERLINE_WAVE
) ||
4613 (eOverline
== UNDERLINE_DOUBLEWAVE
) ||
4614 (eOverline
== UNDERLINE_BOLDWAVE
) )
4616 ImplDrawWaveTextLine( nBaseX
, nY
, nX
, nY
, nWidth
, eOverline
, aOverlineColor
, TRUE
);
4617 bOverlineDone
= TRUE
;
4620 if ( (eStrikeout
== STRIKEOUT_SLASH
) ||
4621 (eStrikeout
== STRIKEOUT_X
) )
4623 ImplDrawStrikeoutChar( nBaseX
, nY
, nX
, nY
, nWidth
, eStrikeout
, aStrikeoutColor
);
4624 bStrikeoutDone
= TRUE
;
4627 if ( !bUnderlineDone
)
4628 ImplDrawStraightTextLine( nBaseX
, nY
, nX
, nY
, nWidth
, eUnderline
, aUnderlineColor
, bUnderlineAbove
);
4630 if ( !bOverlineDone
)
4631 ImplDrawStraightTextLine( nBaseX
, nY
, nX
, nY
, nWidth
, eOverline
, aOverlineColor
, TRUE
);
4633 if ( !bStrikeoutDone
)
4634 ImplDrawStrikeoutLine( nBaseX
, nY
, nX
, nY
, nWidth
, eStrikeout
, aStrikeoutColor
);
4637 // -----------------------------------------------------------------------
4639 void OutputDevice::ImplDrawTextLines( SalLayout
& rSalLayout
,
4640 FontStrikeout eStrikeout
, FontUnderline eUnderline
, FontUnderline eOverline
, BOOL bWordLine
, BOOL bUnderlineAbove
)
4644 Point aPos
, aStartPt
;
4645 sal_Int32 nWidth
= 0, nAdvance
=0;
4646 for( int nStart
= 0;;)
4648 sal_GlyphId nGlyphIndex
;
4649 if( !rSalLayout
.GetNextGlyphs( 1, &nGlyphIndex
, aPos
, nStart
, &nAdvance
) )
4652 if( !rSalLayout
.IsSpacingGlyph( nGlyphIndex
) )
4656 aStartPt
= aPos
;//rSalLayout.DrawBase() - (aPos - rSalLayout.DrawOffset());
4661 else if( nWidth
> 0 )
4663 ImplDrawTextLine( rSalLayout
.DrawBase().X(), aStartPt
.X(), aStartPt
.Y(), nWidth
,
4664 eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
4671 ImplDrawTextLine( rSalLayout
.DrawBase().X(), aStartPt
.X(), aStartPt
.Y(), nWidth
,
4672 eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
4677 Point aStartPt
= rSalLayout
.GetDrawPosition();
4678 int nWidth
= rSalLayout
.GetTextWidth() / rSalLayout
.GetUnitsPerPixel();
4679 ImplDrawTextLine( rSalLayout
.DrawBase().X(), aStartPt
.X(), aStartPt
.Y(), nWidth
,
4680 eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
4684 // -----------------------------------------------------------------------
4686 void OutputDevice::ImplDrawMnemonicLine( long nX
, long nY
, long nWidth
)
4689 if( /*ImplHasMirroredGraphics() &&*/ IsRTLEnabled() )
4692 // add some strange offset
4694 // revert the hack that will be done later in ImplDrawTextLine
4695 nX
= nBaseX
- nWidth
- (nX
- nBaseX
- 1);
4698 ImplDrawTextLine( nBaseX
, nX
, nY
, nWidth
, STRIKEOUT_NONE
, UNDERLINE_SINGLE
, UNDERLINE_NONE
, FALSE
);
4701 // -----------------------------------------------------------------------
4703 void OutputDevice::ImplGetEmphasisMark( PolyPolygon
& rPolyPoly
, BOOL
& rPolyLine
,
4704 Rectangle
& rRect1
, Rectangle
& rRect2
,
4705 long& rYOff
, long& rWidth
,
4706 FontEmphasisMark eEmphasis
,
4707 long nHeight
, short /*nOrient*/ )
4709 static const BYTE aAccentPolyFlags
[24] =
4711 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 2, 2, 0, 0, 2, 0, 2, 2
4714 static const long aAccentPos
[48] =
4749 FontEmphasisMark nEmphasisStyle
= eEmphasis
& EMPHASISMARK_STYLE
;
4751 switch ( nEmphasisStyle
)
4753 case EMPHASISMARK_DOT
:
4754 // Dot has 55% of the height
4755 nDotSize
= (nHeight
*550)/1000;
4758 if ( nDotSize
<= 2 )
4759 rRect1
= Rectangle( Point(), Size( nDotSize
, nDotSize
) );
4762 long nRad
= nDotSize
/2;
4763 Polygon
aPoly( Point( nRad
, nRad
), nRad
, nRad
);
4764 rPolyPoly
.Insert( aPoly
);
4766 rYOff
= ((nHeight
*250)/1000)/2; // Center to the anthoer EmphasisMarks
4770 case EMPHASISMARK_CIRCLE
:
4771 // Dot has 80% of the height
4772 nDotSize
= (nHeight
*800)/1000;
4775 if ( nDotSize
<= 2 )
4776 rRect1
= Rectangle( Point(), Size( nDotSize
, nDotSize
) );
4779 long nRad
= nDotSize
/2;
4780 Polygon
aPoly( Point( nRad
, nRad
), nRad
, nRad
);
4781 rPolyPoly
.Insert( aPoly
);
4782 // BorderWidth is 15%
4783 long nBorder
= (nDotSize
*150)/1000;
4788 Polygon
aPoly2( Point( nRad
, nRad
),
4789 nRad
-nBorder
, nRad
-nBorder
);
4790 rPolyPoly
.Insert( aPoly2
);
4796 case EMPHASISMARK_DISC
:
4797 // Dot has 80% of the height
4798 nDotSize
= (nHeight
*800)/1000;
4801 if ( nDotSize
<= 2 )
4802 rRect1
= Rectangle( Point(), Size( nDotSize
, nDotSize
) );
4805 long nRad
= nDotSize
/2;
4806 Polygon
aPoly( Point( nRad
, nRad
), nRad
, nRad
);
4807 rPolyPoly
.Insert( aPoly
);
4812 case EMPHASISMARK_ACCENT
:
4813 // Dot has 80% of the height
4814 nDotSize
= (nHeight
*800)/1000;
4817 if ( nDotSize
<= 2 )
4819 if ( nDotSize
== 1 )
4821 rRect1
= Rectangle( Point(), Size( nDotSize
, nDotSize
) );
4826 rRect1
= Rectangle( Point(), Size( 1, 1 ) );
4827 rRect2
= Rectangle( Point( 1, 1 ), Size( 1, 1 ) );
4832 Polygon
aPoly( sizeof( aAccentPos
) / sizeof( long ) / 2,
4833 (const Point
*)aAccentPos
,
4835 double dScale
= ((double)nDotSize
)/1000.0;
4836 aPoly
.Scale( dScale
, dScale
);
4838 aPoly
.GetSimple( aTemp
);
4839 Rectangle aBoundRect
= aTemp
.GetBoundRect();
4840 rWidth
= aBoundRect
.GetWidth();
4841 nDotSize
= aBoundRect
.GetHeight();
4842 rPolyPoly
.Insert( aTemp
);
4847 // calculate position
4848 long nOffY
= 1+(mnDPIY
/300); // one visible pixel space
4849 long nSpaceY
= nHeight
-nDotSize
;
4850 if ( nSpaceY
>= nOffY
*2 )
4852 if ( !(eEmphasis
& EMPHASISMARK_POS_BELOW
) )
4856 // -----------------------------------------------------------------------
4858 void OutputDevice::ImplDrawEmphasisMark( long nBaseX
, long nX
, long nY
,
4859 const PolyPolygon
& rPolyPoly
, BOOL bPolyLine
,
4860 const Rectangle
& rRect1
, const Rectangle
& rRect2
)
4862 // TODO: pass nWidth as width of this mark
4865 if( IsRTLEnabled() )
4866 // --- RTL --- mirror at basex
4867 nX
= nBaseX
- nWidth
- (nX
- nBaseX
- 1);
4872 if ( rPolyPoly
.Count() )
4876 Polygon aPoly
= rPolyPoly
.GetObject( 0 );
4877 aPoly
.Move( nX
, nY
);
4878 DrawPolyLine( aPoly
);
4882 PolyPolygon aPolyPoly
= rPolyPoly
;
4883 aPolyPoly
.Move( nX
, nY
);
4884 DrawPolyPolygon( aPolyPoly
);
4888 if ( !rRect1
.IsEmpty() )
4890 Rectangle
aRect( Point( nX
+rRect1
.Left(),
4891 nY
+rRect1
.Top() ), rRect1
.GetSize() );
4895 if ( !rRect2
.IsEmpty() )
4897 Rectangle
aRect( Point( nX
+rRect2
.Left(),
4898 nY
+rRect2
.Top() ), rRect2
.GetSize() );
4904 // -----------------------------------------------------------------------
4906 void OutputDevice::ImplDrawEmphasisMarks( SalLayout
& rSalLayout
)
4908 Color aOldColor
= GetTextColor();
4909 Color aOldLineColor
= GetLineColor();
4910 Color aOldFillColor
= GetFillColor();
4911 BOOL bOldMap
= mbMap
;
4912 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
4914 EnableMapMode( FALSE
);
4916 FontEmphasisMark nEmphasisMark
= ImplGetEmphasisMarkStyle( maFont
);
4917 PolyPolygon aPolyPoly
;
4921 long nEmphasisWidth
;
4922 long nEmphasisHeight
;
4925 if ( nEmphasisMark
& EMPHASISMARK_POS_BELOW
)
4926 nEmphasisHeight
= mnEmphasisDescent
;
4928 nEmphasisHeight
= mnEmphasisAscent
;
4930 ImplGetEmphasisMark( aPolyPoly
, bPolyLine
,
4932 nEmphasisYOff
, nEmphasisWidth
,
4934 nEmphasisHeight
, mpFontEntry
->mnOrientation
);
4938 SetLineColor( GetTextColor() );
4944 SetFillColor( GetTextColor() );
4947 Point aOffset
= Point(0,0);
4949 if ( nEmphasisMark
& EMPHASISMARK_POS_BELOW
)
4950 aOffset
.Y() += mpFontEntry
->maMetric
.mnDescent
+ nEmphasisYOff
;
4952 aOffset
.Y() -= mpFontEntry
->maMetric
.mnAscent
+ nEmphasisYOff
;
4954 long nEmphasisWidth2
= nEmphasisWidth
/ 2;
4955 long nEmphasisHeight2
= nEmphasisHeight
/ 2;
4956 aOffset
+= Point( nEmphasisWidth2
, nEmphasisHeight2
);
4959 Rectangle aRectangle
;
4960 for( int nStart
= 0;;)
4962 sal_GlyphId nGlyphIndex
;
4963 if( !rSalLayout
.GetNextGlyphs( 1, &nGlyphIndex
, aOutPoint
, nStart
) )
4966 if( !mpGraphics
->GetGlyphBoundRect( nGlyphIndex
, aRectangle
) )
4969 if( !rSalLayout
.IsSpacingGlyph( nGlyphIndex
) )
4971 Point aAdjPoint
= aOffset
;
4972 aAdjPoint
.X() += aRectangle
.Left() + (aRectangle
.GetWidth() - nEmphasisWidth
) / 2;
4973 if ( mpFontEntry
->mnOrientation
)
4974 ImplRotatePos( 0, 0, aAdjPoint
.X(), aAdjPoint
.Y(), mpFontEntry
->mnOrientation
);
4975 aOutPoint
+= aAdjPoint
;
4976 aOutPoint
-= Point( nEmphasisWidth2
, nEmphasisHeight2
);
4977 ImplDrawEmphasisMark( rSalLayout
.DrawBase().X(),
4978 aOutPoint
.X(), aOutPoint
.Y(),
4979 aPolyPoly
, bPolyLine
, aRect1
, aRect2
);
4983 SetLineColor( aOldLineColor
);
4984 SetFillColor( aOldFillColor
);
4985 EnableMapMode( bOldMap
);
4986 mpMetaFile
= pOldMetaFile
;
4989 // -----------------------------------------------------------------------
4991 bool OutputDevice::ImplDrawRotateText( SalLayout
& rSalLayout
)
4993 int nX
= rSalLayout
.DrawBase().X();
4994 int nY
= rSalLayout
.DrawBase().Y();
4996 Rectangle aBoundRect
;
4997 rSalLayout
.DrawBase() = Point( 0, 0 );
4998 rSalLayout
.DrawOffset() = Point( 0, 0 );
4999 if( !rSalLayout
.GetBoundRect( *mpGraphics
, aBoundRect
) )
5001 // guess vertical text extents if GetBoundRect failed
5002 int nRight
= rSalLayout
.GetTextWidth();
5003 int nTop
= mpFontEntry
->maMetric
.mnAscent
+ mnEmphasisAscent
;
5004 long nHeight
= mpFontEntry
->mnLineHeight
+ mnEmphasisAscent
+ mnEmphasisDescent
;
5005 aBoundRect
= Rectangle( 0, -nTop
, nRight
, nHeight
- nTop
);
5008 // cache virtual device for rotation
5009 if ( !mpOutDevData
)
5010 ImplInitOutDevData();
5011 if ( !mpOutDevData
->mpRotateDev
)
5012 mpOutDevData
->mpRotateDev
= new VirtualDevice( *this, 1 );
5013 VirtualDevice
* pVDev
= mpOutDevData
->mpRotateDev
;
5015 // size it accordingly
5016 if( !pVDev
->SetOutputSizePixel( aBoundRect
.GetSize() ) )
5019 Font
aFont( GetFont() );
5020 aFont
.SetOrientation( 0 );
5021 aFont
.SetSize( Size( mpFontEntry
->maFontSelData
.mnWidth
, mpFontEntry
->maFontSelData
.mnHeight
) );
5022 pVDev
->SetFont( aFont
);
5023 pVDev
->SetTextColor( Color( COL_BLACK
) );
5024 pVDev
->SetTextFillColor();
5025 pVDev
->ImplNewFont();
5026 pVDev
->ImplInitFont();
5027 pVDev
->ImplInitTextColor();
5029 // draw text into upper left corner
5030 rSalLayout
.DrawBase() -= aBoundRect
.TopLeft();
5031 rSalLayout
.DrawText( *((OutputDevice
*)pVDev
)->mpGraphics
);
5033 Bitmap aBmp
= pVDev
->GetBitmap( Point(), aBoundRect
.GetSize() );
5034 if ( !aBmp
|| !aBmp
.Rotate( mpFontEntry
->mnOwnOrientation
, COL_WHITE
) )
5037 // calculate rotation offset
5038 Polygon
aPoly( aBoundRect
);
5039 aPoly
.Rotate( Point(), mpFontEntry
->mnOwnOrientation
);
5040 Point aPoint
= aPoly
.GetBoundRect().TopLeft();
5041 aPoint
+= Point( nX
, nY
);
5043 // mask output with text colored bitmap
5044 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
5045 long nOldOffX
= mnOutOffX
;
5046 long nOldOffY
= mnOutOffY
;
5047 BOOL bOldMap
= mbMap
;
5052 EnableMapMode( FALSE
);
5054 DrawMask( aPoint
, aBmp
, GetTextColor() );
5056 EnableMapMode( bOldMap
);
5057 mnOutOffX
= nOldOffX
;
5058 mnOutOffY
= nOldOffY
;
5059 mpMetaFile
= pOldMetaFile
;
5064 // -----------------------------------------------------------------------
5066 void OutputDevice::ImplDrawTextDirect( SalLayout
& rSalLayout
, BOOL bTextLines
)
5068 if( mpFontEntry
->mnOwnOrientation
)
5069 if( ImplDrawRotateText( rSalLayout
) )
5072 long nOldX
= rSalLayout
.DrawBase().X();
5073 if( ! (mpPDFWriter
&& mpPDFWriter
->isBuiltinFont(mpFontEntry
->maFontSelData
.mpFontData
) ) )
5075 if( ImplHasMirroredGraphics() )
5077 long w
= meOutDevType
== OUTDEV_VIRDEV
? mnOutWidth
: mpGraphics
->GetGraphicsWidth();
5078 long x
= rSalLayout
.DrawBase().X();
5079 rSalLayout
.DrawBase().X() = w
- 1 - x
;
5080 if( !IsRTLEnabled() )
5082 OutputDevice
*pOutDevRef
= (OutputDevice
*)this;
5083 // mirror this window back
5084 long devX
= w
-pOutDevRef
->mnOutWidth
-pOutDevRef
->mnOutOffX
; // re-mirrored mnOutOffX
5085 rSalLayout
.DrawBase().X() = devX
+ ( pOutDevRef
->mnOutWidth
- 1 - (rSalLayout
.DrawBase().X() - devX
) ) ;
5088 else if( IsRTLEnabled() )
5090 //long w = meOutDevType == OUTDEV_VIRDEV ? mnOutWidth : mpGraphics->GetGraphicsWidth();
5091 //long x = rSalLayout.DrawBase().X();
5092 OutputDevice
*pOutDevRef
= (OutputDevice
*)this;
5093 // mirror this window back
5094 long devX
= pOutDevRef
->mnOutOffX
; // re-mirrored mnOutOffX
5095 rSalLayout
.DrawBase().X() = pOutDevRef
->mnOutWidth
- 1 - (rSalLayout
.DrawBase().X() - devX
) + devX
;
5098 rSalLayout
.DrawText( *mpGraphics
);
5101 rSalLayout
.DrawBase().X() = nOldX
;
5104 ImplDrawTextLines( rSalLayout
,
5105 maFont
.GetStrikeout(), maFont
.GetUnderline(), maFont
.GetOverline(),
5106 maFont
.IsWordLineMode(), ImplIsUnderlineAbove( maFont
) );
5109 if( maFont
.GetEmphasisMark() & EMPHASISMARK_STYLE
)
5110 ImplDrawEmphasisMarks( rSalLayout
);
5113 // -----------------------------------------------------------------------
5115 void OutputDevice::ImplDrawSpecialText( SalLayout
& rSalLayout
)
5117 Color aOldColor
= GetTextColor();
5118 Color aOldTextLineColor
= GetTextLineColor();
5119 Color aOldOverlineColor
= GetOverlineColor();
5120 FontRelief eRelief
= maFont
.GetRelief();
5122 Point aOrigPos
= rSalLayout
.DrawBase();
5123 if ( eRelief
!= RELIEF_NONE
)
5125 Color
aReliefColor( COL_LIGHTGRAY
);
5126 Color
aTextColor( aOldColor
);
5128 Color
aTextLineColor( aOldTextLineColor
);
5129 Color
aOverlineColor( aOldOverlineColor
);
5131 // we don't have a automatic color, so black is always drawn on white
5132 if ( aTextColor
.GetColor() == COL_BLACK
)
5133 aTextColor
= Color( COL_WHITE
);
5134 if ( aTextLineColor
.GetColor() == COL_BLACK
)
5135 aTextLineColor
= Color( COL_WHITE
);
5136 if ( aOverlineColor
.GetColor() == COL_BLACK
)
5137 aOverlineColor
= Color( COL_WHITE
);
5139 // relief-color is black for white text, in all other cases
5140 // we set this to LightGray
5141 if ( aTextColor
.GetColor() == COL_WHITE
)
5142 aReliefColor
= Color( COL_BLACK
);
5143 SetTextLineColor( aReliefColor
);
5144 SetOverlineColor( aReliefColor
);
5145 SetTextColor( aReliefColor
);
5146 ImplInitTextColor();
5148 // calculate offset - for high resolution printers the offset
5149 // should be greater so that the effect is visible
5153 if ( eRelief
== RELIEF_ENGRAVED
)
5155 rSalLayout
.DrawOffset() += Point( nOff
, nOff
);
5156 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5157 rSalLayout
.DrawOffset() -= Point( nOff
, nOff
);
5159 SetTextLineColor( aTextLineColor
);
5160 SetOverlineColor( aOverlineColor
);
5161 SetTextColor( aTextColor
);
5162 ImplInitTextColor();
5163 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5165 SetTextLineColor( aOldTextLineColor
);
5166 SetOverlineColor( aOldOverlineColor
);
5168 if ( aTextColor
!= aOldColor
)
5170 SetTextColor( aOldColor
);
5171 ImplInitTextColor();
5176 if ( maFont
.IsShadow() )
5178 long nOff
= 1 + ((mpFontEntry
->mnLineHeight
-24)/24);
5179 if ( maFont
.IsOutline() )
5183 if ( (GetTextColor().GetColor() == COL_BLACK
)
5184 || (GetTextColor().GetLuminance() < 8) )
5185 SetTextColor( Color( COL_LIGHTGRAY
) );
5187 SetTextColor( Color( COL_BLACK
) );
5188 ImplInitTextColor();
5189 rSalLayout
.DrawBase() += Point( nOff
, nOff
);
5190 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5191 rSalLayout
.DrawBase() -= Point( nOff
, nOff
);
5192 SetTextColor( aOldColor
);
5193 SetTextLineColor( aOldTextLineColor
);
5194 SetOverlineColor( aOldOverlineColor
);
5195 ImplInitTextColor();
5197 if ( !maFont
.IsOutline() )
5198 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5201 if ( maFont
.IsOutline() )
5203 rSalLayout
.DrawBase() = aOrigPos
+ Point(-1,-1);
5204 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5205 rSalLayout
.DrawBase() = aOrigPos
+ Point(+1,+1);
5206 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5207 rSalLayout
.DrawBase() = aOrigPos
+ Point(-1,+0);
5208 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5209 rSalLayout
.DrawBase() = aOrigPos
+ Point(-1,+1);
5210 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5211 rSalLayout
.DrawBase() = aOrigPos
+ Point(+0,+1);
5212 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5213 rSalLayout
.DrawBase() = aOrigPos
+ Point(+0,-1);
5214 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5215 rSalLayout
.DrawBase() = aOrigPos
+ Point(+1,-1);
5216 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5217 rSalLayout
.DrawBase() = aOrigPos
+ Point(+1,+0);
5218 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5219 rSalLayout
.DrawBase() = aOrigPos
;
5221 SetTextColor( Color( COL_WHITE
) );
5222 SetTextLineColor( Color( COL_WHITE
) );
5223 SetOverlineColor( Color( COL_WHITE
) );
5224 ImplInitTextColor();
5225 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5226 SetTextColor( aOldColor
);
5227 SetTextLineColor( aOldTextLineColor
);
5228 SetOverlineColor( aOldOverlineColor
);
5229 ImplInitTextColor();
5234 // -----------------------------------------------------------------------
5236 void OutputDevice::ImplDrawText( SalLayout
& rSalLayout
)
5238 if( mbInitClipRegion
)
5239 ImplInitClipRegion();
5240 if( mbOutputClipped
)
5242 if( mbInitTextColor
)
5243 ImplInitTextColor();
5245 rSalLayout
.DrawBase() += Point( mnTextOffX
, mnTextOffY
);
5247 if( IsTextFillColor() )
5248 ImplDrawTextBackground( rSalLayout
);
5251 ImplDrawSpecialText( rSalLayout
);
5253 ImplDrawTextDirect( rSalLayout
, mbTextLines
);
5256 // -----------------------------------------------------------------------
5258 long OutputDevice::ImplGetTextLines( ImplMultiTextLineInfo
& rLineInfo
,
5259 long nWidth
, const XubString
& rStr
,
5260 USHORT nStyle
) const
5262 DBG_ASSERTWARNING( nWidth
>= 0, "ImplGetTextLines: nWidth <= 0!" );
5267 long nMaxLineWidth
= 0;
5269 if ( rStr
.Len() && (nWidth
> 0) )
5271 ::rtl::OUString
aText( rStr
);
5272 uno::Reference
< i18n::XBreakIterator
> xBI
;
5273 // get service provider
5274 uno::Reference
< lang::XMultiServiceFactory
> xSMgr( unohelper::GetMultiServiceFactory() );
5276 uno::Reference
< linguistic2::XHyphenator
> xHyph
;
5279 uno::Reference
< linguistic2::XLinguServiceManager
> xLinguMgr(xSMgr
->createInstance(::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("com.sun.star.linguistic2.LinguServiceManager"))),uno::UNO_QUERY
);
5280 if ( xLinguMgr
.is() )
5282 xHyph
= xLinguMgr
->getHyphenator();
5286 i18n::LineBreakHyphenationOptions
aHyphOptions( xHyph
, uno::Sequence
<beans::PropertyValue
>(), 1 );
5287 i18n::LineBreakUserOptions aUserOptions
;
5289 xub_StrLen nPos
= 0;
5290 xub_StrLen nLen
= rStr
.Len();
5291 while ( nPos
< nLen
)
5293 xub_StrLen nBreakPos
= nPos
;
5295 while ( ( nBreakPos
< nLen
) && ( rStr
.GetChar( nBreakPos
) != _CR
) && ( rStr
.GetChar( nBreakPos
) != _LF
) )
5298 long nLineWidth
= GetTextWidth( rStr
, nPos
, nBreakPos
-nPos
);
5299 if ( ( nLineWidth
> nWidth
) && ( nStyle
& TEXT_DRAW_WORDBREAK
) )
5302 xBI
= vcl::unohelper::CreateBreakIterator();
5306 const com::sun::star::lang::Locale
& rDefLocale(Application::GetSettings().GetUILocale());
5307 xub_StrLen nSoftBreak
= GetTextBreak( rStr
, nWidth
, nPos
, nBreakPos
- nPos
);
5308 DBG_ASSERT( nSoftBreak
< nBreakPos
, "Break?!" );
5309 //aHyphOptions.hyphenIndex = nSoftBreak;
5310 i18n::LineBreakResults aLBR
= xBI
->getLineBreak( aText
, nSoftBreak
, rDefLocale
, nPos
, aHyphOptions
, aUserOptions
);
5311 nBreakPos
= (xub_StrLen
)aLBR
.breakIndex
;
5312 if ( nBreakPos
<= nPos
)
5313 nBreakPos
= nSoftBreak
;
5314 if ( (nStyle
& TEXT_DRAW_WORDBREAK_HYPHENATION
) == TEXT_DRAW_WORDBREAK_HYPHENATION
)
5316 // Egal ob Trenner oder nicht: Das Wort nach dem Trenner durch
5317 // die Silbentrennung jagen...
5318 // nMaxBreakPos ist das letzte Zeichen was in die Zeile passt,
5319 // nBreakPos ist der Wort-Anfang
5320 // Ein Problem gibt es, wenn das Dok so schmal ist, dass ein Wort
5321 // auf mehr als Zwei Zeilen gebrochen wird...
5324 sal_Unicode cAlternateReplChar
= 0;
5325 sal_Unicode cAlternateExtraChar
= 0;
5326 i18n::Boundary aBoundary
= xBI
->getWordBoundary( aText
, nBreakPos
, rDefLocale
, ::com::sun::star::i18n::WordType::DICTIONARY_WORD
, sal_True
);
5327 // sal_uInt16 nWordStart = nBreakPos;
5328 // sal_uInt16 nBreakPos_OLD = nBreakPos;
5329 sal_uInt16 nWordStart
= nPos
;
5330 sal_uInt16 nWordEnd
= (USHORT
) aBoundary
.endPos
;
5331 DBG_ASSERT( nWordEnd
> nWordStart
, "ImpBreakLine: Start >= End?" );
5333 USHORT nWordLen
= nWordEnd
- nWordStart
;
5334 if ( ( nWordEnd
>= nSoftBreak
) && ( nWordLen
> 3 ) )
5336 // #104415# May happen, because getLineBreak may differ from getWordBoudary with DICTIONARY_WORD
5337 // DBG_ASSERT( nWordEnd >= nMaxBreakPos, "Hyph: Break?" );
5338 String
aWord( aText
, nWordStart
, nWordLen
);
5339 sal_uInt16 nMinTrail
= static_cast<sal_uInt16
>(nWordEnd
-nSoftBreak
+1); //+1: Vor dem angeknacksten Buchstaben
5340 uno::Reference
< linguistic2::XHyphenatedWord
> xHyphWord
;
5342 xHyphWord
= xHyph
->hyphenate( aWord
, rDefLocale
, aWord
.Len() - nMinTrail
, uno::Sequence
< beans::PropertyValue
>() );
5345 sal_Bool bAlternate
= xHyphWord
->isAlternativeSpelling();
5346 sal_uInt16 _nWordLen
= 1 + xHyphWord
->getHyphenPos();
5348 if ( ( _nWordLen
>= 2 ) && ( (nWordStart
+_nWordLen
) >= ( 2 ) ) )
5352 nBreakPos
= nWordStart
+ _nWordLen
;
5356 String
aAlt( xHyphWord
->getHyphenatedWord() );
5358 // Wir gehen von zwei Faellen aus, die nun
5359 // vorliegen koennen:
5360 // 1) packen wird zu pak-ken
5361 // 2) Schiffahrt wird zu Schiff-fahrt
5362 // In Fall 1 muss ein Zeichen ersetzt werden,
5363 // in Fall 2 wird ein Zeichen hinzugefuegt.
5364 // Die Identifikation wird erschwert durch Worte wie
5365 // "Schiffahrtsbrennesseln", da der Hyphenator alle
5366 // Position des Wortes auftrennt und "Schifffahrtsbrennnesseln"
5367 // ermittelt. Wir koennen also eigentlich nicht unmittelbar vom
5368 // Index des AlternativWord auf aWord schliessen.
5370 // Das ganze geraffel wird durch eine Funktion am
5371 // Hyphenator vereinfacht werden, sobald AMA sie einbaut...
5372 sal_uInt16 nAltStart
= _nWordLen
- 1;
5373 sal_uInt16 nTxtStart
= nAltStart
- (aAlt
.Len() - aWord
.Len());
5374 sal_uInt16 nTxtEnd
= nTxtStart
;
5375 sal_uInt16 nAltEnd
= nAltStart
;
5377 // Die Bereiche zwischen den nStart und nEnd ist
5378 // die Differenz zwischen Alternativ- und OriginalString.
5379 while( nTxtEnd
< aWord
.Len() && nAltEnd
< aAlt
.Len() &&
5380 aWord
.GetChar(nTxtEnd
) != aAlt
.GetChar(nAltEnd
) )
5386 // Wenn ein Zeichen hinzugekommen ist, dann bemerken wir es jetzt:
5387 if( nAltEnd
> nTxtEnd
&& nAltStart
== nAltEnd
&&
5388 aWord
.GetChar( nTxtEnd
) == aAlt
.GetChar(nAltEnd
) )
5395 DBG_ASSERT( ( nAltEnd
- nAltStart
) == 1, "Alternate: Falsche Annahme!" );
5397 if ( nTxtEnd
> nTxtStart
)
5398 cAlternateReplChar
= aAlt
.GetChar( nAltStart
);
5400 cAlternateExtraChar
= aAlt
.GetChar( nAltStart
);
5402 nBreakPos
= nWordStart
+ nTxtStart
;
5403 if ( cAlternateReplChar
)
5406 } // if (xHyphWord.is())
5407 } // if ( ( nWordEnd >= nSoftBreak ) && ( nWordLen > 3 ) )
5408 } // if ( xHyph.is() )
5409 } // if ( (nStyle & TEXT_DRAW_WORDBREAK_HYPHENATION) == TEXT_DRAW_WORDBREAK_HYPHENATION )
5411 nLineWidth
= GetTextWidth( rStr
, nPos
, nBreakPos
-nPos
);
5415 // fallback to something really simple
5416 USHORT nSpacePos
= STRING_LEN
;
5420 nSpacePos
= rStr
.SearchBackward( sal_Unicode(' '), nSpacePos
);
5421 if( nSpacePos
!= STRING_NOTFOUND
)
5423 if( nSpacePos
> nPos
)
5425 nW
= GetTextWidth( rStr
, nPos
, nSpacePos
-nPos
);
5427 } while( nW
> nWidth
);
5429 if( nSpacePos
!= STRING_NOTFOUND
)
5431 nBreakPos
= nSpacePos
;
5432 nLineWidth
= GetTextWidth( rStr
, nPos
, nBreakPos
-nPos
);
5433 if( nBreakPos
< rStr
.Len()-1 )
5439 if ( nLineWidth
> nMaxLineWidth
)
5440 nMaxLineWidth
= nLineWidth
;
5442 rLineInfo
.AddLine( new ImplTextLineInfo( nLineWidth
, nPos
, nBreakPos
-nPos
) );
5444 if ( nBreakPos
== nPos
)
5448 if ( ( rStr
.GetChar( nPos
) == _CR
) || ( rStr
.GetChar( nPos
) == _LF
) )
5452 if ( ( nPos
< nLen
) && ( rStr
.GetChar( nPos
) == _LF
) && ( rStr
.GetChar( nPos
-1 ) == _CR
) )
5458 for ( USHORT nL
= 0; nL
< rLineInfo
.Count(); nL
++ )
5460 ImplTextLineInfo
* pLine
= rLineInfo
.GetLine( nL
);
5461 String
aLine( rStr
, pLine
->GetIndex(), pLine
->GetLen() );
5462 DBG_ASSERT( aLine
.Search( _CR
) == STRING_NOTFOUND
, "ImplGetTextLines - Found CR!" );
5463 DBG_ASSERT( aLine
.Search( _LF
) == STRING_NOTFOUND
, "ImplGetTextLines - Found LF!" );
5467 return nMaxLineWidth
;
5470 // =======================================================================
5472 void OutputDevice::SetAntialiasing( USHORT nMode
)
5474 if ( mnAntialiasing
!= nMode
)
5476 mnAntialiasing
= nMode
;
5481 mpGraphics
->setAntiAliasB2DDraw(mnAntialiasing
& ANTIALIASING_ENABLE_B2DDRAW
);
5486 mpAlphaVDev
->SetAntialiasing( nMode
);
5489 // -----------------------------------------------------------------------
5491 void OutputDevice::SetFont( const Font
& rNewFont
)
5493 DBG_TRACE( "OutputDevice::SetFont()" );
5494 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5495 DBG_CHKOBJ( &rNewFont
, Font
, NULL
);
5497 Font
aFont( rNewFont
);
5498 aFont
.SetLanguage(rNewFont
.GetLanguage());
5499 if ( mnDrawMode
& (DRAWMODE_BLACKTEXT
| DRAWMODE_WHITETEXT
| DRAWMODE_GRAYTEXT
| DRAWMODE_GHOSTEDTEXT
| DRAWMODE_SETTINGSTEXT
|
5500 DRAWMODE_BLACKFILL
| DRAWMODE_WHITEFILL
| DRAWMODE_GRAYFILL
| DRAWMODE_NOFILL
|
5501 DRAWMODE_GHOSTEDFILL
| DRAWMODE_SETTINGSFILL
) )
5503 Color
aTextColor( aFont
.GetColor() );
5505 if ( mnDrawMode
& DRAWMODE_BLACKTEXT
)
5506 aTextColor
= Color( COL_BLACK
);
5507 else if ( mnDrawMode
& DRAWMODE_WHITETEXT
)
5508 aTextColor
= Color( COL_WHITE
);
5509 else if ( mnDrawMode
& DRAWMODE_GRAYTEXT
)
5511 const UINT8 cLum
= aTextColor
.GetLuminance();
5512 aTextColor
= Color( cLum
, cLum
, cLum
);
5514 else if ( mnDrawMode
& DRAWMODE_SETTINGSTEXT
)
5515 aTextColor
= GetSettings().GetStyleSettings().GetFontColor();
5517 if ( mnDrawMode
& DRAWMODE_GHOSTEDTEXT
)
5519 aTextColor
= Color( (aTextColor
.GetRed() >> 1 ) | 0x80,
5520 (aTextColor
.GetGreen() >> 1 ) | 0x80,
5521 (aTextColor
.GetBlue() >> 1 ) | 0x80 );
5524 aFont
.SetColor( aTextColor
);
5526 BOOL bTransFill
= aFont
.IsTransparent();
5529 Color
aTextFillColor( aFont
.GetFillColor() );
5531 if ( mnDrawMode
& DRAWMODE_BLACKFILL
)
5532 aTextFillColor
= Color( COL_BLACK
);
5533 else if ( mnDrawMode
& DRAWMODE_WHITEFILL
)
5534 aTextFillColor
= Color( COL_WHITE
);
5535 else if ( mnDrawMode
& DRAWMODE_GRAYFILL
)
5537 const UINT8 cLum
= aTextFillColor
.GetLuminance();
5538 aTextFillColor
= Color( cLum
, cLum
, cLum
);
5540 else if( mnDrawMode
& DRAWMODE_SETTINGSFILL
)
5541 aTextFillColor
= GetSettings().GetStyleSettings().GetWindowColor();
5542 else if ( mnDrawMode
& DRAWMODE_NOFILL
)
5544 aTextFillColor
= Color( COL_TRANSPARENT
);
5548 if ( !bTransFill
&& (mnDrawMode
& DRAWMODE_GHOSTEDFILL
) )
5550 aTextFillColor
= Color( (aTextFillColor
.GetRed() >> 1) | 0x80,
5551 (aTextFillColor
.GetGreen() >> 1) | 0x80,
5552 (aTextFillColor
.GetBlue() >> 1) | 0x80 );
5555 aFont
.SetFillColor( aTextFillColor
);
5561 mpMetaFile
->AddAction( new MetaFontAction( aFont
) );
5562 // the color and alignment actions don't belong here
5563 // TODO: get rid of them without breaking anything...
5564 mpMetaFile
->AddAction( new MetaTextAlignAction( aFont
.GetAlign() ) );
5565 mpMetaFile
->AddAction( new MetaTextFillColorAction( aFont
.GetFillColor(), !aFont
.IsTransparent() ) );
5568 #if (OSL_DEBUG_LEVEL > 2) || defined (HDU_DEBUG)
5569 fprintf( stderr
, " OutputDevice::SetFont( name=\"%s\", h=%ld)\n",
5570 OUStringToOString( aFont
.GetName(), RTL_TEXTENCODING_UTF8
).getStr(),
5571 aFont
.GetSize().Height() );
5574 if ( !maFont
.IsSameInstance( aFont
) )
5576 // Optimization MT/HDU: COL_TRANSPARENT means SetFont should ignore the font color,
5577 // because SetTextColor() is used for this.
5578 // #i28759# maTextColor might have been changed behind our back, commit then, too.
5579 if( aFont
.GetColor() != COL_TRANSPARENT
5580 && (aFont
.GetColor() != maFont
.GetColor() || aFont
.GetColor() != maTextColor
) )
5582 maTextColor
= aFont
.GetColor();
5583 mbInitTextColor
= TRUE
;
5585 mpMetaFile
->AddAction( new MetaTextColorAction( aFont
.GetColor() ) );
5593 // Since SetFont might change the text color, apply that only
5594 // selectively to alpha vdev (which normally paints opaque text
5596 if( aFont
.GetColor() != COL_TRANSPARENT
)
5598 mpAlphaVDev
->SetTextColor( COL_BLACK
);
5599 aFont
.SetColor( COL_TRANSPARENT
);
5602 mpAlphaVDev
->SetFont( aFont
);
5607 // -----------------------------------------------------------------------
5609 void OutputDevice::SetLayoutMode( ULONG nTextLayoutMode
)
5611 DBG_TRACE( "OutputDevice::SetTextLayoutMode()" );
5614 mpMetaFile
->AddAction( new MetaLayoutModeAction( nTextLayoutMode
) );
5616 mnTextLayoutMode
= nTextLayoutMode
;
5619 mpAlphaVDev
->SetLayoutMode( nTextLayoutMode
);
5622 // -----------------------------------------------------------------------
5624 void OutputDevice::SetDigitLanguage( LanguageType eTextLanguage
)
5626 DBG_TRACE( "OutputDevice::SetTextLanguage()" );
5629 mpMetaFile
->AddAction( new MetaTextLanguageAction( eTextLanguage
) );
5631 meTextLanguage
= eTextLanguage
;
5634 mpAlphaVDev
->SetDigitLanguage( eTextLanguage
);
5637 // -----------------------------------------------------------------------
5639 void OutputDevice::SetTextColor( const Color
& rColor
)
5641 DBG_TRACE( "OutputDevice::SetTextColor()" );
5642 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5644 Color
aColor( rColor
);
5646 if ( mnDrawMode
& ( DRAWMODE_BLACKTEXT
| DRAWMODE_WHITETEXT
|
5647 DRAWMODE_GRAYTEXT
| DRAWMODE_GHOSTEDTEXT
|
5648 DRAWMODE_SETTINGSTEXT
) )
5650 if ( mnDrawMode
& DRAWMODE_BLACKTEXT
)
5651 aColor
= Color( COL_BLACK
);
5652 else if ( mnDrawMode
& DRAWMODE_WHITETEXT
)
5653 aColor
= Color( COL_WHITE
);
5654 else if ( mnDrawMode
& DRAWMODE_GRAYTEXT
)
5656 const UINT8 cLum
= aColor
.GetLuminance();
5657 aColor
= Color( cLum
, cLum
, cLum
);
5659 else if ( mnDrawMode
& DRAWMODE_SETTINGSTEXT
)
5660 aColor
= GetSettings().GetStyleSettings().GetFontColor();
5662 if ( mnDrawMode
& DRAWMODE_GHOSTEDTEXT
)
5664 aColor
= Color( (aColor
.GetRed() >> 1) | 0x80,
5665 (aColor
.GetGreen() >> 1) | 0x80,
5666 (aColor
.GetBlue() >> 1) | 0x80 );
5671 mpMetaFile
->AddAction( new MetaTextColorAction( aColor
) );
5673 if ( maTextColor
!= aColor
)
5675 maTextColor
= aColor
;
5676 mbInitTextColor
= TRUE
;
5680 mpAlphaVDev
->SetTextColor( COL_BLACK
);
5683 // -----------------------------------------------------------------------
5685 void OutputDevice::SetTextFillColor()
5687 DBG_TRACE( "OutputDevice::SetTextFillColor()" );
5688 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5691 mpMetaFile
->AddAction( new MetaTextFillColorAction( Color(), FALSE
) );
5693 if ( maFont
.GetColor() != Color( COL_TRANSPARENT
) )
5694 maFont
.SetFillColor( Color( COL_TRANSPARENT
) );
5695 if ( !maFont
.IsTransparent() )
5696 maFont
.SetTransparent( TRUE
);
5699 mpAlphaVDev
->SetTextFillColor();
5702 // -----------------------------------------------------------------------
5704 void OutputDevice::SetTextFillColor( const Color
& rColor
)
5706 DBG_TRACE( "OutputDevice::SetTextFillColor()" );
5707 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5709 Color
aColor( rColor
);
5710 BOOL bTransFill
= ImplIsColorTransparent( aColor
) ? TRUE
: FALSE
;
5714 if ( mnDrawMode
& ( DRAWMODE_BLACKFILL
| DRAWMODE_WHITEFILL
|
5715 DRAWMODE_GRAYFILL
| DRAWMODE_NOFILL
|
5716 DRAWMODE_GHOSTEDFILL
| DRAWMODE_SETTINGSFILL
) )
5718 if ( mnDrawMode
& DRAWMODE_BLACKFILL
)
5719 aColor
= Color( COL_BLACK
);
5720 else if ( mnDrawMode
& DRAWMODE_WHITEFILL
)
5721 aColor
= Color( COL_WHITE
);
5722 else if ( mnDrawMode
& DRAWMODE_GRAYFILL
)
5724 const UINT8 cLum
= aColor
.GetLuminance();
5725 aColor
= Color( cLum
, cLum
, cLum
);
5727 else if( mnDrawMode
& DRAWMODE_SETTINGSFILL
)
5728 aColor
= GetSettings().GetStyleSettings().GetWindowColor();
5729 else if ( mnDrawMode
& DRAWMODE_NOFILL
)
5731 aColor
= Color( COL_TRANSPARENT
);
5735 if ( !bTransFill
&& (mnDrawMode
& DRAWMODE_GHOSTEDFILL
) )
5737 aColor
= Color( (aColor
.GetRed() >> 1) | 0x80,
5738 (aColor
.GetGreen() >> 1) | 0x80,
5739 (aColor
.GetBlue() >> 1) | 0x80 );
5745 mpMetaFile
->AddAction( new MetaTextFillColorAction( aColor
, TRUE
) );
5747 if ( maFont
.GetFillColor() != aColor
)
5748 maFont
.SetFillColor( aColor
);
5749 if ( maFont
.IsTransparent() != bTransFill
)
5750 maFont
.SetTransparent( bTransFill
);
5753 mpAlphaVDev
->SetTextFillColor( COL_BLACK
);
5756 // -----------------------------------------------------------------------
5758 Color
OutputDevice::GetTextFillColor() const
5760 if ( maFont
.IsTransparent() )
5761 return Color( COL_TRANSPARENT
);
5763 return maFont
.GetFillColor();
5766 // -----------------------------------------------------------------------
5768 void OutputDevice::SetTextLineColor()
5770 DBG_TRACE( "OutputDevice::SetTextLineColor()" );
5771 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5774 mpMetaFile
->AddAction( new MetaTextLineColorAction( Color(), FALSE
) );
5776 maTextLineColor
= Color( COL_TRANSPARENT
);
5779 mpAlphaVDev
->SetTextLineColor();
5782 // -----------------------------------------------------------------------
5784 void OutputDevice::SetTextLineColor( const Color
& rColor
)
5786 DBG_TRACE( "OutputDevice::SetTextLineColor()" );
5787 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5789 Color
aColor( rColor
);
5791 if ( mnDrawMode
& ( DRAWMODE_BLACKTEXT
| DRAWMODE_WHITETEXT
|
5792 DRAWMODE_GRAYTEXT
| DRAWMODE_GHOSTEDTEXT
|
5793 DRAWMODE_SETTINGSTEXT
) )
5795 if ( mnDrawMode
& DRAWMODE_BLACKTEXT
)
5796 aColor
= Color( COL_BLACK
);
5797 else if ( mnDrawMode
& DRAWMODE_WHITETEXT
)
5798 aColor
= Color( COL_WHITE
);
5799 else if ( mnDrawMode
& DRAWMODE_GRAYTEXT
)
5801 const UINT8 cLum
= aColor
.GetLuminance();
5802 aColor
= Color( cLum
, cLum
, cLum
);
5804 else if ( mnDrawMode
& DRAWMODE_SETTINGSTEXT
)
5805 aColor
= GetSettings().GetStyleSettings().GetFontColor();
5807 if( (mnDrawMode
& DRAWMODE_GHOSTEDTEXT
)
5808 && (aColor
.GetColor() != COL_TRANSPARENT
) )
5810 aColor
= Color( (aColor
.GetRed() >> 1) | 0x80,
5811 (aColor
.GetGreen() >> 1) | 0x80,
5812 (aColor
.GetBlue() >> 1) | 0x80 );
5817 mpMetaFile
->AddAction( new MetaTextLineColorAction( aColor
, TRUE
) );
5819 maTextLineColor
= aColor
;
5822 mpAlphaVDev
->SetTextLineColor( COL_BLACK
);
5825 // -----------------------------------------------------------------------
5827 void OutputDevice::SetOverlineColor()
5829 DBG_TRACE( "OutputDevice::SetOverlineColor()" );
5830 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5833 mpMetaFile
->AddAction( new MetaOverlineColorAction( Color(), FALSE
) );
5835 maOverlineColor
= Color( COL_TRANSPARENT
);
5838 mpAlphaVDev
->SetOverlineColor();
5841 // -----------------------------------------------------------------------
5843 void OutputDevice::SetOverlineColor( const Color
& rColor
)
5845 DBG_TRACE( "OutputDevice::SetOverlineColor()" );
5846 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5848 Color
aColor( rColor
);
5850 if ( mnDrawMode
& ( DRAWMODE_BLACKTEXT
| DRAWMODE_WHITETEXT
|
5851 DRAWMODE_GRAYTEXT
| DRAWMODE_GHOSTEDTEXT
|
5852 DRAWMODE_SETTINGSTEXT
) )
5854 if ( mnDrawMode
& DRAWMODE_BLACKTEXT
)
5855 aColor
= Color( COL_BLACK
);
5856 else if ( mnDrawMode
& DRAWMODE_WHITETEXT
)
5857 aColor
= Color( COL_WHITE
);
5858 else if ( mnDrawMode
& DRAWMODE_GRAYTEXT
)
5860 const UINT8 cLum
= aColor
.GetLuminance();
5861 aColor
= Color( cLum
, cLum
, cLum
);
5863 else if ( mnDrawMode
& DRAWMODE_SETTINGSTEXT
)
5864 aColor
= GetSettings().GetStyleSettings().GetFontColor();
5866 if( (mnDrawMode
& DRAWMODE_GHOSTEDTEXT
)
5867 && (aColor
.GetColor() != COL_TRANSPARENT
) )
5869 aColor
= Color( (aColor
.GetRed() >> 1) | 0x80,
5870 (aColor
.GetGreen() >> 1) | 0x80,
5871 (aColor
.GetBlue() >> 1) | 0x80 );
5876 mpMetaFile
->AddAction( new MetaOverlineColorAction( aColor
, TRUE
) );
5878 maOverlineColor
= aColor
;
5881 mpAlphaVDev
->SetOverlineColor( COL_BLACK
);
5884 // -----------------------------------------------------------------------
5887 void OutputDevice::SetTextAlign( TextAlign eAlign
)
5889 DBG_TRACE( "OutputDevice::SetTextAlign()" );
5890 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5893 mpMetaFile
->AddAction( new MetaTextAlignAction( eAlign
) );
5895 if ( maFont
.GetAlign() != eAlign
)
5897 maFont
.SetAlign( eAlign
);
5902 mpAlphaVDev
->SetTextAlign( eAlign
);
5905 // -----------------------------------------------------------------------
5907 void OutputDevice::DrawTextLine( const Point
& rPos
, long nWidth
,
5908 FontStrikeout eStrikeout
,
5909 FontUnderline eUnderline
,
5910 FontUnderline eOverline
,
5911 BOOL bUnderlineAbove
)
5913 DBG_TRACE( "OutputDevice::DrawTextLine()" );
5914 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5917 mpMetaFile
->AddAction( new MetaTextLineAction( rPos
, nWidth
, eStrikeout
, eUnderline
, eOverline
) );
5919 if ( ((eUnderline
== UNDERLINE_NONE
) || (eUnderline
== UNDERLINE_DONTKNOW
)) &&
5920 ((eOverline
== UNDERLINE_NONE
) || (eOverline
== UNDERLINE_DONTKNOW
)) &&
5921 ((eStrikeout
== STRIKEOUT_NONE
) || (eStrikeout
== STRIKEOUT_DONTKNOW
)) )
5924 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
5927 // we need a graphics
5928 if( !mpGraphics
&& !ImplGetGraphics() )
5930 if( mbInitClipRegion
)
5931 ImplInitClipRegion();
5932 if( mbOutputClipped
)
5935 // initialize font if needed to get text offsets
5936 // TODO: only needed for mnTextOff!=(0,0)
5938 if( !ImplNewFont() )
5943 Point aPos
= ImplLogicToDevicePixel( rPos
);
5944 nWidth
= ImplLogicWidthToDevicePixel( nWidth
);
5945 aPos
+= Point( mnTextOffX
, mnTextOffY
);
5946 ImplDrawTextLine( aPos
.X(), aPos
.X(), aPos
.Y(), nWidth
, eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
5949 mpAlphaVDev
->DrawTextLine( rPos
, nWidth
, eStrikeout
, eUnderline
, eOverline
, bUnderlineAbove
);
5952 // ------------------------------------------------------------------------
5954 BOOL
OutputDevice::IsTextUnderlineAbove( const Font
& rFont
)
5956 return ImplIsUnderlineAbove( rFont
);
5959 // ------------------------------------------------------------------------
5961 void OutputDevice::DrawWaveLine( const Point
& rStartPos
, const Point
& rEndPos
,
5964 DBG_TRACE( "OutputDevice::DrawWaveLine()" );
5965 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
5967 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
5970 // we need a graphics
5972 if( !ImplGetGraphics() )
5975 if ( mbInitClipRegion
)
5976 ImplInitClipRegion();
5977 if ( mbOutputClipped
)
5981 if( !ImplNewFont() )
5984 Point aStartPt
= ImplLogicToDevicePixel( rStartPos
);
5985 Point aEndPt
= ImplLogicToDevicePixel( rEndPos
);
5986 long nStartX
= aStartPt
.X();
5987 long nStartY
= aStartPt
.Y();
5988 long nEndX
= aEndPt
.X();
5989 long nEndY
= aEndPt
.Y();
5990 short nOrientation
= 0;
5993 if ( (nStartY
!= nEndY
) || (nStartX
> nEndX
) )
5995 long nDX
= nEndX
- nStartX
;
5996 double nO
= atan2( -nEndY
+ nStartY
, ((nDX
== 0L) ? 0.000000001 : nDX
) );
5998 nOrientation
= (short)nO
;
5999 ImplRotatePos( nStartX
, nStartY
, nEndX
, nEndY
, -nOrientation
);
6003 if ( nStyle
== WAVE_NORMAL
)
6009 else if( nStyle
== WAVE_SMALL
)
6018 // #109280# make sure the waveline does not exceed the descent to avoid paint problems
6019 ImplFontEntry
* pFontEntry
= mpFontEntry
;
6020 if( nWaveHeight
> pFontEntry
->maMetric
.mnWUnderlineSize
)
6021 nWaveHeight
= pFontEntry
->maMetric
.mnWUnderlineSize
;
6023 ImplDrawWaveLine( nStartX
, nStartY
, nStartX
, nStartY
,
6024 nEndX
-nStartX
, nWaveHeight
, 1,
6025 nOrientation
, GetLineColor() );
6027 mpAlphaVDev
->DrawWaveLine( rStartPos
, rEndPos
, nStyle
);
6030 // -----------------------------------------------------------------------
6032 void OutputDevice::DrawText( const Point
& rStartPt
, const String
& rStr
,
6033 xub_StrLen nIndex
, xub_StrLen nLen
,
6034 MetricVector
* pVector
, String
* pDisplayText
6037 if( mpOutDevData
&& mpOutDevData
->mpRecordLayout
)
6039 pVector
= &mpOutDevData
->mpRecordLayout
->m_aUnicodeBoundRects
;
6040 pDisplayText
= &mpOutDevData
->mpRecordLayout
->m_aDisplayText
;
6043 DBG_TRACE( "OutputDevice::DrawText()" );
6044 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6046 #if OSL_DEBUG_LEVEL > 2
6047 fprintf( stderr
, " OutputDevice::DrawText(\"%s\")\n",
6048 OUStringToOString( rStr
, RTL_TEXTENCODING_UTF8
).getStr() );
6052 mpMetaFile
->AddAction( new MetaTextAction( rStartPt
, rStr
, nIndex
, nLen
) );
6055 Region
aClip( GetClipRegion() );
6056 if( meOutDevType
== OUTDEV_WINDOW
)
6057 aClip
.Intersect( Rectangle( Point(), GetOutputSize() ) );
6058 if( mpOutDevData
&& mpOutDevData
->mpRecordLayout
)
6060 mpOutDevData
->mpRecordLayout
->m_aLineIndices
.push_back( mpOutDevData
->mpRecordLayout
->m_aDisplayText
.Len() );
6061 aClip
.Intersect( mpOutDevData
->maRecordRect
);
6063 if( ! aClip
.IsNull() )
6066 GetGlyphBoundRects( rStartPt
, rStr
, nIndex
, nLen
, nIndex
, aTmp
);
6068 bool bInserted
= false;
6069 for( MetricVector::const_iterator it
= aTmp
.begin(); it
!= aTmp
.end(); ++it
, nIndex
++ )
6071 bool bAppend
= false;
6073 if( aClip
.IsOver( *it
) )
6075 else if( rStr
.GetChar( nIndex
) == ' ' && bInserted
)
6077 MetricVector::const_iterator next
= it
;
6079 if( next
!= aTmp
.end() && aClip
.IsOver( *next
) )
6085 pVector
->push_back( *it
);
6087 pDisplayText
->Append( rStr
.GetChar( nIndex
) );
6094 GetGlyphBoundRects( rStartPt
, rStr
, nIndex
, nLen
, nIndex
, *pVector
);
6096 pDisplayText
->Append( rStr
.Copy( nIndex
, nLen
) );
6100 if ( !IsDeviceOutputNecessary() || pVector
)
6103 SalLayout
* pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
, rStartPt
, 0, NULL
, true );
6106 ImplDrawText( *pSalLayout
);
6107 pSalLayout
->Release();
6111 mpAlphaVDev
->DrawText( rStartPt
, rStr
, nIndex
, nLen
, pVector
, pDisplayText
);
6114 // -----------------------------------------------------------------------
6116 long OutputDevice::GetTextWidth( const String
& rStr
,
6117 xub_StrLen nIndex
, xub_StrLen nLen
) const
6119 DBG_TRACE( "OutputDevice::GetTextWidth()" );
6120 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6122 long nWidth
= GetTextArray( rStr
, NULL
, nIndex
, nLen
);
6126 // -----------------------------------------------------------------------
6128 long OutputDevice::GetTextHeight() const
6130 DBG_TRACE( "OutputDevice::GetTextHeight()" );
6131 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6134 if( !ImplNewFont() )
6137 if( !ImplNewFont() )
6140 long nHeight
= mpFontEntry
->mnLineHeight
+ mnEmphasisAscent
+ mnEmphasisDescent
;
6143 nHeight
= ImplDevicePixelToLogicHeight( nHeight
);
6148 // -----------------------------------------------------------------------
6150 void OutputDevice::DrawTextArray( const Point
& rStartPt
, const String
& rStr
,
6151 const sal_Int32
* pDXAry
,
6152 xub_StrLen nIndex
, xub_StrLen nLen
)
6154 DBG_TRACE( "OutputDevice::DrawTextArray()" );
6155 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6158 mpMetaFile
->AddAction( new MetaTextArrayAction( rStartPt
, rStr
, pDXAry
, nIndex
, nLen
) );
6160 if ( !IsDeviceOutputNecessary() )
6163 SalLayout
* pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
, rStartPt
, 0, pDXAry
, true );
6166 ImplDrawText( *pSalLayout
);
6167 pSalLayout
->Release();
6171 mpAlphaVDev
->DrawTextArray( rStartPt
, rStr
, pDXAry
, nIndex
, nLen
);
6174 // -----------------------------------------------------------------------
6176 long OutputDevice::GetTextArray( const String
& rStr
, sal_Int32
* pDXAry
,
6177 xub_StrLen nIndex
, xub_StrLen nLen
) const
6179 DBG_TRACE( "OutputDevice::GetTextArray()" );
6180 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6182 if( nIndex
>= rStr
.Len() )
6184 if( (ULONG
)nIndex
+nLen
>= rStr
.Len() )
6185 nLen
= rStr
.Len() - nIndex
;
6188 SalLayout
* pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
);
6192 long nWidth
= pSalLayout
->FillDXArray( pDXAry
);
6193 int nWidthFactor
= pSalLayout
->GetUnitsPerPixel();
6194 pSalLayout
->Release();
6196 // convert virtual char widths to virtual absolute positions
6198 for( int i
= 1; i
< nLen
; ++i
)
6199 pDXAry
[ i
] += pDXAry
[ i
-1 ];
6201 // convert from font units to logical units
6205 for( int i
= 0; i
< nLen
; ++i
)
6206 pDXAry
[i
] = ImplDevicePixelToLogicWidth( pDXAry
[i
] );
6207 nWidth
= ImplDevicePixelToLogicWidth( nWidth
);
6210 if( nWidthFactor
> 1 )
6213 for( int i
= 0; i
< nLen
; ++i
)
6214 pDXAry
[i
] /= nWidthFactor
;
6215 nWidth
/= nWidthFactor
;
6221 // -----------------------------------------------------------------------
6223 bool OutputDevice::GetCaretPositions( const XubString
& rStr
, sal_Int32
* pCaretXArray
,
6224 xub_StrLen nIndex
, xub_StrLen nLen
,
6225 sal_Int32
* pDXAry
, long nLayoutWidth
,
6226 BOOL bCellBreaking
) const
6228 DBG_TRACE( "OutputDevice::GetCaretPositions()" );
6229 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6231 if( nIndex
>= rStr
.Len() )
6233 if( (ULONG
)nIndex
+nLen
>= rStr
.Len() )
6234 nLen
= rStr
.Len() - nIndex
;
6236 // layout complex text
6237 SalLayout
* pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
,
6238 Point(0,0), nLayoutWidth
, pDXAry
);
6242 int nWidthFactor
= pSalLayout
->GetUnitsPerPixel();
6243 pSalLayout
->GetCaretPositions( 2*nLen
, pCaretXArray
);
6244 long nWidth
= pSalLayout
->GetTextWidth();
6245 pSalLayout
->Release();
6247 // fixup unknown caret positions
6249 for( i
= 0; i
< 2 * nLen
; ++i
)
6250 if( pCaretXArray
[ i
] >= 0 )
6252 long nXPos
= pCaretXArray
[ i
];
6253 for( i
= 0; i
< 2 * nLen
; ++i
)
6255 if( pCaretXArray
[ i
] >= 0 )
6256 nXPos
= pCaretXArray
[ i
];
6258 pCaretXArray
[ i
] = nXPos
;
6261 // handle window mirroring
6262 if( IsRTLEnabled() )
6264 for( i
= 0; i
< 2 * nLen
; ++i
)
6265 pCaretXArray
[i
] = nWidth
- pCaretXArray
[i
] - 1;
6268 // convert from font units to logical units
6271 for( i
= 0; i
< 2*nLen
; ++i
)
6272 pCaretXArray
[i
] = ImplDevicePixelToLogicWidth( pCaretXArray
[i
] );
6275 if( nWidthFactor
!= 1 )
6277 for( i
= 0; i
< 2*nLen
; ++i
)
6278 pCaretXArray
[i
] /= nWidthFactor
;
6281 // if requested move caret position to cell limits
6290 // -----------------------------------------------------------------------
6292 void OutputDevice::DrawStretchText( const Point
& rStartPt
, ULONG nWidth
,
6294 xub_StrLen nIndex
, xub_StrLen nLen
)
6296 DBG_TRACE( "OutputDevice::DrawStretchText()" );
6297 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6300 mpMetaFile
->AddAction( new MetaStretchTextAction( rStartPt
, nWidth
, rStr
, nIndex
, nLen
) );
6302 if ( !IsDeviceOutputNecessary() )
6305 SalLayout
* pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
, rStartPt
, nWidth
, NULL
, true );
6308 ImplDrawText( *pSalLayout
);
6309 pSalLayout
->Release();
6313 mpAlphaVDev
->DrawStretchText( rStartPt
, nWidth
, rStr
, nIndex
, nLen
);
6316 // -----------------------------------------------------------------------
6318 ImplLayoutArgs
OutputDevice::ImplPrepareLayoutArgs( String
& rStr
,
6319 xub_StrLen nMinIndex
, xub_StrLen nLen
,
6320 long nPixelWidth
, const sal_Int32
* pDXArray
) const
6322 // get string length for calculating extents
6323 xub_StrLen nEndIndex
= rStr
.Len();
6324 if( (ULONG
)nMinIndex
+ nLen
< nEndIndex
)
6325 nEndIndex
= nMinIndex
+ nLen
;
6327 // don't bother if there is nothing to do
6328 if( nEndIndex
< nMinIndex
)
6329 nEndIndex
= nMinIndex
;
6331 int nLayoutFlags
= 0;
6332 if( mnTextLayoutMode
& TEXT_LAYOUT_BIDI_RTL
)
6333 nLayoutFlags
|= SAL_LAYOUT_BIDI_RTL
;
6334 if( mnTextLayoutMode
& TEXT_LAYOUT_BIDI_STRONG
)
6335 nLayoutFlags
|= SAL_LAYOUT_BIDI_STRONG
;
6336 else if( 0 == (mnTextLayoutMode
& TEXT_LAYOUT_BIDI_RTL
) )
6338 // disable Bidi if no RTL hint and no RTL codes used
6339 const xub_Unicode
* pStr
= rStr
.GetBuffer() + nMinIndex
;
6340 const xub_Unicode
* pEnd
= rStr
.GetBuffer() + nEndIndex
;
6341 for( ; pStr
< pEnd
; ++pStr
)
6342 if( ((*pStr
>= 0x0580) && (*pStr
< 0x0800)) // middle eastern scripts
6343 || ((*pStr
>= 0xFB18) && (*pStr
< 0xFE00)) // hebrew + arabic A presentation forms
6344 || ((*pStr
>= 0xFE70) && (*pStr
< 0xFEFF)) ) // arabic presentation forms B
6347 nLayoutFlags
|= SAL_LAYOUT_BIDI_STRONG
;
6351 nLayoutFlags
|= SAL_LAYOUT_KERNING_PAIRS
;
6352 if( maFont
.GetKerning() & KERNING_ASIAN
)
6353 nLayoutFlags
|= SAL_LAYOUT_KERNING_ASIAN
;
6354 if( maFont
.IsVertical() )
6355 nLayoutFlags
|= SAL_LAYOUT_VERTICAL
;
6357 if( mnTextLayoutMode
& TEXT_LAYOUT_ENABLE_LIGATURES
)
6358 nLayoutFlags
|= SAL_LAYOUT_ENABLE_LIGATURES
;
6359 else if( mnTextLayoutMode
& TEXT_LAYOUT_COMPLEX_DISABLED
)
6360 nLayoutFlags
|= SAL_LAYOUT_COMPLEX_DISABLED
;
6363 // disable CTL for non-CTL text
6364 const sal_Unicode
* pStr
= rStr
.GetBuffer() + nMinIndex
;
6365 const sal_Unicode
* pEnd
= rStr
.GetBuffer() + nEndIndex
;
6366 for( ; pStr
< pEnd
; ++pStr
)
6367 if( ((*pStr
>= 0x0300) && (*pStr
< 0x0370)) // diacritical marks
6368 || ((*pStr
>= 0x0590) && (*pStr
< 0x10A0)) // many CTL scripts
6369 || ((*pStr
>= 0x1100) && (*pStr
< 0x1200)) // hangul jamo
6370 || ((*pStr
>= 0x1700) && (*pStr
< 0x1900)) // many CTL scripts
6371 || ((*pStr
>= 0xFB1D) && (*pStr
< 0xFE00)) // middle east presentation
6372 || ((*pStr
>= 0xFE70) && (*pStr
< 0xFEFF)) ) // arabic presentation B
6375 nLayoutFlags
|= SAL_LAYOUT_COMPLEX_DISABLED
;
6378 if( meTextLanguage
) //TODO: (mnTextLayoutMode & TEXT_LAYOUT_SUBSTITUTE_DIGITS)
6380 // disable character localization when no digits used
6381 const sal_Unicode
* pBase
= rStr
.GetBuffer();
6382 const sal_Unicode
* pStr
= pBase
+ nMinIndex
;
6383 const sal_Unicode
* pEnd
= pBase
+ nEndIndex
;
6384 for( ; pStr
< pEnd
; ++pStr
)
6386 // TODO: are there non-digit localizations?
6387 if( (*pStr
>= '0') && (*pStr
<= '9') )
6389 // translate characters to local preference
6390 sal_UCS4 cChar
= GetLocalizedChar( *pStr
, meTextLanguage
);
6391 if( cChar
!= *pStr
)
6392 // TODO: are the localized digit surrogates?
6393 rStr
.SetChar( static_cast<USHORT
>(pStr
- pBase
),
6394 static_cast<sal_Unicode
>(cChar
) );
6399 // right align for RTL text, DRAWPOS_REVERSED, RTL window style
6400 bool bRightAlign
= ((mnTextLayoutMode
& TEXT_LAYOUT_BIDI_RTL
) != 0);
6401 if( mnTextLayoutMode
& TEXT_LAYOUT_TEXTORIGIN_LEFT
)
6402 bRightAlign
= false;
6403 else if ( mnTextLayoutMode
& TEXT_LAYOUT_TEXTORIGIN_RIGHT
)
6405 // SSA: hack for western office, ie text get right aligned
6406 // for debugging purposes of mirrored UI
6407 //static const char* pEnv = getenv( "SAL_RTL_MIRRORTEXT" );
6408 bool bRTLWindow
= IsRTLEnabled();
6409 bRightAlign
^= bRTLWindow
;
6411 nLayoutFlags
|= SAL_LAYOUT_RIGHT_ALIGN
;
6413 // set layout options
6414 ImplLayoutArgs
aLayoutArgs( rStr
.GetBuffer(), rStr
.Len(), nMinIndex
, nEndIndex
, nLayoutFlags
);
6416 int nOrientation
= mpFontEntry
? mpFontEntry
->mnOrientation
: 0;
6417 aLayoutArgs
.SetOrientation( nOrientation
);
6419 aLayoutArgs
.SetLayoutWidth( nPixelWidth
);
6420 aLayoutArgs
.SetDXArray( pDXArray
);
6425 // -----------------------------------------------------------------------
6427 SalLayout
* OutputDevice::ImplLayout( const String
& rOrigStr
,
6428 xub_StrLen nMinIndex
,
6430 const Point
& rLogicalPos
,
6432 const sal_Int32
* pDXArray
,
6433 bool bFilter
) const
6435 // we need a graphics
6437 if( !ImplGetGraphics() )
6440 // initialize font if needed
6442 if( !ImplNewFont() )
6447 // check string index and length
6448 String aStr
= rOrigStr
;
6449 if( (ULONG
)nMinIndex
+ nLen
>= aStr
.Len() )
6451 if( nMinIndex
< aStr
.Len() )
6452 nLen
= aStr
.Len() - nMinIndex
;
6457 // filter out special markers
6460 xub_StrLen nCutStart
, nCutStop
, nOrgLen
= nLen
;
6461 bool bFiltered
= mpGraphics
->filterText( rOrigStr
, aStr
, nMinIndex
, nLen
, nCutStart
, nCutStop
);
6465 if( bFiltered
&& nCutStop
!= nCutStart
&& pDXArray
)
6471 sal_Int32
* pAry
= (sal_Int32
*)alloca(sizeof(sal_Int32
)*nLen
);
6472 if( nCutStart
> nMinIndex
)
6473 memcpy( pAry
, pDXArray
, sizeof(sal_Int32
)*(nCutStart
-nMinIndex
) );
6474 // note: nCutStart will never be smaller than nMinIndex
6475 memcpy( pAry
+nCutStart
-nMinIndex
,
6476 pDXArray
+ nOrgLen
- (nCutStop
-nMinIndex
),
6477 sizeof(sal_Int32
)*(nLen
- (nCutStart
-nMinIndex
)) );
6483 // convert from logical units to physical units
6484 // recode string if needed
6485 if( mpFontEntry
->mpConversion
)
6486 ImplRecodeString( mpFontEntry
->mpConversion
, aStr
, 0, aStr
.Len() );
6488 long nPixelWidth
= nLogicalWidth
;
6489 if( nLogicalWidth
&& mbMap
)
6490 nPixelWidth
= ImplLogicWidthToDevicePixel( nLogicalWidth
);
6491 if( pDXArray
&& mbMap
)
6493 // convert from logical units to font units using a temporary array
6494 sal_Int32
* pTempDXAry
= (sal_Int32
*)alloca( nLen
* sizeof(sal_Int32
) );
6495 // using base position for better rounding a.k.a. "dancing characters"
6496 int nPixelXOfs
= ImplLogicWidthToDevicePixel( rLogicalPos
.X() );
6497 for( int i
= 0; i
< nLen
; ++i
)
6498 pTempDXAry
[i
] = ImplLogicWidthToDevicePixel( rLogicalPos
.X() + pDXArray
[i
] ) - nPixelXOfs
;
6500 pDXArray
= pTempDXAry
;
6503 ImplLayoutArgs aLayoutArgs
= ImplPrepareLayoutArgs( aStr
, nMinIndex
, nLen
, nPixelWidth
, pDXArray
);
6505 // get matching layout object for base font
6506 SalLayout
* pSalLayout
= NULL
;
6508 pSalLayout
= mpPDFWriter
->GetTextLayout( aLayoutArgs
, &mpFontEntry
->maFontSelData
);
6511 pSalLayout
= mpGraphics
->GetTextLayout( aLayoutArgs
, 0 );
6514 if( pSalLayout
&& !pSalLayout
->LayoutText( aLayoutArgs
) )
6516 pSalLayout
->Release();
6523 // do glyph fallback if needed
6524 // #105768# avoid fallback for very small font sizes
6525 if( aLayoutArgs
.NeedFallback() )
6526 if( mpFontEntry
&& (mpFontEntry
->maFontSelData
.mnHeight
>= 3) )
6527 pSalLayout
= ImplGlyphFallbackLayout( pSalLayout
, aLayoutArgs
);
6529 // position, justify, etc. the layout
6530 pSalLayout
->AdjustLayout( aLayoutArgs
);
6531 pSalLayout
->DrawBase() = ImplLogicToDevicePixel( rLogicalPos
);
6532 // adjust to right alignment if necessary
6533 if( aLayoutArgs
.mnFlags
& SAL_LAYOUT_RIGHT_ALIGN
)
6537 nRTLOffset
= pDXArray
[ nLen
- 1 ];
6538 else if( nPixelWidth
)
6539 nRTLOffset
= nPixelWidth
;
6541 nRTLOffset
= pSalLayout
->GetTextWidth() / pSalLayout
->GetUnitsPerPixel();
6542 pSalLayout
->DrawOffset().X() = 1 - nRTLOffset
;
6548 // -----------------------------------------------------------------------
6550 SalLayout
* OutputDevice::ImplGlyphFallbackLayout( SalLayout
* pSalLayout
, ImplLayoutArgs
& rLayoutArgs
) const
6552 // prepare multi level glyph fallback
6553 MultiSalLayout
* pMultiSalLayout
= NULL
;
6554 ImplLayoutRuns aLayoutRuns
= rLayoutArgs
.maRuns
;
6555 rLayoutArgs
.PrepareFallback();
6556 rLayoutArgs
.mnFlags
|= SAL_LAYOUT_FOR_FALLBACK
;
6558 #if defined(HDU_DEBUG)
6562 fprintf(stderr
,"OD:ImplLayout Glyph Fallback for");
6563 for( int i
=0; i
<8 && rLayoutArgs
.GetNextPos( &nCharPos
, &bRTL
); ++i
)
6564 fprintf(stderr
," U+%04X", rLayoutArgs
.mpStr
[ nCharPos
] );
6565 fprintf(stderr
,"\n");
6566 rLayoutArgs
.ResetPos();
6569 // get list of unicodes that need glyph fallback
6572 rtl::OUStringBuffer aMissingCodeBuf
;
6573 while( rLayoutArgs
.GetNextPos( &nCharPos
, &bRTL
) )
6574 aMissingCodeBuf
.append( rLayoutArgs
.mpStr
[ nCharPos
] );
6575 rLayoutArgs
.ResetPos();
6576 rtl::OUString aMissingCodes
= aMissingCodeBuf
.makeStringAndClear();
6578 ImplFontSelectData aFontSelData
= mpFontEntry
->maFontSelData
;
6579 // when device specific font substitution may have been performed for
6580 // the originally selected font then make sure that a fallback to that
6581 // font is performed first
6582 int nDevSpecificFallback
= 0;
6583 if( mpOutDevData
&& !mpOutDevData
->maDevFontSubst
.Empty() )
6584 nDevSpecificFallback
= 1;
6586 // try if fallback fonts support the missing unicodes
6587 for( int nFallbackLevel
= 1; nFallbackLevel
< MAX_FALLBACK
; ++nFallbackLevel
)
6589 // find a font family suited for glyph fallback
6590 #ifndef FONTFALLBACK_HOOKS_DISABLED
6591 // GetGlyphFallbackFont() needs a valid aFontSelData.mpFontEntry
6592 // if the system-specific glyph fallback is active
6593 aFontSelData
.mpFontEntry
= mpFontEntry
; // reset the fontentry to base-level
6595 ImplFontEntry
* pFallbackFont
= mpFontCache
->GetGlyphFallbackFont( mpFontList
,
6596 aFontSelData
, nFallbackLevel
-nDevSpecificFallback
, aMissingCodes
);
6597 if( !pFallbackFont
)
6600 aFontSelData
.mpFontEntry
= pFallbackFont
;
6601 aFontSelData
.mpFontData
= pFallbackFont
->maFontSelData
.mpFontData
;
6602 if( mpFontEntry
&& nFallbackLevel
< MAX_FALLBACK
-1)
6604 // ignore fallback font if it is the same as the original font
6605 if( mpFontEntry
->maFontSelData
.mpFontData
== aFontSelData
.mpFontData
)
6607 mpFontCache
->Release( pFallbackFont
);
6612 #if defined(HDU_DEBUG)
6614 ByteString
aOrigFontName( maFont
.GetName(), RTL_TEXTENCODING_UTF8
);
6615 ByteString
aFallbackName( aFontSelData
.mpFontData
->GetFamilyName(),
6616 RTL_TEXTENCODING_UTF8
);
6617 fprintf(stderr
,"\tGlyphFallback[lvl=%d] \"%s\" -> \"%s\" (q=%d)\n",
6618 nFallbackLevel
, aOrigFontName
.GetBuffer(), aFallbackName
.GetBuffer(),
6619 aFontSelData
.mpFontData
->GetQuality());
6623 pFallbackFont
->mnSetFontFlags
= mpGraphics
->SetFont( &aFontSelData
, nFallbackLevel
);
6625 // create and add glyph fallback layout to multilayout
6626 rLayoutArgs
.ResetPos();
6627 SalLayout
* pFallback
= mpGraphics
->GetTextLayout( rLayoutArgs
, nFallbackLevel
);
6630 if( pFallback
->LayoutText( rLayoutArgs
) )
6632 if( !pMultiSalLayout
)
6633 pMultiSalLayout
= new MultiSalLayout( *pSalLayout
);
6634 pMultiSalLayout
->AddFallback( *pFallback
,
6635 rLayoutArgs
.maRuns
, aFontSelData
.mpFontData
);
6636 if (nFallbackLevel
== MAX_FALLBACK
-1)
6637 pMultiSalLayout
->SetInComplete();
6641 // there is no need for a font that couldn't resolve anything
6642 pFallback
->Release();
6646 mpFontCache
->Release( pFallbackFont
);
6648 // break when this fallback was sufficient
6649 if( !rLayoutArgs
.PrepareFallback() )
6653 if( pMultiSalLayout
&& pMultiSalLayout
->LayoutText( rLayoutArgs
) )
6654 pSalLayout
= pMultiSalLayout
;
6656 // restore orig font settings
6657 pSalLayout
->InitFont();
6658 rLayoutArgs
.maRuns
= aLayoutRuns
;
6663 // -----------------------------------------------------------------------
6665 BOOL
OutputDevice::GetTextIsRTL(
6666 const String
& rString
,
6667 xub_StrLen nIndex
, xub_StrLen nLen
) const
6669 String
aStr( rString
);
6670 ImplLayoutArgs aArgs
= ImplPrepareLayoutArgs( aStr
, nIndex
, nLen
, 0, NULL
);
6673 aArgs
.GetNextPos( &nCharPos
, &bRTL
);
6674 return (nCharPos
!= nIndex
) ? TRUE
: FALSE
;
6677 // -----------------------------------------------------------------------
6679 xub_StrLen
OutputDevice::GetTextBreak( const String
& rStr
, long nTextWidth
,
6680 xub_StrLen nIndex
, xub_StrLen nLen
,
6681 long nCharExtra
, BOOL
/*TODO: bCellBreaking*/ ) const
6683 DBG_TRACE( "OutputDevice::GetTextBreak()" );
6684 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6686 SalLayout
* pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
);
6687 xub_StrLen nRetVal
= STRING_LEN
;
6690 // convert logical widths into layout units
6691 // NOTE: be very careful to avoid rounding errors for nCharExtra case
6692 // problem with rounding errors especially for small nCharExtras
6693 // TODO: remove when layout units have subpixel granularity
6694 long nWidthFactor
= pSalLayout
->GetUnitsPerPixel();
6695 long nSubPixelFactor
= (nWidthFactor
< 64 ) ? 64 : 1;
6696 nTextWidth
*= nWidthFactor
* nSubPixelFactor
;
6697 long nTextPixelWidth
= ImplLogicWidthToDevicePixel( nTextWidth
);
6698 long nExtraPixelWidth
= 0;
6699 if( nCharExtra
!= 0 )
6701 nCharExtra
*= nWidthFactor
* nSubPixelFactor
;
6702 nExtraPixelWidth
= ImplLogicWidthToDevicePixel( nCharExtra
);
6704 nRetVal
= sal::static_int_cast
<xub_StrLen
>(pSalLayout
->GetTextBreak( nTextPixelWidth
, nExtraPixelWidth
, nSubPixelFactor
));
6706 pSalLayout
->Release();
6712 // -----------------------------------------------------------------------
6714 xub_StrLen
OutputDevice::GetTextBreak( const String
& rStr
, long nTextWidth
,
6715 sal_Unicode nHyphenatorChar
, xub_StrLen
& rHyphenatorPos
,
6716 xub_StrLen nIndex
, xub_StrLen nLen
,
6717 long nCharExtra
) const
6719 DBG_TRACE( "OutputDevice::GetTextBreak()" );
6720 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
6722 rHyphenatorPos
= STRING_LEN
;
6724 SalLayout
* pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
);
6728 // convert logical widths into layout units
6729 // NOTE: be very careful to avoid rounding errors for nCharExtra case
6730 // problem with rounding errors especially for small nCharExtras
6731 // TODO: remove when layout units have subpixel granularity
6732 long nWidthFactor
= pSalLayout
->GetUnitsPerPixel();
6733 long nSubPixelFactor
= (nWidthFactor
< 64 ) ? 64 : 1;
6735 nTextWidth
*= nWidthFactor
* nSubPixelFactor
;
6736 long nTextPixelWidth
= ImplLogicWidthToDevicePixel( nTextWidth
);
6737 long nExtraPixelWidth
= 0;
6738 if( nCharExtra
!= 0 )
6740 nCharExtra
*= nWidthFactor
* nSubPixelFactor
;
6741 nExtraPixelWidth
= ImplLogicWidthToDevicePixel( nCharExtra
);
6744 // calculate un-hyphenated break position
6745 xub_StrLen nRetVal
= sal::static_int_cast
<xub_StrLen
>(pSalLayout
->GetTextBreak( nTextPixelWidth
, nExtraPixelWidth
, nSubPixelFactor
));
6747 // calculate hyphenated break position
6748 String
aHyphenatorStr( &nHyphenatorChar
, 1 );
6749 xub_StrLen nTempLen
= 1;
6750 SalLayout
* pHyphenatorLayout
= ImplLayout( aHyphenatorStr
, 0, nTempLen
);
6751 if( pHyphenatorLayout
)
6753 // calculate subpixel width of hyphenation character
6754 long nHyphenatorPixelWidth
= pHyphenatorLayout
->GetTextWidth() * nSubPixelFactor
;
6755 pHyphenatorLayout
->Release();
6757 // calculate hyphenated break position
6758 nTextPixelWidth
-= nHyphenatorPixelWidth
;
6759 if( nExtraPixelWidth
> 0 )
6760 nTextPixelWidth
-= nExtraPixelWidth
;
6762 rHyphenatorPos
= sal::static_int_cast
<xub_StrLen
>(pSalLayout
->GetTextBreak( nTextPixelWidth
, nExtraPixelWidth
, nSubPixelFactor
));
6764 if( rHyphenatorPos
> nRetVal
)
6765 rHyphenatorPos
= nRetVal
;
6768 pSalLayout
->Release();
6772 // -----------------------------------------------------------------------
6774 void OutputDevice::ImplDrawText( const Rectangle
& rRect
,
6775 const String
& rOrigStr
, USHORT nStyle
,
6776 MetricVector
* pVector
, String
* pDisplayText
)
6778 Color aOldTextColor
;
6779 Color aOldTextFillColor
;
6780 BOOL bRestoreFillColor
= false;
6781 if ( (nStyle
& TEXT_DRAW_DISABLE
) && ! pVector
)
6783 BOOL bHighContrastBlack
= FALSE
;
6784 BOOL bHighContrastWhite
= FALSE
;
6785 const StyleSettings
& rStyleSettings( GetSettings().GetStyleSettings() );
6786 if( rStyleSettings
.GetHighContrastMode() )
6789 if( IsBackground() )
6790 aCol
= GetBackground().GetColor();
6792 // best guess is the face color here
6793 // but it may be totally wrong. the background color
6794 // was typically already reset
6795 aCol
= rStyleSettings
.GetFaceColor();
6797 bHighContrastBlack
= aCol
.IsDark();
6798 bHighContrastWhite
= aCol
.IsBright();
6801 aOldTextColor
= GetTextColor();
6802 if ( IsTextFillColor() )
6804 bRestoreFillColor
= TRUE
;
6805 aOldTextFillColor
= GetTextFillColor();
6807 if( bHighContrastBlack
)
6808 SetTextColor( COL_GREEN
);
6809 else if( bHighContrastWhite
)
6810 SetTextColor( COL_LIGHTGREEN
);
6813 // draw disabled text always without shadow
6814 // as it fits better with native look
6816 SetTextColor( GetSettings().GetStyleSettings().GetLightColor() );
6817 Rectangle aRect = rRect;
6819 DrawText( aRect, rOrigStr, nStyle & ~TEXT_DRAW_DISABLE );
6821 SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
6825 long nWidth
= rRect
.GetWidth();
6826 long nHeight
= rRect
.GetHeight();
6828 if ( ((nWidth
<= 0) || (nHeight
<= 0)) && (nStyle
& TEXT_DRAW_CLIP
) )
6831 Point aPos
= rRect
.TopLeft();
6833 long nTextHeight
= GetTextHeight();
6834 TextAlign eAlign
= GetTextAlign();
6835 xub_StrLen nMnemonicPos
= STRING_NOTFOUND
;
6837 String aStr
= rOrigStr
;
6838 if ( nStyle
& TEXT_DRAW_MNEMONIC
)
6839 aStr
= GetNonMnemonicString( aStr
, nMnemonicPos
);
6841 // Mehrzeiligen Text behandeln wir anders
6842 if ( nStyle
& TEXT_DRAW_MULTILINE
)
6845 XubString aLastLine
;
6846 ImplMultiTextLineInfo aMultiLineInfo
;
6847 ImplTextLineInfo
* pLineInfo
;
6851 xub_StrLen nFormatLines
;
6855 nMaxTextWidth
= ImplGetTextLines( aMultiLineInfo
, nWidth
, aStr
, nStyle
);
6856 nLines
= (xub_StrLen
)(nHeight
/nTextHeight
);
6857 nFormatLines
= aMultiLineInfo
.Count();
6860 if ( nFormatLines
> nLines
)
6862 if ( nStyle
& TEXT_DRAW_ENDELLIPSIS
)
6864 // Letzte Zeile zusammenbauen und kuerzen
6865 nFormatLines
= nLines
-1;
6867 pLineInfo
= aMultiLineInfo
.GetLine( nFormatLines
);
6868 aLastLine
= aStr
.Copy( pLineInfo
->GetIndex() );
6869 aLastLine
.ConvertLineEnd( LINEEND_LF
);
6870 // Alle LineFeed's durch Spaces ersetzen
6871 xub_StrLen nLastLineLen
= aLastLine
.Len();
6872 for ( i
= 0; i
< nLastLineLen
; i
++ )
6874 if ( aLastLine
.GetChar( i
) == _LF
)
6875 aLastLine
.SetChar( i
, ' ' );
6877 aLastLine
= GetEllipsisString( aLastLine
, nWidth
, nStyle
);
6878 nStyle
&= ~(TEXT_DRAW_VCENTER
| TEXT_DRAW_BOTTOM
);
6879 nStyle
|= TEXT_DRAW_TOP
;
6884 if ( nMaxTextWidth
<= nWidth
)
6885 nStyle
&= ~TEXT_DRAW_CLIP
;
6888 // Muss in der Hoehe geclippt werden?
6889 if ( nFormatLines
*nTextHeight
> nHeight
)
6890 nStyle
|= TEXT_DRAW_CLIP
;
6893 if ( nStyle
& TEXT_DRAW_CLIP
)
6895 Push( PUSH_CLIPREGION
);
6896 IntersectClipRegion( rRect
);
6899 // Vertikales Alignment
6900 if ( nStyle
& TEXT_DRAW_BOTTOM
)
6901 aPos
.Y() += nHeight
-(nFormatLines
*nTextHeight
);
6902 else if ( nStyle
& TEXT_DRAW_VCENTER
)
6903 aPos
.Y() += (nHeight
-(nFormatLines
*nTextHeight
))/2;
6906 if ( eAlign
== ALIGN_BOTTOM
)
6907 aPos
.Y() += nTextHeight
;
6908 else if ( eAlign
== ALIGN_BASELINE
)
6909 aPos
.Y() += GetFontMetric().GetAscent();
6911 // Alle Zeilen ausgeben, bis auf die letzte
6912 for ( i
= 0; i
< nFormatLines
; i
++ )
6914 pLineInfo
= aMultiLineInfo
.GetLine( i
);
6915 if ( nStyle
& TEXT_DRAW_RIGHT
)
6916 aPos
.X() += nWidth
-pLineInfo
->GetWidth();
6917 else if ( nStyle
& TEXT_DRAW_CENTER
)
6918 aPos
.X() += (nWidth
-pLineInfo
->GetWidth())/2;
6919 xub_StrLen nIndex
= pLineInfo
->GetIndex();
6920 xub_StrLen nLineLen
= pLineInfo
->GetLen();
6921 DrawText( aPos
, aStr
, nIndex
, nLineLen
, pVector
, pDisplayText
);
6922 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS
) && !pVector
)
6924 if ( (nMnemonicPos
>= nIndex
) && (nMnemonicPos
< nIndex
+nLineLen
) )
6928 long nMnemonicWidth
;
6930 sal_Int32
* pCaretXArray
= (sal_Int32
*) alloca( 2 * sizeof(sal_Int32
) * nLineLen
);
6931 /*BOOL bRet =*/ GetCaretPositions( aStr
, pCaretXArray
,
6933 long lc_x1
= pCaretXArray
[2*(nMnemonicPos
- nIndex
)];
6934 long lc_x2
= pCaretXArray
[2*(nMnemonicPos
- nIndex
)+1];
6935 nMnemonicWidth
= ::abs((int)(lc_x1
- lc_x2
));
6937 Point aTempPos
= LogicToPixel( aPos
);
6938 nMnemonicX
= mnOutOffX
+ aTempPos
.X() + ImplLogicWidthToDevicePixel( Min( lc_x1
, lc_x2
) );
6939 nMnemonicY
= mnOutOffY
+ aTempPos
.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() );
6940 ImplDrawMnemonicLine( nMnemonicX
, nMnemonicY
, nMnemonicWidth
);
6943 aPos
.Y() += nTextHeight
;
6944 aPos
.X() = rRect
.Left();
6948 // Gibt es noch eine letzte Zeile, dann diese linksbuendig ausgeben,
6949 // da die Zeile gekuerzt wurde
6950 if ( aLastLine
.Len() )
6951 DrawText( aPos
, aLastLine
, 0, STRING_LEN
, pVector
, pDisplayText
);
6953 // Clipping zuruecksetzen
6954 if ( nStyle
& TEXT_DRAW_CLIP
)
6960 long nTextWidth
= GetTextWidth( aStr
);
6962 // Evt. Text kuerzen
6963 if ( nTextWidth
> nWidth
)
6965 if ( nStyle
& TEXT_DRAW_ELLIPSIS
)
6967 aStr
= GetEllipsisString( aStr
, nWidth
, nStyle
);
6968 nStyle
&= ~(TEXT_DRAW_CENTER
| TEXT_DRAW_RIGHT
);
6969 nStyle
|= TEXT_DRAW_LEFT
;
6970 nTextWidth
= GetTextWidth( aStr
);
6975 if ( nTextHeight
<= nHeight
)
6976 nStyle
&= ~TEXT_DRAW_CLIP
;
6979 // horizontal text alignment
6980 if ( nStyle
& TEXT_DRAW_RIGHT
)
6981 aPos
.X() += nWidth
-nTextWidth
;
6982 else if ( nStyle
& TEXT_DRAW_CENTER
)
6983 aPos
.X() += (nWidth
-nTextWidth
)/2;
6985 // vertical font alignment
6986 if ( eAlign
== ALIGN_BOTTOM
)
6987 aPos
.Y() += nTextHeight
;
6988 else if ( eAlign
== ALIGN_BASELINE
)
6989 aPos
.Y() += GetFontMetric().GetAscent();
6991 if ( nStyle
& TEXT_DRAW_BOTTOM
)
6992 aPos
.Y() += nHeight
-nTextHeight
;
6993 else if ( nStyle
& TEXT_DRAW_VCENTER
)
6994 aPos
.Y() += (nHeight
-nTextHeight
)/2;
6996 long nMnemonicX
= 0;
6997 long nMnemonicY
= 0;
6998 long nMnemonicWidth
= 0;
6999 if ( nMnemonicPos
!= STRING_NOTFOUND
)
7001 sal_Int32
* pCaretXArray
= (sal_Int32
*) alloca( 2 * sizeof(sal_Int32
) * aStr
.Len() );
7002 /*BOOL bRet =*/ GetCaretPositions( aStr
, pCaretXArray
, 0, aStr
.Len() );
7003 long lc_x1
= pCaretXArray
[2*(nMnemonicPos
)];
7004 long lc_x2
= pCaretXArray
[2*(nMnemonicPos
)+1];
7005 nMnemonicWidth
= ::abs((int)(lc_x1
- lc_x2
));
7007 Point aTempPos
= LogicToPixel( aPos
);
7008 nMnemonicX
= mnOutOffX
+ aTempPos
.X() + ImplLogicWidthToDevicePixel( Min(lc_x1
, lc_x2
) );
7009 nMnemonicY
= mnOutOffY
+ aTempPos
.Y() + ImplLogicWidthToDevicePixel( GetFontMetric().GetAscent() );
7012 if ( nStyle
& TEXT_DRAW_CLIP
)
7014 Push( PUSH_CLIPREGION
);
7015 IntersectClipRegion( rRect
);
7016 DrawText( aPos
, aStr
, 0, STRING_LEN
, pVector
, pDisplayText
);
7017 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS
) && !pVector
)
7019 if ( nMnemonicPos
!= STRING_NOTFOUND
)
7020 ImplDrawMnemonicLine( nMnemonicX
, nMnemonicY
, nMnemonicWidth
);
7026 DrawText( aPos
, aStr
, 0, STRING_LEN
, pVector
, pDisplayText
);
7027 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS
) && !pVector
)
7029 if ( nMnemonicPos
!= STRING_NOTFOUND
)
7030 ImplDrawMnemonicLine( nMnemonicX
, nMnemonicY
, nMnemonicWidth
);
7035 if ( nStyle
& TEXT_DRAW_DISABLE
&& !pVector
)
7037 SetTextColor( aOldTextColor
);
7038 if ( bRestoreFillColor
)
7039 SetTextFillColor( aOldTextFillColor
);
7043 // -----------------------------------------------------------------------
7045 void OutputDevice::AddTextRectActions( const Rectangle
& rRect
,
7046 const String
& rOrigStr
,
7050 DBG_TRACE( "OutputDevice::AddTextRectActions( const Rectangle& )" );
7051 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7053 if ( !rOrigStr
.Len() || rRect
.IsEmpty() )
7056 // we need a graphics
7057 if( !mpGraphics
&& !ImplGetGraphics() )
7059 if( mbInitClipRegion
)
7060 ImplInitClipRegion();
7062 // temporarily swap in passed mtf for action generation, and
7063 // disable output generation.
7064 const BOOL
bOutputEnabled( IsOutputEnabled() );
7065 GDIMetaFile
* pMtf
= mpMetaFile
;
7068 EnableOutput( FALSE
);
7070 // #i47157# Factored out to ImplDrawTextRect(), to be shared
7071 // between us and DrawText()
7072 ImplDrawText( rRect
, rOrigStr
, nStyle
, NULL
, NULL
);
7074 // and restore again
7075 EnableOutput( bOutputEnabled
);
7079 // -----------------------------------------------------------------------
7081 void OutputDevice::DrawText( const Rectangle
& rRect
,
7082 const String
& rOrigStr
, USHORT nStyle
,
7083 MetricVector
* pVector
, String
* pDisplayText
)
7086 if( mpOutDevData
&& mpOutDevData
->mpRecordLayout
)
7088 pVector
= &mpOutDevData
->mpRecordLayout
->m_aUnicodeBoundRects
;
7089 pDisplayText
= &mpOutDevData
->mpRecordLayout
->m_aDisplayText
;
7092 DBG_TRACE( "OutputDevice::DrawText( const Rectangle& )" );
7093 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7096 mpMetaFile
->AddAction( new MetaTextRectAction( rRect
, rOrigStr
, nStyle
) );
7098 if ( ( !IsDeviceOutputNecessary() && ! pVector
) || !rOrigStr
.Len() || rRect
.IsEmpty() )
7101 // we need a graphics
7102 if( !mpGraphics
&& !ImplGetGraphics() )
7104 if( mbInitClipRegion
)
7105 ImplInitClipRegion();
7106 if( mbOutputClipped
)
7109 // temporarily disable mtf action generation (ImplDrawText _does_
7110 // create META_TEXT_ACTIONs otherwise)
7111 GDIMetaFile
* pMtf
= mpMetaFile
;
7114 // #i47157# Factored out to ImplDrawTextRect(), to be used also
7115 // from AddTextRectActions()
7116 ImplDrawText( rRect
, rOrigStr
, nStyle
, pVector
, pDisplayText
);
7122 mpAlphaVDev
->DrawText( rRect
, rOrigStr
, nStyle
, pVector
, pDisplayText
);
7125 // -----------------------------------------------------------------------
7127 Rectangle
OutputDevice::GetTextRect( const Rectangle
& rRect
,
7128 const String
& rOrigStr
, USHORT nStyle
,
7129 TextRectInfo
* pInfo
) const
7131 DBG_TRACE( "OutputDevice::GetTextRect()" );
7132 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7134 Rectangle aRect
= rRect
;
7136 long nWidth
= rRect
.GetWidth();
7138 long nTextHeight
= GetTextHeight();
7140 String aStr
= rOrigStr
;
7141 if ( nStyle
& TEXT_DRAW_MNEMONIC
)
7142 aStr
= GetNonMnemonicString( aStr
);
7144 if ( nStyle
& TEXT_DRAW_MULTILINE
)
7146 ImplMultiTextLineInfo aMultiLineInfo
;
7147 ImplTextLineInfo
* pLineInfo
;
7148 xub_StrLen nFormatLines
;
7152 ImplGetTextLines( aMultiLineInfo
, nWidth
, aStr
, nStyle
);
7153 nFormatLines
= aMultiLineInfo
.Count();
7156 nLines
= (USHORT
)(aRect
.GetHeight()/nTextHeight
);
7158 pInfo
->mnLineCount
= nFormatLines
;
7161 if ( nFormatLines
<= nLines
)
7162 nLines
= nFormatLines
;
7165 if ( !(nStyle
& TEXT_DRAW_ENDELLIPSIS
) )
7166 nLines
= nFormatLines
;
7170 pInfo
->mbEllipsis
= TRUE
;
7176 BOOL bMaxWidth
= nMaxWidth
== 0;
7177 pInfo
->mnMaxWidth
= 0;
7178 for ( i
= 0; i
< nLines
; i
++ )
7180 pLineInfo
= aMultiLineInfo
.GetLine( i
);
7181 if ( bMaxWidth
&& (pLineInfo
->GetWidth() > nMaxWidth
) )
7182 nMaxWidth
= pLineInfo
->GetWidth();
7183 if ( pLineInfo
->GetWidth() > pInfo
->mnMaxWidth
)
7184 pInfo
->mnMaxWidth
= pLineInfo
->GetWidth();
7187 else if ( !nMaxWidth
)
7189 for ( i
= 0; i
< nLines
; i
++ )
7191 pLineInfo
= aMultiLineInfo
.GetLine( i
);
7192 if ( pLineInfo
->GetWidth() > nMaxWidth
)
7193 nMaxWidth
= pLineInfo
->GetWidth();
7200 nMaxWidth
= GetTextWidth( aStr
);
7204 pInfo
->mnLineCount
= 1;
7205 pInfo
->mnMaxWidth
= nMaxWidth
;
7208 if ( (nMaxWidth
> nWidth
) && (nStyle
& TEXT_DRAW_ELLIPSIS
) )
7211 pInfo
->mbEllipsis
= TRUE
;
7216 if ( nStyle
& TEXT_DRAW_RIGHT
)
7217 aRect
.Left() = aRect
.Right()-nMaxWidth
+1;
7218 else if ( nStyle
& TEXT_DRAW_CENTER
)
7220 aRect
.Left() += (nWidth
-nMaxWidth
)/2;
7221 aRect
.Right() = aRect
.Left()+nMaxWidth
-1;
7224 aRect
.Right() = aRect
.Left()+nMaxWidth
-1;
7226 if ( nStyle
& TEXT_DRAW_BOTTOM
)
7227 aRect
.Top() = aRect
.Bottom()-(nTextHeight
*nLines
)+1;
7228 else if ( nStyle
& TEXT_DRAW_VCENTER
)
7230 aRect
.Top() += (aRect
.GetHeight()-(nTextHeight
*nLines
))/2;
7231 aRect
.Bottom() = aRect
.Top()+(nTextHeight
*nLines
)-1;
7234 aRect
.Bottom() = aRect
.Top()+(nTextHeight
*nLines
)-1;
7236 aRect
.Right()++; // #99188# get rid of rounding problems when using this rect later
7240 // -----------------------------------------------------------------------
7242 static BOOL
ImplIsCharIn( xub_Unicode c
, const sal_Char
* pStr
)
7254 // -----------------------------------------------------------------------
7256 String
OutputDevice::GetEllipsisString( const String
& rOrigStr
, long nMaxWidth
,
7257 USHORT nStyle
) const
7259 DBG_TRACE( "OutputDevice::GetEllipsisString()" );
7260 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7262 String aStr
= rOrigStr
;
7263 xub_StrLen nIndex
= GetTextBreak( aStr
, nMaxWidth
);
7266 if ( nIndex
!= STRING_LEN
)
7268 if ( nStyle
& TEXT_DRAW_ENDELLIPSIS
)
7270 aStr
.Erase( nIndex
);
7273 aStr
.AppendAscii( "..." );
7274 while ( aStr
.Len() && (GetTextWidth( aStr
) > nMaxWidth
) )
7276 if ( (nIndex
> 1) || (nIndex
== aStr
.Len()) )
7278 aStr
.Erase( nIndex
, 1 );
7282 if ( !aStr
.Len() && (nStyle
& TEXT_DRAW_CLIP
) )
7283 aStr
+= rOrigStr
.GetChar( 0 );
7285 else if ( nStyle
& TEXT_DRAW_PATHELLIPSIS
)
7287 rtl::OUString
aPath( rOrigStr
);
7288 rtl::OUString aAbbreviatedPath
;
7289 osl_abbreviateSystemPath( aPath
.pData
, &aAbbreviatedPath
.pData
, nIndex
, NULL
);
7290 aStr
= aAbbreviatedPath
;
7292 else if ( nStyle
& TEXT_DRAW_NEWSELLIPSIS
)
7294 static sal_Char
const pSepChars
[] = ".";
7295 // Letztes Teilstueck ermitteln
7296 xub_StrLen nLastContent
= aStr
.Len();
7297 while ( nLastContent
)
7300 if ( ImplIsCharIn( aStr
.GetChar( nLastContent
), pSepChars
) )
7303 while ( nLastContent
&&
7304 ImplIsCharIn( aStr
.GetChar( nLastContent
-1 ), pSepChars
) )
7307 XubString
aLastStr( aStr
, nLastContent
, aStr
.Len() );
7308 XubString
aTempLastStr1( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
7309 aTempLastStr1
+= aLastStr
;
7310 if ( GetTextWidth( aTempLastStr1
) > nMaxWidth
)
7311 aStr
= GetEllipsisString( aStr
, nMaxWidth
, nStyle
| TEXT_DRAW_ENDELLIPSIS
);
7314 USHORT nFirstContent
= 0;
7315 while ( nFirstContent
< nLastContent
)
7318 if ( ImplIsCharIn( aStr
.GetChar( nFirstContent
), pSepChars
) )
7321 while ( (nFirstContent
< nLastContent
) &&
7322 ImplIsCharIn( aStr
.GetChar( nFirstContent
), pSepChars
) )
7325 if ( nFirstContent
>= nLastContent
)
7326 aStr
= GetEllipsisString( aStr
, nMaxWidth
, nStyle
| TEXT_DRAW_ENDELLIPSIS
);
7329 if ( nFirstContent
> 4 )
7331 XubString
aFirstStr( aStr
, 0, nFirstContent
);
7332 aFirstStr
.AppendAscii( "..." );
7333 XubString aTempStr
= aFirstStr
;
7334 aTempStr
+= aLastStr
;
7335 if ( GetTextWidth( aTempStr
) > nMaxWidth
)
7336 aStr
= GetEllipsisString( aStr
, nMaxWidth
, nStyle
| TEXT_DRAW_ENDELLIPSIS
);
7342 if( nLastContent
> aStr
.Len() )
7343 nLastContent
= aStr
.Len();
7344 while ( nFirstContent
< nLastContent
)
7347 if ( ImplIsCharIn( aStr
.GetChar( nLastContent
), pSepChars
) )
7351 while ( (nFirstContent
< nLastContent
) &&
7352 ImplIsCharIn( aStr
.GetChar( nLastContent
-1 ), pSepChars
) )
7355 if ( nFirstContent
< nLastContent
)
7357 XubString
aTempLastStr( aStr
, nLastContent
, aStr
.Len() );
7358 aTempStr
= aFirstStr
;
7359 aTempStr
+= aTempLastStr
;
7360 if ( GetTextWidth( aTempStr
) > nMaxWidth
)
7364 while ( nFirstContent
< nLastContent
);
7374 // -----------------------------------------------------------------------
7376 void OutputDevice::DrawCtrlText( const Point
& rPos
, const XubString
& rStr
,
7377 xub_StrLen nIndex
, xub_StrLen nLen
,
7378 USHORT nStyle
, MetricVector
* pVector
, String
* pDisplayText
)
7380 DBG_TRACE( "OutputDevice::DrawCtrlText()" );
7381 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7383 if ( !IsDeviceOutputNecessary() || (nIndex
>= rStr
.Len()) )
7386 // better get graphics here because ImplDrawMnemonicLine() will not
7387 // we need a graphics
7388 if( !mpGraphics
&& !ImplGetGraphics() )
7390 if( mbInitClipRegion
)
7391 ImplInitClipRegion();
7392 if ( mbOutputClipped
)
7395 if( nIndex
>= rStr
.Len() )
7397 if( (ULONG
)nIndex
+nLen
>= rStr
.Len() )
7398 nLen
= rStr
.Len() - nIndex
;
7400 XubString aStr
= rStr
;
7401 xub_StrLen nMnemonicPos
= STRING_NOTFOUND
;
7403 long nMnemonicX
= 0;
7404 long nMnemonicY
= 0;
7405 long nMnemonicWidth
= 0;
7406 if ( (nStyle
& TEXT_DRAW_MNEMONIC
) && nLen
> 1 )
7408 aStr
= GetNonMnemonicString( aStr
, nMnemonicPos
);
7409 if ( nMnemonicPos
!= STRING_NOTFOUND
)
7411 if( nMnemonicPos
< nIndex
)
7413 else if( nLen
< STRING_LEN
)
7415 if( nMnemonicPos
< (nIndex
+nLen
) )
7417 DBG_ASSERT( nMnemonicPos
< (nIndex
+nLen
), "Mnemonic underline marker after last character" );
7419 BOOL bInvalidPos
= FALSE
;
7421 if( nMnemonicPos
>= nLen
)
7424 // may occur in BiDi-Strings: the '~' is sometimes found behind the last char
7425 // due to some strange BiDi text editors
7426 // ->place the underline behind the string to indicate a failure
7428 nMnemonicPos
= nLen
-1;
7431 sal_Int32
* pCaretXArray
= (sal_Int32
*)alloca( 2 * sizeof(sal_Int32
) * nLen
);
7432 /*BOOL bRet =*/ GetCaretPositions( aStr
, pCaretXArray
, nIndex
, nLen
);
7433 long lc_x1
= pCaretXArray
[ 2*(nMnemonicPos
- nIndex
) ];
7434 long lc_x2
= pCaretXArray
[ 2*(nMnemonicPos
- nIndex
)+1 ];
7435 nMnemonicWidth
= ::abs((int)(lc_x1
- lc_x2
));
7437 Point
aTempPos( Min(lc_x1
,lc_x2
), GetFontMetric().GetAscent() );
7438 if( bInvalidPos
) // #106952#, place behind the (last) character
7439 aTempPos
= Point( Max(lc_x1
,lc_x2
), GetFontMetric().GetAscent() );
7442 aTempPos
= LogicToPixel( aTempPos
);
7443 nMnemonicX
= mnOutOffX
+ aTempPos
.X();
7444 nMnemonicY
= mnOutOffY
+ aTempPos
.Y();
7448 if ( nStyle
& TEXT_DRAW_DISABLE
&& ! pVector
)
7450 Color aOldTextColor
;
7451 Color aOldTextFillColor
;
7452 BOOL bRestoreFillColor
;
7453 BOOL bHighContrastBlack
= FALSE
;
7454 BOOL bHighContrastWhite
= FALSE
;
7455 const StyleSettings
& rStyleSettings( GetSettings().GetStyleSettings() );
7456 if( rStyleSettings
.GetHighContrastMode() )
7458 if( IsBackground() )
7460 Wallpaper aWall
= GetBackground();
7461 Color aCol
= aWall
.GetColor();
7462 bHighContrastBlack
= aCol
.IsDark();
7463 bHighContrastWhite
= aCol
.IsBright();
7467 aOldTextColor
= GetTextColor();
7468 if ( IsTextFillColor() )
7470 bRestoreFillColor
= TRUE
;
7471 aOldTextFillColor
= GetTextFillColor();
7474 bRestoreFillColor
= FALSE
;
7476 if( bHighContrastBlack
)
7477 SetTextColor( COL_GREEN
);
7478 else if( bHighContrastWhite
)
7479 SetTextColor( COL_LIGHTGREEN
);
7481 SetTextColor( GetSettings().GetStyleSettings().GetDisableColor() );
7483 DrawText( rPos
, aStr
, nIndex
, nLen
, pVector
, pDisplayText
);
7484 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS
) && !pVector
)
7486 if ( nMnemonicPos
!= STRING_NOTFOUND
)
7487 ImplDrawMnemonicLine( nMnemonicX
, nMnemonicY
, nMnemonicWidth
);
7489 SetTextColor( aOldTextColor
);
7490 if ( bRestoreFillColor
)
7491 SetTextFillColor( aOldTextFillColor
);
7495 DrawText( rPos
, aStr
, nIndex
, nLen
, pVector
, pDisplayText
);
7496 if ( !(GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_NOMNEMONICS
) && !pVector
)
7498 if ( nMnemonicPos
!= STRING_NOTFOUND
)
7499 ImplDrawMnemonicLine( nMnemonicX
, nMnemonicY
, nMnemonicWidth
);
7504 mpAlphaVDev
->DrawCtrlText( rPos
, rStr
, nIndex
, nLen
, nStyle
, pVector
, pDisplayText
);
7507 // -----------------------------------------------------------------------
7509 long OutputDevice::GetCtrlTextWidth( const String
& rStr
,
7510 xub_StrLen nIndex
, xub_StrLen nLen
,
7511 USHORT nStyle
) const
7513 DBG_TRACE( "OutputDevice::GetCtrlTextSize()" );
7514 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7516 if ( nStyle
& TEXT_DRAW_MNEMONIC
)
7518 xub_StrLen nMnemonicPos
;
7519 XubString aStr
= GetNonMnemonicString( rStr
, nMnemonicPos
);
7520 if ( nMnemonicPos
!= STRING_NOTFOUND
)
7522 if ( nMnemonicPos
< nIndex
)
7524 else if ( (nLen
< STRING_LEN
) &&
7525 (nMnemonicPos
>= nIndex
) && (nMnemonicPos
< (ULONG
)(nIndex
+nLen
)) )
7528 return GetTextWidth( aStr
, nIndex
, nLen
);
7531 return GetTextWidth( rStr
, nIndex
, nLen
);
7534 // -----------------------------------------------------------------------
7536 String
OutputDevice::GetNonMnemonicString( const String
& rStr
, xub_StrLen
& rMnemonicPos
)
7539 xub_StrLen nLen
= aStr
.Len();
7542 rMnemonicPos
= STRING_NOTFOUND
;
7545 if ( aStr
.GetChar( i
) == '~' )
7547 if ( aStr
.GetChar( i
+1 ) != '~' )
7549 if ( rMnemonicPos
== STRING_NOTFOUND
)
7568 // -----------------------------------------------------------------------
7570 int OutputDevice::GetDevFontCount() const
7572 DBG_TRACE( "OutputDevice::GetDevFontCount()" );
7573 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7575 if( !mpGetDevFontList
)
7576 mpGetDevFontList
= mpFontList
->GetDevFontList();
7577 return mpGetDevFontList
->Count();
7580 // -----------------------------------------------------------------------
7582 FontInfo
OutputDevice::GetDevFont( int nDevFontIndex
) const
7584 DBG_TRACE( "OutputDevice::GetDevFont()" );
7585 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7591 int nCount
= GetDevFontCount();
7592 if( nDevFontIndex
< nCount
)
7594 const ImplFontData
& rData
= *mpGetDevFontList
->Get( nDevFontIndex
);
7595 aFontInfo
.SetName( rData
.maName
);
7596 aFontInfo
.SetStyleName( rData
.maStyleName
);
7597 aFontInfo
.SetCharSet( rData
.mbSymbolFlag
? RTL_TEXTENCODING_SYMBOL
: RTL_TEXTENCODING_UNICODE
);
7598 aFontInfo
.SetFamily( rData
.meFamily
);
7599 aFontInfo
.SetPitch( rData
.mePitch
);
7600 aFontInfo
.SetWeight( rData
.meWeight
);
7601 aFontInfo
.SetItalic( rData
.meItalic
);
7602 aFontInfo
.SetWidthType( rData
.meWidthType
);
7603 if( rData
.IsScalable() )
7604 aFontInfo
.mpImplMetric
->mnMiscFlags
|= ImplFontMetric::SCALABLE_FLAG
;
7605 if( rData
.mbDevice
)
7606 aFontInfo
.mpImplMetric
->mnMiscFlags
|= ImplFontMetric::DEVICE_FLAG
;
7612 // -----------------------------------------------------------------------
7614 BOOL
OutputDevice::AddTempDevFont( const String
& rFileURL
, const String
& rFontName
)
7616 DBG_TRACE( "OutputDevice::AddTempDevFont()" );
7617 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7621 if( !mpGraphics
&& !ImplGetGraphics() )
7624 bool bRC
= mpGraphics
->AddTempDevFont( mpFontList
, rFileURL
, rFontName
);
7629 mpAlphaVDev
->AddTempDevFont( rFileURL
, rFontName
);
7631 mpFontCache
->Invalidate();
7635 // -----------------------------------------------------------------------
7637 int OutputDevice::GetDevFontSizeCount( const Font
& rFont
) const
7639 DBG_TRACE( "OutputDevice::GetDevFontSizeCount()" );
7640 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7642 delete mpGetDevSizeList
;
7645 mpGetDevSizeList
= mpFontList
->GetDevSizeList( rFont
.GetName() );
7646 return mpGetDevSizeList
->Count();
7649 // -----------------------------------------------------------------------
7651 Size
OutputDevice::GetDevFontSize( const Font
& rFont
, int nSizeIndex
) const
7653 DBG_TRACE( "OutputDevice::GetDevFontSize()" );
7654 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7657 int nCount
= GetDevFontSizeCount( rFont
);
7658 if ( nSizeIndex
>= nCount
)
7661 // when mapping is enabled round to .5 points
7662 Size
aSize( 0, mpGetDevSizeList
->Get( nSizeIndex
) );
7665 aSize
.Height() *= 10;
7666 MapMode
aMap( MAP_10TH_INCH
, Point(), Fraction( 1, 72 ), Fraction( 1, 72 ) );
7667 aSize
= PixelToLogic( aSize
, aMap
);
7668 aSize
.Height() += 5;
7669 aSize
.Height() /= 10;
7670 long nRound
= aSize
.Height() % 5;
7672 aSize
.Height() += (5-nRound
);
7674 aSize
.Height() -= nRound
;
7675 aSize
.Height() *= 10;
7676 aSize
= LogicToPixel( aSize
, aMap
);
7677 aSize
= PixelToLogic( aSize
);
7678 aSize
.Height() += 5;
7679 aSize
.Height() /= 10;
7684 // -----------------------------------------------------------------------
7686 BOOL
OutputDevice::IsFontAvailable( const String
& rFontName
) const
7688 DBG_TRACE( "OutputDevice::IsFontAvailable()" );
7689 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7691 ImplDevFontListData
* pFound
= mpFontList
->FindFontFamily( rFontName
);
7692 return (pFound
!= NULL
);
7695 // -----------------------------------------------------------------------
7697 FontMetric
OutputDevice::GetFontMetric() const
7699 DBG_TRACE( "OutputDevice::GetFontMetric()" );
7700 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7703 if( mbNewFont
&& !ImplNewFont() )
7706 ImplFontEntry
* pEntry
= mpFontEntry
;
7707 ImplFontMetricData
* pMetric
= &(pEntry
->maMetric
);
7710 aMetric
.Font::operator=( maFont
);
7712 // set aMetric with info from font
7713 aMetric
.SetName( maFont
.GetName() );
7714 aMetric
.SetStyleName( pMetric
->maStyleName
);
7715 aMetric
.SetSize( PixelToLogic( Size( pMetric
->mnWidth
, pMetric
->mnAscent
+pMetric
->mnDescent
-pMetric
->mnIntLeading
) ) );
7716 aMetric
.SetCharSet( pMetric
->mbSymbolFlag
? RTL_TEXTENCODING_SYMBOL
: RTL_TEXTENCODING_UNICODE
);
7717 aMetric
.SetFamily( pMetric
->meFamily
);
7718 aMetric
.SetPitch( pMetric
->mePitch
);
7719 aMetric
.SetWeight( pMetric
->meWeight
);
7720 aMetric
.SetItalic( pMetric
->meItalic
);
7721 aMetric
.SetWidthType( pMetric
->meWidthType
);
7722 if ( pEntry
->mnOwnOrientation
)
7723 aMetric
.SetOrientation( pEntry
->mnOwnOrientation
);
7725 aMetric
.SetOrientation( pMetric
->mnOrientation
);
7726 if( !pEntry
->maMetric
.mbKernableFont
)
7727 aMetric
.SetKerning( maFont
.GetKerning() & ~KERNING_FONTSPECIFIC
);
7729 // set remaining metric fields
7730 aMetric
.mpImplMetric
->mnMiscFlags
= 0;
7731 if( pMetric
->mbDevice
)
7732 aMetric
.mpImplMetric
->mnMiscFlags
|= ImplFontMetric::DEVICE_FLAG
;
7733 if( pMetric
->mbScalableFont
)
7734 aMetric
.mpImplMetric
->mnMiscFlags
|= ImplFontMetric::SCALABLE_FLAG
;
7735 aMetric
.mpImplMetric
->mnAscent
= ImplDevicePixelToLogicHeight( pMetric
->mnAscent
+mnEmphasisAscent
);
7736 aMetric
.mpImplMetric
->mnDescent
= ImplDevicePixelToLogicHeight( pMetric
->mnDescent
+mnEmphasisDescent
);
7737 aMetric
.mpImplMetric
->mnIntLeading
= ImplDevicePixelToLogicHeight( pMetric
->mnIntLeading
+mnEmphasisAscent
);
7738 aMetric
.mpImplMetric
->mnExtLeading
= ImplDevicePixelToLogicHeight( pMetric
->mnExtLeading
);
7739 aMetric
.mpImplMetric
->mnLineHeight
= ImplDevicePixelToLogicHeight( pMetric
->mnAscent
+pMetric
->mnDescent
+mnEmphasisAscent
+mnEmphasisDescent
);
7740 aMetric
.mpImplMetric
->mnSlant
= ImplDevicePixelToLogicHeight( pMetric
->mnSlant
);
7743 // backwards compatible line metrics after fixing #i60945#
7744 if( (meOutDevType
== OUTDEV_VIRDEV
)
7745 && static_cast<const VirtualDevice
*>(this)->ForceZeroExtleadBug() )
7746 aMetric
.mpImplMetric
->mnExtLeading
= 0;
7752 // -----------------------------------------------------------------------
7754 FontMetric
OutputDevice::GetFontMetric( const Font
& rFont
) const
7756 // select font, query metrics, select original font again
7757 Font aOldFont
= GetFont();
7758 const_cast<OutputDevice
*>(this)->SetFont( rFont
);
7759 FontMetric
aMetric( GetFontMetric() );
7760 const_cast<OutputDevice
*>(this)->SetFont( aOldFont
);
7764 // -----------------------------------------------------------------------
7766 /** OutputDevice::GetSysFontData
7768 * @param nFallbacklevel Fallback font level (0 = best matching font)
7770 * Retrieve detailed font information in platform independent structure
7772 * @return SystemFontData
7774 SystemFontData
OutputDevice::GetSysFontData(int nFallbacklevel
) const
7776 SystemFontData aSysFontData
;
7777 aSysFontData
.nSize
= sizeof(aSysFontData
);
7779 if (!mpGraphics
) ImplGetGraphics();
7780 if (mpGraphics
) aSysFontData
= mpGraphics
->GetSysFontData(nFallbacklevel
);
7782 return aSysFontData
;
7786 // -----------------------------------------------------------------------
7788 /** OutputDevice::GetSysTextLayoutData
7790 * @param rStartPt Start point of the text
7791 * @param rStr Text string that will be transformed into layout of glyphs
7792 * @param nIndex Position in the string from where layout will be done
7793 * @param nLen Length of the string
7794 * @param pDXAry Custom layout adjustment data
7796 * Export finalized glyph layout data as platform independent SystemTextLayoutData
7797 * (see vcl/inc/vcl/sysdata.hxx)
7799 * Only parameters rStartPt and rStr are mandatory, the rest is optional
7800 * (default values will be used)
7802 * @return SystemTextLayoutData
7804 SystemTextLayoutData
OutputDevice::GetSysTextLayoutData(const Point
& rStartPt
, const XubString
& rStr
, xub_StrLen nIndex
, xub_StrLen nLen
,
7805 const sal_Int32
* pDXAry
) const
7807 DBG_TRACE( "OutputDevice::GetSysTextLayoutData()" );
7808 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7810 SystemTextLayoutData aSysLayoutData
;
7811 aSysLayoutData
.nSize
= sizeof(aSysLayoutData
);
7812 aSysLayoutData
.rGlyphData
.reserve( 256 );
7816 mpMetaFile
->AddAction( new MetaTextArrayAction( rStartPt
, rStr
, pDXAry
, nIndex
, nLen
) );
7818 mpMetaFile
->AddAction( new MetaTextAction( rStartPt
, rStr
, nIndex
, nLen
) );
7821 if ( !IsDeviceOutputNecessary() ) return aSysLayoutData
;
7823 SalLayout
* rLayout
= ImplLayout( rStr
, nIndex
, nLen
, rStartPt
, 0, pDXAry
, true );
7827 sal_GlyphId aGlyphId
;
7828 int nFallbacklevel
= 0;
7829 for( int nStart
= 0; rLayout
->GetNextGlyphs( 1, &aGlyphId
, aPos
, nStart
); )
7831 // NOTE: Windows backend is producing unicode chars (ucs4), so on windows,
7832 // ETO_GLYPH_INDEX is unusable, unless extra glyph conversion is made.
7834 SystemGlyphData aGlyph
;
7835 aGlyph
.index
= static_cast<unsigned long> (aGlyphId
& GF_IDXMASK
);
7836 aGlyph
.x
= aPos
.X();
7837 aGlyph
.y
= aPos
.Y();
7838 aSysLayoutData
.rGlyphData
.push_back(aGlyph
);
7840 int nLevel
= (aGlyphId
& GF_FONTMASK
) >> GF_FONTSHIFT
;
7841 if (nLevel
> nFallbacklevel
&& nLevel
< MAX_FALLBACK
)
7842 nFallbacklevel
= nLevel
;
7846 aSysLayoutData
.aSysFontData
= GetSysFontData(nFallbacklevel
);
7847 aSysLayoutData
.orientation
= rLayout
->GetOrientation();
7851 return aSysLayoutData
;
7854 // -----------------------------------------------------------------------
7857 long OutputDevice::GetMinKashida() const
7859 DBG_TRACE( "OutputDevice::GetMinKashida()" );
7860 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7861 if( mbNewFont
&& !ImplNewFont() )
7864 ImplFontEntry
* pEntry
= mpFontEntry
;
7865 ImplFontMetricData
* pMetric
= &(pEntry
->maMetric
);
7866 return ImplDevicePixelToLogicWidth( pMetric
->mnMinKashida
);
7868 // -----------------------------------------------------------------------
7870 long OutputDevice::GetMinKashida( const Font
& rFont
) const
7872 // select font, query Kashida, select original font again
7873 Font aOldFont
= GetFont();
7874 const_cast<OutputDevice
*>(this)->SetFont( rFont
);
7875 long aKashida
= GetMinKashida();
7876 const_cast<OutputDevice
*>(this)->SetFont( aOldFont
);
7880 // -----------------------------------------------------------------------
7881 xub_StrLen
OutputDevice::ValidateKashidas ( const String
& rTxt
,
7882 xub_StrLen nIdx
, xub_StrLen nLen
,
7883 xub_StrLen nKashCount
,
7884 const xub_StrLen
* pKashidaPos
,
7885 xub_StrLen
* pKashidaPosDropped
) const
7888 SalLayout
* pSalLayout
= ImplLayout( rTxt
, nIdx
, nLen
);
7891 xub_StrLen nDropped
= 0;
7892 for( int i
= 0; i
< nKashCount
; ++i
)
7894 if( !pSalLayout
->IsKashidaPosValid( pKashidaPos
[ i
] ))
7896 pKashidaPosDropped
[ nDropped
] = pKashidaPos
[ i
];
7900 pSalLayout
->Release();
7906 // -----------------------------------------------------------------------
7909 // TODO: best is to get rid of this method completely
7910 ULONG
OutputDevice::GetKerningPairCount() const
7912 DBG_TRACE( "OutputDevice::GetKerningPairCount()" );
7913 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7915 if( mbNewFont
&& !ImplNewFont() )
7920 if( mpPDFWriter
&& mpPDFWriter
->isBuiltinFont( mpFontEntry
->maFontSelData
.mpFontData
) )
7923 // get the kerning pair count from the device layer
7924 int nKernPairs
= mpGraphics
->GetKernPairs( 0, NULL
);
7928 // -----------------------------------------------------------------------
7930 inline bool CmpKernData( const KerningPair
& a
, const KerningPair
& b
)
7932 return (a
.nChar1
< b
.nChar1
) || ((a
.nChar1
== a
.nChar2
) && (a
.nChar2
< a
.nChar2
));
7935 // TODO: best is to get rid of this method completely
7936 void OutputDevice::GetKerningPairs( ULONG nRequestedPairs
, KerningPair
* pKernPairs
) const
7938 DBG_TRACE( "OutputDevice::GetKerningPairs()" );
7939 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7941 if( mbNewFont
&& !ImplNewFont() )
7946 if( mpPDFWriter
&& mpPDFWriter
->isBuiltinFont( mpFontEntry
->maFontSelData
.mpFontData
) )
7949 // get the kerning pairs directly from the device layer
7950 int nKernPairs
= mpGraphics
->GetKernPairs( nRequestedPairs
, (ImplKernPairData
*)pKernPairs
);
7952 // sort kerning pairs
7953 std::sort( pKernPairs
, pKernPairs
+nKernPairs
, CmpKernData
);
7956 // -----------------------------------------------------------------------
7958 BOOL
OutputDevice::GetGlyphBoundRects( const Point
& rOrigin
, const String
& rStr
,
7959 int nIndex
, int nLen
, int nBase
, MetricVector
& rVector
)
7961 DBG_TRACE( "OutputDevice::GetGlyphBoundRect_CTL()" );
7962 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7966 if( nLen
== STRING_LEN
)
7967 nLen
= rStr
.Len() - nIndex
;
7970 for( int i
= 0; i
< nLen
; i
++ )
7972 if( !GetTextBoundRect( aRect
, rStr
, sal::static_int_cast
<xub_StrLen
>(nBase
), sal::static_int_cast
<xub_StrLen
>(nIndex
+i
), 1 ) )
7974 aRect
.Move( rOrigin
.X(), rOrigin
.Y() );
7975 rVector
.push_back( aRect
);
7978 return (nLen
== (int)rVector
.size());
7981 // -----------------------------------------------------------------------
7983 BOOL
OutputDevice::GetTextBoundRect( Rectangle
& rRect
,
7984 const String
& rStr
, xub_StrLen nBase
, xub_StrLen nIndex
, xub_StrLen nLen
,
7985 ULONG nLayoutWidth
, const sal_Int32
* pDXAry
) const
7987 DBG_TRACE( "OutputDevice::GetTextBoundRect()" );
7988 DBG_CHKTHIS( OutputDevice
, ImplDbgCheckOutputDevice
);
7993 SalLayout
* pSalLayout
= NULL
;
7995 // calculate offset when nBase!=nIndex
7997 if( nBase
!= nIndex
)
7999 xub_StrLen nStart
= Min( nBase
, nIndex
);
8000 xub_StrLen nOfsLen
= Max( nBase
, nIndex
) - nStart
;
8001 pSalLayout
= ImplLayout( rStr
, nStart
, nOfsLen
, aPoint
, nLayoutWidth
, pDXAry
);
8004 nXOffset
= pSalLayout
->GetTextWidth();
8005 nXOffset
/= pSalLayout
->GetUnitsPerPixel();
8006 pSalLayout
->Release();
8007 // TODO: fix offset calculation for Bidi case
8009 nXOffset
= -nXOffset
;
8013 pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
, aPoint
, nLayoutWidth
, pDXAry
);
8014 Rectangle aPixelRect
;
8017 bRet
= pSalLayout
->GetBoundRect( *mpGraphics
, aPixelRect
);
8021 int nWidthFactor
= pSalLayout
->GetUnitsPerPixel();
8023 if( nWidthFactor
> 1 )
8025 double fFactor
= 1.0 / nWidthFactor
;
8027 = static_cast< long >(aPixelRect
.Left() * fFactor
);
8029 = static_cast< long >(aPixelRect
.Right() * fFactor
);
8031 = static_cast< long >(aPixelRect
.Top() * fFactor
);
8033 = static_cast< long >(aPixelRect
.Bottom() * fFactor
);
8036 Point
aRotatedOfs( mnTextOffX
, mnTextOffY
);
8037 aRotatedOfs
-= pSalLayout
->GetDrawPosition( Point( nXOffset
, 0 ) );
8038 aPixelRect
+= aRotatedOfs
;
8039 rRect
= PixelToLogic( aPixelRect
);
8041 rRect
+= Point( maMapRes
.mnMapOfsX
, maMapRes
.mnMapOfsY
);
8044 pSalLayout
->Release();
8047 if( bRet
|| (OUTDEV_PRINTER
== meOutDevType
) || !mpFontEntry
)
8050 // fall back to bitmap method to get the bounding rectangle,
8051 // so we need a monochrome virtual device with matching font
8052 VirtualDevice
aVDev( 1 );
8053 Font
aFont( GetFont() );
8054 aFont
.SetShadow( FALSE
);
8055 aFont
.SetOutline( FALSE
);
8056 aFont
.SetRelief( RELIEF_NONE
);
8057 aFont
.SetOrientation( 0 );
8058 aFont
.SetSize( Size( mpFontEntry
->maFontSelData
.mnWidth
, mpFontEntry
->maFontSelData
.mnHeight
) );
8059 aVDev
.SetFont( aFont
);
8060 aVDev
.SetTextAlign( ALIGN_TOP
);
8062 // layout the text on the virtual device
8063 pSalLayout
= aVDev
.ImplLayout( rStr
, nIndex
, nLen
, aPoint
, nLayoutWidth
, pDXAry
);
8067 // make the bitmap big enough
8068 // TODO: use factors when it would get too big
8069 long nWidth
= pSalLayout
->GetTextWidth();
8070 long nHeight
= mpFontEntry
->mnLineHeight
+ mnEmphasisAscent
+ mnEmphasisDescent
;
8071 Point
aOffset( nWidth
/2, 8 );
8072 Size
aOutSize( nWidth
+ 2*aOffset
.X(), nHeight
+ 2*aOffset
.Y() );
8073 if( !nWidth
|| !aVDev
.SetOutputSizePixel( aOutSize
) )
8076 // draw text in black
8077 pSalLayout
->DrawBase() = aOffset
;
8078 aVDev
.SetTextColor( Color( COL_BLACK
) );
8079 aVDev
.SetTextFillColor();
8080 aVDev
.ImplInitTextColor();
8081 aVDev
.ImplDrawText( *pSalLayout
);
8082 pSalLayout
->Release();
8084 // find extents using the bitmap
8085 Bitmap aBmp
= aVDev
.GetBitmap( Point(), aOutSize
);
8086 BitmapReadAccess
* pAcc
= aBmp
.AcquireReadAccess();
8089 const BitmapColor
aBlack( pAcc
->GetBestMatchingColor( Color( COL_BLACK
) ) );
8090 const long nW
= pAcc
->Width();
8091 const long nH
= pAcc
->Height();
8095 // find top left point
8097 for(; nTop
< nH
; ++nTop
)
8099 for( nLeft
= 0; nLeft
< nW
; ++nLeft
)
8100 if( pAcc
->GetPixel( nTop
, nLeft
) == aBlack
)
8106 // find bottom right point
8108 while( --nBottom
>= nTop
)
8110 for( nRight
= nW
; --nRight
>= 0; )
8111 if( pAcc
->GetPixel( nBottom
, nRight
) == aBlack
)
8116 if( nRight
< nLeft
)
8123 for( long nY
= nTop
; nY
<= nBottom
; ++nY
)
8125 // find leftmost point
8127 for( nX
= 0; nX
< nLeft
; ++nX
)
8128 if( pAcc
->GetPixel( nY
, nX
) == aBlack
)
8132 // find rightmost point
8133 for( nX
= nW
; --nX
> nRight
; )
8134 if( pAcc
->GetPixel( nY
, nX
) == aBlack
)
8139 aBmp
.ReleaseAccess( pAcc
);
8141 if( nTop
<= nBottom
)
8143 Size
aSize( nRight
- nLeft
+ 1, nBottom
- nTop
+ 1 );
8144 Point
aTopLeft( nLeft
, nTop
);
8145 aTopLeft
-= aOffset
;
8146 // adjust to text alignment
8147 aTopLeft
.Y()+= mnTextOffY
- (mpFontEntry
->maMetric
.mnAscent
+ mnEmphasisAscent
);
8148 // convert to logical coordinates
8149 aSize
= PixelToLogic( aSize
);
8150 aTopLeft
.X() = ImplDevicePixelToLogicWidth( aTopLeft
.X() );
8151 aTopLeft
.Y() = ImplDevicePixelToLogicHeight( aTopLeft
.Y() );
8152 rRect
= Rectangle( aTopLeft
, aSize
);
8159 // -----------------------------------------------------------------------
8161 BOOL
OutputDevice::GetTextOutlines( ::basegfx::B2DPolyPolygonVector
& rVector
,
8162 const String
& rStr
, xub_StrLen nBase
, xub_StrLen nIndex
, xub_StrLen nLen
,
8163 BOOL bOptimize
, ULONG nTWidth
, const sal_Int32
* pDXArray
) const
8165 // the fonts need to be initialized
8175 if( nLen
== STRING_LEN
)
8176 nLen
= rStr
.Len() - nIndex
;
8177 rVector
.reserve( nLen
);
8179 // we want to get the Rectangle in logical units, so to
8180 // avoid rounding errors we just size the font in logical units
8181 BOOL bOldMap
= mbMap
;
8184 const_cast<OutputDevice
&>(*this).mbMap
= FALSE
;
8185 const_cast<OutputDevice
&>(*this).mbNewFont
= TRUE
;
8188 SalLayout
* pSalLayout
= NULL
;
8190 // calculate offset when nBase!=nIndex
8192 if( nBase
!= nIndex
)
8194 xub_StrLen nStart
= Min( nBase
, nIndex
);
8195 xub_StrLen nOfsLen
= Max( nBase
, nIndex
) - nStart
;
8196 pSalLayout
= ImplLayout( rStr
, nStart
, nOfsLen
, Point(0,0), nTWidth
, pDXArray
);
8199 nXOffset
= pSalLayout
->GetTextWidth();
8200 pSalLayout
->Release();
8201 // TODO: fix offset calculation for Bidi case
8203 nXOffset
= -nXOffset
;
8207 pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
, Point(0,0), nTWidth
, pDXArray
);
8210 bRet
= pSalLayout
->GetOutline( *mpGraphics
, rVector
);
8213 // transform polygon to pixel units
8214 ::basegfx::B2DHomMatrix aMatrix
;
8216 int nWidthFactor
= pSalLayout
->GetUnitsPerPixel();
8217 if( nXOffset
| mnTextOffX
| mnTextOffY
)
8219 Point
aRotatedOfs( mnTextOffX
*nWidthFactor
, mnTextOffY
*nWidthFactor
);
8220 aRotatedOfs
-= pSalLayout
->GetDrawPosition( Point( nXOffset
, 0 ) );
8221 aMatrix
.translate( aRotatedOfs
.X(), aRotatedOfs
.Y() );
8224 if( nWidthFactor
> 1 )
8226 double fFactor
= 1.0 / nWidthFactor
;
8227 aMatrix
.scale( fFactor
, fFactor
);
8230 if( !aMatrix
.isIdentity() )
8232 ::basegfx::B2DPolyPolygonVector::iterator aIt
= rVector
.begin();
8233 for(; aIt
!= rVector
.end(); ++aIt
)
8234 (*aIt
).transform( aMatrix
);
8238 pSalLayout
->Release();
8243 // restore original font size and map mode
8244 const_cast<OutputDevice
&>(*this).mbMap
= bOldMap
;
8245 const_cast<OutputDevice
&>(*this).mbNewFont
= TRUE
;
8248 if( bRet
|| (OUTDEV_PRINTER
== meOutDevType
) || !mpFontEntry
)
8251 // fall back to bitmap conversion ------------------------------------------
8253 // Here, we can savely assume that the mapping between characters and glyphs
8254 // is one-to-one. This is most probably valid for the old bitmap fonts.
8256 // fall back to bitmap method to get the bounding rectangle,
8257 // so we need a monochrome virtual device with matching font
8258 pSalLayout
= ImplLayout( rStr
, nIndex
, nLen
, Point(0,0), nTWidth
, pDXArray
);
8259 if (pSalLayout
== 0)
8261 long nOrgWidth
= pSalLayout
->GetTextWidth();
8262 long nOrgHeight
= mpFontEntry
->mnLineHeight
+ mnEmphasisAscent
8263 + mnEmphasisDescent
;
8264 pSalLayout
->Release();
8266 VirtualDevice
aVDev(1);
8268 Font
aFont(GetFont());
8269 aFont
.SetShadow(false);
8270 aFont
.SetOutline(false);
8271 aFont
.SetRelief(RELIEF_NONE
);
8272 aFont
.SetOrientation(0);
8275 aFont
.SetSize( Size( 0, GLYPH_FONT_HEIGHT
) );
8276 aVDev
.SetMapMode( MAP_PIXEL
);
8278 aVDev
.SetFont( aFont
);
8279 aVDev
.SetTextAlign( ALIGN_TOP
);
8280 aVDev
.SetTextColor( Color(COL_BLACK
) );
8281 aVDev
.SetTextFillColor();
8283 pSalLayout
= aVDev
.ImplLayout( rStr
, nIndex
, nLen
, Point(0,0), nTWidth
, pDXArray
);
8284 if (pSalLayout
== 0)
8286 long nWidth
= pSalLayout
->GetTextWidth();
8287 long nHeight
= ((OutputDevice
*)&aVDev
)->mpFontEntry
->mnLineHeight
+ ((OutputDevice
*)&aVDev
)->mnEmphasisAscent
8288 + ((OutputDevice
*)&aVDev
)->mnEmphasisDescent
;
8289 pSalLayout
->Release();
8291 if( !nWidth
|| !nHeight
)
8293 double fScaleX
= static_cast< double >(nOrgWidth
) / nWidth
;
8294 double fScaleY
= static_cast< double >(nOrgHeight
) / nHeight
;
8296 // calculate offset when nBase!=nIndex
8297 // TODO: fix offset calculation for Bidi case
8299 if( nBase
!= nIndex
)
8301 xub_StrLen nStart
= ((nBase
< nIndex
) ? nBase
: nIndex
);
8302 xub_StrLen nLength
= ((nBase
> nIndex
) ? nBase
: nIndex
) - nStart
;
8303 pSalLayout
= aVDev
.ImplLayout( rStr
, nStart
, nLength
, Point(0,0), nTWidth
, pDXArray
);
8306 nXOffset
= pSalLayout
->GetTextWidth();
8307 pSalLayout
->Release();
8309 nXOffset
= -nXOffset
;
8315 String
aStr( rStr
); // prepare for e.g. localized digits
8316 ImplLayoutArgs aLayoutArgs
= ImplPrepareLayoutArgs( aStr
, nIndex
, nLen
, 0, NULL
);
8317 for( int nCharPos
= -1; aLayoutArgs
.GetNextPos( &nCharPos
, &bRTL
);)
8319 bool bSuccess
= false;
8321 // draw character into virtual device
8322 pSalLayout
= aVDev
.ImplLayout( rStr
, static_cast< xub_StrLen
>(nCharPos
), 1, Point(0,0), nTWidth
, pDXArray
);
8323 if (pSalLayout
== 0)
8325 long nCharWidth
= pSalLayout
->GetTextWidth();
8327 Point
aOffset(nCharWidth
/ 2, 8);
8328 Size
aSize(nCharWidth
+ 2 * aOffset
.X(), nHeight
+ 2 * aOffset
.Y());
8329 bSuccess
= (bool)aVDev
.SetOutputSizePixel(aSize
);
8332 // draw glyph into virtual device
8334 pSalLayout
->DrawBase() += aOffset
;
8335 pSalLayout
->DrawBase() += Point( ((OutputDevice
*)&aVDev
)->mnTextOffX
, ((OutputDevice
*)&aVDev
)->mnTextOffY
);
8336 pSalLayout
->DrawText( *((OutputDevice
*)&aVDev
)->mpGraphics
);
8337 pSalLayout
->Release();
8339 // convert character image into outline
8340 Bitmap
aBmp( aVDev
.GetBitmap(Point(0, 0), aSize
));
8342 PolyPolygon aPolyPoly
;
8343 bool bVectorized
= aBmp
.Vectorize(aPolyPoly
, BMP_VECTORIZE_OUTER
| BMP_VECTORIZE_REDUCE_EDGES
);
8348 // convert units to logical width
8349 for (USHORT j
= 0; j
< aPolyPoly
.Count(); ++j
)
8351 Polygon
& rPoly
= aPolyPoly
[j
];
8352 for (USHORT k
= 0; k
< rPoly
.GetSize(); ++k
)
8354 Point
& rPt
= rPoly
[k
];
8356 int nPixelX
= rPt
.X() - ((OutputDevice
&)aVDev
).mnTextOffX
+ nXOffset
;
8357 int nPixelY
= rPt
.Y() - ((OutputDevice
&)aVDev
).mnTextOffY
;
8358 rPt
.X() = ImplDevicePixelToLogicWidth( nPixelX
);
8359 rPt
.Y() = ImplDevicePixelToLogicHeight( nPixelY
);
8364 // ignore "empty" glyphs:
8365 if( aPolyPoly
.Count() > 0 )
8367 // convert to B2DPolyPolygon
8368 // TODO: get rid of intermediate tool's PolyPolygon
8369 ::basegfx::B2DPolyPolygon aB2DPolyPoly
= aPolyPoly
.getB2DPolyPolygon();
8370 ::basegfx::B2DHomMatrix aMatrix
;
8371 aMatrix
.scale( fScaleX
, fScaleY
);
8372 int nAngle
= GetFont().GetOrientation();
8374 aMatrix
.rotate( nAngle
* F_PI1800
);
8375 aB2DPolyPoly
.transform( aMatrix
);
8376 rVector
.push_back( aB2DPolyPoly
);
8381 nXOffset
+= nCharWidth
;
8382 bRet
= bRet
&& bSuccess
;
8388 // -----------------------------------------------------------------------
8390 BOOL
OutputDevice::GetTextOutlines( PolyPolyVector
& rResultVector
,
8391 const String
& rStr
, xub_StrLen nBase
, xub_StrLen nIndex
,
8392 xub_StrLen nLen
, BOOL bOptimize
, ULONG nTWidth
, const sal_Int32
* pDXArray
) const
8394 rResultVector
.clear();
8396 // get the basegfx polypolygon vector
8397 ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector
;
8398 if( !GetTextOutlines( aB2DPolyPolyVector
, rStr
, nBase
, nIndex
, nLen
,
8399 bOptimize
, nTWidth
, pDXArray
) )
8402 // convert to a tool polypolygon vector
8403 rResultVector
.reserve( aB2DPolyPolyVector
.size() );
8404 ::basegfx::B2DPolyPolygonVector::const_iterator aIt
= aB2DPolyPolyVector
.begin();
8405 for(; aIt
!= aB2DPolyPolyVector
.end(); ++aIt
)
8406 rResultVector
.push_back(PolyPolygon(*aIt
)); // #i76339#
8411 // -----------------------------------------------------------------------
8413 BOOL
OutputDevice::GetTextOutline( PolyPolygon
& rPolyPoly
,
8414 const String
& rStr
, xub_StrLen nBase
, xub_StrLen nIndex
, xub_StrLen nLen
,
8415 BOOL bOptimize
, ULONG nTWidth
, const sal_Int32
* pDXArray
) const
8419 // get the basegfx polypolygon vector
8420 ::basegfx::B2DPolyPolygonVector aB2DPolyPolyVector
;
8421 if( !GetTextOutlines( aB2DPolyPolyVector
, rStr
, nBase
, nIndex
, nLen
,
8422 bOptimize
, nTWidth
, pDXArray
) )
8425 // convert and merge into a tool polypolygon
8426 ::basegfx::B2DPolyPolygonVector::const_iterator aIt
= aB2DPolyPolyVector
.begin();
8427 for(; aIt
!= aB2DPolyPolyVector
.end(); ++aIt
)
8428 for( unsigned int i
= 0; i
< aIt
->count(); ++i
)
8429 rPolyPoly
.Insert(Polygon((*aIt
).getB2DPolygon( i
))); // #i76339#
8434 // -----------------------------------------------------------------------
8436 BOOL
OutputDevice::GetFontCharMap( FontCharMap
& rFontCharMap
) const
8438 rFontCharMap
.Reset();
8440 // we need a graphics
8441 if( !mpGraphics
&& !ImplGetGraphics() )
8451 // a little font charmap cache helps considerably
8452 static const int NMAXITEMS
= 16;
8453 static int nUsedItems
= 0, nCurItem
= 0;
8455 struct CharMapCacheItem
{ const ImplFontData
* mpFontData
; FontCharMap maCharMap
; };
8456 static CharMapCacheItem aCache
[ NMAXITEMS
];
8458 const ImplFontData
* pFontData
= mpFontEntry
->maFontSelData
.mpFontData
;
8461 for( i
= nUsedItems
; --i
>= 0; )
8462 if( pFontData
== aCache
[i
].mpFontData
)
8464 if( i
>= 0 ) // found in cache
8466 rFontCharMap
.Reset( aCache
[i
].maCharMap
.mpImpl
);
8468 else // need to cache
8470 ImplFontCharMap
* pNewMap
= mpGraphics
->GetImplFontCharMap();
8471 rFontCharMap
.Reset( pNewMap
);
8473 // manage cache round-robin and insert data
8474 CharMapCacheItem
& rItem
= aCache
[ nCurItem
];
8475 rItem
.mpFontData
= pFontData
;
8476 rItem
.maCharMap
.Reset( pNewMap
);
8478 if( ++nCurItem
>= NMAXITEMS
)
8481 if( ++nUsedItems
>= NMAXITEMS
)
8482 nUsedItems
= NMAXITEMS
;
8485 if( rFontCharMap
.IsDefaultMap() )
8490 // -----------------------------------------------------------------------
8492 xub_StrLen
OutputDevice::HasGlyphs( const Font
& rTempFont
, const String
& rStr
,
8493 xub_StrLen nIndex
, xub_StrLen nLen
) const
8495 if( nIndex
>= rStr
.Len() )
8497 xub_StrLen nEnd
= nIndex
+ nLen
;
8498 if( (ULONG
)nIndex
+nLen
> rStr
.Len() )
8501 DBG_ASSERT( nIndex
< nEnd
, "StartPos >= EndPos?" );
8502 DBG_ASSERT( nEnd
<= rStr
.Len(), "String too short" );
8504 // to get the map temporarily set font
8505 const Font aOrigFont
= GetFont();
8506 const_cast<OutputDevice
&>(*this).SetFont( rTempFont
);
8507 FontCharMap aFontCharMap
;
8508 BOOL bRet
= GetFontCharMap( aFontCharMap
);
8509 const_cast<OutputDevice
&>(*this).SetFont( aOrigFont
);
8511 // if fontmap is unknown assume it doesn't have the glyphs
8515 const sal_Unicode
* pStr
= rStr
.GetBuffer();
8516 for( pStr
+= nIndex
; nIndex
< nEnd
; ++pStr
, ++nIndex
)
8517 if( ! aFontCharMap
.HasChar( *pStr
) )
8523 // -----------------------------------------------------------------------