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