ref: f711b4426695620ce7646d3036f69275be73e59f
dir: /otf.c.in/
/* this file is generated. do not modify. */ #include "otfsys.h" #include "otf.h" #include "otfpriv.h" #define f2dot14(o) (f = b[2*o]<<8 | b[2*o+1], (f>>14)+(f&((1<<14)-1))/16384.0) int indentΔ = 2; #define rchr(s) (be ? ((s)[0]<<8 | (s)[1]) : ((s)[1]<<8 | (s)[0])) static u8int mark[] = {0x00, 0x00, 0xc0, 0xe0, 0xf0}; static int utf16to8(u8int *o, int osz, u8int *s, int sz) { u32int c, c2; int i, wr, j, be; i = 0; be = 1; if(s[0] == 0xfe && s[1] == 0xff) i += 2; else if(s[0] == 0xff && s[1] == 0xfe){ be = 0; i += 2; } for(; i < sz-1 && osz > 1;){ c = rchr(&s[i]); i += 2; if(c >= 0xd800 && c <= 0xdbff && i < sz-1){ c2 = rchr(&s[i]); if(c2 >= 0xdc00 && c2 <= 0xdfff){ c = 0x10000 | (c - 0xd800)<<10 | (c2 - 0xdc00); i += 2; }else return -1; }else if(c >= 0xdc00 && c <= 0xdfff) return -1; if(c < 0x80) wr = 1; else if(c < 0x800) wr = 2; else if(c < 0x10000) wr = 3; else wr = 4; osz -= wr; if(osz < 1) break; o += wr; for(j = wr; j > 1; j--){ *(--o) = (c & 0xbf) | 0x80; c >>= 6; } *(--o) = (u8int)c | mark[wr]; o += wr; } *o = 0; return i; } static char * strtoutf8(Otf *o, u8int *in, int sz) { char *s; // FIXME this is not sufficient, obviously - need more platform/encoding handling if(o->platformID == 0 || (o->platformID == 3 && o->encodingID == 1)){ s = malloc(sz/2+1); utf16to8((u8int*)s, sz/2+1, in, sz); }else{ s = malloc(sz+1); memcpy(s, in, sz); s[sz] = 0; } return s; } Otf * otfopen(Otfile *f) { Otf *o; if((o = calloc(1, sizeof(*o))) == nil){ werrstr("no memory"); }else{ o->f = f; if(read_TableDirectory(o, &o->td) != 0){ free(o); o = nil; } } return o; } void otfprint(Otf *o, Otfile *out, int indent) { print_TableDirectory(out, indent, o, &o->td); } void otfclose(Otf *o) { if(o == nil) return; // FIXME traverse and free everything free(o); } static int otfpushrange(Otf *o, int off, int len) { Range *r; int x; r = nil; if(o->r != nil){ if(len < 0) len = o->r->len - off; if(len < 0 || off+len > o->r->len){ werrstr("range overflow (len %d) by %d bytes", len, off+len - o->r->len); goto err; } off += o->r->start; }else if(len < 0){ len = 0x7fffffff; } if((r = malloc(sizeof(*r))) == nil){ werrstr("no memory"); goto err; } r->par = o->r; r->start = off; r->len = len; r->prevoff = o->off; if((x = o->f->seek(o->f->aux, off, 0)) != off){ werrstr("seek offset: need %d, got %d", off, x); goto err; } o->off = off; o->r = r; return 0; err: free(r); return -1; } static int otfpoprange(Otf *o) { Range *r; int x; r = o->r; if(r == nil){ werrstr("pop without push"); goto err; } if((x = o->f->seek(o->f->aux, r->prevoff, 0)) != r->prevoff){ werrstr("seek offset: need %d, got %d", r->prevoff, x); goto err; } o->off = r->prevoff; o->r = r->par; free(r); return 0; err: return -1; } static void otfpopranges(Otf *o) { while(o->r != nil) otfpoprange(o); } static u8int * otfreadn(Otf *o, int n) { Range *r; u8int *b; int x; r = o->r; if(r != nil && o->off+n > r->start+r->len){ werrstr("need %d at %d, have %d at %d", n, o->off, r->len, r->start); goto err; } if(n > o->bufsz){ if((b = realloc(o->buf, n)) == nil){ werrstr("no memory"); goto err; } o->buf = b; o->bufsz = n; } if((x = o->f->read(o->f->aux, o->buf, n)) != n){ werrstr("need %d, got %d; off %d", n, x, o->off); goto err; } o->off += n; return o->buf; err: return nil; } static int otfarray(Otf *o, void **arr_, void *fun_, int elsz, int num) { int i; int (*fun)(Otf*, void*); u8int *arr; if((arr = calloc(num, elsz)) == nil){ werrstr("no memory"); goto err; } fun = fun_; for(i = 0; i < num; i++){ if(fun(o, arr + i*elsz) < 0) goto err; } *arr_ = arr; return 0; err: free(arr); 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, "", "pitchBits", v->pitchBits); 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"); } f->print(a, "%*s%s: %d\n", indent, "", "ppemX", v->ppemX); f->print(a, "%*s%s: %d\n", indent, "", "ppemY", v->ppemY); if(v->numComponents > 0){ f->print(a, "%*s%s: %d\n", indent, "", "numComponents", v->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, CGLYPH_FL_OVERLAP_COMPOUND = 1<<10, CGLYPH_FL_UNSCALED_COMPONENT_OFFSET = 1<<12, }; static int read_ComponentGlyph(Otf *o, ComponentGlyph **out, int instr) { ComponentGlyph *v; u8int *b; s16int f; if((v = calloc(1, sizeof(*v))) == nil){ nomem: werrstr("no memory"); goto err; } if((b = otfreadn(o, 2*2)) == nil) goto err; v->flags = (b[0]<<8 | b[1]) & ~CGLYPH_FL_OVERLAP_COMPOUND; v->glyphIndex = b[2]<<8 | b[3]; instr |= v->flags & CGLYPH_FL_INSTRUCTIONS; if(v->flags & CGLYPH_FL_UNSCALED_COMPONENT_OFFSET) v->flags &= ~(CGLYPH_FL_UNSCALED_COMPONENT_OFFSET | CGLYPH_FL_SCALED_COMPONENT_OFFSET); if((v->flags & CGLYPH_FL_WORD_ARGS) != 0 && (b = otfreadn(o, 2*2)) != nil){ if(v->flags & CGLYPH_FL_SIGNED_XY){ v->arg1 = (s16int)(b[0]<<8 | b[1]); v->arg2 = (s16int)(b[2]<<8 | b[3]); }else{ v->arg1 = b[0]<<8 | b[1]; v->arg1 = b[2]<<8 | b[3]; } }else if((b = otfreadn(o, 2)) != nil){ if(v->flags & CGLYPH_FL_SIGNED_XY){ v->arg1 = (s8int)b[0]; v->arg2 = (s8int)b[1]; }else{ v->arg1 = b[0]; v->arg2 = b[1]; } } if(b == nil) goto err; v->scaleX = 1.0; v->scaleY = 1.0; if((v->flags & CGLYPH_FL_SCALE) != 0 && (b = otfreadn(o, 2)) != nil){ v->scaleX = f2dot14(0); v->scaleY = v->scaleX; v->flags &= ~CGLYPH_FL_SCALE; v->flags |= CGLYPH_FL_SCALE_XY; }else if((v->flags & CGLYPH_FL_SCALE_XY) != 0 && (b = otfreadn(o, 2*2)) != nil){ v->scaleX = f2dot14(0); v->scaleY = f2dot14(1); }else if((v->flags & CGLYPH_FL_2X2_TRANSFORM) != 0 && (b = otfreadn(o, 2*2*2)) != nil){ v->scaleX = f2dot14(0); v->scale01 = f2dot14(1); v->scale10 = f2dot14(2); v->scaleY = f2dot14(3); } if(b == nil) goto err; if((v->flags & CGLYPH_FL_MORE_COMPONENTS) != 0){ if(read_ComponentGlyph(o, &v->next, instr) != 0){ free(v); return -1; } }else if(instr != 0){ if((b = otfreadn(o, 2)) == nil) goto err; v->numInstr = b[0]<<8 | b[1]; if((v->instr = malloc(v->numInstr)) == nil) goto nomem; if(v->numInstr > 0 && (b = otfreadn(o, v->numInstr)) == nil) goto err; memcpy(v->instr, b, v->numInstr); } *out = v; return 0; err: if(v != nil) free(v->instr); free(v); werrstr("ComponentGlyph: %r"); return -1; } void print_ComponentGlyph(Otfile *f, int indent, Otf *o, ComponentGlyph *v) { void *a = f->aux; f->print(a, "%*s%s: %#"PRIx16"%s%s%s%s%s%s%s%s%s%s\n", indent, "", "flags", v->flags, (v->flags&CGLYPH_FL_SIGNED_XY)?" CGLYPH_FL_SIGNED_XY":"", (v->flags&CGLYPH_FL_ROUND_TO_GRID_XY)?" CGLYPH_FL_ROUND_TO_GRID_XY":"", (v->flags&CGLYPH_FL_SCALE)?" CGLYPH_FL_SCALE":"", (v->flags&CGLYPH_FL_MORE_COMPONENTS)?" CGLYPH_FL_MORE_COMPONENTS":"", (v->flags&CGLYPH_FL_SCALE_XY)?" CGLYPH_FL_SCALE_XY":"", (v->flags&CGLYPH_FL_2X2_TRANSFORM)?" CGLYPH_FL_2X2_TRANSFORM":"", (v->flags&CGLYPH_FL_INSTRUCTIONS)?" CGLYPH_FL_INSTRUCTIONS":"", (v->flags&CGLYPH_FL_METRICS)?" CGLYPH_FL_METRICS":"", (v->flags&CGLYPH_FL_OVERLAP_COMPOUND)?" CGLYPH_FL_OVERLAP_COMPOUND":"", (v->flags&CGLYPH_FL_SCALED_COMPONENT_OFFSET)?" CGLYPH_FL_SCALED_COMPONENT_OFFSET":"" ); f->print(a, "%*s%s: %"PRIu16"\n", indent, "", "glyphIndex", v->glyphIndex); if(v->arg1 != 0 || v->arg2 != 0){ f->print(f->aux, "%*s%s: %d\n", indent, "", "arg1", v->arg1); f->print(f->aux, "%*s%s: %d\n", indent, "", "arg2", v->arg2); } if(v->flags & CGLYPH_FL_SCALE_XY){ f->print(a, "%*s%s: %g\n", indent, "", "scaleX", v->scaleX); f->print(a, "%*s%s: %g\n", indent, "", "scaleY", v->scaleY); }else if(v->flags & CGLYPH_FL_2X2_TRANSFORM){ f->print(a, "%*s%s: %g\n", indent, "", "scaleX", v->scaleX); f->print(a, "%*s%s: %g\n", indent, "", "scale01", v->scale01); f->print(a, "%*s%s: %g\n", indent, "", "scale10", v->scale10); f->print(a, "%*s%s: %g\n", indent, "", "scaleY", v->scaleY); } if(v->numInstr > 0 && v->instr != nil){ f->print(a, "%*s%s: %"PRIu16"\n", indent, "", "numInstr", v->numInstr); f->print(a, "%*s%s:", indent, "", "instr"); for(int i = 0; i < v->numInstr; i++) f->print(a, " %02"PRIx8, v->instr[i]); f->print(a, "\n"); } if(v->next != nil){ f->print(a, "%*s%s:\n", indent, "", "next"); print_ComponentGlyph(f, indent+indentΔ, o, v->next); } } enum { GLYPH_FL_ON_CURVE_POINT = 1<<0, GLYPH_FL_X_SHORT_VECTOR = 1<<1, GLYPH_FL_Y_SHORT_VECTOR = 1<<2, GLYPH_FL_REPEAT = 1<<3, GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR = 1<<4, GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR = 1<<5, GLYPH_FL_OVERLAP_SIMPLE = 1<<6, }; static int read_SimpleGlyph(Otf *o, SimpleGlyph **out) { SimpleGlyph *v; u8int *b, *flags; int i, n, nflags, c, nc; flags = nil; if((v = calloc(1, sizeof(*v))) == nil){ nomem: werrstr("no memory"); goto err; } v->numEndPtsOfContours = o->numberOfContours; n = o->numberOfContours; if((b = otfreadn(o, 2*n+2)) == nil) goto err; if((v->endPtsOfContours = malloc(2*n)) == nil) goto nomem; for(int i = 0; i < n; i++) v->endPtsOfContours[i] = b[2*i+0]<<8 | b[2*i+1]; v->numPoints = 1 + v->endPtsOfContours[o->numberOfContours-1]; v->instructionLength = b[2*n+0]<<8 | b[2*n+1]; n = v->instructionLength; if((b = otfreadn(o, n)) == nil) goto err; if((v->instructions = malloc(n)) == nil) goto nomem; memcpy(v->instructions, b, n); if((flags = malloc(v->numPoints)) == nil) /* not supposed to be more than that, 64Kb max */ goto nomem; for(nflags = 0; nflags < v->numPoints;){ if((b = otfreadn(o, 1)) == nil) goto err; if((flags[nflags++] = *b) & GLYPH_FL_REPEAT){ flags[nflags-1] ^= GLYPH_FL_REPEAT; if((b = otfreadn(o, 1)) == nil) goto err; if(nflags + *b > v->numPoints){ werrstr("repeat overflow (%d+%d > %d)", nflags, *b, v->numPoints); goto err; } memset(flags+nflags, flags[nflags-1], *b); nflags += *b; } } if((v->points = calloc(v->numPoints, sizeof(*v->points))) == nil) goto nomem; /* flags first */ for(i = n = 0; i < nflags && n < v->numPoints; i++, n++) v->points[n].onCurve = (flags[i] & GLYPH_FL_ON_CURVE_POINT) != 0; /* read packed x coordinates */ c = 0; for(i = n = 0; i < nflags && n < v->numPoints; i++){ if((flags[i] & GLYPH_FL_X_SHORT_VECTOR) != 0){ if((b = otfreadn(o, 1)) == nil) goto err; nc = *b; if((flags[i] & GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) == 0) nc = -nc; c = v->points[n++].x = c + nc; }else if((flags[i] & GLYPH_FL_X_IS_SAME_OR_POSITIVE_X_SHORT_VECTOR) != 0){ v->points[n++].x = c; }else{ if((b = otfreadn(o, 2)) == nil) goto err; c += (s16int)(b[0]<<8 | b[1]); v->points[n++].x = c; } } /* read packed y coordinates */ c = 0; for(i = n = 0; i < nflags && n < v->numPoints; i++){ if((flags[i] & GLYPH_FL_Y_SHORT_VECTOR) != 0){ if((b = otfreadn(o, 1)) == nil) goto err; nc = *b; if((flags[i] & GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) == 0) nc = -nc; c = v->points[n++].y = c + nc; }else if((flags[i] & GLYPH_FL_Y_IS_SAME_OR_POSITIVE_Y_SHORT_VECTOR) != 0){ v->points[n++].y = c; }else{ if((b = otfreadn(o, 2)) == nil) goto err; c += (s16int)(b[0]<<8 | b[1]); v->points[n++].y = c; } } free(flags); *out = v; return 0; err: free(flags); if(v != nil){ free(v->endPtsOfContours); free(v->instructions); free(v->points); } free(v); werrstr("SimpleGlyph: %r"); return -1; } void print_SimpleGlyph(Otfile *f, int indent, Otf *o, SimpleGlyph *v) { void *a = f->aux; USED(o); if(v->numEndPtsOfContours > 0){ f->print(a, "%*s%s:", indent, "", "endPtsOfContours"); for(int i = 0; i < v->numEndPtsOfContours; i++) f->print(a, " %"PRId16, v->endPtsOfContours[i]); f->print(a, "\n"); } if(v->instructionLength > 0){ f->print(a, "%*s%s: %"PRId16"\n", indent, "", "instructionLength", v->instructionLength); f->print(a, "%*s%s:", indent, "", "instructions"); for(int i = 0; i < v->instructionLength; i++) f->print(a, " %02"PRIx8, v->instructions[i]); f->print(a, "\n"); } if(v->numPoints > 0){ f->print(a, "%*s%s: %d\n", indent, "", "numPoints", v->numPoints); f->print(a, "%*s%s:", indent, "", "points"); for(int i = 0; i < v->numPoints; i++) f->print(a, " (%d,%d,%s)", v->points[i].x, v->points[i].y, v->points[i].onCurve?"on":"off"); f->print(a, "\n"); } } static Glyf * bitebdt(Otf *o, Glyf *g, BitmapGlyph *bg) { u8int *b; int i, n; 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; }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->numComponents = 0; if(bg->format == 2 || bg->format == 5 || bg->format == 7){ /* bit-aligned - last row is padded to a full byte */ bg->pitchBits = g->xMax - g->xMin; bg->size = (bg->pitchBits*(g->yMax-g->yMin)*bg->bitDepth + 7)/8; }else{ /* byte-aligned - every row is byte-aligned */ n = ((g->xMax-g->xMin)*bg->bitDepth + 7)/8; bg->size = n * (g->yMax-g->yMin); bg->pitchBits = n * 8; } switch(bg->format){ case 8: if(otfreadn(o, 1) == nil) /* skip uint8 pad */ goto err; /* fallthrough */ case 9: if((b = otfreadn(o, 2)) == nil) goto err; bg->numComponents = b[0]<<8 | b[1]; if(otfarray(o, &bg->components, read_EbdtComponent, sizeof(EbdtComponent), bg->numComponents) < 0) goto err; /* no image, both 8 and 9 are component */ bg->pitchBits = 0; bg->size = 0; /* fallthrough */ case 1: case 2: case 5: case 6: case 7: g->bitmap = malloc(sizeof(*bg) + bg->size); memcpy(g->bitmap, bg, sizeof(*bg)); if(bg->size > 0){ if((b = otfreadn(o, bg->size)) == nil) goto err; memcpy(g->bitmap->image, b, bg->size); } break; } otfpoprange(o); otfpoprange(o); return g; err: free(g->bitmap); free(g); otfpopranges(o); return nil; } static int ppemcmp(BitmapGlyph *a, BitmapGlyph *b) { if(a->ppemX != b->ppemX) return a->ppemX - b->ppemX; if(a->ppemY != b->ppemY) return a->ppemY - b->ppemY; /* FIXME - is there anything else to compare? bit depth? */ return 0; } static Glyf * bitglyf(Otf *o, Glyf *g, RasterOpts *opts) { BitmapGlyph b, best, want; IndexSubtableRecord *isr; int i, j, k, n, r, found; IndexSubtable *is; BitmapSize *bs; want.ppemX = opts->ppemX; want.ppemY = opts->ppemY; found = 0; r = -1; 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) continue; if(g->index > bs->endGlyphIndex) break; b.bitDepth = bs->bitDepth; if(b.bitDepth != 1 && b.bitDepth != 8){ werrstr("unsupported bit depth: %d", b.bitDepth); goto err; } b.ppemX = bs->ppemX; b.ppemY = bs->ppemY; isr = bs->indexSubtableList; for(j = 0; j < (int)bs->numberOfIndexSubtables; j++, isr++){ if(g->index < isr->firstGlyphIndex) break; if(g->index > isr->lastGlyphIndex || (is = isr->indexSubtable) == nil) continue; 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) continue; 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) continue; 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: continue; } /* now try to choose the best match */ if((n = ppemcmp(&b, &want)) == 0 || found == 0){ better: memcpy(&best, &b, sizeof(b)); found = 1; if((r = n) == 0) goto done; continue; } /* both better, but the new is closer */ if(n > 0 && (r > 0 && ppemcmp(&b, &best) < 0)) goto better; /* both worse, but the new one is better so far */ if(n < 0 && (r < 0 && ppemcmp(&b, &best) > 0)) goto better; } } done: if(found) return bitebdt(o, g, &best); werrstr("no bitmap"); err: free(g); return nil; } Glyf * otfglyf(Otf *o, int index, RasterOpts *opts) { static TableRecord noGlyf; int off, len, i; Glyf *g; if(index < 0 || index >= o->numGlyphs){ werrstr("index out of range"); return nil; } if(o->td.head == nil){ werrstr("no head table"); return nil; } if((g = calloc(1, sizeof(*g))) == nil){ werrstr("no memory"); return nil; } g->index = index; 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; break; } } if(o->glyf == nil) o->glyf = &noGlyf; } if(o->glyf != &noGlyf && o->td.loca != nil){ if(o->indexToLocFormat == 0){ off = (int)o->td.loca->shortOffsets[index]*2; len = (int)o->td.loca->shortOffsets[index+1]*2 - off; }else{ off = o->td.loca->longOffsets[index]; len = o->td.loca->longOffsets[index+1] - off; } if(len > 0){ if(otfpushrange(o, o->glyf->offset, o->glyf->length) < 0){ err: free(g); otfpopranges(o); return nil; } if(otfpushrange(o, off, len) < 0) goto err; if(read_Glyf(o, g) < 0) goto err; otfpoprange(o); otfpoprange(o); return g; } if(o->td.eblc == nil && o->td.ebdt == nil) return g; } if(o->td.eblc != nil && o->td.ebdt != nil) return bitglyf(o, g, opts); free(g); return nil; } int otfglyfnum(Otf *o) { return o->numGlyphs; } int otfrune2glyph(Otf *o, Rune r) { RuneMapper *m; int i, g; for(i = 0, m = o->td.cmap->mappers; i < o->td.cmap->numMappers; i++, m++){ if((g = m->rune2glyph(m->aux, r)) >= 0) return g; } return -1; } Rune otfglyph2rune(Otf *o, int g) { RuneMapper *m; Rune r; int i; for(i = 0, m = o->td.cmap->mappers; i < o->td.cmap->numMappers; i++, m++){ if((r = m->glyph2rune(m->aux, g)) != NoRune) return r; } return NoRune; } enum { PLAT_UNICODE, PLAT_MACINTOSH, /* "currently discouraged", unsupported */ PLAT_ISO, /* deprecated, unsupported */ PLAT_WINDOWS, PLAT_CUSTOM, /* deprecated, unsupported */ }; /* supported subtable formats: 4, 6, 10, 12, 13 */ /* FIXME: need to implement (higher to lower prio): 14 */ enum { ENC_UNICODE_1_0, /* deprecated, unsupported */ ENC_UNICODE_1_1, /* deprecated, unsupported */ ENC_UNICODE_ISO, /* deprecated, unsupported */ ENC_UNICODE_2_0_BMP, /* subtable format 4, 6 */ ENC_UNICODE_2_0_FULL, /* subtable format 10, 12 */ ENC_UNICODE_VAR_SEQ, /* subtable format 14 */ ENC_UNICODE_FULL, /* subtable format 13 (many-to-one) */ ENC_WINDOWS_SYMBOL = 0, /* unsupported */ ENC_WINDOWS_UNICODE_BMP, /* subtable format 4 */ ENC_WINDOWS_SHIFTJIS, /* unsupported */ ENC_WINDOWS_PRC, /* unsupported */ ENC_WINDOWS_BIG5, /* unsupported */ ENC_WINDOWS_WANSUNG, /* unsupported */ ENC_WINDOWS_JOHAB, /* unsupported */ ENC_WINDOWS_UNICODE_FULL = 10, /* subtable format 12 */ }; static int cmap4rune2glyph(void *aux, Rune r) { SubtableCmap4 *sc; int i, b, e, n, x, segC; if(r > 0xffff) return -1; sc = aux; segC = sc->segCountX2/2; for(b = 0, e = segC-1; b <= e; ){ i = (b + e)/2; if(sc->endCode[i] < r) b = i + 1; else if(sc->startCode[i] > r) e = i - 1; else if(sc->idRangeOffset[i] == 0){ x = r + sc->idDelta[i]; if(x < 0) x += 65536; return x; }else{ x = i + sc->idRangeOffset[i]/2 + (r - sc->startCode[i]) - segC; n = (sc->length-((8*2)+(sc->segCountX2*4)))/2; if(x < 0 || x >= n) break; return sc->glyphIdArray[x]; } } return -1; } static Rune cmap4glyph2rune(void *aux, int g) { USED(aux); USED(g); /* FIXME - other mapper will hopefully pick up after */ return 'x'; } static int cmap6rune2glyph(void *aux, Rune r) { SubtableCmap6 *sc; sc = aux; if(r >= sc->firstCode){ r -= sc->firstCode; if(r < sc->entryCount) return sc->glyphIdArray[r]; } return -1; } static Rune cmap6glyph2rune(void *aux, int g) { SubtableCmap6 *sc; sc = aux; if(g >= 0 && g < sc->entryCount) return (Rune)sc->firstCode + g; return NoRune; } static int cmap10rune2glyph(void *aux, Rune r) { SubtableCmap10 *sc; sc = aux; if(r >= sc->startCharCode){ r -= sc->startCharCode; if(r < sc->numChars) return sc->glyphIdArray[r]; } return -1; } static Rune cmap10glyph2rune(void *aux, int g) { SubtableCmap10 *sc; sc = aux; if(g >= 0 && g < sc->numChars) return sc->startCharCode + g; return NoRune; } static int cmap12rune2glyph(void *aux, Rune r) { SubtableCmap12or13 *sc; MapGroup *m; int b, e, x; sc = aux; for(b = 0, e = sc->numGroups-1; b <= e; ){ x = (b + e)/2; m = sc->groups + x; if(m->endCharCode < r) b = x + 1; else if(m->startCharCode > r) e = x - 1; else return m->startGlyphID + (r - m->startCharCode); } return -1; } static Rune cmap12glyph2rune(void *aux, int g) { SubtableCmap12or13 *sc; MapGroup *m; int i; sc = aux; for(i = 0, m = sc->groups; i < sc->numGroups; i++, m++){ if(g >= m->startGlyphID && g <= m->startGlyphID+(m->endCharCode-m->startCharCode)) return m->startCharCode + (g - m->startGlyphID); } return NoRune; } static int cmap13rune2glyph(void *aux, Rune r) { SubtableCmap12or13 *sc; MapGroup *m; int b, e, x; sc = aux; for(b = 0, e = sc->numGroups-1; b <= e; ){ x = (b + e)/2; m = sc->groups + x; if(m->endCharCode < r) b = x + 1; else if(m->startCharCode > r) e = x - 1; else return m->startGlyphID; } return -1; } static Rune cmap13glyph2rune(void *aux, int g) { SubtableCmap12or13 *sc; MapGroup *m; int i; sc = aux; for(i = 0, m = sc->groups; i < sc->numGroups; i++, m++){ if(g == m->startGlyphID) return m->startCharCode;/* this doesn't make sense for constant mapping */ } return NoRune; } static int otfcmapUnicode(TableCmap *c, EncodingRecord *er, int *parsed, int *unsupported) { SubtableCmap *sc; sc = er->subtable; switch(er->encodingID){ case ENC_UNICODE_2_0_BMP: if(sc->format == 4){ c->mappers[c->numMappers].rune2glyph = cmap4rune2glyph; c->mappers[c->numMappers].glyph2rune = cmap4glyph2rune; c->mappers[c->numMappers++].aux = &sc->sub4; (*parsed)++; break; } if(sc->format == 6){ c->mappers[c->numMappers].rune2glyph = cmap6rune2glyph; c->mappers[c->numMappers].glyph2rune = cmap6glyph2rune; c->mappers[c->numMappers++].aux = &sc->sub6; (*parsed)++; break; } (*unsupported)++; werrstr("2.0 bmp: fmt %d", sc->format); goto err; case ENC_UNICODE_2_0_FULL: /* this one is good */ if(sc->format == 10){ if(sc->sub10.numChars < 1){ werrstr("2.0 full: no chars"); goto err; } c->mappers[c->numMappers].rune2glyph = cmap10rune2glyph; c->mappers[c->numMappers].glyph2rune = cmap10glyph2rune; c->mappers[c->numMappers++].aux = &sc->sub10; (*parsed)++; break; } if(sc->format == 12){ if(sc->sub12or13.numGroups < 1){ werrstr("2.0 full: no groups"); goto err; } c->mappers[c->numMappers].rune2glyph = cmap12rune2glyph; c->mappers[c->numMappers].glyph2rune = cmap12glyph2rune; c->mappers[c->numMappers++].aux = &sc->sub12or13; (*parsed)++; break; } (*unsupported)++; werrstr("2.0 full: fmt %d", sc->format); goto err; case ENC_UNICODE_VAR_SEQ: /* FIXME */ break; case ENC_UNICODE_FULL: if(sc->format == 13){ if(sc->sub12or13.numGroups < 1){ werrstr("full: no groups"); goto err; } c->mappers[c->numMappers].rune2glyph = cmap13rune2glyph; c->mappers[c->numMappers].glyph2rune = cmap13glyph2rune; c->mappers[c->numMappers++].aux = &sc->sub12or13; (*parsed)++; break; } (*unsupported)++; werrstr("full: fmt %d", sc->format); goto err; case ENC_UNICODE_1_0: case ENC_UNICODE_1_1: case ENC_UNICODE_ISO: (*unsupported)++; werrstr("deprecated encoding: %d", er->encodingID); goto err; default: (*unsupported)++; werrstr("unknown encoding: %d", er->encodingID); goto err; } return 0; err: werrstr("unicode: %r"); return -1; } static int otfcmapWindows(TableCmap *c, EncodingRecord *er, int *parsed, int *unsupported) { SubtableCmap *sc; sc = er->subtable; switch(er->encodingID){ case ENC_WINDOWS_UNICODE_BMP: if(sc->format == 4){ c->mappers[c->numMappers].rune2glyph = cmap4rune2glyph; c->mappers[c->numMappers].glyph2rune = cmap4glyph2rune; c->mappers[c->numMappers++].aux = &sc->sub4; (*parsed)++; break; } if(sc->format == 6){ c->mappers[c->numMappers].rune2glyph = cmap6rune2glyph; c->mappers[c->numMappers].glyph2rune = cmap6glyph2rune; c->mappers[c->numMappers++].aux = &sc->sub6; (*parsed)++; break; } (*unsupported)++; werrstr("unicode bmp: fmt %d", sc->format); goto err; case ENC_WINDOWS_UNICODE_FULL: if(sc->format != 12){ (*unsupported)++; werrstr("unicode full: fmt %d", sc->format); goto err; } if(sc->sub12or13.numGroups < 1){ werrstr("unicode full: no groups"); goto err; } c->mappers[c->numMappers].rune2glyph = cmap12rune2glyph; c->mappers[c->numMappers].glyph2rune = cmap12glyph2rune; c->mappers[c->numMappers++].aux = &sc->sub12or13; (*parsed)++; break; case ENC_WINDOWS_SYMBOL: case ENC_WINDOWS_SHIFTJIS: case ENC_WINDOWS_PRC: case ENC_WINDOWS_BIG5: case ENC_WINDOWS_WANSUNG: case ENC_WINDOWS_JOHAB: (*unsupported)++; werrstr("unsupported encoding: %d", er->encodingID); goto err; default: (*unsupported)++; werrstr("unknown encoding: %d", er->encodingID); goto err; } return 0; err: werrstr("windows: %r"); return -1; } static int otfcmap(TableCmap *c) { int i, parsed, unsupported; EncodingRecord *er; parsed = 0; unsupported = 0; for(i = 0, er = c->encodingRecords; i < c->numTables; i++, er++){ if(c->numMappers >= nelem(c->mappers)) /* give up */ break; switch(er->platformID){ case PLAT_UNICODE: /* FIXME issue a warning if returned non-zero */ if(otfcmapUnicode(c, er, &parsed, &unsupported) != 0) goto err; break; case PLAT_WINDOWS: /* FIXME issue a warning if returned non-zero */ if(otfcmapWindows(c, er, &parsed, &unsupported) != 0) goto err; break; case PLAT_MACINTOSH: case PLAT_ISO: case PLAT_CUSTOM: default: unsupported++; break; } } if(parsed > 0) return 0; if(unsupported > 0) werrstr(" (%d unsupported)", unsupported); else werrstr(""); werrstr("no usable records%r"); /* FIXME - eventually this return should be removed */ return 0; err: werrstr("cmap: %r"); return -1; }