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 <sal/types.h>
21 :
22 : #include <cassert>
23 :
24 : #include <basebmp/scanlineformats.hxx>
25 : #include <basegfx/polygon/b2dpolypolygon.hxx>
26 : #include <basegfx/range/b2drange.hxx>
27 : #include <basegfx/range/b2ibox.hxx>
28 : #include <rtl/instance.hxx>
29 : #include <tools/debug.hxx>
30 : #include <vcl/sysdata.hxx>
31 :
32 : #include "generic/geninst.h"
33 : #include "generic/genpspgraphics.h"
34 : #include "generic/glyphcache.hxx"
35 : #include "headless/svpbmp.hxx"
36 : #include "headless/svpgdi.hxx"
37 : #include "impfont.hxx"
38 : #include "outfont.hxx"
39 : #include "PhysicalFontFace.hxx"
40 :
41 : class PhysicalFontCollection;
42 :
43 : using namespace basegfx;
44 : using namespace basebmp;
45 :
46 0 : class SvpGlyphPeer : public GlyphCachePeer
47 : {
48 : public:
49 0 : SvpGlyphPeer() {}
50 :
51 : BitmapDeviceSharedPtr GetGlyphBmp( ServerFont&, sal_GlyphId,
52 : basebmp::Format nBmpFormat, B2IPoint& rTargetPos );
53 :
54 : protected:
55 : virtual void RemovingFont( ServerFont& ) SAL_OVERRIDE;
56 : virtual void RemovingGlyph( GlyphData& ) SAL_OVERRIDE;
57 :
58 0 : class SvpGcpHelper
59 : {
60 : public:
61 : RawBitmap maRawBitmap;
62 : BitmapDeviceSharedPtr maBitmapDev;
63 : };
64 : };
65 :
66 0 : class SvpGlyphCache : public GlyphCache
67 : {
68 : public:
69 0 : SvpGlyphCache( SvpGlyphPeer& rPeer ) : GlyphCache( rPeer) {}
70 0 : 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 0 : GlyphCacheHolder()
83 : {
84 0 : m_pSvpGlyphPeer = new SvpGlyphPeer();
85 0 : m_pSvpGlyphCache = new SvpGlyphCache( *m_pSvpGlyphPeer );
86 0 : }
87 0 : void release()
88 : {
89 0 : delete m_pSvpGlyphCache;
90 0 : delete m_pSvpGlyphPeer;
91 0 : m_pSvpGlyphCache = NULL;
92 0 : m_pSvpGlyphPeer = NULL;
93 0 : }
94 0 : SvpGlyphCache& getGlyphCache()
95 : {
96 0 : return *m_pSvpGlyphCache;
97 : }
98 0 : ~GlyphCacheHolder()
99 : {
100 0 : release();
101 0 : }
102 : };
103 :
104 : struct theGlyphCacheHolder :
105 : public rtl::Static<GlyphCacheHolder, theGlyphCacheHolder>
106 : {};
107 : }
108 :
109 0 : SvpGlyphCache& SvpGlyphCache::GetInstance()
110 : {
111 0 : return theGlyphCacheHolder::get().getGlyphCache();
112 : }
113 :
114 0 : BitmapDeviceSharedPtr SvpGlyphPeer::GetGlyphBmp( ServerFont& rServerFont,
115 : sal_GlyphId aGlyphId, basebmp::Format nBmpFormat, B2IPoint& rTargetPos )
116 : {
117 0 : GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId );
118 :
119 0 : if( rGlyphData.ExtDataRef().meInfo != nBmpFormat )
120 : {
121 : SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
122 0 : rGlyphData.ExtDataRef().mpData);
123 0 : bool bNew = pGcpHelper == 0;
124 0 : if( bNew )
125 0 : pGcpHelper = new SvpGcpHelper;
126 :
127 : // get glyph bitmap in matching format
128 0 : bool bFound = false;
129 0 : switch( nBmpFormat )
130 : {
131 : case FORMAT_ONE_BIT_LSB_GREY:
132 0 : bFound = rServerFont.GetGlyphBitmap1( aGlyphId, pGcpHelper->maRawBitmap );
133 0 : break;
134 : case FORMAT_EIGHT_BIT_GREY:
135 0 : bFound = rServerFont.GetGlyphBitmap8( aGlyphId, pGcpHelper->maRawBitmap );
136 0 : break;
137 : default:
138 : OSL_FAIL( "SVP GCP::GetGlyphBmp(): illegal scanline format");
139 : // fall back to black&white mask
140 0 : nBmpFormat = FORMAT_ONE_BIT_LSB_GREY;
141 0 : bFound = false;
142 0 : break;
143 : }
144 :
145 : // return .notdef glyph if needed
146 0 : if( !bFound && (aGlyphId != 0) )
147 : {
148 0 : if( bNew )
149 0 : delete pGcpHelper;
150 0 : return GetGlyphBmp( rServerFont, 0, nBmpFormat, rTargetPos );
151 : }
152 :
153 : // construct alpha mask from raw bitmap
154 : const B2IVector aSize(
155 : pGcpHelper->maRawBitmap.mnScanlineSize,
156 0 : pGcpHelper->maRawBitmap.mnHeight );
157 0 : if( aSize.getX() && aSize.getY() )
158 : {
159 0 : static PaletteMemorySharedVector aDummyPAL;
160 0 : pGcpHelper->maBitmapDev = createBitmapDevice( aSize, true, nBmpFormat, pGcpHelper->maRawBitmap.mpBits, aDummyPAL );
161 : }
162 :
163 0 : rGlyphData.ExtDataRef().meInfo = nBmpFormat;
164 0 : rGlyphData.ExtDataRef().mpData = pGcpHelper;
165 : }
166 :
167 : SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
168 0 : rGlyphData.ExtDataRef().mpData);
169 : assert(pGcpHelper != 0);
170 0 : rTargetPos += B2IPoint( pGcpHelper->maRawBitmap.mnXOffset, pGcpHelper->maRawBitmap.mnYOffset );
171 0 : return pGcpHelper->maBitmapDev;
172 : }
173 :
174 0 : void SvpGlyphPeer::RemovingFont( ServerFont& )
175 : {
176 : // nothing to do: no font resources held in SvpGlyphPeer
177 0 : }
178 :
179 0 : void SvpGlyphPeer::RemovingGlyph( GlyphData& rGlyphData )
180 : {
181 : SvpGcpHelper* pGcpHelper = static_cast<SvpGcpHelper*>(
182 0 : rGlyphData.ExtDataRef().mpData);
183 0 : rGlyphData.ExtDataRef().meInfo = basebmp::FORMAT_NONE;
184 0 : rGlyphData.ExtDataRef().mpData = 0;
185 0 : delete pGcpHelper;
186 0 : }
187 :
188 0 : sal_uInt16 SvpSalGraphics::SetFont( FontSelectPattern* pIFSD, int nFallbackLevel )
189 : {
190 : // release all no longer needed font resources
191 0 : for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
192 : {
193 0 : if( m_pServerFont[i] != NULL )
194 : {
195 : // old server side font is no longer referenced
196 0 : SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] );
197 0 : m_pServerFont[i] = NULL;
198 : }
199 : }
200 :
201 : // return early if there is no new font
202 0 : if( !pIFSD )
203 0 : return 0;
204 :
205 : // handle the request for a non-native X11-font => use the GlyphCache
206 0 : ServerFont* pServerFont = SvpGlyphCache::GetInstance().CacheFont( *pIFSD );
207 0 : if( !pServerFont )
208 0 : return SAL_SETFONT_BADFONT;
209 :
210 : // check selected font
211 0 : if( !pServerFont->TestFont() )
212 : {
213 0 : SvpGlyphCache::GetInstance().UncacheFont( *pServerFont );
214 0 : return SAL_SETFONT_BADFONT;
215 : }
216 :
217 : // update SalGraphics font settings
218 0 : m_pServerFont[ nFallbackLevel ] = pServerFont;
219 0 : return SAL_SETFONT_USEDRAWTEXTARRAY;
220 : }
221 :
222 0 : void SvpSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel )
223 : {
224 0 : if( nFallbackLevel >= MAX_FALLBACK )
225 0 : return;
226 :
227 0 : if( m_pServerFont[nFallbackLevel] != NULL )
228 : {
229 : long rDummyFactor;
230 0 : m_pServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor );
231 : }
232 : }
233 :
234 0 : const ImplFontCharMap* SvpSalGraphics::GetImplFontCharMap() const
235 : {
236 0 : if( !m_pServerFont[0] )
237 0 : return NULL;
238 :
239 0 : const ImplFontCharMap* pIFCMap = m_pServerFont[0]->GetImplFontCharMap();
240 0 : return pIFCMap;
241 : }
242 :
243 0 : bool SvpSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
244 : {
245 0 : if (!m_pServerFont[0])
246 0 : return false;
247 :
248 0 : return m_pServerFont[0]->GetFontCapabilities(rFontCapabilities);
249 : }
250 :
251 0 : void SvpSalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection )
252 : {
253 0 : GlyphCache& rGC = SvpGlyphCache::GetInstance();
254 :
255 0 : psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
256 0 : psp::FastPrintFontInfo aInfo;
257 0 : ::std::list< psp::fontID > aList;
258 0 : rMgr.getFontList( aList );
259 0 : ::std::list< psp::fontID >::iterator it;
260 0 : for( it = aList.begin(); it != aList.end(); ++it )
261 : {
262 0 : if( !rMgr.getFontFastInfo( *it, aInfo ) )
263 0 : continue;
264 :
265 : // normalize face number to the GlyphCache
266 0 : int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID );
267 :
268 : // inform GlyphCache about this font provided by the PsPrint subsystem
269 0 : ImplDevFontAttributes aDFA = GenPspGraphics::Info2DevFontAttributes( aInfo );
270 0 : aDFA.mnQuality += 4096;
271 0 : const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID );
272 0 : rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA );
273 0 : }
274 :
275 : // announce glyphcache fonts
276 0 : rGC.AnnounceFonts( pFontCollection );
277 :
278 : // register platform specific font substitutions if available
279 0 : SalGenericInstance::RegisterFontSubstitutors( pFontCollection );
280 :
281 0 : ImplGetSVData()->maGDIData.mbNativeFontConfig = true;
282 0 : }
283 :
284 0 : void SvpSalGraphics::ClearDevFontCache()
285 : {
286 0 : GlyphCache& rGC = SvpGlyphCache::GetInstance();
287 0 : rGC.ClearFontCache();
288 0 : }
289 :
290 0 : bool SvpSalGraphics::AddTempDevFont( PhysicalFontCollection*,
291 : const OUString&, const OUString& )
292 : {
293 0 : return false;
294 : }
295 :
296 0 : bool SvpSalGraphics::CreateFontSubset(
297 : const OUString& rToFile,
298 : const PhysicalFontFace* pFont,
299 : sal_GlyphId* pGlyphIds,
300 : sal_uInt8* pEncoding,
301 : sal_Int32* pWidths,
302 : int nGlyphCount,
303 : FontSubsetInfo& rInfo
304 : )
305 : {
306 : // in this context the pFont->GetFontId() is a valid PSP
307 : // font since they are the only ones left after the PDF
308 : // export has filtered its list of subsettable fonts (for
309 : // which this method was created). The correct way would
310 : // be to have the GlyphCache search for the PhysicalFontFace pFont
311 0 : psp::fontID aFont = pFont->GetFontId();
312 :
313 0 : psp::PrintFontManager& rMgr = psp::PrintFontManager::get();
314 : bool bSuccess = rMgr.createFontSubset( rInfo,
315 : aFont,
316 : rToFile,
317 : pGlyphIds,
318 : pEncoding,
319 : pWidths,
320 0 : nGlyphCount );
321 0 : return bSuccess;
322 : }
323 :
324 0 : const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded )
325 : {
326 : // in this context the pFont->GetFontId() is a valid PSP
327 : // font since they are the only ones left after the PDF
328 : // export has filtered its list of subsettable fonts (for
329 : // which this method was created). The correct way would
330 : // be to have the GlyphCache search for the PhysicalFontFace pFont
331 0 : psp::fontID aFont = pFont->GetFontId();
332 0 : return GenPspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded );
333 : }
334 :
335 0 : const void* SvpSalGraphics::GetEmbedFontData(
336 : const PhysicalFontFace* pFont,
337 : const sal_Ucs* pUnicodes,
338 : sal_Int32* pWidths,
339 : FontSubsetInfo& rInfo,
340 : long* pDataLen
341 : )
342 : {
343 : // in this context the pFont->GetFontId() is a valid PSP
344 : // font since they are the only ones left after the PDF
345 : // export has filtered its list of subsettable fonts (for
346 : // which this method was created). The correct way would
347 : // be to have the GlyphCache search for the PhysicalFontFace pFont
348 0 : psp::fontID aFont = pFont->GetFontId();
349 0 : return GenPspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen );
350 : }
351 :
352 0 : void SvpSalGraphics::FreeEmbedFontData( const void* pData, long nLen )
353 : {
354 0 : GenPspGraphics::DoFreeEmbedFontData( pData, nLen );
355 0 : }
356 :
357 0 : void SvpSalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont,
358 : bool bVertical,
359 : Int32Vector& rWidths,
360 : Ucs2UIntMap& rUnicodeEnc )
361 : {
362 : // in this context the pFont->GetFontId() is a valid PSP
363 : // font since they are the only ones left after the PDF
364 : // export has filtered its list of subsettable fonts (for
365 : // which this method was created). The correct way would
366 : // be to have the GlyphCache search for the PhysicalFontFace pFont
367 0 : psp::fontID aFont = pFont->GetFontId();
368 0 : GenPspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc );
369 0 : }
370 :
371 0 : bool SvpSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect )
372 : {
373 0 : const int nLevel = aGlyphId >> GF_FONTSHIFT;
374 0 : if( nLevel >= MAX_FALLBACK )
375 0 : return false;
376 :
377 0 : ServerFont* pSF = m_pServerFont[ nLevel ];
378 0 : if( !pSF )
379 0 : return false;
380 :
381 0 : aGlyphId &= GF_IDXMASK;
382 0 : const GlyphMetric& rGM = pSF->GetGlyphMetric( aGlyphId );
383 0 : rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() );
384 0 : return true;
385 : }
386 :
387 0 : bool SvpSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, B2DPolyPolygon& rPolyPoly )
388 : {
389 0 : const int nLevel = aGlyphId >> GF_FONTSHIFT;
390 0 : if( nLevel >= MAX_FALLBACK )
391 0 : return false;
392 :
393 0 : const ServerFont* pSF = m_pServerFont[ nLevel ];
394 0 : if( !pSF )
395 0 : return false;
396 :
397 0 : aGlyphId &= GF_IDXMASK;
398 0 : if( pSF->GetGlyphOutline( aGlyphId, rPolyPoly ) )
399 0 : return true;
400 :
401 0 : return false;
402 : }
403 :
404 0 : SalLayout* SvpSalGraphics::GetTextLayout( ImplLayoutArgs&, int nFallbackLevel )
405 : {
406 0 : GenericSalLayout* pLayout = NULL;
407 :
408 0 : if( m_pServerFont[ nFallbackLevel ] )
409 0 : pLayout = new ServerFontLayout( *m_pServerFont[ nFallbackLevel ] );
410 :
411 0 : return pLayout;
412 : }
413 :
414 0 : void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout& rSalLayout )
415 : {
416 : // iterate over all glyphs in the layout
417 0 : Point aPos;
418 : sal_GlyphId aGlyphId;
419 0 : SvpGlyphPeer& rGlyphPeer = SvpGlyphCache::GetInstance().GetPeer();
420 0 : for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); )
421 : {
422 0 : int nLevel = aGlyphId >> GF_FONTSHIFT;
423 : DBG_ASSERT( nLevel < MAX_FALLBACK, "SvpGDI: invalid glyph fallback level" );
424 0 : ServerFont* pSF = m_pServerFont[ nLevel ];
425 0 : if( !pSF )
426 0 : continue;
427 :
428 : // get the glyph's alpha mask and adjust the drawing position
429 0 : aGlyphId &= GF_IDXMASK;
430 0 : B2IPoint aDstPoint( aPos.X(), aPos.Y() );
431 : BitmapDeviceSharedPtr aAlphaMask
432 0 : = rGlyphPeer.GetGlyphBmp( *pSF, aGlyphId, m_eTextFmt, aDstPoint );
433 0 : if( !aAlphaMask ) // ignore empty glyphs
434 0 : continue;
435 :
436 : // blend text color into target using the glyph's mask
437 0 : const B2IBox aSrcRect( B2ITuple(0,0), aAlphaMask->getSize() );
438 0 : const B2IBox aClipRect( aDstPoint, aAlphaMask->getSize() );
439 :
440 0 : SvpSalGraphics::ClipUndoHandle aUndo( this );
441 0 : if( !isClippedSetup( aClipRect, aUndo ) )
442 : m_aDevice->drawMaskedColor( m_aTextColor, aAlphaMask,
443 0 : aSrcRect, aDstPoint, m_aClipMap );
444 0 : }
445 0 : }
446 :
447 0 : void SvpSalGraphics::SetTextColor( SalColor nSalColor )
448 : {
449 0 : m_aTextColor = basebmp::Color( nSalColor );
450 0 : }
451 :
452 0 : SystemFontData SvpSalGraphics::GetSysFontData( int nFallbacklevel ) const
453 : {
454 0 : SystemFontData aSysFontData;
455 :
456 0 : if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1;
457 0 : if (nFallbacklevel < 0 ) nFallbacklevel = 0;
458 :
459 0 : aSysFontData.nSize = sizeof( SystemFontData );
460 0 : aSysFontData.nFontId = 0;
461 0 : aSysFontData.nFontFlags = 0;
462 0 : aSysFontData.bFakeBold = false;
463 0 : aSysFontData.bFakeItalic = false;
464 0 : aSysFontData.bAntialias = true;
465 0 : return aSysFontData;
466 3 : }
467 :
468 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|