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