Coverage Report

Created: 2026-03-12 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwpg/src/lib/WPG2Parser.cpp
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2
/* libwpg
3
 * Version: MPL 2.0 / LGPLv2.1+
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
 * Major Contributor(s):
10
 * Copyright (C) 2006 Ariya Hidayat (ariya@kde.org)
11
 * Copyright (C) 2005-2007 Fridrich Strba (fridrich.strba@bluewin.ch)
12
 * Copyright (C) 2004 Marc Oude Kotte (marc@solcon.nl)
13
 *
14
 * For minor contributions see the git repository.
15
 *
16
 * Alternatively, the contents of this file may be used under the terms
17
 * of the GNU Lesser General Public License Version 2.1 or later
18
 * (LGPLv2.1+), in which case the provisions of the LGPLv2.1+ are
19
 * applicable instead of those above.
20
 *
21
 * For further information visit http://libwpg.sourceforge.net
22
 */
23
24
/* "This product is not manufactured, approved, or supported by
25
 * Corel Corporation or Corel Corporation Limited."
26
 */
27
28
#include "WPG2Parser.h"
29
30
#include <cstring>
31
#include <limits>
32
#include <math.h>
33
#include <vector>
34
35
#include <librevenge/librevenge.h>
36
37
#include <libwpd/libwpd.h>
38
39
#include "WPGTextDataHandler.h"
40
#include "libwpg_utils.h"
41
42
#define DUMP_BINARY_DATA 0
43
44
#if DUMP_BINARY_DATA
45
#include <sstream>
46
#endif
47
48
// MSVC++ 6.0 does not have the macro defined, so we define it
49
#ifndef M_PI
50
#define M_PI 3.14159265358979323846
51
#endif
52
53
using namespace libwpd;
54
55
using libwpg::getRemainingLength;
56
57
namespace
58
{
59
60
static double fixedPointToDouble(const unsigned int fixedPointNumber)
61
79.4k
{
62
79.4k
  auto fixedPointNumberIntegerPart = (short)((fixedPointNumber & 0xFFFF0000) >> 16);
63
79.4k
  auto fixedPointNumberFractionalPart = (double)((double)(fixedPointNumber & 0x0000FFFF)/(double)0xFFFF);
64
79.4k
  return ((fixedPointNumberIntegerPart >= 0) ?
65
71.6k
          ((double)fixedPointNumberIntegerPart + fixedPointNumberFractionalPart) :
66
79.4k
          ((double)fixedPointNumberIntegerPart - fixedPointNumberFractionalPart));
67
79.4k
}
68
69
long safeSubtract(long left, const long right)
70
3.88M
{
71
3.88M
  if (right > 0)
72
1.00M
  {
73
1.00M
    if (left > std::numeric_limits<long>::min() + right)
74
1.00M
      left -= right;
75
6.33k
    else
76
6.33k
      left = std::numeric_limits<long>::min();
77
1.00M
  }
78
2.87M
  else if (right < 0)
79
2.50M
  {
80
2.50M
    if (left < std::numeric_limits<long>::max() + right)
81
2.48M
      left -= right;
82
20.3k
    else
83
20.3k
      left = std::numeric_limits<long>::max();
84
2.50M
  }
85
3.88M
  return left;
86
3.88M
}
87
88
}
89
90
static const unsigned char defaultWPG2PaletteRed[] =
91
{
92
  0x00, 0xFF, 0x7F, 0xBF, 0x00, 0x00, 0x00, 0x7F,
93
  0x7F, 0x7F, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
94
  0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
95
  0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
96
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
97
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
98
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
99
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
100
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
101
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
102
  0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A,
103
  0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2,
104
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
105
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
106
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
107
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
108
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
109
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
110
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
111
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
112
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
113
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
114
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
115
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
116
  0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A,
117
  0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2,
118
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF,
119
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
120
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF,
121
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
122
  0x33, 0x47, 0x61, 0x73, 0x87, 0x9C, 0xB0, 0xC7,
123
  0xCC, 0xD4, 0xDB, 0xE3, 0xE8, 0xF0, 0xF7, 0xFF,
124
};
125
126
static const unsigned char defaultWPG2PaletteGreen[] =
127
{
128
  0x00, 0xFF, 0x7F, 0xBF, 0x00, 0x7F, 0x7F, 0x00,
129
  0x00, 0x7F, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF,
130
  0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
131
  0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
132
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
133
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
134
  0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A,
135
  0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2,
136
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
137
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
138
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
139
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
140
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
141
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
142
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
143
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
144
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
145
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
146
  0x56, 0x64, 0x72, 0x80, 0x8E, 0x9C, 0xAA, 0xB1,
147
  0xB8, 0xBF, 0xC6, 0xCD, 0xD4, 0xDB, 0xE2, 0xE9,
148
  0x2B, 0x32, 0x39, 0x40, 0x47, 0x4E, 0x55, 0x63,
149
  0x71, 0x7F, 0x8D, 0x9B, 0xA9, 0xB7, 0xC5, 0xD3,
150
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
151
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
152
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
153
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
154
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
155
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
156
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
157
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
158
  0x29, 0x38, 0x45, 0x4F, 0x5C, 0x63, 0x69, 0xD4,
159
  0x87, 0x8F, 0x9C, 0xA8, 0xB3, 0xC4, 0xCF, 0xE0,
160
};
161
162
static const unsigned char defaultWPG2PaletteBlue[] =
163
{
164
  0x00, 0xFF, 0x7F, 0xBF, 0x7F, 0x00, 0x7F, 0x00,
165
  0x7F, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00,
166
  0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
167
  0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
168
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
169
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
170
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
171
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
172
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
173
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
174
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
175
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
176
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16,
177
  0x2C, 0x42, 0x58, 0x6E, 0x84, 0x9A, 0xB0, 0xC6,
178
  0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A,
179
  0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2,
180
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE9, 0xFF, 0xFF,
181
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
182
  0x7B, 0x91, 0xA7, 0xB0, 0xD3, 0xE4, 0xFF, 0xFF,
183
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
184
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF,
185
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
186
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF,
187
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
188
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF,
189
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
190
  0x7B, 0x91, 0xA7, 0xBD, 0xD3, 0xE4, 0xFF, 0xFF,
191
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
192
  0x3D, 0x48, 0x53, 0x5E, 0x69, 0x74, 0x7F, 0x8A,
193
  0x95, 0xA0, 0xAB, 0xB6, 0xC1, 0xCC, 0xD7, 0xE2,
194
  0x11, 0x17, 0x1C, 0x24, 0x29, 0x2B, 0x2B, 0x30,
195
  0x47, 0x57, 0x69, 0x78, 0x8C, 0x9C, 0xB0, 0xC7,
196
};
197
198
class WPG2Parser::ObjectCharacterization
199
{
200
public:
201
  bool taper;
202
  bool translate;
203
  bool skew;
204
  bool scale;
205
  bool rotate;
206
  bool hasObjectId;
207
  bool editLock;
208
  bool windingRule;
209
  bool filled;
210
  bool closed;
211
  bool framed;
212
213
  unsigned long objectId;
214
  unsigned long lockFlags;
215
  double rotationAngle;
216
  long sxcos;
217
  long sycos;
218
  long kxsin;
219
  long kysin;
220
  long txinteger;
221
  unsigned short txfraction;
222
  long tyinteger;
223
  unsigned short tyfraction;
224
  long px;
225
  long py;
226
227
  WPG2TransformMatrix matrix;
228
229
  ObjectCharacterization():
230
123k
    taper(false),
231
123k
    translate(false),
232
123k
    skew(false),
233
123k
    scale(false),
234
123k
    rotate(false),
235
123k
    hasObjectId(false),
236
123k
    editLock(false),
237
123k
    windingRule(false),
238
123k
    filled(false),
239
123k
    closed(false),
240
123k
    framed(true),
241
123k
    objectId(0),
242
123k
    lockFlags(0),
243
123k
    rotationAngle(0.0),
244
123k
    sxcos(0),
245
123k
    sycos(0),
246
123k
    kxsin(0),
247
123k
    kysin(0),
248
123k
    txinteger(0),
249
123k
    txfraction(0),
250
123k
    tyinteger(0),
251
123k
    tyfraction(0),
252
123k
    px(0),
253
123k
    py(0),
254
123k
    matrix()
255
123k
  {}
256
};
257
258
WPG2Parser::WPG2Parser(librevenge::RVNGInputStream *input, librevenge::RVNGDrawingInterface *painter, bool isEmbedded):
259
13.3k
  WPGXParser(input, painter),
260
13.3k
  m_recordLength(0),
261
13.3k
  m_recordEnd(0),
262
13.3k
  m_success(true), m_exit(false), m_graphicsStarted(isEmbedded),
263
13.3k
  m_xres(1200), m_yres(1200),
264
13.3k
  m_xofs(0), m_yofs(0),
265
13.3k
  m_width(0), m_height(0),
266
13.3k
  m_doublePrecision(false),
267
13.3k
  m_style(),
268
13.3k
  m_penForeColor(0,0,0),
269
13.3k
  m_penBackColor(0xff,0xff,0xff),
270
13.3k
  m_brushForeColor(0,0,0),
271
13.3k
  m_brushBackColor(0xff,0xff,0xff),
272
13.3k
  m_dashArray(),
273
13.3k
  m_gradient(),
274
13.3k
  m_dashArrayStyles(),
275
13.3k
  m_layerOpened(false),
276
#ifdef DEBUG
277
  m_layerId(0),
278
#endif
279
13.3k
  m_matrix(),
280
13.3k
  m_gradientAngle(0.0),
281
13.3k
  m_gradientRef(),
282
13.3k
  m_groupStack(),
283
13.3k
  m_compoundMatrix(),
284
13.3k
  m_compoundWindingRule(false),
285
13.3k
  m_compoundFilled(false),
286
13.3k
  m_compoundFramed(true),
287
13.3k
  m_compoundClosed(false),
288
13.3k
  m_bitmap(),
289
13.3k
  m_binaryData(),
290
13.3k
  m_hFlipped(false),
291
13.3k
  m_vFlipped(false),
292
13.3k
  m_textData(),
293
13.3k
  m_drawTextData(false)
294
#if DUMP_BINARY_DATA
295
  , m_binaryId(0)
296
#endif
297
13.3k
{
298
13.3k
  m_style.insert("draw:fill", "solid");
299
  // default style
300
13.3k
  m_penForeColor = libwpg::WPGColor(0,0,0);
301
13.3k
  m_penBackColor = libwpg::WPGColor(0xff,0xff,0xff);
302
13.3k
  m_style.insert("svg:stroke-width", 0.0);
303
13.3k
  m_style.insert("draw:stroke", "solid");
304
13.3k
  m_dashArray = libwpg::WPGDashArray();
305
13.3k
  m_brushForeColor = libwpg::WPGColor(0,0,0);
306
13.3k
  m_brushBackColor = libwpg::WPGColor(0xff,0xff,0xff);
307
308
13.3k
  m_style.insert("svg:stroke-color", m_penForeColor.getColorString());
309
13.3k
  m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT);
310
13.3k
  m_style.insert("draw:fill-color", m_brushForeColor.getColorString());
311
13.3k
  m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT);
312
313
13.3k
  resetPalette();
314
13.3k
  m_style.insert("draw:fill", "solid");
315
13.3k
}
316
317
bool WPG2Parser::parse()
318
13.3k
{
319
13.3k
  typedef void (WPG2Parser::*Method)();
320
321
13.3k
  struct RecordHandler
322
13.3k
  {
323
13.3k
    int type;
324
13.3k
    const char *name;
325
13.3k
    Method handler;
326
13.3k
  };
327
328
13.3k
  static const struct RecordHandler handlers[] =
329
13.3k
  {
330
13.3k
    { 0x01, "Start WPG",            &WPG2Parser::handleStartWPG },
331
13.3k
    { 0x02, "End WPG",              &WPG2Parser::handleEndWPG },
332
13.3k
    { 0x03, "Form Settings",        &WPG2Parser::handleFormSettings },
333
13.3k
    { 0x04, "Ruler Settings",       nullptr },     // ignored
334
13.3k
    { 0x05, "Grid Settings",        nullptr },     // ignored
335
13.3k
    { 0x06, "Layer",                &WPG2Parser::handleLayer },
336
13.3k
    { 0x08, "Pen Style Definition", &WPG2Parser::handlePenStyleDefinition },
337
13.3k
    { 0x09, "Pattern Definition",   &WPG2Parser::handlePatternDefinition },
338
13.3k
    { 0x0a, "Comment",              nullptr },     // ignored
339
13.3k
    { 0x0b, "Color Transfer",       nullptr },
340
13.3k
    { 0x0c, "Color Palette",        &WPG2Parser::handleColorPalette },
341
13.3k
    { 0x0d, "DP Color Palette",     &WPG2Parser::handleDPColorPalette },
342
13.3k
    { 0x0e, "Bitmap Data",          &WPG2Parser::handleBitmapData },
343
13.3k
    { 0x0f, "Text Data",            &WPG2Parser::handleTextData },
344
13.3k
    { 0x10, "Chart Style",          nullptr },     // ignored
345
13.3k
    { 0x11, "Chart Data",           nullptr },     // ignored
346
13.3k
    { 0x12, "Object Image",         &WPG2Parser::handleObjectImage },
347
13.3k
    { 0x15, "Polyline",             &WPG2Parser::handlePolyline },
348
13.3k
    { 0x16, "Polyspline",           &WPG2Parser::handlePolyspline },
349
13.3k
    { 0x17, "Polycurve",            &WPG2Parser::handlePolycurve },
350
13.3k
    { 0x18, "Rectangle",            &WPG2Parser::handleRectangle },
351
13.3k
    { 0x19, "Arc",                  &WPG2Parser::handleArc },
352
13.3k
    { 0x1a, "Compound Polygon",     &WPG2Parser::handleCompoundPolygon },
353
13.3k
    { 0x1b, "Bitmap",               &WPG2Parser::handleBitmap },
354
13.3k
    { 0x1c, "Text Line",            &WPG2Parser::handleTextLine },
355
13.3k
    { 0x1d, "Text Block",           &WPG2Parser::handleTextBlock },
356
13.3k
    { 0x1e, "Text Path",            &WPG2Parser::handleTextPath },
357
13.3k
    { 0x1f, "Chart",                nullptr },
358
13.3k
    { 0x20, "Group",                nullptr },
359
13.3k
    { 0x21, "Object Capsule",       &WPG2Parser::handleObjectCapsule },
360
13.3k
    { 0x22, "Font Settings",        nullptr },
361
13.3k
    { 0x25, "Pen Fore Color",       &WPG2Parser::handlePenForeColor },
362
13.3k
    { 0x26, "DP Pen Fore Color",    &WPG2Parser::handleDPPenForeColor },
363
13.3k
    { 0x27, "Pen Back Color",       &WPG2Parser::handlePenBackColor },
364
13.3k
    { 0x28, "DP Pen Back Color",    &WPG2Parser::handleDPPenBackColor },
365
13.3k
    { 0x29, "Pen Style",            &WPG2Parser::handlePenStyle },
366
13.3k
    { 0x2a, "Pen Pattern",          nullptr },
367
13.3k
    { 0x2b, "Pen Size",             &WPG2Parser::handlePenSize },
368
13.3k
    { 0x2c, "DP Pen Size",          &WPG2Parser::handleDPPenSize  },
369
13.3k
    { 0x2d, "Line Cap",             &WPG2Parser::handleLineCap },
370
13.3k
    { 0x2e, "Line Join",            &WPG2Parser::handleLineJoin },
371
13.3k
    { 0x2f, "Brush Gradient",       &WPG2Parser::handleBrushGradient },
372
13.3k
    { 0x30, "DP Brush Gradient",    &WPG2Parser::handleDPBrushGradient },
373
13.3k
    { 0x31, "Brush Fore Color",     &WPG2Parser::handleBrushForeColor },
374
13.3k
    { 0x32, "DP Brush Fore Color",  &WPG2Parser::handleDPBrushForeColor },
375
13.3k
    { 0x33, "Brush Back Color",     &WPG2Parser::handleBrushBackColor },
376
13.3k
    { 0x34, "DP Brush Back Color",  &WPG2Parser::handleDPBrushBackColor },
377
13.3k
    { 0x35, "Brush Pattern",        &WPG2Parser::handleBrushPattern },
378
13.3k
    { 0x36, "Horizontal Line",      nullptr },
379
13.3k
    { 0x37, "Vertical Line",        nullptr },
380
13.3k
    { 0x38, "Poster Settings",      nullptr },
381
13.3k
    { 0x39, "Image State",          nullptr },
382
13.3k
    { 0x3a, "Envelope Definition",  nullptr },
383
13.3k
    { 0x3b, "Envelope",             nullptr },
384
13.3k
    { 0x3c, "Texture Definition",   nullptr },
385
13.3k
    { 0x3d, "Brush Texture",        nullptr },
386
13.3k
    { 0x3e, "Texture Alignment",    nullptr },
387
13.3k
    { 0x3f, "Pen Texture ",         nullptr },
388
13.3k
    { 0x00, nullptr, nullptr } // end marker
389
13.3k
  };
390
391
680k
  while (!m_input->isEnd())
392
668k
  {
393
#ifdef DEBUG
394
    long recordPos = m_input->tell();
395
#endif
396
668k
    readU8();
397
668k
    int recordType = readU8();
398
668k
    if (recordType == 0 || recordType > (int)0x3f)
399
1.26k
      break;
400
666k
    auto extension = (int) readVariableLengthInteger();
401
666k
    unsigned int recordLength = readVariableLengthInteger();
402
666k
    const unsigned long maxLength = getRemainingLength(m_input);
403
666k
    if (recordLength > maxLength)
404
11.1k
      recordLength = static_cast<unsigned int>(maxLength);
405
666k
    if (recordLength > static_cast<unsigned int>(std::numeric_limits<int>::max()))
406
0
    {
407
0
      WPG_DEBUG_MSG(("record length %u is bigger than max int, clamping\n", recordLength));
408
0
      recordLength = std::numeric_limits<int>::max();
409
0
    }
410
666k
    m_recordLength = int(recordLength);
411
666k
    m_recordEnd = m_input->tell() + m_recordLength - 1;
412
413
    // inside a subgroup, one less sub record
414
666k
    if (!m_groupStack.empty())
415
638k
      m_groupStack.top().subIndex--;
416
417
    // search function to handler this record
418
666k
    int index = -1;
419
10.3M
    for (int i = 0; (index < 0) && handlers[i].name; i++)
420
9.68M
      if (handlers[i].type == recordType)
421
666k
        index = i;
422
423
666k
    WPG_DEBUG_MSG(("\n"));
424
666k
    if (index < 0)
425
710
    {
426
710
      WPG_DEBUG_MSG(("Unknown record type 0x%02x at %li  size %d  extension %d\n",
427
710
                     recordType, recordPos, m_recordLength, extension));
428
710
    }
429
666k
    else
430
666k
    {
431
666k
      Method recordHandler = handlers[index].handler;
432
433
666k
      if (!recordHandler)
434
68.8k
        WPG_DEBUG_MSG(("Record '%s' (ignored) type 0x%02x at %li  size %d  extension %d\n",
435
68.8k
                       handlers[index].name, recordType, recordPos, m_recordLength, extension));
436
597k
      else
437
597k
      {
438
597k
        WPG_DEBUG_MSG(("Record '%s' type 0x%02x at %li  size %d  extension %d\n",
439
597k
                       handlers[index].name, recordType, recordPos, m_recordLength, extension));
440
441
        // invoke the handler for this record
442
597k
        (this->*recordHandler)();
443
597k
      }
444
666k
    }
445
446
    // the last subgroup
447
666k
    if (!m_groupStack.empty())
448
638k
    {
449
638k
      WPGGroupContext &context = m_groupStack.top();
450
638k
      if (context.subIndex == 0)
451
73.0k
      {
452
73.0k
        if (context.isCompoundPolygon())
453
11.0k
          flushCompoundPolygon();
454
73.0k
        m_groupStack.pop();
455
73.0k
      }
456
638k
    }
457
458
    // we enter another subgroup, save the context to stack
459
666k
    if (extension > 0)
460
590k
    {
461
590k
      WPGGroupContext context;
462
590k
      context.parentType = recordType;
463
590k
      context.subIndex = (unsigned int) extension;
464
590k
      if (context.isCompoundPolygon())
465
11.7k
      {
466
11.7k
        context.compoundMatrix = m_compoundMatrix;
467
11.7k
        context.compoundFilled = m_compoundFilled;
468
11.7k
        context.compoundFramed = m_compoundFramed;
469
11.7k
        context.compoundClosed = m_compoundClosed;
470
11.7k
      }
471
590k
      m_groupStack.push(context);
472
590k
    }
473
474
    //if(m_input->tell() > m_recordEnd+1)
475
666k
    {
476
      //WPG_DEBUG_MSG(("Record 0x%x consumes more bytes than necessary!\n", recordType));
477
666k
      WPG_DEBUG_MSG(("Current stream position: %li\n", m_input->tell()));
478
666k
    }
479
480
666k
    if (m_exit) break;
481
482
666k
    m_input->seek(m_recordEnd+1, librevenge::RVNG_SEEK_SET);
483
666k
  }
484
485
13.3k
  if (!m_exit)
486
13.1k
    handleEndWPG();
487
488
13.3k
  return m_success;
489
13.3k
}
490
491
#ifdef DEBUG
492
static const char *describePrecision(unsigned char precision)
493
{
494
  const char *result = "Unknown";
495
  switch (precision)
496
  {
497
  case 0:
498
    result = "single";
499
    break;
500
  case 1:
501
    result = "double";
502
    break;
503
  default:
504
    break;
505
  }
506
  return result;
507
}
508
509
static const char *describeGradient(unsigned char gradientType)
510
{
511
  const char *result = "Unknown";
512
  switch (gradientType)
513
  {
514
  case 0:
515
    result = "None";
516
    break;
517
  case 1:
518
    result = "Linear";
519
    break;
520
  case 2:
521
    result = "Polygonal";
522
    break;
523
  case 3:
524
    result = "Concentric Circles";
525
    break;
526
  case 4:
527
    result = "Convergent Circles";
528
    break;
529
  case 5:
530
    result = "Concentric Ellipses";
531
    break;
532
  case 6:
533
    result = "Convergent Ellipses";
534
    break;
535
  case 7:
536
    result = "Concentric Squares";
537
    break;
538
  case 8:
539
    result = "Convergent Squares";
540
    break;
541
  case 9:
542
    result = "Concentric Rectangles";
543
    break;
544
  case 10:
545
    result = "Convergent Rectangles";
546
    break;
547
  default:
548
    break;
549
  }
550
  return result;
551
}
552
#endif
553
554
void WPG2Parser::handleStartWPG()
555
13.1k
{
556
13.1k
  if (m_graphicsStarted) // second start wpg in the document == possible corruption, bail out
557
102
  {
558
102
    handleEndWPG();
559
102
    return;
560
102
  }
561
562
13.0k
  unsigned int horizontalUnit = readU16();
563
13.0k
  unsigned int verticalUnit = readU16();
564
13.0k
  unsigned char precision = readU8();
565
566
  // sanity check
567
13.0k
  m_xres = horizontalUnit;
568
13.0k
  m_yres = verticalUnit;
569
13.0k
  if ((horizontalUnit==0) || (verticalUnit==0))
570
8.61k
  {
571
8.61k
    m_xres = m_yres = 1200;
572
8.61k
    WPG_DEBUG_MSG(("Warning ! Insane unit of measure"));
573
8.61k
  }
574
575
  // danger if we do not recognize the precision code
576
13.0k
  if (precision != 0 && precision != 1)
577
16
  {
578
16
    m_success = false;
579
16
    m_exit = true;
580
16
    return;
581
16
  }
582
13.0k
  m_doublePrecision = (precision == 1);
583
584
#ifdef DEBUG
585
  long viewportX1 = (m_doublePrecision) ? readS32() : readS16();
586
  long viewportY1 = (m_doublePrecision) ? readS32() : readS16();
587
  long viewportX2 = (m_doublePrecision) ? readS32() : readS16();
588
  long viewportY2 = (m_doublePrecision) ? readS32() : readS16();
589
#else
590
13.0k
  m_input->seek(((m_doublePrecision) ? 16 : 8), librevenge::RVNG_SEEK_CUR);
591
13.0k
#endif
592
13.0k
  long imageX1 = (m_doublePrecision) ? readS32() : readS16();
593
13.0k
  long imageY1 = (m_doublePrecision) ? readS32() : readS16();
594
13.0k
  long imageX2 = (m_doublePrecision) ? readS32() : readS16();
595
13.0k
  long imageY2 = (m_doublePrecision) ? readS32() : readS16();
596
597
  // used to adjust coordinates
598
13.0k
  m_xofs = (imageX1 < imageX2) ? imageX1 : imageX2;
599
13.0k
  m_yofs = (imageY1 < imageY2) ? imageY1 : imageX2;
600
13.0k
  m_width = (imageX2 > imageX1) ? imageX2-imageX1 : imageX1-imageX2;
601
13.0k
  m_height = (imageY2 > imageY1) ? imageY2-imageY1 : imageY1-imageY2;
602
603
13.0k
  WPG_DEBUG_MSG(("StartWPG 2\n"));
604
13.0k
  WPG_DEBUG_MSG(("  Horizontal unit of measure : %d pixels/inch\n", (int) horizontalUnit));
605
13.0k
  WPG_DEBUG_MSG(("    Vertical unit of measure : %d pixels/inch\n", (int) verticalUnit));
606
13.0k
  WPG_DEBUG_MSG(("              Data precision : %d (%s)\n", precision, describePrecision(precision)));
607
13.0k
  WPG_DEBUG_MSG(("                 Viewport X1 : %li\n", viewportX1));
608
13.0k
  WPG_DEBUG_MSG(("                 Viewport Y1 : %li\n", viewportY1));
609
13.0k
  WPG_DEBUG_MSG(("                 Viewport X2 : %li\n", viewportX2));
610
13.0k
  WPG_DEBUG_MSG(("                 Viewport Y2 : %li\n", viewportY2));
611
13.0k
  WPG_DEBUG_MSG(("                    Image X1 : %li\n", imageX1));
612
13.0k
  WPG_DEBUG_MSG(("                    Image Y1 : %li\n", imageY1));
613
13.0k
  WPG_DEBUG_MSG(("                    Image X2 : %li\n", imageX2));
614
13.0k
  WPG_DEBUG_MSG(("                    Image Y2 : %li\n", imageY2));
615
13.0k
  WPG_DEBUG_MSG(("                    X offset : %li\n", m_xofs));
616
13.0k
  WPG_DEBUG_MSG(("                    Y offset : %li\n", m_yofs));
617
13.0k
  WPG_DEBUG_MSG(("                       width : %li\n", m_width));
618
13.0k
  WPG_DEBUG_MSG(("                      height : %li\n", m_height));
619
620
13.0k
  librevenge::RVNGPropertyList propList;
621
13.0k
  propList.insert("svg:width", ((toDouble(m_width)) / m_xres));
622
13.0k
  propList.insert("svg:height", ((toDouble(m_height)) / m_yres));
623
624
13.0k
  m_painter->startDocument(librevenge::RVNGPropertyList());
625
13.0k
  m_painter->startPage(propList);
626
627
13.0k
  static const int WPG2_defaultPenDashes[] =
628
13.0k
  {
629
13.0k
    1,   291,  0,                            // style #0 (actually solid)
630
13.0k
    1,   218, 73,                            // style #1
631
13.0k
    1,   145, 73,                            // style #2
632
13.0k
    1,    73, 73,                            // style #3
633
13.0k
    1,    36, 36,                            // style #4
634
13.0k
    1,    18, 18,                            // style #5
635
13.0k
    1,    18, 55,                            // style #6
636
13.0k
    3,    18, 55,  18, 55, 18, 127,          // style #7
637
13.0k
    2,   164, 55,  18, 55,                   // style #8
638
13.0k
    3,   145, 36,  18, 36, 18,  36,          // style #9
639
13.0k
    3,    91, 55,  91, 55, 18,  55,          // style #10
640
13.0k
    4,    91, 36,  91, 36, 18,  36, 18, 36,  // style #11
641
13.0k
    2,   182, 73,  73, 73,                   // style #12
642
13.0k
    3,   182, 36,  55, 36, 55,  36,          // style #13
643
13.0k
    3,   255, 73, 266, 73, 73,  73,          // style #14
644
13.0k
    4,   273, 36, 273, 36, 55,  36, 55, 36   // style #15
645
13.0k
  };
646
647
  // create default pen styles
648
13.0k
  size_t styleNo = 0;
649
221k
  for (size_t i = 0; i < (sizeof(WPG2_defaultPenDashes)/sizeof(WPG2_defaultPenDashes[0]));)
650
208k
  {
651
208k
    size_t segments = 2 * WPG2_defaultPenDashes[i++];
652
208k
    libwpg::WPGDashArray dashArray;
653
1.09M
    for (size_t j = 0; j < segments; j++, i++)
654
885k
      dashArray.add(WPG2_defaultPenDashes[i]*3.6/218.0);
655
208k
    m_dashArrayStyles[styleNo] = dashArray;
656
208k
    styleNo++;
657
208k
  }
658
13.0k
  m_graphicsStarted = true;
659
13.0k
}
660
661
void WPG2Parser::handleEndWPG()
662
13.8k
{
663
13.8k
  if (!m_graphicsStarted)
664
787
    return;
665
  // sentinel
666
13.0k
  if (m_layerOpened)
667
87
    m_painter->endLayer();
668
669
13.0k
  m_painter->endPage();
670
13.0k
  m_painter->endDocument();
671
13.0k
  m_exit = true;
672
13.0k
}
673
674
void WPG2Parser::handleFormSettings()
675
1.57k
{
676
#ifdef DEBUG
677
  unsigned int w = (m_doublePrecision) ? readU32() : readU16();
678
  unsigned int h = (m_doublePrecision) ? readU32() : readU16();
679
  double width = (toDouble(w)) / m_xres;
680
  double height = (toDouble(h)) / m_yres;
681
  m_input->seek(((m_doublePrecision) ? 4 : 2), librevenge::RVNG_SEEK_CUR);
682
  unsigned int ml = (m_doublePrecision) ? readU32() : readU16();
683
  unsigned int mr = (m_doublePrecision) ? readU32() : readU16();
684
  unsigned int mt = (m_doublePrecision) ? readU32() : readU16();
685
  unsigned int mb = (m_doublePrecision) ? readU32() : readU16();
686
  double margL = (toDouble(ml)) / m_xres;
687
  double margR = (toDouble(mr)) / m_xres;
688
  double margT = (toDouble(mt)) / m_xres;
689
  double margB = (toDouble(mb)) / m_xres;
690
691
  WPG_DEBUG_MSG(("Form Settings: width: %f height : %f\n", width, height));
692
  WPG_DEBUG_MSG(("Form Margins:  left: %f right : %f top: %f bottom: %f\n", margL, margR, margT, margB));
693
#endif
694
1.57k
}
695
696
void WPG2Parser::handleLayer()
697
259k
{
698
259k
  if (!m_graphicsStarted)
699
221
    return;
700
259k
  librevenge::RVNGPropertyList propList;
701
259k
  propList.insert("svg:id", (int)readU16());
702
703
  // close previous one
704
259k
  if (m_layerOpened)
705
259k
    m_painter->endLayer();
706
707
259k
  m_painter->startLayer(propList);
708
259k
  m_layerOpened = true;
709
710
259k
  WPG_DEBUG_MSG(("  Layer Id: %d\n", (int) m_layerId));
711
259k
}
712
713
void WPG2Parser::handleCompoundPolygon()
714
13.8k
{
715
13.8k
  if (!m_graphicsStarted)
716
706
    return;
717
13.1k
  ObjectCharacterization objCh;
718
13.1k
  parseCharacterization(&objCh);
719
720
13.1k
  m_compoundWindingRule = objCh.windingRule;
721
13.1k
  m_compoundMatrix = objCh.matrix;
722
13.1k
  m_compoundFilled = objCh.filled;
723
13.1k
  m_compoundFramed = objCh.framed;
724
13.1k
  m_compoundClosed = objCh.closed;
725
13.1k
}
726
727
void WPG2Parser::flushCompoundPolygon()
728
11.0k
{
729
11.0k
  if (!m_graphicsStarted)
730
535
    return;
731
10.5k
  WPGGroupContext &context = m_groupStack.top();
732
733
10.5k
  librevenge::RVNGPropertyList tmpStyle = m_style;
734
735
10.5k
  if (!context.compoundFilled)
736
8.36k
    tmpStyle.insert("draw:fill", "none");
737
10.5k
  if (!context.compoundFramed)
738
6.95k
    tmpStyle.insert("draw:stroke", "none");
739
740
10.5k
  if (context.compoundWindingRule)
741
0
    tmpStyle.insert("svg:fill-rule", "nonzero");
742
10.5k
  else
743
10.5k
    tmpStyle.insert("svg:fill-rule", "evenodd");
744
745
10.5k
  if (context.compoundFilled || m_gradient.count())
746
2.48k
    tmpStyle.insert("svg:linearGradient", m_gradient);
747
10.5k
  m_painter->setStyle(tmpStyle);
748
749
10.5k
  if (context.compoundClosed)
750
238
  {
751
238
    librevenge::RVNGPropertyList element;
752
238
    element.insert("librevenge:path-action", "Z");
753
238
    context.compoundPath.append(element);
754
238
  }
755
10.5k
  librevenge::RVNGPropertyList propList;
756
10.5k
  propList.insert("svg:d", context.compoundPath);
757
10.5k
  m_painter->drawPath(propList);
758
10.5k
}
759
760
void WPG2Parser::handlePenStyleDefinition()
761
34.2k
{
762
34.2k
  if (!m_graphicsStarted)
763
390
    return;
764
33.8k
  unsigned int style = readU16();
765
33.8k
  unsigned int segments = readU16();
766
767
33.8k
  const unsigned int maxSegments = getRemainingRecordLength() / (m_doublePrecision ? 4 : 2) / 2;
768
33.8k
  if (segments > maxSegments)
769
31.9k
    segments = maxSegments;
770
771
33.8k
  libwpg::WPGDashArray dashArray;
772
487k
  for (unsigned i = 0; i < segments; i++)
773
453k
  {
774
453k
    unsigned int p = (m_doublePrecision) ? readU32() : readU16();
775
453k
    unsigned int q = (m_doublePrecision) ? readU32() : readU16();
776
453k
    dashArray.add(toDouble(p)*3.6/218.0);
777
453k
    dashArray.add(toDouble(q)*3.6/218.0);
778
453k
  }
779
33.8k
  m_dashArrayStyles[style] = dashArray;
780
781
33.8k
  WPG_DEBUG_MSG(("          Style : %d\n", (int) style));
782
33.8k
  WPG_DEBUG_MSG(("  Segment pairs : %d\n", (int) segments));
783
33.8k
}
784
785
// TODO
786
void WPG2Parser::handlePatternDefinition()
787
1.12k
{
788
1.12k
  if (!m_graphicsStarted)
789
1
    return;
790
1.12k
  WPG_DEBUG_MSG(("PatternDefinition\n"));
791
1.12k
}
792
793
void WPG2Parser::handleColorPalette()
794
617
{
795
617
  if (!m_graphicsStarted)
796
205
    return;
797
412
  unsigned startIndex = readU16();
798
412
  unsigned numEntries = readU16();
799
800
1.95M
  for (unsigned i = 0; i < numEntries; i++)
801
1.95M
  {
802
1.95M
    unsigned char red = readU8();
803
1.95M
    unsigned char green = readU8();
804
1.95M
    unsigned char blue = readU8();
805
1.95M
    unsigned char alpha = 0xff - readU8();
806
1.95M
    libwpg::WPGColor color(red, green, blue, alpha);
807
1.95M
    m_colorPalette[int(startIndex+i)] = color;
808
1.95M
    WPG_DEBUG_MSG(("Index#%d: RGB %s\n", startIndex+i, color.getColorString().cstr()));
809
1.95M
  }
810
412
}
811
812
void WPG2Parser::handleDPColorPalette()
813
11.1k
{
814
11.1k
  if (!m_graphicsStarted)
815
196
    return;
816
10.9k
  unsigned startIndex = readU16();
817
10.9k
  unsigned numEntries = readU16();
818
819
2.10M
  for (unsigned int i = 0; i < numEntries; i++)
820
2.09M
  {
821
2.09M
    unsigned char red = readU16() >> 8 ;
822
2.09M
    unsigned char green = readU16() >> 8 ;
823
2.09M
    unsigned char blue = readU16() >> 8 ;
824
2.09M
    unsigned char alpha = 0xff - (readU16() >> 8) ;
825
2.09M
    libwpg::WPGColor color(red, green, blue, alpha);
826
2.09M
    m_colorPalette[int(startIndex+i)] = color;
827
2.09M
    WPG_DEBUG_MSG(("Index#%d: RGB %s\n", startIndex+i, color.getColorString().cstr()));
828
2.09M
  }
829
10.9k
}
830
831
void WPG2Parser::handlePenForeColor()
832
889
{
833
889
  if (!m_graphicsStarted)
834
219
    return;
835
670
  if (!m_groupStack.empty())
836
469
  {
837
469
    if (m_groupStack.top().isCompoundPolygon())
838
66
      return;
839
403
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
840
129
      return;
841
403
  }
842
475
  unsigned char red = readU8();
843
475
  unsigned char green = readU8();
844
475
  unsigned char blue = readU8();
845
475
  unsigned char alpha = 0xff - readU8();
846
847
475
  m_penForeColor = libwpg::WPGColor(red, green, blue, alpha);
848
849
475
  m_style.insert("svg:stroke-color", m_penForeColor.getColorString());
850
475
  m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT);
851
852
475
  WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
853
475
}
854
855
void WPG2Parser::handleDPPenForeColor()
856
1.34k
{
857
1.34k
  if (!m_graphicsStarted)
858
209
    return;
859
1.13k
  if (!m_groupStack.empty())
860
788
  {
861
788
    if (m_groupStack.top().isCompoundPolygon())
862
69
      return;
863
719
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
864
117
      return;
865
719
  }
866
  // we just ignore the least significant 8 bits
867
947
  unsigned char red = (m_doublePrecision)   ? readU16()>>8 : readU8();
868
947
  unsigned char green = (m_doublePrecision) ? readU16()>>8 : readU8();
869
947
  unsigned char blue = (m_doublePrecision)  ? readU16()>>8 : readU8();
870
947
  unsigned char alpha = 0xff - ((m_doublePrecision) ? readU16()>>8 : readU8());
871
872
947
  m_penForeColor = libwpg::WPGColor(red, green, blue, alpha);
873
874
947
  m_style.insert("svg:stroke-color", m_penForeColor.getColorString());
875
947
  m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT);
876
877
947
  WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
878
947
}
879
880
void WPG2Parser::handlePenBackColor()
881
6.09k
{
882
6.09k
  if (!m_graphicsStarted)
883
232
    return;
884
5.86k
  if (!m_groupStack.empty() && m_groupStack.top().isCompoundPolygon())
885
573
    return;
886
887
5.29k
  unsigned char red = readU8();
888
5.29k
  unsigned char green = readU8();
889
5.29k
  unsigned char blue = readU8();
890
5.29k
  unsigned char alpha = 0xff - readU8();
891
892
5.29k
  m_penBackColor = libwpg::WPGColor(red, green, blue, alpha);
893
894
5.29k
  m_style.insert("svg:stroke-color", m_penForeColor.getColorString());
895
5.29k
  m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT);
896
897
5.29k
  WPG_DEBUG_MSG(("   Background color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
898
5.29k
}
899
900
void WPG2Parser::handleDPPenBackColor()
901
3.43k
{
902
3.43k
  if (!m_graphicsStarted)
903
311
    return;
904
3.11k
  if (!m_groupStack.empty() && m_groupStack.top().isCompoundPolygon())
905
2.40k
    return;
906
907
  // we just ignore the least significant 8 bits
908
710
  unsigned int red = (m_doublePrecision)   ? readU16()>>8 : readU8();
909
710
  unsigned int green = (m_doublePrecision) ? readU16()>>8 : readU8();
910
710
  unsigned int blue = (m_doublePrecision)  ? readU16()>>8 : readU8();
911
710
  unsigned int alpha = 0xff - ((m_doublePrecision) ? readU16()>>8 : readU8());
912
913
710
  m_penBackColor = libwpg::WPGColor((int) red, (int) green, (int) blue, (int) alpha);
914
915
710
  m_style.insert("svg:stroke-color", m_penForeColor.getColorString());
916
710
  m_style.insert("svg:stroke-opacity", m_penForeColor.getOpacity(), librevenge::RVNG_PERCENT);
917
918
710
  WPG_DEBUG_MSG(("   Background color (RGBA): %d %d %d %d\n", (int) red, (int) green, (int) blue, (int) alpha));
919
710
}
920
921
void WPG2Parser::setPenStyle()
922
36.0k
{
923
36.0k
  if (!m_style["draw:stroke"] || m_style["draw:stroke"]->getStr() != "dash")
924
22.8k
    return;
925
13.1k
  {
926
13.1k
    double strokeWidth = m_style["svg:stroke-width"] ? m_style["svg:stroke-width"]->getDouble() : 0.0;
927
13.1k
    m_style.insert("draw:dots1", m_dashArray.getDots1());
928
13.1k
    m_style.insert("draw:dots1-length", 72.0*72.0*strokeWidth*(m_dashArray.getDots1Length()), librevenge::RVNG_POINT);
929
13.1k
    m_style.insert("draw:dots2", m_dashArray.getDots2());
930
13.1k
    m_style.insert("draw:dots2-length", 72.0*72.0*strokeWidth*(m_dashArray.getDots2Length()), librevenge::RVNG_POINT);
931
13.1k
    m_style.insert("draw:distance", 72.0*72.0*strokeWidth*(m_dashArray.getDistance()), librevenge::RVNG_POINT);
932
13.1k
  }
933
13.1k
}
934
935
void WPG2Parser::handlePenStyle()
936
37.8k
{
937
37.8k
  if (!m_graphicsStarted)
938
283
    return;
939
37.5k
  if (!m_groupStack.empty())
940
37.3k
  {
941
37.3k
    if (m_groupStack.top().isCompoundPolygon())
942
1.01k
      return;
943
36.2k
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
944
461
      return;
945
36.2k
  }
946
36.0k
  unsigned int style = readU16();
947
948
36.0k
  m_dashArray = m_dashArrayStyles[style];
949
950
36.0k
  if (!m_dashArray.getDots1() || !m_dashArray.getDots2())
951
22.8k
    m_style.insert("draw:stroke", "solid");
952
13.1k
  else
953
13.1k
    m_style.insert("draw:stroke", "dash");
954
955
36.0k
  setPenStyle();
956
957
36.0k
  WPG_DEBUG_MSG(("   Pen style : %d\n", (int) style));
958
36.0k
}
959
960
void WPG2Parser::handlePenSize()
961
9.09k
{
962
9.09k
  if (!m_graphicsStarted)
963
225
    return;
964
8.87k
  if (!m_groupStack.empty())
965
8.69k
  {
966
8.69k
    if (m_groupStack.top().isCompoundPolygon())
967
423
      return;
968
8.27k
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
969
147
      return;
970
8.27k
  }
971
8.30k
  unsigned int width = readU16();
972
973
8.30k
  m_style.insert("svg:stroke-width", (toDouble(width) / m_xres));
974
975
8.30k
  WPG_DEBUG_MSG(("   Width: %d\n", (int) width));
976
8.30k
}
977
978
void WPG2Parser::handleDPPenSize()
979
9.32k
{
980
9.32k
  if (!m_graphicsStarted)
981
279
    return;
982
9.04k
  if (!m_groupStack.empty())
983
8.45k
  {
984
8.45k
    if (m_groupStack.top().isCompoundPolygon())
985
230
      return;
986
8.22k
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
987
138
      return;
988
8.22k
  }
989
8.67k
  unsigned long width = readU32();
990
991
8.67k
  m_style.insert("svg:stroke-width", toDouble(width) / m_xres / 256);
992
//  m_pen.height = toDouble(height) / m_yres / 256;
993
994
8.67k
  WPG_DEBUG_MSG(("   Width: %li\n", (long) width));
995
8.67k
}
996
997
void WPG2Parser::handleLineCap()
998
306
{
999
306
  if (!m_graphicsStarted)
1000
135
    return;
1001
171
  if (!m_groupStack.empty())
1002
169
  {
1003
169
    if (m_groupStack.top().isCompoundPolygon())
1004
1
      return;
1005
168
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
1006
9
      return;
1007
168
  }
1008
//  WPG_DEBUG_MSG(("   Line cap : %d\n", style));
1009
171
}
1010
1011
void WPG2Parser::handleLineJoin()
1012
274
{
1013
274
  if (!m_graphicsStarted)
1014
255
    return;
1015
19
  if (!m_groupStack.empty())
1016
19
  {
1017
19
    if (m_groupStack.top().isCompoundPolygon())
1018
0
      return;
1019
19
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
1020
4
      return;
1021
19
  }
1022
//  WPG_DEBUG_MSG(("   Line join : %d\n", style));
1023
19
}
1024
1025
void WPG2Parser::handleBrushGradient()
1026
2.77k
{
1027
2.77k
  if (!m_graphicsStarted)
1028
365
    return;
1029
2.41k
  if (!m_groupStack.empty())
1030
1.90k
  {
1031
1.90k
    if (m_groupStack.top().isCompoundPolygon())
1032
341
      return;
1033
1.56k
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
1034
388
      return;
1035
1.56k
  }
1036
1.68k
  unsigned angleFraction = readU16();
1037
1.68k
  unsigned angleInteger = readU16();
1038
1.68k
  unsigned xref = readU16();
1039
1.68k
  unsigned yref = readU16();
1040
#ifdef DEBUG
1041
  unsigned flag = readU16();
1042
  bool granular = flag & (1<<6);
1043
  bool anchor = flag & (1<<7);
1044
#else
1045
1.68k
  readU16();
1046
1.68k
#endif
1047
1048
  // TODO: get gradient extent
1049
1050
1.68k
  m_gradientAngle = angleInteger + (double)angleFraction/65536.0;
1051
1.68k
  m_gradientRef.insert("svg:cx", (double)xref);
1052
1.68k
  m_gradientRef.insert("svg:cy", (double)yref);
1053
1054
1.68k
  WPG_DEBUG_MSG(("       Gradient angle : %d.%d\n", (int) angleInteger, (int) angleFraction));
1055
1.68k
  WPG_DEBUG_MSG(("   Gradient reference : %d.%d\n", (int) xref, (int) yref));
1056
1.68k
  WPG_DEBUG_MSG(("   Granular : %s\n", (granular ? "yes" : "no")));
1057
1.68k
  WPG_DEBUG_MSG(("   Anchored : %s\n", (anchor ? "yes" : "no")));
1058
1.68k
}
1059
1060
void WPG2Parser::handleDPBrushGradient()
1061
6.86k
{
1062
6.86k
  if (!m_graphicsStarted)
1063
511
    return;
1064
6.35k
  if (!m_groupStack.empty())
1065
5.29k
  {
1066
5.29k
    if (m_groupStack.top().isCompoundPolygon())
1067
716
      return;
1068
4.58k
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
1069
717
      return;
1070
4.58k
  }
1071
4.92k
  unsigned angleFraction = readU16();
1072
4.92k
  unsigned angleInteger = readU16();
1073
4.92k
  unsigned xref = readU16();
1074
4.92k
  unsigned yref = readU16();
1075
#ifdef DEBUG
1076
  unsigned flag = readU16();
1077
  bool granular = flag & (1<<6);
1078
  bool anchor = flag & (1<<7);
1079
#else
1080
4.92k
  readU16();
1081
4.92k
#endif
1082
1083
  // TODO: get gradient extent (in double precision)
1084
1085
4.92k
  m_gradientAngle = angleFraction + (double)angleInteger/65536.0;
1086
4.92k
  m_gradientRef.insert("svg:cx", (double)xref);
1087
4.92k
  m_gradientRef.insert("svg:cy", (double)yref);
1088
1089
4.92k
  WPG_DEBUG_MSG(("       Gradient angle : %d.%d\n", (int) angleInteger, (int) angleFraction));
1090
4.92k
  WPG_DEBUG_MSG(("   Gradient reference : %d.%d\n", (int) xref, (int) yref));
1091
4.92k
  WPG_DEBUG_MSG(("   Granular : %s\n", (granular ? "yes" : "no")));
1092
4.92k
  WPG_DEBUG_MSG(("   Anchored : %s\n", (anchor ? "yes" : "no")));
1093
4.92k
}
1094
1095
void WPG2Parser::handleBrushForeColor()
1096
11.7k
{
1097
11.7k
  if (!m_graphicsStarted)
1098
1.24k
    return;
1099
10.5k
  if (!m_groupStack.empty())
1100
8.76k
  {
1101
8.76k
    if (m_groupStack.top().isCompoundPolygon())
1102
1.53k
      return;
1103
7.22k
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
1104
1.48k
      return;
1105
7.22k
  }
1106
7.53k
  unsigned char gradientType = readU8();
1107
7.53k
  WPG_DEBUG_MSG(("   Gradient type : %d (%s)\n", gradientType, describeGradient(gradientType)));
1108
1109
7.53k
  if (gradientType == 0)
1110
5.43k
  {
1111
5.43k
    unsigned char red = readU8();
1112
5.43k
    unsigned char green = readU8();
1113
5.43k
    unsigned char blue = readU8();
1114
5.43k
    unsigned char alpha = 0xff - readU8();
1115
5.43k
    WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
1116
1117
5.43k
    m_brushForeColor = libwpg::WPGColor(red, green, blue, alpha);
1118
1119
5.43k
    m_style.insert("draw:fill-color", m_brushForeColor.getColorString());
1120
5.43k
    m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT);
1121
1122
5.43k
    if (!m_style["draw:fill"] || m_style["draw:fill"]->getStr() != "gradient")
1123
5.18k
      m_style.insert("draw:fill", "solid");
1124
5.43k
  }
1125
2.09k
  else
1126
2.09k
  {
1127
2.09k
    unsigned count = readU16();
1128
2.09k
    std::vector<libwpg::WPGColor> colors;
1129
2.09k
    std::vector<double> positions;
1130
2.09k
    WPG_DEBUG_MSG(("  Gradient colors : %d\n", (int) count));
1131
1132
2.09k
    if (count > 0)
1133
2.04k
    {
1134
9.11M
      for (unsigned i = 0; i < count; i++)
1135
9.11M
      {
1136
9.11M
        unsigned char red = readU8();
1137
9.11M
        unsigned char green = readU8();
1138
9.11M
        unsigned char blue = readU8();
1139
9.11M
        unsigned char alpha = 0xff - readU8();
1140
9.11M
        libwpg::WPGColor color(red, green, blue, alpha);
1141
9.11M
        colors.push_back(color);
1142
9.11M
        WPG_DEBUG_MSG(("   Color #%d (RGBA): %d %d %d %d\n", i+1, red, green, blue, alpha));
1143
9.11M
      }
1144
1145
9.11M
      for (unsigned j = 0; j < count-1; j++)
1146
9.11M
      {
1147
9.11M
        unsigned pos = readU16();
1148
9.11M
        positions.push_back(toDouble(pos));
1149
9.11M
        WPG_DEBUG_MSG(("   Position #%d : %d\n", j+1, (int) pos));
1150
9.11M
      }
1151
2.04k
    }
1152
1153
    // looks like Corel Presentations only create 2 colors gradient
1154
    // and they are actually in reverse order
1155
2.09k
    if (count == 2)
1156
717
    {
1157
717
      const int cx = m_gradientRef["svg:cx"] ? m_gradientRef["svg:cx"]->getInt() : 65535;
1158
717
      const int cy = m_gradientRef["svg:cy"] ? m_gradientRef["svg:cy"]->getInt() : 65535;
1159
717
      double xref = double(cx) / 65536.0;
1160
717
      double yref = double(cy) / 65536.0;
1161
717
      double angle = m_gradientAngle*M_PI/180.0;
1162
717
      double tanangle = tan(angle);
1163
717
      double ref = (tanangle < 1e2 && tanangle > -1e2) ? (yref+xref*tanangle)/(1+tanangle) : xref;
1164
717
      librevenge::RVNGPropertyListVector gradient;
1165
717
      m_style.insert("draw:angle", (int)(-m_gradientAngle)); // upside down
1166
717
      librevenge::RVNGPropertyList propList;
1167
717
      propList.insert("svg:offset", 0.0, librevenge::RVNG_PERCENT);
1168
717
      propList.insert("svg:stop-color", colors[1].getColorString());
1169
717
      propList.insert("svg:stop-opacity", colors[1].getOpacity(), librevenge::RVNG_PERCENT);
1170
717
      gradient.append(propList);
1171
717
      propList.clear();
1172
717
      propList.insert("svg:offset", ref, librevenge::RVNG_PERCENT);
1173
717
      propList.insert("svg:stop-color", colors[0].getColorString());
1174
717
      propList.insert("svg:stop-opacity", colors[0].getOpacity(), librevenge::RVNG_PERCENT);
1175
717
      gradient.append(propList);
1176
717
      propList.clear();
1177
717
      if ((cx != 65535) && (cy != 65535))
1178
341
      {
1179
341
        propList.insert("svg:offset", 1.0, librevenge::RVNG_PERCENT);
1180
341
        propList.insert("svg:stop-color", colors[1].getColorString());
1181
341
        propList.insert("svg:stop-opacity", colors[1].getOpacity(), librevenge::RVNG_PERCENT);
1182
341
        gradient.append(propList);
1183
341
      }
1184
717
      m_gradient = gradient;
1185
717
      m_style.insert("draw:fill", "gradient");
1186
717
    }
1187
2.09k
  }
1188
7.53k
}
1189
1190
void WPG2Parser::handleDPBrushForeColor()
1191
6.48k
{
1192
6.48k
  if (!m_graphicsStarted)
1193
759
    return;
1194
5.72k
  if (!m_groupStack.empty())
1195
4.86k
  {
1196
4.86k
    if (m_groupStack.top().isCompoundPolygon())
1197
626
      return;
1198
4.24k
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
1199
847
      return;
1200
4.24k
  }
1201
4.25k
  unsigned char gradientType = readU8();
1202
4.25k
  WPG_DEBUG_MSG(("   Gradient type : %d (%s)\n", gradientType, describeGradient(gradientType)));
1203
1204
4.25k
  if (gradientType == 0)
1205
2.74k
  {
1206
2.74k
    unsigned char red = (m_doublePrecision)   ? readU16()>>8 : readU8();
1207
2.74k
    unsigned char green = (m_doublePrecision)   ? readU16()>>8 : readU8();
1208
2.74k
    unsigned char blue = (m_doublePrecision)   ? readU16()>>8 : readU8();
1209
2.74k
    unsigned char alpha = 0xff - ((m_doublePrecision)   ? readU16()>>8 : readU8());
1210
2.74k
    WPG_DEBUG_MSG(("   Foreground color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
1211
1212
2.74k
    m_brushForeColor = libwpg::WPGColor(red, green, blue, alpha);
1213
1214
2.74k
    m_style.insert("draw:fill-color", m_brushForeColor.getColorString());
1215
2.74k
    m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT);
1216
1217
2.74k
    if (!m_style["draw:fill"] || m_style["draw:fill"]->getStr() != "none")
1218
2.74k
      m_style.insert("draw:fill", "solid");
1219
2.74k
  }
1220
1.50k
  else
1221
1.50k
  {
1222
1.50k
    unsigned count = readU16();
1223
1.50k
    std::vector<libwpg::WPGColor> colors;
1224
1.50k
    std::vector<double> positions;
1225
1.50k
    WPG_DEBUG_MSG(("  Gradient colors : %d\n", (int) count));
1226
1227
1.50k
    if (count > 0)
1228
1.39k
    {
1229
2.36M
      for (unsigned i = 0; i < count; i++)
1230
2.36M
      {
1231
2.36M
        unsigned char red = (m_doublePrecision)   ? readU16()>>8 : readU8();
1232
2.36M
        unsigned char green = (m_doublePrecision)   ? readU16()>>8 : readU8();
1233
2.36M
        unsigned char blue = (m_doublePrecision)   ? readU16()>>8 : readU8();
1234
2.36M
        unsigned char alpha = 0xff - ((m_doublePrecision)   ? readU16()>>8 : readU8());
1235
2.36M
        libwpg::WPGColor color(red, green, blue, alpha);
1236
2.36M
        colors.push_back(color);
1237
2.36M
        WPG_DEBUG_MSG(("   Color #%d (RGBA): %d %d %d %d\n", i+1, red, green, blue, alpha));
1238
2.36M
      }
1239
1240
2.36M
      for (unsigned j = 0; j < count-1; j++)
1241
2.36M
      {
1242
2.36M
        unsigned pos = readU16();
1243
2.36M
        positions.push_back(toDouble(pos));
1244
2.36M
        WPG_DEBUG_MSG(("   Position #%d : %d\n", j+1, (int) pos));
1245
2.36M
      }
1246
1.39k
    }
1247
1248
    // looks like Corel Presentations only create 2 colors gradient
1249
    // and they are actually in reverse order
1250
1.50k
    if (count == 2)
1251
905
    {
1252
905
      const int cx = m_gradientRef["svg:cx"] ? m_gradientRef["svg:cx"]->getInt() : 65535;
1253
905
      const int cy = m_gradientRef["svg:cy"] ? m_gradientRef["svg:cy"]->getInt() : 65535;
1254
905
      const double xref = double(cx)/65536.0;
1255
905
      const double yref = double(cy)/65536.0;
1256
905
      double angle = m_gradientAngle*M_PI/180.0;
1257
905
      double tanangle = tan(angle);
1258
905
      double ref = (tanangle<1e2) ? (yref+xref*tanangle)/(1+tanangle) : xref;
1259
905
      librevenge::RVNGPropertyListVector gradient;
1260
905
      m_style.insert("draw:angle", (int)(-m_gradientAngle));
1261
1262
905
      librevenge::RVNGPropertyList propList;
1263
905
      propList.insert("svg:offset", 0.0, librevenge::RVNG_PERCENT);
1264
905
      propList.insert("svg:stop-color", colors[1].getColorString());
1265
905
      propList.insert("svg:stop-opacity", colors[1].getOpacity(), librevenge::RVNG_PERCENT);
1266
905
      gradient.append(propList);
1267
905
      propList.clear();
1268
905
      propList.insert("svg:offset", ref, librevenge::RVNG_PERCENT);
1269
905
      propList.insert("svg:stop-color", colors[0].getColorString());
1270
905
      propList.insert("svg:stop-opacity", colors[0].getOpacity(), librevenge::RVNG_PERCENT);
1271
905
      gradient.append(propList);
1272
905
      propList.clear();
1273
905
      if ((cx != 65535) && (cy != 65535))
1274
413
      {
1275
413
        propList.insert("svg:offset", 1.0, librevenge::RVNG_PERCENT);
1276
413
        propList.insert("svg:stop-color", colors[1].getColorString());
1277
413
        propList.insert("svg:stop-opacity", colors[1].getOpacity(), librevenge::RVNG_PERCENT);
1278
413
        gradient.append(propList);
1279
413
      }
1280
905
      m_gradient = gradient;
1281
905
    }
1282
1.50k
    m_style.insert("draw:fill", "gradient");
1283
1.50k
  }
1284
4.25k
}
1285
1286
void WPG2Parser::handleBrushBackColor()
1287
578
{
1288
578
  if (!m_graphicsStarted)
1289
229
    return;
1290
349
  if (!m_groupStack.empty() && m_groupStack.top().isCompoundPolygon())
1291
5
    return;
1292
344
  unsigned char red = readU8();
1293
344
  unsigned char green = readU8();
1294
344
  unsigned char blue = readU8();
1295
344
  unsigned char alpha = 0xff - readU8();
1296
1297
344
  m_brushBackColor = libwpg::WPGColor(red, green, blue, alpha);
1298
1299
344
  m_style.insert("draw:fill-color", m_brushForeColor.getColorString());
1300
344
  m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT);
1301
1302
344
  if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "none")
1303
0
    m_style.insert("draw:fill", "solid");
1304
1305
344
  WPG_DEBUG_MSG(("   Backround color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
1306
344
}
1307
1308
void WPG2Parser::handleDPBrushBackColor()
1309
879
{
1310
879
  if (!m_graphicsStarted)
1311
321
    return;
1312
558
  if (!m_groupStack.empty() && m_groupStack.top().isCompoundPolygon())
1313
10
    return;
1314
  // we just ignore the least significant 8 bits
1315
548
  unsigned int red = (m_doublePrecision)   ? readU16()>>8 : readU8();
1316
548
  unsigned int green = (m_doublePrecision) ? readU16()>>8 : readU8();
1317
548
  unsigned int blue = (m_doublePrecision)  ? readU16()>>8 : readU8();
1318
548
  unsigned int alpha = 0xff - (m_doublePrecision) ? readU16()>>8 : readU8();
1319
1320
548
  m_brushBackColor = libwpg::WPGColor(red, green, blue, alpha);
1321
1322
548
  m_style.insert("draw:fill-color", m_brushForeColor.getColorString());
1323
548
  m_style.insert("draw:opacity", m_brushForeColor.getOpacity(), librevenge::RVNG_PERCENT);
1324
1325
548
  if (m_style["draw:fill"] && m_style["draw:fill"]->getStr() == "none")
1326
0
    m_style.insert("draw:fill", "solid");
1327
1328
548
  WPG_DEBUG_MSG(("   Background color (RGBA): %d %d %d %d\n", red, green, blue, alpha));
1329
548
}
1330
1331
void WPG2Parser::handleBrushPattern()
1332
329
{
1333
329
  if (!m_graphicsStarted)
1334
10
    return;
1335
319
  if (!m_groupStack.empty())
1336
312
  {
1337
312
    if (m_groupStack.top().isCompoundPolygon())
1338
3
      return;
1339
309
    if (m_groupStack.top().parentType == 0x01) // we don't handle Page Attributes for now
1340
21
      return;
1341
309
  }
1342
#ifdef DEBUG
1343
  unsigned int pattern = readU16();
1344
#endif
1345
1346
  // TODO
1347
1348
295
  WPG_DEBUG_MSG(("   Pattern : %d\n", (int) pattern));
1349
295
}
1350
1351
void WPG2Parser::parseCharacterization(ObjectCharacterization *ch)
1352
123k
{
1353
  // sanity check
1354
123k
  if (!ch) return;
1355
1356
  // identity
1357
123k
  ch->matrix = WPG2TransformMatrix();
1358
1359
123k
  unsigned int flags = readU16();
1360
123k
  ch->taper = (flags & 0x01) != 0;
1361
123k
  ch->translate = (flags & 0x02) != 0;
1362
123k
  ch->skew = (flags & 0x04) != 0;
1363
123k
  ch->scale = (flags & 0x08) != 0;
1364
123k
  ch->rotate = (flags & 0x10) != 0;
1365
123k
  ch->hasObjectId = (flags & 0x20) != 0;
1366
123k
  ch->editLock = (flags & 0x80) != 0;
1367
123k
  ch->windingRule = (flags & (1<<12)) != 0;
1368
123k
  ch->filled = (flags & (1<<13)) != 0;
1369
123k
  ch->closed = (flags & (1<<14)) != 0;
1370
123k
  ch->framed = (flags & (1<<15)) != 0;
1371
1372
123k
  if (ch->editLock) ch->lockFlags = readU32();
1373
1374
  // object ID can be 2 or 4 bytes
1375
123k
  if (ch->hasObjectId) ch->objectId = readU16();
1376
123k
  if (ch->objectId >> 15) ch->objectId = ((ch->objectId  & 0x7fff) << 16) | readU16();
1377
1378
123k
  if (ch->rotate) ch->rotationAngle = fixedPointToDouble(readU32());
1379
1380
123k
  if (ch->rotate || ch->scale)
1381
59.8k
  {
1382
59.8k
    ch->sxcos = readS32();
1383
59.8k
    ch->sycos = readS32();
1384
59.8k
    ch->matrix.element[0][0] = (double)(ch->sxcos)/65536;
1385
59.8k
    ch->matrix.element[1][1] = (double)(ch->sxcos)/65536;
1386
59.8k
  }
1387
1388
123k
  if (ch->rotate || ch->skew)
1389
66.4k
  {
1390
66.4k
    ch->kxsin = readS32();
1391
66.4k
    ch->kysin = readS32();
1392
66.4k
    ch->matrix.element[1][0] = (double)(ch->kxsin)/65536;
1393
66.4k
    ch->matrix.element[0][1] = (double)(ch->kysin)/65536;
1394
66.4k
  }
1395
1396
123k
  if (ch->translate)
1397
62.6k
  {
1398
62.6k
    ch->txfraction = readU16();
1399
62.6k
    ch->txinteger = readS32();
1400
62.6k
    ch->tyfraction = readU16();
1401
62.6k
    ch->tyinteger = readS32();
1402
62.6k
    ch->matrix.element[2][0] = (double)(ch->txinteger);
1403
62.6k
    ch->matrix.element[2][1] = (double)(ch->tyinteger);
1404
62.6k
  }
1405
1406
123k
  if (ch->taper)
1407
75.3k
  {
1408
75.3k
    ch->px = readS32();
1409
75.3k
    ch->py = readS32();
1410
75.3k
    ch->matrix.element[0][2] = (double)(ch->px);
1411
75.3k
    ch->matrix.element[1][2] = (double)(ch->py);
1412
75.3k
  }
1413
1414
123k
  WPG_DEBUG_MSG(("ObjectCharacterization\n"));
1415
123k
  WPG_DEBUG_MSG(("       taper : %s\n", (ch->taper ? "yes" : "no")));
1416
123k
  WPG_DEBUG_MSG(("   translate : %s\n", (ch->translate ? "yes" : "no")));
1417
123k
  WPG_DEBUG_MSG(("        skew : %s\n", (ch->skew ? "yes" : "no")));
1418
123k
  WPG_DEBUG_MSG(("       scale : %s\n", (ch->scale ? "yes" : "no")));
1419
123k
  WPG_DEBUG_MSG(("      rotate : %s\n", (ch->rotate ? "yes" : "no")));
1420
123k
  WPG_DEBUG_MSG((" hasObjectId : %s\n", (ch->hasObjectId ? "yes" : "no")));
1421
123k
  WPG_DEBUG_MSG(("    editLock : %s\n", (ch->editLock ? "yes" : "no")));
1422
123k
  WPG_DEBUG_MSG(("      closed : %s\n", (ch->closed ? "yes" : "no")));
1423
123k
  WPG_DEBUG_MSG(("      framed : %s\n", (ch->framed ? "yes" : "no")));
1424
123k
  WPG_DEBUG_MSG(("      filled : %s\n", (ch->filled ? "yes" : "no")));
1425
#ifdef DEBUG
1426
  if (ch->editLock) WPG_DEBUG_MSG(("  lock flags : 0x%x\n", (unsigned)ch->lockFlags));
1427
  if (ch->hasObjectId) WPG_DEBUG_MSG(("   object ID : 0x%x\n", (unsigned)ch->objectId));
1428
  if (ch->translate) WPG_DEBUG_MSG(("    tx : %li %d\n", ch->txinteger, ch->txfraction));
1429
  if (ch->translate) WPG_DEBUG_MSG(("    ty : %li %d\n", ch->tyinteger, ch->tyfraction));
1430
#endif
1431
123k
  WPG_DEBUG_MSG(("transform matrix:\n"));
1432
123k
  WPG_DEBUG_MSG(("%f %f %f\n", ch->matrix.element[0][0], ch->matrix.element[0][1],ch->matrix.element[0][2]));
1433
123k
  WPG_DEBUG_MSG(("%f %f %f\n", ch->matrix.element[1][0], ch->matrix.element[1][1],ch->matrix.element[1][2]));
1434
123k
  WPG_DEBUG_MSG(("%f %f %f\n", ch->matrix.element[2][0], ch->matrix.element[2][1],ch->matrix.element[2][2]));
1435
123k
}
1436
1437
void WPG2Parser::handlePolyline()
1438
11.4k
{
1439
11.4k
  if (!m_graphicsStarted)
1440
469
    return;
1441
11.0k
  ObjectCharacterization objCh;
1442
11.0k
  parseCharacterization(&objCh);
1443
11.0k
  m_matrix = objCh.matrix;
1444
1445
11.0k
  librevenge::RVNGPropertyList tmpStyle = m_style;
1446
1447
11.0k
  if (!objCh.filled)
1448
6.43k
    tmpStyle.insert("draw:fill", "none");
1449
11.0k
  if (!objCh.framed)
1450
10.3k
    tmpStyle.insert("draw:stroke", "none");
1451
1452
11.0k
  bool insideCompound = m_groupStack.empty() ? false :
1453
11.0k
                        m_groupStack.top().isCompoundPolygon();
1454
1455
  // inside a compound, so take the parent transformation into account
1456
11.0k
  if (insideCompound)
1457
5.25k
    m_matrix.transformBy(m_groupStack.top().compoundMatrix);
1458
1459
11.0k
  unsigned long count = readU16();
1460
11.0k
  const unsigned long maxCount = getRemainingRecordLength() / (m_doublePrecision ? 4 : 2) / 2;
1461
11.0k
  if (count > maxCount)
1462
6.18k
    count = maxCount;
1463
1464
11.0k
  librevenge::RVNGPropertyListVector points;
1465
130k
  for (unsigned long i = 0; i < count; i++)
1466
119k
  {
1467
119k
    librevenge::RVNGPropertyList point;
1468
119k
    long x = (m_doublePrecision) ? readS32() : readS16();
1469
119k
    long y = (m_doublePrecision) ? readS32() : readS16();
1470
119k
    transformXY(x,y);
1471
119k
    point.insert("svg:x", (toDouble(x)/m_xres));
1472
119k
    point.insert("svg:y", (toDouble(y)/m_yres));
1473
119k
    points.append(point);
1474
119k
  }
1475
1476
11.0k
  librevenge::RVNGPropertyList tmpPoints;
1477
11.0k
  tmpPoints.insert("svg:points", points);
1478
1479
11.0k
  if (insideCompound)
1480
5.25k
  {
1481
5.25k
    if (count > 0)
1482
364
    {
1483
      // inside a compound ? convert it into path because for compound
1484
      // we will only use paths
1485
364
      librevenge::RVNGPropertyListVector &path = m_groupStack.top().compoundPath;
1486
364
      librevenge::RVNGPropertyList element;
1487
364
      element = points[0];
1488
364
      element.insert("librevenge:path-action", "M");
1489
364
      path.append(element);
1490
100k
      for (unsigned long ii = 1; ii < count; ii++)
1491
100k
      {
1492
100k
        element.clear();
1493
100k
        element = points[ii];
1494
100k
        element.insert("librevenge:path-action", "L");
1495
100k
        path.append(element);
1496
100k
      }
1497
364
    }
1498
5.25k
  }
1499
5.76k
  else
1500
5.76k
  {
1501
    // otherwise draw directly
1502
5.76k
    if (count > 2)
1503
507
    {
1504
507
      if (objCh.windingRule)
1505
89
        tmpStyle.insert("svg:fill-rule", "nonzero");
1506
418
      else
1507
418
        tmpStyle.insert("svg:fill-rule", "evenodd");
1508
1509
507
      if (objCh.filled || m_gradient.count())
1510
163
        tmpStyle.insert("svg:linearGradient", m_gradient);
1511
507
      m_painter->setStyle(tmpStyle);
1512
1513
507
      if (objCh.filled || objCh.closed)
1514
160
        m_painter->drawPolygon(tmpPoints);
1515
347
      else
1516
347
        m_painter->drawPolyline(tmpPoints);
1517
507
    }
1518
5.26k
    else
1519
5.26k
    {
1520
1521
5.26k
      m_painter->setStyle(tmpStyle);
1522
5.26k
      m_painter->drawPolyline(tmpPoints);
1523
5.26k
    }
1524
5.76k
  }
1525
1526
11.0k
  WPG_DEBUG_MSG(("   Vertices count : %li\n", (long) count));
1527
130k
  for (unsigned long j = 0; j < count; j++)
1528
119k
    WPG_DEBUG_MSG(("        Point #%lu : %g,%g\n", j+1, points[j]["svg:x"]->getDouble(), points[j]["svg:x"]->getDouble()));
1529
11.0k
}
1530
1531
void WPG2Parser::handlePolyspline()
1532
6.71k
{
1533
  // fprintf(stderr, "This is actually not an error, just a crash so that we know ");
1534
  // fprintf(stderr, "that there is an actual document containing the Polyspline record\n");
1535
  // crash here !!!
1536
  // *((int *)NULL) = 0;
1537
6.71k
  if (!m_graphicsStarted)
1538
222
    return;
1539
  // We have never seen a polyspline in a WPG file and we are not even able to generate
1540
  // one, so, we draw a polyline instead and wait for bug reports :)
1541
6.49k
  handlePolyline();
1542
6.49k
}
1543
1544
void WPG2Parser::handlePolycurve()
1545
47.0k
{
1546
47.0k
  if (!m_graphicsStarted)
1547
288
    return;
1548
46.7k
  ObjectCharacterization objCh;
1549
46.7k
  parseCharacterization(&objCh);
1550
46.7k
  m_matrix = objCh.matrix;
1551
1552
46.7k
  librevenge::RVNGPropertyList tmpStyle = m_style;
1553
1554
46.7k
  if (!objCh.filled)
1555
45.1k
    tmpStyle.insert("draw:fill", "none");
1556
46.7k
  if (!objCh.framed)
1557
45.8k
    tmpStyle.insert("draw:stroke", "none");
1558
1559
46.7k
  bool insideCompound = m_groupStack.empty() ? false :
1560
46.7k
                        m_groupStack.top().isCompoundPolygon();
1561
1562
  // inside a compound, so take the parent transformation into account
1563
46.7k
  if (insideCompound)
1564
3.48k
    m_matrix.transformBy(m_groupStack.top().compoundMatrix);
1565
1566
46.7k
  unsigned int count = readU16();
1567
46.7k
  const unsigned int maxCount = getRemainingRecordLength() / (m_doublePrecision ? 4 : 2) / 6;
1568
46.7k
  if (count > maxCount)
1569
43.5k
    count = maxCount;
1570
1571
46.7k
  librevenge::RVNGPropertyListVector path;
1572
46.7k
  librevenge::RVNGPropertyList element;
1573
46.7k
  librevenge::RVNGPropertyListVector vertices;
1574
46.7k
  librevenge::RVNGPropertyListVector controlPoints;
1575
411k
  for (unsigned int i = 0; i < count; i++)
1576
365k
  {
1577
365k
    long ix = (m_doublePrecision) ? readS32() : readS16();
1578
365k
    long iy = (m_doublePrecision) ? readS32() : readS16();
1579
365k
    transformXY(ix,iy);
1580
1581
365k
    long ax = (m_doublePrecision) ? readS32() : readS16();
1582
365k
    long ay = (m_doublePrecision) ? readS32() : readS16();
1583
365k
    transformXY(ax,ay);
1584
1585
365k
    long tx = (m_doublePrecision) ? readS32() : readS16();
1586
365k
    long ty = (m_doublePrecision) ? readS32() : readS16();
1587
365k
    transformXY(tx,ty);
1588
1589
365k
    element.insert("svg:x", (toDouble(ax)/m_xres));
1590
365k
    element.insert("svg:y", (toDouble(ay)/m_yres));
1591
365k
    if (i == 0)
1592
458
      element.insert("librevenge:path-action", "M");
1593
364k
    else
1594
364k
    {
1595
364k
      element.insert("svg:x2", (toDouble(ix)/m_xres));
1596
364k
      element.insert("svg:y2", (toDouble(iy)/m_yres));
1597
364k
      element.insert("librevenge:path-action", "C");
1598
364k
    }
1599
365k
    path.append(element);
1600
365k
    element.insert("svg:x1", (toDouble(tx)/m_xres));
1601
365k
    element.insert("svg:y1", (toDouble(ty)/m_yres));
1602
365k
  }
1603
1604
46.7k
  element.clear();
1605
46.7k
  if (objCh.closed)
1606
1.05k
  {
1607
1.05k
    element.insert("librevenge:path-action", "Z");
1608
1.05k
    path.append(element);
1609
1.05k
  }
1610
1611
46.7k
  if (insideCompound)
1612
    // inside a compound ? just collect the path together
1613
3.48k
    m_groupStack.top().compoundPath.append(path);
1614
43.2k
  else
1615
43.2k
  {
1616
    // otherwise draw directly
1617
43.2k
    if (objCh.windingRule)
1618
42.0k
      tmpStyle.insert("svg:fill-rule", "nonzero");
1619
1.16k
    else
1620
1.16k
      tmpStyle.insert("svg:fill-rule", "evenodd");
1621
43.2k
    if (objCh.filled || m_gradient.count())
1622
1.68k
      tmpStyle.insert("svg:linearGradient", m_gradient);
1623
43.2k
    m_painter->setStyle(tmpStyle);
1624
43.2k
    librevenge::RVNGPropertyList propList;
1625
43.2k
    propList.insert("svg:d", path);
1626
43.2k
    m_painter->drawPath(propList);
1627
43.2k
  }
1628
46.7k
}
1629
1630
void WPG2Parser::handleRectangle()
1631
7.28k
{
1632
7.28k
  if (!m_graphicsStarted)
1633
195
    return;
1634
7.09k
  ObjectCharacterization objCh;
1635
7.09k
  parseCharacterization(&objCh);
1636
7.09k
  m_matrix = objCh.matrix;
1637
1638
7.09k
  librevenge::RVNGPropertyList tmpStyle = m_style;
1639
1640
7.09k
  if (!objCh.filled)
1641
6.82k
    tmpStyle.insert("draw:fill", "none");
1642
7.09k
  if (!objCh.framed)
1643
6.80k
    tmpStyle.insert("draw:stroke", "none");
1644
1645
7.09k
  long x1 = (m_doublePrecision) ? readS32() : readS16();
1646
7.09k
  long y1 = (m_doublePrecision) ? readS32() : readS16();
1647
7.09k
  transformXY(x1,y1);
1648
1649
7.09k
  long x2 = (m_doublePrecision) ? readS32() : readS16();
1650
7.09k
  long y2 = (m_doublePrecision) ? readS32() : readS16();
1651
7.09k
  transformXY(x2,y2);
1652
1653
7.09k
  long xs1 = (x1 <= x2) ? x1 : x2;
1654
7.09k
  long xs2 = (x1 <= x2) ? x2 : x1;
1655
7.09k
  long ys1 = (y1 <= y2) ? y1 : y2;
1656
7.09k
  long ys2 = (y1 <= y2) ? y2 : y1;
1657
1658
7.09k
  long rx = (m_doublePrecision) ? readS32() : readS16();
1659
7.09k
  long ry = (m_doublePrecision) ? readS32() : readS16();
1660
1661
7.09k
  librevenge::RVNGPropertyList propList;
1662
7.09k
  propList.insert("svg:x", (toDouble(xs1) / m_xres));
1663
7.09k
  propList.insert("svg:width", (toDouble(xs2-xs1) / m_xres));
1664
7.09k
  propList.insert("svg:y", (toDouble(ys1) / m_yres));
1665
7.09k
  propList.insert("svg:height", (toDouble(ys2-ys1) / m_yres));
1666
1667
7.09k
  propList.insert("svg:rx", (toDouble(rx)/m_xres));
1668
7.09k
  propList.insert("svg:ry", (toDouble(ry)/m_yres));
1669
1670
7.09k
  if (objCh.filled || m_gradient.count())
1671
599
    tmpStyle.insert("svg:linearGradient", m_gradient);
1672
7.09k
  m_painter->setStyle(tmpStyle);
1673
7.09k
  m_painter->drawRectangle(propList);
1674
1675
7.09k
  WPG_DEBUG_MSG(("      X1 : %li\n", x1));
1676
7.09k
  WPG_DEBUG_MSG(("      Y1 : %li\n", y1));
1677
7.09k
  WPG_DEBUG_MSG(("      X2 : %li\n", x2));
1678
7.09k
  WPG_DEBUG_MSG(("      Y2 : %li\n", y2));
1679
7.09k
  WPG_DEBUG_MSG((" Round X : %li\n", rx));
1680
7.09k
  WPG_DEBUG_MSG((" Round Y : %li\n", ry));
1681
7.09k
}
1682
1683
void WPG2Parser::handleArc()
1684
5.72k
{
1685
5.72k
  if (!m_graphicsStarted)
1686
443
    return;
1687
5.28k
  ObjectCharacterization objCh;
1688
5.28k
  parseCharacterization(&objCh);
1689
5.28k
  m_matrix = objCh.matrix;
1690
1691
5.28k
  librevenge::RVNGPropertyList tmpStyle = m_style;
1692
1693
5.28k
  if (!objCh.filled)
1694
4.40k
    tmpStyle.insert("draw:fill", "none");
1695
5.28k
  if (!objCh.framed)
1696
5.17k
    tmpStyle.insert("draw:stroke", "none");
1697
1698
5.28k
  long cx = (m_doublePrecision) ? readS32() : readS16();
1699
5.28k
  long cy = (m_doublePrecision) ? readS32() : readS16();
1700
1701
5.28k
  long radx = (m_doublePrecision) ? readS32() : readS16();
1702
5.28k
  long rady = (m_doublePrecision) ? readS32() : readS16();
1703
1704
5.28k
  long ix = (m_doublePrecision) ? readS32() : readS16();
1705
5.28k
  ix += cx;
1706
5.28k
  long iy = (m_doublePrecision) ? readS32() : readS16();
1707
5.28k
  iy += cy;
1708
1709
5.28k
  long ex = (m_doublePrecision) ? readS32() : readS16();
1710
5.28k
  ex += cx;
1711
5.28k
  long ey = (m_doublePrecision) ? readS32() : readS16();
1712
5.28k
  ey += cy;
1713
1714
5.28k
  transformXY(cx,cy);
1715
5.28k
  transformXY(ix,iy);
1716
5.28k
  transformXY(ex,ey);
1717
1718
5.28k
  if (objCh.filled || m_gradient.count())
1719
1.23k
    tmpStyle.insert("svg:linearGradient", m_gradient);
1720
5.28k
  m_painter->setStyle(tmpStyle);
1721
1722
5.28k
  if (ix == ex && iy == ey)
1723
1.45k
  {
1724
1.45k
    librevenge::RVNGPropertyList propList;
1725
1.45k
    propList.insert("svg:cx", (toDouble(cx) / m_xres));
1726
1.45k
    propList.insert("svg:cy", (toDouble(cy) / m_xres));
1727
1.45k
    propList.insert("svg:rx", (toDouble(radx) / m_xres));
1728
1.45k
    propList.insert("svg:ry", (toDouble(rady) / m_xres));
1729
1.45k
    if (objCh.rotate)
1730
904
      propList.insert("librevenge:rotate", objCh.rotationAngle, librevenge::RVNG_GENERIC);
1731
1732
1.45k
    m_painter->drawEllipse(propList);
1733
1.45k
  }
1734
3.82k
  else
1735
3.82k
  {
1736
3.82k
    librevenge::RVNGPropertyList element;
1737
3.82k
    librevenge::RVNGPropertyListVector path;
1738
1739
3.82k
    element.insert("librevenge:path-action", "M");
1740
3.82k
    element.insert("svg:x", (toDouble(ix)/m_xres));
1741
3.82k
    element.insert("svg:y", (toDouble(iy)/m_yres));
1742
3.82k
    path.append(element);
1743
3.82k
    element.clear();
1744
1745
3.82k
    element.insert("librevenge:path-action", "A");
1746
3.82k
    element.insert("svg:rx", (toDouble(radx)/m_xres));
1747
3.82k
    element.insert("svg:ry", (toDouble(rady)/m_yres));
1748
3.82k
    element.insert("svg:x", (toDouble(ex)/m_xres));
1749
3.82k
    element.insert("svg:y", (toDouble(ey)/m_yres));
1750
3.82k
    if (objCh.rotate)
1751
1.45k
      element.insert("librevenge:rotate", objCh.rotationAngle, librevenge::RVNG_GENERIC);
1752
3.82k
    path.append(element);
1753
1754
3.82k
    librevenge::RVNGPropertyList propList;
1755
3.82k
    propList.insert("svg:d", path);
1756
3.82k
    m_painter->drawPath(propList);
1757
3.82k
  }
1758
1759
5.28k
  WPG_DEBUG_MSG(("   Center point x : %li\n", cx));
1760
5.28k
  WPG_DEBUG_MSG(("   Center point y : %li\n", cy));
1761
5.28k
  WPG_DEBUG_MSG(("         Radius x : %li\n", radx));
1762
5.28k
  WPG_DEBUG_MSG(("         Radius y : %li\n", rady));
1763
5.28k
  WPG_DEBUG_MSG(("  Initial point x : %li\n", ix));
1764
5.28k
  WPG_DEBUG_MSG(("  Initial point y : %li\n", iy));
1765
5.28k
  WPG_DEBUG_MSG(("      End point x : %li\n", ex));
1766
5.28k
  WPG_DEBUG_MSG(("      End point y : %li\n", ey));
1767
5.28k
}
1768
1769
void WPG2Parser::handleBitmap()
1770
4.84k
{
1771
4.84k
  if (!m_graphicsStarted)
1772
197
    return;
1773
4.64k
  ObjectCharacterization objCh;
1774
4.64k
  parseCharacterization(&objCh);
1775
1776
4.64k
  if (objCh.scale)
1777
2.96k
  {
1778
2.96k
    if (objCh.sxcos < 0)
1779
822
      m_hFlipped = true;
1780
2.96k
    if (objCh.sycos < 0)
1781
616
      m_vFlipped = true;
1782
2.96k
  }
1783
4.64k
  m_matrix = objCh.matrix;
1784
1785
4.64k
  long x1 = (m_doublePrecision) ? readS32() : readS16();
1786
4.64k
  long y1 = (m_doublePrecision) ? readS32() : readS16();
1787
4.64k
  long x2 = (m_doublePrecision) ? readS32() : readS16();
1788
4.64k
  long y2 = (m_doublePrecision) ? readS32() : readS16();
1789
4.64k
  transformXY(x1,y1);
1790
4.64k
  transformXY(x2,y2);
1791
1792
4.64k
  long hres = (m_doublePrecision) ? readS32() : readS16();
1793
4.64k
  long vres = (m_doublePrecision) ? readS32() : readS16();
1794
1795
4.64k
  long xs1 = (x1 <= x2) ? x1 : x2;
1796
4.64k
  long xs2 = (x1 <= x2) ? x2 : x1;
1797
4.64k
  long ys1 = (y1 <= y2) ? y1 : y2;
1798
4.64k
  long ys2 = (y1 <= y2) ? y2 : y1;
1799
1800
4.64k
  m_bitmap.x1 = toDouble(xs1) / m_xres;
1801
4.64k
  m_bitmap.y1 = toDouble(ys1) / m_yres;
1802
4.64k
  m_bitmap.x2 = toDouble(xs2) / m_xres;
1803
4.64k
  m_bitmap.y2 = toDouble(ys2) / m_yres;
1804
4.64k
  if (hres == 0)
1805
1.19k
    hres = 72;
1806
4.64k
  m_bitmap.hres = hres;
1807
4.64k
  if (vres == 0)
1808
1.32k
    vres = 72;
1809
4.64k
  m_bitmap.vres = vres;
1810
1811
4.64k
  WPG_DEBUG_MSG(("   x1 : %li\n", x1));
1812
4.64k
  WPG_DEBUG_MSG(("   y1 : %li\n", y1));
1813
4.64k
  WPG_DEBUG_MSG(("   x2 : %li\n", x2));
1814
4.64k
  WPG_DEBUG_MSG(("   y2 : %li\n", y2));
1815
4.64k
  WPG_DEBUG_MSG((" hres : %li (pixel per inch)\n", hres));
1816
4.64k
  WPG_DEBUG_MSG((" vres : %li (pixel per inch)\n", vres));
1817
4.64k
}
1818
1819
void WPG2Parser::handleBitmapData()
1820
11.9k
{
1821
11.9k
  if (!m_graphicsStarted)
1822
233
    return;
1823
11.7k
  unsigned width = readU16();
1824
11.7k
  unsigned height = readU16();
1825
11.7k
  unsigned color_format = readU8();
1826
11.7k
  unsigned compression_format = readU8();
1827
1828
11.7k
  WPG_DEBUG_MSG(("     dimension : %g, %g  %g, %g\n", m_bitmap.x1, m_bitmap.y1, m_bitmap.x2, m_bitmap.y2));
1829
11.7k
  WPG_DEBUG_MSG(("         width : %i pixels\n", (int) width));
1830
11.7k
  WPG_DEBUG_MSG(("        height : %i pixels\n", (int) height));
1831
11.7k
  WPG_DEBUG_MSG(("  color format : %d\n", (int) color_format));
1832
11.7k
  WPG_DEBUG_MSG(("   compression : %d (%s)\n", (int) compression_format,
1833
11.7k
                 (compression_format==0) ? "uncompressed":
1834
11.7k
                 (compression_format==1) ? "run-length encoding" : "unknown"));
1835
1836
11.7k
  if (color_format > 12) // not documented and we are likely not knowing what to do with this
1837
568
    return;
1838
11.1k
  unsigned tmpBufferSize;
1839
11.1k
  unsigned raster_len = width;
1840
11.1k
  if (color_format == 1)
1841
842
  {
1842
842
    tmpBufferSize = (width/8+1)*height;
1843
842
    raster_len = width/8 + ((width % 8) ? 1 : 0);
1844
842
  }
1845
10.2k
  else if (color_format == 2)
1846
1.25k
  {
1847
1.25k
    tmpBufferSize = (width/4+1)*height;
1848
1.25k
    raster_len = width/4 + ((width % 4) ? 1 : 0);
1849
1.25k
  }
1850
9.03k
  else if (color_format == 3)
1851
488
  {
1852
488
    tmpBufferSize = (width/2+1)*height;
1853
488
    raster_len = width/2 + ((width % 2) ? 1 : 0);
1854
488
  }
1855
8.55k
  else if (color_format == 5 || color_format == 6 || color_format == 7)
1856
2.04k
    tmpBufferSize = 2*width*height;
1857
6.50k
  else if (color_format == 8)
1858
1.64k
    tmpBufferSize = 3*width*height;
1859
4.86k
  else if (color_format == 9)
1860
166
    tmpBufferSize = 4*width*height;
1861
4.69k
  else if (color_format == 10)
1862
566
    tmpBufferSize = 6*width*height;
1863
4.12k
  else if (color_format == 11)
1864
103
    tmpBufferSize = 8*width*height;
1865
4.02k
  else
1866
4.02k
    tmpBufferSize = width*height;
1867
1868
1869
11.1k
  std::vector<unsigned char> buffer;
1870
1871
  // plain data, uncompression
1872
11.1k
  if (compression_format==0)
1873
3.34k
  {
1874
3.34k
    if (tmpBufferSize > getRemainingLength(m_input))
1875
1.02k
      return;
1876
2.32k
    buffer.reserve(tmpBufferSize);
1877
173k
    for (unsigned ii=0; ii < tmpBufferSize && !m_input->isEnd() && m_input->tell() <= m_recordEnd; ii++)
1878
170k
      buffer.push_back(readU8());
1879
2.32k
  }
1880
  // run-length encoding
1881
7.78k
  else if (compression_format==1)
1882
6.45k
  {
1883
6.45k
    unsigned char data[256];
1884
6.45k
    bool xor_raster = false;
1885
6.45k
    unsigned next_scanline = 0;
1886
6.45k
    unsigned data_size = 1;
1887
6.45k
    data[0] = 0;
1888
1889
6.45k
    if (!checkRLESize(tmpBufferSize))
1890
1.50k
      return;
1891
1892
4.94k
    WPG_DEBUG_MSG(("Decoding RLE data\n"));
1893
1894
    // FIXME check for ptr, it should not go out of bound!!
1895
273k
    while (m_input->tell() <= m_recordEnd && !m_input->isEnd() && buffer.size() < tmpBufferSize)
1896
268k
    {
1897
268k
      unsigned char opcode = readU8();
1898
      // specify data size
1899
268k
      if (opcode == 0x7d)
1900
2.48k
      {
1901
2.48k
        unsigned new_data_size = readU8();
1902
2.48k
        if (new_data_size != data_size)
1903
1.48k
        {
1904
1.48k
          data_size = new_data_size;
1905
1.48k
          std::memset(data, 0, data_size);
1906
1.48k
          if (tmpBufferSize < data_size*width*height)
1907
788
          {
1908
788
            tmpBufferSize = data_size*width*height;
1909
788
            if (!checkRLESize(tmpBufferSize))
1910
150
              return;
1911
638
            buffer.reserve(tmpBufferSize);
1912
638
          }
1913
1.33k
          raster_len = data_size*width;
1914
1.33k
        }
1915
2.48k
      }
1916
1917
      // a run of black (index #0)
1918
266k
      else if (opcode == 0x7f)
1919
1.54k
      {
1920
1.54k
        unsigned count = 1 + readU8();
1921
194k
        for (; count ; --count)
1922
24.3M
          for (unsigned j = 0; j < data_size; j++)
1923
24.1M
            buffer.push_back(0);
1924
1925
1.54k
      }
1926
1927
      // a run of white (index #255)
1928
264k
      else if (opcode == 0xff)
1929
29.8k
      {
1930
29.8k
        unsigned count = 1 + readU8();
1931
1932
7.24M
        for (; count ; --count)
1933
196M
          for (unsigned j = 0; j < data_size; j++)
1934
189M
            buffer.push_back(255);
1935
29.8k
      }
1936
1937
      // extend previous run
1938
235k
      else if (opcode == 0xfd)
1939
2.39k
      {
1940
2.39k
        unsigned count = 1 + readU8();
1941
536k
        for (; count; --count)
1942
52.1M
          for (unsigned j = 0; j < data_size; j++)
1943
51.6M
            buffer.push_back(data[j]);
1944
2.39k
      }
1945
1946
      // repeat raster
1947
232k
      else if (opcode == 0xfe)
1948
1.75k
      {
1949
1.75k
        unsigned count = 1 + readU8();
1950
1.75k
        if (buffer.size() < raster_len)
1951
23
          break;
1952
1.73k
        unsigned raster_source = buffer.size() - raster_len;
1953
321k
        for (; count; --count)
1954
148M
          for (unsigned long r = 0; r < raster_len; r++)
1955
147M
          {
1956
147M
            unsigned char pixel = buffer[raster_source + r];
1957
147M
            buffer.push_back(pixel);
1958
147M
          }
1959
1.73k
      }
1960
1961
      // XOR
1962
230k
      else if (opcode == 0x7e)
1963
3.87k
      {
1964
        // Xor-ing will happen when about to enter next raster
1965
        // see after the last if down below
1966
3.87k
        xor_raster = true;
1967
3.87k
        next_scanline = buffer.size() + raster_len;
1968
3.87k
      }
1969
1970
      // NOTE: the following two IFs here must be the last ones
1971
1972
      // a run of data
1973
226k
      else if (opcode >= 0x80)
1974
23.5k
      {
1975
23.5k
        unsigned count = 1 + (opcode & 0x7f);
1976
23.5k
        unsigned i = 0;
1977
245k
        for (; i < data_size && !m_input->isEnd(); i++)
1978
221k
          data[i] = readU8();
1979
30.1k
        while (i < data_size)
1980
6.54k
          data[i++] = 0;
1981
1.88M
        for (; count; --count)
1982
18.6M
          for (unsigned j = 0; j < data_size; j++)
1983
16.7M
            buffer.push_back(data[j]);
1984
23.5k
      }
1985
1986
      // simple copy
1987
203k
      else if (opcode <= 0x7f)
1988
203k
      {
1989
203k
        unsigned count = opcode + 1;
1990
1.43M
        for (; count; --count)
1991
4.41M
          for (unsigned j = 0; j < data_size && !m_input->isEnd(); j++)
1992
3.18M
            buffer.push_back(readU8());
1993
203k
      }
1994
1995
      // unreachable: only sentinel
1996
0
      else
1997
0
      {
1998
0
        WPG_DEBUG_MSG(("  ! unknown opcode %02x\n", opcode));
1999
0
        break;
2000
0
      }
2001
2002
      // new raster/scanline? if necessary do the XOR now
2003
268k
      if (xor_raster && buffer.size() >= next_scanline)
2004
1.30k
      {
2005
        // reset, because XOR in one raster at a time
2006
1.30k
        xor_raster = false;
2007
2008
1.30k
        if (raster_len > next_scanline / 2)
2009
77
          return;
2010
2011
        // current raster must be XORed with previous raster
2012
1.22k
        unsigned current = next_scanline - raster_len;
2013
1.22k
        unsigned previous = current - raster_len;
2014
145k
        for (unsigned r = 0; r < raster_len; r++)
2015
144k
          buffer[current++] ^= buffer[previous++];
2016
2017
1.22k
      }
2018
2019
268k
    }
2020
2021
4.72k
    WPG_DEBUG_MSG(("Finish decoding RLE data\n"));
2022
4.72k
  }
2023
2024
  // no buffer? format is unknown
2025
8.37k
  if (!buffer.size()) return;
2026
2027
112M
  while (buffer.size() < tmpBufferSize)
2028
112M
    buffer.push_back(0);
2029
2030
  // prepare the bitmap structure for the listener
2031
6.35k
  libwpg::WPGBitmap bitmap((int) width, (int) height, m_vFlipped, m_hFlipped);
2032
6.35k
  librevenge::RVNGPropertyList propList;
2033
6.35k
  propList.insert("svg:x", (double)m_bitmap.x1);
2034
6.35k
  propList.insert("svg:y", (double)m_bitmap.y1);
2035
6.35k
  propList.insert("svg:width", (m_bitmap.x2 - m_bitmap.x1));
2036
6.35k
  propList.insert("svg:height", (m_bitmap.y2 - m_bitmap.y1));
2037
6.35k
  propList.insert("librevenge:mime-type", "image/bmp");
2038
2039
  // format 1: each byte represents 8 pixels, the color fetched from the palette
2040
6.35k
  if (color_format == 1)
2041
579
  {
2042
579
    size_t i = 0;
2043
809k
    for (unsigned long y = 0; y < height; y++)
2044
4.91M
      for (unsigned long x = 0; x < width; x++, i++)
2045
4.10M
      {
2046
4.10M
        if ((x==0) && (i % 8 != 0))
2047
429k
          i = (i/8 + 1) * 8;
2048
4.10M
        unsigned index = ((buffer[i/8] & (0x01 << (7 - (i % 8)))) >> (7 - (i % 8)));
2049
4.10M
        const libwpg::WPGColor &color = m_colorPalette[(int) index];
2050
4.10M
        bitmap.setPixel((int) x, (int) y, color);
2051
4.10M
      }
2052
579
    propList.insert("office:binary-data", bitmap.getDIB());
2053
579
    m_painter->drawGraphicObject(propList);
2054
579
  }
2055
  // format 2: each byte represents 4 pixels, the color fetched from the palette
2056
5.77k
  else if (color_format == 2)
2057
831
  {
2058
831
    size_t i = 0;
2059
1.76M
    for (unsigned long y = 0; y < height; y++)
2060
7.66M
      for (unsigned long x = 0; x < width; x++, i++)
2061
5.90M
      {
2062
5.90M
        if ((x==0) && (i % 4 != 0))
2063
1.65M
          i = (i/4 + 1) * 4;
2064
5.90M
        unsigned index = ((buffer[i/4] & (0x03 << 2*(3 - (i % 4)))) >> 2*(3 - (i % 4)));
2065
5.90M
        const libwpg::WPGColor &color = m_colorPalette[(int) index];
2066
5.90M
        bitmap.setPixel((int) x, (int) y, color);
2067
5.90M
      }
2068
831
    propList.insert("office:binary-data", bitmap.getDIB());
2069
831
    m_painter->drawGraphicObject(propList);
2070
831
  }
2071
  // format 3: each byte represents 2 pixels, the color fetched from the palette
2072
4.94k
  else if (color_format == 3)
2073
128
  {
2074
128
    int i = 0;
2075
55.4k
    for (unsigned long y = 0; y < height; y++)
2076
281k
      for (unsigned long x = 0; x < width; x++, i++)
2077
225k
      {
2078
225k
        if ((x==0) && (i % 2 != 0))
2079
6.16k
          i = (i/2 + 1) * 2;
2080
225k
        unsigned index = ((buffer[size_t(i/2)] & (0x0f << 4*(1 - (i % 2)))) >> 4*(1 - (i % 2)));
2081
225k
        const libwpg::WPGColor &color = m_colorPalette[(int) index];
2082
225k
        bitmap.setPixel((int) x, (int) y, color);
2083
225k
      }
2084
128
    propList.insert("office:binary-data", bitmap.getDIB());
2085
128
    m_painter->drawGraphicObject(propList);
2086
128
  }
2087
  // format 4: each byte represents a pixel, the color fetched from the palette
2088
4.81k
  else if (color_format == 4)
2089
1.30k
  {
2090
1.30k
    size_t i = 0;
2091
392k
    for (unsigned long y = 0; y < height; y++)
2092
1.83M
      for (unsigned long x = 0; x < width; x++, i++)
2093
1.44M
      {
2094
1.44M
        const libwpg::WPGColor &color = m_colorPalette[buffer[i]];
2095
1.44M
        bitmap.setPixel((int) x, (int) y, color);
2096
1.44M
      }
2097
2098
1.30k
    propList.insert("office:binary-data", bitmap.getDIB());
2099
1.30k
    m_painter->drawGraphicObject(propList);
2100
1.30k
  }
2101
  // format 5: greyscale of 16 bits
2102
3.51k
  else if (color_format == 5)
2103
95
  {
2104
95
    size_t i = 0;
2105
2.41k
    for (unsigned long y = 0; y < height; y++)
2106
9.02k
      for (unsigned long x = 0; x < width; x++, i++)
2107
6.70k
      {
2108
2109
6.70k
        const libwpg::WPGColor color(buffer[2*i+1], buffer[2*i+1], buffer[2*i+1]);
2110
6.70k
        bitmap.setPixel((int) x, (int) y, color);
2111
6.70k
      }
2112
2113
95
    propList.insert("office:binary-data", bitmap.getDIB());
2114
95
    m_painter->drawGraphicObject(propList);
2115
95
  }
2116
  // format 6: RGB, with 5 bits per colour
2117
3.41k
  else if (color_format == 6)
2118
1.39k
  {
2119
1.39k
    size_t i = 0;
2120
386k
    for (unsigned long y = 0; y < height; y++)
2121
774k
      for (unsigned long x = 0; x < width; x++, i++)
2122
389k
      {
2123
389k
        auto tmpColor = (unsigned short)(buffer[2*i] | (buffer[2*i+1] << 8));
2124
389k
        const libwpg::WPGColor color((tmpColor >> 10) & 0x1f, (tmpColor >> 5) & 0x1f, tmpColor & 0x1f);
2125
389k
        bitmap.setPixel((int) x, (int) y, color);
2126
389k
      }
2127
2128
1.39k
    propList.insert("office:binary-data", bitmap.getDIB());
2129
1.39k
    m_painter->drawGraphicObject(propList);
2130
1.39k
  }
2131
  // format 7:
2132
2.02k
  else if (color_format == 7)
2133
181
  {
2134
181
    size_t i = 0;
2135
2.64k
    for (unsigned long y = 0; y < height; y++)
2136
198k
      for (unsigned long x = 0; x < width; x++, i++)
2137
196k
      {
2138
196k
        auto tmpColor = (unsigned short)(buffer[2*i] | (buffer[2*i+1] << 8));
2139
196k
        const libwpg::WPGColor color(tmpColor & 0x0f, (tmpColor >> 4) & 0x0f, (tmpColor >> 8) & 0x0f, (tmpColor >> 12) & 0x0f);
2140
196k
        bitmap.setPixel((int) x, (int) y, color);
2141
196k
      }
2142
2143
181
    propList.insert("office:binary-data", bitmap.getDIB());
2144
181
    m_painter->drawGraphicObject(propList);
2145
181
  }
2146
  // format 8: RGB, with 8 bits per colour
2147
1.84k
  else if (color_format == 8)
2148
776
  {
2149
776
    size_t i = 0;
2150
37.3k
    for (unsigned long y = 0; y < height; y++)
2151
381k
      for (unsigned long x = 0; x < width; x++, i++)
2152
344k
      {
2153
344k
        const libwpg::WPGColor color(buffer[3*i] & 0xff, buffer[3*i+1] & 0xff, buffer[3*i+2] & 0xff);
2154
344k
        bitmap.setPixel((int) x, (int) y, color);
2155
344k
      }
2156
2157
776
    propList.insert("office:binary-data", bitmap.getDIB());
2158
776
    m_painter->drawGraphicObject(propList);
2159
776
  }
2160
  // format 9: RGBA, with 8 bits per colour
2161
1.07k
  else if (color_format == 9)
2162
138
  {
2163
138
    size_t i = 0;
2164
4.89k
    for (unsigned long y = 0; y < height; y++)
2165
18.0k
      for (unsigned long x = 0; x < width; x++, i++)
2166
13.2k
      {
2167
13.2k
        const libwpg::WPGColor color(buffer[4*i], buffer[4*i+1] & 0xff, buffer[4*i+2] & 0xff, buffer[4*i+3] & 0xff);
2168
13.2k
        bitmap.setPixel((int) x, (int) y, color);
2169
13.2k
      }
2170
2171
138
    propList.insert("office:binary-data", bitmap.getDIB());
2172
138
    m_painter->drawGraphicObject(propList);
2173
138
  }
2174
932
  else if (color_format == 12)
2175
517
  {
2176
517
    size_t i = 0;
2177
52.2k
    for (unsigned long y = 0; y < height; y++)
2178
172k
      for (unsigned long x = 0; x < width; x++, i++)
2179
120k
      {
2180
2181
120k
        const libwpg::WPGColor color(buffer[i], buffer[i], buffer[i]);
2182
120k
        bitmap.setPixel((int) x, (int) y, color);
2183
120k
      }
2184
2185
517
    propList.insert("office:binary-data", bitmap.getDIB());
2186
517
    m_painter->drawGraphicObject(propList);
2187
517
  }
2188
2189
6.35k
}
2190
2191
void WPG2Parser::handleObjectCapsule()
2192
4.21k
{
2193
4.21k
  if (!m_graphicsStarted)
2194
458
    return;
2195
3.75k
  ObjectCharacterization objCh;
2196
3.75k
  parseCharacterization(&objCh);
2197
3.75k
  m_matrix = objCh.matrix;
2198
2199
3.75k
  long x1 = (m_doublePrecision) ? readS32() : readS16();
2200
3.75k
  long y1 = (m_doublePrecision) ? readS32() : readS16();
2201
3.75k
  long x2 = (m_doublePrecision) ? readS32() : readS16();
2202
3.75k
  long y2 = (m_doublePrecision) ? readS32() : readS16();
2203
3.75k
  transformXY(x1,y1);
2204
3.75k
  transformXY(x2,y2);
2205
2206
3.75k
  long xs1 = (x1 <= x2) ? x1 : x2;
2207
3.75k
  long xs2 = (x1 <= x2) ? x2 : x1;
2208
3.75k
  long ys1 = (y1 <= y2) ? y1 : y2;
2209
3.75k
  long ys2 = (y1 <= y2) ? y2 : y1;
2210
2211
3.75k
  m_binaryData.x1 = toDouble(xs1) / m_xres;
2212
3.75k
  m_binaryData.y1 = toDouble(ys1) / m_yres;
2213
3.75k
  m_binaryData.x2 = toDouble(xs2) / m_xres;
2214
3.75k
  m_binaryData.y2 = toDouble(ys2) / m_yres;
2215
2216
3.75k
  unsigned long numDescriptions = readU16();
2217
2218
3.75k
  m_binaryData.mimeTypes.clear();
2219
3.75k
  m_binaryData.mimeTypes.reserve(numDescriptions);
2220
2221
3.75k
  static const char* const mimeTypesMap[] =
2222
3.75k
  {
2223
3.75k
    "", // 0
2224
3.75k
    "", // "image/x-wpg",
2225
3.75k
    "", // "image/x-wpg",
2226
3.75k
    "",
2227
3.75k
    "",
2228
3.75k
    "", // 5
2229
3.75k
    "image/bmp",
2230
3.75k
    "image/cgm",
2231
3.75k
    "",
2232
3.75k
    "image/x-dxf",
2233
3.75k
    "image/x-eps", // 0xA
2234
3.75k
    "",
2235
3.75k
    "image/gif",
2236
3.75k
    "application/vnd.hp-hpgl",
2237
3.75k
    "",
2238
3.75k
    "", // 0xF
2239
3.75k
    "", // 0x10
2240
3.75k
    "",
2241
3.75k
    "",
2242
3.75k
    "image/x-pcx ",
2243
3.75k
    "image/x-lotus-pic",
2244
3.75k
    "", // Ox15
2245
3.75k
    "",
2246
3.75k
    "image/x-quicktime",
2247
3.75k
    "",
2248
3.75k
    "application/x-postscript",
2249
3.75k
    "", // 0x1A
2250
3.75k
    "",
2251
3.75k
    "image/x-targa",
2252
3.75k
    "image/tiff",
2253
3.75k
    "",
2254
3.75k
    "image/wmf", // 0x1f
2255
3.75k
    "", // 0x20
2256
3.75k
    "",
2257
3.75k
    "",
2258
3.75k
    "",
2259
3.75k
    "",
2260
3.75k
    "image/png",
2261
3.75k
    "image/gif" // 0x26
2262
3.75k
  };
2263
2264
34.2k
  for (unsigned long i = 0; m_input->tell() <= m_recordEnd && !m_input->isEnd() && i < numDescriptions; i++)
2265
30.5k
  {
2266
30.5k
    unsigned char description = readU8();
2267
30.5k
    if (description < 0x27)
2268
28.4k
      m_binaryData.mimeTypes.push_back(librevenge::RVNGString(mimeTypesMap[description]));
2269
30.5k
    m_input->seek(7, librevenge::RVNG_SEEK_CUR);
2270
30.5k
  }
2271
2272
3.75k
  m_binaryData.objectIndex = 0;
2273
2274
3.75k
  WPG_DEBUG_MSG(("             x1 : %li\n", x1));
2275
3.75k
  WPG_DEBUG_MSG(("             y1 : %li\n", y1));
2276
3.75k
  WPG_DEBUG_MSG(("             x2 : %li\n", x2));
2277
3.75k
  WPG_DEBUG_MSG(("             y2 : %li\n", y2));
2278
3.75k
  WPG_DEBUG_MSG(("numDescriptions : %li\n", (long) numDescriptions));
2279
3.75k
}
2280
2281
void WPG2Parser::handleObjectImage()
2282
19.7k
{
2283
19.7k
  if (!m_graphicsStarted)
2284
552
    return;
2285
19.2k
  if ((unsigned long)m_binaryData.objectIndex >= m_binaryData.mimeTypes.size())
2286
5.51k
    return;
2287
13.7k
  unsigned accessoryDataLength = readU16();
2288
13.7k
  m_input->seek((long) accessoryDataLength, librevenge::RVNG_SEEK_CUR);
2289
2290
13.7k
  librevenge::RVNGPropertyList propList;
2291
13.7k
  propList.insert("svg:x", (double)m_binaryData.x1);
2292
13.7k
  propList.insert("svg:y", (double)m_binaryData.y1);
2293
13.7k
  propList.insert("svg:width", (m_binaryData.x2 - m_binaryData.x1));
2294
13.7k
  propList.insert("svg:height", (m_binaryData.y2 - m_binaryData.y1));
2295
13.7k
  propList.insert("librevenge:mime-type", m_binaryData.mimeTypes[(size_t) m_binaryData.objectIndex]);
2296
2297
13.7k
  WPG_DEBUG_MSG(("Image Object Mime Type : %s\n", propList["librevenge:mime-type"]->getStr().cstr()));
2298
2299
13.7k
  librevenge::RVNGBinaryData binaryData;
2300
13.7k
  if (!m_input->isEnd() && m_input->tell() <= m_recordEnd)
2301
79
  {
2302
79
    unsigned long numBytes = 0;
2303
79
    const unsigned char *const data = m_input->read(m_recordEnd - m_input->tell(), numBytes);
2304
79
    binaryData = librevenge::RVNGBinaryData(data, numBytes);
2305
79
  }
2306
13.7k
  WPG_DEBUG_MSG(("     Image Object Size : %li\n", (unsigned long)binaryData.size()));
2307
2308
  // temporary for debug - dump the binary data (need to have write access in the current directory
2309
#if DUMP_BINARY_DATA
2310
  std::ostringstream filename;
2311
  filename << "binarydump" << m_binaryId++ << ".bin";
2312
  FILE *f = fopen(filename.str().c_str(), "wb");
2313
  if (f)
2314
  {
2315
    const char *tmpBinaryBuffer = binaryData.getDataBuffer();
2316
    unsigned long tmpBufferSize = binaryData.size();
2317
    for (unsigned long k = 0; k < tmpBufferSize; k++)
2318
      fprintf(f, "%c",tmpBinaryBuffer[k]);
2319
    fclose(f);
2320
  }
2321
#endif
2322
2323
2324
13.7k
  propList.insert("office:binary-data", binaryData);
2325
13.7k
  m_painter->drawGraphicObject(propList);
2326
13.7k
  m_binaryData.objectIndex++;
2327
13.7k
}
2328
2329
void WPG2Parser::handleTextLine()
2330
29.6k
{
2331
29.6k
  if (!m_graphicsStarted)
2332
484
    return;
2333
29.1k
  ObjectCharacterization objCh;
2334
29.1k
  parseCharacterization(&objCh);
2335
29.1k
  m_matrix = objCh.matrix;
2336
2337
29.1k
  unsigned short textFlags = readU16();
2338
29.1k
  long x = (m_doublePrecision) ? readS32() : readS16();
2339
29.1k
  long y = (m_doublePrecision) ? readS32() : readS16();
2340
29.1k
  transformXY(x,y);
2341
2342
29.1k
  unsigned char horizontalAlignment = readU8();
2343
29.1k
  unsigned char verticalAlignment = readU8();
2344
2345
29.1k
  double baseLineAngle = fixedPointToDouble(readU32());
2346
2347
29.1k
  WPG_DEBUG_MSG(("            text flags : 0x%.4x\n", textFlags));
2348
29.1k
  WPG_DEBUG_MSG(("                     x : %li\n", x));
2349
29.1k
  WPG_DEBUG_MSG(("                     y : %li\n", y));
2350
29.1k
  WPG_DEBUG_MSG(("  horizontal alignment : 0x%.2x\n", horizontalAlignment));
2351
29.1k
  WPG_DEBUG_MSG(("    vertical alignment : 0x%.2x\n", verticalAlignment));
2352
29.1k
  WPG_DEBUG_MSG(("        baseline angle : %.4f\n", baseLineAngle));
2353
2354
29.1k
  m_textData.x1 = toDouble(x)/m_xres;
2355
29.1k
  m_textData.y1 = toDouble(y)/m_yres;
2356
29.1k
  m_textData.x2 = toDouble(x)/m_xres;
2357
29.1k
  m_textData.y2 = toDouble(y)/m_yres;
2358
29.1k
  m_textData.flags = textFlags;
2359
29.1k
  m_textData.horAlign = horizontalAlignment;
2360
29.1k
  m_textData.vertAlign = verticalAlignment;
2361
29.1k
  m_textData.baseLineAngle = baseLineAngle;
2362
2363
29.1k
  m_drawTextData = true;
2364
29.1k
}
2365
2366
void WPG2Parser::handleTextBlock()
2367
2.39k
{
2368
2.39k
  if (!m_graphicsStarted)
2369
230
    return;
2370
2.16k
  ObjectCharacterization objCh;
2371
2.16k
  parseCharacterization(&objCh);
2372
2.16k
  m_matrix = objCh.matrix;
2373
2374
2.16k
  long x1 = (m_doublePrecision) ? readS32() : readS16();
2375
2.16k
  long y1 = (m_doublePrecision) ? readS32() : readS16();
2376
2.16k
  long x2 = (m_doublePrecision) ? readS32() : readS16();
2377
2.16k
  long y2 = (m_doublePrecision) ? readS32() : readS16();
2378
2.16k
  transformXY(x1,y1);
2379
2.16k
  transformXY(x2,y2);
2380
2381
2.16k
  long xs1 = (x1 <= x2) ? x1 : x2;
2382
2.16k
  long xs2 = (x1 <= x2) ? x2 : x1;
2383
2.16k
  long ys1 = (y1 <= y2) ? y1 : y2;
2384
2.16k
  long ys2 = (y1 <= y2) ? y2 : y1;
2385
2386
2.16k
  WPG_DEBUG_MSG(("             x1 : %li\n", xs1));
2387
2.16k
  WPG_DEBUG_MSG(("             y1 : %li\n", ys1));
2388
2.16k
  WPG_DEBUG_MSG(("             x2 : %li\n", xs2));
2389
2.16k
  WPG_DEBUG_MSG(("             y2 : %li\n", ys2));
2390
2391
2.16k
  m_textData.x1 = toDouble(xs1)/m_xres;
2392
2.16k
  m_textData.y1 = toDouble(ys1)/m_yres;
2393
2.16k
  m_textData.x2 = toDouble(xs2)/m_xres;
2394
2.16k
  m_textData.y2 = toDouble(ys2)/m_yres;
2395
2.16k
  m_textData.flags = 0;
2396
2.16k
  m_textData.horAlign = 0;
2397
2.16k
  m_textData.vertAlign = 0;
2398
2.16k
  m_textData.baseLineAngle = 0.0;
2399
2400
2.16k
  m_drawTextData = false;
2401
2.16k
}
2402
2403
void WPG2Parser::handleTextPath()
2404
1.05k
{
2405
1.05k
  if (!m_graphicsStarted)
2406
196
    return;
2407
2408
862
  m_drawTextData = false;
2409
862
}
2410
2411
void WPG2Parser::handleTextData()
2412
17.6k
{
2413
17.6k
  if (!m_graphicsStarted)
2414
242
    return;
2415
17.3k
  if (!m_drawTextData)
2416
482
    return;
2417
16.8k
  if (m_input->isEnd() || m_input->tell() >= m_recordEnd)
2418
686
    return;
2419
2420
16.2k
  unsigned long numBytes = 0;
2421
16.2k
  const unsigned char *const data = m_input->read(m_recordEnd - m_input->tell(), numBytes);
2422
16.2k
  librevenge::RVNGBinaryData textData(data, numBytes);
2423
2424
16.2k
  WPGTextDataHandler handler(m_painter);
2425
16.2k
  librevenge::RVNGPropertyList propList;
2426
2427
16.2k
  propList.insert("svg:x", (double)m_textData.x1);
2428
16.2k
  propList.insert("svg:y", (double)m_textData.y1);
2429
16.2k
  if ((m_textData.x1 < m_textData.x2 || m_textData.x1 > m_textData.x2) &&
2430
0
          (m_textData.y1 < m_textData.y2 || m_textData.y1 > m_textData.y2))
2431
0
  {
2432
0
    propList.insert("svg:width", (m_textData.x2 - m_textData.x1));
2433
0
    propList.insert("svg:height", (m_textData.y2 - m_textData.y1));
2434
0
  }
2435
2436
16.2k
  m_painter->startTextObject(propList);
2437
2438
16.2k
  WPDocument::parseSubDocument(const_cast<librevenge::RVNGInputStream *>(textData.getDataStream()), &handler, WPD_FILE_FORMAT_WP6);
2439
2440
16.2k
  m_painter->endTextObject();
2441
2442
16.2k
  m_drawTextData = false;
2443
16.2k
}
2444
2445
void WPG2Parser::resetPalette()
2446
13.3k
{
2447
13.3k
  m_colorPalette.clear();
2448
3.42M
  for (int i=0; i<256; i++)
2449
3.40M
  {
2450
3.40M
    unsigned char red = defaultWPG2PaletteRed[i];
2451
3.40M
    unsigned char green = defaultWPG2PaletteGreen[i];
2452
3.40M
    unsigned char blue = defaultWPG2PaletteBlue[i];
2453
3.40M
    libwpg::WPGColor color(red, green, blue);
2454
3.40M
    m_colorPalette[i] = color;
2455
3.40M
  }
2456
13.3k
}
2457
2458
unsigned int WPG2Parser::getRemainingRecordLength() const
2459
98.8k
{
2460
98.8k
  if (m_recordEnd < m_input->tell())
2461
65.1k
    return 0;
2462
33.7k
  return static_cast<unsigned int>(m_recordEnd - m_input->tell() + 1);
2463
98.8k
}
2464
2465
bool WPG2Parser::checkRLESize(const unsigned bytes) const
2466
7.24k
{
2467
  // The upper bound of the number of bytes encoded in this RLE record
2468
7.24k
  const unsigned long maxSize = ((getRemainingRecordLength() + 1) / 2) * 256;
2469
7.24k
  return bytes < maxSize;
2470
7.24k
}
2471
2472
double WPG2Parser::toDouble(long x) const
2473
15.0M
{
2474
15.0M
  return m_doublePrecision ? double(x)/65536.0 : double(x);
2475
15.0M
}
2476
2477
void WPG2Parser::transformXY(long &x, long &y) const
2478
1.29M
{
2479
1.29M
  m_matrix.transform(x,y);
2480
1.29M
  x = safeSubtract(x, m_xofs);
2481
1.29M
  y = safeSubtract(y, m_yofs);
2482
1.29M
  y = safeSubtract(m_height, y);
2483
1.29M
}
2484
2485
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */