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