fz_rect * fz_bound_text(fz_context *ctx, const 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; }
static void fz_list_clip_stroke_text(fz_device *dev, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm) { fz_display_node *node; fz_context *ctx = dev->ctx; node = fz_new_display_node(ctx, FZ_CMD_CLIP_STROKE_TEXT, ctm, NULL, NULL, 0); fz_try(ctx) { node->rect = fz_bound_text(dev->ctx, text, ctm); fz_adjust_rect_for_stroke(&node->rect, stroke, &ctm); node->item.text = fz_clone_text(dev->ctx, text); node->stroke = fz_keep_stroke_state(dev->ctx, stroke); } fz_catch(ctx) { fz_free_display_node(ctx, node); fz_rethrow(ctx); } fz_append_display_node(dev->user, node); }
fz_rect * fz_bound_path(fz_context *ctx, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, fz_rect *r) { fz_point p; int i = 0, k = 0; /* If the path is empty, return the empty rectangle here - don't wait * for it to be expanded in the stroked case below. * A path must start with a moveto - and if that's all there is * then the path is empty. */ if (path->cmd_len == 0 || path->cmd_len == 1) { *r = fz_empty_rect; return r; } /* Initial moveto point */ p.x = path->coords[0]; p.y = path->coords[1]; fz_transform_point(&p, ctm); r->x0 = r->x1 = p.x; r->y0 = r->y1 = p.y; while (i < path->cmd_len) { switch (path->cmds[i++]) { case FZ_CURVETO: p.x = path->coords[k++]; p.y = path->coords[k++]; bound_expand(r, fz_transform_point(&p, ctm)); p.x = path->coords[k++]; p.y = path->coords[k++]; bound_expand(r, fz_transform_point(&p, ctm)); p.x = path->coords[k++]; p.y = path->coords[k++]; bound_expand(r, fz_transform_point(&p, ctm)); break; case FZ_MOVETO: if (k + 2 == path->coord_len) { /* Trailing Moveto - cannot affect bbox */ k += 2; break; } /* fallthrough */ case FZ_LINETO: p.x = path->coords[k++]; p.y = path->coords[k++]; bound_expand(r, fz_transform_point(&p, ctm)); break; case FZ_CLOSE_PATH: break; } } if (stroke) { fz_adjust_rect_for_stroke(r, stroke, ctm); } return r; }