ultimatepp/uppsrc/PdfDraw/TTFReader.cpp
2022-01-05 08:45:00 +01:00

230 lines
4.7 KiB
C++

#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();
}
}