1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
31 #include <basegfx/range/b2drange.hxx>
32 #include <basegfx/range/b2irange.hxx>
33 #include <basegfx/polygon/b2dpolypolygon.hxx>
34 #include <basebmp/scanlineformats.hxx>
36 #include <tools/debug.hxx>
38 #if OSL_DEBUG_LEVEL > 2
39 #include <basebmp/debug.hxx>
42 #include <vcl/outfont.hxx>
43 #include <vcl/glyphcache.hxx>
44 #include <vcl/impfont.hxx>
46 #include "svppspgraphics.hxx"
48 using namespace basegfx
;
49 using namespace basebmp
;
51 // ===========================================================================
54 : public GlyphCachePeer
59 BitmapDeviceSharedPtr
GetGlyphBmp( ServerFont
&, int nGlyphIndex
,
60 sal_uInt32 nBmpFormat
, B2IPoint
& rTargetPos
);
63 virtual void RemovingFont( ServerFont
& );
64 virtual void RemovingGlyph( ServerFont
&, GlyphData
&, int nGlyphIndex
);
69 RawBitmap maRawBitmap
;
70 BitmapDeviceSharedPtr maBitmapDev
;
74 // ===========================================================================
76 class SvpGlyphCache
: public GlyphCache
79 SvpGlyphPeer
& GetPeer() { return reinterpret_cast<SvpGlyphPeer
&>( mrPeer
); }
80 static SvpGlyphCache
& GetInstance();
82 SvpGlyphCache( SvpGlyphPeer
& rPeer
) : GlyphCache( rPeer
) {}
85 //--------------------------------------------------------------------------
87 SvpGlyphCache
& SvpGlyphCache::GetInstance()
89 static SvpGlyphPeer aSvpGlyphPeer
;
90 static SvpGlyphCache
aGC( aSvpGlyphPeer
);
94 // ===========================================================================
96 BitmapDeviceSharedPtr
SvpGlyphPeer::GetGlyphBmp( ServerFont
& rServerFont
,
97 int nGlyphIndex
, sal_uInt32 nBmpFormat
, B2IPoint
& rTargetPos
)
99 GlyphData
& rGlyphData
= rServerFont
.GetGlyphData( nGlyphIndex
);
100 SvpGcpHelper
* pGcpHelper
= (SvpGcpHelper
*)rGlyphData
.ExtDataRef().mpData
;
102 // nothing to do if the GlyphPeer hasn't allocated resources for the glyph
103 if( rGlyphData
.ExtDataRef().meInfo
!= sal::static_int_cast
<int>(nBmpFormat
) )
105 if( rGlyphData
.ExtDataRef().meInfo
== Format::NONE
)
106 pGcpHelper
= new SvpGcpHelper
;
107 RawBitmap
& rRawBitmap
= pGcpHelper
->maRawBitmap
;
109 // get glyph bitmap in matching format
113 case Format::ONE_BIT_LSB_GREY
:
114 bFound
= rServerFont
.GetGlyphBitmap1( nGlyphIndex
, pGcpHelper
->maRawBitmap
);
116 case Format::EIGHT_BIT_GREY
:
117 bFound
= rServerFont
.GetGlyphBitmap8( nGlyphIndex
, pGcpHelper
->maRawBitmap
);
120 DBG_ERROR( "SVP GCP::GetGlyphBmp(): illegal scanline format");
121 // fall back to black&white mask
122 nBmpFormat
= Format::ONE_BIT_LSB_GREY
;
127 // return .notdef glyph if needed
128 if( !bFound
&& (nGlyphIndex
!= 0) )
131 return GetGlyphBmp( rServerFont
, 0, nBmpFormat
, rTargetPos
);
134 // construct alpha mask from raw bitmap
135 const B2IVector
aSize( rRawBitmap
.mnScanlineSize
, rRawBitmap
.mnHeight
);
136 if( aSize
.getX() && aSize
.getY() )
138 static PaletteMemorySharedVector aDummyPAL
;
139 RawMemorySharedArray
aRawPtr( rRawBitmap
.mpBits
);
140 pGcpHelper
->maBitmapDev
= createBitmapDevice( aSize
, true, nBmpFormat
, aRawPtr
, aDummyPAL
);
143 rServerFont
.SetExtended( nBmpFormat
, (void*)pGcpHelper
);
146 rTargetPos
+= B2IPoint( pGcpHelper
->maRawBitmap
.mnXOffset
, pGcpHelper
->maRawBitmap
.mnYOffset
);
147 return pGcpHelper
->maBitmapDev
;
150 //--------------------------------------------------------------------------
152 void SvpGlyphPeer::RemovingFont( ServerFont
& )
154 // nothing to do: no font resources held in SvpGlyphPeer
157 //--------------------------------------------------------------------------
159 void SvpGlyphPeer::RemovingGlyph( ServerFont
&, GlyphData
& rGlyphData
, int /*nGlyphIndex*/ )
161 if( rGlyphData
.ExtDataRef().mpData
!= Format::NONE
)
163 // release the glyph related resources
164 DBG_ASSERT( (rGlyphData
.ExtDataRef().meInfo
<= Format::MAX
), "SVP::RG() invalid alpha format" );
165 SvpGcpHelper
* pGcpHelper
= (SvpGcpHelper
*)rGlyphData
.ExtDataRef().mpData
;
166 delete[] pGcpHelper
->maRawBitmap
.mpBits
;
171 // ===========================================================================
173 // PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#)
174 class PspKernInfo
: public ExtraKernInfo
177 PspKernInfo( int nFontId
) : ExtraKernInfo(nFontId
) {}
179 virtual void Initialize() const;
182 //--------------------------------------------------------------------------
184 void PspKernInfo::Initialize() const
186 mbInitialized
= true;
188 // get the kerning pairs from psprint
189 const psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
190 typedef std::list
< psp::KernPair
> PspKernPairs
;
191 const PspKernPairs
& rKernPairs
= rMgr
.getKernPairs( mnFontId
);
192 if( rKernPairs
.empty() )
195 // feed psprint's kerning list into a lookup-friendly container
196 maUnicodeKernPairs
.resize( rKernPairs
.size() );
197 PspKernPairs::const_iterator it
= rKernPairs
.begin();
198 for(; it
!= rKernPairs
.end(); ++it
)
200 ImplKernPairData aKernPair
= { it
->first
, it
->second
, it
->kern_x
};
201 maUnicodeKernPairs
.insert( aKernPair
);
205 // ===========================================================================
207 USHORT
SvpSalGraphics::SetFont( ImplFontSelectData
* pIFSD
, int nFallbackLevel
)
209 // release all no longer needed font resources
210 for( int i
= nFallbackLevel
; i
< MAX_FALLBACK
; ++i
)
212 if( m_pServerFont
[i
] != NULL
)
214 // old server side font is no longer referenced
215 SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont
[i
] );
216 m_pServerFont
[i
] = NULL
;
220 // return early if there is no new font
224 // handle the request for a non-native X11-font => use the GlyphCache
225 ServerFont
* pServerFont
= SvpGlyphCache::GetInstance().CacheFont( *pIFSD
);
227 return SAL_SETFONT_BADFONT
;
229 // check selected font
230 if( !pServerFont
->TestFont() )
232 SvpGlyphCache::GetInstance().UncacheFont( *pServerFont
);
233 return SAL_SETFONT_BADFONT
;
236 // update SalGraphics font settings
237 m_pServerFont
[ nFallbackLevel
] = pServerFont
;
238 return SAL_SETFONT_USEDRAWTEXTARRAY
;
241 // ---------------------------------------------------------------------------
243 void SvpSalGraphics::GetFontMetric( ImplFontMetricData
* pMetric
)
245 if( m_pServerFont
[0] != NULL
)
248 m_pServerFont
[0]->FetchFontMetric( *pMetric
, rDummyFactor
);
252 // ---------------------------------------------------------------------------
254 ULONG
SvpSalGraphics::GetKernPairs( ULONG nPairs
, ImplKernPairData
* pKernPairs
)
258 if( m_pServerFont
[0] != NULL
)
260 ImplKernPairData
* pTmpKernPairs
= NULL
;
261 nGotPairs
= m_pServerFont
[0]->GetKernPairs( &pTmpKernPairs
);
262 for( ULONG i
= 0; i
< nPairs
&& i
< nGotPairs
; ++i
)
263 pKernPairs
[ i
] = pTmpKernPairs
[ i
];
264 delete[] pTmpKernPairs
;
270 // ---------------------------------------------------------------------------
272 ImplFontCharMap
* SvpSalGraphics::GetImplFontCharMap() const
274 if( !m_pServerFont
[0] )
277 CmapResult aCmapResult
;
278 if( !m_pServerFont
[0]->GetFontCodeRanges( aCmapResult
) )
280 return new ImplFontCharMap( aCmapResult
);
283 // ---------------------------------------------------------------------------
285 void SvpSalGraphics::GetDevFontList( ImplDevFontList
* pDevFontList
)
287 GlyphCache
& rGC
= SvpGlyphCache::GetInstance();
289 psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
290 psp::FastPrintFontInfo aInfo
;
291 ::std::list
< psp::fontID
> aList
;
292 rMgr
.getFontList( aList
);
293 ::std::list
< psp::fontID
>::iterator it
;
294 for( it
= aList
.begin(); it
!= aList
.end(); ++it
)
296 if( !rMgr
.getFontFastInfo( *it
, aInfo
) )
299 // the GlyphCache must not bother with builtin fonts because
300 // it cannot access or use them anyway
301 if( aInfo
.m_eType
== psp::fonttype::Builtin
)
304 // normalize face number to the GlyphCache
305 int nFaceNum
= rMgr
.getFontFaceNumber( aInfo
.m_nID
);
309 // for fonts where extra kerning info can be provided on demand
310 // an ExtraKernInfo object is supplied
311 const ExtraKernInfo
* pExtraKernInfo
= NULL
;
312 if( aInfo
.m_eType
== psp::fonttype::Type1
)
313 pExtraKernInfo
= new PspKernInfo( *it
);
315 // inform GlyphCache about this font provided by the PsPrint subsystem
316 ImplDevFontAttributes aDFA
= PspGraphics::Info2DevFontAttributes( aInfo
);
317 aDFA
.mnQuality
+= 4096;
318 const rtl::OString
& rFileName
= rMgr
.getFontFileSysPath( aInfo
.m_nID
);
319 rGC
.AddFontFile( rFileName
, nFaceNum
, aInfo
.m_nID
, aDFA
, pExtraKernInfo
);
322 // announce glyphcache fonts
323 rGC
.AnnounceFonts( pDevFontList
);
326 // ---------------------------------------------------------------------------
328 void SvpSalGraphics::GetDevFontSubstList( OutputDevice
* )
331 // ---------------------------------------------------------------------------
333 bool SvpSalGraphics::AddTempDevFont( ImplDevFontList
*,
334 const String
&, const String
& )
339 // ---------------------------------------------------------------------------
341 BOOL
SvpSalGraphics::CreateFontSubset(
342 const rtl::OUString
& rToFile
,
343 const ImplFontData
* pFont
,
344 sal_Int32
* pGlyphIDs
,
345 sal_uInt8
* pEncoding
,
348 FontSubsetInfo
& rInfo
351 // in this context the pFont->GetFontId() is a valid PSP
352 // font since they are the only ones left after the PDF
353 // export has filtered its list of subsettable fonts (for
354 // which this method was created). The correct way would
355 // be to have the GlyphCache search for the ImplFontData pFont
356 psp::fontID aFont
= pFont
->GetFontId();
358 psp::PrintFontManager
& rMgr
= psp::PrintFontManager::get();
359 bool bSuccess
= rMgr
.createFontSubset( rInfo
,
369 // ---------------------------------------------------------------------------
371 const Ucs2SIntMap
* SvpSalGraphics::GetFontEncodingVector( const ImplFontData
* pFont
, const Ucs2OStrMap
** pNonEncoded
)
373 // in this context the pFont->GetFontId() is a valid PSP
374 // font since they are the only ones left after the PDF
375 // export has filtered its list of subsettable fonts (for
376 // which this method was created). The correct way would
377 // be to have the GlyphCache search for the ImplFontData pFont
378 psp::fontID aFont
= pFont
->GetFontId();
379 return PspGraphics::DoGetFontEncodingVector( aFont
, pNonEncoded
);
382 // ---------------------------------------------------------------------------
384 const void* SvpSalGraphics::GetEmbedFontData(
385 const ImplFontData
* pFont
,
386 const sal_Ucs
* pUnicodes
,
388 FontSubsetInfo
& rInfo
,
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 ImplFontData pFont
397 psp::fontID aFont
= pFont
->GetFontId();
398 return PspGraphics::DoGetEmbedFontData( aFont
, pUnicodes
, pWidths
, rInfo
, pDataLen
);
401 // ---------------------------------------------------------------------------
403 void SvpSalGraphics::FreeEmbedFontData( const void* pData
, long nLen
)
405 PspGraphics::DoFreeEmbedFontData( pData
, nLen
);
408 void SvpSalGraphics::GetGlyphWidths( const ImplFontData
* pFont
,
410 Int32Vector
& rWidths
,
411 Ucs2UIntMap
& rUnicodeEnc
)
413 // in this context the pFont->GetFontId() is a valid PSP
414 // font since they are the only ones left after the PDF
415 // export has filtered its list of subsettable fonts (for
416 // which this method was created). The correct way would
417 // be to have the GlyphCache search for the ImplFontData pFont
418 psp::fontID aFont
= pFont
->GetFontId();
419 PspGraphics::DoGetGlyphWidths( aFont
, bVertical
, rWidths
, rUnicodeEnc
);
422 // ---------------------------------------------------------------------------
424 BOOL
SvpSalGraphics::GetGlyphBoundRect( long nGlyphIndex
, Rectangle
& rRect
)
426 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
427 if( nLevel
>= MAX_FALLBACK
)
430 ServerFont
* pSF
= m_pServerFont
[ nLevel
];
434 nGlyphIndex
&= ~GF_FONTMASK
;
435 const GlyphMetric
& rGM
= pSF
->GetGlyphMetric( nGlyphIndex
);
436 rRect
= Rectangle( rGM
.GetOffset(), rGM
.GetSize() );
440 // ---------------------------------------------------------------------------
442 BOOL
SvpSalGraphics::GetGlyphOutline( long nGlyphIndex
, B2DPolyPolygon
& rPolyPoly
)
444 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
445 if( nLevel
>= MAX_FALLBACK
)
448 const ServerFont
* pSF
= m_pServerFont
[ nLevel
];
452 nGlyphIndex
&= ~GF_FONTMASK
;
453 if( pSF
->GetGlyphOutline( nGlyphIndex
, rPolyPoly
) )
459 // ---------------------------------------------------------------------------
461 SalLayout
* SvpSalGraphics::GetTextLayout( ImplLayoutArgs
&, int nFallbackLevel
)
463 GenericSalLayout
* pLayout
= NULL
;
465 if( m_pServerFont
[ nFallbackLevel
] )
466 pLayout
= new ServerFontLayout( *m_pServerFont
[ nFallbackLevel
] );
471 // ---------------------------------------------------------------------------
473 void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout
& rSalLayout
)
475 // iterate over all glyphs in the layout
477 sal_GlyphId nGlyphIndex
;
478 SvpGlyphPeer
& rGlyphPeer
= SvpGlyphCache::GetInstance().GetPeer();
479 for( int nStart
= 0; rSalLayout
.GetNextGlyphs( 1, &nGlyphIndex
, aPos
, nStart
); )
481 int nLevel
= nGlyphIndex
>> GF_FONTSHIFT
;
482 DBG_ASSERT( nLevel
< MAX_FALLBACK
, "SvpGDI: invalid glyph fallback level" );
483 ServerFont
* pSF
= m_pServerFont
[ nLevel
];
487 // get the glyph's alpha mask and adjust the drawing position
488 nGlyphIndex
&= ~GF_FONTMASK
;
489 B2IPoint
aDstPoint( aPos
.X(), aPos
.Y() );
490 BitmapDeviceSharedPtr aAlphaMask
491 = rGlyphPeer
.GetGlyphBmp( *pSF
, nGlyphIndex
, m_eTextFmt
, aDstPoint
);
492 if( !aAlphaMask
) // ignore empty glyphs
495 // blend text color into target using the glyph's mask
496 const B2IRange
aSrcRect( B2ITuple(0,0), aAlphaMask
->getSize() );
497 m_aDevice
->drawMaskedColor( m_aTextColor
, aAlphaMask
, aSrcRect
, aDstPoint
, m_aClipMap
);
501 // ===========================================================================