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