Subversion Repositories Scribus

Rev

Rev 13510 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
12971 jghali 1
/*
2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
7
 
8
/* Code inspired by KOffice libwmf and adapted for Scribus by Jean Ghali */
9
 
10
#include "scconfig.h"
11
#include "wmfimport.h"
12
 
13
#include <QCursor>
14
#include <QDrag>
15
#include <QBuffer>
16
#include <QDataStream>
17
#include <QFile>
18
#include <QMimeData>
19
#include <QPainterPath>
20
#include <QRegExp>
21
 
22
#include "customfdialog.h"
23
#include "scribus.h"
24
#include "scribusXml.h"
25
#include "propertiespalette.h"
26
#include "prefsfile.h"
27
 
28
#include <cmath>
29
#include "commonstrings.h"
30
#include "fpointarray.h"
31
#include "menumanager.h"
32
#include "prefsmanager.h"
33
#include "pageitem.h"
34
#include "scmimedata.h"
35
#include "scraction.h"
36
#include "scribuscore.h"
37
#include "scribusdoc.h"
38
#include "selection.h"
39
#include "undomanager.h"
40
#include "loadsaveplugin.h"
41
#include "util.h"
42
#include "util_icon.h"
43
#include "util_math.h"
44
#include "fonts/scfontmetrics.h"
45
 
46
using namespace std;
47
 
48
#include "wmfstruct.h"
49
#include "wmfcmd.h"
50
#include "wmfcontext.h"
51
#include "wmfhandle.h"
52
#include "metafuncs.h"
53
 
54
#define WMFIMPORT_DEBUG 0
55
#define MAX_OBJHANDLE   128
56
 
57
#define ANSI_CHARSET                    0               // ANSI charset (Windows-1252)
58
#define DEFAULT_CHARSET                 1
59
#define SYMBOL_CHARSET                  2
60
#define MAC_CHARSET                             77
61
#define SHIFTJIS_CHARSET                128             // Shift JIS charset    (Windows-932)
62
#define HANGEUL_CHARSET                 129             // Hangeul charset      (Windows-949)
63
#define JOHAB_CHARSET                   130             // Johab charset        (Windows-1361)
64
#define GB2312_CHARSET                  134             // GB2312 charset       (Windows-936)
65
#define CHINESEBIG5_CHARSET             136             // Chinese Big5 charset (Windows-950)
66
#define GREEK_CHARSET                   161             // Greek charset        (Windows-1253)
67
#define TURKISH_CHARSET                 162             // Turkish charset      (Windows-1254)
68
#define VIETNAMESE_CHARSET              163             // Vietnamese charset   (Windows-1258)
69
#define HEBREW_CHARSET                  177             // Hebrew charset       (Windows-1255)
70
#define ARABIC_CHARSET                  178             // Arabic charset       (Windows-1256)
71
#define BALTIC_CHARSET                  186             // Baltic charset       (Windows-1257)
72
#define RUSSIAN_CHARSET                 204             // Cyrillic charset     (Windows-1251)
73
#define THAI_CHARSET                    222             // Thai charset         (Windows-874)
74
#define EASTEUROPE_CHARSET              238             // Eastern european charset (Windows-1250)
75
#define OEM_CHARSET                             255
76
 
77
/* Symbol to unicode conversion table copied from http://root.cern.ch/viewvc/trunk/qt/src/TQtSymbolCodec.cxx
78
This code is placed under GPL licence (http://root.cern.ch/viewvc/trunk/LICENSE) */
79
static const ushort greek_symbol_to_unicode[64] = {
80
//
81
//  upper case letters:
82
//  ----------------
83
//   Alpha   Beta     Chi   Delta   Epsilon   Phi    Gamma    Eta
84
        0x0391, 0x0392, 0x03A7, 0x0394, 0x0395, 0x03A6, 0x0393, 0x0397,
85
//   Iota   Theta(S) Kappa  Lambda    Mu      Nu    Omicron   Pi
86
        0x0399, 0x03D1, 0x039A, 0x039B, 0x039C, 0x039D, 0x039F, 0x03A0,
87
//  Theta    Rho    Sigma    Tau    Upsilon Stigma   Omega     Xi
88
        0x0398, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03DB, 0x03A9, 0x039E,
89
//   Psi     Zeta   Sigma    Tau    Upsilon  ????   Omega     Xi
90
        0x03A8, 0x0396, 0x03EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
91
//
92
//  lower case letters:
93
//  ----------------
94
//   Alpha   Beta    Chi    Delta   Epsilon   Phi    Gamma    Eta
95
        0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x03B5, 0x03D5, 0x03B3, 0x03B7,
96
//   Iota   Phi (2) Kappa   Lambda    Mu      Nu    Omicron   Pi
97
        0x03B9, 0x03C6, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF, 0x03C0,
98
//  Theta    Rho    Sigma    Tau    Upsilon OmegaPi Omega     Xi
99
        0x03B8, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03B9, 0x03BE,
100
//   Psi     Zeta   Sigma    Tau    Upsilon  ????   Omega     Xi
101
        0x03C8, 0x03B6, 0x03EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
102
};
103
 
104
/* Symbol to unicode conversion table copied from http://root.cern.ch/viewvc/trunk/qt/src/TQtSymbolCodec.cxx
105
This code is placed under GPL licence (http://root.cern.ch/viewvc/trunk/LICENSE) */
106
static const ushort symbol_to_unicode[96] = {
107
//
108
//  upper case letters:
109
//  ----------------
110
// UPSILON  NUMBER  LessEq   Div   INFINITY ???????  CLUB   DIAMOND     
111
        0x03D2, 0x0374, 0x2264, 0x2215, 0x221E, 0x0395, 0x2663, 0x2666,
112
//   HEART  SPADE   <--->   <---             -->             RING
113
        0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193, 0x2218,
114
//  Theta    Rho    Great    ????   Propor  diff    bullet   ????
115
        0x0398, 0x03A1, 0x2265, 0x03A4, 0x221D, 0x2202, 0x2219, 0x03A8,
116
//   NonEq  Ident    ????   ellips   div     minus  ?????   aleph
117
        0x2260, 0x2261, 0xFFFD, 0x22EF, 0x2223, 0x2212, 0xFFFD, 0xFFFD,
118
//
119
//  lower case letters:
120
//  ----------------
121
//   Alpha   Beta    Chi    Delta   Epsilon   Phi    Gamma    Eta
122
        0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x03B5, 0x03D5, 0x03B3, 0x03B7,
123
//   Iota   Phi (2) Kappa   Lambda    Mu      Nu    Omicron   Pi
124
        0x03B9, 0x03C6, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF, 0x03C0,
125
//  Theta    Rho    Sigma    Tau    Upsilon OmegaPi Omega     Xi
126
        0x03B8, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03B9, 0x03BE,
127
//   Psi     Zeta   arrow    Tau    Upsilon  ????   Omega     Xi
128
        0x03C8, 0x03B6, 0x21D4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD,
129
//  lower case letters:
130
//  ----------------
131
//   Alpha   Beta    Chi    Delta   Sigma     Phi    Gamma    Eta
132
        0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x2211, 0x03D5, 0x03B3, 0x03B7,
133
//   Iota   Phi (2) Kappa   Lambda    Mu      Nu    Omicron   Pi
134
        0x03B9, 0x03C6, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF, 0x03C0,
135
//  Theta   Integr  Sigma    Tau    Upsilon OmegaPi Omega     Xi
136
        0x03B8, 0x222b, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03B9, 0x03BE,
137
//   Psi     Zeta   Sigma    Tau    Upsilon  ????   Omega     Xi
138
        0x03C8, 0x03B6, 0x03EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD
139
};
140
 
141
WMFImport::WMFImport( ScribusMainWindow* mw, int flags ) :
142
        QObject(mw)
143
{      
144
        m_tmpSel = new Selection(this, false);
145
        m_Doc    = mw->doc;
146
        unsupported = false;
147
        importFailed = false;
148
        importCanceled = true;
149
        importedColors.clear();
150
        m_docDesc = "";
151
        m_docTitle = "";
152
        interactive = (flags & LoadSavePlugin::lfInteractive);
153
 
154
        m_Valid        = false;
155
        m_ObjHandleTab = NULL;
156
        m_Dpi          = 1440;
157
}
158
 
159
WMFImport::~WMFImport()
160
{
161
        qDeleteAll(m_commands);
162
        m_commands.clear();
163
        if ( m_tmpSel) delete m_tmpSel;
164
        if ( m_ObjHandleTab )
165
        {
166
                for (int i = 0; i < MAX_OBJHANDLE; ++i)
167
                {
168
                        if (m_ObjHandleTab[i])
169
                                delete m_ObjHandleTab[i];
170
                }
171
                delete[] m_ObjHandleTab;
172
        }
173
}
174
 
175
QString WMFImport::importColor(const QColor& color)
176
{
177
        bool found = false;
178
        int r, g, b;
179
        QColor  tmpColor;
180
        QString retColorName;
181
        ColorList::Iterator it;
182
        for (it = m_Doc->PageColors.begin(); it != m_Doc->PageColors.end(); ++it)
183
        {
184
                if (it.value().getColorModel() == colorModelRGB)
185
                {
186
                        it.value().getRGB(&r, &g, &b);
187
                        tmpColor.setRgb(r, g, b);
188
                        if (color == tmpColor)
189
                        {
190
                                retColorName = it.key();
191
                                found = true;
192
                                break;
193
                        }
194
                }
195
        }
196
        if (!found)
197
        {
198
                ScColor tmp;
199
                tmp.fromQColor(color);
200
                tmp.setSpotColor(false);
201
                tmp.setRegistrationColor(false);
202
                m_Doc->PageColors.insert("FromWMF"+color.name(), tmp);
203
                importedColors.append("FromWMF"+color.name());
204
                retColorName = "FromWMF"+color.name();
205
        }
206
        return retColorName;
207
}
208
 
209
QColor WMFImport::colorFromParam( short* params )
210
{
211
        unsigned int colorRef;
212
        int red, green, blue;
213
 
214
        colorRef = toDWord( params ) & 0xffffff;
215
        red      = colorRef & 255;
216
        green    = ( colorRef>>8 ) & 255;
217
        blue     = ( colorRef>>16 ) & 255;
218
 
219
        return QColor( red, green, blue );
220
}
221
 
222
QTextCodec* WMFImport::codecFromCharset( int charset )
223
{
224
        QTextCodec* codec = NULL;
225
        if (charset == DEFAULT_CHARSET || charset == OEM_CHARSET)
226
                codec = QTextCodec::codecForLocale();
227
        else if (charset == ANSI_CHARSET)
228
                codec = QTextCodec::codecForName("windows-1252");
229
        /*else if (charset == SYMBOL_CHARSET)
230
                codec = QTextCodec::codecForLocale();// Not supported yet*/
231
        else if (charset == MAC_CHARSET)
232
                codec = QTextCodec::codecForName("Apple Roman");
233
        else if (charset == SHIFTJIS_CHARSET)
234
                codec = QTextCodec::codecForName("Shift-JIS");
235
        else if (charset == HANGEUL_CHARSET)
236
                codec = QTextCodec::codecForName("CP949");
237
        else if (charset == GB2312_CHARSET)
238
                codec = QTextCodec::codecForName("CP936");
239
        else if (charset == CHINESEBIG5_CHARSET)
240
                codec = QTextCodec::codecForName("Big5");
241
        else if (charset == GREEK_CHARSET)
242
                codec = QTextCodec::codecForName("windows-1253");
243
        else if (charset == TURKISH_CHARSET)
244
                codec = QTextCodec::codecForName("windows-1254");
245
        else if (charset == VIETNAMESE_CHARSET)
246
                codec = QTextCodec::codecForName("windows-1258");
247
        else if (charset == HEBREW_CHARSET)
248
                codec = QTextCodec::codecForName("windows-1255");
249
        else if (charset == ARABIC_CHARSET)
250
                codec = QTextCodec::codecForName("windows-1256");
251
        else if (charset == BALTIC_CHARSET)
252
                codec = QTextCodec::codecForName("windows-1257");
253
        else if (charset == RUSSIAN_CHARSET)
254
                codec = QTextCodec::codecForName("windows-1251");
255
        else if (charset == THAI_CHARSET)
256
                codec = QTextCodec::codecForName("CP874");
257
        else if (charset == EASTEUROPE_CHARSET)
258
                codec = QTextCodec::codecForName("windows-1250");
259
        return codec;
260
}
261
 
262
QString WMFImport::symbolToUnicode ( const QByteArray& chars )
263
{
264
        /*Code under GPL licence (http://root.cern.ch/viewvc/trunk/LICENSE)
265
        taken from http://root.cern.ch/viewvc/trunk/qt/src/TQtSymbolCodec.cxx*/
266
        QString r;
267
        const unsigned char * c = (const unsigned char *) chars.data();
268
 
269
        if( chars.size() == 0 ) return r;
270
 
271
        for (int i = 0; i < chars.size(); ++i)
272
        {
273
                if ( 64 < c[i] && c[i] <= 64+32 )
274
                        r.append( QChar(greek_symbol_to_unicode[c[i]-65]) );
275
                else if (64+32+1 <= c[i] && c[i] < 64+32+32+1)
276
                        r.append( QChar(greek_symbol_to_unicode[c[i]-65-32]+32) );
277
                else if (161 <= c[i] )
278
                        r.append(  QChar(symbol_to_unicode[c[i]-161]) );
279
                else
280
                        r.append( QChar(c[i]) );
281
        }
282
        return r;
283
}
284
 
285
FPointArray WMFImport::pointsFromParam( short num, short* params )
286
{
287
        FPointArray points;
288
        points.resize( num );
289
 
290
        for ( int i = 0; i < num; i++, params += 2 )
291
                points.setPoint( i, params[ 0 ], params[ 1 ] );
292
 
293
        return points;
294
}
295
 
296
FPointArray WMFImport::pointsToPolyline( const FPointArray& points, bool closePath )
297
{
298
        bool bFirst = true;
299
        double x = 0.0, y = 0.0;
300
        FPointArray polyline;
301
        polyline.svgInit();
302
        for( uint i = 0; i < points.size(); ++i )
303
        {
304
                FPoint point = points.point(i);
305
                if( bFirst )
306
                {
307
                        x = point.x();
308
                        y = point.y();
309
                        polyline.svgMoveTo(x, y);
310
                        bFirst = false;
311
                }
312
                else
313
                {
314
                        x = point.x();
315
                        y = point.y();
316
                        polyline.svgLineTo(x, y);
317
                }
318
        }
319
        if (closePath && (points.size() > 4))
320
                polyline.svgClosePath();
321
        return polyline;
322
}
323
 
324
void WMFImport::pointsToAngle( double xStart, double yStart, double xEnd, double yEnd, double& angleStart, double& angleLength )
325
{
326
        double aStart  = atan2( yStart,  xStart );
327
        double aLength = atan2( yEnd, xEnd ) - aStart;
328
 
329
        angleStart  = (int)(aStart * 180.0 / 3.14166);
330
        angleLength = (int)(aLength * 180.0 / 3.14166);
331
        if ( angleLength < 0 ) angleLength = 360.0 + angleLength;
332
}
333
 
13371 jghali 334
bool WMFImport::import(QString fname, const TransactionSettings& trSettings, int flags)
12971 jghali 335
{
336
        if (!loadWMF(fname))
337
        {
338
                importFailed = true;
339
                return false;
340
        }
341
        QString CurDirP = QDir::currentPath();
342
        QFileInfo efp(fname);
343
        QDir::setCurrent(efp.path());
13371 jghali 344
        bool success = importWMF(trSettings, flags);
12971 jghali 345
        QDir::setCurrent(CurDirP);
346
        return success;
347
}
348
 
349
bool WMFImport::loadWMF( const QString &fileName )
350
{
351
        QFile file( fileName );
352
 
353
        if ( !file.exists() )
354
        {
355
                cerr << "File " << QFile::encodeName(fileName).data() << " does not exist" << endl;
356
                return false;
357
        }
358
 
359
        if ( !file.open( QIODevice::ReadOnly ) )
360
        {
361
                cerr << "Cannot open file " << QFile::encodeName(fileName).data() << endl;
362
                return false;
363
        }
364
 
365
        QByteArray ba = file.readAll();
366
        file.close();
367
 
368
        QBuffer buffer( &ba );
369
        buffer.open( QIODevice::ReadOnly );
370
        return loadWMF( buffer );
371
}
372
 
373
bool WMFImport::loadWMF( QBuffer &buffer )
374
{
375
        QDataStream st;
376
        WmfEnhMetaHeader eheader;
377
        WmfMetaHeader header;
378
        WmfPlaceableHeader pheader;
379
        WORD16 checksum;
380
        int filePos, idx, i;
381
        WmfCmd *cmd;
382
        WORD32 rdSize;
383
        WORD16 rdFunc;
384
 
385
        header.mtSize = 0;
386
        header.mtHeaderSize = 0;
387
        header.mtNoParameters = 0;
388
 
389
        qDeleteAll(m_commands);
390
        m_commands.clear();
391
 
392
        st.setDevice( &buffer );
393
        st.setByteOrder( QDataStream::LittleEndian ); // Great, I love Qt !
394
 
395
        //----- Read placeable metafile header
396
        st >> pheader.key;
13325 jghali 397
        m_IsPlaceable = (pheader.key == (WORD32) APMHEADER_KEY);
12971 jghali 398
        if ( m_IsPlaceable )
399
        {
400
                st >> pheader.hmf;
401
                st >> pheader.bbox.left;
402
                st >> pheader.bbox.top;
403
                st >> pheader.bbox.right;
404
                st >> pheader.bbox.bottom;
405
                st >> pheader.inch;
406
                st >> pheader.reserved;
407
                st >> pheader.checksum;
408
                checksum = calcCheckSum( &pheader );
409
                if ( pheader.checksum!=checksum ) m_IsPlaceable = false;
410
 
411
                m_Dpi = pheader.inch;
412
                m_BBox.setLeft( pheader.bbox.left );
413
                m_BBox.setTop( pheader.bbox.top );
414
                m_BBox.setRight( pheader.bbox.right );
415
                m_BBox.setBottom( pheader.bbox.bottom );
416
                m_HeaderBoundingBox = m_BBox;
417
                if ( WMFIMPORT_DEBUG )
418
                {
419
                        cerr << endl << "-------------------------------------------------" << endl;
420
                        cerr << "WMF Placeable Header ( " << static_cast<int>(sizeof( pheader ) ) << "):" << endl;
421
                        cerr << "  bbox=( " << m_BBox.left() << "; " << m_BBox.top() << "; " << m_BBox.width() << "; " << m_BBox.height() << ")" << endl;
422
                        cerr << "  inch=" << pheader.inch << endl;
423
                        cerr << "  checksum=" << pheader.checksum << "( " << (pheader.checksum==checksum?"ok":"wrong") << " )" << endl;
424
                }
425
        }
426
        else buffer.seek( 0 );
427
 
428
        //----- Read as enhanced metafile header
429
        filePos = buffer.pos();
430
        st >> eheader.iType;
431
        st >> eheader.nSize;
432
        st >> eheader.rclBounds.left;
433
        st >> eheader.rclBounds.top;
434
        st >> eheader.rclBounds.right;
435
        st >> eheader.rclBounds.bottom;
436
        st >> eheader.rclFrame.left;
437
        st >> eheader.rclFrame.top;
438
        st >> eheader.rclFrame.right;
439
        st >> eheader.rclFrame.bottom;
440
        st >> eheader.dSignature;
441
        m_IsEnhanced = ( eheader.dSignature==ENHMETA_SIGNATURE );
442
        if ( m_IsEnhanced ) // is it really enhanced ?
443
        {
444
                st >> eheader.nVersion;
445
                st >> eheader.nBytes;
446
                st >> eheader.nRecords;
447
                st >> eheader.nHandles;
448
                st >> eheader.sReserved;
449
                st >> eheader.nDescription;
450
                st >> eheader.offDescription;
451
                st >> eheader.nPalEntries;
452
                st >> eheader.szlDevice.width;
453
                st >> eheader.szlDevice.height;
454
                st >> eheader.szlMillimeters.width;
455
                st >> eheader.szlMillimeters.height;
456
 
457
                if ( WMFIMPORT_DEBUG )
458
                {
459
                        cerr << endl << "-------------------------------------------------" << endl;
460
                        cerr << "WMF Extended Header:" << endl;
461
                        cerr << "  iType=" << eheader.iType << endl;
462
                        cerr << "  nSize=" << eheader.nSize << endl;
463
                        cerr << "  rclBounds=( " << eheader.rclBounds.left << "; " << eheader.rclBounds.top << "; "
464
                                          << eheader.rclBounds.right << "; " << eheader.rclBounds.bottom << ")" << endl;
465
                        cerr << "  rclFrame=( " << eheader.rclFrame.left << "; " << eheader.rclFrame.top << "; "
466
                                          << eheader.rclFrame.right << "; " << eheader.rclFrame.bottom << ")" << endl;
467
                        cerr << "  nBytes=" << eheader.nBytes << endl;
468
                        cerr << "\nNOT YET IMPLEMENTED, SORRY." << endl;
469
                }
470
        }
471
        else // no, not enhanced
472
        {
473
                //----- Read as standard metafile header
474
                buffer.seek( filePos );
475
                st >> header.mtType;
476
                st >> header.mtHeaderSize;
477
                st >> header.mtVersion;
478
                st >> header.mtSize;
479
                st >> header.mtNoObjects;
480
                st >> header.mtMaxRecord;
481
                st >> header.mtNoParameters;
482
                if ( WMFIMPORT_DEBUG ) {
483
                        cerr << "WMF Header: " <<  "mtSize=" << header.mtSize << endl;
484
                }
485
        }
486
 
487
        //----- Test header validity
488
        m_Valid = ((header.mtHeaderSize == 9) && (header.mtNoParameters == 0)) || m_IsEnhanced || m_IsPlaceable;
489
        if ( m_Valid )
490
        {
491
                //----- Read Metafile Records
492
                rdFunc = -1;
493
                while ( !st.atEnd() && (rdFunc != 0) )
494
                {
495
                        st >> rdSize;
496
                        st >> rdFunc;
497
                        idx = findFunc( rdFunc );
498
                        rdSize -= 3;
499
 
500
                        cmd = new WmfCmd;
501
                        m_commands.append(cmd);
502
 
503
                        cmd->funcIndex = idx;
504
                        cmd->numParam = rdSize;
505
                        cmd->params = new WORD16[ rdSize ];
506
 
507
                        for ( i=0; i<rdSize && !st.atEnd(); i++ )
508
                                st >> cmd->params[ i ];
509
 
510
 
511
                        if ( rdFunc == 0x020B && !m_IsPlaceable) {         // SETWINDOWORG: dimensions
512
                                m_BBox.setLeft( qMin((int) cmd->params[ 1 ], m_BBox.left()) );
513
                                m_BBox.setTop ( qMin((int) cmd->params[ 0 ], m_BBox.top()) );
514
                        }
515
                        if ( rdFunc == 0x020C && !m_IsPlaceable ) {         // SETWINDOWEXT: dimensions
516
                                m_BBox.setWidth ( qMax((int) cmd->params[ 1 ], m_BBox.width()) );
517
                                m_BBox.setHeight( qMax((int) cmd->params[ 0 ], m_BBox.height()));
518
                        }
519
 
520
                        if ( i<rdSize )
521
                        {
522
                                cerr << "WMF : file truncated !" << endl;
523
                                return false;
524
                        }
525
                }
526
                //----- Test records validities
527
                m_Valid = (rdFunc == 0) && (m_BBox.width() != 0) && (m_BBox.height() != 0);
528
                if ( !m_Valid ) {
529
                        cerr << "WMF : incorrect file format !" << endl;
530
                }
531
        }
532
        else {
533
                cerr << "WMF Header : incorrect header !" << endl;
534
        }
535
 
536
        buffer.close();
537
        return m_Valid;
538
}
539
 
13371 jghali 540
bool WMFImport::importWMF(const TransactionSettings& trSettings, int flags)
12971 jghali 541
{
542
        bool ret = false;
543
        //double scale = (m_Dpi > 288) ? 288.0 / m_Dpi : 1.0;
544
        double scale  = (m_Dpi > 0) ? 72.0 / m_Dpi : 0.05;
545
        double width  = m_BBox.width() * scale;
546
        double height = m_BBox.height() * scale;
547
        if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
548
        {
549
                m_Doc->setPage(fabs(width), fabs(height), 0, 0, 0, 0, 0, 0, false, false);
550
                m_Doc->addPage(0);
551
                m_Doc->view()->addPage(0);
552
        }
553
        else
554
        {
555
                if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
556
                {
557
                        m_Doc=ScCore->primaryMainWindow()->doFileNew(fabs(width), fabs(height), 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
558
                        ScCore->primaryMainWindow()->HaveNewDoc();
559
                        ret = true;
560
                }
561
        }
562
        if ((ret) || (!interactive))
563
        {
564
                if (width > height)
565
                        m_Doc->PageOri = 1;
566
                else
567
                        m_Doc->PageOri = 0;
568
                m_Doc->m_pageSize = "Custom";
569
        }
570
        FPoint minSize = m_Doc->minCanvasCoordinate;
571
        FPoint maxSize = m_Doc->maxCanvasCoordinate;
572
        FPoint cOrigin = m_Doc->view()->canvasOrigin();
573
        m_Doc->view()->Deselect();
574
        m_Doc->setLoading(true);
575
        m_Doc->DoDrawing = false;
576
        m_Doc->view()->updatesOn(false);
14751 fschmid 577
        bool wasScriptRunning = m_Doc->scMW()->ScriptRunning;
12971 jghali 578
        m_Doc->scMW()->ScriptRunning = true;
579
        qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
580
        //gc->Family = m_Doc->toolSettings.defFont;
581
        m_Doc->PageColors.ensureBlackAndWhite();
582
        //m_gc.push( gc );
583
        QList<PageItem*> Elements = parseWmfCommands();
584
        if (flags & LoadSavePlugin::lfCreateDoc)
585
        {
586
                m_Doc->documentInfo.setTitle(m_docTitle);
587
                m_Doc->documentInfo.setComments(m_docDesc);
588
        }
589
        m_tmpSel->clear();
590
        if (Elements.count() == 0)
591
        {
592
                importFailed = true;
593
                if (importedColors.count() != 0)
594
                {
595
                        for (int cd = 0; cd < importedColors.count(); cd++)
596
                        {
597
                                m_Doc->PageColors.remove(importedColors[cd]);
598
                        }
599
                }
600
        }
601
        if (Elements.count() > 1)
602
        {
603
                bool isGroup = true;
604
                int firstElem = -1;
605
                if (Elements.at(0)->Groups.count() != 0)
606
                        firstElem = Elements.at(0)->Groups.top();
607
                for (int bx = 0; bx < Elements.count(); ++bx)
608
                {
609
                        PageItem* bxi = Elements.at(bx);
610
                        if (bxi->Groups.count() != 0)
611
                        {
612
                                if (bxi->Groups.top() != firstElem)
613
                                        isGroup = false;
614
                        }
615
                        else
616
                                isGroup = false;
617
                }
618
                if (!isGroup)
619
                {
620
                        double minx = 99999.9;
621
                        double miny = 99999.9;
622
                        double maxx = -99999.9;
623
                        double maxy = -99999.9;
624
                        uint lowestItem = 999999;
625
                        uint highestItem = 0;
626
                        for (int a = 0; a < Elements.count(); ++a)
627
                        {
628
                                Elements.at(a)->Groups.push(m_Doc->GroupCounter);
629
                                PageItem* currItem = Elements.at(a);
630
                                lowestItem = qMin(lowestItem, currItem->ItemNr);
631
                                highestItem = qMax(highestItem, currItem->ItemNr);
632
                                double x1, x2, y1, y2;
633
                                currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
634
                                minx = qMin(minx, x1);
635
                                miny = qMin(miny, y1);
636
                                maxx = qMax(maxx, x2);
637
                                maxy = qMax(maxy, y2);
638
                        }
639
                        double gx = minx;
640
                        double gy = miny;
641
                        double gw = maxx - minx;
642
                        double gh = maxy - miny;
643
                        PageItem *high = m_Doc->Items->at(highestItem);
644
                        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, gx, gy, gw, gh, 0, m_Doc->toolSettings.dBrush, m_Doc->toolSettings.dPen, true);
645
                        PageItem *neu = m_Doc->Items->takeAt(z);
646
                        m_Doc->Items->insert(lowestItem, neu);
647
                        neu->Groups.push(m_Doc->GroupCounter);
648
                        neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
649
                        neu->AutoName = false;
650
                        neu->isGroupControl = true;
651
                        neu->groupsLastItem = high;
652
                        for (int a = 0; a < m_Doc->Items->count(); ++a)
653
                        {
654
                                m_Doc->Items->at(a)->ItemNr = a;
655
                        }
656
                        neu->setRedrawBounding();
657
                        neu->setTextFlowMode(PageItem::TextFlowDisabled);
658
                        Elements.prepend(neu);
659
                        m_Doc->GroupCounter++;
660
                }
661
        }
662
        m_Doc->DoDrawing = true;
14751 fschmid 663
        m_Doc->scMW()->ScriptRunning = wasScriptRunning;
12971 jghali 664
        if (interactive)
665
                m_Doc->setLoading(false);
666
        qApp->setOverrideCursor(QCursor(Qt::ArrowCursor));
667
        if ((Elements.count() > 0) && (!ret) && (interactive))
668
        {
669
                if (flags & LoadSavePlugin::lfScripted)
670
                {
671
                        bool loadF = m_Doc->isLoading();
672
                        m_Doc->setLoading(false);
673
                        m_Doc->changed();
674
                        m_Doc->setLoading(loadF);
675
                        m_Doc->m_Selection->delaySignalsOn();
676
                        for (int dre=0; dre<Elements.count(); ++dre)
677
                        {
678
                                m_Doc->m_Selection->addItem(Elements.at(dre), true);
679
                        }
680
                        m_Doc->m_Selection->delaySignalsOff();
681
                        m_Doc->m_Selection->setGroupRect();
682
                        m_Doc->view()->updatesOn(true);
683
                        importCanceled = false;
684
                }
685
                else
686
                {
687
                        m_Doc->DragP = true;
688
                        m_Doc->DraggedElem = 0;
689
                        m_Doc->DragElements.clear();
690
                        m_Doc->m_Selection->delaySignalsOn();
691
                        for (int dre=0; dre<Elements.count(); ++dre)
692
                        {
693
                                m_Doc->DragElements.append(Elements.at(dre)->ItemNr);
694
                                m_tmpSel->addItem(Elements.at(dre), true);
695
                        }
696
                        ScriXmlDoc *ss = new ScriXmlDoc();
697
                        m_tmpSel->setGroupRect();
698
                        ScElemMimeData* md = new ScElemMimeData();
699
                        md->setScribusElem(ss->WriteElem(m_Doc, m_Doc->view(), m_tmpSel));
700
                        delete ss;
701
/*#ifndef QT_MAC*/
702
// see #2526
703
                        m_Doc->itemSelection_DeleteItem(m_tmpSel);
704
/*#endif*/
705
                        m_Doc->view()->updatesOn(true);
706
                        m_Doc->m_Selection->delaySignalsOff();
13371 jghali 707
                        // We must copy the TransationSettings object as it is owned
708
                        // by handleObjectImport method afterwards
709
                        TransactionSettings* transacSettings = new TransactionSettings(trSettings);
710
                        m_Doc->view()->handleObjectImport(md, transacSettings);
12971 jghali 711
                        m_Doc->DragP = false;
712
                        m_Doc->DraggedElem = 0;
713
                        m_Doc->DragElements.clear();
714
                }
715
        }
716
        else
717
        {
718
                bool loadF = m_Doc->isLoading();
719
                m_Doc->setLoading(false);
720
                m_Doc->changed();
721
                m_Doc->reformPages();
722
                m_Doc->view()->updatesOn(true);
723
                m_Doc->setLoading(loadF);
724
        }
725
        return true;
726
}
727
 
728
QList<PageItem*> WMFImport::parseWmfCommands(void)
729
{
730
        int idx, i;
731
        const WmfCmd* cmd;
732
        QList<PageItem*> elements;
733
 
734
        m_context.reset();
735
 
736
        if ( !m_Valid )  return elements;
737
 
738
        if ( m_ObjHandleTab ) delete[] m_ObjHandleTab;
739
        m_ObjHandleTab = new WmfObjHandle* [ MAX_OBJHANDLE ];
740
        for ( i = MAX_OBJHANDLE-1; i >= 0; i-- )
741
                m_ObjHandleTab[ i ] = NULL;
742
 
743
        if ( WMFIMPORT_DEBUG )  {
744
                cerr << "Bounding box : " << m_BBox.left() << " " << m_BBox.top() << " " << m_BBox.right() << " " << m_BBox.bottom() << endl;
745
        }
746
 
747
        double scale  = (m_Dpi > 0) ? 72.0 / m_Dpi : 0.05;
748
        m_context.setViewportOrg( 0, 0 );
749
        m_context.setViewportExt( m_BBox.width() * scale, m_BBox.height() * scale );
750
        m_context.setWindowOrg( m_BBox.left(), m_BBox.bottom() );
751
        m_context.setWindowExt( m_BBox.width(), m_BBox.height() );
752
 
753
        for (int index = 0; index < m_commands.count(); ++index)
754
        {
755
                cmd = m_commands.at(index);
756
                idx = cmd->funcIndex;
757
                ( this->*metaFuncTab[ idx ].method )( elements, cmd->numParam, cmd->params );
758
 
759
                if ( WMFIMPORT_DEBUG )  {
760
                        QString str = "", param;
761
                        if ( metaFuncTab[ idx ].name == NULL ) {
762
                                str += "UNKNOWN ";
763
                        }
764
                        if ( metaFuncTab[ idx ].method == &WMFImport::noop ) {
765
                                str += "UNIMPLEMENTED ";
766
                        }
767
                        str += metaFuncTab[ idx ].name;
768
                        str += " : ";
769
 
770
                        for ( i=0 ; i < cmd->numParam ; i++ ) {
771
                                param.setNum( cmd->params[ i ] );
772
                                str += param;
773
                                str += " ";
774
                        }
775
                        cerr << str.toAscii().data() << endl;
776
                }
777
        }
778
        return elements;
779
}
780
 
781
void WMFImport::finishCmdParsing( PageItem* item )
782
{
783
        QMatrix gcm  = m_context.worldMatrix();
784
        double coeff1 = sqrt(gcm.m11() * gcm.m11() + gcm.m12() * gcm.m12());
785
        double coeff2 = sqrt(gcm.m21() * gcm.m21() + gcm.m22() * gcm.m22());
786
        if( item->asImageFrame() )
787
        {
788
                item->moveBy(gcm.dx(), gcm.dy());
789
                item->setWidthHeight(item->width() * gcm.m11(), item->height() * gcm.m22());
790
                item->setLineWidth(qMax(item->lineWidth() * (coeff1 + coeff2) / 2.0, 0.25));
13097 subik 791
                if (item->PictureIsAvailable)
12971 jghali 792
                        item->setImageXYScale(item->width() / item->pixm.width(), item->height() / item->pixm.height());
793
        }
794
        else if( item->asTextFrame() )
795
        {
796
                item->setLineWidth(qMax(item->lineWidth() * (coeff1 + coeff2) / 2.0, 0.25));
797
        }
798
        else
799
        {
800
                item->ClipEdited = true;
801
                item->FrameType = 3;
802
                item->PoLine.map(gcm);
803
                item->setLineWidth(qMax(item->lineWidth() * (coeff1 + coeff2) / 2.0, 0.25));
804
                FPoint wh = getMaxClipF(&item->PoLine);
805
                item->setWidthHeight(wh.x(), wh.y());
806
                m_Doc->AdjustItemSize(item);
807
        }
808
        item->setRedrawBounding();
809
        item->OwnPage   = m_Doc->OnPage(item);
810
        item->PLineEnd  = m_context.pen().capStyle();
811
        item->PLineJoin = m_context.pen().joinStyle();
812
        item->setTextFlowMode(PageItem::TextFlowDisabled);
813
        //item->DashOffset = gc->dashOffset;
814
        //item->DashValues = gc->dashArray;
815
}
816
 
817
void WMFImport::setWindowOrg( QList<PageItem*>& /*items*/, long, short* params )
818
{
819
        m_context.setWindowOrg( params[ 1 ], params[ 0 ] );
820
}
821
 
822
void WMFImport::setWindowExt( QList<PageItem*>& /*items*/, long, short* params )
823
{
824
        m_context.setWindowExt( params[ 1 ], params[ 0 ] );
825
}
826
 
827
void WMFImport::lineTo( QList<PageItem*>& items, long, short* params )
828
{
829
        double BaseX = m_Doc->currentPage()->xOffset();
830
        double BaseY = m_Doc->currentPage()->yOffset();
831
        QPoint currentPos = m_context.position();
832
        bool   doStroke = (m_context.pen().style() != Qt::NoPen);
833
        if (doStroke)
834
        {
835
                double x1 = currentPos.x();
836
                double y1 = currentPos.y();
837
                double x2 = params[1];
838
                double y2 = params[0];
839
                double  lineWidth = m_context.pen().width();
840
                QString lineColor = importColor(m_context.pen().color());
841
                int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, lineWidth, CommonStrings::None, lineColor, true);
842
                PageItem* ite = m_Doc->Items->at(z);
843
                ite->PoLine.resize(4);
844
                ite->PoLine.setPoint(0, FPoint(x1, y1));
845
                ite->PoLine.setPoint(1, FPoint(x1, y1));
846
                ite->PoLine.setPoint(2, FPoint(x2, y2));
847
                ite->PoLine.setPoint(3, FPoint(x2, y2));
848
                finishCmdParsing(ite);
849
                items.append(ite);
850
        }
851
        m_context.setPosition( QPoint(params[1], params[0]) );
852
}
853
 
854
void WMFImport::moveTo( QList<PageItem*>& /*items*/, long, short* params )
855
{
856
        m_context.setPosition( QPoint(params[1], params[0]) );
857
}
858
 
859
void WMFImport::ellipse( QList<PageItem*>& items, long, short* params )
860
{
861
        double BaseX = m_Doc->currentPage()->xOffset();
862
        double BaseY = m_Doc->currentPage()->yOffset();
863
        double rx = (params[ 1 ] - params[ 3 ]) / 2.0;
864
        double ry = (params[ 0 ] - params[ 2 ]) / 2.0;
865
        double px = (params[ 1 ] + params[ 3 ]) / 2.0 - rx;
866
        double py = (params[ 0 ] + params[ 2 ]) / 2.0 - ry;
867
        bool   doFill = m_context.brush().style() != Qt::NoBrush;
868
        bool   doStroke = m_context.pen().style() != Qt::NoPen;
869
        QString fillColor   = doFill ? importColor( m_context.brush().color() ) : CommonStrings::None;
870
        QString strokeColor = doStroke ? importColor( m_context.pen().color() ) : CommonStrings::None;
871
        double  lineWidth   = m_context.pen().width();
872
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, rx * 2.0, ry * 2.0, lineWidth, fillColor, strokeColor, true);
873
        PageItem* ite = m_Doc->Items->at(z);
874
        QMatrix mm(1.0, 0.0, 0.0, 1.0, px, py);
875
        ite->PoLine.map(mm);
876
        finishCmdParsing(ite);
877
        items.append(ite);
878
}
879
 
880
void WMFImport::polygon( QList<PageItem*>& items, long, short* params )
881
{
882
        //cerr << "WMFImport::polygon unimplemented" << endl;
883
        double  BaseX = m_Doc->currentPage()->xOffset();
884
        double  BaseY = m_Doc->currentPage()->yOffset();
885
        bool    doFill = m_context.brush().style() != Qt::NoBrush;
886
        bool    doStroke = m_context.pen().style() != Qt::NoPen;
887
        QString fillColor   = doFill ? importColor( m_context.brush().color() ) : CommonStrings::None;
888
        QString strokeColor = doStroke ? importColor( m_context.pen().color() ) : CommonStrings::None;
889
        double  lineWidth   = m_context.pen().width();
890
        if (doStroke && lineWidth <= 0.0 )
891
                lineWidth = 1.0;
892
        FPointArray paramPoints = pointsFromParam( params[0], &params[1] );
893
        FPointArray points      = pointsToPolyline( paramPoints, true );
894
        if( paramPoints.size() > 0 )
895
        {
896
                int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, lineWidth, fillColor, strokeColor, true);
897
                PageItem* ite = m_Doc->Items->at(z);
898
                ite->PoLine = points;
899
                ite->fillRule = !m_context.windingFill();
900
                finishCmdParsing(ite);
901
                items.append(ite);
902
        }
903
}
904
 
905
void WMFImport::polyPolygon( QList<PageItem*>& items, long num, short* params )
906
{
907
        int numPolys   = params[0];
908
        int pointIndex = params[0] + 1;
909
        for (int i = 0; i < numPolys; ++i)
910
        {
911
                short  numPoints  = params[i + 1];
912
                short* paramArray = new short[1 + 2 * numPoints];
913
                paramArray[0] = numPoints;
914
                memcpy(&paramArray[1], &params[pointIndex], 2 * numPoints * sizeof(short));
915
                polygon(items, num, paramArray);
916
                delete[] paramArray;
917
                pointIndex += (2 * numPoints);
918
        }
919
}
920
 
921
void WMFImport::polyline( QList<PageItem*>& items, long, short* params )
922
{
923
        //cerr << "WMFImport::polyline unimplemented" << endl;
924
        double  BaseX = m_Doc->currentPage()->xOffset();
925
        double  BaseY = m_Doc->currentPage()->yOffset();
926
        bool    doStroke = m_context.pen().style() != Qt::NoPen;
927
        QString fillColor   = CommonStrings::None;
928
        QString strokeColor = doStroke ? importColor( m_context.pen().color() ) : CommonStrings::None;
929
        double  lineWidth   = m_context.pen().width();
930
        if (doStroke && lineWidth <= 0.0 )
931
                lineWidth = 1.0;
932
        FPointArray paramPoints = pointsFromParam( params[0], &params[1] );
933
        FPointArray points      = pointsToPolyline( paramPoints, false );
934
        if( paramPoints.size() > 0 )
935
        {
936
                int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, lineWidth, fillColor, strokeColor, true);
937
                PageItem* ite = m_Doc->Items->at(z);
938
                ite->PoLine = points;
939
                finishCmdParsing(ite);
940
                items.append(ite);
941
        }
942
}
943
 
944
void WMFImport::rectangle( QList<PageItem*>& items, long, short* params )
945
{
946
        //cerr << "WMFImport::rectangle unimplemented" << endl;
947
        double  BaseX = m_Doc->currentPage()->xOffset();
948
        double  BaseY = m_Doc->currentPage()->yOffset();
949
        bool    doFill = m_context.brush().style() != Qt::NoBrush;
950
        bool    doStroke = m_context.pen().style() != Qt::NoPen;
951
        QString fillColor   = doFill ? importColor( m_context.brush().color() ) : CommonStrings::None;
952
        QString strokeColor = doStroke ? importColor( m_context.pen().color() ) : CommonStrings::None;
953
        double  lineWidth   = m_context.pen().width();
954
        if (doStroke && lineWidth <= 0.0 )
955
                lineWidth = 1.0;
956
        double x = ((params[3] - params[1]) > 0) ? params[1] : params[3];
957
        double y = ((params[2] - params[0]) > 0) ? params[0] : params[2];
958
        double width  = fabs((double) params[3] - params[1]);
959
        double height = fabs((double) params[2] - params[0]);
960
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, width, height, lineWidth, fillColor, strokeColor, true);
961
        PageItem* ite = m_Doc->Items->at(z);
962
        QMatrix mm(1.0, 0.0, 0.0, 1.0, x, y);
963
        ite->PoLine.map(mm);
964
        finishCmdParsing(ite);
965
        items.append(ite);
966
}
967
 
968
void WMFImport::roundRect( QList<PageItem*>& items, long, short* params )
969
{
970
        //cerr << "WMFImport::roundRect unimplemented" << endl;
971
        double  BaseX = m_Doc->currentPage()->xOffset();
972
        double  BaseY = m_Doc->currentPage()->yOffset();
973
        bool    doFill = m_context.brush().style() != Qt::NoBrush;
974
        bool    doStroke = m_context.pen().style() != Qt::NoPen;
975
        QString fillColor   = doFill ? importColor( m_context.brush().color() ) : CommonStrings::None;
976
        QString strokeColor = doStroke ? importColor( m_context.pen().color() ) : CommonStrings::None;
977
        double  lineWidth   = m_context.pen().width();
978
        if (doStroke && lineWidth <= 0.0 )
979
                lineWidth = 1.0;
980
        double x = ((params[5] - params[3]) > 0) ? params[3] : params[5];
981
        double y = ((params[4] - params[2]) > 0) ? params[2] : params[4];
982
        double width  = fabs((double) params[5] - params[3]);
983
        double height = fabs((double) params[4] - params[2]);
984
        double rx     = params[1] / 2.0;
985
        double ry     = params[0] / 2.0;
986
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, width, height, lineWidth, fillColor, strokeColor, true);
987
        PageItem* ite = m_Doc->Items->at(z);
988
        if ((rx != 0.0) || (ry != 0.0))
989
        {
990
                ite->setCornerRadius(qMax(rx, ry));
991
                ite->SetFrameRound();
992
                m_Doc->setRedrawBounding(ite);
993
        }
994
        QMatrix mm(1.0, 0.0, 0.0, 1.0, x, y);
995
        ite->PoLine.map(mm);
996
        finishCmdParsing(ite);
997
        items.append(ite);
998
}
999
 
1000
void WMFImport::arc( QList<PageItem*>& items, long, short* params )
1001
{
1002
        FPointArray  pointArray;
1003
        QPainterPath painterPath;
1004
        double  BaseX = m_Doc->currentPage()->xOffset();
1005
        double  BaseY = m_Doc->currentPage()->yOffset();
1006
        bool    doStroke = m_context.pen().style() != Qt::NoPen;
1007
        QString fillColor   = CommonStrings::None;
1008
        QString strokeColor = doStroke ? importColor( m_context.pen().color() ) : CommonStrings::None;
1009
        double  lineWidth   = m_context.pen().width();
1010
        if (doStroke && lineWidth <= 0.0 )
1011
                lineWidth = 1.0;
1012
        double  angleStart, angleLength;
1013
        double  x = ((params[7] - params[5]) > 0) ? params[5] : params[7];
1014
        double  y = ((params[6] - params[4]) > 0) ? params[4] : params[6];
1015
        double  xCenter = (params[5] + params[7]) / 2.0;
1016
        double  yCenter = (params[4] + params[6]) / 2.0;
1017
        double  xWidth  =  fabs((double) params[5] - params[7]);
1018
        double  yHeight =  fabs((double) params[4] - params[6]);
1019
        pointsToAngle(params[3] - xCenter, yCenter - params[2], params[1] - xCenter, yCenter - params[0], angleStart, angleLength);
1020
        painterPath.arcMoveTo(x, y, xWidth, yHeight, angleStart);
1021
        painterPath.arcTo(x, y, xWidth, yHeight, angleStart, angleLength);
1022
        pointArray.fromQPainterPath(painterPath);
1023
        if( pointArray.size() > 0 )
1024
        {
1025
                int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, lineWidth, fillColor, strokeColor, true);
1026
                PageItem* ite = m_Doc->Items->at(z);
1027
                ite->PoLine = pointArray;
1028
                finishCmdParsing(ite);
1029
                items.append(ite);
1030
        }
1031
}
1032
 
1033
void WMFImport::chord( QList<PageItem*>& items, long, short* params )
1034
{
1035
        QPointF      firstPoint;
1036
        FPointArray  pointArray;
1037
        QPainterPath painterPath;
1038
        double  BaseX = m_Doc->currentPage()->xOffset();
1039
        double  BaseY = m_Doc->currentPage()->yOffset();
1040
        bool    doFill   = m_context.brush().style() != Qt::NoBrush;
1041
        bool    doStroke = m_context.pen().style() != Qt::NoPen;
1042
        QString fillColor   = doFill ? importColor( m_context.brush().color() ) : CommonStrings::None;
1043
        QString strokeColor = doStroke ? importColor( m_context.pen().color() ) : CommonStrings::None;
1044
        double  lineWidth   = m_context.pen().width();
1045
        if (doStroke && lineWidth <= 0.0 )
1046
                lineWidth = 1.0;
1047
        double  angleStart, angleLength;
1048
        double  x = ((params[7] - params[5]) > 0) ? params[5] : params[7];
1049
        double  y = ((params[6] - params[4]) > 0) ? params[4] : params[6];
1050
        double  xCenter = (params[5] + params[7]) / 2.0;
1051
        double  yCenter = (params[4] + params[6]) / 2.0;
1052
        double  xWidth  =  fabs((double) params[5] - params[7]);
1053
        double  yHeight =  fabs((double) params[4] - params[6]);
1054
        pointsToAngle(params[3] - xCenter, yCenter - params[2], params[1] - xCenter, yCenter - params[0], angleStart, angleLength);
1055
        painterPath.arcMoveTo(x, y, xWidth, yHeight, angleStart);
1056
        firstPoint = painterPath.currentPosition();
1057
        painterPath.arcTo (x, y, xWidth, yHeight, angleStart, angleLength);
1058
        painterPath.lineTo(firstPoint);
1059
        pointArray.fromQPainterPath(painterPath);
1060
        if( pointArray.size() > 0 )
1061
        {
1062
                int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, lineWidth, fillColor, strokeColor, true);
1063
                PageItem* ite = m_Doc->Items->at(z);
1064
                ite->PoLine = pointArray;
1065
                finishCmdParsing(ite);
1066
                items.append(ite);
1067
        }
1068
}
1069
 
1070
void WMFImport::pie( QList<PageItem*>& items, long, short* params )
1071
{
1072
        QPointF      firstPoint;
1073
        FPointArray  pointArray;
1074
        QPainterPath painterPath;
1075
        double  BaseX = m_Doc->currentPage()->xOffset();
1076
        double  BaseY = m_Doc->currentPage()->yOffset();
1077
        bool    doFill   = m_context.brush().style() != Qt::NoBrush;
1078
        bool    doStroke = m_context.pen().style() != Qt::NoPen;
1079
        QString fillColor   = doFill ? importColor( m_context.brush().color() ) : CommonStrings::None;
1080
        QString strokeColor = doStroke ? importColor( m_context.pen().color() ) : CommonStrings::None;
1081
        double  lineWidth   = m_context.pen().width();
1082
        if (doStroke && lineWidth <= 0.0 )
1083
                lineWidth = 1.0;
1084
        double  angleStart, angleLength;
1085
        double  x = ((params[7] - params[5]) > 0) ? params[5] : params[7];
1086
        double  y = ((params[6] - params[4]) > 0) ? params[4] : params[6];
1087
        double  xCenter = (params[5] + params[7]) / 2.0;
1088
        double  yCenter = (params[4] + params[6]) / 2.0;
1089
        double  xWidth  =  fabs((double) params[5] - params[7]);
1090
        double  yHeight =  fabs((double) params[4] - params[6]);
1091
        pointsToAngle(params[3] - xCenter, yCenter - params[2], params[1] - xCenter, yCenter - params[0], angleStart, angleLength);
1092
        painterPath.arcMoveTo(x,y, xWidth, yHeight, angleStart);
1093
        firstPoint = painterPath.currentPosition();
1094
        painterPath.arcTo (x, y, xWidth, yHeight, angleStart, angleLength);
1095
        painterPath.lineTo(xCenter, yCenter);
1096
        painterPath.lineTo(firstPoint);
1097
        pointArray.fromQPainterPath(painterPath);
1098
        if( pointArray.size() > 0 )
1099
        {
1100
                int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, lineWidth, fillColor, strokeColor, true);
1101
                PageItem* ite = m_Doc->Items->at(z);
1102
                ite->PoLine = pointArray;
1103
                finishCmdParsing(ite);
1104
                items.append(ite);
1105
        }
1106
}
1107
 
1108
void WMFImport::setPolyFillMode( QList<PageItem*>& /*items*/, long, short* params )
1109
{
1110
        m_context.setWindingFill( params[0] );
1111
}
1112
 
1113
void WMFImport::setBkColor( QList<PageItem*>& /*items*/, long, short* params )
1114
{
1115
        m_context.setBackgroundColor( colorFromParam( params ) );
1116
}
1117
 
1118
void WMFImport::setBkMode( QList<PageItem*>& /*items*/, long, short* params )
1119
{
1120
        if ( params[ 0 ]==1 )
1121
                m_context.setBackgroundMode( Qt::TransparentMode );
1122
        else
1123
                m_context.setBackgroundMode( Qt::OpaqueMode );
1124
}
1125
 
1126
void WMFImport::saveDC( QList<PageItem*>& /*items*/, long, short* )
1127
{
1128
        m_context.save();
1129
}
1130
 
1131
void WMFImport::restoreDC( QList<PageItem*>& /*items*/, long, short *params )
1132
{
1133
        for ( int i=0; i > params[ 0 ] ; i-- )
1134
                m_context.restore();
1135
}
1136
 
1137
void WMFImport::intersectClipRect( QList<PageItem*>& /*items*/, long, short* /*params*/ )
1138
{
1139
        cerr << "WMFImport::intersectClipRect unimplemented" << endl;
1140
}
1141
 
1142
void WMFImport::excludeClipRect( QList<PageItem*>& /*items*/, long, short* /*params*/ )
1143
{
1144
        cerr << "WMFImport::excludeClipRect unimplemented" << endl;
1145
}
1146
 
1147
void WMFImport::setTextColor( QList<PageItem*>& /*items*/, long, short* params )
1148
{
1149
        m_context.setTextColor( colorFromParam(params) );
1150
}
1151
 
1152
void WMFImport::setTextAlign( QList<PageItem*>& /*items*/, long, short* params )
1153
{
1154
        m_context.setTextAlign(params[ 0 ]);
1155
}
1156
 
1157
void WMFImport::textOut( QList<PageItem*>& items, long num, short* params )
1158
{
1159
        short *copyParm = new short[num + 1];
1160
 
1161
        // re-order parameters
1162
        int idxOffset = (params[0] / 2) + 1 + (params[0] & 1);
1163
        copyParm[0] = params[idxOffset];
1164
        copyParm[1] = params[idxOffset + 1];
1165
        copyParm[2] = params[0];
1166
        copyParm[3] = 0;
1167
        memcpy( &copyParm[4], &params[1], params[0] );
1168
 
1169
        extTextOut(items, num + 1, copyParm );
1170
        delete [] copyParm;
1171
}
1172
 
1173
void WMFImport::extTextOut( QList<PageItem*>& items, long num, short* params )
1174
{
1175
        QString    textString;
1176
        double  BaseX = m_Doc->currentPage()->xOffset();
1177
        double  BaseY = m_Doc->currentPage()->yOffset();
1178
 
1179
        if (params[3] & 0x0010) // ETO_GLYPH_INDEX
1180
        {
1181
                cerr << "WMFImport::extTextOut: ETO_GLYPH_INDEX option not supported " << endl;
1182
                unsupported = true;
1183
                return;
1184
        }
1185
 
1186
        // ETO_CLIPPED flag add 4 parameters
1187
        char* ptStr = (params[3] & 0x0004) ? ((char*)&params[8]) : ((char*)&params[4]);
1188
        QByteArray textArray( ptStr, params[2] );
1189
 
1190
        QTextCodec* codec = codecFromCharset( m_context.textCharSet() );
1191
        if (codec)
1192
                textString = codec->toUnicode(textArray);
1193
        else if ( m_context.textCharSet() == SYMBOL_CHARSET )
1194
                textString = symbolToUnicode(textArray);
1195
        else
1196
                textString = QString::fromLocal8Bit(textArray.data());
1197
 
1198
        QFontMetrics fm( m_context.font() );
1199
        int width  = fm.width(textString) + fm.descent();  // because fm.width(text) isn't rigth with Italic text
1200
        /*int height = fm.height();
1201
        int ascent = fm.ascent();*/
1202
 
1203
        double startX = params[1], startY = params[0];
1204
        int    textAlign    = m_context.textAlign();
1205
        double textRotation = m_context.textRotation();
1206
        if ( textAlign & 0x01 ) {       // (left, top) position = current logical position
1207
                QPoint pos = m_context.position();
1208
                startX = pos.x();
1209
                startY = pos.y();
1210
        }
1211
 
1212
        m_context.save();
1213
        // A bit hacky but should be sufficient to have text not flipped
1214
        // top down in some wmfs (see cell.wmf sample from libwmf)
1215
        if ( m_context.worldMatrix().m22() < 0.0)
1216
        {
1217
                m_context.translate(startX, startY);
1218
                m_context.scale (1.0, -1.0);
1219
                m_context.translate( -startX, -startY);
1220
        }
1221
        if ( textRotation != 0.0) {
1222
                m_context.translate(startX, startY);
1223
                m_context.rotate ( textRotation );
1224
                m_context.translate( -startX, -startY);
1225
        }
1226
 
1227
        if ( (textAlign & 0x04) && (textAlign & 0x02) ) // TA_CENTER 0x06
1228
                startX -= (width / 2);
1229
        else if ( textAlign & 0x02 ) // TA_RIGHT 0x02
1230
                startX -= width;
1231
        if ( textAlign == 0 ) // TA_TOP                       
1232
                startY += fm.ascent();
1233
 
1234
        bool eto_empty = (params[3] == 0);
1235
        bool eto_clipped_set = (params[3] & 0x0004);
1236
        bool eto_pdy_set     = (params[3] & 0x2000);
1237
 
1238
        int  idxOffset = (params[ 2 ] / 2) + 4 + (params[ 2 ] & 1) + (eto_clipped_set ? 4 : 0);
1239
        int  minParams = eto_pdy_set ? (idxOffset + 2 * (params[2] - 1)) : (idxOffset + params[2]);
1240
        bool useCharInterdistances = (num >= minParams) && (eto_empty || eto_pdy_set);
1241
        if ((params[2] > 1) && useCharInterdistances)
1242
        {
1243
                double xpos  = startX;
1244
                double ypos  = startY;
1245
                double lineWidth = 0.0;
1246
                FPointArray textPath;
1247
                QString textColor = importColor( m_context.textColor() );
1248
                for (int index = 0; (index < params[2] && index < textString.length()); ++index)
1249
                {
1250
                        QPainterPath painterPath;
1251
                        if (index > 0 && eto_pdy_set)
1252
                        {
1253
                                xpos += params[idxOffset + index * 2 - 1];
1254
                                ypos += params[idxOffset + index * 2];
1255
                        }
1256
                        else if (index > 0)
1257
                                xpos += params[idxOffset + index - 1];
1258
                        painterPath.addText(xpos, ypos, m_context.font(), textString.at(index));
1259
                        textPath.fromQPainterPath(painterPath);
1260
                        if (textPath.size() > 0)
1261
                        {
1262
                                int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, lineWidth, textColor, CommonStrings::None, true);
1263
                                PageItem* ite = m_Doc->Items->at(z);
1264
                                ite->PoLine = textPath;
1265
                                finishCmdParsing(ite);
1266
                                items.append(ite);
1267
                        }
1268
                }
1269
        }
1270
        else
1271
        {
1272
                FPointArray textPath;
1273
                QString textColor = importColor( m_context.textColor() );
1274
                QPainterPath painterPath;
1275
                painterPath.addText( startX, startY, m_context.font(), textString );
1276
                textPath.fromQPainterPath(painterPath);
1277
                if (textPath.size() > 0)
1278
                {
1279
                        double  lineWidth = 0.0;
1280
                        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, lineWidth, textColor, CommonStrings::None, true);
1281
                        PageItem* ite = m_Doc->Items->at(z);
1282
                        ite->PoLine = textPath;
1283
                        finishCmdParsing(ite);
1284
                        items.append(ite);
1285
                }
1286
        }
1287
        m_context.restore();
1288
}
1289
 
1290
void WMFImport::selectObject( QList<PageItem*>& /*items*/, long, short* params )
1291
{
1292
        int idx = params[ 0 ];
1293
        if ( idx >= 0 && idx < MAX_OBJHANDLE && m_ObjHandleTab[ idx ] )
1294
                m_ObjHandleTab[ idx ]->apply( m_context );
1295
}
1296
 
1297
void WMFImport::deleteObject( QList<PageItem*>& /*items*/, long, short* params )
1298
{
1299
        deleteHandle( params[ 0 ] );
1300
}
1301
 
1302
void WMFImport::createEmptyObject( QList<PageItem*>& /*items*/, long, short* )
1303
{
1304
        // allocation of an empty object (to keep object counting in sync)
1305
        WmfObjPenHandle* handle = new WmfObjPenHandle();
1306
        addHandle( handle );
1307
        cerr << "WMFImport: unimplemented createObject " << endl;
1308
}
1309
 
1310
void WMFImport::createBrushIndirect( QList<PageItem*>& /*items*/, long, short* params )
1311
{
1312
        static Qt::BrushStyle hatchedStyleTab[] =
1313
        {
1314
                Qt::HorPattern,
1315
                Qt::FDiagPattern,
1316
                Qt::BDiagPattern,
1317
                Qt::CrossPattern,
1318
                Qt::DiagCrossPattern
1319
        };
1320
        static Qt::BrushStyle styleTab[] =
1321
        { Qt::SolidPattern,
1322
          Qt::NoBrush,
1323
          Qt::FDiagPattern,   /* hatched */
1324
          Qt::Dense4Pattern,  /* should be custom bitmap pattern */
1325
          Qt::HorPattern,     /* should be BS_INDEXED (?) */
1326
          Qt::VerPattern,     /* should be device-independent bitmap */
1327
          Qt::Dense6Pattern,  /* should be device-independent packed-bitmap */
1328
          Qt::Dense2Pattern,  /* should be BS_PATTERN8x8 */
1329
          Qt::Dense3Pattern   /* should be device-independent BS_DIBPATTERN8x8 */
1330
        };
1331
        Qt::BrushStyle style;
1332
        short arg;
1333
        WmfObjBrushHandle* handle = new WmfObjBrushHandle();
1334
        addHandle( handle );
1335
 
1336
        arg = params[0];
1337
        if ( arg == 2 )
1338
        {
1339
                arg = params[3];
1340
                if ( arg >= 0 && arg < 5 )
1341
                        style = hatchedStyleTab[ arg ];
1342
                else
1343
                {
1344
                        cerr << "WMFImport::createBrushIndirect: invalid hatched brush " << arg << endl;
1345
                        style = Qt::SolidPattern;
1346
                }
1347
        }
1348
        else if ( arg >= 0 && arg < 9 )
1349
                style = styleTab[arg];
1350
        else
1351
        {
1352
                cerr << "WMFImport::createBrushIndirect: invalid brush " << arg << endl;
1353
                style = Qt::SolidPattern;
1354
        }
1355
        handle->brush.setStyle( style );
1356
        handle->brush.setColor( colorFromParam( params+1 ) );
1357
}
1358
 
1359
void WMFImport::createPenIndirect( QList<PageItem*>& /*items*/, long, short* params )
1360
{
1361
        static Qt::PenStyle styleTab[] = { Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine,
1362
          Qt::NoPen, Qt::SolidLine };
1363
        Qt::PenStyle style;
1364
        WmfObjPenHandle* handle = new WmfObjPenHandle();
1365
        addHandle( handle );
1366
 
1367
        if ( params[0] >= 0 && params[0] < 6 )
1368
                style = styleTab[ params[0] ];
1369
        else
1370
        {
1371
                cerr << "WMFImport::createPenIndirect: invalid pen " << params[ 0 ] << endl;
1372
                style = Qt::SolidLine;
1373
        }
1374
 
1375
        handle->pen.setStyle( style );
1376
        handle->pen.setWidth( params[1] );
1377
        handle->pen.setColor( colorFromParam( params+3 ) );
1378
        handle->pen.setCapStyle( Qt::RoundCap );
1379
}
1380
 
1381
void WMFImport::createFontIndirect( QList<PageItem*>& /*items*/, long , short* params)
1382
{
1383
        WmfObjFontHandle* handle = new WmfObjFontHandle();
1384
        addHandle( handle );
1385
 
1386
        QString family( (const char*)&params[ 9 ] );
1387
 
1388
        handle->rotation = -params[ 2 ]  / 10; // text rotation (in 1/10 degree)
1389
        handle->font.setFamily( family );
1390
        handle->font.setStyleStrategy( QFont::PreferOutline );
1391
        handle->font.setFixedPitch( ((params[ 8 ] & 0x01) == 0) );
1392
        // TODO: investigation why some test case need -2. (size of font in logical point)
1393
        int fontSize = (params[0] != 0) ? (qAbs(params[0]) - 2) : 12;
1394
        handle->font.setPixelSize( fontSize );
1395
        handle->font.setWeight( (params[ 4 ] >> 3) );
1396
        handle->font.setItalic( (params[ 5 ] & 0x01) );
1397
        handle->font.setUnderline( (params[ 5 ] & 0x100) );
1398
        handle->font.setStrikeOut( (params[ 6 ] & 0x01) );
1399
        handle->charset = (params[ 6 ] & 0xFF00) >> 8;
1400
}
1401
 
1402
void WMFImport::noop( QList<PageItem*>& /*items*/, long, short* )
1403
{
1404
}
1405
 
1406
void WMFImport::end( QList<PageItem*>& /*items*/, long, short* )
1407
{
1408
        //cerr << "WMFImport::end unimplemented" << endl;
1409
}
1410
 
1411
void WMFImport::addHandle( WmfObjHandle* handle )
1412
{
1413
        int idx;
1414
 
1415
        for ( idx =0; idx < MAX_OBJHANDLE ; idx++ )
1416
                if ( m_ObjHandleTab[ idx ] == NULL )  break;
1417
 
1418
        if ( idx < MAX_OBJHANDLE )
1419
                m_ObjHandleTab[ idx ] = handle;
1420
        else
1421
                cerr << "WMFImport error: handle table full !" << endl;
1422
}
1423
 
1424
void WMFImport::deleteHandle( int idx )
1425
{
1426
        if ( idx >= 0 && idx < MAX_OBJHANDLE && m_ObjHandleTab[ idx ] )
1427
        {
1428
                delete m_ObjHandleTab[ idx ];
1429
                m_ObjHandleTab[ idx ] = NULL;
1430
        }
1431
}
1432
 
1433
unsigned short WMFImport::calcCheckSum( WmfPlaceableHeader* apmfh )
1434
{
1435
        WORD16*  lpWord;
1436
        WORD16   wResult, i;
1437
 
1438
        // Start with the first word
1439
        wResult = *( lpWord = ( WORD16* )( apmfh ) );
1440
        // XOR in each of the other 9 words
1441
        for( i=1; i<=9; i++ )
1442
        {
1443
                wResult ^= lpWord[ i ];
1444
        }
1445
        return wResult;
1446
}
1447
 
1448
int WMFImport::findFunc( unsigned short aFunc ) const
1449
{
1450
        int i = 0;
1451
 
1452
        for ( i=0; metaFuncTab[ i ].name; i++ )
1453
                if ( metaFuncTab[ i ].func == aFunc ) return i;
1454
 
1455
        // here : unknown function
1456
        return i;
1457
}
1458
 
1459
unsigned int WMFImport::toDWord( short* params )
1460
{
1461
        unsigned int l;
1462
#if !defined( WORDS_BIGENDIAN )
1463
        l = *( unsigned int* )( params );
1464
#else
1465
        char *bytes;
1466
        char swap[ 4 ];
1467
        bytes = ( char* )params;
1468
        swap[ 0 ] = bytes[ 2 ];
1469
        swap[ 1 ] = bytes[ 3 ];
1470
        swap[ 2 ] = bytes[ 0 ];
1471
        swap[ 3 ] = bytes[ 1 ];
1472
        l = *( unsigned int* )( swap );
1473
#endif
1474
        return l;
1475
}