xref: /plan9/sys/src/cmd/gs/src/gdevcgml.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
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