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