1 #/************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include <basegfx/range/b2drange.hxx> 29 #include <basegfx/range/b2irange.hxx> 30 #include <basegfx/polygon/b2dpolypolygon.hxx> 31 32 #include <basebmp/scanlineformats.hxx> 33 34 #include <tools/debug.hxx> 35 36 #if OSL_DEBUG_LEVEL > 2 37 #include <basebmp/debug.hxx> 38 #endif 39 40 #include <outfont.hxx> 41 #include <glyphcache.hxx> 42 #include <impfont.hxx> 43 44 #include "svpgdi.hxx" 45 #include "svpbmp.hxx" 46 #include "svppspgraphics.hxx" 47 48 using namespace basegfx; 49 using namespace basebmp; 50 51 // =========================================================================== 52 53 class SvpGlyphPeer 54 : public GlyphCachePeer 55 { 56 public: 57 SvpGlyphPeer() {} 58 59 BitmapDeviceSharedPtr GetGlyphBmp( ServerFont&, int nGlyphIndex, 60 sal_uInt32 nBmpFormat, B2IPoint& rTargetPos ); 61 62 protected: 63 virtual void RemovingFont( ServerFont& ); 64 virtual void RemovingGlyph( ServerFont&, GlyphData&, int nGlyphIndex ); 65 66 class SvpGcpHelper 67 { 68 public: 69 RawBitmap maRawBitmap; 70 BitmapDeviceSharedPtr maBitmapDev; 71 }; 72 }; 73 74 // =========================================================================== 75 76 class SvpGlyphCache : public GlyphCache 77 { 78 public: 79 SvpGlyphPeer& GetPeer() { return reinterpret_cast<SvpGlyphPeer&>( mrPeer ); } 80 static SvpGlyphCache& GetInstance(); 81 private: 82 SvpGlyphCache( SvpGlyphPeer& rPeer ) : GlyphCache( rPeer) {} 83 }; 84 85 //-------------------------------------------------------------------------- 86 87 SvpGlyphCache& SvpGlyphCache::GetInstance() 88 { 89 static SvpGlyphPeer aSvpGlyphPeer; 90 static SvpGlyphCache aGC( aSvpGlyphPeer ); 91 return aGC; 92 } 93 94 // =========================================================================== 95 96 BitmapDeviceSharedPtr SvpGlyphPeer::GetGlyphBmp( ServerFont& rServerFont, 97 int nGlyphIndex, sal_uInt32 nBmpFormat, B2IPoint& rTargetPos ) 98 { 99 GlyphData& rGlyphData = rServerFont.GetGlyphData( nGlyphIndex ); 100 SvpGcpHelper* pGcpHelper = (SvpGcpHelper*)rGlyphData.ExtDataRef().mpData; 101 102 // nothing to do if the GlyphPeer hasn't allocated resources for the glyph 103 if( rGlyphData.ExtDataRef().meInfo != sal::static_int_cast<int>(nBmpFormat) ) 104 { 105 if( rGlyphData.ExtDataRef().meInfo == Format::NONE ) 106 pGcpHelper = new SvpGcpHelper; 107 RawBitmap& rRawBitmap = pGcpHelper->maRawBitmap; 108 109 // get glyph bitmap in matching format 110 bool bFound = false; 111 switch( nBmpFormat ) 112 { 113 case Format::ONE_BIT_LSB_GREY: 114 bFound = rServerFont.GetGlyphBitmap1( nGlyphIndex, pGcpHelper->maRawBitmap ); 115 break; 116 case Format::EIGHT_BIT_GREY: 117 bFound = rServerFont.GetGlyphBitmap8( nGlyphIndex, pGcpHelper->maRawBitmap ); 118 break; 119 default: 120 DBG_ERROR( "SVP GCP::GetGlyphBmp(): illegal scanline format"); 121 // fall back to black&white mask 122 nBmpFormat = Format::ONE_BIT_LSB_GREY; 123 bFound = false; 124 break; 125 } 126 127 // return .notdef glyph if needed 128 if( !bFound && (nGlyphIndex != 0) ) 129 { 130 delete pGcpHelper; 131 return GetGlyphBmp( rServerFont, 0, nBmpFormat, rTargetPos ); 132 } 133 134 // construct alpha mask from raw bitmap 135 const B2IVector aSize( rRawBitmap.mnScanlineSize, rRawBitmap.mnHeight ); 136 if( aSize.getX() && aSize.getY() ) 137 { 138 static PaletteMemorySharedVector aDummyPAL; 139 RawMemorySharedArray aRawPtr( rRawBitmap.mpBits ); 140 pGcpHelper->maBitmapDev = createBitmapDevice( aSize, true, nBmpFormat, aRawPtr, aDummyPAL ); 141 } 142 143 rServerFont.SetExtended( nBmpFormat, (void*)pGcpHelper ); 144 } 145 146 rTargetPos += B2IPoint( pGcpHelper->maRawBitmap.mnXOffset, pGcpHelper->maRawBitmap.mnYOffset ); 147 return pGcpHelper->maBitmapDev; 148 } 149 150 //-------------------------------------------------------------------------- 151 152 void SvpGlyphPeer::RemovingFont( ServerFont& ) 153 { 154 // nothing to do: no font resources held in SvpGlyphPeer 155 } 156 157 //-------------------------------------------------------------------------- 158 159 void SvpGlyphPeer::RemovingGlyph( ServerFont&, GlyphData& rGlyphData, int /*nGlyphIndex*/ ) 160 { 161 if( rGlyphData.ExtDataRef().mpData != Format::NONE ) 162 { 163 // release the glyph related resources 164 DBG_ASSERT( (rGlyphData.ExtDataRef().meInfo <= Format::MAX), "SVP::RG() invalid alpha format" ); 165 SvpGcpHelper* pGcpHelper = (SvpGcpHelper*)rGlyphData.ExtDataRef().mpData; 166 delete[] pGcpHelper->maRawBitmap.mpBits; 167 delete pGcpHelper; 168 } 169 } 170 171 // =========================================================================== 172 173 // PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#) 174 class PspKernInfo : public ExtraKernInfo 175 { 176 public: 177 PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {} 178 protected: 179 virtual void Initialize() const; 180 }; 181 182 //-------------------------------------------------------------------------- 183 184 void PspKernInfo::Initialize() const 185 { 186 mbInitialized = true; 187 188 // get the kerning pairs from psprint 189 const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); 190 typedef std::list< psp::KernPair > PspKernPairs; 191 const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId ); 192 if( rKernPairs.empty() ) 193 return; 194 195 // feed psprint's kerning list into a lookup-friendly container 196 maUnicodeKernPairs.resize( rKernPairs.size() ); 197 PspKernPairs::const_iterator it = rKernPairs.begin(); 198 for(; it != rKernPairs.end(); ++it ) 199 { 200 ImplKernPairData aKernPair = { it->first, it->second, it->kern_x }; 201 maUnicodeKernPairs.insert( aKernPair ); 202 } 203 } 204 205 // =========================================================================== 206 207 sal_uInt16 SvpSalGraphics::SetFont( ImplFontSelectData* pIFSD, int nFallbackLevel ) 208 { 209 // release all no longer needed font resources 210 for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) 211 { 212 if( m_pServerFont[i] != NULL ) 213 { 214 // old server side font is no longer referenced 215 SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] ); 216 m_pServerFont[i] = NULL; 217 } 218 } 219 220 // return early if there is no new font 221 if( !pIFSD ) 222 return 0; 223 224 // handle the request for a non-native X11-font => use the GlyphCache 225 ServerFont* pServerFont = SvpGlyphCache::GetInstance().CacheFont( *pIFSD ); 226 if( !pServerFont ) 227 return SAL_SETFONT_BADFONT; 228 229 // check selected font 230 if( !pServerFont->TestFont() ) 231 { 232 SvpGlyphCache::GetInstance().UncacheFont( *pServerFont ); 233 return SAL_SETFONT_BADFONT; 234 } 235 236 // update SalGraphics font settings 237 m_pServerFont[ nFallbackLevel ] = pServerFont; 238 return SAL_SETFONT_USEDRAWTEXTARRAY; 239 } 240 241 // --------------------------------------------------------------------------- 242 243 void SvpSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel ) 244 { 245 if( nFallbackLevel >= MAX_FALLBACK ) 246 return; 247 248 if( m_pServerFont[nFallbackLevel] != NULL ) 249 { 250 long rDummyFactor; 251 m_pServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor ); 252 } 253 } 254 255 // --------------------------------------------------------------------------- 256 257 sal_uLong SvpSalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs ) 258 { 259 sal_uLong nGotPairs = 0; 260 261 if( m_pServerFont[0] != NULL ) 262 { 263 ImplKernPairData* pTmpKernPairs = NULL; 264 nGotPairs = m_pServerFont[0]->GetKernPairs( &pTmpKernPairs ); 265 for( sal_uLong i = 0; i < nPairs && i < nGotPairs; ++i ) 266 pKernPairs[ i ] = pTmpKernPairs[ i ]; 267 delete[] pTmpKernPairs; 268 } 269 270 return nGotPairs; 271 } 272 273 // --------------------------------------------------------------------------- 274 275 const ImplFontCharMap* SvpSalGraphics::GetImplFontCharMap() const 276 { 277 if( !m_pServerFont[0] ) 278 return NULL; 279 280 const ImplFontCharMap* pIFCMap = m_pServerFont[0]->GetImplFontCharMap(); 281 return pIFCMap; 282 } 283 284 // --------------------------------------------------------------------------- 285 286 void SvpSalGraphics::GetDevFontList( ImplDevFontList* pDevFontList ) 287 { 288 GlyphCache& rGC = SvpGlyphCache::GetInstance(); 289 290 psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); 291 psp::FastPrintFontInfo aInfo; 292 ::std::list< psp::fontID > aList; 293 rMgr.getFontList( aList ); 294 ::std::list< psp::fontID >::iterator it; 295 for( it = aList.begin(); it != aList.end(); ++it ) 296 { 297 if( !rMgr.getFontFastInfo( *it, aInfo ) ) 298 continue; 299 300 // the GlyphCache must not bother with builtin fonts because 301 // it cannot access or use them anyway 302 if( aInfo.m_eType == psp::fonttype::Builtin ) 303 continue; 304 305 // normalize face number to the GlyphCache 306 int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); 307 if( nFaceNum < 0 ) 308 nFaceNum = 0; 309 310 // for fonts where extra kerning info can be provided on demand 311 // an ExtraKernInfo object is supplied 312 const ExtraKernInfo* pExtraKernInfo = NULL; 313 if( aInfo.m_eType == psp::fonttype::Type1 ) 314 pExtraKernInfo = new PspKernInfo( *it ); 315 316 // inform GlyphCache about this font provided by the PsPrint subsystem 317 ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo ); 318 aDFA.mnQuality += 4096; 319 const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); 320 rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo ); 321 } 322 323 // announce glyphcache fonts 324 rGC.AnnounceFonts( pDevFontList ); 325 } 326 327 // --------------------------------------------------------------------------- 328 329 void SvpSalGraphics::GetDevFontSubstList( OutputDevice* ) 330 {} 331 332 // --------------------------------------------------------------------------- 333 334 bool SvpSalGraphics::AddTempDevFont( ImplDevFontList*, 335 const String&, const String& ) 336 { 337 return false; 338 } 339 340 // --------------------------------------------------------------------------- 341 342 sal_Bool SvpSalGraphics::CreateFontSubset( 343 const rtl::OUString& rToFile, 344 const ImplFontData* pFont, 345 sal_Int32* pGlyphIDs, 346 sal_uInt8* pEncoding, 347 sal_Int32* pWidths, 348 int nGlyphCount, 349 FontSubsetInfo& rInfo 350 ) 351 { 352 // in this context the pFont->GetFontId() is a valid PSP 353 // font since they are the only ones left after the PDF 354 // export has filtered its list of subsettable fonts (for 355 // which this method was created). The correct way would 356 // be to have the GlyphCache search for the ImplFontData pFont 357 psp::fontID aFont = pFont->GetFontId(); 358 359 psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); 360 bool bSuccess = rMgr.createFontSubset( rInfo, 361 aFont, 362 rToFile, 363 pGlyphIDs, 364 pEncoding, 365 pWidths, 366 nGlyphCount ); 367 return bSuccess; 368 } 369 370 // --------------------------------------------------------------------------- 371 372 const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded ) 373 { 374 // in this context the pFont->GetFontId() is a valid PSP 375 // font since they are the only ones left after the PDF 376 // export has filtered its list of subsettable fonts (for 377 // which this method was created). The correct way would 378 // be to have the GlyphCache search for the ImplFontData pFont 379 psp::fontID aFont = pFont->GetFontId(); 380 return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); 381 } 382 383 // --------------------------------------------------------------------------- 384 385 const void* SvpSalGraphics::GetEmbedFontData( 386 const ImplFontData* pFont, 387 const sal_Ucs* pUnicodes, 388 sal_Int32* pWidths, 389 FontSubsetInfo& rInfo, 390 long* pDataLen 391 ) 392 { 393 // in this context the pFont->GetFontId() is a valid PSP 394 // font since they are the only ones left after the PDF 395 // export has filtered its list of subsettable fonts (for 396 // which this method was created). The correct way would 397 // be to have the GlyphCache search for the ImplFontData pFont 398 psp::fontID aFont = pFont->GetFontId(); 399 return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen ); 400 } 401 402 // --------------------------------------------------------------------------- 403 404 void SvpSalGraphics::FreeEmbedFontData( const void* pData, long nLen ) 405 { 406 PspGraphics::DoFreeEmbedFontData( pData, nLen ); 407 } 408 409 void SvpSalGraphics::GetGlyphWidths( const ImplFontData* pFont, 410 bool bVertical, 411 Int32Vector& rWidths, 412 Ucs2UIntMap& rUnicodeEnc ) 413 { 414 // in this context the pFont->GetFontId() is a valid PSP 415 // font since they are the only ones left after the PDF 416 // export has filtered its list of subsettable fonts (for 417 // which this method was created). The correct way would 418 // be to have the GlyphCache search for the ImplFontData pFont 419 psp::fontID aFont = pFont->GetFontId(); 420 PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); 421 } 422 423 // --------------------------------------------------------------------------- 424 425 sal_Bool SvpSalGraphics::GetGlyphBoundRect( long nGlyphIndex, Rectangle& rRect ) 426 { 427 int nLevel = nGlyphIndex >> GF_FONTSHIFT; 428 if( nLevel >= MAX_FALLBACK ) 429 return sal_False; 430 431 ServerFont* pSF = m_pServerFont[ nLevel ]; 432 if( !pSF ) 433 return sal_False; 434 435 nGlyphIndex &= ~GF_FONTMASK; 436 const GlyphMetric& rGM = pSF->GetGlyphMetric( nGlyphIndex ); 437 rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() ); 438 return sal_True; 439 } 440 441 // --------------------------------------------------------------------------- 442 443 sal_Bool SvpSalGraphics::GetGlyphOutline( long nGlyphIndex, B2DPolyPolygon& rPolyPoly ) 444 { 445 int nLevel = nGlyphIndex >> GF_FONTSHIFT; 446 if( nLevel >= MAX_FALLBACK ) 447 return sal_False; 448 449 const ServerFont* pSF = m_pServerFont[ nLevel ]; 450 if( !pSF ) 451 return sal_False; 452 453 nGlyphIndex &= ~GF_FONTMASK; 454 if( pSF->GetGlyphOutline( nGlyphIndex, rPolyPoly ) ) 455 return sal_True; 456 457 return sal_False; 458 } 459 460 // --------------------------------------------------------------------------- 461 462 SalLayout* SvpSalGraphics::GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ) 463 { 464 GenericSalLayout* pLayout = NULL; 465 466 if( m_pServerFont[ nFallbackLevel ] ) 467 pLayout = new ServerFontLayout( *m_pServerFont[ nFallbackLevel ] ); 468 469 return pLayout; 470 } 471 472 // --------------------------------------------------------------------------- 473 474 void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout& rSalLayout ) 475 { 476 // iterate over all glyphs in the layout 477 Point aPos; 478 sal_GlyphId nGlyphIndex; 479 SvpGlyphPeer& rGlyphPeer = SvpGlyphCache::GetInstance().GetPeer(); 480 for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &nGlyphIndex, aPos, nStart ); ) 481 { 482 int nLevel = nGlyphIndex >> GF_FONTSHIFT; 483 DBG_ASSERT( nLevel < MAX_FALLBACK, "SvpGDI: invalid glyph fallback level" ); 484 ServerFont* pSF = m_pServerFont[ nLevel ]; 485 if( !pSF ) 486 continue; 487 488 // get the glyph's alpha mask and adjust the drawing position 489 nGlyphIndex &= ~GF_FONTMASK; 490 B2IPoint aDstPoint( aPos.X(), aPos.Y() ); 491 BitmapDeviceSharedPtr aAlphaMask 492 = rGlyphPeer.GetGlyphBmp( *pSF, nGlyphIndex, m_eTextFmt, aDstPoint ); 493 if( !aAlphaMask ) // ignore empty glyphs 494 continue; 495 496 // blend text color into target using the glyph's mask 497 const B2IRange aSrcRect( B2ITuple(0,0), aAlphaMask->getSize() ); 498 m_aDevice->drawMaskedColor( m_aTextColor, aAlphaMask, aSrcRect, aDstPoint, m_aClipMap ); 499 } 500 } 501 502 // =========================================================================== 503