1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <basegfx/range/b2drange.hxx>
21 #include <basegfx/range/b2ibox.hxx>
22 #include <basegfx/polygon/b2dpolypolygon.hxx>
24 #include <basebmp/scanlineformats.hxx>
26 #include <tools/debug.hxx>
28 #include <outfont.hxx>
29 #include <impfont.hxx>
30 #include <rtl/instance.hxx>
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"
39 using namespace basegfx
;
40 using namespace basebmp
;
43 : public GlyphCachePeer
48 BitmapDeviceSharedPtr
GetGlyphBmp( ServerFont
&, int nGlyphIndex
,
49 sal_uInt32 nBmpFormat
, B2IPoint
& rTargetPos
);
52 virtual void RemovingFont( ServerFont
& );
53 virtual void RemovingGlyph( ServerFont
&, GlyphData
&, int nGlyphIndex
);
58 RawBitmap maRawBitmap
;
59 BitmapDeviceSharedPtr maBitmapDev
;
63 class SvpGlyphCache
: public GlyphCache
66 SvpGlyphCache( SvpGlyphPeer
& rPeer
) : GlyphCache( rPeer
) {}
67 SvpGlyphPeer
& GetPeer() { return reinterpret_cast<SvpGlyphPeer
&>( mrPeer
); }
68 static SvpGlyphCache
& GetInstance();
73 struct GlyphCacheHolder
76 SvpGlyphPeer
* m_pSvpGlyphPeer
;
77 SvpGlyphCache
* m_pSvpGlyphCache
;
81 m_pSvpGlyphPeer
= new SvpGlyphPeer();
82 m_pSvpGlyphCache
= new SvpGlyphCache( *m_pSvpGlyphPeer
);
86 delete m_pSvpGlyphCache
;
87 delete m_pSvpGlyphPeer
;
88 m_pSvpGlyphCache
= NULL
;
89 m_pSvpGlyphPeer
= NULL
;
91 SvpGlyphCache
& getGlyphCache()
93 return *m_pSvpGlyphCache
;
101 struct theGlyphCacheHolder
:
102 public rtl::Static
<GlyphCacheHolder
, theGlyphCacheHolder
>
106 SvpGlyphCache
& SvpGlyphCache::GetInstance()
108 return theGlyphCacheHolder::get().getGlyphCache();
112 BitmapDeviceSharedPtr
SvpGlyphPeer::GetGlyphBmp( ServerFont
& rServerFont
,
113 int nGlyphIndex
, sal_uInt32 nBmpFormat
, B2IPoint
& rTargetPos
)
115 GlyphData
& rGlyphData
= rServerFont
.GetGlyphData( nGlyphIndex
);
116 SvpGcpHelper
* pGcpHelper
= (SvpGcpHelper
*)rGlyphData
.ExtDataRef().mpData
;
118 // nothing to do if the GlyphPeer hasn't allocated resources for the glyph
119 if( rGlyphData
.ExtDataRef().meInfo
!= sal::static_int_cast
<int>(nBmpFormat
) )
121 if( rGlyphData
.ExtDataRef().meInfo
== Format::NONE
)
122 pGcpHelper
= new SvpGcpHelper
;
123 RawBitmap
& rRawBitmap
= pGcpHelper
->maRawBitmap
;
125 // get glyph bitmap in matching format
129 case Format::ONE_BIT_LSB_GREY
:
130 bFound
= rServerFont
.GetGlyphBitmap1( nGlyphIndex
, pGcpHelper
->maRawBitmap
);
132 case Format::EIGHT_BIT_GREY
:
133 bFound
= rServerFont
.GetGlyphBitmap8( nGlyphIndex
, pGcpHelper
->maRawBitmap
);
136 OSL_FAIL( "SVP GCP::GetGlyphBmp(): illegal scanline format");
137 // fall back to black&white mask
138 nBmpFormat
= Format::ONE_BIT_LSB_GREY
;
143 // return .notdef glyph if needed
144 if( !bFound
&& (nGlyphIndex
!= 0) )
147 return GetGlyphBmp( rServerFont
, 0, nBmpFormat
, rTargetPos
);
150 // construct alpha mask from raw bitmap
151 const B2IVector
aSize( rRawBitmap
.mnScanlineSize
, rRawBitmap
.mnHeight
);
152 if( aSize
.getX() && aSize
.getY() )
154 static PaletteMemorySharedVector aDummyPAL
;
155 RawMemorySharedArray
aRawPtr( rRawBitmap
.mpBits
);
156 pGcpHelper
->maBitmapDev
= createBitmapDevice( aSize
, true, nBmpFormat
, aRawPtr
, aDummyPAL
);
159 rServerFont
.SetExtended( nBmpFormat
, (void*)pGcpHelper
);
162 rTargetPos
+= B2IPoint( pGcpHelper
->maRawBitmap
.mnXOffset
, pGcpHelper
->maRawBitmap
.mnYOffset
);
163 return pGcpHelper
->maBitmapDev
;
167 void SvpGlyphPeer::RemovingFont( ServerFont
& )
169 // nothing to do: no font resources held in SvpGlyphPeer
173 void SvpGlyphPeer::RemovingGlyph( ServerFont
&, GlyphData
& rGlyphData
, int /*nGlyphIndex*/ )
175 if( rGlyphData
.ExtDataRef().mpData
!= Format::NONE
)
177 // release the glyph related resources
178 DBG_ASSERT( (rGlyphData
.ExtDataRef().meInfo
<= Format::MAX
), "SVP::RG() invalid alpha format" );
179 SvpGcpHelper
* pGcpHelper
= (SvpGcpHelper
*)rGlyphData
.ExtDataRef().mpData
;
180 delete[] pGcpHelper
->maRawBitmap
.mpBits
;
186 // PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
187 class PspKernInfo
: public ExtraKernInfo
190 PspKernInfo( int nFontId
) : ExtraKernInfo(nFontId
) {}
192 virtual void Initialize() const;
196 void PspKernInfo::Initialize() const
198 mbInitialized
= true;
200 // get the kerning pairs from psprint
201 const psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
202 typedef std::list
< psp::KernPair
> PspKernPairs
;
203 const PspKernPairs
& rKernPairs
= rMgr
.getKernPairs( mnFontId
);
204 if( rKernPairs
.empty() )
207 PspKernPairs::const_iterator it
= rKernPairs
.begin();
208 for(; it
!= rKernPairs
.end(); ++it
)
210 ImplKernPairData aKernPair
= { it
->first
, it
->second
, it
->kern_x
};
211 maUnicodeKernPairs
.insert( aKernPair
);
216 sal_uInt16
SvpSalGraphics::SetFont( FontSelectPattern
* pIFSD
, int nFallbackLevel
)
218 // release all no longer needed font resources
219 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
221 if( m_pServerFont
[i
] != NULL
)
223 // old server side font is no longer referenced
224 SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont
[i
] );
225 m_pServerFont
[i
] = NULL
;
229 // return early if there is no new font
233 // handle the request for a non-native X11-font => use the GlyphCache
234 ServerFont
* pServerFont
= SvpGlyphCache::GetInstance().CacheFont( *pIFSD
);
236 return SAL_SETFONT_BADFONT
;
238 // check selected font
239 if( !pServerFont
->TestFont() )
241 SvpGlyphCache::GetInstance().UncacheFont( *pServerFont
);
242 return SAL_SETFONT_BADFONT
;
245 // update SalGraphics font settings
246 m_pServerFont
[ nFallbackLevel
] = pServerFont
;
247 return SAL_SETFONT_USEDRAWTEXTARRAY
;
251 void SvpSalGraphics::GetFontMetric( ImplFontMetricData
* pMetric
, int nFallbackLevel
)
253 if( nFallbackLevel
>= MAX_FALLBACK
)
256 if( m_pServerFont
[nFallbackLevel
] != NULL
)
259 m_pServerFont
[nFallbackLevel
]->FetchFontMetric( *pMetric
, rDummyFactor
);
264 sal_uLong
SvpSalGraphics::GetKernPairs( sal_uLong nPairs
, ImplKernPairData
* pKernPairs
)
266 sal_uLong nGotPairs
= 0;
268 if( m_pServerFont
[0] != NULL
)
270 ImplKernPairData
* pTmpKernPairs
= NULL
;
271 nGotPairs
= m_pServerFont
[0]->GetKernPairs( &pTmpKernPairs
);
272 for( sal_uLong i
= 0; i
< nPairs
&& i
< nGotPairs
; ++i
)
273 pKernPairs
[ i
] = pTmpKernPairs
[ i
];
274 delete[] pTmpKernPairs
;
281 const ImplFontCharMap
* SvpSalGraphics::GetImplFontCharMap() const
283 if( !m_pServerFont
[0] )
286 const ImplFontCharMap
* pIFCMap
= m_pServerFont
[0]->GetImplFontCharMap();
290 bool SvpSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
292 if (!m_pServerFont
[0])
295 return m_pServerFont
[0]->GetFontCapabilities(rFontCapabilities
);
299 void SvpSalGraphics::GetDevFontList( ImplDevFontList
* pDevFontList
)
301 GlyphCache
& rGC
= SvpGlyphCache::GetInstance();
303 psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
304 psp::FastPrintFontInfo aInfo
;
305 ::std::list
< psp::fontID
> aList
;
306 rMgr
.getFontList( aList
);
307 ::std::list
< psp::fontID
>::iterator it
;
308 for( it
= aList
.begin(); it
!= aList
.end(); ++it
)
310 if( !rMgr
.getFontFastInfo( *it
, aInfo
) )
313 // the GlyphCache must not bother with builtin fonts because
314 // it cannot access or use them anyway
315 if( aInfo
.m_eType
== psp::fonttype::Builtin
)
318 // normalize face number to the GlyphCache
319 int nFaceNum
= rMgr
.getFontFaceNumber( aInfo
.m_nID
);
321 // for fonts where extra kerning info can be provided on demand
322 // an ExtraKernInfo object is supplied
323 const ExtraKernInfo
* pExtraKernInfo
= NULL
;
324 if( aInfo
.m_eType
== psp::fonttype::Type1
)
325 pExtraKernInfo
= new PspKernInfo( *it
);
327 // inform GlyphCache about this font provided by the PsPrint subsystem
328 ImplDevFontAttributes aDFA
= GenPspGraphics::Info2DevFontAttributes( aInfo
);
329 aDFA
.mnQuality
+= 4096;
330 const OString
& rFileName
= rMgr
.getFontFileSysPath( aInfo
.m_nID
);
331 rGC
.AddFontFile( rFileName
, nFaceNum
, aInfo
.m_nID
, aDFA
, pExtraKernInfo
);
334 // announce glyphcache fonts
335 rGC
.AnnounceFonts( pDevFontList
);
337 // register platform specific font substitutions if available
338 SalGenericInstance::RegisterFontSubstitutors( pDevFontList
);
340 ImplGetSVData()->maGDIData
.mbNativeFontConfig
= true;
343 void SvpSalGraphics::ClearDevFontCache()
345 GlyphCache
& rGC
= SvpGlyphCache::GetInstance();
346 rGC
.ClearFontCache();
350 void SvpSalGraphics::GetDevFontSubstList( OutputDevice
* )
354 bool SvpSalGraphics::AddTempDevFont( ImplDevFontList
*,
355 const OUString
&, const OUString
& )
361 sal_Bool
SvpSalGraphics::CreateFontSubset(
362 const OUString
& rToFile
,
363 const PhysicalFontFace
* pFont
,
364 sal_Int32
* pGlyphIDs
,
365 sal_uInt8
* pEncoding
,
368 FontSubsetInfo
& rInfo
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 psp::fontID aFont
= pFont
->GetFontId();
378 psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
379 bool bSuccess
= rMgr
.createFontSubset( rInfo
,
390 const Ucs2SIntMap
* SvpSalGraphics::GetFontEncodingVector( const PhysicalFontFace
* pFont
, const Ucs2OStrMap
** pNonEncoded
)
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 psp::fontID aFont
= pFont
->GetFontId();
398 return GenPspGraphics::DoGetFontEncodingVector( aFont
, pNonEncoded
);
402 const void* SvpSalGraphics::GetEmbedFontData(
403 const PhysicalFontFace
* pFont
,
404 const sal_Ucs
* pUnicodes
,
406 FontSubsetInfo
& rInfo
,
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 psp::fontID aFont
= pFont
->GetFontId();
416 return GenPspGraphics::DoGetEmbedFontData( aFont
, pUnicodes
, pWidths
, rInfo
, pDataLen
);
420 void SvpSalGraphics::FreeEmbedFontData( const void* pData
, long nLen
)
422 GenPspGraphics::DoFreeEmbedFontData( pData
, nLen
);
425 void SvpSalGraphics::GetGlyphWidths( const PhysicalFontFace
* pFont
,
427 Int32Vector
& rWidths
,
428 Ucs2UIntMap
& rUnicodeEnc
)
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 psp::fontID aFont
= pFont
->GetFontId();
436 GenPspGraphics::DoGetGlyphWidths( aFont
, bVertical
, rWidths
, rUnicodeEnc
);
440 sal_Bool
SvpSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphIndex
, Rectangle
& rRect
)
442 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
443 if( nLevel
>= MAX_FALLBACK
)
446 ServerFont
* pSF
= m_pServerFont
[ nLevel
];
450 nGlyphIndex
&= GF_IDXMASK
;
451 const GlyphMetric
& rGM
= pSF
->GetGlyphMetric( nGlyphIndex
);
452 rRect
= Rectangle( rGM
.GetOffset(), rGM
.GetSize() );
457 sal_Bool
SvpSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphIndex
, B2DPolyPolygon
& rPolyPoly
)
459 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
460 if( nLevel
>= MAX_FALLBACK
)
463 const ServerFont
* pSF
= m_pServerFont
[ nLevel
];
467 nGlyphIndex
&= GF_IDXMASK
;
468 if( pSF
->GetGlyphOutline( nGlyphIndex
, rPolyPoly
) )
475 SalLayout
* SvpSalGraphics::GetTextLayout( ImplLayoutArgs
&, int nFallbackLevel
)
477 GenericSalLayout
* pLayout
= NULL
;
479 if( m_pServerFont
[ nFallbackLevel
] )
480 pLayout
= new ServerFontLayout( *m_pServerFont
[ nFallbackLevel
] );
486 void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout
& rSalLayout
)
488 // iterate over all glyphs in the layout
490 sal_GlyphId nGlyphIndex
;
491 SvpGlyphPeer
& rGlyphPeer
= SvpGlyphCache::GetInstance().GetPeer();
492 for( int nStart
= 0; rSalLayout
.GetNextGlyphs( 1, &nGlyphIndex
, aPos
, nStart
); )
494 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
495 DBG_ASSERT( nLevel
< MAX_FALLBACK
, "SvpGDI: invalid glyph fallback level" );
496 ServerFont
* pSF
= m_pServerFont
[ nLevel
];
500 // get the glyph's alpha mask and adjust the drawing position
501 nGlyphIndex
&= GF_IDXMASK
;
502 B2IPoint
aDstPoint( aPos
.X(), aPos
.Y() );
503 BitmapDeviceSharedPtr aAlphaMask
504 = rGlyphPeer
.GetGlyphBmp( *pSF
, nGlyphIndex
, m_eTextFmt
, aDstPoint
);
505 if( !aAlphaMask
) // ignore empty glyphs
508 // blend text color into target using the glyph's mask
509 const B2IBox
aSrcRect( B2ITuple(0,0), aAlphaMask
->getSize() );
510 const B2IBox
aClipRect( aDstPoint
, aAlphaMask
->getSize() );
512 SvpSalGraphics::ClipUndoHandle
aUndo( this );
513 if( !isClippedSetup( aClipRect
, aUndo
) )
514 m_aDevice
->drawMaskedColor( m_aTextColor
, aAlphaMask
,
515 aSrcRect
, aDstPoint
, m_aClipMap
);
519 void SvpSalGraphics::SetTextColor( SalColor nSalColor
)
521 m_aTextColor
= basebmp::Color( nSalColor
);
524 SystemFontData
SvpSalGraphics::GetSysFontData( int nFallbacklevel
) const
526 SystemFontData aSysFontData
;
528 if (nFallbacklevel
>= MAX_FALLBACK
) nFallbacklevel
= MAX_FALLBACK
- 1;
529 if (nFallbacklevel
< 0 ) nFallbacklevel
= 0;
531 aSysFontData
.nSize
= sizeof( SystemFontData
);
532 aSysFontData
.nFontId
= 0;
533 aSysFontData
.nFontFlags
= 0;
534 aSysFontData
.bFakeBold
= false;
535 aSysFontData
.bFakeItalic
= false;
536 aSysFontData
.bAntialias
= true;
540 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */