1 /* Fo
2 * area-to-pdf.c: Convert area tree into PDF
3 *
4 * Copyright (C) 2001-2005 Sun Microsystems
5 * Copyright (C) 2007-2009 Menteith Consulting Ltd
6 *
7 * See COPYING for the status of this software.
8 */
9
10
11 #include <string.h>
12 #include "area-to-pdf.h"
13 #include "area/fo-all-area.h"
14 #include "area/fo-area-table-continuation-private.h"
15 #include "property/fo-property-border.h"
16 #include "property/fo-property-border-bottom-style.h"
17 #include "property/fo-property-border-left-style.h"
18 #include "property/fo-property-border-right-style.h"
19 #include "property/fo-property-border-top-style.h"
20 #include "property/fo-property-color.h"
21 #include "property/fo-property-font-size.h"
22 #include "fo/fo-cbpbp-fo.h"
23
24
25 typedef struct
26 {
27 gdouble x1; /* X-coordinate of one corner. */
28 gdouble y1; /* Y-coordinate of one corner. */
29 gdouble x2; /* X-coordinate of the opposite corner. */
30 gdouble y2; /* Y-coordinate of the opposite corder. */
31 gdouble x1delta; /* Relative x-offset of interior corner nearest (x1,y1). */
32 gdouble y1delta; /* Relative y-offset of interior corner nearest (x1,y1). */
33 gdouble x2delta; /* Relative x-offset of interior corner nearest (x2,y2). */
34 gdouble y2delta; /* Relative y-offset of interior corner nearest (x2,y2). */
35 } FoPdfOneBorderCoords;
36
37 /**
38 * fo_pdf_draw_background:
39 * @fo_doc: #FoDoc
40 * @x: X-coordinate of top-left corner.
41 * @y: Y-coordinate of top-left corner.
42 * @width: Width of background area
43 * @height: Height of background area
44 * @background_color: Background color, or an #FoEnum if background is
45 * transparent.
46 *
47 * If @background_color is an #FoColor, draw a rectangle of the
48 * background color with top-left corner at (@x, @y) with width @width
49 * and height @height.
50 **/
51 static void
fo_pdf_draw_background(FoDoc * fo_doc,gdouble x,gdouble y,gdouble width,gdouble height,FoDatatype * background_color)52 fo_pdf_draw_background (FoDoc *fo_doc,
53 gdouble x,
54 gdouble y,
55 gdouble width,
56 gdouble height,
57 FoDatatype *background_color)
58 {
59
60 #if defined(LIBFO_DEBUG) && 0
61 g_message ("draw_background:: x: %f; y; %f; width: %f; height: %f",
62 x,
63 y,
64 width,
65 height);
66 fo_object_debug_dump (background_color, 0);
67 #endif
68
69 if (FO_IS_COLOR (background_color))
70 {
71 fo_doc_set_fill_color (fo_doc,
72 background_color);
73
74 fo_doc_rect_filled (fo_doc,
75 x,
76 y - height,
77 width,
78 height);
79 }
80 }
81
82 /**
83 * fo_pdf_clip_to_coords:
84 * @fo_doc: #FoDoc.
85 * @coords: Coordinates of one border of an area.
86 *
87 * Clip the drawing area of @fo_doc to @coords
88 **/
89 static void
fo_pdf_clip_to_coords(FoDoc * fo_doc,FoPdfOneBorderCoords * coords)90 fo_pdf_clip_to_coords (FoDoc *fo_doc,
91 FoPdfOneBorderCoords *coords)
92 {
93 fo_doc_move_to (fo_doc,
94 coords->x1,
95 coords->y1);
96 fo_doc_line_to (fo_doc,
97 coords->x2,
98 coords->y2);
99 fo_doc_line_to (fo_doc,
100 coords->x2 + coords->x2delta,
101 coords->y2 + coords->y2delta);
102 fo_doc_line_to (fo_doc,
103 coords->x1 + coords->x1delta,
104 coords->y1 + coords->y1delta);
105 fo_doc_clip (fo_doc);
106 }
107
108 /**
109 * fo_pdf_draw_border_two_tone_vertical:
110 * @fo_doc: #FoDoc
111 * @inner_color: Color of the inner band
112 * @outer_color: Color of the outer band
113 * @coords: Coordinates of one border of an area
114 *
115 * Draw a left or right two-tone border.
116 **/
117 static void
fo_pdf_draw_border_two_tone_vertical(FoDoc * fo_doc,FoDatatype * inner_color,FoDatatype * outer_color,FoPdfOneBorderCoords * coords)118 fo_pdf_draw_border_two_tone_vertical (FoDoc *fo_doc,
119 FoDatatype *inner_color,
120 FoDatatype *outer_color,
121 FoPdfOneBorderCoords *coords)
122 {
123 fo_doc_set_line_width (fo_doc,
124 ABS (coords->x1delta) / 2);
125
126 fo_doc_set_stroke_color (fo_doc, outer_color);
127 fo_doc_move_to (fo_doc,
128 coords->x1 + coords->x1delta / 4.0,
129 coords->y1);
130 fo_doc_line_to (fo_doc,
131 coords->x2 + coords->x2delta / 4.0,
132 coords->y2);
133 fo_doc_stroke (fo_doc);
134
135 fo_doc_set_stroke_color (fo_doc, inner_color);
136 fo_doc_move_to (fo_doc,
137 coords->x1 + 3.0 * coords->x1delta / 4.0,
138 coords->y1);
139 fo_doc_line_to (fo_doc,
140 coords->x2 + 3.0 * coords->x2delta / 4.0,
141 coords->y2);
142 fo_doc_stroke (fo_doc);
143 }
144
145 /**
146 * fo_pdf_draw_border_two_tone_horizontal:
147 * @fo_doc: #FoDoc
148 * @inner_color: Color of the inner band
149 * @outer_color: Color of the outer band
150 * @coords: Coordinates of one border of an area
151 *
152 * Draw a top or bottom two-tone border.
153 **/
154 static void
fo_pdf_draw_border_two_tone_horizontal(FoDoc * fo_doc,FoDatatype * inner_color,FoDatatype * outer_color,FoPdfOneBorderCoords * coords)155 fo_pdf_draw_border_two_tone_horizontal (FoDoc *fo_doc,
156 FoDatatype *inner_color,
157 FoDatatype *outer_color,
158 FoPdfOneBorderCoords *coords)
159 {
160 fo_doc_set_line_width (fo_doc,
161 ABS (coords->y1delta) / 2);
162
163 fo_doc_set_stroke_color (fo_doc,
164 inner_color);
165 fo_doc_move_to (fo_doc,
166 coords->x1,
167 coords->y1 + 3.0 * coords->y1delta / 4.0);
168 fo_doc_line_to (fo_doc,
169 coords->x2,
170 coords->y2 + 3.0 * coords->y2delta / 4.0);
171 fo_doc_stroke (fo_doc);
172
173 fo_doc_set_stroke_color (fo_doc,
174 outer_color);
175 fo_doc_move_to (fo_doc,
176 coords->x1,
177 coords->y1 + coords->y1delta / 4.0);
178 fo_doc_line_to (fo_doc,
179 coords->x2,
180 coords->y2 + coords->y2delta / 4.0);
181 fo_doc_stroke (fo_doc);
182 }
183
184 /**
185 * fo_pdf_draw_border_solid:
186 * @fo_doc: #FoDoc
187 * @color: Border color
188 * @coords: Coordinates of one border of an area
189 *
190 * Draw a solid border with color @color and coordinates @coords.
191 **/
192 static void
fo_pdf_draw_border_solid(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)193 fo_pdf_draw_border_solid (FoDoc *fo_doc,
194 FoDatatype *color,
195 FoPdfOneBorderCoords *coords)
196 {
197 fo_doc_set_fill_color (fo_doc,
198 color);
199
200 fo_doc_move_to (fo_doc,
201 coords->x1,
202 coords->y1);
203 fo_doc_line_to (fo_doc,
204 coords->x2,
205 coords->y2);
206 fo_doc_line_to (fo_doc,
207 coords->x2 + coords->x2delta,
208 coords->y2 + coords->y2delta);
209 fo_doc_line_to (fo_doc,
210 coords->x1 + coords->x1delta,
211 coords->y1 + coords->y1delta);
212 fo_doc_fill (fo_doc);
213 }
214
215 /**
216 * fo_pdf_draw_border_double:
217 * @fo_doc: #FoDoc
218 * @color: Border color
219 * @coords: Coordinates of one border of an area
220 *
221 * Draw a double border with color @color and coordinates @coords.
222 **/
223 static void
fo_pdf_draw_border_double(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)224 fo_pdf_draw_border_double (FoDoc *fo_doc,
225 FoDatatype *color,
226 FoPdfOneBorderCoords *coords)
227 {
228 fo_doc_set_fill_color (fo_doc,
229 color);
230
231 fo_doc_move_to (fo_doc,
232 coords->x1,
233 coords->y1);
234 fo_doc_line_to (fo_doc,
235 coords->x2,
236 coords->y2);
237 fo_doc_line_to (fo_doc,
238 coords->x2 + coords->x2delta / 3,
239 coords->y2 + coords->y2delta / 3);
240 fo_doc_line_to (fo_doc,
241 coords->x1 + coords->x1delta / 3,
242 coords->y1 + coords->y1delta / 3);
243 fo_doc_fill (fo_doc);
244
245 fo_doc_move_to (fo_doc,
246 coords->x1 + 2 * coords->x1delta / 3,
247 coords->y1 + 2 * coords->y1delta / 3);
248 fo_doc_line_to (fo_doc,
249 coords->x2 + 2 * coords->x2delta / 3,
250 coords->y2 + 2 * coords->y2delta / 3);
251 fo_doc_line_to (fo_doc,
252 coords->x2 + coords->x2delta,
253 coords->y2 + coords->y2delta);
254 fo_doc_line_to (fo_doc,
255 coords->x1 + coords->x1delta,
256 coords->y1 + coords->y1delta);
257 fo_doc_fill (fo_doc);
258 }
259
260 /**
261 * fo_pdf_draw_border_dotted:
262 * @fo_doc: #FoDoc
263 * @color: Border color
264 * @coords: Coordinates of one border of an area
265 *
266 * Draw a dotted border with color @color and coordinates @coords.
267 **/
268 static void
fo_pdf_draw_border_dotted(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)269 fo_pdf_draw_border_dotted (FoDoc *fo_doc,
270 FoDatatype *color,
271 FoPdfOneBorderCoords *coords)
272 {
273 fo_doc_set_stroke_color (fo_doc,
274 color);
275
276 /* fo_doc_set_line_cap (fo_doc,
277 FO_DOC_LINE_CAP_ROUND);*/ /* round end caps */
278
279 fo_doc_move_to (fo_doc,
280 coords->x1,
281 coords->y1);
282 fo_doc_line_to (fo_doc,
283 coords->x2,
284 coords->y2);
285 fo_doc_line_to (fo_doc,
286 coords->x2 + coords->x2delta,
287 coords->y2 + coords->y2delta);
288 fo_doc_line_to (fo_doc,
289 coords->x1 + coords->x1delta,
290 coords->y1 + coords->y1delta);
291 fo_doc_clip (fo_doc);
292
293 if (coords->x1 == coords->x2)
294 { /* vertical */
295 fo_doc_set_dash (fo_doc,
296 ABS (coords->x1delta),
297 ABS (coords->x1delta));
298 fo_doc_set_line_width (fo_doc,
299 ABS (coords->x1delta));
300
301 fo_doc_move_to (fo_doc,
302 coords->x1 + coords->x1delta / 2,
303 coords->y1);
304 fo_doc_line_to (fo_doc,
305 coords->x2 + coords->x2delta / 2,
306 coords->y2);
307 }
308 else
309 { /* horizontal */
310 fo_doc_set_dash (fo_doc,
311 ABS (coords->y1delta),
312 ABS (coords->y1delta));
313 fo_doc_set_line_width (fo_doc,
314 ABS (coords->y1delta));
315
316 fo_doc_move_to (fo_doc,
317 coords->x1,
318 coords->y1 + coords->y1delta / 2);
319 fo_doc_line_to (fo_doc,
320 coords->x2,
321 coords->y2 + coords->y2delta / 2);
322 }
323
324 fo_doc_stroke (fo_doc);
325 }
326
327 /**
328 * fo_pdf_draw_border_dashed:
329 * @fo_doc: #FoDoc
330 * @color: Border color
331 * @coords: Coordinates of one border of an area
332 *
333 * Draw a dashed border with color @color and coordinates @coords.
334 **/
335 static void
fo_pdf_draw_border_dashed(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)336 fo_pdf_draw_border_dashed (FoDoc *fo_doc,
337 FoDatatype *color,
338 FoPdfOneBorderCoords *coords)
339 {
340 /* fo_doc_set_line_cap (fo_doc,
341 FO_DOC_LINE_CAP_BUTT);*/ /* butt end caps */
342
343 fo_pdf_clip_to_coords (fo_doc, coords);
344
345 fo_doc_set_stroke_color (fo_doc,
346 color);
347
348 if (coords->x1 == coords->x2)
349 { /* vertical */
350 fo_doc_set_dash (fo_doc,
351 ABS (coords->x1delta) * 3,
352 ABS (coords->x1delta) * 3);
353 fo_doc_set_line_width (fo_doc,
354 ABS (coords->x1delta));
355
356 fo_doc_move_to (fo_doc,
357 coords->x1 + coords->x1delta / 2,
358 coords->y1);
359 fo_doc_line_to (fo_doc,
360 coords->x2 + coords->x2delta / 2,
361 coords->y2);
362 }
363 else
364 { /* horizontal */
365 fo_doc_set_dash (fo_doc,
366 ABS (coords->y1delta) * 3,
367 ABS (coords->y1delta) * 3);
368 fo_doc_set_line_width (fo_doc,
369 ABS (coords->y1delta));
370
371 fo_doc_move_to (fo_doc,
372 coords->x1,
373 coords->y1 + coords->y1delta / 2);
374 fo_doc_line_to (fo_doc,
375 coords->x2,
376 coords->y2 + coords->y2delta / 2);
377 }
378 fo_doc_stroke (fo_doc);
379 }
380
381 /**
382 * fo_pdf_draw_border_groove:
383 * @fo_doc: #FoDoc
384 * @color: Border color
385 * @coords: Coordinates of one border of an area
386 *
387 * Draw a grooved border with colors based on @color and coordinates @coords.
388 **/
389 static void
fo_pdf_draw_border_groove(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)390 fo_pdf_draw_border_groove (FoDoc *fo_doc,
391 FoDatatype *color,
392 FoPdfOneBorderCoords *coords)
393 {
394 fo_doc_set_dash (fo_doc, 0.0, 0.0);
395
396 fo_pdf_clip_to_coords (fo_doc, coords);
397
398 if (coords->x1 == coords->x2)
399 { /* vertical */
400 if (coords->x1delta >= 0)
401 { /* left */
402 fo_pdf_draw_border_two_tone_vertical (fo_doc,
403 color,
404 fo_color_get_color_one_quarter (color),
405 coords);
406 }
407 else
408 { /* right */
409 fo_pdf_draw_border_two_tone_vertical (fo_doc,
410 fo_color_get_color_one_quarter (color),
411 color,
412 coords);
413 }
414 }
415 else
416 { /* horizontal */
417 if (coords->y1delta >= 0)
418 { /* bottom */
419 fo_pdf_draw_border_two_tone_horizontal (fo_doc,
420 fo_color_get_color_one_quarter (color),
421 color,
422 coords);
423 }
424 else
425 { /* top */
426 /* 3/4 color */
427 fo_pdf_draw_border_two_tone_horizontal (fo_doc,
428 color,
429 fo_color_get_color_one_quarter (color),
430 coords);
431 }
432 }
433 }
434
435 /**
436 * fo_pdf_draw_border_ridge:
437 * @fo_doc: #FoDoc
438 * @color: Border color
439 * @coords: Coordinates of one border of an area
440 *
441 * Draw a ridged border with colors based on @color and coordinates @coords.
442 **/
443 static void
fo_pdf_draw_border_ridge(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)444 fo_pdf_draw_border_ridge (FoDoc *fo_doc,
445 FoDatatype *color,
446 FoPdfOneBorderCoords *coords)
447 {
448 fo_doc_set_dash (fo_doc, 0.0, 0.0);
449
450 fo_pdf_clip_to_coords (fo_doc, coords);
451
452 if (coords->x1 == coords->x2)
453 { /* vertical */
454 if (coords->x1delta >= 0)
455 { /* left */
456 fo_pdf_draw_border_two_tone_vertical (fo_doc,
457 fo_color_get_color_one_half (color),
458 fo_color_get_color_three_quarter (color),
459 coords);
460 }
461 else
462 { /* right */
463 fo_pdf_draw_border_two_tone_vertical (fo_doc,
464 fo_color_get_color_three_quarter (color),
465 fo_color_get_color_one_half (color),
466 coords);
467 }
468 }
469 else
470 { /* horizontal */
471 if (coords->y1delta >= 0)
472 { /* bottom */
473 fo_pdf_draw_border_two_tone_horizontal (fo_doc,
474 fo_color_get_color_one_half (color),
475 fo_color_get_color_three_quarter (color),
476 coords);
477 }
478 else
479 { /* top */
480 /* 3/4 color */
481 fo_pdf_draw_border_two_tone_horizontal (fo_doc,
482 fo_color_get_color_three_quarter (color),
483 fo_color_get_color_one_half (color),
484 coords);
485 }
486 }
487 }
488
489 /**
490 * fo_pdf_draw_border_inset:
491 * @fo_doc: #FoDoc
492 * @color: Border color
493 * @coords: Coordinates of one border of an area
494 *
495 * Draw an inset border with colors based on @color and coordinates @coords.
496 **/
497 static void
fo_pdf_draw_border_inset(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)498 fo_pdf_draw_border_inset (FoDoc *fo_doc,
499 FoDatatype *color,
500 FoPdfOneBorderCoords *coords)
501 {
502 fo_doc_set_dash (fo_doc, 0.0, 0.0);
503
504 fo_pdf_clip_to_coords (fo_doc, coords);
505
506 if (coords->x1 == coords->x2)
507 { /* vertical */
508 if (coords->x1delta >= 0)
509 { /* left */
510 fo_pdf_draw_border_two_tone_vertical (fo_doc,
511 fo_color_get_color_one_half (color),
512 fo_color_get_color_one_quarter (color),
513 coords);
514 }
515 else
516 { /* right */
517 fo_pdf_draw_border_two_tone_vertical (fo_doc,
518 fo_color_get_color_three_quarter (color),
519 color,
520 coords);
521 }
522 }
523 else
524 { /* horizontal */
525 if (coords->y1delta >= 0)
526 { /* bottom */
527 fo_pdf_draw_border_two_tone_horizontal (fo_doc,
528 fo_color_get_color_three_quarter (color),
529 color,
530 coords);
531 }
532 else
533 { /* top */
534 /* 1/4 color */
535 fo_pdf_draw_border_two_tone_horizontal (fo_doc,
536 fo_color_get_color_one_half (color),
537 fo_color_get_color_one_quarter (color),
538 coords);
539 }
540 }
541 }
542
543 /**
544 * fo_pdf_draw_border_outset:
545 * @fo_doc: #FoDoc
546 * @color: Border color
547 * @coords: Coordinates of one border of an area
548 *
549 * Draw an outset border with colors based on @color and coordinates @coords.
550 **/
551 static void
fo_pdf_draw_border_outset(FoDoc * fo_doc,FoDatatype * color,FoPdfOneBorderCoords * coords)552 fo_pdf_draw_border_outset (FoDoc *fo_doc,
553 FoDatatype *color,
554 FoPdfOneBorderCoords *coords)
555 {
556 fo_doc_set_dash (fo_doc, 0.0, 0.0);
557
558 fo_pdf_clip_to_coords (fo_doc, coords);
559
560 if (coords->x1 == coords->x2)
561 { /* vertical */
562 if (coords->x1delta >= 0)
563 { /* left */
564 fo_pdf_draw_border_two_tone_vertical (fo_doc,
565 color,
566 fo_color_get_color_three_quarter (color),
567 coords);
568 }
569 else
570 { /* right */
571 fo_pdf_draw_border_two_tone_vertical (fo_doc,
572 fo_color_get_color_one_quarter (color),
573 fo_color_get_color_one_half (color),
574 coords);
575 }
576 }
577 else
578 { /* horizontal */
579 if (coords->y1delta >= 0)
580 { /* bottom */
581 fo_pdf_draw_border_two_tone_horizontal (fo_doc,
582 fo_color_get_color_one_quarter (color),
583 fo_color_get_color_one_half (color),
584 coords);
585 }
586 else
587 { /* top */
588 /* 3/4 color */
589 fo_pdf_draw_border_two_tone_horizontal (fo_doc,
590 color,
591 fo_color_get_color_three_quarter (color),
592 coords);
593 }
594 }
595 }
596
597 /**
598 * fo_pdf_draw_one_border:
599 * @fo_doc: #FoDoc
600 * @border_style: Border style
601 * @x1: X-coordinate of one corner
602 * @y1: Y-coordinate of one corner
603 * @x2: X-coordinate of the opposite corner
604 * @y2: Y-coordinate of the opposite corner
605 * @x1delta: Relative x-offset of interior corner of border
606 closest to (x1, y1)
607 * @y1delta: Relative y-offset of interior corner of border
608 closest to (x1, y1)
609 * @x2delta: Relative x-offset of interior corner of border
610 closest to (x2, y2)
611 * @y2delta: Relative y-offset of interior corner of border
612 closest to (x2, y2)
613 *
614 * Draw one border by outputting PDF statements to PDF document.
615 *
616 * Borders are mitred, i.e., the angle between the outer corner and
617 * the inner corner at the end of one border depends on both the width
618 * of the border and the width of the adjacent border that is at right
619 * angles to the current border.
620 **/
621 static void
fo_pdf_draw_one_border(FoDoc * fo_doc,FoDatatype * color,FoEnumEnum border_style,FoPdfOneBorderCoords * coords)622 fo_pdf_draw_one_border (FoDoc *fo_doc,
623 FoDatatype *color,
624 FoEnumEnum border_style,
625 FoPdfOneBorderCoords *coords)
626 {
627 fo_doc_save (fo_doc);
628
629 #if defined(LIBFO_DEBUG) && 1
630 g_message ("draw_one_border:: style: %d; x1: %f; y1; %f; x2: %f; y2: %f",
631 border_style, x1, y1, x2, y2);
632 g_message (" x1delta: %f; y1delta: %f; x2delta: %f; y2delta: %f",
633 x1delta, y1delta, x2delta, y2delta);
634 #endif
635
636 switch (border_style) {
637 case FO_ENUM_ENUM_SOLID:
638 fo_pdf_draw_border_solid (fo_doc,
639 color,
640 coords);
641 break;
642 case FO_ENUM_ENUM_DOUBLE:
643 fo_pdf_draw_border_double (fo_doc,
644 color,
645 coords);
646 break;
647 case FO_ENUM_ENUM_DOTTED:
648 fo_pdf_draw_border_dotted (fo_doc,
649 color,
650 coords);
651 break;
652 case FO_ENUM_ENUM_DASHED:
653 fo_pdf_draw_border_dashed (fo_doc,
654 color,
655 coords);
656 break;
657 case FO_ENUM_ENUM_GROOVE:
658 fo_pdf_draw_border_groove (fo_doc,
659 color,
660 coords);
661 break;
662 case FO_ENUM_ENUM_RIDGE:
663 fo_pdf_draw_border_ridge (fo_doc,
664 color,
665 coords);
666 break;
667 case FO_ENUM_ENUM_INSET:
668 fo_pdf_draw_border_inset (fo_doc,
669 color,
670 coords);
671 break;
672 case FO_ENUM_ENUM_OUTSET:
673 fo_pdf_draw_border_outset (fo_doc,
674 color,
675 coords);
676 break;
677 default:
678 g_error ("Unexpected enumeration.");
679 }
680 fo_doc_restore (fo_doc);
681 }
682
683 /**
684 * fo_pdf_draw_borders:
685 * @fo_doc: #FoDoc document
686 * @area_node: #FoArea node
687 *
688 * Draw the borders appropriate to @area_node.
689 *
690 * FIXME: Does not work correctly for #FoAreaSpanningTableCell.
691 **/
692 static void
fo_pdf_draw_borders(FoDoc * fo_doc,FoArea * area_node,gdouble width,gdouble height)693 fo_pdf_draw_borders (FoDoc *fo_doc,
694 FoArea *area_node,
695 gdouble width,
696 gdouble height)
697 {
698 GValue value = { 0, {{0}, {0}} };
699 FoFo *fo = fo_area_get_generated_by (area_node);
700 FoDatatype *color;
701 FoEnumEnum border_style;
702 gdouble x = fo_area_area_get_x (area_node);
703 gdouble y = fo_area_area_get_y (area_node);
704 gdouble border_before =
705 fo_area_area_get_border_before (area_node);
706 gdouble border_after =
707 fo_area_area_get_border_after (area_node);
708 gdouble border_start =
709 fo_area_area_get_border_start (area_node);
710 gdouble border_end =
711 fo_area_area_get_border_end (area_node);
712
713 g_value_init (&value, G_TYPE_OBJECT);
714
715 /* before == top */
716 if (border_before != 0.0)
717 {
718 border_style =
719 fo_enum_get_value (fo_property_get_value (fo_cbpbp_fo_get_border_before_style (fo)));
720
721 if ((border_style != FO_ENUM_ENUM_NONE) &&
722 (border_style != FO_ENUM_ENUM_HIDDEN))
723 {
724 FoPdfOneBorderCoords coords = {x,
725 y,
726 x + width,
727 y,
728 border_start,
729 -border_before,
730 -border_end,
731 -border_before};
732
733 color =
734 fo_property_get_value (fo_cbpbp_fo_get_border_before_color (fo));
735
736 fo_pdf_draw_one_border (fo_doc,
737 color,
738 border_style,
739 &coords);
740 }
741 }
742 /* start == left */
743 if (border_start != 0.0)
744 {
745 border_style =
746 fo_enum_get_value (fo_property_get_value (fo_cbpbp_fo_get_border_start_style (fo)));
747
748 if ((border_style != FO_ENUM_ENUM_NONE) &&
749 (border_style != FO_ENUM_ENUM_HIDDEN))
750 {
751 FoPdfOneBorderCoords coords = {x,
752 y,
753 x,
754 y - height,
755 border_start,
756 -border_before,
757 border_start,
758 border_after};
759
760 color =
761 fo_property_get_value (fo_cbpbp_fo_get_border_start_color (fo));
762
763 fo_pdf_draw_one_border (fo_doc,
764 color,
765 border_style,
766 &coords);
767 }
768 }
769 /* end == right */
770 if (border_end != 0.0)
771 {
772 border_style =
773 fo_enum_get_value (fo_property_get_value (fo_cbpbp_fo_get_border_end_style (fo)));
774
775 if ((border_style != FO_ENUM_ENUM_NONE) &&
776 (border_style != FO_ENUM_ENUM_HIDDEN))
777 {
778 FoPdfOneBorderCoords coords = {x + width,
779 y,
780 x + width,
781 y - height,
782 -border_end,
783 -border_before,
784 -border_end,
785 border_after};
786
787 color =
788 fo_property_get_value (fo_cbpbp_fo_get_border_end_color (fo));
789
790 fo_pdf_draw_one_border (fo_doc,
791 color,
792 border_style,
793 &coords);
794 }
795 }
796 /* after == bottom */
797 if (border_after != 0.0)
798 {
799 border_style =
800 fo_enum_get_value (fo_property_get_value (fo_cbpbp_fo_get_border_after_style (fo)));
801
802 if ((border_style != FO_ENUM_ENUM_NONE) &&
803 (border_style != FO_ENUM_ENUM_HIDDEN))
804 {
805 FoPdfOneBorderCoords coords = {x,
806 y - height,
807 x + width,
808 y - height,
809 border_start,
810 border_after,
811 -border_end,
812 border_after};
813
814 color =
815 fo_property_get_value (fo_cbpbp_fo_get_border_after_color (fo));
816
817 fo_pdf_draw_one_border (fo_doc,
818 color,
819 border_style,
820 &coords);
821 }
822 }
823 }
824
825 /**
826 * fo_area_tree_to_pdf:
827 * @area_node: #FoArea node to be output to PDF file
828 * @data: Pointer to #FoAreaToPDFData with additional data
829 *
830 * Add @area_node and its descendants to the PDF document. The PDF
831 * document pointer and other required data is in @data.
832 *
833 * This conforms to FoAreaForeachFunc type so can use
834 * fo_area_children_foreach() on any children of @area_node.
835 **/
836 void
fo_area_tree_to_pdf(FoArea * area_node,gpointer data)837 fo_area_tree_to_pdf (FoArea *area_node,
838 gpointer data)
839 {
840 FoAreaToPDFData *fo_area_to_pdf_data = (FoAreaToPDFData *) data;
841 FoDoc *fo_doc;
842 FoFo *fo;
843 FoProperty *prop_background_color;
844 FoDatatype *background_color;
845
846 GValue value = { 0, {{0}, {0}} };
847
848 g_value_init (&value, G_TYPE_OBJECT);
849
850 g_return_if_fail (area_node != NULL);
851 g_return_if_fail (FO_IS_AREA (area_node));
852
853 fo_doc = fo_area_to_pdf_data->fo_doc;
854
855 fo = fo_area_get_generated_by (area_node);
856
857 if (FO_IS_AREA_PAGE (area_node))
858 {
859 fo_doc_begin_page (fo_doc,
860 fo_area_page_get_page_width (area_node),
861 fo_area_page_get_page_height (area_node),
862 NULL);
863
864 fo_area_children_foreach (area_node,
865 G_TRAVERSE_ALL,
866 &fo_area_tree_to_pdf,
867 (gpointer) fo_area_to_pdf_data);
868
869 fo_doc_end_page (fo_doc);
870 }
871 else if (FO_IS_AREA_LAYOUT (area_node))
872 {
873 FoPropertyColor *prop_color;
874 FoPropertyFontSize *prop_font_size;
875 FoDatatype *color;
876 FoDatatype *length;
877 gdouble x = fo_area_area_get_x (area_node);
878 gdouble y = fo_area_area_get_y (area_node);
879 gdouble width = fo_area_area_get_width (area_node);
880 gdouble height = fo_area_area_get_height (area_node);
881 gdouble border_before =
882 fo_area_area_get_border_before (area_node);
883 gdouble border_start =
884 fo_area_area_get_border_start (area_node);
885 gdouble padding_before =
886 fo_area_area_get_padding_before (area_node);
887 gdouble padding_start =
888 fo_area_area_get_padding_start (area_node);
889
890 fo_doc_save (fo_doc);
891
892 /* font-size */
893 g_object_get_property (G_OBJECT (fo),
894 "font-size",
895 &value);
896
897 prop_font_size = g_value_get_object (&value);
898
899 g_object_get_property (G_OBJECT (prop_font_size),
900 "value",
901 &value);
902
903 length = g_value_get_object (&value);
904
905 /* background-color */
906 g_object_get_property (G_OBJECT (fo),
907 "background-color",
908 &value);
909
910 prop_background_color = g_value_get_object (&value);
911
912 g_object_get_property (G_OBJECT (prop_background_color),
913 "value",
914 &value);
915
916 background_color = g_value_get_object (&value);
917
918 fo_pdf_draw_background (fo_doc,
919 x,
920 y,
921 width,
922 height,
923 background_color);
924
925 /* color */
926 g_object_get_property (G_OBJECT (fo),
927 "color",
928 &value);
929
930 prop_color = g_value_get_object (&value);
931
932 g_object_get_property (G_OBJECT (prop_color),
933 "value",
934 &value);
935
936 color = g_value_get_object (&value);
937
938 fo_doc_set_fill_color (fo_doc,
939 color);
940
941 #if defined(LIBFO_DEBUG) && 0
942 fo_object_debug_dump (area_node, 0);
943 #endif
944
945 fo_doc_render_layout_lines (fo_doc,
946 area_node,
947 x + border_start + padding_start,
948 y - border_before - padding_before);
949
950 /* borders */
951 fo_pdf_draw_borders (fo_doc, area_node, width, height);
952
953 fo_doc_restore (fo_doc);
954 }
955 else if (FO_IS_AREA_NORMAL (area_node))
956 {
957 gdouble width = fo_area_area_get_width (area_node);
958 gdouble height = fo_area_area_get_height (area_node);
959
960 fo_pdf_draw_borders (fo_doc, area_node, width, height);
961
962 fo_doc_translate (fo_doc,
963 fo_area_area_get_x (area_node),
964 fo_area_area_get_y (area_node));
965
966 fo_area_children_foreach (area_node,
967 G_TRAVERSE_ALL,
968 &fo_area_tree_to_pdf,
969 fo_area_to_pdf_data);
970 fo_doc_translate (fo_doc,
971 - fo_area_area_get_x (area_node),
972 - fo_area_area_get_y (area_node));
973 }
974 else if (FO_IS_AREA_VIEWPORT_REFERENCE (area_node))
975 {
976 FoProperty *prop_overflow;
977 FoEnumEnum overflow;
978 gdouble x = fo_area_area_get_x (area_node);
979 gdouble y = fo_area_area_get_y (area_node);
980 /* FIXME: Why is this available width and height only? */
981 gdouble width = fo_area_get_available_width (area_node);
982 gdouble height = fo_area_get_available_height (area_node);
983
984 /* background-color */
985 background_color = fo_property_get_value (fo_cbpbp_fo_get_background_color (fo));
986
987 fo_pdf_draw_background (fo_doc,
988 x,
989 y,
990 width,
991 height,
992 background_color);
993
994 /* borders */
995 fo_pdf_draw_borders (fo_doc, area_node, width, height);
996
997 fo_doc_save (fo_doc);
998 fo_doc_translate (fo_doc,
999 fo_area_area_get_x (area_node),
1000 fo_area_area_get_y (area_node));
1001
1002 /* overflow */
1003 g_object_get_property (G_OBJECT (fo_fo_get_area_fo (fo)),
1004 "overflow",
1005 &value);
1006 prop_overflow = g_value_get_object (&value);
1007 overflow =
1008 fo_enum_get_value (fo_property_get_value (prop_overflow));
1009 if ((overflow == FO_ENUM_ENUM_HIDDEN) ||
1010 (overflow == FO_ENUM_ENUM_SCROLL))
1011 {
1012 fo_doc_move_to (fo_doc,
1013 0,
1014 0);
1015 fo_doc_line_to (fo_doc,
1016 0,
1017 -height);
1018 fo_doc_line_to (fo_doc,
1019 width,
1020 -height);
1021 fo_doc_line_to (fo_doc,
1022 width,
1023 0);
1024 fo_doc_clip (fo_doc);
1025 }
1026
1027 fo_area_children_foreach (area_node,
1028 G_TRAVERSE_ALL,
1029 &fo_area_tree_to_pdf,
1030 fo_area_to_pdf_data);
1031
1032 fo_doc_restore (fo_doc);
1033 }
1034 else if (FO_IS_AREA_SPANNING_TABLE_CELL (area_node))
1035 {
1036 gdouble x = fo_area_area_get_x (area_node);
1037 gdouble y = fo_area_area_get_y (area_node);
1038 gdouble width = fo_area_area_get_width (area_node);
1039 gdouble height = fo_area_spanning_table_cell_get_real_available_height (area_node);
1040
1041 fo_doc_save (fo_doc);
1042
1043 /* background-color */
1044 g_object_get_property (G_OBJECT (fo),
1045 "background-color",
1046 &value);
1047
1048 prop_background_color = g_value_get_object (&value);
1049
1050 g_object_get_property (G_OBJECT (prop_background_color),
1051 "value",
1052 &value);
1053
1054 background_color = g_value_get_object (&value);
1055
1056 fo_pdf_draw_background (fo_doc,
1057 x,
1058 y,
1059 width,
1060 height,
1061 background_color);
1062
1063 /* borders */
1064 fo_pdf_draw_borders (fo_doc, area_node, width, height);
1065
1066 fo_doc_translate (fo_doc,
1067 fo_area_area_get_x (area_node),
1068 fo_area_area_get_y (area_node));
1069
1070 fo_area_children_foreach (area_node,
1071 G_TRAVERSE_ALL,
1072 &fo_area_tree_to_pdf,
1073 fo_area_to_pdf_data);
1074
1075 fo_doc_restore (fo_doc);
1076 }
1077 else if (FO_IS_AREA_TABLE_CONTINUATION (area_node))
1078 {
1079 FoArea *table_header = FO_AREA_TABLE_CONTINUATION (area_node)->table_header;
1080 gdouble x = fo_area_area_get_x (area_node);
1081 gdouble y = fo_area_area_get_y (area_node);
1082 gdouble width = fo_area_area_get_width (area_node);
1083 gdouble height = fo_area_area_get_height (area_node);
1084
1085 if (table_header != NULL)
1086 {
1087 fo_doc_save (fo_doc);
1088 fo_doc_translate (fo_doc,
1089 fo_area_area_get_x (area_node),
1090 fo_area_area_get_y (area_node));
1091
1092 fo_area_tree_to_pdf (table_header,
1093 fo_area_to_pdf_data);
1094
1095 fo_doc_restore (fo_doc);
1096 }
1097
1098 fo_doc_save (fo_doc);
1099
1100 /* background-color */
1101 g_object_get_property (G_OBJECT (fo),
1102 "background-color",
1103 &value);
1104
1105 prop_background_color = g_value_get_object (&value);
1106
1107 g_object_get_property (G_OBJECT (prop_background_color),
1108 "value",
1109 &value);
1110
1111 background_color = g_value_get_object (&value);
1112
1113 fo_pdf_draw_background (fo_doc,
1114 x,
1115 y -
1116 (table_header ? fo_area_area_get_height (table_header) : 0.0),
1117 width,
1118 height,
1119 background_color);
1120
1121 /* borders */
1122 fo_pdf_draw_borders (fo_doc, area_node, width, height);
1123
1124 fo_doc_translate (fo_doc,
1125 fo_area_area_get_x (area_node),
1126 fo_area_area_get_y (area_node) -
1127 (table_header ? fo_area_area_get_height (table_header) : 0.0) -
1128 (table_header ? fo_area_area_get_height (table_header) : 0.0));
1129
1130 fo_area_children_foreach (area_node,
1131 G_TRAVERSE_ALL,
1132 &fo_area_tree_to_pdf,
1133 fo_area_to_pdf_data);
1134
1135 fo_doc_restore (fo_doc);
1136 }
1137 else if (FO_IS_AREA_REFERENCE (area_node))
1138 {
1139 gdouble x = fo_area_area_get_x (area_node);
1140 gdouble y = fo_area_area_get_y (area_node);
1141 gdouble width = fo_area_area_get_width (area_node);
1142 gdouble height = fo_area_area_get_height (area_node);
1143
1144 fo_doc_save (fo_doc);
1145
1146 /* background-color */
1147 g_object_get_property (G_OBJECT (fo),
1148 "background-color",
1149 &value);
1150
1151 prop_background_color = g_value_get_object (&value);
1152
1153 g_object_get_property (G_OBJECT (prop_background_color),
1154 "value",
1155 &value);
1156
1157 background_color = g_value_get_object (&value);
1158
1159 fo_pdf_draw_background (fo_doc,
1160 x,
1161 y,
1162 width,
1163 height,
1164 background_color);
1165
1166 /* borders */
1167 fo_pdf_draw_borders (fo_doc, area_node, width, height);
1168
1169 fo_doc_translate (fo_doc,
1170 fo_area_area_get_x (area_node),
1171 fo_area_area_get_y (area_node));
1172
1173 fo_area_children_foreach (area_node,
1174 G_TRAVERSE_ALL,
1175 &fo_area_tree_to_pdf,
1176 fo_area_to_pdf_data);
1177
1178 fo_doc_restore (fo_doc);
1179 }
1180 else if (FO_IS_AREA_AREA (area_node))
1181 {
1182 gdouble width = fo_area_area_get_width (area_node);
1183 gdouble height = fo_area_area_get_height (area_node);
1184
1185 /* borders */
1186 fo_pdf_draw_borders (fo_doc, area_node, width, height);
1187
1188 fo_doc_translate (fo_doc,
1189 fo_area_area_get_x (area_node),
1190 fo_area_area_get_y (area_node));
1191
1192 fo_area_children_foreach (area_node,
1193 G_TRAVERSE_ALL,
1194 &fo_area_tree_to_pdf,
1195 fo_area_to_pdf_data);
1196
1197 fo_doc_translate (fo_doc,
1198 - fo_area_area_get_x (area_node),
1199 - fo_area_area_get_y (area_node));
1200 }
1201 else
1202 {
1203 fo_area_children_foreach (area_node,
1204 G_TRAVERSE_ALL,
1205 &fo_area_tree_to_pdf,
1206 fo_area_to_pdf_data);
1207 }
1208 }
1209
1210