michael@0: /* GRAPHITE2 LICENSING michael@0: michael@0: Copyright 2010, SIL International michael@0: All rights reserved. michael@0: michael@0: This library is free software; you can redistribute it and/or modify michael@0: it under the terms of the GNU Lesser General Public License as published michael@0: by the Free Software Foundation; either version 2.1 of License, or michael@0: (at your option) any later version. michael@0: michael@0: This program is distributed in the hope that it will be useful, michael@0: but WITHOUT ANY WARRANTY; without even the implied warranty of michael@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU michael@0: Lesser General Public License for more details. michael@0: michael@0: You should also have received a copy of the GNU Lesser General Public michael@0: License along with this library in the file named "LICENSE". michael@0: If not, write to the Free Software Foundation, 51 Franklin Street, michael@0: Suite 500, Boston, MA 02110-1335, USA or visit their web page on the michael@0: internet at http://www.fsf.org/licenses/lgpl.html. michael@0: michael@0: Alternatively, the contents of this file may be used under the terms of the michael@0: Mozilla Public License (http://mozilla.org/MPL) or the GNU General Public michael@0: License, as published by the Free Software Foundation, either version 2 michael@0: of the License or (at your option) any later version. michael@0: */ michael@0: #include "inc/GlyphFaceCache.h" michael@0: #include "graphite2/Font.h" michael@0: #include "inc/Face.h" //for the tags michael@0: #include "inc/Endian.h" michael@0: michael@0: using namespace graphite2; michael@0: michael@0: /*virtual*/ bool GlyphFaceCacheHeader::initialize(const Face & face, const bool dumb_font) //return result indicates success. Do not use if failed. michael@0: { michael@0: if ((m_pLoca = face.getTable(Tag::loca, &m_lLoca)) == NULL) return false; michael@0: if ((m_pHead = face.getTable(Tag::head)) == NULL) return false; michael@0: if ((m_pGlyf = face.getTable(Tag::glyf, &m_lGlyf)) == NULL) return false; michael@0: if ((m_pHmtx = face.getTable(Tag::hmtx, &m_lHmtx)) == NULL) return false; michael@0: if ((m_pHHea = face.getTable(Tag::hhea)) == NULL) return false; michael@0: michael@0: const void* pMaxp = face.getTable(Tag::maxp); michael@0: if (pMaxp == NULL) return false; michael@0: m_nGlyphs = m_nGlyphsWithGraphics = (unsigned short)TtfUtil::GlyphCount(pMaxp); michael@0: if (TtfUtil::LocaLookup(m_nGlyphs-1, m_pLoca, m_lLoca, m_pHead) == size_t(-1)) michael@0: return false; // This will fail if m_nGlyphs is wildly out of range. michael@0: michael@0: if (!dumb_font) michael@0: { michael@0: if ((m_pGlat = face.getTable(Tag::Glat, &m_lGlat)) == NULL) return false; michael@0: m_fGlat = be::peek(m_pGlat); michael@0: size_t lGloc; michael@0: if ((m_pGloc = face.getTable(Tag::Gloc, &lGloc)) == NULL) return false; michael@0: if (lGloc < 6) return false; michael@0: int version = be::read(m_pGloc); michael@0: if (version != 0x00010000) return false; michael@0: michael@0: const uint16 locFlags = be::read(m_pGloc); michael@0: m_numAttrs = be::read(m_pGloc); michael@0: if (m_numAttrs > 0x1000) return false; // is this hard limit appropriate? michael@0: michael@0: if (locFlags & 1) michael@0: { michael@0: m_locFlagsUse32Bit = true; michael@0: m_nGlyphsWithAttributes = (unsigned short)((lGloc - 12) / 4); michael@0: } michael@0: else michael@0: { michael@0: m_locFlagsUse32Bit = false; michael@0: m_nGlyphsWithAttributes = (unsigned short)((lGloc - 10) / 2); michael@0: } michael@0: michael@0: if (m_nGlyphsWithAttributes > m_nGlyphs) michael@0: m_nGlyphs = m_nGlyphsWithAttributes; michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: michael@0: GlyphFaceCache* GlyphFaceCache::makeCache(const GlyphFaceCacheHeader& hdr) michael@0: { michael@0: return new (hdr) GlyphFaceCache(hdr); michael@0: } michael@0: michael@0: GlyphFaceCache::GlyphFaceCache(const GlyphFaceCacheHeader& hdr) michael@0: : GlyphFaceCacheHeader(hdr) michael@0: { michael@0: unsigned int nGlyphs = numGlyphs(); michael@0: michael@0: for (unsigned int i = 0; i < nGlyphs; i++) michael@0: { michael@0: *glyphPtrDirect(i) = NULL; michael@0: } michael@0: } michael@0: michael@0: GlyphFaceCache::~GlyphFaceCache() michael@0: { michael@0: unsigned int nGlyphs = numGlyphs(); michael@0: int deltaPointers = (*glyphPtrDirect(nGlyphs-1u) - *glyphPtrDirect(0u)); michael@0: if ((nGlyphs > 0u) && (deltaPointers == static_cast(nGlyphs - 1))) michael@0: { michael@0: for (unsigned int i=0 ; i~GlyphFace(); michael@0: } michael@0: free (*glyphPtrDirect(0)); michael@0: } michael@0: else michael@0: { michael@0: for (unsigned int i=0 ; i~GlyphFace(); michael@0: free(p); michael@0: } michael@0: } michael@0: } michael@0: } michael@0: michael@0: void GlyphFaceCache::loadAllGlyphs() michael@0: { michael@0: unsigned int nGlyphs = numGlyphs(); michael@0: // size_t sparse_size = 0; michael@0: GlyphFace * glyphs = gralloc(nGlyphs); michael@0: for (unsigned short glyphid = 0; glyphid < nGlyphs; glyphid++) michael@0: { michael@0: GlyphFace **p = glyphPtrDirect(glyphid); michael@0: *p = &(glyphs[glyphid]); michael@0: new(*p) GlyphFace(*this, glyphid); michael@0: // sparse_size += (*p)->m_attrs._sizeof(); michael@0: } michael@0: // const size_t flat_size = nGlyphs*(sizeof(uint16*) + sizeof(uint16)*numAttrs()); michael@0: // assert(sparse_size <= flat_size); michael@0: } michael@0: michael@0: /*virtual*/ const GlyphFace *GlyphFaceCache::glyph(unsigned short glyphid) const //result may be changed by subsequent call with a different glyphid michael@0: { michael@0: GlyphFace **p = glyphPtrDirect(glyphid); michael@0: if (*p) michael@0: return *p; michael@0: michael@0: *p = (GlyphFace*)malloc(sizeof(GlyphFace)); michael@0: new(*p) GlyphFace(*this, glyphid); michael@0: return *p; michael@0: }