Subversion Repositories Scribus

Rev

Rev 6719 | Rev 6741 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4430 cbradney 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
*/
68 Franz 7
#include "svgplugin.h"
8
#include "svgplugin.moc"
2688 craig 9
 
10
#include "scconfig.h"
11
 
68 Franz 12
#include "customfdialog.h"
13
#include "color.h"
3207 craig 14
#include "scribus.h"
68 Franz 15
#include "scribusXml.h"
265 Franz 16
#include "mpalette.h"
415 Franz 17
#include "prefsfile.h"
68 Franz 18
#include <qfile.h>
19
#include <qtextstream.h>
1525 cbradney 20
#include <qdragobject.h>
68 Franz 21
#include <qregexp.h>
282 Franz 22
#include <qcursor.h>
68 Franz 23
#include <cmath>
24
#ifdef HAVE_LIBZ
25
#include <zlib.h>
26
#endif
3934 cbradney 27
#include "commonstrings.h"
28
#include "fpointarray.h"
29
#include "menumanager.h"
2834 cbradney 30
#include "prefsmanager.h"
3207 craig 31
#include "pageitem.h"
3934 cbradney 32
#include "scfontmetrics.h"
33
#include "scraction.h"
3207 craig 34
#include "scribusdoc.h"
3934 cbradney 35
#include "selection.h"
36
#include "undomanager.h"
37
#include "util.h"
68 Franz 38
 
504 cbradney 39
using namespace std;
40
 
3207 craig 41
int svgimplugin_getPluginAPIVersion()
68 Franz 42
{
3207 craig 43
        return PLUGIN_API_VERSION;
68 Franz 44
}
45
 
3207 craig 46
ScPlugin* svgimplugin_getPlugin()
68 Franz 47
{
3207 craig 48
        SVGImportPlugin* plug = new SVGImportPlugin();
49
        Q_CHECK_PTR(plug);
50
        return plug;
68 Franz 51
}
52
 
3207 craig 53
void svgimplugin_freePlugin(ScPlugin* plugin)
512 fschmid 54
{
3207 craig 55
        SVGImportPlugin* plug = dynamic_cast<SVGImportPlugin*>(plugin);
56
        Q_ASSERT(plug);
57
        delete plug;
512 fschmid 58
}
59
 
3696 craig 60
SVGImportPlugin::SVGImportPlugin() : LoadSavePlugin(),
61
        importAction(new ScrAction(ScrAction::DLL, QIconSet(), "", QKeySequence(), this, "ImportSVG"))
1208 cbradney 62
{
3207 craig 63
        // Set action info in languageChange, so we only have to do
3686 craig 64
        // it in one place. This includes registering file format
65
        // support.
3207 craig 66
        languageChange();
3696 craig 67
 
68
        importAction->setEnabled(true);
69
        connect( importAction, SIGNAL(activated()), SLOT(import()) );
4026 craig 70
        ScMW->scrMenuMgr->addMenuItem(importAction, "FileImport");
1208 cbradney 71
}
72
 
3686 craig 73
SVGImportPlugin::~SVGImportPlugin()
74
{
75
        unregisterAll();
76
};
3207 craig 77
 
78
void SVGImportPlugin::languageChange()
1208 cbradney 79
{
3696 craig 80
        importAction->setMenuText(tr("Import &SVG..."));
3686 craig 81
        // (Re)register file format support.
82
        unregisterAll();
83
        registerFormats();
1208 cbradney 84
}
85
 
3207 craig 86
const QString SVGImportPlugin::fullTrName() const
1208 cbradney 87
{
3207 craig 88
        return QObject::tr("SVG Import");
1208 cbradney 89
}
90
 
3207 craig 91
const ScActionPlugin::AboutData* SVGImportPlugin::getAboutData() const
1208 cbradney 92
{
3241 craig 93
        AboutData* about = new AboutData;
3344 fschmid 94
        about->authors = "Franz Schmid <franz@scribus.info>";
3355 cbradney 95
        about->shortDescription = tr("Imports SVG Files");
3357 cbradney 96
        about->description = tr("Imports most SVG files into the current document,\nconverting their vector data into Scribus objects.");
3344 fschmid 97
        about->license = "GPL";
3241 craig 98
        Q_CHECK_PTR(about);
99
        return about;
1208 cbradney 100
}
101
 
3241 craig 102
void SVGImportPlugin::deleteAboutData(const AboutData* about) const
1208 cbradney 103
{
3241 craig 104
        Q_ASSERT(about);
105
        delete about;
1208 cbradney 106
}
107
 
3686 craig 108
void SVGImportPlugin::registerFormats()
3487 craig 109
{
110
        QString svgName = tr("Scalable Vector Graphics");
4024 craig 111
        FileFormat fmt(this);
3643 craig 112
        fmt.trName = svgName;
4024 craig 113
        fmt.formatId = FORMATID_SVGIMPORT;
3686 craig 114
#ifdef HAVE_LIBZ
4309 craig 115
        fmt.filter = svgName + " (*.svg *.SVG *.svgz *.SVGZ)";
3688 craig 116
        fmt.nameMatch = QRegExp("\\.(svg|svgz)$", false);
3686 craig 117
#else
4309 craig 118
        fmt.filter = svgName + " (*.svg *.SVG)";
3688 craig 119
        fmt.nameMatch = QRegExp("\\.svg$", false);
3686 craig 120
#endif
121
        fmt.load = true;
122
        fmt.save = false;
3643 craig 123
        fmt.mimeTypes = QStringList("image/svg+xml");
124
        fmt.priority = 64;
3686 craig 125
        registerFormat(fmt);
3487 craig 126
}
127
 
128
bool SVGImportPlugin::fileSupported(QIODevice* /* file */) const
129
{
130
        // TODO: identify valid SVG
131
        return true;
132
}
133
 
5535 mrdocs 134
bool SVGImportPlugin::loadFile(const QString & fileName, const FileFormat & /* fmt */, int flags, int /*index*/)
4024 craig 135
{
136
        // For now, "load file" and import are the same thing for this plugin
5747 jghali 137
        return import(fileName, flags);
4024 craig 138
}
139
 
5535 mrdocs 140
bool SVGImportPlugin::import(QString filename, int flags)
68 Franz 141
{
5535 mrdocs 142
        if (!checkFlags(flags))
143
                return false;
3207 craig 144
        if (filename.isEmpty())
506 fschmid 145
        {
5535 mrdocs 146
                flags |= lfInteractive;
2856 cbradney 147
                PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("SVGPlugin");
506 fschmid 148
                QString wdir = prefs->get("wdir", ".");
68 Franz 149
#ifdef HAVE_LIBZ
4026 craig 150
                CustomFDialog diaf(ScMW, wdir, QObject::tr("Open"), QObject::tr("SVG-Images (*.svg *.svgz);;All Files (*)"));
68 Franz 151
#else
4026 craig 152
                CustomFDialog diaf(ScMW, wdir, QObject::tr("Open"), QObject::tr("SVG-Images (*.svg);;All Files (*)"));
68 Franz 153
#endif
506 fschmid 154
                if (diaf.exec())
155
                {
3207 craig 156
                        filename = diaf.selectedFile();
157
                        prefs->set("wdir", filename.left(filename.findRev("/")));
506 fschmid 158
                }
159
                else
3207 craig 160
                        return true;
415 Franz 161
        }
4026 craig 162
        if (UndoManager::undoEnabled() && ScMW->HaveDoc)
1439 tsoots 163
        {
4026 craig 164
                UndoManager::instance()->beginTransaction(ScMW->doc->currentPage->getUName(),Um::IImageFrame,Um::ImportSVG, filename, Um::ISVG);
1439 tsoots 165
        }
4026 craig 166
        else if (UndoManager::undoEnabled() && !ScMW->HaveDoc)
1439 tsoots 167
                UndoManager::instance()->setUndoEnabled(false);
5535 mrdocs 168
        SVGPlug *dia = new SVGPlug(filename, flags);
3207 craig 169
        Q_CHECK_PTR(dia);
1435 tsoots 170
        if (UndoManager::undoEnabled())
171
                UndoManager::instance()->commit();
1439 tsoots 172
        else
173
                UndoManager::instance()->setUndoEnabled(true);
3800 subik 174
 
175
        if (dia->unsupported)
176
        {
4026 craig 177
                QMessageBox::warning(ScMW, CommonStrings::trWarning, tr("SVG file contains some unsupported features"), 1, 0, 0);
3800 subik 178
        }
179
 
217 Franz 180
        delete dia;
3207 craig 181
        return true;
68 Franz 182
}
183
 
5535 mrdocs 184
SVGPlug::SVGPlug( QString fName, int flags ) :
4026 craig 185
        QObject(ScMW)
68 Franz 186
{
3800 subik 187
        unsupported = false;
5535 mrdocs 188
        interactive = (flags & LoadSavePlugin::lfInteractive);
68 Franz 189
        QString f = "";
190
#ifdef HAVE_LIBZ
191
        if(fName.right(2) == "gz")
217 Franz 192
        {
68 Franz 193
                gzFile gzDoc;
194
                char buff[4097];
195
                int i;
196
                gzDoc = gzopen(fName.latin1(),"rb");
197
                if(gzDoc == NULL)
198
                        return;
199
                while((i = gzread(gzDoc,&buff,4096)) > 0)
217 Franz 200
                {
68 Franz 201
                        buff[i] = '\0';
202
                        f.append(buff);
217 Franz 203
                }
68 Franz 204
                gzclose(gzDoc);
217 Franz 205
        }
68 Franz 206
        else
207
                loadText(fName, &f);
208
#else
209
        loadText(fName, &f);
210
#endif
211
        if(!inpdoc.setContent(f))
212
                return;
213
        m_gc.setAutoDelete( true );
214
        QString CurDirP = QDir::currentDirPath();
215
        QFileInfo efp(fName);
216
        QDir::setCurrent(efp.dirPath());
5535 mrdocs 217
        convert(flags);
68 Franz 218
        QDir::setCurrent(CurDirP);
219
}
220
 
5535 mrdocs 221
void SVGPlug::convert(int flags)
68 Franz 222
{
223
        bool ret = false;
224
        SvgStyle *gc = new SvgStyle;
2607 fschmid 225
        Conversion = 0.8;
68 Franz 226
        QDomElement docElem = inpdoc.documentElement();
456 fschmid 227
        double width = !docElem.attribute("width").isEmpty() ? parseUnit(docElem.attribute( "width" )) : 550.0;
228
        double height = !docElem.attribute("height").isEmpty() ? parseUnit(docElem.attribute( "height" )) : 841.0;
2607 fschmid 229
        Conversion = 0.8;
5535 mrdocs 230
        if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
217 Franz 231
        {
4026 craig 232
                ScMW->doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
233
                ScMW->doc->addPage(0);
234
                ScMW->view->addPage(0);
217 Franz 235
        }
506 fschmid 236
        else
237
        {
5535 mrdocs 238
                if (!ScMW->HaveDoc || (flags & LoadSavePlugin::lfCreateDoc))
506 fschmid 239
                {
4026 craig 240
                        ScMW->doFileNew(width, height, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom");
4268 fschmid 241
                        ScMW->HaveNewDoc();
506 fschmid 242
                        ret = true;
243
                }
244
        }
3207 craig 245
        if ((ret) || (!interactive))
550 fschmid 246
        {
247
                if (width > height)
4026 craig 248
                        ScMW->doc->PageOri = 1;
550 fschmid 249
                else
4026 craig 250
                        ScMW->doc->PageOri = 0;
251
                ScMW->doc->PageSize = "Custom";
550 fschmid 252
        }
4026 craig 253
        currDoc = ScMW->doc;
3292 cbradney 254
        FPoint minSize = currDoc->minCanvasCoordinate;
255
        FPoint maxSize = currDoc->maxCanvasCoordinate;
4026 craig 256
        ScMW->view->Deselect();
68 Franz 257
        Elements.clear();
3292 cbradney 258
        currDoc->setLoading(true);
259
        currDoc->DoDrawing = false;
4026 craig 260
        ScMW->view->setUpdatesEnabled(false);
261
        ScMW->ScriptRunning = true;
282 Franz 262
        qApp->setOverrideCursor(QCursor(waitCursor), true);
3292 cbradney 263
        gc->Family = currDoc->toolSettings.defFont;
264
        if (!currDoc->PageColors.contains("Black"))
265
                currDoc->PageColors.insert("Black", ScColor(0, 0, 0, 255));
68 Franz 266
        m_gc.push( gc );
1013 fschmid 267
        viewTransformX = 0;
268
        viewTransformY = 0;
269
        viewScaleX = 1;
270
        viewScaleY = 1;
271
        haveViewBox = false;
272
        if( !docElem.attribute( "viewBox" ).isEmpty() )
273
        {
2607 fschmid 274
                Conversion = 1.0;
275
                double w2 = !docElem.attribute("width").isEmpty() ? parseUnit(docElem.attribute( "width" )) : 550.0;
276
                double h2 = !docElem.attribute("height").isEmpty() ? parseUnit(docElem.attribute( "height" )) : 841.0;
277
                Conversion = 0.8;
1013 fschmid 278
                QString viewbox( docElem.attribute( "viewBox" ) );
279
                QStringList points = QStringList::split( ' ', viewbox.replace( QRegExp(","), " ").simplifyWhiteSpace() );
280
                viewTransformX = points[0].toDouble();
281
                viewTransformY = points[1].toDouble();
2607 fschmid 282
                viewScaleX = w2 / points[2].toDouble();
283
                viewScaleY = h2 / points[3].toDouble();
1013 fschmid 284
                haveViewBox = true;
285
        }
68 Franz 286
        parseGroup( docElem );
4847 cbradney 287
        currDoc->m_Selection->clear();
302 Franz 288
        if (Elements.count() > 1)
217 Franz 289
        {
68 Franz 290
                for (uint a = 0; a < Elements.count(); ++a)
217 Franz 291
                {
3292 cbradney 292
                        Elements.at(a)->Groups.push(currDoc->GroupCounter);
217 Franz 293
                }
3292 cbradney 294
                currDoc->GroupCounter++;
217 Franz 295
        }
3292 cbradney 296
        currDoc->DoDrawing = true;
4026 craig 297
        ScMW->view->setUpdatesEnabled(true);
298
        ScMW->ScriptRunning = false;
3207 craig 299
        if (interactive)
3292 cbradney 300
                currDoc->setLoading(false);
282 Franz 301
        qApp->setOverrideCursor(QCursor(arrowCursor), true);
3207 craig 302
        if ((Elements.count() > 0) && (!ret) && (interactive))
217 Franz 303
        {
3292 cbradney 304
                currDoc->DragP = true;
305
                currDoc->DraggedElem = 0;
306
                currDoc->DragElements.clear();
68 Franz 307
                for (uint dre=0; dre<Elements.count(); ++dre)
217 Franz 308
                {
3292 cbradney 309
                        currDoc->DragElements.append(Elements.at(dre)->ItemNr);
4847 cbradney 310
                        currDoc->m_Selection->addItem(Elements.at(dre));
217 Franz 311
                }
312
                ScriXmlDoc *ss = new ScriXmlDoc();
4026 craig 313
                ScMW->view->setGroupRect();
314
                //QDragObject *dr = new QTextDrag(ss->WriteElem(&ScMW->view->SelItem, currDoc, ScMW->view), ScMW->view->viewport());
4847 cbradney 315
                QDragObject *dr = new QTextDrag(ss->WriteElem(currDoc, ScMW->view, currDoc->m_Selection), ScMW->view->viewport());
4302 avox 316
#ifndef QT_MAC
317
// see #2526
4707 cbradney 318
                currDoc->itemSelection_DeleteItem();
4302 avox 319
#endif
4593 cbradney 320
                ScMW->view->resizeContents(qRound((maxSize.x() - minSize.x()) * ScMW->view->scale()), qRound((maxSize.y() - minSize.y()) * ScMW->view->scale()));
321
                ScMW->view->scrollBy(qRound((currDoc->minCanvasCoordinate.x() - minSize.x()) * ScMW->view->scale()), qRound((currDoc->minCanvasCoordinate.y() - minSize.y()) * ScMW->view->scale()));
3292 cbradney 322
                currDoc->minCanvasCoordinate = minSize;
323
                currDoc->maxCanvasCoordinate = maxSize;
68 Franz 324
                dr->setPixmap(loadIcon("DragPix.xpm"));
4302 avox 325
                if (!dr->drag())
6500 cbradney 326
                        qDebug("%s", QString("SVGImport: Could not start drag operation!").ascii());
68 Franz 327
                delete ss;
3292 cbradney 328
                currDoc->DragP = false;
329
                currDoc->DraggedElem = 0;
330
                currDoc->DragElements.clear();
217 Franz 331
        }
68 Franz 332
        else
357 Franz 333
        {
3292 cbradney 334
                currDoc->setModified(false);
4026 craig 335
                ScMW->slotDocCh();
357 Franz 336
        }
68 Franz 337
}
338
 
339
void SVGPlug::addGraphicContext()
340
{
341
        SvgStyle *gc = new SvgStyle;
342
        if ( m_gc.current() )
343
                *gc = *( m_gc.current() );
344
        m_gc.push( gc );
345
}
346
 
347
void SVGPlug::setupTransform( const QDomElement &e )
348
{
349
        SvgStyle *gc = m_gc.current();
350
        QWMatrix mat = parseTransform( e.attribute( "transform" ) );
351
        if (!e.attribute("transform").isEmpty())
352
                gc->matrix = mat * gc->matrix;
353
}
354
 
991 fschmid 355
QPtrList<PageItem> SVGPlug::parseGroup(const QDomElement &e)
68 Franz 356
{
357
        QPtrList<PageItem> GElements;
358
        FPointArray ImgClip;
359
        ImgClip.resize(0);
3292 cbradney 360
        double BaseX = currDoc->currentPage->xOffset();
361
        double BaseY = currDoc->currentPage->yOffset();
68 Franz 362
        for( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
217 Franz 363
        {
68 Franz 364
                int z = -1;
365
                QDomElement b = n.toElement();
366
                if( b.isNull() )
367
                        continue;
6355 jghali 368
                SvgStyle svgStyle;
369
                parseStyle( &svgStyle, b );
370
                if (!svgStyle.Display)
371
                        continue;
68 Franz 372
                QString STag = b.tagName();
373
                if( STag == "g" )
217 Franz 374
                {
68 Franz 375
                        addGraphicContext();
376
                        SvgStyle *gc = m_gc.current();
377
                        setupTransform( b );
378
                        parseStyle( gc, b );
991 fschmid 379
                        QPtrList<PageItem> gElements = parseGroup( b );
380
                        for (uint gr = 0; gr < gElements.count(); ++gr)
217 Franz 381
                        {
3292 cbradney 382
                                gElements.at(gr)->Groups.push(currDoc->GroupCounter);
991 fschmid 383
                                GElements.append(gElements.at(gr));
217 Franz 384
                        }
68 Franz 385
                        delete( m_gc.pop() );
3292 cbradney 386
                        currDoc->GroupCounter++;
68 Franz 387
                        continue;
217 Franz 388
                }
68 Franz 389
                if( b.tagName() == "defs" )
217 Franz 390
                {
68 Franz 391
                        parseGroup( b );        // try for gradients at least
392
                        continue;
217 Franz 393
                }
68 Franz 394
                else if( STag == "linearGradient" || STag == "radialGradient" )
217 Franz 395
                {
68 Franz 396
                        parseGradient( b );
397
                        continue;
217 Franz 398
                }
68 Franz 399
                else if( STag == "rect" )
217 Franz 400
                {
68 Franz 401
                        addGraphicContext();
3292 cbradney 402
                        double x = parseUnit( b.attribute( "x" ) );
403
                        double y = parseUnit( b.attribute( "y" ) );
456 fschmid 404
                        double width = parseUnit( b.attribute( "width" ));
405
                        double height = parseUnit( b.attribute( "height" ) );
68 Franz 406
                        double rx = b.attribute( "rx" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "rx" ) );
407
                        double ry = b.attribute( "ry" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "ry" ) );
408
                        SvgStyle *gc = m_gc.current();
409
                        parseStyle( gc, b );
4025 cbradney 410
                        z = currDoc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, width, height, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
3727 cbradney 411
                        PageItem* ite = currDoc->Items->at(z);
68 Franz 412
                        if ((rx != 0) || (ry != 0))
217 Franz 413
                        {
3989 cbradney 414
                                ite->setCornerRadius(QMAX(rx, ry));
3242 cbradney 415
                                ite->SetFrameRound();
4672 cbradney 416
                                currDoc->setRedrawBounding(ite);
217 Franz 417
                        }
68 Franz 418
                        QWMatrix mm = QWMatrix();
419
                        mm.translate(x, y);
420
                        ite->PoLine.map(mm);
1065 cbradney 421
                        FPoint wh = getMaxClipF(&ite->PoLine);
3934 cbradney 422
                        ite->setWidthHeight(wh.x(), wh.y());
217 Franz 423
                }
68 Franz 424
                else if( STag == "ellipse" )
217 Franz 425
                {
68 Franz 426
                        addGraphicContext();
456 fschmid 427
                        double rx = parseUnit( b.attribute( "rx" ) );
428
                        double ry = parseUnit( b.attribute( "ry" ) );
429
                        double x = parseUnit( b.attribute( "cx" ) ) - rx;
430
                        double y = parseUnit( b.attribute( "cy" ) ) - ry;
68 Franz 431
                        SvgStyle *gc = m_gc.current();
432
                        parseStyle( gc, b );
4025 cbradney 433
                        z = currDoc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, rx * 2.0, ry * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
3727 cbradney 434
                        PageItem* ite = currDoc->Items->at(z);
68 Franz 435
                        QWMatrix mm = QWMatrix();
436
                        mm.translate(x, y);
437
                        ite->PoLine.map(mm);
1065 cbradney 438
                        FPoint wh = getMaxClipF(&ite->PoLine);
3934 cbradney 439
                        ite->setWidthHeight(wh.x(), wh.y());
217 Franz 440
                }
68 Franz 441
                else if( STag == "circle" )
217 Franz 442
                {
68 Franz 443
                        addGraphicContext();
3292 cbradney 444
                        double r = parseUnit( b.attribute( "r" ) );
445
                        double x = parseUnit( b.attribute( "cx" ) ) - r;
446
                        double y = parseUnit( b.attribute( "cy" ) ) - r;
68 Franz 447
                        SvgStyle *gc = m_gc.current();
448
                        parseStyle( gc, b );
4025 cbradney 449
                        z = currDoc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, r * 2.0, r * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
3727 cbradney 450
                        PageItem* ite = currDoc->Items->at(z);
68 Franz 451
                        QWMatrix mm = QWMatrix();
452
                        mm.translate(x, y);
453
                        ite->PoLine.map(mm);
1065 cbradney 454
                        FPoint wh = getMaxClipF(&ite->PoLine);
3934 cbradney 455
                        ite->setWidthHeight(wh.x(), wh.y());
217 Franz 456
                }
68 Franz 457
                else if( STag == "line" )
217 Franz 458
                {
68 Franz 459
                        addGraphicContext();
460
                        double x1 = b.attribute( "x1" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x1" ) );
461
                        double y1 = b.attribute( "y1" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y1" ) );
462
                        double x2 = b.attribute( "x2" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x2" ) );
463
                        double y2 = b.attribute( "y2" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y2" ) );
464
                        SvgStyle *gc = m_gc.current();
465
                        parseStyle( gc, b );
4025 cbradney 466
                        z = currDoc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
3727 cbradney 467
                        PageItem* ite = currDoc->Items->at(z);
68 Franz 468
                        ite->PoLine.resize(4);
469
                        ite->PoLine.setPoint(0, FPoint(x1, y1));
470
                        ite->PoLine.setPoint(1, FPoint(x1, y1));
471
                        ite->PoLine.setPoint(2, FPoint(x2, y2));
472
                        ite->PoLine.setPoint(3, FPoint(x2, y2));
217 Franz 473
                }
68 Franz 474
                else if( STag == "clipPath" )
217 Franz 475
                {
68 Franz 476
                        QDomNode n2 = b.firstChild();
477
                        QDomElement b2 = n2.toElement();
478
                        parseSVG( b2.attribute( "d" ), &ImgClip );
479
                        continue;
217 Franz 480
                }
68 Franz 481
                else if( STag == "path" )
217 Franz 482
                {
68 Franz 483
                        addGraphicContext();
484
                        SvgStyle *gc = m_gc.current();
485
                        parseStyle( gc, b );
6612 jghali 486
                        FPointArray pArray;
487
                        PageItem::ItemType itype = parseSVG(b.attribute("d"), &pArray) ? PageItem::PolyLine : PageItem::Polygon;
488
                        z = currDoc->itemAdd(itype, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
3727 cbradney 489
                        PageItem* ite = currDoc->Items->at(z);
6719 jghali 490
                        ite->fillRule = (gc->fillRule != "nonzero");
6612 jghali 491
                        ite->PoLine = pArray;
68 Franz 492
                        if (ite->PoLine.size() < 4)
217 Franz 493
                        {
4847 cbradney 494
                                currDoc->m_Selection->addItem(ite);
4707 cbradney 495
                                currDoc->itemSelection_DeleteItem();
68 Franz 496
                                z = -1;
497
                        }
217 Franz 498
                }
68 Franz 499
                else if( STag == "polyline" || b.tagName() == "polygon" )
217 Franz 500
                {
68 Franz 501
                        addGraphicContext();
502
                        SvgStyle *gc = m_gc.current();
503
                        parseStyle( gc, b );
504
                        if( b.tagName() == "polygon" )
4025 cbradney 505
                                z = currDoc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
68 Franz 506
                        else
4025 cbradney 507
                                z = currDoc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
3727 cbradney 508
                        PageItem* ite = currDoc->Items->at(z);
4926 avox 509
                        ite->fillRule = (gc->fillRule != "nonzero");
68 Franz 510
                        ite->PoLine.resize(0);
511
                        bool bFirst = true;
512
                        double x = 0.0;
513
                        double y = 0.0;
4819 cbradney 514
                        QString points = b.attribute( "points" ).simplifyWhiteSpace().replace(',', " ");
515
                        /*
68 Franz 516
                        points.replace( QRegExp( "," ), " " );
517
                        points.replace( QRegExp( "\r" ), "" );
217 Franz 518
                        points.replace( QRegExp( "\n" ), "" );
4819 cbradney 519
                        */
68 Franz 520
                        QStringList pointList = QStringList::split( ' ', points );
521
                        FirstM = true;
522
                        for( QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++ )
217 Franz 523
                        {
524
                                if( bFirst )
68 Franz 525
                                {
526
                                        x = (*(it++)).toDouble();
527
                                        y = (*it).toDouble();
2597 fschmid 528
                                        svgMoveTo(x * Conversion, y * Conversion);
68 Franz 529
                                        bFirst = false;
530
                                        WasM = true;
217 Franz 531
                                }
68 Franz 532
                                else
217 Franz 533
                                {
68 Franz 534
                                        x = (*(it++)).toDouble();
535
                                        y = (*it).toDouble();
2597 fschmid 536
                                        svgLineTo(&ite->PoLine, x * Conversion, y * Conversion);
68 Franz 537
                                }
217 Franz 538
                        }
68 Franz 539
                        if( STag == "polygon" )
540
                                svgClosePath(&ite->PoLine);
541
                        else
1460 cbradney 542
                                ite->convertTo(PageItem::PolyLine);
217 Franz 543
                }
68 Franz 544
                else if( STag == "text" )
217 Franz 545
                {
68 Franz 546
                        addGraphicContext();
547
                        SvgStyle *gc = m_gc.current();
548
                        double x = b.attribute( "x" ).isEmpty() ? 0.0 : parseUnit(b.attribute("x"));
549
                        double y = b.attribute( "y" ).isEmpty() ? 0.0 : parseUnit(b.attribute("y"));
550
                        parseStyle(gc, b);
456 fschmid 551
                        QPtrList<PageItem> el = parseText(x+BaseX, y+BaseY, b);
215 Franz 552
                        for (uint ec = 0; ec < el.count(); ++ec)
553
                        {
554
                                GElements.append(el.at(ec));
68 Franz 555
                        }
215 Franz 556
                        z = -1;
217 Franz 557
                }
68 Franz 558
                else if( STag == "image" )
217 Franz 559
                {
68 Franz 560
                        addGraphicContext();
561
                        QString fname = b.attribute("xlink:href");
562
                        double x = b.attribute( "x" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "x" ) );
563
                        double y = b.attribute( "y" ).isEmpty() ? 0.0 : parseUnit( b.attribute( "y" ) );
564
                        double w = b.attribute( "width" ).isEmpty() ? 1.0 : parseUnit( b.attribute( "width" ) );
565
                        double h = b.attribute( "height" ).isEmpty() ? 1.0 : parseUnit( b.attribute( "height" ) );
4026 craig 566
                        //z = ScMW->view->PaintPict(x+BaseX, y+BaseY, w, h);
4546 subik 567
                        z = currDoc->itemAdd(PageItem::ImageFrame, PageItem::Unspecified, x+BaseX, y+BaseY, w, h, 1, currDoc->toolSettings.dBrushPict, CommonStrings::None, true);
2877 cbradney 568
                        if (!fname.isEmpty())
3650 cbradney 569
                                currDoc->LoadPict(fname, z);
3727 cbradney 570
                        PageItem* ite = currDoc->Items->at(z);
68 Franz 571
                        if (ImgClip.size() != 0)
572
                                ite->PoLine = ImgClip.copy();
573
                        ImgClip.resize(0);
574
                        ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
217 Franz 575
                }
68 Franz 576
                else
3800 subik 577
                {
6500 cbradney 578
                        qDebug("%s", QString("Unsupported SVG Feature: %1").arg(STag).ascii());
3800 subik 579
                        // warn if unsupported SVG feature
580
                        unsupported = true;
68 Franz 581
                        continue;
3800 subik 582
                }
68 Franz 583
                if (z != -1)
217 Franz 584
                {
68 Franz 585
                        setupTransform( b );
586
                        SvgStyle *gc = m_gc.current();
3727 cbradney 587
                        PageItem* ite = currDoc->Items->at(z);
6719 jghali 588
                        QWMatrix gcm = gc->matrix;
589
                        double coeff1 = sqrt(gcm.m11() * gcm.m11() + gcm.m12() * gcm.m12());
590
                        double coeff2 = sqrt(gcm.m21() * gcm.m21() + gcm.m22() * gcm.m22());
1460 cbradney 591
                        switch (ite->itemType())
217 Franz 592
                        {
1460 cbradney 593
                        case PageItem::ImageFrame:
68 Franz 594
                                {
595
                                        QWMatrix mm = gc->matrix;
3934 cbradney 596
                                        ite->moveBy(mm.dx(), mm.dy());
597
                                        ite->setWidthHeight(ite->width() * mm.m11(), ite->height() * mm.m22());
6719 jghali 598
                                        ite->setLineWidth(ite->lineWidth() * (coeff1 + coeff2) / 2.0);
68 Franz 599
                                        if (ite->PicAvail)
3985 cbradney 600
                                                ite->setImageXYScale(ite->width() / ite->pixm.width(), ite->height() / ite->pixm.height());
68 Franz 601
                                        break;
217 Franz 602
                                }
1460 cbradney 603
                        case PageItem::TextFrame:
330 Franz 604
                                {
605
                                        QWMatrix mm = gc->matrix;
6719 jghali 606
                                        ite->setLineWidth(ite->lineWidth() * (coeff1 + coeff2) / 2.0);
330 Franz 607
                                }
217 Franz 608
                                break;
609
                        default:
610
                                {
68 Franz 611
                                        ite->ClipEdited = true;
612
                                        ite->FrameType = 3;
613
                                        QWMatrix mm = gc->matrix;
614
                                        ite->PoLine.map(mm);
1013 fschmid 615
                                        if (haveViewBox)
616
                                        {
617
                                                QWMatrix mv;
618
                                                mv.translate(viewTransformX, viewTransformY);
619
                                                mv.scale(viewScaleX, viewScaleY);
620
                                                ite->PoLine.map(mv);
621
                                        }
6719 jghali 622
                                        ite->setLineWidth(ite->lineWidth() * (coeff1 + coeff2) / 2.0);
1065 cbradney 623
                                        FPoint wh = getMaxClipF(&ite->PoLine);
3934 cbradney 624
                                        ite->setWidthHeight(wh.x(), wh.y());
68 Franz 625
                                        ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
4026 craig 626
                                        ScMW->view->AdjustItemSize(ite);
68 Franz 627
                                        break;
628
                                }
217 Franz 629
                        }
68 Franz 630
                        if( !b.attribute("id").isEmpty() )
1361 tsoots 631
                                ite->setItemName(" "+b.attribute("id"));
6126 jghali 632
                        ite->setFillTransparency( 1 - gc->FillOpacity * gc->Opacity);
633
                        ite->setLineTransparency( 1 - gc->StrokeOpacity * gc->Opacity);
68 Franz 634
                        ite->PLineEnd = gc->PLineEnd;
635
                        ite->PLineJoin = gc->PLineJoin;
1653 craig 636
                        ite->setTextFlowsAroundFrame(false);
68 Franz 637
                        ite->DashOffset = gc->dashOffset;
638
                        ite->DashValues = gc->dashArray;
639
                        if (gc->Gradient != 0)
217 Franz 640
                        {
298 Franz 641
                                ite->fill_gradient = gc->GradCo;
642
                                if (!gc->CSpace)
296 Franz 643
                                {
3934 cbradney 644
                                        ite->GrStartX = gc->GX1 * ite->width();
645
                                        ite->GrStartY = gc->GY1 * ite->height();
646
                                        ite->GrEndX = gc->GX2 * ite->width();
647
                                        ite->GrEndY = gc->GY2 * ite->height();
302 Franz 648
                                        double angle1 = atan2(gc->GY2-gc->GY1,gc->GX2-gc->GX1)*(180.0/M_PI);
649
                                        double angle2 = atan2(ite->GrEndY-ite->GrStartX,ite->GrEndX-ite->GrStartX)*(180.0/M_PI);
650
                                        double dx = ite->GrStartX + (ite->GrEndX-ite->GrStartX) / 2.0;
651
                                        double dy = ite->GrStartY + (ite->GrEndY-ite->GrStartY) / 2.0;
776 fschmid 652
                                        QWMatrix mm, mm2;
308 Franz 653
                                        if ((gc->GY1 < gc->GY2) && (gc->GX1 < gc->GX2))
302 Franz 654
                                        {
655
                                                mm.rotate(-angle2);
776 fschmid 656
                                                mm2.rotate(angle1);
302 Franz 657
                                        }
658
                                        FPointArray gra;
659
                                        gra.setPoints(2, ite->GrStartX-dx, ite->GrStartY-dy, ite->GrEndX-dx, ite->GrEndY-dy);
776 fschmid 660
                                        gra.map(mm*mm2);
302 Franz 661
                                        gra.translate(dx, dy);
662
                                        ite->GrStartX = gra.point(0).x();
663
                                        ite->GrStartY = gra.point(0).y();
664
                                        ite->GrEndX = gra.point(1).x();
665
                                        ite->GrEndY = gra.point(1).y();
298 Franz 666
                                }
667
                                else
668
                                {
296 Franz 669
                                        QWMatrix mm = gc->matrix;
6308 jghali 670
                                        mm = gc->matrixg * mm;
296 Franz 671
                                        FPointArray gra;
672
                                        gra.setPoints(2, gc->GX1, gc->GY1, gc->GX2, gc->GY2);
673
                                        gra.map(mm);
674
                                        gc->GX1 = gra.point(0).x();
675
                                        gc->GY1 = gra.point(0).y();
676
                                        gc->GX2 = gra.point(1).x();
677
                                        gc->GY2 = gra.point(1).y();
6308 jghali 678
                                        ite->GrStartX = gc->GX1 - ite->xPos() + BaseX;
679
                                        ite->GrStartY = gc->GY1 - ite->yPos() + BaseY;
680
                                        ite->GrEndX = gc->GX2 - ite->xPos() + BaseX;
681
                                        ite->GrEndY = gc->GY2 - ite->yPos() + BaseY;
298 Franz 682
                                }
296 Franz 683
                                ite->GrType = gc->Gradient;
217 Franz 684
                        }
68 Franz 685
                        GElements.append(ite);
686
                        Elements.append(ite);
217 Franz 687
                }
68 Franz 688
                delete( m_gc.pop() );
217 Franz 689
        }
991 fschmid 690
        return GElements;
68 Franz 691
}
692
 
693
double SVGPlug::fromPercentage( const QString &s )
694
{
695
        if( s.endsWith( "%" ) )
696
                return s.toDouble() / 100.0;
697
        else
698
                return s.toDouble();
699
}
700
 
701
double SVGPlug::parseUnit(const QString &unit)
702
{
693 fschmid 703
        bool noUnit = false;
270 Franz 704
        QString unitval=unit;
705
        if( unit.right( 2 ) == "pt" )
706
                unitval.replace( "pt", "" );
707
        else if( unit.right( 2 ) == "cm" )
708
                unitval.replace( "cm", "" );
709
        else if( unit.right( 2 ) == "mm" )
710
                unitval.replace( "mm" , "" );
711
        else if( unit.right( 2 ) == "in" )
712
                unitval.replace( "in", "" );
713
        else if( unit.right( 2 ) == "px" )
714
                unitval.replace( "px", "" );
693 fschmid 715
        if (unitval == unit)
716
                noUnit = true;
270 Franz 717
        double value = unitval.toDouble();
718
        if( unit.right( 2 ) == "pt" )
719
                value = value;
720
        else if( unit.right( 2 ) == "cm" )
721
                value = ( value / 2.54 ) * 72;
722
        else if( unit.right( 2 ) == "mm" )
723
                value = ( value / 25.4 ) * 72;
724
        else if( unit.right( 2 ) == "in" )
725
                value = value * 72;
726
        else if( unit.right( 2 ) == "px" )
865 fschmid 727
                value = value * 0.8;
693 fschmid 728
        else if(noUnit)
976 fschmid 729
                value = value * Conversion;
68 Franz 730
        return value;
731
}
732
 
733
QWMatrix SVGPlug::parseTransform( const QString &transform )
734
{
2597 fschmid 735
        QWMatrix ret;
68 Franz 736
        // Split string for handling 1 transform statement at a time
737
        QStringList subtransforms = QStringList::split(')', transform);
738
        QStringList::ConstIterator it = subtransforms.begin();
739
        QStringList::ConstIterator end = subtransforms.end();
740
        for(; it != end; ++it)
741
        {
2597 fschmid 742
                QWMatrix result;
68 Franz 743
                QStringList subtransform = QStringList::split('(', (*it));
744
                subtransform[0] = subtransform[0].stripWhiteSpace().lower();
745
                subtransform[1] = subtransform[1].simplifyWhiteSpace();
746
                QRegExp reg("[,( ]");
747
                QStringList params = QStringList::split(reg, subtransform[1]);
748
                if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
749
                        subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
750
                if(subtransform[0] == "rotate")
751
                {
752
                        if(params.count() == 3)
753
                        {
976 fschmid 754
                                double x = params[1].toDouble() * Conversion;
755
                                double y = params[2].toDouble() * Conversion;
68 Franz 756
                                result.translate(x, y);
757
                                result.rotate(params[0].toDouble());
758
                                result.translate(-x, -y);
759
                        }
760
                        else
761
                                result.rotate(params[0].toDouble());
762
                }
763
                else if(subtransform[0] == "translate")
764
                {
765
                        if(params.count() == 2)
976 fschmid 766
                                result.translate(params[0].toDouble() * Conversion, params[1].toDouble() * Conversion);
68 Franz 767
                        else    // Spec : if only one param given, assume 2nd param to be 0
2597 fschmid 768
                                result.translate(params[0].toDouble() * Conversion, 0);
68 Franz 769
                }
770
                else if(subtransform[0] == "scale")
771
                {
772
                        if(params.count() == 2)
773
                                result.scale(params[0].toDouble(), params[1].toDouble());
774
                        else    // Spec : if only one param given, assume uniform scaling
775
                                result.scale(params[0].toDouble(), params[0].toDouble());
776
                }
777
                else if(subtransform[0] == "skewx")
778
                        result.shear(tan(params[0].toDouble() * 0.01745329251994329576), 0.0F);
779
                else if(subtransform[0] == "skewy")
780
                        result.shear(0.0F, tan(params[0].toDouble() * 0.01745329251994329576));
781
                else if(subtransform[0] == "matrix")
782
                {
783
                        if(params.count() >= 6)
332 Franz 784
                        {
785
                                double sx = params[0].toDouble();
786
                                double sy = params[3].toDouble();
976 fschmid 787
                                result.setMatrix(sx, params[1].toDouble(), params[2].toDouble(), sy, params[4].toDouble() * Conversion, params[5].toDouble() * Conversion);
332 Franz 788
                        }
68 Franz 789
                }
6610 jghali 790
                ret = result * ret;
68 Franz 791
        }
2597 fschmid 792
        return ret;
68 Franz 793
}
794
 
795
const char * SVGPlug::getCoord( const char *ptr, double &number )
796
{
797
        int integer, exponent;
798
        double decimal, frac;
799
        int sign, expsign;
800
 
801
        exponent = 0;
802
        integer = 0;
803
        frac = 1.0;
804
        decimal = 0;
805
        sign = 1;
806
        expsign = 1;
807
 
808
        // read the sign
809
        if(*ptr == '+')
810
                ptr++;
811
        else if(*ptr == '-')
812
        {
813
                ptr++;
814
                sign = -1;
815
        }
816
 
817
        // read the integer part
818
        while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
819
                integer = (integer * 10) + *(ptr++) - '0';
820
        if(*ptr == '.') // read the decimals
217 Franz 821
        {
68 Franz 822
                ptr++;
823
                while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
824
                        decimal += (*(ptr++) - '0') * (frac *= 0.1);
217 Franz 825
        }
68 Franz 826
 
827
        if(*ptr == 'e' || *ptr == 'E') // read the exponent part
828
        {
829
                ptr++;
830
 
831
                // read the sign of the exponent
832
                if(*ptr == '+')
833
                        ptr++;
834
                else if(*ptr == '-')
835
                {
836
                        ptr++;
837
                        expsign = -1;
838
                }
839
 
840
                exponent = 0;
841
                while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
842
                {
843
                        exponent *= 10;
844
                        exponent += *ptr - '0';
845
                        ptr++;
846
                }
217 Franz 847
        }
68 Franz 848
        number = integer + decimal;
80 Franz 849
        number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
68 Franz 850
        // skip the following space
851
        if(*ptr == ' ')
852
                ptr++;
853
 
854
        return ptr;
855
}
856
 
857
bool SVGPlug::parseSVG( const QString &s, FPointArray *ite )
858
{
859
        QString d = s;
860
        d = d.replace( QRegExp( "," ), " ");
861
        bool ret = false;
862
        if( !d.isEmpty() )
217 Franz 863
        {
68 Franz 864
                d = d.simplifyWhiteSpace();
865
                const char *ptr = d.latin1();
866
                const char *end = d.latin1() + d.length() + 1;
867
                double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
868
                double px1, py1, px2, py2, px3, py3;
869
                bool relative;
870
                FirstM = true;
871
                char command = *(ptr++), lastCommand = ' ';
872
                subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
873
                while( ptr < end )
217 Franz 874
                {
68 Franz 875
                        if( *ptr == ' ' )
876
                                ptr++;
877
                        relative = false;
878
                        switch( command )
879
                        {
217 Franz 880
                        case 'm':
881
                                relative = true;
882
                        case 'M':
883
                                {
68 Franz 884
                                        ptr = getCoord( ptr, tox );
885
                                        ptr = getCoord( ptr, toy );
976 fschmid 886
                                        tox *= Conversion;
887
                                        toy *= Conversion;
68 Franz 888
                                        WasM = true;
889
                                        subpathx = curx = relative ? curx + tox : tox;
890
                                        subpathy = cury = relative ? cury + toy : toy;
456 fschmid 891
                                        svgMoveTo(curx, cury );
68 Franz 892
                                        break;
217 Franz 893
                                }
894
                        case 'l':
895
                                relative = true;
896
                        case 'L':
897
                                {
68 Franz 898
                                        ptr = getCoord( ptr, tox );
899
                                        ptr = getCoord( ptr, toy );
976 fschmid 900
                                        tox *= Conversion;
901
                                        toy *= Conversion;
68 Franz 902
                                        curx = relative ? curx + tox : tox;
903
                                        cury = relative ? cury + toy : toy;
904
                                        svgLineTo(ite, curx, cury );
905
                                        break;
217 Franz 906
                                }
907
                        case 'h':
908
                                {
68 Franz 909
                                        ptr = getCoord( ptr, tox );
976 fschmid 910
                                        tox *= Conversion;
68 Franz 911
                                        curx = curx + tox;
912
                                        svgLineTo(ite, curx, cury );
913
                                        break;
217 Franz 914
                                }
915
                        case 'H':
916
                                {
68 Franz 917
                                        ptr = getCoord( ptr, tox );
976 fschmid 918
                                        tox *= Conversion;
68 Franz 919
                                        curx = tox;
920
                                        svgLineTo(ite, curx, cury );
921
                                        break;
217 Franz 922
                                }
923
                        case 'v':
924
                                {
68 Franz 925
                                        ptr = getCoord( ptr, toy );
976 fschmid 926
                                        toy *= Conversion;
68 Franz 927
                                        cury = cury + toy;
928
                                        svgLineTo(ite, curx, cury );
929
                                        break;
217 Franz 930
                                }
931
                        case 'V':
932
                                {
68 Franz 933
                                        ptr = getCoord( ptr, toy );
976 fschmid 934
                                        toy *= Conversion;
68 Franz 935
                                        cury = toy;
936
                                        svgLineTo(ite,  curx, cury );
937
                                        break;
217 Franz 938
                                }
939
                        case 'z':
940
                        case 'Z':
941
                                {
68 Franz 942
                                        curx = subpathx;
943
                                        cury = subpathy;
944
                                        svgClosePath(ite);
945
                                        break;
217 Franz 946
                                }
947
                        case 'c':
948
                                relative = true;
949
                        case 'C':
950
                                {
68 Franz 951
                                        ptr = getCoord( ptr, x1 );
952
                                        ptr = getCoord( ptr, y1 );
953
                                        ptr = getCoord( ptr, x2 );
954
                                        ptr = getCoord( ptr, y2 );
955
                                        ptr = getCoord( ptr, tox );
956
                                        ptr = getCoord( ptr, toy );
976 fschmid 957
                                        tox *= Conversion;
958
                                        toy *= Conversion;
959
                                        x1 *= Conversion;
960
                                        y1 *= Conversion;
961
                                        x2 *= Conversion;
962
                                        y2 *= Conversion;
68 Franz 963
                                        px1 = relative ? curx + x1 : x1;
964
                                        py1 = relative ? cury + y1 : y1;
965
                                        px2 = relative ? curx + x2 : x2;
966
                                        py2 = relative ? cury + y2 : y2;
967
                                        px3 = relative ? curx + tox : tox;
968
                                        py3 = relative ? cury + toy : toy;
217 Franz 969
                                        svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
970
                                        contrlx = relative ? curx + x2 : x2;
68 Franz 971
                                        contrly = relative ? cury + y2 : y2;
972
                                        curx = relative ? curx + tox : tox;
973
                                        cury = relative ? cury + toy : toy;
974
                                        break;
217 Franz 975
                                }
976
                        case 's':
977
                                relative = true;
978
                        case 'S':
979
                                {
68 Franz 980
                                        ptr = getCoord( ptr, x2 );
981
                                        ptr = getCoord( ptr, y2 );
982
                                        ptr = getCoord( ptr, tox );
983
                                        ptr = getCoord( ptr, toy );
976 fschmid 984
                                        tox *= Conversion;
985
                                        toy *= Conversion;
986
                                        x2 *= Conversion;
987
                                        y2 *= Conversion;
68 Franz 988
                                        px1 = 2 * curx - contrlx;
989
                                        py1 = 2 * cury - contrly;
990
                                        px2 = relative ? curx + x2 : x2;
991
                                        py2 = relative ? cury + y2 : y2;
992
                                        px3 = relative ? curx + tox : tox;
993
                                        py3 = relative ? cury + toy : toy;
994
                                        svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
995
                                        contrlx = relative ? curx + x2 : x2;
996
                                        contrly = relative ? cury + y2 : y2;
997
                                        curx = relative ? curx + tox : tox;
998
                                        cury = relative ? cury + toy : toy;
999
                                        break;
217 Franz 1000
                                }
1001
                        case 'q':
1002
                                relative = true;
1003
                        case 'Q':
1004
                                {
68 Franz 1005
                                        ptr = getCoord( ptr, x1 );
1006
                                        ptr = getCoord( ptr, y1 );
1007
                                        ptr = getCoord( ptr, tox );
1008
                                        ptr = getCoord( ptr, toy );
976 fschmid 1009
                                        tox *= Conversion;
1010
                                        toy *= Conversion;
1011
                                        x1 *= Conversion;
1012
                                        y1 *= Conversion;
68 Franz 1013
                                        px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
1014
                                        py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
1015
                                        px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
1016
                                        py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
1017
                                        px3 = relative ? curx + tox : tox;
1018
                                        py3 = relative ? cury + toy : toy;
1019
                                        svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1020
                                        contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0);
1021
                                        contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0);
1022
                                        curx = relative ? curx + tox : tox;
1023
                                        cury = relative ? cury + toy : toy;
1024
                                        break;
217 Franz 1025
                                }
1026
                        case 't':
1027
                                relative = true;
1028
                        case 'T':
1029
                                {
68 Franz 1030
                                        ptr = getCoord(ptr, tox);
1031
                                        ptr = getCoord(ptr, toy);
976 fschmid 1032
                                        tox *= Conversion;
1033
                                        toy *= Conversion;
68 Franz 1034
                                        xc = 2 * curx - contrlx;
1035
                                        yc = 2 * cury - contrly;
1036
                                        px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0);
1037
                                        py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0);
1038
                                        px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
1039
                                        py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
1040
                                        px3 = relative ? curx + tox : tox;
1041
                                        py3 = relative ? cury + toy : toy;
1042
                                        svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1043
                                        contrlx = xc;
1044
                                        contrly = yc;
1045
                                        curx = relative ? curx + tox : tox;
1046
                                        cury = relative ? cury + toy : toy;
1047
                                        break;
217 Franz 1048
                                }
1049
                        case 'a':
1050
                                relative = true;
1051
                        case 'A':
1052
                                {
68 Franz 1053
                                        bool largeArc, sweep;
1054
                                        double angle, rx, ry;
1055
                                        ptr = getCoord( ptr, rx );
1056
                                        ptr = getCoord( ptr, ry );
1057
                                        ptr = getCoord( ptr, angle );
1058
                                        ptr = getCoord( ptr, tox );
976 fschmid 1059
                                        ry *= Conversion;
1060
                                        rx *= Conversion;
68 Franz 1061
                                        largeArc = tox == 1;
1062
                                        ptr = getCoord( ptr, tox );
1063
                                        sweep = tox == 1;
1064
                                        ptr = getCoord( ptr, tox );
1065
                                        ptr = getCoord( ptr, toy );
976 fschmid 1066
                                        tox *= Conversion;
1067
                                        toy *= Conversion;
68 Franz 1068
                                        calculateArc(ite, relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep );
1069
                                }
217 Franz 1070
                        }
68 Franz 1071
                        lastCommand = command;
1072
                        if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
217 Franz 1073
                        {
68 Franz 1074
                                // there are still coords in this command
1075
                                if(command == 'M')
1076
                                        command = 'L';
1077
                                else if(command == 'm')
1078
                                        command = 'l';
217 Franz 1079
                        }
68 Franz 1080
                        else
1081
                                command = *(ptr++);
1082
 
1083
                        if( lastCommand != 'C' && lastCommand != 'c' &&
217 Franz 1084
                                lastCommand != 'S' && lastCommand != 's' &&
1085
                                lastCommand != 'Q' && lastCommand != 'q' &&
1086
                                lastCommand != 'T' && lastCommand != 't')
68 Franz 1087
                        {
1088
                                contrlx = curx;
1089
                                contrly = cury;
1090
                        }
1091
                }
1092
                if ((lastCommand != 'z') && (lastCommand != 'Z'))
1093
                        ret = true;
1094
                if (ite->size() > 2)
217 Franz 1095
                {
68 Franz 1096
                        if ((ite->point(0).x() == ite->point(ite->size()-2).x()) && (ite->point(0).y() == ite->point(ite->size()-2).y()))
1097
                                ret = false;
217 Franz 1098
                }
68 Franz 1099
        }
1100
        return ret;
1101
}
1102
 
1103
void SVGPlug::calculateArc(FPointArray *ite, bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag)
1104
{
1105
        double sin_th, cos_th;
1106
        double a00, a01, a10, a11;
1107
        double x0, y0, x1, y1, xc, yc;
1108
        double d, sfactor, sfactor_sq;
1109
        double th0, th1, th_arc;
1110
        int i, n_segs;
1111
        sin_th = sin(angle * (M_PI / 180.0));
1112
        cos_th = cos(angle * (M_PI / 180.0));
1113
        double dx;
1114
        if(!relative)
1115
                dx = (curx - x) / 2.0;
1116
        else
1117
                dx = -x / 2.0;
1118
        double dy;
1119
        if(!relative)
1120
                dy = (cury - y) / 2.0;
1121
        else
1122
                dy = -y / 2.0;
1123
        double _x1 =  cos_th * dx + sin_th * dy;
1124
        double _y1 = -sin_th * dx + cos_th * dy;
1125
        double Pr1 = r1 * r1;
1126
        double Pr2 = r2 * r2;
1127
        double Px = _x1 * _x1;
1128
        double Py = _y1 * _y1;
1129
        // Spec : check if radii are large enough
1130
        double check = Px / Pr1 + Py / Pr2;
1131
        if(check > 1)
1132
        {
1133
                r1 = r1 * sqrt(check);
1134
                r2 = r2 * sqrt(check);
1135
        }
1136
        a00 = cos_th / r1;
1137
        a01 = sin_th / r1;
1138
        a10 = -sin_th / r2;
1139
        a11 = cos_th / r2;
1140
        x0 = a00 * curx + a01 * cury;
1141
        y0 = a10 * curx + a11 * cury;
1142
        if(!relative)
1143
                x1 = a00 * x + a01 * y;
1144
        else
1145
                x1 = a00 * (curx + x) + a01 * (cury + y);
1146
        if(!relative)
1147
                y1 = a10 * x + a11 * y;
1148
        else
1149
                y1 = a10 * (curx + x) + a11 * (cury + y);
1150
        /* (x0, y0) is current point in transformed coordinate space.
1151
           (x1, y1) is new point in transformed coordinate space.
1152
 
1153
           The arc fits a unit-radius circle in this space.
217 Franz 1154
            */
68 Franz 1155
        d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
1156
        sfactor_sq = 1.0 / d - 0.25;
1157
        if(sfactor_sq < 0)
1158
                sfactor_sq = 0;
1159
        sfactor = sqrt(sfactor_sq);
1160
        if(sweepFlag == largeArcFlag)
1161
                sfactor = -sfactor;
1162
        xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
1163
        yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
1164
 
1165
        /* (xc, yc) is center of the circle. */
1166
        th0 = atan2(y0 - yc, x0 - xc);
1167
        th1 = atan2(y1 - yc, x1 - xc);
1168
        th_arc = th1 - th0;
1169
        if(th_arc < 0 && sweepFlag)
1170
                th_arc += 2 * M_PI;
1171
        else if(th_arc > 0 && !sweepFlag)
1172
                th_arc -= 2 * M_PI;
80 Franz 1173
        n_segs = static_cast<int>(ceil(fabs(th_arc / (M_PI * 0.5 + 0.001))));
68 Franz 1174
        for(i = 0; i < n_segs; i++)
1175
        {
1176
                {
1177
                        double sin_th, cos_th;
1178
                        double a00, a01, a10, a11;
1179
                        double x1, y1, x2, y2, x3, y3;
1180
                        double t;
1181
                        double th_half;
1182
                        double _th0 = th0 + i * th_arc / n_segs;
1183
                        double _th1 = th0 + (i + 1) * th_arc / n_segs;
1184
                        sin_th = sin(angle * (M_PI / 180.0));
1185
                        cos_th = cos(angle * (M_PI / 180.0));
1186
                        /* inverse transform compared with rsvg_path_arc */
1187
                        a00 = cos_th * r1;
1188
                        a01 = -sin_th * r2;
1189
                        a10 = sin_th * r1;
1190
                        a11 = cos_th * r2;
1191
                        th_half = 0.5 * (_th1 - _th0);
1192
                        t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
1193
                        x1 = xc + cos(_th0) - t * sin(_th0);
1194
                        y1 = yc + sin(_th0) + t * cos(_th0);
1195
                        x3 = xc + cos(_th1);
1196
                        y3 = yc + sin(_th1);
1197
                        x2 = x3 + t * sin(_th1);
1198
                        y2 = y3 - t * cos(_th1);
1199
                        svgCurveToCubic(ite, a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3 );
1200
                }
1201
        }
1202
        if(!relative)
1203
                curx = x;
1204
        else
1205
                curx += x;
1206
        if(!relative)
1207
                cury = y;
1208
        else
1209
                cury += y;
1210
}
1211
 
456 fschmid 1212
void SVGPlug::svgMoveTo(double x1, double y1)
68 Franz 1213
{
1214
        CurrX = x1;
1215
        CurrY = y1;
1216
        StartX = x1;
1217
        StartY = y1;
1218
        PathLen = 0;
1219
}
1220
 
1221
void SVGPlug::svgLineTo(FPointArray *i, double x1, double y1)
1222
{
1223
        if ((!FirstM) && (WasM))
217 Franz 1224
        {
68 Franz 1225
                i->setMarker();
1226
                PathLen += 4;
217 Franz 1227
        }
68 Franz 1228
        FirstM = false;
1229
        WasM = false;
87 Franz 1230
        if (i->size() > 3)
217 Franz 1231
        {
87 Franz 1232
                FPoint b1 = i->point(i->size()-4);
1233
                FPoint b2 = i->point(i->size()-3);
1234
                FPoint b3 = i->point(i->size()-2);
1235
                FPoint b4 = i->point(i->size()-1);
1236
                FPoint n1 = FPoint(CurrX, CurrY);
1237
                FPoint n2 = FPoint(x1, y1);
1238
                if ((b1 == n1) && (b2 == n1) && (b3 == n2) && (b4 == n2))
1239
                        return;
217 Franz 1240
        }
87 Franz 1241
        i->addPoint(FPoint(CurrX, CurrY));
1242
        i->addPoint(FPoint(CurrX, CurrY));
1243
        i->addPoint(FPoint(x1, y1));
1244
        i->addPoint(FPoint(x1, y1));
68 Franz 1245
        CurrX = x1;
1246
        CurrY = y1;
1247
        PathLen += 4;
1248
}
1249
 
1250
void SVGPlug::svgCurveToCubic(FPointArray *i, double x1, double y1, double x2, double y2, double x3, double y3)
1251
{
1252
        if ((!FirstM) && (WasM))
217 Franz 1253
        {
68 Franz 1254
                i->setMarker();
1255
                PathLen += 4;
217 Franz 1256
        }
68 Franz 1257
        FirstM = false;
1258
        WasM = false;
87 Franz 1259
        if (PathLen > 3)
217 Franz 1260
        {
87 Franz 1261
                FPoint b1 = i->point(i->size()-4);
1262
                FPoint b2 = i->point(i->size()-3);
1263
                FPoint b3 = i->point(i->size()-2);
1264
                FPoint b4 = i->point(i->size()-1);
1265
                FPoint n1 = FPoint(CurrX, CurrY);
1266
                FPoint n2 = FPoint(x1, y1);
1267
                FPoint n3 = FPoint(x3, y3);
1268
                FPoint n4 = FPoint(x2, y2);
1269
                if ((b1 == n1) && (b2 == n2) && (b3 == n3) && (b4 == n4))
1270
                        return;
217 Franz 1271
        }
87 Franz 1272
        i->addPoint(FPoint(CurrX, CurrY));
1273
        i->addPoint(FPoint(x1, y1));
1274
        i->addPoint(FPoint(x3, y3));
1275
        i->addPoint(FPoint(x2, y2));
68 Franz 1276
        CurrX = x3;
1277
        CurrY = y3;
1278
        PathLen += 4;
1279
}
1280
 
1281
void SVGPlug::svgClosePath(FPointArray *i)
1282
{
501 fschmid 1283
        if (PathLen > 2)
217 Franz 1284
        {
501 fschmid 1285
                if ((PathLen == 4) || (i->point(i->size()-2).x() != StartX) || (i->point(i->size()-2).y() != StartY))
1286
                {
1287
                        i->addPoint(i->point(i->size()-2));
1288
                        i->addPoint(i->point(i->size()-3));
1289
                        i->addPoint(FPoint(StartX, StartY));
1290
                        i->addPoint(FPoint(StartX, StartY));
1291
                }
217 Franz 1292
        }
68 Franz 1293
}
1294
 
1295
QColor SVGPlug::parseColorN( const QString &rgbColor )
1296
{
1297
        int r, g, b;
1298
        keywordToRGB( rgbColor, r, g, b );
1299
        return QColor( r, g, b );
1300
}
1301
 
4645 subik 1302
 
68 Franz 1303
QString SVGPlug::parseColor( const QString &s )
1304
{
1305
        QColor c;
4546 subik 1306
        QString ret = CommonStrings::None;
68 Franz 1307
        if( s.startsWith( "rgb(" ) )
217 Franz 1308
        {
68 Franz 1309
                QString parse = s.stripWhiteSpace();
1310
                QStringList colors = QStringList::split( ',', parse );
1311
                QString r = colors[0].right( ( colors[0].length() - 4 ) );
1312
                QString g = colors[1];
1313
                QString b = colors[2].left( ( colors[2].length() - 1 ) );
1314
                if( r.contains( "%" ) )
217 Franz 1315
                {
68 Franz 1316
                        r = r.left( r.length() - 1 );
80 Franz 1317
                        r = QString::number( static_cast<int>( ( static_cast<double>( 255 * r.toDouble() ) / 100.0 ) ) );
217 Franz 1318
                }
68 Franz 1319
                if( g.contains( "%" ) )
217 Franz 1320
                {
68 Franz 1321
                        g = g.left( g.length() - 1 );
80 Franz 1322
                        g = QString::number( static_cast<int>( ( static_cast<double>( 255 * g.toDouble() ) / 100.0 ) ) );
217 Franz 1323
                }
68 Franz 1324
                if( b.contains( "%" ) )
217 Franz 1325
                {
68 Franz 1326
                        b = b.left( b.length() - 1 );
80 Franz 1327
                        b = QString::number( static_cast<int>( ( static_cast<double>( 255 * b.toDouble() ) / 100.0 ) ) );
217 Franz 1328
                }
68 Franz 1329
                c = QColor(r.toInt(), g.toInt(), b.toInt());
217 Franz 1330
        }
68 Franz 1331
        else
217 Franz 1332
        {
68 Franz 1333
                QString rgbColor = s.stripWhiteSpace();
1334
                if( rgbColor.startsWith( "#" ) )
1335
                        c.setNamedColor( rgbColor );
1336
                else
1337
                        c = parseColorN( rgbColor );
217 Franz 1338
        }
1065 cbradney 1339
        ColorList::Iterator it;
68 Franz 1340
        bool found = false;
1488 fschmid 1341
        int r, g, b;
1342
        QColor tmpR;
3292 cbradney 1343
        for (it = currDoc->PageColors.begin(); it != currDoc->PageColors.end(); ++it)
217 Franz 1344
        {
3292 cbradney 1345
                currDoc->PageColors[it.key()].getRGB(&r, &g, &b);
1488 fschmid 1346
                tmpR.setRgb(r, g, b);
3292 cbradney 1347
                if (c == tmpR && currDoc->PageColors[it.key()].getColorModel() == colorModelRGB)
68 Franz 1348
                {
1349
                        ret = it.key();
1350
                        found = true;
1351
                }
217 Franz 1352
        }
68 Franz 1353
        if (!found)
217 Franz 1354
        {
2886 fschmid 1355
                ScColor tmp;
68 Franz 1356
                tmp.fromQColor(c);
3292 cbradney 1357
                currDoc->PageColors.insert("FromSVG"+c.name(), tmp);
4026 craig 1358
                ScMW->propertiesPalette->updateColorList();
68 Franz 1359
                ret = "FromSVG"+c.name();
217 Franz 1360
        }
68 Franz 1361
        return ret;
1362
}
1363
 
1364
void SVGPlug::parsePA( SvgStyle *obj, const QString &command, const QString &params )
1365
{
6355 jghali 1366
        if( command == "display" )
1367
                obj->Display = (params == "none") ? false : true;
1368
        else if( command == "stroke-opacity" )
6126 jghali 1369
                obj->StrokeOpacity  = fromPercentage(params);
976 fschmid 1370
        else if( command == "fill-opacity" )
6126 jghali 1371
                obj->FillOpacity = fromPercentage(params);
976 fschmid 1372
        else if( command == "opacity" )
6126 jghali 1373
                obj->Opacity = fromPercentage(params);
976 fschmid 1374
        else if( command == "fill" )
1375
        {
217 Franz 1376
                if ((obj->InherCol) && (params == "currentColor"))
1377
                        obj->FillCol = obj->CurCol;
1378
                else if (params == "none")
68 Franz 1379
                {
4546 subik 1380
                        obj->FillCol = CommonStrings::None;
68 Franz 1381
                }
217 Franz 1382
                else if( params.startsWith( "url(" ) )
68 Franz 1383
                {
217 Franz 1384
                        unsigned int start = params.find("#") + 1;
1385
                        unsigned int end = params.findRev(")");
1386
                        QString key = params.mid(start, end - start);
2877 cbradney 1387
                        while (!m_gradients[key].reference.isEmpty())
943 fschmid 1388
                        {
976 fschmid 1389
                                QString key2 = m_gradients[key].reference;
1390
                                if (m_gradients[key2].typeValid)
1391
                                        obj->Gradient = m_gradients[key2].Type;
1392
                                if (m_gradients[key2].gradientValid)
1393
                                        obj->GradCo = m_gradients[key2].gradient;
1394
                                if (m_gradients[key2].cspaceValid)
1395
                                        obj->CSpace = m_gradients[key2].CSpace;
1396
                                if (m_gradients[key2].x1Valid)
1397
                                        obj->GX1 = m_gradients[key2].X1;
1398
                                if (m_gradients[key2].y1Valid)
1399
                                        obj->GY1 = m_gradients[key2].Y1;
1400
                                if (m_gradients[key2].x2Valid)
1401
                                        obj->GX2 = m_gradients[key2].X2;
1402
                                if (m_gradients[key2].y2Valid)
1403
                                        obj->GY2 = m_gradients[key2].Y2;
1404
                                if (m_gradients[key2].matrixValid)
1405
                                        obj->matrixg = m_gradients[key2].matrix;
1406
                                key = m_gradients[key].reference;
943 fschmid 1407
                        }
976 fschmid 1408
                        key = params.mid(start, end - start);
943 fschmid 1409
                        if (m_gradients[key].typeValid)
1410
                                obj->Gradient = m_gradients[key].Type;
1411
                        if (m_gradients[key].gradientValid)
1412
                                obj->GradCo = m_gradients[key].gradient;
1413
                        if (m_gradients[key].cspaceValid)
1414
                                obj->CSpace = m_gradients[key].CSpace;
1415
                        if (m_gradients[key].x1Valid)
1416
                                obj->GX1 = m_gradients[key].X1;
1417
                        if (m_gradients[key].y1Valid)
1418
                                obj->GY1 = m_gradients[key].Y1;
1419
                        if (m_gradients[key].x2Valid)
1420
                                obj->GX2 = m_gradients[key].X2;
1421
                        if (m_gradients[key].y2Valid)
1422
                                obj->GY2 = m_gradients[key].Y2;
1423
                        if (m_gradients[key].matrixValid)
1424
                                obj->matrixg = m_gradients[key].matrix;
4546 subik 1425
                        obj->FillCol = CommonStrings::None;
68 Franz 1426
                }
217 Franz 1427
                else
1428
                        obj->FillCol = parseColor(params);
68 Franz 1429
        }
4926 avox 1430
        else if( command == "fill-rule" )
1431
        {
1432
                obj->fillRule = params;
1433
        }
68 Franz 1434
        else if( command == "color" )
1435
        {
1436
                if (params == "none")
4546 subik 1437
                        obj->CurCol = CommonStrings::None;
68 Franz 1438
                else if( params.startsWith( "url(" ) )
217 Franz 1439
                {
4546 subik 1440
                        obj->CurCol = CommonStrings::None;
217 Franz 1441
                }
68 Franz 1442
                else
217 Franz 1443
                {
68 Franz 1444
                        obj->CurCol = parseColor(params);
217 Franz 1445
                }
68 Franz 1446
        }
1447
        else if( command == "stroke" )
1448
        {
217 Franz 1449
                if ((obj->InherCol) && (params == "currentColor"))
1450
                        obj->StrokeCol = obj->CurCol;
1451
                else if (params == "none")
68 Franz 1452
                {
4546 subik 1453
                        obj->StrokeCol = CommonStrings::None;
68 Franz 1454
                }
1455
                else if( params.startsWith( "url(" ) )
1456
                {
4546 subik 1457
                        obj->StrokeCol = CommonStrings::None;
68 Franz 1458
                }
1459
                else
217 Franz 1460
                        obj->StrokeCol = parseColor(params);
1461
                /*              if( params == "none" )
1462
                                        gc->stroke.setType( VStroke::none );
1463
                                else if( params.startsWith( "url(" ) )
1464
                                {
1465
                                        unsigned int start = params.find("#") + 1;
1466
                                        unsigned int end = params.findRev(")");
1467
                                        QString key = params.mid( start, end - start );
1468
                                        gc->stroke.gradient() = m_gradients[ key ].gradient;
1469
                                        gc->stroke.gradient().transform( m_gradients[ key ].gradientTransform );
1470
                                        gc->stroke.gradient().transform( gc->matrix );
1471
                                        gc->stroke.setType( VStroke::grad );
1472
                                }
1473
                                else
1474
                                {
1475
                                        parseColor( strokecolor, params );
1476
                                        gc->stroke.setType( VStroke::solid );
1477
                                } */
68 Franz 1478
        }
1479
        else if( command == "stroke-width" )
1480
                obj->LWidth = parseUnit( params );
1481
        else if( command == "stroke-linejoin" )
217 Franz 1482
        {
68 Franz 1483
                if( params == "miter" )
1484
                        obj->PLineJoin = Qt::MiterJoin;
1485
                else if( params == "round" )
1486
                        obj->PLineJoin = Qt::RoundJoin;
1487
                else if( params == "bevel" )
1488
                        obj->PLineJoin = Qt::BevelJoin;
217 Franz 1489
        }
68 Franz 1490
        else if( command == "stroke-linecap" )
217 Franz 1491
        {
68 Franz 1492
                if( params == "butt" )
1493
                        obj->PLineEnd = Qt::FlatCap;
1494
                else if( params == "round" )
1495
                        obj->PLineEnd = Qt::RoundCap;
1496
                else if( params == "square" )
1497
                        obj->PLineEnd = Qt::SquareCap;
217 Franz 1498
        }
1499
        //      else if( command == "stroke-miterlimit" )
1500
        //              gc->stroke.setMiterLimit( params.todouble() );
68 Franz 1501
        else if( command == "stroke-dasharray" )
217 Franz 1502
        {
80 Franz 1503
                QValueList<double> array;
68 Franz 1504
                if(params != "none")
217 Franz 1505
                {
68 Franz 1506
                        QStringList dashes = QStringList::split( ' ', params );
217 Franz 1507
                        for( QStringList::Iterator it = dashes.begin(); it != dashes.end(); ++it )
80 Franz 1508
                                array.append( (*it).toDouble() );
217 Franz 1509
                }
68 Franz 1510
                obj->dashArray = array;
217 Franz 1511
        }
68 Franz 1512
        else if( command == "stroke-dashoffset" )
80 Franz 1513
                obj->dashOffset = params.toDouble();
68 Franz 1514
        else if( command == "font-family" )
217 Franz 1515
        {
68 Franz 1516
                QString family = params;
1517
                QString ret = "";
1518
                family.replace( QRegExp( "'" ) , QChar( ' ' ) );
3292 cbradney 1519
                obj->Family = currDoc->toolSettings.defFont; // family;
68 Franz 1520
                bool found = false;
2834 cbradney 1521
                SCFontsIterator it(PrefsManager::instance()->appPrefs.AvailFonts);
68 Franz 1522
                for ( ; it.current(); ++it)
217 Franz 1523
                {
68 Franz 1524
                        QString fam;
3544 avox 1525
                        QString fn = it.current()->scName();
68 Franz 1526
                        int     pos=fn.find(" ");
1527
                        fam = fn.left(pos);
1528
                        if (fam == family)
217 Franz 1529
                        {
68 Franz 1530
                                found = true;
1531
                                ret = fn;
1532
                        }
217 Franz 1533
                }
68 Franz 1534
                if (found)
1535
                        obj->Family = ret;
1536
                else
3292 cbradney 1537
                        obj->Family = currDoc->toolSettings.defFont;
217 Franz 1538
        }
68 Franz 1539
        else if( command == "font-size" )
111 Franz 1540
                obj->FontSize = static_cast<int>(parseUnit(params) * 10.0);
6574 jghali 1541
        else if( command == "text-anchor" )
1542
                obj->textAnchor = params;
3800 subik 1543
        else
1544
                unsupported = true;
68 Franz 1545
}
1546
 
1547
void SVGPlug::parseStyle( SvgStyle *obj, const QDomElement &e )
1548
{
1549
        SvgStyle *gc = m_gc.current();
1550
        if (!gc)
1551
                return;
6355 jghali 1552
        if( !e.attribute( "display" ).isEmpty() )
1553
                parsePA( obj, "display", e.attribute( "display" ) );
68 Franz 1554
        if( !e.attribute( "color" ).isEmpty() )
217 Franz 1555
        {
68 Franz 1556
                if (e.attribute( "color" ) == "inherit")
1557
                        gc->InherCol = true;
1558
                else
1559
                        parsePA( obj, "color", e.attribute( "color" ) );
217 Franz 1560
        }
68 Franz 1561
        if( !e.attribute( "fill" ).isEmpty() )
1562
                parsePA( obj, "fill", e.attribute( "fill" ) );
1563
        if( !e.attribute( "stroke" ).isEmpty() )
1564
                parsePA( obj, "stroke", e.attribute( "stroke" ) );
1565
        if( !e.attribute( "stroke-width" ).isEmpty() )
1566
                parsePA( obj, "stroke-width", e.attribute( "stroke-width" ) );
1567
        if( !e.attribute( "stroke-linejoin" ).isEmpty() )
1568
                parsePA( obj, "stroke-linejoin", e.attribute( "stroke-linejoin" ) );
1569
        if( !e.attribute( "stroke-linecap" ).isEmpty() )
1570
                parsePA( obj, "stroke-linecap", e.attribute( "stroke-linecap" ) );
1571
        if( !e.attribute( "stroke-dasharray" ).isEmpty() )
1572
                parsePA( obj, "stroke-dasharray", e.attribute( "stroke-dasharray" ) );
1573
        if( !e.attribute( "stroke-dashoffset" ).isEmpty() )
1574
                parsePA( obj, "stroke-dashoffset", e.attribute( "stroke-dashoffset" ) );
1575
        if( !e.attribute( "stroke-opacity" ).isEmpty() )
1576
                parsePA( obj, "stroke-opacity", e.attribute( "stroke-opacity" ) );
217 Franz 1577
        /*      if( !e.attribute( "stroke-miterlimit" ).isEmpty() )
1578
                        parsePA( obj, "stroke-miterlimit", e.attribute( "stroke-miterlimit" ) );   */
68 Franz 1579
        if( !e.attribute( "fill-opacity" ).isEmpty() )
1580
                parsePA( obj, "fill-opacity", e.attribute( "fill-opacity" ) );
1581
        if( !e.attribute( "opacity" ).isEmpty() )
1582
                parsePA( obj, "opacity", e.attribute( "opacity" ) );
1583
        if( !e.attribute( "font-family" ).isEmpty() )
1584
                parsePA( obj, "font-family", e.attribute( "font-family" ) );
1585
        if( !e.attribute( "font-size" ).isEmpty() )
1586
                parsePA( obj, "font-size", e.attribute( "font-size" ) );
6574 jghali 1587
        if( !e.attribute( "text-anchor" ).isEmpty() )
1588
                parsePA( obj, "text-anchor", e.attribute( "text-anchor" ) );
68 Franz 1589
        QString style = e.attribute( "style" ).simplifyWhiteSpace();
1590
        QStringList substyles = QStringList::split( ';', style );
217 Franz 1591
        for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
1592
        {
68 Franz 1593
                QStringList substyle = QStringList::split( ':', (*it) );
1594
                QString command = substyle[0].stripWhiteSpace();
1595
                QString params  = substyle[1].stripWhiteSpace();
1596
                parsePA( obj, command, params );
217 Franz 1597
        }
68 Franz 1598
        return;
1599
}
1600
 
1601
void SVGPlug::parseColorStops(GradientHelper *gradient, const QDomElement &e)
1602
{
1603
        QString Col = "Black";
705 fschmid 1604
        double offset = 0;
1605
        double opa;
68 Franz 1606
        for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
217 Franz 1607
        {
296 Franz 1608
                opa = 1.0;
68 Franz 1609
                QDomElement stop = n.toElement();
1610
                if(stop.tagName() == "stop")
217 Franz 1611
                {
68 Franz 1612
                        QString temp = stop.attribute( "offset" );
1613
                        if( temp.contains( '%' ) )
217 Franz 1614
                        {
68 Franz 1615
                                temp = temp.left( temp.length() - 1 );
80 Franz 1616
                                offset = temp.toDouble() / 100.0;
217 Franz 1617
                        }
68 Franz 1618
                        else
80 Franz 1619
                                offset = temp.toDouble();
296 Franz 1620
                        if( !stop.attribute( "stop-opacity" ).isEmpty() )
1621
                                opa = fromPercentage(stop.attribute("stop-opacity"));
68 Franz 1622
                        if( !stop.attribute( "stop-color" ).isEmpty() )
1623
                                Col = parseColor(stop.attribute("stop-color"));
1624
                        else
217 Franz 1625
                        {
68 Franz 1626
                                QString style = stop.attribute( "style" ).simplifyWhiteSpace();
1627
                                QStringList substyles = QStringList::split( ';', style );
217 Franz 1628
                                for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
1629
                                {
68 Franz 1630
                                        QStringList substyle = QStringList::split( ':', (*it) );
1631
                                        QString command = substyle[0].stripWhiteSpace();
1632
                                        QString params  = substyle[1].stripWhiteSpace();
1633
                                        if( command == "stop-color" )
1634
                                                Col = parseColor(params);
296 Franz 1635
                                        if( command == "stop-opacity" )
1636
                                                opa = fromPercentage(params);
68 Franz 1637
                                }
1638
                        }
217 Franz 1639
                }
3292 cbradney 1640
                gradient->gradient.addStop( currDoc->PageColors[Col].getRGBColor(), offset, 0.5, opa, Col, 100 );
943 fschmid 1641
                gradient->gradientValid = true;
217 Franz 1642
        }
6496 jghali 1643
        if (gradient->gradientValid)
1644
                gradient->gradient.filterStops();
68 Franz 1645
}
1646
 
1647
void SVGPlug::parseGradient( const QDomElement &e )
1648
{
1649
        GradientHelper gradhelper;
943 fschmid 1650
        gradhelper.gradientValid = false;
68 Franz 1651
        gradhelper.gradient.clearStops();
1652
        gradhelper.gradient.setRepeatMethod( VGradient::none );
1653
 
1654
        QString href = e.attribute("xlink:href").mid(1);
1655
        double x1, y1, x2, y2;
1656
        if (!href.isEmpty())
217 Franz 1657
        {
943 fschmid 1658
                if (m_gradients.contains(href))
1659
                {
1660
                        gradhelper.Type = m_gradients[href].Type;
1661
                        gradhelper.gradient = m_gradients[href].gradient;
1662
                        gradhelper.X1 = m_gradients[href].X1;
1663
                        gradhelper.Y1 = m_gradients[href].Y1;
1664
                        gradhelper.X2 = m_gradients[href].X2;
1665
                        gradhelper.Y2 = m_gradients[href].Y2;
1666
                        gradhelper.CSpace = m_gradients[href].CSpace;
1667
                        gradhelper.matrix = m_gradients[href].matrix;
1668
                        gradhelper.x1Valid = m_gradients[href].x1Valid;
1669
                        gradhelper.x2Valid = m_gradients[href].x2Valid;
1670
                        gradhelper.y1Valid = m_gradients[href].y1Valid;
1671
                        gradhelper.y2Valid = m_gradients[href].y2Valid;
1672
                        gradhelper.cspaceValid = m_gradients[href].cspaceValid;
1673
                        gradhelper.matrixValid = m_gradients[href].matrixValid;
1674
                        gradhelper.gradientValid = m_gradients[href].gradientValid;
1675
                        gradhelper.typeValid = m_gradients[href].typeValid;
1676
                }
1677
                gradhelper.reference = href;
217 Franz 1678
        }
296 Franz 1679
        if (e.tagName() == "linearGradient")
1680
        {
943 fschmid 1681
                if (e.hasAttribute("x1"))
1682
                {
6308 jghali 1683
                        gradhelper.X1 = parseUnit(e.attribute( "x1", "0"));
943 fschmid 1684
                        gradhelper.x1Valid = true;
1685
                }
1686
                if (e.hasAttribute("y1"))
1687
                {
6308 jghali 1688
                        gradhelper.Y1 = parseUnit(e.attribute( "y1", "0" ));
943 fschmid 1689
                        gradhelper.y1Valid = true;
1690
                }
1691
                if (e.hasAttribute("x2"))
1692
                {
6308 jghali 1693
                        gradhelper.X2 = parseUnit(e.attribute( "x2", "1" ));
943 fschmid 1694
                        gradhelper.x2Valid = true;
1695
                }
1696
                if (e.hasAttribute("y2"))
1697
                {
6308 jghali 1698
                        gradhelper.Y2 = parseUnit(e.attribute( "y2", "0" ));
943 fschmid 1699
                        gradhelper.y2Valid = true;
1700
                }
296 Franz 1701
                gradhelper.Type = 6;
943 fschmid 1702
                gradhelper.typeValid = true;
296 Franz 1703
        }
1704
        else
1705
        {
5535 mrdocs 1706
                if (e.hasAttribute("cx"))
943 fschmid 1707
                {
6308 jghali 1708
                        x1 = parseUnit(e.attribute("cx", "0.5"));
943 fschmid 1709
                        gradhelper.x1Valid = true;
1710
                }
5535 mrdocs 1711
                if (e.hasAttribute("cy"))
943 fschmid 1712
                {
6308 jghali 1713
                        y1 = parseUnit(e.attribute("cy", "0.5" ));
943 fschmid 1714
                        gradhelper.y1Valid = true;
1715
                }
5535 mrdocs 1716
                if (e.hasAttribute("r"))
943 fschmid 1717
                {
6308 jghali 1718
                        x2 = parseUnit(e.attribute("r", "0.5" ));
943 fschmid 1719
                        gradhelper.x2Valid = true;
1720
                }
296 Franz 1721
                y2 = y1;
943 fschmid 1722
                gradhelper.y2Valid = true;
296 Franz 1723
                gradhelper.X1 = x1;
1724
                gradhelper.Y1 = y1;
1725
                gradhelper.X2 = x1 + x2;
1726
                gradhelper.Y2 = y1;
1727
                gradhelper.Type = 7;
943 fschmid 1728
                gradhelper.typeValid = true;
296 Franz 1729
        }
298 Franz 1730
        if ( !e.attribute( "gradientUnits" ).isEmpty() )
1731
        {
1732
                QString uni = e.attribute( "gradientUnits");
1733
                if (uni == "userSpaceOnUse")
1734
                        gradhelper.CSpace = true;
1735
                else
1736
                        gradhelper.CSpace = false;
943 fschmid 1737
                gradhelper.cspaceValid = true;
298 Franz 1738
        }
1739
        else
943 fschmid 1740
        {
298 Franz 1741
                gradhelper.CSpace = false;
943 fschmid 1742
                gradhelper.cspaceValid = false;
1743
        }
296 Franz 1744
        QString transf = e.attribute("gradientTransform");
1745
        if( !transf.isEmpty() )
1746
        {
6308 jghali 1747
                gradhelper.matrix = parseTransform( e.attribute("gradientTransform") );
943 fschmid 1748
                gradhelper.matrixValid = true;
296 Franz 1749
        }
943 fschmid 1750
        else
1751
                gradhelper.matrixValid = false;
296 Franz 1752
        QString spreadMethod = e.attribute( "spreadMethod" );
1753
        if( !spreadMethod.isEmpty() )
1754
        {
1755
                if( spreadMethod == "reflect" )
1756
                        gradhelper.gradient.setRepeatMethod( VGradient::reflect );
1757
                else if( spreadMethod == "repeat" )
1758
                        gradhelper.gradient.setRepeatMethod( VGradient::repeat );
1759
        }
1760
        parseColorStops(&gradhelper, e);
68 Franz 1761
        m_gradients.insert(e.attribute("id"), gradhelper);
1762
}
1763
 
215 Franz 1764
QPtrList<PageItem> SVGPlug::parseText(double x, double y, const QDomElement &e)
68 Franz 1765
{
215 Franz 1766
        QPtrList<PageItem> GElements;
1767
        setupTransform(e);
68 Franz 1768
        QDomNode c = e.firstChild();
1769
        if ((!c.isNull()) && (c.toElement().tagName() == "tspan"))
215 Franz 1770
        {
68 Franz 1771
                for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
215 Franz 1772
                {
68 Franz 1773
                        QDomElement tspan = n.toElement();
1774
                        addGraphicContext();
1775
                        SvgStyle *gc = m_gc.current();
1776
                        parseStyle(gc, tspan);
6574 jghali 1777
                        if (!gc->Display)
1778
                                continue;
1779
                        QPtrList<PageItem> el = parseTextElement(x, y, tspan);
1780
                        for (uint ec = 0; ec < el.count(); ++ec)
215 Franz 1781
                        {
6574 jghali 1782
                                GElements.append(el.at(ec));
1783
                                Elements.append(el.at(ec));
215 Franz 1784
                        }
68 Franz 1785
                        delete( m_gc.pop() );
1786
                }
215 Franz 1787
        }
68 Franz 1788
        else
215 Franz 1789
        {
68 Franz 1790
                SvgStyle *gc = m_gc.current();
6574 jghali 1791
                QPtrList<PageItem> el = parseTextElement(x, y, e);
1792
                for (uint ec = 0; ec < el.count(); ++ec)
215 Franz 1793
                {
6574 jghali 1794
                        GElements.append(el.at(ec));
1795
                        Elements.append(el.at(ec));
68 Franz 1796
                }
215 Franz 1797
        }
6574 jghali 1798
        return GElements;
1799
}
1800
 
1801
QPtrList<PageItem> SVGPlug::parseTextElement(double x, double y, const QDomElement &e)
1802
{
1803
        ScText *hg;
1804
        QPtrList<PageItem> GElements;
1805
        QFont ff(m_gc.current()->Family);
1806
        ff.setPointSize(QMAX(qRound(m_gc.current()->FontSize / 10.0), 1));
6675 jghali 1807
        QFontMetrics fontMetrics(ff);
1808
        int desc = fontMetrics.descent();
6574 jghali 1809
        double BaseX = currDoc->currentPage->xOffset();
1810
        double BaseY = currDoc->currentPage->yOffset();
1811
        QString Text = QString::fromUtf8(e.text()).stripWhiteSpace();
1812
        QDomNode c = e.firstChild();
1813
        if ( e.tagName() == "tspan" && e.text().isNull() )
1814
                        Text = " ";
1815
 
6697 jghali 1816
        double maxHeight = 0;
1817
        double tempW = 0, tempH = 0;
6574 jghali 1818
        SvgStyle *gc = m_gc.current();
1819
        int ity = (e.tagName() == "tspan") ? y : (y - qRound(gc->FontSize / 10.0));
1820
        int z = currDoc->itemAdd(PageItem::TextFrame, PageItem::Unspecified, x, ity, 10, 10, gc->LWidth, CommonStrings::None, gc->FillCol, true);
1821
        PageItem* ite = currDoc->Items->at(z);
1822
        ite->setTextToFrameDist(0.0, 0.0, 0.0, 0.0);
1823
        ite->setLineSpacing(gc->FontSize / 10.0 + 2);
1824
        ite->setHeight(ite->lineSpacing()+desc+2);
1825
        ScMW->SetNewFont(gc->Family);
1826
        QWMatrix mm = gc->matrix;
1827
        if( (!e.attribute("x").isEmpty()) && (!e.attribute("y").isEmpty()) )
1828
        {
1829
                double x1 = parseUnit( e.attribute( "x", "0" ) );
1830
                double y1 = parseUnit( e.attribute( "y", "0" ) );
1831
                double mx = mm.m11() * x1 + mm.m21() * y1 + mm.dx();
1832
                double my = mm.m22() * y1 + mm.m12() * x1 + mm.dy();
1833
                ite->setXPos(mx + BaseX);
1834
                ite->setYPos(my + BaseY);
1835
        }
1836
        else
1837
        {
1838
                double mx = mm.m11() * x + mm.m21() * y + mm.dx();
1839
                double my = mm.m22() * y + mm.m12() * x + mm.dy();
1840
                ite->setXPos(mx);
1841
                ite->setYPos(my);
1842
        }
1843
        ite->setFont(gc->Family);
6603 jghali 1844
        ite->setFillColor(CommonStrings::None);
6695 jghali 1845
        ite->setLineColor(CommonStrings::None);
6574 jghali 1846
        ite->TxtFill = gc->FillCol;
1847
        ite->ShTxtFill = 100;
1848
        ite->TxtStroke = gc->StrokeCol;
1849
        ite->ShTxtStroke = 100;
1850
        ite->setFontSize(gc->FontSize);
1851
        ite->TxTStyle = 0;
1852
        ite->TxtScale = 1000;
1853
        ite->TxtScaleV = 1000;
1854
        ite->TxtBase = 0;
1855
        ite->TxtShadowX = 50;
1856
        ite->TxtShadowY = -50;
1857
        ite->TxtOutline = 10;
1858
        ite->TxtUnderPos = -1;
1859
        ite->TxtUnderWidth = -1;
1860
        ite->TxtStrikePos = -1;
1861
        ite->TxtStrikeWidth = -1;
1862
        for (uint tt = 0; tt < Text.length(); ++tt)
1863
        {
1864
                hg = new ScText;
1865
                hg->ch = Text.at(tt);
1866
                hg->cfont = (*currDoc->AllFonts)[gc->Family];
1867
                hg->csize = gc->FontSize;
1868
                hg->ccolor = gc->FillCol;
1869
                hg->cextra = 0;
1870
                hg->cshade = 100;
1871
                hg->cstroke = gc->StrokeCol;
1872
                hg->cshade2 = 100;
1873
                hg->cscale = 1000;
1874
                hg->cscalev = 1000;
1875
                hg-