/src/libxlsxwriter/src/vml.c
Line | Count | Source (jump to first uncovered line) |
1 | | /***************************************************************************** |
2 | | * vml - A library for creating Excel XLSX vml files. |
3 | | * |
4 | | * Used in conjunction with the libxlsxwriter library. |
5 | | * |
6 | | * SPDX-License-Identifier: BSD-2-Clause |
7 | | * Copyright 2014-2025, John McNamara, jmcnamara@cpan.org. |
8 | | * |
9 | | */ |
10 | | |
11 | | #include "xlsxwriter/xmlwriter.h" |
12 | | #include "xlsxwriter/vml.h" |
13 | | #include "xlsxwriter/utility.h" |
14 | | |
15 | | /* |
16 | | * Forward declarations. |
17 | | */ |
18 | | |
19 | | /***************************************************************************** |
20 | | * |
21 | | * Private functions. |
22 | | * |
23 | | ****************************************************************************/ |
24 | | |
25 | | /* |
26 | | * Create a new vml object. |
27 | | */ |
28 | | lxw_vml * |
29 | | lxw_vml_new(void) |
30 | 0 | { |
31 | 0 | lxw_vml *vml = calloc(1, sizeof(lxw_vml)); |
32 | 0 | GOTO_LABEL_ON_MEM_ERROR(vml, mem_error); |
33 | | |
34 | 0 | return vml; |
35 | | |
36 | 0 | mem_error: |
37 | 0 | lxw_vml_free(vml); |
38 | 0 | return NULL; |
39 | 0 | } |
40 | | |
41 | | /* |
42 | | * Free a vml object. |
43 | | */ |
44 | | void |
45 | | lxw_vml_free(lxw_vml *vml) |
46 | 0 | { |
47 | 0 | if (!vml) |
48 | 0 | return; |
49 | | |
50 | 0 | free(vml); |
51 | 0 | } |
52 | | |
53 | | /***************************************************************************** |
54 | | * |
55 | | * XML functions. |
56 | | * |
57 | | ****************************************************************************/ |
58 | | /* |
59 | | * Write the <x:Visible> element. |
60 | | */ |
61 | | STATIC void |
62 | | _vml_write_visible(lxw_vml *self) |
63 | 0 | { |
64 | 0 | lxw_xml_empty_tag(self->file, "x:Visible", NULL); |
65 | 0 | } |
66 | | |
67 | | /* |
68 | | * Write the <v:f> element. |
69 | | */ |
70 | | STATIC void |
71 | | _vml_write_formula(lxw_vml *self, char *equation) |
72 | 0 | { |
73 | 0 | struct xml_attribute_list attributes; |
74 | 0 | struct xml_attribute *attribute; |
75 | |
|
76 | 0 | LXW_INIT_ATTRIBUTES(); |
77 | 0 | LXW_PUSH_ATTRIBUTES_STR("eqn", equation); |
78 | |
|
79 | 0 | lxw_xml_empty_tag(self->file, "v:f", &attributes); |
80 | |
|
81 | 0 | LXW_FREE_ATTRIBUTES(); |
82 | 0 | } |
83 | | |
84 | | /* |
85 | | * Write the <v:formulas> element. |
86 | | */ |
87 | | STATIC void |
88 | | _vml_write_formulas(lxw_vml *self) |
89 | 0 | { |
90 | 0 | lxw_xml_start_tag(self->file, "v:formulas", NULL); |
91 | |
|
92 | 0 | _vml_write_formula(self, "if lineDrawn pixelLineWidth 0"); |
93 | 0 | _vml_write_formula(self, "sum @0 1 0"); |
94 | 0 | _vml_write_formula(self, "sum 0 0 @1"); |
95 | 0 | _vml_write_formula(self, "prod @2 1 2"); |
96 | 0 | _vml_write_formula(self, "prod @3 21600 pixelWidth"); |
97 | 0 | _vml_write_formula(self, "prod @3 21600 pixelHeight"); |
98 | 0 | _vml_write_formula(self, "sum @0 0 1"); |
99 | 0 | _vml_write_formula(self, "prod @6 1 2"); |
100 | 0 | _vml_write_formula(self, "prod @7 21600 pixelWidth"); |
101 | 0 | _vml_write_formula(self, "sum @8 21600 0"); |
102 | 0 | _vml_write_formula(self, "prod @7 21600 pixelHeight"); |
103 | 0 | _vml_write_formula(self, "sum @10 21600 0"); |
104 | |
|
105 | 0 | lxw_xml_end_tag(self->file, "v:formulas"); |
106 | 0 | } |
107 | | |
108 | | /* |
109 | | * Write the <x:TextHAlign> element. |
110 | | */ |
111 | | STATIC void |
112 | | _vml_write_text_halign(lxw_vml *self) |
113 | 0 | { |
114 | |
|
115 | 0 | lxw_xml_data_element(self->file, "x:TextHAlign", "Center", NULL); |
116 | 0 | } |
117 | | |
118 | | /* |
119 | | * Write the <x:TextVAlign> element. |
120 | | */ |
121 | | STATIC void |
122 | | _vml_write_text_valign(lxw_vml *self) |
123 | 0 | { |
124 | 0 | lxw_xml_data_element(self->file, "x:TextVAlign", "Center", NULL); |
125 | 0 | } |
126 | | |
127 | | /* |
128 | | * Write the <x:FmlaMacro> element. |
129 | | */ |
130 | | STATIC void |
131 | | _vml_write_fmla_macro(lxw_vml *self, lxw_vml_obj *vml_obj) |
132 | 0 | { |
133 | 0 | lxw_xml_data_element(self->file, "x:FmlaMacro", vml_obj->macro, NULL); |
134 | 0 | } |
135 | | |
136 | | /* |
137 | | * Write the <x:PrintObject> element. |
138 | | */ |
139 | | STATIC void |
140 | | _vml_write_print_object(lxw_vml *self) |
141 | 0 | { |
142 | 0 | lxw_xml_data_element(self->file, "x:PrintObject", "False", NULL); |
143 | 0 | } |
144 | | |
145 | | /* |
146 | | * Write the <o:lock> element. |
147 | | */ |
148 | | STATIC void |
149 | | _vml_write_aspect_ratio_lock(lxw_vml *self) |
150 | 0 | { |
151 | 0 | struct xml_attribute_list attributes; |
152 | 0 | struct xml_attribute *attribute; |
153 | |
|
154 | 0 | LXW_INIT_ATTRIBUTES(); |
155 | 0 | LXW_PUSH_ATTRIBUTES_STR("v:ext", "edit"); |
156 | 0 | LXW_PUSH_ATTRIBUTES_STR("aspectratio", "t"); |
157 | |
|
158 | 0 | lxw_xml_empty_tag(self->file, "o:lock", &attributes); |
159 | |
|
160 | 0 | LXW_FREE_ATTRIBUTES(); |
161 | 0 | } |
162 | | |
163 | | /* |
164 | | * Write the <o:lock> element. |
165 | | */ |
166 | | STATIC void |
167 | | _vml_write_rotation_lock(lxw_vml *self) |
168 | 0 | { |
169 | 0 | struct xml_attribute_list attributes; |
170 | 0 | struct xml_attribute *attribute; |
171 | |
|
172 | 0 | LXW_INIT_ATTRIBUTES(); |
173 | 0 | LXW_PUSH_ATTRIBUTES_STR("v:ext", "edit"); |
174 | 0 | LXW_PUSH_ATTRIBUTES_STR("rotation", "t"); |
175 | |
|
176 | 0 | lxw_xml_empty_tag(self->file, "o:lock", &attributes); |
177 | |
|
178 | 0 | LXW_FREE_ATTRIBUTES(); |
179 | 0 | } |
180 | | |
181 | | /* |
182 | | * Write the <x:Column> element. |
183 | | */ |
184 | | STATIC void |
185 | | _vml_write_column(lxw_vml *self, lxw_vml_obj *vml_obj) |
186 | 0 | { |
187 | 0 | char data[LXW_ATTR_32]; |
188 | |
|
189 | 0 | lxw_snprintf(data, LXW_ATTR_32, "%d", vml_obj->col); |
190 | |
|
191 | 0 | lxw_xml_data_element(self->file, "x:Column", data, NULL); |
192 | 0 | } |
193 | | |
194 | | /* |
195 | | * Write the <x:Row> element. |
196 | | */ |
197 | | STATIC void |
198 | | _vml_write_row(lxw_vml *self, lxw_vml_obj *vml_obj) |
199 | 0 | { |
200 | 0 | char data[LXW_ATTR_32]; |
201 | |
|
202 | 0 | lxw_snprintf(data, LXW_ATTR_32, "%d", vml_obj->row); |
203 | |
|
204 | 0 | lxw_xml_data_element(self->file, "x:Row", data, NULL); |
205 | 0 | } |
206 | | |
207 | | /* |
208 | | * Write the <x:AutoFill> element. |
209 | | */ |
210 | | STATIC void |
211 | | _vml_write_auto_fill(lxw_vml *self) |
212 | 0 | { |
213 | 0 | lxw_xml_data_element(self->file, "x:AutoFill", "False", NULL); |
214 | 0 | } |
215 | | |
216 | | /* |
217 | | * Write the <x:Anchor> element. |
218 | | */ |
219 | | STATIC void |
220 | | _vml_write_anchor(lxw_vml *self, lxw_vml_obj *vml_obj) |
221 | 0 | { |
222 | 0 | char anchor_data[LXW_MAX_ATTRIBUTE_LENGTH]; |
223 | |
|
224 | 0 | lxw_snprintf(anchor_data, |
225 | 0 | LXW_MAX_ATTRIBUTE_LENGTH, |
226 | 0 | "%d, %d, %d, %d, %d, %d, %d, %d", |
227 | 0 | vml_obj->from.col, |
228 | 0 | (uint32_t) vml_obj->from.col_offset, |
229 | 0 | vml_obj->from.row, |
230 | 0 | (uint32_t) vml_obj->from.row_offset, |
231 | 0 | vml_obj->to.col, |
232 | 0 | (uint32_t) vml_obj->to.col_offset, |
233 | 0 | vml_obj->to.row, (uint32_t) vml_obj->to.row_offset); |
234 | |
|
235 | 0 | lxw_xml_data_element(self->file, "x:Anchor", anchor_data, NULL); |
236 | 0 | } |
237 | | |
238 | | /* |
239 | | * Write the <x:SizeWithCells> element. |
240 | | */ |
241 | | STATIC void |
242 | | _vml_write_size_with_cells(lxw_vml *self) |
243 | 0 | { |
244 | 0 | lxw_xml_empty_tag(self->file, "x:SizeWithCells", NULL); |
245 | 0 | } |
246 | | |
247 | | /* |
248 | | * Write the <x:MoveWithCells> element. |
249 | | */ |
250 | | STATIC void |
251 | | _vml_write_move_with_cells(lxw_vml *self) |
252 | 0 | { |
253 | 0 | lxw_xml_empty_tag(self->file, "x:MoveWithCells", NULL); |
254 | 0 | } |
255 | | |
256 | | /* |
257 | | * Write the <v:shadow> element. |
258 | | */ |
259 | | STATIC void |
260 | | _vml_write_shadow(lxw_vml *self) |
261 | 0 | { |
262 | 0 | struct xml_attribute_list attributes; |
263 | 0 | struct xml_attribute *attribute; |
264 | |
|
265 | 0 | LXW_INIT_ATTRIBUTES(); |
266 | 0 | LXW_PUSH_ATTRIBUTES_STR("on", "t"); |
267 | 0 | LXW_PUSH_ATTRIBUTES_STR("color", "black"); |
268 | 0 | LXW_PUSH_ATTRIBUTES_STR("obscured", "t"); |
269 | |
|
270 | 0 | lxw_xml_empty_tag(self->file, "v:shadow", &attributes); |
271 | |
|
272 | 0 | LXW_FREE_ATTRIBUTES(); |
273 | 0 | } |
274 | | |
275 | | /* |
276 | | * Write the <v:stroke> element. |
277 | | */ |
278 | | STATIC void |
279 | | _vml_write_stroke(lxw_vml *self) |
280 | 0 | { |
281 | 0 | struct xml_attribute_list attributes; |
282 | 0 | struct xml_attribute *attribute; |
283 | |
|
284 | 0 | LXW_INIT_ATTRIBUTES(); |
285 | 0 | LXW_PUSH_ATTRIBUTES_STR("joinstyle", "miter"); |
286 | |
|
287 | 0 | lxw_xml_empty_tag(self->file, "v:stroke", &attributes); |
288 | |
|
289 | 0 | LXW_FREE_ATTRIBUTES(); |
290 | 0 | } |
291 | | |
292 | | /* |
293 | | * Write the <o:lock> element. |
294 | | */ |
295 | | STATIC void |
296 | | _vml_write_shapetype_lock(lxw_vml *self) |
297 | 0 | { |
298 | 0 | struct xml_attribute_list attributes; |
299 | 0 | struct xml_attribute *attribute; |
300 | |
|
301 | 0 | LXW_INIT_ATTRIBUTES(); |
302 | 0 | LXW_PUSH_ATTRIBUTES_STR("v:ext", "edit"); |
303 | 0 | LXW_PUSH_ATTRIBUTES_STR("shapetype", "t"); |
304 | |
|
305 | 0 | lxw_xml_empty_tag(self->file, "o:lock", &attributes); |
306 | |
|
307 | 0 | LXW_FREE_ATTRIBUTES(); |
308 | 0 | } |
309 | | |
310 | | /* |
311 | | * Write the <font> element. |
312 | | */ |
313 | | STATIC void |
314 | | _vml_write_font(lxw_vml *self, lxw_vml_obj *vml_obj) |
315 | 0 | { |
316 | 0 | struct xml_attribute_list attributes; |
317 | 0 | struct xml_attribute *attribute; |
318 | |
|
319 | 0 | LXW_INIT_ATTRIBUTES(); |
320 | 0 | LXW_PUSH_ATTRIBUTES_STR("face", "Calibri"); |
321 | 0 | LXW_PUSH_ATTRIBUTES_STR("size", "220"); |
322 | 0 | LXW_PUSH_ATTRIBUTES_STR("color", "#000000"); |
323 | |
|
324 | 0 | lxw_xml_data_element(self->file, "font", vml_obj->name, &attributes); |
325 | |
|
326 | 0 | LXW_FREE_ATTRIBUTES(); |
327 | 0 | } |
328 | | |
329 | | /* |
330 | | * Write the <v:imagedata> element. |
331 | | */ |
332 | | STATIC void |
333 | | _vml_write_imagedata(lxw_vml *self, uint32_t rel_index, char *name) |
334 | 0 | { |
335 | 0 | struct xml_attribute_list attributes; |
336 | 0 | struct xml_attribute *attribute; |
337 | 0 | char rel_id[LXW_ATTR_32]; |
338 | |
|
339 | 0 | lxw_snprintf(rel_id, LXW_ATTR_32, "rId%d", rel_index); |
340 | |
|
341 | 0 | LXW_INIT_ATTRIBUTES(); |
342 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:relid", rel_id); |
343 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:title", name); |
344 | |
|
345 | 0 | lxw_xml_empty_tag(self->file, "v:imagedata", &attributes); |
346 | |
|
347 | 0 | LXW_FREE_ATTRIBUTES(); |
348 | 0 | } |
349 | | |
350 | | /* |
351 | | * Write the <v:path> element. |
352 | | */ |
353 | | STATIC void |
354 | | _vml_write_image_path(lxw_vml *self) |
355 | 0 | { |
356 | 0 | struct xml_attribute_list attributes; |
357 | 0 | struct xml_attribute *attribute; |
358 | |
|
359 | 0 | LXW_INIT_ATTRIBUTES(); |
360 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:extrusionok", "f"); |
361 | 0 | LXW_PUSH_ATTRIBUTES_STR("gradientshapeok", "t"); |
362 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:connecttype", "rect"); |
363 | |
|
364 | 0 | lxw_xml_empty_tag(self->file, "v:path", &attributes); |
365 | |
|
366 | 0 | LXW_FREE_ATTRIBUTES(); |
367 | 0 | } |
368 | | |
369 | | /* |
370 | | * Write the <v:shape> element. |
371 | | */ |
372 | | STATIC void |
373 | | _vml_write_image_shape(lxw_vml *self, uint32_t vml_shape_id, uint32_t z_index, |
374 | | lxw_vml_obj *image_obj) |
375 | 0 | { |
376 | 0 | struct xml_attribute_list attributes; |
377 | 0 | struct xml_attribute *attribute; |
378 | 0 | char width_str[LXW_ATTR_32]; |
379 | 0 | char height_str[LXW_ATTR_32]; |
380 | 0 | char style[LXW_MAX_ATTRIBUTE_LENGTH]; |
381 | 0 | char o_spid[LXW_ATTR_32]; |
382 | 0 | char type[] = "#_x0000_t75"; |
383 | 0 | double width; |
384 | 0 | double height; |
385 | | |
386 | | /* Scale the height/width by the resolution, relative to 72dpi. */ |
387 | 0 | width = image_obj->width * (72.0 / image_obj->x_dpi); |
388 | 0 | height = image_obj->height * (72.0 / image_obj->y_dpi); |
389 | | |
390 | | /* Excel uses a rounding based around 72 and 96 dpi. */ |
391 | 0 | width = 72.0 / 96.0 * (uint32_t) (width * 96.0 / 72 + 0.25); |
392 | 0 | height = 72.0 / 96.0 * (uint32_t) (height * 96.0 / 72 + 0.25); |
393 | |
|
394 | 0 | lxw_sprintf_dbl(width_str, width); |
395 | 0 | lxw_sprintf_dbl(height_str, height); |
396 | |
|
397 | 0 | lxw_snprintf(o_spid, LXW_ATTR_32, "_x0000_s%d", vml_shape_id); |
398 | |
|
399 | 0 | lxw_snprintf(style, |
400 | 0 | LXW_MAX_ATTRIBUTE_LENGTH, |
401 | 0 | "position:absolute;" |
402 | 0 | "margin-left:0;" |
403 | 0 | "margin-top:0;" |
404 | 0 | "width:%spt;" |
405 | 0 | "height:%spt;" "z-index:%d", width_str, height_str, z_index); |
406 | |
|
407 | 0 | LXW_INIT_ATTRIBUTES(); |
408 | 0 | LXW_PUSH_ATTRIBUTES_STR("id", image_obj->image_position); |
409 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:spid", o_spid); |
410 | 0 | LXW_PUSH_ATTRIBUTES_STR("type", type); |
411 | 0 | LXW_PUSH_ATTRIBUTES_STR("style", style); |
412 | |
|
413 | 0 | lxw_xml_start_tag(self->file, "v:shape", &attributes); |
414 | | |
415 | | /* Write the v:imagedata element. */ |
416 | 0 | _vml_write_imagedata(self, image_obj->rel_index, image_obj->name); |
417 | | |
418 | | /* Write the o:lock element. */ |
419 | 0 | _vml_write_rotation_lock(self); |
420 | |
|
421 | 0 | lxw_xml_end_tag(self->file, "v:shape"); |
422 | |
|
423 | 0 | LXW_FREE_ATTRIBUTES(); |
424 | 0 | } |
425 | | |
426 | | /* |
427 | | * Write the <v:shapetype> element for images. |
428 | | */ |
429 | | STATIC void |
430 | | _vml_write_image_shapetype(lxw_vml *self) |
431 | 0 | { |
432 | 0 | struct xml_attribute_list attributes; |
433 | 0 | struct xml_attribute *attribute; |
434 | 0 | char id[] = "_x0000_t75"; |
435 | 0 | char coordsize[] = "21600,21600"; |
436 | 0 | char o_spt[] = "75"; |
437 | 0 | char o_preferrelative[] = "t"; |
438 | 0 | char path[] = "m@4@5l@4@11@9@11@9@5xe"; |
439 | 0 | char filled[] = "f"; |
440 | 0 | char stroked[] = "f"; |
441 | |
|
442 | 0 | LXW_INIT_ATTRIBUTES(); |
443 | 0 | LXW_PUSH_ATTRIBUTES_STR("id", id); |
444 | 0 | LXW_PUSH_ATTRIBUTES_STR("coordsize", coordsize); |
445 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:spt", o_spt); |
446 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:preferrelative", o_preferrelative); |
447 | 0 | LXW_PUSH_ATTRIBUTES_STR("path", path); |
448 | 0 | LXW_PUSH_ATTRIBUTES_STR("filled", filled); |
449 | 0 | LXW_PUSH_ATTRIBUTES_STR("stroked", stroked); |
450 | |
|
451 | 0 | lxw_xml_start_tag(self->file, "v:shapetype", &attributes); |
452 | | |
453 | | /* Write the v:stroke element. */ |
454 | 0 | _vml_write_stroke(self); |
455 | | |
456 | | /* Write the v:formulas element. */ |
457 | 0 | _vml_write_formulas(self); |
458 | | |
459 | | /* Write the v:path element. */ |
460 | 0 | _vml_write_image_path(self); |
461 | | |
462 | | /* Write the o:lock element. */ |
463 | 0 | _vml_write_aspect_ratio_lock(self); |
464 | |
|
465 | 0 | lxw_xml_end_tag(self->file, "v:shapetype"); |
466 | |
|
467 | 0 | LXW_FREE_ATTRIBUTES(); |
468 | 0 | } |
469 | | |
470 | | /* |
471 | | * Write the <x:ClientData> element. |
472 | | */ |
473 | | STATIC void |
474 | | _vml_write_button_client_data(lxw_vml *self, lxw_vml_obj *vml_obj) |
475 | 0 | { |
476 | 0 | struct xml_attribute_list attributes; |
477 | 0 | struct xml_attribute *attribute; |
478 | |
|
479 | 0 | LXW_INIT_ATTRIBUTES(); |
480 | 0 | LXW_PUSH_ATTRIBUTES_STR("ObjectType", "Button"); |
481 | |
|
482 | 0 | lxw_xml_start_tag(self->file, "x:ClientData", &attributes); |
483 | | |
484 | | /* Write the <x:Anchor> element. */ |
485 | 0 | _vml_write_anchor(self, vml_obj); |
486 | | |
487 | | /* Write the x:PrintObject element. */ |
488 | 0 | _vml_write_print_object(self); |
489 | | |
490 | | /* Write the x:AutoFill element. */ |
491 | 0 | _vml_write_auto_fill(self); |
492 | | |
493 | | /* Write the x:FmlaMacro element. */ |
494 | 0 | _vml_write_fmla_macro(self, vml_obj); |
495 | | |
496 | | /* Write the x:TextHAlign element. */ |
497 | 0 | _vml_write_text_halign(self); |
498 | | |
499 | | /* Write the x:TextVAlign element. */ |
500 | 0 | _vml_write_text_valign(self); |
501 | |
|
502 | 0 | lxw_xml_end_tag(self->file, "x:ClientData"); |
503 | |
|
504 | 0 | LXW_FREE_ATTRIBUTES(); |
505 | 0 | } |
506 | | |
507 | | /* |
508 | | * Write the <div> element. |
509 | | */ |
510 | | STATIC void |
511 | | _vml_write_button_div(lxw_vml *self, lxw_vml_obj *vml_obj) |
512 | 0 | { |
513 | 0 | struct xml_attribute_list attributes; |
514 | 0 | struct xml_attribute *attribute; |
515 | |
|
516 | 0 | LXW_INIT_ATTRIBUTES(); |
517 | 0 | LXW_PUSH_ATTRIBUTES_STR("style", "text-align:center"); |
518 | |
|
519 | 0 | lxw_xml_start_tag(self->file, "div", &attributes); |
520 | | |
521 | | /* Write the font element. */ |
522 | 0 | _vml_write_font(self, vml_obj); |
523 | |
|
524 | 0 | lxw_xml_end_tag(self->file, "div"); |
525 | |
|
526 | 0 | LXW_FREE_ATTRIBUTES(); |
527 | 0 | } |
528 | | |
529 | | /* |
530 | | * Write the <v:textbox> element. |
531 | | */ |
532 | | STATIC void |
533 | | _vml_write_button_textbox(lxw_vml *self, lxw_vml_obj *vml_obj) |
534 | 0 | { |
535 | 0 | struct xml_attribute_list attributes; |
536 | 0 | struct xml_attribute *attribute; |
537 | |
|
538 | 0 | LXW_INIT_ATTRIBUTES(); |
539 | 0 | LXW_PUSH_ATTRIBUTES_STR("style", "mso-direction-alt:auto"); |
540 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:singleclick", "f"); |
541 | |
|
542 | 0 | lxw_xml_start_tag(self->file, "v:textbox", &attributes); |
543 | | |
544 | | /* Write the div element. */ |
545 | 0 | _vml_write_button_div(self, vml_obj); |
546 | |
|
547 | 0 | lxw_xml_end_tag(self->file, "v:textbox"); |
548 | |
|
549 | 0 | LXW_FREE_ATTRIBUTES(); |
550 | 0 | } |
551 | | |
552 | | /* |
553 | | * Write the <v:fill> element. |
554 | | */ |
555 | | STATIC void |
556 | | _vml_write_button_fill(lxw_vml *self) |
557 | 0 | { |
558 | 0 | struct xml_attribute_list attributes; |
559 | 0 | struct xml_attribute *attribute; |
560 | |
|
561 | 0 | LXW_INIT_ATTRIBUTES(); |
562 | 0 | LXW_PUSH_ATTRIBUTES_STR("color2", "buttonFace [67]"); |
563 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:detectmouseclick", "t"); |
564 | |
|
565 | 0 | lxw_xml_empty_tag(self->file, "v:fill", &attributes); |
566 | |
|
567 | 0 | LXW_FREE_ATTRIBUTES(); |
568 | 0 | } |
569 | | |
570 | | /* |
571 | | * Write the <v:path> element for buttons. |
572 | | */ |
573 | | STATIC void |
574 | | _vml_write_button_path(lxw_vml *self) |
575 | 0 | { |
576 | 0 | struct xml_attribute_list attributes; |
577 | 0 | struct xml_attribute *attribute; |
578 | |
|
579 | 0 | LXW_INIT_ATTRIBUTES(); |
580 | 0 | LXW_PUSH_ATTRIBUTES_STR("shadowok", "f"); |
581 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:extrusionok", "f"); |
582 | 0 | LXW_PUSH_ATTRIBUTES_STR("strokeok", "f"); |
583 | 0 | LXW_PUSH_ATTRIBUTES_STR("fillok", "f"); |
584 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:connecttype", "rect"); |
585 | |
|
586 | 0 | lxw_xml_empty_tag(self->file, "v:path", &attributes); |
587 | |
|
588 | 0 | LXW_FREE_ATTRIBUTES(); |
589 | 0 | } |
590 | | |
591 | | /* |
592 | | * Write the <v:shape> element for buttons. |
593 | | */ |
594 | | STATIC void |
595 | | _vml_write_button_shape(lxw_vml *self, uint32_t vml_shape_id, |
596 | | uint32_t z_index, lxw_vml_obj *vml_obj) |
597 | 0 | { |
598 | 0 | struct xml_attribute_list attributes; |
599 | 0 | struct xml_attribute *attribute; |
600 | 0 | char type[] = "#_x0000_t201"; |
601 | 0 | char o_button[] = "t"; |
602 | 0 | char fillcolor[] = "buttonFace [67]"; |
603 | 0 | char strokecolor[] = "windowText [64]"; |
604 | 0 | char o_insetmode[] = "auto"; |
605 | |
|
606 | 0 | char id[LXW_ATTR_32]; |
607 | 0 | char margin_left[LXW_ATTR_32]; |
608 | 0 | char margin_top[LXW_ATTR_32]; |
609 | 0 | char width[LXW_ATTR_32]; |
610 | 0 | char height[LXW_ATTR_32]; |
611 | 0 | char style[LXW_MAX_ATTRIBUTE_LENGTH]; |
612 | |
|
613 | 0 | lxw_sprintf_dbl(margin_left, vml_obj->col_absolute * 0.75); |
614 | 0 | lxw_sprintf_dbl(margin_top, vml_obj->row_absolute * 0.75); |
615 | 0 | lxw_sprintf_dbl(width, vml_obj->width * 0.75); |
616 | 0 | lxw_sprintf_dbl(height, vml_obj->height * 0.75); |
617 | |
|
618 | 0 | lxw_snprintf(id, LXW_ATTR_32, "_x0000_s%d", vml_shape_id); |
619 | |
|
620 | 0 | lxw_snprintf(style, |
621 | 0 | LXW_MAX_ATTRIBUTE_LENGTH, |
622 | 0 | "position:absolute;" |
623 | 0 | "margin-left:%spt;" |
624 | 0 | "margin-top:%spt;" |
625 | 0 | "width:%spt;" |
626 | 0 | "height:%spt;" |
627 | 0 | "z-index:%d;" |
628 | 0 | "mso-wrap-style:tight", |
629 | 0 | margin_left, margin_top, width, height, z_index); |
630 | |
|
631 | 0 | LXW_INIT_ATTRIBUTES(); |
632 | 0 | LXW_PUSH_ATTRIBUTES_STR("id", id); |
633 | 0 | LXW_PUSH_ATTRIBUTES_STR("type", type); |
634 | |
|
635 | 0 | if (vml_obj->text) |
636 | 0 | LXW_PUSH_ATTRIBUTES_STR("alt", vml_obj->text); |
637 | |
|
638 | 0 | LXW_PUSH_ATTRIBUTES_STR("style", style); |
639 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:button", o_button); |
640 | 0 | LXW_PUSH_ATTRIBUTES_STR("fillcolor", fillcolor); |
641 | 0 | LXW_PUSH_ATTRIBUTES_STR("strokecolor", strokecolor); |
642 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:insetmode", o_insetmode); |
643 | |
|
644 | 0 | lxw_xml_start_tag(self->file, "v:shape", &attributes); |
645 | | |
646 | | /* Write the v:fill element. */ |
647 | 0 | _vml_write_button_fill(self); |
648 | | |
649 | | /* Write the o:lock element. */ |
650 | 0 | _vml_write_rotation_lock(self); |
651 | | |
652 | | /* Write the v:textbox element. */ |
653 | 0 | _vml_write_button_textbox(self, vml_obj); |
654 | | |
655 | | /* Write the x:ClientData element. */ |
656 | 0 | _vml_write_button_client_data(self, vml_obj); |
657 | |
|
658 | 0 | lxw_xml_end_tag(self->file, "v:shape"); |
659 | |
|
660 | 0 | LXW_FREE_ATTRIBUTES(); |
661 | 0 | } |
662 | | |
663 | | /* |
664 | | * Write the <v:shapetype> element for buttons. |
665 | | */ |
666 | | STATIC void |
667 | | _vml_write_button_shapetype(lxw_vml *self) |
668 | 0 | { |
669 | 0 | struct xml_attribute_list attributes; |
670 | 0 | struct xml_attribute *attribute; |
671 | 0 | char id[] = "_x0000_t201"; |
672 | 0 | char coordsize[] = "21600,21600"; |
673 | 0 | char o_spt[] = "201"; |
674 | 0 | char path[] = "m,l,21600r21600,l21600,xe"; |
675 | |
|
676 | 0 | LXW_INIT_ATTRIBUTES(); |
677 | 0 | LXW_PUSH_ATTRIBUTES_STR("id", id); |
678 | 0 | LXW_PUSH_ATTRIBUTES_STR("coordsize", coordsize); |
679 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:spt", o_spt); |
680 | 0 | LXW_PUSH_ATTRIBUTES_STR("path", path); |
681 | |
|
682 | 0 | lxw_xml_start_tag(self->file, "v:shapetype", &attributes); |
683 | | |
684 | | /* Write the v:stroke element. */ |
685 | 0 | _vml_write_stroke(self); |
686 | | |
687 | | /* Write the v:path element. */ |
688 | 0 | _vml_write_button_path(self); |
689 | | |
690 | | /* Write the o:lock element. */ |
691 | 0 | _vml_write_shapetype_lock(self); |
692 | |
|
693 | 0 | lxw_xml_end_tag(self->file, "v:shapetype"); |
694 | |
|
695 | 0 | LXW_FREE_ATTRIBUTES(); |
696 | 0 | } |
697 | | |
698 | | /* |
699 | | * Write the <x:ClientData> element. |
700 | | */ |
701 | | STATIC void |
702 | | _vml_write_comment_client_data(lxw_vml *self, lxw_vml_obj *vml_obj) |
703 | 0 | { |
704 | 0 | struct xml_attribute_list attributes; |
705 | 0 | struct xml_attribute *attribute; |
706 | |
|
707 | 0 | LXW_INIT_ATTRIBUTES(); |
708 | 0 | LXW_PUSH_ATTRIBUTES_STR("ObjectType", "Note"); |
709 | |
|
710 | 0 | lxw_xml_start_tag(self->file, "x:ClientData", &attributes); |
711 | | |
712 | | /* Write the <x:MoveWithCells> element. */ |
713 | 0 | _vml_write_move_with_cells(self); |
714 | | |
715 | | /* Write the <x:SizeWithCells> element. */ |
716 | 0 | _vml_write_size_with_cells(self); |
717 | | |
718 | | /* Write the <x:Anchor> element. */ |
719 | 0 | _vml_write_anchor(self, vml_obj); |
720 | | |
721 | | /* Write the <x:AutoFill> element. */ |
722 | 0 | _vml_write_auto_fill(self); |
723 | | |
724 | | /* Write the <x:Row> element. */ |
725 | 0 | _vml_write_row(self, vml_obj); |
726 | | |
727 | | /* Write the <x:Column> element. */ |
728 | 0 | _vml_write_column(self, vml_obj); |
729 | | |
730 | | /* Write the x:Visible element. */ |
731 | 0 | if (vml_obj->visible == LXW_COMMENT_DISPLAY_VISIBLE) |
732 | 0 | _vml_write_visible(self); |
733 | |
|
734 | 0 | lxw_xml_end_tag(self->file, "x:ClientData"); |
735 | |
|
736 | 0 | LXW_FREE_ATTRIBUTES(); |
737 | 0 | } |
738 | | |
739 | | /* |
740 | | * Write the <div> element. |
741 | | */ |
742 | | STATIC void |
743 | | _vml_write_comment_div(lxw_vml *self) |
744 | 0 | { |
745 | 0 | struct xml_attribute_list attributes; |
746 | 0 | struct xml_attribute *attribute; |
747 | |
|
748 | 0 | LXW_INIT_ATTRIBUTES(); |
749 | 0 | LXW_PUSH_ATTRIBUTES_STR("style", "text-align:left"); |
750 | |
|
751 | 0 | lxw_xml_start_tag(self->file, "div", &attributes); |
752 | |
|
753 | 0 | lxw_xml_end_tag(self->file, "div"); |
754 | |
|
755 | 0 | LXW_FREE_ATTRIBUTES(); |
756 | 0 | } |
757 | | |
758 | | /* |
759 | | * Write the <v:textbox> element. |
760 | | */ |
761 | | STATIC void |
762 | | _vml_write_comment_textbox(lxw_vml *self) |
763 | 0 | { |
764 | 0 | struct xml_attribute_list attributes; |
765 | 0 | struct xml_attribute *attribute; |
766 | |
|
767 | 0 | LXW_INIT_ATTRIBUTES(); |
768 | 0 | LXW_PUSH_ATTRIBUTES_STR("style", "mso-direction-alt:auto"); |
769 | |
|
770 | 0 | lxw_xml_start_tag(self->file, "v:textbox", &attributes); |
771 | | |
772 | | /* Write the div element. */ |
773 | 0 | _vml_write_comment_div(self); |
774 | |
|
775 | 0 | lxw_xml_end_tag(self->file, "v:textbox"); |
776 | |
|
777 | 0 | LXW_FREE_ATTRIBUTES(); |
778 | 0 | } |
779 | | |
780 | | /* |
781 | | * Write the <v:fill> element. |
782 | | */ |
783 | | STATIC void |
784 | | _vml_write_comment_fill(lxw_vml *self) |
785 | 0 | { |
786 | 0 | struct xml_attribute_list attributes; |
787 | 0 | struct xml_attribute *attribute; |
788 | |
|
789 | 0 | LXW_INIT_ATTRIBUTES(); |
790 | 0 | LXW_PUSH_ATTRIBUTES_STR("color2", "#ffffe1"); |
791 | |
|
792 | 0 | lxw_xml_empty_tag(self->file, "v:fill", &attributes); |
793 | |
|
794 | 0 | LXW_FREE_ATTRIBUTES(); |
795 | 0 | } |
796 | | |
797 | | /* |
798 | | * Write the <v:path> element. |
799 | | */ |
800 | | STATIC void |
801 | | _vml_write_comment_path(lxw_vml *self, uint8_t has_gradient, char *type) |
802 | 0 | { |
803 | 0 | struct xml_attribute_list attributes; |
804 | 0 | struct xml_attribute *attribute; |
805 | |
|
806 | 0 | LXW_INIT_ATTRIBUTES(); |
807 | |
|
808 | 0 | if (has_gradient) |
809 | 0 | LXW_PUSH_ATTRIBUTES_STR("gradientshapeok", "t"); |
810 | |
|
811 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:connecttype", type); |
812 | |
|
813 | 0 | lxw_xml_empty_tag(self->file, "v:path", &attributes); |
814 | |
|
815 | 0 | LXW_FREE_ATTRIBUTES(); |
816 | 0 | } |
817 | | |
818 | | /* |
819 | | * Write the <v:shape> element for comments. |
820 | | */ |
821 | | STATIC void |
822 | | _vml_write_comment_shape(lxw_vml *self, uint32_t vml_shape_id, |
823 | | uint32_t z_index, lxw_vml_obj *vml_obj) |
824 | 0 | { |
825 | 0 | struct xml_attribute_list attributes; |
826 | 0 | struct xml_attribute *attribute; |
827 | 0 | char id[LXW_ATTR_32]; |
828 | 0 | char margin_left[LXW_ATTR_32]; |
829 | 0 | char margin_top[LXW_ATTR_32]; |
830 | 0 | char width[LXW_ATTR_32]; |
831 | 0 | char height[LXW_ATTR_32]; |
832 | 0 | char visible[LXW_ATTR_32]; |
833 | 0 | char fillcolor[LXW_ATTR_32]; |
834 | 0 | char style[LXW_MAX_ATTRIBUTE_LENGTH]; |
835 | 0 | char type[] = "#_x0000_t202"; |
836 | 0 | char o_insetmode[] = "auto"; |
837 | |
|
838 | 0 | lxw_sprintf_dbl(margin_left, vml_obj->col_absolute * 0.75); |
839 | 0 | lxw_sprintf_dbl(margin_top, vml_obj->row_absolute * 0.75); |
840 | 0 | lxw_sprintf_dbl(width, vml_obj->width * 0.75); |
841 | 0 | lxw_sprintf_dbl(height, vml_obj->height * 0.75); |
842 | |
|
843 | 0 | lxw_snprintf(id, LXW_ATTR_32, "_x0000_s%d", vml_shape_id); |
844 | |
|
845 | 0 | if (vml_obj->visible == LXW_COMMENT_DISPLAY_DEFAULT) |
846 | 0 | vml_obj->visible = self->comment_display_default; |
847 | |
|
848 | 0 | if (vml_obj->visible == LXW_COMMENT_DISPLAY_VISIBLE) |
849 | 0 | lxw_snprintf(visible, LXW_ATTR_32, "visible"); |
850 | 0 | else |
851 | 0 | lxw_snprintf(visible, LXW_ATTR_32, "hidden"); |
852 | |
|
853 | 0 | if (vml_obj->color) |
854 | 0 | lxw_snprintf(fillcolor, LXW_ATTR_32, "#%06x", |
855 | 0 | vml_obj->color & LXW_COLOR_MASK); |
856 | 0 | else |
857 | 0 | lxw_snprintf(fillcolor, LXW_ATTR_32, "#%06x", 0xffffe1); |
858 | |
|
859 | 0 | lxw_snprintf(style, |
860 | 0 | LXW_MAX_ATTRIBUTE_LENGTH, |
861 | 0 | "position:absolute;" |
862 | 0 | "margin-left:%spt;" |
863 | 0 | "margin-top:%spt;" |
864 | 0 | "width:%spt;" |
865 | 0 | "height:%spt;" |
866 | 0 | "z-index:%d;" |
867 | 0 | "visibility:%s", |
868 | 0 | margin_left, margin_top, width, height, z_index, visible); |
869 | |
|
870 | 0 | LXW_INIT_ATTRIBUTES(); |
871 | 0 | LXW_PUSH_ATTRIBUTES_STR("id", id); |
872 | 0 | LXW_PUSH_ATTRIBUTES_STR("type", type); |
873 | 0 | LXW_PUSH_ATTRIBUTES_STR("style", style); |
874 | 0 | LXW_PUSH_ATTRIBUTES_STR("fillcolor", fillcolor); |
875 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:insetmode", o_insetmode); |
876 | |
|
877 | 0 | lxw_xml_start_tag(self->file, "v:shape", &attributes); |
878 | | |
879 | | /* Write the v:fill element. */ |
880 | 0 | _vml_write_comment_fill(self); |
881 | | |
882 | | /* Write the v:shadow element. */ |
883 | 0 | _vml_write_shadow(self); |
884 | | |
885 | | /* Write the v:path element. */ |
886 | 0 | _vml_write_comment_path(self, LXW_FALSE, "none"); |
887 | | |
888 | | /* Write the v:textbox element. */ |
889 | 0 | _vml_write_comment_textbox(self); |
890 | | |
891 | | /* Write the x:ClientData element. */ |
892 | 0 | _vml_write_comment_client_data(self, vml_obj); |
893 | |
|
894 | 0 | lxw_xml_end_tag(self->file, "v:shape"); |
895 | |
|
896 | 0 | LXW_FREE_ATTRIBUTES(); |
897 | 0 | } |
898 | | |
899 | | /* |
900 | | * Write the <v:shapetype> element for comments. |
901 | | */ |
902 | | STATIC void |
903 | | _vml_write_comment_shapetype(lxw_vml *self) |
904 | 0 | { |
905 | 0 | struct xml_attribute_list attributes; |
906 | 0 | struct xml_attribute *attribute; |
907 | 0 | char id[] = "_x0000_t202"; |
908 | 0 | char coordsize[] = "21600,21600"; |
909 | 0 | char o_spt[] = "202"; |
910 | 0 | char path[] = "m,l,21600r21600,l21600,xe"; |
911 | |
|
912 | 0 | LXW_INIT_ATTRIBUTES(); |
913 | 0 | LXW_PUSH_ATTRIBUTES_STR("id", id); |
914 | 0 | LXW_PUSH_ATTRIBUTES_STR("coordsize", coordsize); |
915 | 0 | LXW_PUSH_ATTRIBUTES_STR("o:spt", o_spt); |
916 | 0 | LXW_PUSH_ATTRIBUTES_STR("path", path); |
917 | |
|
918 | 0 | lxw_xml_start_tag(self->file, "v:shapetype", &attributes); |
919 | | |
920 | | /* Write the v:stroke element. */ |
921 | 0 | _vml_write_stroke(self); |
922 | | |
923 | | /* Write the v:path element. */ |
924 | 0 | _vml_write_comment_path(self, LXW_TRUE, "rect"); |
925 | |
|
926 | 0 | lxw_xml_end_tag(self->file, "v:shapetype"); |
927 | |
|
928 | 0 | LXW_FREE_ATTRIBUTES(); |
929 | 0 | } |
930 | | |
931 | | /* |
932 | | * Write the <o:idmap> element. |
933 | | */ |
934 | | STATIC void |
935 | | _vml_write_idmap(lxw_vml *self) |
936 | 0 | { |
937 | | /* Since the vml_data_id_str may exceed the LXW_MAX_ATTRIBUTE_LENGTH we |
938 | | * write it directly without the xml helper functions. */ |
939 | 0 | fprintf(self->file, "<o:idmap v:ext=\"edit\" data=\"%s\"/>", |
940 | 0 | self->vml_data_id_str); |
941 | 0 | } |
942 | | |
943 | | /* |
944 | | * Write the <o:shapelayout> element. |
945 | | */ |
946 | | STATIC void |
947 | | _vml_write_shapelayout(lxw_vml *self) |
948 | 0 | { |
949 | 0 | struct xml_attribute_list attributes; |
950 | 0 | struct xml_attribute *attribute; |
951 | |
|
952 | 0 | LXW_INIT_ATTRIBUTES(); |
953 | 0 | LXW_PUSH_ATTRIBUTES_STR("v:ext", "edit"); |
954 | |
|
955 | 0 | lxw_xml_start_tag(self->file, "o:shapelayout", &attributes); |
956 | | |
957 | | /* Write the o:idmap element. */ |
958 | 0 | _vml_write_idmap(self); |
959 | |
|
960 | 0 | lxw_xml_end_tag(self->file, "o:shapelayout"); |
961 | |
|
962 | 0 | LXW_FREE_ATTRIBUTES(); |
963 | 0 | } |
964 | | |
965 | | /* |
966 | | * Write the <xml> element. |
967 | | */ |
968 | | STATIC void |
969 | | _vml_write_xml_namespace(lxw_vml *self) |
970 | 0 | { |
971 | 0 | struct xml_attribute_list attributes; |
972 | 0 | struct xml_attribute *attribute; |
973 | 0 | char xmlns_v[] = "urn:schemas-microsoft-com:vml"; |
974 | 0 | char xmlns_o[] = "urn:schemas-microsoft-com:office:office"; |
975 | 0 | char xmlns_x[] = "urn:schemas-microsoft-com:office:excel"; |
976 | |
|
977 | 0 | LXW_INIT_ATTRIBUTES(); |
978 | 0 | LXW_PUSH_ATTRIBUTES_STR("xmlns:v", xmlns_v); |
979 | 0 | LXW_PUSH_ATTRIBUTES_STR("xmlns:o", xmlns_o); |
980 | 0 | LXW_PUSH_ATTRIBUTES_STR("xmlns:x", xmlns_x); |
981 | |
|
982 | 0 | lxw_xml_start_tag(self->file, "xml", &attributes); |
983 | |
|
984 | 0 | LXW_FREE_ATTRIBUTES(); |
985 | 0 | } |
986 | | |
987 | | /***************************************************************************** |
988 | | * |
989 | | * XML file assembly functions. |
990 | | * |
991 | | ****************************************************************************/ |
992 | | |
993 | | /* |
994 | | * Assemble and write the XML file. |
995 | | */ |
996 | | void |
997 | | lxw_vml_assemble_xml_file(lxw_vml *self) |
998 | 0 | { |
999 | 0 | lxw_vml_obj *comment_obj; |
1000 | 0 | lxw_vml_obj *button_obj; |
1001 | 0 | lxw_vml_obj *image_obj; |
1002 | 0 | uint32_t z_index = 1; |
1003 | | |
1004 | | /* Write the xml namespace element. Note, the VML files have no |
1005 | | * XML declaration.*/ |
1006 | 0 | _vml_write_xml_namespace(self); |
1007 | | |
1008 | | /* Write the o:shapelayout element. */ |
1009 | 0 | _vml_write_shapelayout(self); |
1010 | |
|
1011 | 0 | if (self->button_objs && !STAILQ_EMPTY(self->button_objs)) { |
1012 | | /* Write the <v:shapetype> element. */ |
1013 | 0 | _vml_write_button_shapetype(self); |
1014 | |
|
1015 | 0 | STAILQ_FOREACH(button_obj, self->button_objs, list_pointers) { |
1016 | 0 | self->vml_shape_id++; |
1017 | | |
1018 | | /* Write the <v:shape> element. */ |
1019 | 0 | _vml_write_button_shape(self, self->vml_shape_id, z_index, |
1020 | 0 | button_obj); |
1021 | |
|
1022 | 0 | z_index++; |
1023 | 0 | } |
1024 | 0 | } |
1025 | |
|
1026 | 0 | if (self->comment_objs && !STAILQ_EMPTY(self->comment_objs)) { |
1027 | | /* Write the <v:shapetype> element. */ |
1028 | 0 | _vml_write_comment_shapetype(self); |
1029 | |
|
1030 | 0 | STAILQ_FOREACH(comment_obj, self->comment_objs, list_pointers) { |
1031 | 0 | self->vml_shape_id++; |
1032 | | |
1033 | | /* Write the <v:shape> element. */ |
1034 | 0 | _vml_write_comment_shape(self, self->vml_shape_id, z_index, |
1035 | 0 | comment_obj); |
1036 | |
|
1037 | 0 | z_index++; |
1038 | 0 | } |
1039 | 0 | } |
1040 | |
|
1041 | 0 | if (self->image_objs && !STAILQ_EMPTY(self->image_objs)) { |
1042 | | /* Write the <v:shapetype> element. */ |
1043 | 0 | _vml_write_image_shapetype(self); |
1044 | |
|
1045 | 0 | STAILQ_FOREACH(image_obj, self->image_objs, list_pointers) { |
1046 | 0 | self->vml_shape_id++; |
1047 | | |
1048 | | /* Write the <v:shape> element. */ |
1049 | 0 | _vml_write_image_shape(self, self->vml_shape_id, z_index, |
1050 | 0 | image_obj); |
1051 | |
|
1052 | 0 | z_index++; |
1053 | 0 | } |
1054 | 0 | } |
1055 | |
|
1056 | 0 | lxw_xml_end_tag(self->file, "xml"); |
1057 | 0 | } |
1058 | | |
1059 | | /***************************************************************************** |
1060 | | * |
1061 | | * Public functions. |
1062 | | * |
1063 | | ****************************************************************************/ |