From fa0bffa57e7e2164f0201b0f2fdc984d475674ae Mon Sep 17 00:00:00 2001 From: Tor Andersson <tor.andersson@artifex.com> Date: Fri, 9 Oct 2015 11:07:42 +0200 Subject: Keep spans of multiple fonts and sizes in one fz_text object. --- source/fitz/draw-device.c | 338 +++++++++++++++++++++++--------------------- source/fitz/stext-device.c | 76 ++++++---- source/fitz/svg-device.c | 214 +++++++++++++++------------- source/fitz/text.c | 165 ++++++++++++--------- source/fitz/trace-device.c | 76 +++++----- source/html/html-layout.c | 50 +++---- source/pdf/pdf-appearance.c | 58 ++++---- source/pdf/pdf-device.c | 122 +++++++++------- source/pdf/pdf-op-run.c | 24 +--- source/xps/xps-glyphs.c | 13 +- 10 files changed, 616 insertions(+), 520 deletions(-) (limited to 'source') 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 @@ -13,13 +13,6 @@ fz_trace_matrix(fz_context *ctx, fz_output *out, const fz_matrix *ctm) ctm->a, ctm->b, ctm->c, ctm->d, ctm->e, ctm->f); } -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) { @@ -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"); diff --git a/source/html/html-layout.c b/source/html/html-layout.c index f742969c..b7e2b779 100644 --- a/source/html/html-layout.c +++ b/source/html/html-layout.c @@ -825,11 +825,9 @@ static void draw_flow_box(fz_context *ctx, fz_html *box, float page_top, float p { fz_html_flow *node; fz_text *text; - fz_text *falltext; fz_matrix trm; const char *s; float color[3]; - float x, y; int c, g; for (node = box->flow_head; node; node = node->next) @@ -853,11 +851,11 @@ static void draw_flow_box(fz_context *ctx, fz_html *box, float page_top, float p color[1] = node->style->color.g / 255.0f; color[2] = node->style->color.b / 255.0f; - text = NULL; - falltext = NULL; + /* TODO: reuse text object if color is unchanged */ + text = fz_new_text(ctx); - x = node->x; - y = node->y; + trm.e = node->x; + trm.f = node->y; s = node->text; while (*s) { @@ -866,12 +864,8 @@ static void draw_flow_box(fz_context *ctx, fz_html *box, float page_top, float p if (g) { if (node->style->visibility == V_VISIBLE) - { - if (!text) - text = fz_new_text(ctx, node->style->font, &trm, 0); - fz_add_text(ctx, text, g, c, x, y); - } - x += fz_advance_glyph(ctx, node->style->font, g) * node->em; + fz_add_text(ctx, text, node->style->font, 0, &trm, g, c); + trm.e += fz_advance_glyph(ctx, node->style->font, g) * node->em; } else { @@ -879,13 +873,16 @@ static void draw_flow_box(fz_context *ctx, fz_html *box, float page_top, float p if (g) { if (node->style->visibility == V_VISIBLE) - { - if (!falltext) - falltext = fz_new_text(ctx, node->style->fallback, &trm, 0); - fz_add_text(ctx, falltext, g, c, x, y); - } + fz_add_text(ctx, text, node->style->fallback, 0, &trm, g, c); + trm.e += fz_advance_glyph(ctx, node->style->fallback, g) * node->em; + } + else + { + g = fz_encode_character(ctx, node->style->font, 0x25CF); /* bullet */ + if (node->style->visibility == V_VISIBLE) + fz_add_text(ctx, text, node->style->font, 0, &trm, g, c); + trm.e += fz_advance_glyph(ctx, node->style->font, g) * node->em; } - x += fz_advance_glyph(ctx, node->style->fallback, g) * node->em; } } @@ -894,11 +891,6 @@ static void draw_flow_box(fz_context *ctx, fz_html *box, float page_top, float p fz_fill_text(ctx, dev, text, ctm, fz_device_rgb(ctx), color, 1); fz_drop_text(ctx, text); } - if (falltext) - { - fz_fill_text(ctx, dev, falltext, ctm, fz_device_rgb(ctx), color, 1); - fz_drop_text(ctx, falltext); - } } else if (node->type == FLOW_IMAGE) { @@ -1039,14 +1031,15 @@ static void draw_list_mark(fz_context *ctx, fz_html *box, float page_top, float fz_text *text; fz_matrix trm; fz_html_flow *line; - float x, y, w; + float y, w; float color[3]; const char *s; char buf[40]; int c, g; fz_scale(&trm, box->em, -box->em); - text = fz_new_text(ctx, box->style.font, &trm, 0); + + text = fz_new_text(ctx); line = find_list_mark_anchor(ctx, box); if (line) @@ -1078,13 +1071,14 @@ static void draw_list_mark(fz_context *ctx, fz_html *box, float page_top, float } s = buf; - x = box->x - w; + trm.e = box->x - w; + trm.f = y; while (*s) { s += fz_chartorune(&c, s); g = fz_encode_character(ctx, box->style.font, c); - fz_add_text(ctx, text, g, c, x, y); - x += fz_advance_glyph(ctx, box->style.font, g) * box->em; + fz_add_text(ctx, text, box->style.font, 0, &trm, g, c); + trm.e += fz_advance_glyph(ctx, box->style.font, g) * box->em; } color[0] = box->style.color.r / 255.0f; diff --git a/source/pdf/pdf-appearance.c b/source/pdf/pdf-appearance.c index 9bd3754b..6132f97f 100644 --- a/source/pdf/pdf-appearance.c +++ b/source/pdf/pdf-appearance.c @@ -1898,36 +1898,37 @@ void pdf_update_ink_appearance(fz_context *ctx, pdf_document *doc, pdf_annot *an } } -static void add_text(fz_context *ctx, font_info *font_rec, fz_text *text, char *str, int str_len, float x, float y) +static void add_text(fz_context *ctx, font_info *font_rec, fz_text *text, char *str, int str_len, const fz_matrix *tm_) { fz_font *font = font_rec->font->font; - int mask = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; + fz_matrix tm = *tm_; + int ucs, gid, n; - while (str_len--) + while (str_len > 0) { - FT_Fixed adv; - - /* FIXME: convert str from utf8 to WinAnsi */ - int gid = FT_Get_Char_Index(font->ft_face, *str); - fz_add_text(ctx, text, gid, *str++, x, y); - - FT_Get_Advance(font->ft_face, gid, mask, &adv); - x += ((float)adv) * font_rec->da_rec.font_size / ((FT_Face)font->ft_face)->units_per_EM; + n = fz_chartorune(&ucs, str); + str += n; + str_len -= n; + gid = fz_encode_character(ctx, font, ucs); + fz_add_text(ctx, text, font, 0, &tm, gid, ucs); + tm.e += fz_advance_glyph(ctx, font, gid) * font_rec->da_rec.font_size; } } static fz_text *layout_text(fz_context *ctx, font_info *font_rec, char *str, float x, float y) { - fz_matrix tm; - fz_font *font = font_rec->font->font; fz_text *text; + fz_matrix tm; fz_scale(&tm, font_rec->da_rec.font_size, font_rec->da_rec.font_size); - text = fz_new_text(ctx, font, &tm, 0); + tm.e = x; + tm.f = y; + + text = fz_new_text(ctx); fz_try(ctx) { - add_text(ctx, font_rec, text, str, strlen(str), x, y); + add_text(ctx, font_rec, text, str, strlen(str), &tm); } fz_catch(ctx) { @@ -1944,6 +1945,7 @@ static fz_text *fit_text(fz_context *ctx, font_info *font_rec, char *str, fz_rec float height = bounds->y1 - bounds->y0; fz_matrix tm; fz_text *text = NULL; + fz_text_span *span; text_splitter splitter; float ascender; @@ -1961,14 +1963,15 @@ static fz_text *fit_text(fz_context *ctx, font_info *font_rec, char *str, fz_rec /* Try a layout pass */ int line = 0; float font_size; - float x = 0.0; - float y = 0.0; fz_drop_text(ctx, text); text = NULL; font_size = font_rec->da_rec.font_size; fz_scale(&tm, font_size, font_size); - text = fz_new_text(ctx, font_rec->font->font, &tm, 0); + tm.e = 0; + tm.f = 0; + + text = fz_new_text(ctx); text_splitter_start_pass(&splitter); @@ -1989,9 +1992,9 @@ static fz_text *fit_text(fz_context *ctx, font_info *font_rec, char *str, fz_rec int wordlen = splitter.text_end-splitter.text_start; text_splitter_move(&splitter, -line, &dx, &dy); - x += dx; - y += dy; - add_text(ctx, font_rec, text, word, wordlen, x, y); + tm.e += dx; + tm.f += dy; + add_text(ctx, font_rec, text, word, wordlen, &tm); } } @@ -2004,12 +2007,15 @@ static fz_text *fit_text(fz_context *ctx, font_info *font_rec, char *str, fz_rec /* Post process text with the scale determined by the splitter * and with the required offst */ - fz_pre_scale(&text->trm, splitter.scale, splitter.scale); - ascender = font_rec->font->ascent * font_rec->da_rec.font_size * splitter.scale / 1000.0f; - for (i = 0; i < text->len; i++) + for (span = text->head; span; span = span->next) { - text->items[i].x = text->items[i].x * splitter.scale + bounds->x0; - text->items[i].y = text->items[i].y * splitter.scale + bounds->y1 - ascender; + fz_pre_scale(&span->trm, splitter.scale, splitter.scale); + ascender = font_rec->font->ascent * font_rec->da_rec.font_size * splitter.scale / 1000.0f; + for (i = 0; i < span->len; i++) + { + span->items[i].x = span->items[i].x * splitter.scale + bounds->x0; + span->items[i].y = span->items[i].y * splitter.scale + bounds->y1 - ascender; + } } } fz_catch(ctx) diff --git a/source/pdf/pdf-device.c b/source/pdf/pdf-device.c index 51c5ee9e..a2ee1295 100644 --- a/source/pdf/pdf-device.c +++ b/source/pdf/pdf-device.c @@ -667,7 +667,7 @@ pdf_dev_pop(fz_context *ctx, pdf_device *pdev) } static void -pdf_dev_text(fz_context *ctx, pdf_device *pdev, fz_text *text, float size) +pdf_dev_text_span(fz_context *ctx, pdf_device *pdev, fz_text_span *span, float size) { int mask = FT_LOAD_NO_SCALE | FT_LOAD_IGNORE_TRANSFORM; int i; @@ -686,9 +686,9 @@ pdf_dev_text(fz_context *ctx, pdf_device *pdev, fz_text *text, float size) fz_invert_matrix(&inverse, &trunc_trm); i = 0; - while (i < text->len) + while (i < span->len) { - fz_text_item *it = &text->items[i]; + fz_text_item *it = &span->items[i]; fz_point delta; float x; int j; @@ -704,17 +704,17 @@ pdf_dev_text(fz_context *ctx, pdf_device *pdev, fz_text *text, float size) } j = i+1; - if (text->font->ft_face) + if (span->font->ft_face) { /* Find prefix of text for which the advance of each character accounts * for the position offset */ x = it->x; - while (j < text->len) + while (j < span->len) { FT_Fixed adv; - FT_Get_Advance(text->font->ft_face, text->items[j-1].gid, mask, &adv); - x += (float)adv * size /((FT_Face)text->font->ft_face)->units_per_EM; - if (fabs(x - text->items[j].x) > ALLOWED_TEXT_POS_ERROR || fabs(it->y - text->items[j].y) > ALLOWED_TEXT_POS_ERROR) + FT_Get_Advance(span->font->ft_face, span->items[j-1].gid, mask, &adv); + x += (float)adv * size /((FT_Face)span->font->ft_face)->units_per_EM; + if (fabs(x - span->items[j].x) > ALLOWED_TEXT_POS_ERROR || fabs(it->y - span->items[j].y) > ALLOWED_TEXT_POS_ERROR) break; j++; } @@ -725,7 +725,7 @@ pdf_dev_text(fz_context *ctx, pdf_device *pdev, fz_text *text, float size) { /* FIXME: should use it->gid, rather than it->ucs, and convert * to the correct encoding */ - fz_buffer_printf(ctx, gs->buf, "%02x", text->items[i].ucs); + fz_buffer_printf(ctx, gs->buf, "%02x", span->items[i].ucs); } fz_buffer_printf(ctx, gs->buf, "> Tj\n"); } @@ -935,83 +935,105 @@ pdf_dev_clip_stroke_path(fz_context *ctx, fz_device *dev, fz_path *path, const f static void pdf_dev_fill_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) + fz_colorspace *colorspace, float *color, float alpha) { pdf_device *pdev = (pdf_device*)dev; - fz_matrix trm = text->trm; - float size = fz_matrix_expansion(&trm); + fz_text_span *span; - fz_pre_scale(&trm, 1/size, 1/size); + for (span = text->head; span; span = span->next) + { + fz_matrix trm = span->trm; + float size = fz_matrix_expansion(&trm); - pdf_dev_begin_text(ctx, pdev, &trm, 0); - pdf_dev_font(ctx, pdev, text->font, size); - pdf_dev_ctm(ctx, pdev, ctm); - pdf_dev_alpha(ctx, pdev, alpha, 0); - pdf_dev_color(ctx, pdev, colorspace, color, 0); - pdf_dev_text(ctx, pdev, text, size); + fz_pre_scale(&trm, 1/size, 1/size); + + pdf_dev_begin_text(ctx, pdev, &trm, 0); + pdf_dev_font(ctx, pdev, span->font, size); + pdf_dev_ctm(ctx, pdev, ctm); + pdf_dev_alpha(ctx, pdev, alpha, 0); + pdf_dev_color(ctx, pdev, colorspace, color, 0); + pdf_dev_text_span(ctx, pdev, span, size); + } } static void pdf_dev_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm, - fz_colorspace *colorspace, float *color, float alpha) + fz_colorspace *colorspace, float *color, float alpha) { pdf_device *pdev = (pdf_device*)dev; - fz_matrix trm = text->trm; - float size = fz_matrix_expansion(&trm); + fz_text_span *span; - fz_pre_scale(&trm, 1/size, 1/size); + for (span = text->head; span; span = span->next) + { + fz_matrix trm = span->trm; + float size = fz_matrix_expansion(&trm); - pdf_dev_begin_text(ctx, pdev, &text->trm, 1); - pdf_dev_font(ctx, pdev, text->font, 1); - pdf_dev_ctm(ctx, pdev, ctm); - pdf_dev_alpha(ctx, pdev, alpha, 1); - pdf_dev_color(ctx, pdev, colorspace, color, 1); - pdf_dev_text(ctx, pdev, text, size); + fz_pre_scale(&trm, 1/size, 1/size); + + pdf_dev_begin_text(ctx, pdev, &span->trm, 1); + pdf_dev_font(ctx, pdev, span->font, 1); + pdf_dev_ctm(ctx, pdev, ctm); + pdf_dev_alpha(ctx, pdev, alpha, 1); + pdf_dev_color(ctx, pdev, colorspace, color, 1); + pdf_dev_text_span(ctx, pdev, span, size); + } } static void pdf_dev_clip_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm, int accumulate) { pdf_device *pdev = (pdf_device*)dev; - fz_matrix trm = text->trm; - float size = fz_matrix_expansion(&trm); + fz_text_span *span; + for (span = text->head; span; span = span->next) + { + fz_matrix trm = span->trm; + float size = fz_matrix_expansion(&trm); - fz_pre_scale(&trm, 1/size, 1/size); + fz_pre_scale(&trm, 1/size, 1/size); - pdf_dev_begin_text(ctx, pdev, &text->trm, 0); - pdf_dev_ctm(ctx, pdev, ctm); - pdf_dev_font(ctx, pdev, text->font, 7); - pdf_dev_text(ctx, pdev, text, size); + pdf_dev_begin_text(ctx, pdev, &span->trm, 0); + pdf_dev_ctm(ctx, pdev, ctm); + pdf_dev_font(ctx, pdev, span->font, 7); + pdf_dev_text_span(ctx, pdev, span, size); + } } static void pdf_dev_clip_stroke_text(fz_context *ctx, fz_device *dev, fz_text *text, fz_stroke_state *stroke, const fz_matrix *ctm) { pdf_device *pdev = (pdf_device*)dev; - fz_matrix trm = text->trm; - float size = fz_matrix_expansion(&trm); + fz_text_span *span; + for (span = text->head; span; span = span->next) + { + fz_matrix trm = span->trm; + float size = fz_matrix_expansion(&trm); - fz_pre_scale(&trm, 1/size, 1/size); + fz_pre_scale(&trm, 1/size, 1/size); - pdf_dev_begin_text(ctx, pdev, &text->trm, 0); - pdf_dev_font(ctx, pdev, text->font, 5); - pdf_dev_ctm(ctx, pdev, ctm); - pdf_dev_text(ctx, pdev, text, size); + pdf_dev_begin_text(ctx, pdev, &span->trm, 0); + pdf_dev_font(ctx, pdev, span->font, 5); + pdf_dev_ctm(ctx, pdev, ctm); + pdf_dev_text_span(ctx, pdev, span, size); + } } static void pdf_dev_ignore_text(fz_context *ctx, fz_device *dev, fz_text *text, const fz_matrix *ctm) { pdf_device *pdev = (pdf_device*)dev; - fz_matrix trm = text->trm; - float size = fz_matrix_expansion(&trm); + fz_text_span *span; + for (span = text->head; span; span = span->next) + { + fz_matrix trm = span->trm; + float size = fz_matrix_expansion(&trm); - fz_pre_scale(&trm, 1/size, 1/size); + fz_pre_scale(&trm, 1/size, 1/size); - pdf_dev_begin_text(ctx, pdev, &text->trm, 0); - pdf_dev_ctm(ctx, pdev, ctm); - pdf_dev_font(ctx, pdev, text->font, 3); - pdf_dev_text(ctx, pdev, text, size); + pdf_dev_begin_text(ctx, pdev, &span->trm, 0); + pdf_dev_ctm(ctx, pdev, ctm); + pdf_dev_font(ctx, pdev, span->font, 3); + pdf_dev_text_span(ctx, pdev, span, size); + } } static void diff --git a/source/pdf/pdf-op-run.c b/source/pdf/pdf-op-run.c index dbd9386d..ea2384be 100644 --- a/source/pdf/pdf-op-run.c +++ b/source/pdf/pdf-op-run.c @@ -754,7 +754,7 @@ pdf_flush_text(fz_context *ctx, pdf_run_processor *pr) fz_adjust_rect_for_stroke(ctx, &tb, gstate->stroke_state, &gstate->ctm); /* Don't bother sending a text group with nothing in it */ - if (text->len == 0) + if (!text->head) break; if (dofill || dostroke) @@ -921,22 +921,12 @@ pdf_show_char(fz_context *ctx, pdf_run_processor *pr, int cid) * uncachable, then render direct. */ render_direct = (!fontdesc->font->ft_face && pr->nested_depth > 0) || !fz_glyph_cacheable(ctx, fontdesc->font, gid); - /* flush buffered text if face or matrix or rendermode has changed */ - if (!pr->text || - fontdesc->font != pr->text->font || - fontdesc->wmode != pr->text->wmode || - fabsf(trm.a - pr->text->trm.a) > FLT_EPSILON || - fabsf(trm.b - pr->text->trm.b) > FLT_EPSILON || - fabsf(trm.c - pr->text->trm.c) > FLT_EPSILON || - fabsf(trm.d - pr->text->trm.d) > FLT_EPSILON || - gstate->render != pr->text_mode || - render_direct) + /* flush buffered text if rendermode has changed */ + if (!pr->text || gstate->render != pr->text_mode || render_direct) { gstate = pdf_flush_text(ctx, pr); - pr->text = fz_new_text(ctx, fontdesc->font, &trm, fontdesc->wmode); - pr->text->trm.e = 0; - pr->text->trm.f = 0; + pr->text = fz_new_text(ctx); pr->text_mode = gstate->render; pr->text_bbox = fz_empty_rect; } @@ -956,11 +946,11 @@ pdf_show_char(fz_context *ctx, pdf_run_processor *pr, int cid) fz_union_rect(&pr->text_bbox, &bbox); /* add glyph to textobject */ - fz_add_text(ctx, pr->text, gid, ucsbuf[0], trm.e, trm.f); + fz_add_text(ctx, pr->text, fontdesc->font, fontdesc->wmode, &trm, gid, ucsbuf[0]); /* add filler glyphs for one-to-many unicode mapping */ for (i = 1; i < ucslen; i++) - fz_add_text(ctx, pr->text, -1, ucsbuf[i], trm.e, trm.f); + fz_add_text(ctx, pr->text, fontdesc->font, fontdesc->wmode, &trm, -1, ucsbuf[i]); if (fontdesc->wmode == 0) { @@ -1658,7 +1648,7 @@ static void pdf_run_Tw(fz_context *ctx, pdf_processor *proc, float wordspace) static void pdf_run_Tz(fz_context *ctx, pdf_processor *proc, float scale) { pdf_run_processor *pr = (pdf_run_processor *)proc; - pdf_gstate *gstate = pdf_flush_text(ctx, pr); + pdf_gstate *gstate = pr->gstate + pr->gtop; gstate->scale = scale / 100; } diff --git a/source/xps/xps-glyphs.c b/source/xps/xps-glyphs.c index 06d2820d..4434c4ed 100644 --- a/source/xps/xps-glyphs.c +++ b/source/xps/xps-glyphs.c @@ -348,7 +348,6 @@ xps_parse_glyphs_imp(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, xps_glyph_metrics mtx; fz_text *text; fz_matrix tm; - float e, f; float x = originx; float y = originy; char *us = unicode; @@ -372,7 +371,7 @@ xps_parse_glyphs_imp(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, else fz_scale(&tm, size, -size); - text = fz_new_text(ctx, font, &tm, is_sideways); + text = fz_new_text(ctx); while ((us && un > 0) || (is && *is)) { @@ -440,16 +439,16 @@ xps_parse_glyphs_imp(fz_context *ctx, xps_document *doc, const fz_matrix *ctm, if (is_sideways) { - e = x + u_offset + (mtx.vorg * size); - f = y - v_offset + (mtx.hadv * 0.5f * size); + tm.e = x + u_offset + (mtx.vorg * size); + tm.f = y - v_offset + (mtx.hadv * 0.5f * size); } else { - e = x + u_offset; - f = y - v_offset; + tm.e = x + u_offset; + tm.f = y - v_offset; } - fz_add_text(ctx, text, glyph_index, char_code, e, f); + fz_add_text(ctx, text, font, is_sideways, &tm, glyph_index, char_code); x += advance * 0.01f * size; } -- cgit v1.2.3