summaryrefslogtreecommitdiff
path: root/fitz
diff options
context:
space:
mode:
authorTor Andersson <tor@ghostscript.com>2010-07-13 23:11:32 +0200
committerTor Andersson <tor@ghostscript.com>2010-07-13 23:11:32 +0200
commit8d7b9a09a45ce20edd5ce3dad45f2b9af6884550 (patch)
tree3f199962bda7c445d07c0db5010bc73f11cebb95 /fitz
parent84b10eb85392bfa907c395ceb58d776c9004ae14 (diff)
downloadmupdf-8d7b9a09a45ce20edd5ce3dad45f2b9af6884550.tar.xz
Implement stroked text.
Diffstat (limited to 'fitz')
-rw-r--r--fitz/dev_draw.c107
-rw-r--r--fitz/fitz.h2
-rw-r--r--fitz/res_font.c100
3 files changed, 203 insertions, 6 deletions
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 <ft2build.h>
#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...
*/