Coverage Report

Created: 2025-08-08 06:02

/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
 ****************************************************************************/