Coverage Report

Created: 2026-04-29 07:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libmwaw/src/lib/MWAWGraphicStyle.cxx
Line
Count
Source
1
/* -*- Mode: C++; c-default-style: "k&r"; indent-tabs-mode: nil; tab-width: 2; c-basic-offset: 2 -*- */
2
3
/* libmwaw
4
* Version: MPL 2.0 / LGPLv2+
5
*
6
* The contents of this file are subject to the Mozilla Public License Version
7
* 2.0 (the "License"); you may not use this file except in compliance with
8
* the License or as specified alternatively below. You may obtain a copy of
9
* the License at http://www.mozilla.org/MPL/
10
*
11
* Software distributed under the License is distributed on an "AS IS" basis,
12
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
* for the specific language governing rights and limitations under the
14
* License.
15
*
16
* Major Contributor(s):
17
* Copyright (C) 2002 William Lachance (wrlach@gmail.com)
18
* Copyright (C) 2002,2004 Marc Maurer (uwog@uwog.net)
19
* Copyright (C) 2004-2006 Fridrich Strba (fridrich.strba@bluewin.ch)
20
* Copyright (C) 2006, 2007 Andrew Ziem
21
* Copyright (C) 2011, 2012 Alonso Laurent (alonso@loria.fr)
22
*
23
*
24
* All Rights Reserved.
25
*
26
* For minor contributions see the git repository.
27
*
28
* Alternatively, the contents of this file may be used under the terms of
29
* the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
30
* in which case the provisions of the LGPLv2+ are applicable
31
* instead of those above.
32
*/
33
34
/* This header contains code specific to a pict mac file
35
 */
36
#include <string.h>
37
38
#include <iomanip>
39
#include <iostream>
40
#include <sstream>
41
#include <string>
42
43
#include <librevenge/librevenge.h>
44
#include <libmwaw/libmwaw.hxx>
45
46
#include "libmwaw_internal.hxx"
47
48
#include "MWAWFontConverter.hxx"
49
#include "MWAWPictBitmap.hxx"
50
51
#include "MWAWGraphicStyle.hxx"
52
53
////////////////////////////////////////////////////////////
54
// arrow
55
////////////////////////////////////////////////////////////
56
void MWAWGraphicStyle::Arrow::addTo(librevenge::RVNGPropertyList &propList, std::string const &type) const
57
1.26M
{
58
1.26M
  if (isEmpty())
59
0
    return;
60
1.26M
  if (type!="start" && type!="end") {
61
0
    MWAW_DEBUG_MSG(("MWAWGraphicStyle::Arrow::addTo: oops, find unexpected type\n"));
62
0
    return;
63
0
  }
64
1.26M
  std::stringstream s, s2;
65
1.26M
  s << "draw:marker-" << type << "-path";
66
1.26M
  propList.insert(s.str().c_str(), m_path.c_str());
67
1.26M
  s.str("");
68
1.26M
  s << "draw:marker-" << type << "-viewbox";
69
1.26M
  s2 << m_viewBox[0][0] << " " << m_viewBox[0][1] << " " << m_viewBox[1][0] << " " << m_viewBox[1][1];
70
1.26M
  propList.insert(s.str().c_str(), s2.str().c_str());
71
1.26M
  s.str("");
72
1.26M
  s << "draw:marker-" << type << "-center";
73
1.26M
  propList.insert(s.str().c_str(), m_isCentered);
74
1.26M
  s.str("");
75
1.26M
  s << "draw:marker-" << type << "-width";
76
1.26M
  propList.insert(s.str().c_str(), double(m_width), librevenge::RVNG_POINT);
77
1.26M
}
78
79
////////////////////////////////////////////////////////////
80
// pattern
81
////////////////////////////////////////////////////////////
82
MWAWGraphicStyle::Pattern::~Pattern()
83
786M
{
84
786M
}
85
86
bool MWAWGraphicStyle::Pattern::getUniqueColor(MWAWColor &col) const
87
63.0M
{
88
63.0M
  if (empty() || !m_picture.isEmpty() || m_data.empty()) return false;
89
33.5M
  if (m_colors[0]==m_colors[1]) {
90
3.70M
    col = m_colors[0];
91
3.70M
    return true;
92
3.70M
  }
93
29.8M
  unsigned char def=m_data[0];
94
29.8M
  if (def!=0 && def!=0xFF) return false;
95
62.6M
  for (size_t c=1; c < m_data.size(); ++c)
96
55.4M
    if (m_data[c]!=def) return false;
97
7.16M
  col = m_colors[def ? 1 : 0];
98
7.16M
  return true;
99
10.5M
}
100
101
bool MWAWGraphicStyle::Pattern::getAverageColor(MWAWColor &color) const
102
50.6M
{
103
50.6M
  if (empty()) return false;
104
21.7M
  if (!m_picture.isEmpty()) {
105
537k
    color=m_pictureAverageColor;
106
537k
    return true;
107
537k
  }
108
21.1M
  if (m_data.empty()) return false;
109
21.1M
  if (m_colors[0]==m_colors[1]) {
110
192k
    color = m_colors[0];
111
192k
    return true;
112
192k
  }
113
21.0M
  int numOne=0, numZero=0;
114
168M
  for (auto data : m_data) {
115
1.51G
    for (int depl=1, b=0; b < 8; ++b, depl*=2) {
116
1.34G
      if (data & depl)
117
426M
        numOne++;
118
917M
      else
119
917M
        numZero++;
120
1.34G
    }
121
168M
  }
122
21.0M
  if (!numOne && !numZero) return false;
123
21.0M
  float percent=float(numOne)/float(numOne+numZero);
124
21.0M
  color = MWAWColor::barycenter(1.f-percent,m_colors[0],percent,m_colors[1]);
125
21.0M
  return true;
126
21.0M
}
127
128
bool MWAWGraphicStyle::Pattern::getBinary(MWAWEmbeddedObject &picture) const
129
3.15M
{
130
3.15M
  if (empty()) {
131
0
    MWAW_DEBUG_MSG(("MWAWGraphicStyle::Pattern::getBinary: called on invalid pattern\n"));
132
0
    return false;
133
0
  }
134
3.15M
  if (!m_picture.isEmpty()) {
135
622k
    picture=m_picture;
136
622k
    return true;
137
622k
  }
138
  /* We create a indexed bitmap to obtain a final binary data.
139
140
     But it will probably better to recode that differently
141
   */
142
2.53M
  MWAWPictBitmapIndexed bitmap(m_dim);
143
2.53M
  std::vector<MWAWColor> colors;
144
2.53M
  for (auto const &color : m_colors)
145
5.07M
    colors.push_back(color);
146
2.53M
  bitmap.setColors(colors);
147
2.53M
  int numBytesByLines = m_dim[0]/8;
148
2.53M
  unsigned char const *ptr = &m_data[0];
149
2.53M
  std::vector<int> rowValues(static_cast<size_t>(m_dim[0]));
150
22.8M
  for (int h=0; h < m_dim[1]; ++h) {
151
20.2M
    size_t i=0;
152
40.5M
    for (int b=0; b < numBytesByLines; ++b) {
153
20.2M
      unsigned char c=*(ptr++);
154
20.2M
      unsigned char depl=0x80;
155
182M
      for (int byt=0; byt<8; ++byt) {
156
162M
        rowValues[i++] = (c&depl) ? 1 : 0;
157
162M
        depl=static_cast<unsigned char>(depl>>1);
158
162M
      }
159
20.2M
    }
160
20.2M
    bitmap.setRow(h, &rowValues[0]);
161
20.2M
  }
162
2.53M
  return bitmap.getBinary(picture);
163
3.15M
}
164
165
////////////////////////////////////////////////////////////
166
// gradient
167
////////////////////////////////////////////////////////////
168
bool MWAWGraphicStyle::Gradient::getAverageColor(MWAWColor &color) const
169
0
{
170
0
  if (m_stopList.empty())
171
0
    return false;
172
0
  if (m_stopList.size()==1) {
173
0
    color=m_stopList[0].m_color;
174
0
    return true;
175
0
  }
176
  // fixme: check the offset are sorted and use then to compute a better barycenter
177
0
  unsigned n[]= {0,0,0,0};
178
0
  for (auto const &st : m_stopList) {
179
0
    n[0]+=st.m_color.getRed();
180
0
    n[1]+=st.m_color.getGreen();
181
0
    n[2]+=st.m_color.getBlue();
182
0
    n[3]+=st.m_color.getAlpha();
183
0
  }
184
0
  color=MWAWColor((unsigned char)(n[0]/(unsigned)(m_stopList.size())),
185
0
                  (unsigned char)(n[1]/(unsigned)(m_stopList.size())),
186
0
                  (unsigned char)(n[2]/(unsigned)(m_stopList.size())),
187
0
                  (unsigned char)(n[3]/(unsigned)(m_stopList.size())));
188
0
  return true;
189
0
}
190
191
void MWAWGraphicStyle::Gradient::addTo(librevenge::RVNGPropertyList &propList) const
192
514k
{
193
514k
  if (!hasGradient()) return;
194
514k
  propList.insert("draw:fill", "gradient");
195
514k
  switch (m_type) {
196
11.9k
  case G_Axial:
197
11.9k
    propList.insert("draw:style", "axial");
198
11.9k
    break;
199
48.4k
  case G_Radial:
200
48.4k
    propList.insert("draw:style", "radial");
201
48.4k
    break;
202
59.7k
  case G_Rectangular:
203
59.7k
    propList.insert("draw:style", "rectangular");
204
59.7k
    break;
205
0
  case G_Square:
206
0
    propList.insert("draw:style", "square");
207
0
    break;
208
0
  case G_Ellipsoid:
209
0
    propList.insert("draw:style", "ellipsoid");
210
0
    break;
211
394k
  case G_Linear:
212
394k
  case G_None:
213
#if !defined(__clang__)
214
  default:
215
#endif
216
394k
    propList.insert("draw:style", "linear");
217
394k
    break;
218
514k
  }
219
514k
  if (m_stopList.size()==2 &&m_stopList[0].m_offset <= 0 &&
220
434k
      m_stopList[1].m_offset >=1) {
221
434k
    size_t first=(m_type==G_Linear || m_type==G_Axial) ? 0 : 1;
222
434k
    propList.insert("draw:start-color",m_stopList[first].m_color.str().c_str());
223
434k
    propList.insert("librevenge:start-opacity", double(m_stopList[first].m_opacity), librevenge::RVNG_PERCENT);
224
434k
    propList.insert("draw:end-color",m_stopList[1-first].m_color.str().c_str());
225
434k
    propList.insert("librevenge:end-opacity", double(m_stopList[1-first].m_opacity), librevenge::RVNG_PERCENT);
226
434k
  }
227
80.3k
  else {
228
80.3k
    librevenge::RVNGPropertyListVector gradient;
229
223k
    for (auto const &gr :m_stopList) {
230
223k
      librevenge::RVNGPropertyList grad;
231
223k
      grad.insert("svg:offset", double(gr.m_offset), librevenge::RVNG_PERCENT);
232
223k
      grad.insert("svg:stop-color", gr.m_color.str().c_str());
233
223k
      grad.insert("svg:stop-opacity", double(gr.m_opacity), librevenge::RVNG_PERCENT);
234
223k
      gradient.append(grad);
235
223k
    }
236
80.3k
    propList.insert("svg:linearGradient", gradient);
237
80.3k
  }
238
514k
  propList.insert("draw:angle", double(m_angle), librevenge::RVNG_GENERIC);
239
514k
  propList.insert("draw:border", double(m_border), librevenge::RVNG_PERCENT);
240
514k
  if (m_type != G_Linear) {
241
120k
    propList.insert("svg:cx", double(m_percentCenter[0]), librevenge::RVNG_PERCENT);
242
120k
    propList.insert("svg:cy", double(m_percentCenter[1]), librevenge::RVNG_PERCENT);
243
120k
  }
244
514k
  if (m_type == G_Radial)
245
48.4k
    propList.insert("svg:r", double(m_radius), librevenge::RVNG_PERCENT); // checkme
246
514k
}
247
248
////////////////////////////////////////////////////////////
249
// hatch
250
////////////////////////////////////////////////////////////
251
void MWAWGraphicStyle::Hatch::addTo(librevenge::RVNGPropertyList &propList) const
252
0
{
253
0
  if (!hasHatch()) return;
254
0
  propList.insert("draw:fill", "hatch");
255
0
  if (int(m_type)>=1 && int(m_type)<4) {
256
0
    char const *wh[]= {"single", "double", "triple"};
257
0
    propList.insert("draw:style", wh[int(m_type)-1]);
258
0
  }
259
0
  else {
260
0
    MWAW_DEBUG_MSG(("MWAWGraphicStyle::Hatch::addTo: unknown hash type %d\n", int(m_type)));
261
0
  }
262
0
  propList.insert("draw:color", m_color.str().c_str());
263
0
  propList.insert("draw:distance", double(m_distance), librevenge::RVNG_INCH);
264
0
  if (m_rotation<0 || m_rotation>0) propList.insert("draw:rotation", double(m_rotation), librevenge::RVNG_GENERIC);
265
0
}
266
267
////////////////////////////////////////////////////////////
268
// style
269
////////////////////////////////////////////////////////////
270
MWAWGraphicStyle::~MWAWGraphicStyle()
271
614M
{
272
614M
}
273
274
void MWAWGraphicStyle::setBorders(int wh, MWAWBorder const &border)
275
792k
{
276
792k
  int const allBits = libmwaw::LeftBit|libmwaw::RightBit|libmwaw::TopBit|libmwaw::BottomBit;
277
792k
  if (wh & (~allBits)) {
278
0
    MWAW_DEBUG_MSG(("MWAWGraphicStyle::setBorders: unknown borders\n"));
279
0
    return;
280
0
  }
281
792k
  size_t numData = 4;
282
792k
  if (m_bordersList.size() < numData) {
283
772k
    MWAWBorder emptyBorder;
284
772k
    emptyBorder.m_style = MWAWBorder::None;
285
772k
    m_bordersList.resize(numData, emptyBorder);
286
772k
  }
287
792k
  if (wh & libmwaw::LeftBit) m_bordersList[libmwaw::Left] = border;
288
792k
  if (wh & libmwaw::RightBit) m_bordersList[libmwaw::Right] = border;
289
792k
  if (wh & libmwaw::TopBit) m_bordersList[libmwaw::Top] = border;
290
792k
  if (wh & libmwaw::BottomBit) m_bordersList[libmwaw::Bottom] = border;
291
792k
}
292
293
void MWAWGraphicStyle::addTo(librevenge::RVNGPropertyList &list, bool only1D) const
294
26.0M
{
295
26.0M
  if (!hasLine())
296
16.8M
    list.insert("draw:stroke", "none");
297
9.17M
  else if (m_lineDashWidth.size()>=2) {
298
126k
    int nDots1=0, nDots2=0;
299
126k
    float size1=0, size2=0, totalGap=0.0;
300
335k
    for (size_t c=0; c+1 < m_lineDashWidth.size();) {
301
241k
      float sz=m_lineDashWidth[c++];
302
241k
      if (nDots2 && (sz<size2||sz>size2)) {
303
32.8k
        static bool first=true;
304
32.8k
        if (first) {
305
28
          MWAW_DEBUG_MSG(("MWAWGraphicStyle::addTo: can not set some dash\n"));
306
28
          first = false;
307
28
        }
308
32.8k
        break;
309
32.8k
      }
310
208k
      if (nDots2)
311
13.7k
        nDots2++;
312
194k
      else if (!nDots1 || (sz>=size1 && sz <= size1)) {
313
132k
        nDots1++;
314
132k
        size1=sz;
315
132k
      }
316
62.1k
      else {
317
62.1k
        nDots2=1;
318
62.1k
        size2=sz;
319
62.1k
      }
320
208k
      totalGap += m_lineDashWidth[c++];
321
208k
    }
322
126k
    list.insert("draw:stroke", "dash");
323
126k
    list.insert("draw:dots1", nDots1);
324
126k
    list.insert("draw:dots1-length", double(size1), librevenge::RVNG_POINT);
325
126k
    if (nDots2) {
326
62.1k
      list.insert("draw:dots2", nDots2);
327
62.1k
      list.insert("draw:dots2-length", double(size2), librevenge::RVNG_POINT);
328
62.1k
    }
329
126k
    const double distance = ((nDots1 + nDots2) > 0) ? double(totalGap)/double(nDots1+nDots2) : double(totalGap);
330
126k
    list.insert("draw:distance", distance, librevenge::RVNG_POINT);;
331
126k
  }
332
9.04M
  else
333
9.04M
    list.insert("draw:stroke", "solid");
334
26.0M
  list.insert("svg:stroke-color", m_lineColor.str().c_str());
335
26.0M
  list.insert("svg:stroke-width", double(m_lineWidth),librevenge::RVNG_POINT);
336
337
26.0M
  if (m_lineOpacity < 1)
338
393k
    list.insert("svg:stroke-opacity", double(m_lineOpacity), librevenge::RVNG_PERCENT);
339
26.0M
  switch (m_lineCap) {
340
95
  case C_Round:
341
95
    list.insert("svg:stroke-linecap", "round");
342
95
    break;
343
30
  case C_Square:
344
30
    list.insert("svg:stroke-linecap", "square");
345
30
    break;
346
26.0M
  case C_Butt:
347
#if !defined(__clang__)
348
  default:
349
#endif
350
26.0M
    break;
351
26.0M
  }
352
26.0M
  switch (m_lineJoin) {
353
88
  case J_Round:
354
88
    list.insert("draw:stroke-linejoin", "round");
355
88
    break;
356
154
  case J_Bevel:
357
154
    list.insert("draw:stroke-linejoin", "bevel");
358
154
    break;
359
26.0M
  case J_Miter:
360
#if !defined(__clang__)
361
  default:
362
#endif
363
26.0M
    break;
364
26.0M
  }
365
  // alignment
366
26.0M
  switch (m_verticalAlignment) {
367
0
  case V_AlignTop:
368
0
    list.insert("draw:textarea-vertical-align", "top");
369
0
    break;
370
0
  case V_AlignCenter:
371
0
    list.insert("draw:textarea-vertical-align", "middle");
372
0
    break;
373
0
  case V_AlignBottom:
374
0
    list.insert("draw:textarea-vertical-align", "bottom");
375
0
    break;
376
0
  case V_AlignJustify:
377
0
    list.insert("draw:textarea-vertical-align", "justify");
378
0
    break;
379
26.0M
  case V_AlignDefault:
380
26.0M
    break; // default
381
#if !defined(__clang__)
382
  default:
383
#endif
384
0
    MWAW_DEBUG_MSG(("MWAWStyle::addTo: called with unknown valign=%d\n", m_verticalAlignment));
385
26.0M
  }
386
26.0M
  if (!m_arrows[0].isEmpty()) m_arrows[0].addTo(list,"start");
387
26.0M
  if (!m_arrows[1].isEmpty()) m_arrows[1].addTo(list,"end");
388
26.0M
  if (hasShadow()) {
389
41.6k
    list.insert("draw:shadow", "visible");
390
41.6k
    list.insert("draw:shadow-color", m_shadowColor.str().c_str());
391
41.6k
    list.insert("draw:shadow-opacity", double(m_shadowOpacity), librevenge::RVNG_PERCENT);
392
    // in cm
393
41.6k
    list.insert("draw:shadow-offset-x", double(m_shadowOffset[0])/72.*2.54, librevenge::RVNG_GENERIC); // cm
394
41.6k
    list.insert("draw:shadow-offset-y", double(m_shadowOffset[1])/72.*2.54, librevenge::RVNG_GENERIC); // cm
395
41.6k
  }
396
26.0M
  if (m_doNotPrint)
397
0
    list.insert("style:print-content", false);
398
26.0M
  if (only1D || !hasSurface()) {
399
16.5M
    list.insert("draw:fill", "none");
400
16.5M
    return;
401
16.5M
  }
402
9.51M
  list.insert("svg:fill-rule", m_fillRuleEvenOdd ? "evenodd" : "nonzero");
403
9.51M
  if (hasGradient())
404
514k
    m_gradient.addTo(list);
405
9.00M
  else if (hasHatch()) {
406
0
    m_hatch.addTo(list);
407
0
    if (hasSurfaceColor()) {
408
0
      list.insert("draw:fill-color", m_surfaceColor.str().c_str());
409
0
      list.insert("draw:opacity", double(m_surfaceOpacity), librevenge::RVNG_PERCENT);
410
0
      list.insert("draw:fill-hatch-solid", true);
411
0
    }
412
0
  }
413
9.00M
  else {
414
9.00M
    bool done = false;
415
9.00M
    MWAWColor surfaceColor=m_surfaceColor;
416
9.00M
    float surfaceOpacity = m_surfaceOpacity;
417
9.00M
    if (hasPattern()) {
418
3.17M
      MWAWColor col;
419
3.17M
      if (m_pattern.getUniqueColor(col)) {
420
        // no need to create a uniform pattern
421
20.4k
        surfaceColor = col;
422
20.4k
        surfaceOpacity = 1;
423
20.4k
      }
424
3.15M
      else {
425
3.15M
        MWAWEmbeddedObject picture;
426
3.15M
        if (m_pattern.getBinary(picture) && !picture.m_dataList.empty() && !picture.m_dataList[0].empty()) {
427
3.15M
          list.insert("draw:fill", "bitmap");
428
3.15M
          list.insert("draw:fill-image", picture.m_dataList[0].getBase64Data());
429
3.15M
          list.insert("draw:fill-image-width", m_pattern.m_dim[0], librevenge::RVNG_POINT);
430
3.15M
          list.insert("draw:fill-image-height", m_pattern.m_dim[1], librevenge::RVNG_POINT);
431
3.15M
          list.insert("draw:fill-image-ref-point-x",0, librevenge::RVNG_POINT);
432
3.15M
          list.insert("draw:fill-image-ref-point-y",0, librevenge::RVNG_POINT);
433
3.15M
          if (surfaceOpacity<1)
434
56
            list.insert("draw:opacity", double(surfaceOpacity), librevenge::RVNG_PERCENT);
435
3.15M
          list.insert("librevenge:mime-type", picture.m_typeList.empty() ? "image/pict" : picture.m_typeList[0].c_str());
436
3.15M
          done = true;
437
3.15M
        }
438
0
        else {
439
0
          MWAW_DEBUG_MSG(("MWAWGraphicStyle::addTo: can not set the pattern\n"));
440
0
        }
441
3.15M
      }
442
3.17M
    }
443
9.00M
    if (!done) {
444
5.84M
      list.insert("draw:fill", "solid");
445
5.84M
      list.insert("draw:fill-color", surfaceColor.str().c_str());
446
5.84M
      list.insert("draw:opacity", double(surfaceOpacity), librevenge::RVNG_PERCENT);
447
5.84M
    }
448
9.00M
  }
449
9.51M
}
450
451
void MWAWGraphicStyle::addFrameTo(librevenge::RVNGPropertyList &list) const
452
7.24M
{
453
7.24M
  if (m_backgroundOpacity>=0) {
454
3.91M
    if (m_backgroundOpacity>0)
455
955k
      list.insert("fo:background-color", m_backgroundColor.str().c_str());
456
3.91M
    if (m_backgroundOpacity<1)
457
2.96M
      list.insert("style:background-transparency", 1.-double(m_backgroundOpacity), librevenge::RVNG_PERCENT);
458
3.91M
  }
459
7.24M
  if (hasBorders()) {
460
570k
    if (hasSameBorders())
461
569k
      m_bordersList[0].addTo(list, "");
462
1.11k
    else {
463
5.55k
      for (size_t c = 0; c < m_bordersList.size(); c++) {
464
4.44k
        if (c >= 4) break;
465
4.44k
        switch (c) {
466
1.11k
        case libmwaw::Left:
467
1.11k
          m_bordersList[c].addTo(list, "left");
468
1.11k
          break;
469
1.11k
        case libmwaw::Right:
470
1.11k
          m_bordersList[c].addTo(list, "right");
471
1.11k
          break;
472
1.11k
        case libmwaw::Top:
473
1.11k
          m_bordersList[c].addTo(list, "top");
474
1.11k
          break;
475
1.11k
        case libmwaw::Bottom:
476
1.11k
          m_bordersList[c].addTo(list, "bottom");
477
1.11k
          break;
478
#if !defined(__clang__)
479
        default:
480
          MWAW_DEBUG_MSG(("MWAWGraphicStyle::addFrameTo: can not send %d border\n",int(c)));
481
          break;
482
#endif
483
4.44k
        }
484
4.44k
      }
485
1.11k
    }
486
570k
  }
487
7.24M
  if (hasShadow()) {
488
69.4k
    list.insert("draw:shadow", "visible");
489
69.4k
    list.insert("draw:shadow-color", m_shadowColor.str().c_str());
490
69.4k
    list.insert("draw:shadow-opacity", double(m_shadowOpacity), librevenge::RVNG_PERCENT);
491
    // in cm
492
69.4k
    list.insert("draw:shadow-offset-x", double(m_shadowOffset[0])/72.*2.54, librevenge::RVNG_GENERIC); // cm
493
69.4k
    list.insert("draw:shadow-offset-y", double(m_shadowOffset[1])/72.*2.54, librevenge::RVNG_GENERIC); // cm
494
69.4k
  }
495
7.24M
  if (!m_frameName.empty())
496
77.7k
    list.insert("librevenge:frame-name",m_frameName.c_str());
497
7.24M
}
498
499
int MWAWGraphicStyle::cmp(MWAWGraphicStyle const &a) const
500
0
{
501
0
  if (m_lineWidth < a.m_lineWidth) return -1;
502
0
  if (m_lineWidth > a.m_lineWidth) return 1;
503
0
  if (m_lineCap < a.m_lineCap) return -1;
504
0
  if (m_lineCap > a.m_lineCap) return 1;
505
0
  if (m_lineJoin < a.m_lineJoin) return -1;
506
0
  if (m_lineJoin > a.m_lineJoin) return 1;
507
0
  if (m_lineOpacity < a.m_lineOpacity) return -1;
508
0
  if (m_lineOpacity > a.m_lineOpacity) return 1;
509
0
  if (m_lineColor < a.m_lineColor) return -1;
510
0
  if (m_lineColor > a.m_lineColor) return 1;
511
512
0
  if (m_lineDashWidth.size() < a.m_lineDashWidth.size()) return -1;
513
0
  if (m_lineDashWidth.size() > a.m_lineDashWidth.size()) return 1;
514
0
  for (size_t d=0; d < m_lineDashWidth.size(); ++d) {
515
0
    if (m_lineDashWidth[d] > a.m_lineDashWidth[d]) return -1;
516
0
    if (m_lineDashWidth[d] < a.m_lineDashWidth[d]) return 1;
517
0
  }
518
0
  for (int i=0; i<2; ++i) {
519
0
    if (m_arrows[i]!=a.m_arrows[i])
520
0
      return m_arrows[i]<a.m_arrows[i] ? -1 : 1;
521
0
    if (m_flip[i]!=a.m_flip[i])
522
0
      return m_flip[i] ? 1 : -1;
523
0
  }
524
525
0
  if (m_fillRuleEvenOdd != a.m_fillRuleEvenOdd) return m_fillRuleEvenOdd ? 1: -1;
526
527
0
  if (m_surfaceColor < a.m_surfaceColor) return -1;
528
0
  if (m_surfaceColor > a.m_surfaceColor) return 1;
529
0
  if (m_surfaceOpacity < a.m_surfaceOpacity) return -1;
530
0
  if (m_surfaceOpacity > a.m_surfaceOpacity) return 1;
531
532
0
  if (m_shadowColor < a.m_shadowColor) return -1;
533
0
  if (m_shadowColor > a.m_shadowColor) return 1;
534
0
  if (m_shadowOpacity < a.m_shadowOpacity) return -1;
535
0
  if (m_shadowOpacity > a.m_shadowOpacity) return 1;
536
0
  int diff=m_shadowOffset.cmp(a.m_shadowOffset);
537
0
  if (diff) return diff;
538
539
0
  diff = m_pattern.cmp(a.m_pattern);
540
0
  if (diff) return diff;
541
0
  diff = m_gradient.cmp(a.m_gradient);
542
0
  if (diff) return diff;
543
0
  diff = m_hatch.cmp(a.m_hatch);
544
0
  if (diff) return diff;
545
546
0
  size_t numBorders=m_bordersList.size();
547
0
  if (a.m_bordersList.size()>numBorders)
548
0
    numBorders=a.m_bordersList.size();
549
0
  for (size_t b=0; b<numBorders; ++b) {
550
0
    bool empty=b>=m_bordersList.size() || m_bordersList[b].isEmpty();
551
0
    bool aEmpty=b>=a.m_bordersList.size() || a.m_bordersList[b].isEmpty();
552
0
    if (empty!=aEmpty) return empty ? 1 : -1;
553
0
    diff=m_bordersList[b].compare(a.m_bordersList[b]);
554
0
    if (diff) return diff;
555
0
  }
556
0
  if (m_backgroundColor < a.m_backgroundColor) return -1;
557
0
  if (m_backgroundColor > a.m_backgroundColor) return 1;
558
0
  if (m_backgroundOpacity < a.m_backgroundOpacity) return -1;
559
0
  if (m_backgroundOpacity > a.m_backgroundOpacity) return 1;
560
0
  if (m_frameName < a.m_frameName) return -1;
561
0
  if (m_frameName > a.m_frameName) return 1;
562
0
  if (m_frameNextName < a.m_frameNextName) return -1;
563
0
  if (m_frameNextName > a.m_frameNextName) return 1;
564
0
  if (m_verticalAlignment < a.m_verticalAlignment) return -1;
565
0
  if (m_verticalAlignment > a.m_verticalAlignment) return 1;
566
567
0
  if (m_rotate < a.m_rotate) return -1;
568
0
  if (m_rotate > a.m_rotate) return 1;
569
0
  return 0;
570
0
}
571
572
std::ostream &operator<<(std::ostream &o, MWAWGraphicStyle const &st)
573
0
{
574
0
  if (st.m_rotate<0 || st.m_rotate>0)
575
0
    o << "rot=" << st.m_rotate << ",";
576
0
  if (st.m_flip[0]) o << "flipX,";
577
0
  if (st.m_flip[1]) o << "flipY,";
578
0
  o << "line=[";
579
0
  if (st.m_lineWidth<1 || st.m_lineWidth>1)
580
0
    o << "width=" << st.m_lineWidth << ",";
581
0
  if (!st.m_lineDashWidth.empty()) {
582
0
    o << "dash=[";
583
0
    for (auto w : st.m_lineDashWidth)
584
0
      o << w << ",";
585
0
    o << "],";
586
0
  }
587
0
  switch (st.m_lineCap) {
588
0
  case MWAWGraphicStyle::C_Square:
589
0
    o << "cap=square,";
590
0
    break;
591
0
  case MWAWGraphicStyle::C_Round:
592
0
    o << "cap=round,";
593
0
    break;
594
0
  case MWAWGraphicStyle::C_Butt:
595
#if !defined(__clang__)
596
  default:
597
#endif
598
0
    break;
599
0
  }
600
0
  switch (st.m_lineJoin) {
601
0
  case MWAWGraphicStyle::J_Bevel:
602
0
    o << "join=bevel,";
603
0
    break;
604
0
  case MWAWGraphicStyle::J_Round:
605
0
    o << "join=round,";
606
0
    break;
607
0
  case MWAWGraphicStyle::J_Miter:
608
#if !defined(__clang__)
609
  default:
610
#endif
611
0
    break;
612
0
  }
613
0
  if (st.m_lineOpacity<1)
614
0
    o << "opacity=" << st.m_lineOpacity << ",";
615
0
  if (!st.m_lineColor.isBlack())
616
0
    o << "color=" << st.m_lineColor << ",";
617
0
  if (!st.m_arrows[0].isEmpty()) o << "arrow[start]=[" << st.m_arrows[0] << "],";
618
0
  if (!st.m_arrows[1].isEmpty()) o << "arrow[end]=[" << st.m_arrows[1] << "],";
619
0
  o << "],";
620
0
  if (st.hasSurfaceColor()) {
621
0
    o << "surf=[";
622
0
    if (!st.m_surfaceColor.isWhite())
623
0
      o << "color=" << st.m_surfaceColor << ",";
624
0
    if (st.m_surfaceOpacity > 0)
625
0
      o << "opacity=" << st.m_surfaceOpacity << ",";
626
0
    o << "],";
627
0
    if (st.m_fillRuleEvenOdd)
628
0
      o << "fill[evenOdd],";
629
0
  }
630
0
  if (st.hasPattern())
631
0
    o << "pattern=[" << st.m_pattern << "],";
632
0
  if (st.hasGradient())
633
0
    o << "grad=[" << st.m_gradient << "],";
634
0
  if (st.hasHatch())
635
0
    o << "hatch=[" << st.m_hatch << "],";
636
0
  if (st.hasShadow()) {
637
0
    o << "shadow=[";
638
0
    if (!st.m_shadowColor.isBlack())
639
0
      o << "color=" << st.m_shadowColor << ",";
640
0
    if (st.m_shadowOpacity > 0)
641
0
      o << "opacity=" << st.m_shadowOpacity << ",";
642
0
    o << "offset=" << st.m_shadowOffset << ",";
643
0
    o << "],";
644
0
  }
645
0
  if (st.hasBorders()) {
646
0
    for (size_t i = 0; i < st.m_bordersList.size(); i++) {
647
0
      if (st.m_bordersList[i].m_style == MWAWBorder::None)
648
0
        continue;
649
0
      o << "bord";
650
0
      if (i < 4) {
651
0
        static char const* const wh[] = { "L", "R", "T", "B"};
652
0
        o << wh[i];
653
0
      }
654
0
      else o << "[#wh=" << i << "]";
655
0
      o << "=" << st.m_bordersList[i] << ",";
656
0
    }
657
0
  }
658
0
  if (!st.m_backgroundColor.isWhite())
659
0
    o << "background[color]=" << st.m_backgroundColor << ",";
660
0
  if (st.m_backgroundOpacity>=0)
661
0
    o << "background[opacity]=" << 100.f *st.m_backgroundOpacity << "%,";
662
0
  if (!st.m_frameName.empty())
663
0
    o << "frame[name]=" << st.m_frameName << ",";
664
0
  if (!st.m_frameNextName.empty())
665
0
    o << "frame[linkedto]=" << st.m_frameNextName << ",";
666
0
  o << st.m_extra;
667
0
  return o;
668
0
}
669
670
// vim: set filetype=cpp tabstop=2 shiftwidth=2 cindent autoindent smartindent noexpandtab: