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:
SvpGlyphPeer()53 SvpGlyphPeer() {}
54
55 BitmapDeviceSharedPtr GetGlyphBmp( ServerFont&, sal_GlyphId,
56 sal_uInt32 nBmpFormat, B2IPoint& rTargetPos );
57
58 protected:
59 virtual void RemovingFont( ServerFont& );
60 virtual void RemovingGlyph( ServerFont&, GlyphData&, sal_GlyphId );
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:
GetPeer()75 SvpGlyphPeer& GetPeer() { return reinterpret_cast<SvpGlyphPeer&>( mrPeer ); }
76 static SvpGlyphCache& GetInstance();
77 private:
SvpGlyphCache(SvpGlyphPeer & rPeer)78 SvpGlyphCache( SvpGlyphPeer& rPeer ) : GlyphCache( rPeer) {}
79 };
80
81 //--------------------------------------------------------------------------
82
GetInstance()83 SvpGlyphCache& SvpGlyphCache::GetInstance()
84 {
85 static SvpGlyphPeer aSvpGlyphPeer;
86 static SvpGlyphCache aGC( aSvpGlyphPeer );
87 return aGC;
88 }
89
90 // ===========================================================================
91
GetGlyphBmp(ServerFont & rServerFont,sal_GlyphId aGlyphId,sal_uInt32 nBmpFormat,B2IPoint & rTargetPos)92 BitmapDeviceSharedPtr SvpGlyphPeer::GetGlyphBmp( ServerFont& rServerFont,
93 sal_GlyphId aGlyphId, sal_uInt32 nBmpFormat, B2IPoint& rTargetPos )
94 {
95 GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId );
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( aGlyphId, pGcpHelper->maRawBitmap );
111 break;
112 case Format::EIGHT_BIT_GREY:
113 bFound = rServerFont.GetGlyphBitmap8( aGlyphId, 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 && (aGlyphId != 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
RemovingFont(ServerFont &)148 void SvpGlyphPeer::RemovingFont( ServerFont& )
149 {
150 // nothing to do: no font resources held in SvpGlyphPeer
151 }
152
153 //--------------------------------------------------------------------------
154
RemovingGlyph(ServerFont &,GlyphData & rGlyphData,sal_GlyphId)155 void SvpGlyphPeer::RemovingGlyph( ServerFont&, GlyphData& rGlyphData, sal_GlyphId /*aGlyphId*/ )
156 {
157 if( rGlyphData.ExtDataRef().mpData != NULL )
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:
PspKernInfo(int nFontId)173 PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {}
174 protected:
175 virtual void Initialize() const;
176 };
177
178 //--------------------------------------------------------------------------
179
Initialize() const180 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
SetFont(ImplFontSelectData * pIFSD,int nFallbackLevel)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
GetFontMetric(ImplFontMetricData * pMetric,int nFallbackLevel)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
GetKernPairs(sal_uLong nPairs,ImplKernPairData * pKernPairs)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
GetImplFontCharMap() const271 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
GetDevFontList(ImplDevFontList * pDevFontList)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
GetDevFontSubstList(OutputDevice *)325 void SvpSalGraphics::GetDevFontSubstList( OutputDevice* )
326 {}
327
328 // ---------------------------------------------------------------------------
329
AddTempDevFont(ImplDevFontList *,const String &,const String &)330 bool SvpSalGraphics::AddTempDevFont( ImplDevFontList*,
331 const String&, const String& )
332 {
333 return false;
334 }
335
336 // ---------------------------------------------------------------------------
337
CreateFontSubset(const rtl::OUString & rToFile,const ImplFontData * pFont,sal_GlyphId * pGlyphIds,sal_uInt8 * pEncoding,sal_Int32 * pWidths,int nGlyphCount,FontSubsetInfo & rInfo)338 sal_Bool SvpSalGraphics::CreateFontSubset(
339 const rtl::OUString& rToFile,
340 const ImplFontData* pFont,
341 sal_GlyphId* 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
GetFontEncodingVector(const ImplFontData * pFont,const Ucs2OStrMap ** pNonEncoded)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
GetEmbedFontData(const ImplFontData * pFont,const sal_Ucs * pUnicodes,sal_Int32 * pWidths,FontSubsetInfo & rInfo,long * pDataLen)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
FreeEmbedFontData(const void * pData,long nLen)400 void SvpSalGraphics::FreeEmbedFontData( const void* pData, long nLen )
401 {
402 PspGraphics::DoFreeEmbedFontData( pData, nLen );
403 }
404
GetGlyphWidths(const ImplFontData * pFont,bool bVertical,Int32Vector & rWidths,Ucs2UIntMap & rUnicodeEnc)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
GetGlyphBoundRect(sal_GlyphId aGlyphId,Rectangle & rRect)421 bool SvpSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect )
422 {
423 const int nLevel = aGlyphId >> GF_FONTSHIFT;
424 if( nLevel >= MAX_FALLBACK )
425 return false;
426
427 ServerFont* pSF = m_pServerFont[ nLevel ];
428 if( !pSF )
429 return false;
430
431 aGlyphId &= ~GF_FONTMASK;
432 const GlyphMetric& rGM = pSF->GetGlyphMetric( aGlyphId );
433 rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
434 return true;
435 }
436
437 // ---------------------------------------------------------------------------
438
GetGlyphOutline(sal_GlyphId aGlyphId,B2DPolyPolygon & rPolyPoly)439 bool SvpSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, B2DPolyPolygon& rPolyPoly )
440 {
441 const int nLevel = aGlyphId >> GF_FONTSHIFT;
442 if( nLevel >= MAX_FALLBACK )
443 return false;
444
445 const ServerFont* pSF = m_pServerFont[ nLevel ];
446 if( !pSF )
447 return false;
448
449 aGlyphId &= ~GF_FONTMASK;
450 bool bOK = pSF->GetGlyphOutline( aGlyphId, rPolyPoly );
451 return bOK;
452 }
453
454 // ---------------------------------------------------------------------------
455
GetTextLayout(ImplLayoutArgs &,int nFallbackLevel)456 SalLayout* SvpSalGraphics::GetTextLayout( ImplLayoutArgs&, int nFallbackLevel )
457 {
458 GenericSalLayout* pLayout = NULL;
459
460 if( m_pServerFont[ nFallbackLevel ] )
461 pLayout = new ServerFontLayout( *m_pServerFont[ nFallbackLevel ] );
462
463 return pLayout;
464 }
465
466 // ---------------------------------------------------------------------------
467
DrawServerFontLayout(const ServerFontLayout & rSalLayout)468 void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout& rSalLayout )
469 {
470 // iterate over all glyphs in the layout
471 Point aPos;
472 sal_GlyphId aGlyphId;
473 SvpGlyphPeer& rGlyphPeer = SvpGlyphCache::GetInstance().GetPeer();
474 for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
475 {
476 int nLevel = aGlyphId >> GF_FONTSHIFT;
477 DBG_ASSERT( nLevel < MAX_FALLBACK, "SvpGDI: invalid glyph fallback level" );
478 ServerFont* pSF = m_pServerFont[ nLevel ];
479 if( !pSF )
480 continue;
481
482 // get the glyph's alpha mask and adjust the drawing position
483 aGlyphId &= ~GF_FONTMASK;
484 B2IPoint aDstPoint( aPos.X(), aPos.Y() );
485 BitmapDeviceSharedPtr aAlphaMask
486 = rGlyphPeer.GetGlyphBmp( *pSF, aGlyphId, m_eTextFmt, aDstPoint );
487 if( !aAlphaMask ) // ignore empty glyphs
488 continue;
489
490 // blend text color into target using the glyph's mask
491 const B2IRange aSrcRect( B2ITuple(0,0), aAlphaMask->getSize() );
492 m_aDevice->drawMaskedColor( m_aTextColor, aAlphaMask, aSrcRect, aDstPoint, m_aClipMap );
493 }
494 }
495
496 // ===========================================================================
497