Coverage Report

Created: 2026-09-14 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libvisio/src/lib/VSDXTheme.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/*
3
 * This file is part of the libvisio project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 */
9
10
#include "VSDXTheme.h"
11
12
#include <memory>
13
14
#include "VSDXMLTokenMap.h"
15
#include "libvisio_utils.h"
16
#include "libvisio_xml.h"
17
18
using std::shared_ptr;
19
20
libvisio::VSDXVariationClrScheme::VSDXVariationClrScheme()
21
0
  : m_varColor1()
22
0
  , m_varColor2()
23
0
  , m_varColor3()
24
0
  , m_varColor4()
25
0
  , m_varColor5()
26
0
  , m_varColor6()
27
0
  , m_varColor7()
28
0
{
29
0
}
30
31
libvisio::VSDXClrScheme::VSDXClrScheme()
32
821
  : m_dk1()
33
821
  , m_lt1()
34
821
  , m_dk2()
35
821
  , m_lt2()
36
821
  , m_accent1()
37
821
  , m_accent2()
38
821
  , m_accent3()
39
821
  , m_accent4()
40
821
  , m_accent5()
41
821
  , m_accent6()
42
821
  , m_hlink()
43
821
  , m_folHlink()
44
821
  , m_bkgnd()
45
821
  , m_variationClrSchemeLst()
46
821
{
47
821
}
48
49
libvisio::VSDXFont::VSDXFont()
50
1.64k
  : m_latinTypeFace(),
51
1.64k
    m_eaTypeFace(),
52
1.64k
    m_csTypeFace(),
53
1.64k
    m_typeFaces()
54
1.64k
{
55
1.64k
}
56
57
libvisio::VSDXFontScheme::VSDXFontScheme()
58
821
  : m_majorFont(),
59
821
    m_minorFont(),
60
821
    m_schemeId(0)
61
821
{
62
821
}
63
64
libvisio::VSDXVariationStyleScheme::VSDXVariationStyleScheme()
65
0
  : m_varStyles()
66
0
{
67
0
}
68
69
libvisio::VSDXTheme::VSDXTheme()
70
821
  : m_clrScheme(),
71
821
    m_fontScheme(),
72
821
    m_fillStyleLst(),
73
821
    m_variationStyleSchemeLst()
74
821
{
75
821
}
76
77
libvisio::VSDXTheme::~VSDXTheme()
78
821
{
79
821
}
80
81
82
int libvisio::VSDXTheme::getElementToken(xmlTextReaderPtr reader)
83
0
{
84
0
  return VSDXMLTokenMap::getTokenId(xmlTextReaderConstName(reader));
85
0
}
86
87
bool libvisio::VSDXTheme::parse(librevenge::RVNGInputStream *input)
88
0
{
89
0
  VSD_DEBUG_MSG(("VSDXTheme::parse\n"));
90
0
  if (!input)
91
0
    return false;
92
93
0
  auto reader = xmlReaderForStream(input, nullptr, false);
94
0
  if (!reader)
95
0
    return false;
96
97
0
  try
98
0
  {
99
0
    int ret = xmlTextReaderRead(reader.get());
100
0
    while (1 == ret)
101
0
    {
102
0
      int tokenId = getElementToken(reader.get());
103
104
0
      switch (tokenId)
105
0
      {
106
0
      case XML_A_CLRSCHEME:
107
0
        readClrScheme(reader.get());
108
0
        break;
109
0
      case XML_A_FONTSCHEME:
110
0
        readFontScheme(reader.get());
111
0
        break;
112
0
      case XML_A_FMTSCHEME:
113
0
        readFmtScheme(reader.get());
114
0
        break;
115
0
      case XML_VT_VARIATIONSTYLESCHEMELST:
116
0
        readVariationStyleSchemeLst(reader.get());
117
0
        break;
118
0
      default:
119
0
        break;
120
0
      }
121
0
      ret = xmlTextReaderRead(reader.get());
122
0
    }
123
0
  }
124
0
  catch (...)
125
0
  {
126
0
    return false;
127
0
  }
128
0
  return true;
129
0
}
130
131
std::optional<libvisio::Colour> libvisio::VSDXTheme::readSrgbClr(xmlTextReaderPtr reader)
132
0
{
133
0
  std::optional<libvisio::Colour> retVal;
134
0
  if (XML_A_SRGBCLR == getElementToken(reader))
135
0
  {
136
0
    const shared_ptr<xmlChar> val(xmlTextReaderGetAttribute(reader, BAD_CAST("val")), xmlFree);
137
0
    if (val)
138
0
    {
139
0
      try
140
0
      {
141
0
        retVal = xmlStringToColour(val);
142
0
      }
143
0
      catch (const XmlParserException &)
144
0
      {
145
0
      }
146
0
    }
147
0
  }
148
0
  return retVal;
149
0
}
150
151
std::optional<libvisio::Colour> libvisio::VSDXTheme::readSysClr(xmlTextReaderPtr reader)
152
0
{
153
0
  std::optional<libvisio::Colour> retVal;
154
0
  if (XML_A_SYSCLR == getElementToken(reader))
155
0
  {
156
0
    const shared_ptr<xmlChar> lastClr(xmlTextReaderGetAttribute(reader, BAD_CAST("lastClr")), xmlFree);
157
0
    if (lastClr)
158
0
    {
159
0
      try
160
0
      {
161
0
        retVal = xmlStringToColour(lastClr);
162
0
      }
163
0
      catch (const XmlParserException &)
164
0
      {
165
0
      }
166
0
    }
167
0
  }
168
0
  return retVal;
169
0
}
170
171
std::optional<libvisio::Colour> libvisio::VSDXTheme::readSchemeClr(xmlTextReaderPtr reader)
172
0
{
173
0
  std::optional<libvisio::Colour> retVal;
174
0
  if (XML_A_SCHEMECLR == getElementToken(reader))
175
0
  {
176
0
    const shared_ptr<xmlChar> val(xmlTextReaderGetAttribute(reader, BAD_CAST("val")), xmlFree);
177
0
    if (val)
178
0
    {
179
0
      std::string aSchameName((const char *)val.get());
180
0
      if (aSchameName == "dk1")
181
0
        retVal = m_clrScheme.m_dk1;
182
0
      else if (aSchameName == "lt1")
183
0
        retVal = m_clrScheme.m_lt1;
184
0
      else if (aSchameName == "dk2")
185
0
        retVal = m_clrScheme.m_dk2;
186
0
      else if (aSchameName == "lt2")
187
0
        retVal = m_clrScheme.m_lt2;
188
0
      else if (aSchameName == "accent1")
189
0
        retVal = m_clrScheme.m_accent1;
190
0
      else if (aSchameName == "accent2")
191
0
        retVal = m_clrScheme.m_accent2;
192
0
      else if (aSchameName == "accent3")
193
0
        retVal = m_clrScheme.m_accent3;
194
0
      else if (aSchameName == "accent4")
195
0
        retVal = m_clrScheme.m_accent4;
196
0
      else if (aSchameName == "accent5")
197
0
        retVal = m_clrScheme.m_accent5;
198
0
      else if (aSchameName == "accent6")
199
0
        retVal = m_clrScheme.m_accent6;
200
0
      else if (aSchameName == "hlink")
201
0
        retVal = m_clrScheme.m_hlink;
202
0
      else if (aSchameName == "folHlink")
203
0
        retVal = m_clrScheme.m_folHlink;
204
0
      else if (aSchameName == "bkgnd")
205
0
        retVal = m_clrScheme.m_bkgnd;
206
0
      else
207
0
      {
208
        //TODO: handle more color schames like phClr
209
0
        VSD_DEBUG_MSG(("VSDXTheme::readSchemeClr: unknown name %s\n", val.get()));
210
0
      }
211
0
    }
212
0
  }
213
0
  return retVal;
214
0
}
215
216
void libvisio::VSDXTheme::readFontScheme(xmlTextReaderPtr reader)
217
0
{
218
0
  VSD_DEBUG_MSG(("VSDXTheme::readFontScheme\n"));
219
0
  int ret = 1;
220
0
  int tokenId = XML_TOKEN_INVALID;
221
0
  int tokenType = -1;
222
0
  do
223
0
  {
224
0
    ret = xmlTextReaderRead(reader);
225
0
    tokenId = getElementToken(reader);
226
0
    if (XML_TOKEN_INVALID == tokenId)
227
0
    {
228
0
      VSD_DEBUG_MSG(("VSDXTheme::readFontScheme: unknown token %s\n", xmlTextReaderConstName(reader)));
229
0
    }
230
0
    tokenType = xmlTextReaderNodeType(reader);
231
0
    switch (tokenId)
232
0
    {
233
0
    case XML_A_MAJORFONT:
234
0
      readFont(reader, tokenId, m_fontScheme.m_majorFont);
235
0
      break;
236
0
    case XML_A_MINORFONT:
237
0
      readFont(reader, tokenId, m_fontScheme.m_minorFont);
238
0
      break;
239
0
    case XML_VT_SCHEMEID:
240
0
      break;
241
0
    default:
242
0
      break;
243
0
    }
244
0
  }
245
0
  while ((XML_A_FONTSCHEME != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
246
0
}
247
248
void libvisio::VSDXTheme::readFont(xmlTextReaderPtr reader, int idToken, VSDXFont &font)
249
0
{
250
0
  VSD_DEBUG_MSG(("VSDXTheme::readFont\n"));
251
0
  int ret = 1;
252
0
  int tokenId = XML_TOKEN_INVALID;
253
0
  int tokenType = -1;
254
0
  do
255
0
  {
256
0
    ret = xmlTextReaderRead(reader);
257
0
    tokenId = getElementToken(reader);
258
0
    if (XML_TOKEN_INVALID == tokenId)
259
0
    {
260
0
      VSD_DEBUG_MSG(("VSDXTheme::readFont: unknown token %s\n", xmlTextReaderConstName(reader)));
261
0
    }
262
0
    tokenType = xmlTextReaderNodeType(reader);
263
0
    switch (tokenId)
264
0
    {
265
0
    case XML_A_LATIN:
266
0
      readTypeFace(reader, font.m_latinTypeFace);
267
0
      break;
268
0
    case XML_A_EA:
269
0
      readTypeFace(reader, font.m_eaTypeFace);
270
0
      break;
271
0
    case XML_A_CS:
272
0
      readTypeFace(reader, font.m_csTypeFace);
273
0
      break;
274
0
    case XML_A_FONT:
275
0
    {
276
0
      int script;
277
0
      librevenge::RVNGString typeFace;
278
0
      if (readTypeFace(reader, script, typeFace) && !typeFace.empty())
279
0
        font.m_typeFaces[script] = typeFace;
280
0
      break;
281
0
    }
282
0
    default:
283
0
      break;
284
0
    }
285
0
  }
286
0
  while ((idToken != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
287
0
}
288
289
bool libvisio::VSDXTheme::readTypeFace(xmlTextReaderPtr reader, librevenge::RVNGString &typeFace)
290
0
{
291
0
  const shared_ptr<xmlChar> sTypeFace(xmlTextReaderGetAttribute(reader, BAD_CAST("typeface")), xmlFree);
292
0
  if (sTypeFace)
293
0
  {
294
0
    typeFace.clear();
295
0
    typeFace.sprintf("%s", (const char *)sTypeFace.get());
296
0
  }
297
0
  return bool(sTypeFace);
298
0
}
299
300
bool libvisio::VSDXTheme::readTypeFace(xmlTextReaderPtr reader, int &script, librevenge::RVNGString &typeFace)
301
0
{
302
0
  const shared_ptr<xmlChar> sScript(xmlTextReaderGetAttribute(reader, BAD_CAST("script")), xmlFree);
303
0
  bool knownScript = false;
304
0
  if (sScript)
305
0
  {
306
0
    int token = libvisio::VSDXMLTokenMap::getTokenId(sScript.get());
307
0
    knownScript = XML_TOKEN_INVALID != token;
308
0
    if (knownScript)
309
0
      script = token;
310
0
  }
311
0
  return readTypeFace(reader, typeFace) && knownScript;
312
0
}
313
314
void libvisio::VSDXTheme::readClrScheme(xmlTextReaderPtr reader)
315
0
{
316
0
  VSD_DEBUG_MSG(("VSDXTheme::readClrScheme\n"));
317
0
  int ret = 1;
318
0
  int tokenId = XML_TOKEN_INVALID;
319
0
  int tokenType = -1;
320
0
  m_clrScheme.m_variationClrSchemeLst.clear();
321
0
  do
322
0
  {
323
0
    ret = xmlTextReaderRead(reader);
324
0
    tokenId = getElementToken(reader);
325
0
    if (XML_TOKEN_INVALID == tokenId)
326
0
    {
327
0
      VSD_DEBUG_MSG(("VSDXTheme::readClrScheme: unknown token %s\n", xmlTextReaderConstName(reader)));
328
0
    }
329
0
    tokenType = xmlTextReaderNodeType(reader);
330
0
    switch (tokenId)
331
0
    {
332
0
    case XML_A_DK1:
333
0
      readThemeColour(reader, tokenId, m_clrScheme.m_dk1);
334
0
      break;
335
0
    case XML_A_DK2:
336
0
      readThemeColour(reader, tokenId, m_clrScheme.m_dk2);
337
0
      break;
338
0
    case XML_A_LT1:
339
0
      readThemeColour(reader, tokenId, m_clrScheme.m_lt1);
340
0
      break;
341
0
    case XML_A_LT2:
342
0
      readThemeColour(reader, tokenId, m_clrScheme.m_lt2);
343
0
      break;
344
0
    case XML_A_ACCENT1:
345
0
      readThemeColour(reader, tokenId, m_clrScheme.m_accent1);
346
0
      break;
347
0
    case XML_A_ACCENT2:
348
0
      readThemeColour(reader, tokenId, m_clrScheme.m_accent2);
349
0
      break;
350
0
    case XML_A_ACCENT3:
351
0
      readThemeColour(reader, tokenId, m_clrScheme.m_accent3);
352
0
      break;
353
0
    case XML_A_ACCENT4:
354
0
      readThemeColour(reader, tokenId, m_clrScheme.m_accent4);
355
0
      break;
356
0
    case XML_A_ACCENT5:
357
0
      readThemeColour(reader, tokenId, m_clrScheme.m_accent5);
358
0
      break;
359
0
    case XML_A_ACCENT6:
360
0
      readThemeColour(reader, tokenId, m_clrScheme.m_accent6);
361
0
      break;
362
0
    case XML_A_HLINK:
363
0
      readThemeColour(reader, tokenId, m_clrScheme.m_hlink);
364
0
      break;
365
0
    case XML_A_FOLHLINK:
366
0
      readThemeColour(reader, tokenId, m_clrScheme.m_folHlink);
367
0
      break;
368
0
    case XML_VT_BKGND:
369
0
      readThemeColour(reader, tokenId, m_clrScheme.m_bkgnd);
370
0
      break;
371
0
    case XML_VT_VARIATIONCLRSCHEMELST:
372
0
      readVariationClrSchemeLst(reader);
373
0
      break;
374
0
    default:
375
0
      break;
376
0
    }
377
0
  }
378
0
  while ((XML_A_CLRSCHEME != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
379
0
}
380
381
bool libvisio::VSDXTheme::readThemeColour(xmlTextReaderPtr reader, int idToken, Colour &clr)
382
0
{
383
0
  int ret = 1;
384
0
  int tokenId = XML_TOKEN_INVALID;
385
0
  int tokenType = -1;
386
0
  std::optional<libvisio::Colour> colour;
387
0
  do
388
0
  {
389
0
    ret = xmlTextReaderRead(reader);
390
0
    tokenId = getElementToken(reader);
391
0
    if (XML_TOKEN_INVALID == tokenId)
392
0
    {
393
0
      VSD_DEBUG_MSG(("VSDXTheme::readThemeColour: unknown token %s\n", xmlTextReaderConstName(reader)));
394
0
    }
395
0
    tokenType = xmlTextReaderNodeType(reader);
396
0
    switch (tokenId)
397
0
    {
398
0
    case XML_A_SRGBCLR:
399
0
      colour = readSrgbClr(reader);
400
0
      break;
401
0
    case XML_A_SYSCLR:
402
0
      colour = readSysClr(reader);
403
0
      break;
404
0
    case XML_A_SCHEMECLR:
405
0
      colour = readSchemeClr(reader);
406
0
      break;
407
0
    default:
408
0
      break;
409
0
    }
410
0
  }
411
0
  while ((idToken != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
412
413
0
  if (colour)
414
0
  {
415
0
    clr = *colour;
416
0
    return true;
417
0
  }
418
0
  return false;
419
0
}
420
421
void libvisio::VSDXTheme::readVariationClrSchemeLst(xmlTextReaderPtr reader)
422
0
{
423
0
  VSD_DEBUG_MSG(("VSDXTheme::readVariationClrSchemeLst\n"));
424
0
  int ret = 1;
425
0
  int tokenId = XML_TOKEN_INVALID;
426
0
  int tokenType = -1;
427
0
  do
428
0
  {
429
0
    ret = xmlTextReaderRead(reader);
430
0
    tokenId = getElementToken(reader);
431
0
    if (XML_TOKEN_INVALID == tokenId)
432
0
    {
433
0
      VSD_DEBUG_MSG(("VSDXTheme::readVariationClrSchemeLst: unknown token %s\n", xmlTextReaderConstName(reader)));
434
0
    }
435
0
    tokenType = xmlTextReaderNodeType(reader);
436
0
    switch (tokenId)
437
0
    {
438
0
    case XML_VT_VARIATIONCLRSCHEME:
439
0
    {
440
0
      VSDXVariationClrScheme varClrSch;
441
0
      readVariationClrScheme(reader, varClrSch);
442
0
      m_clrScheme.m_variationClrSchemeLst.push_back(varClrSch);
443
0
      break;
444
0
    }
445
0
    default:
446
0
      break;
447
0
    }
448
0
  }
449
0
  while ((XML_VT_VARIATIONCLRSCHEMELST != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
450
0
}
451
452
void libvisio::VSDXTheme::readVariationClrScheme(xmlTextReaderPtr reader, VSDXVariationClrScheme &varClrSch)
453
0
{
454
0
  VSD_DEBUG_MSG(("VSDXTheme::readVariationClrScheme\n"));
455
0
  int ret = 1;
456
0
  int tokenId = XML_TOKEN_INVALID;
457
0
  int tokenType = -1;
458
0
  do
459
0
  {
460
0
    ret = xmlTextReaderRead(reader);
461
0
    tokenId = getElementToken(reader);
462
0
    if (XML_TOKEN_INVALID == tokenId)
463
0
    {
464
0
      VSD_DEBUG_MSG(("VSDXTheme::readVariationClrScheme: unknown token %s\n", xmlTextReaderConstName(reader)));
465
0
    }
466
0
    tokenType = xmlTextReaderNodeType(reader);
467
0
    switch (tokenId)
468
0
    {
469
0
    case XML_VT_VARCOLOR1:
470
0
      readThemeColour(reader, tokenId, varClrSch.m_varColor1);
471
0
      break;
472
0
    case XML_VT_VARCOLOR2:
473
0
      readThemeColour(reader, tokenId, varClrSch.m_varColor2);
474
0
      break;
475
0
    case XML_VT_VARCOLOR3:
476
0
      readThemeColour(reader, tokenId, varClrSch.m_varColor3);
477
0
      break;
478
0
    case XML_VT_VARCOLOR4:
479
0
      readThemeColour(reader, tokenId, varClrSch.m_varColor4);
480
0
      break;
481
0
    case XML_VT_VARCOLOR5:
482
0
      readThemeColour(reader, tokenId, varClrSch.m_varColor5);
483
0
      break;
484
0
    case XML_VT_VARCOLOR6:
485
0
      readThemeColour(reader, tokenId, varClrSch.m_varColor6);
486
0
      break;
487
0
    case XML_VT_VARCOLOR7:
488
0
      readThemeColour(reader, tokenId, varClrSch.m_varColor7);
489
0
      break;
490
0
    default:
491
0
      break;
492
0
    }
493
0
  }
494
0
  while ((XML_VT_VARIATIONCLRSCHEME != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
495
0
}
496
497
std::optional<libvisio::Colour> libvisio::VSDXTheme::getThemeColour(unsigned value, unsigned variationIndex) const
498
0
{
499
0
  if (value < 100)
500
0
  {
501
0
    switch (value)
502
0
    {
503
0
    case 0:
504
0
      return m_clrScheme.m_dk1;
505
0
    case 1:
506
0
      return m_clrScheme.m_lt1;
507
0
    case 2:
508
0
      return m_clrScheme.m_accent1;
509
0
    case 3:
510
0
      return m_clrScheme.m_accent2;
511
0
    case 4:
512
0
      return m_clrScheme.m_accent3;
513
0
    case 5:
514
0
      return m_clrScheme.m_accent4;
515
0
    case 6:
516
0
      return m_clrScheme.m_accent5;
517
0
    case 7:
518
0
      return m_clrScheme.m_accent6;
519
0
    case 8:
520
0
      return m_clrScheme.m_bkgnd;
521
0
    default:
522
0
      break;
523
0
    }
524
0
  }
525
0
  else if (!m_clrScheme.m_variationClrSchemeLst.empty())
526
0
  {
527
0
    if (variationIndex >= m_clrScheme.m_variationClrSchemeLst.size())
528
0
      variationIndex = 0;
529
0
    switch (value)
530
0
    {
531
0
    case 100:
532
0
    case 200:
533
0
      return m_clrScheme.m_variationClrSchemeLst[variationIndex].m_varColor1;
534
0
    case 101:
535
0
    case 201:
536
0
      return m_clrScheme.m_variationClrSchemeLst[variationIndex].m_varColor2;
537
0
    case 102:
538
0
    case 202:
539
0
      return m_clrScheme.m_variationClrSchemeLst[variationIndex].m_varColor3;
540
0
    case 103:
541
0
    case 203:
542
0
      return m_clrScheme.m_variationClrSchemeLst[variationIndex].m_varColor4;
543
0
    case 104:
544
0
    case 204:
545
0
      return m_clrScheme.m_variationClrSchemeLst[variationIndex].m_varColor5;
546
0
    case 105:
547
0
    case 205:
548
0
      return m_clrScheme.m_variationClrSchemeLst[variationIndex].m_varColor6;
549
0
    case 106:
550
0
    case 206:
551
0
      return m_clrScheme.m_variationClrSchemeLst[variationIndex].m_varColor7;
552
0
    default:
553
0
      break;
554
0
    }
555
0
  }
556
0
  return std::optional<libvisio::Colour>();
557
0
}
558
559
void libvisio::VSDXTheme::readVariationStyleSchemeLst(xmlTextReaderPtr reader)
560
0
{
561
0
  VSD_DEBUG_MSG(("VSDXTheme::readVariationStyleSchemeLst\n"));
562
0
  int ret = 1;
563
0
  int tokenId = XML_TOKEN_INVALID;
564
0
  int tokenType = -1;
565
0
  m_variationStyleSchemeLst.clear();
566
0
  do
567
0
  {
568
0
    ret = xmlTextReaderRead(reader);
569
0
    tokenId = getElementToken(reader);
570
0
    if (XML_TOKEN_INVALID == tokenId)
571
0
    {
572
0
      VSD_DEBUG_MSG(("VSDXTheme::readVariationStyleSchemeLst: unknown token %s\n", xmlTextReaderConstName(reader)));
573
0
    }
574
0
    tokenType = xmlTextReaderNodeType(reader);
575
0
    switch (tokenId)
576
0
    {
577
0
    case XML_VT_VARIATIONSTYLESCHEME:
578
0
    {
579
0
      VSDXVariationStyleScheme vaStyleSch;
580
0
      readVariationStyleScheme(reader, tokenId, vaStyleSch);
581
0
      m_variationStyleSchemeLst.push_back(vaStyleSch);
582
0
      break;
583
0
    }
584
0
    default:
585
0
      break;
586
0
    }
587
0
  }
588
0
  while ((XML_VT_VARIATIONCLRSCHEMELST != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
589
0
}
590
591
void libvisio::VSDXTheme::readVariationStyleScheme(xmlTextReaderPtr reader, int idToken, VSDXVariationStyleScheme &vaStyleSch)
592
0
{
593
0
  int ret = 1;
594
0
  int tokenId = XML_TOKEN_INVALID;
595
0
  int tokenType = -1;
596
0
  size_t iVNum = 0;
597
0
  do
598
0
  {
599
0
    ret = xmlTextReaderRead(reader);
600
0
    tokenId = getElementToken(reader);
601
0
    if (XML_TOKEN_INVALID == tokenId)
602
0
    {
603
0
      VSD_DEBUG_MSG(("VSDXTheme::readVariationStyleScheme: unknown token %s\n", xmlTextReaderConstName(reader)));
604
0
    }
605
0
    tokenType = xmlTextReaderNodeType(reader);
606
0
    switch (tokenId)
607
0
    {
608
0
      case XML_VT_VARSTYLE:
609
0
      {
610
0
        if (vaStyleSch.m_varStyles.size() > iVNum)
611
0
        {
612
0
          readVarIdx(reader, vaStyleSch.m_varStyles[iVNum++]);
613
0
        }
614
0
        else
615
0
        {
616
0
          VSD_DEBUG_MSG(("Only four XML_VT_VARSTYLE can exists.\n"));
617
0
        }
618
0
        break;
619
0
      }
620
0
      default:
621
0
        break;
622
0
    }
623
0
  }
624
0
  while ((idToken != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
625
0
}
626
627
void libvisio::VSDXTheme::readVarIdx(xmlTextReaderPtr reader, std::array<unsigned, 4>& varStyle)
628
0
{
629
0
  if (XML_VT_VARSTYLE == getElementToken(reader))
630
0
  {
631
    // https://learn.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-vsdx/07c6a18a-16ec-4c36-942b-8c611dd3d140
632
0
    const shared_ptr<xmlChar> valFillIdx(xmlTextReaderGetAttribute(reader, BAD_CAST("fillIdx")), xmlFree);
633
0
    varStyle[0] = valFillIdx ? (unsigned)xmlStringToLong(valFillIdx) : MINUS_ONE;
634
635
0
    const shared_ptr<xmlChar> valLineIdx(xmlTextReaderGetAttribute(reader, BAD_CAST("lineIdx")), xmlFree);
636
0
    varStyle[1] = valLineIdx ? (unsigned)xmlStringToLong(valLineIdx) : MINUS_ONE;
637
638
0
    const shared_ptr<xmlChar> valEffIdx(xmlTextReaderGetAttribute(reader, BAD_CAST("effectIdx")), xmlFree);
639
0
    varStyle[2] = valEffIdx ? (unsigned)xmlStringToLong(valEffIdx) : MINUS_ONE;
640
641
0
    const shared_ptr<xmlChar> valFontIdx(xmlTextReaderGetAttribute(reader, BAD_CAST("fontIdx")), xmlFree);
642
0
    varStyle[3] = valFontIdx ? (unsigned)xmlStringToLong(valFontIdx) : MINUS_ONE;
643
0
  }
644
0
}
645
646
std::optional<libvisio::Colour> libvisio::VSDXTheme::getStyleColour(unsigned value, unsigned variationIndex) const
647
0
{
648
0
  if (!m_variationStyleSchemeLst.empty())
649
0
  {
650
    // https://learn.microsoft.com/en-us/openspecs/sharepoint_protocols/ms-vsdx/25689058-b1e7-4d3c-a833-0a4c7180f5f2
651
0
    if (variationIndex >= m_variationStyleSchemeLst.size())
652
0
      variationIndex = 0;
653
0
    switch (value)
654
0
    {
655
0
    case 100:
656
0
    case 200:
657
0
    {
658
0
      std::array<unsigned, 4> varStyle = m_variationStyleSchemeLst[variationIndex].m_varStyles[0];
659
0
      return getFillStyleColour(varStyle[0]);
660
0
    }
661
0
    case 101:
662
0
    case 201:
663
0
    {
664
0
      std::array<unsigned, 4> varStyle = m_variationStyleSchemeLst[variationIndex].m_varStyles[1];
665
0
      return getFillStyleColour(varStyle[0]);
666
0
    }
667
0
    case 102:
668
0
    case 202:
669
0
    {
670
0
      std::array<unsigned, 4> varStyle = m_variationStyleSchemeLst[variationIndex].m_varStyles[2];
671
0
      return getFillStyleColour(varStyle[0]);
672
0
    }
673
0
    case 103:
674
0
    case 203:
675
0
    {
676
0
      std::array<unsigned, 4> varStyle = m_variationStyleSchemeLst[variationIndex].m_varStyles[3];
677
0
      return getFillStyleColour(varStyle[0]);
678
0
    }
679
0
    default:
680
0
      break;
681
0
    }
682
0
  }
683
0
  return std::optional<libvisio::Colour>();
684
0
}
685
686
void libvisio::VSDXTheme::readFmtScheme(xmlTextReaderPtr reader)
687
0
{
688
0
  VSD_DEBUG_MSG(("VSDXTheme::readFmtScheme\n"));
689
0
  int ret = 1;
690
0
  int tokenId = XML_TOKEN_INVALID;
691
0
  int tokenType = -1;
692
0
  do
693
0
  {
694
0
    ret = xmlTextReaderRead(reader);
695
0
    tokenId = getElementToken(reader);
696
0
    if (XML_TOKEN_INVALID == tokenId)
697
0
    {
698
0
      VSD_DEBUG_MSG(("VSDXTheme::readFmtScheme: unknown token %s\n", xmlTextReaderConstName(reader)));
699
0
    }
700
0
    tokenType = xmlTextReaderNodeType(reader);
701
0
    switch (tokenId)
702
0
    {
703
0
    case XML_A_FILLSTYLELST:
704
0
    {
705
0
      readFillStyleLst(reader);
706
0
      break;
707
0
    }
708
0
    default:
709
      // Other style lists not implemented
710
0
      break;
711
0
    }
712
0
  }
713
0
  while ((XML_A_FMTSCHEME != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
714
0
}
715
716
void libvisio::VSDXTheme::skipUnimplemented(xmlTextReaderPtr reader, int idToken)
717
0
{
718
0
  int ret = 1;
719
0
  int tokenId = XML_TOKEN_INVALID;
720
0
  int tokenType = -1;
721
0
  do
722
0
  {
723
0
    ret = xmlTextReaderRead(reader);
724
0
    tokenId = getElementToken(reader);
725
0
    if (XML_TOKEN_INVALID == tokenId)
726
0
    {
727
0
      VSD_DEBUG_MSG(("VSDXTheme::skipUnimplemented: unknown token %s\n", xmlTextReaderConstName(reader)));
728
0
    }
729
0
    tokenType = xmlTextReaderNodeType(reader);
730
0
  }
731
0
  while ((idToken != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
732
0
}
733
734
void libvisio::VSDXTheme::readFillStyleLst(xmlTextReaderPtr reader)
735
0
{
736
0
  VSD_DEBUG_MSG(("VSDXTheme::readFillStyleLst\n"));
737
0
  int ret = xmlTextReaderRead(reader);
738
0
  int tokenId = getElementToken(reader);
739
0
  m_fillStyleLst.fill(std::vector<std::optional<libvisio::Colour>>());
740
0
  if (XML_TOKEN_INVALID == tokenId)
741
0
  {
742
0
    VSD_DEBUG_MSG(("VSDXTheme::readFillStyleLst: unknown token %s\n", xmlTextReaderConstName(reader)));
743
0
  }
744
0
  int tokenType = xmlTextReaderNodeType(reader);
745
0
  std::size_t i = 0;
746
0
  while ((XML_A_FILLSTYLELST != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret)
747
0
  {
748
0
    switch (tokenId)
749
0
    {
750
0
    case XML_A_SOLIDFILL:
751
0
    {
752
0
      Colour colour;
753
0
      if (readThemeColour(reader, tokenId, colour))
754
0
      {
755
0
        if (i < m_fillStyleLst.size())
756
0
        {
757
0
          m_fillStyleLst[i].push_back(colour);
758
0
        }
759
0
        else
760
0
        {
761
0
          VSD_DEBUG_MSG(("VSDXTheme::readFillStyleLst Error: Unable to add colour #%02x%02x%02x\n", colour.r, colour.g, colour.b));
762
0
        }
763
0
      }
764
0
      break;
765
0
    }
766
0
    case XML_A_GRADFILL:
767
0
    {
768
0
      readGradFill(reader, i);
769
0
      break;
770
0
    }
771
0
    default:
772
      // Skip unimplemented fill type
773
0
      skipUnimplemented(reader, tokenId);
774
0
      break;
775
0
    }
776
0
    ret = xmlTextReaderRead(reader);
777
0
    tokenId = getElementToken(reader);
778
0
    if (XML_TOKEN_INVALID == tokenId)
779
0
    {
780
0
      VSD_DEBUG_MSG(("VSDXTheme::readFillStyleLst: unknown token %s\n", xmlTextReaderConstName(reader)));
781
0
    }
782
0
    tokenType = xmlTextReaderNodeType(reader);
783
0
    i++;
784
0
  }
785
0
}
786
787
void libvisio::VSDXTheme::readGradFill(xmlTextReaderPtr reader, std::size_t nPos)
788
0
{
789
0
  VSD_DEBUG_MSG(("VSDXTheme::readGradFill\n"));
790
0
  int ret = 1;
791
0
  int tokenId = XML_TOKEN_INVALID;
792
0
  int tokenType = -1;
793
0
  do
794
0
  {
795
0
    ret = xmlTextReaderRead(reader);
796
0
    tokenId = getElementToken(reader);
797
0
    if (XML_TOKEN_INVALID == tokenId)
798
0
    {
799
0
      VSD_DEBUG_MSG(("VSDXTheme::readGradFill: unknown token %s\n", xmlTextReaderConstName(reader)));
800
0
    }
801
0
    tokenType = xmlTextReaderNodeType(reader);
802
0
    switch (tokenId)
803
0
    {
804
0
    case XML_A_GSLST:
805
0
    {
806
0
      readGradFillLst(reader, nPos);
807
0
      break;
808
0
    }
809
0
    default:
810
0
      break;
811
0
    }
812
0
  }
813
0
  while ((XML_A_GRADFILL != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret);
814
0
}
815
816
void libvisio::VSDXTheme::readGradFillLst(xmlTextReaderPtr reader, std::size_t nPos)
817
0
{
818
0
  VSD_DEBUG_MSG(("VSDXTheme::readGradFillLst\n"));
819
0
  int ret = xmlTextReaderRead(reader);
820
0
  int tokenId = getElementToken(reader);
821
0
  if (XML_TOKEN_INVALID == tokenId)
822
0
  {
823
0
    VSD_DEBUG_MSG(("VSDXTheme::readGradFillLst: unknown token %s\n", xmlTextReaderConstName(reader)));
824
0
  }
825
0
  int tokenType = xmlTextReaderNodeType(reader);
826
0
  while ((XML_A_GSLST != tokenId || XML_READER_TYPE_END_ELEMENT != tokenType) && 1 == ret)
827
0
  {
828
0
    switch (tokenId)
829
0
    {
830
0
    case XML_A_GS:
831
0
    {
832
0
      Colour colour;
833
0
      if (readThemeColour(reader, tokenId, colour))
834
0
      {
835
0
        if (nPos < m_fillStyleLst.size())
836
0
          m_fillStyleLst[nPos].push_back(colour);
837
0
        else
838
0
          VSD_DEBUG_MSG(("VSDXTheme::readGradFillLst Error: Unable to add colour #%02x%02x%02x\n", colour.r, colour.g, colour.b));
839
0
      }
840
0
      break;
841
0
    }
842
0
    default:
843
0
      break;
844
0
    }
845
0
    ret = xmlTextReaderRead(reader);
846
0
    tokenId = getElementToken(reader);
847
0
    if (XML_TOKEN_INVALID == tokenId)
848
0
    {
849
0
      VSD_DEBUG_MSG(("VSDXTheme::readGradFillLst: unknown token %s\n", xmlTextReaderConstName(reader)));
850
0
    }
851
0
    tokenType = xmlTextReaderNodeType(reader);
852
0
  }
853
0
}
854
855
std::optional<libvisio::Colour> libvisio::VSDXTheme::getFillStyleColour(unsigned value) const
856
0
{
857
0
  if (value == 0 || value > m_fillStyleLst.size() || m_fillStyleLst[value - 1].empty())
858
0
    return std::optional<libvisio::Colour>();
859
  // TODO: only the first colour is used until we support gradient fills
860
0
  return m_fillStyleLst[value - 1].front();
861
0
}
862
863
/* vim:set shiftwidth=2 softtabstop=2 expandtab: */