1 /* Copyright (C) 1995, 1996, 1998 artofcode LLC. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify it
4 under the terms of the GNU General Public License as published by the
5 Free Software Foundation; either version 2 of the License, or (at your
6 option) any later version.
7
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along
14 with this program; if not, write to the Free Software Foundation, Inc.,
15 59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16
17 */
18
19 /*$Id: gdevcgml.c,v 1.2.6.1.2.1 2003/01/17 00:49:00 giles Exp $ */
20 /* CGM-writing library */
21 #include "memory_.h"
22 #include "stdio_.h"
23 #include "gdevcgmx.h"
24
25 /* Forward references to command-writing procedures */
26 private void begin_command(P2(cgm_state *, cgm_op_index));
27
28 #define OP(op) begin_command(st, op)
29 private cgm_result end_command(P1(cgm_state *));
30
31 #define END_OP (void)end_command(st)
32 #define DONE return end_command(st)
33 /* Parameters */
34 private void put_int(P3(cgm_state *, cgm_int, int));
35
36 #define CI(ci) put_int(st, ci, st->metafile.color_index_precision)
37 #define I(i) put_int(st, i, st->metafile.integer_precision)
38 #define IX(ix) put_int(st, ix, st->metafile.index_precision)
39 #define E(e) put_int(st, (int)(e), 16)
40 private void put_real(P3(cgm_state *, cgm_real, const cgm_precision *));
41
42 #define R(r) put_real(st, r, &st->metafile.real_precision)
43 private void put_vdc(P2(cgm_state *, const cgm_vdc *));
44
45 #define VDC(vdc) put_vdc(st, vdc)
46 #define VDC2(vdc1, vdc2) VDC(vdc1); VDC(vdc2)
47 #define VDC4(vdc1, vdc2, vdc3, vdc4) VDC2(vdc1, vdc2); VDC2(vdc3, vdc4)
48 private void put_vdc_r(P3(cgm_state *, const cgm_line_marker_extent *, cgm_line_marker_specification_mode));
49
50 #define VDC_R(vdcr, mode) put_vdc_r(st, vdcr, mode)
51 private void put_point(P2(cgm_state *, const cgm_point *));
52
53 #define P(p) put_point(st, p)
54 private void put_points(P3(cgm_state *, const cgm_point *, int));
55
56 #define nP(p, n) put_points(st, p, n)
57 private void put_string(P3(cgm_state *, const char *, uint));
58
59 #define S(s, l) put_string(st, s, l)
60 private void put_color(P2(cgm_state *, const cgm_color *));
61
62 #define CO(co) put_color(st, co)
63 private void put_rgb(P2(cgm_state *, const cgm_rgb *));
64
65 #define CD(cd) put_rgb(st, cd)
66 /* Other data types */
67 #define put_byte(st, b)\
68 if ( st->command_count == command_max_count ) write_command(st, false);\
69 st->command[st->command_count++] = (byte)(b)
70 private void put_bytes(P3(cgm_state *, const byte *, uint));
71 private void write_command(P2(cgm_state *, bool));
72 private void put_real_precision(P2(cgm_state *, const cgm_precision *));
73
74 /* ================ Public routines ================ */
75
76 /* ---------------- Initialize/terminate ---------------- */
77
78 /* Initialize a CGM writer. */
79 cgm_state *
cgm_initialize(FILE * file,const cgm_allocator * cal)80 cgm_initialize(FILE * file, const cgm_allocator * cal)
81 {
82 cgm_state *st = (*cal->alloc) (cal->private_data, sizeof(cgm_state));
83
84 if (st == 0)
85 return 0;
86 st->file = file;
87 st->allocator = *cal;
88 /* Initialize metafile elements. */
89 st->metafile.vdc_type = cgm_vdc_integer;
90 st->metafile.integer_precision = 16;
91 st->metafile.real_precision.representation = cgm_representation_fixed;
92 st->metafile.real_precision.exponent_or_whole_width = 16;
93 st->metafile.real_precision.fraction_width = 16;
94 st->metafile.index_precision = 16;
95 st->metafile.color_precision = 8;
96 st->metafile.color_index_precision = 8;
97 st->metafile.maximum_color_index = 63;
98 /* color_value_extent */
99 /*st->metafile.character_coding_announcer = 0; */
100 /* Initialize picture elements. */
101 st->picture.scaling_mode = cgm_scaling_abstract;
102 st->picture.color_selection_mode = cgm_color_selection_indexed;
103 st->picture.line_width_specification_mode = cgm_line_marker_absolute;
104 st->picture.marker_size_specification_mode = cgm_line_marker_absolute;
105 st->picture.edge_width_specification_mode = cgm_line_marker_absolute;
106 /* vdc_extent */
107 /* background_color */
108 /* Initialize control elements. */
109 st->vdc_integer_precision = st->metafile.integer_precision;
110 st->vdc_real_precision = st->metafile.real_precision;
111 st->transparency = cgm_transparency_on;
112 /* clip_rectangle */
113 st->clip_indicator = cgm_clip_on;
114 /* Initialize other state elements. */
115 st->line_bundle_index = 1;
116 st->line_type = cgm_line_solid;
117 /* line_width */
118 /* line_color */
119 st->marker_bundle_index = 1;
120 st->marker_type = cgm_marker_asterisk;
121 /* marker_size */
122 /* marker_color */
123 st->text_bundle_index = 1;
124 st->text_font_index = 1;
125 st->text_precision = cgm_text_precision_string;
126 st->character_expansion_factor = 1.0;
127 st->character_spacing = 0.0;
128 /* text_color */
129 /* character_height */
130 /* character_orientation */
131 st->text_path = cgm_text_path_right;
132 /* text_alignment */
133 st->character_set_index = 1;
134 st->alternate_character_set_index = 1;
135 st->fill_bundle_index = 1;
136 st->interior_style = cgm_interior_style_hollow;
137 st->hatch_index = cgm_hatch_horizontal;
138 st->pattern_index = 1;
139 st->edge_bundle_index = 1;
140 st->edge_type = cgm_edge_solid;
141 /* edge_width */
142 st->edge_visibility = false;
143 /* fill_reference_point */
144 /* pattern_table */
145 /* pattern_size */
146 /* color_table */
147 memset(st->source_flags, (byte) cgm_aspect_source_individual,
148 sizeof(st->source_flags));
149 return st;
150 }
151
152 /* Terminate a CGM writer. */
153 cgm_result
cgm_terminate(cgm_state * st)154 cgm_terminate(cgm_state * st)
155 {
156 (*st->allocator.free) (st->allocator.private_data, st);
157 return cgm_result_ok;
158 }
159
160 /* ---------------- Metafile elements ---------------- */
161
162 cgm_result
cgm_BEGIN_METAFILE(cgm_state * st,const char * str,uint len)163 cgm_BEGIN_METAFILE(cgm_state * st, const char *str, uint len)
164 {
165 OP(BEGIN_METAFILE);
166 S(str, len);
167 DONE;
168 }
169
170 cgm_result
cgm_set_metafile_elements(cgm_state * st,const cgm_metafile_elements * meta,long mask)171 cgm_set_metafile_elements(cgm_state * st, const cgm_metafile_elements * meta, long mask)
172 {
173 if ((mask & cgm_set_METAFILE_VERSION)) {
174 OP(METAFILE_VERSION);
175 I(meta->metafile_version);
176 END_OP;
177 st->metafile.metafile_version = meta->metafile_version;
178 }
179 if ((mask & cgm_set_METAFILE_DESCRIPTION)) {
180 OP(METAFILE_DESCRIPTION);
181 S(meta->metafile_description.chars, meta->metafile_description.length);
182 END_OP;
183 st->metafile.metafile_description = meta->metafile_description;
184 }
185 if ((mask & cgm_set_VDC_TYPE)) {
186 OP(VDC_TYPE);
187 E(meta->vdc_type);
188 END_OP;
189 st->metafile.vdc_type = meta->vdc_type;
190 }
191 if ((mask & cgm_set_INTEGER_PRECISION)) {
192 OP(INTEGER_PRECISION);
193 I(meta->integer_precision);
194 END_OP;
195 st->metafile.integer_precision = meta->integer_precision;
196 }
197 if ((mask & cgm_set_REAL_PRECISION)) {
198 OP(REAL_PRECISION);
199 put_real_precision(st, &meta->real_precision);
200 END_OP;
201 st->metafile.real_precision = meta->real_precision;
202 }
203 if ((mask & cgm_set_INDEX_PRECISION)) {
204 OP(INDEX_PRECISION);
205 I(meta->index_precision);
206 END_OP;
207 st->metafile.index_precision = meta->index_precision;
208 }
209 if ((mask & cgm_set_COLOR_PRECISION)) {
210 OP(COLOR_PRECISION);
211 I(meta->color_precision);
212 END_OP;
213 st->metafile.color_index_precision = meta->color_index_precision;
214 }
215 if ((mask & cgm_set_COLOR_INDEX_PRECISION)) {
216 OP(COLOR_INDEX_PRECISION);
217 I(meta->color_index_precision);
218 END_OP;
219 st->metafile.color_index_precision = meta->color_index_precision;
220 }
221 if ((mask & cgm_set_MAXIMUM_COLOR_INDEX)) {
222 OP(MAXIMUM_COLOR_INDEX);
223 CI(meta->maximum_color_index);
224 END_OP;
225 st->metafile.maximum_color_index = meta->maximum_color_index;
226 }
227 if ((mask & cgm_set_METAFILE_ELEMENT_LIST)) {
228 int i;
229 const int *p;
230
231 OP(METAFILE_ELEMENT_LIST);
232 for (i = 0, p = meta->metafile_element_list;
233 i < meta->metafile_element_list_count;
234 i++, p += 2
235 ) {
236 I(p[0]);
237 I(p[1]);
238 }
239 END_OP;
240 st->metafile.metafile_element_list =
241 meta->metafile_element_list;
242 st->metafile.metafile_element_list_count =
243 meta->metafile_element_list_count;
244 }
245 /* element list */
246 if ((mask & cgm_set_FONT_LIST)) {
247 int i;
248
249 OP(FONT_LIST);
250 for (i = 0; i < meta->font_list_count; ++i)
251 S(meta->font_list[i].chars, meta->font_list[i].length);
252 END_OP;
253 st->metafile.font_list = meta->font_list;
254 st->metafile.font_list_count = meta->font_list_count;
255 }
256 /* character set list */
257 /* character coding announcer */
258 return st->result;
259 }
260
261 cgm_result
cgm_END_METAFILE(cgm_state * st)262 cgm_END_METAFILE(cgm_state * st)
263 {
264 OP(END_METAFILE);
265 DONE;
266 }
267
268 /* ---------------- Picture elements ---------------- */
269
270 cgm_result
cgm_BEGIN_PICTURE(cgm_state * st,const char * str,uint len)271 cgm_BEGIN_PICTURE(cgm_state * st, const char *str, uint len)
272 {
273 OP(BEGIN_PICTURE);
274 S(str, len);
275 DONE;
276 }
277
278 cgm_result
cgm_set_picture_elements(cgm_state * st,const cgm_picture_elements * pic,long mask)279 cgm_set_picture_elements(cgm_state * st, const cgm_picture_elements * pic, long mask)
280 {
281 if ((mask & cgm_set_SCALING_MODE)) {
282 OP(SCALING_MODE);
283 E(pic->scaling_mode);
284 R(pic->scale_factor);
285 st->picture.scaling_mode = pic->scaling_mode;
286 st->picture.scale_factor = pic->scale_factor;
287 END_OP;
288 }
289 if ((mask & cgm_set_COLOR_SELECTION_MODE)) {
290 OP(COLOR_SELECTION_MODE);
291 E(pic->color_selection_mode);
292 END_OP;
293 st->picture.color_selection_mode = pic->color_selection_mode;
294 }
295 if ((mask & cgm_set_LINE_WIDTH_SPECIFICATION_MODE)) {
296 OP(LINE_WIDTH_SPECIFICATION_MODE);
297 E(pic->line_width_specification_mode);
298 END_OP;
299 st->picture.line_width_specification_mode = pic->line_width_specification_mode;
300 }
301 if ((mask & cgm_set_MARKER_SIZE_SPECIFICATION_MODE)) {
302 OP(MARKER_SIZE_SPECIFICATION_MODE);
303 E(pic->marker_size_specification_mode);
304 END_OP;
305 st->picture.marker_size_specification_mode = pic->marker_size_specification_mode;
306 }
307 if ((mask & cgm_set_EDGE_WIDTH_SPECIFICATION_MODE)) {
308 OP(EDGE_WIDTH_SPECIFICATION_MODE);
309 E(pic->edge_width_specification_mode);
310 END_OP;
311 st->picture.edge_width_specification_mode = pic->edge_width_specification_mode;
312 }
313 if ((mask & cgm_set_VDC_EXTENT)) {
314 OP(VDC_EXTENT);
315 P(&pic->vdc_extent[0]);
316 P(&pic->vdc_extent[1]);
317 END_OP;
318 st->picture.vdc_extent[0] = pic->vdc_extent[0];
319 st->picture.vdc_extent[1] = pic->vdc_extent[1];
320 }
321 if ((mask & cgm_set_BACKGROUND_COLOR)) {
322 OP(BACKGROUND_COLOR);
323 CD(&pic->background_color.rgb);
324 DONE;
325 st->picture.background_color = pic->background_color;
326 }
327 return st->result;
328 }
329
330 cgm_result
cgm_BEGIN_PICTURE_BODY(cgm_state * st)331 cgm_BEGIN_PICTURE_BODY(cgm_state * st)
332 {
333 OP(BEGIN_PICTURE_BODY);
334 DONE;
335 }
336
337 cgm_result
cgm_END_PICTURE(cgm_state * st)338 cgm_END_PICTURE(cgm_state * st)
339 {
340 OP(END_PICTURE);
341 DONE;
342 }
343
344 /* ---------------- Control elements ---------------- */
345
346 cgm_result
cgm_VDC_INTEGER_PRECISION(cgm_state * st,int precision)347 cgm_VDC_INTEGER_PRECISION(cgm_state * st, int precision)
348 {
349 if (st->vdc_integer_precision != precision) {
350 OP(VDC_INTEGER_PRECISION);
351 I(precision);
352 st->vdc_integer_precision = precision;
353 DONE;
354 } else
355 return cgm_result_ok;
356 }
357
358 cgm_result
cgm_VDC_REAL_PRECISION(cgm_state * st,const cgm_precision * precision)359 cgm_VDC_REAL_PRECISION(cgm_state * st, const cgm_precision * precision)
360 {
361 OP(VDC_REAL_PRECISION);
362 put_real_precision(st, precision);
363 st->vdc_real_precision = *precision;
364 DONE;
365 }
366
367 cgm_result
cgm_AUXILIARY_COLOR(cgm_state * st,const cgm_color * color)368 cgm_AUXILIARY_COLOR(cgm_state * st, const cgm_color * color)
369 {
370 OP(AUXILIARY_COLOR);
371 CO(color);
372 st->auxiliary_color = *color;
373 DONE;
374 }
375
376 cgm_result
cgm_TRANSPARENCY(cgm_state * st,cgm_transparency transparency)377 cgm_TRANSPARENCY(cgm_state * st, cgm_transparency transparency)
378 {
379 OP(TRANSPARENCY);
380 E(transparency);
381 st->transparency = transparency;
382 DONE;
383 }
384
385 cgm_result
cgm_CLIP_RECTANGLE(cgm_state * st,const cgm_point rectangle[2])386 cgm_CLIP_RECTANGLE(cgm_state * st, const cgm_point rectangle[2])
387 {
388 OP(CLIP_RECTANGLE);
389 P(&rectangle[0]);
390 st->clip_rectangle[0] = rectangle[0];
391 P(&rectangle[1]);
392 st->clip_rectangle[1] = rectangle[1];
393 DONE;
394 }
395
396 cgm_result
cgm_CLIP_INDICATOR(cgm_state * st,cgm_clip_indicator clip)397 cgm_CLIP_INDICATOR(cgm_state * st, cgm_clip_indicator clip)
398 {
399 OP(CLIP_INDICATOR);
400 E(clip);
401 st->clip_indicator = clip;
402 DONE;
403 }
404
405 /* ---------------- Graphical primitive elements ---------------- */
406
407 cgm_result
cgm_POLYLINE(cgm_state * st,const cgm_point * vertices,int count)408 cgm_POLYLINE(cgm_state * st, const cgm_point * vertices, int count)
409 {
410 OP(POLYLINE);
411 nP(vertices, count);
412 DONE;
413 }
414
415 cgm_result
cgm_DISJOINT_POLYLINE(cgm_state * st,const cgm_point * endpoints,int count)416 cgm_DISJOINT_POLYLINE(cgm_state * st, const cgm_point * endpoints, int count)
417 {
418 OP(DISJOINT_POLYLINE);
419 nP(endpoints, count);
420 DONE;
421 }
422
423 cgm_result
cgm_POLYMARKER(cgm_state * st,const cgm_point * positions,int count)424 cgm_POLYMARKER(cgm_state * st, const cgm_point * positions, int count)
425 {
426 OP(POLYMARKER);
427 nP(positions, count);
428 DONE;
429 }
430
431 cgm_result
cgm_TEXT(cgm_state * st,const cgm_point * position,bool final,const char * str,uint len)432 cgm_TEXT(cgm_state * st, const cgm_point * position, bool final, const char *str, uint len)
433 {
434 OP(TEXT);
435 P(position);
436 E(final);
437 S(str, len);
438 DONE;
439 }
440
441 cgm_result
cgm_RESTRICTED_TEXT(cgm_state * st,const cgm_vdc * delta_width,const cgm_vdc * delta_height,const cgm_point * position,bool final,const char * str,uint len)442 cgm_RESTRICTED_TEXT(cgm_state * st, const cgm_vdc * delta_width, const cgm_vdc * delta_height, const cgm_point * position, bool final, const char *str, uint len)
443 {
444 OP(RESTRICTED_TEXT);
445 VDC2(delta_width, delta_height);
446 P(position);
447 E(final);
448 S(str, len);
449 DONE;
450 }
451
452 cgm_result
cgm_APPEND_TEXT(cgm_state * st,bool final,const char * str,uint len)453 cgm_APPEND_TEXT(cgm_state * st, bool final, const char *str, uint len)
454 {
455 OP(APPEND_TEXT);
456 E(final);
457 S(str, len);
458 DONE;
459 }
460
461 cgm_result
cgm_POLYGON(cgm_state * st,const cgm_point * vertices,int count)462 cgm_POLYGON(cgm_state * st, const cgm_point * vertices, int count)
463 {
464 OP(POLYGON);
465 nP(vertices, count);
466 DONE;
467 }
468
469 cgm_result
cgm_POLYGON_SET(cgm_state * st,const cgm_polygon_edge * vertices,int count)470 cgm_POLYGON_SET(cgm_state * st, const cgm_polygon_edge * vertices, int count)
471 {
472 int i;
473
474 OP(POLYGON);
475 for (i = 0; i < count; ++i) {
476 P(&vertices[i].vertex);
477 E(vertices[i].edge_out);
478 }
479 DONE;
480 }
481
482 cgm_result
cgm_CELL_ARRAY(cgm_state * st,const cgm_point * pqr,cgm_int nx,cgm_int ny,cgm_int local_color_precision,cgm_cell_representation_mode mode,const byte * values,uint source_bit,uint raster)483 cgm_CELL_ARRAY(cgm_state * st, const cgm_point * pqr /*[3] */ , cgm_int nx, cgm_int ny, cgm_int local_color_precision, cgm_cell_representation_mode mode, const byte * values, uint source_bit, uint raster)
484 {
485 int precision = local_color_precision;
486 int bits_per_pixel;
487 uint row_bytes;
488 const byte *row = values + (source_bit >> 3);
489 int bit = source_bit & 7;
490 int y;
491
492 /* Currently we ignore the cell representation_mode, and always */
493 /* produce cell arrays in 'packed' format. */
494 mode = cgm_cell_mode_packed;
495 OP(CELL_ARRAY);
496 nP(pqr, 3);
497 I(nx);
498 I(ny);
499 I(local_color_precision);
500 E(mode);
501 if (precision == 0)
502 precision = (st->picture.color_selection_mode ==
503 cgm_color_selection_indexed ?
504 st->metafile.color_index_precision :
505 st->metafile.color_precision);
506 bits_per_pixel =
507 (st->picture.color_selection_mode == cgm_color_selection_indexed ?
508 precision : precision * 3);
509 row_bytes = (bits_per_pixel * nx + 7) >> 3;
510 for (y = 0; y < ny; y++, row += raster) {
511 if (bit == 0)
512 put_bytes(st, row, row_bytes);
513 else {
514 uint i;
515
516 for (i = 0; i < row_bytes; i++) {
517 byte b = (row[i] << bit) +
518 (row[i + 1] >> (8 - bit));
519
520 put_byte(st, b);
521 }
522 }
523 if ((row_bytes & 1)) {
524 put_byte(st, 0);
525 }
526 }
527 DONE;
528 }
529
530 cgm_result
cgm_RECTANGLE(cgm_state * st,const cgm_point * corner1,const cgm_point * corner2)531 cgm_RECTANGLE(cgm_state * st, const cgm_point * corner1, const cgm_point * corner2)
532 {
533 OP(RECTANGLE);
534 P(corner1);
535 P(corner2);
536 DONE;
537 }
538
539 cgm_result
cgm_CIRCLE(cgm_state * st,const cgm_point * center,const cgm_vdc * radius)540 cgm_CIRCLE(cgm_state * st, const cgm_point * center, const cgm_vdc * radius)
541 {
542 OP(CIRCLE);
543 P(center);
544 VDC(radius);
545 DONE;
546 }
547
548 cgm_result
cgm_CIRCULAR_ARC_3_POINT(cgm_state * st,const cgm_point * start,const cgm_point * intermediate,const cgm_point * end)549 cgm_CIRCULAR_ARC_3_POINT(cgm_state * st, const cgm_point * start, const cgm_point * intermediate, const cgm_point * end)
550 {
551 OP(CIRCULAR_ARC_3_POINT);
552 P(start);
553 P(intermediate);
554 P(end);
555 DONE;
556 }
557
558 cgm_result
cgm_CIRCULAR_ARC_3_POINT_CLOSE(cgm_state * st,const cgm_point * start,const cgm_point * intermediate,const cgm_point * end,cgm_arc_closure closure)559 cgm_CIRCULAR_ARC_3_POINT_CLOSE(cgm_state * st, const cgm_point * start, const cgm_point * intermediate, const cgm_point * end, cgm_arc_closure closure)
560 {
561 OP(CIRCULAR_ARC_3_POINT_CLOSE);
562 P(start);
563 P(intermediate);
564 P(end);
565 E(closure);
566 DONE;
567 }
568
569 cgm_result
cgm_CIRCULAR_ARC_CENTER(cgm_state * st,const cgm_point * center,const cgm_vdc * dx_start,const cgm_vdc * dy_start,const cgm_vdc * dx_end,const cgm_vdc * dy_end,const cgm_vdc * radius)570 cgm_CIRCULAR_ARC_CENTER(cgm_state * st, const cgm_point * center, const cgm_vdc * dx_start, const cgm_vdc * dy_start, const cgm_vdc * dx_end, const cgm_vdc * dy_end, const cgm_vdc * radius)
571 {
572 OP(CIRCULAR_ARC_CENTER);
573 P(center);
574 VDC4(dx_start, dy_start, dx_end, dy_end);
575 VDC(radius);
576 DONE;
577 }
578
579 cgm_result
cgm_CIRCULAR_ARC_CENTER_CLOSE(cgm_state * st,const cgm_point * center,const cgm_vdc * dx_start,const cgm_vdc * dy_start,const cgm_vdc * dx_end,const cgm_vdc * dy_end,const cgm_vdc * radius,cgm_arc_closure closure)580 cgm_CIRCULAR_ARC_CENTER_CLOSE(cgm_state * st, const cgm_point * center, const cgm_vdc * dx_start, const cgm_vdc * dy_start, const cgm_vdc * dx_end, const cgm_vdc * dy_end, const cgm_vdc * radius, cgm_arc_closure closure)
581 {
582 OP(CIRCULAR_ARC_CENTER_CLOSE);
583 P(center);
584 VDC4(dx_start, dy_start, dx_end, dy_end);
585 VDC(radius);
586 E(closure);
587 DONE;
588 }
589
590 cgm_result
cgm_ELLIPSE(cgm_state * st,const cgm_point * center,const cgm_point * cd1_end,const cgm_point * cd2_end)591 cgm_ELLIPSE(cgm_state * st, const cgm_point * center, const cgm_point * cd1_end, const cgm_point * cd2_end)
592 {
593 OP(ELLIPSE);
594 P(center);
595 P(cd1_end);
596 P(cd2_end);
597 DONE;
598 }
599
600 cgm_result
cgm_ELLIPTICAL_ARC(cgm_state * st,const cgm_point * center,const cgm_point * cd1_end,const cgm_point * cd2_end,const cgm_vdc * dx_start,const cgm_vdc * dy_start,const cgm_vdc * dx_end,const cgm_vdc * dy_end)601 cgm_ELLIPTICAL_ARC(cgm_state * st, const cgm_point * center, const cgm_point * cd1_end, const cgm_point * cd2_end, const cgm_vdc * dx_start, const cgm_vdc * dy_start, const cgm_vdc * dx_end, const cgm_vdc * dy_end)
602 {
603 OP(ELLIPTICAL_ARC);
604 P(center);
605 P(cd1_end);
606 P(cd2_end);
607 VDC4(dx_start, dy_start, dx_end, dy_end);
608 DONE;
609 }
610
611 cgm_result
cgm_ELLIPTICAL_ARC_CLOSE(cgm_state * st,const cgm_point * center,const cgm_point * cd1_end,const cgm_point * cd2_end,const cgm_vdc * dx_start,const cgm_vdc * dy_start,const cgm_vdc * dx_end,const cgm_vdc * dy_end,cgm_arc_closure closure)612 cgm_ELLIPTICAL_ARC_CLOSE(cgm_state * st, const cgm_point * center, const cgm_point * cd1_end, const cgm_point * cd2_end, const cgm_vdc * dx_start, const cgm_vdc * dy_start, const cgm_vdc * dx_end, const cgm_vdc * dy_end, cgm_arc_closure closure)
613 {
614 OP(ELLIPTICAL_ARC_CLOSE);
615 P(center);
616 P(cd1_end);
617 P(cd2_end);
618 VDC4(dx_start, dy_start, dx_end, dy_end);
619 E(closure);
620 DONE;
621 }
622
623 /* ---------------- Attribute elements ---------------- */
624
625 cgm_result
cgm_LINE_BUNDLE_INDEX(cgm_state * st,cgm_int index)626 cgm_LINE_BUNDLE_INDEX(cgm_state * st, cgm_int index)
627 {
628 OP(LINE_BUNDLE_INDEX);
629 IX(index);
630 st->line_bundle_index = index;
631 DONE;
632 }
633
634 cgm_result
cgm_LINE_TYPE(cgm_state * st,cgm_line_type line_type)635 cgm_LINE_TYPE(cgm_state * st, cgm_line_type line_type)
636 {
637 OP(LINE_TYPE);
638 IX((int)line_type);
639 st->line_type = line_type;
640 DONE;
641 }
642
643 cgm_result
cgm_LINE_WIDTH(cgm_state * st,const cgm_line_width * line_width)644 cgm_LINE_WIDTH(cgm_state * st, const cgm_line_width * line_width)
645 {
646 OP(LINE_WIDTH);
647 VDC_R(line_width, st->picture.line_width_specification_mode);
648 st->line_width = *line_width;
649 DONE;
650 }
651
652 cgm_result
cgm_LINE_COLOR(cgm_state * st,const cgm_color * color)653 cgm_LINE_COLOR(cgm_state * st, const cgm_color * color)
654 {
655 OP(LINE_COLOR);
656 CO(color);
657 st->line_color = *color;
658 DONE;
659 }
660
661 cgm_result
cgm_MARKER_BUNDLE_INDEX(cgm_state * st,cgm_int index)662 cgm_MARKER_BUNDLE_INDEX(cgm_state * st, cgm_int index)
663 {
664 OP(MARKER_BUNDLE_INDEX);
665 IX(index);
666 st->marker_bundle_index = index;
667 DONE;
668 }
669
670 cgm_result
cgm_MARKER_TYPE(cgm_state * st,cgm_marker_type marker_type)671 cgm_MARKER_TYPE(cgm_state * st, cgm_marker_type marker_type)
672 {
673 OP(MARKER_TYPE);
674 IX((int)marker_type);
675 st->marker_type = marker_type;
676 DONE;
677 }
678
679 cgm_result
cgm_MARKER_SIZE(cgm_state * st,const cgm_marker_size * marker_size)680 cgm_MARKER_SIZE(cgm_state * st, const cgm_marker_size * marker_size)
681 {
682 OP(MARKER_SIZE);
683 VDC_R(marker_size, st->picture.marker_size_specification_mode);
684 st->marker_size = *marker_size;
685 DONE;
686 }
687
688 cgm_result
cgm_MARKER_COLOR(cgm_state * st,const cgm_color * color)689 cgm_MARKER_COLOR(cgm_state * st, const cgm_color * color)
690 {
691 OP(MARKER_COLOR);
692 CO(color);
693 st->marker_color = *color;
694 DONE;
695 }
696
697 cgm_result
cgm_TEXT_BUNDLE_INDEX(cgm_state * st,cgm_int index)698 cgm_TEXT_BUNDLE_INDEX(cgm_state * st, cgm_int index)
699 {
700 OP(TEXT_BUNDLE_INDEX);
701 IX(index);
702 st->text_bundle_index = index;
703 DONE;
704 }
705
706 cgm_result
cgm_TEXT_FONT_INDEX(cgm_state * st,cgm_int index)707 cgm_TEXT_FONT_INDEX(cgm_state * st, cgm_int index)
708 {
709 OP(TEXT_FONT_INDEX);
710 IX(index);
711 st->text_font_index = index;
712 DONE;
713 }
714
715 cgm_result
cgm_TEXT_PRECISION(cgm_state * st,cgm_text_precision precision)716 cgm_TEXT_PRECISION(cgm_state * st, cgm_text_precision precision)
717 {
718 OP(TEXT_PRECISION);
719 E(precision);
720 st->text_precision = precision;
721 DONE;
722 }
723
724 cgm_result
cgm_CHARACTER_EXPANSION_FACTOR(cgm_state * st,cgm_real factor)725 cgm_CHARACTER_EXPANSION_FACTOR(cgm_state * st, cgm_real factor)
726 {
727 OP(CHARACTER_EXPANSION_FACTOR);
728 R(factor);
729 st->character_expansion_factor = factor;
730 DONE;
731 }
732
733 cgm_result
cgm_CHARACTER_SPACING(cgm_state * st,cgm_real spacing)734 cgm_CHARACTER_SPACING(cgm_state * st, cgm_real spacing)
735 {
736 OP(CHARACTER_SPACING);
737 R(spacing);
738 st->character_spacing = spacing;
739 DONE;
740 }
741
742 cgm_result
cgm_TEXT_COLOR(cgm_state * st,const cgm_color * color)743 cgm_TEXT_COLOR(cgm_state * st, const cgm_color * color)
744 {
745 OP(TEXT_COLOR);
746 CO(color);
747 st->text_color = *color;
748 DONE;
749 }
750
751 cgm_result
cgm_CHARACTER_HEIGHT(cgm_state * st,const cgm_vdc * height)752 cgm_CHARACTER_HEIGHT(cgm_state * st, const cgm_vdc * height)
753 {
754 OP(CHARACTER_HEIGHT);
755 VDC(height);
756 st->character_height = *height;
757 DONE;
758 }
759
760 cgm_result
cgm_CHARACTER_ORIENTATION(cgm_state * st,const cgm_vdc * x_up,const cgm_vdc * y_up,const cgm_vdc * x_base,const cgm_vdc * y_base)761 cgm_CHARACTER_ORIENTATION(cgm_state * st, const cgm_vdc * x_up, const cgm_vdc * y_up, const cgm_vdc * x_base, const cgm_vdc * y_base)
762 {
763 OP(CHARACTER_ORIENTATION);
764 VDC4(x_up, y_up, x_base, y_base);
765 st->character_orientation[0] = *x_up;
766 st->character_orientation[1] = *y_up;
767 st->character_orientation[2] = *x_base;
768 st->character_orientation[3] = *y_base;
769 DONE;
770 }
771
772 cgm_result
cgm_TEXT_PATH(cgm_state * st,cgm_text_path text_path)773 cgm_TEXT_PATH(cgm_state * st, cgm_text_path text_path)
774 {
775 OP(TEXT_PATH);
776 E(text_path);
777 st->text_path = text_path;
778 DONE;
779 }
780
781 cgm_result
cgm_TEXT_ALIGNMENT(cgm_state * st,cgm_text_alignment_horizontal align_h,cgm_text_alignment_vertical align_v,cgm_real align_cont_h,cgm_real align_cont_v)782 cgm_TEXT_ALIGNMENT(cgm_state * st, cgm_text_alignment_horizontal align_h, cgm_text_alignment_vertical align_v, cgm_real align_cont_h, cgm_real align_cont_v)
783 {
784 OP(TEXT_ALIGNMENT);
785 E(align_h);
786 E(align_v);
787 R(align_cont_h);
788 R(align_cont_v);
789 DONE;
790 }
791
792 cgm_result
cgm_CHARACTER_SET_INDEX(cgm_state * st,cgm_int index)793 cgm_CHARACTER_SET_INDEX(cgm_state * st, cgm_int index)
794 {
795 OP(CHARACTER_SET_INDEX);
796 IX(index);
797 st->character_set_index = index;
798 DONE;
799 }
800
801 /* See gdevcgml.c for why this isn't named cgm_ALTERNATE_.... */
802 cgm_result
cgm_ALT_CHARACTER_SET_INDEX(cgm_state * st,cgm_int index)803 cgm_ALT_CHARACTER_SET_INDEX(cgm_state * st, cgm_int index)
804 {
805 OP(ALTERNATE_CHARACTER_SET_INDEX);
806 IX(index);
807 st->alternate_character_set_index = index;
808 DONE;
809 }
810
811 cgm_result
cgm_FILL_BUNDLE_INDEX(cgm_state * st,cgm_int index)812 cgm_FILL_BUNDLE_INDEX(cgm_state * st, cgm_int index)
813 {
814 OP(FILL_BUNDLE_INDEX);
815 IX(index);
816 st->fill_bundle_index = index;
817 DONE;
818 }
819
820 cgm_result
cgm_INTERIOR_STYLE(cgm_state * st,cgm_interior_style interior_style)821 cgm_INTERIOR_STYLE(cgm_state * st, cgm_interior_style interior_style)
822 {
823 OP(INTERIOR_STYLE);
824 E(interior_style);
825 st->interior_style = interior_style;
826 DONE;
827 }
828
829 cgm_result
cgm_FILL_COLOR(cgm_state * st,const cgm_color * color)830 cgm_FILL_COLOR(cgm_state * st, const cgm_color * color)
831 {
832 OP(FILL_COLOR);
833 CO(color);
834 st->fill_color = *color;
835 DONE;
836 }
837
838 cgm_result
cgm_HATCH_INDEX(cgm_state * st,cgm_hatch_index hatch_index)839 cgm_HATCH_INDEX(cgm_state * st, cgm_hatch_index hatch_index)
840 {
841 OP(HATCH_INDEX);
842 IX((int)hatch_index);
843 st->hatch_index = hatch_index;
844 DONE;
845 }
846
847 cgm_result
cgm_PATTERN_INDEX(cgm_state * st,cgm_int index)848 cgm_PATTERN_INDEX(cgm_state * st, cgm_int index)
849 {
850 OP(PATTERN_INDEX);
851 IX(index);
852 st->pattern_index = index;
853 DONE;
854 }
855
856 cgm_result
cgm_EDGE_BUNDLE_INDEX(cgm_state * st,cgm_int index)857 cgm_EDGE_BUNDLE_INDEX(cgm_state * st, cgm_int index)
858 {
859 OP(EDGE_BUNDLE_INDEX);
860 IX(index);
861 st->edge_bundle_index = index;
862 DONE;
863 }
864
865 cgm_result
cgm_EDGE_TYPE(cgm_state * st,cgm_edge_type edge_type)866 cgm_EDGE_TYPE(cgm_state * st, cgm_edge_type edge_type)
867 {
868 OP(EDGE_TYPE);
869 IX((int)edge_type);
870 st->edge_type = edge_type;
871 DONE;
872 }
873
874 cgm_result
cgm_EDGE_WIDTH(cgm_state * st,const cgm_edge_width * edge_width)875 cgm_EDGE_WIDTH(cgm_state * st, const cgm_edge_width * edge_width)
876 {
877 OP(EDGE_WIDTH);
878 VDC_R(edge_width, st->picture.edge_width_specification_mode);
879 st->edge_width = *edge_width;
880 DONE;
881 }
882
883 cgm_result
cgm_EDGE_COLOR(cgm_state * st,const cgm_color * color)884 cgm_EDGE_COLOR(cgm_state * st, const cgm_color * color)
885 {
886 OP(EDGE_COLOR);
887 CO(color);
888 DONE;
889 }
890
891 cgm_result
cgm_EDGE_VISIBILITY(cgm_state * st,bool visibility)892 cgm_EDGE_VISIBILITY(cgm_state * st, bool visibility)
893 {
894 OP(EDGE_VISIBILITY);
895 E(visibility);
896 st->edge_visibility = visibility;
897 DONE;
898 }
899
900 cgm_result
cgm_FILL_REFERENCE_POINT(cgm_state * st,const cgm_point * reference_point)901 cgm_FILL_REFERENCE_POINT(cgm_state * st, const cgm_point * reference_point)
902 {
903 OP(FILL_REFERENCE_POINT);
904 P(reference_point);
905 st->fill_reference_point = *reference_point;
906 DONE;
907 }
908
909 /* PATTERN_TABLE */
910
911 cgm_result
cgm_PATTERN_SIZE(cgm_state * st,const cgm_vdc * x_height,const cgm_vdc * y_height,const cgm_vdc * x_width,const cgm_vdc * y_width)912 cgm_PATTERN_SIZE(cgm_state * st, const cgm_vdc * x_height, const cgm_vdc * y_height, const cgm_vdc * x_width, const cgm_vdc * y_width)
913 {
914 OP(PATTERN_SIZE);
915 VDC4(x_height, y_height, x_width, y_width);
916 st->pattern_size[0] = *x_height;
917 st->pattern_size[1] = *y_height;
918 st->pattern_size[2] = *x_width;
919 st->pattern_size[3] = *y_width;
920 DONE;
921 }
922
923 cgm_result
cgm_COLOR_TABLE(cgm_state * st,cgm_int index,const cgm_color * values,int count)924 cgm_COLOR_TABLE(cgm_state * st, cgm_int index, const cgm_color * values, int count)
925 {
926 int i;
927
928 OP(COLOR_TABLE);
929 CI(index);
930 for (i = 0; i < count; ++i)
931 CD(&values[i].rgb);
932 DONE;
933 }
934
935 cgm_result
cgm_ASPECT_SOURCE_FLAGS(cgm_state * st,const cgm_aspect_source_flag * flags,int count)936 cgm_ASPECT_SOURCE_FLAGS(cgm_state * st, const cgm_aspect_source_flag * flags, int count)
937 {
938 int i;
939
940 OP(ASPECT_SOURCE_FLAGS);
941 for (i = 0; i < count; ++i) {
942 E(flags[i].type);
943 E(flags[i].source);
944 st->source_flags[flags[i].type] = (byte) flags[i].source;
945 }
946 DONE;
947 }
948
949 /* ================ Internal routines ================ */
950
951 /* Begin a command. */
952 private void
begin_command(cgm_state * st,cgm_op_index op)953 begin_command(cgm_state * st, cgm_op_index op)
954 {
955 uint op_word = (uint) op << cgm_op_id_shift;
956
957 st->command[0] = (byte) (op_word >> 8);
958 st->command[1] = (byte) (op_word);
959 st->command_count = 4; /* leave room for extension */
960 st->command_first = true;
961 st->result = cgm_result_ok;
962 }
963
964 /* Write the buffer for a partial command. */
965 /* Note that we always write an even number of bytes. */
966 private void
write_command(cgm_state * st,bool last)967 write_command(cgm_state * st, bool last)
968 {
969 byte *command = st->command;
970 int count = st->command_count;
971
972 if (st->command_first) {
973 if (count <= 34) {
974 command[2] = command[0];
975 command[3] = command[1] + count - 4;
976 command += 2, count -= 2;
977 } else {
978 int pcount = count - 4;
979
980 command[1] |= 31;
981 command[2] = (byte) (pcount >> 8);
982 if (!last)
983 command[2] |= 0x80;
984 command[3] = (byte) pcount;
985 }
986 st->command_first = false;
987 } else {
988 int pcount = count - 2;
989
990 command[0] = (byte) (pcount >> 8);
991 if (!last)
992 command[0] |= 0x80;
993 command[1] = (byte) pcount;
994 }
995 fwrite(command, sizeof(byte), count + (count & 1), st->file);
996 st->command_count = 2; /* leave room for extension header */
997 if (ferror(st->file))
998 st->result = cgm_result_io_error;
999 }
1000
1001 /* End a command. */
1002 private cgm_result
end_command(cgm_state * st)1003 end_command(cgm_state * st)
1004 {
1005 write_command(st, true);
1006 return st->result;
1007 }
1008
1009 /* Put an integer value. */
1010 private void
put_int(cgm_state * st,cgm_int value,int precision)1011 put_int(cgm_state * st, cgm_int value, int precision)
1012 {
1013 switch (precision) {
1014 case 32:
1015 put_byte(st, value >> 24);
1016 case 24:
1017 put_byte(st, value >> 16);
1018 case 16:
1019 put_byte(st, value >> 8);
1020 case 8:
1021 put_byte(st, value);
1022 }
1023 }
1024
1025 /* Put a real value. */
1026 private void
put_real(cgm_state * st,cgm_real value,const cgm_precision * pr)1027 put_real(cgm_state * st, cgm_real value, const cgm_precision * pr)
1028 {
1029 if (pr->representation == cgm_representation_floating) {
1030 } else { /* Casting to integer simply discards the fraction, */
1031 /* so we need to be careful with negative values. */
1032 long whole = (long)value;
1033 double fpart;
1034
1035 if (value < whole)
1036 --whole;
1037 fpart = value - whole;
1038 put_int(st, whole, pr->exponent_or_whole_width);
1039 if (pr->fraction_width == 16) {
1040 uint fraction = (uint) (fpart * (1.0 * 0x10000));
1041
1042 put_int(st, fraction, 16);
1043 } else { /* pr->fraction_width == 32 */
1044 ulong fraction =
1045 (ulong) (fpart * (1.0 * 0x10000 * 0x10000));
1046
1047 put_int(st, fraction, 32);
1048 }
1049 }
1050 }
1051
1052 /* Put a real precision. */
1053 private void
put_real_precision(cgm_state * st,const cgm_precision * precision)1054 put_real_precision(cgm_state * st, const cgm_precision * precision)
1055 {
1056 I((int)precision->representation);
1057 I(precision->exponent_or_whole_width);
1058 I(precision->fraction_width);
1059 }
1060
1061 /* Put a VDC. */
1062 private void
put_vdc(cgm_state * st,const cgm_vdc * pvdc)1063 put_vdc(cgm_state * st, const cgm_vdc * pvdc)
1064 {
1065 if (st->metafile.vdc_type == cgm_vdc_integer)
1066 put_int(st, pvdc->integer, st->vdc_integer_precision);
1067 else
1068 put_real(st, pvdc->real, &st->vdc_real_precision);
1069 }
1070
1071 /* Put a VDC or a real. */
1072 private void
put_vdc_r(cgm_state * st,const cgm_line_marker_extent * extent,cgm_line_marker_specification_mode mode)1073 put_vdc_r(cgm_state * st, const cgm_line_marker_extent * extent,
1074 cgm_line_marker_specification_mode mode)
1075 {
1076 if (mode == cgm_line_marker_absolute)
1077 VDC(&extent->absolute);
1078 else
1079 R(extent->scaled);
1080 }
1081
1082 /* Put a point (pair of VDCs). */
1083 private void
put_point(cgm_state * st,const cgm_point * ppt)1084 put_point(cgm_state * st, const cgm_point * ppt)
1085 {
1086 if (st->metafile.vdc_type == cgm_vdc_integer) {
1087 put_int(st, ppt->integer.x, st->vdc_integer_precision);
1088 put_int(st, ppt->integer.y, st->vdc_integer_precision);
1089 } else {
1090 put_real(st, ppt->real.x, &st->vdc_real_precision);
1091 put_real(st, ppt->real.y, &st->vdc_real_precision);
1092 }
1093 }
1094
1095 /* Put a list of points. */
1096 private void
put_points(cgm_state * st,const cgm_point * ppt,int count)1097 put_points(cgm_state * st, const cgm_point * ppt, int count)
1098 {
1099 int i;
1100
1101 for (i = 0; i < count; i++)
1102 P(ppt + i);
1103 }
1104
1105 /* Put bytes. */
1106 private void
put_bytes(cgm_state * st,const byte * data,uint length)1107 put_bytes(cgm_state * st, const byte * data, uint length)
1108 {
1109 int count;
1110
1111 while (length > (count = command_max_count - st->command_count)) {
1112 memcpy(st->command + st->command_count, data, count);
1113 st->command_count += count;
1114 write_command(st, false);
1115 data += count;
1116 length -= count;
1117 }
1118 memcpy(st->command + st->command_count, data, length);
1119 st->command_count += length;
1120 }
1121
1122 /* Put a string. */
1123 private void
put_string(cgm_state * st,const char * data,uint length)1124 put_string(cgm_state * st, const char *data, uint length)
1125 { /* The CGM specification seems to imply that the continuation */
1126 /* mechanism for commands and the mechanism for strings */
1127 /* are orthogonal; we take this interpretation. */
1128 if (length >= 255) {
1129 put_byte(st, 255);
1130 while (length > 32767) {
1131 put_int(st, 65535, 2);
1132 put_bytes(st, (const byte *)data, 32767);
1133 data += 32767;
1134 length -= 32767;
1135 }
1136 }
1137 put_byte(st, length);
1138 put_bytes(st, (const byte *)data, length);
1139 }
1140
1141 /* Put a color. */
1142 private void
put_color(cgm_state * st,const cgm_color * color)1143 put_color(cgm_state * st, const cgm_color * color)
1144 {
1145 if (st->picture.color_selection_mode == cgm_color_selection_indexed)
1146 CI(color->index);
1147 else
1148 CD(&color->rgb);
1149 }
1150
1151 /* Put an RGB value. */
1152 private void
put_rgb(cgm_state * st,const cgm_rgb * rgb)1153 put_rgb(cgm_state * st, const cgm_rgb * rgb)
1154 {
1155 put_int(st, rgb->r, st->metafile.color_precision);
1156 put_int(st, rgb->g, st->metafile.color_precision);
1157 put_int(st, rgb->b, st->metafile.color_precision);
1158 }
1159