static void fz_draw_stroke_path(fz_device *devp, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = devp->user; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_bbox bbox; int i; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; if (model == NULL) model = fz_device_gray; if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, state->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, state->scissor); if (fz_is_empty_rect(bbox)) return; if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); fz_convert_color(dev->ctx, model, colorfv, colorspace, color); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scan_convert(dev->gel, 0, bbox, state->dest, colorbv); if (state->shape) { fz_reset_gel(dev->gel, state->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); colorbv[0] = 255; fz_scan_convert(dev->gel, 0, bbox, state->shape, colorbv); } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
static void fz_draw_clip_stroke_path(fz_context *ctx, void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; fz_pixmap *mask, *dest, *shape; fz_bbox bbox; if (dev->top == dev->stack_max) fz_grow_stack(dev); if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, dev->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(ctx, dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(ctx, dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); mask = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(mask); dest = fz_new_pixmap_with_rect(ctx, model, bbox); /* FIXME: See note #1 */ fz_clear_pixmap(dest); if (dev->shape) { shape = fz_new_pixmap_with_rect(ctx, NULL, bbox); fz_clear_pixmap(shape); } else shape = NULL; if (!fz_is_empty_rect(bbox)) fz_scan_convert(dev->gel, 0, bbox, mask, NULL); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->stack[dev->top].shape = dev->shape; /* FIXME: See note #1 */ dev->stack[dev->top].blendmode = dev->blendmode | FZ_BLEND_ISOLATED; dev->scissor = bbox; dev->dest = dest; dev->shape = shape; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, "Clip (stroke) begin\n"); #endif dev->top++; }
static void fz_draw_clip_stroke_path(fz_device *devp, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm) { fz_draw_device *dev = devp->user; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; fz_bbox bbox; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model; fz_context *ctx = dev->ctx; if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, state->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); state = push_stack(dev); model = state->dest->colorspace; bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, state->scissor); if (rect) bbox = fz_intersect_bbox(bbox, fz_bbox_covering_rect(*rect)); /* SumatraPDF: try to match rendering with and without display list */ else bbox = fz_intersect_bbox(bbox, fz_bbox_covering_rect(fz_bound_path(ctx, path, stroke, ctm))); fz_try(ctx) { state[1].mask = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, state[1].mask); state[1].dest = fz_new_pixmap_with_bbox(dev->ctx, model, bbox); fz_clear_pixmap(dev->ctx, state[1].dest); if (state->shape) { state[1].shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, state[1].shape); } if (!fz_is_empty_rect(bbox)) fz_scan_convert(dev->gel, 0, bbox, state[1].mask, NULL); state[1].blendmode |= FZ_BLEND_ISOLATED; state[1].scissor = bbox; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top-1, "Clip (stroke) begin\n"); #endif } fz_catch(ctx) { emergency_pop_stack(dev, state); } }
static void fz_draw_clip_stroke_path(void *user, fz_path *path, fz_rect *rect, fz_stroke_state *stroke, fz_matrix ctm) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; fz_pixmap *mask, *dest; fz_bbox bbox; if (dev->top == STACK_SIZE) { fz_warn("assert: too many buffers on stack"); return; } if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, dev->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (rect) bbox = fz_intersect_bbox(bbox, fz_round_rect(*rect)); mask = fz_new_pixmap_with_rect(NULL, bbox); dest = fz_new_pixmap_with_rect(model, bbox); fz_clear_pixmap(mask); fz_clear_pixmap(dest); if (!fz_is_empty_rect(bbox)) fz_scan_convert(dev->gel, 0, bbox, mask, NULL); dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = mask; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; }
static void fz_draw_stroke_path(void *user, fz_path *path, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; float expansion = fz_matrix_expansion(ctm); float flatness = 0.3f / expansion; float linewidth = stroke->linewidth; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_bbox bbox; int i; if (linewidth * expansion < 0.1f) linewidth = 1 / expansion; fz_reset_gel(dev->gel, dev->scissor); if (stroke->dash_len > 0) fz_flatten_dash_path(dev->gel, path, stroke, ctm, flatness, linewidth); else fz_flatten_stroke_path(dev->gel, path, stroke, ctm, flatness, linewidth); fz_sort_gel(dev->gel); bbox = fz_bound_gel(dev->gel); bbox = fz_intersect_bbox(bbox, dev->scissor); if (fz_is_empty_rect(bbox)) return; fz_convert_color(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_scan_convert(dev->gel, 0, bbox, dev->dest, colorbv); }
void fz_flatten_dash_path(fz_gel *gel, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth) { struct sctx s; fz_point p0, p1, p2, p3, beg; float phase_len, max_expand; int i; s.gel = gel; s.ctm = ctm; s.flatness = flatness; s.linejoin = stroke->linejoin; s.linewidth = linewidth * 0.5f; s.miterlimit = stroke->miterlimit; s.sn = 0; s.bn = 0; s.dot = 0; s.dash_list = stroke->dash_list; s.dash_phase = stroke->dash_phase; s.dash_len = stroke->dash_len; s.toggle = 0; s.offset = 0; s.phase = 0; s.cap = stroke->start_cap; if (path->len > 0 && path->items[0].k != FZ_MOVETO) return; phase_len = 0; for (i = 0; i < stroke->dash_len; i++) phase_len += stroke->dash_list[i]; max_expand = fz_matrix_max_expansion(ctm); if (phase_len < 1.0f && phase_len * max_expand < 0.5f) { fz_flatten_stroke_path(gel, path, stroke, ctm, flatness, linewidth); return; } p0.x = p0.y = 0; i = 0; while (i < path->len) { switch (path->items[i++].k) { case FZ_MOVETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; fz_dash_moveto(&s, p1, stroke->start_cap, stroke->end_cap); beg = p0 = p1; break; case FZ_LINETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; fz_dash_lineto(&s, p1, stroke->dash_cap, 0); p0 = p1; break; case FZ_CURVETO: p1.x = path->items[i++].v; p1.y = path->items[i++].v; p2.x = path->items[i++].v; p2.y = path->items[i++].v; p3.x = path->items[i++].v; p3.y = path->items[i++].v; fz_dash_bezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0, stroke->dash_cap); p0 = p3; break; case FZ_CLOSE_PATH: fz_dash_lineto(&s, beg, stroke->dash_cap, 0); p0 = p1 = beg; break; } } fz_stroke_flush(&s, s.cap, stroke->end_cap); }
void fz_flatten_dash_path(fz_gel *gel, fz_path *path, const fz_stroke_state *stroke, const fz_matrix *ctm, float flatness, float linewidth) { struct sctx s; fz_point p0, p1, p2, p3, beg; float phase_len, max_expand; int i, k; fz_matrix inv; s.gel = gel; s.ctm = ctm; s.flatness = flatness; s.linejoin = stroke->linejoin; s.linewidth = linewidth * 0.5f; s.miterlimit = stroke->miterlimit; s.sn = 0; s.dot = 0; s.dash_list = stroke->dash_list; s.dash_phase = stroke->dash_phase; s.dash_len = stroke->dash_len; s.toggle = 0; s.offset = 0; s.phase = 0; s.cap = stroke->start_cap; if (path->cmd_len > 0 && path->cmds[0] != FZ_MOVETO) return; phase_len = 0; for (i = 0; i < stroke->dash_len; i++) phase_len += stroke->dash_list[i]; if (stroke->dash_len > 0 && phase_len == 0) return; fz_gel_scissor(gel, &s.rect); if (fz_try_invert_matrix(&inv, ctm)) return; fz_transform_rect(&s.rect, &inv); s.rect.x0 -= linewidth; s.rect.x1 += linewidth; s.rect.y0 -= linewidth; s.rect.y1 += linewidth; max_expand = fz_matrix_max_expansion(ctm); if (phase_len < 1.0f && phase_len * max_expand < 0.5f) { fz_flatten_stroke_path(gel, path, stroke, ctm, flatness, linewidth); return; } s.dash_total = phase_len; /* cf. http://git.ghostscript.com/?p=mupdf.git;a=commitdiff;h=fd54bf89f2adfd5545202a6df87076fb7269f62c */ s.dash_phase = fmodf(s.dash_phase, s.dash_total); p0.x = p0.y = 0; i = k = 0; while (i < path->cmd_len) { switch (path->cmds[i++]) { case FZ_MOVETO: p1.x = path->coords[k++]; p1.y = path->coords[k++]; fz_dash_moveto(&s, p1, stroke->start_cap, stroke->end_cap); beg = p0 = p1; break; case FZ_LINETO: p1.x = path->coords[k++]; p1.y = path->coords[k++]; fz_dash_lineto(&s, p1, stroke->dash_cap, 0); p0 = p1; break; case FZ_CURVETO: p1.x = path->coords[k++]; p1.y = path->coords[k++]; p2.x = path->coords[k++]; p2.y = path->coords[k++]; p3.x = path->coords[k++]; p3.y = path->coords[k++]; fz_dash_bezier(&s, p0.x, p0.y, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, 0, stroke->dash_cap); p0 = p3; break; case FZ_CLOSE_PATH: fz_dash_lineto(&s, beg, stroke->dash_cap, 0); p0 = p1 = beg; break; } } fz_stroke_flush(&s, s.cap, stroke->end_cap); }