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