From 8d7b9a09a45ce20edd5ce3dad45f2b9af6884550 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 13 Jul 2010 23:11:32 +0200 Subject: Implement stroked text. --- fitz/dev_draw.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- fitz/fitz.h | 2 ++ fitz/res_font.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 203 insertions(+), 6 deletions(-) (limited to 'fitz') diff --git a/fitz/dev_draw.c b/fitz/dev_draw.c index e769f10a..369cdf06 100644 --- a/fitz/dev_draw.c +++ b/fitz/dev_draw.c @@ -245,7 +245,8 @@ fz_drawclipstrokepath(void *user, fz_path *path, fz_strokestate *stroke, fz_matr } static void -drawglyph(unsigned char *colorbv, fz_pixmap *dst, fz_pixmap *src, int xorig, int yorig, fz_bbox scissor) +drawglyph(unsigned char *colorbv, fz_pixmap *dst, fz_pixmap *src, + int xorig, int yorig, fz_bbox scissor) { unsigned char *dp, *sp; int w, h; @@ -269,8 +270,8 @@ drawglyph(unsigned char *colorbv, fz_pixmap *dst, fz_pixmap *src, int xorig, int if (y1 <= dy0 || y0 >= dy1) return; if (x0 < dx0) { sx0 += dx0 - x0; x0 = dx0; } if (y0 < dy0) { sy0 += dy0 - y0; y0 = dy0; } - if (x1 > dx1) { sx1 += dx1 - x1; x1 = dx1; } - if (y1 > dy1) { sy1 += dy1 - y1; y1 = dy1; } + if (x1 > dx1) { sx1 += dx1 - x1; } + if (y1 > dy1) { sy1 += dy1 - y1; } sp = src->samples + (sy0 * src->w + sx0); dp = dst->samples + ((y0 - dst->y) * dst->w + (x0 - dst->x)) * dst->n; @@ -348,8 +349,47 @@ static void fz_drawstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { - fz_warn("stroked text not implemented; filling instead"); - fz_drawfilltext(user, text, ctm, colorspace, color, alpha); + fz_drawdevice *dev = user; + unsigned char colorbv[FZ_MAXCOLORS + 1]; + float colorfv[FZ_MAXCOLORS]; + fz_matrix tm, trm; + fz_pixmap *glyph; + int i, x, y, gid; + + if (dev->model) + { + fz_convertcolor(colorspace, color, dev->model, colorfv); + for (i = 0; i < dev->model->n; i++) + colorbv[i] = colorfv[i] * 255; + colorbv[i] = alpha * 255; + } + + tm = text->trm; + + for (i = 0; i < text->len; i++) + { + gid = text->els[i].gid; + if (gid < 0) + continue; + + tm.e = text->els[i].x; + tm.f = text->els[i].y; + trm = fz_concat(tm, ctm); + x = floorf(trm.e); + y = floorf(trm.f); + trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); + trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); + + glyph = fz_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke); + if (glyph) + { + if (dev->model) + drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor); + else + drawglyph(nil, dev->dest, glyph, x, y, dev->scissor); + fz_droppixmap(glyph); + } + } } static void @@ -435,7 +475,62 @@ fz_drawcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate) static void fz_drawclipstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix ctm) { - fz_drawcliptext(user, text, ctm, 0); + fz_drawdevice *dev = user; + fz_bbox bbox; + fz_pixmap *mask, *dest; + fz_matrix tm, trm; + fz_pixmap *glyph; + int i, x, y, gid; + + if (dev->cliptop == MAXCLIP) + { + fz_warn("assert: too many clip masks on stack"); + return; + } + + /* make the mask the exact size needed */ + bbox = fz_roundrect(fz_boundtext(text, ctm)); + bbox = fz_intersectbbox(bbox, dev->scissor); + + mask = fz_newpixmapwithrect(nil, bbox); + dest = fz_newpixmapwithrect(dev->model, bbox); + + memset(mask->samples, 0, mask->w * mask->h * mask->n); + memset(dest->samples, 0, dest->w * dest->h * dest->n); + + dev->clipstack[dev->cliptop].scissor = dev->scissor; + dev->clipstack[dev->cliptop].mask = mask; + dev->clipstack[dev->cliptop].dest = dev->dest; + dev->scissor = bbox; + dev->dest = dest; + dev->cliptop++; + + if (!fz_isemptyrect(bbox)) + { + tm = text->trm; + + for (i = 0; i < text->len; i++) + { + gid = text->els[i].gid; + if (gid < 0) + continue; + + tm.e = text->els[i].x; + tm.f = text->els[i].y; + trm = fz_concat(tm, ctm); + x = floorf(trm.e); + y = floorf(trm.f); + trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); + trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); + + glyph = fz_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke); + if (glyph) + { + drawglyph(NULL, mask, glyph, x, y, bbox); + fz_droppixmap(glyph); + } + } + } } static void diff --git a/fitz/fitz.h b/fitz/fitz.h index 9dbbafdc..5adf331a 100644 --- a/fitz/fitz.h +++ b/fitz/fitz.h @@ -919,7 +919,9 @@ typedef struct fz_glyphcache_s fz_glyphcache; fz_glyphcache * fz_newglyphcache(void); fz_pixmap * fz_renderftglyph(fz_font *font, int cid, fz_matrix trm); fz_pixmap * fz_rendert3glyph(fz_font *font, int cid, fz_matrix trm); +fz_pixmap * fz_renderftstrokedglyph(fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_strokestate *state); fz_pixmap * fz_renderglyph(fz_glyphcache*, fz_font*, int, fz_matrix); +fz_pixmap * fz_renderstrokedglyph(fz_glyphcache*, fz_font*, int, fz_matrix, fz_matrix, fz_strokestate *stroke); void fz_freeglyphcache(fz_glyphcache *); /* diff --git a/fitz/res_font.c b/fitz/res_font.c index 419acc5c..aca58c0b 100644 --- a/fitz/res_font.c +++ b/fitz/res_font.c @@ -2,6 +2,7 @@ #include #include FT_FREETYPE_H +#include FT_STROKER_H static void fz_finalizefreetype(void); @@ -298,12 +299,18 @@ fz_renderftglyph(fz_font *font, int gid, fz_matrix trm) { 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, @@ -321,6 +328,99 @@ fz_renderftglyph(fz_font *font, int gid, fz_matrix trm) return glyph; } +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; +} + /* * Type 3 fonts... */ -- cgit v1.2.3