#include "PdfDraw.h" namespace Upp { #define LLOG(x) // LOG(x) #define LDUMP(x) // LLOG(#x << " = " << x); int TTFReader::Peek8(const char *s) { if(s + 1 > current_table.End()) Error(); return (byte)*s; } int TTFReader::Peek16(const char *s) { if(s + 2 > current_table.End()) Error(); return ((byte)s[0] << 8) | (byte)s[1]; } int TTFReader::Peek32(const char *s) { if(s + 4 > current_table.End()) Error(); return ((byte)s[0] << 24) | ((byte)s[1] << 16) | ((byte)s[2] << 8) | (byte)s[3]; } int TTFReader::Peek8(const char *s, int i) { return Peek16(s + i); } int TTFReader::Peek16(const char *s, int i) { return Peek16(s + 2 * i); } int TTFReader::Peek32(const char *s, int i) { return Peek32(s + 4 * i); } int TTFReader::Read8(const char *&s) { int q = byte(*s); s++; return q; } int TTFReader::Read16(const char *&s) { int q = Peek16(s); s += 2; return q; } int TTFReader::Read32(const char *&s) { int q = Peek32(s); s += 4; return q; } String TTFReader::Read(const char *&s, int n) { if(s + n > current_table.End()) Error(); String q(s, n); s += n; return q; } void TTFReader::Reset() { glyph_map.Clear(); } void TTFReader::SetGlyph(wchar chr, word glyph) { glyph_map.GetAdd(chr) = glyph; } const char *TTFReader::Seek(const char *tab, int& len) { ASSERT(strlen(tab) == 4); current_table = font.GetData(tab); len = current_table.GetCount(); return current_table; } const char *TTFReader::Seek(const char *tab) { int dummy; return Seek(tab, dummy); } void TTFReader::Seek(const char *tab, TTFStreamIn& s) { int len; s.beg = s.s = Seek(tab, len); s.lim = s.s + len; } String TTFReader::GetTable(const char *tab) { ASSERT(strlen(tab) == 4); return font.GetData(tab); } bool TTFReader::Open(const Font& fnt, bool symbol, bool justcheck) { try { int i; Reset(); table.Clear(); glyphinfo.Clear(); font = fnt; TTFStreamIn is; Seek("head", is); head.Serialize(is); if(head.magicNumber != 0x5F0F3CF5) Error(); LDUMP(head.unitsPerEm); LDUMP(head.xMin); LDUMP(head.yMin); LDUMP(head.xMax); LDUMP(head.yMax); LDUMP(head.indexToLocFormat); Seek("maxp", is); maxp.Serialize(is); LDUMP(maxp.numGlyphs); Seek("post", is); post.Serialize(is); // LLOGHEXLDUMP(is.s, is.lim - is.s); LDUMP((post.format >> 16)); LDUMP(post.italicAngle); LDUMP(post.italicAngle); LDUMP(post.underlinePosition); LDUMP(post.underlineThickness); LDUMP(post.italicAngle); Seek("hhea", is); hhea.Serialize(is); LDUMP(hhea.ascent); LDUMP(hhea.descent); LDUMP(hhea.lineGap); LDUMP(hhea.advanceWidthMax); LDUMP(hhea.numOfLongHorMetrics); if(hhea.numOfLongHorMetrics > maxp.numGlyphs) Error(); glyphinfo.SetCount(maxp.numGlyphs); if(justcheck) return ReadCmap(fnt, [&](int, int, int) {}, CMAP_ALLOW_SYMBOL); const char *s = Seek("hmtx"); if(!s) Error(); int aw = 0; for(i = 0; i < hhea.numOfLongHorMetrics; i++) { aw = glyphinfo[i].advanceWidth = (uint16)Read16(s); glyphinfo[i].leftSideBearing = (int16)Read16(s); } for(; i < maxp.numGlyphs; i++) { glyphinfo[i].advanceWidth = aw; glyphinfo[i].leftSideBearing = (int16)Read16(s); } s = Seek("loca"); if(!s) Error(); for(i = 0; i < maxp.numGlyphs; i++) if(head.indexToLocFormat) { glyphinfo[i].offset = Peek32(s, i); glyphinfo[i].size = Peek32(s, i + 1) - glyphinfo[i].offset; } else { glyphinfo[i].offset = 2 * (word)Peek16(s, i); glyphinfo[i].size = 2 * (word)Peek16(s, i + 1) - glyphinfo[i].offset; } for(i = 0; i < maxp.numGlyphs; i++) LLOG(i << " advance: " << glyphinfo[i].advanceWidth << ", left: " << glyphinfo[i].leftSideBearing << ", offset: " << glyphinfo[i].offset << ", size: " << glyphinfo[i].size); ReadCmap(fnt, [&](int start, int end, int glyph) { for(int ch = start; ch <= end; ch++) SetGlyph(ch, glyph++); }, CMAP_GLYPHS|CMAP_ALLOW_SYMBOL); const char *strings = Seek("name"); if(!strings) Error(); s = strings + 2; int count = Read16(s); strings += (word)Read16(s); for(int i = 0; i < count; i++) { int platform = Read16(s); s += 4; if(Read16(s) == 6) { int len = Read16(s); int offset = Read16(s); if(platform == 1) ps_name = String(strings + offset, len); else { s = strings + offset; len >>= 1; while(len--) ps_name.Cat(Read16(s)); } break; } s += 4; } LDUMP(ps_name); } catch(Fail) { return false; } catch(TTFStream::Fail) { return false; } return true; } TTFReader::TTFReader() { Reset(); } }