From 9b8213e2fadbc3c59f7e445098ae38cf266119cc Mon Sep 17 00:00:00 2001 From: Keith Stribley Date: Tue, 29 Jun 2010 14:14:34 +0630 Subject: [PATCH 1/2] graphite03: #i112730# updated graphite patch and improvements to glyph metric caching --- vcl/inc/vcl/graphite_adaptors.hxx | 4 +- vcl/inc/vcl/graphite_cache.hxx | 34 ++++++++++--- vcl/inc/vcl/graphite_layout.hxx | 15 +++++- vcl/source/glyphs/graphite_adaptors.cxx | 52 +++++++++++-------- vcl/source/glyphs/graphite_cache.cxx | 2 +- vcl/source/glyphs/graphite_layout.cxx | 67 ++++++++++++++++++------- vcl/source/glyphs/graphite_textsrc.hxx | 1 + vcl/win/source/gdi/winlayout.cxx | 2 +- 8 files changed, 125 insertions(+), 52 deletions(-) mode change 100644 => 100755 vcl/win/source/gdi/winlayout.cxx diff --git a/vcl/inc/vcl/graphite_adaptors.hxx b/vcl/inc/vcl/graphite_adaptors.hxx index 43c2e37a5fb2..e58881c9f463 100644 --- a/vcl/inc/vcl/graphite_adaptors.hxx +++ b/vcl/inc/vcl/graphite_adaptors.hxx @@ -86,8 +86,8 @@ namespace grutils // class VCL_DLLPUBLIC GraphiteFontAdaptor : public gr::Font { -typedef std::map > GlyphMetricMap; - + typedef std::map > GlyphMetricMap; + friend class GrFontHasher; public: static bool IsGraphiteEnabledFont(ServerFont &) throw(); diff --git a/vcl/inc/vcl/graphite_cache.hxx b/vcl/inc/vcl/graphite_cache.hxx index 5472b32dd62f..af1392ed4d4b 100644 --- a/vcl/inc/vcl/graphite_cache.hxx +++ b/vcl/inc/vcl/graphite_cache.hxx @@ -105,15 +105,16 @@ typedef std::pair GrRMEntr */ class GraphiteSegmentCache { +public: enum { // not really sure what good values are here, // bucket size should be >> cache size - SEG_BUCKET_SIZE = 4096, - SEG_CACHE_SIZE = 255 + SEG_BUCKET_FACTOR = 4, + SEG_DEFAULT_CACHE_SIZE = 2047 }; -public: - GraphiteSegmentCache() - : m_segMap(SEG_BUCKET_SIZE), + GraphiteSegmentCache(sal_uInt32 nSegCacheSize) + : m_segMap(nSegCacheSize * SEG_BUCKET_FACTOR), + m_nSegCacheSize(nSegCacheSize), m_oldestKey(NULL) {}; ~GraphiteSegmentCache() { @@ -224,6 +225,7 @@ public: private: GraphiteSegMap m_segMap; GraphiteRopeMap m_ropeMap; + sal_uInt32 m_nSegCacheSize; const xub_Unicode * m_oldestKey; const xub_Unicode * m_prevKey; }; @@ -236,7 +238,24 @@ typedef std::hash_map > GraphiteCach class GraphiteCacheHandler { public: - GraphiteCacheHandler() : m_cacheMap(255) {}; + GraphiteCacheHandler() : m_cacheMap(255) + { + const char * pEnvCache = getenv( "SAL_GRAPHITE_CACHE_SIZE" ); + if (pEnvCache != NULL) + { + int envCacheSize = atoi(pEnvCache); + if (envCacheSize <= 0) + m_nSegCacheSize = GraphiteSegmentCache::SEG_DEFAULT_CACHE_SIZE; + else + { + m_nSegCacheSize = envCacheSize; + } + } + else + { + m_nSegCacheSize = GraphiteSegmentCache::SEG_DEFAULT_CACHE_SIZE; + } + }; ~GraphiteCacheHandler() { GraphiteCacheMap::iterator i = m_cacheMap.begin(); @@ -257,12 +276,13 @@ public: { return m_cacheMap.find(fontHash)->second; } - GraphiteSegmentCache *pCache = new GraphiteSegmentCache(); + GraphiteSegmentCache *pCache = new GraphiteSegmentCache(m_nSegCacheSize); m_cacheMap[fontHash] = pCache; return pCache; } private: GraphiteCacheMap m_cacheMap; + sal_uInt32 m_nSegCacheSize; }; #endif diff --git a/vcl/inc/vcl/graphite_layout.hxx b/vcl/inc/vcl/graphite_layout.hxx index 520f4620cd90..765a154a9898 100644 --- a/vcl/inc/vcl/graphite_layout.hxx +++ b/vcl/inc/vcl/graphite_layout.hxx @@ -65,6 +65,19 @@ class GraphiteFontAdaptor; class GrSegRecord; // SAL/VCL types class ServerFont; + +#ifdef WNT +// The GraphiteWinFont is just a wrapper to enable GrFontHasher to be a friend +// so that UniqueCacheInfo can be called. +#include +class GraphiteWinFont : public gr::WinFont +{ + friend class GrFontHasher; +public: + GraphiteWinFont(HDC hdc) : gr::WinFont(hdc) {}; + virtual ~GraphiteWinFont() {}; +}; +#endif // Graphite types namespace gr { class Segment; class GlyphIterator; } namespace grutils { class GrFeatureParser; } @@ -98,7 +111,7 @@ public: iterator_pair_t neighbour_clusters(const_iterator) const; private: std::pair appendCluster(gr::Segment & rSeg, ImplLayoutArgs & rArgs, - bool bRtl, int nFirstCharInCluster, int nNextChar, + bool bRtl, float fSegmentAdvance, int nFirstCharInCluster, int nNextChar, int nFirstGlyphInCluster, int nNextGlyph, float fScaling, std::vector & rChar2Base, std::vector & rGlyph2Char, std::vector & rCharDxs, long & rDXOffset); diff --git a/vcl/source/glyphs/graphite_adaptors.cxx b/vcl/source/glyphs/graphite_adaptors.cxx index f66f5b48e39e..f82e3afe39c8 100644 --- a/vcl/source/glyphs/graphite_adaptors.cxx +++ b/vcl/source/glyphs/graphite_adaptors.cxx @@ -99,12 +99,18 @@ FontProperties::FontProperties(const FreetypeServerFont &font) throw() fItalic = false; } - // Get the font name. + // Get the font name, but prefix with file name hash in case + // there are 2 fonts on the system with the same face name + sal_Int32 nHashCode = font.GetFontFileName()->hashCode(); + ::rtl::OUStringBuffer nHashFaceName; + nHashFaceName.append(nHashCode, 16); const sal_Unicode * name = font.GetFontSelData().maName.GetBuffer(); - const size_t name_sz = std::min(sizeof szFaceName/sizeof(wchar_t)-1, - size_t(font.GetFontSelData().maName.Len())); + nHashFaceName.append(name); - std::copy(name, name + name_sz, szFaceName); + const size_t name_sz = std::min(sizeof szFaceName/sizeof(wchar_t)-1, + static_cast(nHashFaceName.getLength())); + + std::copy(nHashFaceName.getStr(), nHashFaceName.getStr() + name_sz, szFaceName); szFaceName[name_sz] = '\0'; } @@ -120,13 +126,13 @@ GraphiteFontAdaptor::GraphiteFontAdaptor(ServerFont & sfont, const sal_Int32 dpi mfEmUnits(static_cast(sfont).GetMetricsFT().y_ppem), mpFeatures(NULL) { - //std::wstring face_name(maFontProperties.szFaceName); const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( sfont.GetFontSelData().meLanguage ); -#ifdef DEBUG - printf("GraphiteFontAdaptor %lx\n", (long)this); -#endif rtl::OString name = rtl::OUStringToOString( sfont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 ); +#ifdef DEBUG + printf("GraphiteFontAdaptor %lx %s italic=%u bold=%u\n", (long)this, name.getStr(), + maFontProperties.fItalic, maFontProperties.fBold); +#endif sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1; if (nFeat > 0) { @@ -259,21 +265,24 @@ const void * GraphiteFontAdaptor::getTable(gr::fontTableId32 table_id, size_t * // Return the glyph's metrics in pixels. void GraphiteFontAdaptor::getGlyphMetrics(gr::gid16 nGlyphId, gr::Rect & aBounding, gr::Point & advances) { - // Graphite gets really confused if the glyphs have been transformed, so - // if orientation has been set we can't use the font's glyph cache - // unfortunately the font selection data, doesn't always have the orientation - // set, even if it was when the glyphs were cached, so we use our own cache. + // There used to be problems when orientation was set however, this no + // longer seems to be the case and the Glyph Metric cache in + // FreetypeServerFont is more efficient since it lasts between calls to VCL +#if 1 + const GlyphMetric & metric = mrFont.GetGlyphMetric(nGlyphId); -// const GlyphMetric & metric = mrFont.GetGlyphMetric(nGlyphId); -// -// aBounding.right = aBounding.left = metric.GetOffset().X(); -// aBounding.bottom = aBounding.top = -metric.GetOffset().Y(); -// aBounding.right += metric.GetSize().Width(); -// aBounding.bottom -= metric.GetSize().Height(); -// -// advances.x = metric.GetDelta().X(); -// advances.y = -metric.GetDelta().Y(); + aBounding.right = aBounding.left = metric.GetOffset().X(); + aBounding.bottom = aBounding.top = -metric.GetOffset().Y(); + aBounding.right += metric.GetSize().Width(); + aBounding.bottom -= metric.GetSize().Height(); + advances.x = metric.GetDelta().X(); + advances.y = -metric.GetDelta().Y(); + +#else + // The problem with the code below is that the cache only lasts + // as long as the life time of the GraphiteFontAdaptor, which + // is created once per call to X11SalGraphics::GetTextLayout GlyphMetricMap::const_iterator gm_itr = maGlyphMetricMap.find(nGlyphId); if (gm_itr != maGlyphMetricMap.end()) { @@ -321,6 +330,7 @@ void GraphiteFontAdaptor::getGlyphMetrics(gr::gid16 nGlyphId, gr::Rect & aBoundi // Now add an entry to our metrics map. maGlyphMetricMap[nGlyphId] = std::make_pair(aBounding, advances); } +#endif } #endif diff --git a/vcl/source/glyphs/graphite_cache.cxx b/vcl/source/glyphs/graphite_cache.cxx index 64bbb0a38d60..389accd631f0 100644 --- a/vcl/source/glyphs/graphite_cache.cxx +++ b/vcl/source/glyphs/graphite_cache.cxx @@ -105,7 +105,7 @@ GrSegRecord * GraphiteSegmentCache::cacheSegment(TextSourceAdaptor * adapter, gr // when the next key is added, the record for the prevKey's m_nextKey field // is updated to the newest key so that m_oldestKey can be updated to the // next oldest key when the record for m_oldestKey is deleted - if (m_segMap.size() > SEG_CACHE_SIZE) + if (m_segMap.size() > m_nSegCacheSize) { GraphiteSegMap::iterator oldestPair = m_segMap.find(reinterpret_cast(m_oldestKey)); // oldest record may no longer exist if a buffer was changed diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx index ff2fd8f306b1..ae7ec8246e33 100644 --- a/vcl/source/glyphs/graphite_layout.cxx +++ b/vcl/source/glyphs/graphite_layout.cxx @@ -56,6 +56,10 @@ #include #endif +#ifdef UNX +#include +#endif + #include #include @@ -175,7 +179,8 @@ GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs, glyph_range_t iGlyphs = rSegment.glyphs(); int nGlyphs = iGlyphs.second - iGlyphs.first; gr::GlyphIterator prevBase = iGlyphs.second; - float fMinX = rSegment.advanceWidth(); + float fSegmentAdvance = rSegment.advanceWidth(); + float fMinX = fSegmentAdvance; float fMaxX = 0.0f; rGlyph2Char.assign(nGlyphs, -1); long nDxOffset = 0; @@ -222,7 +227,8 @@ GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs, nFirstGlyphInCluster != nGlyphIndex) { std::pair aBounds = - appendCluster(rSegment, rArgs, bRtl, nFirstCharInCluster, + appendCluster(rSegment, rArgs, bRtl, + fSegmentAdvance, nFirstCharInCluster, nNextChar, nFirstGlyphInCluster, nGlyphIndex, fScaling, rChar2Base, rGlyph2Char, rCharDxs, nDxOffset); fMinX = std::min(aBounds.first, fMinX); @@ -285,7 +291,8 @@ GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs, nFirstGlyphInCluster != nGlyphIndex) { std::pair aBounds = - appendCluster(rSegment, rArgs, bRtl, nFirstCharInCluster, nNextChar, + appendCluster(rSegment, rArgs, bRtl, fSegmentAdvance, + nFirstCharInCluster, nNextChar, nFirstGlyphInCluster, nGlyphIndex, fScaling, rChar2Base, rGlyph2Char, rCharDxs, nDxOffset); fMinX = std::min(aBounds.first, fMinX); @@ -334,11 +341,11 @@ GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs, } } -std::pair GraphiteLayout::Glyphs::appendCluster(gr::Segment & rSeg, - ImplLayoutArgs & rArgs, bool bRtl, int nFirstCharInCluster, int nNextChar, - int nFirstGlyphInCluster, int nNextGlyph, float fScaling, - std::vector & rChar2Base, std::vector & rGlyph2Char, - std::vector & rCharDxs, long & rDXOffset) +std::pair GraphiteLayout::Glyphs::appendCluster(gr::Segment& rSeg, + ImplLayoutArgs & rArgs, bool bRtl,float fSegmentAdvance, + int nFirstCharInCluster, int nNextChar, int nFirstGlyphInCluster, + int nNextGlyph, float fScaling, std::vector & rChar2Base, + std::vector & rGlyph2Char, std::vector & rCharDxs, long & rDXOffset) { glyph_range_t iGlyphs = rSeg.glyphs(); int nGlyphs = iGlyphs.second - iGlyphs.first; @@ -402,9 +409,9 @@ std::pair GraphiteLayout::Glyphs::appendCluster(gr::Segment & rSeg, gr::GlyphInfo aGlyph = *(iGlyphs.first + j); if (j + nDelta >= nGlyphs || j + nDelta < 0) // at rhs ltr,rtl { - fNextOrigin = rSeg.advanceWidth(); - nNextOrigin = round(rSeg.advanceWidth() * fScaling + rDXOffset); - aBounds.second = std::max(rSeg.advanceWidth(), aBounds.second); + fNextOrigin = fSegmentAdvance; + nNextOrigin = round(fSegmentAdvance * fScaling + rDXOffset); + aBounds.second = std::max(fSegmentAdvance, aBounds.second); } else { @@ -546,7 +553,7 @@ GraphiteLayout::GraphiteLayout(const gr::Font & font, const grutils::GrFeaturePa // If true, it can cause end of line spaces to be hidden e.g. Doulos SIL maLayout.setStartOfLine(false); maLayout.setEndOfLine(false); -// maLayout.setDumbFallback(false); + maLayout.setDumbFallback(true); // trailing ws doesn't seem to always take affect if end of line is true maLayout.setTrailingWs(gr::ktwshAll); #ifdef GRLAYOUT_DEBUG @@ -598,6 +605,8 @@ bool GraphiteLayout::LayoutText(ImplLayoutArgs & rArgs) else delete pSegment; #else gr::Segment * pSegment = CreateSegment(rArgs); + if (!pSegment) + return false; bool success = LayoutGlyphs(rArgs, pSegment); delete pSegment; #endif @@ -649,7 +658,19 @@ public: #endif return hash; }; - +protected: + virtual void UniqueCacheInfo(std::wstring & stuFace, bool & fBold, bool & fItalic) + { +#ifdef WIN32 + dynamic_cast(mrRealFont).UniqueCacheInfo(stuFace, fBold, fItalic); +#else +#ifdef UNX + dynamic_cast(mrRealFont).UniqueCacheInfo(stuFace, fBold, fItalic); +#else +#error Unknown base type for gr::Font::UniqueCacheInfo +#endif +#endif + } private: gr::Font & mrRealFont; }; @@ -738,6 +759,14 @@ gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) } else { +#ifdef GRLAYOUT_DEBUG + fprintf(grLog(), "Gr::LayoutText failed: "); + for (int i = mnMinCharPos; i < limit; i++) + { + fprintf(grLog(), "%04x ", rArgs.mpStr[i]); + } + fprintf(grLog(), "\n"); +#endif clear(); return NULL; } @@ -897,7 +926,7 @@ long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const if (i > 0) pDXArray[i] -= mvCharDxs[i-1]; } #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"%d,%d,%ld ", (int)i, (int)mvCharDxs[i], pDXArray[i]); + fprintf(grLog(),"%d,%d,%d ", (int)i, (int)mvCharDxs[i], pDXArray[i]); #endif } //std::adjacent_difference(mvCharDxs.begin(), mvCharDxs.end(), pDXArray); @@ -1020,7 +1049,7 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector & rDelt #ifdef GRLAYOUT_DEBUG for (size_t iDx = 0; iDx < mvCharDxs.size(); iDx++) - fprintf(grLog(),"%d,%d,%ld ", (int)iDx, (int)mvCharDxs[iDx], args.mpDXArray[iDx]); + fprintf(grLog(),"%d,%d,%d ", (int)iDx, (int)mvCharDxs[iDx], args.mpDXArray[iDx]); fprintf(grLog(),"ApplyDx\n"); #endif bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL; @@ -1090,7 +1119,7 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector & rDelt } long nDWidth = nNewClusterWidth - nOrigClusterWidth; #ifdef GRLAYOUT_DEBUG - fprintf(grLog(), "c%d last glyph %d/%d\n", i, nLastGlyph, mvGlyphs.size()); + fprintf(grLog(), "c%lu last glyph %d/%lu\n", i, nLastGlyph, mvGlyphs.size()); #endif assert((nLastGlyph > -1) && (nLastGlyph < (signed)mvGlyphs.size())); mvGlyphs[nLastGlyph].mnNewWidth += nDWidth; @@ -1128,7 +1157,7 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector & rDelt std::copy(args.mpDXArray, args.mpDXArray + nChars, mvCharDxs.begin() + (args.mnMinCharPos - mnMinCharPos)); #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"ApplyDx %ld(%ld)\n", args.mpDXArray[nChars - 1], mnWidth); + fprintf(grLog(),"ApplyDx %d(%ld)\n", args.mpDXArray[nChars - 1], mnWidth); #endif mnWidth = args.mpDXArray[nChars - 1]; } @@ -1170,7 +1199,7 @@ void GraphiteLayout::kashidaJustify(std::vector& rDeltaWidths, sal_GlyphId } nKashidaCount = 1 + (nGapWidth / nKashidaWidth); #ifdef GRLAYOUT_DEBUG - printf("inserting %d kashidas at %ld\n", nKashidaCount, (*i).mnGlyphIndex); + printf("inserting %d kashidas at %u\n", nKashidaCount, (*i).mnGlyphIndex); #endif GlyphItem glyphItem = *i; Point aPos(0, 0); @@ -1309,7 +1338,7 @@ void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray pCaretXArray[i] = pCaretXArray[i+1] = 0; } #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"%d,%ld-%ld\t", nCharSlot, pCaretXArray[i], pCaretXArray[i+1]); + fprintf(grLog(),"%d,%d-%d\t", nCharSlot, pCaretXArray[i], pCaretXArray[i+1]); #endif } #ifdef GRLAYOUT_DEBUG diff --git a/vcl/source/glyphs/graphite_textsrc.hxx b/vcl/source/glyphs/graphite_textsrc.hxx index 2b9c705a5ea7..3912977cc9be 100644 --- a/vcl/source/glyphs/graphite_textsrc.hxx +++ b/vcl/source/glyphs/graphite_textsrc.hxx @@ -93,6 +93,7 @@ public: virtual ext_std::pair propertyRange(gr::toffset ich); virtual size_t getFontFeatures(gr::toffset ich, gr::FeatureSetting * prgfset); virtual bool sameSegment(gr::toffset ich1, gr::toffset ich2); + virtual bool featureVariations() { return false; } operator ImplLayoutArgs & () throw(); void setFeatures(const grutils::GrFeatureParser * pFeatures); diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx old mode 100644 new mode 100755 index ba19f2255646..6f0c98279e7b --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -2821,7 +2821,7 @@ sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth) class GraphiteWinLayout : public WinLayout { private: - mutable gr::WinFont mpFont; + mutable GraphiteWinFont mpFont; grutils::GrFeatureParser * mpFeatures; mutable GraphiteLayoutWinImpl maImpl; public: From 9b0e62544b3ef60377c04943f211f4543f2c3a7c Mon Sep 17 00:00:00 2001 From: "Herbert Duerr [hdu]" Date: Wed, 30 Jun 2010 13:26:06 +0200 Subject: [PATCH 2/2] #i112365# ignore missing fc_local.conf files but complain about parse error in them --- vcl/unx/source/fontmanager/fontconfig.cxx | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/vcl/unx/source/fontmanager/fontconfig.cxx b/vcl/unx/source/fontmanager/fontconfig.cxx index 816c8fb0b4c4..69c5330977bd 100644 --- a/vcl/unx/source/fontmanager/fontconfig.cxx +++ b/vcl/unx/source/fontmanager/fontconfig.cxx @@ -854,19 +854,22 @@ bool PrintFontManager::addFontconfigDir( const rtl::OString& rDirName ) fprintf( stderr, "FcConfigAppFontAddDir( \"%s\") => %d\n", pDirName, bRet ); #endif - if( bDirOk ) - { - const rtl::OString aConfFileName = rDirName + "/fc_local.conf"; - bool bCfgOk = rWrapper.FcConfigParseAndLoad( rWrapper.FcConfigGetCurrent(), - (FcChar8*)aConfFileName.getStr(), FcTrue ); - (void)bCfgOk; // silence compiler warning + if( !bDirOk ) + return false; -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk ); -#endif + // load dir-specific fc-config file too if available + const rtl::OString aConfFileName = rDirName + "/fc_local.conf"; + FILE* pCfgFile = fopen( aConfFileName.getStr(), "rb" ); + if( pCfgFile ) + { + fclose( pCfgFile); + bool bCfgOk = rWrapper.FcConfigParseAndLoad( rWrapper.FcConfigGetCurrent(), + (FcChar8*)aConfFileName.getStr(), FcTrue ); + if( !bCfgOk ) + fprintf( stderr, "FcConfigParseAndLoad( \"%s\") => %d\n", aConfFileName.getStr(), bCfgOk ); } - return bDirOk; + return true; } static void addtopattern(FontCfgWrapper& rWrapper, FcPattern *pPattern,