static void fz_drawfillimage(void *user, fz_pixmap *image, fz_matrix ctm, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *converted = nil; fz_pixmap *scaled = nil; int dx, dy; if (!model) { fz_warn("cannot render image directly to an alpha mask"); return; } if (image->w == 0 || image->h == 0) return; if (image->colorspace != model) { converted = fz_newpixmap(model, image->x, image->y, image->w, image->h); fz_convertpixmap(image, converted); image = converted; } #ifdef SMOOTHSCALE dx = sqrtf(ctm.a * ctm.a + ctm.c * ctm.c); dy = sqrtf(ctm.b * ctm.b + ctm.d * ctm.d); if (dx < image->w && dy < image->h) { scaled = fz_smoothtransformpixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_smoothscalepixmap(image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } #else if (fz_calcimagescale(image, ctm, &dx, &dy)) { scaled = fz_scalepixmap(image, dx, dy); image = scaled; } #endif fz_paintimage(dev->dest, dev->scissor, image, ctm, alpha * 255); if (scaled) fz_droppixmap(scaled); if (converted) fz_droppixmap(converted); }
void fz_droprenderer(fz_renderer *gc) { if (gc->dest) fz_droppixmap(gc->dest); if (gc->over) fz_droppixmap(gc->over); if (gc->model) fz_dropcolorspace(gc->model); if (gc->cache) fz_dropglyphcache(gc->cache); if (gc->gel) fz_dropgel(gc->gel); if (gc->ael) fz_dropael(gc->ael); fz_free(gc); }
fz_error * fz_rendertreeover(fz_renderer *gc, fz_pixmap *dest, fz_tree *tree, fz_matrix ctm) { fz_error *error; assert(!gc->maskonly); assert(dest->n == 4); gc->clip.x0 = dest->x; gc->clip.y0 = dest->y; gc->clip.x1 = dest->x + dest->w; gc->clip.y1 = dest->y + dest->h; gc->over = dest; error = rendernode(gc, tree->root, ctm); if (error) { gc->over = nil; return error; } if (gc->dest) { blendover(gc, gc->dest, gc->over); fz_droppixmap(gc->dest); gc->dest = nil; } gc->over = nil; return fz_okay; }
void pdfapp_close(pdfapp_t *app) { if (app->cache) fz_freeglyphcache(app->cache); app->cache = nil; if (app->page) pdf_droppage(app->page); app->page = nil; if (app->image) fz_droppixmap(app->image); app->image = nil; if (app->text) fz_freetextspan(app->text); app->text = nil; if (app->outline) pdf_dropoutline(app->outline); app->outline = nil; if (app->xref->store) pdf_dropstore(app->xref->store); app->xref->store = nil; pdf_closexref(app->xref); app->xref = nil; }
void pdfapp_close(pdfapp_t *app) { if (app->pages) pdf_droppagetree(app->pages); app->pages = nil; if (app->page) pdf_droppage(app->page); app->page = nil; if (app->image) fz_droppixmap(app->image); app->image = nil; if (app->outline) pdf_dropoutline(app->outline); app->outline = nil; if (app->xref->store) pdf_dropstore(app->xref->store); app->xref->store = nil; pdf_closexref(app->xref); app->xref = nil; }
static int pdfLoadPage(PDFContext* ctx) { if (fullPageBuffer != NULL) { fz_droppixmap(fullPageBuffer); fullPageBuffer = NULL; } strcpy(lastPageError, "No error"); fz_error *error; fz_obj *obj; if (ctx->page) pdf_droppage(ctx->page); ctx->page = 0; // empty store to save memory if (ctx->xref->store) pdf_emptystore(ctx->xref->store); bk_pdf_resetbufferssize(); /* pdf_item *item; fz_obj *key; list<fz_obj *key> keys; for (item = ctx->xref->store->root; item; item = item->next) { if (item->kind == PDF_KIMAGE) keys << key; } list<fz_obj *key>::iterator it(keys.begin); while (it != keys.end()) { ++it; } */ obj = pdf_getpageobject(ctx->pages, ctx->pageno - 1, ctx->xref); error = pdf_loadpage(&ctx->page, ctx->xref, obj); if (error) { printf("errLP1: %s\n", error->msg); strcpy(lastPageError, error->msg); return -1; } //printf("\n\n debug tree ------------------------------------------------\n"); //fz_debugtree(ctx->page->tree); //optimizeNode(ctx->page->tree->root); //printf("\n\n OPT debug tree OPT ------------------------------------------------\n"); //fz_debugtree(ctx->page->tree); recalcScreenMediaBox(ctx); if (BKUser::options.pdfFastScroll) { pdfRenderFullPage(ctx); } return 0; }
static void fz_drawpopclip(void *user) { fz_drawdevice *dev = user; fz_pixmap *mask, *dest; if (dev->top > 0) { dev->top--; dev->scissor = dev->stack[dev->top].scissor; mask = dev->stack[dev->top].mask; dest = dev->stack[dev->top].dest; if (mask && dest) { fz_pixmap *scratch = dev->dest; fz_paintpixmapmask(dest, scratch, mask); fz_droppixmap(mask); fz_droppixmap(scratch); dev->dest = dest; } } }
static void fz_drawfillimagemask(void *user, fz_pixmap *image, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAXCOLORS + 1]; float colorfv[FZ_MAXCOLORS]; fz_pixmap *scaled = nil; int dx, dy; int i; if (image->w == 0 || image->h == 0) return; #ifdef SMOOTHSCALE 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) { scaled = fz_smoothtransformpixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_smoothscalepixmap(image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } #else if (fz_calcimagescale(image, ctm, &dx, &dy)) { scaled = fz_scalepixmap(image, dx, dy); image = scaled; } #endif fz_convertcolor(colorspace, color, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = alpha * 255; fz_paintimagecolor(dev->dest, dev->scissor, image, ctm, colorbv); if (scaled) fz_droppixmap(scaled); }
fz_error fz_rendert3glyph(fz_glyph *glyph, fz_font *font, int gid, fz_matrix trm) { fz_error error; fz_renderer *gc; fz_tree *tree; fz_matrix ctm; fz_irect bbox; /* TODO: make it reentrant */ static fz_pixmap *pixmap = nil; if (pixmap) { fz_droppixmap(pixmap); pixmap = nil; } if (gid < 0 || gid > 255) return fz_throw("assert: glyph out of range"); tree = font->t3procs[gid]; if (!tree) { glyph->w = 0; glyph->h = 0; return fz_okay; } ctm = fz_concat(font->t3matrix, trm); bbox = fz_roundrect(fz_boundtree(tree, ctm)); error = fz_newrenderer(&gc, pdf_devicegray, 1, 4096); if (error) return fz_rethrow(error, "cannot create renderer"); error = fz_rendertree(&pixmap, gc, tree, ctm, bbox, 0); fz_droprenderer(gc); if (error) return fz_rethrow(error, "cannot render glyph"); assert(pixmap->n == 1); glyph->x = pixmap->x; glyph->y = pixmap->y; glyph->w = pixmap->w; glyph->h = pixmap->h; glyph->samples = pixmap->samples; return fz_okay; }
void pdfapp_close(pdfapp_t *app) { #if 0 if (app->page) pdf_droppage(app->page); app->page = nil; if (app->image) fz_droppixmap(app->image); app->image = nil; /* if (app->outline) pdf_dropoutline(app->outline); app->outline = nil;*/ if (app->xref->store) pdf_dropstore(app->xref->store); app->xref->store = nil; pdf_closexref(app->xref); app->xref = nil; #else if (app->cache) fz_free_glyph_cache(app->cache); app->cache = NULL; if (app->image) fz_drop_pixmap(app->image); app->image = NULL; if (app->outline) pdf_free_outline(app->outline); app->outline = NULL; if (app->xref) { if (app->xref->store) pdf_free_store(app->xref->store); app->xref->store = NULL; pdf_free_xref(app->xref); app->xref = NULL; } fz_flush_warnings(); #endif }
NPError NPP_Destroy(NPP inst, NPSavedData **saved) { pdfmoz_t *moz = inst->pdata; int i; //MSG("NPP_Destroy"); inst->pdata = NULL; DeleteObject(moz->graybrush); DestroyCursor(moz->arrow); DestroyCursor(moz->hand); DestroyCursor(moz->wait); fz_free(moz->dibinf); for (i = 0; i < moz->pagecount; i++) { if (moz->pages[i].obj) fz_dropobj(moz->pages[i].obj); if (moz->pages[i].page) pdf_droppage(moz->pages[i].page); if (moz->pages[i].image) fz_droppixmap(moz->pages[i].image); } fz_free(moz->pages); if (moz->xref) { if (moz->xref->store) { pdf_dropstore(moz->xref->store); moz->xref->store = nil; } pdf_closexref(moz->xref); } fz_free(moz); return NPERR_NO_ERROR; }
BKPDF::~BKPDF() { if (ctx != 0) { saveLastView(); pdfClose(ctx); delete ctx; } ctx = 0; singleton = 0; if (fullPageBuffer != NULL) { fz_droppixmap(fullPageBuffer); fullPageBuffer = NULL; } //#error reactivate the hash! //#error idea - list allocs linear, list frees linear, do merge every N allocs bkfree_all(); }
static fz_error * renderover(fz_renderer *gc, fz_overnode *over, fz_matrix ctm) { fz_error *error; fz_node *child; int cluster = 0; if (!gc->over) { DEBUG("over cluster %d\n{\n", gc->maskonly ? 1 : 4); cluster = 1; if (gc->maskonly) error = fz_newpixmapwithrect(&gc->over, gc->clip, 1); else error = fz_newpixmapwithrect(&gc->over, gc->clip, 4); if (error) return error; fz_clearpixmap(gc->over); } else DEBUG("over\n{\n"); for (child = over->super.first; child; child = child->next) { error = rendernode(gc, child, ctm); if (error) return error; if (gc->dest) { blendover(gc, gc->dest, gc->over); fz_droppixmap(gc->dest); gc->dest = nil; } } if (cluster) { gc->dest = gc->over; gc->over = nil; } DEBUG("}\n"); return fz_okay; }
fz_error * fz_rendertree(fz_pixmap **outp, fz_renderer *gc, fz_tree *tree, fz_matrix ctm, fz_irect bbox, int white) { fz_error *error; gc->clip = bbox; gc->over = nil; if (gc->maskonly) error = fz_newpixmapwithrect(&gc->over, bbox, 1); else error = fz_newpixmapwithrect(&gc->over, bbox, 4); if (error) return error; if (white) memset(gc->over->samples, 0xff, gc->over->w * gc->over->h * gc->over->n); else memset(gc->over->samples, 0x00, gc->over->w * gc->over->h * gc->over->n); DEBUG("tree %d [%d %d %d %d]\n{\n", gc->maskonly ? 1 : 4, bbox.x0, bbox.y0, bbox.x1, bbox.y1); error = rendernode(gc, tree->root, ctm); if (error) return error; DEBUG("}\n"); if (gc->dest) { blendover(gc, gc->dest, gc->over); fz_droppixmap(gc->dest); gc->dest = nil; } *outp = gc->over; gc->over = nil; return fz_okay; }
static void pdfRenderFullPage(PDFContext* ctx) { if (fullPageBuffer != NULL) { fz_droppixmap(fullPageBuffer); fullPageBuffer = NULL; } float h = ctx->page->mediabox.y1 - ctx->page->mediabox.y0; float w = ctx->page->mediabox.x1 - ctx->page->mediabox.x0; fullPageBuffer = pdfRenderTile(ctx, (int)ctx->page->mediabox.x0, (int)ctx->page->mediabox.y0, (int)w, (int)h, true); // precalc color shift unsigned int* s = (unsigned int*)fullPageBuffer->samples; unsigned int n = fullPageBuffer->w * fullPageBuffer->h; for (unsigned int i = 0; i < n; ++i) { *s >>= 8; ++s; } }
fz_pixmap * fz_rendert3glyph(fz_font *font, int gid, fz_matrix trm) { fz_error error; fz_matrix ctm; fz_buffer *contents; fz_bbox bbox; fz_device *dev; fz_glyphcache *cache; fz_pixmap *glyph; fz_pixmap *result; if (gid < 0 || gid > 255) return NULL; contents = font->t3procs[gid]; if (!contents) return NULL; ctm = fz_concat(font->t3matrix, trm); dev = fz_newbboxdevice(&bbox); error = font->t3run(font->t3xref, font->t3resources, contents, dev, ctm); if (error) fz_catch(error, "cannot draw type3 glyph"); fz_freedevice(dev); glyph = fz_newpixmap(fz_devicegray, bbox.x0-1, bbox.y0-1, bbox.x1 - bbox.x0 + 1, bbox.y1 - bbox.y0 + 1); fz_clearpixmap(glyph, 0); cache = fz_newglyphcache(); dev = fz_newdrawdevice(cache, glyph); error = font->t3run(font->t3xref, font->t3resources, contents, dev, ctm); if (error) fz_catch(error, "cannot draw type3 glyph"); fz_freedevice(dev); fz_freeglyphcache(cache); result = fz_alphafromgray(glyph, 0); fz_droppixmap(glyph); return result; }
static void fz_drawstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix ctm, fz_colorspace *colorspace, float *color, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; unsigned char colorbv[FZ_MAXCOLORS + 1]; float colorfv[FZ_MAXCOLORS]; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; fz_convertcolor(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->els[i].gid; if (gid < 0) continue; tm.e = text->els[i].x; tm.f = text->els[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_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { drawglyph(colorbv, dev->dest, glyph, x, y, dev->scissor); fz_droppixmap(glyph); } } }
static void fz_drawendmask(void *user) { fz_drawdevice *dev = user; fz_pixmap *mask = dev->dest; fz_pixmap *temp, *dest; fz_bbox bbox; int luminosity; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } if (dev->top > 0) { /* pop soft mask buffer */ dev->top--; luminosity = dev->stack[dev->top].luminosity; dev->scissor = dev->stack[dev->top].scissor; dev->dest = dev->stack[dev->top].dest; /* convert to alpha mask */ temp = fz_alphafromgray(mask, luminosity); fz_droppixmap(mask); /* create new dest scratch buffer */ bbox = fz_boundpixmap(temp); dest = fz_newpixmapwithrect(dev->dest->colorspace, bbox); fz_clearpixmap(dest, 0); /* push soft mask as clip mask */ dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = temp; dev->stack[dev->top].dest = dev->dest; dev->scissor = bbox; dev->dest = dest; dev->top++; } }
static void fz_drawendgroup(void *user) { fz_drawdevice *dev = user; fz_pixmap *group = dev->dest; fz_blendmode blendmode; float alpha; if (dev->top > 0) { dev->top--; alpha = dev->stack[dev->top].alpha; blendmode = dev->stack[dev->top].blendmode; dev->dest = dev->stack[dev->top].dest; dev->scissor = dev->stack[dev->top].scissor; if (blendmode == FZ_BNORMAL) fz_paintpixmap(dev->dest, group, alpha * 255); else fz_blendpixmap(dev->dest, group, alpha * 255, blendmode); fz_droppixmap(group); } }
static void fz_drawclipimagemask(void *user, fz_pixmap *image, fz_matrix ctm) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_pixmap *scaled = nil; int dx, dy; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } if (image->w == 0 || image->h == 0) { dev->stack[dev->top].scissor = dev->scissor; dev->stack[dev->top].mask = nil; dev->stack[dev->top].dest = nil; dev->scissor = fz_emptybbox; dev->top++; return; } bbox = fz_roundrect(fz_transformrect(ctm, fz_unitrect)); bbox = fz_intersectbbox(bbox, dev->scissor); mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(mask, 0); fz_clearpixmap(dest, 0); #ifdef SMOOTHSCALE 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) { scaled = fz_smoothtransformpixmap(image, &ctm, dev->dest->x, dev->dest->y, dx, dy); if (scaled == NULL) { if (dx < 1) dx = 1; if (dy < 1) dy = 1; scaled = fz_smoothscalepixmap(image, image->x, image->y, dx, dy); } if (scaled != NULL) image = scaled; } #else if (fz_calcimagescale(image, ctm, &dx, &dy)) { scaled = fz_scalepixmap(image, dx, dy); image = scaled; } #endif fz_paintimage(mask, bbox, image, ctm, 255); if (scaled) fz_droppixmap(scaled); 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 fz_error pdf_loadimageimp(fz_pixmap **imgp, pdf_xref *xref, fz_obj *rdb, fz_obj *dict, fz_stream *cstm, int forcemask) { fz_stream *stm; fz_pixmap *tile; fz_obj *obj, *res; fz_error error; int w, h, bpc, n; int imagemask; int interpolate; int indexed; fz_colorspace *colorspace; fz_pixmap *mask; /* explicit mask/softmask image */ int usecolorkey; int colorkey[FZ_MAXCOLORS * 2]; float decode[FZ_MAXCOLORS * 2]; int scale; int stride; unsigned char *samples; int i, len; /* special case for JPEG2000 images */ if (pdf_isjpximage(dict)) { tile = nil; error = pdf_loadjpximage(&tile, xref, dict); if (error) return fz_rethrow(error, "cannot load jpx image"); if (forcemask) { if (tile->n != 2) { fz_droppixmap(tile); return fz_throw("softmask must be grayscale"); } mask = fz_alphafromgray(tile, 1); fz_droppixmap(tile); *imgp = mask; return fz_okay; } *imgp = tile; return fz_okay; } w = fz_toint(fz_dictgetsa(dict, "Width", "W")); h = fz_toint(fz_dictgetsa(dict, "Height", "H")); bpc = fz_toint(fz_dictgetsa(dict, "BitsPerComponent", "BPC")); imagemask = fz_tobool(fz_dictgetsa(dict, "ImageMask", "IM")); interpolate = fz_tobool(fz_dictgetsa(dict, "Interpolate", "I")); indexed = 0; usecolorkey = 0; colorspace = nil; mask = nil; if (imagemask) bpc = 1; if (w == 0) return fz_throw("image width is zero"); if (h == 0) return fz_throw("image height is zero"); if (bpc == 0) return fz_throw("image depth is zero"); if (w > (1 << 16)) return fz_throw("image is too wide"); if (h > (1 << 16)) return fz_throw("image is too high"); obj = fz_dictgetsa(dict, "ColorSpace", "CS"); if (obj && !imagemask && !forcemask) { /* colorspace resource lookup is only done for inline images */ if (fz_isname(obj)) { res = fz_dictget(fz_dictgets(rdb, "ColorSpace"), obj); if (res) obj = res; } error = pdf_loadcolorspace(&colorspace, xref, obj); if (error) return fz_rethrow(error, "cannot load image colorspace"); if (!strcmp(colorspace->name, "Indexed")) indexed = 1; n = colorspace->n; } else { n = 1; } obj = fz_dictgetsa(dict, "Decode", "D"); if (obj) { for (i = 0; i < n * 2; i++) decode[i] = fz_toreal(fz_arrayget(obj, i)); } else { float maxval = indexed ? (1 << bpc) - 1 : 1; for (i = 0; i < n * 2; i++) decode[i] = i & 1 ? maxval : 0; } obj = fz_dictgetsa(dict, "SMask", "Mask"); if (fz_isdict(obj)) { /* Not allowed for inline images */ if (!cstm) { error = pdf_loadimageimp(&mask, xref, rdb, obj, nil, 1); if (error) { if (colorspace) fz_dropcolorspace(colorspace); return fz_rethrow(error, "cannot load image mask/softmask"); } } } else if (fz_isarray(obj)) { usecolorkey = 1; for (i = 0; i < n * 2; i++) colorkey[i] = fz_toint(fz_arrayget(obj, i)); } stride = (w * n * bpc + 7) / 8; samples = fz_calloc(h, stride); if (cstm) { stm = pdf_openinlinestream(cstm, xref, dict, stride * h); } else { error = pdf_openstream(&stm, xref, fz_tonum(dict), fz_togen(dict)); if (error) { if (colorspace) fz_dropcolorspace(colorspace); if (mask) fz_droppixmap(mask); return fz_rethrow(error, "cannot open image data stream (%d 0 R)", fz_tonum(dict)); } } len = fz_read(stm, samples, h * stride); if (len < 0) { fz_close(stm); if (colorspace) fz_dropcolorspace(colorspace); if (mask) fz_droppixmap(mask); return fz_rethrow(len, "cannot read image data"); } /* Make sure we read the EOF marker (for inline images only) */ if (cstm) { unsigned char tbuf[512]; int tlen = fz_read(stm, tbuf, sizeof tbuf); if (tlen < 0) fz_catch(tlen, "ignoring error at end of image"); if (tlen > 0) fz_warn("ignoring garbage at end of image"); } fz_close(stm); /* Pad truncated images */ if (len < stride * h) { fz_warn("padding truncated image (%d 0 R)", fz_tonum(dict)); memset(samples + len, 0, stride * h - len); } /* Invert 1-bit image masks */ if (imagemask) { /* 0=opaque and 1=transparent so we need to invert */ unsigned char *p = samples; len = h * stride; for (i = 0; i < len; i++) p[i] = ~p[i]; } pdf_logimage("size %dx%d n=%d bpc=%d imagemask=%d indexed=%d\n", w, h, n, bpc, imagemask, indexed); /* Unpack samples into pixmap */ tile = fz_newpixmap(colorspace, 0, 0, w, h); scale = 1; if (!indexed) { switch (bpc) { case 1: scale = 255; break; case 2: scale = 85; break; case 4: scale = 17; break; } } fz_unpacktile(tile, samples, n, bpc, stride, scale); if (usecolorkey) pdf_maskcolorkey(tile, n, colorkey); if (indexed) { fz_pixmap *conv; fz_decodeindexedtile(tile, decode, (1 << bpc) - 1); conv = pdf_expandindexedpixmap(tile); fz_droppixmap(tile); tile = conv; } else { fz_decodetile(tile, decode); } if (colorspace) fz_dropcolorspace(colorspace); tile->mask = mask; tile->interpolate = interpolate; fz_free(samples); *imgp = tile; return fz_okay; }
static void fz_drawfillshade(void *user, fz_shade *shade, fz_matrix ctm, float alpha) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_pixmap *dest = dev->dest; fz_rect bounds; fz_bbox bbox; float colorfv[FZ_MAXCOLORS]; unsigned char colorbv[FZ_MAXCOLORS + 1]; bounds = fz_boundshade(shade, ctm); bbox = fz_intersectbbox(fz_roundrect(bounds), dev->scissor); // TODO: proper clip by shade->bbox if (!fz_isemptyrect(shade->bbox)) { bounds = fz_transformrect(fz_concat(shade->matrix, ctm), shade->bbox); bbox = fz_intersectbbox(fz_roundrect(bounds), bbox); } if (fz_isemptyrect(bbox)) return; if (!model) { fz_warn("cannot render shading directly to an alpha mask"); return; } if (alpha < 1) { dest = fz_newpixmapwithrect(dev->dest->colorspace, bbox); fz_clearpixmap(dest, 0); } if (shade->usebackground) { unsigned char *s; int x, y, n, i; fz_convertcolor(shade->cs, shade->background, model, colorfv); for (i = 0; i < model->n; i++) colorbv[i] = colorfv[i] * 255; colorbv[i] = 255; n = dest->n; for (y = bbox.y0; y < bbox.y1; y++) { s = dest->samples + ((bbox.x0 - dest->x) + (y - dest->y) * dest->w) * dest->n; for (x = bbox.x0; x < bbox.x1; x++) { for (i = 0; i < n; i++) *s++ = colorbv[i]; } } } fz_rendershade(shade, ctm, dest, bbox); if (alpha < 1) { fz_paintpixmap(dev->dest, dest, alpha * 255); fz_droppixmap(dest); } }
static void fz_drawclipstroketext(void *user, fz_text *text, fz_strokestate *stroke, fz_matrix ctm) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } /* make the mask the exact size needed */ bbox = fz_roundrect(fz_boundtext(text, ctm)); bbox = fz_intersectbbox(bbox, dev->scissor); mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(mask, 0); fz_clearpixmap(dest, 0); 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++; if (!fz_isemptyrect(bbox)) { tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->els[i].gid; if (gid < 0) continue; tm.e = text->els[i].x; tm.f = text->els[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_renderstrokedglyph(dev->cache, text->font, gid, trm, ctm, stroke); if (glyph) { drawglyph(nil, mask, glyph, x, y, bbox); fz_droppixmap(glyph); } } } }
static void drawpnm(int pagenum, struct benchmark *loadtimes, struct benchmark *drawtimes) { fz_error error; fz_matrix ctm; fz_irect bbox; fz_pixmap *pix; char name[256]; char pnmhdr[256]; int i, x, y, w, h, b, bh; int fd = -1; long start; long end; long elapsed; fz_md5 digest; if (!drawpattern) fz_md5init(&digest); drawloadpage(pagenum, loadtimes); if (benchmark) gettime(&start); ctm = fz_identity(); ctm = fz_concat(ctm, fz_translate(0, -drawpage->mediabox.y1)); ctm = fz_concat(ctm, fz_scale(drawzoom, -drawzoom)); ctm = fz_concat(ctm, fz_rotate(drawrotate + drawpage->rotate)); bbox = fz_roundrect(fz_transformaabb(ctm, drawpage->mediabox)); w = bbox.x1 - bbox.x0; h = bbox.y1 - bbox.y0; bh = h / drawbands; if (drawpattern) { sprintf(name, drawpattern, drawcount++); fd = open(name, O_BINARY|O_WRONLY|O_CREAT|O_TRUNC, 0666); if (fd < 0) die(fz_throw("ioerror: could not open file '%s'", name)); sprintf(pnmhdr, "P6\n%d %d\n255\n", w, h); write(fd, pnmhdr, strlen(pnmhdr)); } error = fz_newpixmap(&pix, bbox.x0, bbox.y0, w, bh, 4); if (error) die(error); memset(pix->samples, 0xff, pix->h * pix->w * pix->n); for (b = 0; b < drawbands; b++) { if (drawbands > 1) fprintf(stderr, "drawing band %d / %d\n", b + 1, drawbands); error = fz_rendertreeover(drawgc, pix, drawpage->tree, ctm); if (error) die(error); if (drawpattern) { for (y = 0; y < pix->h; y++) { unsigned char *src = pix->samples + y * pix->w * 4; unsigned char *dst = src; for (x = 0; x < pix->w; x++) { dst[x * 3 + 0] = src[x * 4 + 1]; dst[x * 3 + 1] = src[x * 4 + 2]; dst[x * 3 + 2] = src[x * 4 + 3]; } write(fd, dst, pix->w * 3); memset(src, 0xff, pix->w * 4); } } if (!drawpattern) fz_md5update(&digest, pix->samples, pix->h * pix->w * 4); pix->y += bh; if (pix->y + pix->h > bbox.y1) pix->h = bbox.y1 - pix->y; } fz_droppixmap(pix); if (!drawpattern) { unsigned char buf[16]; fz_md5final(&digest, buf); for (i = 0; i < 16; i++) fprintf(stderr, "%02x", buf[i]); } if (drawpattern) close(fd); drawfreepage(); if (benchmark) { gettime(&end); elapsed = end - start; if (elapsed < drawtimes->min) { drawtimes->min = elapsed; drawtimes->minpage = pagenum; } if (elapsed > drawtimes->max) { drawtimes->max = elapsed; drawtimes->maxpage = pagenum; } drawtimes->avg += elapsed; drawtimes->pages++; fprintf(stderr, " time %.3fs", elapsed / 1000000.0); } fprintf(stderr, "\n"); }
static fz_error pdf_loadjpximage(fz_pixmap **imgp, pdf_xref *xref, fz_obj *dict) { fz_error error; fz_buffer *buf; fz_pixmap *img; fz_obj *obj; pdf_logimage("jpeg2000\n"); error = pdf_loadstream(&buf, xref, fz_tonum(dict), fz_togen(dict)); if (error) return fz_rethrow(error, "cannot load jpx image data"); error = fz_loadjpximage(&img, buf->data, buf->len); if (error) { fz_dropbuffer(buf); return fz_rethrow(error, "cannot load jpx image"); } fz_dropbuffer(buf); obj = fz_dictgetsa(dict, "SMask", "Mask"); if (fz_isdict(obj)) { error = pdf_loadimageimp(&img->mask, xref, nil, obj, nil, 1); if (error) { fz_droppixmap(img); return fz_rethrow(error, "cannot load image mask/softmask"); } } obj = fz_dictgets(dict, "ColorSpace"); if (obj) { fz_colorspace *original = img->colorspace; img->colorspace = nil; error = pdf_loadcolorspace(&img->colorspace, xref, obj); if (error) { fz_dropcolorspace(original); return fz_rethrow(error, "cannot load image colorspace"); } if (original->n != img->colorspace->n) { fz_warn("jpeg-2000 colorspace (%s) does not match promised colorspace (%s)", original->name, img->colorspace->name); fz_dropcolorspace(img->colorspace); img->colorspace = original; } else fz_dropcolorspace(original); if (!strcmp(img->colorspace->name, "Indexed")) { fz_pixmap *conv; conv = pdf_expandindexedpixmap(img); fz_droppixmap(img); img = conv; } } *imgp = img; return fz_okay; }
static void saveimage(fz_obj *obj, int num, int gen) { pdf_image *img = nil; fz_obj *ref; fz_error error; fz_pixmap *pix; char name[1024]; FILE *f; int bpc; int w; int h; int n; int x; int y; error = fz_newindirect(&ref, num, gen, xref); if (error) die(error); error = pdf_newstore(&xref->store); if (error) die(error); error = pdf_loadimage(&img, xref, ref); if (error) die(error); n = img->super.n; w = img->super.w; h = img->super.h; bpc = img->bpc; error = fz_newpixmap(&pix, 0, 0, w, h, n + 1); if (error) die(error); error = img->super.loadtile(&img->super, pix); if (error) die(error); if (bpc == 1 && n == 0) { fz_pixmap *temp; error = fz_newpixmap(&temp, pix->x, pix->y, pix->w, pix->h, pdf_devicergb->n + 1); if (error) die(error); for (y = 0; y < pix->h; y++) for (x = 0; x < pix->w; x++) { int pixel = y * pix->w + x; temp->samples[pixel * temp->n + 0] = 255; temp->samples[pixel * temp->n + 1] = pix->samples[pixel]; temp->samples[pixel * temp->n + 2] = pix->samples[pixel]; temp->samples[pixel * temp->n + 3] = pix->samples[pixel]; } fz_droppixmap(pix); pix = temp; } if (img->super.cs && strcmp(img->super.cs->name, "DeviceRGB")) { fz_pixmap *temp; error = fz_newpixmap(&temp, pix->x, pix->y, pix->w, pix->h, pdf_devicergb->n + 1); if (error) die(error); fz_convertpixmap(img->super.cs, pix, pdf_devicergb, temp); fz_droppixmap(pix); pix = temp; } sprintf(name, "img-%04d.pnm", num); f = fopen(name, "wb"); if (f == NULL) die(fz_throw("Error creating image file")); fprintf(f, "P6\n%d %d\n%d\n", w, h, 255); for (y = 0; y < pix->h; y++) for (x = 0; x < pix->w; x++) { fz_sample *sample = &pix->samples[(y * pix->w + x) * (pdf_devicergb->n + 1)]; unsigned char r = sample[1]; unsigned char g = sample[2]; unsigned char b = sample[3]; fprintf(f, "%c%c%c", r, g, b); } if (fclose(f) < 0) die(fz_throw("Error closing image file")); fz_droppixmap(pix); pdf_dropstore(xref->store); xref->store = nil; fz_dropimage(&img->super); fz_dropobj(ref); }
LRESULT CALLBACK MozWinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { pdfmoz_t *moz = (pdfmoz_t*) GetWindowLongPtr(hwnd, GWLP_USERDATA); char buf[256]; int x = (signed short) LOWORD(lParam); int y = (signed short) HIWORD(lParam); int i, h; SCROLLINFO si; PAINTSTRUCT ps; HDC hdc; RECT rc; RECT pad; WORD sendmsg; float zoom; GetClientRect(hwnd, &rc); h = rc.bottom - rc.top; if (strlen(moz->error)) { if (msg == WM_PAINT) { hdc = BeginPaint(hwnd, &ps); FillRect(hdc, &rc, GetStockBrush(WHITE_BRUSH)); rc.top += 10; rc.bottom -= 10; rc.left += 10; rc.right -= 10; DrawText(hdc, moz->error, strlen(moz->error), &rc, 0); // DT_SINGLELINE|DT_CENTER|DT_VCENTER); EndPaint(hwnd, &ps); } if (msg == WM_MOUSEMOVE) { SetCursor(moz->arrow); } return 0; } switch (msg) { case WM_PAINT: GetClientRect(moz->hwnd, &rc); si.cbSize = sizeof(si); si.fMask = SIF_ALL; GetScrollInfo(hwnd, SB_VERT, &si); decodescroll(moz, si.nPos); /* evict out-of-range images and pages */ for (i = 0; i < moz->pagecount; i++) { if (i < moz->scrollpage - 2 || i > moz->scrollpage + 6) { if (moz->pages[i].page) { pdf_droppage(moz->pages[i].page); moz->pages[i].page = nil; } } if (i < moz->scrollpage - 1 || i > moz->scrollpage + 3) { if (moz->pages[i].image) { fz_droppixmap(moz->pages[i].image); moz->pages[i].image = nil; } } } i = moz->scrollpage; pdfmoz_loadpage(moz, i); if (moz->error[0]) return 0; pdfmoz_drawpage(moz, i); if (moz->error[0]) return 0; y = -moz->scrollyofs; while (y < h && i < moz->pagecount) { pdfmoz_loadpage(moz, i); if (moz->error[0]) return 0; pdfmoz_drawpage(moz, i); if (moz->error[0]) return 0; y += moz->pages[i].image->h; i ++; } hdc = BeginPaint(hwnd, &ps); pad.left = rc.left; pad.right = rc.right; i = moz->scrollpage; y = -moz->scrollyofs; while (y < h && i < moz->pagecount) { drawimage(hdc, moz, moz->pages[i].image, y); y += moz->pages[i].image->h; i ++; pad.top = y; pad.bottom = y + PAD; FillRect(hdc, &pad, moz->graybrush); y += PAD; } if (y < h) { pad.top = y; pad.bottom = h; FillRect(hdc, &pad, moz->graybrush); } EndPaint(hwnd, &ps); return 0; case WM_SIZE: ShowScrollBar(moz->hwnd, SB_VERT, TRUE); GetClientRect(moz->hwnd, &rc); si.cbSize = sizeof(si); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; si.nPos = 0; si.nMin = 0; si.nMax = 0; // si.nPage = MAX(30, rc.bottom - rc.top - 30); si.nPage = rc.bottom - rc.top; for (i = 0; i < moz->pagecount; i++) { zoom = (rc.right - rc.left) / (float) moz->pages[i].w; moz->pages[i].px = zoom * moz->pages[i].h + PAD; if (moz->scrollpage == i) { si.nPos = si.nMax; if (moz->pages[i].image) { si.nPos += moz->pages[i].px * moz->scrollyofs / moz->pages[i].image->h + 1; } } if (moz->pages[i].image) { fz_droppixmap(moz->pages[i].image); moz->pages[i].image = nil; } si.nMax += moz->pages[i].px; } si.nMax --; SetScrollInfo(moz->hwnd, SB_VERT, &si, TRUE); break; case WM_MOUSEMOVE: pdfmoz_onmouse(moz, x, y, 0); break; case WM_LBUTTONDOWN: SetFocus(hwnd); pdfmoz_onmouse(moz, x, y, 1); break; case WM_VSCROLL: si.cbSize = sizeof(si); si.fMask = SIF_ALL; GetScrollInfo(hwnd, SB_VERT, &si); switch (LOWORD(wParam)) { case SB_BOTTOM: si.nPos = si.nMax; break; case SB_TOP: si.nPos = 0; break; case SB_LINEUP: si.nPos -= 50; break; case SB_LINEDOWN: si.nPos += 50; break; case SB_PAGEUP: si.nPos -= si.nPage; break; case SB_PAGEDOWN: si.nPos += si.nPage; break; case SB_THUMBTRACK: si.nPos = si.nTrackPos; break; case SB_THUMBPOSITION: si.nPos = si.nTrackPos; break; } si.fMask = SIF_POS; si.nPos = MAX(0, MIN(si.nPos, si.nMax)); SetScrollInfo(hwnd, SB_VERT, &si, TRUE); InvalidateRect(moz->hwnd, NULL, FALSE); decodescroll(moz, si.nPos); sprintf(buf, "Page %d of %d", moz->scrollpage + 1, moz->pagecount); NPN_Status(moz->inst, buf); return 0; case WM_MOUSEWHEEL: if ((signed short)HIWORD(wParam) > 0) SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0); else SendMessage(hwnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0); break; case WM_KEYDOWN: sendmsg = 0xFFFF; switch (wParam) { case VK_UP: sendmsg = SB_LINEUP; break; case VK_PRIOR: sendmsg = SB_PAGEUP; break; case ' ': case VK_NEXT: sendmsg = SB_PAGEDOWN; break; case '\r': case VK_DOWN: sendmsg = SB_LINEDOWN; break; case VK_HOME: sendmsg = SB_TOP; break; case VK_END: sendmsg = SB_BOTTOM; break; } if (sendmsg != 0xFFFF) SendMessage(hwnd, WM_VSCROLL, MAKELONG(sendmsg, 0), 0); /* ick! someone eats events instead of bubbling... not my fault! */ break; default: break; } return moz->winproc(hwnd, msg, wParam, lParam); }
static fz_error * renderimage(fz_renderer *gc, fz_imagenode *node, fz_matrix ctm) { fz_error *error; fz_image *image = node->image; fz_irect bbox; fz_irect clip; int dx, dy; fz_pixmap *tile; fz_pixmap *temp; fz_matrix imgmat; fz_matrix invmat; int fa, fb, fc, fd; int u0, v0; int x0, y0; int w, h; int tileheight; DEBUG("image %dx%d %d+%d %s\n{\n", image->w, image->h, image->n, image->a, image->cs?image->cs->name:"(nil)"); bbox = fz_roundrect(fz_boundnode((fz_node*)node, ctm)); clip = fz_intersectirects(gc->clip, bbox); if (fz_isemptyrect(clip)) return fz_okay; if (image->w == 0 || image->h == 0) return fz_okay; if (image->n + image->a == 0) return fz_okay; calcimagescale(ctm, image->w, image->h, &dx, &dy); /* try to fit tile into a typical L2 cachce */ tileheight = 512 * 1024 / (image->w * (image->n + image->a)); /* tileheight must be an even multiple of dy, except for last band */ tileheight = (tileheight + dy - 1) / dy * dy; if ((dx != 1 || dy != 1) && image->h > tileheight) { int y = 0; DEBUG(" load image tile size = %dx%d\n", image->w, tileheight); error = fz_newpixmap(&tile, 0, 0, image->w, tileheight, image->n + 1); if (error) return error; error = fz_newscaledpixmap(&temp, image->w, image->h, image->n + 1, dx, dy); if (error) goto cleanup; do { if (y + tileheight > image->h) tileheight = image->h - y; tile->y = y; tile->h = tileheight; DEBUG(" tile xywh=%d %d %d %d sxsy=1/%d 1/%d\n", 0, y, image->w, tileheight, dx, dy); error = image->loadtile(image, tile); if (error) goto cleanup1; error = fz_scalepixmaptile(temp, 0, y, tile, dx, dy); if (error) goto cleanup1; y += tileheight; } while (y < image->h); fz_droppixmap(tile); tile = temp; } else { DEBUG(" load image\n"); error = fz_newpixmap(&tile, 0, 0, image->w, image->h, image->n + 1); if (error) return error; error = image->loadtile(image, tile); if (error) goto cleanup; if (dx != 1 || dy != 1) { DEBUG(" scale image 1/%d 1/%d\n", dx, dy); error = fz_scalepixmap(&temp, tile, dx, dy); if (error) goto cleanup; fz_droppixmap(tile); tile = temp; } } if (image->cs && image->cs != gc->model) { DEBUG(" convert from %s to %s\n", image->cs->name, gc->model->name); error = fz_newpixmap(&temp, tile->x, tile->y, tile->w, tile->h, gc->model->n + 1); if (error) goto cleanup; fz_convertpixmap(image->cs, tile, gc->model, temp); fz_droppixmap(tile); tile = temp; } imgmat.a = 1.0 / tile->w; imgmat.b = 0.0; imgmat.c = 0.0; imgmat.d = -1.0 / tile->h; imgmat.e = 0.0; imgmat.f = 1.0; invmat = fz_invertmatrix(fz_concat(imgmat, ctm)); w = clip.x1 - clip.x0; h = clip.y1 - clip.y0; x0 = clip.x0; y0 = clip.y0; u0 = (invmat.a * (x0+0.5) + invmat.c * (y0+0.5) + invmat.e) * 65536; v0 = (invmat.b * (x0+0.5) + invmat.d * (y0+0.5) + invmat.f) * 65536; fa = invmat.a * 65536; fb = invmat.b * 65536; fc = invmat.c * 65536; fd = invmat.d * 65536; #define PSRC tile->samples, tile->w, tile->h #define PDST(p) p->samples + ((y0-p->y) * p->w + (x0-p->x)) * p->n, p->w * p->n #define PCTM u0, v0, fa, fb, fc, fd, w, h switch (gc->flag) { case FNONE: { DEBUG(" fnone %d x %d\n", w, h); if (image->cs) error = fz_newpixmapwithrect(&gc->dest, clip, gc->model->n + 1); else error = fz_newpixmapwithrect(&gc->dest, clip, 1); if (error) goto cleanup; if (image->cs) fz_img_4c4(PSRC, PDST(gc->dest), PCTM); else fz_img_1c1(PSRC, PDST(gc->dest), PCTM); } break; case FOVER: { DEBUG(" fover %d x %d\n", w, h); if (image->cs) fz_img_4o4(PSRC, PDST(gc->over), PCTM); else fz_img_1o1(PSRC, PDST(gc->over), PCTM); } break; case FOVER | FRGB: DEBUG(" fover+rgb %d x %d\n", w, h); fz_img_w4i1o4(gc->argb, PSRC, PDST(gc->over), PCTM); break; default: assert(!"impossible flag in image span function"); } DEBUG("}\n"); fz_droppixmap(tile); return fz_okay; cleanup1: fz_droppixmap(temp); cleanup: fz_droppixmap(tile); return error; }
static void fz_drawcliptext(void *user, fz_text *text, fz_matrix ctm, int accumulate) { fz_drawdevice *dev = user; fz_colorspace *model = dev->dest->colorspace; fz_bbox bbox; fz_pixmap *mask, *dest; fz_matrix tm, trm; fz_pixmap *glyph; int i, x, y, gid; /* 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 */ /* If accumulate == 2 then this text object is a continuation */ if (dev->top == STACKSIZE) { fz_warn("assert: too many buffers on stack"); return; } if (accumulate == 0) { /* make the mask the exact size needed */ bbox = fz_roundrect(fz_boundtext(text, ctm)); bbox = fz_intersectbbox(bbox, dev->scissor); } else { /* be conservative about the size of the mask needed */ bbox = dev->scissor; } if (accumulate == 0 || accumulate == 1) { mask = fz_newpixmapwithrect(nil, bbox); dest = fz_newpixmapwithrect(model, bbox); fz_clearpixmap(mask, 0); fz_clearpixmap(dest, 0); 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++; } else { mask = dev->stack[dev->top-1].mask; } if (!fz_isemptyrect(bbox)) { tm = text->trm; for (i = 0; i < text->len; i++) { gid = text->els[i].gid; if (gid < 0) continue; tm.e = text->els[i].x; tm.f = text->els[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_renderglyph(dev->cache, text->font, gid, trm); if (glyph) { drawglyph(nil, mask, glyph, x, y, bbox); fz_droppixmap(glyph); } } } }
static fz_error * rendermask(fz_renderer *gc, fz_masknode *mask, fz_matrix ctm) { fz_error *error; int oldmaskonly; fz_pixmap *oldover; fz_irect oldclip; fz_irect bbox; fz_irect clip; fz_pixmap *shapepix = nil; fz_pixmap *colorpix = nil; fz_node *shape; fz_node *color; float rgb[3]; shape = mask->super.first; color = shape->next; /* special case black voodo */ if (gc->flag & FOVER) { if (fz_issolidnode(color)) { fz_solidnode *solid = (fz_solidnode*)color; fz_convertcolor(solid->cs, solid->samples, gc->model, rgb); gc->argb[0] = solid->a * 255; gc->argb[1] = rgb[0] * solid->a * 255; gc->argb[2] = rgb[1] * solid->a * 255; gc->argb[3] = rgb[2] * solid->a * 255; gc->argb[4] = rgb[0] * 255; gc->argb[5] = rgb[1] * 255; gc->argb[6] = rgb[2] * 255; gc->flag |= FRGB; /* we know these can handle the FRGB shortcut */ if (fz_ispathnode(shape)) return renderpath(gc, (fz_pathnode*)shape, ctm); if (fz_istextnode(shape)) return rendertext(gc, (fz_textnode*)shape, ctm); if (fz_isimagenode(shape)) return renderimage(gc, (fz_imagenode*)shape, ctm); } } oldclip = gc->clip; oldover = gc->over; bbox = fz_roundrect(fz_boundnode(shape, ctm)); clip = fz_intersectirects(bbox, gc->clip); bbox = fz_roundrect(fz_boundnode(color, ctm)); clip = fz_intersectirects(bbox, clip); if (fz_isemptyrect(clip)) return fz_okay; DEBUG("mask [%d %d %d %d]\n{\n", clip.x0, clip.y0, clip.x1, clip.y1); { fz_irect sbox = fz_roundrect(fz_boundnode(shape, ctm)); fz_irect cbox = fz_roundrect(fz_boundnode(color, ctm)); if (cbox.x0 >= sbox.x0 && cbox.x1 <= sbox.x1) if (cbox.y0 >= sbox.y0 && cbox.y1 <= sbox.y1) DEBUG("potentially useless mask\n"); } gc->clip = clip; gc->over = nil; oldmaskonly = gc->maskonly; gc->maskonly = 1; error = rendernode(gc, shape, ctm); if (error) goto cleanup; shapepix = gc->dest; gc->dest = nil; gc->maskonly = oldmaskonly; error = rendernode(gc, color, ctm); if (error) goto cleanup; colorpix = gc->dest; gc->dest = nil; gc->clip = oldclip; gc->over = oldover; if (shapepix && colorpix) { if (gc->over) { blendmask(gc, colorpix, shapepix, gc->over, 1); } else { clip.x0 = MAX(colorpix->x, shapepix->x); clip.y0 = MAX(colorpix->y, shapepix->y); clip.x1 = MIN(colorpix->x+colorpix->w, shapepix->x+shapepix->w); clip.y1 = MIN(colorpix->y+colorpix->h, shapepix->y+shapepix->h); error = fz_newpixmapwithrect(&gc->dest, clip, colorpix->n); if (error) goto cleanup; blendmask(gc, colorpix, shapepix, gc->dest, 0); } } DEBUG("}\n"); if (shapepix) fz_droppixmap(shapepix); if (colorpix) fz_droppixmap(colorpix); return fz_okay; cleanup: if (shapepix) fz_droppixmap(shapepix); if (colorpix) fz_droppixmap(colorpix); return error; }