5 pdf_initgstate(pdf_gstate
*gs
)
13 memset(gs
->dashlist
, 0, sizeof(gs
->dashlist
));
15 gs
->stroke
.kind
= PDF_MCOLOR
;
16 gs
->stroke
.cs
= fz_keepcolorspace(pdf_devicegray
);
18 gs
->stroke
.indexed
= nil
;
19 gs
->stroke
.pattern
= nil
;
20 gs
->stroke
.shade
= nil
;
22 gs
->fill
.kind
= PDF_MCOLOR
;
23 gs
->fill
.cs
= fz_keepcolorspace(pdf_devicegray
);
25 gs
->fill
.indexed
= nil
;
26 gs
->fill
.pattern
= nil
;
42 pdf_setcolorspace(pdf_csi
*csi
, int what
, fz_colorspace
*cs
)
44 pdf_gstate
*gs
= csi
->gstate
+ csi
->gtop
;
48 error
= pdf_flushtext(csi
);
52 mat
= what
== PDF_MFILL
? &gs
->fill
: &gs
->stroke
;
54 fz_dropcolorspace(mat
->cs
);
56 mat
->kind
= PDF_MCOLOR
;
57 mat
->cs
= fz_keepcolorspace(cs
);
59 mat
->v
[0] = 0; /* FIXME: default color */
60 mat
->v
[1] = 0; /* FIXME: default color */
61 mat
->v
[2] = 0; /* FIXME: default color */
62 mat
->v
[3] = 1; /* FIXME: default color */
64 if (!strcmp(cs
->name
, "Indexed"))
66 mat
->kind
= PDF_MINDEXED
;
67 mat
->indexed
= (pdf_indexed
*)cs
;
68 mat
->cs
= mat
->indexed
->base
;
71 if (!strcmp(cs
->name
, "Lab"))
78 pdf_setcolor(pdf_csi
*csi
, int what
, float *v
)
80 pdf_gstate
*gs
= csi
->gstate
+ csi
->gtop
;
86 error
= pdf_flushtext(csi
);
90 mat
= what
== PDF_MFILL
? &gs
->fill
: &gs
->stroke
;
95 if (!strcmp(mat
->cs
->name
, "Lab"))
97 if (!strcmp(mat
->cs
->name
, "Indexed"))
102 for (i
= 0; i
< mat
->cs
->n
; i
++)
108 mat
->v
[0] = v
[0] / 100.0;
109 mat
->v
[1] = (v
[1] + 100) / 200.0;
110 mat
->v
[2] = (v
[2] + 100) / 200.0;
116 i
= CLAMP(v
[0], 0, ind
->high
);
117 for (k
= 0; k
< ind
->base
->n
; k
++)
118 mat
->v
[k
] = ind
->lookup
[ind
->base
->n
* i
+ k
] / 255.0;
122 return fz_throw("syntaxerror: color not compatible with material");
129 pdf_setpattern(pdf_csi
*csi
, int what
, pdf_pattern
*pat
, float *v
)
131 pdf_gstate
*gs
= csi
->gstate
+ csi
->gtop
;
135 error
= pdf_flushtext(csi
);
139 if (what
== PDF_MFILL
)
144 // TODO: this possibly drops a pattern too many times resulting in droping pattern
145 // used in other places, so don't drop it (better leak than crash).
146 // It's possible that overzeleaus dropping happens in some other place
149 pdf_droppattern(mat
->pattern
);
152 mat
->kind
= PDF_MPATTERN
;
154 mat
->pattern
= pdf_keeppattern(pat
);
159 return pdf_setcolor(csi
, what
, v
);
165 pdf_setshade(pdf_csi
*csi
, int what
, fz_shade
*shade
)
167 pdf_gstate
*gs
= csi
->gstate
+ csi
->gtop
;
171 error
= pdf_flushtext(csi
);
175 mat
= what
== PDF_MFILL
? &gs
->fill
: &gs
->stroke
;
178 fz_dropshade(mat
->shade
);
180 mat
->kind
= PDF_MSHADE
;
181 mat
->shade
= fz_keepshade(shade
);
187 pdf_buildstrokepath(pdf_gstate
*gs
, fz_pathnode
*path
)
193 stroke
.linecap
= gs
->linecap
;
194 stroke
.linejoin
= gs
->linejoin
;
195 stroke
.linewidth
= gs
->linewidth
;
196 stroke
.miterlimit
= gs
->miterlimit
;
200 error
= fz_newdash(&dash
, gs
->dashphase
, gs
->dashlen
, gs
->dashlist
);
207 error
= fz_endpath(path
, FZ_STROKE
, &stroke
, dash
);
217 pdf_buildfillpath(pdf_gstate
*gs
, fz_pathnode
*path
, int eofill
)
219 return fz_endpath(path
, eofill
? FZ_EOFILL
: FZ_FILL
, nil
, nil
);
223 addcolorshape(pdf_gstate
*gs
, fz_node
*shape
, fz_colorspace
*cs
, float *v
)
229 error
= fz_newmasknode(&mask
);
230 if (error
) return error
;
232 error
= fz_newsolidnode(&solid
, cs
, cs
->n
, v
);
233 if (error
) return error
;
235 fz_insertnodelast(mask
, shape
);
236 fz_insertnodelast(mask
, solid
);
237 fz_insertnodelast(gs
->head
, mask
);
243 addinvisibleshape(pdf_gstate
*gs
, fz_node
*shape
)
249 error
= fz_newmasknode(&mask
);
250 if (error
) return error
;
252 error
= fz_newpathnode(&path
);
253 if (error
) return error
;
254 error
= fz_endpath(path
, FZ_FILL
, nil
, nil
);
255 if (error
) return error
;
257 fz_insertnodelast(mask
, (fz_node
*)path
);
258 fz_insertnodelast(mask
, shape
);
259 fz_insertnodelast(gs
->head
, mask
);
264 static fz_matrix
getmatrix(fz_node
*node
)
268 fz_matrix ptm
= getmatrix(node
->parent
);
269 if (fz_istransformnode(node
))
270 return fz_concat(((fz_transformnode
*)node
)->m
, ptm
);
273 if (fz_istransformnode(node
))
274 return ((fz_transformnode
*)node
)->m
;
275 return fz_identity();
279 addpatternshape(pdf_gstate
*gs
, fz_node
*shape
,
280 pdf_pattern
*pat
, fz_colorspace
*cs
, float *v
)
293 int x
, y
, x0
, y0
, x1
, y1
;
295 /* patterns are painted in user space */
296 ctm
= getmatrix(gs
->head
);
297 inv
= fz_invertmatrix(ctm
);
299 error
= fz_newmasknode(&mask
);
300 if (error
) return error
;
302 ptm
= fz_concat(pat
->matrix
, fz_invertmatrix(ctm
));
303 error
= fz_newtransformnode(&xform
, ptm
);
304 if (error
) return error
;
306 error
= fz_packobj(&dict
, "<< /Tree %p /XStep %f /YStep %f "
307 " /Matrix[%f %f %f %f %f %f] >>",
308 pat
->tree
, pat
->xstep
, pat
->ystep
,
309 pat
->matrix
.a
, pat
->matrix
.b
,
310 pat
->matrix
.c
, pat
->matrix
.d
,
311 pat
->matrix
.e
, pat
->matrix
.f
);
312 if (error
) return error
;
314 error
= fz_newmetanode(&meta
, "Pattern", dict
);
315 if (error
) return error
;
317 error
= fz_newovernode(&over
);
318 if (error
) return error
;
320 fz_insertnodelast(mask
, shape
);
321 fz_insertnodelast(mask
, meta
);
322 fz_insertnodelast(meta
, xform
);
323 fz_insertnodelast(xform
, over
);
325 /* get bbox of shape in pattern space for stamping */
326 ptm
= fz_concat(ctm
, fz_invertmatrix(pat
->matrix
));
327 bbox
= fz_boundnode(shape
, ptm
);
329 /* expand bbox by pattern bbox */
330 bbox
.x0
+= pat
->bbox
.x0
;
331 bbox
.y0
+= pat
->bbox
.y0
;
332 bbox
.x1
+= pat
->bbox
.x1
;
333 bbox
.y1
+= pat
->bbox
.y1
;
335 x0
= fz_floor(bbox
.x0
/ pat
->xstep
);
336 y0
= fz_floor(bbox
.y0
/ pat
->ystep
);
337 x1
= fz_ceil(bbox
.x1
/ pat
->xstep
);
338 y1
= fz_ceil(bbox
.y1
/ pat
->ystep
);
340 for (y
= y0
; y
<= y1
; y
++)
342 for (x
= x0
; x
<= x1
; x
++)
344 ptm
= fz_translate(x
* pat
->xstep
, y
* pat
->ystep
);
345 error
= fz_newtransformnode(&xform
, ptm
);
346 if (error
) return error
;
347 error
= fz_newlinknode(&link
, pat
->tree
);
348 if (error
) return error
;
349 fz_insertnodelast(xform
, link
);
350 fz_insertnodelast(over
, xform
);
355 return addcolorshape(gs
, mask
, cs
, v
);
357 fz_insertnodelast(gs
->head
, mask
);
362 pdf_addshade(pdf_gstate
*gs
, fz_shade
*shade
)
367 error
= fz_newshadenode(&node
, shade
);
368 if (error
) return error
;
370 fz_insertnodelast(gs
->head
, node
);
376 addshadeshape(pdf_gstate
*gs
, fz_node
*shape
, fz_shade
*shade
)
387 ctm
= getmatrix(gs
->head
);
388 inv
= fz_invertmatrix(ctm
);
390 error
= fz_newtransformnode(&xform
, inv
);
391 if (error
) return error
;
393 error
= fz_newmasknode(&mask
);
394 if (error
) return error
;
396 error
= fz_newshadenode(&color
, shade
);
397 if (error
) return error
;
399 if (shade
->usebackground
)
401 error
= fz_newovernode(&over
);
402 if (error
) return error
;
404 error
= fz_newsolidnode(&bgnd
, shade
->cs
, shade
->cs
->n
, shade
->background
);
405 if (error
) return error
;
407 fz_insertnodelast(mask
, shape
);
408 fz_insertnodelast(over
, bgnd
);
409 fz_insertnodelast(over
, color
);
410 fz_insertnodelast(xform
, over
);
411 fz_insertnodelast(mask
, xform
);
412 fz_insertnodelast(gs
->head
, mask
);
416 fz_insertnodelast(mask
, shape
);
417 fz_insertnodelast(xform
, color
);
418 fz_insertnodelast(mask
, xform
);
419 fz_insertnodelast(gs
->head
, mask
);
426 pdf_addfillshape(pdf_gstate
*gs
, fz_node
*shape
)
428 switch (gs
->fill
.kind
)
431 fz_insertnodelast(gs
->head
, shape
);
436 return addcolorshape(gs
, shape
, gs
->fill
.cs
, gs
->fill
.v
);
438 // this is a work-around to make http://kpdf.kde.org/stuff/nytimes-firefox-final.pdf
439 // not crash see http://blog.kowalczyk.info/forum_sumatra/topic.php?TopicId=287&Posts=0
440 if (gs
->fill
.pattern
)
441 return addpatternshape(gs
, shape
, gs
->fill
.pattern
, gs
->fill
.cs
, gs
->fill
.v
);
445 return addshadeshape(gs
, shape
, gs
->fill
.shade
);
447 return fz_throw("unimplemented material");
452 pdf_addstrokeshape(pdf_gstate
*gs
, fz_node
*shape
)
454 switch (gs
->stroke
.kind
)
457 fz_insertnodelast(gs
->head
, shape
);
462 return addcolorshape(gs
, shape
, gs
->stroke
.cs
, gs
->stroke
.v
);
464 return addpatternshape(gs
, shape
, gs
->stroke
.pattern
, gs
->stroke
.cs
, gs
->stroke
.v
);
466 return addshadeshape(gs
, shape
, gs
->stroke
.shade
);
468 return fz_throw("unimplemented material");
473 pdf_addclipmask(pdf_gstate
*gs
, fz_node
*shape
)
479 error
= fz_newmasknode(&mask
);
480 if (error
) return error
;
482 error
= fz_newovernode(&over
);
483 if (error
) return error
;
485 fz_insertnodelast(mask
, shape
);
486 fz_insertnodelast(mask
, over
);
487 fz_insertnodelast(gs
->head
, mask
);
494 pdf_addtransform(pdf_gstate
*gs
, fz_node
*transform
)
499 error
= fz_newovernode(&over
);
500 if (error
) return error
;
502 fz_insertnodelast(gs
->head
, transform
);
503 fz_insertnodelast(transform
, over
);
510 pdf_showimage(pdf_csi
*csi
, pdf_image
*img
)
517 error
= fz_newimagenode(&color
, (fz_image
*)img
);
521 if (img
->super
.n
== 0 && img
->super
.a
== 1)
523 error
= pdf_addfillshape(csi
->gstate
+ csi
->gtop
, color
);
533 error
= fz_newimagenode(&shape
, (fz_image
*)img
->mask
);
534 if (error
) return error
;
535 error
= fz_newmasknode(&mask
);
536 if (error
) return error
;
537 fz_insertnodelast(mask
, shape
);
538 fz_insertnodelast(mask
, color
);
539 fz_insertnodelast(csi
->gstate
[csi
->gtop
].head
, mask
);
543 fz_insertnodelast(csi
->gstate
[csi
->gtop
].head
, color
);
551 pdf_showpath(pdf_csi
*csi
,
552 int doclose
, int dofill
, int dostroke
, int evenodd
)
554 pdf_gstate
*gstate
= csi
->gstate
+ csi
->gtop
;
561 error
= fz_closepath(csi
->path
);
562 if (error
) return error
;
565 if (dofill
&& dostroke
)
568 error
= fz_clonepathnode(&spath
, fpath
);
569 if (error
) return error
;
573 spath
= fpath
= csi
->path
;
578 error
= pdf_buildfillpath(gstate
, fpath
, evenodd
);
579 if (error
) return error
;
580 error
= pdf_addfillshape(gstate
, (fz_node
*)fpath
);
581 if (error
) return error
;
586 error
= pdf_buildstrokepath(gstate
, spath
);
587 if (error
) return error
;
588 error
= pdf_addstrokeshape(gstate
, (fz_node
*)spath
);
589 if (error
) return error
;
595 error
= fz_clonepathnode(&clip
, csi
->path
);
596 if (error
) return error
;
597 error
= fz_endpath(clip
, FZ_FILL
, nil
, nil
);
598 if (error
) return error
;
599 error
= pdf_addclipmask(gstate
, (fz_node
*)clip
);
600 if (error
) return error
;
604 if (!dofill
&& !dostroke
)
606 fz_dropnode((fz_node
*)csi
->path
);
611 error
= fz_newpathnode(&csi
->path
);
612 if (error
) return error
;
618 pdf_flushtext(pdf_csi
*csi
)
620 pdf_gstate
*gstate
= csi
->gstate
+ csi
->gtop
;
625 switch (csi
->textmode
)
629 case 2: /* stroke + fill */
630 error
= pdf_addfillshape(gstate
, (fz_node
*)csi
->text
);
635 case 3: /* invisible */
636 error
= addinvisibleshape(gstate
, (fz_node
*)csi
->text
);
641 case 4: /* fill + clip */
642 case 5: /* stroke + clip */
643 case 6: /* stroke + fill + clip */
646 error
= fz_clonetextnode(&temp
, csi
->text
);
649 error
= pdf_addfillshape(gstate
, (fz_node
*)temp
);
655 case 7: /* invisible clip */
658 error
= fz_newovernode(&csi
->textclip
);
662 fz_insertnodelast(csi
->textclip
, (fz_node
*)csi
->text
);
673 showglyph(pdf_csi
*csi
, int cid
)
675 pdf_gstate
*gstate
= csi
->gstate
+ csi
->gtop
;
676 pdf_font
*font
= gstate
->font
;
679 float w0
, w1
, tx
, ty
;
683 tsm
.a
= gstate
->size
* gstate
->scale
;
686 tsm
.d
= gstate
->size
;
688 tsm
.f
= gstate
->rise
;
690 if (font
->super
.wmode
== 1)
692 v
= fz_getvmtx((fz_font
*)font
, cid
);
693 tsm
.e
-= v
.x
* gstate
->size
/ 1000.0;
694 tsm
.f
-= v
.y
* gstate
->size
/ 1000.0;
697 trm
= fz_concat(tsm
, csi
->tm
);
699 /* flush buffered text if face or matrix or rendermode has changed */
701 ((fz_font
*)font
) != csi
->text
->font
||
702 fabs(trm
.a
- csi
->text
->trm
.a
) > FLT_EPSILON
||
703 fabs(trm
.b
- csi
->text
->trm
.b
) > FLT_EPSILON
||
704 fabs(trm
.c
- csi
->text
->trm
.c
) > FLT_EPSILON
||
705 fabs(trm
.d
- csi
->text
->trm
.d
) > FLT_EPSILON
||
706 gstate
->render
!= csi
->textmode
)
708 error
= pdf_flushtext(csi
);
709 if (error
) return error
;
711 error
= fz_newtextnode(&csi
->text
, (fz_font
*)font
);
712 if (error
) return error
;
714 csi
->text
->trm
= trm
;
715 csi
->text
->trm
.e
= 0;
716 csi
->text
->trm
.f
= 0;
717 csi
->textmode
= gstate
->render
;
720 /* add glyph to textobject */
721 error
= fz_addtext(csi
->text
, cid
, trm
.e
, trm
.f
);
725 if (font
->super
.wmode
== 0)
727 h
= fz_gethmtx((fz_font
*)font
, cid
);
729 tx
= (w0
* gstate
->size
+ gstate
->charspace
) * gstate
->scale
;
730 csi
->tm
= fz_concat(fz_translate(tx
, 0), csi
->tm
);
735 ty
= w1
* gstate
->size
+ gstate
->charspace
;
736 csi
->tm
= fz_concat(fz_translate(0, ty
), csi
->tm
);
743 showspace(pdf_csi
*csi
, float tadj
)
745 pdf_gstate
*gstate
= csi
->gstate
+ csi
->gtop
;
746 pdf_font
*font
= gstate
->font
;
747 if (font
->super
.wmode
== 0)
748 csi
->tm
= fz_concat(fz_translate(tadj
* gstate
->scale
, 0), csi
->tm
);
750 csi
->tm
= fz_concat(fz_translate(0, tadj
), csi
->tm
);
754 pdf_showtext(pdf_csi
*csi
, fz_obj
*text
)
756 pdf_gstate
*gstate
= csi
->gstate
+ csi
->gtop
;
757 pdf_font
*font
= gstate
->font
;
764 if (fz_isarray(text
))
766 for (i
= 0; i
< fz_arraylen(text
); i
++)
768 fz_obj
*item
= fz_arrayget(text
, i
);
769 if (fz_isstring(item
))
771 error
= pdf_showtext(csi
, item
);
772 if (error
) return error
;
776 showspace(csi
, - fz_toreal(item
) * gstate
->size
/ 1000.0);
782 buf
= fz_tostrbuf(text
);
783 len
= fz_tostrlen(text
);
788 buf
= pdf_decodecmap(font
->encoding
, buf
, &cpt
);
789 cid
= pdf_lookupcmap(font
->encoding
, cpt
);
793 error
= showglyph(csi
, cid
);
798 showspace(csi
, gstate
->wordspace
);