static void fz_draw_end_group(fz_device *devp) { fz_draw_device *dev = devp->user; int blendmode; int isolated; float alpha; fz_context *ctx = dev->ctx; fz_draw_state *state; if (dev->top == 0) { fz_warn(ctx, "Unexpected end_group"); return; } state = &dev->stack[--dev->top]; alpha = state[1].alpha; blendmode = state[1].blendmode & FZ_BLEND_MODEMASK; isolated = state[1].blendmode & FZ_BLEND_ISOLATED; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, ""); fz_dump_blend(dev->ctx, state[1].dest, "Group end: blending "); if (state[1].shape) fz_dump_blend(dev->ctx, state[1].shape, "/"); fz_dump_blend(dev->ctx, state[0].dest, " onto "); if (state[0].shape) fz_dump_blend(dev->ctx, state[0].shape, "/"); if (alpha != 1.0f) printf(" (alpha %g)", alpha); if (blendmode != 0) printf(" (blend %d)", blendmode); if (isolated != 0) printf(" (isolated)"); if (state[1].blendmode & FZ_BLEND_KNOCKOUT) printf(" (knockout)"); #endif if ((blendmode == 0) && (state[0].shape == state[1].shape)) fz_paint_pixmap(state[0].dest, state[1].dest, alpha * 255); else fz_blend_pixmap(state[0].dest, state[1].dest, alpha * 255, blendmode, isolated, state[1].shape); fz_drop_pixmap(dev->ctx, state[1].dest); if (state[0].shape != state[1].shape) { if (state[0].shape) fz_paint_pixmap(state[0].shape, state[1].shape, alpha * 255); fz_drop_pixmap(dev->ctx, state[1].shape); } #ifdef DUMP_GROUP_BLENDS fz_dump_blend(dev->ctx, state[0].dest, " to get "); if (state[0].shape) fz_dump_blend(dev->ctx, state[0].shape, "/"); printf("\n"); #endif if (state[0].blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
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_stroke_text(fz_context *ctx, void *user, fz_text *text, 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; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); fz_convert_color(ctx, colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_stroked_glyph(ctx, dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor); if (dev->shape) draw_glyph(colorbv, dev->shape, glyph, x, y, dev->scissor); fz_drop_pixmap(ctx, glyph); } } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_fill_path(fz_device *devp, fz_path *path, int even_odd, 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; 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; fz_reset_gel(dev->gel, state->scissor); fz_flatten_fill_path(dev->gel, path, ctm, flatness); 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, even_odd, bbox, state->dest, colorbv); if (state->shape) { fz_reset_gel(dev->gel, state->scissor); fz_flatten_fill_path(dev->gel, path, ctm, flatness); fz_sort_gel(dev->gel); colorbv[0] = alpha * 255; fz_scan_convert(dev->gel, even_odd, bbox, state->shape, colorbv); } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
static void fz_draw_fill_image(fz_context *ctx, void *user, fz_pixmap *image, fz_matrix ctm, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *converted = NULL; fz_pixmap *scaled = NULL; int after; int dx, dy; if (!model) { fz_warn(ctx, "cannot render image directly to an alpha mask"); return; } if (image->w == 0 || image->h == 0) return; /* convert images with more components (cmyk->rgb) before scaling */ /* convert images with fewer components (gray->rgb after scaling */ /* convert images with expensive colorspace transforms after scaling */ if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); after = 0; if (image->colorspace == fz_device_gray) after = 1; if (image->colorspace != model && !after) { converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(image)); fz_convert_pixmap(ctx, image, converted); image = converted; } dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); if (dx < image->w && dy < image->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); scaled = fz_transform_pixmap(ctx, image, &ctm, dev->dest->x, dev->dest->y, dx, dy, gridfit); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(ctx, image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } if (image->colorspace != model) { if ((image->colorspace == fz_device_gray && model == fz_device_rgb) || (image->colorspace == fz_device_gray && model == fz_device_bgr)) { /* We have special case rendering code for gray -> rgb/bgr */ } else { converted = fz_new_pixmap_with_rect(ctx, model, fz_bound_pixmap(image)); fz_convert_pixmap(ctx, image, converted); image = converted; } } fz_paint_image(dev->dest, dev->scissor, dev->shape, image, ctm, alpha * 255); if (scaled) fz_drop_pixmap(ctx, scaled); if (converted) fz_drop_pixmap(ctx, converted); if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_fill_shade(fz_context *ctx, void *user, fz_shade *shade, fz_matrix ctm, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *dest = dev->dest; fz_rect bounds; fz_bbox bbox, scissor; float colorfv[FZ_MAX_COLORS]; unsigned char colorbv[FZ_MAX_COLORS + 1]; bounds = fz_bound_shade(shade, ctm); bbox = fz_intersect_bbox(fz_round_rect(bounds), dev->scissor); scissor = dev->scissor; // TODO: proper clip by shade->bbox if (fz_is_empty_rect(bbox)) return; if (!model) { fz_warn(ctx, "cannot render shading directly to an alpha mask"); return; } if (alpha < 1) { dest = fz_new_pixmap_with_rect(ctx, dev->dest->colorspace, bbox); fz_clear_pixmap(dest); } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); if (shade->use_background) { unsigned char *s; int x, y, n, i; fz_convert_color(ctx, shade->colorspace, shade->background, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; n = dest->n; for (y = scissor.y0; y < scissor.y1; y++) { s = dest->samples + ((scissor.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n; for (x = scissor.x0; x < scissor.x1; x++) { for (i = 0; i < n; i++) *s++ = colorbv[i]; } } if (dev->shape) { for (y = scissor.y0; y < scissor.y1; y++) { s = dev->shape->samples + (scissor.x0 - dev->shape->x) + (y - dev->shape->y) * dev->shape->w; for (x = scissor.x0; x < scissor.x1; x++) { *s++ = 255; } } } } fz_paint_shade(ctx, shade, ctm, dest, bbox); if (dev->shape) fz_clear_pixmap_rect_with_color(dev->shape, 255, bbox); if (alpha < 1) { fz_paint_pixmap(dev->dest, dest, alpha * 255); fz_drop_pixmap(ctx, dest); } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_fill_text(fz_context *ctx, void *user, fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAX_COLORS + 1]; unsigned char shapebv; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_begin(ctx, dev); fz_convert_color(ctx, colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; shapebv = 255; tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); glyph = fz_render_glyph(ctx, dev->cache, text->font, gid, trm, model); if (glyph) { /* cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1746 */ if (glyph->n > 1 && text->font->t3procs) { float light; fz_convert_color(ctx, colorspace, color, fz_device_gray, &light); if (light != 0) { fz_pixmap *gray = fz_new_pixmap_with_rect(ctx, fz_device_gray, fz_bound_pixmap(glyph)); fz_convert_pixmap(ctx, glyph, gray); fz_drop_pixmap(ctx, glyph); glyph = fz_alpha_from_gray(ctx, gray, 0); fz_drop_pixmap(ctx, gray); } } if (glyph->n == 1) { draw_glyph(colorbv, dev->dest, glyph, x, y, dev->scissor); if (dev->shape) draw_glyph(&shapebv, dev->shape, glyph, x, y, dev->scissor); } else { fz_matrix ctm = {glyph->w, 0.0, 0.0, -glyph->h, x + glyph->x, y + glyph->y + glyph->h}; fz_paint_image(dev->dest, dev->scissor, dev->shape, glyph, ctm, alpha * 255); } fz_drop_pixmap(ctx, glyph); } } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_end_group(fz_context *ctx, void *user) { fz_draw_device *dev = user; fz_pixmap *group = dev->dest; fz_pixmap *shape = dev->shape; int blendmode; int isolated; float alpha; if (dev->top > 0) { dev->top--; alpha = dev->stack[dev->top].alpha; blendmode = dev->blendmode & FZ_BLEND_MODEMASK; isolated = dev->blendmode & FZ_BLEND_ISOLATED; dev->blendmode = dev->stack[dev->top].blendmode; dev->shape = dev->stack[dev->top].shape; dev->dest = dev->stack[dev->top].dest; dev->scissor = dev->stack[dev->top].scissor; #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, ""); fz_dump_blend(group, "Blending "); if (shape) fz_dump_blend(shape, "/"); fz_dump_blend(dev->dest, " onto "); if (dev->shape) fz_dump_blend(dev->shape, "/"); if (alpha != 1.0f) printf(" (alpha %g)", alpha); if (blendmode != 0) printf(" (blend %d)", blendmode); if (isolated != 0) printf(" (isolated)"); if (blendmode & FZ_BLEND_KNOCKOUT) printf(" (knockout)"); #endif if ((blendmode == 0) && (shape == NULL)) fz_paint_pixmap(dev->dest, group, alpha * 255); else fz_blend_pixmap(dev->dest, group, alpha * 255, blendmode, isolated, shape); fz_drop_pixmap(ctx, group); if (shape != dev->shape) { if (dev->shape) { fz_paint_pixmap(dev->shape, shape, alpha * 255); } fz_drop_pixmap(ctx, shape); } #ifdef DUMP_GROUP_BLENDS fz_dump_blend(dev->dest, " to get "); if (dev->shape) fz_dump_blend(dev->shape, "/"); printf("\n"); #endif } if (dev->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(ctx, dev); }
static void fz_draw_stroke_text(fz_device *devp, fz_text *text, fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = devp->user; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_matrix tm, trm, trunc_trm; fz_pixmap *glyph; int i, x, y, gid; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; fz_bbox scissor = state->scissor; 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; tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->items[i].gid; if (gid < 0) continue; tm.e = text->items[i].x; tm.f = text->items[i].y; trm = fz_concat(tm, ctm); x = floorf(trm.e); y = floorf(trm.f); trunc_trm = trm; trunc_trm.e = QUANT(trm.e - floorf(trm.e), HSUBPIX); trunc_trm.f = QUANT(trm.f - floorf(trm.f), VSUBPIX); scissor.x0 -= x; scissor.x1 -= x; scissor.y0 -= y; scissor.y1 -= y; glyph = fz_render_stroked_glyph(dev->ctx, text->font, gid, trunc_trm, ctm, stroke, scissor); if (glyph) { 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_pixmap(dev->ctx, glyph); } else { fz_path *path = fz_outline_glyph(dev->ctx, text->font, gid, trm); if (path) { fz_draw_stroke_path(devp, path, stroke, fz_identity, colorspace, color, alpha); fz_free_path(dev->ctx, path); } else { fz_warn(dev->ctx, "cannot render glyph"); } } } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
static void fz_draw_fill_image(fz_device *devp, fz_image *image, fz_matrix ctm, float alpha) { fz_draw_device *dev = devp->user; fz_pixmap *converted = NULL; fz_pixmap *scaled = NULL; fz_pixmap *pixmap; fz_pixmap *orig_pixmap; int after; int dx, dy; fz_context *ctx = dev->ctx; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; fz_bbox clip = fz_pixmap_bbox(ctx, state->dest); clip = fz_intersect_bbox(clip, state->scissor); fz_var(scaled); if (!model) { fz_warn(dev->ctx, "cannot render image directly to an alpha mask"); return; } if (image->w == 0 || image->h == 0) return; dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); pixmap = fz_image_to_pixmap(ctx, image, dx, dy); orig_pixmap = pixmap; /* convert images with more components (cmyk->rgb) before scaling */ /* convert images with fewer components (gray->rgb after scaling */ /* convert images with expensive colorspace transforms after scaling */ fz_try(ctx) { if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); after = 0; if (pixmap->colorspace == fz_device_gray) after = 1; if (pixmap->colorspace != model && !after) { converted = fz_new_pixmap_with_bbox(ctx, model, fz_pixmap_bbox(ctx, pixmap)); fz_convert_pixmap(ctx, converted, pixmap); pixmap = converted; } if (dx < pixmap->w && dy < pixmap->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); scaled = fz_transform_pixmap(ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); if (!scaled) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL); } if (scaled) pixmap = scaled; } if (pixmap->colorspace != model) { if ((pixmap->colorspace == fz_device_gray && model == fz_device_rgb) || (pixmap->colorspace == fz_device_gray && model == fz_device_bgr)) { /* We have special case rendering code for gray -> rgb/bgr */ } else { converted = fz_new_pixmap_with_bbox(ctx, model, fz_pixmap_bbox(ctx, pixmap)); fz_convert_pixmap(ctx, converted, pixmap); pixmap = converted; } } fz_paint_image(state->dest, state->scissor, state->shape, pixmap, ctm, alpha * 255); if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); } fz_always(ctx) { fz_drop_pixmap(ctx, scaled); fz_drop_pixmap(ctx, converted); fz_drop_pixmap(ctx, orig_pixmap); } fz_catch(ctx) { fz_rethrow(ctx); } }
static void fz_draw_fill_shade(fz_device *devp, fz_shade *shade, fz_matrix ctm, float alpha) { fz_draw_device *dev = devp->user; fz_rect bounds; fz_bbox bbox, scissor; fz_pixmap *dest, *shape; float colorfv[FZ_MAX_COLORS]; unsigned char colorbv[FZ_MAX_COLORS + 1]; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; bounds = fz_bound_shade(dev->ctx, shade, ctm); scissor = state->scissor; bbox = fz_intersect_bbox(fz_bbox_covering_rect(bounds), scissor); if (fz_is_empty_rect(bbox)) return; if (!model) { fz_warn(dev->ctx, "cannot render shading directly to an alpha mask"); return; } if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); dest = state->dest; shape = state->shape; if (alpha < 1) { dest = fz_new_pixmap_with_bbox(dev->ctx, state->dest->colorspace, bbox); fz_clear_pixmap(dev->ctx, dest); if (shape) { shape = fz_new_pixmap_with_bbox(dev->ctx, NULL, bbox); fz_clear_pixmap(dev->ctx, shape); } } if (shade->use_background) { unsigned char *s; int x, y, n, i; fz_convert_color(dev->ctx, model, colorfv, shade->colorspace, shade->background); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; n = dest->n; for (y = scissor.y0; y < scissor.y1; y++) { s = dest->samples + (unsigned int)(((scissor.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n); for (x = scissor.x0; x < scissor.x1; x++) { for (i = 0; i < n; i++) *s++ = colorbv[i]; } } if (shape) { for (y = scissor.y0; y < scissor.y1; y++) { s = shape->samples + (unsigned int)((scissor.x0 - shape->x) + (y - shape->y) * shape->w); for (x = scissor.x0; x < scissor.x1; x++) { *s++ = 255; } } } } fz_paint_shade(dev->ctx, shade, ctm, dest, bbox); if (shape) fz_clear_pixmap_rect_with_value(dev->ctx, shape, 255, bbox); if (alpha < 1) { fz_paint_pixmap(state->dest, dest, alpha * 255); fz_drop_pixmap(dev->ctx, dest); if (shape) { fz_paint_pixmap(state->shape, shape, alpha * 255); fz_drop_pixmap(dev->ctx, shape); } } if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
static void fz_draw_end_tile(fz_device *devp) { fz_draw_device *dev = devp->user; float xstep, ystep; fz_matrix ctm, ttm, shapectm; fz_rect area; int x0, y0, x1, y1, x, y; fz_context *ctx = dev->ctx; fz_draw_state *state; if (dev->top == 0) { fz_warn(ctx, "Unexpected end_tile"); return; } state = &dev->stack[--dev->top]; xstep = state[1].xstep; ystep = state[1].ystep; area = state[1].area; ctm = state[1].ctm; x0 = floorf(area.x0 / xstep); y0 = floorf(area.y0 / ystep); x1 = ceilf(area.x1 / xstep); y1 = ceilf(area.y1 / ystep); ctm.e = state[1].dest->x; ctm.f = state[1].dest->y; if (state[1].shape) { shapectm = ctm; shapectm.e = state[1].shape->x; shapectm.f = state[1].shape->y; } #ifdef DUMP_GROUP_BLENDS dump_spaces(dev->top, ""); fz_dump_blend(dev->ctx, state[1].dest, "Tiling "); if (state[1].shape) fz_dump_blend(dev->ctx, state[1].shape, "/"); fz_dump_blend(dev->ctx, state[0].dest, " onto "); if (state[0].shape) fz_dump_blend(dev->ctx, state[0].shape, "/"); #endif for (y = y0; y < y1; y++) { for (x = x0; x < x1; x++) { ttm = fz_concat(fz_translate(x * xstep, y * ystep), ctm); state[1].dest->x = ttm.e; state[1].dest->y = ttm.f; fz_paint_pixmap_with_rect(state[0].dest, state[1].dest, 255, state[0].scissor); if (state[1].shape) { ttm = fz_concat(fz_translate(x * xstep, y * ystep), shapectm); state[1].shape->x = ttm.e; state[1].shape->y = ttm.f; fz_paint_pixmap_with_rect(state[0].shape, state[1].shape, 255, state[0].scissor); } } } fz_drop_pixmap(dev->ctx, state[1].dest); fz_drop_pixmap(dev->ctx, state[1].shape); #ifdef DUMP_GROUP_BLENDS fz_dump_blend(dev->ctx, state[0].dest, " to get "); if (state[0].shape) fz_dump_blend(dev->ctx, state[0].shape, "/"); printf("\n"); #endif if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); }
static void fz_draw_fill_image_mask(fz_device *devp, fz_image *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_draw_device *dev = devp->user; unsigned char colorbv[FZ_MAX_COLORS + 1]; float colorfv[FZ_MAX_COLORS]; fz_pixmap *scaled = NULL; fz_pixmap *pixmap; fz_pixmap *orig_pixmap; int dx, dy; int i; fz_context *ctx = dev->ctx; fz_draw_state *state = &dev->stack[dev->top]; fz_colorspace *model = state->dest->colorspace; fz_bbox clip = fz_pixmap_bbox(ctx, state->dest); clip = fz_intersect_bbox(clip, state->scissor); if (image->w == 0 || image->h == 0) return; dx = sqrtf(ctm.a * ctm.a + ctm.b * ctm.b); dy = sqrtf(ctm.c * ctm.c + ctm.d * ctm.d); pixmap = fz_image_to_pixmap(ctx, image, dx, dy); orig_pixmap = pixmap; fz_try(ctx) { if (state->blendmode & FZ_BLEND_KNOCKOUT) state = fz_knockout_begin(dev); if (dx < pixmap->w && dy < pixmap->h) { int gridfit = alpha == 1.0f && !(dev->flags & FZ_DRAWDEV_FLAGS_TYPE3); scaled = fz_transform_pixmap(dev->ctx, pixmap, &ctm, state->dest->x, state->dest->y, dx, dy, gridfit, &clip); if (!scaled) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_scale_pixmap(dev->ctx, pixmap, pixmap->x, pixmap->y, dx, dy, NULL); } if (scaled) pixmap = scaled; } 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_paint_image_with_color(state->dest, state->scissor, state->shape, pixmap, ctm, colorbv); if (scaled) fz_drop_pixmap(dev->ctx, scaled); if (state->blendmode & FZ_BLEND_KNOCKOUT) fz_knockout_end(dev); } fz_always(ctx) { fz_drop_pixmap(dev->ctx, orig_pixmap); } fz_catch(ctx) { fz_rethrow(ctx); } }