summaryrefslogtreecommitdiff
path: root/vcl/source/glyphs
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 /vcl/source/glyphs
parente2c95099c8946ab051de02c28d98d18b2c3037e7 (diff)
graphite2 consolidated patch
Diffstat (limited to 'vcl/source/glyphs')
-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
8 files changed, 669 insertions, 1250 deletions
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