diff options
-rw-r--r-- | comphelper/qa/weakbag/test_weakbag_noadditional.cxx | 2 | ||||
-rw-r--r-- | vcl/inc/vcl/graphite_adaptors.hxx | 145 | ||||
-rw-r--r-- | vcl/inc/vcl/graphite_cache.hxx | 290 | ||||
-rw-r--r-- | vcl/inc/vcl/graphite_features.hxx | 47 | ||||
-rw-r--r-- | vcl/inc/vcl/graphite_layout.hxx | 113 | ||||
-rw-r--r-- | vcl/inc/vcl/graphite_serverfont.hxx | 25 | ||||
-rw-r--r-- | vcl/source/glyphs/gcach_ftyp.cxx | 65 | ||||
-rw-r--r-- | vcl/source/glyphs/gcach_ftyp.hxx | 15 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_adaptors.cxx | 339 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_cache.cxx | 201 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_features.cxx | 233 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_layout.cxx | 958 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_serverfont.cxx | 100 | ||||
-rw-r--r-- | vcl/source/glyphs/makefile.mk | 8 | ||||
-rw-r--r-- | vcl/unx/source/gdi/pspgraphics.cxx | 8 | ||||
-rw-r--r-- | vcl/unx/source/gdi/salgdi3.cxx | 11 | ||||
-rwxr-xr-x | vcl/util/makefile.mk | 6 | ||||
-rw-r--r-- | vcl/win/inc/salgdi.h | 29 | ||||
-rw-r--r-- | vcl/win/source/gdi/salgdi.cxx | 3 | ||||
-rw-r--r-- | vcl/win/source/gdi/salgdi3.cxx | 202 | ||||
-rw-r--r-- | vcl/win/source/gdi/winlayout.cxx | 116 |
21 files changed, 1031 insertions, 1885 deletions
diff --git a/comphelper/qa/weakbag/test_weakbag_noadditional.cxx b/comphelper/qa/weakbag/test_weakbag_noadditional.cxx index 9f3bfe5061ab..b809c701cea8 100644 --- a/comphelper/qa/weakbag/test_weakbag_noadditional.cxx +++ b/comphelper/qa/weakbag/test_weakbag_noadditional.cxx @@ -28,6 +28,6 @@ #include <cppunit/plugin/TestPlugIn.h> -CPPUNIT_PLUGIN_IMPLEMENT(); +// CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/graphite_adaptors.hxx b/vcl/inc/vcl/graphite_adaptors.hxx deleted file mode 100644 index 439a87bda947..000000000000 --- a/vcl/inc/vcl/graphite_adaptors.hxx +++ /dev/null @@ -1,145 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -#ifndef _SV_GRAPHITEADAPTORS_HXX -#define _SV_GRAPHITEADAPTORS_HXX - -// We need this to enable namespace support in libgrengine headers. -#define GR_NAMESPACE - -// Standard Library -#include <stdexcept> -// Platform - -#include <tools/svwin.h> - -#include <svsys.h> - -#include <vcl/salgdi.hxx> - -#include <vcl/sallayout.hxx> - -// Module -#include "vcl/dllapi.h" - -// Libraries -#include <graphite/GrClient.h> -#include <graphite/Font.h> -#include <graphite/ITextSource.h> - -// Module type definitions and forward declarations. -// -#ifndef MSC -// SAL/VCL types -class ServerFont; -class FreetypeServerFont; - -// Graphite types - -struct FontProperties : gr::FontProps -{ - FontProperties(const FreetypeServerFont & font) throw(); -}; - -namespace grutils -{ - class GrFeatureParser; -} - -// This class adapts the Sal font and graphics services to form required by -// the Graphite engine. -// @author tse -// -class VCL_DLLPUBLIC GraphiteFontAdaptor : public gr::Font -{ - typedef std::map<const gr::gid16, std::pair<gr::Rect, gr::Point> > GlyphMetricMap; - friend class GrFontHasher; -public: - static bool IsGraphiteEnabledFont(ServerFont &) throw(); - - GraphiteFontAdaptor(ServerFont & font, const sal_Int32 dpi_x, const sal_Int32 dpi_y); - GraphiteFontAdaptor(const GraphiteFontAdaptor &) throw(); - ~GraphiteFontAdaptor() throw(); - - gr::Font * copyThis(); - - // Basic attribute accessors. - virtual float ascent(); - virtual float descent(); - virtual bool bold(); - virtual bool italic(); - virtual float height(); - virtual unsigned int getDPIx(); - virtual unsigned int getDPIy(); - - // Font access methods. - virtual const void * getTable(gr::fontTableId32 tableID, size_t * pcbSize); - virtual void getFontMetrics(float * ascent_out, float * descent_out = 0, float * em_square_out = 0); - - // Glyph metrics. - virtual void getGlyphMetrics(gr::gid16 glyphID, gr::Rect & boundingBox, gr::Point & advances); - - // Adaptor attributes. - const FontProperties & fontProperties() const throw(); - FreetypeServerFont & font() const throw(); - const grutils::GrFeatureParser * features() const { return mpFeatures; }; - -private: - virtual void UniqueCacheInfo(std::wstring &, bool &, bool &); - - FreetypeServerFont& mrFont; - FontProperties maFontProperties; - const unsigned int mnDpiX, mnDpiY; - const float mfAscent, - mfDescent, - mfEmUnits; - grutils::GrFeatureParser * mpFeatures; - GlyphMetricMap maGlyphMetricMap; -}; - -// Partial implementation of class GraphiteFontAdaptor. -// -inline const FontProperties & GraphiteFontAdaptor::fontProperties() const throw() { - return maFontProperties; -} - -inline FreetypeServerFont & GraphiteFontAdaptor::font() const throw() { - return mrFont; -} -#endif // not MFC - -// Partial implementation of class TextSourceAdaptor. -// -//inline const ImplLayoutArgs & TextSourceAdaptor::layoutArgs() const throw() { -// return _layout_args; -//} - - -#endif // _SV_GRAPHITEADAPTORS_HXX - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/graphite_cache.hxx b/vcl/inc/vcl/graphite_cache.hxx deleted file mode 100644 index ecf667fdbaaf..000000000000 --- a/vcl/inc/vcl/graphite_cache.hxx +++ /dev/null @@ -1,290 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// Description: Classes to cache Graphite Segments to try to improve -// rendering performance. - -#ifndef GraphiteSegmentCache_h -#define GraphiteSegmentCache_h - -#include <tools/solar.h> -#include <rtl/ustring.h> - -#define GRCACHE_REUSE_VECTORS 1 - -#include <boost/unordered_map.hpp> - -class TextSourceAdaptor; -/** -* GrSegRecord stores a Graphite Segment and its associated text -*/ -class GrSegRecord { -public: - GrSegRecord(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl); - - ~GrSegRecord(); - - void reuse(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl); - - void clearVectors(); - void clear(); -#ifdef GRCACHE_REUSE_VECTORS - void setGlyphVectors(long nWidth, GraphiteLayout::Glyphs & vGlyphs, std::vector<int> vCharDxs, - std::vector<int> & vChar2Base, std::vector<int> & vGlyph2Char, float fScale) - { - clearVectors(); - mnWidth = nWidth; - m_fontScale = fScale; - mvGlyphs.insert(mvGlyphs.begin(), vGlyphs.begin(), vGlyphs.end()); - mvCharDxs.insert(mvCharDxs.begin(),vCharDxs.begin(),vCharDxs.end()); - mvChar2BaseGlyph.insert(mvChar2BaseGlyph.begin(),vChar2Base.begin(),vChar2Base.end()); - mvGlyph2Char.insert(mvGlyph2Char.begin(),vGlyph2Char.begin(),vGlyph2Char.end()); - } -#endif - gr::Segment * getSegment() { return m_seg; } - TextSourceAdaptor * getTextSrc() { return m_text; } - void unlock() { --m_lockCount; } - bool isRtl() const { return mbIsRtl; } -#ifdef GRCACHE_REUSE_VECTORS - const long & width() const { return mnWidth; } - const GraphiteLayout::Glyphs & glyphs() const { return mvGlyphs; } - const std::vector<int> & charDxs() const { return mvCharDxs; } - const std::vector<int> & char2BaseGlyph() const { return mvChar2BaseGlyph; } - const std::vector<int> & glyph2Char() const { return mvGlyph2Char; } - float & fontScale() { return m_fontScale; } -#endif -private: - rtl::OUString * m_rope; - TextSourceAdaptor * m_text; - gr::Segment * m_seg; - const xub_Unicode * m_nextKey; - const xub_Unicode* m_pStr; - size_t m_startChar; - float m_fontScale; - long mnWidth; - GraphiteLayout::Glyphs mvGlyphs; // glyphs in display order - std::vector<int> mvCharDxs; // right hand side x offset of each glyph - std::vector<int> mvChar2BaseGlyph; - std::vector<int> mvGlyph2Char; - bool mbIsRtl; - int m_lockCount; - friend class GraphiteSegmentCache; -}; - -typedef boost::unordered_map<long, GrSegRecord*, boost::hash<long> > GraphiteSegMap; -typedef boost::unordered_multimap<size_t, GrSegRecord*> GraphiteRopeMap; -typedef std::pair<GraphiteRopeMap::iterator, GraphiteRopeMap::iterator> GrRMEntry; - -/** -* GraphiteSegmentCache contains the cached Segments for one particular font size -*/ -class GraphiteSegmentCache -{ -public: - enum { - // not really sure what good values are here, - // bucket size should be >> cache size - SEG_BUCKET_FACTOR = 4, - SEG_DEFAULT_CACHE_SIZE = 2047 - }; - GraphiteSegmentCache(sal_uInt32 nSegCacheSize) - : m_segMap(nSegCacheSize * SEG_BUCKET_FACTOR), - m_nSegCacheSize(nSegCacheSize), - m_oldestKey(NULL) {}; - ~GraphiteSegmentCache() - { - m_ropeMap.clear(); - GraphiteSegMap::iterator i = m_segMap.begin(); - while (i != m_segMap.end()) - { - GrSegRecord *r = i->second; - delete r; - ++i; - } - m_segMap.clear(); - }; - GrSegRecord * getSegment(ImplLayoutArgs & layoutArgs, bool bIsRtl, int segCharLimit) - { - GrSegRecord * found = NULL; - // try to find a segment starting at correct place, if not, try to find a - // match for the complete buffer - GraphiteSegMap::iterator iMap = - m_segMap.find(reinterpret_cast<long>(layoutArgs.mpStr + - layoutArgs.mnMinCharPos)); - if (iMap != m_segMap.end()) - { - found = iMap->second; - } - else - { - iMap = m_segMap.find(reinterpret_cast<long>(layoutArgs.mpStr)); - if (iMap != m_segMap.end()) - { - found = iMap->second; - } - } - if (found) - { - if (found->m_seg->startCharacter() <= layoutArgs.mnMinCharPos && - found->m_seg->stopCharacter() >= layoutArgs.mnEndCharPos) - { - DBG_ASSERT(found && found->m_seg, "null entry in GraphiteSegmentCache"); - // restore original start character, in case it has changed - found->m_seg->setTextSourceOffset(found->m_startChar); - // check that characters are the same, at least in the range of - // interest - // We could use substr and ==, but substr does a copy, - // so its probably faster to do it like this - for (int i = layoutArgs.mnMinCharPos; i < segCharLimit; i++) - { - //if (!found->m_rope->match(rtl::OUString(layoutArgs.mpStr[i], layoutArgs.mnLength), i - found->m_seg->startCharacter())) - if (found->m_rope->getStr()[i-found->m_seg->startCharacter()] != layoutArgs.mpStr[i]) - return NULL; - } - if (found->isRtl() != bIsRtl) - { - return NULL; - } - if (found->m_seg->stopCharacter() > layoutArgs.mnEndCharPos && - static_cast<int>(found->char2BaseGlyph().size()) > layoutArgs.mnEndCharPos) - { - // check that the requested end character isn't mid cluster - if (found->char2BaseGlyph()[layoutArgs.mnEndCharPos-layoutArgs.mnMinCharPos] == -1) - { - return NULL; - } - } -// if (found->m_lockCount != 0) -// OutputDebugString("Multple users of SegRecord!"); - found->m_lockCount++; - } - else found = NULL; - } - else - { - // the pointers aren't the same, but we might still have the same text in a segment - // this is expecially needed when editing a large paragraph - // each edit changes the pointers, but if we don't reuse any segments it gets very - // slow. - rtl::OUString * rope = new rtl::OUString(layoutArgs.mpStr + layoutArgs.mnMinCharPos, - segCharLimit - layoutArgs.mnMinCharPos); - if (!rope) return NULL; - size_t nHash = (*(rope)).hashCode(); - GrRMEntry range = m_ropeMap.equal_range(nHash); - while (range.first != range.second) - { - found = range.first->second; - if (found->m_lockCount == 0) - { - if(rope->match(*(found->m_rope))) - { - // found, but the pointers are all wrong - found->m_seg->setTextSourceOffset(layoutArgs.mnMinCharPos); - // the switch is done in graphite_layout.cxx - //found->m_text->switchLayoutArgs(layoutArgs); - found->m_lockCount++; - break; - } - else - found = NULL; - } - else - found = NULL; - ++(range.first); - } - delete rope; - } - return found; - }; - GrSegRecord * cacheSegment(TextSourceAdaptor * adapter, gr::Segment * seg, bool bIsRtl); -private: - GraphiteSegMap m_segMap; - GraphiteRopeMap m_ropeMap; - sal_uInt32 m_nSegCacheSize; - const xub_Unicode * m_oldestKey; - const xub_Unicode * m_prevKey; -}; - -typedef boost::unordered_map<int, GraphiteSegmentCache *, boost::hash<int> > GraphiteCacheMap; - -/** -* GraphiteCacheHandler maps a particular font, style, size to a GraphiteSegmentCache -*/ -class GraphiteCacheHandler -{ -public: - 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(); - while (i != m_cacheMap.end()) - { - GraphiteSegmentCache *r = i->second; - delete r; - ++i; - } - m_cacheMap.clear(); - }; - - static GraphiteCacheHandler instance; - - GraphiteSegmentCache * getCache(sal_Int32 & fontHash) - { - if (m_cacheMap.count(fontHash) > 0) - { - return m_cacheMap.find(fontHash)->second; - } - GraphiteSegmentCache *pCache = new GraphiteSegmentCache(m_nSegCacheSize); - m_cacheMap[fontHash] = pCache; - return pCache; - } -private: - GraphiteCacheMap m_cacheMap; - sal_uInt32 m_nSegCacheSize; -}; - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/graphite_features.hxx b/vcl/inc/vcl/graphite_features.hxx index 5dda6825ce76..742ad2c3f5f5 100644 --- a/vcl/inc/vcl/graphite_features.hxx +++ b/vcl/inc/vcl/graphite_features.hxx @@ -30,12 +30,17 @@ // Parse a string of features specified as ; separated pairs. // e.g. // 1001=1&2002=2&fav1=0 -#include <graphite/GrClient.h> -#include <graphite/Font.h> -#include <graphite/GrFeature.h> +#include <sal/types.h> +#include <rtl/ustring.hxx> +#include <graphite2/Font.h> namespace grutils { + union FeatId + { + gr_uint32 num; + unsigned char label[5]; + }; class GrFeatureParser { @@ -44,32 +49,30 @@ namespace grutils static const char FEAT_PREFIX; static const char FEAT_SEPARATOR; static const char FEAT_ID_VALUE_SEPARATOR; - GrFeatureParser(gr::Font & font, const std::string features, const std::string lang); - GrFeatureParser(gr::Font & font, const std::string lang); - GrFeatureParser(const GrFeatureParser & copy); + GrFeatureParser(const gr_face * face, const ::rtl::OString features, const ::rtl::OString lang); + GrFeatureParser(const gr_face * face, const ::rtl::OString lang); ~GrFeatureParser(); - size_t getFontFeatures(gr::FeatureSetting settings[MAX_FEATURES]) const; + //size_t getFontFeatures(gr::FeatureSetting settings[MAX_FEATURES]) const; bool parseErrors() { return mbErrors; }; - static bool isValid(gr::Font & font, gr::FeatureSetting & setting); - gr::isocode getLanguage() const { return maLang; }; - bool hasLanguage() const { return (maLang.rgch[0] != '\0'); } - sal_Int32 hashCode() const; + //static bool isValid(gr::Font & font, gr::FeatureSetting & setting); + gr_uint32 getLanguage() const { return maLang.num; }; + bool hasLanguage() const { return (maLang.label[0] != '\0'); } + sal_Int32 hashCode() const { return mnHash; } + size_t numFeatures() const { return mnNumSettings; } + gr_feature_val * values() const { return mpSettings; }; private: - void setLang(gr::Font & font, const std::string & lang); - bool isCharId(const std::string & id, size_t offset, size_t length); - int getCharId(const std::string & id, size_t offset, size_t length); - int getIntValue(const std::string & id, size_t offset, size_t length); + GrFeatureParser(const GrFeatureParser & copy); + void setLang(const gr_face * face, const ::rtl::OString & lang); + bool isCharId(const ::rtl::OString & id, size_t offset, size_t length); + gr_uint32 getCharId(const ::rtl::OString & id, size_t offset, size_t length); + short getIntValue(const ::rtl::OString & id, size_t offset, size_t length); size_t mnNumSettings; - gr::isocode maLang; + FeatId maLang; bool mbErrors; - gr::FeatureSetting maSettings[64]; + sal_uInt32 mnHash; + gr_feature_val * mpSettings; }; - union FeatId - { - gr::featid num; - unsigned char label[5]; - }; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/graphite_layout.hxx b/vcl/inc/vcl/graphite_layout.hxx index 60c7de16b1dd..2da56addc1e3 100644 --- a/vcl/inc/vcl/graphite_layout.hxx +++ b/vcl/inc/vcl/graphite_layout.hxx @@ -34,29 +34,19 @@ // We need this to enable namespace support in libgrengine headers. #define GR_NAMESPACE -#define GRCACHE 1 - // Standard Library #include <memory> #include <vector> +#include <map> #include <utility> // Libraries -#include <graphite/GrClient.h> -#include <graphite/Font.h> -#include <graphite/GrConstants.h> -#include <graphite/GrAppData.h> -#include <graphite/SegmentAux.h> +#include <graphite2/Font.h> +#include <graphite2/Segment.h> // Platform #include <vcl/sallayout.hxx> #include <vcl/dllapi.h> // Module -// For backwards compatibility with 2.4.x -#if (SUPD == 680) -typedef sal_Int32 sal_GlyphId; -#endif - - // Module type definitions and forward declarations. // class TextSourceAdaptor; @@ -65,21 +55,38 @@ 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 <graphite/WinFont.h> -class GraphiteWinFont : public gr::WinFont +// Graphite types +namespace grutils { class GrFeatureParser; } + +class GraphiteFaceWrapper { - friend class GrFontHasher; public: - GraphiteWinFont(HDC hdc) : gr::WinFont(hdc) {}; - virtual ~GraphiteWinFont() {}; + typedef std::map<int, gr_font*> GrFontMap; + GraphiteFaceWrapper(gr_face * pFace) : m_pFace(pFace) {} + ~GraphiteFaceWrapper() + { + GrFontMap::iterator i = m_fonts.begin(); + while (i != m_fonts.end()) + gr_font_destroy((*i++).second); + m_fonts.clear(); + gr_face_destroy(m_pFace); + } + const gr_face * face() const { return m_pFace; } + gr_font * font(int ppm) const + { + GrFontMap::const_iterator i = m_fonts.find(ppm); + if (i != m_fonts.end()) + return i->second; + return NULL; + }; + void addFont(int ppm, gr_font * pFont) + { + m_fonts[ppm] = pFont; + } +private: + gr_face * m_pFace; + GrFontMap m_fonts; }; -#endif -// Graphite types -namespace gr { class Segment; class GlyphIterator; } -namespace grutils { class GrFeatureParser; } // This class uses the SIL Graphite engine to provide complex text layout services to the VCL // @author tse @@ -87,63 +94,38 @@ namespace grutils { class GrFeatureParser; } class VCL_DLLPUBLIC GraphiteLayout : public SalLayout { public: - // Mask to allow Word break status to be stored within mvChar2BaseGlyph - enum { - WORD_BREAK_BEFORE = 0x40000000, - HYPHEN_BREAK_BEFORE = 0x80000000, - BREAK_MASK = 0xC0000000, - GLYPH_INDEX_MASK = 0x3FFFFFFF - } LineBreakMask; class Glyphs : public std::vector<GlyphItem> { public: typedef std::pair<Glyphs::const_iterator, Glyphs::const_iterator> iterator_pair_t; - void fill_from(gr::Segment & rSeg, ImplLayoutArgs & rArgs, - bool bRtl, long &rWidth, float fScaling, - std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, - std::vector<int> & rCharDxs); - void move_glyph(Glyphs::iterator, long dx); - - const_iterator cluster_base(const_iterator) const; - iterator_pair_t neighbour_clusters(const_iterator) const; - private: - std::pair<float,float> appendCluster(gr::Segment & rSeg, ImplLayoutArgs & rArgs, - bool bRtl, float fSegmentAdvance, int nFirstCharInCluster, int nNextChar, - int nFirstGlyphInCluster, int nNextGlyph, float fScaling, - std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, - std::vector<int> & rCharDxs, long & rDXOffset); - void append(gr::Segment & rSeg, ImplLayoutArgs & rArgs, gr::GlyphInfo & rGi, float nextGlyphOrigin, float fScaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset, bool bIsBase); }; mutable Glyphs mvGlyphs; void clear(); private: - TextSourceAdaptor * mpTextSrc; // Text source. - gr::LayoutEnvironment maLayout; - const gr::Font &mrFont; + const gr_face * mpFace; // not owned by layout + gr_font * mpFont; // owned by layout + int mnSegCharOffset; // relative to ImplLayoutArgs::mpStr long mnWidth; - std::vector<int> mvCharDxs; std::vector<int> mvChar2BaseGlyph; std::vector<int> mvGlyph2Char; + std::vector<int> mvCharDxs; + std::vector<int> mvCharBreaks; float mfScaling; const grutils::GrFeatureParser * mpFeatures; public: - GraphiteLayout(const gr::Font & font, const grutils::GrFeatureParser * features = NULL) throw(); + GraphiteLayout(const gr_face * pFace, gr_font * pFont = NULL, + const grutils::GrFeatureParser * features = NULL) throw(); // used by upper layers virtual bool LayoutText( ImplLayoutArgs& ); // first step of layout // split into two stages to allow dc to be restored on the segment -#ifdef GRCACHE - gr::Segment * CreateSegment(ImplLayoutArgs& rArgs, GrSegRecord ** pRecord = NULL); - bool LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment, GrSegRecord * pSegRecord); -#else - gr::Segment * CreateSegment(ImplLayoutArgs& rArgs); - bool LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment); -#endif + gr_segment * CreateSegment(ImplLayoutArgs& rArgs); + bool LayoutGlyphs(ImplLayoutArgs& rArgs, gr_segment * pSegment); virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting positions @@ -167,19 +149,22 @@ public: virtual void DrawText(SalGraphics&) const {}; virtual ~GraphiteLayout() throw(); + void SetFont(gr_font * pFont) { mpFont = pFont; } void SetFeatures(grutils::GrFeatureParser * aFeature) { mpFeatures = aFeature; } void SetFontScale(float s) { mfScaling = s; }; - const TextSourceAdaptor * textSrc() const { return mpTextSrc; }; virtual sal_GlyphId getKashidaGlyph(int & width) = 0; void kashidaJustify(std::vector<int> & rDeltaWidth, sal_GlyphId, int width); static const int EXTRA_CONTEXT_LENGTH; private: - int glyph_to_char(Glyphs::iterator); - std::pair<int,int> glyph_to_chars(const GlyphItem &) const; - - std::pair<long,long> caret_positions(size_t) const; void expandOrCondense(ImplLayoutArgs &rArgs); + void fillFrom(gr_segment * rSeg, ImplLayoutArgs & rArgs, float fScaling); + + void append(gr_segment * pSeg, + ImplLayoutArgs & rArgs, + const gr_slot * pSlot, + float nextGlyphOrigin, float fScaling, + long & rDXOffset, bool bIsBase, int baseChar); }; diff --git a/vcl/inc/vcl/graphite_serverfont.hxx b/vcl/inc/vcl/graphite_serverfont.hxx index 06a61db42f80..8de41337feae 100644 --- a/vcl/inc/vcl/graphite_serverfont.hxx +++ b/vcl/inc/vcl/graphite_serverfont.hxx @@ -33,20 +33,20 @@ #define GR_NAMESPACE #ifndef MSC -#include <vcl/graphite_layout.hxx> -#include <vcl/graphite_adaptors.hxx> +#include "vcl/graphite_layout.hxx" // Modules class VCL_DLLPUBLIC GraphiteLayoutImpl : public GraphiteLayout { public: - GraphiteLayoutImpl(const gr::Font & font, const grutils::GrFeatureParser * features, GraphiteFontAdaptor * pFont) throw() - : GraphiteLayout(font, features), mpFont(pFont) {}; + GraphiteLayoutImpl(const gr_face * pFace, + ServerFont & rServerFont) throw() + : GraphiteLayout(pFace), mrServerFont(rServerFont) {}; virtual ~GraphiteLayoutImpl() throw() {}; virtual sal_GlyphId getKashidaGlyph(int & width); private: - GraphiteFontAdaptor * mpFont; + ServerFont & mrServerFont; }; // This class implments the server font specific parts. @@ -55,13 +55,19 @@ private: class VCL_DLLPUBLIC GraphiteServerFontLayout : public ServerFontLayout { private: - mutable GraphiteFontAdaptor * mpFont; // mutable so that the DrawOffset/DrawBase can be set mutable GraphiteLayoutImpl maImpl; + grutils::GrFeatureParser * mpFeatures; + const sal_Unicode * mpStr; public: - GraphiteServerFontLayout(GraphiteFontAdaptor * font) throw(); + GraphiteServerFontLayout(ServerFont& pServerFont) throw(); - virtual bool LayoutText( ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); return maImpl.LayoutText(rArgs); }; // first step of layout + virtual bool LayoutText( ImplLayoutArgs& rArgs) + { + mpStr = rArgs.mpStr; + SalLayout::AdjustLayout(rArgs); + return maImpl.LayoutText(rArgs); + }; // first step of layout virtual void AdjustLayout( ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); @@ -89,8 +95,9 @@ public: virtual ~GraphiteServerFontLayout() throw(); + static bool IsGraphiteEnabledFont(ServerFont * pServerFont); // For use with PspGraphics - const sal_Unicode* getTextPtr() const; + const sal_Unicode* getTextPtr() const { return mpStr; }; int getMinCharPos() const { return mnMinCharPos; } int getMaxCharPos() const { return mnEndCharPos; } }; diff --git a/vcl/source/glyphs/gcach_ftyp.cxx b/vcl/source/glyphs/gcach_ftyp.cxx index 43cf4310a879..e9b8546801c0 100644 --- a/vcl/source/glyphs/gcach_ftyp.cxx +++ b/vcl/source/glyphs/gcach_ftyp.cxx @@ -39,6 +39,10 @@ #include "vcl/svapp.hxx" #include "vcl/outfont.hxx" #include "vcl/impfont.hxx" +#ifdef ENABLE_GRAPHITE +#include <graphite2/Font.h> +#include "vcl/graphite_layout.hxx" +#endif #include "tools/poly.hxx" #include "basegfx/matrix/b2dhommatrix.hxx" @@ -290,6 +294,33 @@ void FtFontFile::Unmap() mpFileMap = NULL; } +#ifdef ENABLE_GRAPHITE +// wrap FtFontInfo's table function +const void * graphiteFontTable(const void* appFaceHandle, unsigned int name, size_t *len) +{ + const FtFontInfo * pFontInfo = reinterpret_cast<const FtFontInfo*>(appFaceHandle); + typedef union { + char m_c[5]; + unsigned int m_id; + } TableId; + TableId tableId; + tableId.m_id = name; +#ifndef WORDS_BIGENDIAN + TableId swapped; + swapped.m_c[3] = tableId.m_c[0]; + swapped.m_c[2] = tableId.m_c[1]; + swapped.m_c[1] = tableId.m_c[2]; + swapped.m_c[0] = tableId.m_c[3]; + tableId.m_id = swapped.m_id; +#endif + tableId.m_c[4] = '\0'; + ULONG nLength = 0; + const void * pTable = static_cast<const void*>(pFontInfo->GetTable(tableId.m_c, &nLength)); + if (len) *len = static_cast<size_t>(nLength); + return pTable; +} +#endif + // ======================================================================= FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes, @@ -298,9 +329,15 @@ FtFontInfo::FtFontInfo( const ImplDevFontAttributes& rDevFontAttributes, : maFaceFT( NULL ), mpFontFile( FtFontFile::FindFontFile( rNativeFileName ) ), +#ifdef ENABLE_GRAPHITE + mpGraphiteFace(NULL), +#endif mnFaceNum( nFaceNum ), mnRefCount( 0 ), mnSynthetic( nSynthetic ), +#ifdef ENABLE_GRAPHITE + mbCheckedGraphite(false), +#endif mnFontId( nFontId ), maDevFontAttributes( rDevFontAttributes ), mpChar2Glyph( NULL ), @@ -323,6 +360,10 @@ FtFontInfo::~FtFontInfo() delete mpExtraKernInfo; delete mpChar2Glyph; delete mpGlyph2Char; +#ifdef ENABLE_GRAPHITE + if (mpGraphiteFace) + delete mpGraphiteFace; +#endif } void FtFontInfo::InitHashes() const @@ -351,6 +392,30 @@ FT_FaceRec_* FtFontInfo::GetFaceFT() return maFaceFT; } +#ifdef ENABLE_GRAPHITE +GraphiteFaceWrapper * FtFontInfo::GetGraphiteFace() +{ + if (mbCheckedGraphite) + return mpGraphiteFace; + // test for graphite here so that it is cached most efficiently + if (GetTable("Silf", 0)) + { + int graphiteSegCacheSize = 10000; + static const char* pGraphiteCacheStr = getenv( "SAL_GRAPHITE_CACHE_SIZE" ); + graphiteSegCacheSize = pGraphiteCacheStr ? (atoi(pGraphiteCacheStr)) : 0; + gr_face * pGraphiteFace; + if (graphiteSegCacheSize > 500) + pGraphiteFace = gr_make_face_with_seg_cache(this, graphiteFontTable, graphiteSegCacheSize, gr_face_cacheCmap); + else + pGraphiteFace = gr_make_face(this, graphiteFontTable, gr_face_cacheCmap); + if (pGraphiteFace) + mpGraphiteFace = new GraphiteFaceWrapper(pGraphiteFace); + } + mbCheckedGraphite = true; + return mpGraphiteFace; +} +#endif + // ----------------------------------------------------------------------- void FtFontInfo::ReleaseFaceFT( FT_FaceRec_* pFaceFT ) diff --git a/vcl/source/glyphs/gcach_ftyp.hxx b/vcl/source/glyphs/gcach_ftyp.hxx index f37404033611..1aa0c58157d5 100644 --- a/vcl/source/glyphs/gcach_ftyp.hxx +++ b/vcl/source/glyphs/gcach_ftyp.hxx @@ -36,6 +36,10 @@ #include FT_FREETYPE_H class FreetypeServerFont; +#ifdef ENABLE_GRAPHITE +class GraphiteFaceWrapper; +#endif + struct FT_GlyphRec_; // ----------------------------------------------------------------------- @@ -81,6 +85,9 @@ public: const unsigned char* GetTable( const char*, ULONG* pLength=0 ) const; FT_FaceRec_* GetFaceFT(); +#ifdef ENABLE_GRAPHITE + GraphiteFaceWrapper* GetGraphiteFace(); +#endif void ReleaseFaceFT( FT_FaceRec_* ); const ::rtl::OString* GetFontFileName() const { return mpFontFile->GetFileName(); } @@ -105,7 +112,10 @@ private: const int mnFaceNum; int mnRefCount; const int mnSynthetic; - +#ifdef ENABLE_GRAPHITE + bool mbCheckedGraphite; + GraphiteFaceWrapper * mpGraphiteFace; +#endif sal_IntPtr mnFontId; ImplDevFontAttributes maDevFontAttributes; @@ -198,6 +208,9 @@ public: { return mpFontInfo->GetTable( pName, pLength ); } int GetEmUnits() const; const FT_Size_Metrics& GetMetricsFT() const { return maSizeFT->metrics; } +#ifdef ENABLE_GRAPHITE + GraphiteFaceWrapper* GetGraphiteFace() const { return mpFontInfo->GetGraphiteFace(); } +#endif protected: friend class GlyphCache; diff --git a/vcl/source/glyphs/graphite_adaptors.cxx b/vcl/source/glyphs/graphite_adaptors.cxx deleted file mode 100644 index a4f1860d9bfb..000000000000 --- a/vcl/source/glyphs/graphite_adaptors.cxx +++ /dev/null @@ -1,339 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// Description: Implements the Graphite interfaces with access to the -// platform's font and graphics systems. - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_vcl.hxx" - -// We need this to enable namespace support in libgrengine headers. -#define GR_NAMESPACE - -// Header files -// -// Standard Library -#include <string> -#include <cassert> -// Libraries -#include <rtl/string.hxx> -#include <rtl/ustring.hxx> -#include <i18npool/mslangid.hxx> -// Platform -#ifndef WNT -#include <saldisp.hxx> - -#include <vcl/salgdi.hxx> - -#include <freetype/ftsynth.h> - -// Module -#include "gcach_ftyp.hxx" - -#include <vcl/graphite_features.hxx> -#include <vcl/graphite_adaptors.hxx> - -// Module private type definitions and forward declarations. -// -using gr::GrResult; -namespace -{ - inline float from_hinted(const int x) { - return static_cast<float>(x + 32) / 64.0; - } - typedef boost::unordered_map<long,bool> SilfMap; -} -extern FT_Error (*pFTEmbolden)(FT_GlyphSlot); -extern FT_Error (*pFTOblique)(FT_GlyphSlot); - -// class CharacterRenderProperties implentation. -// -FontProperties::FontProperties(const FreetypeServerFont &font) throw() -{ - clrFore = gr::kclrBlack; - clrBack = gr::kclrTransparent; - - pixHeight = from_hinted(font.GetMetricsFT().height); - - switch (font.GetFontSelData().meWeight) - { - case WEIGHT_SEMIBOLD: case WEIGHT_BOLD: - case WEIGHT_ULTRABOLD: case WEIGHT_BLACK: - fBold = true; - break; - default : - fBold = false; - } - - switch (font.GetFontSelData().meItalic) - { - case ITALIC_NORMAL: case ITALIC_OBLIQUE: - fItalic = true; - break; - default : - fItalic = false; - } - - // 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(); - nHashFaceName.append(name); - - const size_t name_sz = std::min(sizeof szFaceName/sizeof(wchar_t)-1, - static_cast<size_t>(nHashFaceName.getLength())); - - std::copy(nHashFaceName.getStr(), nHashFaceName.getStr() + name_sz, szFaceName); - szFaceName[name_sz] = '\0'; -} - -// class GraphiteFontAdaptor implementaion. -// -GraphiteFontAdaptor::GraphiteFontAdaptor(ServerFont & sfont, const sal_Int32 dpiX, const sal_Int32 dpiY) - : mrFont(static_cast<FreetypeServerFont &>(sfont)), - maFontProperties(static_cast<FreetypeServerFont &>(sfont)), - mnDpiX(dpiX), - mnDpiY(dpiY), - mfAscent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().ascender)), - mfDescent(from_hinted(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().descender)), - mfEmUnits(static_cast<FreetypeServerFont &>(sfont).GetMetricsFT().y_ppem), - mpFeatures(NULL) -{ - const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( sfont.GetFontSelData().meLanguage ); - 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) - { - rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat); - mpFeatures = new grutils::GrFeatureParser(*this, aFeat.getStr(), aLang.getStr()); -#ifdef DEBUG - printf("GraphiteFontAdaptor %s/%s/%s %x language %d features %d errors\n", - rtl::OUStringToOString( sfont.GetFontSelData().maName, - RTL_TEXTENCODING_UTF8 ).getStr(), - rtl::OUStringToOString( sfont.GetFontSelData().maTargetName, - RTL_TEXTENCODING_UTF8 ).getStr(), - rtl::OUStringToOString( sfont.GetFontSelData().maSearchName, - RTL_TEXTENCODING_UTF8 ).getStr(), - sfont.GetFontSelData().meLanguage, - (int)mpFeatures->getFontFeatures(NULL), mpFeatures->parseErrors()); -#endif - } - else - { - mpFeatures = new grutils::GrFeatureParser(*this, aLang.getStr()); - } -} - -GraphiteFontAdaptor::GraphiteFontAdaptor(const GraphiteFontAdaptor &rhs) throw() - : Font(rhs), - mrFont (rhs.mrFont), maFontProperties(rhs.maFontProperties), - mnDpiX(rhs.mnDpiX), mnDpiY(rhs.mnDpiY), - mfAscent(rhs.mfAscent), mfDescent(rhs.mfDescent), mfEmUnits(rhs.mfEmUnits), - mpFeatures(NULL) -{ - if (rhs.mpFeatures) mpFeatures = new grutils::GrFeatureParser(*(rhs.mpFeatures)); -} - - -GraphiteFontAdaptor::~GraphiteFontAdaptor() throw() -{ - maGlyphMetricMap.clear(); - if (mpFeatures) delete mpFeatures; - mpFeatures = NULL; -} - -void GraphiteFontAdaptor::UniqueCacheInfo(std::wstring & face_name_out, bool & bold_out, bool & italic_out) -{ - face_name_out = maFontProperties.szFaceName; - bold_out = maFontProperties.fBold; - italic_out = maFontProperties.fItalic; -} - -bool GraphiteFontAdaptor::IsGraphiteEnabledFont(ServerFont & font) throw() -{ - static SilfMap sSilfMap; - // NOTE: this assumes that the same FTFace pointer won't be reused, - // so FtFontInfo::ReleaseFaceFT must only be called at shutdown. - FreetypeServerFont & aFtFont = dynamic_cast<FreetypeServerFont &>(font); - FT_Face aFace = reinterpret_cast<FT_FaceRec_*>(aFtFont.GetFtFace()); - SilfMap::iterator i = sSilfMap.find(reinterpret_cast<long>(aFace)); - if (i != sSilfMap.end()) - { -#ifdef DEBUG - if (static_cast<bool>(aFtFont.GetTable("Silf", 0)) != (*i).second) - printf("Silf cache font mismatch\n"); -#endif - return (*i).second; - } - bool bHasSilf = aFtFont.GetTable("Silf", 0); - sSilfMap[reinterpret_cast<long>(aFace)] = bHasSilf; - return bHasSilf; -} - - -gr::Font * GraphiteFontAdaptor::copyThis() { - return new GraphiteFontAdaptor(*this); -} - - -unsigned int GraphiteFontAdaptor::getDPIx() { - return mnDpiX; -} - - -unsigned int GraphiteFontAdaptor::getDPIy() { - return mnDpiY; -} - - -float GraphiteFontAdaptor::ascent() { - return mfAscent; -} - - -float GraphiteFontAdaptor::descent() { - return mfDescent; -} - - -bool GraphiteFontAdaptor::bold() { - return maFontProperties.fBold; -} - - -bool GraphiteFontAdaptor::italic() { - return maFontProperties.fItalic; -} - - -float GraphiteFontAdaptor::height() { - return maFontProperties.pixHeight; -} - - -void GraphiteFontAdaptor::getFontMetrics(float * ascent_out, float * descent_out, float * em_square_out) { - if (ascent_out) *ascent_out = mfAscent; - if (descent_out) *descent_out = mfDescent; - if (em_square_out) *em_square_out = mfEmUnits; -} - - -const void * GraphiteFontAdaptor::getTable(gr::fontTableId32 table_id, size_t * buffer_sz) -{ - char tag_name[5] = {char(table_id >> 24), char(table_id >> 16), char(table_id >> 8), char(table_id), 0}; - ULONG temp = *buffer_sz; - - const void * const tbl_buf = static_cast<FreetypeServerFont &>(mrFont).GetTable(tag_name, &temp); - *buffer_sz = temp; - - return tbl_buf; -} - -#define fix26_6(x) (x >> 6) + (x & 32 ? (x > 0 ? 1 : 0) : (x < 0 ? -1 : 0)) - -// Return the glyph's metrics in pixels. -void GraphiteFontAdaptor::getGlyphMetrics(gr::gid16 nGlyphId, gr::Rect & aBounding, gr::Point & advances) -{ - // 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); - - 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()) - { - // We've cached the results from last time. - aBounding = gm_itr->second.first; - advances = gm_itr->second.second; - } - else - { - // We need to look up the glyph. - FT_Int nLoadFlags = mrFont.GetLoadFlags(); - - FT_Face aFace = reinterpret_cast<FT_Face>(mrFont.GetFtFace()); - if (!aFace) - { - aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0; - advances.x = advances.y = 0; - return; - } - FT_Error aStatus = -1; - aStatus = FT_Load_Glyph(aFace, nGlyphId, nLoadFlags); - if( aStatus != FT_Err_Ok || (!aFace->glyph)) - { - aBounding.top = aBounding.bottom = aBounding.left = aBounding.right = 0; - advances.x = advances.y = 0; - return; - } - // check whether we need synthetic bold/italic otherwise metric is wrong - if (mrFont.NeedsArtificialBold() && pFTEmbolden) - (*pFTEmbolden)(aFace->glyph); - - if (mrFont.NeedsArtificialItalic() && pFTOblique) - (*pFTOblique)(aFace->glyph); - - const FT_Glyph_Metrics &gm = aFace->glyph->metrics; - - // Fill out the bounding box an advances. - aBounding.top = aBounding.bottom = fix26_6(gm.horiBearingY); - aBounding.bottom -= fix26_6(gm.height); - aBounding.left = aBounding.right = fix26_6(gm.horiBearingX); - aBounding.right += fix26_6(gm.width); - advances.x = fix26_6(gm.horiAdvance); - advances.y = 0; - - // Now add an entry to our metrics map. - maGlyphMetricMap[nGlyphId] = std::make_pair(aBounding, advances); - } -#endif -} - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/glyphs/graphite_cache.cxx b/vcl/source/glyphs/graphite_cache.cxx deleted file mode 100644 index b3f48aa1c476..000000000000 --- a/vcl/source/glyphs/graphite_cache.cxx +++ /dev/null @@ -1,201 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_vcl.hxx" - -#ifdef WNT -#include <tools/svwin.h> -#include <svsys.h> -#endif - -#include <tools/debug.hxx> -#include <vcl/sallayout.hxx> - -#include <graphite/GrClient.h> -#include <graphite/Segment.h> - -#include <rtl/ustring.hxx> -#include <vcl/graphite_layout.hxx> -#include <vcl/graphite_cache.hxx> - -#include "graphite_textsrc.hxx" - -GrSegRecord::GrSegRecord(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl) - : m_rope(rope), m_text(textSrc), m_seg(seg), m_nextKey(NULL), - m_fontScale(0.0f), mbIsRtl(bIsRtl), m_lockCount(0) -{ - m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter(); - m_startChar = seg->startCharacter(); -} - -GrSegRecord::~GrSegRecord() -{ - clear(); -} - -void GrSegRecord::reuse(rtl::OUString * rope, TextSourceAdaptor * textSrc, gr::Segment * seg, bool bIsRtl) -{ - clear(); - mnWidth = 0; - m_rope = rope; - m_text = textSrc; - m_seg = seg; - m_nextKey = NULL; - m_pStr = textSrc->getLayoutArgs().mpStr + seg->startCharacter(); - m_startChar = seg->startCharacter(); - mbIsRtl = bIsRtl; -} - -void GrSegRecord::clearVectors() -{ - mvGlyphs.clear(); - mvCharDxs.clear(); - mvChar2BaseGlyph.clear(); - mvGlyph2Char.clear(); -} - -void GrSegRecord::clear() -{ -#ifdef GR_DEBUG_TEXT - if (m_lockCount != 0) - OutputDebugString("GrSegRecord locked!"); -#endif - clearVectors(); - delete m_rope; - delete m_seg; - delete m_text; - m_rope = NULL; - m_seg = NULL; - m_text = NULL; - m_fontScale = 0.0f; - m_lockCount = 0; -} - -GrSegRecord * GraphiteSegmentCache::cacheSegment(TextSourceAdaptor * adapter, gr::Segment * seg, bool bIsRtl) -{ - GrSegRecord * record = NULL; - // We keep a record of the oldest key and the last key added - // 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() > m_nSegCacheSize) - { - GraphiteSegMap::iterator oldestPair = m_segMap.find(reinterpret_cast<long>(m_oldestKey)); - // oldest record may no longer exist if a buffer was changed - if (oldestPair != m_segMap.end()) - { - record = oldestPair->second; - m_segMap.erase(reinterpret_cast<long>(m_oldestKey)); - GrRMEntry range = m_ropeMap.equal_range((*(record->m_rope)).hashCode()); - while (range.first != range.second) - { - if (range.first->second == record) - { - m_ropeMap.erase(range.first); - break; - } - ++range.first; - } - m_oldestKey = record->m_nextKey; - // record will be reused, so don't delete - } - } - - -// const int seg_char_limit = min(adapter->maLayoutArgs().mnLength, -// adapter->maLayoutArgs().mnEndCharPos -// + GraphiteLayout::EXTRA_CONTEXT_LENGTH); -// if (seg->stopCharacter() - seg->startCharacter() <= 0) -// OutputDebugString("Invalid seg indices\n"); - rtl::OUString * pRope = new rtl::OUString(adapter->getLayoutArgs().mpStr + seg->startCharacter(), - seg->stopCharacter() - seg->startCharacter()); - if (!pRope) return NULL; - bool reuse = false; - if (record) - record->reuse(pRope, adapter, seg, bIsRtl); - else - record = new GrSegRecord(pRope, adapter, seg, bIsRtl); - if (!record) - { - delete pRope; - return NULL; - } - GraphiteSegMap::iterator iMap = - m_segMap.find(reinterpret_cast<long>(record->m_pStr)); - if (iMap != m_segMap.end()) - { - // the buffer has changed, so the old cached Segment is useless - reuse = true; - GrSegRecord * found = iMap->second; - // Note: we reuse the old next key to avoid breaking our history - // chain. This means it will be prematurely deleted, but this is - // unlikely to happen very often. - record->m_nextKey = found->m_nextKey; - // overwrite the old record - m_segMap[reinterpret_cast<long>(record->m_pStr)] = record; - // erase the old rope key and save the new one - GrRMEntry range = m_ropeMap.equal_range((*(found->m_rope)).hashCode()); - while (range.first != range.second) - { - if (range.first->second == found) - { - m_ropeMap.erase(range.first); - break; - } - ++range.first; - } - GraphiteRopeMap::value_type mapEntry(record->m_rope->hashCode(), record); - m_ropeMap.insert(mapEntry); - // remove the old record - delete found; - record->m_lockCount++; - return record; - } - m_segMap[reinterpret_cast<long>(record->m_pStr)] = record; - GraphiteRopeMap::value_type mapEntry((*(record->m_rope)).hashCode(), record); - m_ropeMap.insert(mapEntry); - - if (m_oldestKey == NULL) - { - m_oldestKey = record->m_pStr; - m_prevKey = record->m_pStr; - } - else if (reuse == false) - { - DBG_ASSERT(m_segMap.count(reinterpret_cast<long>(m_prevKey)), - "Previous key got lost somehow!"); - m_segMap.find(reinterpret_cast<long>(m_prevKey)) - ->second->m_nextKey = record->m_pStr; - m_prevKey = record->m_pStr; - } - record->m_lockCount++; - return record; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/glyphs/graphite_features.cxx b/vcl/source/glyphs/graphite_features.cxx index a49505d7d9e5..3be036987865 100644 --- a/vcl/source/glyphs/graphite_features.cxx +++ b/vcl/source/glyphs/graphite_features.cxx @@ -49,79 +49,107 @@ const char GrFeatureParser::FEAT_PREFIX = ':'; const char GrFeatureParser::FEAT_SEPARATOR = '&'; const char GrFeatureParser::FEAT_ID_VALUE_SEPARATOR = '='; -GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string lang) - : mnNumSettings(0), mbErrors(false) +GrFeatureParser::GrFeatureParser(const gr_face * pFace, const ::rtl::OString lang) + : mnNumSettings(0), mbErrors(false), mpSettings(NULL) { - maLang.rgch[0] = maLang.rgch[1] = maLang.rgch[2] = maLang.rgch[3] = '\0'; - setLang(font, lang); + maLang.label[0] = maLang.label[1] = maLang.label[2] = maLang.label[3] = '\0'; + setLang(pFace, lang); } -GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string features, const std::string lang) - : mnNumSettings(0), mbErrors(false) +GrFeatureParser::GrFeatureParser(const gr_face * pFace, const ::rtl::OString features, const ::rtl::OString lang) + : mnNumSettings(0), mbErrors(false), mpSettings(NULL) { - size_t nEquals = 0; - size_t nFeatEnd = 0; - size_t pos = 0; - maLang.rgch[0] = maLang.rgch[1] = maLang.rgch[2] = maLang.rgch[3] = '\0'; - setLang(font, lang); - while (pos < features.length() && mnNumSettings < MAX_FEATURES) + sal_Int32 nEquals = 0; + sal_Int32 nFeatEnd = 0; + sal_Int32 pos = 0; + maLang.num = 0u; + setLang(pFace, lang); + while ((pos < features.getLength()) && (mnNumSettings < MAX_FEATURES)) { - nEquals = features.find(FEAT_ID_VALUE_SEPARATOR,pos); - if (nEquals == std::string::npos) + nEquals = features.indexOf(FEAT_ID_VALUE_SEPARATOR, pos); + if (nEquals == -1) { mbErrors = true; break; } // check for a lang=xxx specification - if (features.compare(pos, nEquals - pos, "lang") == 0) + const ::rtl::OString aLangPrefix("lang"); + if (features.match(aLangPrefix, pos )) { pos = nEquals + 1; - nFeatEnd = features.find(FEAT_SEPARATOR, pos); - if (nFeatEnd == std::string::npos) + nFeatEnd = features.indexOf(FEAT_SEPARATOR, pos); + if (nFeatEnd == -1) { - nFeatEnd = features.length(); + nFeatEnd = features.getLength(); } if (nFeatEnd - pos > 3) mbErrors = true; else { - gr::isocode aLang = maLang; - for (size_t i = pos; i < nFeatEnd; i++) - aLang.rgch[i-pos] = features[i]; - std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported - = font.getSupportedLanguages(); - gr::LanguageIterator iL = aSupported.first; - while (iL != aSupported.second) + FeatId aLang = maLang; + aLang.num = 0; + for (sal_Int32 i = pos; i < nFeatEnd; i++) + aLang.label[i-pos] = features[i]; + + //ext_std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported + // = font.getSupportedLanguages(); + //gr::LanguageIterator iL = aSupported.first; + unsigned short i = 0; + for (; i < gr_face_n_languages(pFace); i++) { - gr::isocode aSupportedLang = *iL; + gr_uint32 nFaceLang = gr_face_lang_by_index(pFace, i); + FeatId aSupportedLang; + aSupportedLang.num = nFaceLang; +#ifdef __BIG_ENDIAN__ // here we only expect full 3 letter codes - if (aLang.rgch[0] == aSupportedLang.rgch[0] && - aLang.rgch[1] == aSupportedLang.rgch[1] && - aLang.rgch[2] == aSupportedLang.rgch[2] && - aLang.rgch[3] == aSupportedLang.rgch[3]) break; - ++iL; + if (aLang.label[0] == aSupportedLang.label[0] && + aLang.label[1] == aSupportedLang.label[1] && + aLang.label[2] == aSupportedLang.label[2] && + aLang.label[3] == aSupportedLang.label[3]) +#else + if (aLang.label[0] == aSupportedLang.label[3] && + aLang.label[1] == aSupportedLang.label[2] && + aLang.label[2] == aSupportedLang.label[1] && + aLang.label[3] == aSupportedLang.label[0]) +#endif + { + maLang = aSupportedLang; + break; + } + } + if (i == gr_face_n_languages(pFace)) mbErrors = true; + else + { + mnHash = maLang.num; + mpSettings = gr_face_featureval_for_lang(pFace, maLang.num); } - if (iL == aSupported.second) mbErrors = true; - else maLang = aLang; } } else { + sal_uInt32 featId = 0; if (isCharId(features, pos, nEquals - pos)) - maSettings[mnNumSettings].id = getCharId(features, pos, nEquals - pos); - else maSettings[mnNumSettings].id = getIntValue(features, pos, nEquals - pos); - pos = nEquals + 1; - nFeatEnd = features.find(FEAT_SEPARATOR, pos); - if (nFeatEnd == std::string::npos) { - nFeatEnd = features.length(); + featId = getCharId(features, pos, nEquals - pos); } - if (isCharId(features, pos, nFeatEnd - pos)) - maSettings[mnNumSettings].value = getCharId(features, pos, nFeatEnd - pos); else - maSettings[mnNumSettings].value= getIntValue(features, pos, nFeatEnd - pos); - if (isValid(font, maSettings[mnNumSettings])) + { + featId = getIntValue(features, pos, nEquals - pos); + } + const gr_feature_ref * pFref = gr_face_find_fref(pFace, featId); + pos = nEquals + 1; + nFeatEnd = features.indexOf(FEAT_SEPARATOR, pos); + if (nFeatEnd == -1) + { + nFeatEnd = features.getLength(); + } + sal_Int16 featValue = 0; + featValue = getIntValue(features, pos, nFeatEnd - pos); + if (pFref && gr_fref_set_feature_value(pFref, featValue, mpSettings)) + { + mnHash = (mnHash << 16) ^ ((featId << 8) | featValue); mnNumSettings++; + } else mbErrors = true; } @@ -129,89 +157,80 @@ GrFeatureParser::GrFeatureParser(gr::Font & font, const std::string features, co } } -void GrFeatureParser::setLang(gr::Font & font, const std::string & lang) +void GrFeatureParser::setLang(const gr_face * pFace, const rtl::OString & lang) { - gr::isocode aLang = {{0,0,0,0}}; - if (lang.length() > 2) + FeatId aLang; + aLang.num = 0; + if (lang.getLength() > 2) { - for (size_t i = 0; i < lang.length() && i < 3; i++) + for (sal_Int32 i = 0; i < lang.getLength() && i < 3; i++) { if (lang[i] == '-') break; - aLang.rgch[i] = lang[i]; + aLang.label[i] = lang[i]; } - std::pair<gr::LanguageIterator,gr::LanguageIterator> aSupported - = font.getSupportedLanguages(); - gr::LanguageIterator iL = aSupported.first; - while (iL != aSupported.second) + unsigned short i = 0; + for (; i < gr_face_n_languages(pFace); i++) { - gr::isocode aSupportedLang = *iL; - if (aLang.rgch[0] == aSupportedLang.rgch[0] && - aLang.rgch[1] == aSupportedLang.rgch[1] && - aLang.rgch[2] == aSupportedLang.rgch[2] && - aLang.rgch[3] == aSupportedLang.rgch[3]) break; - ++iL; - } - if (iL != aSupported.second) - maLang = aLang; -#ifdef DEBUG - else - printf("%s has no features\n", aLang.rgch); + gr_uint32 nFaceLang = gr_face_lang_by_index(pFace, i); + FeatId aSupportedLang; + aSupportedLang.num = nFaceLang; + // here we only expect full 2 & 3 letter codes +#ifdef __BIG_ENDIAN__ + if (aLang.label[0] == aSupportedLang.label[0] && + aLang.label[1] == aSupportedLang.label[1] && + aLang.label[2] == aSupportedLang.label[2] && + aLang.label[3] == aSupportedLang.label[3]) +#else + if (aLang.label[0] == aSupportedLang.label[3] && + aLang.label[1] == aSupportedLang.label[2] && + aLang.label[2] == aSupportedLang.label[1] && + aLang.label[3] == aSupportedLang.label[0]) #endif + { + maLang = aSupportedLang; + break; + } + } + if (i != gr_face_n_languages(pFace)) + { + if (mpSettings) + { + gr_featureval_destroy(mpSettings); + } + mpSettings = gr_face_featureval_for_lang(pFace, maLang.num); + mnHash = maLang.num; + } } -} - -GrFeatureParser::GrFeatureParser(const GrFeatureParser & aCopy) - : maLang(aCopy.maLang), mbErrors(aCopy.mbErrors) -{ - mnNumSettings = aCopy.getFontFeatures(maSettings); -} - -GrFeatureParser::~GrFeatureParser() -{ -} - -size_t GrFeatureParser::getFontFeatures(gr::FeatureSetting settings[64]) const -{ - if (settings) + if (!mpSettings) { - std::copy(maSettings, maSettings + mnNumSettings, settings); + mpSettings = gr_face_featureval_for_lang(pFace, 0); } - return mnNumSettings; } -bool GrFeatureParser::isValid(gr::Font & font, gr::FeatureSetting & setting) +GrFeatureParser::~GrFeatureParser() { - gr::FeatureIterator i = font.featureWithID(setting.id); - if (font.getFeatures().second == i) + if (mpSettings) { - return false; + gr_featureval_destroy(mpSettings); + mpSettings = NULL; } - std::pair< gr::FeatureSettingIterator, gr::FeatureSettingIterator > - validValues = font.getFeatureSettings(i); - gr::FeatureSettingIterator j = validValues.first; - while (j != validValues.second) - { - if (*j == setting.value) return true; - ++j; - } - return false; } -bool GrFeatureParser::isCharId(const std::string & id, size_t offset, size_t length) +bool GrFeatureParser::isCharId(const rtl::OString & id, size_t offset, size_t length) { if (length > 4) return false; for (size_t i = 0; i < length; i++) { if (i > 0 && id[offset+i] == '\0') continue; - if ((id[offset+i]) < 0x20 || (id[offset+i]) < 0) + if ((id[offset+i] < 0x20) || (id[offset+i] < 0)) return false; - if (i==0 && id[offset+i] < 0x41) + if (i==0 && (id[offset+i] < 0x41)) return false; } return true; } -int GrFeatureParser::getCharId(const std::string & id, size_t offset, size_t length) +gr_uint32 GrFeatureParser::getCharId(const rtl::OString & id, size_t offset, size_t length) { FeatId charId; charId.num = 0; @@ -229,9 +248,9 @@ int GrFeatureParser::getCharId(const std::string & id, size_t offset, size_t len return charId.num; } -int GrFeatureParser::getIntValue(const std::string & id, size_t offset, size_t length) +short GrFeatureParser::getIntValue(const rtl::OString & id, size_t offset, size_t length) { - int value = 0; + short value = 0; int sign = 1; for (size_t i = 0; i < length; i++) { @@ -271,18 +290,4 @@ int GrFeatureParser::getIntValue(const std::string & id, size_t offset, size_t l return value; } - -sal_Int32 GrFeatureParser::hashCode() const -{ - union IsoHash { sal_Int32 mInt; gr::isocode mCode; }; - IsoHash isoHash; - isoHash.mCode = maLang; - sal_Int32 hash = isoHash.mInt; - for (size_t i = 0; i < mnNumSettings; i++) - { - hash = (hash << 16) ^ ((maSettings[i].id << 8) | maSettings[i].value); - } - return hash; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/glyphs/graphite_layout.cxx b/vcl/source/glyphs/graphite_layout.cxx index 01c671ef17ec..b43edb5928e7 100644 --- a/vcl/source/glyphs/graphite_layout.cxx +++ b/vcl/source/glyphs/graphite_layout.cxx @@ -37,8 +37,9 @@ // Enable lots of debug info #ifdef DEBUG +#include <cstdio> //#define GRLAYOUT_DEBUG 1 -//#undef NDEBUG +#undef NDEBUG #endif // Header files @@ -57,10 +58,6 @@ #include <svsys.h> #endif -#ifdef UNX -#include <vcl/graphite_adaptors.hxx> -#endif - #include <vcl/salgdi.hxx> #include <unicode/uchar.h> @@ -68,16 +65,10 @@ #include <unicode/uscript.h> // Graphite Libraries (must be after vcl headers on windows) -#include <graphite/GrClient.h> -#include <graphite/Font.h> -#include <graphite/ITextSource.h> -#include <graphite/Segment.h> -#include <graphite/SegmentPainter.h> - -#include <vcl/graphite_layout.hxx> -#include <vcl/graphite_features.hxx> -#include "graphite_textsrc.hxx" +#include <graphite2/Segment.h> +#include "vcl/graphite_layout.hxx" +#include "vcl/graphite_features.hxx" // Module private type definitions and forward declarations. // @@ -85,48 +76,38 @@ // #ifdef GRLAYOUT_DEBUG -FILE * grLogFile = NULL; -FILE * grLog() +static FILE * grLogFile = NULL; +static FILE * grLog() { #ifdef WNT std::string logFileName(getenv("TEMP")); - logFileName.append("\\graphitelayout.log"); + logFileName.append("/graphitelayout.log"); if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"w"); else fflush(grLogFile); return grLogFile; #else + fflush(stdout); return stdout; #endif } #endif -#ifdef GRCACHE -#include <vcl/graphite_cache.hxx> -#endif - - namespace { - typedef std::pair<gr::GlyphIterator, gr::GlyphIterator> glyph_range_t; - typedef std::pair<gr::GlyphSetIterator, gr::GlyphSetIterator> glyph_set_range_t; - inline long round(const float n) { return long(n + (n < 0 ? -0.5 : 0.5)); } - template<typename T> inline bool in_range(const T i, const T b, const T e) { return !(b > i) && i < e; } - template<typename T> inline bool is_subrange(const T sb, const T se, const T b, const T e) { return !(b > sb || se > e); } - template<typename T> inline bool is_subrange(const std::pair<T, T> &s, const T b, const T e) { return is_subrange(s.first, s.second, b, e); @@ -149,9 +130,18 @@ namespace return limit; } -} // namespace - + template <typename T> + T maximum(T a, T b) + { + return (a > b)? a : b; + } + template <typename T> + T minimum(T a, T b) + { + return (a < b)? a : b; + } +} // namespace // Impementation of the GraphiteLayout::Glyphs container class. // This is an extended vector class with methods added to enable @@ -160,412 +150,364 @@ namespace // o manipulations that affect neighouring glyphs. const int GraphiteLayout::EXTRA_CONTEXT_LENGTH = 10; -#ifdef GRCACHE -GraphiteCacheHandler GraphiteCacheHandler::instance; -#endif + +// find first slot of cluster and first slot of subsequent cluster +static void findFirstClusterSlot(const gr_slot* base, gr_slot const** first, gr_slot const** after, int * firstChar, int * lastChar, bool bRtl) +{ + if (gr_slot_attached_to(base) == NULL) + { + *first = base; + *after = (bRtl)? gr_slot_prev_in_segment(base) : + gr_slot_next_in_segment(base); + *firstChar = gr_slot_before(base); + *lastChar = gr_slot_after(base); + } + const gr_slot * attachment = gr_slot_first_attachment(base); + while (attachment) + { + if (gr_slot_origin_X(*first) > gr_slot_origin_X(attachment)) + *first = attachment; + const gr_slot* attachmentNext = (bRtl)? + gr_slot_prev_in_segment(attachment) : gr_slot_next_in_segment(attachment); + if (attachmentNext) + { + if (*after && (gr_slot_origin_X(*after) < gr_slot_origin_X(attachmentNext))) + *after = attachmentNext; + } + else + { + *after = NULL; + } + if (gr_slot_before(attachment) < *firstChar) + *firstChar = gr_slot_before(attachment); + if (gr_slot_after(attachment) > *lastChar) + *lastChar = gr_slot_after(attachment); + if (gr_slot_first_attachment(attachment)) + findFirstClusterSlot(attachment, first, after, firstChar, lastChar, bRtl); + attachment = gr_slot_next_sibling_attachment(attachment); + } +} // The Graphite glyph stream is really a sequence of glyph attachment trees -// each rooted at a non-attached base glyph. fill_from walks the glyph stream -// find each non-attached base glyph and calls append to record them as a +// each rooted at a non-attached base glyph. fill_from walks the glyph stream, +// finds each non-attached base glyph and calls append to record them as a // sequence of clusters. void -GraphiteLayout::Glyphs::fill_from(gr::Segment & rSegment, ImplLayoutArgs &rArgs, - bool bRtl, long &rWidth, float fScaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs) +GraphiteLayout::fillFrom(gr_segment * pSegment, ImplLayoutArgs &rArgs, float fScaling) { - // Create a glyph item for each of the glyph and append it to the base class glyph list. - typedef std::pair< gr::GlyphSetIterator, gr::GlyphSetIterator > GrGlyphSet; - int nChar = rArgs.mnEndCharPos - rArgs.mnMinCharPos; - glyph_range_t iGlyphs = rSegment.glyphs(); - int nGlyphs = iGlyphs.second - iGlyphs.first; - float fSegmentAdvance = rSegment.advanceWidth(); - float fMinX = fSegmentAdvance; + bool bRtl = (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL); + int nCharRequested = rArgs.mnEndCharPos - rArgs.mnMinCharPos; + int nChar = gr_seg_n_cinfo(pSegment); + float fMinX = gr_seg_advance_X(pSegment); float fMaxX = 0.0f; - rGlyph2Char.assign(nGlyphs, -1); - long nDxOffset = 0; - int nGlyphIndex = (bRtl)? (nGlyphs - 1) : 0; - // OOo always expects the glyphs in ltr order - int nDelta = (bRtl)? -1 : 1; - - int nLastGlyph = (bRtl)? nGlyphs - 1: 0; - int nNextChar = (bRtl)? (rSegment.stopCharacter() - 1) : rSegment.startCharacter();//rArgs.mnMinCharPos; - // current glyph number (Graphite glyphs) - //int currGlyph = 0; - int nFirstCharInCluster = nNextChar; - int nFirstGlyphInCluster = nLastGlyph; - - // ltr first char in cluster is lowest, same is true for rtl - // ltr first glyph in cluster is lowest, rtl first glyph is highest - - // loop over the glyphs determining which characters are linked to them - gr::GlyphIterator gi; - for (gi = iGlyphs.first + nGlyphIndex; - nGlyphIndex >= 0 && nGlyphIndex < nGlyphs; - nGlyphIndex+= nDelta, gi = iGlyphs.first + nGlyphIndex) + long nDxOffset = 0; // from dropped glyphs + int nFirstCharInCluster = 0; + int nLastCharInCluster = 0; + unsigned int nGlyphs = gr_seg_n_slots(pSegment); + mvGlyph2Char.assign(nGlyphs, -1); + mvGlyphs.reserve(nGlyphs); + + if (bRtl) { - gr::GlyphInfo info = (*gi); -#ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"Glyph %d %f,%f\n", (int)info.logicalIndex(), info.origin(), info.yOffset()); -#endif - // the last character associated with this glyph is after - // our current cluster buffer position - if ((bRtl && ((signed)info.firstChar() <= nNextChar)) || - (!bRtl && ((signed)info.lastChar() >= nNextChar))) + const gr_slot* prevBase = NULL; + const gr_slot* baseSlot = gr_seg_last_slot(pSegment); + // find first base + while (baseSlot && (gr_slot_attached_to(baseSlot) != NULL)) + baseSlot = gr_slot_prev_in_segment(baseSlot); + int iChar = nChar - 1; + int iNextChar = nChar - 1; + bool reordered = false; + int nBaseGlyphIndex = 0; + // now loop over bases + while (baseSlot) { - if ((bRtl && nGlyphIndex < nLastGlyph) || - (!bRtl && nGlyphIndex > nLastGlyph)) + bool bCluster = !reordered; + const gr_slot * clusterFirst = NULL; + const gr_slot * clusterAfter = NULL; + int firstChar = -1; + int lastChar = -1; + findFirstClusterSlot(baseSlot, &clusterFirst, &clusterAfter, &firstChar, &lastChar, bRtl); + iNextChar = minimum<int>(firstChar, iNextChar); + if (bCluster) { - // this glyph is after the previous one left->right - // if insertion is allowed before it then we are in a - // new cluster - int nAttachedBase = (*(info.attachedClusterBase())).logicalIndex(); - if (!info.isAttached() || - !in_range(nAttachedBase, nFirstGlyphInCluster, nGlyphIndex)) + nBaseGlyphIndex = mvGlyphs.size(); + mvGlyph2Char[nBaseGlyphIndex] = iChar + mnSegCharOffset; + nFirstCharInCluster = firstChar; + nLastCharInCluster = lastChar; + } + else + { + mvGlyph2Char[mvGlyphs.size()] = firstChar + mnSegCharOffset; + nFirstCharInCluster = minimum<int>(firstChar, nFirstCharInCluster); + nLastCharInCluster = maximum<int>(firstChar, nLastCharInCluster); + } + float leftBoundary = gr_slot_origin_X(clusterFirst); + float rightBoundary = (clusterAfter)? + gr_slot_origin_X(clusterAfter) : gr_seg_advance_X(pSegment); + if (lastChar < iChar && gr_cinfo_after(gr_seg_cinfo(pSegment, iChar)) > gr_slot_index(clusterAfter)) + { + reordered = true; + } + else + { + reordered = false; + iChar = iNextChar - 1; + } + if (mnSegCharOffset + nFirstCharInCluster >= mnMinCharPos && + mnSegCharOffset + nFirstCharInCluster < mnEndCharPos) + { + fMinX = minimum<float>(fMinX, leftBoundary); + fMaxX = maximum<float>(fMaxX, rightBoundary); + if (!reordered) { - if (in_range(nFirstCharInCluster, rArgs.mnMinCharPos, rArgs.mnEndCharPos) && - nFirstGlyphInCluster != nGlyphIndex) + for (int i = nFirstCharInCluster; i <= nLastCharInCluster; i++) { - std::pair <float,float> aBounds = - appendCluster(rSegment, rArgs, bRtl, - fSegmentAdvance, nFirstCharInCluster, - nNextChar, nFirstGlyphInCluster, nGlyphIndex, fScaling, - rChar2Base, rGlyph2Char, rCharDxs, nDxOffset); - fMinX = std::min(aBounds.first, fMinX); - fMaxX = std::max(aBounds.second, fMaxX); + if (mnSegCharOffset + i >= mnEndCharPos) + break; + // from the point of view of the dx array, the xpos is + // the origin of the first glyph of the cluster rtl + mvCharDxs[mnSegCharOffset + i - mnMinCharPos] = + static_cast<int>(leftBoundary * fScaling) + nDxOffset; + mvCharBreaks[mnSegCharOffset + i - mnMinCharPos] = gr_cinfo_break_weight(gr_seg_cinfo(pSegment, i)); } - nFirstCharInCluster = (bRtl)? info.lastChar() : info.firstChar(); - nFirstGlyphInCluster = nGlyphIndex; + mvChar2BaseGlyph[mnSegCharOffset + nFirstCharInCluster - mnMinCharPos] = nBaseGlyphIndex; } - nLastGlyph = (bRtl)? std::min(nGlyphIndex, nAttachedBase) : - std::max(nGlyphIndex, nAttachedBase); + append(pSegment, rArgs, baseSlot, rightBoundary, fScaling, + nDxOffset, bCluster, mnSegCharOffset + firstChar); + } + if (mnSegCharOffset + nLastCharInCluster < mnMinCharPos) + break; + prevBase = baseSlot; + baseSlot = gr_slot_next_sibling_attachment(baseSlot); + } + } + else + { + const gr_slot* prevBase = NULL; + const gr_slot* baseSlot = gr_seg_first_slot(pSegment); + // find first base + while (baseSlot && (gr_slot_attached_to(baseSlot) != NULL)) + baseSlot = gr_slot_next_in_segment(baseSlot); + int iChar = 0; // relative to segment + int iNextChar = 0; + bool reordered = false; + int nBaseGlyphIndex = 0; + // now loop over bases + while (baseSlot) + { + bool bCluster = !reordered; + const gr_slot * clusterFirst = NULL; + const gr_slot * clusterAfter = NULL; + int firstChar = -1; + int lastChar = -1; + findFirstClusterSlot(baseSlot, &clusterFirst, &clusterAfter, &firstChar, &lastChar, bRtl); + iNextChar = maximum<int>(lastChar, iNextChar); + if (bCluster) + { + nBaseGlyphIndex = mvGlyphs.size(); + mvGlyph2Char[nBaseGlyphIndex] = iChar + mnSegCharOffset; + nFirstCharInCluster = firstChar; + nLastCharInCluster = lastChar; } - // loop over chacters associated with this glyph and characters - // between nextChar and the last character associated with this glyph - // giving them the current cluster id. This allows for character /glyph - // order reversal. - // For each character we do a reverse glyph id look up - // and store the glyph id with the highest logical index in nLastGlyph - while ((bRtl && ((signed)info.firstChar() <= nNextChar)) || - (!bRtl && (signed)info.lastChar() >= nNextChar)) + else { - GrGlyphSet charGlyphs = rSegment.charToGlyphs(nNextChar); - nNextChar += nDelta; - gr::GlyphSetIterator gj = charGlyphs.first; - while (gj != charGlyphs.second) - { - nLastGlyph = (bRtl)? min(nLastGlyph, (signed)(*gj).logicalIndex()) : max(nLastGlyph, (signed)(*gj).logicalIndex()); - ++gj; - } + mvGlyph2Char[mvGlyphs.size()] = firstChar + mnSegCharOffset; + nFirstCharInCluster = minimum<int>(firstChar, nFirstCharInCluster); + nLastCharInCluster = maximum<int>(lastChar, nLastCharInCluster); } - // Loop over attached glyphs and make sure they are all in the cluster since you - // can have glyphs attached with another base glyph in between - glyph_set_range_t iAttached = info.attachedClusterGlyphs(); - for (gr::GlyphSetIterator agi = iAttached.first; agi != iAttached.second; ++agi) + if (firstChar > iChar && gr_cinfo_before(gr_seg_cinfo(pSegment, iChar)) > gr_slot_index(clusterFirst)) { - nLastGlyph = (bRtl)? min(nLastGlyph, (signed)(*agi).logicalIndex()) : max(nLastGlyph, (signed)(*agi).logicalIndex()); + reordered = true; } - - // if this is a rtl attached glyph, then we need to include its - // base in the cluster, which will have a lower graphite index - if (bRtl) + else + { + reordered = false; + iChar = iNextChar + 1; + } + float leftBoundary = gr_slot_origin_X(clusterFirst); + float rightBoundary = (clusterAfter)? + gr_slot_origin_X(clusterAfter) : gr_seg_advance_X(pSegment); + if (mnSegCharOffset + nFirstCharInCluster >= mnMinCharPos && + mnSegCharOffset + nFirstCharInCluster < mnEndCharPos) { - if ((signed)info.attachedClusterBase()->logicalIndex() < nLastGlyph) + fMinX = minimum<float>(fMinX, leftBoundary); + fMaxX = maximum<float>(fMaxX, rightBoundary); + if (!reordered) { - nLastGlyph = info.attachedClusterBase()->logicalIndex(); + for (int i = nFirstCharInCluster; i <= nLastCharInCluster; i++) + { + if (mnSegCharOffset + i >= mnEndCharPos) + break; + // from the point of view of the dx array, the xpos is + // the origin of the first glyph of the next cluster ltr + mvCharDxs[mnSegCharOffset + i - mnMinCharPos] = + static_cast<int>(rightBoundary * fScaling) + nDxOffset; + mvCharBreaks[mnSegCharOffset + i - mnMinCharPos] = gr_cinfo_break_weight(gr_seg_cinfo(pSegment, i)); + } + // only set mvChar2BaseGlyph for first character of cluster + mvChar2BaseGlyph[mnSegCharOffset + nFirstCharInCluster - mnMinCharPos] = nBaseGlyphIndex; } + append(pSegment, rArgs, baseSlot, rightBoundary, fScaling, + nDxOffset, true, mnSegCharOffset + firstChar); } + if (mnSegCharOffset + nFirstCharInCluster >= mnEndCharPos) + break; + prevBase = baseSlot; + baseSlot = gr_slot_next_sibling_attachment(baseSlot); } - - // it is possible for the lastChar to be after nextChar and - // firstChar to be before the nFirstCharInCluster in rare - // circumstances e.g. Myanmar word for cemetery - if ((bRtl && ((signed)info.lastChar() > nFirstCharInCluster)) || - (!bRtl && ((signed)info.firstChar() < nFirstCharInCluster))) - { - nFirstCharInCluster = info.firstChar(); - } - } - // process last cluster - if (in_range(nFirstCharInCluster, rArgs.mnMinCharPos, rArgs.mnEndCharPos) && - nFirstGlyphInCluster != nGlyphIndex) - { - std::pair <float,float> aBounds = - appendCluster(rSegment, rArgs, bRtl, fSegmentAdvance, - nFirstCharInCluster, nNextChar, - nFirstGlyphInCluster, nGlyphIndex, fScaling, - rChar2Base, rGlyph2Char, rCharDxs, nDxOffset); - fMinX = std::min(aBounds.first, fMinX); - fMaxX = std::max(aBounds.second, fMaxX); } long nXOffset = round(fMinX * fScaling); - rWidth = round(fMaxX * fScaling) - nXOffset + nDxOffset; - if (rWidth < 0) + mnWidth = round(fMaxX * fScaling) - nXOffset + nDxOffset; + if (mnWidth < 0) { // This can happen when there was no base inside the range - rWidth = 0; + mnWidth = 0; } // fill up non-base char dx with cluster widths from previous base glyph if (bRtl) { - if (rCharDxs[nChar-1] == -1) - rCharDxs[nChar-1] = 0; + if (mvCharDxs[nCharRequested-1] == -1) + mvCharDxs[nCharRequested-1] = 0; else - rCharDxs[nChar-1] -= nXOffset; - for (int i = nChar - 2; i >= 0; i--) + mvCharDxs[nCharRequested-1] -= nXOffset; + for (int i = nCharRequested - 2; i >= 0; i--) { - if (rCharDxs[i] == -1) rCharDxs[i] = rCharDxs[i+1]; - else rCharDxs[i] -= nXOffset; + if (mvCharDxs[i] == -1) mvCharDxs[i] = mvCharDxs[i+1]; + else mvCharDxs[i] -= nXOffset; } } else { - if (rCharDxs[0] == -1) - rCharDxs[0] = 0; + if (mvCharDxs[0] == -1) + mvCharDxs[0] = 0; else - rCharDxs[0] -= nXOffset; - for (int i = 1; i < nChar; i++) + mvCharDxs[0] -= nXOffset; + for (int i = 1; i < nCharRequested; i++) { - if (rCharDxs[i] == -1) rCharDxs[i] = rCharDxs[i-1]; - else rCharDxs[i] -= nXOffset; - } - } + if (mvCharDxs[i] == -1) mvCharDxs[i] = mvCharDxs[i-1]; + else mvCharDxs[i] -= nXOffset; #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"Glyphs xOff%ld dropDx%ld w%ld\n", nXOffset, nDxOffset, rWidth); + fprintf(grLog(),"%d,%d ", (int)i, (int)mvCharDxs[i]); #endif - // remove offset due to context if there is one - if (nXOffset != 0) - { - for (size_t i = 0; i < size(); i++) - (*this)[i].maLinearPos.X() -= nXOffset; - } -} - -std::pair<float,float> GraphiteLayout::Glyphs::appendCluster(gr::Segment& rSeg, - ImplLayoutArgs & rArgs, bool bRtl,float fSegmentAdvance, - int nFirstCharInCluster, int nNextChar, int nFirstGlyphInCluster, - int nNextGlyph, float fScaling, std::vector<int> & rChar2Base, - std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset) -{ - glyph_range_t iGlyphs = rSeg.glyphs(); - int nGlyphs = iGlyphs.second - iGlyphs.first; - int nDelta = (bRtl)? -1 : 1; - gr::GlyphInfo aFirstGlyph = *(iGlyphs.first + nFirstGlyphInCluster); - std::pair <float, float> aBounds; - aBounds.first = aFirstGlyph.origin(); - aBounds.second = aFirstGlyph.origin(); - // before we add the glyphs to this vector, we record the - // glyph's index in the vector (which is not the same as - // the Segment's glyph index!) - assert(size() < rGlyph2Char.size()); - rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] = size(); - rGlyph2Char[size()] = nFirstCharInCluster; - - // can we break before this cluster? - // Glyphs may have either a positive or negative breakWeight refering to - // the position after or before the glyph respectively - int nPrevBreakWeight = 0; - if (nFirstGlyphInCluster > 0) - { - nPrevBreakWeight = (iGlyphs.first + (nFirstGlyphInCluster - 1))->breakweight(); - } - int nBreakWeight = aFirstGlyph.breakweight(); - if (nBreakWeight < 0) - { - // negative means it applies to the position before the glyph's character - nBreakWeight *= -1; - if (nPrevBreakWeight > 0 && nPrevBreakWeight < nBreakWeight) - { - // prevBreakWeight wins - nBreakWeight = nPrevBreakWeight; } } - else - { - nBreakWeight = 0; - // positive means break after - if (nPrevBreakWeight > 0) - nBreakWeight = nPrevBreakWeight; - } - if (nBreakWeight > gr::klbNoBreak/*0*/ && - // nBreakWeight <= gr::klbHyphenBreak) // uses Graphite hyphenation - nBreakWeight <= gr::klbLetterBreak) // Needed for issue 111272 - { - if (nBreakWeight < gr::klbHyphenBreak) - rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE; - else - rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= HYPHEN_BREAK_BEFORE; - } - // always allow a break before a space even if graphite doesn't - if (rArgs.mpStr[nFirstCharInCluster] == 0x20) - rChar2Base[nFirstCharInCluster-rArgs.mnMinCharPos] |= WORD_BREAK_BEFORE; - - bool bBaseGlyph = true; - for (int j = nFirstGlyphInCluster; - j != nNextGlyph; j += nDelta) - { - long nNextOrigin; - float fNextOrigin; - gr::GlyphInfo aGlyph = *(iGlyphs.first + j); - if (j + nDelta >= nGlyphs || j + nDelta < 0) // at rhs ltr,rtl - { - fNextOrigin = fSegmentAdvance; - nNextOrigin = round(fSegmentAdvance * fScaling + rDXOffset); - aBounds.second = std::max(fSegmentAdvance, aBounds.second); - } - else - { - gr::GlyphInfo aNextGlyph = *(iGlyphs.first + j + nDelta); - fNextOrigin = std::max(aNextGlyph.attachedClusterBase()->origin(), aNextGlyph.origin()); - aBounds.second = std::max(fNextOrigin, aBounds.second); - nNextOrigin = round(fNextOrigin * fScaling + rDXOffset); - } - aBounds.first = std::min(aGlyph.origin(), aBounds.first); - if ((signed)aGlyph.firstChar() < rArgs.mnEndCharPos && - (signed)aGlyph.firstChar() >= rArgs.mnMinCharPos) - { - rCharDxs[aGlyph.firstChar()-rArgs.mnMinCharPos] = nNextOrigin; - } - if ((signed)aGlyph.attachedClusterBase()->logicalIndex() == j) - { - append(rSeg, rArgs, aGlyph, fNextOrigin, fScaling, rChar2Base, rGlyph2Char, rCharDxs, rDXOffset, bBaseGlyph); - bBaseGlyph = false; - } - } - // from the point of view of the dx array, the xpos is - // the origin of the first glyph of the next cluster ltr - // rtl it is the origin of the 1st glyph of the cluster - long nXPos = (bRtl)? - round(aFirstGlyph.attachedClusterBase()->origin() * fScaling) + rDXOffset : - round(aBounds.second * fScaling) + rDXOffset; - // force the last char in range to have the width of the cluster - if (bRtl) - { - for (int n = nNextChar + 1; n <= nFirstCharInCluster; n++) - { - if ((n < rArgs.mnEndCharPos) && (n >= rArgs.mnMinCharPos)) - rCharDxs[n-rArgs.mnMinCharPos] = nXPos; - } - } - else + // remove offset due to context if there is one + if (nXOffset != 0) { - for (int n = nNextChar - 1; n >= nFirstCharInCluster; n--) - { - if (n < rArgs.mnEndCharPos && n >= rArgs.mnMinCharPos) - rCharDxs[n-rArgs.mnMinCharPos] = nXPos; - } + for (size_t i = 0; i < mvGlyphs.size(); i++) + mvGlyphs[i].maLinearPos.X() -= nXOffset; } #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"Cluster g[%d-%d) c[%d-%d)%x x%ld y%f bw%d\n", nFirstGlyphInCluster, nNextGlyph, nFirstCharInCluster, nNextChar, rArgs.mpStr[nFirstCharInCluster], nXPos, aFirstGlyph.yOffset(), nBreakWeight); + fprintf(grLog(), "fillFrom %d glyphs offset %ld width %d\n", mvGlyphs.size(), nXOffset, mnWidth); #endif - return aBounds; } // append walks an attachment tree, flattening it, and converting it into a // sequence of GlyphItem objects which we can later manipulate. void -GraphiteLayout::Glyphs::append(gr::Segment &segment, ImplLayoutArgs &args, gr::GlyphInfo & gi, float nextGlyphOrigin, float scaling, std::vector<int> & rChar2Base, std::vector<int> & rGlyph2Char, std::vector<int> & rCharDxs, long & rDXOffset, bool bIsBase) +GraphiteLayout::append(gr_segment *pSeg, ImplLayoutArgs &rArgs, + const gr_slot * gi, float nextGlyphOrigin, float scaling, long & rDXOffset, + bool bIsBase, int baseChar) { + bool bRtl = (rArgs.mnFlags & SAL_LAYOUT_BIDI_RTL); float nextOrigin = nextGlyphOrigin; - int firstChar = std::min(gi.firstChar(), gi.lastChar()); - assert(size() < rGlyph2Char.size()); - if (!bIsBase) rGlyph2Char[size()] = firstChar; + assert(gi); + assert(gr_slot_before(gi) <= gr_slot_after(gi)); + int firstChar = gr_slot_before(gi) + mnSegCharOffset; + assert(mvGlyphs.size() < mvGlyph2Char.size()); + if (!bIsBase) mvGlyph2Char[mvGlyphs.size()] = baseChar;//firstChar; // is the next glyph attached or in the next cluster? - glyph_set_range_t iAttached = gi.attachedClusterGlyphs(); - if (iAttached.first != iAttached.second) + //glyph_set_range_t iAttached = gi.attachedClusterGlyphs(); + const gr_slot * pFirstAttached = gr_slot_first_attachment(gi); + if (pFirstAttached) { - nextOrigin = iAttached.first->origin(); + nextOrigin = gr_slot_origin_X(pFirstAttached); } - long glyphId = gi.glyphID(); + long glyphId = gr_slot_gid(gi); long deltaOffset = 0; - int glyphWidth = round(nextOrigin * scaling) - round(gi.origin() * scaling); + int scaledGlyphPos = round(gr_slot_origin_X(gi) * scaling); + int glyphWidth = round(nextOrigin * scaling) - scaledGlyphPos; + if (glyphWidth < 0) + glyphWidth = 0; #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"c%d g%d gWidth%d x%f ", firstChar, (int)gi.logicalIndex(), glyphWidth, nextOrigin); + fprintf(grLog(),"c%d g%ld,X%d W%d nX%f ", firstChar, glyphId, + (int)(gr_slot_origin_X(gi) * scaling), glyphWidth, nextOrigin * scaling); #endif if (glyphId == 0) { - args.NeedFallback( - firstChar, - gr::RightToLeftDir(gr::DirCode(gi.directionality()))); - if( (SAL_LAYOUT_FOR_FALLBACK & args.mnFlags )) + rArgs.NeedFallback(firstChar, bRtl); + if( (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags )) { glyphId = GF_DROPPED; deltaOffset -= glyphWidth; glyphWidth = 0; } } - else if(args.mnFlags & SAL_LAYOUT_FOR_FALLBACK) + else if(rArgs.mnFlags & SAL_LAYOUT_FOR_FALLBACK) { #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"fallback c%d %x in run %d\n", firstChar, args.mpStr[firstChar], - args.maRuns.PosIsInAnyRun(firstChar)); + fprintf(grLog(),"fallback c%d %x in run %d\n", firstChar, rArgs.mpStr[firstChar], + rArgs.maRuns.PosIsInAnyRun(firstChar)); #endif // glyphs that aren't requested for fallback will be taken from base // layout, so mark them as dropped (should this wait until Simplify(false) is called?) - if (!args.maRuns.PosIsInAnyRun(firstChar) && - in_range(firstChar, args.mnMinCharPos, args.mnEndCharPos)) + if (!rArgs.maRuns.PosIsInAnyRun(firstChar) && + in_range(firstChar, rArgs.mnMinCharPos, rArgs.mnEndCharPos)) { glyphId = GF_DROPPED; deltaOffset -= glyphWidth; glyphWidth = 0; } } - // append this glyph. + // append this glyph. Set the cluster flag if this glyph is attached to another long nGlyphFlags = bIsBase ? 0 : GlyphItem::IS_IN_CLUSTER; - // directionality seems to be unreliable - //nGlyphFlags |= gr::RightToLeftDir(gr::DirCode(gi.attachedClusterBase()->directionality())) ? GlyphItem::IS_RTL_GLYPH : 0; - nGlyphFlags |= (gi.directionLevel() & 0x1)? GlyphItem::IS_RTL_GLYPH : 0; - GlyphItem aGlyphItem(size(),//gi.logicalIndex(), + nGlyphFlags |= (bRtl)? GlyphItem::IS_RTL_GLYPH : 0; + GlyphItem aGlyphItem(mvGlyphs.size(), glyphId, - Point(round(gi.origin() * scaling + rDXOffset), - round((-gi.yOffset() * scaling) - segment.AscentOffset()* scaling)), + Point(scaledGlyphPos + rDXOffset, + round((-gr_slot_origin_Y(gi) * scaling))), nGlyphFlags, glyphWidth); - aGlyphItem.mnOrigWidth = round(gi.advanceWidth() * scaling); - push_back(aGlyphItem); + if (glyphId != static_cast<long>(GF_DROPPED)) + aGlyphItem.mnOrigWidth = round(gr_slot_advance_X(gi, mpFace, mpFont) * scaling); + mvGlyphs.push_back(aGlyphItem); // update the offset if this glyph was dropped rDXOffset += deltaOffset; - // Recursively apply append all the attached glyphs. - for (gr::GlyphSetIterator agi = iAttached.first; agi != iAttached.second; ++agi) + // Recursively append all the attached glyphs. + for (const gr_slot * agi = gr_slot_first_attachment(gi); agi != NULL; + agi = gr_slot_next_sibling_attachment(agi)) { - if (agi + 1 == iAttached.second) - append(segment, args, *agi, nextGlyphOrigin, scaling, rChar2Base, rGlyph2Char,rCharDxs, rDXOffset, false); + if (gr_slot_next_sibling_attachment(agi) == NULL) + append(pSeg, rArgs, agi, nextGlyphOrigin, scaling, rDXOffset, + false, baseChar); else - append(segment, args, *agi, (agi + 1)->origin(), scaling, rChar2Base, rGlyph2Char, rCharDxs, rDXOffset, false); + append(pSeg, rArgs, agi, gr_slot_origin_X(gr_slot_next_sibling_attachment(agi)), + scaling, rDXOffset, false, baseChar); } } // // An implementation of the SalLayout interface to enable Graphite enabled fonts to be used. // -GraphiteLayout::GraphiteLayout(const gr::Font & font, const grutils::GrFeatureParser * pFeatures) throw() - : mpTextSrc(0), - mrFont(font), +GraphiteLayout::GraphiteLayout(const gr_face * face, gr_font * font, + const grutils::GrFeatureParser * pFeatures) throw() + : mpFace(face), + mpFont(font), mnWidth(0), mfScaling(1.0), mpFeatures(pFeatures) { - // Line settings can have subtle affects on space handling - // since we don't really know whether it is the end of a line or just a run - // in the middle, it is hard to know what to set them to. - // If true, it can cause end of line spaces to be hidden e.g. Doulos SIL - maLayout.setStartOfLine(false); - maLayout.setEndOfLine(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 - gr::ScriptDirCode aDirCode = font.getSupportedScriptDirections(); - fprintf(grLog(),"GraphiteLayout scripts %x %lx\n", aDirCode, long(this)); -#endif -} +} GraphiteLayout::~GraphiteLayout() throw() { clear(); - // the features are owned by the platform layers + // the features and font are owned by the platform layers mpFeatures = NULL; + mpFont = NULL; } void GraphiteLayout::clear() @@ -577,12 +519,7 @@ void GraphiteLayout::clear() mvChar2BaseGlyph.clear(); mvGlyph2Char.clear(); -#ifndef GRCACHE - delete mpTextSrc; -#endif - // Reset the state to the empty state. - mpTextSrc=0; mnWidth = 0; // Don't reset the scaling, because it is set before LayoutText } @@ -590,28 +527,7 @@ void GraphiteLayout::clear() // This method shouldn't be called on windows, since it needs the dc reset bool GraphiteLayout::LayoutText(ImplLayoutArgs & rArgs) { -#ifdef GRCACHE - GrSegRecord * pSegRecord = NULL; - gr::Segment * pSegment = NULL; - // Graphite can in rare cases crash with a zero length - if (rArgs.mnMinCharPos < rArgs.mnEndCharPos) - { - pSegment = CreateSegment(rArgs, &pSegRecord); - if (!pSegment) - return false; - } - else - { - clear(); - return true; - } - // layout the glyphs as required by OpenOffice - bool success = LayoutGlyphs(rArgs, pSegment, pSegRecord); - - if (pSegRecord) pSegRecord->unlock(); - else delete pSegment; -#else - gr::Segment * pSegment = NULL; + gr_segment * pSegment = NULL; bool success = true; if (rArgs.mnMinCharPos < rArgs.mnEndCharPos) { @@ -619,88 +535,25 @@ bool GraphiteLayout::LayoutText(ImplLayoutArgs & rArgs) if (!pSegment) return false; success = LayoutGlyphs(rArgs, pSegment); - if (pSegment) delete pSegment; + if (pSegment) + { + gr_seg_destroy(pSegment); + pSegment = NULL; + } } else { clear(); } -#endif return success; } -#ifdef GRCACHE -class GrFontHasher : public gr::Font -{ -public: - GrFontHasher(const gr::Font & aFont) : gr::Font(aFont), mrRealFont(const_cast<gr::Font&>(aFont)) {}; - ~GrFontHasher(){}; - virtual bool bold() { return mrRealFont.bold(); }; - virtual bool italic() { return mrRealFont.italic(); }; - virtual float ascent() { return mrRealFont.ascent(); }; - virtual float descent() { return mrRealFont.descent(); }; - virtual float height() { return mrRealFont.height(); }; - virtual gr::Font* copyThis() { return mrRealFont.copyThis(); }; - virtual unsigned int getDPIx() { return mrRealFont.getDPIx(); }; - virtual unsigned int getDPIy() { return mrRealFont.getDPIy(); }; - virtual const void* getTable(gr::fontTableId32 nId, size_t* nSize) - { return mrRealFont.getTable(nId,nSize); } - virtual void getFontMetrics(float*pA, float*pB, float*pC) { mrRealFont.getFontMetrics(pA,pB,pC); }; - - sal_Int32 hashCode(const grutils::GrFeatureParser * mpFeatures) - { - // is this sufficient? - std::wstring aFace; - bool bBold; - bool bItalic; - UniqueCacheInfo(aFace, bBold, bItalic); - sal_Unicode uName[32]; // max length used in gr::Font - // Note: graphite stores font names as UTF-16 even if wchar_t is 32bit - // this conversion should be OK. - for (size_t i = 0; i < aFace.size() && i < 32; i++) - { - uName[i] = aFace[i]; - } - size_t iSize = aFace.size(); - if (0 == iSize) return 0; - sal_Int32 hash = rtl_ustr_hashCode_WithLength(uName, iSize); - hash ^= static_cast<sal_Int32>(height()); - hash |= (bBold)? 0x1000000 : 0; - hash |= (bItalic)? 0x2000000 : 0; - if (mpFeatures) - hash ^= mpFeatures->hashCode(); -#ifdef GRLAYOUT_DEBUG - fprintf(grLog(), "font hash %x size %f\n", (int)hash, height()); -#endif - return hash; - }; -protected: - virtual void UniqueCacheInfo( std::wstring& stuFace, bool& fBold, bool& fItalic ) - { -#ifdef WIN32 - dynamic_cast<GraphiteWinFont&>(mrRealFont).UniqueCacheInfo(stuFace, fBold, fItalic); -#else -#ifdef UNX - dynamic_cast<GraphiteFontAdaptor&>(mrRealFont).UniqueCacheInfo(stuFace, fBold, fItalic); -#else -#error Unknown base type for gr::Font::UniqueCacheInfo -#endif -#endif - } -private: - gr::Font & mrRealFont; -}; -#endif -#ifdef GRCACHE -gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs, GrSegRecord ** pSegRecord) -#else -gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) -#endif +gr_segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) { assert(rArgs.mnLength >= 0); - gr::Segment * pSegment = NULL; + gr_segment * pSegment = NULL; // Set the SalLayouts values to be the inital ones. SalLayout::AdjustLayout(rArgs); @@ -715,89 +568,47 @@ gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) { // Don't set RTL if font doesn't support it otherwise it forces rtl on // everything - if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl)) - maLayout.setRightToLeft(bRtl); + //if (bRtl && (mrFont.getSupportedScriptDirections() & gr::kfsdcHorizRtl)) + // maLayout.setRightToLeft(bRtl); // Context is often needed beyond the specified end, however, we don't // want it if there has been a direction change, since it is hard // to tell between reordering within one direction and multi-directional // text. Extra context, can also cause problems with ligatures stradling // a hyphenation point, so disable if CTL is disabled. - const int nSegCharLimit = min(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH); + mnSegCharOffset = rArgs.mnMinCharPos; int limit = rArgs.mnEndCharPos; - if ((nSegCharLimit > limit) && !(SAL_LAYOUT_COMPLEX_DISABLED & rArgs.mnFlags)) - { - limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos, - nSegCharLimit - rArgs.mnEndCharPos, bRtl); - } - -#ifdef GRCACHE - GrFontHasher hasher(mrFont); - sal_Int32 aFontHash = hasher.hashCode(mpFeatures); - GraphiteSegmentCache * pCache = - (GraphiteCacheHandler::instance).getCache(aFontHash); - if (pCache) + if (!(SAL_LAYOUT_COMPLEX_DISABLED & rArgs.mnFlags)) { - *pSegRecord = pCache->getSegment(rArgs, bRtl, limit); - if (*pSegRecord) + const int nSegCharMin = maximum<int>(0, mnMinCharPos - EXTRA_CONTEXT_LENGTH); + const int nSegCharLimit = minimum(rArgs.mnLength, mnEndCharPos + EXTRA_CONTEXT_LENGTH); + if (nSegCharMin < mnSegCharOffset) { - pSegment = (*pSegRecord)->getSegment(); - mpTextSrc = (*pSegRecord)->getTextSrc(); - maLayout.setRightToLeft((*pSegRecord)->isRtl()); - if (rArgs.mpStr != mpTextSrc->getLayoutArgs().mpStr || - rArgs.mnMinCharPos != mpTextSrc->getLayoutArgs().mnMinCharPos || - rArgs.mnEndCharPos != mpTextSrc->getLayoutArgs().mnEndCharPos || - (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) ) - { - (*pSegRecord)->clearVectors(); - } - mpTextSrc->switchLayoutArgs(rArgs); - if (limit > rArgs.mnMinCharPos && limit == rArgs.mnEndCharPos - && pSegment->stopCharacter() != limit) - { - // check that the last character is not part of a ligature - glyph_set_range_t aGlyphSet = pSegment->charToGlyphs(limit - 1); - if (aGlyphSet.first == aGlyphSet.second) - { - // no glyphs associated with this glyph - occurs mid ligature - pSegment = NULL; - *pSegRecord = NULL; - } - else - { - while (aGlyphSet.first != aGlyphSet.second) - { - int lastChar = static_cast<int>((*aGlyphSet.first).lastChar()); - if (lastChar >= limit) - { - pSegment = NULL; - *pSegRecord = NULL; - break; - } - aGlyphSet.first++; - } - } - } - if (pSegment) - return pSegment; + int sameDirEnd = findSameDirLimit(rArgs.mpStr + nSegCharMin, + rArgs.mnEndCharPos - nSegCharMin, bRtl); + if (sameDirEnd == rArgs.mnEndCharPos) + mnSegCharOffset = nSegCharMin; + } + if (nSegCharLimit > limit) + { + limit += findSameDirLimit(rArgs.mpStr + rArgs.mnEndCharPos, + nSegCharLimit - rArgs.mnEndCharPos, bRtl); } } -#endif - // Create a new TextSource object for the engine. - mpTextSrc = new TextSourceAdaptor(rArgs, limit); - if (mpFeatures) mpTextSrc->setFeatures(mpFeatures); + if (mpFeatures) + pSegment = gr_make_seg(mpFont, mpFace, 0, mpFeatures->values(), gr_utf16, + rArgs.mpStr + mnSegCharOffset, limit - mnSegCharOffset, bRtl); + else + pSegment = gr_make_seg(mpFont, mpFace, 0, NULL, gr_utf16, + rArgs.mpStr + mnSegCharOffset, limit - mnSegCharOffset, bRtl); - pSegment = new gr::RangeSegment((gr::Font *)&mrFont, mpTextSrc, &maLayout, mnMinCharPos, limit); + //pSegment = new gr::RangeSegment((gr::Font *)&mrFont, mpTextSrc, &maLayout, mnMinCharPos, limit); if (pSegment != NULL) { #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"Gr::LayoutText %d-%d, context %d,len%d rtl%d/%d scaling %f\n", rArgs.mnMinCharPos, - rArgs.mnEndCharPos, limit, rArgs.mnLength, maLayout.rightToLeft(), pSegment->rightToLeft(), mfScaling); -#endif -#ifdef GRCACHE - // on a new segment rightToLeft should be correct - *pSegRecord = pCache->cacheSegment(mpTextSrc, pSegment, pSegment->rightToLeft()); + fprintf(grLog(),"Gr::LayoutText %d-%d, context %d,len%d rtl%d scaling %f\n", rArgs.mnMinCharPos, + rArgs.mnEndCharPos, limit, rArgs.mnLength, bRtl, mfScaling); #endif } else @@ -822,47 +633,20 @@ gr::Segment * GraphiteLayout::CreateSegment(ImplLayoutArgs& rArgs) return pSegment; } -#ifdef GRCACHE -bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment, GrSegRecord * pSegRecord) -#else -bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment) -#endif +bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr_segment * pSegment) { -#ifdef GRCACHE -#ifdef GRCACHE_REUSE_VECTORS - // if we have an exact match, then we can reuse the glyph vectors from before - if (pSegRecord && (pSegRecord->glyphs().size() > 0) && - (pSegRecord->fontScale() == mfScaling) && - !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags) ) - { - mnWidth = pSegRecord->width(); - mvGlyphs = pSegRecord->glyphs(); - mvCharDxs = pSegRecord->charDxs(); - mvChar2BaseGlyph = pSegRecord->char2BaseGlyph(); - mvGlyph2Char = pSegRecord->glyph2Char(); - return true; - } -#endif -#endif // Calculate the initial character dxs. mvCharDxs.assign(mnEndCharPos - mnMinCharPos, -1); mvChar2BaseGlyph.assign(mnEndCharPos - mnMinCharPos, -1); + mvCharBreaks.assign(mnEndCharPos - mnMinCharPos, 0); mnWidth = 0; if (mvCharDxs.size() > 0) { // Discover all the clusters. try { - // Note: we use the layout rightToLeft() because in cached segments - // rightToLeft() may no longer be valid if the engine has been run - // ltr since the segment was created. -#ifdef GRCACHE - bool bRtl = pSegRecord? pSegRecord->isRtl() : pSegment->rightToLeft(); -#else - bool bRtl = pSegment->rightToLeft(); -#endif - mvGlyphs.fill_from(*pSegment, rArgs, bRtl, - mnWidth, mfScaling, mvChar2BaseGlyph, mvGlyph2Char, mvCharDxs); + bool bRtl = mnLayoutFlags & SAL_LAYOUT_BIDI_RTL; + fillFrom(pSegment, rArgs, mfScaling); if (bRtl) { @@ -872,17 +656,6 @@ bool GraphiteLayout::LayoutGlyphs(ImplLayoutArgs& rArgs, gr::Segment * pSegment) // fixup last dx to ensure it always equals the width mvCharDxs[mvCharDxs.size() - 1] = mnWidth; } -#ifdef GRCACHE -#ifdef GRCACHE_REUSE_VECTORS - if (pSegRecord && rArgs.maReruns.IsEmpty() && - !(SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags)) - { - pSegRecord->setGlyphVectors(mnWidth, mvGlyphs, mvCharDxs, - mvChar2BaseGlyph, mvGlyph2Char, - mfScaling); - } -#endif -#endif } catch (std::exception e) { @@ -918,24 +691,33 @@ int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) c return STRING_LEN; long nWidth = mvCharDxs[0] * factor; + long wLastBreak = 0; int nLastBreak = -1; + int nEmergency = -1; for (size_t i = 1; i < mvCharDxs.size(); i++) { nWidth += char_extra; if (nWidth > maxmnWidth) break; if (mvChar2BaseGlyph[i] != -1) { - if (mvChar2BaseGlyph[i] & (WORD_BREAK_BEFORE | HYPHEN_BREAK_BEFORE)) + if ((mvCharBreaks[i] > -25 || mvCharBreaks[i-1] > 0 && mvCharBreaks[i-1] < 25) && (mvCharBreaks[i-1] < 25 || mvCharBreaks[i] < 0 && mvCharBreaks[i] > -25)) + { nLastBreak = static_cast<int>(i); + wLastBreak = nWidth; + } + nEmergency = static_cast<int>(i); } nWidth += (mvCharDxs[i] - mvCharDxs[i-1]) * factor; } int nBreak = mnMinCharPos; - if (nLastBreak > -1) + if (wLastBreak > 9 * maxmnWidth / 10) nBreak += nLastBreak; + else + if (nEmergency > -1) + nBreak += nEmergency; #ifdef GRLAYOUT_DEBUG - fprintf(grLog(), "Gr::GetTextBreak break after %d\n", nBreak - mnMinCharPos); + fprintf(grLog(), "Gr::GetTextBreak break after %d, weights(%d, %d)\n", nBreak - mnMinCharPos, mvCharBreaks[nBreak - mnMinCharPos], mvCharBreaks[nBreak - mnMinCharPos - 1]); #endif if (nBreak > mnEndCharPos) nBreak = STRING_LEN; @@ -943,7 +725,6 @@ int GraphiteLayout::GetTextBreak(long maxmnWidth, long char_extra, int factor) c return nBreak; } - long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const { if (mnEndCharPos == mnMinCharPos) @@ -955,9 +736,9 @@ long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const for (size_t i = 0; i < mvCharDxs.size(); i++) { assert( (mvChar2BaseGlyph[i] == -1) || - ((signed)(mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK) < (signed)mvGlyphs.size())); + ((signed)(mvChar2BaseGlyph[i]) < (signed)mvGlyphs.size())); if (mvChar2BaseGlyph[i] != -1 && - mvGlyphs[mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK].mnGlyphIndex == GF_DROPPED) + mvGlyphs[mvChar2BaseGlyph[i]].mnGlyphIndex == GF_DROPPED) { // when used in MultiSalLayout::GetTextBreak dropped glyphs // must have zero width @@ -978,12 +759,11 @@ long GraphiteLayout::FillDXArray( sal_Int32* pDXArray ) const //fprintf(grLog(),"FillDX %ld,%d\n", mnWidth, std::accumulate(pDXArray, pDXArray + mvCharDxs.size(), 0)); } #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"FillDXArray %d-%d,%d=%ld\n", mnMinCharPos, mnEndCharPos, (int)mpTextSrc->getLength(), mnWidth); + fprintf(grLog(),"FillDXArray %d-%d=%ld\n", mnMinCharPos, mnEndCharPos, mnWidth); #endif return mnWidth; } - void GraphiteLayout::AdjustLayout(ImplLayoutArgs& rArgs) { SalLayout::AdjustLayout(rArgs); @@ -1029,6 +809,9 @@ void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs) int nDeltaWidth = rArgs.mnLayoutWidth - mnWidth; if (nDeltaWidth > 0) // expand, just expand between clusters { + // NOTE: for expansion we can use base glyphs (which have IsClusterStart set) + // even though they may have been reordered in which case they will have + // been placed in a bigger cluster for other purposes. int nClusterCount = 0; for (size_t j = 0; j < mvGlyphs.size(); j++) { @@ -1046,15 +829,18 @@ void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs) { if (mvGlyphs[i].IsClusterStart()) { - nOffset = fExtraPerCluster * nCluster; - size_t nCharIndex = mvGlyph2Char[i]; - mvCharDxs[nCharIndex] += nOffset; + nOffset = static_cast<int>(fExtraPerCluster * nCluster); + int nCharIndex = mvGlyph2Char[i]; + assert(nCharIndex > -1); + mvCharDxs[nCharIndex-mnMinCharPos] += nOffset; // adjust char dxs for rest of characters in cluster - while (++nCharIndex < mvGlyph2Char.size()) + while (++nCharIndex < static_cast<int>(mvGlyph2Char.size())) { - int nChar2Base = (mvChar2BaseGlyph[nCharIndex] == -1)? -1 : mvChar2BaseGlyph[nCharIndex] & GLYPH_INDEX_MASK; + int nChar2Base = mvChar2BaseGlyph[nCharIndex-mnMinCharPos]; if (nChar2Base == -1 || nChar2Base == static_cast<int>(i)) - mvCharDxs[nCharIndex] += nOffset; + mvCharDxs[nCharIndex-mnMinCharPos] += nOffset; + else + break; } ++nCluster; } @@ -1062,25 +848,27 @@ void GraphiteLayout::expandOrCondense(ImplLayoutArgs &rArgs) } } } - else // condense - apply a factor to all glyph positions + else if (nDeltaWidth < 0)// condense - apply a factor to all glyph positions { if (mvGlyphs.size() == 0) return; Glyphs::iterator iLastGlyph = mvGlyphs.begin() + (mvGlyphs.size() - 1); // position last glyph using original width float fXFactor = static_cast<float>(rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth) / static_cast<float>(iLastGlyph->maLinearPos.X()); #ifdef GRLAYOUT_DEBUG - fprintf(grLog(), "Condense by factor %f\n", fXFactor); + fprintf(grLog(), "Condense by factor %f last x%ld\n", fXFactor, iLastGlyph->maLinearPos.X()); #endif + if (fXFactor < 0) + return; // probably a bad mnOrigWidth value iLastGlyph->maLinearPos.X() = rArgs.mnLayoutWidth - iLastGlyph->mnOrigWidth; Glyphs::iterator iGlyph = mvGlyphs.begin(); while (iGlyph != iLastGlyph) { - iGlyph->maLinearPos.X() = static_cast<float>(iGlyph->maLinearPos.X()) * fXFactor; + iGlyph->maLinearPos.X() = static_cast<int>(static_cast<float>(iGlyph->maLinearPos.X()) * fXFactor); ++iGlyph; } for (size_t i = 0; i < mvCharDxs.size(); i++) { - mvCharDxs[i] = fXFactor * static_cast<float>(mvCharDxs[i]); + mvCharDxs[i] = static_cast<int>(fXFactor * static_cast<float>(mvCharDxs[i])); } } mnWidth = rArgs.mnLayoutWidth; @@ -1106,7 +894,7 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDelt int nPrevClusterLastChar = -1; for (size_t i = 0; i < nChars; i++) { - int nChar2Base = (mvChar2BaseGlyph[i] == -1)? -1 : mvChar2BaseGlyph[i] & GLYPH_INDEX_MASK; + int nChar2Base = mvChar2BaseGlyph[i]; if ((nChar2Base > -1) && (nChar2Base != nPrevClusterGlyph)) { assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size())); @@ -1118,11 +906,12 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDelt size_t j = i + 1; int nLastChar = i; int nLastGlyph = nChar2Base; + int nChar2BaseJ = -1; for (; j < nChars; j++) { - int nChar2BaseJ = (mvChar2BaseGlyph[j] == -1)? -1 : mvChar2BaseGlyph[j] & GLYPH_INDEX_MASK; + nChar2BaseJ = mvChar2BaseGlyph[j]; assert((nChar2BaseJ >= -1) && (nChar2BaseJ < (signed)mvGlyphs.size())); - if (nChar2BaseJ != -1 && mvGlyphs[nChar2BaseJ].IsClusterStart()) + if (nChar2BaseJ != -1 ) { nLastGlyph = nChar2BaseJ + ((bRtl)? 1 : -1); nLastChar = j - 1; @@ -1150,6 +939,12 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDelt nLastChar = nChars - 1; if (!bRtl) nLastGlyph = mvGlyphs.size() - 1; } + int nBaseCount = 0; + // count bases within cluster - may be more than 1 with reordering + for (int k = nChar2Base; k <= nLastGlyph; k++) + { + if (mvGlyphs[k].IsClusterStart()) ++nBaseCount; + } assert((nLastChar > -1) && (nLastChar < (signed)nChars)); long nNewClusterWidth = args.mpDXArray[nLastChar]; long nOrigClusterWidth = mvCharDxs[nLastChar]; @@ -1171,21 +966,25 @@ void GraphiteLayout::ApplyDXArray(ImplLayoutArgs &args, std::vector<int> & rDelt mvGlyphs[nLastGlyph].mnNewWidth += nDWidth; else nDGlyphOrigin += nDWidth; + long nDOriginPerBase = (nBaseCount > 0)? nDWidth / nBaseCount : 0; + nBaseCount = -1; // update glyph positions if (bRtl) { for (int n = nChar2Base; n <= nLastGlyph; n++) { + if (mvGlyphs[n].IsClusterStart()) ++nBaseCount; assert((n > - 1) && (n < (signed)mvGlyphs.size())); - mvGlyphs[n].maLinearPos.X() += -nDGlyphOrigin + nXOffset; + mvGlyphs[n].maLinearPos.X() += -(nDGlyphOrigin + nDOriginPerBase * nBaseCount) + nXOffset; } } else { for (int n = nChar2Base; n <= nLastGlyph; n++) { + if (mvGlyphs[n].IsClusterStart()) ++nBaseCount; assert((n > - 1) && (n < (signed)mvGlyphs.size())); - mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + nXOffset; + mvGlyphs[n].maLinearPos.X() += nDGlyphOrigin + (nDOriginPerBase * nBaseCount) + nXOffset; } } rDeltaWidth[nChar2Base] = nDWidth; @@ -1288,15 +1087,15 @@ void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray std::fill(pCaretXArray, pCaretXArray + nArraySize, -1); // the layout method doesn't modify the layout even though it isn't // const in the interface - bool bRtl = const_cast<GraphiteLayout*>(this)->maLayout.rightToLeft(); + bool bRtl = (mnLayoutFlags & SAL_LAYOUT_BIDI_RTL);//const_cast<GraphiteLayout*>(this)->maLayout.rightToLeft(); int prevBase = -1; long prevClusterWidth = 0; for (int i = 0, nCharSlot = 0; i < nArraySize && nCharSlot < static_cast<int>(mvCharDxs.size()); ++nCharSlot, i+=2) { if (mvChar2BaseGlyph[nCharSlot] != -1) { - int nChar2Base = mvChar2BaseGlyph[nCharSlot] & GLYPH_INDEX_MASK; - assert((mvChar2BaseGlyph[nCharSlot] > -1) && (nChar2Base < (signed)mvGlyphs.size())); + int nChar2Base = mvChar2BaseGlyph[nCharSlot]; + assert((nChar2Base > -1) && (nChar2Base < (signed)mvGlyphs.size())); GlyphItem gi = mvGlyphs[nChar2Base]; if (gi.mnGlyphIndex == GF_DROPPED) { @@ -1313,8 +1112,8 @@ void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray origClusterWidth += mvGlyphs[nCluster].mnNewWidth; if (mvGlyph2Char[nCluster] == nCharSlot) { - nMin = std::min(nMin, mvGlyphs[nCluster].maLinearPos.X()); - nMax = std::min(nMax, mvGlyphs[nCluster].maLinearPos.X() + mvGlyphs[nCluster].mnNewWidth); + nMin = minimum(nMin, mvGlyphs[nCluster].maLinearPos.X()); + nMax = maximum(nMax, mvGlyphs[nCluster].maLinearPos.X() + mvGlyphs[nCluster].mnNewWidth); } } if (bRtl) @@ -1388,7 +1187,6 @@ void GraphiteLayout::GetCaretPositions( int nArraySize, sal_Int32* pCaretXArray #endif } - // GetNextGlyphs returns a contiguous sequence of glyphs that can be // rendered together. It should never return a dropped glyph. // The glyph_slot returned should be the index of the next visible @@ -1416,7 +1214,7 @@ int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out, ++glyph_slot) {}; // Update the length - const int nGlyphSlotEnd = std::min(size_t(glyph_slot + length), mvGlyphs.size()); + const int nGlyphSlotEnd = minimum(size_t(glyph_slot + length), mvGlyphs.size()); // We're all out of glyphs here. if (glyph_slot == nGlyphSlotEnd) @@ -1434,17 +1232,23 @@ int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out, //aPosOut = glyph_itr->maLinearPos; aPosOut = GetDrawPosition(aStartPos); - for (;;) // Forever { // last index of the range from glyph_to_chars does not include this glyph if (char_index) { - assert((glyph_slot >= -1) && (glyph_slot < (signed)mvGlyph2Char.size())); - if (mvGlyph2Char[glyph_slot] == -1) - *char_index++ = mvCharDxs.size(); - else - *char_index++ = mvGlyph2Char[glyph_slot]; + if (glyph_slot >= (signed)mvGlyph2Char.size()) + { + *char_index++ = mnMinCharPos + mvCharDxs.size(); + } + else + { + assert(glyph_slot > -1); + if (mvGlyph2Char[glyph_slot] == -1) + *char_index++ = mnMinCharPos + mvCharDxs.size(); + else + *char_index++ = mvGlyph2Char[glyph_slot]; + } } // Copy out this glyphs data. ++glyph_slot; @@ -1457,8 +1261,9 @@ int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out, ((glyph_itr+1)->maLinearPos.X() - glyph_itr->maLinearPos.X()); #ifdef GRLAYOUT_DEBUG - fprintf(grLog(),"GetNextGlyphs g%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n", glyph_slot - 1, - GLYPH_INDEX_MASK&mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance, + fprintf(grLog(),"GetNextGlyphs g%d gid%d c%d x%ld,%ld adv%ld, pos %ld,%ld\n", + glyph_slot - 1, glyph_itr->mnGlyphIndex, + mvGlyph2Char[glyph_slot-1], glyph_itr->maLinearPos.X(), glyph_itr->maLinearPos.Y(), nGlyphAdvance, aPosOut.X(), aPosOut.Y()); #endif @@ -1488,7 +1293,6 @@ int GraphiteLayout::GetNextGlyphs( int length, sal_GlyphId * glyph_out, return numGlyphs; } - void GraphiteLayout::MoveGlyph( int nGlyphIndex, long nNewPos ) { // TODO it might be better to actualy implement simplify properly, but this @@ -1515,7 +1319,6 @@ void GraphiteLayout::MoveGlyph( int nGlyphIndex, long nNewPos ) mnWidth += dx; } - void GraphiteLayout::DropGlyph( int nGlyphIndex ) { if(nGlyphIndex >= signed(mvGlyphs.size())) @@ -1547,7 +1350,6 @@ void GraphiteLayout::Simplify( bool isBaseLayout ) { deltaX = 0; } - //mvCharDxs[mvGlyph2Char[gi->mnCharPos]] -= deltaX; ++gi; } #ifdef GRLAYOUT_DEBUG diff --git a/vcl/source/glyphs/graphite_serverfont.cxx b/vcl/source/glyphs/graphite_serverfont.cxx index cda2cd434cba..ec1388d9bb29 100644 --- a/vcl/source/glyphs/graphite_serverfont.cxx +++ b/vcl/source/glyphs/graphite_serverfont.cxx @@ -36,44 +36,120 @@ // // Platform +#include <i18npool/mslangid.hxx> #include <vcl/sallayout.hxx> // Module #include "gcach_ftyp.hxx" +#include <vcl/glyphcache.hxx> #include <vcl/graphite_features.hxx> -#include "graphite_textsrc.hxx" +//#include "graphite_textsrc.hxx" #include <vcl/graphite_serverfont.hxx> #ifndef WNT +float freetypeServerFontAdvance(const void* appFontHandle, gr_uint16 glyphId) +{ + FreetypeServerFont * pServerFont = + const_cast<FreetypeServerFont*> + (reinterpret_cast<const FreetypeServerFont*>(appFontHandle)); + if (pServerFont) + { + return static_cast<float>(pServerFont->GetGlyphMetric(glyphId).GetCharWidth()); + } + return .0f; +} + // // An implementation of the GraphiteLayout interface to enable Graphite enabled fonts to be used. // -GraphiteServerFontLayout::GraphiteServerFontLayout(GraphiteFontAdaptor * pFont) throw() - : ServerFontLayout(pFont->font()), mpFont(pFont), - maImpl(*mpFont, mpFont->features(), pFont) +GraphiteServerFontLayout::GraphiteServerFontLayout(ServerFont & rServerFont) throw() + : ServerFontLayout(rServerFont), + maImpl(dynamic_cast<FreetypeServerFont&>(rServerFont).GetGraphiteFace()->face(), + rServerFont), + mpFeatures(NULL) { - // Nothing needed here + FreetypeServerFont& rFTServerFont = dynamic_cast<FreetypeServerFont&>(rServerFont); + gr_font * pFont = rFTServerFont.GetGraphiteFace()->font(rServerFont.GetFontSelData().mnHeight); + if (!pFont) + { + pFont = gr_make_font_with_advance_fn( + // need to use mnHeight here, mfExactHeight can give wrong values + static_cast<float>(rServerFont.GetFontSelData().mnHeight), + &rFTServerFont, + freetypeServerFontAdvance, + rFTServerFont.GetGraphiteFace()->face()); + rFTServerFont.GetGraphiteFace()->addFont(rServerFont.GetFontSelData().mnHeight, pFont); + } + maImpl.SetFont(pFont); + rtl::OString aLang(""); + if (rServerFont.GetFontSelData().meLanguage != LANGUAGE_DONTKNOW) + { + aLang = MsLangId::convertLanguageToIsoByteString( + rServerFont.GetFontSelData().meLanguage ); + } + rtl::OString name = rtl::OUStringToOString( + rServerFont.GetFontSelData().maTargetName, RTL_TEXTENCODING_UTF8 ); +#ifdef DEBUG + printf("GraphiteServerFontLayout %lx %s size %d %f\n", (long unsigned int)this, name.getStr(), + rFTServerFont.GetMetricsFT().x_ppem, + rServerFont.GetFontSelData().mfExactHeight); +#endif + sal_Int32 nFeat = name.indexOf(grutils::GrFeatureParser::FEAT_PREFIX) + 1; + if (nFeat > 0) + { + rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat); + mpFeatures = new grutils::GrFeatureParser( + rFTServerFont.GetGraphiteFace()->face(), aFeat, aLang); +#ifdef DEBUG + if (mpFeatures) + printf("GraphiteServerFontLayout %s/%s/%s %x language %d features %d errors\n", + rtl::OUStringToOString( rServerFont.GetFontSelData().maName, + RTL_TEXTENCODING_UTF8 ).getStr(), + rtl::OUStringToOString( rServerFont.GetFontSelData().maTargetName, + RTL_TEXTENCODING_UTF8 ).getStr(), + rtl::OUStringToOString( rServerFont.GetFontSelData().maSearchName, + RTL_TEXTENCODING_UTF8 ).getStr(), + rServerFont.GetFontSelData().meLanguage, + (int)mpFeatures->numFeatures(), mpFeatures->parseErrors()); +#endif + } + else + { + mpFeatures = new grutils::GrFeatureParser( + rFTServerFont.GetGraphiteFace()->face(), aLang); + } + maImpl.SetFeatures(mpFeatures); } GraphiteServerFontLayout::~GraphiteServerFontLayout() throw() { - delete mpFont; - mpFont = NULL; + delete mpFeatures; + mpFeatures = NULL; } -const sal_Unicode* GraphiteServerFontLayout::getTextPtr() const +bool GraphiteServerFontLayout::IsGraphiteEnabledFont(ServerFont * pServerFont) { - return maImpl.textSrc()->getLayoutArgs().mpStr + - maImpl.textSrc()->getLayoutArgs().mnMinCharPos; + FreetypeServerFont * pFtServerFont = dynamic_cast<FreetypeServerFont*>(pServerFont); + if (pFtServerFont) + { + if (pFtServerFont->GetGraphiteFace()) + { +#ifdef DEBUG + printf("IsGraphiteEnabledFont\n"); +#endif + return true; + } + } + return false; } sal_GlyphId GraphiteLayoutImpl::getKashidaGlyph(int & width) { - int nKashidaIndex = mpFont->font().GetGlyphIndex( 0x0640 ); + int nKashidaIndex = mrServerFont.GetGlyphIndex( 0x0640 ); if( nKashidaIndex != 0 ) { - const GlyphMetric& rGM = mpFont->font().GetGlyphMetric( nKashidaIndex ); + const GlyphMetric& rGM = mrServerFont.GetGlyphMetric( nKashidaIndex ); width = rGM.GetCharWidth(); } else diff --git a/vcl/source/glyphs/makefile.mk b/vcl/source/glyphs/makefile.mk index fa9af02ca75f..6bd64cdb5fb5 100644 --- a/vcl/source/glyphs/makefile.mk +++ b/vcl/source/glyphs/makefile.mk @@ -52,12 +52,11 @@ SLOFILES=\ .IF "$(ENABLE_GRAPHITE)" != "" # Graphite support using the glyphcache infrastructure CFLAGS+=-DENABLE_GRAPHITE -SLOFILES+= $(SLO)$/graphite_adaptors.obj \ +SLOFILES+=\ $(SLO)$/graphite_features.obj \ - $(SLO)$/graphite_cache.obj \ - $(SLO)$/graphite_textsrc.obj \ $(SLO)$/graphite_serverfont.obj \ $(SLO)$/graphite_layout.obj + .ENDIF .ELSE @@ -65,10 +64,9 @@ SLOFILES+= $(SLO)$/graphite_adaptors.obj \ .IF "$(ENABLE_GRAPHITE)" == "TRUE" # Graphite support on non-UNX platforms SLOFILES=\ - $(SLO)$/graphite_textsrc.obj \ - $(SLO)$/graphite_cache.obj \ $(SLO)$/graphite_features.obj \ $(SLO)$/graphite_layout.obj + .ENDIF .ENDIF diff --git a/vcl/unx/source/gdi/pspgraphics.cxx b/vcl/unx/source/gdi/pspgraphics.cxx index bdccf4a82e01..5fe67ec32e26 100644 --- a/vcl/unx/source/gdi/pspgraphics.cxx +++ b/vcl/unx/source/gdi/pspgraphics.cxx @@ -992,13 +992,9 @@ SalLayout* PspGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel { #ifdef ENABLE_GRAPHITE // Is this a Graphite font? - if (GraphiteFontAdaptor::IsGraphiteEnabledFont(*m_pServerFont[nFallbackLevel])) + if (GraphiteServerFontLayout::IsGraphiteEnabledFont(m_pServerFont[nFallbackLevel])) { - sal_Int32 xdpi, ydpi; - GetResolution(xdpi, ydpi); - GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *m_pServerFont[nFallbackLevel], xdpi, ydpi); - if (!pGrfont) return NULL; - pLayout = new GraphiteServerFontLayout(pGrfont); + pLayout = new GraphiteServerFontLayout(*m_pServerFont[nFallbackLevel]); } else #endif diff --git a/vcl/unx/source/gdi/salgdi3.cxx b/vcl/unx/source/gdi/salgdi3.cxx index b135ac4eb00e..776fdb330b80 100644 --- a/vcl/unx/source/gdi/salgdi3.cxx +++ b/vcl/unx/source/gdi/salgdi3.cxx @@ -1823,16 +1823,9 @@ SalLayout* X11SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe #ifdef ENABLE_GRAPHITE // Is this a Graphite font? if (!bDisableGraphite_ && - GraphiteFontAdaptor::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel])) + GraphiteServerFontLayout::IsGraphiteEnabledFont(mpServerFont[nFallbackLevel])) { - sal_Int32 xdpi, ydpi; - - xdpi = GetDisplay()->GetResolution().A(); - ydpi = GetDisplay()->GetResolution().B(); - - GraphiteFontAdaptor * pGrfont = new GraphiteFontAdaptor( *mpServerFont[nFallbackLevel], xdpi, ydpi); - if (!pGrfont) return NULL; - pLayout = new GraphiteServerFontLayout(pGrfont); + pLayout = new GraphiteServerFontLayout(*mpServerFont[nFallbackLevel]); } else #endif diff --git a/vcl/util/makefile.mk b/vcl/util/makefile.mk index 7f80738c61a1..6e75f09498fb 100755 --- a/vcl/util/makefile.mk +++ b/vcl/util/makefile.mk @@ -187,7 +187,7 @@ SHL1STDLIBS+=\ .IF "$(SYSTEM_GRAPHITE)" == "YES" SHL1STDLIBS+= $(GRAPHITE_LIBS) .ELSE -SHL1STDLIBS+= $(SOLARVERSION)/$(INPATH)/lib$(UPDMINOREXT)/libgraphite.a +SHL1STDLIBS+= -lgraphite2 .ENDIF .ENDIF .ENDIF @@ -232,9 +232,9 @@ DEFLIB1NAME =vcl .IF "$(ENABLE_GRAPHITE)" == "TRUE" .IF "$(COM)" == "GCC" -SHL1STDLIBS += -lgraphite +SHL1STDLIBS += -lgraphite2 .ELSE -SHL1STDLIBS += graphite_dll.lib +SHL1STDLIBS += graphite2.lib .ENDIF .ENDIF diff --git a/vcl/win/inc/salgdi.h b/vcl/win/inc/salgdi.h index 637a759b0b46..951e0c8d7690 100644 --- a/vcl/win/inc/salgdi.h +++ b/vcl/win/inc/salgdi.h @@ -39,6 +39,10 @@ #include "boost/scoped_ptr.hpp" #include <boost/unordered_set.hpp> +#ifdef ENABLE_GRAPHITE +#include <graphite2/Font.h> +#endif + class ImplFontSelectData; class ImplWinFontEntry; class ImplFontAttrCache; @@ -55,6 +59,26 @@ class ImplFontAttrCache; #define GCP_KERN_HACK #define GNG_VERT_HACK +#ifdef ENABLE_GRAPHITE +class RawFontData; +class GrFontData +{ +public: + GrFontData(HDC hDC); + ~GrFontData(); + const void * getTable(unsigned int name, size_t *len) const; + const gr_face * getFace() const { return mpFace; } + void AddReference() { ++mnRefCount; } + void DeReference() { if (--mnRefCount == 0) delete this; } +private: + GrFontData(GrFontData &) {}; + HDC mhDC; + mutable std::vector<RawFontData*> mvData; + gr_face * mpFace; + unsigned int mnRefCount; +}; +#endif + // win32 specific physically available font face class ImplWinFontData : public ImplFontData { @@ -82,6 +106,7 @@ public: bool AliasSymbolsLow() const { return mbAliasSymbolsLow; } #ifdef ENABLE_GRAPHITE bool SupportsGraphite() const { return mbHasGraphiteSupport; } + const gr_face* GraphiteFace() const; #endif ImplFontCharMap* GetImplFontCharMap() const; @@ -101,6 +126,7 @@ private: mutable bool mbHasKoreanRange; mutable bool mbHasCJKSupport; #ifdef ENABLE_GRAPHITE + mutable GrFontData* mpGraphiteData; mutable bool mbHasGraphiteSupport; #endif mutable bool mbHasArabicSupport; @@ -144,7 +170,8 @@ public: HFONT mhFonts[ MAX_FALLBACK ]; // Font + Fallbacks const ImplWinFontData* mpWinFontData[ MAX_FALLBACK ]; // pointer to the most recent font face ImplWinFontEntry* mpWinFontEntry[ MAX_FALLBACK ]; // pointer to the most recent font instance - float mfFontScale; // allows metrics emulation of huge font sizes + float mfFontScale[ MAX_FALLBACK ]; // allows metrics emulation of huge font sizes + float mfCurrentFontScale; HPEN mhPen; // Pen HBRUSH mhBrush; // Brush HRGN mhRegion; // Region Handle diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx index f06108393716..cac65c8c229b 100644 --- a/vcl/win/source/gdi/salgdi.cxx +++ b/vcl/win/source/gdi/salgdi.cxx @@ -722,9 +722,10 @@ WinSalGraphics::WinSalGraphics() mhFonts[ i ] = 0; mpWinFontData[ i ] = NULL; mpWinFontEntry[ i ] = NULL; + mfFontScale[ i ] = 1.0; } - mfFontScale = 1.0; + mfCurrentFontScale = 1.0; mhDC = 0; mhPen = 0; diff --git a/vcl/win/source/gdi/salgdi3.cxx b/vcl/win/source/gdi/salgdi3.cxx index 5b744f599815..da7b42807acf 100644 --- a/vcl/win/source/gdi/salgdi3.cxx +++ b/vcl/win/source/gdi/salgdi3.cxx @@ -78,8 +78,7 @@ #endif #ifdef ENABLE_GRAPHITE -#include <graphite/GrClient.h> -#include <graphite/WinFont.h> +#include <graphite2/Font.h> #endif #include <vector> @@ -1091,6 +1090,106 @@ void ImplSalLogFontToFontW( HDC hDC, const LOGFONTW& rLogFont, Font& rFont ) } // ======================================================================= +#ifdef ENABLE_GRAPHITE + +#ifdef DEBUG +static FILE * grLogFile = NULL; +static FILE * grLog() +{ +#ifdef WNT + std::string logFileName(getenv("TEMP")); + logFileName.append("\\grface.log"); + if (grLogFile == NULL) grLogFile = fopen(logFileName.c_str(),"w"); + else fflush(grLogFile); + return grLogFile; +#else + fflush(stdout); + return stdout; +#endif +} +#undef NDEBUG +#endif + +const void * getGrTable(const void* appFaceHandle, unsigned int name, size_t *len) +{ + const GrFontData * fontTables = reinterpret_cast<const GrFontData*>(appFaceHandle); + return fontTables->getTable(name, len); +} + +GrFontData::GrFontData(HDC hDC) : + mhDC(hDC), mpFace(NULL), mnRefCount(1) +{ + // The face options ensure that the tables are all read at construction + // time so there is no need to keep the hDC uptodate + static const char* pGraphiteCacheStr = getenv( "SAL_GRAPHITE_CACHE_SIZE" ); + unsigned long graphiteSegCacheSize = pGraphiteCacheStr ? (atoi(pGraphiteCacheStr)) : 0; + if (graphiteSegCacheSize > 500) + mpFace = gr_make_face_with_seg_cache(this, getGrTable, + graphiteSegCacheSize, gr_face_preloadGlyphs | gr_face_cacheCmap); + else + mpFace = gr_make_face(this, getGrTable, + gr_face_preloadGlyphs | gr_face_cacheCmap); +#ifdef DEBUG + fprintf(grLog(), "gr_make_face %lx for WinFontData %lx\n", (unsigned long)mpFace, + (unsigned long)this); +#endif + mhDC = NULL; +} + +GrFontData::~GrFontData() +{ + if (mpFace) + { +#ifdef DEBUG + fprintf(grLog(), "gr_face_destroy %lx for WinFontData %lx\n", (unsigned long)mpFace, + (unsigned long)this); +#endif + gr_face_destroy(mpFace); + mpFace = NULL; + } + std::vector<RawFontData*>::iterator i = mvData.begin(); + while (i != mvData.end()) + { + delete *i; + ++i; + } + mvData.clear(); +} + +const void * GrFontData::getTable(unsigned int name, size_t *len) const +{ +#ifdef DEBUG +#undef NDEBUG +#endif + assert(mhDC); + // swap the bytes + union TtfTag { + unsigned int i; + unsigned char c[4]; + }; + TtfTag littleEndianTag; + littleEndianTag.i = name; + TtfTag bigEndianTag; + bigEndianTag.c[0] = littleEndianTag.c[3]; + bigEndianTag.c[1] = littleEndianTag.c[2]; + bigEndianTag.c[2] = littleEndianTag.c[1]; + bigEndianTag.c[3] = littleEndianTag.c[0]; + mvData.push_back(new RawFontData(mhDC, bigEndianTag.i)); + const RawFontData * data = mvData[mvData.size()-1]; + if (data && (data->size() > 0)) + { + if (len) + *len = data->size(); + return reinterpret_cast<const void *>(data->get()); + } + else + { + if (len) + *len = 0; + return NULL; + } +} +#endif ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS, int nHeight, WIN_BYTE eWinCharSet, WIN_BYTE nPitchAndFamily ) @@ -1112,6 +1211,9 @@ ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS, mbAliasSymbolsHigh( false ), mnId( 0 ), mpEncodingVector( NULL ) +#ifdef ENABLE_GRAPHITE + ,mpGraphiteData(NULL) +#endif { SetBitmapSize( 0, nHeight ); @@ -1135,6 +1237,9 @@ ImplWinFontData::ImplWinFontData( const ImplDevFontAttributes& rDFS, mbAliasSymbolsHigh = true; } } +#ifdef DEBUG + fprintf(grLog(), "ImplWinFontData::ImplWinFontData() %lx\n", (unsigned long)this); +#endif } // ----------------------------------------------------------------------- @@ -1145,6 +1250,13 @@ ImplWinFontData::~ImplWinFontData() if( mpUnicodeMap ) mpUnicodeMap->DeReference(); +#ifdef ENABLE_GRAPHITE + if (mpGraphiteData) + mpGraphiteData->DeReference(); +#ifdef DEBUG + fprintf(grLog(), "ImplWinFontData::~ImplWinFontData %lx\n", (unsigned long)this); +#endif +#endif // ENABLE_GRAPHITE delete mpEncodingVector; } @@ -1157,6 +1269,11 @@ sal_IntPtr ImplWinFontData::GetFontId() const // ----------------------------------------------------------------------- +static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);} +static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);} +//static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));} +static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); } + void ImplWinFontData::UpdateFromHDC( HDC hDC ) const { // short circuit if already initialized @@ -1169,7 +1286,26 @@ void ImplWinFontData::UpdateFromHDC( HDC hDC ) const static const char* pDisableGraphiteText = getenv( "SAL_DISABLE_GRAPHITE" ); if( !pDisableGraphiteText || (pDisableGraphiteText[0] == '0') ) { - mbHasGraphiteSupport = gr::WinFont::FontHasGraphiteTables(hDC); + const DWORD nSilfTag = CalcTag("Silf"); + const RawFontData aRawFontData( hDC, nSilfTag ); + mbHasGraphiteSupport = (aRawFontData.size() > 0); + if (mbHasGraphiteSupport) + { +#ifdef DEBUG + fprintf(grLog(), "ImplWinFontData::UpdateFromHDC %lx\n", + (unsigned long)this); +#endif + if (mpGraphiteData == NULL) + { + mpGraphiteData = new GrFontData(hDC); + if (!mpGraphiteData->getFace()) + { + mbHasGraphiteSupport = false; + delete mpGraphiteData; + mpGraphiteData = NULL; + } + } + } } #endif @@ -1183,6 +1319,17 @@ void ImplWinFontData::UpdateFromHDC( HDC hDC ) const } +#ifdef ENABLE_GRAPHITE +const gr_face* ImplWinFontData::GraphiteFace() const +{ +#ifdef DEBUG + fprintf(grLog(), "ImplWinFontData::GraphiteFace %lx has face %lx\n", + (unsigned long)this, mpGraphiteData? mpGraphiteData->getFace(): 0); +#endif + assert((mpGraphiteData == NULL) || (mpGraphiteData->getFontData() == this)); + return (mpGraphiteData)? mpGraphiteData->getFace() : NULL; +} +#endif // ----------------------------------------------------------------------- bool ImplWinFontData::HasGSUBstitutions( HDC hDC ) const @@ -1222,6 +1369,31 @@ static unsigned GetUShort( const unsigned char* p ){ return((p[0]<<8)+p[1]);} //static signed GetSShort( const unsigned char* p ){ return((short)((p[0]<<8)+p[1]));} static inline DWORD CalcTag( const char p[4]) { return (p[0]+(p[1]<<8)+(p[2]<<16)+(p[3]<<24)); } +void ImplWinFontData::ReadOs2Table( HDC hDC ) const +{ + const DWORD Os2Tag = CalcTag( "OS/2" ); + DWORD nLength = ::GetFontData( hDC, Os2Tag, 0, NULL, 0 ); + if( (nLength == GDI_ERROR) || !nLength ) + return; + std::vector<unsigned char> aOS2map( nLength ); + unsigned char* pOS2map = &aOS2map[0]; + ::GetFontData( hDC, Os2Tag, 0, pOS2map, nLength ); + sal_uInt32 nVersion = GetUShort( pOS2map ); + if ( nVersion >= 0x0001 && nLength >= 58 ) + { + // We need at least version 0x0001 (TrueType rev 1.66) + // to have access to the needed struct members. + sal_uInt32 ulUnicodeRange1 = GetUInt( pOS2map + 42 ); + sal_uInt32 ulUnicodeRange2 = GetUInt( pOS2map + 46 ); + + // Check for CJK capabilities of the current font + mbHasCJKSupport = (ulUnicodeRange2 & 0x2DF00000); + mbHasKoreanRange= (ulUnicodeRange1 & 0x10000000) + | (ulUnicodeRange2 & 0x01100000); + mbHasArabicSupport = (ulUnicodeRange1 & 0x00002000); + } +} + // ----------------------------------------------------------------------- void ImplWinFontData::ReadGsubTable( HDC hDC ) const @@ -1545,6 +1717,7 @@ USHORT WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel ) // deselect still active font if( mhDefFont ) ::SelectFont( mhDC, mhDefFont ); + mfCurrentFontScale = mfFontScale[nFallbackLevel]; // release no longer referenced font handles for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) { @@ -1561,7 +1734,8 @@ USHORT WinSalGraphics::SetFont( ImplFontSelectData* pFont, int nFallbackLevel ) mpWinFontData[ nFallbackLevel ] = static_cast<const ImplWinFontData*>( pFont->mpFontData ); HFONT hOldFont = 0; - HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale, hOldFont ); + HFONT hNewFont = ImplDoSetFont( pFont, mfFontScale[ nFallbackLevel ], hOldFont ); + mfCurrentFontScale = mfFontScale[nFallbackLevel]; if( !mhDefFont ) { @@ -1655,11 +1829,11 @@ void WinSalGraphics::GetFontMetric( ImplFontMetricData* pMetric, int nFallbackLe } // transformation dependend font metrics - pMetric->mnWidth = static_cast<int>( mfFontScale * aWinMetric.tmAveCharWidth ); - pMetric->mnIntLeading = static_cast<int>( mfFontScale * aWinMetric.tmInternalLeading ); - pMetric->mnExtLeading = static_cast<int>( mfFontScale * aWinMetric.tmExternalLeading ); - pMetric->mnAscent = static_cast<int>( mfFontScale * aWinMetric.tmAscent ); - pMetric->mnDescent = static_cast<int>( mfFontScale * aWinMetric.tmDescent ); + pMetric->mnWidth = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmAveCharWidth ); + pMetric->mnIntLeading = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmInternalLeading ); + pMetric->mnExtLeading = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmExternalLeading ); + pMetric->mnAscent = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmAscent ); + pMetric->mnDescent = static_cast<int>( mfFontScale[nFallbackLevel] * aWinMetric.tmDescent ); // #107888# improved metric compatibility for Asian fonts... // TODO: assess workaround below for CWS >= extleading @@ -2386,10 +2560,10 @@ BOOL WinSalGraphics::GetGlyphBoundRect( long nIndex, Rectangle& rRect ) rRect = Rectangle( Point( +aGM.gmptGlyphOrigin.x, -aGM.gmptGlyphOrigin.y ), Size( aGM.gmBlackBoxX, aGM.gmBlackBoxY ) ); - rRect.Left() = static_cast<int>( mfFontScale * rRect.Left() ); - rRect.Right() = static_cast<int>( mfFontScale * rRect.Right() ); - rRect.Top() = static_cast<int>( mfFontScale * rRect.Top() ); - rRect.Bottom() = static_cast<int>( mfFontScale * rRect.Bottom() ); + rRect.Left() = static_cast<int>( mfCurrentFontScale * rRect.Left() ); + rRect.Right() = static_cast<int>( mfCurrentFontScale * rRect.Right() ); + rRect.Top() = static_cast<int>( mfCurrentFontScale * rRect.Top() ); + rRect.Bottom() = static_cast<int>( mfCurrentFontScale * rRect.Bottom() ); return true; } @@ -2575,7 +2749,7 @@ BOOL WinSalGraphics::GetGlyphOutline( long nIndex, // rescaling needed for the PolyPolygon conversion if( rB2DPolyPoly.count() ) { - const double fFactor(mfFontScale/256); + const double fFactor(mfCurrentFontScale/256); rB2DPolyPoly.transform(basegfx::tools::createScaleB2DHomMatrix(fFactor, fFactor)); } diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 1114de6f098b..a340ab512a57 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -74,11 +74,7 @@ typedef std::set<int> IntSet; // Graphite headers #ifdef ENABLE_GRAPHITE #include <i18npool/mslangid.hxx> -#include <graphite/GrClient.h> -#include <graphite/WinFont.h> -#include <graphite/Segment.h> #include <vcl/graphite_layout.hxx> -#include <vcl/graphite_cache.hxx> #include <vcl/graphite_features.hxx> #endif @@ -1951,11 +1947,11 @@ int UniscribeLayout::GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, } else { - nExtraOfs += nToFillWidth; // at right of cell - nSubIter = 0; // done with glyph injection + nExtraOfs += nToFillWidth; // at right of cell + nSubIter = 0; // done with glyph injection } if( !bManualCellAlign ) - nExtraOfs -= nExtraWidth; // adjust for right-aligned cells + nExtraOfs -= nExtraWidth; // adjust for right-aligned cells // adjust the draw position for the injected-glyphs case if( nExtraOfs ) @@ -2561,8 +2557,8 @@ void UniscribeLayout::KashidaItemFix( int nMinGlyphPos, int nEndGlyphPos ) { // check for vowels if( (i > nMinGlyphPos && !mpGlyphAdvances[ i-1 ]) - && (1U << mpVisualAttrs[i].uJustification) & 0xFF83 ) // all Arabic justifiction types - { // including SCRIPT_JUSTIFY_NONE + && (1U << mpVisualAttrs[i].uJustification) & 0xFF83 ) // all Arabic justifiction types + { // including SCRIPT_JUSTIFY_NONE // vowel, we do it like ScriptJustify does // the vowel gets the extra width long nSpaceAdded = mpJustifications[ i ] - mpGlyphAdvances[ i ]; @@ -2695,7 +2691,7 @@ void UniscribeLayout::Justify( long nNewWidth ) if( nOldWidth <= 0 ) return; - nNewWidth *= mnUnitsPerPixel; // convert into font units + nNewWidth *= mnUnitsPerPixel; // convert into font units if( nNewWidth == nOldWidth ) return; // prepare to distribute the extra width evenly among the visual items @@ -2757,8 +2753,8 @@ bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const if ( nMinGlyphIndex == -1 || !mpLogClusters[ nCharPos ] ) return false; -// This test didn't give the expected results -/* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ]) +// This test didn't give the expected results +/* if( mpLogClusters[ nCharPos+1 ] == mpLogClusters[ nCharPos ]) // two chars, one glyph return false;*/ @@ -2782,9 +2778,9 @@ bool UniscribeLayout::IsKashidaPosValid ( int nCharPos ) const class GraphiteLayoutWinImpl : public GraphiteLayout { public: - GraphiteLayoutWinImpl(const gr::Font & font, ImplWinFontEntry & rFont) + GraphiteLayoutWinImpl(const gr_face * pFace, ImplWinFontEntry & rFont) throw() - : GraphiteLayout(font), mrFont(rFont) {}; + : GraphiteLayout(pFace), mrFont(rFont) {}; virtual ~GraphiteLayoutWinImpl() throw() {}; virtual sal_GlyphId getKashidaGlyph(int & rWidth); private: @@ -2803,18 +2799,15 @@ sal_GlyphId GraphiteLayoutWinImpl::getKashidaGlyph(int & rWidth) class GraphiteWinLayout : public WinLayout { private: - mutable GraphiteWinFont mpFont; + gr_font * mpFont; grutils::GrFeatureParser * mpFeatures; mutable GraphiteLayoutWinImpl maImpl; public: GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE); - static bool IsGraphiteEnabledFont(HDC hDC) throw(); - // used by upper layers virtual bool LayoutText( ImplLayoutArgs& ); // first step of layout virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting after fallback etc. - // virtual void InitFont() const; virtual void DrawText( SalGraphics& ) const; // methods using string indexing @@ -2832,20 +2825,31 @@ public: virtual void DropGlyph( int nStart ); virtual void Simplify( bool bIsBase ); ~GraphiteWinLayout() { delete mpFeatures; mpFeatures = NULL; }; -protected: - virtual void ReplaceDC(gr::Segment & segment) const; - virtual void RestoreDC(gr::Segment & segment) const; }; -bool GraphiteWinLayout::IsGraphiteEnabledFont(HDC hDC) throw() +float gr_fontAdvance(const void* appFontHandle, gr_uint16 glyphId) { - return gr::WinFont::FontHasGraphiteTables(hDC); + HDC hDC = reinterpret_cast<HDC>(const_cast<void*>(appFontHandle)); + GLYPHMETRICS gm; + const MAT2 mat2 = {{0,1}, {0,0}, {0,0}, {0,1}}; + if (GDI_ERROR == ::GetGlyphOutlineW(hDC, glyphId, GGO_GLYPH_INDEX | GGO_METRICS, + &gm, 0, NULL, &mat2)) + { + return .0f; + } + return gm.gmCellIncX; } GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplWinFontEntry& rWFE) throw() - : WinLayout(hDC, rWFD, rWFE), mpFont(hDC), - maImpl(mpFont, rWFE) + : WinLayout(hDC, rWFD, rWFE), mpFont(NULL), + maImpl(rWFD.GraphiteFace(), rWFE) { + // the log font size may differ from the font entry size if scaling is used for large fonts + LOGFONTW aLogFont; + ::GetObjectW( mhFont, sizeof(LOGFONTW), &aLogFont); + mpFont = gr_make_font_with_advance_fn(static_cast<float>(-aLogFont.lfHeight), + hDC, gr_fontAdvance, rWFD.GraphiteFace()); + maImpl.TakeFont(mpFont); const rtl::OString aLang = MsLangId::convertLanguageToIsoByteString( rWFE.maFontSelData.meLanguage ); rtl::OString name = rtl::OUStringToOString( rWFE.maFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 ); @@ -2853,27 +2857,15 @@ GraphiteWinLayout::GraphiteWinLayout(HDC hDC, const ImplWinFontData& rWFD, ImplW if (nFeat > 0) { rtl::OString aFeat = name.copy(nFeat, name.getLength() - nFeat); - mpFeatures = new grutils::GrFeatureParser(mpFont, aFeat.getStr(), aLang.getStr()); + mpFeatures = new grutils::GrFeatureParser(rWFD.GraphiteFace(), aFeat.getStr(), aLang.getStr()); } else { - mpFeatures = new grutils::GrFeatureParser(mpFont, aLang.getStr()); + mpFeatures = new grutils::GrFeatureParser(rWFD.GraphiteFace(), aLang.getStr()); } maImpl.SetFeatures(mpFeatures); } -void GraphiteWinLayout::ReplaceDC(gr::Segment & segment) const -{ - COLORREF color = GetTextColor(mhDC); - dynamic_cast<gr::WinFont&>(segment.getFont()).replaceDC(mhDC); - SetTextColor(mhDC, color); -} - -void GraphiteWinLayout::RestoreDC(gr::Segment & segment) const -{ - dynamic_cast<gr::WinFont&>(segment.getFont()).restoreDC(); -} - bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args) { if (args.mnMinCharPos >= args.mnEndCharPos) @@ -2881,7 +2873,7 @@ bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args) maImpl.clear(); return true; } - HFONT hUnRotatedFont; + HFONT hUnRotatedFont = 0; if (args.mnOrientation) { // Graphite gets very confused if the font is rotated @@ -2893,36 +2885,16 @@ bool GraphiteWinLayout::LayoutText( ImplLayoutArgs & args) ::SelectFont(mhDC, hUnRotatedFont); } WinLayout::AdjustLayout(args); - mpFont.replaceDC(mhDC); maImpl.SetFontScale(WinLayout::mfFontScale); - //bool succeeded = maImpl.LayoutText(args); -#ifdef GRCACHE - GrSegRecord * pSegRecord = NULL; - gr::Segment * pSegment = maImpl.CreateSegment(args, &pSegRecord); -#else - gr::Segment * pSegment = maImpl.CreateSegment(args); -#endif + gr_segment * pSegment = maImpl.CreateSegment(args); bool bSucceeded = false; if (pSegment) { // replace the DC on the font within the segment - ReplaceDC(*pSegment); // create glyph vectors -#ifdef GRCACHE - bSucceeded = maImpl.LayoutGlyphs(args, pSegment, pSegRecord); -#else bSucceeded = maImpl.LayoutGlyphs(args, pSegment); -#endif - // restore original DC - RestoreDC(*pSegment); -#ifdef GRCACHE - if (pSegRecord) pSegRecord->unlock(); - else delete pSegment; -#else - delete pSegment; -#endif + gr_seg_destroy(pSegment); } - mpFont.restoreDC(); if (args.mnOrientation) { // restore the rotated font @@ -2971,9 +2943,7 @@ void GraphiteWinLayout::DrawText(SalGraphics &sal_graphics) const int GraphiteWinLayout::GetTextBreak( long nMaxWidth, long nCharExtra, int nFactor ) const { - mpFont.replaceDC(mhDC); int nBreak = maImpl.GetTextBreak(nMaxWidth, nCharExtra, nFactor); - mpFont.restoreDC(); return nBreak; } @@ -3027,7 +2997,9 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe { #ifdef ENABLE_GRAPHITE if (rFontFace.SupportsGraphite()) + { pWinLayout = new GraphiteWinLayout(mhDC, rFontFace, rFontInstance); + } else #endif // ENABLE_GRAPHITE // script complexity is determined in upper layers @@ -3060,20 +3032,20 @@ SalLayout* WinSalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLe pWinLayout = new SimpleWinLayout( mhDC, eCharSet, rFontFace, rFontInstance ); } - if( mfFontScale != 1.0 ) - pWinLayout->SetFontScale( mfFontScale ); + if( mfFontScale[nFallbackLevel] != 1.0 ) + pWinLayout->SetFontScale( mfFontScale[nFallbackLevel] ); return pWinLayout; } // ----------------------------------------------------------------------- -int WinSalGraphics::GetMinKashidaWidth() +int WinSalGraphics::GetMinKashidaWidth() { if( !mpWinFontEntry[0] ) return 0; mpWinFontEntry[0]->InitKashidaHandling( mhDC ); - int nMinKashida = static_cast<int>(mfFontScale * mpWinFontEntry[0]->GetMinKashidaWidth()); + int nMinKashida = static_cast<int>(mfFontScale[0] * mpWinFontEntry[0]->GetMinKashidaWidth()); return nMinKashida; } @@ -3084,8 +3056,8 @@ ImplWinFontEntry::ImplWinFontEntry( ImplFontSelectData& rFSD ) , maWidthMap( 512 ) , mpKerningPairs( NULL ) , mnKerningPairs( -1 ) -, mnMinKashidaWidth( -1 ) -, mnMinKashidaGlyph( -1 ) +, mnMinKashidaWidth( -1 ) +, mnMinKashidaGlyph( -1 ) { #ifdef USE_UNISCRIBE maScriptCache = NULL; @@ -3175,6 +3147,10 @@ ImplFontData* ImplWinFontData::Clone() const { if( mpUnicodeMap ) mpUnicodeMap->AddReference(); +#ifdef ENABLE_GRAPHITE + if ( mpGraphiteData ) + mpGraphiteData->AddReference(); +#endif ImplFontData* pClone = new ImplWinFontData( *this ); return pClone; } |