/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ # #include #include #include #include #include #if OSL_DEBUG_LEVEL > 2 #include #endif #include #include #include #include "svpgdi.hxx" #include "svpbmp.hxx" #include "svppspgraphics.hxx" using namespace basegfx; using namespace basebmp; // =========================================================================== class SvpGlyphPeer : public GlyphCachePeer { public: SvpGlyphPeer() {} BitmapDeviceSharedPtr GetGlyphBmp( ServerFont&, sal_GlyphId, sal_uInt32 nBmpFormat, B2IPoint& rTargetPos ); protected: virtual void RemovingFont( ServerFont& ); virtual void RemovingGlyph( ServerFont&, GlyphData&, sal_GlyphId ); class SvpGcpHelper { public: RawBitmap maRawBitmap; BitmapDeviceSharedPtr maBitmapDev; }; }; // =========================================================================== class SvpGlyphCache : public GlyphCache { public: SvpGlyphPeer& GetPeer() { return reinterpret_cast( mrPeer ); } static SvpGlyphCache& GetInstance(); private: SvpGlyphCache( SvpGlyphPeer& rPeer ) : GlyphCache( rPeer) {} }; //-------------------------------------------------------------------------- SvpGlyphCache& SvpGlyphCache::GetInstance() { static SvpGlyphPeer aSvpGlyphPeer; static SvpGlyphCache aGC( aSvpGlyphPeer ); return aGC; } // =========================================================================== BitmapDeviceSharedPtr SvpGlyphPeer::GetGlyphBmp( ServerFont& rServerFont, sal_GlyphId aGlyphId, sal_uInt32 nBmpFormat, B2IPoint& rTargetPos ) { GlyphData& rGlyphData = rServerFont.GetGlyphData( aGlyphId ); SvpGcpHelper* pGcpHelper = (SvpGcpHelper*)rGlyphData.ExtDataRef().mpData; // nothing to do if the GlyphPeer hasn't allocated resources for the glyph if( rGlyphData.ExtDataRef().meInfo != sal::static_int_cast(nBmpFormat) ) { if( rGlyphData.ExtDataRef().meInfo == Format::NONE ) pGcpHelper = new SvpGcpHelper; RawBitmap& rRawBitmap = pGcpHelper->maRawBitmap; // get glyph bitmap in matching format bool bFound = false; switch( nBmpFormat ) { case Format::ONE_BIT_LSB_GREY: bFound = rServerFont.GetGlyphBitmap1( aGlyphId, pGcpHelper->maRawBitmap ); break; case Format::EIGHT_BIT_GREY: bFound = rServerFont.GetGlyphBitmap8( aGlyphId, pGcpHelper->maRawBitmap ); break; default: DBG_ERROR( "SVP GCP::GetGlyphBmp(): illegal scanline format"); // fall back to black&white mask nBmpFormat = Format::ONE_BIT_LSB_GREY; bFound = false; break; } // return .notdef glyph if needed if( !bFound && (aGlyphId != 0) ) { delete pGcpHelper; return GetGlyphBmp( rServerFont, 0, nBmpFormat, rTargetPos ); } // construct alpha mask from raw bitmap const B2IVector aSize( rRawBitmap.mnScanlineSize, rRawBitmap.mnHeight ); if( aSize.getX() && aSize.getY() ) { static PaletteMemorySharedVector aDummyPAL; RawMemorySharedArray aRawPtr( rRawBitmap.mpBits ); pGcpHelper->maBitmapDev = createBitmapDevice( aSize, true, nBmpFormat, aRawPtr, aDummyPAL ); } rServerFont.SetExtended( nBmpFormat, (void*)pGcpHelper ); } rTargetPos += B2IPoint( pGcpHelper->maRawBitmap.mnXOffset, pGcpHelper->maRawBitmap.mnYOffset ); return pGcpHelper->maBitmapDev; } //-------------------------------------------------------------------------- void SvpGlyphPeer::RemovingFont( ServerFont& ) { // nothing to do: no font resources held in SvpGlyphPeer } //-------------------------------------------------------------------------- void SvpGlyphPeer::RemovingGlyph( ServerFont&, GlyphData& rGlyphData, sal_GlyphId /*aGlyphId*/ ) { if( rGlyphData.ExtDataRef().mpData != NULL ) { // release the glyph related resources DBG_ASSERT( (rGlyphData.ExtDataRef().meInfo <= Format::MAX), "SVP::RG() invalid alpha format" ); SvpGcpHelper* pGcpHelper = (SvpGcpHelper*)rGlyphData.ExtDataRef().mpData; delete[] pGcpHelper->maRawBitmap.mpBits; delete pGcpHelper; } } // =========================================================================== // PspKernInfo allows on-demand-querying of psprint provided kerning info (#i29881#) class PspKernInfo : public ExtraKernInfo { public: PspKernInfo( int nFontId ) : ExtraKernInfo(nFontId) {} protected: virtual void Initialize() const; }; //-------------------------------------------------------------------------- void PspKernInfo::Initialize() const { mbInitialized = true; // get the kerning pairs from psprint const psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); typedef std::list< psp::KernPair > PspKernPairs; const PspKernPairs& rKernPairs = rMgr.getKernPairs( mnFontId ); if( rKernPairs.empty() ) return; // feed psprint's kerning list into a lookup-friendly container maUnicodeKernPairs.rehash( rKernPairs.size() ); PspKernPairs::const_iterator it = rKernPairs.begin(); for(; it != rKernPairs.end(); ++it ) { ImplKernPairData aKernPair = { it->first, it->second, it->kern_x }; maUnicodeKernPairs.insert( aKernPair ); } } // =========================================================================== sal_uInt16 SvpSalGraphics::SetFont( ImplFontSelectData* pIFSD, int nFallbackLevel ) { // release all no longer needed font resources for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) { if( m_pServerFont[i] != NULL ) { // old server side font is no longer referenced SvpGlyphCache::GetInstance().UncacheFont( *m_pServerFont[i] ); m_pServerFont[i] = NULL; } } // return early if there is no new font if( !pIFSD ) return 0; // handle the request for a non-native X11-font => use the GlyphCache ServerFont* pServerFont = SvpGlyphCache::GetInstance().CacheFont( *pIFSD ); if( !pServerFont ) return SAL_SETFONT_BADFONT; // check selected font if( !pServerFont->TestFont() ) { SvpGlyphCache::GetInstance().UncacheFont( *pServerFont ); return SAL_SETFONT_BADFONT; } // update SalGraphics font settings m_pServerFont[ nFallbackLevel ] = pServerFont; return SAL_SETFONT_USEDRAWTEXTARRAY; } // --------------------------------------------------------------------------- void SvpSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLevel ) { if( nFallbackLevel >= MAX_FALLBACK ) return; if( m_pServerFont[nFallbackLevel] != NULL ) { long rDummyFactor; m_pServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor ); } } // --------------------------------------------------------------------------- sal_uLong SvpSalGraphics::GetKernPairs( sal_uLong nPairs, ImplKernPairData* pKernPairs ) { sal_uLong nGotPairs = 0; if( m_pServerFont[0] != NULL ) { ImplKernPairData* pTmpKernPairs = NULL; nGotPairs = m_pServerFont[0]->GetKernPairs( &pTmpKernPairs ); for( sal_uLong i = 0; i < nPairs && i < nGotPairs; ++i ) pKernPairs[ i ] = pTmpKernPairs[ i ]; delete[] pTmpKernPairs; } return nGotPairs; } // --------------------------------------------------------------------------- const ImplFontCharMap* SvpSalGraphics::GetImplFontCharMap() const { if( !m_pServerFont[0] ) return NULL; const ImplFontCharMap* pIFCMap = m_pServerFont[0]->GetImplFontCharMap(); return pIFCMap; } // --------------------------------------------------------------------------- void SvpSalGraphics::GetDevFontList( ImplDevFontList* pDevFontList ) { GlyphCache& rGC = SvpGlyphCache::GetInstance(); psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); psp::FastPrintFontInfo aInfo; ::std::list< psp::fontID > aList; rMgr.getFontList( aList ); ::std::list< psp::fontID >::iterator it; for( it = aList.begin(); it != aList.end(); ++it ) { if( !rMgr.getFontFastInfo( *it, aInfo ) ) continue; // the GlyphCache must not bother with builtin fonts because // it cannot access or use them anyway if( aInfo.m_eType == psp::fonttype::Builtin ) continue; // normalize face number to the GlyphCache int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); if( nFaceNum < 0 ) nFaceNum = 0; // for fonts where extra kerning info can be provided on demand // an ExtraKernInfo object is supplied const ExtraKernInfo* pExtraKernInfo = NULL; if( aInfo.m_eType == psp::fonttype::Type1 ) pExtraKernInfo = new PspKernInfo( *it ); // inform GlyphCache about this font provided by the PsPrint subsystem ImplDevFontAttributes aDFA = PspGraphics::Info2DevFontAttributes( aInfo ); aDFA.mnQuality += 4096; const rtl::OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA, pExtraKernInfo ); } // announce glyphcache fonts rGC.AnnounceFonts( pDevFontList ); } // --------------------------------------------------------------------------- void SvpSalGraphics::GetDevFontSubstList( OutputDevice* ) {} // --------------------------------------------------------------------------- bool SvpSalGraphics::AddTempDevFont( ImplDevFontList*, const String&, const String& ) { return false; } // --------------------------------------------------------------------------- sal_Bool SvpSalGraphics::CreateFontSubset( const rtl::OUString& rToFile, const ImplFontData* pFont, sal_GlyphId* pGlyphIds, sal_uInt8* pEncoding, sal_Int32* pWidths, int nGlyphCount, FontSubsetInfo& rInfo ) { // in this context the pFont->GetFontId() is a valid PSP // font since they are the only ones left after the PDF // export has filtered its list of subsettable fonts (for // which this method was created). The correct way would // be to have the GlyphCache search for the ImplFontData pFont psp::fontID aFont = pFont->GetFontId(); psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); bool bSuccess = rMgr.createFontSubset( rInfo, aFont, rToFile, pGlyphIds, pEncoding, pWidths, nGlyphCount ); return bSuccess; } // --------------------------------------------------------------------------- const Ucs2SIntMap* SvpSalGraphics::GetFontEncodingVector( const ImplFontData* pFont, const Ucs2OStrMap** pNonEncoded ) { // in this context the pFont->GetFontId() is a valid PSP // font since they are the only ones left after the PDF // export has filtered its list of subsettable fonts (for // which this method was created). The correct way would // be to have the GlyphCache search for the ImplFontData pFont psp::fontID aFont = pFont->GetFontId(); return PspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); } // --------------------------------------------------------------------------- const void* SvpSalGraphics::GetEmbedFontData( const ImplFontData* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen ) { // in this context the pFont->GetFontId() is a valid PSP // font since they are the only ones left after the PDF // export has filtered its list of subsettable fonts (for // which this method was created). The correct way would // be to have the GlyphCache search for the ImplFontData pFont psp::fontID aFont = pFont->GetFontId(); return PspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen ); } // --------------------------------------------------------------------------- void SvpSalGraphics::FreeEmbedFontData( const void* pData, long nLen ) { PspGraphics::DoFreeEmbedFontData( pData, nLen ); } void SvpSalGraphics::GetGlyphWidths( const ImplFontData* pFont, bool bVertical, Int32Vector& rWidths, Ucs2UIntMap& rUnicodeEnc ) { // in this context the pFont->GetFontId() is a valid PSP // font since they are the only ones left after the PDF // export has filtered its list of subsettable fonts (for // which this method was created). The correct way would // be to have the GlyphCache search for the ImplFontData pFont psp::fontID aFont = pFont->GetFontId(); PspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); } // --------------------------------------------------------------------------- bool SvpSalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) { const int nLevel = aGlyphId >> GF_FONTSHIFT; if( nLevel >= MAX_FALLBACK ) return false; ServerFont* pSF = m_pServerFont[ nLevel ]; if( !pSF ) return false; aGlyphId &= ~GF_FONTMASK; const GlyphMetric& rGM = pSF->GetGlyphMetric( aGlyphId ); rRect = Rectangle( rGM.GetOffset(), rGM.GetSize() ); return true; } // --------------------------------------------------------------------------- bool SvpSalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, B2DPolyPolygon& rPolyPoly ) { const int nLevel = aGlyphId >> GF_FONTSHIFT; if( nLevel >= MAX_FALLBACK ) return false; const ServerFont* pSF = m_pServerFont[ nLevel ]; if( !pSF ) return false; aGlyphId &= ~GF_FONTMASK; bool bOK = pSF->GetGlyphOutline( aGlyphId, rPolyPoly ); return bOK; } // --------------------------------------------------------------------------- SalLayout* SvpSalGraphics::GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ) { GenericSalLayout* pLayout = NULL; if( m_pServerFont[ nFallbackLevel ] ) pLayout = new ServerFontLayout( *m_pServerFont[ nFallbackLevel ] ); return pLayout; } // --------------------------------------------------------------------------- void SvpSalGraphics::DrawServerFontLayout( const ServerFontLayout& rSalLayout ) { // iterate over all glyphs in the layout Point aPos; sal_GlyphId aGlyphId; SvpGlyphPeer& rGlyphPeer = SvpGlyphCache::GetInstance().GetPeer(); for( int nStart = 0; rSalLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); ) { int nLevel = aGlyphId >> GF_FONTSHIFT; DBG_ASSERT( nLevel < MAX_FALLBACK, "SvpGDI: invalid glyph fallback level" ); ServerFont* pSF = m_pServerFont[ nLevel ]; if( !pSF ) continue; // get the glyph's alpha mask and adjust the drawing position aGlyphId &= ~GF_FONTMASK; B2IPoint aDstPoint( aPos.X(), aPos.Y() ); BitmapDeviceSharedPtr aAlphaMask = rGlyphPeer.GetGlyphBmp( *pSF, aGlyphId, m_eTextFmt, aDstPoint ); if( !aAlphaMask ) // ignore empty glyphs continue; // blend text color into target using the glyph's mask const B2IRange aSrcRect( B2ITuple(0,0), aAlphaMask->getSize() ); m_aDevice->drawMaskedColor( m_aTextColor, aAlphaMask, aSrcRect, aDstPoint, m_aClipMap ); } } // ===========================================================================