summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Hosken <martin_hosken@sil.org>2011-02-25 16:10:55 +0700
committerMartin Hosken <martin_hosken@sil.org>2011-03-10 22:40:13 +0700
commitdf3c7e76cca60d246277731d0c525d5f7e6f6597 (patch)
tree3526bbe9a0eb2ca6e6373a75697fc5d9bcefac63
parentfix for 3.3.2 blocker fdo#34718 - change the type of nDrawerHeight to long (diff)
downloadcore-df3c7e76cca60d246277731d0c525d5f7e6f6597.tar.gz
core-df3c7e76cca60d246277731d0c525d5f7e6f6597.zip
graphite2 consolidated patch
-rw-r--r--comphelper/qa/weakbag/test_weakbag_noadditional.cxx2
-rw-r--r--vcl/inc/vcl/graphite_adaptors.hxx145
-rw-r--r--vcl/inc/vcl/graphite_cache.hxx290
-rw-r--r--vcl/inc/vcl/graphite_features.hxx47
-rw-r--r--vcl/inc/vcl/graphite_layout.hxx113
-rw-r--r--vcl/inc/vcl/graphite_serverfont.hxx25
-rw-r--r--vcl/source/glyphs/gcach_ftyp.cxx65
-rw-r--r--vcl/source/glyphs/gcach_ftyp.hxx15
-rw-r--r--vcl/source/glyphs/graphite_adaptors.cxx339
-rw-r--r--vcl/source/glyphs/graphite_cache.cxx201
-rw-r--r--vcl/source/glyphs/graphite_features.cxx233
-rw-r--r--vcl/source/glyphs/graphite_layout.cxx958
-rw-r--r--vcl/source/glyphs/graphite_serverfont.cxx100
-rw-r--r--vcl/source/glyphs/makefile.mk8
-rw-r--r--vcl/unx/source/gdi/pspgraphics.cxx8
-rw-r--r--vcl/unx/source/gdi/salgdi3.cxx11
-rwxr-xr-xvcl/util/makefile.mk6
-rw-r--r--vcl/win/inc/salgdi.h29
-rw-r--r--vcl/win/source/gdi/salgdi.cxx3
-rw-r--r--vcl/win/source/gdi/salgdi3.cxx202
-rw-r--r--vcl/win/source/gdi/winlayout.cxx116
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;
}