ref: 094b3e1d61c9c7cd85c3dfba8a6b40185004eed3
parent: a100cd99db8f71ec9d1caeb4d16b65f1f7d0a693
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed Jul 24 13:16:47 EDT 2024
initial bitmap fonts support
--- a/otf.c.in
+++ b/otf.c.in
@@ -236,6 +236,34 @@
return -1;
}
+void
+print_BitmapGlyph(Otfile *f, int indent, Otf *o, BitmapGlyph *v)
+{
+ void *a = f->aux;
+ int i;
+
+ USED(o);
+ if(v->bitDepth > 0)
+ f->print(a, "%*s%s: %d\n", indent, "", "bitDepth", v->bitDepth);
+ f->print(a, "%*s%s: %d\n", indent, "", "format", v->format);
+ f->print(a, "%*s%s: %d\n", indent, "", "offset", v->offset);
+ if(v->size > 0){
+ f->print(a, "%*s%s: %d\n", indent, "", "size", v->size);
+ f->print(a, "%*s%s: ", indent, "", "image");
+ for(i = 0; i < v->size; i++)
+ f->print(a, "%02"PRIx8, v->image[i]);
+ f->print(a, "\n");
+ }
+ if(v->numComponents > 0){
+ f->print(a, "%*s%s: %d\n", indent, "", "numComponents");
+ f->print(a, "%*s%s:\n", indent, "", "components");
+ for(i = 0; i < v->numComponents; i++){
+ f->print(a, "%*s%d:\n", indent+indentΔ, "", i);
+ print_EbdtComponent(f, indent+indentΔ+indentΔ, o, v->components+i);
+ }
+ }
+}
+
enum {
CGLYPH_FL_WORD_ARGS = 1<<0,
CGLYPH_FL_SCALE = 1<<3,
@@ -519,16 +547,198 @@
}
}
+static Glyf *
+bitebdt(Otf *o, Glyf *g, BitmapGlyph *bg)
+{
+ u8int *b;
+ int i;
+
+ if(o->ebdt == nil){
+ for(i = 0; i < o->td.numTables; i++){
+ TableRecord *rec = o->td.tableRecords+i;
+ if(rec->tableTag == (u32int)('E'<<24|'B'<<16|'D'<<8|'T')){
+ o->ebdt = rec;
+ break;
+ }
+ }
+ if(o->ebdt == nil){
+ werrstr("no EBDT table");
+ goto err;
+ }
+ }
+
+ if(otfpushrange(o, o->ebdt->offset, o->ebdt->length) < 0)
+ goto err;
+ if(otfpushrange(o, bg->offset, bg->size) < 0)
+ goto err;
+ if(bg->format == 1 || bg->format == 2 || bg->format == 8){
+ SmallGlyphMetrics sm;
+ if(read_SmallGlyphMetrics(o, &sm) < 0)
+ goto err;
+ g->xMin = sm.bearingX;
+ g->yMin = sm.bearingY - sm.height;
+ g->xMax = sm.bearingX + sm.width;
+ g->yMax = sm.bearingY;
+ bg->size -= 6;
+ }else if(bg->format == 6 || bg->format == 7 || bg->format == 9){
+ BigGlyphMetrics bm;
+ if(read_BigGlyphMetrics(o, &bm) < 0)
+ goto err;
+ /* FIXME only horizontal metrics, also this is probably wrong */
+ g->xMax = bm.width;
+ g->yMax = bm.height;
+ g->xMin = -(int)bm.horiBearingX;
+ g->yMin = -(int)bm.horiBearingY;
+ g->xMax += g->xMin;
+ g->yMax += g->yMin;
+ bg->size -= 8;
+ }
+
+ bg->numComponents = 0;
+ switch(bg->format){
+ case 8:
+ if(otfreadn(o, 1) == nil) /* skip uint8 pad */
+ goto err;
+ bg->size -= 1;
+ /* fallthrough */
+ case 9:
+ if((b = otfreadn(o, 2)) == nil)
+ goto err;
+ bg->numComponents = b[0]<<8 | b[1];
+ bg->size -= 2;
+ if(otfarray(o, &bg->components, read_EbdtComponent, sizeof(EbdtComponent), bg->numComponents) < 0)
+ goto err;
+ bg->size -= 4*bg->numComponents;
+ /* fallthrough */
+ case 1:
+ case 2:
+ case 5:
+ case 6:
+ case 7:
+ if((b = otfreadn(o, bg->size)) == nil)
+ goto err;
+ g->bitmap = malloc(sizeof(*bg) + bg->size);
+ memcpy(g->bitmap, bg, sizeof(*bg));
+ memcpy(g->bitmap->image, b, bg->size);
+ }
+ otfpoprange(o);
+ otfpoprange(o);
+
+ return g;
+err:
+ free(g->bitmap);
+ free(g);
+ otfpopranges(o);
+ return nil;
+}
+
+static Glyf *
+bitglyf(Otf *o, Glyf *g)
+{
+ IndexSubtableRecord *isr;
+ IndexSubtable *is;
+ BitmapSize *bs;
+ int i, j, k, n;
+ BitmapGlyph b;
+
+ g->type = GLYPH_BITMAP;
+ bs = o->td.eblc->bitmapSizes;
+ for(i = 0; i < (int)o->td.eblc->numSizes; i++, bs++){
+ if(g->index >= bs->startGlyphIndex && g->index <= bs->endGlyphIndex){
+ b.bitDepth = bs->bitDepth;
+ isr = bs->indexSubtableList;
+ for(j = 0; j < (int)bs->numberOfIndexSubtables; j++){
+ if(g->index >= isr->firstGlyphIndex && g->index <= isr->lastGlyphIndex){
+ is = isr->indexSubtable;
+ if(is == nil)
+ break;
+ b.format = is->imageFormat;
+ b.offset = is->imageDataOffset;
+ n = g->index - isr->firstGlyphIndex;
+ switch(is->indexFormat){
+ case 1:
+ b.offset += is->sub1.sbitOffsets[n];
+ b.size = is->sub1.sbitOffsets[n+1] - is->sub1.sbitOffsets[n];
+ break;
+ case 2:
+ b.offset += n*is->sub2.imageSize;
+ b.size = is->sub2.imageSize;
+ /* FIXME - vertical metrics are not used here, also this is probably wrong */
+ g->xMin = -is->sub2.bigMetrics.horiBearingX;
+ g->yMin = is->sub2.bigMetrics.horiBearingY - is->sub2.bigMetrics.height;
+ g->xMax = is->sub2.bigMetrics.width + g->xMin;
+ g->yMax = is->sub2.bigMetrics.height + g->yMin;
+ break;
+ case 3:
+ b.offset += is->sub3.sbitOffsets[n];
+ b.size = is->sub3.sbitOffsets[n+1] - is->sub3.sbitOffsets[n];
+ break;
+ case 4:
+ n = is->sub4.numGlyphs;
+ for(k = 0; k < n; k++){
+ if(is->sub4.glyphArray[k].glyphID == g->index)
+ break;
+ }
+ if(k >= n){
+ werrstr("not in glyph array");
+ goto err;
+ }
+ b.offset += is->sub4.glyphArray[k].sbitOffset;
+ b.size = is->sub4.glyphArray[k+1].sbitOffset - is->sub4.glyphArray[k].sbitOffset;
+ break;
+ case 5:
+ n = is->sub5.numGlyphs;
+ for(k = 0; k < n; k++){
+ if(is->sub5.glyphIdArray[k] == g->index)
+ break;
+ }
+ if(k >= n){
+ werrstr("not in glyph id array");
+ goto err;
+ }
+ b.offset += k*is->sub5.imageSize;
+ b.size = is->sub5.imageSize;
+ /* FIXME - vertical metrics are not used here, also this is probably wrong */
+ g->xMin = -is->sub5.bigMetrics.horiBearingX;
+ g->yMin = is->sub5.bigMetrics.horiBearingY - is->sub5.bigMetrics.height;
+ g->xMax = is->sub5.bigMetrics.width + g->xMin;
+ g->yMax = is->sub5.bigMetrics.height + g->yMin;
+ break;
+ default:
+ werrstr("unsupported index format: %d", is->indexFormat);
+ goto err;
+ }
+
+ return bitebdt(o, g, &b);
+ }
+ }
+ }
+ }
+
+ werrstr("no bitmap");
+err:
+ free(g);
+ return nil;
+}
+
Glyf *
otfglyf(Otf *o, int index)
{
- Glyf *g;
int off, len, i;
+ Glyf *g;
if((g = calloc(1, sizeof(*g))) == nil){
werrstr("no memory");
goto err;
}
+ if(index < 0 || index >= o->numGlyphs){
+ werrstr("index out of range");
+ goto err;
+ }
+ g->index = index;
+ if(o->td.eblc != nil && o->td.ebdt != nil)
+ return bitglyf(o, g);
+
if(o->td.head == nil){
werrstr("no head table");
goto err;
@@ -537,23 +747,19 @@
werrstr("no loca table");
goto err;
}
- if(o->glyf.offset == 0){
+ if(o->glyf == nil){
for(i = 0; i < o->td.numTables; i++){
TableRecord *rec = o->td.tableRecords+i;
if(rec->tableTag == (u32int)('g'<<24|'l'<<16|'y'<<8|'f')){
- o->glyf = *rec;
+ o->glyf = rec;
break;
}
}
- if(o->glyf.offset == 0){
+ if(o->glyf == nil){
werrstr("no glyf table");
goto err;
}
}
- if(index < 0 || index >= o->numGlyphs){
- werrstr("index out of range");
- goto err;
- }
if(o->indexToLocFormat == 0){
off = (int)o->td.loca->shortOffsets[index]*2;
len = (int)o->td.loca->shortOffsets[index+1]*2 - off;
@@ -564,7 +770,7 @@
if(len < 1) /* no outlines */
return g;
- if(otfpushrange(o, o->glyf.offset, o->glyf.length) < 0)
+ if(otfpushrange(o, o->glyf->offset, o->glyf->length) < 0)
goto err;
if(otfpushrange(o, off, len) < 0)
goto err;
@@ -574,6 +780,7 @@
}
otfpoprange(o);
otfpoprange(o);
+ g->type = g->numberOfContours < 0 ? GLYPH_COMPONENT : GLYPH_SIMPLE;
return g;
err:
--- a/otf.h.in
+++ b/otf.h.in
@@ -36,6 +36,26 @@
#define NoRune (~(Rune)0)
+enum {
+ GLYPH_EMPTY,
+ GLYPH_SIMPLE,
+ GLYPH_COMPONENT,
+ GLYPH_BITMAP,
+};
+
+typedef struct BitmapGlyph BitmapGlyph;
+typedef struct EbdtComponent EbdtComponent;
+
+struct BitmapGlyph {
+ int bitDepth;
+ int format;
+ int offset;
+ int size;
+ int numComponents;
+ EbdtComponent *components;
+ u8int image[];
+};
+
typedef struct ComponentGlyph ComponentGlyph;
enum {
--- a/otf.rkt
+++ b/otf.rkt
@@ -201,6 +201,11 @@
{uint16 numberOfHMetrics ->o}
#:tag "hhea")
+(mkcmplx EbdtComponent
+ {uint16 glyphID}
+ {int8 xOffset}
+ {int8 yOffset})
+
(mkcmplx
Glyf
{int16 numberOfContours ->o}
@@ -209,17 +214,32 @@
{int16 xMax}
{int16 yMax}
#:extra
- (list (cons 'field (list (~a "ComponentGlyph *component;") (~a "SimpleGlyph *simple;")))
+ (list (cons 'field (list (~a "int index;")
+ (~a "int type;")
+ (~a "union {");
+ (~a " ComponentGlyph *component;")
+ (~a " SimpleGlyph *simple;")
+ (~a " BitmapGlyph *bitmap;")
+ (~a "};")))
(cons 'read
- (list (~a "if(v->numberOfContours < 0 && read_ComponentGlyph(o, &v->component, 0) < 0)")
- (~a " goto err;")
- (~a "if(v->numberOfContours > 0 && read_SimpleGlyph(o, &v->simple) < 0)")
- (~a " goto err;")))
- (cons 'print
- (list (~a "if(v->component != nil){")
+ (list (~a "if(v->numberOfContours < 0){")
+ (~a " if(read_ComponentGlyph(o, &v->component, 0) < 0)")
+ (~a " goto err;")
+ (~a " v->type = GLYPH_COMPONENT;")
+ (~a "}else if(v->numberOfContours > 0){")
+ (~a " if(read_SimpleGlyph(o, &v->simple) < 0)")
+ (~a " goto err;")
+ (~a " v->type = GLYPH_SIMPLE;")
+ (~a "}else if(o->td.eblc != nil && o->td.ebdt != nil)")
+ (~a " v->type = GLYPH_BITMAP;")))
+ (cons 'print
+ (list (~a "if(v->type == GLYPH_BITMAP){")
+ (~a " f->print(f->aux, \"%*s%s:\\n\", indent, \"\", \"bitmap\");")
+ (~a " print_BitmapGlyph(f, indent+indentΔ, o, v->bitmap);")
+ (~a "}else if(v->type == GLYPH_COMPONENT){")
(~a " f->print(f->aux, \"%*s%s:\\n\", indent, \"\", \"component\");")
(~a " print_ComponentGlyph(f, indent+indentΔ, o, v->component);")
- (~a "}else if(v->simple != nil){")
+ (~a "}else if(v->type == GLYPH_SIMPLE){")
(~a " f->print(f->aux, \"%*s%s:\\n\", indent, \"\", \"simple\");")
(~a " print_SimpleGlyph(f, indent+indentΔ, o, v->simple);")
(~a "}")))))
@@ -347,7 +367,7 @@
{uint16 endGlyphIndex}
{uint8 ppemX}
{uint8 ppemY}
- {uint8 bitDepth}
+ {uint8 bitDepth (== 1 2 4 8)}
{int8 flags hex (bits bitmapSizeFlags)}
{IndexSubtableRecord indexSubtableList [numberOfIndexSubtables] (at indexSubtableListOffset)})
--- a/otfpriv.h.in
+++ b/otfpriv.h.in
@@ -9,7 +9,8 @@
/* extra fields to simplify parsing */
TableDirectory td;
- TableRecord glyf;
+ TableRecord *glyf;
+ TableRecord *ebdt;
OTF_EXTRA_FIELDS
};
--- a/plan9/otf.c
+++ b/plan9/otf.c
@@ -237,6 +237,34 @@
return -1;
}
+void
+print_BitmapGlyph(Otfile *f, int indent, Otf *o, BitmapGlyph *v)
+{
+ void *a = f->aux;
+ int i;
+
+ USED(o);
+ if(v->bitDepth > 0)
+ f->print(a, "%*s%s: %d\n", indent, "", "bitDepth", v->bitDepth);
+ f->print(a, "%*s%s: %d\n", indent, "", "format", v->format);
+ f->print(a, "%*s%s: %d\n", indent, "", "offset", v->offset);
+ if(v->size > 0){
+ f->print(a, "%*s%s: %d\n", indent, "", "size", v->size);
+ f->print(a, "%*s%s: ", indent, "", "image");
+ for(i = 0; i < v->size; i++)
+ f->print(a, "%02"PRIx8, v->image[i]);
+ f->print(a, "\n");
+ }
+ if(v->numComponents > 0){
+ f->print(a, "%*s%s: %d\n", indent, "", "numComponents");
+ f->print(a, "%*s%s:\n", indent, "", "components");
+ for(i = 0; i < v->numComponents; i++){
+ f->print(a, "%*s%d:\n", indent+indentΔ, "", i);
+ print_EbdtComponent(f, indent+indentΔ+indentΔ, o, v->components+i);
+ }
+ }
+}
+
enum {
CGLYPH_FL_WORD_ARGS = 1<<0,
CGLYPH_FL_SCALE = 1<<3,
@@ -520,16 +548,198 @@
}
}
+static Glyf *
+bitebdt(Otf *o, Glyf *g, BitmapGlyph *bg)
+{
+ u8int *b;
+ int i;
+
+ if(o->ebdt == nil){
+ for(i = 0; i < o->td.numTables; i++){
+ TableRecord *rec = o->td.tableRecords+i;
+ if(rec->tableTag == (u32int)('E'<<24|'B'<<16|'D'<<8|'T')){
+ o->ebdt = rec;
+ break;
+ }
+ }
+ if(o->ebdt == nil){
+ werrstr("no EBDT table");
+ goto err;
+ }
+ }
+
+ if(otfpushrange(o, o->ebdt->offset, o->ebdt->length) < 0)
+ goto err;
+ if(otfpushrange(o, bg->offset, bg->size) < 0)
+ goto err;
+ if(bg->format == 1 || bg->format == 2 || bg->format == 8){
+ SmallGlyphMetrics sm;
+ if(read_SmallGlyphMetrics(o, &sm) < 0)
+ goto err;
+ g->xMin = sm.bearingX;
+ g->yMin = sm.bearingY - sm.height;
+ g->xMax = sm.bearingX + sm.width;
+ g->yMax = sm.bearingY;
+ bg->size -= 6;
+ }else if(bg->format == 6 || bg->format == 7 || bg->format == 9){
+ BigGlyphMetrics bm;
+ if(read_BigGlyphMetrics(o, &bm) < 0)
+ goto err;
+ /* FIXME only horizontal metrics, also this is probably wrong */
+ g->xMax = bm.width;
+ g->yMax = bm.height;
+ g->xMin = -(int)bm.horiBearingX;
+ g->yMin = -(int)bm.horiBearingY;
+ g->xMax += g->xMin;
+ g->yMax += g->yMin;
+ bg->size -= 8;
+ }
+
+ bg->numComponents = 0;
+ switch(bg->format){
+ case 8:
+ if(otfreadn(o, 1) == nil) /* skip uint8 pad */
+ goto err;
+ bg->size -= 1;
+ /* fallthrough */
+ case 9:
+ if((b = otfreadn(o, 2)) == nil)
+ goto err;
+ bg->numComponents = b[0]<<8 | b[1];
+ bg->size -= 2;
+ if(otfarray(o, &bg->components, read_EbdtComponent, sizeof(EbdtComponent), bg->numComponents) < 0)
+ goto err;
+ bg->size -= 4*bg->numComponents;
+ /* fallthrough */
+ case 1:
+ case 2:
+ case 5:
+ case 6:
+ case 7:
+ if((b = otfreadn(o, bg->size)) == nil)
+ goto err;
+ g->bitmap = malloc(sizeof(*bg) + bg->size);
+ memcpy(g->bitmap, bg, sizeof(*bg));
+ memcpy(g->bitmap->image, b, bg->size);
+ }
+ otfpoprange(o);
+ otfpoprange(o);
+
+ return g;
+err:
+ free(g->bitmap);
+ free(g);
+ otfpopranges(o);
+ return nil;
+}
+
+static Glyf *
+bitglyf(Otf *o, Glyf *g)
+{
+ IndexSubtableRecord *isr;
+ IndexSubtable *is;
+ BitmapSize *bs;
+ int i, j, k, n;
+ BitmapGlyph b;
+
+ g->type = GLYPH_BITMAP;
+ bs = o->td.eblc->bitmapSizes;
+ for(i = 0; i < (int)o->td.eblc->numSizes; i++, bs++){
+ if(g->index >= bs->startGlyphIndex && g->index <= bs->endGlyphIndex){
+ b.bitDepth = bs->bitDepth;
+ isr = bs->indexSubtableList;
+ for(j = 0; j < (int)bs->numberOfIndexSubtables; j++){
+ if(g->index >= isr->firstGlyphIndex && g->index <= isr->lastGlyphIndex){
+ is = isr->indexSubtable;
+ if(is == nil)
+ break;
+ b.format = is->imageFormat;
+ b.offset = is->imageDataOffset;
+ n = g->index - isr->firstGlyphIndex;
+ switch(is->indexFormat){
+ case 1:
+ b.offset += is->sub1.sbitOffsets[n];
+ b.size = is->sub1.sbitOffsets[n+1] - is->sub1.sbitOffsets[n];
+ break;
+ case 2:
+ b.offset += n*is->sub2.imageSize;
+ b.size = is->sub2.imageSize;
+ /* FIXME - vertical metrics are not used here, also this is probably wrong */
+ g->xMin = -is->sub2.bigMetrics.horiBearingX;
+ g->yMin = is->sub2.bigMetrics.horiBearingY - is->sub2.bigMetrics.height;
+ g->xMax = is->sub2.bigMetrics.width + g->xMin;
+ g->yMax = is->sub2.bigMetrics.height + g->yMin;
+ break;
+ case 3:
+ b.offset += is->sub3.sbitOffsets[n];
+ b.size = is->sub3.sbitOffsets[n+1] - is->sub3.sbitOffsets[n];
+ break;
+ case 4:
+ n = is->sub4.numGlyphs;
+ for(k = 0; k < n; k++){
+ if(is->sub4.glyphArray[k].glyphID == g->index)
+ break;
+ }
+ if(k >= n){
+ werrstr("not in glyph array");
+ goto err;
+ }
+ b.offset += is->sub4.glyphArray[k].sbitOffset;
+ b.size = is->sub4.glyphArray[k+1].sbitOffset - is->sub4.glyphArray[k].sbitOffset;
+ break;
+ case 5:
+ n = is->sub5.numGlyphs;
+ for(k = 0; k < n; k++){
+ if(is->sub5.glyphIdArray[k] == g->index)
+ break;
+ }
+ if(k >= n){
+ werrstr("not in glyph id array");
+ goto err;
+ }
+ b.offset += k*is->sub5.imageSize;
+ b.size = is->sub5.imageSize;
+ /* FIXME - vertical metrics are not used here, also this is probably wrong */
+ g->xMin = -is->sub5.bigMetrics.horiBearingX;
+ g->yMin = is->sub5.bigMetrics.horiBearingY - is->sub5.bigMetrics.height;
+ g->xMax = is->sub5.bigMetrics.width + g->xMin;
+ g->yMax = is->sub5.bigMetrics.height + g->yMin;
+ break;
+ default:
+ werrstr("unsupported index format: %d", is->indexFormat);
+ goto err;
+ }
+
+ return bitebdt(o, g, &b);
+ }
+ }
+ }
+ }
+
+ werrstr("no bitmap");
+err:
+ free(g);
+ return nil;
+}
+
Glyf *
otfglyf(Otf *o, int index)
{
- Glyf *g;
int off, len, i;
+ Glyf *g;
if((g = calloc(1, sizeof(*g))) == nil){
werrstr("no memory");
goto err;
}
+ if(index < 0 || index >= o->numGlyphs){
+ werrstr("index out of range");
+ goto err;
+ }
+ g->index = index;
+ if(o->td.eblc != nil && o->td.ebdt != nil)
+ return bitglyf(o, g);
+
if(o->td.head == nil){
werrstr("no head table");
goto err;
@@ -538,23 +748,19 @@
werrstr("no loca table");
goto err;
}
- if(o->glyf.offset == 0){
+ if(o->glyf == nil){
for(i = 0; i < o->td.numTables; i++){
TableRecord *rec = o->td.tableRecords+i;
if(rec->tableTag == (u32int)('g'<<24|'l'<<16|'y'<<8|'f')){
- o->glyf = *rec;
+ o->glyf = rec;
break;
}
}
- if(o->glyf.offset == 0){
+ if(o->glyf == nil){
werrstr("no glyf table");
goto err;
}
}
- if(index < 0 || index >= o->numGlyphs){
- werrstr("index out of range");
- goto err;
- }
if(o->indexToLocFormat == 0){
off = (int)o->td.loca->shortOffsets[index]*2;
len = (int)o->td.loca->shortOffsets[index+1]*2 - off;
@@ -565,7 +771,7 @@
if(len < 1) /* no outlines */
return g;
- if(otfpushrange(o, o->glyf.offset, o->glyf.length) < 0)
+ if(otfpushrange(o, o->glyf->offset, o->glyf->length) < 0)
goto err;
if(otfpushrange(o, off, len) < 0)
goto err;
@@ -575,6 +781,7 @@
}
otfpoprange(o);
otfpoprange(o);
+ g->type = g->numberOfContours < 0 ? GLYPH_COMPONENT : GLYPH_SIMPLE;
return g;
err:
@@ -1814,6 +2021,30 @@
}
int
+read_EbdtComponent(Otf *o, EbdtComponent *v)
+{
+ u8int *b = nil; USED(b);
+ if((b = otfreadn(o, 4)) == nil)
+ goto err;
+ v->glyphID = b[0]<<8 | b[1];
+ v->xOffset = b[2];
+ v->yOffset = b[3];
+ return 0;
+err:
+ werrstr("%s: %r", "EbdtComponent");
+ return -1;
+}
+
+void
+print_EbdtComponent(Otfile *f, int indent, Otf *o, EbdtComponent *v)
+{
+ f->print(f->aux, "%*s%s: %ud\n", indent, "", "glyphID", v->glyphID);
+ f->print(f->aux, "%*s%s: %d\n", indent, "", "xOffset", v->xOffset);
+ f->print(f->aux, "%*s%s: %d\n", indent, "", "yOffset", v->yOffset);
+ USED(o);
+}
+
+int
read_Glyf(Otf *o, Glyf *v)
{
u8int *b = nil; USED(b);
@@ -1825,10 +2056,16 @@
v->yMin = b[4]<<8 | b[5];
v->xMax = b[6]<<8 | b[7];
v->yMax = b[8]<<8 | b[9];
- if(v->numberOfContours < 0 && read_ComponentGlyph(o, &v->component, 0) < 0)
- goto err;
- if(v->numberOfContours > 0 && read_SimpleGlyph(o, &v->simple) < 0)
- goto err;
+ if(v->numberOfContours < 0){
+ if(read_ComponentGlyph(o, &v->component, 0) < 0)
+ goto err;
+ v->type = GLYPH_COMPONENT;
+ }else if(v->numberOfContours > 0){
+ if(read_SimpleGlyph(o, &v->simple) < 0)
+ goto err;
+ v->type = GLYPH_SIMPLE;
+ }else if(o->td.eblc != nil && o->td.ebdt != nil)
+ v->type = GLYPH_BITMAP;
return 0;
err:
werrstr("%s: %r", "Glyf");
@@ -1843,10 +2080,13 @@
f->print(f->aux, "%*s%s: %d\n", indent, "", "yMin", v->yMin);
f->print(f->aux, "%*s%s: %d\n", indent, "", "xMax", v->xMax);
f->print(f->aux, "%*s%s: %d\n", indent, "", "yMax", v->yMax);
- if(v->component != nil){
+ if(v->type == GLYPH_BITMAP){
+ f->print(f->aux, "%*s%s:\n", indent, "", "bitmap");
+ print_BitmapGlyph(f, indent+indentΔ, o, v->bitmap);
+ }else if(v->type == GLYPH_COMPONENT){
f->print(f->aux, "%*s%s:\n", indent, "", "component");
print_ComponentGlyph(f, indent+indentΔ, o, v->component);
- }else if(v->simple != nil){
+ }else if(v->type == GLYPH_SIMPLE){
f->print(f->aux, "%*s%s:\n", indent, "", "simple");
print_SimpleGlyph(f, indent+indentΔ, o, v->simple);
}
@@ -2495,6 +2735,10 @@
v->ppemX = b[4];
v->ppemY = b[5];
v->bitDepth = b[6];
+ if(v->bitDepth != 1 && v->bitDepth != 2 && v->bitDepth != 4 && v->bitDepth != 8){
+ werrstr("%s: invalid value: %d (%#ux)", "bitDepth", v->bitDepth, v->bitDepth);
+ goto err;
+ }
v->flags = b[7];
if(v->indexSubtableListOffset != 0){
if(otfpushrange(o, v->indexSubtableListOffset, -1) < 0)
--- a/plan9/otf.h
+++ b/plan9/otf.h
@@ -37,6 +37,26 @@
#define NoRune (~(Rune)0)
+enum {
+ GLYPH_EMPTY,
+ GLYPH_SIMPLE,
+ GLYPH_COMPONENT,
+ GLYPH_BITMAP,
+};
+
+typedef struct BitmapGlyph BitmapGlyph;
+typedef struct EbdtComponent EbdtComponent;
+
+struct BitmapGlyph {
+ int bitDepth;
+ int format;
+ int offset;
+ int size;
+ int numComponents;
+ EbdtComponent *components;
+ u8int image[];
+};
+
typedef struct ComponentGlyph ComponentGlyph;
enum {
@@ -132,6 +152,7 @@
typedef struct TableCmap TableCmap;
typedef struct TableHead TableHead;
typedef struct TableHhea TableHhea;
+typedef struct EbdtComponent EbdtComponent;
typedef struct Glyf Glyf;
typedef struct LongHorMetric LongHorMetric;
typedef struct TableMaxp TableMaxp;
@@ -476,6 +497,15 @@
int read_TableHhea(Otf *o, TableHhea *v);
void print_TableHhea(Otfile *f, int indent, Otf *o, TableHhea *v);
+struct EbdtComponent {
+ u16int glyphID;
+ s8int xOffset;
+ s8int yOffset;
+};
+
+int read_EbdtComponent(Otf *o, EbdtComponent *v);
+void print_EbdtComponent(Otfile *f, int indent, Otf *o, EbdtComponent *v);
+
struct Glyf {
s16int numberOfContours;
s16int xMin;
@@ -482,8 +512,13 @@
s16int yMin;
s16int xMax;
s16int yMax;
- ComponentGlyph *component;
- SimpleGlyph *simple;
+ int index;
+ int type;
+ union {
+ ComponentGlyph *component;
+ SimpleGlyph *simple;
+ BitmapGlyph *bitmap;
+ };
};
int read_Glyf(Otf *o, Glyf *v);
--- a/plan9/otfpriv.h
+++ b/plan9/otfpriv.h
@@ -10,7 +10,8 @@
/* extra fields to simplify parsing */
TableDirectory td;
- TableRecord glyf;
+ TableRecord *glyf;
+ TableRecord *ebdt;
s16int indexToLocFormat;
u16int numberOfHMetrics;
s16int numberOfContours;
@@ -26,7 +27,7 @@
u16int designAxisSize;
u16int designAxisCount;
u16int axisValueCount;
-#line 14"otfpriv.h.in"
+#line 15"otfpriv.h.in"
};
struct Range {
--- a/rast.c
+++ b/rast.c
@@ -547,11 +547,11 @@
return npts < 2 ? 0 : npts;
}
-GlyfImage *
-otfdrawglyf(Otf *o, Glyf *g, double ppem, double scaleX, double scaleY)
+static GlyfImage *
+outlineglyf(Otf *o, Glyf *g, double ppem, double scaleX, double scaleY)
{
int i, j, maxptstotal, maxpts, ngs, w, h, npx, baseline;
- Glyf *gs[MAXCOMPONENTS];
+ Glyf *gs[MAXCOMPONENTS] = {nil};
ComponentGlyph *cg;
SegQ *s₀, *s, *p;
GlyfImage *im;
@@ -679,4 +679,69 @@
}
free(pts);
return im;
+}
+
+GlyfImage *
+bitmapglyf(Otf *o, Glyf *g, double ppem, double scaleX, double scaleY)
+{
+ int zoomX, zoomY, w, h, x, y, i;
+ BitmapGlyph *bg;
+ GlyfImage *im;
+ u8int *b, *p;
+
+ USED(o);
+ bg = g->bitmap;
+ if(bg->numComponents > 0){
+ /* FIXME implement this. components may also be outlines */
+ werrstr("components not implemented");
+ return nil;
+ }
+
+ if((zoomX = scaleX * ppem / 72) < 1)
+ zoomX = 1;
+ if((zoomY = scaleY * ppem / 72) < 1)
+ zoomY = 1;
+
+ w = g->xMax - g->xMin;
+ h = g->yMax - g->yMin;
+ im = calloc(1, sizeof(*im) + w*zoomX*h*zoomY);
+ im->w = w*zoomX;
+ im->h = h*zoomY;
+ im->baseline = g->yMin * zoomY;
+ b = im->b;
+ if(bg->bitDepth == 1){
+ for(y = 0; y < h; y++){
+ p = b;
+ for(x = w-1; x >= 0; x--){
+ *b++ = (bg->image[(y*w+x)/8] & (1<<(x&7))) ? 0 : 255;
+ for(i = 1; i < zoomX; i++, b++)
+ *b = b[-1];
+ }
+ for(i = 1; i < zoomY; i++, b += im->w)
+ memcpy(b, p, im->w);
+ }
+ }else if(bg->bitDepth == 4){
+ /* FIXME */
+ werrstr("bitDepth 4 not implemented");
+ free(im);
+ im = nil;
+ }else if(bg->bitDepth == 8){
+ /* FIXME */
+ werrstr("bitDepth 8 not implemented");
+ free(im);
+ im = nil;
+ }
+
+ return im;
+}
+
+GlyfImage *
+otfdrawglyf(Otf *o, Glyf *g, double ppem, double scaleX, double scaleY)
+{
+ if(g->type == GLYPH_SIMPLE || g->type == GLYPH_COMPONENT)
+ return outlineglyf(o, g, ppem, scaleX, scaleY);
+ if(g->type == GLYPH_BITMAP)
+ return bitmapglyf(o, g, ppem, scaleX, scaleY);
+ werrstr("empty glyph");
+ return nil;
}
--- a/test.h
+++ b/test.h
@@ -19,6 +19,12 @@
static int gind = -1, map, highlight = -1, runesonly;
static double ppem, scaleX = 1, scaleY = 1;
static Rune rune = NoRune;
+static char *gtypes[] = {
+ [GLYPH_EMPTY] = "empty",
+ [GLYPH_BITMAP] = "bitmap",
+ [GLYPH_SIMPLE] = "simple",
+ [GLYPH_COMPONENT] = "component",
+};
static int
dumpmap(Otfile *f, GlyfImage **im, int n)
@@ -151,12 +157,11 @@
werrstr("glyph %d: %r", gind);
return -1;
}
- if(ppem > 0 && g->numberOfContours != 0){
+ if(ppem > 0 && g->type != GLYPH_EMPTY){
if((im[i] = otfdrawglyf(o, g, ppem, scaleX, scaleY)) == nil)
goto glypherr;
}else if(ppem <= 0){
- out->print(out->aux, "%d (%s):\n", i,
- g->simple ? "simple" : (g->component ? "component" : "empty"));
+ out->print(out->aux, "%d (%s):\n", i, gtypes[g->type]);
print_Glyf(out, indentΔ, o, g);
}
free(g);