diff options
Diffstat (limited to 'source/fitz')
-rw-r--r-- | source/fitz/draw-device.c | 338 | ||||
-rw-r--r-- | source/fitz/stext-device.c | 76 | ||||
-rw-r--r-- | source/fitz/svg-device.c | 214 | ||||
-rw-r--r-- | source/fitz/text.c | 165 | ||||
-rw-r--r-- | source/fitz/trace-device.c | 76 |
5 files changed, 477 insertions, 392 deletions
diff --git a/source/fitz/draw-device.c b/source/fitz/draw-device.c index b109e6b7..ab6ebbe7 100644 --- a/source/fitz/draw-device.c +++ b/source/fitz/draw-device.c @@ -562,15 +562,13 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, fz_text *text, const fz_matr fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = (fz_draw_device*)devp; - + fz_draw_state *state = &dev->stack[dev->top]; + fz_colorspace *model = state->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; unsigned char shapebv; float colorfv[FZ_MAX_COLORS]; - fz_matrix tm, trm; - fz_glyph *glyph; - int i, gid; - fz_draw_state *state = &dev->stack[dev->top]; - fz_colorspace *model = state->dest->colorspace; + fz_text_span *span; + int i; if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(ctx, dev); @@ -581,50 +579,57 @@ fz_draw_fill_text(fz_context *ctx, fz_device *devp, fz_text *text, const fz_matr colorbv[i] = alpha * 255; shapebv = 255; - tm = text->trm; - - for (i = 0; i < text->len; i++) + for (span = text->head; span; span = span->next) { - gid = text->items[i].gid; - if (gid < 0) - continue; + fz_matrix tm, trm; + fz_glyph *glyph; + int gid; - tm.e = text->items[i].x; - tm.f = text->items[i].y; - fz_concat(&trm, &tm, ctm); + tm = span->trm; - glyph = fz_render_glyph(ctx, text->font, gid, &trm, model, &state->scissor); - if (glyph) - { - fz_pixmap *pixmap = glyph->pixmap; - int x = floorf(trm.e); - int y = floorf(trm.f); - if (pixmap == NULL || pixmap->n == 1) - { - draw_glyph(colorbv, state->dest, glyph, x, y, &state->scissor); - if (state->shape) - draw_glyph(&shapebv, state->shape, glyph, x, y, &state->scissor); - } - else - { - fz_matrix mat; - mat.a = pixmap->w; mat.b = mat.c = 0; mat.d = pixmap->h; - mat.e = x + pixmap->x; mat.f = y + pixmap->y; - fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &mat, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED); - } - fz_drop_glyph(ctx, glyph); - } - else + for (i = 0; i < span->len; i++) { - fz_path *path = fz_outline_glyph(ctx, text->font, gid, &tm); - if (path) + gid = span->items[i].gid; + if (gid < 0) + continue; + + tm.e = span->items[i].x; + tm.f = span->items[i].y; + fz_concat(&trm, &tm, ctm); + + glyph = fz_render_glyph(ctx, span->font, gid, &trm, model, &state->scissor); + if (glyph) { - fz_draw_fill_path(ctx, devp, path, 0, ctm, colorspace, color, alpha); - fz_drop_path(ctx, path); + fz_pixmap *pixmap = glyph->pixmap; + int x = floorf(trm.e); + int y = floorf(trm.f); + if (pixmap == NULL || pixmap->n == 1) + { + draw_glyph(colorbv, state->dest, glyph, x, y, &state->scissor); + if (state->shape) + draw_glyph(&shapebv, state->shape, glyph, x, y, &state->scissor); + } + else + { + fz_matrix mat; + mat.a = pixmap->w; mat.b = mat.c = 0; mat.d = pixmap->h; + mat.e = x + pixmap->x; mat.f = y + pixmap->y; + fz_paint_image(state->dest, &state->scissor, state->shape, pixmap, &mat, alpha * 255, !(devp->hints & FZ_DONT_INTERPOLATE_IMAGES), devp->flags & FZ_DEVFLAG_GRIDFIT_AS_TILED); + } + fz_drop_glyph(ctx, glyph); } else { - fz_warn(ctx, "cannot render glyph"); + fz_path *path = fz_outline_glyph(ctx, span->font, gid, &tm); + if (path) + { + fz_draw_fill_path(ctx, devp, path, 0, ctm, colorspace, color, alpha); + fz_drop_path(ctx, path); + } + else + { + fz_warn(ctx, "cannot render glyph"); + } } } } @@ -639,14 +644,12 @@ fz_draw_stroke_text(fz_context *ctx, fz_device *devp, fz_text *text, fz_stroke_s float *color, float alpha) { fz_draw_device *dev = (fz_draw_device*)devp; - - unsigned char colorbv[FZ_MAX_COLORS + 1]; - float colorfv[FZ_MAX_COLORS]; - fz_matrix tm, trm; - fz_glyph *glyph; - int i, gid; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; + unsigned char colorbv[FZ_MAX_COLORS + 1]; + float colorfv[FZ_MAX_COLORS]; + fz_text_span *span; + int i; if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(ctx, dev); @@ -656,39 +659,46 @@ fz_draw_stroke_text(fz_context *ctx, fz_device *devp, fz_text *text, fz_stroke_s colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; - tm = text->trm; - - for (i = 0; i < text->len; i++) + for (span = text->head; span; span = span->next) { - gid = text->items[i].gid; - if (gid < 0) - continue; + fz_matrix tm, trm; + fz_glyph *glyph; + int gid; - tm.e = text->items[i].x; - tm.f = text->items[i].y; - fz_concat(&trm, &tm, ctm); + tm = span->trm; - glyph = fz_render_stroked_glyph(ctx, text->font, gid, &trm, ctm, stroke, &state->scissor); - if (glyph) - { - int x = (int)trm.e; - int y = (int)trm.f; - draw_glyph(colorbv, state->dest, glyph, x, y, &state->scissor); - if (state->shape) - draw_glyph(colorbv, state->shape, glyph, x, y, &state->scissor); - fz_drop_glyph(ctx, glyph); - } - else + for (i = 0; i < span->len; i++) { - fz_path *path = fz_outline_glyph(ctx, text->font, gid, &tm); - if (path) + gid = span->items[i].gid; + if (gid < 0) + continue; + + tm.e = span->items[i].x; + tm.f = span->items[i].y; + fz_concat(&trm, &tm, ctm); + + glyph = fz_render_stroked_glyph(ctx, span->font, gid, &trm, ctm, stroke, &state->scissor); + if (glyph) { - fz_draw_stroke_path(ctx, devp, path, stroke, ctm, colorspace, color, alpha); - fz_drop_path(ctx, path); + int x = (int)trm.e; + int y = (int)trm.f; + draw_glyph(colorbv, state->dest, glyph, x, y, &state->scissor); + if (state->shape) + draw_glyph(colorbv, state->shape, glyph, x, y, &state->scissor); + fz_drop_glyph(ctx, glyph); } else { - fz_warn(ctx, "cannot render glyph"); + fz_path *path = fz_outline_glyph(ctx, span->font, gid, &tm); + if (path) + { + fz_draw_stroke_path(ctx, devp, path, stroke, ctm, colorspace, color, alpha); + fz_drop_path(ctx, path); + } + else + { + fz_warn(ctx, "cannot render glyph"); + } } } } @@ -708,6 +718,7 @@ fz_draw_clip_text(fz_context *ctx, fz_device *devp, fz_text *text, const fz_matr int i, gid; fz_draw_state *state; fz_colorspace *model; + fz_text_span *span; /* If accumulate == 0 then this text object is guaranteed complete */ /* If accumulate == 1 then this text object is the first (or only) in a sequence */ @@ -765,58 +776,61 @@ fz_draw_clip_text(fz_context *ctx, fz_device *devp, fz_text *text, const fz_matr if (!fz_is_empty_irect(&bbox) && mask) { - tm = text->trm; - - for (i = 0; i < text->len; i++) + for (span = text->head; span; span = span->next) { - gid = text->items[i].gid; - if (gid < 0) - continue; + tm = span->trm; - tm.e = text->items[i].x; - tm.f = text->items[i].y; - fz_concat(&trm, &tm, ctm); - - glyph = fz_render_glyph(ctx, text->font, gid, &trm, model, &state->scissor); - if (glyph) + for (i = 0; i < span->len; i++) { - int x = (int)trm.e; - int y = (int)trm.f; - draw_glyph(NULL, mask, glyph, x, y, &bbox); - if (state[1].shape) - draw_glyph(NULL, state[1].shape, glyph, x, y, &bbox); - fz_drop_glyph(ctx, glyph); - } - else - { - fz_path *path = fz_outline_glyph(ctx, text->font, gid, &tm); - if (path) - { - fz_pixmap *old_dest; - float white = 1; + gid = span->items[i].gid; + if (gid < 0) + continue; - old_dest = state[1].dest; - state[1].dest = state[1].mask; - state[1].mask = NULL; - fz_try(ctx) - { - fz_draw_fill_path(ctx, devp, path, 0, ctm, fz_device_gray(ctx), &white, 1); - } - fz_always(ctx) + tm.e = span->items[i].x; + tm.f = span->items[i].y; + fz_concat(&trm, &tm, ctm); + + glyph = fz_render_glyph(ctx, span->font, gid, &trm, model, &state->scissor); + if (glyph) + { + int x = (int)trm.e; + int y = (int)trm.f; + draw_glyph(NULL, mask, glyph, x, y, &bbox); + if (state[1].shape) + draw_glyph(NULL, state[1].shape, glyph, x, y, &bbox); + fz_drop_glyph(ctx, glyph); + } + else + { + fz_path *path = fz_outline_glyph(ctx, span->font, gid, &tm); + if (path) { - state[1].mask = state[1].dest; - state[1].dest = old_dest; - fz_drop_path(ctx, path); + fz_pixmap *old_dest; + float white = 1; + + old_dest = state[1].dest; + state[1].dest = state[1].mask; + state[1].mask = NULL; + fz_try(ctx) + { + fz_draw_fill_path(ctx, devp, path, 0, ctm, fz_device_gray(ctx), &white, 1); + } + fz_always(ctx) + { + state[1].mask = state[1].dest; + state[1].dest = old_dest; + fz_drop_path(ctx, path); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } } - fz_catch(ctx) + else { - fz_rethrow(ctx); + fz_warn(ctx, "cannot render glyph for clipping"); } } - else - { - fz_warn(ctx, "cannot render glyph for clipping"); - } } } } @@ -840,6 +854,7 @@ fz_draw_clip_stroke_text(fz_context *ctx, fz_device *devp, fz_text *text, fz_str int i, gid; fz_draw_state *state = push_stack(ctx, dev); fz_colorspace *model = state->dest->colorspace; + fz_text_span *span; fz_rect rect; STACK_PUSHED("clip stroke text"); @@ -869,59 +884,62 @@ fz_draw_clip_stroke_text(fz_context *ctx, fz_device *devp, fz_text *text, fz_str if (!fz_is_empty_irect(&bbox)) { - tm = text->trm; - - for (i = 0; i < text->len; i++) + for (span = text->head; span; span = span->next) { - gid = text->items[i].gid; - if (gid < 0) - continue; - - tm.e = text->items[i].x; - tm.f = text->items[i].y; - fz_concat(&trm, &tm, ctm); + tm = span->trm; - glyph = fz_render_stroked_glyph(ctx, text->font, gid, &trm, ctm, stroke, &state->scissor); - if (glyph) - { - int x = (int)trm.e; - int y = (int)trm.f; - draw_glyph(NULL, mask, glyph, x, y, &bbox); - if (shape) - draw_glyph(NULL, shape, glyph, x, y, &bbox); - fz_drop_glyph(ctx, glyph); - } - else + for (i = 0; i < span->len; i++) { - fz_path *path = fz_outline_glyph(ctx, text->font, gid, &tm); - if (path) + gid = span->items[i].gid; + if (gid < 0) + continue; + + tm.e = span->items[i].x; + tm.f = span->items[i].y; + fz_concat(&trm, &tm, ctm); + + glyph = fz_render_stroked_glyph(ctx, span->font, gid, &trm, ctm, stroke, &state->scissor); + if (glyph) { - fz_pixmap *old_dest; - float white = 1; - - state = &dev->stack[dev->top]; - old_dest = state[0].dest; - state[0].dest = state[0].mask; - state[0].mask = NULL; - fz_try(ctx) - { - fz_draw_stroke_path(ctx, devp, path, stroke, ctm, fz_device_gray(ctx), &white, 1); - } - fz_always(ctx) + int x = (int)trm.e; + int y = (int)trm.f; + draw_glyph(NULL, mask, glyph, x, y, &bbox); + if (shape) + draw_glyph(NULL, shape, glyph, x, y, &bbox); + fz_drop_glyph(ctx, glyph); + } + else + { + fz_path *path = fz_outline_glyph(ctx, span->font, gid, &tm); + if (path) { - state[0].mask = state[0].dest; - state[0].dest = old_dest; - fz_drop_path(ctx, path); + fz_pixmap *old_dest; + float white = 1; + + state = &dev->stack[dev->top]; + old_dest = state[0].dest; + state[0].dest = state[0].mask; + state[0].mask = NULL; + fz_try(ctx) + { + fz_draw_stroke_path(ctx, devp, path, stroke, ctm, fz_device_gray(ctx), &white, 1); + } + fz_always(ctx) + { + state[0].mask = state[0].dest; + state[0].dest = old_dest; + fz_drop_path(ctx, path); + } + fz_catch(ctx) + { + fz_rethrow(ctx); + } } - fz_catch(ctx) + else { - fz_rethrow(ctx); + fz_warn(ctx, "cannot render glyph for stroked clipping"); } } - else - { - fz_warn(ctx, "cannot render glyph for stroked clipping"); - } } } } diff --git a/source/fitz/stext-device.c b/source/fitz/stext-device.c index 4e14b298..060311d3 100644 --- a/source/fitz/stext-device.c +++ b/source/fitz/stext-device.c @@ -437,15 +437,15 @@ fz_lookup_stext_style_imp(fz_context *ctx, fz_stext_sheet *sheet, } static fz_stext_style * -fz_lookup_stext_style(fz_context *ctx, fz_stext_sheet *sheet, fz_text *text, const fz_matrix *ctm, +fz_lookup_stext_style(fz_context *ctx, fz_stext_sheet *sheet, fz_text_span *span, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha, fz_stroke_state *stroke) { float size = 1.0f; - fz_font *font = text ? text->font : NULL; - int wmode = text ? text->wmode : 0; - if (ctm && text) + fz_font *font = span ? span->font : NULL; + int wmode = span ? span->wmode : 0; + if (ctm && span) { - fz_matrix tm = text->trm; + fz_matrix tm = span->trm; fz_matrix trm; tm.e = 0; tm.f = 0; @@ -744,11 +744,11 @@ fz_add_stext_char(fz_context *ctx, fz_stext_device *dev, fz_stext_style *style, } static void -fz_stext_extract(fz_context *ctx, fz_stext_device *dev, fz_text *text, const fz_matrix *ctm, fz_stext_style *style) +fz_stext_extract(fz_context *ctx, fz_stext_device *dev, fz_text_span *span, const fz_matrix *ctm, fz_stext_style *style) { - fz_font *font = text->font; + fz_font *font = span->font; FT_Face face = font->ft_face; - fz_matrix tm = text->trm; + fz_matrix tm = span->trm; fz_matrix trm; float adv; float ascender = 1; @@ -756,7 +756,7 @@ fz_stext_extract(fz_context *ctx, fz_stext_device *dev, fz_text *text, const fz_ int multi; int i, j, err; - if (text->len == 0) + if (span->len == 0) return; if (dev->spans == NULL) @@ -792,36 +792,36 @@ fz_stext_extract(fz_context *ctx, fz_stext_device *dev, fz_text *text, const fz_ tm.f = 0; fz_concat(&trm, &tm, ctm); - for (i = 0; i < text->len; i++) + for (i = 0; i < span->len; i++) { /* Calculate new pen location and delta */ - tm.e = text->items[i].x; - tm.f = text->items[i].y; + tm.e = span->items[i].x; + tm.f = span->items[i].y; fz_concat(&trm, &tm, ctm); /* Calculate bounding box and new pen position based on font metrics */ - adv = fz_advance_glyph(ctx, font, text->items[i].gid); + adv = fz_advance_glyph(ctx, font, span->items[i].gid); /* Check for one glyph to many char mapping */ - for (j = i + 1; j < text->len; j++) - if (text->items[j].gid >= 0) + for (j = i + 1; j < span->len; j++) + if (span->items[j].gid >= 0) break; multi = j - i; if (multi == 1) { - fz_add_stext_char(ctx, dev, style, text->items[i].ucs, &trm, adv, text->wmode); + fz_add_stext_char(ctx, dev, style, span->items[i].ucs, &trm, adv, span->wmode); } else { for (j = 0; j < multi; j++) { - fz_add_stext_char(ctx, dev, style, text->items[i + j].ucs, &trm, adv/multi, text->wmode); + fz_add_stext_char(ctx, dev, style, span->items[i + j].ucs, &trm, adv/multi, span->wmode); } i += j - 1; } - dev->lastchar = text->items[i].ucs; + dev->lastchar = span->items[i].ucs; } } @@ -831,8 +831,12 @@ fz_stext_fill_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matr { fz_stext_device *tdev = (fz_stext_device*)dev; fz_stext_style *style; - style = fz_lookup_stext_style(ctx, tdev->sheet, text, ctm, colorspace, color, alpha, NULL); - fz_stext_extract(ctx, tdev, text, ctm, style); + fz_text_span *span; + for (span = text->head; span; span = span->next) + { + style = fz_lookup_stext_style(ctx, tdev->sheet, span, ctm, colorspace, color, alpha, NULL); + fz_stext_extract(ctx, tdev, span, ctm, style); + } } static void @@ -841,8 +845,12 @@ fz_stext_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_s { fz_stext_device *tdev = (fz_stext_device*)dev; fz_stext_style *style; - style = fz_lookup_stext_style(ctx, tdev->sheet, text, ctm, colorspace, color, alpha, stroke); - fz_stext_extract(ctx, tdev, text, ctm, style); + fz_text_span *span; + for (span = text->head; span; span = span->next) + { + style = fz_lookup_stext_style(ctx, tdev->sheet, span, ctm, colorspace, color, alpha, stroke); + fz_stext_extract(ctx, tdev, span, ctm, style); + } } static void @@ -850,8 +858,12 @@ fz_stext_clip_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matr { fz_stext_device *tdev = (fz_stext_device*)dev; fz_stext_style *style; - style = fz_lookup_stext_style(ctx, tdev->sheet, text, ctm, NULL, NULL, 0, NULL); - fz_stext_extract(ctx, tdev, text, ctm, style); + fz_text_span *span; + for (span = text->head; span; span = span->next) + { + style = fz_lookup_stext_style(ctx, tdev->sheet, span, ctm, NULL, NULL, 0, NULL); + fz_stext_extract(ctx, tdev, span, ctm, style); + } } static void @@ -859,8 +871,12 @@ fz_stext_clip_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_str { fz_stext_device *tdev = (fz_stext_device*)dev; fz_stext_style *style; - style = fz_lookup_stext_style(ctx, tdev->sheet, text, ctm, NULL, NULL, 0, stroke); - fz_stext_extract(ctx, tdev, text, ctm, style); + fz_text_span *span; + for (span = text->head; span; span = span->next) + { + style = fz_lookup_stext_style(ctx, tdev->sheet, span, ctm, NULL, NULL, 0, stroke); + fz_stext_extract(ctx, tdev, span, ctm, style); + } } static void @@ -868,8 +884,12 @@ fz_stext_ignore_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_ma { fz_stext_device *tdev = (fz_stext_device*)dev; fz_stext_style *style; - style = fz_lookup_stext_style(ctx, tdev->sheet, text, ctm, NULL, NULL, 0, NULL); - fz_stext_extract(ctx, tdev, text, ctm, style); + fz_text_span *span; + for (span = text->head; span; span = span->next) + { + style = fz_lookup_stext_style(ctx, tdev->sheet, span, ctm, NULL, NULL, 0, NULL); + fz_stext_extract(ctx, tdev, span, ctm, style); + } } static void diff --git a/source/fitz/svg-device.c b/source/fitz/svg-device.c index 4461f79e..a2cc5ed1 100644 --- a/source/fitz/svg-device.c +++ b/source/fitz/svg-device.c @@ -238,82 +238,86 @@ svg_dev_text(fz_context *ctx, svg_device *sdev, const fz_matrix *ctm, fz_text *t fz_matrix local_trm; float size; int start, is_wspace, was_wspace; + fz_text_span *span; - /* Rely on the fact that trm.{e,f} == 0 */ - size = fz_matrix_expansion(&text->trm); - local_trm.a = text->trm.a / size; - local_trm.b = text->trm.b / size; - local_trm.c = -text->trm.c / size; - local_trm.d = -text->trm.d / size; - local_trm.e = 0; - local_trm.f = 0; - fz_invert_matrix(&inverse, &local_trm); - fz_concat(&local_trm, &local_trm, ctm); + for (span = text->head; text; span = span->next) + { + /* Rely on the fact that trm.{e,f} == 0 */ + size = fz_matrix_expansion(&span->trm); + local_trm.a = span->trm.a / size; + local_trm.b = span->trm.b / size; + local_trm.c = -span->trm.c / size; + local_trm.d = -span->trm.d / size; + local_trm.e = 0; + local_trm.f = 0; + fz_invert_matrix(&inverse, &local_trm); + fz_concat(&local_trm, &local_trm, ctm); - fz_printf(ctx, out, " transform=\"matrix(%g,%g,%g,%g,%g,%g)\"", - local_trm.a, local_trm.b, local_trm.c, local_trm.d, local_trm.e, local_trm.f); - fz_printf(ctx, out, " font-size=\"%g\"", size); - fz_printf(ctx, out, " font-family=\"%s\"", text->font->name); + fz_printf(ctx, out, " transform=\"matrix(%g,%g,%g,%g,%g,%g)\"", + local_trm.a, local_trm.b, local_trm.c, local_trm.d, local_trm.e, local_trm.f); + fz_printf(ctx, out, " font-size=\"%g\"", size); + fz_printf(ctx, out, " font-family=\"%s\"", span->font->name); - /* Leading (and repeated) whitespace presents a problem for SVG - * text, so elide it here. */ - for (start=0; start < text->len; start++) - { - fz_text_item *it = &text->items[start]; - if (!is_xml_wspace(it->ucs)) - break; - } + /* Leading (and repeated) whitespace presents a problem for SVG + * text, so elide it here. */ + for (start=0; start < span->len; start++) + { + fz_text_item *it = &span->items[start]; + if (!is_xml_wspace(it->ucs)) + break; + } - fz_printf(ctx, out, " x="); - was_wspace = 0; - for (i=start; i < text->len; i++) - { - fz_text_item *it = &text->items[i]; - fz_point p; - is_wspace = is_xml_wspace(it->ucs); - if (is_wspace && was_wspace) - continue; - was_wspace = is_wspace; - p.x = it->x; - p.y = it->y; - fz_transform_point(&p, &inverse); - fz_printf(ctx, out, "%c%g", i == start ? '\"' : ' ', p.x); - } - fz_printf(ctx, out, "\" y="); - was_wspace = 0; - for (i=start; i < text->len; i++) - { - fz_text_item *it = &text->items[i]; - fz_point p; - is_wspace = is_xml_wspace(it->ucs); - if (is_wspace && was_wspace) - continue; - was_wspace = is_wspace; - p.x = it->x; - p.y = it->y; - fz_transform_point(&p, &inverse); - fz_printf(ctx, out, "%c%g", i == start ? '\"' : ' ', p.y); - } - fz_printf(ctx, out, "\">\n"); - was_wspace = 0; - for (i=start; i < text->len; i++) - { - fz_text_item *it = &text->items[i]; - int c = it->ucs; - is_wspace = is_xml_wspace(c); - if (is_wspace && was_wspace) - continue; - was_wspace = is_wspace; - if (c >= 32 && c <= 127 && c != '<' && c != '&') - fz_printf(ctx, out, "%c", c); - else - fz_printf(ctx, out, "&#x%04x;", c); + fz_printf(ctx, out, " x="); + was_wspace = 0; + for (i=start; i < span->len; i++) + { + fz_text_item *it = &span->items[i]; + fz_point p; + is_wspace = is_xml_wspace(it->ucs); + if (is_wspace && was_wspace) + continue; + was_wspace = is_wspace; + p.x = it->x; + p.y = it->y; + fz_transform_point(&p, &inverse); + fz_printf(ctx, out, "%c%g", i == start ? '\"' : ' ', p.x); + } + fz_printf(ctx, out, "\" y="); + was_wspace = 0; + for (i=start; i < span->len; i++) + { + fz_text_item *it = &span->items[i]; + fz_point p; + is_wspace = is_xml_wspace(it->ucs); + if (is_wspace && was_wspace) + continue; + was_wspace = is_wspace; + p.x = it->x; + p.y = it->y; + fz_transform_point(&p, &inverse); + fz_printf(ctx, out, "%c%g", i == start ? '\"' : ' ', p.y); + } + fz_printf(ctx, out, "\">\n"); + was_wspace = 0; + for (i=start; i < span->len; i++) + { + fz_text_item *it = &span->items[i]; + int c = it->ucs; + is_wspace = is_xml_wspace(c); + if (is_wspace && was_wspace) + continue; + was_wspace = is_wspace; + if (c >= 32 && c <= 127 && c != '<' && c != '&') + fz_printf(ctx, out, "%c", c); + else + fz_printf(ctx, out, "&#x%04x;", c); + } + fz_printf(ctx, out, "\n</text>\n"); } - fz_printf(ctx, out, "\n</text>\n"); } static font * -svg_dev_text_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm) +svg_dev_text_span_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text_span *span, const fz_matrix *ctm) { svg_device *sdev = (svg_device*)dev; fz_output *out = sdev->out; @@ -323,7 +327,7 @@ svg_dev_text_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text *text, const for (font_idx = 0; font_idx < sdev->num_fonts; font_idx++) { - if (sdev->fonts[font_idx].font == text->font) + if (sdev->fonts[font_idx].font == span->font) break; } if (font_idx == sdev->num_fonts) @@ -339,14 +343,14 @@ svg_dev_text_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text *text, const sdev->max_fonts = newmax; } sdev->fonts[font_idx].id = sdev->id++; - sdev->fonts[font_idx].font = fz_keep_font(ctx, text->font); + sdev->fonts[font_idx].font = fz_keep_font(ctx, span->font); sdev->num_fonts++; } fnt = &sdev->fonts[font_idx]; - for (i=0; i < text->len; i++) + for (i=0; i < span->len; i++) { - fz_text_item *it = &text->items[i]; + fz_text_item *it = &span->items[i]; int gid = it->gid; if (gid < 0) @@ -367,7 +371,7 @@ svg_dev_text_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text *text, const /* Need to send this one */ fz_rect rect; fz_path *path; - path = fz_outline_glyph(ctx, text->font, gid, &fz_identity); + path = fz_outline_glyph(ctx, span->font, gid, &fz_identity); if (path) { fz_bound_path(ctx, path, NULL, &fz_identity, &rect); @@ -382,12 +386,12 @@ svg_dev_text_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text *text, const } else { - fz_bound_glyph(ctx, text->font, gid, &fz_identity, &rect); + fz_bound_glyph(ctx, span->font, gid, &fz_identity, &rect); shift.e = -rect.x0; shift.f = -rect.y0; out = start_def(ctx, sdev); fz_printf(ctx, out, "<symbol id=\"font_%x_%x\">", fnt->id, gid); - fz_run_t3_glyph(ctx, text->font, gid, &shift, dev); + fz_run_t3_glyph(ctx, span->font, gid, &shift, dev); } fz_printf(ctx, out, "</symbol>"); out = end_def(ctx, sdev); @@ -399,7 +403,7 @@ svg_dev_text_as_paths_defs(fz_context *ctx, fz_device *dev, fz_text *text, const } static void -svg_dev_text_as_paths_fill(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm, +svg_dev_text_span_as_paths_fill(fz_context *ctx, fz_device *dev, fz_text_span *span, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha, font *fnt) { svg_device *sdev = (svg_device*)dev; @@ -410,16 +414,16 @@ svg_dev_text_as_paths_fill(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix shift = { 1, 0, 0, 1, 0, 0}; /* Rely on the fact that trm.{e,f} == 0 */ - local_trm.a = text->trm.a; - local_trm.b = text->trm.b; - local_trm.c = text->trm.c; - local_trm.d = text->trm.d; + local_trm.a = span->trm.a; + local_trm.b = span->trm.b; + local_trm.c = span->trm.c; + local_trm.d = span->trm.d; local_trm.e = 0; local_trm.f = 0; - for (i=0; i < text->len; i++) + for (i=0; i < span->len; i++) { - fz_text_item *it = &text->items[i]; + fz_text_item *it = &span->items[i]; int gid = it->gid; if (gid < 0) @@ -439,7 +443,7 @@ svg_dev_text_as_paths_fill(fz_context *ctx, fz_device *dev, fz_text *text, const } static void -svg_dev_text_as_paths_stroke(fz_context *ctx, fz_device *dev, fz_text *text, +svg_dev_text_span_as_paths_stroke(fz_context *ctx, fz_device *dev, fz_text_span *span, fz_stroke_state *stroke, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha, font *fnt) { @@ -451,16 +455,16 @@ svg_dev_text_as_paths_stroke(fz_context *ctx, fz_device *dev, fz_text *text, fz_matrix shift = { 1, 0, 0, 1, 0, 0}; /* Rely on the fact that trm.{e,f} == 0 */ - local_trm.a = text->trm.a; - local_trm.b = text->trm.b; - local_trm.c = text->trm.c; - local_trm.d = text->trm.d; + local_trm.a = span->trm.a; + local_trm.b = span->trm.b; + local_trm.c = span->trm.c; + local_trm.d = span->trm.d; local_trm.e = 0; local_trm.f = 0; - for (i=0; i < text->len; i++) + for (i=0; i < span->len; i++) { - fz_text_item *it = &text->items[i]; + fz_text_item *it = &span->items[i]; int gid = it->gid; if (gid < 0) @@ -566,12 +570,16 @@ svg_dev_fill_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matri fz_output *out = sdev->out; font *fnt; + fz_text_span *span; fz_printf(ctx, out, "<text"); svg_dev_fill_color(ctx, sdev, colorspace, color, 0.0f); svg_dev_text(ctx, sdev, ctm, text); - fnt = svg_dev_text_as_paths_defs(ctx, dev, text, ctm); - svg_dev_text_as_paths_fill(ctx, dev, text, ctm, colorspace, color, alpha, fnt); + for (span = text->head; span; span = span->next) + { + fnt = svg_dev_text_span_as_paths_defs(ctx, dev, span, ctm); + svg_dev_text_span_as_paths_fill(ctx, dev, span, ctm, colorspace, color, alpha, fnt); + } } static void @@ -582,12 +590,16 @@ svg_dev_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_st fz_output *out = sdev->out; font *fnt; + fz_text_span *span; fz_printf(ctx, out, "<text"); svg_dev_fill_color(ctx, sdev, colorspace, color, 0.0f); svg_dev_text(ctx, sdev, ctm, text); - fnt = svg_dev_text_as_paths_defs(ctx, dev, text, ctm); - svg_dev_text_as_paths_stroke(ctx, dev, text, stroke, ctm, colorspace, color, alpha, fnt); + for (span = text->head; span; span = span->next) + { + fnt = svg_dev_text_span_as_paths_defs(ctx, dev, span, ctm); + svg_dev_text_span_as_paths_stroke(ctx, dev, span, stroke, ctm, colorspace, color, alpha, fnt); + } } static void @@ -600,6 +612,7 @@ svg_dev_clip_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matri int num = sdev->id++; float white[3] = { 1, 1, 1 }; font *fnt; + fz_text_span *span; fz_bound_text(ctx, text, NULL, ctm, &bounds); @@ -609,8 +622,11 @@ svg_dev_clip_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matri fz_printf(ctx, out, "<text"); svg_dev_fill_color(ctx, sdev, fz_device_rgb(ctx), white, 0.0f); svg_dev_text(ctx, sdev, ctm, text); - fnt = svg_dev_text_as_paths_defs(ctx, dev, text, ctm); - svg_dev_text_as_paths_fill(ctx, dev, text, ctm, fz_device_rgb(ctx), white, 1.0f, fnt); + for (span = text->head; span; span = span->next) + { + fnt = svg_dev_text_span_as_paths_defs(ctx, dev, span, ctm); + svg_dev_text_span_as_paths_fill(ctx, dev, span, ctm, fz_device_rgb(ctx), white, 1.0f, fnt); + } fz_printf(ctx, out, "</mask>\n"); out = end_def(ctx, sdev); fz_printf(ctx, out, "<g mask=\"url(#ma%d)\">\n", num); @@ -626,6 +642,7 @@ svg_dev_clip_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stro int num = sdev->id++; float white[3] = { 255, 255, 255 }; font *fnt; + fz_text_span *span; fz_bound_text(ctx, text, NULL, ctm, &bounds); @@ -636,8 +653,11 @@ svg_dev_clip_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stro svg_dev_stroke_state(ctx, sdev, stroke, &fz_identity); svg_dev_stroke_color(ctx, sdev, fz_device_rgb(ctx), white, 0.0f); svg_dev_text(ctx, sdev, ctm, text); - fnt = svg_dev_text_as_paths_defs(ctx, dev, text, ctm); - svg_dev_text_as_paths_stroke(ctx, dev, text, stroke, ctm, fz_device_rgb(ctx), white, 1.0f, fnt); + for (span = text->head; span; span = span->next) + { + fnt = svg_dev_text_span_as_paths_defs(ctx, dev, span, ctm); + svg_dev_text_span_as_paths_stroke(ctx, dev, span, stroke, ctm, fz_device_rgb(ctx), white, 1.0f, fnt); + } fz_printf(ctx, out, "</mask>\n"); out = end_def(ctx, sdev); fz_printf(ctx, out, "<g mask=\"url(#ma%d)\">\n", num); diff --git a/source/fitz/text.c b/source/fitz/text.c index 0616d6a9..f90fee53 100644 --- a/source/fitz/text.c +++ b/source/fitz/text.c @@ -1,19 +1,10 @@ #include "mupdf/fitz.h" fz_text * -fz_new_text(fz_context *ctx, fz_font *font, const fz_matrix *trm, int wmode) +fz_new_text(fz_context *ctx) { - fz_text *text; - - text = fz_malloc_struct(ctx, fz_text); + fz_text *text = fz_malloc_struct(ctx, fz_text); text->refs = 1; - text->font = fz_keep_font(ctx, font); - text->trm = *trm; - text->wmode = wmode; - text->len = 0; - text->cap = 0; - text->items = NULL; - return text; } @@ -28,84 +19,122 @@ fz_drop_text(fz_context *ctx, fz_text *text) { if (fz_drop_imp(ctx, text, &text->refs)) { - fz_drop_font(ctx, text->font); - fz_free(ctx, text->items); + fz_text_span *span = text->head; + while (span) + { + fz_text_span *next = span->next; + fz_drop_font(ctx, span->font); + fz_free(ctx, span->items); + fz_free(ctx, span); + span = next; + } fz_free(ctx, text); } } -fz_rect * -fz_bound_text(fz_context *ctx, fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *bbox) +static fz_text_span * +fz_new_text_span(fz_context *ctx, fz_font *font, int wmode, const fz_matrix *trm) { - fz_matrix tm, trm; - fz_rect gbox; - int i; + fz_text_span *span = fz_malloc_struct(ctx, fz_text_span); + span->font = fz_keep_font(ctx, font); + span->wmode = wmode; + span->trm = *trm; + span->trm.e = 0; + span->trm.f = 0; + return span; +} - if (text->len == 0) +static fz_text_span * +fz_add_text_span(fz_context *ctx, fz_text *text, fz_font *font, int wmode, const fz_matrix *trm) +{ + if (!text->tail) { - *bbox = fz_empty_rect; - return bbox; + text->head = text->tail = fz_new_text_span(ctx, font, wmode, trm); } - - // TODO: stroke state - - tm = text->trm; - - tm.e = text->items[0].x; - tm.f = text->items[0].y; - fz_concat(&trm, &tm, ctm); - fz_bound_glyph(ctx, text->font, text->items[0].gid, &trm, bbox); - - for (i = 1; i < text->len; i++) + else if (text->tail->font != font || + text->tail->wmode != wmode || + text->tail->trm.a != trm->a || + text->tail->trm.b != trm->b || + text->tail->trm.c != trm->c || + text->tail->trm.d != trm->d) { - if (text->items[i].gid >= 0) - { - tm.e = text->items[i].x; - tm.f = text->items[i].y; - fz_concat(&trm, &tm, ctm); - fz_bound_glyph(ctx, text->font, text->items[i].gid, &trm, &gbox); - - bbox->x0 = fz_min(bbox->x0, gbox.x0); - bbox->y0 = fz_min(bbox->y0, gbox.y0); - bbox->x1 = fz_max(bbox->x1, gbox.x1); - bbox->y1 = fz_max(bbox->y1, gbox.y1); - } + text->tail = text->tail->next = fz_new_text_span(ctx, font, wmode, trm); } - - if (stroke) - fz_adjust_rect_for_stroke(ctx, bbox, stroke, ctm); - - /* Compensate for the glyph cache limited positioning precision */ - bbox->x0 -= 1; - bbox->y0 -= 1; - bbox->x1 += 1; - bbox->y1 += 1; - - return bbox; + return text->tail; } static void -fz_grow_text(fz_context *ctx, fz_text *text, int n) +fz_grow_text_span(fz_context *ctx, fz_text_span *span, int n) { - int new_cap = text->cap; - if (text->len + n < new_cap) + int new_cap = span->cap; + if (span->len + n < new_cap) return; - while (text->len + n > new_cap) + while (span->len + n > new_cap) new_cap = new_cap + 36; - text->items = fz_resize_array(ctx, text->items, new_cap, sizeof(fz_text_item)); - text->cap = new_cap; + span->items = fz_resize_array(ctx, span->items, new_cap, sizeof(fz_text_item)); + span->cap = new_cap; } void -fz_add_text(fz_context *ctx, fz_text *text, int gid, int ucs, float x, float y) +fz_add_text(fz_context *ctx, fz_text *text, fz_font *font, int wmode, const fz_matrix *trm, int gid, int ucs) { + fz_text_span *span; + if (text->refs != 1) fz_throw(ctx, FZ_ERROR_GENERIC, "cannot modify shared text objects"); - fz_grow_text(ctx, text, 1); - text->items[text->len].ucs = ucs; - text->items[text->len].gid = gid; - text->items[text->len].x = x; - text->items[text->len].y = y; - text->len++; + span = fz_add_text_span(ctx, text, font, wmode, trm); + + fz_grow_text_span(ctx, span, 1); + + span->items[span->len].ucs = ucs; + span->items[span->len].gid = gid; + span->items[span->len].x = trm->e; + span->items[span->len].y = trm->f; + span->len++; +} + +fz_rect * +fz_bound_text(fz_context *ctx, fz_text *text, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *bbox) +{ + fz_text_span *span; + fz_matrix tm, trm; + fz_rect gbox; + int i; + + *bbox = fz_empty_rect; + + for (span = text->head; span; span = span->next) + { + if (span->len > 0) + { + tm = span->trm; + for (i = 0; i < span->len; i++) + { + if (span->items[i].gid >= 0) + { + tm.e = span->items[i].x; + tm.f = span->items[i].y; + fz_concat(&trm, &tm, ctm); + fz_bound_glyph(ctx, span->font, span->items[i].gid, &trm, &gbox); + fz_union_rect(bbox, &gbox); + } + } + + } + } + + if (!fz_is_empty_rect(bbox)) + { + if (stroke) + fz_adjust_rect_for_stroke(ctx, bbox, stroke, ctm); + + /* Compensate for the glyph cache limited positioning precision */ + bbox->x0 -= 1; + bbox->y0 -= 1; + bbox->x1 += 1; + bbox->y1 += 1; + } + + return bbox; } diff --git a/source/fitz/trace-device.c b/source/fitz/trace-device.c index 59ea8ad8..df2f6455 100644 --- a/source/fitz/trace-device.c +++ b/source/fitz/trace-device.c @@ -14,13 +14,6 @@ fz_trace_matrix(fz_context *ctx, fz_output *out, const fz_matrix *ctm) } static void -fz_trace_trm(fz_context *ctx, fz_output *out, const fz_matrix *trm) -{ - fz_printf(ctx, out, " trm=\"%g %g %g %g\"", - trm->a, trm->b, trm->c, trm->d); -} - -static void fz_trace_color(fz_context *ctx, fz_output *out, fz_colorspace *colorspace, float *color, float alpha) { int i; @@ -32,6 +25,38 @@ fz_trace_color(fz_context *ctx, fz_output *out, fz_colorspace *colorspace, float fz_printf(ctx, out, " alpha=\"%g\"", alpha); } +static int +isxmlmeta(int c) +{ + return c < 32 || c >= 128 || c == '&' || c == '<' || c == '>' || c == '\'' || c == '"'; +} + +static void +fz_trace_text_span(fz_context *ctx, fz_output *out, fz_text_span *span) +{ + int i; + fz_printf(ctx, out, "<span font=\"%s\" wmode=\"%d\"", span->font->name, span->wmode); + fz_printf(ctx, out, " trm=\"%g %g %g %g\">\n", span->trm.a, span->trm.b, span->trm.c, span->trm.d); + for (i = 0; i < span->len; i++) + { + if (!isxmlmeta(span->items[i].ucs)) + fz_printf(ctx, out, "<g ucs=\"%c\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n", + span->items[i].ucs, span->items[i].gid, span->items[i].x, span->items[i].y); + else + fz_printf(ctx, out, "<g ucs=\"U+%04X\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n", + span->items[i].ucs, span->items[i].gid, span->items[i].x, span->items[i].y); + } + fz_printf(ctx, out, "</span>\n"); +} + +static void +fz_trace_text(fz_context *ctx, fz_output *out, fz_text *text) +{ + fz_text_span *span; + for (span = text->head; span; span = span->next) + fz_trace_text_span(ctx, out, span); +} + static void trace_moveto(fz_context *ctx, void *arg, float x, float y) { @@ -166,36 +191,14 @@ fz_trace_clip_stroke_path(fz_context *ctx, fz_device *dev, fz_path *path, const fz_printf(ctx, out, "</clip_stroke_path>\n"); } -static int -isxmlmeta(int c) -{ - return c < 32 || c >= 128 || c == '&' || c == '<' || c == '>' || c == '\'' || c == '"'; -} - -static void -fz_trace_text(fz_context *ctx, fz_output *out, fz_text *text) -{ - int i; - for (i = 0; i < text->len; i++) - { - if (!isxmlmeta(text->items[i].ucs)) - fz_printf(ctx, out, "<g ucs=\"%c\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n", - text->items[i].ucs, text->items[i].gid, text->items[i].x, text->items[i].y); - else - fz_printf(ctx, out, "<g ucs=\"U+%04X\" gid=\"%d\" x=\"%g\" y=\"%g\" />\n", - text->items[i].ucs, text->items[i].gid, text->items[i].x, text->items[i].y); - } -} - static void fz_trace_fill_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_output *out = ((fz_trace_device*)dev)->out; - fz_printf(ctx, out, "<fill_text font=\"%s\" wmode=\"%d\"", text->font->name, text->wmode); + fz_printf(ctx, out, "<fill_text"); fz_trace_color(ctx, out, colorspace, color, alpha); fz_trace_matrix(ctx, out, ctm); - fz_trace_trm(ctx, out, &text->trm); fz_printf(ctx, out, ">\n"); fz_trace_text(ctx, out, text); fz_printf(ctx, out, "</fill_text>\n"); @@ -206,10 +209,9 @@ fz_trace_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_s fz_colorspace *colorspace, float *color, float alpha) { fz_output *out = ((fz_trace_device*)dev)->out; - fz_printf(ctx, out, "<stroke_text font=\"%s\" wmode=\"%d\"", text->font->name, text->wmode); + fz_printf(ctx, out, "<stroke_text"); fz_trace_color(ctx, out, colorspace, color, alpha); fz_trace_matrix(ctx, out, ctm); - fz_trace_trm(ctx, out, &text->trm); fz_printf(ctx, out, ">\n"); fz_trace_text(ctx, out, text); fz_printf(ctx, out, "</stroke_text>\n"); @@ -219,10 +221,8 @@ static void fz_trace_clip_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate) { fz_output *out = ((fz_trace_device*)dev)->out; - fz_printf(ctx, out, "<clip_text font=\"%s\" wmode=\"%d\"", text->font->name, text->wmode); - fz_printf(ctx, out, " accumulate=\"%d\"", accumulate); + fz_printf(ctx, out, "<clip_text"); fz_trace_matrix(ctx, out, ctm); - fz_trace_trm(ctx, out, &text->trm); fz_printf(ctx, out, ">\n"); fz_trace_text(ctx, out, text); fz_printf(ctx, out, "</clip_text>\n"); @@ -232,9 +232,8 @@ static void fz_trace_clip_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm) { fz_output *out = ((fz_trace_device*)dev)->out; - fz_printf(ctx, out, "<clip_stroke_text font=\"%s\" wmode=\"%d\"", text->font->name, text->wmode); + fz_printf(ctx, out, "<clip_stroke_text"); fz_trace_matrix(ctx, out, ctm); - fz_trace_trm(ctx, out, &text->trm); fz_printf(ctx, out, ">\n"); fz_trace_text(ctx, out, text); fz_printf(ctx, out, "</clip_stroke_text>\n"); @@ -244,9 +243,8 @@ static void fz_trace_ignore_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm) { fz_output *out = ((fz_trace_device*)dev)->out; - fz_printf(ctx, out, "<ignore_text font=\"%s\" wmode=\"%d\"", text->font->name, text->wmode); + fz_printf(ctx, out, "<ignore_text"); fz_trace_matrix(ctx, out, ctm); - fz_trace_trm(ctx, out, &text->trm); fz_printf(ctx, out, ">\n"); fz_trace_text(ctx, out, text); fz_printf(ctx, out, "</ignore_text>\n"); |