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