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