xref: /aoo42x/main/vcl/unx/headless/svptext.cxx (revision cdf0e10c)
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