1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7
8 #include <QByteArray>
9 #include <QCursor>
10 #include <QDrag>
11 #include <QFile>
12 #include <QList>
13 #include <QMimeData>
14 #include <QRegExp>
15 #include <QStack>
16 #include <QDebug>
17
18 #include <cstdlib>
19
20 #include "importshape.h"
21
22
23 #include "commonstrings.h"
24 #include "loadsaveplugin.h"
25 #include "pagesize.h"
26 #include "prefscontext.h"
27 #include "prefsfile.h"
28 #include "prefsmanager.h"
29 #include "prefstable.h"
30 #include "rawimage.h"
31 #include "scclocale.h"
32 #include "sccolorengine.h"
33 #include "scconfig.h"
34 #include "sclimits.h"
35 #include "scmimedata.h"
36 #include "scpaths.h"
37 #include "scribusXml.h"
38 #include "scribuscore.h"
39 #include "scribusdoc.h"
40 #include "scribusview.h"
41 #include "sctextstream.h"
42 #include "selection.h"
43 #include "ui/customfdialog.h"
44 #include "ui/missing.h"
45 #include "ui/multiprogressdialog.h"
46 #include "ui/propertiespalette.h"
47 #include "undomanager.h"
48 #include "units.h"
49 #include "util.h"
50 #include "util_formats.h"
51 #include "util_math.h"
52
ShapePlug(ScribusDoc * doc,int flags)53 ShapePlug::ShapePlug(ScribusDoc* doc, int flags)
54 {
55 tmpSel=new Selection(this, false);
56 m_Doc=doc;
57 importerFlags = flags;
58 interactive = (flags & LoadSavePlugin::lfInteractive);
59 progressDialog = nullptr;
60 }
61
readThumbnail(const QString & fName)62 QImage ShapePlug::readThumbnail(const QString& fName)
63 {
64 QFileInfo fi = QFileInfo(fName);
65 baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath()+"/"));
66 double b = 0.0, h = 0.0;
67 parseHeader(fName, b, h);
68 if (b == 0.0)
69 b = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
70 if (h == 0.0)
71 h = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
72 docWidth = b;
73 docHeight = h;
74 progressDialog = nullptr;
75 m_Doc = new ScribusDoc();
76 m_Doc->setup(0, 1, 1, 1, 1, "Custom", "Custom");
77 m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
78 m_Doc->addPage(0);
79 m_Doc->setGUI(false, ScCore->primaryMainWindow(), nullptr);
80 baseX = m_Doc->currentPage()->xOffset();
81 baseY = m_Doc->currentPage()->yOffset();
82 Elements.clear();
83 m_Doc->setLoading(true);
84 m_Doc->DoDrawing = false;
85 m_Doc->scMW()->setScriptRunning(true);
86 QString CurDirP = QDir::currentPath();
87 QDir::setCurrent(fi.path());
88 if (convert(fName))
89 {
90 tmpSel->clear();
91 QDir::setCurrent(CurDirP);
92 if (Elements.count() > 1)
93 m_Doc->groupObjectsList(Elements);
94 m_Doc->DoDrawing = true;
95 m_Doc->m_Selection->delaySignalsOn();
96 QImage tmpImage;
97 if (Elements.count() > 0)
98 {
99 for (int dre=0; dre<Elements.count(); ++dre)
100 {
101 tmpSel->addItem(Elements.at(dre), true);
102 }
103 tmpSel->setGroupRect();
104 double xs = tmpSel->width();
105 double ys = tmpSel->height();
106 tmpImage = Elements.at(0)->DrawObj_toImage(500);
107 tmpImage.setText("XSize", QString("%1").arg(xs));
108 tmpImage.setText("YSize", QString("%1").arg(ys));
109 }
110 m_Doc->scMW()->setScriptRunning(false);
111 m_Doc->setLoading(false);
112 m_Doc->m_Selection->delaySignalsOff();
113 delete m_Doc;
114 return tmpImage;
115 }
116 QDir::setCurrent(CurDirP);
117 m_Doc->DoDrawing = true;
118 m_Doc->scMW()->setScriptRunning(false);
119 delete m_Doc;
120 return QImage();
121 }
122
import(const QString & fNameIn,const TransactionSettings & trSettings,int flags,bool showProgress)123 bool ShapePlug::import(const QString& fNameIn, const TransactionSettings& trSettings, int flags, bool showProgress)
124 {
125 bool success = false;
126 interactive = (flags & LoadSavePlugin::lfInteractive);
127 importerFlags = flags;
128 cancel = false;
129 // double x, y, b, h;
130 double b, h;
131 bool ret = false;
132 QFileInfo fi = QFileInfo(fNameIn);
133 if ( !ScCore->usingGUI() )
134 {
135 interactive = false;
136 showProgress = false;
137 }
138 baseFile = QDir::cleanPath(QDir::toNativeSeparators(fi.absolutePath()+"/"));
139 if ( showProgress )
140 {
141 ScribusMainWindow* mw=(m_Doc==nullptr) ? ScCore->primaryMainWindow() : m_Doc->scMW();
142 progressDialog = new MultiProgressDialog( tr("Importing: %1").arg(fi.fileName()), CommonStrings::tr_Cancel, mw );
143 QStringList barNames, barTexts;
144 barNames << "GI";
145 barTexts << tr("Analyzing File:");
146 QList<bool> barsNumeric;
147 barsNumeric << false;
148 progressDialog->addExtraProgressBars(barNames, barTexts, barsNumeric);
149 progressDialog->setOverallTotalSteps(3);
150 progressDialog->setOverallProgress(0);
151 progressDialog->setProgress("GI", 0);
152 progressDialog->show();
153 connect(progressDialog, SIGNAL(canceled()), this, SLOT(cancelRequested()));
154 qApp->processEvents();
155 }
156 else
157 progressDialog = nullptr;
158 /* Set default Page to size defined in Preferences */
159 // x = 0.0;
160 // y = 0.0;
161 b = 0.0;
162 h = 0.0;
163 if (progressDialog)
164 {
165 progressDialog->setOverallProgress(1);
166 qApp->processEvents();
167 }
168 parseHeader(fNameIn, b, h);
169 if (b == 0.0)
170 b = PrefsManager::instance().appPrefs.docSetupPrefs.pageWidth;
171 if (h == 0.0)
172 h = PrefsManager::instance().appPrefs.docSetupPrefs.pageHeight;
173 docWidth = b;
174 docHeight = h;
175 baseX = 0;
176 baseY = 0;
177 if (!interactive || (flags & LoadSavePlugin::lfInsertPage))
178 {
179 m_Doc->setPage(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false);
180 m_Doc->addPage(0);
181 m_Doc->view()->addPage(0, true);
182 baseX = 0;
183 baseY = 0;
184 }
185 else
186 {
187 if (!m_Doc || (flags & LoadSavePlugin::lfCreateDoc))
188 {
189 m_Doc=ScCore->primaryMainWindow()->doFileNew(docWidth, docHeight, 0, 0, 0, 0, 0, 0, false, false, 0, false, 0, 1, "Custom", true);
190 ScCore->primaryMainWindow()->HaveNewDoc();
191 ret = true;
192 baseX = 0;
193 baseY = 0;
194 baseX = m_Doc->currentPage()->xOffset();
195 baseY = m_Doc->currentPage()->yOffset();
196 }
197 }
198 if ((!ret) && (interactive))
199 {
200 baseX = m_Doc->currentPage()->xOffset();
201 baseY = m_Doc->currentPage()->yOffset();
202 }
203 if ((ret) || (!interactive))
204 {
205 if (docWidth > docHeight)
206 m_Doc->setPageOrientation(1);
207 else
208 m_Doc->setPageOrientation(0);
209 m_Doc->setPageSize("Custom");
210 }
211 if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
212 m_Doc->view()->deselectItems();
213 Elements.clear();
214 m_Doc->setLoading(true);
215 m_Doc->DoDrawing = false;
216 if ((!(flags & LoadSavePlugin::lfLoadAsPattern)) && (m_Doc->view() != nullptr))
217 m_Doc->view()->updatesOn(false);
218 m_Doc->scMW()->setScriptRunning(true);
219 qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
220 QString CurDirP = QDir::currentPath();
221 QDir::setCurrent(fi.path());
222 if (convert(fNameIn))
223 {
224 tmpSel->clear();
225 QDir::setCurrent(CurDirP);
226 if ((Elements.count() > 1) && (!(importerFlags & LoadSavePlugin::lfCreateDoc)))
227 m_Doc->groupObjectsList(Elements);
228 m_Doc->DoDrawing = true;
229 m_Doc->scMW()->setScriptRunning(false);
230 m_Doc->setLoading(false);
231 qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
232 if ((Elements.count() > 0) && (!ret) && (interactive))
233 {
234 if (flags & LoadSavePlugin::lfScripted)
235 {
236 bool loadF = m_Doc->isLoading();
237 m_Doc->setLoading(false);
238 m_Doc->changed();
239 m_Doc->setLoading(loadF);
240 if (!(flags & LoadSavePlugin::lfLoadAsPattern))
241 {
242 m_Doc->m_Selection->delaySignalsOn();
243 for (int dre=0; dre<Elements.count(); ++dre)
244 {
245 m_Doc->m_Selection->addItem(Elements.at(dre), true);
246 }
247 m_Doc->m_Selection->delaySignalsOff();
248 m_Doc->m_Selection->setGroupRect();
249 if (m_Doc->view() != nullptr)
250 m_Doc->view()->updatesOn(true);
251 }
252 }
253 else
254 {
255 m_Doc->DragP = true;
256 m_Doc->DraggedElem = nullptr;
257 m_Doc->DragElements.clear();
258 m_Doc->m_Selection->delaySignalsOn();
259 for (int dre=0; dre<Elements.count(); ++dre)
260 {
261 tmpSel->addItem(Elements.at(dre), true);
262 }
263 tmpSel->setGroupRect();
264 ScElemMimeData* md = ScriXmlDoc::writeToMimeData(m_Doc, tmpSel);
265 m_Doc->itemSelection_DeleteItem(tmpSel);
266 m_Doc->view()->updatesOn(true);
267 m_Doc->m_Selection->delaySignalsOff();
268 // We must copy the TransationSettings object as it is owned
269 // by handleObjectImport method afterwards
270 TransactionSettings* transacSettings = new TransactionSettings(trSettings);
271 m_Doc->view()->handleObjectImport(md, transacSettings);
272 m_Doc->DragP = false;
273 m_Doc->DraggedElem = nullptr;
274 m_Doc->DragElements.clear();
275 }
276 }
277 else
278 {
279 m_Doc->changed();
280 m_Doc->reformPages();
281 if (!(flags & LoadSavePlugin::lfLoadAsPattern))
282 m_Doc->view()->updatesOn(true);
283 }
284 success = true;
285 }
286 else
287 {
288 QDir::setCurrent(CurDirP);
289 m_Doc->DoDrawing = true;
290 m_Doc->scMW()->setScriptRunning(false);
291 if (!(flags & LoadSavePlugin::lfLoadAsPattern))
292 m_Doc->view()->updatesOn(true);
293 qApp->changeOverrideCursor(QCursor(Qt::ArrowCursor));
294 }
295 if (interactive)
296 m_Doc->setLoading(false);
297 //CB If we have a gui we must refresh it if we have used the progressbar
298 if (!(flags & LoadSavePlugin::lfLoadAsPattern))
299 {
300 if ((showProgress) && (!interactive))
301 m_Doc->view()->DrawNew();
302 }
303 qApp->restoreOverrideCursor();
304 return success;
305 }
306
~ShapePlug()307 ShapePlug::~ShapePlug()
308 {
309 delete progressDialog;
310 delete tmpSel;
311 }
312
parseHeader(const QString & fName,double & b,double & h)313 void ShapePlug::parseHeader(const QString& fName, double &b, double &h)
314 {
315 QFile f(fName);
316 if (f.open(QIODevice::ReadOnly))
317 {
318 double minXCoor = 0.0;
319 double minYCoor = 0.0;
320 double maxXCoor = 0.0;
321 double maxYCoor = 0.0;
322 QDomDocument docu("scridoc");
323 docu.setContent(&f);
324 QDomElement elem = docu.documentElement();
325 QDomNodeList list = elem.elementsByTagName("svg:svg");
326 if (list.count() == 0)
327 return;
328 QDomElement svg = list.item(0).toElement();
329 QDomNode DOC = svg.firstChild();
330 Conversion = 1.0;
331 bool firstCheck = true;
332 parseGroupProperties(DOC, minXCoor, minYCoor, maxXCoor, maxYCoor, firstCheck);
333 b = maxXCoor - minXCoor;
334 h = maxYCoor - minYCoor;
335 Conversion = 100.0 / qMax(b, h);
336 b *= Conversion;
337 h *= Conversion;
338 f.close();
339 }
340 }
341
convert(const QString & fn)342 bool ShapePlug::convert(const QString& fn)
343 {
344 importedColors.clear();
345 QList<PageItem*> gElements;
346 groupStack.push(gElements);
347 if (progressDialog)
348 {
349 progressDialog->setOverallProgress(2);
350 progressDialog->setLabel("GI", tr("Generating Items"));
351 qApp->processEvents();
352 }
353 QFile f(fn);
354 if (f.open(QIODevice::ReadOnly))
355 {
356 QDomDocument docu("scridoc");
357 docu.setContent(&f);
358 QDomElement elem = docu.documentElement();
359 if (elem.tagName() != "shape")
360 return false;
361 QDomNodeList list = elem.elementsByTagName("svg:svg");
362 if (list.count() == 0)
363 return false;
364 QDomElement svg = list.item(0).toElement();
365 QDomNode DOC = svg.firstChild();
366 parseGroup(DOC);
367 if (Elements.count() == 0)
368 {
369 if (importedColors.count() != 0)
370 {
371 for (int cd = 0; cd < importedColors.count(); cd++)
372 {
373 m_Doc->PageColors.remove(importedColors[cd]);
374 }
375 }
376 }
377 f.close();
378 }
379 if (progressDialog)
380 progressDialog->close();
381 return true;
382 }
383
finishItem(PageItem * ite)384 void ShapePlug::finishItem(PageItem* ite)
385 {
386 ite->ClipEdited = true;
387 ite->FrameType = 3;
388 ite->setFillShade(100);
389 ite->setLineShade(100);
390 ite->setTextFlowMode(PageItem::TextFlowDisabled);
391 ite->PoLine.translate(m_Doc->currentPage()->xOffset(), m_Doc->currentPage()->yOffset());
392 m_Doc->adjustItemSize(ite);
393 ite->OldB2 = ite->width();
394 ite->OldH2 = ite->height();
395 ite->updateClip();
396 Elements.append(ite);
397 if (groupStack.count() > 0)
398 groupStack.top().append(ite);
399 }
400
parseGroup(QDomNode & DOC)401 void ShapePlug::parseGroup(QDomNode &DOC)
402 {
403 QString FillCol = "White";
404 QString StrokeCol = "Black";
405 QString defFillCol = "White";
406 QString defStrokeCol = "Black";
407 QColor stroke = Qt::black;
408 QColor fill = Qt::white;
409 // Qt::PenStyle Dash = Qt::SolidLine;
410 Qt::PenCapStyle LineEnd = Qt::FlatCap;
411 Qt::PenJoinStyle LineJoin = Qt::MiterJoin;
412 // int fillStyle = 1;
413 double strokewidth = 0.1;
414 // bool poly = false;
415 while (!DOC.isNull())
416 {
417 double x1, y1, x2, y2;
418 StrokeCol = defStrokeCol;
419 FillCol = defFillCol;
420 stroke = Qt::black;
421 fill = Qt::white;
422 // fillStyle = 1;
423 strokewidth = 1.0;
424 // Dash = Qt::SolidLine;
425 LineEnd = Qt::FlatCap;
426 LineJoin = Qt::MiterJoin;
427 FPointArray PoLine;
428 PoLine.resize(0);
429 QDomElement pg = DOC.toElement();
430 QString STag = pg.tagName();
431 QString style = pg.attribute( "style", "" ).simplified();
432 if (style.isEmpty())
433 style = pg.attribute( "svg:style", "" ).simplified();
434 QStringList substyles = style.split(';', Qt::SkipEmptyParts);
435 for (QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it)
436 {
437 QStringList substyle = (*it).split(':', Qt::SkipEmptyParts);
438 QString command(substyle[0].trimmed());
439 QString params(substyle[1].trimmed());
440 if (command == "fill")
441 {
442 if (!((params == "foreground") || (params == "background") || (params == "fg") || (params == "bg") || (params == "none") || (params == "default") || (params == "inverse")))
443 {
444 if (params == "nofill")
445 FillCol = CommonStrings::None;
446 else
447 {
448 fill.setNamedColor( params );
449 FillCol = "FromDia"+fill.name();
450 ScColor tmp;
451 tmp.fromQColor(fill);
452 tmp.setSpotColor(false);
453 tmp.setRegistrationColor(false);
454 QString fNam = m_Doc->PageColors.tryAddColor(FillCol, tmp);
455 if (fNam == FillCol)
456 importedColors.append(FillCol);
457 FillCol = fNam;
458 }
459 }
460 }
461 else if (command == "stroke")
462 {
463 if (!((params == "foreground") || (params == "background") || (params == "fg") || (params == "bg") || (params == "none") || (params == "default")) || (params == "inverse"))
464 {
465 stroke.setNamedColor( params );
466 StrokeCol = "FromDia"+stroke.name();
467 ScColor tmp;
468 tmp.fromQColor(stroke);
469 tmp.setSpotColor(false);
470 tmp.setRegistrationColor(false);
471 QString fNam = m_Doc->PageColors.tryAddColor(StrokeCol, tmp);
472 if (fNam == StrokeCol)
473 importedColors.append(StrokeCol);
474 StrokeCol = fNam;
475 }
476 }
477 else if (command == "stroke-width")
478 strokewidth = ScCLocale::toDoubleC(params);
479 else if (command == "stroke-linejoin")
480 {
481 if (params == "miter")
482 LineJoin = Qt::MiterJoin;
483 else if (params == "round")
484 LineJoin = Qt::RoundJoin;
485 else if (params == "bevel")
486 LineJoin = Qt::BevelJoin;
487 }
488 else if (command == "stroke-linecap")
489 {
490 if (params == "butt")
491 LineEnd = Qt::FlatCap;
492 else if (params == "round")
493 LineEnd = Qt::RoundCap;
494 else if (params == "square")
495 LineEnd = Qt::SquareCap;
496 }
497 }
498 if (STag == "svg:line")
499 {
500 x1 = ScCLocale::toDoubleC(pg.attribute("x1")) * Conversion;
501 y1 = ScCLocale::toDoubleC(pg.attribute("y1")) * Conversion;
502 x2 = ScCLocale::toDoubleC(pg.attribute("x2")) * Conversion;
503 y2 = ScCLocale::toDoubleC(pg.attribute("y2")) * Conversion;
504 PoLine.addPoint(x1, y1);
505 PoLine.addPoint(x1, y1);
506 PoLine.addPoint(x2, y2);
507 PoLine.addPoint(x2, y2);
508 int z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, strokewidth, CommonStrings::None, StrokeCol);
509 m_Doc->Items->at(z)->PoLine = PoLine.copy();
510 finishItem(m_Doc->Items->at(z));
511 }
512 else if (STag == "svg:rect")
513 {
514 x1 = ScCLocale::toDoubleC(pg.attribute("x")) * Conversion;
515 y1 = ScCLocale::toDoubleC(pg.attribute("y")) * Conversion;
516 x2 = ScCLocale::toDoubleC(pg.attribute("width")) * Conversion;
517 y2 = ScCLocale::toDoubleC(pg.attribute("height")) * Conversion;
518 int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Rectangle, baseX + x1, baseY + y1, x2, y2, strokewidth, FillCol, StrokeCol);
519 m_Doc->Items->at(z)->setLineJoin(LineJoin);
520 m_Doc->Items->at(z)->setLineEnd(LineEnd);
521 finishItem(m_Doc->Items->at(z));
522 }
523 else if ((STag == "svg:polygon") || (STag == "svg:polyline"))
524 {
525 bool bFirst = true;
526 double x = 0.0;
527 double y = 0.0;
528 QString points = pg.attribute( "points" ).simplified().replace(',', " ");
529 QStringList pointList = points.split(' ', Qt::SkipEmptyParts);
530 FirstM = true;
531 for (QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++)
532 {
533 x = ScCLocale::toDoubleC(*(it++));
534 y = ScCLocale::toDoubleC(*it);
535 if (bFirst)
536 {
537 svgMoveTo(x * Conversion, y * Conversion);
538 bFirst = false;
539 WasM = true;
540 }
541 else
542 {
543 svgLineTo(&PoLine, x * Conversion, y * Conversion);
544 }
545 }
546 if (STag == "svg:polygon")
547 svgClosePath(&PoLine);
548 if (PoLine.size() < 4)
549 {
550 DOC = DOC.nextSibling();
551 continue;
552 }
553 int z;
554 if (STag == "svg:polygon")
555 z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, strokewidth, FillCol, StrokeCol);
556 else
557 z = m_Doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, baseX, baseY, 10, 10, strokewidth, CommonStrings::None, StrokeCol);
558 m_Doc->Items->at(z)->PoLine = PoLine.copy();
559 finishItem(m_Doc->Items->at(z));
560 }
561 else if ((STag == "svg:circle") || (STag == "svg:ellipse"))
562 {
563 x1 = ScCLocale::toDoubleC(pg.attribute("r")) * Conversion;
564 y1 = ScCLocale::toDoubleC(pg.attribute("r")) * Conversion;
565 x2 = ScCLocale::toDoubleC(pg.attribute("cx")) * Conversion - x1;
566 y2 = ScCLocale::toDoubleC(pg.attribute("cy")) * Conversion - y1;
567 x1 *= 2.0;
568 y1 *= 2.0;
569 int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Ellipse, baseX + x1, baseY + y1, x2, y2, strokewidth, FillCol, StrokeCol);
570 m_Doc->Items->at(z)->setLineJoin(LineJoin);
571 m_Doc->Items->at(z)->setLineEnd(LineEnd);
572 finishItem(m_Doc->Items->at(z));
573 }
574 else if (STag == "svg:path")
575 {
576 // poly =
577 parseSVG( pg.attribute( "d" ), &PoLine );
578 if (PoLine.size() < 4)
579 {
580 DOC = DOC.nextSibling();
581 continue;
582 }
583 int z = m_Doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, baseX, baseY, 10, 10, strokewidth, FillCol, StrokeCol);
584 m_Doc->Items->at(z)->PoLine = PoLine.copy();
585 finishItem(m_Doc->Items->at(z));
586 }
587 else if (STag == "svg:g")
588 {
589 int z = m_Doc->itemAdd(PageItem::Group, PageItem::Rectangle, baseX, baseX, 1, 1, 0, CommonStrings::None, CommonStrings::None);
590 PageItem *neu = m_Doc->Items->at(z);
591 Elements.append(neu);
592 if (groupStack.count() > 0)
593 groupStack.top().append(neu);
594 QList<PageItem*> gElements;
595 groupStack.push(gElements);
596 QDomNode child = DOC.firstChild();
597 parseGroup(child);
598 if (gElements.count() == 0)
599 {
600 groupStack.pop();
601 Elements.removeAll(neu);
602 groupStack.top().removeAll(neu);
603 Selection tmpSelection(m_Doc, false);
604 tmpSelection.addItem(neu);
605 m_Doc->itemSelection_DeleteItem(&tmpSelection);
606 }
607 else
608 {
609 QList<PageItem*> gElem = groupStack.pop();
610 double minx = std::numeric_limits<double>::max();
611 double miny = std::numeric_limits<double>::max();
612 double maxx = -std::numeric_limits<double>::max();
613 double maxy = -std::numeric_limits<double>::max();
614 for (int gr = 0; gr < gElements.count(); ++gr)
615 {
616 PageItem* currItem = gElem.at(gr);
617 double x1, x2, y1, y2;
618 currItem->getVisualBoundingRect(&x1, &y1, &x2, &y2);
619 minx = qMin(minx, x1);
620 miny = qMin(miny, y1);
621 maxx = qMax(maxx, x2);
622 maxy = qMax(maxy, y2);
623 }
624 double gx = minx;
625 double gy = miny;
626 double gw = maxx - minx;
627 double gh = maxy - miny;
628 neu->setXYPos(gx, gy, true);
629 neu->setWidthHeight(gw, gh, true);
630 neu->SetRectFrame();
631 neu->Clip = flattenPath(neu->PoLine, neu->Segments);
632 neu->setItemName( tr("Group%1").arg(m_Doc->GroupCounter));
633 neu->AutoName = false;
634 neu->gXpos = neu->xPos() - gx;
635 neu->gYpos = neu->yPos() - gy;
636 neu->groupWidth = gw;
637 neu->groupHeight = gh;
638 for (int gr = 0; gr < gElem.count(); ++gr)
639 {
640 PageItem* currItem = gElem.at(gr);
641 currItem->gXpos = currItem->xPos() - gx;
642 currItem->gYpos = currItem->yPos() - gy;
643 currItem->gWidth = gw;
644 currItem->gHeight = gh;
645 currItem->Parent = neu;
646 neu->groupItemList.append(currItem);
647 m_Doc->Items->removeAll(currItem);
648 Elements.removeAll(currItem);
649 }
650 neu->setRedrawBounding();
651 neu->setTextFlowMode(PageItem::TextFlowDisabled);
652 m_Doc->GroupCounter++;
653 }
654 }
655 DOC = DOC.nextSibling();
656 }
657 }
658
parseGroupProperties(QDomNode & DOC,double & minXCoor,double & minYCoor,double & maxXCoor,double & maxYCoor,bool & firstCheck)659 void ShapePlug::parseGroupProperties(QDomNode &DOC, double &minXCoor, double &minYCoor, double &maxXCoor, double &maxYCoor, bool &firstCheck)
660 {
661 while (!DOC.isNull())
662 {
663 double x1, y1, x2, y2;
664 FPointArray PoLine;
665 PoLine.resize(0);
666 QDomElement pg = DOC.toElement();
667 QString STag = pg.tagName();
668 if (STag == "svg:line")
669 {
670 x1 = ScCLocale::toDoubleC(pg.attribute("x1")) * Conversion;
671 y1 = ScCLocale::toDoubleC(pg.attribute("y1")) * Conversion;
672 x2 = ScCLocale::toDoubleC(pg.attribute("x2")) * Conversion;
673 y2 = ScCLocale::toDoubleC(pg.attribute("y2")) * Conversion;
674 PoLine.addPoint(x1, y1);
675 PoLine.addPoint(x1, y1);
676 PoLine.addPoint(x2, y2);
677 PoLine.addPoint(x2, y2);
678 }
679 else if (STag == "svg:rect")
680 {
681 x1 = ScCLocale::toDoubleC(pg.attribute("x")) * Conversion;
682 y1 = ScCLocale::toDoubleC(pg.attribute("y")) * Conversion;
683 x2 = ScCLocale::toDoubleC(pg.attribute("width")) * Conversion;
684 y2 = ScCLocale::toDoubleC(pg.attribute("height")) * Conversion;
685 static double rect[] = {0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0,
686 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0,
687 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0};
688 for (int a = 0; a < 29; a += 4)
689 {
690 double xa = x2 * rect[a];
691 double ya = y2 * rect[a+1];
692 double xb = x2 * rect[a+2];
693 double yb = y2 * rect[a+3];
694 PoLine.addPoint(x1+xa, y1+ya);
695 PoLine.addPoint(x1+xb, y1+yb);
696 }
697 }
698 else if ((STag == "svg:polygon") || (STag == "svg:polyline"))
699 {
700 bool bFirst = true;
701 double x = 0.0;
702 double y = 0.0;
703 QString points = pg.attribute( "points" ).simplified().replace(',', " ");
704 QStringList pointList = points.split(' ', Qt::SkipEmptyParts);
705 FirstM = true;
706 for (QStringList::Iterator it1 = pointList.begin(); it1 != pointList.end(); it1++)
707 {
708 x = ScCLocale::toDoubleC(*(it1++));
709 y = ScCLocale::toDoubleC(*it1);
710 if (bFirst)
711 {
712 svgMoveTo(x * Conversion, y * Conversion);
713 bFirst = false;
714 WasM = true;
715 }
716 else
717 {
718 svgLineTo(&PoLine, x * Conversion, y * Conversion);
719 }
720 }
721 if (STag == "svg:polygon")
722 svgClosePath(&PoLine);
723 if (PoLine.size() < 4)
724 {
725 DOC = DOC.nextSibling();
726 continue;
727 }
728 }
729 else if (STag == "svg:circle")
730 {
731 x1 = ScCLocale::toDoubleC(pg.attribute("r")) * Conversion;
732 y1 = ScCLocale::toDoubleC(pg.attribute("r")) * Conversion;
733 x2 = ScCLocale::toDoubleC(pg.attribute("cx")) * Conversion - x1;
734 y2 = ScCLocale::toDoubleC(pg.attribute("cy")) * Conversion - y1;
735 x1 *= 2.0;
736 y1 *= 2.0;
737 static double rect[] = {1.0, 0.5, 1.0, 0.77615235,0.5, 1.0, 0.77615235, 1.0,
738 0.5, 1.0, 0.22385765, 1.0, 0.0, 0.5, 0.0, 0.77615235,
739 0.0, 0.5, 0.0, 0.22385765, 0.5, 0.0, 0.22385765, 0.0,
740 0.5, 0.0, 0.77615235, 0.0, 1.0, 0.5, 1.0, 0.22385765};
741 for (int a = 0; a < 29; a += 4)
742 {
743 double xa = x1 * rect[a];
744 double ya = y1 * rect[a+1];
745 double xb = x1 * rect[a+2];
746 double yb = y1 * rect[a+3];
747 PoLine.addPoint(x2+xa, y2+ya);
748 PoLine.addPoint(x2+xb, y2+yb);
749 }
750 }
751 else if (STag == "svg:ellipse")
752 {
753 x1 = ScCLocale::toDoubleC(pg.attribute("rx")) * Conversion;
754 y1 = ScCLocale::toDoubleC(pg.attribute("ry")) * Conversion;
755 x2 = ScCLocale::toDoubleC(pg.attribute("cx")) * Conversion - x1;
756 y2 = ScCLocale::toDoubleC(pg.attribute("cy")) * Conversion - y1;
757 x1 *= 2.0;
758 y1 *= 2.0;
759 static double rect[] = {1.0, 0.5, 1.0, 0.77615235,0.5, 1.0, 0.77615235, 1.0,
760 0.5, 1.0, 0.22385765, 1.0, 0.0, 0.5, 0.0, 0.77615235,
761 0.0, 0.5, 0.0, 0.22385765, 0.5, 0.0, 0.22385765, 0.0,
762 0.5, 0.0, 0.77615235, 0.0, 1.0, 0.5, 1.0, 0.22385765};
763 for (int a = 0; a < 29; a += 4)
764 {
765 double xa = x1 * rect[a];
766 double ya = y1 * rect[a+1];
767 double xb = x1 * rect[a+2];
768 double yb = y1 * rect[a+3];
769 PoLine.addPoint(x2+xa, y2+ya);
770 PoLine.addPoint(x2+xb, y2+yb);
771 }
772 }
773 else if (STag == "svg:path")
774 {
775 parseSVG( pg.attribute( "d" ), &PoLine );
776 if (PoLine.size() < 4)
777 {
778 DOC = DOC.nextSibling();
779 continue;
780 }
781 }
782 else if (STag == "svg:g")
783 {
784 QDomNode child = DOC.firstChild();
785 parseGroupProperties(child, minXCoor, minYCoor, maxXCoor, maxYCoor, firstCheck);
786 }
787 if (PoLine.size() < 4)
788 {
789 DOC = DOC.nextSibling();
790 continue;
791 }
792 FPoint tp2(getMinClipF(&PoLine));
793 PoLine.translate(-tp2.x(), -tp2.y());
794 FPoint wh(getMaxClipF(&PoLine));
795 if (firstCheck)
796 {
797 minXCoor = tp2.x();
798 minYCoor = tp2.y();
799 maxXCoor = tp2.x() + wh.x();
800 maxYCoor = tp2.y() + wh.y();
801 firstCheck = false;
802 }
803 else
804 {
805 minXCoor = qMin(minXCoor, tp2.x());
806 minYCoor = qMin(minYCoor, tp2.y());
807 maxXCoor = qMax(maxXCoor, tp2.x() + wh.x());
808 maxYCoor = qMax(maxYCoor, tp2.y() + wh.y());
809 }
810 DOC = DOC.nextSibling();
811 }
812 }
813
parseUnit(const QString & unit)814 double ShapePlug::parseUnit(const QString &unit)
815 {
816 QString sCM(unitGetUntranslatedStrFromIndex(SC_CM));
817 QString sMM(unitGetUntranslatedStrFromIndex(SC_MM));
818 QString sIN(unitGetUntranslatedStrFromIndex(SC_IN));
819 QString sPT(unitGetUntranslatedStrFromIndex(SC_PT));
820 QString sPX("px");
821
822 bool noUnit = false;
823 QString unitval(unit);
824 if (unit.right( 2 ) == sPT)
825 unitval.replace( sPT, "" );
826 else if (unit.right( 2 ) == sCM)
827 unitval.replace( sCM, "" );
828 else if (unit.right( 2 ) == sMM)
829 unitval.replace( sMM , "" );
830 else if (unit.right( 2 ) == sIN)
831 unitval.replace( sIN, "" );
832 else if (unit.right( 2 ) == sPX)
833 unitval.replace( sPX, "" );
834 if (unitval == unit)
835 noUnit = true;
836 double value = ScCLocale::toDoubleC(unitval);
837 if (unit.right( 2 ) == sPT)
838 {}/* value = value; */ //no change
839 else if (unit.right( 2 ) == sCM)
840 {
841 value = cm2pts(value);
842 Conversion = 1/unitGetRatioFromIndex(SC_CM);
843 }
844 else if (unit.right( 2 ) == sMM)
845 {
846 value = mm2pts(value);
847 Conversion = 1/unitGetRatioFromIndex(SC_MM);
848 }
849 else if (unit.right( 2 ) == sIN)
850 {
851 value = in2pts(value);
852 Conversion = 1/unitGetRatioFromIndex(SC_IN);
853 }
854 else if (unit.right( 2 ) == sPX)
855 {
856 value = value * 0.8;
857 Conversion = 0.8;
858 }
859 else if (noUnit)
860 {}/* value = value; */ //no change
861 return value;
862 }
863
getCoord(const char * ptr,double & number)864 const char * ShapePlug::getCoord( const char *ptr, double &number )
865 {
866 int integer, exponent;
867 double decimal, frac;
868 int sign, expsign;
869
870 exponent = 0;
871 integer = 0;
872 frac = 1.0;
873 decimal = 0;
874 sign = 1;
875 expsign = 1;
876
877 // read the sign
878 if (*ptr == '+')
879 ptr++;
880 else if (*ptr == '-')
881 {
882 ptr++;
883 sign = -1;
884 }
885
886 // read the integer part
887 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
888 integer = (integer * 10) + *(ptr++) - '0';
889 if (*ptr == '.') // read the decimals
890 {
891 ptr++;
892 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
893 decimal += (*(ptr++) - '0') * (frac *= 0.1);
894 }
895
896 if (*ptr == 'e' || *ptr == 'E') // read the exponent part
897 {
898 ptr++;
899
900 // read the sign of the exponent
901 if (*ptr == '+')
902 ptr++;
903 else if (*ptr == '-')
904 {
905 ptr++;
906 expsign = -1;
907 }
908
909 exponent = 0;
910 while (*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
911 {
912 exponent *= 10;
913 exponent += *ptr - '0';
914 ptr++;
915 }
916 }
917 number = integer + decimal;
918 number *= sign * pow( static_cast<double>(10), static_cast<double>( expsign * exponent ) );
919 // skip the following space
920 if (*ptr == ' ')
921 ptr++;
922
923 return ptr;
924 }
925
parseSVG(const QString & s,FPointArray * ite)926 bool ShapePlug::parseSVG( const QString &s, FPointArray *ite )
927 {
928 QString d = s;
929 d = d.replace( QRegExp( "," ), " ");
930 bool ret = false;
931 if (!d.isEmpty())
932 {
933 d = d.simplified();
934 QByteArray pathData = d.toLatin1();
935 const char *ptr = pathData.constData();
936 const char *end = pathData.constData() + pathData.length() + 1;
937 double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
938 double px1, py1, px2, py2, px3, py3;
939 bool relative;
940 FirstM = true;
941 char command = *(ptr++), lastCommand = ' ';
942 subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
943 while (ptr < end)
944 {
945 if (*ptr == ' ')
946 ptr++;
947 relative = false;
948 switch (command)
949 {
950 case 'm':
951 relative = true;
952 case 'M':
953 {
954 ptr = getCoord( ptr, tox );
955 ptr = getCoord( ptr, toy );
956 tox *= Conversion;
957 toy *= Conversion;
958 WasM = true;
959 subpathx = curx = relative ? curx + tox : tox;
960 subpathy = cury = relative ? cury + toy : toy;
961 svgMoveTo(curx, cury );
962 break;
963 }
964 case 'l':
965 relative = true;
966 case 'L':
967 {
968 ptr = getCoord( ptr, tox );
969 ptr = getCoord( ptr, toy );
970 tox *= Conversion;
971 toy *= Conversion;
972 curx = relative ? curx + tox : tox;
973 cury = relative ? cury + toy : toy;
974 svgLineTo(ite, curx, cury );
975 break;
976 }
977 case 'h':
978 {
979 ptr = getCoord( ptr, tox );
980 tox *= Conversion;
981 curx = curx + tox;
982 svgLineTo(ite, curx, cury );
983 break;
984 }
985 case 'H':
986 {
987 ptr = getCoord( ptr, tox );
988 tox *= Conversion;
989 curx = tox;
990 svgLineTo(ite, curx, cury );
991 break;
992 }
993 case 'v':
994 {
995 ptr = getCoord( ptr, toy );
996 toy *= Conversion;
997 cury = cury + toy;
998 svgLineTo(ite, curx, cury );
999 break;
1000 }
1001 case 'V':
1002 {
1003 ptr = getCoord( ptr, toy );
1004 toy *= Conversion;
1005 cury = toy;
1006 svgLineTo(ite, curx, cury );
1007 break;
1008 }
1009 case 'z':
1010 case 'Z':
1011 {
1012 curx = subpathx;
1013 cury = subpathy;
1014 svgClosePath(ite);
1015 break;
1016 }
1017 case 'c':
1018 relative = true;
1019 case 'C':
1020 {
1021 ptr = getCoord( ptr, x1 );
1022 ptr = getCoord( ptr, y1 );
1023 ptr = getCoord( ptr, x2 );
1024 ptr = getCoord( ptr, y2 );
1025 ptr = getCoord( ptr, tox );
1026 ptr = getCoord( ptr, toy );
1027 tox *= Conversion;
1028 toy *= Conversion;
1029 x1 *= Conversion;
1030 y1 *= Conversion;
1031 x2 *= Conversion;
1032 y2 *= Conversion;
1033 px1 = relative ? curx + x1 : x1;
1034 py1 = relative ? cury + y1 : y1;
1035 px2 = relative ? curx + x2 : x2;
1036 py2 = relative ? cury + y2 : y2;
1037 px3 = relative ? curx + tox : tox;
1038 py3 = relative ? cury + toy : toy;
1039 svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1040 contrlx = relative ? curx + x2 : x2;
1041 contrly = relative ? cury + y2 : y2;
1042 curx = relative ? curx + tox : tox;
1043 cury = relative ? cury + toy : toy;
1044 break;
1045 }
1046 case 's':
1047 relative = true;
1048 case 'S':
1049 {
1050 ptr = getCoord( ptr, x2 );
1051 ptr = getCoord( ptr, y2 );
1052 ptr = getCoord( ptr, tox );
1053 ptr = getCoord( ptr, toy );
1054 tox *= Conversion;
1055 toy *= Conversion;
1056 x2 *= Conversion;
1057 y2 *= Conversion;
1058 px1 = 2 * curx - contrlx;
1059 py1 = 2 * cury - contrly;
1060 px2 = relative ? curx + x2 : x2;
1061 py2 = relative ? cury + y2 : y2;
1062 px3 = relative ? curx + tox : tox;
1063 py3 = relative ? cury + toy : toy;
1064 svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1065 contrlx = relative ? curx + x2 : x2;
1066 contrly = relative ? cury + y2 : y2;
1067 curx = relative ? curx + tox : tox;
1068 cury = relative ? cury + toy : toy;
1069 break;
1070 }
1071 case 'q':
1072 relative = true;
1073 case 'Q':
1074 {
1075 ptr = getCoord( ptr, x1 );
1076 ptr = getCoord( ptr, y1 );
1077 ptr = getCoord( ptr, tox );
1078 ptr = getCoord( ptr, toy );
1079 tox *= Conversion;
1080 toy *= Conversion;
1081 x1 *= Conversion;
1082 y1 *= Conversion;
1083 px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
1084 py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
1085 px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
1086 py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
1087 px3 = relative ? curx + tox : tox;
1088 py3 = relative ? cury + toy : toy;
1089 svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1090 contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0);
1091 contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0);
1092 curx = relative ? curx + tox : tox;
1093 cury = relative ? cury + toy : toy;
1094 break;
1095 }
1096 case 't':
1097 relative = true;
1098 case 'T':
1099 {
1100 ptr = getCoord(ptr, tox);
1101 ptr = getCoord(ptr, toy);
1102 tox *= Conversion;
1103 toy *= Conversion;
1104 xc = 2 * curx - contrlx;
1105 yc = 2 * cury - contrly;
1106 px1 = relative ? (curx + 2 * xc) * (1.0 / 3.0) : (curx + 2 * xc) * (1.0 / 3.0);
1107 py1 = relative ? (cury + 2 * yc) * (1.0 / 3.0) : (cury + 2 * yc) * (1.0 / 3.0);
1108 px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
1109 py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
1110 px3 = relative ? curx + tox : tox;
1111 py3 = relative ? cury + toy : toy;
1112 svgCurveToCubic(ite, px1, py1, px2, py2, px3, py3 );
1113 contrlx = xc;
1114 contrly = yc;
1115 curx = relative ? curx + tox : tox;
1116 cury = relative ? cury + toy : toy;
1117 break;
1118 }
1119 }
1120 lastCommand = command;
1121 if (*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
1122 {
1123 // there are still coords in this command
1124 if (command == 'M')
1125 command = 'L';
1126 else if (command == 'm')
1127 command = 'l';
1128 }
1129 else
1130 command = *(ptr++);
1131
1132 if (lastCommand != 'C' && lastCommand != 'c' &&
1133 lastCommand != 'S' && lastCommand != 's' &&
1134 lastCommand != 'Q' && lastCommand != 'q' &&
1135 lastCommand != 'T' && lastCommand != 't')
1136 {
1137 contrlx = curx;
1138 contrly = cury;
1139 }
1140 }
1141 if ((lastCommand != 'z') && (lastCommand != 'Z'))
1142 ret = true;
1143 if (ite->size() > 2)
1144 {
1145 if ((ite->point(0).x() == ite->point(ite->size()-2).x()) && (ite->point(0).y() == ite->point(ite->size()-2).y()))
1146 ret = false;
1147 }
1148 }
1149 return ret;
1150 }
1151
svgMoveTo(double x1,double y1)1152 void ShapePlug::svgMoveTo(double x1, double y1)
1153 {
1154 CurrX = x1;
1155 CurrY = y1;
1156 StartX = x1;
1157 StartY = y1;
1158 PathLen = 0;
1159 }
1160
svgLineTo(FPointArray * i,double x1,double y1)1161 void ShapePlug::svgLineTo(FPointArray *i, double x1, double y1)
1162 {
1163 if ((!FirstM) && (WasM))
1164 {
1165 i->setMarker();
1166 PathLen += 4;
1167 }
1168 FirstM = false;
1169 WasM = false;
1170 if (i->size() > 3)
1171 {
1172 const FPoint& b1 = i->point(i->size()-4);
1173 const FPoint& b2 = i->point(i->size()-3);
1174 const FPoint& b3 = i->point(i->size()-2);
1175 const FPoint& b4 = i->point(i->size()-1);
1176 FPoint n1 = FPoint(CurrX, CurrY);
1177 FPoint n2 = FPoint(x1, y1);
1178 if ((b1 == n1) && (b2 == n1) && (b3 == n2) && (b4 == n2))
1179 return;
1180 }
1181 i->addPoint(FPoint(CurrX, CurrY));
1182 i->addPoint(FPoint(CurrX, CurrY));
1183 i->addPoint(FPoint(x1, y1));
1184 i->addPoint(FPoint(x1, y1));
1185 CurrX = x1;
1186 CurrY = y1;
1187 PathLen += 4;
1188 }
1189
svgCurveToCubic(FPointArray * i,double x1,double y1,double x2,double y2,double x3,double y3)1190 void ShapePlug::svgCurveToCubic(FPointArray *i, double x1, double y1, double x2, double y2, double x3, double y3)
1191 {
1192 if ((!FirstM) && (WasM))
1193 {
1194 i->setMarker();
1195 PathLen += 4;
1196 }
1197 FirstM = false;
1198 WasM = false;
1199 if (PathLen > 3)
1200 {
1201 const FPoint& b1 = i->point(i->size()-4);
1202 const FPoint& b2 = i->point(i->size()-3);
1203 const FPoint& b3 = i->point(i->size()-2);
1204 const FPoint& b4 = i->point(i->size()-1);
1205 FPoint n1 = FPoint(CurrX, CurrY);
1206 FPoint n2 = FPoint(x1, y1);
1207 FPoint n3 = FPoint(x3, y3);
1208 FPoint n4 = FPoint(x2, y2);
1209 if ((b1 == n1) && (b2 == n2) && (b3 == n3) && (b4 == n4))
1210 return;
1211 }
1212 i->addPoint(FPoint(CurrX, CurrY));
1213 i->addPoint(FPoint(x1, y1));
1214 i->addPoint(FPoint(x3, y3));
1215 i->addPoint(FPoint(x2, y2));
1216 CurrX = x3;
1217 CurrY = y3;
1218 PathLen += 4;
1219 }
1220
svgClosePath(FPointArray * i)1221 void ShapePlug::svgClosePath(FPointArray *i)
1222 {
1223 if (PathLen > 2)
1224 {
1225 if ((PathLen == 4) || (i->point(i->size()-2).x() != StartX) || (i->point(i->size()-2).y() != StartY))
1226 {
1227 i->addPoint(i->point(i->size()-2));
1228 i->addPoint(i->point(i->size()-3));
1229 i->addPoint(FPoint(StartX, StartY));
1230 i->addPoint(FPoint(StartX, StartY));
1231 }
1232 }
1233 }
1234