static void fz_drawfillpath(void *user, fz_path *path, int evenodd, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrixexpansion(ctm); float flatness = 0.3f / expansion; unsigned char colorbv[FZ_MAXCOLORS + 1]; float colorfv[FZ_MAXCOLORS]; fz_bbox bbox; int i; fz_resetgel(dev->gel, dev->scissor); fz_fillpath(dev->gel, path, ctm, flatness); fz_sortgel(dev->gel); bbox = fz_boundgel(dev->gel); bbox = fz_intersectbbox(bbox, dev->scissor); if (fz_isemptyrect(bbox)) return; fz_convertcolor(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scanconvert(dev->gel, dev->ael, evenodd, bbox, dev->dest, colorbv); }
static fz_error * renderpath(fz_renderer *gc, fz_pathnode *path, fz_matrix ctm) { fz_error *error; float flatness; fz_irect gbox; fz_irect clip; flatness = 0.3 / fz_matrixexpansion(ctm); if (flatness < 0.1) flatness = 0.1; fz_resetgel(gc->gel, HS, VS); if (path->paint == FZ_STROKE) { if (path->dash) error = fz_dashpath(gc->gel, path, ctm, flatness); else error = fz_strokepath(gc->gel, path, ctm, flatness); } else error = fz_fillpath(gc->gel, path, ctm, flatness); if (error) return error; fz_sortgel(gc->gel); gbox = fz_boundgel(gc->gel); clip = fz_intersectirects(gc->clip, gbox); if (fz_isemptyrect(clip)) return nil; DEBUG("path %s;\n", path->paint == FZ_STROKE ? "stroke" : "fill"); if (gc->flag & FRGB) { return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, clip, gc->over, gc->rgb, 1); } else if (gc->flag & FOVER) { return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, clip, gc->over, nil, 1); } else { error = fz_newpixmapwithrect(&gc->dest, clip, 1); if (error) return error; fz_clearpixmap(gc->dest); return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, clip, gc->dest, nil, 0); } }
static void fz_drawclippath(void *user, fz_path *path, int evenodd, fz_matrix ctm) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrixexpansion(ctm); float flatness = 0.3f / expansion; fz_pixmap *mask, *dest; fz_bbox bbox; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } fz_resetgel(dev->gel, dev->scissor); fz_fillpath(dev->gel, path, ctm, flatness); fz_sortgel(dev->gel); bbox = fz_boundgel(dev->gel); bbox = fz_intersectbbox(bbox, dev->scissor); if (fz_isemptyrect(bbox) || fz_isrectgel(dev->gel)) { dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = nil; dev->stack[dev->top].dest = nil; dev->scissor = bbox; dev->top++; return; } mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(mask, 0); fz_clearpixmap(dest, 0); fz_scanconvert(dev->gel, dev->ael, evenodd, bbox, mask, nil); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; }
static void fz_drawclipstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matrix ctm) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrixexpansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; fz_pixmap *mask, *dest; fz_bbox bbox; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_resetgel(dev->gel, dev->scissor); if (stroke->dashlen > 0) fz_dashpath(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_strokepath(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sortgel(dev->gel); bbox = fz_boundgel(dev->gel); bbox = fz_intersectbbox(bbox, dev->scissor); mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(mask, 0); fz_clearpixmap(dest, 0); if (!fz_isemptyrect(bbox)) fz_scanconvert(dev->gel, dev->ael, 0, bbox, mask, nil); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; }
static void fz_drawstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrixexpansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; unsigned char colorbv[FZ_MAXCOLORS + 1]; float colorfv[FZ_MAXCOLORS]; fz_bbox bbox; int i; if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_resetgel(dev->gel, dev->scissor); if (stroke->dashlen > 0) fz_dashpath(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_strokepath(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sortgel(dev->gel); bbox = fz_boundgel(dev->gel); bbox = fz_intersectbbox(bbox, dev->scissor); if (fz_isemptyrect(bbox)) return; fz_convertcolor(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scanconvert(dev->gel, dev->ael, 0, bbox, dev->dest, colorbv); }
fz_error fz_renderftglyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm) { FT_Face face = font->ftface; FT_Matrix m; FT_Vector v; FT_Error fterr; int x, y; #if 0 /* We lost this feature in refactoring. * We can't access pdf_fontdesc metrics from fz_font. * The pdf_fontdesc metrics are character based (cid), * where the glyph being rendered is given by glyph (gid). */ if (font->ftsubstitute && font->wmode == 0) { fz_hmtx subw; int realw; float scale; fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72); if (fterr) return fz_warn("freetype setting character size: %s", ft_errorstring(fterr)); fterr = FT_Load_Glyph(font->ftface, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); if (fterr) return fz_throw("freetype failed to load glyph: %s", ft_errorstring(fterr)); realw = ((FT_Face)font->ftface)->glyph->advance.x; subw = fz_gethmtx(font, cid); // <-- this is the offender if (realw) scale = (float) subw.w / realw; else scale = 1.0; trm = fz_concat(fz_scale(scale, 1.0), trm); } #endif glyph->w = 0; glyph->h = 0; glyph->x = 0; glyph->y = 0; glyph->samples = nil; /* freetype mutilates complex glyphs if they are loaded * with FT_Set_Char_Size 1.0. it rounds the coordinates * before applying transformation. to get more precision in * freetype, we shift part of the scale in the matrix * into FT_Set_Char_Size instead */ m.xx = trm.a * 64; /* should be 65536 */ m.yx = trm.b * 64; m.xy = trm.c * 64; m.yy = trm.d * 64; v.x = trm.e * 64; v.y = trm.f * 64; fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ if (fterr) fz_warn("freetype setting character size: %s", ft_errorstring(fterr)); FT_Set_Transform(face, &m, &v); if (font->fthint) { /* Enable hinting, but keep the huge char size so that * it is hinted for a character. This will in effect nullify * the effect of grid fitting. This form of hinting should * only be used for DynaLab and similar tricky TrueType fonts, * so that we get the correct outline shape. */ #ifdef USE_HINTING /* If you really want grid fitting, enable this code. */ float scale = fz_matrixexpansion(trm); m.xx = trm.a * 65536 / scale; m.xy = trm.b * 65536 / scale; m.yx = trm.c * 65536 / scale; m.yy = trm.d * 65536 / scale; v.x = 0; v.y = 0; fterr = FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); if (fterr) fz_warn("freetype setting character size: %s", ft_errorstring(fterr)); FT_Set_Transform(face, &m, &v); #endif fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP); if (fterr) fz_warn("freetype load glyph (gid %d): %s", gid, ft_errorstring(fterr)); } else { fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); if (fterr) fz_warn("freetype load glyph (gid %d): %s", gid, ft_errorstring(fterr)); } fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if (fterr) fz_warn("freetype render glyph (gid %d): %s", gid, ft_errorstring(fterr)); glyph->w = face->glyph->bitmap.width; glyph->h = face->glyph->bitmap.rows; glyph->x = face->glyph->bitmap_left; glyph->y = face->glyph->bitmap_top - glyph->h; glyph->samples = face->glyph->bitmap.buffer; for (y = 0; y < glyph->h / 2; y++) { for (x = 0; x < glyph->w; x++) { unsigned char a = glyph->samples[y * glyph->w + x ]; unsigned char b = glyph->samples[(glyph->h - y - 1) * glyph->w + x]; glyph->samples[y * glyph->w + x ] = b; glyph->samples[(glyph->h - y - 1) * glyph->w + x] = a; } } return fz_okay; }
static fz_error * renderpath(fz_renderer *gc, fz_pathnode *path, fz_matrix ctm) { fz_error *error; float flatness; fz_irect gbox; fz_irect clip; float expansion = fz_matrixexpansion(ctm); flatness = 0.3 / expansion; if (flatness < 0.1) flatness = 0.1; fz_resetgel(gc->gel, gc->clip); if (path->paint == FZ_STROKE) { float lw = path->linewidth; /* Check for hairline */ if (lw * expansion < 0.1) { lw = 1.0f / expansion; } if (path->dash) error = fz_dashpath(gc->gel, path, ctm, flatness, lw); else error = fz_strokepath(gc->gel, path, ctm, flatness, lw); } else error = fz_fillpath(gc->gel, path, ctm, flatness); if (error) return error; fz_sortgel(gc->gel); gbox = fz_boundgel(gc->gel); clip = fz_intersectirects(gc->clip, gbox); if (fz_isemptyrect(clip)) return fz_okay; DEBUG("path %s;\n", path->paint == FZ_STROKE ? "stroke" : "fill"); if (gc->flag & FRGB) { DEBUG(" path rgb %d %d %d %d, %d %d %d\n", gc->argb[0], gc->argb[1], gc->argb[2], gc->argb[3], gc->argb[4], gc->argb[5], gc->argb[6]); return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, clip, gc->over, gc->argb, 1); } else if (gc->flag & FOVER) { return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, clip, gc->over, nil, 1); } else { error = fz_newpixmapwithrect(&gc->dest, clip, 1); if (error) return error; fz_clearpixmap(gc->dest); return fz_scanconvert(gc->gel, gc->ael, path->paint == FZ_EOFILL, clip, gc->dest, nil, 0); } }
static fz_error * ftrender(fz_glyph *glyph, fz_font *fzfont, int cid, fz_matrix trm) { pdf_font *font = (pdf_font*)fzfont; FT_Face face = font->ftface; FT_Matrix m; FT_Vector v; FT_Error fterr; float scale; int gid; int x, y; int hint = font->hint; gid = ftcidtogid(font, cid); if (font->substitute && fzfont->wmode == 0) { fz_hmtx subw; int realw; FT_Set_Char_Size(face, 1000, 1000, 72, 72); fterr = FT_Load_Glyph(font->ftface, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); if (fterr) return fz_throw("freetype failed to load glyph: %s", ft_errstr(fterr)); realw = ((FT_Face)font->ftface)->glyph->advance.x; subw = fz_gethmtx(fzfont, cid); if (realw) scale = (float) subw.w / realw; else scale = 1.0; trm = fz_concat(fz_scale(scale, 1.0), trm); } glyph->w = 0; glyph->h = 0; glyph->x = 0; glyph->y = 0; glyph->samples = nil; /* freetype mutilates complex glyphs if they are loaded * with FT_Set_Char_Size 1.0. it rounds the coordinates * before applying transformation. to get more precision in * freetype, we shift part of the scale in the matrix * into FT_Set_Char_Size instead */ #ifdef HINT hint = 1; #endif if (hint) { scale = fz_matrixexpansion(trm); m.xx = trm.a * 65536 / scale; m.yx = trm.b * 65536 / scale; m.xy = trm.c * 65536 / scale; m.yy = trm.d * 65536 / scale; v.x = 0; v.y = 0; FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); FT_Set_Transform(face, &m, &v); fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP); if (fterr) fz_warn("freetype load glyph: %s", ft_errstr(fterr)); } else { m.xx = trm.a * 64; /* should be 65536 */ m.yx = trm.b * 64; m.xy = trm.c * 64; m.yy = trm.d * 64; v.x = trm.e * 64; v.y = trm.f * 64; FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ FT_Set_Transform(face, &m, &v); fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); if (fterr) fz_warn("freetype load glyph: %s", ft_errstr(fterr)); } fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if (fterr) fz_warn("freetype render glyph: %s", ft_errstr(fterr)); glyph->w = face->glyph->bitmap.width; glyph->h = face->glyph->bitmap.rows; glyph->x = face->glyph->bitmap_left; glyph->y = face->glyph->bitmap_top - glyph->h; glyph->samples = face->glyph->bitmap.buffer; for (y = 0; y < glyph->h / 2; y++) { for (x = 0; x < glyph->w; x++) { unsigned char a = glyph->samples[y * glyph->w + x ]; unsigned char b = glyph->samples[(glyph->h - y - 1) * glyph->w + x]; glyph->samples[y * glyph->w + x ] = b; glyph->samples[(glyph->h - y - 1) * glyph->w + x] = a; } } return fz_okay; }
fz_pixmap * fz_renderftstrokedglyph(fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_strokestate *state) { FT_Face face = font->ftface; float expansion = fz_matrixexpansion(ctm); int linewidth = state->linewidth * expansion * 64 / 2; FT_Matrix m; FT_Vector v; FT_Error fterr; FT_Stroker stroker; FT_Glyph glyph; FT_BitmapGlyph bitmap; fz_pixmap *pix; int y; m.xx = trm.a * 64; /* should be 65536 */ m.yx = trm.b * 64; m.xy = trm.c * 64; m.yy = trm.d * 64; v.x = trm.e * 64; v.y = trm.f * 64; fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ if (fterr) { fz_warn("FT_Set_Char_Size: %s", ft_errorstring(fterr)); return nil; } FT_Set_Transform(face, &m, &v); fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); if (fterr) { fz_warn("FT_Load_Glyph(gid %d): %s", gid, ft_errorstring(fterr)); return nil; } fterr = FT_Stroker_New(fz_ftlib, &stroker); if (fterr) { fz_warn("FT_Stroker_New: %s", ft_errorstring(fterr)); return nil; } FT_Stroker_Set(stroker, linewidth, state->linecap, state->linejoin, state->miterlimit * 65536); fterr = FT_Get_Glyph(face->glyph, &glyph); if (fterr) { fz_warn("FT_Get_Glyph: %s", ft_errorstring(fterr)); FT_Stroker_Done(stroker); return nil; } fterr = FT_Glyph_Stroke(&glyph, stroker, 1); if (fterr) { fz_warn("FT_Glyph_Stroke: %s", ft_errorstring(fterr)); FT_Done_Glyph(glyph); FT_Stroker_Done(stroker); return nil; } fterr = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1); if (fterr) { fz_warn("FT_Glyph_To_Bitmap: %s", ft_errorstring(fterr)); FT_Done_Glyph(glyph); FT_Stroker_Done(stroker); return nil; } bitmap = (FT_BitmapGlyph)glyph; pix = fz_newpixmap(NULL, bitmap->left, bitmap->top - bitmap->bitmap.rows, bitmap->bitmap.width, bitmap->bitmap.rows); for (y = 0; y < pix->h; y++) { memcpy(pix->samples + y * pix->w, bitmap->bitmap.buffer + (pix->h - y - 1) * bitmap->bitmap.pitch, pix->w); } FT_Done_Glyph(glyph); FT_Stroker_Done(stroker); return pix; }
fz_pixmap * fz_renderftglyph(fz_font *font, int gid, fz_matrix trm) { FT_Face face = font->ftface; FT_Matrix m; FT_Vector v; FT_Error fterr; fz_pixmap *glyph; int y; /* Fudge the font matrix to stretch the glyph if we've substituted the font. */ if (font->ftsubstitute && gid < font->widthcount) { int subw; int realw; float scale; /* TODO: use FT_Get_Advance */ fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72); if (fterr) fz_warn("freetype setting character size: %s", ft_errorstring(fterr)); fterr = FT_Load_Glyph(font->ftface, gid, FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM); if (fterr) fz_warn("freetype failed to load glyph: %s", ft_errorstring(fterr)); realw = ((FT_Face)font->ftface)->glyph->metrics.horiAdvance; subw = font->widthtable[gid]; if (realw) scale = (float) subw / realw; else scale = 1; trm = fz_concat(fz_scale(scale, 1), trm); } /* Freetype mutilates complex glyphs if they are loaded with FT_Set_Char_Size 1.0. it rounds the coordinates before applying transformation. to get more precision in freetype, we shift part of the scale in the matrix into FT_Set_Char_Size instead */ m.xx = trm.a * 64; /* should be 65536 */ m.yx = trm.b * 64; m.xy = trm.c * 64; m.yy = trm.d * 64; v.x = trm.e * 64; v.y = trm.f * 64; fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */ if (fterr) fz_warn("freetype setting character size: %s", ft_errorstring(fterr)); FT_Set_Transform(face, &m, &v); if (font->fthint) { /* Enable hinting, but keep the huge char size so that it is hinted for a character. This will in effect nullify the effect of grid fitting. This form of hinting should only be used for DynaLab and similar tricky TrueType fonts, so that we get the correct outline shape. */ #ifdef GRIDFIT /* If you really want grid fitting, enable this code. */ float scale = fz_matrixexpansion(trm); m.xx = trm.a * 65536 / scale; m.xy = trm.b * 65536 / scale; m.yx = trm.c * 65536 / scale; m.yy = trm.d * 65536 / scale; v.x = 0; v.y = 0; fterr = FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72); if (fterr) fz_warn("freetype setting character size: %s", ft_errorstring(fterr)); FT_Set_Transform(face, &m, &v); #endif fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP); if (fterr) fz_warn("freetype load glyph (gid %d): %s", gid, ft_errorstring(fterr)); } else { fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING); if (fterr) { fz_warn("freetype load glyph (gid %d): %s", gid, ft_errorstring(fterr)); return nil; } } fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal); if (fterr) { fz_warn("freetype render glyph (gid %d): %s", gid, ft_errorstring(fterr)); return nil; } glyph = fz_newpixmap(NULL, face->glyph->bitmap_left, face->glyph->bitmap_top - face->glyph->bitmap.rows, face->glyph->bitmap.width, face->glyph->bitmap.rows); for (y = 0; y < glyph->h; y++) { memcpy(glyph->samples + y * glyph->w, face->glyph->bitmap.buffer + (glyph->h - y - 1) * face->glyph->bitmap.pitch, glyph->w); } return glyph; }