diff options
author | Martin Hosken <martin_hosken@sil.org> | 2011-02-25 16:10:55 +0700 |
---|---|---|
committer | Martin Hosken <martin_hosken@sil.org> | 2011-03-10 22:40:13 +0700 |
commit | df3c7e76cca60d246277731d0c525d5f7e6f6597 (patch) | |
tree | 3526bbe9a0eb2ca6e6373a75697fc5d9bcefac63 /vcl/source/glyphs | |
parent | e2c95099c8946ab051de02c28d98d18b2c3037e7 (diff) |
graphite2 consolidated patch
Diffstat (limited to 'vcl/source/glyphs')
-rw-r--r-- | vcl/source/glyphs/gcach_ftyp.cxx | 65 | ||||
-rw-r--r-- | vcl/source/glyphs/gcach_ftyp.hxx | 15 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_adaptors.cxx | 339 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_cache.cxx | 201 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_features.cxx | 233 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_layout.cxx | 958 | ||||
-rw-r--r-- | vcl/source/glyphs/graphite_serverfont.cxx | 100 | ||||
-rw-r--r-- | vcl/source/glyphs/makefile.mk | 8 |
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 |