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 "generic/geninst.h"
33 #include "generic/genpspgraphics.h"
34 #include "generic/glyphcache.hxx"
35 #include "headless/svpgdi.hxx"
36 #include "headless/svpbmp.hxx"
38 using namespace basegfx
;
39 using namespace basebmp
;
41 // ===========================================================================
44 : public GlyphCachePeer
49 BitmapDeviceSharedPtr
GetGlyphBmp( ServerFont
&, int nGlyphIndex
,
50 sal_uInt32 nBmpFormat
, B2IPoint
& rTargetPos
);
53 virtual void RemovingFont( ServerFont
& );
54 virtual void RemovingGlyph( ServerFont
&, GlyphData
&, int nGlyphIndex
);
59 RawBitmap maRawBitmap
;
60 BitmapDeviceSharedPtr maBitmapDev
;
64 // ===========================================================================
66 class SvpGlyphCache
: public GlyphCache
69 SvpGlyphCache( SvpGlyphPeer
& rPeer
) : GlyphCache( rPeer
) {}
70 SvpGlyphPeer
& GetPeer() { return reinterpret_cast<SvpGlyphPeer
&>( mrPeer
); }
71 static SvpGlyphCache
& GetInstance();
76 struct GlyphCacheHolder
79 SvpGlyphPeer
* m_pSvpGlyphPeer
;
80 SvpGlyphCache
* m_pSvpGlyphCache
;
84 m_pSvpGlyphPeer
= new SvpGlyphPeer();
85 m_pSvpGlyphCache
= new SvpGlyphCache( *m_pSvpGlyphPeer
);
89 delete m_pSvpGlyphCache
;
90 delete m_pSvpGlyphPeer
;
91 m_pSvpGlyphCache
= NULL
;
92 m_pSvpGlyphPeer
= NULL
;
94 SvpGlyphCache
& getGlyphCache()
96 return *m_pSvpGlyphCache
;
104 struct theGlyphCacheHolder
:
105 public rtl::Static
<GlyphCacheHolder
, theGlyphCacheHolder
>
109 SvpGlyphCache
& SvpGlyphCache::GetInstance()
111 return theGlyphCacheHolder::get().getGlyphCache();
114 // ===========================================================================
116 BitmapDeviceSharedPtr
SvpGlyphPeer::GetGlyphBmp( ServerFont
& rServerFont
,
117 int nGlyphIndex
, sal_uInt32 nBmpFormat
, B2IPoint
& rTargetPos
)
119 GlyphData
& rGlyphData
= rServerFont
.GetGlyphData( nGlyphIndex
);
120 SvpGcpHelper
* pGcpHelper
= (SvpGcpHelper
*)rGlyphData
.ExtDataRef().mpData
;
122 // nothing to do if the GlyphPeer hasn't allocated resources for the glyph
123 if( rGlyphData
.ExtDataRef().meInfo
!= sal::static_int_cast
<int>(nBmpFormat
) )
125 if( rGlyphData
.ExtDataRef().meInfo
== Format::NONE
)
126 pGcpHelper
= new SvpGcpHelper
;
127 RawBitmap
& rRawBitmap
= pGcpHelper
->maRawBitmap
;
129 // get glyph bitmap in matching format
133 case Format::ONE_BIT_LSB_GREY
:
134 bFound
= rServerFont
.GetGlyphBitmap1( nGlyphIndex
, pGcpHelper
->maRawBitmap
);
136 case Format::EIGHT_BIT_GREY
:
137 bFound
= rServerFont
.GetGlyphBitmap8( nGlyphIndex
, pGcpHelper
->maRawBitmap
);
140 OSL_FAIL( "SVP GCP::GetGlyphBmp(): illegal scanline format");
141 // fall back to black&white mask
142 nBmpFormat
= Format::ONE_BIT_LSB_GREY
;
147 // return .notdef glyph if needed
148 if( !bFound
&& (nGlyphIndex
!= 0) )
151 return GetGlyphBmp( rServerFont
, 0, nBmpFormat
, rTargetPos
);
154 // construct alpha mask from raw bitmap
155 const B2IVector
aSize( rRawBitmap
.mnScanlineSize
, rRawBitmap
.mnHeight
);
156 if( aSize
.getX() && aSize
.getY() )
158 static PaletteMemorySharedVector aDummyPAL
;
159 RawMemorySharedArray
aRawPtr( rRawBitmap
.mpBits
);
160 pGcpHelper
->maBitmapDev
= createBitmapDevice( aSize
, true, nBmpFormat
, aRawPtr
, aDummyPAL
);
163 rServerFont
.SetExtended( nBmpFormat
, (void*)pGcpHelper
);
166 rTargetPos
+= B2IPoint( pGcpHelper
->maRawBitmap
.mnXOffset
, pGcpHelper
->maRawBitmap
.mnYOffset
);
167 return pGcpHelper
->maBitmapDev
;
170 //--------------------------------------------------------------------------
172 void SvpGlyphPeer::RemovingFont( ServerFont
& )
174 // nothing to do: no font resources held in SvpGlyphPeer
177 //--------------------------------------------------------------------------
179 void SvpGlyphPeer::RemovingGlyph( ServerFont
&, GlyphData
& rGlyphData
, int /*nGlyphIndex*/ )
181 if( rGlyphData
.ExtDataRef().mpData
!= Format::NONE
)
183 // release the glyph related resources
184 DBG_ASSERT( (rGlyphData
.ExtDataRef().meInfo
<= Format::MAX
), "SVP::RG() invalid alpha format" );
185 SvpGcpHelper
* pGcpHelper
= (SvpGcpHelper
*)rGlyphData
.ExtDataRef().mpData
;
186 delete[] pGcpHelper
->maRawBitmap
.mpBits
;
191 // ===========================================================================
193 // PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
194 class PspKernInfo
: public ExtraKernInfo
197 PspKernInfo( int nFontId
) : ExtraKernInfo(nFontId
) {}
199 virtual void Initialize() const;
202 //--------------------------------------------------------------------------
204 void PspKernInfo::Initialize() const
206 mbInitialized
= true;
208 // get the kerning pairs from psprint
209 const psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
210 typedef std::list
< psp::KernPair
> PspKernPairs
;
211 const PspKernPairs
& rKernPairs
= rMgr
.getKernPairs( mnFontId
);
212 if( rKernPairs
.empty() )
215 PspKernPairs::const_iterator it
= rKernPairs
.begin();
216 for(; it
!= rKernPairs
.end(); ++it
)
218 ImplKernPairData aKernPair
= { it
->first
, it
->second
, it
->kern_x
};
219 maUnicodeKernPairs
.insert( aKernPair
);
223 // ===========================================================================
225 sal_uInt16
SvpSalGraphics::SetFont( FontSelectPattern
* pIFSD
, int nFallbackLevel
)
227 // release all no longer needed font resources
228 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
230 if( m_pServerFont
[i
] != NULL
)
232 // old server side font is no longer referenced
233 SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont
[i
] );
234 m_pServerFont
[i
] = NULL
;
238 // return early if there is no new font
242 // handle the request for a non-native X11-font => use the GlyphCache
243 ServerFont
* pServerFont
= SvpGlyphCache::GetInstance().CacheFont( *pIFSD
);
245 return SAL_SETFONT_BADFONT
;
247 // check selected font
248 if( !pServerFont
->TestFont() )
250 SvpGlyphCache::GetInstance().UncacheFont( *pServerFont
);
251 return SAL_SETFONT_BADFONT
;
254 // update SalGraphics font settings
255 m_pServerFont
[ nFallbackLevel
] = pServerFont
;
256 return SAL_SETFONT_USEDRAWTEXTARRAY
;
259 // ---------------------------------------------------------------------------
261 void SvpSalGraphics::GetFontMetric( ImplFontMetricData
* pMetric
, int nFallbackLevel
)
263 if( nFallbackLevel
>= MAX_FALLBACK
)
266 if( m_pServerFont
[nFallbackLevel
] != NULL
)
269 m_pServerFont
[nFallbackLevel
]->FetchFontMetric( *pMetric
, rDummyFactor
);
273 // ---------------------------------------------------------------------------
275 sal_uLong
SvpSalGraphics::GetKernPairs( sal_uLong nPairs
, ImplKernPairData
* pKernPairs
)
277 sal_uLong nGotPairs
= 0;
279 if( m_pServerFont
[0] != NULL
)
281 ImplKernPairData
* pTmpKernPairs
= NULL
;
282 nGotPairs
= m_pServerFont
[0]->GetKernPairs( &pTmpKernPairs
);
283 for( sal_uLong i
= 0; i
< nPairs
&& i
< nGotPairs
; ++i
)
284 pKernPairs
[ i
] = pTmpKernPairs
[ i
];
285 delete[] pTmpKernPairs
;
291 // ---------------------------------------------------------------------------
293 const ImplFontCharMap
* SvpSalGraphics::GetImplFontCharMap() const
295 if( !m_pServerFont
[0] )
298 const ImplFontCharMap
* pIFCMap
= m_pServerFont
[0]->GetImplFontCharMap();
302 bool SvpSalGraphics::GetImplFontCapabilities(vcl::FontCapabilities
&rFontCapabilities
) const
304 if (!m_pServerFont
[0])
307 return m_pServerFont
[0]->GetFontCapabilities(rFontCapabilities
);
310 // ---------------------------------------------------------------------------
312 void SvpSalGraphics::GetDevFontList( ImplDevFontList
* pDevFontList
)
314 GlyphCache
& rGC
= SvpGlyphCache::GetInstance();
316 psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
317 psp::FastPrintFontInfo aInfo
;
318 ::std::list
< psp::fontID
> aList
;
319 rMgr
.getFontList( aList
);
320 ::std::list
< psp::fontID
>::iterator it
;
321 for( it
= aList
.begin(); it
!= aList
.end(); ++it
)
323 if( !rMgr
.getFontFastInfo( *it
, aInfo
) )
326 // the GlyphCache must not bother with builtin fonts because
327 // it cannot access or use them anyway
328 if( aInfo
.m_eType
== psp::fonttype::Builtin
)
331 // normalize face number to the GlyphCache
332 int nFaceNum
= rMgr
.getFontFaceNumber( aInfo
.m_nID
);
334 // for fonts where extra kerning info can be provided on demand
335 // an ExtraKernInfo object is supplied
336 const ExtraKernInfo
* pExtraKernInfo
= NULL
;
337 if( aInfo
.m_eType
== psp::fonttype::Type1
)
338 pExtraKernInfo
= new PspKernInfo( *it
);
340 // inform GlyphCache about this font provided by the PsPrint subsystem
341 ImplDevFontAttributes aDFA
= GenPspGraphics::Info2DevFontAttributes( aInfo
);
342 aDFA
.mnQuality
+= 4096;
343 const rtl::OString
& rFileName
= rMgr
.getFontFileSysPath( aInfo
.m_nID
);
344 rGC
.AddFontFile( rFileName
, nFaceNum
, aInfo
.m_nID
, aDFA
, pExtraKernInfo
);
347 // announce glyphcache fonts
348 rGC
.AnnounceFonts( pDevFontList
);
350 // register platform specific font substitutions if available
351 SalGenericInstance::RegisterFontSubstitutors( pDevFontList
);
353 ImplGetSVData()->maGDIData
.mbNativeFontConfig
= true;
356 void SvpSalGraphics::ClearDevFontCache()
358 GlyphCache
& rGC
= SvpGlyphCache::GetInstance();
359 rGC
.ClearFontCache();
362 // ---------------------------------------------------------------------------
364 void SvpSalGraphics::GetDevFontSubstList( OutputDevice
* )
367 // ---------------------------------------------------------------------------
369 bool SvpSalGraphics::AddTempDevFont( ImplDevFontList
*,
370 const rtl::OUString
&, const rtl::OUString
& )
375 // ---------------------------------------------------------------------------
377 sal_Bool
SvpSalGraphics::CreateFontSubset(
378 const rtl::OUString
& rToFile
,
379 const PhysicalFontFace
* pFont
,
380 sal_Int32
* pGlyphIDs
,
381 sal_uInt8
* pEncoding
,
384 FontSubsetInfo
& rInfo
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 psp::fontID aFont
= pFont
->GetFontId();
394 psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
395 bool bSuccess
= rMgr
.createFontSubset( rInfo
,
405 // ---------------------------------------------------------------------------
407 const Ucs2SIntMap
* SvpSalGraphics::GetFontEncodingVector( const PhysicalFontFace
* pFont
, const Ucs2OStrMap
** pNonEncoded
)
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 psp::fontID aFont
= pFont
->GetFontId();
415 return GenPspGraphics::DoGetFontEncodingVector( aFont
, pNonEncoded
);
418 // ---------------------------------------------------------------------------
420 const void* SvpSalGraphics::GetEmbedFontData(
421 const PhysicalFontFace
* pFont
,
422 const sal_Ucs
* pUnicodes
,
424 FontSubsetInfo
& rInfo
,
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 psp::fontID aFont
= pFont
->GetFontId();
434 return GenPspGraphics::DoGetEmbedFontData( aFont
, pUnicodes
, pWidths
, rInfo
, pDataLen
);
437 // ---------------------------------------------------------------------------
439 void SvpSalGraphics::FreeEmbedFontData( const void* pData
, long nLen
)
441 GenPspGraphics::DoFreeEmbedFontData( pData
, nLen
);
444 void SvpSalGraphics::GetGlyphWidths( const PhysicalFontFace
* pFont
,
446 Int32Vector
& rWidths
,
447 Ucs2UIntMap
& rUnicodeEnc
)
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 psp::fontID aFont
= pFont
->GetFontId();
455 GenPspGraphics::DoGetGlyphWidths( aFont
, bVertical
, rWidths
, rUnicodeEnc
);
458 // ---------------------------------------------------------------------------
460 sal_Bool
SvpSalGraphics::GetGlyphBoundRect( sal_GlyphId nGlyphIndex
, Rectangle
& rRect
)
462 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
463 if( nLevel
>= MAX_FALLBACK
)
466 ServerFont
* pSF
= m_pServerFont
[ nLevel
];
470 nGlyphIndex
&= GF_IDXMASK
;
471 const GlyphMetric
& rGM
= pSF
->GetGlyphMetric( nGlyphIndex
);
472 rRect
= Rectangle( rGM
.GetOffset(), rGM
.GetSize() );
476 // ---------------------------------------------------------------------------
478 sal_Bool
SvpSalGraphics::GetGlyphOutline( sal_GlyphId nGlyphIndex
, B2DPolyPolygon
& rPolyPoly
)
480 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
481 if( nLevel
>= MAX_FALLBACK
)
484 const ServerFont
* pSF
= m_pServerFont
[ nLevel
];
488 nGlyphIndex
&= GF_IDXMASK
;
489 if( pSF
->GetGlyphOutline( nGlyphIndex
, rPolyPoly
) )
495 // ---------------------------------------------------------------------------
497 SalLayout
* SvpSalGraphics::GetTextLayout( ImplLayoutArgs
&, int nFallbackLevel
)
499 GenericSalLayout
* pLayout
= NULL
;
501 if( m_pServerFont
[ nFallbackLevel
] )
502 pLayout
= new ServerFontLayout( *m_pServerFont
[ nFallbackLevel
] );
507 // ---------------------------------------------------------------------------
509 void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout
& rSalLayout
)
511 // iterate over all glyphs in the layout
513 sal_GlyphId nGlyphIndex
;
514 SvpGlyphPeer
& rGlyphPeer
= SvpGlyphCache::GetInstance().GetPeer();
515 for( int nStart
= 0; rSalLayout
.GetNextGlyphs( 1, &nGlyphIndex
, aPos
, nStart
); )
517 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
518 DBG_ASSERT( nLevel
< MAX_FALLBACK
, "SvpGDI: invalid glyph fallback level" );
519 ServerFont
* pSF
= m_pServerFont
[ nLevel
];
523 // get the glyph's alpha mask and adjust the drawing position
524 nGlyphIndex
&= GF_IDXMASK
;
525 B2IPoint
aDstPoint( aPos
.X(), aPos
.Y() );
526 BitmapDeviceSharedPtr aAlphaMask
527 = rGlyphPeer
.GetGlyphBmp( *pSF
, nGlyphIndex
, m_eTextFmt
, aDstPoint
);
528 if( !aAlphaMask
) // ignore empty glyphs
531 // blend text color into target using the glyph's mask
532 const B2IBox
aSrcRect( B2ITuple(0,0), aAlphaMask
->getSize() );
533 const B2IBox
aClipRect( aDstPoint
, aAlphaMask
->getSize() );
535 SvpSalGraphics::ClipUndoHandle
aUndo( this );
536 if( !isClippedSetup( aClipRect
, aUndo
) )
537 m_aDevice
->drawMaskedColor( m_aTextColor
, aAlphaMask
,
538 aSrcRect
, aDstPoint
, m_aClipMap
);
542 // ===========================================================================
544 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */