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