static fz_error * rendertext(fz_renderer *gc, fz_textnode *text, fz_matrix ctm) { fz_error *error; fz_irect tbox; fz_irect clip; fz_matrix tm, trm; fz_glyph glyph; int i, x, y, cid; tbox = fz_roundrect(fz_boundnode((fz_node*)text, ctm)); clip = fz_intersectirects(gc->clip, tbox); DEBUG("text %s n=%d [%g %g %g %g];\n", text->font->name, text->len, text->trm.a, text->trm.b, text->trm.c, text->trm.d); if (fz_isemptyrect(clip)) return fz_okay; if (!(gc->flag & FOVER)) { error = fz_newpixmapwithrect(&gc->dest, clip, 1); if (error) return error; fz_clearpixmap(gc->dest); } tm = text->trm; for (i = 0; i < text->len; i++) { cid = text->els[i].cid; tm.e = text->els[i].x; tm.f = text->els[i].y; trm = fz_concat(tm, ctm); x = fz_floor(trm.e); y = fz_floor(trm.f); trm.e = QUANT(trm.e - fz_floor(trm.e), HSUBPIX); trm.f = QUANT(trm.f - fz_floor(trm.f), VSUBPIX); error = fz_renderglyph(gc->cache, &glyph, text->font, cid, trm); if (error) return error; if (!(gc->flag & FOVER)) drawglyph(gc, gc->dest, &glyph, x, y); else drawglyph(gc, gc->over, &glyph, x, y); } return fz_okay; }
fz_error pdf_loadtype3font(pdf_fontdesc **fontdescp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict) { fz_error error; char buf[256]; char *estrings[256]; pdf_fontdesc *fontdesc; fz_obj *encoding; fz_obj *widths; fz_obj *resources; fz_obj *charprocs; fz_obj *obj; int first, last; int i, k, n; fz_rect bbox; fz_matrix matrix; obj = fz_dictgets(dict, "Name"); if (fz_isname(obj)) strlcpy(buf, fz_toname(obj), sizeof buf); else sprintf(buf, "Unnamed-T3"); fontdesc = pdf_newfontdesc(); pdf_logfont("load type3 font (%d %d R) ptr=%p {\n", fz_tonum(dict), fz_togen(dict), fontdesc); pdf_logfont("name %s\n", buf); obj = fz_dictgets(dict, "FontMatrix"); matrix = pdf_tomatrix(obj); pdf_logfont("matrix [%g %g %g %g %g %g]\n", matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f); obj = fz_dictgets(dict, "FontBBox"); bbox = pdf_torect(obj); pdf_logfont("bbox [%g %g %g %g]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); bbox = fz_transformaabb(matrix, bbox); bbox.x0 = fz_floor(bbox.x0 * 1000); bbox.y0 = fz_floor(bbox.y0 * 1000); bbox.x1 = fz_ceil(bbox.x1 * 1000); bbox.y1 = fz_ceil(bbox.y1 * 1000); fontdesc->font = fz_newtype3font(buf, matrix); fz_setfontbbox(fontdesc->font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* * Encoding */ for (i = 0; i < 256; i++) estrings[i] = nil; encoding = fz_dictgets(dict, "Encoding"); if (!encoding) { error = fz_throw("syntaxerror: Type3 font missing Encoding"); goto cleanup; } if (fz_isname(encoding)) pdf_loadencoding(estrings, fz_toname(encoding)); if (fz_isdict(encoding)) { fz_obj *base, *diff, *item; base = fz_dictgets(encoding, "BaseEncoding"); if (fz_isname(base)) pdf_loadencoding(estrings, fz_toname(base)); diff = fz_dictgets(encoding, "Differences"); if (fz_isarray(diff)) { n = fz_arraylen(diff); k = 0; for (i = 0; i < n; i++) { item = fz_arrayget(diff, i); if (fz_isint(item)) k = fz_toint(item); if (fz_isname(item)) estrings[k++] = fz_toname(item); if (k < 0) k = 0; if (k > 255) k = 255; } } } fontdesc->encoding = pdf_newidentitycmap(0, 1); error = pdf_loadtounicode(fontdesc, xref, estrings, nil, fz_dictgets(dict, "ToUnicode")); if (error) goto cleanup; /* * Widths */ pdf_setdefaulthmtx(fontdesc, 0); first = fz_toint(fz_dictgets(dict, "FirstChar")); last = fz_toint(fz_dictgets(dict, "LastChar")); widths = fz_dictgets(dict, "Widths"); if (!widths) { error = fz_throw("syntaxerror: Type3 font missing Widths"); goto cleanup; } for (i = first; i <= last; i++) { float w = fz_toreal(fz_arrayget(widths, i - first)); w = fontdesc->font->t3matrix.a * w * 1000.0; fontdesc->font->t3widths[i] = w * 0.001; pdf_addhmtx(fontdesc, i, i, w); } pdf_endhmtx(fontdesc); /* * Resources */ resources = fz_dictgets(dict, "Resources"); /* Inherit page's resource dict if type3 font does not have one */ if (!resources && rdb) resources = rdb; else if (!resources && !rdb) fz_warn("no resource dictionary for type 3 font!"); /* * CharProcs */ charprocs = fz_dictgets(dict, "CharProcs"); if (!charprocs) { error = fz_throw("syntaxerror: Type3 font missing CharProcs"); goto cleanup; } for (i = 0; i < 256; i++) { if (estrings[i]) { obj = fz_dictgets(charprocs, estrings[i]); if (obj) { pdf_logfont("load charproc %s {\n", estrings[i]); error = loadcharproc(&fontdesc->font->t3procs[i], xref, resources, obj); if (error) goto cleanup; pdf_logfont("}\n"); } } } pdf_logfont("}\n"); *fontdescp = fontdesc; return fz_okay; cleanup: fz_dropfont(fontdesc->font); fz_free(fontdesc); return fz_rethrow(error, "cannot load type3 font"); }
static void fz_drawtriangle(fz_pixmap *pix, float *av, float *bv, float *cv, int n) { float poly[MAXV][MAXN]; float temp[MAXV][MAXN]; float cx0 = pix->x; float cy0 = pix->y; float cx1 = pix->x + pix->w; float cy1 = pix->y + pix->h; int gel[MAXV][MAXN]; int ael[2][MAXN]; int del[2][MAXN]; int y, s0, s1, e0, e1; int top, bot, len; int i, k; copyvert(poly[0], av, n); copyvert(poly[1], bv, n); copyvert(poly[2], cv, n); len = clippoly(poly, temp, 3, n, cx0, 0, 0); len = clippoly(temp, poly, len, n, cx1, 0, 1); len = clippoly(poly, temp, len, n, cy0, 1, 0); len = clippoly(temp, poly, len, n, cy1, 1, 1); if (len < 3) return; for (i = 0; i < len; i++) { gel[i][0] = fz_floor(poly[i][0] + 0.5) * 65536; /* trunc and fix */ gel[i][1] = fz_floor(poly[i][1] + 0.5); /* y is not fixpoint */ for (k = 2; k < n; k++) gel[i][k] = poly[i][k] * 65536; /* fix with precision */ } top = bot = 0; for (i = 0; i < len; i++) { if (gel[i][1] < gel[top][1]) top = i; if (gel[i][1] > gel[bot][1]) bot = i; } if (gel[bot][1] - gel[top][1] == 0) return; y = gel[top][1]; if (findnext(gel, len, top, &s0, &e0, 1)) return; if (findnext(gel, len, top, &s1, &e1, -1)) return; loadedge(gel, s0, e0, ael[0], del[0], n); loadedge(gel, s1, e1, ael[1], del[1], n); while (1) { int x0 = ael[0][0] >> 16; int x1 = ael[1][0] >> 16; if (ael[0][0] < ael[1][0]) drawscan(pix, y, x0, x1, ael[0]+2, ael[1]+2, n-2); else drawscan(pix, y, x1, x0, ael[1]+2, ael[0]+2, n-2); stepedge(ael[0], del[0], n); stepedge(ael[1], del[1], n); y ++; if (y >= gel[e0][1]) { if (findnext(gel, len, e0, &s0, &e0, 1)) return; loadedge(gel, s0, e0, ael[0], del[0], n); } if (y >= gel[e1][1]) { if (findnext(gel, len, e1, &s1, &e1, -1)) return; loadedge(gel, s1, e1, ael[1], del[1], n); } } }
fz_error * pdf_loadtype3font(pdf_font **fontp, pdf_xref *xref, fz_obj *dict, fz_obj *ref) { fz_error *error; char buf[256]; char *estrings[256]; pdf_font *font; fz_obj *encoding; fz_obj *widths; fz_obj *resources; fz_obj *charprocs; fz_obj *obj; int first, last; int i, k, n; fz_rect bbox; obj = fz_dictgets(dict, "Name"); if (obj) strlcpy(buf, fz_toname(obj), sizeof buf); else sprintf(buf, "Unnamed-T3"); font = pdf_newfont(buf); if (!font) return fz_throw("outofmem: font struct"); pdf_logfont("load type3 font %d %d (%p) {\n", fz_tonum(ref), fz_togen(ref), font); pdf_logfont("name %s\n", buf); font->super.render = t3render; font->super.drop = (void(*)(fz_font*)) t3dropfont; obj = fz_dictgets(dict, "FontMatrix"); font->matrix = pdf_tomatrix(obj); pdf_logfont("matrix [%g %g %g %g %g %g]\n", font->matrix.a, font->matrix.b, font->matrix.c, font->matrix.d, font->matrix.e, font->matrix.f); obj = fz_dictgets(dict, "FontBBox"); bbox = pdf_torect(obj); pdf_logfont("bbox [%g %g %g %g]\n", bbox.x0, bbox.y0, bbox.x1, bbox.y1); bbox = fz_transformaabb(font->matrix, bbox); bbox.x0 = fz_floor(bbox.x0 * 1000); bbox.y0 = fz_floor(bbox.y0 * 1000); bbox.x1 = fz_ceil(bbox.x1 * 1000); bbox.y1 = fz_ceil(bbox.y1 * 1000); fz_setfontbbox((fz_font*)font, bbox.x0, bbox.y0, bbox.x1, bbox.y1); /* * Encoding */ for (i = 0; i < 256; i++) estrings[i] = nil; encoding = fz_dictgets(dict, "Encoding"); if (!encoding) { error = fz_throw("syntaxerror: Type3 font missing Encoding"); goto cleanup; } error = pdf_resolve(&encoding, xref); if (error) goto cleanup; if (fz_isname(obj)) pdf_loadencoding(estrings, fz_toname(encoding)); if (fz_isdict(encoding)) { fz_obj *base, *diff, *item; base = fz_dictgets(encoding, "BaseEncoding"); if (fz_isname(base)) pdf_loadencoding(estrings, fz_toname(base)); diff = fz_dictgets(encoding, "Differences"); if (fz_isarray(diff)) { n = fz_arraylen(diff); k = 0; for (i = 0; i < n; i++) { item = fz_arrayget(diff, i); if (fz_isint(item)) k = fz_toint(item); if (fz_isname(item)) estrings[k++] = fz_toname(item); if (k < 0) k = 0; if (k > 255) k = 255; } } } fz_dropobj(encoding); error = pdf_newidentitycmap(&font->encoding, 0, 1); if (error) goto cleanup; error = pdf_loadtounicode(font, xref, estrings, nil, fz_dictgets(dict, "ToUnicode")); if (error) goto cleanup; /* * Widths */ fz_setdefaulthmtx((fz_font*)font, 0); first = fz_toint(fz_dictgets(dict, "FirstChar")); last = fz_toint(fz_dictgets(dict, "LastChar")); widths = fz_dictgets(dict, "Widths"); if (!widths) { error = fz_throw("syntaxerror: Type3 font missing Widths"); goto cleanup; } error = pdf_resolve(&widths, xref); if (error) goto cleanup; for (i = first; i <= last; i++) { float w = fz_toreal(fz_arrayget(widths, i - first)); w = font->matrix.a * w * 1000.0; error = fz_addhmtx((fz_font*)font, i, i, w); if (error) { fz_dropobj(widths); goto cleanup; } } fz_dropobj(widths); error = fz_endhmtx((fz_font*)font); if (error) goto cleanup; /* * Resources */ resources = nil; obj = fz_dictgets(dict, "Resources"); if (obj) { error = pdf_resolve(&obj, xref); if (error) goto cleanup; error = pdf_loadresources(&resources, xref, obj); fz_dropobj(obj); if (error) goto cleanup; } else pdf_logfont("no resource dict!\n"); /* * CharProcs */ charprocs = fz_dictgets(dict, "CharProcs"); if (!charprocs) { error = fz_throw("syntaxerror: Type3 font missing CharProcs"); goto cleanup2; } error = pdf_resolve(&charprocs, xref); if (error) goto cleanup2; for (i = 0; i < 256; i++) { if (estrings[i]) { obj = fz_dictgets(charprocs, estrings[i]); if (obj) { pdf_logfont("load charproc %s {\n", estrings[i]); error = loadcharproc(&font->charprocs[i], xref, resources, obj); if (error) goto cleanup2; error = fz_optimizetree(font->charprocs[i]); if (error) goto cleanup2; pdf_logfont("}\n"); } } } fz_dropobj(charprocs); if (resources) fz_dropobj(resources); pdf_logfont("}\n"); *fontp = font; return fz_okay; cleanup2: if (resources) fz_dropobj(resources); cleanup: fz_dropfont((fz_font*)font); return fz_rethrow(error, "cannot load type3 font"); }
fz_error fz_insertgel(fz_gel *gel, float fx0, float fy0, float fx1, float fy1) { fz_edge *edge; int dx, dy; int winding; int width; int tmp; int v; int d; int x0 = fz_floor(fx0 * HSCALE); int y0 = fz_floor(fy0 * VSCALE); int x1 = fz_floor(fx1 * HSCALE); int y1 = fz_floor(fy1 * VSCALE); d = cliplerpy(gel->clip.y0, 0, x0, y0, x1, y1, &v); if (d == OUTSIDE) return fz_okay; if (d == LEAVE) { y1 = gel->clip.y0; x1 = v; } if (d == ENTER) { y0 = gel->clip.y0; x0 = v; } d = cliplerpy(gel->clip.y1, 1, x0, y0, x1, y1, &v); if (d == OUTSIDE) return fz_okay; if (d == LEAVE) { y1 = gel->clip.y1; x1 = v; } if (d == ENTER) { y0 = gel->clip.y1; x0 = v; } if (y0 == y1) return fz_okay; if (y0 > y1) { winding = -1; tmp = x0; x0 = x1; x1 = tmp; tmp = y0; y0 = y1; y1 = tmp; } else winding = 1; if (x0 < gel->bbox.x0) gel->bbox.x0 = x0; if (x0 > gel->bbox.x1) gel->bbox.x1 = x0; if (x1 < gel->bbox.x0) gel->bbox.x0 = x1; if (x1 > gel->bbox.x1) gel->bbox.x1 = x1; if (y0 < gel->bbox.y0) gel->bbox.y0 = y0; if (y1 > gel->bbox.y1) gel->bbox.y1 = y1; if (gel->len + 1 == gel->cap) { int newcap = gel->cap + 512; fz_edge *newedges = fz_realloc(gel->edges, sizeof(fz_edge) * newcap); if (!newedges) return fz_rethrow(-1, "out of memory"); gel->cap = newcap; gel->edges = newedges; } edge = &gel->edges[gel->len++]; dy = y1 - y0; dx = x1 - x0; width = dx < 0 ? -dx : dx; edge->xdir = dx > 0 ? 1 : -1; edge->ydir = winding; edge->x = x0; edge->y = y0; edge->h = dy; edge->adjdown = dy; /* initial error term going l->r and r->l */ if (dx >= 0) edge->e = 0; else edge->e = -dy + 1; /* y-major edge */ if (dy >= width) { edge->xmove = 0; edge->adjup = width; } /* x-major edge */ else { edge->xmove = (width / dy) * edge->xdir; edge->adjup = width % dy; } return fz_okay; }
static fz_error * addpatternshape(pdf_gstate *gs, fz_node *shape, pdf_pattern *pat, fz_colorspace *cs, float *v) { fz_error *error; fz_node *xform; fz_node *over; fz_node *mask; fz_node *link; fz_matrix ctm; fz_matrix inv; fz_matrix ptm; fz_rect bbox; int x, y, x0, y0, x1, y1; /* patterns are painted in user space */ ctm = getmatrix(gs->head); inv = fz_invertmatrix(ctm); error = fz_newmasknode(&mask); if (error) return fz_rethrow(error, "cannot create mask node"); ptm = fz_concat(pat->matrix, fz_invertmatrix(ctm)); error = fz_newtransformnode(&xform, ptm); if (error) { fz_dropnode(mask); return fz_rethrow(error, "cannot create transform node"); } error = pdf_newovernode(&over, gs); if (error) { fz_dropnode(xform); fz_dropnode(mask); return fz_rethrow(error, "cannot create over node"); } fz_insertnodelast(mask, shape); fz_insertnodelast(mask, xform); fz_insertnodelast(xform, over); xform = nil; /* over, xform, mask are now owned by the tree */ /* get bbox of shape in pattern space for stamping */ ptm = fz_concat(ctm, fz_invertmatrix(pat->matrix)); bbox = fz_boundnode(shape, ptm); /* expand bbox by pattern bbox */ bbox.x0 += pat->bbox.x0; bbox.y0 += pat->bbox.y0; bbox.x1 += pat->bbox.x1; bbox.y1 += pat->bbox.y1; x0 = fz_floor(bbox.x0 / pat->xstep); y0 = fz_floor(bbox.y0 / pat->ystep); x1 = fz_ceil(bbox.x1 / pat->xstep); y1 = fz_ceil(bbox.y1 / pat->ystep); for (y = y0; y <= y1; y++) { for (x = x0; x <= x1; x++) { ptm = fz_translate(x * pat->xstep, y * pat->ystep); error = fz_newtransformnode(&xform, ptm); if (error) return fz_rethrow(error, "cannot create transform node for stamp"); error = fz_newlinknode(&link, pat->tree); if (error) { fz_dropnode(xform); return fz_rethrow(error, "cannot create link node for stamp"); } fz_insertnodelast(xform, link); fz_insertnodelast(over, xform); } } if (pat->ismask) { error = addcolorshape(gs, mask, 1.0, cs, v); if (error) return fz_rethrow(error, "cannot add colored shape"); return fz_okay; } fz_insertnodelast(gs->head, mask); return fz_okay; }