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 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); } } } }
void pdf_flushtext(pdf_csi *csi) { pdf_gstate *gstate = csi->gstate + csi->gtop; fz_text *text; int dofill = 0; int dostroke = 0; int doclip = 0; int doinvisible = 0; fz_rect bbox; if (!csi->text) return; text = csi->text; csi->text = nil; dofill = dostroke = doclip = doinvisible = 0; switch (csi->textmode) { case 0: dofill = 1; break; case 1: dostroke = 1; break; case 2: dofill = dostroke = 1; break; case 3: doinvisible = 1; break; case 4: dofill = doclip = 1; break; case 5: dostroke = doclip = 1; break; case 6: dofill = dostroke = doclip = 1; break; case 7: doclip = 1; break; } bbox = fz_boundtext(text, gstate->ctm); pdf_begingroup(csi, bbox); if (doinvisible) csi->dev->ignoretext(csi->dev->user, text, gstate->ctm); if (doclip) { if (csi->accumulate < 2) gstate->clipdepth++; csi->dev->cliptext(csi->dev->user, text, gstate->ctm, csi->accumulate); csi->accumulate = 2; } if (dofill) { switch (gstate->fill.kind) { case PDF_MNONE: break; case PDF_MCOLOR: csi->dev->filltext(csi->dev->user, text, gstate->ctm, gstate->fill.colorspace, gstate->fill.v, gstate->fill.alpha); break; case PDF_MPATTERN: if (gstate->fill.pattern) { csi->dev->cliptext(csi->dev->user, text, gstate->ctm, 0); pdf_showpattern(csi, gstate->fill.pattern, bbox, PDF_MFILL); csi->dev->popclip(csi->dev->user); } break; case PDF_MSHADE: if (gstate->fill.shade) { csi->dev->cliptext(csi->dev->user, text, gstate->ctm, 0); csi->dev->fillshade(csi->dev->user, gstate->fill.shade, csi->topctm, gstate->fill.alpha); csi->dev->popclip(csi->dev->user); } break; } } if (dostroke) { switch (gstate->stroke.kind) { case PDF_MNONE: break; case PDF_MCOLOR: csi->dev->stroketext(csi->dev->user, text, &gstate->strokestate, gstate->ctm, gstate->stroke.colorspace, gstate->stroke.v, gstate->stroke.alpha); break; case PDF_MPATTERN: if (gstate->stroke.pattern) { csi->dev->clipstroketext(csi->dev->user, text, &gstate->strokestate, gstate->ctm); pdf_showpattern(csi, gstate->stroke.pattern, bbox, PDF_MFILL); csi->dev->popclip(csi->dev->user); } break; case PDF_MSHADE: if (gstate->stroke.shade) { csi->dev->clipstroketext(csi->dev->user, text, &gstate->strokestate, gstate->ctm); csi->dev->fillshade(csi->dev->user, gstate->stroke.shade, csi->topctm, gstate->stroke.alpha); csi->dev->popclip(csi->dev->user); } break; } } pdf_endgroup(csi); fz_freetext(text); }