Subversion Repositories Scribus

Rev

Rev 14401 | 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
*/
2688 craig 7
 
10223 cbradney 8
#include <QCursor>
13085 jghali 9
#include <QDebug>
9764 jghali 10
#include <QDrag>
10292 cbradney 11
#include <QFile>
12
#include <QList>
9764 jghali 13
#include <QMimeData>
10638 jghali 14
#include <QPainterPath>
10292 cbradney 15
#include <QRegExp>
12795 fschmid 16
#include <QTemporaryFile>
68 Franz 17
#include <cmath>
10292 cbradney 18
#include "color.h"
3934 cbradney 19
#include "commonstrings.h"
10292 cbradney 20
#include "customfdialog.h"
21
#include "fonts/scfontmetrics.h"
3934 cbradney 22
#include "fpointarray.h"
10292 cbradney 23
#include "loadsaveplugin.h"
3934 cbradney 24
#include "menumanager.h"
10292 cbradney 25
#include "pageitem.h"
26
#include "prefsfile.h"
2834 cbradney 27
#include "prefsmanager.h"
10862 cbradney 28
#include "propertiespalette.h"
10292 cbradney 29
#include "sccolorengine.h"
13460 jghali 30
#include "scclocale.h"
10292 cbradney 31
#include "scconfig.h"
11962 jghali 32
#include "scgzfile.h"
12841 jghali 33
#include "scmimedata.h"
12785 fschmid 34
#include "scpaths.h"
12737 fschmid 35
#include "scpattern.h"
3934 cbradney 36
#include "scraction.h"
10292 cbradney 37
#include "scribus.h"
38
#include "scribusXml.h"
5781 cbradney 39
#include "scribuscore.h"
3207 craig 40
#include "scribusdoc.h"
3934 cbradney 41
#include "selection.h"
10292 cbradney 42
#include "svgplugin.h"
3934 cbradney 43
#include "undomanager.h"
44
#include "util.h"
10292 cbradney 45
#include "util_formats.h"
10200 cbradney 46
#include "util_icon.h"
10203 cbradney 47
#include "util_math.h"
68 Franz 48
 
10862 cbradney 49
 
504 cbradney 50
using namespace std;
51
 
3207 craig 52
int svgimplugin_getPluginAPIVersion()
68 Franz 53
{
3207 craig 54
        return PLUGIN_API_VERSION;
68 Franz 55
}
56
 
3207 craig 57
ScPlugin* svgimplugin_getPlugin()
68 Franz 58
{
3207 craig 59
        SVGImportPlugin* plug = new SVGImportPlugin();
60
        Q_CHECK_PTR(plug);
61
        return plug;
68 Franz 62
}
63
 
3207 craig 64
void svgimplugin_freePlugin(ScPlugin* plugin)
512 fschmid 65
{
3207 craig 66
        SVGImportPlugin* plug = dynamic_cast<SVGImportPlugin*>(plugin);
67
        Q_ASSERT(plug);
68
        delete plug;
512 fschmid 69
}
70
 
3696 craig 71
SVGImportPlugin::SVGImportPlugin() : LoadSavePlugin(),
9857 cbradney 72
        importAction(new ScrAction(ScrAction::DLL, QPixmap(), QPixmap(), "", QKeySequence(), this))
1208 cbradney 73
{
3207 craig 74
        // Set action info in languageChange, so we only have to do
3686 craig 75
        // it in one place. This includes registering file format
76
        // support.
3207 craig 77
        languageChange();
5243 cbradney 78
}
12110 fschmid 79
/*
5243 cbradney 80
void SVGImportPlugin::addToMainWindowMenu(ScribusMainWindow *mw)
81
{
3696 craig 82
        importAction->setEnabled(true);
10725 jghali 83
        connect( importAction, SIGNAL(triggered()), SLOT(import()) );
5243 cbradney 84
        mw->scrMenuMgr->addMenuItem(importAction, "FileImport");
1208 cbradney 85
}
12110 fschmid 86
*/
3686 craig 87
SVGImportPlugin::~SVGImportPlugin()
88
{
89
        unregisterAll();
90
};
3207 craig 91
 
92
void SVGImportPlugin::languageChange()
1208 cbradney 93
{
10427 cbradney 94
        importAction->setText( tr("Import &SVG..."));
3686 craig 95
        // (Re)register file format support.
96
        unregisterAll();
97
        registerFormats();
1208 cbradney 98
}
99
 
3207 craig 100
const QString SVGImportPlugin::fullTrName() const
1208 cbradney 101
{
3207 craig 102
        return QObject::tr("SVG Import");
1208 cbradney 103
}
104
 
3207 craig 105
const ScActionPlugin::AboutData* SVGImportPlugin::getAboutData() const
1208 cbradney 106
{
3241 craig 107
        AboutData* about = new AboutData;
3344 fschmid 108
        about->authors = "Franz Schmid <franz@scribus.info>";
3355 cbradney 109
        about->shortDescription = tr("Imports SVG Files");
3357 cbradney 110
        about->description = tr("Imports most SVG files into the current document,\nconverting their vector data into Scribus objects.");
3344 fschmid 111
        about->license = "GPL";
3241 craig 112
        Q_CHECK_PTR(about);
113
        return about;
1208 cbradney 114
}
115
 
3241 craig 116
void SVGImportPlugin::deleteAboutData(const AboutData* about) const
1208 cbradney 117
{
3241 craig 118
        Q_ASSERT(about);
119
        delete about;
1208 cbradney 120
}
121
 
3686 craig 122
void SVGImportPlugin::registerFormats()
3487 craig 123
{
4024 craig 124
        FileFormat fmt(this);
10292 cbradney 125
        fmt.trName = FormatsManager::instance()->nameOfFormat(FormatsManager::SVG);
4024 craig 126
        fmt.formatId = FORMATID_SVGIMPORT;
10292 cbradney 127
        fmt.filter = FormatsManager::instance()->extensionsForFormat(FormatsManager::SVG);
10600 fschmid 128
        fmt.nameMatch = QRegExp("\\."+FormatsManager::instance()->extensionListForFormat(FormatsManager::SVG, 1)+"$", Qt::CaseInsensitive);
3686 craig 129
        fmt.load = true;
130
        fmt.save = false;
10292 cbradney 131
        fmt.mimeTypes = FormatsManager::instance()->mimetypeOfFormat(FormatsManager::SVG);
3643 craig 132
        fmt.priority = 64;
3686 craig 133
        registerFormat(fmt);
3487 craig 134
}
135
 
5642 cbradney 136
bool SVGImportPlugin::fileSupported(QIODevice* /* file */, const QString & fileName) const
3487 craig 137
{
138
        // TODO: identify valid SVG
139
        return true;
140
}
141
 
5539 mrdocs 142
bool SVGImportPlugin::loadFile(const QString & fileName, const FileFormat & /* fmt */, int flags, int /*index*/)
4024 craig 143
{
144
        // For now, "load file" and import are the same thing for this plugin
5539 mrdocs 145
        return import(fileName, flags);
4024 craig 146
}
147
 
5539 mrdocs 148
bool SVGImportPlugin::import(QString filename, int flags)
68 Franz 149
{
5539 mrdocs 150
        if (!checkFlags(flags))
151
                return false;
5781 cbradney 152
        m_Doc=ScCore->primaryMainWindow()->doc;
153
        ScribusMainWindow* mw=(m_Doc==0) ? ScCore->primaryMainWindow() : m_Doc->scMW();
3207 craig 154
        if (filename.isEmpty())
506 fschmid 155
        {
5539 mrdocs 156
                flags |= lfInteractive;
2856 cbradney 157
                PrefsContext* prefs = PrefsManager::instance()->prefsFile->getPluginContext("SVGPlugin");
506 fschmid 158
                QString wdir = prefs->get("wdir", ".");
10292 cbradney 159
                CustomFDialog diaf(mw, wdir, QObject::tr("Open"), FormatsManager::instance()->fileDialogFormatList(FormatsManager::SVG));
506 fschmid 160
                if (diaf.exec())
161
                {
3207 craig 162
                        filename = diaf.selectedFile();
10427 cbradney 163
                        prefs->set("wdir", filename.left(filename.lastIndexOf("/")));
506 fschmid 164
                }
165
                else
3207 craig 166
                        return true;
415 Franz 167
        }
5781 cbradney 168
 
11576 avox 169
        UndoTransaction* activeTransaction = NULL;
170
        bool emptyDoc = (m_Doc == NULL);
13378 jghali 171
        bool hasCurrentPage = (m_Doc && m_Doc->currentPage());
13371 jghali 172
        TransactionSettings trSettings;
13378 jghali 173
        trSettings.targetName   = hasCurrentPage ? m_Doc->currentPage()->getUName() : "";
13371 jghali 174
        trSettings.targetPixmap = Um::IImageFrame;
175
        trSettings.actionName   = Um::ImportSVG;
176
        trSettings.description  = filename;
177
        trSettings.actionPixmap = Um::ISVG;
178
        if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
1439 tsoots 179
                UndoManager::instance()->setUndoEnabled(false);
13371 jghali 180
        if (UndoManager::undoEnabled())
181
                activeTransaction = new UndoTransaction(UndoManager::instance()->beginTransaction(trSettings));
8043 jghali 182
        SVGPlug *dia = new SVGPlug(mw, flags);
3207 craig 183
        Q_CHECK_PTR(dia);
13371 jghali 184
        dia->import(filename, trSettings, flags);
11576 avox 185
        if (activeTransaction)
186
        {
187
                activeTransaction->commit();
188
                delete activeTransaction;
189
                activeTransaction = NULL;
190
        }
13371 jghali 191
        if (emptyDoc || !(flags & lfInteractive) || !(flags & lfScripted))
1439 tsoots 192
                UndoManager::instance()->setUndoEnabled(true);
7795 fschmid 193
        if (dia->importCanceled)
3800 subik 194
        {
7795 fschmid 195
                if (dia->importFailed)
196
                        QMessageBox::warning(mw, CommonStrings::trWarning, tr("The file could not be imported"), 1, 0, 0);
197
                else if (dia->unsupported)
198
                        QMessageBox::warning(mw, CommonStrings::trWarning, tr("SVG file contains some unsupported features"), 1, 0, 0);
3800 subik 199
        }
200
 
217 Franz 201
        delete dia;
3207 craig 202
        return true;
68 Franz 203
}
204
 
8043 jghali 205
SVGPlug::SVGPlug( ScribusMainWindow* mw, int flags ) :
5781 cbradney 206
        QObject(mw)
7564 cbradney 207
{      
7578 cbradney 208
        tmpSel=new Selection(this, false);
5781 cbradney 209
        m_Doc=mw->doc;
3800 subik 210
        unsupported = false;
7794 fschmid 211
        importFailed = false;
7795 fschmid 212
        importCanceled = true;
7991 fschmid 213
        importedColors.clear();
12737 fschmid 214
        importedPatterns.clear();
7866 fschmid 215
        docDesc = "";
216
        docTitle = "";
217
        groupLevel = 0;
5539 mrdocs 218
        interactive = (flags & LoadSavePlugin::lfInteractive);
9922 fschmid 219
//      m_gc.setAutoDelete( true );
8043 jghali 220
}
221
 
13371 jghali 222
bool SVGPlug::import(QString fname, const TransactionSettings& trSettings, int flags)
8043 jghali 223
{
224
        if (!loadData(fname))
13403 jghali 225
        {
226
                importFailed = true;
8043 jghali 227
                return false;
13403 jghali 228
        }
10398 cbradney 229
        QString CurDirP = QDir::currentPath();
8043 jghali 230
        QFileInfo efp(fname);
10600 fschmid 231
        QDir::setCurrent(efp.path());
13371 jghali 232
        convert(trSettings, flags);
8043 jghali 233
        QDir::setCurrent(CurDirP);
234
        return true;
235
}
236
 
237
bool SVGPlug::loadData(QString fName)
238
{
239
        QString f("");
11962 jghali 240
        bool isCompressed = false, success = false;
10600 fschmid 241
        QByteArray bb(3, ' ');
8424 fschmid 242
        QFile fi(fName);
8501 cbradney 243
        if (fi.open(QIODevice::ReadOnly))
217 Franz 244
        {
10600 fschmid 245
                fi.read(bb.data(), 2);
8424 fschmid 246
                fi.close();
8625 subik 247
                // Qt4 bb[0]->QChar(bb[0])
248
                if ((QChar(bb[0]) == QChar(0x1F)) && (QChar(bb[1]) == QChar(0x8B)))
8424 fschmid 249
                        isCompressed = true;
250
        }
251
        if ((fName.right(2) == "gz") || (isCompressed))
252
        {
11962 jghali 253
                ScGzFile file(fName);
254
                if (!file.open(QIODevice::ReadOnly))
8043 jghali 255
                        return false;
11962 jghali 256
                success = inpdoc.setContent(&file);
257
                file.close();
217 Franz 258
        }
68 Franz 259
        else
11962 jghali 260
        {
261
                QFile file(fName);
262
                if (!file.open(QIODevice::ReadOnly))
263
                        return false;
264
                success = inpdoc.setContent(&file);
265
                file.close();
266
        }
267
        return success;
68 Franz 268
}
269
 
13371 jghali 270
void SVGPlug::convert(const TransactionSettings& trSettings, int flags)
68 Franz 271
{
272
        bool ret = false;
273
        SvgStyle *gc = new SvgStyle;
274
        QDomElement docElem = inpdoc.documentElement();
8252 jghali 275
        QSize wh = parseWidthHeight(docElem);
7573 jghali 276
        double width = wh.width();
277
        double height = wh.height();
5539 mrdocs 278
        if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
217 Franz 279
        {
5781 cbradney 280
                m_Doc->setPage(width, height, 0, 0, 0, 0, 0, 0, false, false);
281
                m_Doc->addPage(0);
282
                m_Doc->view()->addPage(0);
217 Franz 283
        }
506 fschmid 284
        else
285
        {
5781 cbradney 286
                if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
506 fschmid 287
                {
5798 jghali 288
                        m_Doc=ScCore->primaryMainWindow()->doFileNew(width, height, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
5781 cbradney 289
                        ScCore->primaryMainWindow()->HaveNewDoc();
506 fschmid 290
                        ret = true;
291
                }
292
        }
3207 craig 293
        if ((ret) || (!interactive))
550 fschmid 294
        {
295
                if (width > height)
5781 cbradney 296
                        m_Doc->PageOri = 1;
550 fschmid 297
                else
5781 cbradney 298
                        m_Doc->PageOri = 0;
5789 cbradney 299
                m_Doc->m_pageSize = "Custom";
550 fschmid 300
        }
5781 cbradney 301
        FPoint minSize = m_Doc->minCanvasCoordinate;
302
        FPoint maxSize = m_Doc->maxCanvasCoordinate;
10907 fschmid 303
        FPoint cOrigin = m_Doc->view()->canvasOrigin();
5781 cbradney 304
        m_Doc->view()->Deselect();
305
        m_Doc->setLoading(true);
306
        m_Doc->DoDrawing = false;
7452 fschmid 307
        m_Doc->view()->updatesOn(false);
14751 fschmid 308
        bool wasScriptRunning = m_Doc->scMW()->ScriptRunning;
5781 cbradney 309
        m_Doc->scMW()->ScriptRunning = true;
9380 fschmid 310
        qApp->changeOverrideCursor(QCursor(Qt::WaitCursor));
10638 jghali 311
        gc->FontFamily = m_Doc->toolSettings.defFont;
5781 cbradney 312
        if (!m_Doc->PageColors.contains("Black"))
313
                m_Doc->PageColors.insert("Black", ScColor(0, 0, 0, 255));
68 Franz 314
        m_gc.push( gc );
1013 fschmid 315
        viewTransformX = 0;
316
        viewTransformY = 0;
317
        viewScaleX = 1;
318
        viewScaleY = 1;
319
        if( !docElem.attribute( "viewBox" ).isEmpty() )
320
        {
321
                QString viewbox( docElem.attribute( "viewBox" ) );
10603 fschmid 322
                QStringList points = viewbox.replace( QRegExp(","), " ").simplified().split( ' ', QString::SkipEmptyParts );
11080 fschmid 323
                if (points.size() > 3)
324
                {
325
                        QMatrix matrix;
326
                        QSize wh2 = parseWidthHeight(docElem);
327
                        double w2 = wh2.width();
328
                        double h2 = wh2.height();
329
                        addGraphicContext();
13460 jghali 330
                        viewTransformX = ScCLocale::toDoubleC(points[0]);
331
                        viewTransformY = ScCLocale::toDoubleC(points[1]);
332
                        viewScaleX = w2 / ScCLocale::toDoubleC(points[2]);
333
                        viewScaleY = h2 / ScCLocale::toDoubleC(points[3]);
12101 jghali 334
                        matrix.translate(-viewTransformX * viewScaleX, -viewTransformY * viewScaleY);
11080 fschmid 335
                        matrix.scale(viewScaleX, viewScaleY);
336
                        m_gc.top()->matrix = matrix;
337
                }
1013 fschmid 338
        }
9856 fschmid 339
        QList<PageItem*> Elements = parseGroup( docElem );
7866 fschmid 340
        if (flags & LoadSavePlugin::lfCreateDoc)
341
        {
342
                m_Doc->documentInfo.setTitle(docTitle);
343
                m_Doc->documentInfo.setComments(docDesc);
344
        }
7578 cbradney 345
        tmpSel->clear();
7794 fschmid 346
        if (Elements.count() == 0)
7991 fschmid 347
        {
7794 fschmid 348
                importFailed = true;
7991 fschmid 349
                if (importedColors.count() != 0)
350
                {
8625 subik 351
                        for (int cd = 0; cd < importedColors.count(); cd++)
7991 fschmid 352
                        {
353
                                m_Doc->PageColors.remove(importedColors[cd]);
354
                        }
355
                }
12737 fschmid 356
                if (importedPatterns.count() != 0)
357
                {
358
                        for (int cd = 0; cd < importedPatterns.count(); cd++)
359
                        {
360
                                m_Doc->docPatterns.remove(importedPatterns[cd]);
361
                        }
362
                }
7991 fschmid 363
        }
302 Franz 364
        if (Elements.count() > 1)
217 Franz 365
        {
7445 fschmid 366
                bool isGroup = true;
367
                int firstElem = -1;
368
                if (Elements.at(0)->Groups.count() != 0)
369
                        firstElem = Elements.at(0)->Groups.top();
9856 fschmid 370
                for (int bx = 0; bx < Elements.count(); ++bx)
217 Franz 371
                {
7445 fschmid 372
                        PageItem* bxi = Elements.at(bx);
373
                        if (bxi->Groups.count() != 0)
6605 fschmid 374
                        {
7445 fschmid 375
                                if (bxi->Groups.top() != firstElem)
376
                                        isGroup = false;
377
                        }
378
                        else
379
                                isGroup = false;
380
                }
381
                if (!isGroup)
382
                {
383
                        double minx = 99999.9;
384
                        double miny = 99999.9;
385
                        double maxx = -99999.9;
386
                        double maxy = -99999.9;
387
                        uint lowestItem = 999999;
388
                        uint highestItem = 0;
9856 fschmid 389
                        for (int a = 0; a < Elements.count(); ++a)
7445 fschmid 390
                        {
391
                                Elements.at(a)->Groups.push(m_Doc->GroupCounter);
392
                                PageItem* currItem = Elements.at(a);
8562 jghali 393
                                lowestItem = qMin(lowestItem, currItem->ItemNr);
394
                                highestItem = qMax(highestItem, currItem->ItemNr);
11889 fschmid 395
                                double x1, x2, y1, y2;
12751 fschmid 396
                                currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
11889 fschmid 397
                                minx = qMin(minx, x1);
398
                                miny = qMin(miny, y1);
399
                                maxx = qMax(maxx, x2);
400
                                maxy = qMax(maxy, y2);
6605 fschmid 401
                        }
7445 fschmid 402
                        double gx = minx;
403
                        double gy = miny;
404
                        double gw = maxx - minx;
405
                        double gh = maxy - miny;
406
                        PageItem *high = m_Doc->Items->at(highestItem);
407
                        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, gx, gy, gw, gh, 0, m_Doc->toolSettings.dBrush, m_Doc->toolSettings.dPen, true);
9856 fschmid 408
                        PageItem *neu = m_Doc->Items->takeAt(z);
7445 fschmid 409
                        m_Doc->Items->insert(lowestItem, neu);
410
                        neu->Groups.push(m_Doc->GroupCounter);
411
                        neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
11889 fschmid 412
                        neu->AutoName = false;
7445 fschmid 413
                        neu->isGroupControl = true;
414
                        neu->groupsLastItem = high;
9856 fschmid 415
                        for (int a = 0; a < m_Doc->Items->count(); ++a)
6605 fschmid 416
                        {
7445 fschmid 417
                                m_Doc->Items->at(a)->ItemNr = a;
6605 fschmid 418
                        }
7620 fschmid 419
                        neu->setRedrawBounding();
11705 fschmid 420
                        neu->setTextFlowMode(PageItem::TextFlowDisabled);
7445 fschmid 421
                        Elements.prepend(neu);
422
                        m_Doc->GroupCounter++;
217 Franz 423
                }
424
        }
5781 cbradney 425
        m_Doc->DoDrawing = true;
14751 fschmid 426
        m_Doc->scMW()->ScriptRunning = wasScriptRunning;
3207 craig 427
        if (interactive)
5781 cbradney 428
                m_Doc->setLoading(false);
9380 fschmid 429
        qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
3207 craig 430
        if ((Elements.count() > 0) && (!ret) && (interactive))
217 Franz 431
        {
8262 fschmid 432
                if (flags & LoadSavePlugin::lfScripted)
217 Franz 433
                {
8262 fschmid 434
                        bool loadF = m_Doc->isLoading();
435
                        m_Doc->setLoading(false);
436
                        m_Doc->changed();
437
                        m_Doc->setLoading(loadF);
11835 fschmid 438
                        m_Doc->m_Selection->delaySignalsOn();
9856 fschmid 439
                        for (int dre=0; dre<Elements.count(); ++dre)
8262 fschmid 440
                        {
441
                                m_Doc->m_Selection->addItem(Elements.at(dre), true);
442
                        }
11835 fschmid 443
                        m_Doc->m_Selection->delaySignalsOff();
8262 fschmid 444
                        m_Doc->m_Selection->setGroupRect();
445
                        m_Doc->view()->updatesOn(true);
446
                        importCanceled = false;
217 Franz 447
                }
8262 fschmid 448
                else
449
                {
450
                        m_Doc->DragP = true;
451
                        m_Doc->DraggedElem = 0;
452
                        m_Doc->DragElements.clear();
11835 fschmid 453
                        m_Doc->m_Selection->delaySignalsOn();
9856 fschmid 454
                        for (int dre=0; dre<Elements.count(); ++dre)
8262 fschmid 455
                        {
456
                                m_Doc->DragElements.append(Elements.at(dre)->ItemNr);
457
                                tmpSel->addItem(Elements.at(dre), true);
458
                        }
459
                        ScriXmlDoc *ss = new ScriXmlDoc();
460
                        tmpSel->setGroupRect();
12841 jghali 461
                        ScElemMimeData* md = new ScElemMimeData();
462
                        md->setScribusElem(ss->WriteElem(m_Doc, m_Doc->view(), tmpSel));
12971 jghali 463
                        delete ss;
464
/*#ifndef Q_WS_MAC*/
4302 avox 465
// see #2526
8262 fschmid 466
                        m_Doc->itemSelection_DeleteItem(tmpSel);
12971 jghali 467
/*#endif*/
8262 fschmid 468
                        m_Doc->view()->updatesOn(true);
12737 fschmid 469
                        if (importedColors.count() != 0)
470
                        {
471
                                for (int cd = 0; cd < importedColors.count(); cd++)
472
                                {
473
                                        m_Doc->PageColors.remove(importedColors[cd]);
474
                                }
475
                        }
476
                        if (importedPatterns.count() != 0)
477
                        {
478
                                for (int cd = 0; cd < importedPatterns.count(); cd++)
479
                                {
480
                                        m_Doc->docPatterns.remove(importedPatterns[cd]);
481
                                }
482
                        }
11835 fschmid 483
                        m_Doc->m_Selection->delaySignalsOff();
13371 jghali 484
                        // We must copy the TransationSettings object as it is owned
485
                        // by handleObjectImport method afterwards
486
                        TransactionSettings* transacSettings = new TransactionSettings(trSettings);
487
                        m_Doc->view()->handleObjectImport(md, transacSettings);
8262 fschmid 488
                        m_Doc->DragP = false;
489
                        m_Doc->DraggedElem = 0;
490
                        m_Doc->DragElements.clear();
7991 fschmid 491
                }
217 Franz 492
        }
68 Franz 493
        else
357 Franz 494
        {
7351 fschmid 495
                bool loadF = m_Doc->isLoading();
496
                m_Doc->setLoading(false);
5781 cbradney 497
                m_Doc->changed();
6556 fschmid 498
                m_Doc->reformPages();
7452 fschmid 499
                m_Doc->view()->updatesOn(true);
7351 fschmid 500
                m_Doc->setLoading(loadF);
357 Franz 501
        }
68 Franz 502
}
503
 
504
void SVGPlug::addGraphicContext()
505
{
506
        SvgStyle *gc = new SvgStyle;
9922 fschmid 507
        if ( m_gc.top() )
508
                *gc = *( m_gc.top() );
68 Franz 509
        m_gc.push( gc );
510
}
511
 
7612 jghali 512
void SVGPlug::setupNode( const QDomElement &e )
513
{
514
        addGraphicContext();
515
        setupTransform( e );
9922 fschmid 516
        parseStyle(m_gc.top(), e);
7612 jghali 517
}
518
 
68 Franz 519
void SVGPlug::setupTransform( const QDomElement &e )
520
{
9922 fschmid 521
        SvgStyle *gc = m_gc.top();
8501 cbradney 522
        QMatrix mat = parseTransform( e.attribute( "transform" ) );
68 Franz 523
        if (!e.attribute("transform").isEmpty())
524
                gc->matrix = mat * gc->matrix;
525
}
526
 
10785 jghali 527
void SVGPlug::finishNode( const QDomNode &e, PageItem* item)
7612 jghali 528
{
9922 fschmid 529
        SvgStyle *gc = m_gc.top();
8501 cbradney 530
        QMatrix gcm = gc->matrix;
7612 jghali 531
        double BaseX = m_Doc->currentPage()->xOffset();
532
        double BaseY = m_Doc->currentPage()->yOffset();
533
        double coeff1 = sqrt(gcm.m11() * gcm.m11() + gcm.m12() * gcm.m12());
534
        double coeff2 = sqrt(gcm.m21() * gcm.m21() + gcm.m22() * gcm.m22());
535
        switch (item->itemType())
536
        {
537
        case PageItem::ImageFrame:
538
                {
12785 fschmid 539
                        item->ClipEdited = true;
540
                        item->FrameType = 3;
8501 cbradney 541
                        QMatrix mm = gc->matrix;
12785 fschmid 542
                        item->PoLine.map(mm);
7612 jghali 543
                        item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
12785 fschmid 544
                        FPoint wh = getMaxClipF(&item->PoLine);
545
                        item->setWidthHeight(wh.x(), wh.y());
546
                        m_Doc->AdjustItemSize(item);
547
//                      item->moveBy(mm.dx(), mm.dy());
548
//                      item->setWidthHeight(item->width() * mm.m11(), item->height() * mm.m22());
549
//                      item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
13097 subik 550
                        if (item->PictureIsAvailable)
12785 fschmid 551
                        {
552
                                item->setImageXYOffset(0.0, 0.0);
553
                                item->setImageXYScale(item->width() / (item->pixm.width() * (item->pixm.imgInfo.xres / 72.0)),
554
                                                                          item->height() / (item->pixm.height() * (item->pixm.imgInfo.yres / 72.0)));
555
                                item->setImageScalingMode(false, false); // fit to frame
556
                        }
7612 jghali 557
                        break;
558
                }
559
        case PageItem::TextFrame:
560
                {
8501 cbradney 561
                        QMatrix mm = gc->matrix;
7612 jghali 562
                        item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
563
                }
564
                break;
565
        default:
566
                {
567
                        item->ClipEdited = true;
568
                        item->FrameType = 3;
8501 cbradney 569
                        QMatrix mm = gc->matrix;
7612 jghali 570
                        item->PoLine.map(mm);
571
                        /*if (haveViewBox)
572
                        {
10030 cbradney 573
                                QMatrix mv;
7612 jghali 574
                                mv.translate(viewTransformX, viewTransformY);
575
                                mv.scale(viewScaleX, viewScaleY);
576
                                ite->PoLine.map(mv);
577
                        }*/
578
                        item->setLineWidth(item->lineWidth() * (coeff1 + coeff2) / 2.0);
579
                        FPoint wh = getMaxClipF(&item->PoLine);
580
                        item->setWidthHeight(wh.x(), wh.y());
7672 fschmid 581
//                      if (item->asPolyLine())
8562 jghali 582
//                              item->setPolyClip(qRound(qMax(item->lineWidth() / 2.0, 1)));
7672 fschmid 583
//                      else
584
//                              item->Clip = FlattenPath(item->PoLine, item->Segments);
12745 fschmid 585
                        FPoint wx = getMinClipF(&item->PoLine);
586
                        inGroupXOrigin = qMin(inGroupXOrigin, wx.x());
587
                        inGroupYOrigin = qMin(inGroupYOrigin, wx.y());
7736 cbradney 588
                        m_Doc->AdjustItemSize(item);
7612 jghali 589
                        break;
590
                }
591
        }
7620 fschmid 592
        item->setRedrawBounding();
7612 jghali 593
        item->OwnPage = m_Doc->OnPage(item);
10785 jghali 594
        if (e.isElement())
595
        {
596
                QString nodeId = e.toElement().attribute("id");
597
                if( !nodeId.isEmpty() )
11889 fschmid 598
                {
10785 jghali 599
                        item->setItemName(" "+nodeId);
11889 fschmid 600
                        item->AutoName = false;
601
                }
10785 jghali 602
        }
7612 jghali 603
        item->setFillTransparency( 1 - gc->FillOpacity * gc->Opacity );
604
        item->setLineTransparency( 1 - gc->StrokeOpacity * gc->Opacity );
605
        item->PLineEnd = gc->PLineEnd;
606
        item->PLineJoin = gc->PLineJoin;
7865 fschmid 607
        if (item->fillColor() == CommonStrings::None)
608
                item->setTextFlowMode(PageItem::TextFlowDisabled);
609
        else
610
                item->setTextFlowMode(PageItem::TextFlowUsesFrameShape);
7678 fschmid 611
        item->DashOffset = gc->dashOffset;
612
        item->DashValues = gc->dashArray;
7612 jghali 613
        if (gc->Gradient != 0)
614
        {
12737 fschmid 615
                if (gc->Gradient == 8)
7612 jghali 616
                {
12737 fschmid 617
                        item->GrType = gc->Gradient;
12745 fschmid 618
                        item->setPattern(importedPattTrans[gc->GCol1]);
619
                        QMatrix mm = gc->matrixg;
12751 fschmid 620
                        double rot = getRotationFromMatrix(mm, 0.0) * 180 / M_PI;
621
                        mm.rotate(rot);
622
                        double patDx = (item->xPos() - BaseX) - mm.dx();
623
                        double patDy = (item->yPos() - BaseY) - mm.dy();
624
                        item->setPatternTransform(mm.m11() * 100.0, mm.m22() * 100.0, patDx, patDy, -rot);
12737 fschmid 625
                }
626
                else
627
                {
628
                        if (gc->GradCo.Stops() > 1)
7612 jghali 629
                        {
12737 fschmid 630
                                item->fill_gradient = gc->GradCo;
631
                                if (!gc->CSpace)
7612 jghali 632
                                {
12737 fschmid 633
                                        item->GrStartX = gc->GX1 * item->width();
634
                                        item->GrStartY = gc->GY1 * item->height();
635
                                        item->GrEndX = gc->GX2 * item->width();
636
                                        item->GrEndY = gc->GY2 * item->height();
637
                                        double angle1 = atan2(gc->GY2-gc->GY1,gc->GX2-gc->GX1)*(180.0/M_PI);
638
                                        double angle2 = atan2(item->GrEndY - item->GrStartX, item->GrEndX - item->GrStartX)*(180.0/M_PI);
639
                                        double dx = item->GrStartX + (item->GrEndX - item->GrStartX) / 2.0;
640
                                        double dy = item->GrStartY + (item->GrEndY - item->GrStartY) / 2.0;
641
                                        QMatrix mm, mm2;
642
                                        if ((gc->GY1 < gc->GY2) && (gc->GX1 < gc->GX2))
643
                                        {
644
                                                mm.rotate(-angle2);
645
                                                mm2.rotate(angle1);
646
                                        }
647
                                        FPointArray gra;
648
                                        gra.setPoints(2, item->GrStartX-dx, item->GrStartY-dy, item->GrEndX-dx, item->GrEndY-dy);
649
                                        gra.map(mm*mm2);
650
                                        gra.translate(dx, dy);
651
                                        item->GrStartX = gra.point(0).x();
652
                                        item->GrStartY = gra.point(0).y();
653
                                        item->GrEndX = gra.point(1).x();
654
                                        item->GrEndY = gra.point(1).y();
7612 jghali 655
                                }
12737 fschmid 656
                                else
657
                                {
658
                                        QMatrix mm = gc->matrix;
659
                                        mm = gc->matrixg * mm;
660
                                        FPointArray gra;
661
                                        gra.setPoints(2, gc->GX1, gc->GY1, gc->GX2, gc->GY2);
662
                                        gra.map(mm);
663
                                        gc->GX1 = gra.point(0).x();
664
                                        gc->GY1 = gra.point(0).y();
665
                                        gc->GX2 = gra.point(1).x();
666
                                        gc->GY2 = gra.point(1).y();
667
                                        item->GrStartX = gc->GX1 - item->xPos() + BaseX;
668
                                        item->GrStartY = gc->GY1 - item->yPos() + BaseY;
669
                                        item->GrEndX = gc->GX2 - item->xPos() + BaseX;
670
                                        item->GrEndY = gc->GY2 - item->yPos() + BaseY;
671
                                }
672
                                item->GrType = gc->Gradient;
7612 jghali 673
                        }
674
                        else
675
                        {
12737 fschmid 676
                                item->GrType = 0;
677
                                QList<VColorStop*> cstops = gc->GradCo.colorStops();
678
                                item->setFillColor(cstops.at(0)->name);
679
                                item->setFillShade(cstops.at(0)->shade);
7612 jghali 680
                        }
681
                }
682
        }
683
}
684
 
7605 jghali 685
bool SVGPlug::isIgnorableNode( const QDomElement &e )
686
{
687
        QString nodeName(e.tagName());
10021 jghali 688
        return isIgnorableNodeName(nodeName);
689
}
690
 
691
bool SVGPlug::isIgnorableNodeName( const QString &n )
692
{
693
        if (n.startsWith("sodipodi") || n.startsWith("inkscape") || n == "metadata")
7605 jghali 694
                return true;
695
        return false;
696
}
697
 
12725 jghali 698
FPoint SVGPlug::parseTextPosition(const QDomElement &e, const FPoint* pos)
8230 jghali 699
{
12725 jghali 700
        // FIXME According to spec, we should in fact return a point list
701
        double  x = pos ? pos->x() : 0.0;
702
        double  y = pos ? pos->y() : 0.0;
703
 
704
        if (e.hasAttribute( "x" ))
8230 jghali 705
        {
12725 jghali 706
                QString xatt =  e.attribute( "x" , "0" );
707
                if ( xatt.contains(',') || xatt.contains(' ') )
708
                {
709
                        xatt.replace(QChar(','), QChar(' '));
710
                        QStringList xl(xatt.split(QChar(' '), QString::SkipEmptyParts));
711
                        xatt = xl.first();
712
                }
713
                x = parseUnit( xatt );
8230 jghali 714
        }
12725 jghali 715
 
716
        if (e.hasAttribute( "y" ))
8230 jghali 717
        {
12725 jghali 718
                QString yatt =  e.attribute( "y" , "0" );
719
                if ( yatt.contains(',') || yatt.contains(' ') )
720
                {
721
                        yatt.replace(QChar(','), QChar(' '));
722
                        QStringList yl(yatt.split(QChar(' '), QString::SkipEmptyParts));
723
                        yatt = yl.first();
724
                }
725
                y = parseUnit( yatt );
8230 jghali 726
        }
12725 jghali 727
 
728
        if (e.hasAttribute( "dx" ))
729
        {
730
                QString dxatt =  e.attribute( "dx" , "0" );
731
                if ( dxatt.contains(',') || dxatt.contains(' ') )
732
                {
733
                        dxatt.replace(QChar(','), QChar(' '));
734
                        QStringList xl(dxatt.split(QChar(' '), QString::SkipEmptyParts));
735
                        dxatt = xl.first();
736
                }
737
                x += parseUnit( dxatt );
738
        }
739
 
740
        if (e.hasAttribute( "dy" ))
741
        {
742
                QString dyatt =  e.attribute( "dy" , "0" );
743
                if ( dyatt.contains(',') || dyatt.contains(' ') )
744
                {
745
                        dyatt.replace(QChar(','), QChar(' '));
746
                        QStringList xl(dyatt.split(QChar(' '), QString::SkipEmptyParts));
747
                        dyatt = xl.first();
748
                }
749
                y += parseUnit( dyatt );
750
        }
751
 
8230 jghali 752
        return FPoint(x, y);
753
}
754
 
8252 jghali 755
QSize SVGPlug::parseWidthHeight(const QDomElement &e)
7573 jghali 756
{
757
        QSize size(550, 841);
758
        QString sw = e.attribute("width", "100%");
759
        QString sh = e.attribute("height", "100%");
760
        double w =  550, h = 841;
761
        if (!sw.isEmpty())
762
                w = sw.endsWith("%") ? fromPercentage(sw) : parseUnit(sw);
763
        if (!sh.isEmpty())
764
                h = sh.endsWith("%") ? fromPercentage(sh) : parseUnit(sh);
765
        if (!e.attribute("viewBox").isEmpty())
766
        {
767
                QRect viewBox = parseViewBox(e);
768
                double scw = (viewBox.width() > 0 && viewBox.height() > 0) ? viewBox.width()  : size.width();
769
                double sch = (viewBox.width() > 0 && viewBox.height() > 0) ? viewBox.height() : size.height();
770
                w *= (sw.endsWith("%") ? scw : 1.0);
771
                h *= (sh.endsWith("%") ? sch : 1.0);
772
        }
773
        else
774
        {
775
                w *= (sw.endsWith("%") ? size.width() : 1.0);
776
                h *= (sh.endsWith("%") ? size.height() : 1.0);
777
        }
8230 jghali 778
        // OpenOffice files may not have width and height attributes, so avoid unnecessary large dimensions
779
        if (w > 10000 || h > 10000)
780
        {
781
                double m = max(w, h);
782
                w = w / m * 842;
783
                h = h / m * 842;
784
        }
7794 fschmid 785
        size.setWidth(qRound(w));
786
        size.setHeight(qRound(h));
7573 jghali 787
        return size;
788
}
789
 
790
QRect SVGPlug::parseViewBox(const QDomElement &e)
791
{
792
        QRect box(0, 0, 0, 0);
793
        if ( !e.attribute( "viewBox" ).isEmpty() )
794
        {
795
                QString viewbox( e.attribute( "viewBox" ) );
10603 fschmid 796
                QStringList points = viewbox.replace( QRegExp(","), " ").simplified().split( ' ', QString::SkipEmptyParts );
11080 fschmid 797
                if (points.size() > 3)
798
                {
13460 jghali 799
                        double left   = ScCLocale::toDoubleC(points[0]);
800
                        double bottom = ScCLocale::toDoubleC(points[1]);
801
                        double width  = ScCLocale::toDoubleC(points[2]);
802
                        double height = ScCLocale::toDoubleC(points[3]);
11080 fschmid 803
                        box.setCoords((int) left, (int) bottom, (int) (left + width), (int) (bottom + height));
804
                }
7573 jghali 805
        }
806
        return box;
807
}
808
 
7556 jghali 809
void SVGPlug::parseDefs(const QDomElement &e)
810
{
811
        for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
812
        {
813
                QDomElement b = n.toElement();
7612 jghali 814
                if ( b.isNull() )
7556 jghali 815
                        continue;
816
                SvgStyle svgStyle;
817
                parseStyle( &svgStyle, b );
7605 jghali 818
                if ( !svgStyle.Display)
7556 jghali 819
                        continue;
820
                QString STag2 = b.tagName();
8507 jghali 821
                if ( STag2 == "g" )
10854 jghali 822
                {
823
                        QString id = b.attribute("id", "");
824
                        if (!id.isEmpty())
825
                                m_nodeMap.insert(id, b);
8507 jghali 826
                        parseDefs(b);
10854 jghali 827
                }
8507 jghali 828
                else if ( STag2 == "linearGradient" || STag2 == "radialGradient" )
7556 jghali 829
                        parseGradient( b );
7607 fschmid 830
                else if (STag2 == "clipPath")
831
                        parseClipPath(b);
12737 fschmid 832
                else if (STag2 == "pattern")
833
                        parsePattern(b);
7556 jghali 834
                else if ( b.hasAttribute("id") )
835
                {
836
                        QString id = b.attribute("id");
837
                        if (!id.isEmpty())
838
                                m_nodeMap.insert(id, b);
839
                }
840
        }
841
}
842
 
7605 jghali 843
void SVGPlug::parseClipPath(const QDomElement &e)
844
{
845
        QString id(e.attribute("id"));
846
        if (!id.isEmpty())
847
        {
848
                FPointArray clip;
849
                QDomNode n2 = e.firstChild();
850
                QDomElement b2 = n2.toElement();
851
                while (b2.nodeName() == "use")
8604 jghali 852
                        b2 = getReferencedNode(b2);
7607 fschmid 853
                if (b2.nodeName() == "path")
854
                        parseSVG( b2.attribute( "d" ), &clip );
855
                else if (b2.nodeName() == "rect")
856
                {
12101 jghali 857
                        double x = parseUnit( b2.attribute( "x", "0.0" ));
858
                        double y = parseUnit( b2.attribute( "y", "0.0" ));
859
                        double width  = parseUnit( b2.attribute( "width" ));
7607 fschmid 860
                        double height = parseUnit( b2.attribute( "height" ) );
12101 jghali 861
                        clip.addQuadPoint(x, y, x, y, width+x, y, width+x, y);
862
                        clip.addQuadPoint(width+x, y, width+x, y, width+x, height+y, width+x, height+y);
863
                        clip.addQuadPoint(width+x, height+y, width+x, height+y, x, height+y, x, height+y);
864
                        clip.addQuadPoint(x, height+y, x, height+y, x, y, x, y);
7607 fschmid 865
                }
7605 jghali 866
                if (clip.size() >= 2)
867
                        m_clipPaths.insert(id, clip);
868
        }
869
}
870
 
871
void SVGPlug::parseClipPathAttr(const QDomElement &e, FPointArray& clipPath)
872
{
873
        clipPath.resize(0);
12802 fschmid 874
/*      if (e.hasAttribute("style"))
12785 fschmid 875
        {
876
                QString style = e.attribute( "style" ).simplified();
877
                QStringList substyles = style.split(';', QString::SkipEmptyParts);
878
                for( QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it )
879
                {
880
                        QStringList substyle = (*it).split(':', QString::SkipEmptyParts);
881
                        QString command(substyle[0].trimmed());
882
                        QString params(substyle[1].trimmed());
883
                        if (command == "clip-path")
884
                        {
885
                                if (params.startsWith( "url("))
886
                                {
887
                                        unsigned int start = params.indexOf("#") + 1;
888
                                        unsigned int end = params.lastIndexOf(")");
889
                                        QString key = params.mid(start, end - start);
890
                                        QMap<QString, FPointArray>::iterator it = m_clipPaths.find(key);
891
                                        if (it != m_clipPaths.end())
892
                                                clipPath = it.value().copy();
893
                                }
894
                        }
895
                }
12802 fschmid 896
        } */
7605 jghali 897
        if (e.hasAttribute("clip-path"))
898
        {
899
                QString attr = e.attribute("clip-path");
900
                if (attr.startsWith( "url("))
901
                {
10517 cbradney 902
                        unsigned int start = attr.indexOf("#") + 1;
10427 cbradney 903
                        unsigned int end = attr.lastIndexOf(")");
7605 jghali 904
                        QString key = attr.mid(start, end - start);
905
                        QMap<QString, FPointArray>::iterator it = m_clipPaths.find(key);
906
                        if (it != m_clipPaths.end())
10516 cbradney 907
                                clipPath = it.value().copy();
7605 jghali 908
                }
909
        }
910
}
911
 
9856 fschmid 912
QList<PageItem*> SVGPlug::parseGroup(const QDomElement &e)
68 Franz 913
{
7612 jghali 914
        FPointArray clipPath;
9856 fschmid 915
        QList<PageItem*> GElements, gElements;
7612 jghali 916
        double BaseX = m_Doc->currentPage()->xOffset();
917
        double BaseY = m_Doc->currentPage()->yOffset();
7866 fschmid 918
        groupLevel++;
7612 jghali 919
        setupNode(e);
920
        parseClipPathAttr(e, clipPath);
7640 fschmid 921
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, 1, 1, 0, CommonStrings::None, CommonStrings::None, true);
7612 jghali 922
        PageItem *neu = m_Doc->Items->at(z);
7315 jghali 923
        for ( QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling() )
217 Franz 924
        {
68 Franz 925
                QDomElement b = n.toElement();
7612 jghali 926
                if( b.isNull() || isIgnorableNode(b) )
68 Franz 927
                        continue;
6356 jghali 928
                SvgStyle svgStyle;
12785 fschmid 929
                parseStyle( &svgStyle, b);
6356 jghali 930
                if (!svgStyle.Display)
7612 jghali 931
                        continue;
9856 fschmid 932
                QList<PageItem*> el = parseElement(b);
933
                for (int ec = 0; ec < el.count(); ++ec)
7612 jghali 934
                        gElements.append(el.at(ec));
7315 jghali 935
        }
7866 fschmid 936
        groupLevel--;
9922 fschmid 937
        SvgStyle *gc = m_gc.top();
12802 fschmid 938
        if (clipPath.size() == 0)
939
        {
940
                if (gc->clipPath.size() != 0)
941
                        clipPath = gc->clipPath.copy();
942
        }
10854 jghali 943
        if (gElements.count() == 0 || (gElements.count() < 2 && (clipPath.size() == 0) && (gc->Opacity == 1.0)))
7612 jghali 944
        {
13356 jghali 945
                // Unfortunately we have to take the long route here, or we risk crash on undo/redo
946
                // FIXME : create group object after parsing grouped objects
947
                /*m_Doc->Items->takeAt(z);
948
                delete neu;*/
949
                Selection tmpSelection(m_Doc, false);
950
                tmpSelection.addItem(neu);
951
                m_Doc->itemSelection_DeleteItem(&tmpSelection);
9856 fschmid 952
                for (int a = 0; a < m_Doc->Items->count(); ++a)
7640 fschmid 953
                {
954
                        m_Doc->Items->at(a)->ItemNr = a;
955
                }
9856 fschmid 956
                for (int gr = 0; gr < gElements.count(); ++gr)
7640 fschmid 957
                {
958
                        GElements.append(gElements.at(gr));
959
                }
7612 jghali 960
        }
961
        else
962
        {
963
                double minx = 99999.9;
964
                double miny = 99999.9;
965
                double maxx = -99999.9;
966
                double maxy = -99999.9;
967
                GElements.append(neu);
9856 fschmid 968
                for (int gr = 0; gr < gElements.count(); ++gr)
7612 jghali 969
                {
970
                        PageItem* currItem = gElements.at(gr);
11889 fschmid 971
                        double x1, x2, y1, y2;
12751 fschmid 972
                        currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
11889 fschmid 973
                        minx = qMin(minx, x1);
974
                        miny = qMin(miny, y1);
975
                        maxx = qMax(maxx, x2);
976
                        maxy = qMax(maxy, y2);
7612 jghali 977
                }
978
                double gx = minx;
979
                double gy = miny;
980
                double gw = maxx - minx;
981
                double gh = maxy - miny;
982
                neu->setXYPos(gx, gy);
983
                neu->setWidthHeight(gw, gh);
984
                if (clipPath.size() != 0)
985
                {
10396 jghali 986
                        QMatrix mm = gc->matrix;
7612 jghali 987
                        neu->PoLine = clipPath.copy();
988
                        neu->PoLine.map(mm);
12101 jghali 989
                        neu->PoLine.translate(-gx + BaseX, -gy + BaseY);
7612 jghali 990
                        clipPath.resize(0);
13356 jghali 991
 
7612 jghali 992
                }
993
                else
994
                        neu->SetRectFrame();
995
                neu->Clip = FlattenPath(neu->PoLine, neu->Segments);
996
                neu->Groups.push(m_Doc->GroupCounter);
997
                neu->isGroupControl = true;
998
                neu->groupsLastItem = gElements.at(gElements.count()-1);
999
                if( !e.attribute("id").isEmpty() )
1000
                        neu->setItemName(e.attribute("id"));
1001
                else
1002
                        neu->setItemName( tr("Group%1").arg(neu->Groups.top()));
11889 fschmid 1003
                neu->AutoName = false;
7612 jghali 1004
                neu->setFillTransparency(1 - gc->Opacity);
12745 fschmid 1005
                neu->gXpos = neu->xPos() - gx;
1006
                neu->gYpos = neu->yPos() - gy;
1007
                neu->gWidth = gw;
1008
                neu->gHeight = gh;
9856 fschmid 1009
                for (int gr = 0; gr < gElements.count(); ++gr)
7612 jghali 1010
                {
1011
                        gElements.at(gr)->Groups.push(m_Doc->GroupCounter);
12745 fschmid 1012
                        gElements.at(gr)->gXpos = gElements.at(gr)->xPos() - gx;
1013
                        gElements.at(gr)->gYpos = gElements.at(gr)->yPos() - gy;
1014
                        gElements.at(gr)->gWidth = gw;
1015
                        gElements.at(gr)->gHeight = gh;
7612 jghali 1016
                        GElements.append(gElements.at(gr));
1017
                }
7620 fschmid 1018
                neu->setRedrawBounding();
11705 fschmid 1019
                neu->setTextFlowMode(PageItem::TextFlowDisabled);
7640 fschmid 1020
                m_Doc->GroupCounter++;
7612 jghali 1021
        }
7597 jghali 1022
        delete( m_gc.pop() );
7315 jghali 1023
        return GElements;
1024
}
1025
 
9856 fschmid 1026
QList<PageItem*> SVGPlug::parseElement(const QDomElement &e)
7315 jghali 1027
{
9856 fschmid 1028
        QList<PageItem*> GElements;
7556 jghali 1029
        if (e.hasAttribute("id"))
1030
                m_nodeMap.insert(e.attribute("id"), e);
7315 jghali 1031
        QString STag = e.tagName();
1032
        if( STag == "g" )
1033
        {
7612 jghali 1034
                GElements = parseGroup( e );
7315 jghali 1035
                return GElements;
1036
        }
8507 jghali 1037
        if( STag == "defs" )
7556 jghali 1038
                parseDefs(e);
8507 jghali 1039
        else if( STag == "switch" )
7315 jghali 1040
                GElements = parseSwitch(e);
8507 jghali 1041
        else if( STag == "symbol" )
1042
                GElements = parseSymbol(e);
1043
        else if( STag == "use" )
7556 jghali 1044
                GElements = parseUse(e);
7315 jghali 1045
        else if( STag == "linearGradient" || STag == "radialGradient" )
1046
                parseGradient( e );
1047
        else if( STag == "rect" )
7612 jghali 1048
                GElements = parseRect(e);
7315 jghali 1049
        else if( STag == "ellipse" )
7612 jghali 1050
                GElements = parseEllipse(e);
7315 jghali 1051
        else if( STag == "circle" )
7612 jghali 1052
                GElements = parseCircle(e);
7315 jghali 1053
        else if( STag == "line" )
7612 jghali 1054
                GElements = parseLine(e);
7315 jghali 1055
        else if( STag == "path" )
7612 jghali 1056
                GElements = parsePath(e);
7315 jghali 1057
        else if( STag == "polyline" || e.tagName() == "polygon" )
7612 jghali 1058
                GElements = parsePolyline(e);
7315 jghali 1059
        else if( STag == "text" )
7612 jghali 1060
                GElements = parseText(e);
7605 jghali 1061
        else if( STag == "clipPath" )
1062
                parseClipPath(e);
7866 fschmid 1063
        else if( STag == "desc" )
1064
        {
1065
                if (groupLevel == 1)
1066
                        docDesc = e.text();
1067
        }
1068
        else if( STag == "title" )
1069
        {
1070
                if (groupLevel == 1)
1071
                        docTitle = e.text();
1072
        }
12785 fschmid 1073
        else if( STag == "image" )
1074
                GElements = parseImage(e);
10493 fschmid 1075
/*      else if( STag == "i:pgf" )
1076
        {
1077
                QByteArray cdat;
1078
                QByteArray ddat;
1079
                cdat = e.text().simplified();
1080
                QList<QByteArray> cdlist = cdat.split(' ');
1081
                for (int cd = 0; cd < cdlist.count(); cd++)
1082
                {
1083
                        ddat += QByteArray::fromBase64(cdlist[cd]);
1084
                }
1085
                QFile outf("/home/franz/testdata.txt");
1086
                outf.open(QIODevice::WriteOnly);
1087
                outf.write(ddat);
1088
                outf.close();
1089
                QString f2 = "/home/franz/testdata_decom.ai";
1090
                FILE *source = fopen("/home/franz/testdata.txt", "rb");
1091
                FILE *dest = fopen(f2, "wb");
1092
                int ret;
1093
                unsigned have;
1094
                z_stream strm;
1095
                char in[4096];
1096
                char out[4096];
1097
                strm.zalloc = Z_NULL;
1098
                strm.zfree = Z_NULL;
1099
                strm.opaque = Z_NULL;
1100
                strm.avail_in = 0;
1101
                strm.next_in = Z_NULL;
1102
                ret = inflateInit(&strm);
1103
                if (ret != Z_OK)
1104
                        return GElements;
1105
                do
1106
                {
1107
                        strm.avail_in = fread(in, 1, 4096, source);
1108
                        if (ferror(source))
1109
                        {
1110
                                (void)inflateEnd(&strm);
1111
                                return GElements;
1112
                        }
1113
                        if (strm.avail_in == 0)
1114
                                break;
1115
                        strm.next_in = (Bytef*)in;
1116
                        do
1117
                        {
1118
                                strm.avail_out = 4096;
1119
                                strm.next_out = (Bytef*)out;
1120
                                ret = inflate(&strm, Z_NO_FLUSH);
1121
                                assert(ret != Z_STREAM_ERROR);
1122
                                switch (ret)
1123
                                {
1124
                                        case Z_NEED_DICT:
1125
                                                ret = Z_DATA_ERROR;
1126
                                        case Z_DATA_ERROR:
1127
                                        case Z_MEM_ERROR:
1128
                                                (void)inflateEnd(&strm);
1129
                                                return GElements;
1130
                                }
1131
                                have = 4096 - strm.avail_out;
1132
                                if (fwrite(out, 1, have, dest) != have || ferror(dest))
1133
                                {
1134
                                        (void)inflateEnd(&strm);
1135
                                        return GElements;
1136
                                }
1137
                        }
1138
                        while (strm.avail_out == 0);
1139
                }
1140
                while (ret != Z_STREAM_END);
1141
                (void)inflateEnd(&strm);
1142
                fclose(source);
1143
                fclose(dest);
1144
        } */
7605 jghali 1145
/*      else if( STag == "image" )
7612 jghali 1146
                GElements = parseImage(e);
7504 fschmid 1147
        } */
10021 jghali 1148
        else if(!isIgnorableNodeName(STag) )
7315 jghali 1149
        {
1150
                // warn if unsupported SVG feature are encountered
13385 jghali 1151
                if (!m_unsupportedFeatures.contains(STag))
1152
                {
1153
                        m_unsupportedFeatures.insert(STag, STag);
1154
                        qDebug() << QString("unsupported SVG feature: %1").arg(STag);
1155
                        unsupported = true;
1156
                }
7315 jghali 1157
        }
7612 jghali 1158
        return GElements;
1159
}
1160
 
9856 fschmid 1161
QList<PageItem*> SVGPlug::parseCircle(const QDomElement &e)
7612 jghali 1162
{
9856 fschmid 1163
        QList<PageItem*> CElements;
7612 jghali 1164
        double BaseX = m_Doc->currentPage()->xOffset();
1165
        double BaseY = m_Doc->currentPage()->yOffset();
1166
        double r = parseUnit( e.attribute( "r" ) );
1167
        double x = parseUnit( e.attribute( "cx" ) ) - r;
1168
        double y = parseUnit( e.attribute( "cy" ) ) - r;
1169
        setupNode(e);
9922 fschmid 1170
        SvgStyle *gc = m_gc.top();
7612 jghali 1171
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, r * 2.0, r * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1172
        PageItem* ite = m_Doc->Items->at(z);
8501 cbradney 1173
        QMatrix mm = QMatrix();
7612 jghali 1174
        mm.translate(x, y);
1175
        ite->PoLine.map(mm);
1176
        FPoint wh = getMaxClipF(&ite->PoLine);
1177
        ite->setWidthHeight(wh.x(), wh.y());
1178
        finishNode(e, ite);
1179
        CElements.append(ite);
1180
        delete( m_gc.pop() );
1181
        return CElements;
1182
}
1183
 
9856 fschmid 1184
QList<PageItem*> SVGPlug::parseEllipse(const QDomElement &e)
7612 jghali 1185
{
9856 fschmid 1186
        QList<PageItem*> EElements;
7612 jghali 1187
        double BaseX = m_Doc->currentPage()->xOffset();
1188
        double BaseY = m_Doc->currentPage()->yOffset();
1189
        double rx = parseUnit( e.attribute( "rx" ) );
1190
        double ry = parseUnit( e.attribute( "ry" ) );
1191
        double x = parseUnit( e.attribute( "cx" ) ) - rx;
1192
        double y = parseUnit( e.attribute( "cy" ) ) - ry;
1193
        setupNode(e);
9922 fschmid 1194
        SvgStyle *gc = m_gc.top();
7612 jghali 1195
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, BaseX, BaseY, rx * 2.0, ry * 2.0, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1196
        PageItem* ite = m_Doc->Items->at(z);
8501 cbradney 1197
        QMatrix mm = QMatrix();
7612 jghali 1198
        mm.translate(x, y);
1199
        ite->PoLine.map(mm);
1200
        FPoint wh = getMaxClipF(&ite->PoLine);
1201
        ite->setWidthHeight(wh.x(), wh.y());
1202
        finishNode(e, ite);
1203
        EElements.append(ite);
1204
        delete( m_gc.pop() );
1205
        return EElements;
1206
}
1207
 
9856 fschmid 1208
QList<PageItem*> SVGPlug::parseImage(const QDomElement &e)
7612 jghali 1209
{
1210
        FPointArray clipPath;
9856 fschmid 1211
        QList<PageItem*> IElements;
7612 jghali 1212
        QString fname = e.attribute("xlink:href");
1213
        double BaseX = m_Doc->currentPage()->xOffset();
1214
        double BaseY = m_Doc->currentPage()->yOffset();
1215
        double x = e.attribute( "x" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x" ) );
1216
        double y = e.attribute( "y" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y" ) );
1217
        double w = e.attribute( "width" ).isEmpty() ? 1.0 : parseUnit( e.attribute( "width" ) );
1218
        double h = e.attribute( "height" ).isEmpty() ? 1.0 : parseUnit( e.attribute( "height" ) );
1219
        setupNode(e);
1220
        parseClipPathAttr(e, clipPath);
1221
        int z = m_Doc->itemAdd(PageItem::ImageFrame, PageItem::Unspecified, x+BaseX, y+BaseY, w, h, 1, m_Doc->toolSettings.dBrushPict, CommonStrings::None, true);
12795 fschmid 1222
        PageItem* ite = m_Doc->Items->at(z);
7612 jghali 1223
        if (!fname.isEmpty())
12785 fschmid 1224
        {
1225
                if (!fname.startsWith("data:"))
1226
                        m_Doc->LoadPict(fname, z);
1227
                else
1228
                {
1229
                        int startData = fname.indexOf(",");
1230
                        QString dataType = fname.left(startData);
1231
                        fname.remove(0, startData+1);
1232
                        QByteArray ba;
1233
                        ba.append(fname);
1234
                        if (dataType.contains("base64"))
1235
                                ba = QByteArray::fromBase64(ba);
12795 fschmid 1236
                        ite->tempImageFile = new QTemporaryFile(QDir::tempPath() + "/scribus_temp_svg_XXXXXX.png");
1237
                        ite->tempImageFile->open();
1238
                        QString fileName = getLongPathName(ite->tempImageFile->fileName());
1239
                        ite->tempImageFile->close();
1240
                        ite->isInlineImage = true;
12785 fschmid 1241
                        QImage img;
1242
                        img.loadFromData(ba);
12795 fschmid 1243
                        img.save(fileName, "PNG");
1244
                        m_Doc->LoadPict(fileName, z);
12785 fschmid 1245
                }
1246
        }
7612 jghali 1247
        if (clipPath.size() != 0)
1248
                ite->PoLine = clipPath.copy();
1249
        clipPath.resize(0);
1250
        ite->Clip = FlattenPath(ite->PoLine, ite->Segments);
1251
        finishNode(e, ite);
1252
        IElements.append(ite);
1253
        delete( m_gc.pop() );
1254
        return IElements;
1255
}
1256
 
9856 fschmid 1257
QList<PageItem*> SVGPlug::parseLine(const QDomElement &e)
7612 jghali 1258
{
9856 fschmid 1259
        QList<PageItem*> LElements;
7612 jghali 1260
        double BaseX = m_Doc->currentPage()->xOffset();
1261
        double BaseY = m_Doc->currentPage()->yOffset();
1262
        double x1 = e.attribute( "x1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x1" ) );
1263
        double y1 = e.attribute( "y1" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y1" ) );
1264
        double x2 = e.attribute( "x2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "x2" ) );
1265
        double y2 = e.attribute( "y2" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "y2" ) );
1266
        setupNode(e);
9922 fschmid 1267
        SvgStyle *gc = m_gc.top();
11263 jghali 1268
        int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
7612 jghali 1269
        PageItem* ite = m_Doc->Items->at(z);
1270
        ite->PoLine.resize(4);
1271
        ite->PoLine.setPoint(0, FPoint(x1, y1));
1272
        ite->PoLine.setPoint(1, FPoint(x1, y1));
1273
        ite->PoLine.setPoint(2, FPoint(x2, y2));
1274
        ite->PoLine.setPoint(3, FPoint(x2, y2));
1275
        finishNode(e, ite);
1276
        LElements.append(ite);
1277
        delete( m_gc.pop() );
1278
        return LElements;
1279
}
1280
 
9856 fschmid 1281
QList<PageItem*> SVGPlug::parsePath(const QDomElement &e)
7612 jghali 1282
{
1283
        FPointArray pArray;
9856 fschmid 1284
        QList<PageItem*> PElements;
7612 jghali 1285
        double BaseX = m_Doc->currentPage()->xOffset();
1286
        double BaseY = m_Doc->currentPage()->yOffset();
1287
        setupNode(e);
9922 fschmid 1288
        SvgStyle *gc = m_gc.top();
7612 jghali 1289
        PageItem::ItemType itype = parseSVG(e.attribute("d"), &pArray) ? PageItem::PolyLine : PageItem::Polygon;
1290
        int z = m_Doc->itemAdd(itype, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1291
        PageItem* ite = m_Doc->Items->at(z);
7678 fschmid 1292
        ite->fillRule = (gc->fillRule != "nonzero");
7612 jghali 1293
        ite->PoLine = pArray;
1294
        if (ite->PoLine.size() < 4)
7315 jghali 1295
        {
7612 jghali 1296
//                      m_Doc->m_Selection->addItem(ite);
1297
                tmpSel->addItem(ite);
1298
//                      m_Doc->itemSelection_DeleteItem();
1299
                m_Doc->itemSelection_DeleteItem(tmpSel);
1300
//                      m_Doc->m_Selection->clear();
1301
        }
1302
        else
1303
        {
1304
                finishNode(e, ite);
1305
                PElements.append(ite);
1306
        }
1307
        delete( m_gc.pop() );
1308
        return PElements;
1309
}
1310
 
9856 fschmid 1311
QList<PageItem*> SVGPlug::parsePolyline(const QDomElement &e)
7612 jghali 1312
{
1313
        int z;
9856 fschmid 1314
        QList<PageItem*> PElements;
7612 jghali 1315
        double BaseX = m_Doc->currentPage()->xOffset();
1316
        double BaseY = m_Doc->currentPage()->yOffset();
1317
        setupNode(e);
9922 fschmid 1318
        SvgStyle *gc = m_gc.top();
7612 jghali 1319
        QString points = e.attribute( "points" );
1320
        if (!points.isEmpty())
1321
        {
1322
                QString STag = e.tagName();
10394 cbradney 1323
                points = points.simplified().replace(',', " ");
10603 fschmid 1324
                QStringList pointList = points.split( ' ', QString::SkipEmptyParts );
7612 jghali 1325
                if (( e.tagName() == "polygon" ) && (pointList.count() > 4))
1326
                        z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1327
                else
1328
                        z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
7315 jghali 1329
                PageItem* ite = m_Doc->Items->at(z);
7612 jghali 1330
                ite->fillRule = (gc->fillRule != "nonzero");
1331
                ite->PoLine.resize(0);
8237 avox 1332
                ite->PoLine.svgInit();
7612 jghali 1333
                bool bFirst = true;
1334
                double x = 0.0;
1335
                double y = 0.0;
1336
                for( QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++ )
217 Franz 1337
                {
7612 jghali 1338
                        if( bFirst )
217 Franz 1339
                        {
13460 jghali 1340
                                x = ScCLocale::toDoubleC(*(it++));
1341
                                y = ScCLocale::toDoubleC(*it);
8252 jghali 1342
                                ite->PoLine.svgMoveTo(x, y);
7612 jghali 1343
                                bFirst = false;
68 Franz 1344
                        }
1345
                        else
7315 jghali 1346
                        {
13460 jghali 1347
                                x = ScCLocale::toDoubleC(*(it++));
1348
                                y = ScCLocale::toDoubleC(*it);
8252 jghali 1349
                                ite->PoLine.svgLineTo(x, y);
7315 jghali 1350
                        }
217 Franz 1351
                }
7612 jghali 1352
                if (( STag == "polygon" ) && (pointList.count() > 4))
8237 avox 1353
                        ite->PoLine.svgClosePath();
7612 jghali 1354
                else
1355
                        ite->convertTo(PageItem::PolyLine);
1356
                finishNode(e, ite);
1357
                PElements.append(ite);
7315 jghali 1358
        }
1359
        delete( m_gc.pop() );
7612 jghali 1360
        return PElements;
7315 jghali 1361
}
1362
 
9856 fschmid 1363
QList<PageItem*> SVGPlug::parseRect(const QDomElement &e)
7612 jghali 1364
{
9856 fschmid 1365
        QList<PageItem*> RElements;
7612 jghali 1366
        double BaseX = m_Doc->currentPage()->xOffset();
1367
        double BaseY = m_Doc->currentPage()->yOffset();
1368
        double x = parseUnit( e.attribute( "x" ) );
1369
        double y = parseUnit( e.attribute( "y" ) );
1370
        double width = parseUnit( e.attribute( "width" ));
1371
        double height = parseUnit( e.attribute( "height" ) );
1372
        double rx = e.attribute( "rx" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "rx" ) );
1373
        double ry = e.attribute( "ry" ).isEmpty() ? 0.0 : parseUnit( e.attribute( "ry" ) );
1374
        setupNode(e);
9922 fschmid 1375
        SvgStyle *gc = m_gc.top();
7612 jghali 1376
        int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, BaseX, BaseY, width, height, gc->LWidth, gc->FillCol, gc->StrokeCol, true);
1377
        PageItem* ite = m_Doc->Items->at(z);
1378
        if ((rx != 0) || (ry != 0))
1379
        {
8562 jghali 1380
                ite->setCornerRadius(qMax(rx, ry));
7612 jghali 1381
                ite->SetFrameRound();
1382
                m_Doc->setRedrawBounding(ite);
1383
        }
8501 cbradney 1384
        QMatrix mm = QMatrix();
7612 jghali 1385
        mm.translate(x, y);
1386
        ite->PoLine.map(mm);
1387
        FPoint wh = getMaxClipF(&ite->PoLine);
1388
        ite->setWidthHeight(wh.x(), wh.y());
1389
        finishNode(e, ite);
1390
        RElements.append(ite);
1391
        delete( m_gc.pop() );
1392
        return RElements;
1393
}
1394
 
9856 fschmid 1395
QList<PageItem*> SVGPlug::parseText(const QDomElement &e)
7315 jghali 1396
{
9856 fschmid 1397
        QList<PageItem*> GElements;
7612 jghali 1398
        setupNode(e);
12725 jghali 1399
        double chunkWidth = 0;
10785 jghali 1400
        FPoint currentPos = parseTextPosition(e);
12725 jghali 1401
        SvgStyle *gc      = m_gc.top();
1402
        if (gc->textAnchor != "start")
1403
                getTextChunkWidth(e, chunkWidth);
12719 fschmid 1404
        for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
7315 jghali 1405
        {
10785 jghali 1406
                if (n.isElement() && (n.toElement().tagName() == "tspan"))
217 Franz 1407
                {
12725 jghali 1408
                        QList<PageItem*> el = parseTextSpan(n.toElement(), currentPos, chunkWidth);
9856 fschmid 1409
                        for (int ec = 0; ec < el.count(); ++ec)
215 Franz 1410
                                GElements.append(el.at(ec));
217 Franz 1411
                }
10785 jghali 1412
                if (n.isText())
1413
                {
12725 jghali 1414
                        QList<PageItem*> el = parseTextNode(n.toText(), currentPos, chunkWidth);
10785 jghali 1415
                        for (int ec = 0; ec < el.count(); ++ec)
1416
                                GElements.append(el.at(ec));
1417
                }
12719 fschmid 1418
        }
7612 jghali 1419
        delete( m_gc.pop() );
7315 jghali 1420
        return GElements;
1421
}
12725 jghali 1422
 
1423
QList<PageItem*> SVGPlug::parseTextSpan(const QDomElement& e, FPoint& currentPos, double chunkW)
7315 jghali 1424
{
9856 fschmid 1425
        QList<PageItem*> GElements;
12725 jghali 1426
        setupNode(e);
1427
        currentPos   = parseTextPosition(e, &currentPos);
1428
        SvgStyle *gc = m_gc.top();
1429
        if ((e.hasAttribute("x") || e.hasAttribute("y")) && (gc->textAnchor != "start"))
12718 fschmid 1430
        {
12725 jghali 1431
                chunkW = 0;
1432
                getTextChunkWidth(e, chunkW);
12718 fschmid 1433
        }
12725 jghali 1434
        for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
12718 fschmid 1435
        {
12725 jghali 1436
                if (n.isElement() && (n.toElement().tagName() == "tspan"))
12718 fschmid 1437
                {
12725 jghali 1438
                        QList<PageItem*> el = parseTextSpan(n.toElement(), currentPos, chunkW);
1439
                        for (int ec = 0; ec < el.count(); ++ec)
1440
                                GElements.append(el.at(ec));
12718 fschmid 1441
                }
12725 jghali 1442
                if (n.isText())
12718 fschmid 1443
                {
12725 jghali 1444
                        QList<PageItem*> el = parseTextNode(n.toText(), currentPos, chunkW);
1445
                        for (int ec = 0; ec < el.count(); ++ec)
1446
                                GElements.append(el.at(ec));
12718 fschmid 1447
                }
1448
        }
12725 jghali 1449
        delete( m_gc.pop() );
12718 fschmid 1450
        return GElements;
1451
}
12725 jghali 1452
 
1453
QList<PageItem*> SVGPlug::parseTextNode(const QDomText& e, FPoint& currentPos, double chunkW)
12718 fschmid 1454
{
1455
        QList<PageItem*> GElements;
1456
        double BaseX  = m_Doc->currentPage()->xOffset();
1457
        double BaseY  = m_Doc->currentPage()->yOffset();
1458
        double StartX = currentPos.x(), StartY = currentPos.y();
12725 jghali 1459
 
1460
        QString textString = e.data().simplified();
10785 jghali 1461
        if ( textString.isEmpty() )
1462
                return GElements;
1463
 
10638 jghali 1464
        SvgStyle *gc   = m_gc.top();
1465
        QFont textFont = getFontFromStyle(*gc);
1466
        QFontMetrics fm(textFont);
1467
    double width   = fm.width(textString);
1468
 
1469
        if( gc->textAnchor == "middle" )
12725 jghali 1470
                StartX -= chunkW / 2.0;
10638 jghali 1471
        else if( gc->textAnchor == "end")
12725 jghali 1472
                StartX -= chunkW;
10638 jghali 1473
 
1474
        FPointArray textPath;
1475
        QString textFillColor   = gc->FillCol;
1476
        QString textStrokeColor = gc->StrokeCol;
1477
        QPainterPath painterPath;
1478
        painterPath.addText( StartX, StartY, textFont, textString );
1479
        textPath.fromQPainterPath(painterPath);
1480
        if (textPath.size() > 0)
1481
        {
12725 jghali 1482
//              double  lineWidth = 0.0;
10638 jghali 1483
                int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, BaseX, BaseY, 10, 10, gc->LWidth, textFillColor, textStrokeColor, true);
1484
                PageItem* ite = m_Doc->Items->at(z);
1485
                ite->PoLine = textPath;
1486
                finishNode(e, ite);
1487
                GElements.append(ite);
1488
        }
10785 jghali 1489
        currentPos.setX( currentPos.x() + width );
10638 jghali 1490
        return GElements;
7315 jghali 1491
}
12725 jghali 1492
 
9856 fschmid 1493
QList<PageItem*> SVGPlug::parseSwitch(const QDomElement &e)
7315 jghali 1494
{
1495
        QString href;
1496
        QStringList hrefs;
9856 fschmid 1497
        QList<PageItem*> SElements;
7315 jghali 1498
        for (QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
1499
        {
1500
                QDomElement de = n.toElement();
1501
                QString STag = de.tagName();
1502
                if (STag == "foreignObject")
217 Franz 1503
                {
7315 jghali 1504
                        if (de.hasAttribute("xlink:href"))
217 Franz 1505
                        {
7315 jghali 1506
                                href = de.attribute("xlink:href").mid(1);
1507
                                if (!href.isEmpty())
1508
                                        hrefs.append(href);
217 Franz 1509
                        }
7315 jghali 1510
                        for (QDomNode n1 = de.firstChild(); !n1.isNull(); n1 = n1.nextSibling())
217 Franz 1511
                        {
7315 jghali 1512
                                QDomElement de1 = n1.toElement();
1513
                                if (de1.hasAttribute("xlink:href"))
296 Franz 1514
                                {
7315 jghali 1515
                                        href = de1.attribute("xlink:href").mid(1);
1516
                                        if (!href.isEmpty())
1517
                                                hrefs.append(href);
298 Franz 1518
                                }
217 Franz 1519
                        }
1520
                }
7315 jghali 1521
                else
1522
                {
1523
                        if (de.hasAttribute("requiredExtensions") || de.hasAttribute("requiredFeatures"))
1524
                                continue;
1525
                        else if (de.hasAttribute("id") && hrefs.contains(de.attribute("id")))
1526
                                continue;
1527
                        else
1528
                        {
1529
                                SElements = parseElement(de);
1530
                                if (SElements.count() > 0)
1531
                                        break;
1532
                        }
1533
                }
217 Franz 1534
        }
7315 jghali 1535
        return SElements;
68 Franz 1536
}
1537
 
9856 fschmid 1538
QList<PageItem*> SVGPlug::parseSymbol(const QDomElement &e)
8507 jghali 1539
{
9856 fschmid 1540
        QList<PageItem*> SElements;
12266 jghali 1541
        QString id = e.attribute("id");
8507 jghali 1542
        if( !id.isEmpty() )
1543
                m_nodeMap.insert(id, e);
1544
        return SElements;
1545
}
1546
 
9856 fschmid 1547
QList<PageItem*> SVGPlug::parseUse(const QDomElement &e)
7556 jghali 1548
{
9856 fschmid 1549
        QList<PageItem*> UElements;
12266 jghali 1550
        setupNode(e);
1551
        if( e.hasAttribute("x") || e.hasAttribute("y") )
1552
        {
1553
                QMatrix matrix;
13460 jghali 1554
                double  xAtt = ScCLocale::toDoubleC(e.attribute("x", "0.0"));
1555
                double  yAtt = ScCLocale::toDoubleC(e.attribute("y", "0.0"));
12266 jghali 1556
                SvgStyle *gc = m_gc.top();
1557
                gc->matrix   = QMatrix(1.0, 0.0, 0.0, 1.0, xAtt, yAtt) * gc->matrix;
1558
        }
1559
        QString href = e.attribute("xlink:href").mid(1);
1560
        QMap<QString, QDomElement>::Iterator it = m_nodeMap.find(href);
1561
        if (it != m_nodeMap.end())
1562
        {
1563
                QDomElement elem = it.value().toElement();
1564
                if( elem.tagName() == "symbol" )
1565
                        UElements = parseGroup(elem);
1566
                else
1567
                        UElements = parseElement(elem);
1568
        }
1569
        delete (m_gc.pop());
7556 jghali 1570
        return UElements;
1571
}
1572
 
10638 jghali 1573
QFont SVGPlug::getFontFromStyle(SvgStyle& style)
1574
{
1575
        QFont font(QApplication::font());
1576
        font.setStyleStrategy( QFont::PreferOutline );
1577
 
1578
        if (!style.FontFamily.isEmpty())
1579
                font.setFamily(style.FontFamily);
1580
 
1581
        if (!style.FontStyle.isEmpty())
1582
        {
1583
                if (style.FontStyle == "normal")
1584
                        font.setStyle(QFont::StyleNormal);
1585
                else if (style.FontStyle == "italic")
1586
                        font.setStyle(QFont::StyleItalic);
1587
                else if (style.FontStyle == "oblique")
1588
                        font.setStyle(QFont::StyleOblique);
1589
        }
1590
 
1591
        if (!style.FontWeight.isEmpty())
1592
        {
1593
                if (style.FontWeight == "normal")
1594
                        font.setWeight(QFont::Normal);
1595
                else if (style.FontWeight == "bold")
1596
                        font.setWeight(QFont::Bold);
1597
                else if (style.FontWeight == "bolder")
1598
                        font.setWeight(QFont::DemiBold);
1599
                else if (style.FontWeight == "lighter")
1600
                        font.setWeight(QFont::Light);
1601
                else
1602
                {
1603
                        bool weightIsNum = false;
1604
                        int  fontWeight  = style.FontWeight.toInt(&weightIsNum);
1605
                        if (weightIsNum)
1606
                        {
1607
                                if (fontWeight == 100 || fontWeight == 200)
1608
                                        font.setWeight(QFont::Light);
1609
                                else if (fontWeight == 300 || fontWeight == 400)
1610
                                        font.setWeight(QFont::Normal);
1611
                                else if (fontWeight == 500 || fontWeight == 600)
1612
                                        font.setWeight(QFont::DemiBold);
1613
                                else if (fontWeight == 700 || fontWeight == 800)
1614
                                        font.setWeight(QFont::Bold);
1615
                                else if (fontWeight == 900)
1616
                                        font.setWeight(QFont::Black);
1617
                        }
1618
                }
1619
        }
1620
 
1621
        if (!style.FontStretch.isEmpty())
1622
        {
1623
                if (style.FontStretch == "normal")
1624
                        font.setStretch(QFont::Unstretched);
1625
                else if (style.FontStretch == "ultra-condensed")
1626
                        font.setStretch(QFont::UltraCondensed);
1627
                else if (style.FontStretch == "extra-condensed")
1628
                        font.setStretch(QFont::ExtraCondensed);
1629
                else if (style.FontStretch == "condensed")
1630
                        font.setStretch(QFont::Condensed);
1631
                else if (style.FontStretch == "semi-condensed")
1632
                        font.setStretch(QFont::SemiCondensed);
1633
                else if (style.FontStretch == "semi-expanded")
1634
                        font.setStretch(QFont::SemiExpanded);
1635
                else if (style.FontStretch == "expanded")
1636
                        font.setStretch(QFont::Expanded);
1637
                else if (style.FontStretch == "extra-expanded")
1638
                        font.setStretch(QFont::ExtraExpanded);
1639
                else if (style.FontStretch == "ultra-expanded")
1640
                        font.setStretch(QFont::UltraExpanded);
1641
                else if (style.FontStretch == "narrower")
1642
                        font.setStretch(QFont::SemiCondensed);
1643
                else if (style.FontStretch == "wider")
1644
                        font.setStretch(QFont::SemiExpanded);
1645
        }
12887 jghali 1646
        if (!style.textDecoration.isEmpty())
1647
        {
1648
                bool underline = false, overline  = false;
1649
                bool strikeOut = false;
1650
                if (style.textDecoration == "underline")
1651
                        underline = true;
1652
                else if (style.textDecoration == "overline")
1653
                        overline = true;
1654
                else if (style.textDecoration == "line-through")
1655
                        strikeOut = true;
1656
                font.setUnderline(underline);
1657
                font.setOverline(overline);
1658
                font.setStrikeOut(strikeOut);
1659
        }
10638 jghali 1660
        font.setPointSize(style.FontSize / 10);
1661
        return font;
1662
}
1663
 
8604 jghali 1664
QDomElement SVGPlug::getReferencedNode(const QDomElement &e)
1665
{
1666
        QDomElement ret;
1667
        QMap<QString, QDomElement>::Iterator it;
1668
        QString href = e.attribute("xlink:href").mid(1);
1669
        it = m_nodeMap.find(href);
1670
        if (it != m_nodeMap.end())
12287 jghali 1671
                ret = it.value().toElement();
8604 jghali 1672
        return ret;
1673
}
1674
 
12725 jghali 1675
bool SVGPlug::getTextChunkWidth(const QDomElement &e, double& width)
1676
{
1677
        bool doBreak = false;
1678
        setupNode(e);
1679
        QDomNode c = e.firstChild();
1680
        for(QDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling())
1681
        {
1682
                if (n.isElement() && (n.toElement().tagName() == "tspan"))
1683
                {
1684
                        QDomElement elem = n.toElement();
1685
                        if (elem.hasAttribute("x") || elem.hasAttribute("y"))
1686
                        {
1687
                                doBreak = true;
1688
                                break;
1689
                        }
1690
                        doBreak = getTextChunkWidth(n.toElement(), width);
1691
                        if (doBreak) break;
1692
                }
1693
                if (n.isText())
1694
                {
1695
                        QDomText text = n.toText();
1696
                        QString  textString = text.data().simplified();
1697
                        if (textString.length() > 0)
1698
                        {
1699
                                SvgStyle *gc   = m_gc.top();
1700
                                QFont textFont = getFontFromStyle(*gc);
1701
                                QFontMetrics fm(textFont);
1702
                                width += fm.width(textString);
1703
                        }
1704
                }
1705
        }
1706
        delete (m_gc.pop());
1707
        return doBreak;
1708
}
1709
 
68 Franz 1710
double SVGPlug::fromPercentage( const QString &s )
1711
{
10668 jghali 1712
        QString s1 = s;
1713
        if (s1.endsWith( ";" ))
1714
                s1 = s1.left(s1.length() - 1);
1715
        if (s1.endsWith( "%" ))
7556 jghali 1716
        {
10668 jghali 1717
                s1 = s1.left(s1.length() - 1);
13460 jghali 1718
                return ScCLocale::toDoubleC(s1) / 100.0;
7556 jghali 1719
        }
68 Franz 1720
        else
13460 jghali 1721
                return ScCLocale::toDoubleC(s1);
68 Franz 1722
}
1723
 
10638 jghali 1724
double SVGPlug::parseFontSize(const QString& fsize)
1725
{
1726
        bool noUnit  = true;
1727
        QString unit = fsize.right(2);
1728
        if (unit == "pt" || unit == "cm" || unit == "mm" ||
1729
                unit == "in" || unit == "px")
1730
        {
1731
                noUnit = false;
1732
        }
1733
        double value = parseUnit(fsize);
1734
        if (noUnit)
1735
                value *= 0.8;
1736
        return value;
1737
}
1738
 
68 Franz 1739
double SVGPlug::parseUnit(const QString &unit)
1740
{
693 fschmid 1741
        bool noUnit = false;
270 Franz 1742
        QString unitval=unit;
1743
        if( unit.right( 2 ) == "pt" )
1744
                unitval.replace( "pt", "" );
1745
        else if( unit.right( 2 ) == "cm" )
1746
                unitval.replace( "cm", "" );
1747
        else if( unit.right( 2 ) == "mm" )
1748
                unitval.replace( "mm" , "" );
1749
        else if( unit.right( 2 ) == "in" )
1750
                unitval.replace( "in", "" );
1751
        else if( unit.right( 2 ) == "px" )
1752
                unitval.replace( "px", "" );
693 fschmid 1753
        if (unitval == unit)
1754
                noUnit = true;
13460 jghali 1755
        double value = ScCLocale::toDoubleC(unitval);
270 Franz 1756
        if( unit.right( 2 ) == "pt" )
1757
                value = value;
1758
        else if( unit.right( 2 ) == "cm" )
1759
                value = ( value / 2.54 ) * 72;
1760
        else if( unit.right( 2 ) == "mm" )
1761
                value = ( value / 25.4 ) * 72;
1762
        else if( unit.right( 2 ) == "in" )
1763
                value = value * 72;
1764
        else if( unit.right( 2 ) == "px" )
865 fschmid 1765
                value = value * 0.8;
693 fschmid 1766
        else if(noUnit)
8252 jghali 1767
                value = value;
68 Franz 1768
        return value;
1769
}
1770
 
8501 cbradney 1771
QMatrix SVGPlug::parseTransform( const QString &transform )
68 Franz 1772
{
8501 cbradney 1773
        QMatrix ret;
12124 jghali 1774
        // Workaround for QString::split() bug when string ends with space
1775
        QString trans = transform.simplified();
68 Franz 1776
        // Split string for handling 1 transform statement at a time
12124 jghali 1777
        QStringList subtransforms = trans.split(')', QString::SkipEmptyParts);
68 Franz 1778
        QStringList::ConstIterator it = subtransforms.begin();
1779
        QStringList::ConstIterator end = subtransforms.end();
1780
        for(; it != end; ++it)
1781
        {
8501 cbradney 1782
                QMatrix result;
12124 jghali 1783
                QStringList subtransform = it->split('(', QString::SkipEmptyParts);
10398 cbradney 1784
                subtransform[0] = subtransform[0].trimmed().toLower();
10394 cbradney 1785
                subtransform[1] = subtransform[1].simplified();
68 Franz 1786
                QRegExp reg("[,( ]");
10603 fschmid 1787
                QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts);
68 Franz 1788
                if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
1789
                        subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
1790
                if(subtransform[0] == "rotate")
1791
                {
1792
                        if(params.count() == 3)
1793
                        {
13460 jghali 1794
                                double x = ScCLocale::toDoubleC(params[1]);
1795
                                double y = ScCLocale::toDoubleC(params[2]);
68 Franz 1796
                                result.translate(x, y);
13460 jghali 1797
                                result.rotate(ScCLocale::toDoubleC(params[0]));
68 Franz 1798
                                result.translate(-x, -y);
1799
                        }
1800
                        else
13460 jghali 1801
                                result.rotate(ScCLocale::toDoubleC(params[0]));
68 Franz 1802
                }
1803
                else if(subtransform[0] == "translate")
1804
                {
1805
                        if(params.count() == 2)
13460 jghali 1806
                                result.translate(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[1]));
68 Franz 1807
                        else    // Spec : if only one param given, assume 2nd param to be 0
13460 jghali 1808
                                result.translate(ScCLocale::toDoubleC(params[0]), 0);
68 Franz 1809
                }
1810
                else if(subtransform[0] == "scale")
1811
                {
1812
                        if(params.count() == 2)
13460 jghali 1813
                                result.scale(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[1]));
68 Franz 1814
                        else    // Spec : if only one param given, assume uniform scaling
13460 jghali 1815
                                result.scale(ScCLocale::toDoubleC(params[0]), ScCLocale::toDoubleC(params[0]));
68 Franz 1816
                }
1817
                else if(subtransform[0] == "skewx")
13460 jghali 1818
                        result.shear(tan(ScCLocale::toDoubleC(params[0]) * 0.01745329251994329576), 0.0F);
68 Franz 1819
                else if(subtransform[0] == "skewy")
13460 jghali 1820
                        result.shear(0.0F, tan(ScCLocale::toDoubleC(params[0]) * 0.01745329251994329576));
68 Franz 1821
                else if(subtransform[0] == "matrix")
1822
                {
1823
                        if(params.count() >= 6)
332 Franz 1824
                        {
13460 jghali 1825
                                double sx = ScCLocale::toDoubleC(params[0]);
1826
                                double sy = ScCLocale::toDoubleC(params[3]);
1827
                                double p1 = ScCLocale::toDoubleC(params[1]);
1828
                                double p2 = ScCLocale::toDoubleC(params[2]);
1829
                                double p4 = ScCLocale::toDoubleC(params[4]);
1830
                                double p5 = ScCLocale::toDoubleC(params[5]);
1831
                                result.setMatrix(sx, p1, p2, sy, p4, p5);
332 Franz 1832
                        }
68 Franz 1833
                }
6611 jghali 1834
                ret = result * ret;
68 Franz 1835
        }
2597 fschmid 1836
        return ret;
68 Franz 1837
}
1838
 
1839
const char * SVGPlug::getCoord( const char *ptr, double &number )
1840
{
1841
        int integer, exponent;
1842
        double decimal, frac;
1843
        int sign, expsign;
1844
 
1845
        exponent = 0;
1846
        integer = 0;
1847
        frac = 1.0;
1848
        decimal = 0;
1849
        sign = 1;
1850
        expsign = 1;
1851
 
1852
        // read the sign
1853
        if(*ptr == '+')
1854
                ptr++;
1855
        else if(*ptr == '-')
1856
        {
1857
                ptr++;
1858
                sign = -1;
1859
        }
1860
 
1861
        // read the integer part
1862
        while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1863
                integer = (integer * 10) + *(ptr++) - '0';
1864
        if(*ptr == '.') // read the decimals
217 Franz 1865
        {
68 Franz 1866
                ptr++;
1867
                while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1868
                        decimal += (*(ptr++) - '0') * (frac *= 0.1);
217 Franz 1869
        }
68 Franz 1870
 
1871
        if(*ptr == 'e' || *ptr == 'E') // read the exponent part
1872
        {
1873
                ptr++;
1874
 
1875
                // read the sign of the exponent
1876
                if(*ptr == '+')
1877
                        ptr++;
1878
                else if(*ptr == '-')
1879
                {
1880
                        ptr++;
1881
                        expsign = -1;
1882
                }
1883
 
1884
                exponent = 0;
1885
                while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
1886
                {
1887
                        exponent *= 10;
1888
                        exponent += *ptr - '0';
1889
                        ptr++;
1890
                }
217 Franz 1891
        }
68 Franz 1892
        number = integer + decimal;
80 Franz 1893
        number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
68 Franz 1894
        // skip the following space
1895
        if(*ptr == ' ')
1896
                ptr++;
1897
 
1898
        return ptr;
1899
}
1900
 
1901
bool SVGPlug::parseSVG( const QString &s, FPointArray *ite )
1902
{
8253 jghali 1903
        return ite->parseSVG(s);
68 Franz 1904
}
1905
 
1906
 
1907
QColor SVGPlug::parseColorN( const QString &rgbColor )
1908
{
1909
        int r, g, b;
10398 cbradney 1910
        keywordToRGB( rgbColor.toLower(), r, g, b );
68 Franz 1911
        return QColor( r, g, b );
1912
}
1913
 
4645 subik 1914
 
68 Franz 1915
QString SVGPlug::parseColor( const QString &s )
1916
{
1917
        QColor c;
6286 jghali 1918
        QString ret = CommonStrings::None;
13391 jghali 1919
        if (s.length() > 11) // icc-color()
217 Franz 1920
        {
13391 jghali 1921
                int iccColorIndex  = s.indexOf("icc-color");
1922
                if (iccColorIndex >= 0)
1923
                {
1924
                        QString iccColorName = parseIccColor(s);
1925
                        if (iccColorName.length() > 0)
1926
                                return iccColorName;
1927
                }
1928
        }
1929
        if (s.startsWith( "rgb(" ) )
1930
        {
10394 cbradney 1931
                QString parse = s.trimmed();
10603 fschmid 1932
                QStringList colors = parse.split(',', QString::SkipEmptyParts);
68 Franz 1933
                QString r = colors[0].right( ( colors[0].length() - 4 ) );
1934
                QString g = colors[1];
1935
                QString b = colors[2].left( ( colors[2].length() - 1 ) );
13391 jghali 1936
                if (r.contains( "%" ))
217 Franz 1937
                {
68 Franz 1938
                        r = r.left( r.length() - 1 );
13460 jghali 1939
                        r = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(r) ) / 100.0 ) ) );
217 Franz 1940
                }
13391 jghali 1941
                if (g.contains( "%" ))
217 Franz 1942
                {
68 Franz 1943
                        g = g.left( g.length() - 1 );
13460 jghali 1944
                        g = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(g) ) / 100.0 ) ) );
217 Franz 1945
                }
13391 jghali 1946
                if (b.contains( "%" ))
217 Franz 1947
                {
68 Franz 1948
                        b = b.left( b.length() - 1 );
13460 jghali 1949
                        b = QString::number( static_cast<int>( ( static_cast<double>( 255 * ScCLocale::toDoubleC(b) ) / 100.0 ) ) );
217 Franz 1950
                }
68 Franz 1951
                c = QColor(r.toInt(), g.toInt(), b.toInt());
217 Franz 1952
        }
68 Franz 1953
        else
217 Franz 1954
        {
10394 cbradney 1955
                QString rgbColor = s.trimmed();
13391 jghali 1956
                if (rgbColor.startsWith( "#" ))
11030 jghali 1957
                {
1958
                        rgbColor = rgbColor.left(7);
68 Franz 1959
      &n