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 xpsexport.cpp - description
9 -------------------
10 begin : Sun Nov 24 08:00:00 CEST 2013
11 copyright : (C) 2013 by Franz Schmid
12 email : Franz.Schmid@altmuehlnet.de
13 ***************************************************************************/
14
15 /***************************************************************************
16 * *
17 * This program is free software; you can redistribute it and/or modify *
18 * it under the terms of the GNU General Public License as published by *
19 * the Free Software Foundation; either version 2 of the License, or *
20 * (at your option) any later version. *
21 * *
22 ***************************************************************************/
23
24 #include <QBuffer>
25 #include <QByteArray>
26 #include <QComboBox>
27 #include <QDataStream>
28 #include <QFile>
29 #include <QList>
30 #include <QMessageBox>
31 #include <QScopedPointer>
32 #include <QTemporaryDir>
33 #include <QTextStream>
34 #include <QUuid>
35
36 #include "xpsexplugin.h"
37
38 #include "scconfig.h"
39 #include "canvas.h"
40 #include "cmsettings.h"
41 #include "commonstrings.h"
42 #include "pageitem_table.h"
43 #include "prefsmanager.h"
44 #include "prefsfile.h"
45 #include "prefscontext.h"
46 #include "scpage.h"
47 #include "scpattern.h"
48 #include "scribuscore.h"
49 #include "scribusdoc.h"
50 #include "scribusview.h"
51 #include "sctextstruct.h"
52 #include "tableutils.h"
53 #include "text/textlayoutpainter.h"
54 #include "util.h"
55 #include "ui/customfdialog.h"
56 #include "ui/guidemanager.h"
57 #include "ui/scmessagebox.h"
58 #include "sccolorengine.h"
59 #include "util_formats.h"
60 #include "util_math.h"
61 #include "third_party/zip/scribus_zip.h"
62 #include "text/boxes.h"
63
xpsexplugin_getPluginAPIVersion()64 int xpsexplugin_getPluginAPIVersion()
65 {
66 return PLUGIN_API_VERSION;
67 }
68
xpsexplugin_getPlugin()69 ScPlugin* xpsexplugin_getPlugin()
70 {
71 XPSExportPlugin* plug = new XPSExportPlugin();
72 Q_CHECK_PTR(plug);
73 return plug;
74 }
75
xpsexplugin_freePlugin(ScPlugin * plugin)76 void xpsexplugin_freePlugin(ScPlugin* plugin)
77 {
78 XPSExportPlugin* plug = qobject_cast<XPSExportPlugin*>(plugin);
79 Q_ASSERT(plug);
80 delete plug;
81 }
82
83 using namespace TableUtils;
84
XPSExportPlugin()85 XPSExportPlugin::XPSExportPlugin()
86 {
87 // Set action info in languageChange, so we only have to do
88 // it in one place.
89 languageChange();
90 }
91
~XPSExportPlugin()92 XPSExportPlugin::~XPSExportPlugin() {};
93
languageChange()94 void XPSExportPlugin::languageChange()
95 {
96 // Note that we leave the unused members unset. They'll be initialised
97 // with their default ctors during construction.
98 // Action name
99 m_actionInfo.name = "ExportAsXPS";
100 // Action text for menu, including accel
101 m_actionInfo.text = tr("Save as XPS...");
102 // Menu
103 m_actionInfo.menu = "FileExport";
104 m_actionInfo.enabledOnStartup = false;
105 m_actionInfo.needsNumObjects = -1;
106 }
107
fullTrName() const108 QString XPSExportPlugin::fullTrName() const
109 {
110 return QObject::tr("XPS Export");
111 }
112
getAboutData() const113 const ScActionPlugin::AboutData* XPSExportPlugin::getAboutData() const
114 {
115 AboutData* about = new AboutData;
116 about->authors = "Franz Schmid <franz@scribus.info>";
117 about->shortDescription = tr("Exports XPS Files");
118 about->description = tr("Exports the current document into an XPS file.");
119 about->license = "GPL";
120 Q_CHECK_PTR(about);
121 return about;
122 }
123
deleteAboutData(const AboutData * about) const124 void XPSExportPlugin::deleteAboutData(const AboutData* about) const
125 {
126 Q_ASSERT(about);
127 delete about;
128 }
129
run(ScribusDoc * doc,const QString & filename)130 bool XPSExportPlugin::run(ScribusDoc* doc, const QString& filename)
131 {
132 Q_ASSERT(filename.isEmpty());
133 QString fileName;
134 if (doc!=nullptr)
135 {
136 PrefsContext* prefs = PrefsManager::instance().prefsFile->getPluginContext("xpsex");
137 QString wdir = prefs->get("wdir", ".");
138 QScopedPointer<CustomFDialog> openDia( new CustomFDialog(doc->scMW(), wdir, QObject::tr("Save as"), QObject::tr("Microsoft XPS (*.xps *.XPS);;All Files (*)"), fdHidePreviewCheckBox) );
139
140 QFrame *Layout = new QFrame(openDia.data());
141 QHBoxLayout *Layout1 = new QHBoxLayout(Layout);
142 Layout1->setSpacing(6);
143 Layout1->setContentsMargins(0, 0, 0, 0);
144 QLabel *text = new QLabel(QObject::tr("Output Settings:"), Layout);
145 Layout1->addWidget(text);
146 QComboBox* compress = new QComboBox(Layout);
147 compress->addItem(QObject::tr("Low Resolution"));
148 compress->addItem(QObject::tr("Medium Resolution"));
149 compress->addItem(QObject::tr("High Resolution"));
150 Layout1->addWidget(compress);
151 QSpacerItem* spacer = new QSpacerItem( 2, 2, QSizePolicy::Expanding, QSizePolicy::Minimum );
152 Layout1->addItem( spacer );
153 compress->setCurrentIndex(1);
154 openDia->addWidgets(Layout);
155 QString fna;
156 if (doc->hasName)
157 {
158 QFileInfo fi(doc->documentFileName());
159 QString completeBaseName = fi.completeBaseName();
160 if (completeBaseName.endsWith(".xps", Qt::CaseInsensitive))
161 completeBaseName.chop(4);
162 wdir = QDir::fromNativeSeparators( fi.path() );
163 fna = QDir::fromNativeSeparators( fi.path() + "/" + completeBaseName + ".xps" );
164 }
165 else
166 {
167 wdir = QDir::fromNativeSeparators( wdir );
168 if (wdir.right(1) != "/")
169 fna = wdir + "/";
170 else
171 fna = wdir;
172 fna += doc->documentFileName() + ".xps";
173 }
174 openDia->setSelection(fna);
175 openDia->setExtension("xps");
176
177 if (!openDia->exec())
178 return true;
179 fileName = openDia->selectedFile();
180 QFileInfo fi(fileName);
181 QString baseDir = fi.absolutePath();
182 fileName = baseDir + "/" + fi.baseName() + ".xps";
183 if (fileName.isEmpty())
184 return true;
185 prefs->set("wdir", fileName.left(fileName.lastIndexOf("/")));
186 QFile f(fileName);
187 if (f.exists())
188 {
189 int exit = ScMessageBox::warning(doc->scMW(), CommonStrings::trWarning,
190 QObject::tr("Do you really want to overwrite the file:\n%1 ?").arg(fileName),
191 QMessageBox::Yes | QMessageBox::No,
192 QMessageBox::NoButton, // GUI default
193 QMessageBox::Yes); // batch default
194 if (exit == QMessageBox::No)
195 return true;
196 }
197 XPSExPlug *dia = new XPSExPlug(doc, compress->currentIndex());
198 dia->doExport(fileName);
199 delete dia;
200 }
201 return true;
202 }
203
XPSExPlug(ScribusDoc * doc,int output_res)204 XPSExPlug::XPSExPlug(ScribusDoc* doc, int output_res)
205 {
206 m_Doc = doc;
207 conversionFactor = 96.0 / 72.0;
208 m_dpi = 96.0;
209 if (output_res == 0)
210 m_dpi = 72.0;
211 else if (output_res == 1)
212 m_dpi = 150.0;
213 else if (output_res == 2)
214 m_dpi = 300.0;
215 }
216
doExport(const QString & fName)217 bool XPSExPlug::doExport(const QString& fName)
218 {
219 ScZipHandler zip(true);
220 if (!zip.open(fName))
221 return false;
222
223 QTemporaryDir dir;
224 if (!dir.isValid())
225 {
226 zip.close();
227 QFile::remove(fName);
228 return false;
229 }
230
231 imageCounter = 0;
232 fontCounter = 0;
233 xps_fontMap.clear();
234 baseDir = dir.path();
235 // Create directory tree
236 QDir outDir(baseDir);
237 outDir.mkdir("_rels");
238 outDir.mkdir("docProps");
239 outDir.mkdir("Documents");
240 outDir.cd("Documents");
241 outDir.mkdir("1");
242 outDir.cd("1");
243 outDir.mkdir("_rels");
244 outDir.mkdir("Pages");
245 outDir.cd("Pages");
246 outDir.mkdir("_rels");
247 outDir.cdUp();
248 outDir.mkdir("Structure");
249 outDir.cdUp();
250 outDir.cdUp();
251 outDir.mkdir("Resources");
252 outDir.cd("Resources");
253 outDir.mkdir("Images");
254 outDir.mkdir("Fonts");
255 outDir.cdUp();
256 writeBaseRel();
257 writeContentType();
258 writeCore();
259 writeDocRels();
260 // Write Thumbnail
261 QImage thumb = m_Doc->view()->PageToPixmap(0, 256, Pixmap_DrawBackground);
262 thumb.save(baseDir + "/docProps/thumbnail.jpeg", "JPG");
263 // Write required DocStructure.struct
264 QFile fts(baseDir + "/Documents/1/Structure/DocStructure.struct");
265 if (fts.open(QIODevice::WriteOnly))
266 {
267 fts.write(QByteArray("<DocumentStructure xmlns=\"http://schemas.microsoft.com/xps/2005/06/documentstructure\">\n</DocumentStructure>"));
268 fts.close();
269 }
270 // Write required FixedDocSeq.fdseq
271 QFile ft(baseDir + "/FixedDocSeq.fdseq");
272 if (ft.open(QIODevice::WriteOnly))
273 {
274 ft.write(QByteArray("<FixedDocumentSequence xmlns=\"http://schemas.microsoft.com/xps/2005/06\">\n\t<DocumentReference Source=\"/Documents/1/FixedDoc.fdoc\"/>\n</FixedDocumentSequence>"));
275 ft.close();
276 }
277 // Write required FixedDoc.fdoc
278 f_docu = QDomDocument("xpsdoc");
279 QString st = "<FixedDocument></FixedDocument>";
280 f_docu.setContent(st);
281 QDomElement root = f_docu.documentElement();
282 root.setAttribute("xmlns", "http://schemas.microsoft.com/xps/2005/06");
283 f_docu.appendChild(root);
284 writePages(root);
285 QFile fdo(baseDir + "/Documents/1/FixedDoc.fdoc");
286 if (fdo.open(QIODevice::WriteOnly))
287 {
288 QString vo = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
289 QDataStream s(&fdo);
290 vo += f_docu.toString();
291 QByteArray utf8wr = vo.toUtf8();
292 s.writeRawData(utf8wr.data(), utf8wr.length());
293 fdo.close();
294 }
295
296 bool written = zip.write(baseDir);
297 zip.close();
298 if (!written)
299 QFile::remove(fName);
300 return written;
301 }
302
writePages(QDomElement & root)303 void XPSExPlug::writePages(QDomElement &root)
304 {
305 for (int i = 0; i < m_Doc->Pages->count(); ++i)
306 {
307 ScPage* Page = m_Doc->Pages->at(i);
308
309 p_docu.setContent(QString("<FixedPage></FixedPage>"));
310 QDomElement droot = p_docu.documentElement();
311 droot.setAttribute("xmlns", "http://schemas.microsoft.com/xps/2005/06");
312 droot.setAttribute("Width", QString("%1").arg(Page->width() * conversionFactor));
313 droot.setAttribute("Height", QString("%1").arg(Page->height() * conversionFactor));
314 QString lang = QLocale::system().name();
315 lang.replace("_", "-");
316 droot.setAttribute("xml:lang", lang);
317
318 r_docu.setContent(QString("<Relationships></Relationships>"));
319 QDomElement rroot = r_docu.documentElement();
320 rroot.setAttribute("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships");
321 xps_fontRel.clear();
322
323 writePage(droot, rroot, Page);
324
325 QFile ft(baseDir + QString("/Documents/1/Pages/%1.fpage").arg(i + 1));
326 if (ft.open(QIODevice::WriteOnly))
327 {
328 QString vo = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
329 QDataStream s(&ft);
330 vo += p_docu.toString();
331 QByteArray utf8wr = vo.toUtf8();
332 s.writeRawData(utf8wr.data(), utf8wr.length());
333 ft.close();
334 }
335
336 QFile ftr(baseDir + QString("/Documents/1/Pages/_rels/%1.fpage.rels").arg(i + 1));
337 if (ftr.open(QIODevice::WriteOnly))
338 {
339 QString vo = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
340 QDataStream s(&ftr);
341 vo += r_docu.toString();
342 QByteArray utf8wr = vo.toUtf8();
343 s.writeRawData(utf8wr.data(), utf8wr.length());
344 ftr.close();
345 }
346
347 QDomElement rel1 = f_docu.createElement("PageContent");
348 rel1.setAttribute("Source", QString("Pages/%1.fpage").arg(i + 1));
349 root.appendChild(rel1);
350 p_docu.clear();
351 r_docu.clear();
352 }
353 }
354
writePage(QDomElement & doc_root,QDomElement & rel_root,ScPage * Page)355 void XPSExPlug::writePage(QDomElement &doc_root, QDomElement &rel_root, ScPage *Page)
356 {
357 ScLayer ll;
358 ll.isPrintable = false;
359 for (int i = 0; i < m_Doc->Layers.count(); i++)
360 {
361 m_Doc->Layers.levelToLayer(ll, i);
362 if (ll.isPrintable)
363 {
364 ScPage *mpage = m_Doc->MasterPages.at(m_Doc->MasterNames[Page->masterPageName()]);
365 writePageLayer(doc_root, rel_root, mpage, ll);
366 writePageLayer(doc_root, rel_root, Page, ll);
367 }
368 }
369 }
370
writePageLayer(QDomElement & doc_root,QDomElement & rel_root,ScPage * page,ScLayer & layer)371 void XPSExPlug::writePageLayer(QDomElement &doc_root, QDomElement &rel_root, ScPage *page, ScLayer& layer)
372 {
373 PageItem *item;
374 QList<PageItem*> items;
375 ScPage* SavedAct = m_Doc->currentPage();
376 if (page->pageNameEmpty())
377 items = m_Doc->DocItems;
378 else
379 items = m_Doc->MasterItems;
380 if (items.count() == 0)
381 return;
382 if (!layer.isPrintable)
383 return;
384 m_Doc->setCurrentPage(page);
385 QDomElement layerGroup = p_docu.createElement("Canvas");
386 if (layer.transparency != 1.0)
387 layerGroup.setAttribute("Opacity", layer.transparency);
388 for (int j = 0; j < items.count(); ++j)
389 {
390 item = items.at(j);
391 if (item->m_layerID != layer.ID)
392 continue;
393 if (!item->printEnabled())
394 continue;
395 double x = page->xOffset();
396 double y = page->yOffset();
397 double w = page->width();
398 double h = page->height();
399 double lw = item->visualLineWidth();
400 double x2 = item->BoundingX - lw / 2.0;
401 double y2 = item->BoundingY - lw / 2.0;
402 double w2 = item->BoundingW + lw;
403 double h2 = item->BoundingH + lw;
404 if (!QRectF(x2, y2, w2, h2).intersects(QRectF(x, y, w, h)))
405 continue;
406 if ((!page->pageNameEmpty()) && (item->OwnPage != static_cast<int>(page->pageNr())) && (item->OwnPage != -1))
407 continue;
408 writeItemOnPage(item->xPos() - page->xOffset(), item->yPos() - page->yOffset(), item, layerGroup, rel_root);
409 }
410 doc_root.appendChild(layerGroup);
411 m_Doc->setCurrentPage(SavedAct);
412 }
413
writeItemOnPage(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)414 void XPSExPlug::writeItemOnPage(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
415 {
416 switch (item->itemType())
417 {
418 case PageItem::Arc:
419 case PageItem::Polygon:
420 case PageItem::PolyLine:
421 case PageItem::RegularPolygon:
422 case PageItem::Spiral:
423 if (checkForFallback(item))
424 handleImageFallBack(item, parentElem, rel_root);
425 else
426 {
427 processPolyItem(xOffset, yOffset, item, parentElem, rel_root);
428 if ((item->lineColor() != CommonStrings::None) && ((item->startArrowIndex() != 0) || (item->endArrowIndex() != 0)))
429 processArrows(xOffset, yOffset, item, parentElem, rel_root);
430 }
431 break;
432 case PageItem::Line:
433 if (checkForFallback(item))
434 handleImageFallBack(item, parentElem, rel_root);
435 else
436 {
437 processLineItem(xOffset, yOffset, item, parentElem, rel_root);
438 if ((item->lineColor() != CommonStrings::None) && ((item->startArrowIndex() != 0) || (item->endArrowIndex() != 0)))
439 processArrows(xOffset, yOffset, item, parentElem, rel_root);
440 }
441 break;
442 case PageItem::ImageFrame:
443 case PageItem::LatexFrame:
444 if (checkForFallback(item))
445 handleImageFallBack(item, parentElem, rel_root);
446 else
447 processImageItem(xOffset, yOffset, item, parentElem, rel_root);
448 break;
449 case PageItem::PathText:
450 case PageItem::TextFrame:
451 if (checkForFallback(item))
452 handleImageFallBack(item, parentElem, rel_root);
453 else
454 processTextItem(xOffset, yOffset, item, parentElem, rel_root);
455 break;
456 case PageItem::Table:
457 if (checkForFallback(item))
458 handleImageFallBack(item, parentElem, rel_root);
459 else
460 processTableItem(xOffset, yOffset, item, parentElem, rel_root);
461 break;
462 case PageItem::Symbol:
463 if (checkForFallback(item))
464 handleImageFallBack(item, parentElem, rel_root);
465 else
466 processSymbolItem(xOffset, yOffset, item, parentElem, rel_root);
467 break;
468 case PageItem::Group:
469 if (item->groupItemList.count() > 0)
470 {
471 if (checkForFallback(item))
472 handleImageFallBack(item, parentElem, rel_root);
473 else
474 {
475 QDomElement ob = p_docu.createElement("Canvas");
476 if (item->GrMask > 0)
477 handleMask(1, item, ob, rel_root, xOffset, yOffset);
478 else
479 {
480 if (item->fillTransparency() != 0)
481 ob.setAttribute("Opacity", FToStr(1.0 - item->fillTransparency()));
482 }
483 if (item->groupClipping())
484 {
485 FPointArray path = item->PoLine.copy();
486 path.scale(conversionFactor, conversionFactor);
487 path.scale(item->groupWidth / item->width(), item->groupHeight / item->height());
488 setClipAttr(ob, &path, item->fillRule);
489 }
490 QTransform mpx;
491 mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
492 mpx.scale(item->width() / item->groupWidth, item->height() / item->groupHeight);
493 if ((item->rotation() != 0.0) || item->imageFlippedH() || item->imageFlippedV())
494 {
495 mpx.rotate(item->rotation());
496 if (item->imageFlippedH())
497 {
498 mpx.translate(item->width() * conversionFactor, 0);
499 mpx.scale(-1, 1);
500 }
501 if (item->imageFlippedV())
502 {
503 mpx.translate(0, item->height() * conversionFactor);
504 mpx.scale(1, -1);
505 }
506 }
507 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
508 for (int em = 0; em < item->groupItemList.count(); ++em)
509 {
510 PageItem* embed = item->groupItemList.at(em);
511 writeItemOnPage(embed->gXpos, embed->gYpos, embed, ob, rel_root);
512 }
513 parentElem.appendChild(ob);
514 }
515 }
516 break;
517 default:
518 handleImageFallBack(item, parentElem, rel_root);
519 break;
520 }
521 }
522
handleImageFallBack(PageItem * item,QDomElement & parentElem,QDomElement & rel_root)523 void XPSExPlug::handleImageFallBack(PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
524 {
525 QDomElement ob = p_docu.createElement("Path");
526 double maxAdd = 0;
527 if (item->hasSoftShadow())
528 maxAdd = qMax(fabs(item->softShadowXOffset()), fabs(item->softShadowYOffset())) + item->softShadowBlurRadius();
529 QRectF bounds = item->getVisualBoundingRect().adjusted(-maxAdd, -maxAdd, maxAdd, maxAdd);
530 QPainterPath path;
531 path.moveTo(0, 0);
532 path.lineTo(bounds.width(), 0);
533 path.lineTo(bounds.width(), bounds.height());
534 path.lineTo(0, bounds.height());
535 path.closeSubpath();
536 QTransform mpp;
537 mpp.translate((item->visualXPos() - m_Doc->currentPage()->xOffset() - maxAdd) * conversionFactor, (item->visualYPos() - m_Doc->currentPage()->yOffset() - maxAdd) * conversionFactor);
538 mpp.scale(conversionFactor, conversionFactor);
539 path = mpp.map(path);
540 FPointArray fPath;
541 fPath.fromQPainterPath(path, true);
542 QString pa = setClipPath(&fPath, true);
543 if (item->fillRule)
544 pa.prepend("F 0 ");
545 else
546 pa.prepend("F 1 ");
547 ob.setAttribute("Data", pa);
548 QDomElement obf = p_docu.createElement("Path.Fill");
549 QDomElement gr = p_docu.createElement("ImageBrush");
550 double maxSize = qMax(bounds.width(), bounds.height());
551 maxSize = qMin(3000.0, maxSize * (m_dpi / 72.0));
552 QImage tmpImg = item->DrawObj_toImage(maxSize);
553 tmpImg.save(baseDir + "/Resources/Images/" + QString("%1.png").arg(imageCounter), "PNG");
554 gr.setAttribute("TileMode", "None");
555 gr.setAttribute("ViewboxUnits", "Absolute");
556 gr.setAttribute("ViewportUnits", "Absolute");
557 gr.setAttribute("Viewport", "0,0,1,1");
558 gr.setAttribute("Viewbox", QString("0, 0, %1, %2").arg(tmpImg.width()).arg(tmpImg.height()));
559 gr.setAttribute("Viewport", QString("%1, %2, %3, %4").arg((item->visualXPos() - m_Doc->currentPage()->xOffset() - maxAdd) * conversionFactor).arg((item->visualYPos() - m_Doc->currentPage()->yOffset() - maxAdd) * conversionFactor).arg(bounds.width() * conversionFactor).arg(bounds.height() * conversionFactor));
560 gr.setAttribute("ImageSource", "/Resources/Images/" + QString("%1.png").arg(imageCounter));
561 QDomElement rel = r_docu.createElement("Relationship");
562 rel.setAttribute("Id", QString("rIDi%1").arg(imageCounter));
563 rel.setAttribute("Type", "http://schemas.microsoft.com/xps/2005/06/required-resource");
564 rel.setAttribute("Target", "/Resources/Images/" + QString("%1.png").arg(imageCounter));
565 rel_root.appendChild(rel);
566 imageCounter++;
567 obf.appendChild(gr);
568 ob.appendChild(obf);
569 parentElem.appendChild(ob);
570 }
571
processPolyItem(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)572 void XPSExPlug::processPolyItem(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
573 {
574 if (((item->GrType == 0) && (item->fillColor() == CommonStrings::None)) && ((item->GrTypeStroke == 0) && (item->lineColor() == CommonStrings::None) && item->NamedLStyle.isEmpty()))
575 return;
576
577 if (item->GrType == Gradient_Hatch)
578 processHatchFill(xOffset, yOffset, item, parentElem, rel_root);
579 bool closedPath;
580 closedPath = ((item->itemType() == PageItem::Polygon) || (item->itemType() == PageItem::RegularPolygon) || (item->itemType() == PageItem::Arc));
581
582 QDomElement ob = p_docu.createElement("Path");
583 FPointArray path = item->PoLine.copy();
584 QTransform mpx;
585 if (item->rotation() != 0.0)
586 {
587 mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
588 mpx.rotate(item->rotation());
589 mpx.translate(-xOffset * conversionFactor, -yOffset * conversionFactor);
590 }
591 path.translate(xOffset, yOffset);
592 path.scale(conversionFactor, conversionFactor);
593 QString pa = setClipPath(&path, closedPath);
594 if (item->fillRule)
595 pa.prepend("F 0 ");
596 else
597 pa.prepend("F 1 ");
598 ob.setAttribute("Data", pa);
599 if (item->GrType != Gradient_Hatch)
600 {
601 if (item->GrMask > 0)
602 handleMask(3, item, ob, rel_root, xOffset, yOffset);
603 getFillStyle(item, ob, rel_root, xOffset, yOffset);
604 }
605 if (item->NamedLStyle.isEmpty())
606 {
607 if ((!item->strokePattern().isEmpty()) && (item->patternStrokePath))
608 {
609 processSymbolStroke(xOffset, yOffset, item, parentElem, rel_root);
610 }
611 else
612 {
613 getStrokeStyle(item, ob, rel_root, xOffset, yOffset);
614 if (item->rotation() != 0.0)
615 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
616 parentElem.appendChild(ob);
617 }
618 }
619 else
620 {
621 QDomElement grp2 = p_docu.createElement("Canvas");
622 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
623 for (int it = ml.size()-1; it > -1; it--)
624 {
625 if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
626 {
627 QDomElement ob3 = p_docu.createElement("Path");
628 ob3.setAttribute("Data", pa);
629 getMultiStroke(&ml[it], ob3);
630 grp2.appendChild(ob3);
631 }
632 }
633 if (item->lineTransparency() != 0)
634 grp2.setAttribute("Opacity", FToStr(1.0 - item->lineTransparency()));
635 if (item->rotation() != 0.0)
636 grp2.setAttribute("RenderTransform", MatrixToStr(mpx));
637 parentElem.appendChild(grp2);
638 }
639 }
640
processLineItem(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)641 void XPSExPlug::processLineItem(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
642 {
643 if ((item->GrTypeStroke != 0) || (item->lineColor() != CommonStrings::None) || !item->NamedLStyle.isEmpty())
644 {
645 QDomElement ob;
646 double x1 = xOffset * conversionFactor;
647 double y1 = yOffset * conversionFactor;
648 double x2 = (item->width() + xOffset) * conversionFactor;
649 double y2 = yOffset * conversionFactor;
650 QLineF line = QLineF(x1, y1, x2, y2);
651 line.setAngle(-item->rotation());
652 if (item->NamedLStyle.isEmpty())
653 {
654 ob = p_docu.createElement("Path");
655 ob.setAttribute("Data", QString("M %1, %2 L %3, %4").arg(line.p1().x()).arg(line.p1().y()).arg(line.p2().x()).arg(line.p2().y()));
656 getStrokeStyle(item, ob, rel_root, xOffset, yOffset);
657 }
658 else
659 {
660 ob = p_docu.createElement("Canvas");
661 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
662 for (int it = ml.size()-1; it > -1; it--)
663 {
664 if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
665 {
666 QDomElement ob2 = p_docu.createElement("Path");
667 ob2.setAttribute("Data", QString("M %1, %2 L %3, %4").arg(line.p1().x()).arg(line.p1().y()).arg(line.p2().x()).arg(line.p2().y()));
668 getMultiStroke(&ml[it], ob2);
669 ob.appendChild(ob2);
670 }
671 }
672 if (item->lineTransparency() != 0)
673 ob.setAttribute("Opacity", FToStr(1.0 - item->lineTransparency()));
674 }
675 parentElem.appendChild(ob);
676 }
677 }
678
processImageItem(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)679 void XPSExPlug::processImageItem(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
680 {
681 if (item->GrType == Gradient_Hatch)
682 processHatchFill(xOffset, yOffset, item, parentElem, rel_root);
683 FPointArray path = item->PoLine.copy();
684 path.translate(xOffset, yOffset);
685 path.scale(conversionFactor, conversionFactor);
686 QString pa = setClipPath(&path, true);
687 if (item->fillRule)
688 pa.prepend("F 0 ");
689 else
690 pa.prepend("F 1 ");
691 QDomElement grp = p_docu.createElement("Canvas");
692 QTransform mpx;
693 if (item->rotation() != 0.0)
694 {
695 mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
696 mpx.rotate(item->rotation());
697 mpx.translate(-xOffset * conversionFactor, -yOffset * conversionFactor);
698 grp.setAttribute("RenderTransform", MatrixToStr(mpx));
699 }
700 if (item->GrType != Gradient_Hatch)
701 {
702 if (item->GrMask > 0)
703 handleMask(1, item, grp, rel_root, xOffset, yOffset);
704 else
705 {
706 if (item->fillTransparency() != 0)
707 grp.setAttribute("Opacity", FToStr(1.0 - item->fillTransparency()));
708 }
709 if ((item->GrType != 0) || (item->fillColor() != CommonStrings::None))
710 {
711 QDomElement ob = p_docu.createElement("Path");
712 ob.setAttribute("Data", pa);
713 getFillStyle(item, ob, rel_root, xOffset, yOffset, false);
714 grp.appendChild(ob);
715 }
716 }
717 if ((item->imageIsAvailable) && (!item->Pfile.isEmpty()))
718 {
719 QDomElement ob2 = p_docu.createElement("Path");
720 ob2.setAttribute("Data", pa);
721 ob2.setAttribute("Clip", pa);
722 QDomElement obf = p_docu.createElement("Path.Fill");
723 QDomElement gr = p_docu.createElement("ImageBrush");
724 ScImage img;
725 CMSettings cms(m_Doc, item->ImageProfile, item->ImageIntent);
726 cms.setUseEmbeddedProfile(item->UseEmbedded);
727 cms.allowSoftProofing(true);
728 img.loadPicture(item->Pfile, item->pixm.imgInfo.actualPageNumber, cms, ScImage::RGBData, 96);
729 img.applyEffect(item->effectsInUse, m_Doc->PageColors, true);
730 img.qImagePtr()->setDotsPerMeterX(3780);
731 img.qImagePtr()->setDotsPerMeterY(3780);
732 img.qImage().save(baseDir + "/Resources/Images/" + QString("%1.png").arg(imageCounter), "PNG");
733 gr.setAttribute("TileMode", "None");
734 gr.setAttribute("ViewboxUnits", "Absolute");
735 gr.setAttribute("ViewportUnits", "Absolute");
736 gr.setAttribute("Viewport", "0,0,1,1");
737 gr.setAttribute("Viewbox", QString("0, 0, %1, %2").arg(img.width()).arg(img.height()));
738 QTransform mpx;
739 double xpos = item->imageXOffset() * item->imageXScale();
740 double ypos = item->imageYOffset() * item->imageYScale();
741 mpx.translate((xOffset + xpos) * conversionFactor, (yOffset + ypos) * conversionFactor);
742 mpx.scale(img.width() * item->imageXScale() * conversionFactor, img.height() * item->imageYScale() * conversionFactor);
743 if (item->imageFlippedH())
744 {
745 mpx.translate(item->width() / (img.width() * item->imageXScale()), 0);
746 mpx.scale(-1, 1);
747 }
748 if (item->imageFlippedV())
749 {
750 mpx.translate(0, item->height() / (img.height() * item->imageYScale()));
751 mpx.scale(1, -1);
752 }
753 mpx.rotate(item->imageRotation());
754 gr.setAttribute("Transform", MatrixToStr(mpx));
755 gr.setAttribute("ImageSource", "/Resources/Images/" + QString("%1.png").arg(imageCounter));
756 QDomElement rel = r_docu.createElement("Relationship");
757 rel.setAttribute("Id", QString("rIDi%1").arg(imageCounter));
758 rel.setAttribute("Type", "http://schemas.microsoft.com/xps/2005/06/required-resource");
759 rel.setAttribute("Target", "/Resources/Images/" + QString("%1.png").arg(imageCounter));
760 rel_root.appendChild(rel);
761 imageCounter++;
762 obf.appendChild(gr);
763 ob2.appendChild(obf);
764 grp.appendChild(ob2);
765 }
766 parentElem.appendChild(grp);
767 if ((item->GrTypeStroke != 0) || (item->lineColor() != CommonStrings::None) || !item->NamedLStyle.isEmpty())
768 {
769 if (item->NamedLStyle.isEmpty())
770 {
771 if ((!item->strokePattern().isEmpty()) && (item->patternStrokePath))
772 {
773 processSymbolStroke(xOffset, yOffset, item, parentElem, rel_root);
774 }
775 else
776 {
777 QDomElement ob3 = p_docu.createElement("Path");
778 ob3.setAttribute("Data", pa);
779 getStrokeStyle(item, ob3, rel_root, xOffset, yOffset);
780 if (item->rotation() != 0.0)
781 ob3.setAttribute("RenderTransform", MatrixToStr(mpx));
782 parentElem.appendChild(ob3);
783 }
784 }
785 else
786 {
787 QDomElement grp2 = p_docu.createElement("Canvas");
788 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
789 for (int it = ml.size()-1; it > -1; it--)
790 {
791 if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
792 {
793 QDomElement ob3 = p_docu.createElement("Path");
794 ob3.setAttribute("Data", pa);
795 getMultiStroke(&ml[it], ob3);
796 grp2.appendChild(ob3);
797 }
798 }
799 if (item->lineTransparency() != 0)
800 grp2.setAttribute("Opacity", FToStr(1.0 - item->lineTransparency()));
801 if (item->rotation() != 0.0)
802 grp2.setAttribute("RenderTransform", MatrixToStr(mpx));
803 parentElem.appendChild(grp2);
804 }
805 }
806 }
807
808 class XPSPainter: public TextLayoutPainter
809 {
810 //PageItem *m_item;
811 QDomElement m_group;
812 XPSExPlug *m_xps;
813 QMap<QString, XPSResourceInfo> &m_fontMap;
814 QSet<QString> &m_fontRel;
815 QDomElement &m_relRoot;
816
817 bool m_restart { true };
818 double m_current_x { 0.0 };
819 double m_current_y { 0.0 };
820 double m_fontSize { 0.0 };
821 QString m_fontUri;
822 TextLayoutColor m_fillColor;
823 QTransform m_transform;
824 QDomElement m_glyphElem;
825
826 public:
XPSPainter(PageItem * item,QDomElement & group,XPSExPlug * xps,QMap<QString,XPSResourceInfo> & xpsFontMap,QSet<QString> & xpsFontRel,QDomElement & rel_root)827 XPSPainter(PageItem *item, QDomElement &group, XPSExPlug *xps, QMap<QString, XPSResourceInfo> &xpsFontMap, QSet<QString> &xpsFontRel, QDomElement &rel_root):
828 // m_item(item),
829 m_group(group),
830 m_xps(xps),
831 m_fontMap(xpsFontMap),
832 m_fontRel(xpsFontRel),
833 m_relRoot(rel_root)
834 { }
835
drawGlyph(const GlyphCluster & gc)836 void drawGlyph(const GlyphCluster& gc) override
837 {
838 if (gc.isControlGlyphs() || gc.isEmpty())
839 return;
840
841 XPSResourceInfo fontInfo;
842 QString replacementName = font().replacementName();
843 if (!m_fontMap.contains(replacementName))
844 m_fontMap.insert(replacementName, m_xps->embedFont(font(), m_relRoot));
845 fontInfo = m_fontMap.value(replacementName);
846
847 if (!m_fontRel.contains(replacementName))
848 {
849 m_xps->addFontRelationship(m_relRoot, fontInfo);
850 m_fontRel.insert(replacementName);
851 }
852
853 QTransform transform = matrix();
854 double size = fontSize() * qMax(gc.scaleV(), gc.scaleH()) * m_xps->conversionFactor;
855 QString fontUri = fontInfo.uri;
856
857 if (m_restart || (size != m_fontSize) || (m_fillColor != fillColor()) || (m_fontUri != fontUri) ||
858 (qAbs(m_current_x - x()) > 1e-6) || (m_current_y != y()) || (m_transform != transform))
859 {
860 m_glyphElem = m_xps->p_docu.createElement("Glyphs");
861 m_glyphElem.setAttribute("RenderTransform", m_xps->MatrixToStr(transform, m_xps->conversionFactor));
862 m_glyphElem.setAttribute("BidiLevel", "0");
863 m_glyphElem.setAttribute("StyleSimulations", "None");
864 m_glyphElem.setAttribute("FontRenderingEmSize", m_xps->FToStr(size));
865 m_glyphElem.setAttribute("FontUri", fontUri);
866 m_glyphElem.setAttribute("Fill", m_xps->setColor(fillColor().color,fillColor().shade, 0));
867 m_glyphElem.setAttribute("OriginX", m_xps->FToStr(x() * m_xps->conversionFactor));
868 m_glyphElem.setAttribute("OriginY", m_xps->FToStr(y() * m_xps->conversionFactor));
869 m_glyphElem.setAttribute("UnicodeString", QString());
870 m_group.appendChild(m_glyphElem);
871 }
872
873 QString unicodeString = m_glyphElem.attribute("UnicodeString");
874 unicodeString += gc.getText();
875 m_glyphElem.setAttribute("UnicodeString", unicodeString);
876
877 QString gcMap;
878 QString indices, allIndices = m_glyphElem.attribute("Indices");
879
880 int gcTextSize = gc.getText().size();
881 int gcGlyphCount = gc.glyphs().size();
882 if (gcTextSize > 1 || gcGlyphCount > 1)
883 gcMap = QString("(%1:%2)").arg(gcTextSize).arg(gcGlyphCount);
884
885 double current_x = 0.0;
886 double clusterWidth = gc.width();
887 const auto& glyphs = gc.glyphs();
888
889 for (int i = 0; i < glyphs.count(); ++i)
890 {
891 const GlyphLayout& gl = glyphs.at(i);
892 if (gl.glyph >= ScFace::CONTROL_GLYPHS)
893 {
894 current_x += gl.xadvance * gl.scaleH;
895 continue;
896 }
897
898 double glWidth = gl.xadvance * gl.scaleH;
899 if (i == glyphs.count() - 1) // Clusters may have some extra width
900 glWidth = clusterWidth - current_x;
901
902 indices += QString("%1,%2,%3,%4;").arg(gl.glyph)
903 .arg((glWidth * m_xps->conversionFactor) / size * 100)
904 .arg((-gl.xoffset * m_xps->conversionFactor) / size * 100)
905 .arg((-gl.yoffset * m_xps->conversionFactor) / size * 100);
906 current_x += glWidth;
907 }
908 indices.chop(1);
909
910 if (!allIndices.isEmpty())
911 allIndices += ";";
912 allIndices += QString("%1%2").arg(gcMap, indices);
913 m_glyphElem.setAttribute("Indices", allIndices);
914
915 m_restart = false;
916 m_current_x = x() + clusterWidth;
917 m_current_y = y();
918 m_fontSize = size;
919 m_fontUri = fontUri;
920 m_fillColor = fillColor();
921 m_transform = transform;
922 }
923
drawGlyphOutline(const GlyphCluster & gc,bool fill)924 void drawGlyphOutline(const GlyphCluster& gc, bool fill) override
925 {
926 if (gc.isControlGlyphs())
927 return;
928
929 double current_x = 0.0;
930 for (const GlyphLayout& gl : gc.glyphs())
931 {
932 if (gl.glyph >= ScFace::CONTROL_GLYPHS)
933 {
934 current_x += gl.xadvance * gl.scaleH;
935 continue;
936 }
937
938 FPointArray outline = font().glyphOutline(gl.glyph);
939 if (outline.size() >= 4)
940 {
941 QTransform transform = matrix();
942 transform.scale((fontSize() * gc.scaleH()) / 10.0, (fontSize() * gc.scaleV()) / 10.0);
943 outline.map(transform);
944 outline.translate(gl.xoffset + current_x, -(fontSize() * gl.scaleV) + gl.yoffset);
945 outline.translate(x(), y());
946 outline.scale(m_xps->conversionFactor, m_xps->conversionFactor);
947 QString pathData = m_xps->setClipPath(&outline, true);
948 QDomElement glyph = m_xps->p_docu.createElement("Path");
949 glyph.setAttribute("Data", pathData);
950 if (!fill)
951 glyph.setAttribute("Fill", m_xps->setColor("None", fillColor().shade, 0));
952 else
953 glyph.setAttribute("Fill", m_xps->setColor(fillColor().color, fillColor().shade, 0));
954 glyph.setAttribute("StrokeThickness", m_xps->FToStr(strokeWidth() * m_xps->conversionFactor));
955 glyph.setAttribute("Stroke", m_xps->setColor(strokeColor().color, strokeColor().shade, 0));
956 m_group.appendChild(glyph);
957 //qDebug() << "StrokeWidth XPS" << strokeWidth();
958 }
959 current_x += gl.xadvance * gl.scaleH;
960 }
961
962 m_restart = true;
963 }
964
drawLine(QPointF start,QPointF end)965 void drawLine(QPointF start, QPointF end) override
966 {
967 QTransform transform = matrix();
968 QDomElement path = m_xps->p_docu.createElement("Path");
969 path.setAttribute("RenderTransform", m_xps->MatrixToStr(transform, m_xps->conversionFactor));
970 path.setAttribute("Data", QString("M%1,%2 L%3,%4").arg((x() + start.x()) * m_xps->conversionFactor).arg((y() + end.y()) * m_xps->conversionFactor).arg((x() + start.x() + end.x()) * m_xps->conversionFactor).arg((y() + end.y()) * m_xps->conversionFactor));
971 path.setAttribute("Stroke", m_xps->setColor(strokeColor().color, strokeColor().shade, 0));
972 path.setAttribute("StrokeThickness", m_xps->FToStr(strokeWidth() * m_xps->conversionFactor));
973 m_group.appendChild(path);
974 m_restart = true;
975 }
976
drawRect(QRectF rect)977 void drawRect(QRectF rect) override
978 {
979 QTransform transform = matrix();
980 double rx = (x() + rect.x()) * m_xps->conversionFactor;
981 double ry = (y() + rect.y()) * m_xps->conversionFactor;
982 double rw = rx + rect.width() * m_xps->conversionFactor;
983 double rh = ry + rect.height() * m_xps->conversionFactor;
984 QString paS = QString("M%1,%2 ").arg(rx).arg(ry);
985 paS += QString("L%1,%2 ").arg(rw).arg(ry);
986 paS += QString("L%1,%2 ").arg(rw).arg(rh);
987 paS += QString("L%1,%2 ").arg(rx).arg(rh);
988 paS += "Z";
989 QDomElement path = m_xps->p_docu.createElement("Path");
990 path.setAttribute("RenderTransform", m_xps->MatrixToStr(transform, m_xps->conversionFactor));
991 path.setAttribute("Data", paS);
992 path.setAttribute("Fill", m_xps->setColor(fillColor().color, fillColor().shade, 0));
993 path.setAttribute("StrokeThickness", m_xps->FToStr(strokeWidth() * m_xps->conversionFactor));
994 path.setAttribute("Stroke", m_xps->setColor(strokeColor().color, strokeColor().shade, 0));
995 m_group.appendChild(path);
996 m_restart = true;
997 }
998
drawObject(PageItem * item)999 void drawObject(PageItem* item) override
1000 {
1001 QDomElement canvas = m_xps->p_docu.createElement("Canvas");
1002 QTransform matrix = QTransform();
1003 matrix.translate(x() * m_xps->conversionFactor, (y() - (item->height() * (scaleV() / 1000.0))) * m_xps->conversionFactor);
1004 if (scaleH() != 1.0)
1005 matrix.scale(scaleH(), 1);
1006 if (scaleV() != 1.0)
1007 matrix.scale(1, scaleV());
1008 canvas.setAttribute("RenderTransform", m_xps->MatrixToStr(matrix));
1009 m_xps->writeItemOnPage(item->gXpos, item->gYpos, item, canvas, m_relRoot);
1010 m_group.appendChild(canvas);
1011 m_restart = true;
1012 }
1013 };
1014
processTextItem(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)1015 void XPSExPlug::processTextItem(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
1016 {
1017 if (item->isAnnotation())
1018 return;
1019 if (item->GrType == Gradient_Hatch)
1020 processHatchFill(xOffset, yOffset, item, parentElem, rel_root);
1021 FPointArray path = item->PoLine.copy();
1022 path.scale(conversionFactor, conversionFactor);
1023 QString pa = setClipPath(&path, true);
1024 if (item->fillRule)
1025 pa.prepend("F 0 ");
1026 else
1027 pa.prepend("F 1 ");
1028 QDomElement grp = p_docu.createElement("Canvas");
1029 QTransform mpx;
1030 QTransform mpl;
1031 mpl.translate(xOffset * conversionFactor, yOffset * conversionFactor);
1032 mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
1033 if ((item->rotation() != 0.0) || item->imageFlippedH() || item->imageFlippedV())
1034 {
1035 mpx.rotate(item->rotation());
1036 mpl.rotate(item->rotation());
1037 if (item->imageFlippedH())
1038 {
1039 mpx.translate(item->width() * conversionFactor, 0);
1040 mpx.scale(-1, 1);
1041 }
1042 if (item->imageFlippedV())
1043 {
1044 mpx.translate(0, item->height() * conversionFactor);
1045 mpx.scale(1, -1);
1046 }
1047 }
1048 grp.setAttribute("RenderTransform", MatrixToStr(mpx));
1049 if (item->isBookmark)
1050 grp.setAttribute("Name", item->itemName());
1051 if (item->GrType != Gradient_Hatch)
1052 {
1053 if (item->GrMask > 0)
1054 handleMask(1, item, grp, rel_root, xOffset, yOffset);
1055 else
1056 {
1057 if (item->fillTransparency() != 0)
1058 grp.setAttribute("Opacity", FToStr(1.0 - item->fillTransparency()));
1059 }
1060 if ((item->GrType != 0) || (item->fillColor() != CommonStrings::None))
1061 {
1062 FPointArray pathi = item->PoLine.copy();
1063 if (item->imageFlippedH() || item->imageFlippedV())
1064 {
1065 QTransform mpi;
1066 if (item->imageFlippedH())
1067 {
1068 mpi.translate(item->width(), 0);
1069 mpi.scale(-1, 1);
1070 }
1071 if (item->imageFlippedV())
1072 {
1073 mpi.translate(0, item->height());
1074 mpi.scale(1, -1);
1075 }
1076 pathi.map(mpi);
1077 }
1078 pathi.scale(conversionFactor, conversionFactor);
1079 QString pai = setClipPath(&pathi, true);
1080 if (item->fillRule)
1081 pai.prepend("F 0 ");
1082 else
1083 pai.prepend("F 1 ");
1084 QDomElement ob = p_docu.createElement("Path");
1085 ob.setAttribute("Data", pai);
1086 getFillStyle(item, ob, rel_root, xOffset, yOffset, false);
1087 grp.appendChild(ob);
1088 }
1089 }
1090 if (item->isPathText())
1091 {
1092 if ((item->PoShow) && (item->lineColor() != CommonStrings::None))
1093 {
1094 QDomElement ob = p_docu.createElement("Path");
1095 FPointArray path = item->PoLine.copy();
1096 path.scale(conversionFactor, conversionFactor);
1097 QString pa = setClipPath(&path, false);
1098 ob.setAttribute("Data", pa);
1099 if (item->NamedLStyle.isEmpty())
1100 {
1101 if ((!item->strokePattern().isEmpty()) && (item->patternStrokePath))
1102 {
1103 processSymbolStroke(xOffset, yOffset, item, parentElem, rel_root);
1104 }
1105 else
1106 {
1107 getStrokeStyle(item, ob, rel_root, xOffset, yOffset);
1108 grp.appendChild(ob);
1109 }
1110 }
1111 else
1112 {
1113 QDomElement grp2 = p_docu.createElement("Canvas");
1114 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
1115 for (int it = ml.size()-1; it > -1; it--)
1116 {
1117 if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
1118 {
1119 QDomElement ob3 = p_docu.createElement("Path");
1120 ob3.setAttribute("Data", pa);
1121 getMultiStroke(&ml[it], ob3);
1122 grp2.appendChild(ob3);
1123 }
1124 }
1125 if (item->lineTransparency() != 0)
1126 grp2.setAttribute("Opacity", FToStr(1.0 - item->lineTransparency()));
1127 grp.appendChild(grp2);
1128 }
1129 }
1130 }
1131
1132 if (grp.hasChildNodes())
1133 parentElem.appendChild(grp);
1134
1135 if (item->itemText.length() != 0)
1136 {
1137 QDomElement grp2 = p_docu.createElement("Canvas");
1138 if (grp.hasAttribute("RenderTransform"))
1139 grp2.setAttribute("RenderTransform", grp.attribute("RenderTransform"));
1140 if (grp.hasAttribute("Name"))
1141 grp2.setAttribute("Name", grp.attribute("Name"));
1142 if (grp.hasAttribute("Opacity"))
1143 grp2.setAttribute("Opacity", grp.attribute("Opacity"));
1144 XPSPainter p(item, grp2, this, xps_fontMap, xps_fontRel, rel_root);
1145 item->textLayout.renderBackground(&p);
1146 item->textLayout.render(&p);
1147 parentElem.appendChild(grp2);
1148 }
1149 if (item->isTextFrame())
1150 {
1151 if ((item->GrTypeStroke != 0) || (item->lineColor() != CommonStrings::None) || !item->NamedLStyle.isEmpty())
1152 {
1153 if (item->NamedLStyle.isEmpty())
1154 {
1155 if ((!item->strokePattern().isEmpty()) && (item->patternStrokePath))
1156 {
1157 processSymbolStroke(xOffset, yOffset, item, parentElem, rel_root);
1158 }
1159 else
1160 {
1161 QDomElement ob3 = p_docu.createElement("Path");
1162 ob3.setAttribute("Data", pa);
1163 getStrokeStyle(item, ob3, rel_root, xOffset, yOffset);
1164 ob3.setAttribute("RenderTransform", MatrixToStr(mpl));
1165 parentElem.appendChild(ob3);
1166 }
1167 }
1168 else
1169 {
1170 QDomElement grp2 = p_docu.createElement("Canvas");
1171 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
1172 for (int it = ml.size()-1; it > -1; it--)
1173 {
1174 if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
1175 {
1176 QDomElement ob3 = p_docu.createElement("Path");
1177 ob3.setAttribute("Data", pa);
1178 getMultiStroke(&ml[it], ob3);
1179 grp2.appendChild(ob3);
1180 }
1181 }
1182 if (item->lineTransparency() != 0)
1183 grp2.setAttribute("Opacity", FToStr(1.0 - item->lineTransparency()));
1184 grp2.setAttribute("RenderTransform", MatrixToStr(mpl));
1185 parentElem.appendChild(grp2);
1186 }
1187 }
1188 }
1189 }
1190
processSymbolItem(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)1191 void XPSExPlug::processSymbolItem(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
1192 {
1193 QDomElement ob = p_docu.createElement("Canvas");
1194 FPointArray path = item->PoLine.copy();
1195 ScPattern pat = m_Doc->docPatterns[item->pattern()];
1196 path.scale(conversionFactor, conversionFactor);
1197 path.scale(pat.width / item->width(), pat.height / item->height());
1198 setClipAttr(ob, &path, item->fillRule);
1199 QTransform mpx;
1200 mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
1201 mpx.scale(item->width() / pat.width, item->height() / pat.height);
1202 if ((item->rotation() != 0.0) || item->imageFlippedH() || item->imageFlippedV())
1203 {
1204 mpx.rotate(item->rotation());
1205 if (item->imageFlippedH())
1206 {
1207 mpx.translate(item->width() * conversionFactor, 0);
1208 mpx.scale(-1, 1);
1209 }
1210 if (item->imageFlippedV())
1211 {
1212 mpx.translate(0, item->height() * conversionFactor);
1213 mpx.scale(1, -1);
1214 }
1215 }
1216 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1217 if (item->GrMask > 0)
1218 handleMask(1, item, ob, rel_root, xOffset, yOffset);
1219 else
1220 {
1221 if (item->fillTransparency() != 0)
1222 ob.setAttribute("Opacity", FToStr(1.0 - item->fillTransparency()));
1223 }
1224 for (int em = 0; em < pat.items.count(); ++em)
1225 {
1226 PageItem* embed = pat.items.at(em);
1227 writeItemOnPage(embed->gXpos, embed->gYpos, embed, ob, rel_root);
1228 }
1229 parentElem.appendChild(ob);
1230 }
1231
processTableItem(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)1232 void XPSExPlug::processTableItem(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
1233 {
1234 QDomElement ob = p_docu.createElement("Canvas");
1235 QTransform mpx;
1236 mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
1237 if (item->rotation() != 0.0)
1238 mpx.rotate(item->rotation());
1239 mpx.translate(item->asTable()->gridOffset().x() * conversionFactor, item->asTable()->gridOffset().y() * conversionFactor);
1240 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1241 // Paint table fill.
1242 if (item->asTable()->fillColor() != CommonStrings::None)
1243 {
1244 int lastCol = item->asTable()->columns() - 1;
1245 int lastRow = item->asTable()->rows() - 1;
1246 double x = item->asTable()->columnPosition(0);
1247 double y = item->asTable()->rowPosition(0);
1248 double width = item->asTable()->columnPosition(lastCol) + item->asTable()->columnWidth(lastCol) - x;
1249 double height = item->asTable()->rowPosition(lastRow) + item->asTable()->rowHeight(lastRow) - y;
1250 FPointArray path;
1251 path.svgInit();
1252 path.svgMoveTo(0, 0);
1253 path.svgLineTo(width, 0);
1254 path.svgLineTo(width, height);
1255 path.svgLineTo(0, height);
1256 path.svgClosePath();
1257 path.scale(conversionFactor, conversionFactor);
1258 QString pa = setClipPath(&path, true);
1259 QDomElement cl = p_docu.createElement("Path");
1260 cl.setAttribute("Data", pa);
1261 cl.setAttribute("Fill", setColor(item->asTable()->fillColor(), item->asTable()->fillShade(), 0));
1262 ob.appendChild(cl);
1263 }
1264 // Pass 1: Paint cell fills.
1265 for (int row = 0; row < item->asTable()->rows(); ++row)
1266 {
1267 int colSpan = 0;
1268 for (int col = 0; col < item->asTable()->columns(); col += colSpan)
1269 {
1270 TableCell cell = item->asTable()->cellAt(row, col);
1271 if (row == cell.row())
1272 {
1273 QString colorName = cell.fillColor();
1274 if (colorName != CommonStrings::None)
1275 {
1276 int row = cell.row();
1277 int col = cell.column();
1278 int lastRow = row + cell.rowSpan() - 1;
1279 int lastCol = col + cell.columnSpan() - 1;
1280 double x = item->asTable()->columnPosition(col);
1281 double y = item->asTable()->rowPosition(row);
1282 double width = item->asTable()->columnPosition(lastCol) + item->asTable()->columnWidth(lastCol) - x;
1283 double height = item->asTable()->rowPosition(lastRow) + item->asTable()->rowHeight(lastRow) - y;
1284 FPointArray path;
1285 path.svgInit();
1286 path.svgMoveTo(x, y);
1287 path.svgLineTo(x + width, y);
1288 path.svgLineTo(x + width, y + height);
1289 path.svgLineTo(x, y + height);
1290 path.svgClosePath();
1291 path.scale(conversionFactor, conversionFactor);
1292 QString pa = setClipPath(&path, true);
1293 QDomElement cl = p_docu.createElement("Path");
1294 cl.setAttribute("Data", pa);
1295 cl.setAttribute("Fill", setColor(colorName, cell.fillShade(), 0));
1296 ob.appendChild(cl);
1297 }
1298 }
1299 colSpan = cell.columnSpan();
1300 }
1301 }
1302 // Pass 2: Paint vertical borders.
1303 for (int row = 0; row < item->asTable()->rows(); ++row)
1304 {
1305 int colSpan = 0;
1306 for (int col = 0; col < item->asTable()->columns(); col += colSpan)
1307 {
1308 TableCell cell = item->asTable()->cellAt(row, col);
1309 if (row == cell.row())
1310 {
1311 const int lastRow = cell.row() + cell.rowSpan() - 1;
1312 const int lastCol = cell.column() + cell.columnSpan() - 1;
1313 const double borderX = item->asTable()->columnPosition(lastCol) + item->asTable()->columnWidth(lastCol);
1314 QPointF start(borderX, 0.0);
1315 QPointF end(borderX, 0.0);
1316 QPointF startOffsetFactors, endOffsetFactors;
1317 int startRow, endRow;
1318 for (int row = cell.row(); row <= lastRow; row += endRow - startRow + 1)
1319 {
1320 TableCell rightCell = item->asTable()->cellAt(row, lastCol + 1);
1321 startRow = qMax(cell.row(), rightCell.row());
1322 endRow = qMin(lastRow, rightCell.isValid() ? rightCell.row() + rightCell.rowSpan() - 1 : lastRow);
1323 TableCell topLeftCell = item->asTable()->cellAt(startRow - 1, lastCol);
1324 TableCell topRightCell = item->asTable()->cellAt(startRow - 1, lastCol + 1);
1325 TableCell bottomRightCell = item->asTable()->cellAt(endRow + 1, lastCol + 1);
1326 TableCell bottomLeftCell = item->asTable()->cellAt(endRow + 1, lastCol);
1327 TableBorder topLeft, top, topRight, border, bottomLeft, bottom, bottomRight;
1328 resolveBordersVertical(topLeftCell, topRightCell, cell, rightCell, bottomLeftCell, bottomRightCell,
1329 &topLeft, &top, &topRight, &border, &bottomLeft, &bottom, &bottomRight, item->asTable());
1330 if (border.isNull())
1331 continue; // Quit early if the border to paint is null.
1332 start.setY(item->asTable()->rowPosition(startRow));
1333 end.setY((item->asTable()->rowPosition(endRow) + item->asTable()->rowHeight(endRow)));
1334 joinVertical(border, topLeft, top, topRight, bottomLeft, bottom, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
1335 paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, ob);
1336 }
1337 if (col == 0)
1338 {
1339 const int lastRow = cell.row() + cell.rowSpan() - 1;
1340 const int firstCol = cell.column();
1341 const double borderX = item->asTable()->columnPosition(firstCol);
1342 QPointF start(borderX, 0.0);
1343 QPointF end(borderX, 0.0);
1344 QPointF startOffsetFactors, endOffsetFactors;
1345 int startRow, endRow;
1346 for (int row = cell.row(); row <= lastRow; row += endRow - startRow + 1)
1347 {
1348 TableCell leftCell = item->asTable()->cellAt(row, firstCol - 1);
1349 startRow = qMax(cell.row(), leftCell.row());
1350 endRow = qMin(lastRow, leftCell.isValid() ? leftCell.row() + leftCell.rowSpan() - 1 : lastRow);
1351 TableCell topLeftCell = item->asTable()->cellAt(startRow - 1, firstCol - 1);
1352 TableCell topRightCell = item->asTable()->cellAt(startRow - 1, firstCol);
1353 TableCell bottomRightCell = item->asTable()->cellAt(lastRow + 1, firstCol);
1354 TableCell bottomLeftCell = item->asTable()->cellAt(lastRow + 1, firstCol - 1);
1355 TableBorder topLeft, top, topRight, border, bottomLeft, bottom, bottomRight;
1356 resolveBordersVertical(topLeftCell, topRightCell, leftCell, cell, bottomLeftCell, bottomRightCell,
1357 &topLeft, &top, &topRight, &border, &bottomLeft, &bottom, &bottomRight, item->asTable());
1358 if (border.isNull())
1359 continue; // Quit early if the border to paint is null.
1360 start.setY(item->asTable()->rowPosition(startRow));
1361 end.setY((item->asTable()->rowPosition(endRow) + item->asTable()->rowHeight(endRow)));
1362 joinVertical(border, topLeft, top, topRight, bottomLeft, bottom, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
1363 paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, ob);
1364 }
1365 }
1366 }
1367 colSpan = cell.columnSpan();
1368 }
1369 }
1370 // Pass 3: Paint horizontal borders.
1371 for (int row = 0; row < item->asTable()->rows(); ++row)
1372 {
1373 int colSpan = 0;
1374 for (int col = 0; col < item->asTable()->columns(); col += colSpan)
1375 {
1376 TableCell cell = item->asTable()->cellAt(row, col);
1377 if (row == cell.row())
1378 {
1379 const int lastRow = cell.row() + cell.rowSpan() - 1;
1380 const int lastCol = cell.column() + cell.columnSpan() - 1;
1381 const double borderY = (item->asTable()->rowPosition(lastRow) + item->asTable()->rowHeight(lastRow));
1382 QPointF start(0.0, borderY);
1383 QPointF end(0.0, borderY);
1384 QPointF startOffsetFactors, endOffsetFactors;
1385 int startCol, endCol;
1386 for (int col = cell.column(); col <= lastCol; col += endCol - startCol + 1)
1387 {
1388 TableCell bottomCell = item->asTable()->cellAt(lastRow + 1, col);
1389 startCol = qMax(cell.column(), bottomCell.column());
1390 endCol = qMin(lastCol, bottomCell.isValid() ? bottomCell.column() + bottomCell.columnSpan() - 1 : lastCol);
1391 TableCell topLeftCell = item->asTable()->cellAt(lastRow, startCol - 1);
1392 TableCell topRightCell = item->asTable()->cellAt(lastRow, endCol + 1);
1393 TableCell bottomRightCell = item->asTable()->cellAt(lastRow + 1, endCol + 1);
1394 TableCell bottomLeftCell = item->asTable()->cellAt(lastRow + 1, startCol - 1);
1395 TableBorder topLeft, left, bottomLeft, border, topRight, right, bottomRight;
1396 resolveBordersHorizontal(topLeftCell, cell, topRightCell, bottomLeftCell, bottomCell,
1397 bottomRightCell, &topLeft, &left, &bottomLeft, &border, &topRight, &right, &bottomRight, item->asTable());
1398 if (border.isNull())
1399 continue; // Quit early if the border is null.
1400 start.setX(item->asTable()->columnPosition(startCol));
1401 end.setX(item->asTable()->columnPosition(endCol) + item->asTable()->columnWidth(endCol));
1402 joinHorizontal(border, topLeft, left, bottomLeft, topRight, right, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
1403 paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, ob);
1404 }
1405 if (row == 0)
1406 {
1407 const int firstRow = cell.row();
1408 const int lastCol = cell.column() + cell.columnSpan() - 1;
1409 const double borderY = item->asTable()->rowPosition(firstRow);
1410 QPointF start(0.0, borderY);
1411 QPointF end(0.0, borderY);
1412 QPointF startOffsetFactors, endOffsetFactors;
1413 int startCol, endCol;
1414 for (int col = cell.column(); col <= lastCol; col += endCol - startCol + 1)
1415 {
1416 TableCell topCell = item->asTable()->cellAt(firstRow - 1, col);
1417 startCol = qMax(cell.column(), topCell.column());
1418 endCol = qMin(lastCol, topCell.isValid() ? topCell.column() + topCell.columnSpan() - 1 : lastCol);
1419 TableCell topLeftCell = item->asTable()->cellAt(firstRow - 1, startCol - 1);
1420 TableCell topRightCell = item->asTable()->cellAt(firstRow - 1, endCol + 1);
1421 TableCell bottomRightCell = item->asTable()->cellAt(firstRow, endCol + 1);
1422 TableCell bottomLeftCell = item->asTable()->cellAt(firstRow, startCol - 1);
1423 TableBorder topLeft, left, bottomLeft, border, topRight, right, bottomRight;
1424 resolveBordersHorizontal(topLeftCell, topCell, topRightCell, bottomLeftCell, cell,
1425 bottomRightCell, &topLeft, &left, &bottomLeft, &border, &topRight, &right, &bottomRight, item->asTable());
1426 if (border.isNull())
1427 continue; // Quit early if the border is null.
1428 start.setX(item->asTable()->columnPosition(startCol));
1429 end.setX(item->asTable()->columnPosition(endCol) + item->asTable()->columnWidth(endCol));
1430 joinHorizontal(border, topLeft, left, bottomLeft, topRight, right, bottomRight, &start, &end, &startOffsetFactors, &endOffsetFactors);
1431 paintBorder(border, start, end, startOffsetFactors, endOffsetFactors, ob);
1432 }
1433 }
1434 }
1435 colSpan = cell.columnSpan();
1436 }
1437 }
1438 // Pass 4: Paint cell content.
1439 for (int row = 0; row < item->asTable()->rows(); ++row)
1440 {
1441 for (int col = 0; col < item->asTable()->columns(); col ++)
1442 {
1443 TableCell cell = item->asTable()->cellAt(row, col);
1444 if (cell.row() == row && cell.column() == col)
1445 {
1446 PageItem* textFrame = cell.textFrame();
1447 processTextItem(cell.contentRect().x(), cell.contentRect().y(), textFrame, ob, rel_root);
1448 }
1449 }
1450 }
1451 if (item->GrMask > 0)
1452 handleMask(1, item, ob, rel_root, xOffset, yOffset);
1453 else
1454 {
1455 if (item->fillTransparency() != 0)
1456 ob.setAttribute("Opacity", FToStr(1.0 - item->fillTransparency()));
1457 }
1458 parentElem.appendChild(ob);
1459 }
1460
paintBorder(const TableBorder & border,const QPointF & start,const QPointF & end,const QPointF & startOffsetFactors,const QPointF & endOffsetFactors,QDomElement & ob)1461 void XPSExPlug::paintBorder(const TableBorder& border, const QPointF& start, const QPointF& end, const QPointF& startOffsetFactors, const QPointF& endOffsetFactors, QDomElement &ob)
1462 {
1463 QPointF lineStart, lineEnd;
1464 for (const TableBorderLine& line : border.borderLines())
1465 {
1466 lineStart.setX(start.x() + line.width() * startOffsetFactors.x());
1467 lineStart.setY(start.y() + line.width() * startOffsetFactors.y());
1468 lineEnd.setX(end.x() + line.width() * endOffsetFactors.x());
1469 lineEnd.setY(end.y() + line.width() * endOffsetFactors.y());
1470 QDomElement cl = p_docu.createElement("Path");
1471 cl.setAttribute("Data", "M" + FToStr(lineStart.x() * conversionFactor) + "," + FToStr(lineStart.y() * conversionFactor) + " L" + FToStr(lineEnd.x() * conversionFactor) + " " + FToStr(lineEnd.y() * conversionFactor));
1472 QString dashVals = "";
1473 if (line.style() != Qt::SolidLine)
1474 dashVals = getDashString(line.style(), qMax(line.width(), 1.0));
1475 if (!dashVals.isEmpty())
1476 cl.setAttribute("StrokeDashArray", dashVals);
1477 if (line.color() != CommonStrings::None)
1478 cl.setAttribute("Stroke", setColor(line.color(), line.shade(), 0));
1479 if (line.width() != 0.0)
1480 cl.setAttribute("StrokeThickness", FToStr(line.width() * conversionFactor));
1481 else
1482 cl.setAttribute("StrokeThickness", FToStr(1.0 * conversionFactor));
1483 ob.appendChild(cl);
1484 }
1485 }
1486
processHatchFill(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)1487 void XPSExPlug::processHatchFill(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
1488 {
1489 QDomElement obC = p_docu.createElement("Canvas");
1490 FPointArray path = item->PoLine.copy();
1491 path.scale(conversionFactor, conversionFactor);
1492 setClipAttr(obC, &path, item->fillRule);
1493 if (item->GrMask > 0)
1494 handleMask(1, item, obC, rel_root, xOffset, yOffset);
1495 else
1496 {
1497 if (item->fillTransparency() != 0)
1498 obC.setAttribute("Opacity", FToStr(1.0 - item->fillTransparency()));
1499 }
1500 QTransform mpo;
1501 mpo.translate(xOffset * conversionFactor, yOffset * conversionFactor);
1502 if (item->rotation() != 0.0)
1503 mpo.rotate(item->rotation());
1504 obC.setAttribute("RenderTransform", MatrixToStr(mpo));
1505 if (item->hatchUseBackground)
1506 {
1507 FPointArray path;
1508 path.svgInit();
1509 path.svgMoveTo(0, 0);
1510 path.svgLineTo(item->width(), 0);
1511 path.svgLineTo(item->width(), item->height());
1512 path.svgLineTo(0, item->height());
1513 path.svgClosePath();
1514 path.scale(conversionFactor, conversionFactor);
1515 QString pa = setClipPath(&path, true);
1516 QDomElement cl = p_docu.createElement("Path");
1517 cl.setAttribute("Data", pa);
1518 cl.setAttribute("Fill", setColor(item->hatchBackground, 100, 0));
1519 obC.appendChild(cl);
1520 }
1521 double lineLen = sqrt((item->width() / 2.0) * (item->width() / 2.0) + (item->height() / 2.0) * (item->height() / 2.0)) * conversionFactor;
1522 double dist = 0.0;
1523 while (dist < lineLen)
1524 {
1525 QTransform mpx;
1526 mpx.translate((item->width() / 2.0) * conversionFactor, (item->height() / 2.0) * conversionFactor);
1527 if (item->hatchAngle != 0.0)
1528 mpx.rotate(-item->hatchAngle);
1529 QDomElement ob = p_docu.createElement("Path");
1530 ob.setAttribute("StrokeThickness", FToStr(conversionFactor));
1531 ob.setAttribute("StrokeDashCap", "Flat");
1532 ob.setAttribute("StrokeEndLineCap", "Flat");
1533 ob.setAttribute("StrokeStartLineCap", "Flat");
1534 ob.setAttribute("StrokeLineJoin", "Miter");
1535 ob.setAttribute("Stroke", setColor(item->hatchForeground, 100, 0));
1536 ob.setAttribute("Data", QString("M %1, %2 L %3, %4").arg(-lineLen).arg(dist).arg(lineLen).arg(dist));
1537 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1538 obC.appendChild(ob);
1539 if (dist > 0)
1540 {
1541 QDomElement ob = p_docu.createElement("Path");
1542 ob.setAttribute("StrokeThickness", FToStr(conversionFactor));
1543 ob.setAttribute("StrokeDashCap", "Flat");
1544 ob.setAttribute("StrokeEndLineCap", "Flat");
1545 ob.setAttribute("StrokeStartLineCap", "Flat");
1546 ob.setAttribute("StrokeLineJoin", "Miter");
1547 ob.setAttribute("Stroke", setColor(item->hatchForeground, 100, 0));
1548 ob.setAttribute("Data", QString("M %1, %2 L %3, %4").arg(-lineLen).arg(-dist).arg(lineLen).arg(-dist));
1549 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1550 obC.appendChild(ob);
1551 }
1552 dist += item->hatchDistance * conversionFactor;
1553 }
1554 if ((item->hatchType == 1) || (item->hatchType == 2))
1555 {
1556 dist = 0.0;
1557 while (dist < lineLen)
1558 {
1559 QTransform mpx;
1560 mpx.translate((item->width() / 2.0) * conversionFactor, (item->height() / 2.0) * conversionFactor);
1561 if (item->hatchAngle != 0.0)
1562 mpx.rotate(-item->hatchAngle + 90);
1563 QDomElement ob = p_docu.createElement("Path");
1564 ob.setAttribute("StrokeThickness", FToStr(conversionFactor));
1565 ob.setAttribute("StrokeDashCap", "Flat");
1566 ob.setAttribute("StrokeEndLineCap", "Flat");
1567 ob.setAttribute("StrokeStartLineCap", "Flat");
1568 ob.setAttribute("StrokeLineJoin", "Miter");
1569 ob.setAttribute("Stroke", setColor(item->hatchForeground, 100, 0));
1570 ob.setAttribute("Data", QString("M %1, %2 L %3, %4").arg(-lineLen).arg(dist).arg(lineLen).arg(dist));
1571 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1572 obC.appendChild(ob);
1573 if (dist > 0)
1574 {
1575 QDomElement ob = p_docu.createElement("Path");
1576 ob.setAttribute("StrokeThickness", FToStr(conversionFactor));
1577 ob.setAttribute("StrokeDashCap", "Flat");
1578 ob.setAttribute("StrokeEndLineCap", "Flat");
1579 ob.setAttribute("StrokeStartLineCap", "Flat");
1580 ob.setAttribute("StrokeLineJoin", "Miter");
1581 ob.setAttribute("Stroke", setColor(item->hatchForeground, 100, 0));
1582 ob.setAttribute("Data", QString("M %1, %2 L %3, %4").arg(-lineLen).arg(-dist).arg(lineLen).arg(-dist));
1583 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1584 obC.appendChild(ob);
1585 }
1586 dist += item->hatchDistance * conversionFactor;
1587 }
1588 }
1589 if (item->hatchType == 2)
1590 {
1591 dist = 0.0;
1592 while (dist < lineLen)
1593 {
1594 double dDist = dist * sqrt(2.0);
1595 QTransform mpx;
1596 mpx.translate((item->width() / 2.0) * conversionFactor, (item->height() / 2.0) * conversionFactor);
1597 if (item->hatchAngle != 0.0)
1598 mpx.rotate(-item->hatchAngle + 45);
1599 QDomElement ob = p_docu.createElement("Path");
1600 ob.setAttribute("StrokeThickness", FToStr(conversionFactor));
1601 ob.setAttribute("StrokeDashCap", "Flat");
1602 ob.setAttribute("StrokeEndLineCap", "Flat");
1603 ob.setAttribute("StrokeStartLineCap", "Flat");
1604 ob.setAttribute("StrokeLineJoin", "Miter");
1605 ob.setAttribute("Stroke", setColor(item->hatchForeground, 100, 0));
1606 ob.setAttribute("Data", QString("M %1, %2 L %3, %4").arg(-lineLen).arg(dDist).arg(lineLen).arg(dDist));
1607 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1608 obC.appendChild(ob);
1609 if (dist > 0)
1610 {
1611 QDomElement ob = p_docu.createElement("Path");
1612 ob.setAttribute("StrokeThickness", FToStr(conversionFactor));
1613 ob.setAttribute("StrokeDashCap", "Flat");
1614 ob.setAttribute("StrokeEndLineCap", "Flat");
1615 ob.setAttribute("StrokeStartLineCap", "Flat");
1616 ob.setAttribute("StrokeLineJoin", "Miter");
1617 ob.setAttribute("Stroke", setColor(item->hatchForeground, 100, 0));
1618 ob.setAttribute("Data", QString("M %1, %2 L %3, %4").arg(-lineLen).arg(-dDist).arg(lineLen).arg(-dDist));
1619 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1620 obC.appendChild(ob);
1621 }
1622 dist += item->hatchDistance * conversionFactor;
1623 }
1624 }
1625 parentElem.appendChild(obC);
1626 }
1627
processSymbolStroke(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)1628 void XPSExPlug::processSymbolStroke(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
1629 {
1630 QDomElement ob = p_docu.createElement("Canvas");
1631 QTransform mpx;
1632 mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
1633 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1634 QPainterPath path = item->PoLine.toQPainterPath(false);
1635 ScPattern pat = m_Doc->docPatterns[item->strokePattern()];
1636 double pLen = path.length() - ((pat.width / 2.0) * (item->patternStrokeScaleX / 100.0));
1637 double adv = pat.width * item->patternStrokeScaleX / 100.0 * item->patternStrokeSpace;
1638 double xpos = item->patternStrokeOffsetX * item->patternStrokeScaleX / 100.0;
1639 while (xpos < pLen)
1640 {
1641 double currPerc = path.percentAtLength(xpos);
1642 double currAngle = path.angleAtPercent(currPerc);
1643 if (currAngle <= 180.0)
1644 currAngle *= -1.0;
1645 else
1646 currAngle = 360.0 - currAngle;
1647 QPointF currPoint = path.pointAtPercent(currPerc);
1648 QTransform trans;
1649 trans.translate(currPoint.x() * conversionFactor, currPoint.y() * conversionFactor);
1650 trans.rotate(currAngle);
1651 trans.translate(0.0, item->patternStrokeOffsetY);
1652 trans.rotate(-item->patternStrokeRotation);
1653 trans.shear(item->patternStrokeSkewX, -item->patternStrokeSkewY);
1654 trans.scale(item->patternStrokeScaleX / 100.0, item->patternStrokeScaleY / 100.0);
1655 trans.translate(-pat.width / 2.0, -pat.height / 2.0);
1656 if (item->patternStrokeMirrorX)
1657 {
1658 trans.translate(pat.width, 0);
1659 trans.scale(-1, 1);
1660 }
1661 if (item->patternStrokeMirrorY)
1662 {
1663 trans.translate(0, pat.height);
1664 trans.scale(1, -1);
1665 }
1666 QDomElement obS = p_docu.createElement("Canvas");
1667 obS.setAttribute("RenderTransform", MatrixToStr(trans));
1668 for (int em = 0; em < pat.items.count(); ++em)
1669 {
1670 PageItem* embed = pat.items.at(em);
1671 writeItemOnPage(embed->gXpos, embed->gYpos, embed, obS, rel_root);
1672 }
1673 ob.appendChild(obS);
1674 xpos += adv;
1675 }
1676 parentElem.appendChild(ob);
1677 }
1678
processArrows(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root)1679 void XPSExPlug::processArrows(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root)
1680 {
1681 if (item->startArrowIndex() != 0)
1682 {
1683 QTransform arrowTrans;
1684 FPointArray arrow = m_Doc->arrowStyles().at(item->startArrowIndex()-1).points.copy();
1685 if (item->itemType() == PageItem::Line)
1686 {
1687 arrowTrans.translate(0, 0);
1688 arrowTrans.scale(item->startArrowScale() / 100.0, item->startArrowScale() / 100.0);
1689 if (item->NamedLStyle.isEmpty())
1690 {
1691 if (item->lineWidth() != 0.0)
1692 arrowTrans.scale(item->lineWidth(), item->lineWidth());
1693 }
1694 else
1695 {
1696 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
1697 if (ml[ml.size()-1].Width != 0.0)
1698 arrowTrans.scale(ml[ml.size()-1].Width, ml[ml.size()-1].Width);
1699 }
1700 arrowTrans.scale(-1,1);
1701 }
1702 else
1703 {
1704 FPoint Start = item->PoLine.point(0);
1705 for (int xx = 1; xx < item->PoLine.size(); xx += 2)
1706 {
1707 FPoint Vector = item->PoLine.point(xx);
1708 if ((Start.x() != Vector.x()) || (Start.y() != Vector.y()))
1709 {
1710 double r = atan2(Start.y()-Vector.y(),Start.x()-Vector.x())*(180.0/M_PI);
1711 arrowTrans.translate(Start.x(), Start.y());
1712 arrowTrans.rotate(r);
1713 arrowTrans.scale(item->startArrowScale() / 100.0, item->startArrowScale() / 100.0);
1714 if (item->NamedLStyle.isEmpty())
1715 {
1716 if (item->lineWidth() != 0.0)
1717 arrowTrans.scale(item->lineWidth(), item->lineWidth());
1718 }
1719 else
1720 {
1721 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
1722 if (ml[ml.size()-1].Width != 0.0)
1723 arrowTrans.scale(ml[ml.size()-1].Width, ml[ml.size()-1].Width);
1724 }
1725 break;
1726 }
1727 }
1728 }
1729 arrow.map(arrowTrans);
1730 drawArrow(xOffset, yOffset, item, parentElem, rel_root, arrow);
1731 }
1732 if (item->endArrowIndex() != 0)
1733 {
1734 QTransform arrowTrans;
1735 FPointArray arrow = m_Doc->arrowStyles().at(item->endArrowIndex()-1).points.copy();
1736 if (item->itemType() == PageItem::Line)
1737 {
1738 arrowTrans.translate(item->width(), 0);
1739 arrowTrans.scale(item->endArrowScale() / 100.0, item->endArrowScale() / 100.0);
1740 if (item->NamedLStyle.isEmpty())
1741 {
1742 if (item->lineWidth() != 0.0)
1743 arrowTrans.scale(item->lineWidth(), item->lineWidth());
1744 }
1745 else
1746 {
1747 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
1748 if (ml[ml.size()-1].Width != 0.0)
1749 arrowTrans.scale(ml[ml.size()-1].Width, ml[ml.size()-1].Width);
1750 }
1751 }
1752 else
1753 {
1754 FPoint End = item->PoLine.point(item->PoLine.size()-2);
1755 for (uint xx = item->PoLine.size()-1; xx > 0; xx -= 2)
1756 {
1757 FPoint Vector = item->PoLine.point(xx);
1758 if ((End.x() != Vector.x()) || (End.y() != Vector.y()))
1759 {
1760 double r = atan2(End.y()-Vector.y(),End.x()-Vector.x())*(180.0/M_PI);
1761 arrowTrans.translate(End.x(), End.y());
1762 arrowTrans.rotate(r);
1763 arrowTrans.scale(item->endArrowScale() / 100.0, item->endArrowScale() / 100.0);
1764 if (item->NamedLStyle.isEmpty())
1765 {
1766 if (item->lineWidth() != 0.0)
1767 arrowTrans.scale(item->lineWidth(), item->lineWidth());
1768 }
1769 else
1770 {
1771 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
1772 if (ml[ml.size()-1].Width != 0.0)
1773 arrowTrans.scale(ml[ml.size()-1].Width, ml[ml.size()-1].Width);
1774 }
1775 break;
1776 }
1777 }
1778 }
1779 arrow.map(arrowTrans);
1780 drawArrow(xOffset, yOffset, item, parentElem, rel_root, arrow);
1781 }
1782 }
1783
drawArrow(double xOffset,double yOffset,PageItem * item,QDomElement & parentElem,QDomElement & rel_root,FPointArray & arrow)1784 void XPSExPlug::drawArrow(double xOffset, double yOffset, PageItem *item, QDomElement &parentElem, QDomElement &rel_root, FPointArray &arrow)
1785 {
1786 QTransform mpx;
1787 if (item->rotation() != 0.0)
1788 {
1789 mpx.translate(xOffset * conversionFactor, yOffset * conversionFactor);
1790 mpx.rotate(item->rotation());
1791 mpx.translate(-xOffset * conversionFactor, -yOffset * conversionFactor);
1792 }
1793 arrow.translate(xOffset, yOffset);
1794 arrow.scale(conversionFactor, conversionFactor);
1795 QString pa = setClipPath(&arrow, true);
1796 if (item->NamedLStyle.isEmpty())
1797 {
1798 QDomElement ob = p_docu.createElement("Path");
1799 ob.setAttribute("Data", pa);
1800 ob.setAttribute("RenderTransform", MatrixToStr(mpx));
1801 getStrokeStyle(item, ob, rel_root, xOffset, yOffset, true);
1802 parentElem.appendChild(ob);
1803 }
1804 else
1805 {
1806 QDomElement grp2 = p_docu.createElement("Canvas");
1807 grp2.setAttribute("RenderTransform", MatrixToStr(mpx));
1808 multiLine ml = m_Doc->docLineStyles[item->NamedLStyle];
1809 if (ml[0].Color != CommonStrings::None)
1810 {
1811 QDomElement ob3 = p_docu.createElement("Path");
1812 ob3.setAttribute("Data", pa);
1813 ob3.setAttribute("Fill", setColor(ml[0].Color, ml[0].Shade, 0));
1814 getMultiStroke(&ml[0], ob3);
1815 grp2.appendChild(ob3);
1816 }
1817 for (int it = ml.size()-1; it > 0; it--)
1818 {
1819 if ((ml[it].Color != CommonStrings::None) && (ml[it].Width != 0))
1820 {
1821 QDomElement ob3 = p_docu.createElement("Path");
1822 ob3.setAttribute("Data", pa);
1823 getMultiStroke(&ml[it], ob3);
1824 grp2.appendChild(ob3);
1825 }
1826 }
1827 parentElem.appendChild(grp2);
1828 }
1829 }
1830
addFontRelationship(QDomElement & rel_root,const XPSResourceInfo & fontInfo)1831 void XPSExPlug::addFontRelationship(QDomElement &rel_root, const XPSResourceInfo& fontInfo)
1832 {
1833 QDomElement rel = r_docu.createElement("Relationship");
1834 rel.setAttribute("Id", fontInfo.id);
1835 rel.setAttribute("Type", "http://schemas.microsoft.com/xps/2005/06/required-resource");
1836 rel.setAttribute("Target", fontInfo.uri);
1837 rel_root.appendChild(rel);
1838 }
1839
embedFont(const ScFace & font,QDomElement & rel_root)1840 XPSResourceInfo XPSExPlug::embedFont(const ScFace& font, QDomElement &rel_root)
1841 {
1842 QByteArray fontData;
1843 loadRawText(font.fontFilePath(), fontData);
1844 QUuid id = QUuid::createUuid();
1845 QString guidString = id.toString();
1846 guidString = guidString.toUpper();
1847 guidString.remove("{");
1848 guidString.remove("}");
1849 unsigned short guid[16];
1850 const static int indexes[] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, 24, 26, 28, 30, 32, 34};
1851 for (int i = 0; i < 16; i++)
1852 {
1853 int hex1 = hex2int(guidString[indexes[i]].cell());
1854 int hex2 = hex2int(guidString[indexes[i]+1].cell());
1855 guid[i] = hex1 * 16 + hex2;
1856 }
1857 // Obfuscation - xor bytes in font binary with bytes from guid (font's filename)
1858 const static int mapping[] = {15, 14, 13, 12, 11, 10, 9, 8, 6, 7, 4, 5, 0, 1, 2, 3};
1859 for (int i = 0; i < 16; i++)
1860 {
1861 fontData[i] = fontData[i] ^ guid[mapping[i]];
1862 fontData[i+16] = fontData[i+16] ^ guid[mapping[i]];
1863 }
1864 QFile ft(baseDir + "/Resources/Fonts/" + guidString + ".odttf");
1865 if (ft.open(QIODevice::WriteOnly))
1866 {
1867 ft.write(fontData);
1868 ft.close();
1869 }
1870
1871 XPSResourceInfo rsrcInfo;
1872 rsrcInfo.id = QString("rIDf%1").arg(fontCounter);
1873 rsrcInfo.uri = "/Resources/Fonts/" + guidString + ".odttf";
1874 fontCounter++;
1875
1876 return rsrcInfo;
1877 }
1878
getMultiStroke(struct SingleLine * sl,QDomElement & parentElem)1879 void XPSExPlug::getMultiStroke(struct SingleLine *sl, QDomElement &parentElem)
1880 {
1881 parentElem.setAttribute("StrokeThickness", FToStr(sl->Width * conversionFactor));
1882 switch (static_cast<Qt::PenCapStyle>(sl->LineEnd))
1883 {
1884 case Qt::FlatCap:
1885 parentElem.setAttribute("StrokeDashCap", "Flat");
1886 parentElem.setAttribute("StrokeEndLineCap", "Flat");
1887 parentElem.setAttribute("StrokeStartLineCap", "Flat");
1888 break;
1889 case Qt::SquareCap:
1890 parentElem.setAttribute("StrokeDashCap", "Square");
1891 parentElem.setAttribute("StrokeEndLineCap", "Square");
1892 parentElem.setAttribute("StrokeStartLineCap", "Square");
1893 break;
1894 case Qt::RoundCap:
1895 parentElem.setAttribute("StrokeDashCap", "Round");
1896 parentElem.setAttribute("StrokeEndLineCap", "Round");
1897 parentElem.setAttribute("StrokeStartLineCap", "Round");
1898 break;
1899 default:
1900 parentElem.setAttribute("StrokeDashCap", "Flat");
1901 parentElem.setAttribute("StrokeEndLineCap", "Flat");
1902 parentElem.setAttribute("StrokeStartLineCap", "Flat");
1903 break;
1904 }
1905 switch (static_cast<Qt::PenJoinStyle>(sl->LineJoin))
1906 {
1907 case Qt::MiterJoin:
1908 parentElem.setAttribute("StrokeLineJoin", "Miter");
1909 break;
1910 case Qt::BevelJoin:
1911 parentElem.setAttribute("StrokeLineJoin", "Bevel");
1912 break;
1913 case Qt::RoundJoin:
1914 parentElem.setAttribute("StrokeLineJoin", "Round");
1915 break;
1916 default:
1917 parentElem.setAttribute("StrokeLineJoin", "Miter");
1918 break;
1919 }
1920 QString dashVals = "";
1921 if (static_cast<Qt::PenStyle>(sl->Dash) != Qt::SolidLine)
1922 dashVals = getDashString(sl->Dash, 1);
1923 if (!dashVals.isEmpty())
1924 parentElem.setAttribute("StrokeDashArray", dashVals);
1925 if (sl->Color != CommonStrings::None)
1926 parentElem.setAttribute("Stroke", setColor(sl->Color, sl->Shade, 0));
1927 }
1928
getStrokeStyle(PageItem * item,QDomElement & parentElem,QDomElement & rel_root,double xOffset,double yOffset,bool forArrow)1929 void XPSExPlug::getStrokeStyle(PageItem *item, QDomElement &parentElem, QDomElement &rel_root, double xOffset, double yOffset, bool forArrow)
1930 {
1931 parentElem.setAttribute("StrokeThickness", FToStr(item->lineWidth() * conversionFactor));
1932 switch (item->PLineEnd)
1933 {
1934 case Qt::FlatCap:
1935 parentElem.setAttribute("StrokeDashCap", "Flat");
1936 parentElem.setAttribute("StrokeEndLineCap", "Flat");
1937 parentElem.setAttribute("StrokeStartLineCap", "Flat");
1938 break;
1939 case Qt::SquareCap:
1940 parentElem.setAttribute("StrokeDashCap", "Square");
1941 parentElem.setAttribute("StrokeEndLineCap", "Square");
1942 parentElem.setAttribute("StrokeStartLineCap", "Square");
1943 break;
1944 case Qt::RoundCap:
1945 parentElem.setAttribute("StrokeDashCap", "Round");
1946 parentElem.setAttribute("StrokeEndLineCap", "Round");
1947 parentElem.setAttribute("StrokeStartLineCap", "Round");
1948 break;
1949 default:
1950 parentElem.setAttribute("StrokeDashCap", "Flat");
1951 parentElem.setAttribute("StrokeEndLineCap", "Flat");
1952 parentElem.setAttribute("StrokeStartLineCap", "Flat");
1953 break;
1954 }
1955 switch (item->PLineJoin)
1956 {
1957 case Qt::MiterJoin:
1958 parentElem.setAttribute("StrokeLineJoin", "Miter");
1959 break;
1960 case Qt::BevelJoin:
1961 parentElem.setAttribute("StrokeLineJoin", "Bevel");
1962 break;
1963 case Qt::RoundJoin:
1964 parentElem.setAttribute("StrokeLineJoin", "Round");
1965 break;
1966 default:
1967 parentElem.setAttribute("StrokeLineJoin", "Miter");
1968 break;
1969 }
1970 QString dashVals = "";
1971 if (item->DashValues.count() != 0)
1972 {
1973 for (auto it = item->DashValues.cbegin(); it != item->DashValues.cend(); ++it)
1974 {
1975 dashVals += FToStr((*it) / item->lineWidth()) + " ";
1976 }
1977 }
1978 else
1979 {
1980 if (item->PLineArt != Qt::SolidLine)
1981 dashVals = getDashString(item->PLineArt, 1);
1982 }
1983 if (!dashVals.isEmpty())
1984 {
1985 parentElem.setAttribute("StrokeDashArray", dashVals);
1986 if (item->DashValues.count() != 0)
1987 parentElem.setAttribute("StrokeDashOffset", FToStr(item->DashOffset));
1988 }
1989 if (item->GrTypeStroke == 0)
1990 {
1991 if (item->lineColor() != CommonStrings::None)
1992 {
1993 if (forArrow)
1994 parentElem.setAttribute("Fill", setColor(item->lineColor(), item->lineShade(), item->lineTransparency()));
1995 else
1996 parentElem.setAttribute("Stroke", setColor(item->lineColor(), item->lineShade(), item->lineTransparency()));
1997 return;
1998 }
1999 }
2000 else
2001 {
2002 if ((!item->strokePattern().isEmpty()) && (!item->patternStrokePath))
2003 {
2004 ScPattern pa = m_Doc->docPatterns[item->strokePattern()];
2005 QDomElement ob;
2006 if (forArrow)
2007 ob = p_docu.createElement("Path.Fill");
2008 else
2009 ob = p_docu.createElement("Path.Stroke");
2010 QDomElement gr = p_docu.createElement("VisualBrush");
2011 gr.setAttribute("TileMode", "Tile");
2012 gr.setAttribute("ViewboxUnits", "Absolute");
2013 gr.setAttribute("ViewportUnits", "Absolute");
2014 gr.setAttribute("Viewbox", QString("0, 0, %1, %2").arg(pa.width * conversionFactor).arg(pa.height * conversionFactor));
2015 double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation, patternSkewX, patternSkewY, patternSpace;
2016 item->strokePatternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation, patternSkewX, patternSkewY, patternSpace);
2017 patternScaleX /= 100.0;
2018 patternScaleY /= 100.0;
2019 double lw2 = item->lineWidth() / 2.0;
2020 gr.setAttribute("Viewport", QString("%1, %2, %3, %4").arg((xOffset + patternOffsetX - lw2) * conversionFactor).arg((yOffset + patternOffsetY - lw2) * conversionFactor).arg((pa.width * patternScaleX) * conversionFactor).arg((pa.height * patternScaleY) * conversionFactor));
2021 bool mirrorX, mirrorY;
2022 item->strokePatternFlip(mirrorX, mirrorY);
2023 if ((patternRotation != 0) || (patternSkewX != 0) || (patternSkewY != 0) || mirrorX || mirrorY)
2024 {
2025 QTransform mpa;
2026 mpa.rotate(patternRotation);
2027 mpa.shear(-patternSkewX, patternSkewY);
2028 mpa.scale(pa.scaleX, pa.scaleY);
2029 if (mirrorX)
2030 mpa.scale(-1, 1);
2031 if (mirrorY)
2032 mpa.scale(1, -1);
2033 gr.setAttribute("Transform", MatrixToStr(mpa));
2034 }
2035 if (item->lineTransparency() != 0)
2036 gr.setAttribute("Opacity", FToStr(1.0 - item->lineTransparency()));
2037 QDomElement grp = p_docu.createElement("VisualBrush.Visual");
2038 for (int em = 0; em < pa.items.count(); ++em)
2039 {
2040 PageItem* embed = pa.items.at(em);
2041 writeItemOnPage(embed->gXpos, embed->gYpos, embed, grp, rel_root);
2042 }
2043 gr.appendChild(grp);
2044 ob.appendChild(gr);
2045 parentElem.appendChild(ob);
2046 }
2047 else if ((item->GrTypeStroke == Gradient_Linear) || (item->GrTypeStroke == Gradient_Radial))
2048 {
2049 QDomElement ob;
2050 if (forArrow)
2051 ob = p_docu.createElement("Path.Fill");
2052 else
2053 ob = p_docu.createElement("Path.Stroke");
2054 QDomElement gr;
2055 double GrStartX = (item->GrStrokeStartX + xOffset) * conversionFactor;
2056 double GrStartY = (item->GrStrokeStartY + yOffset) * conversionFactor;
2057 double GrFocalX = (item->GrStrokeFocalX + xOffset) * conversionFactor;
2058 double GrFocalY = (item->GrStrokeFocalY + yOffset) * conversionFactor;
2059 double GrEndX = (item->GrStrokeEndX + xOffset) * conversionFactor;
2060 double GrEndY = (item->GrStrokeEndY + yOffset) * conversionFactor;
2061 if (item->GrTypeStroke == Gradient_Linear)
2062 {
2063 gr = p_docu.createElement("LinearGradientBrush");
2064 gr.setAttribute("MappingMode", "Absolute");
2065 gr.setAttribute("StartPoint", FToStr(GrStartX) + ", " + FToStr(GrStartY));
2066 gr.setAttribute("EndPoint", FToStr(GrEndX) + ", " + FToStr(GrEndY));
2067 }
2068 else
2069 {
2070 gr = p_docu.createElement("RadialGradientBrush");
2071 double rad = sqrt(pow(GrEndX - GrStartX, 2) + pow(GrEndY - GrStartY,2));
2072 gr.setAttribute("MappingMode", "Absolute");
2073 gr.setAttribute("RadiusX", FToStr(rad));
2074 gr.setAttribute("RadiusY", FToStr(rad));
2075 gr.setAttribute("Center", FToStr(GrStartX) + ", " + FToStr(GrStartY));
2076 gr.setAttribute("GradientOrigin", FToStr(GrFocalX) + ", " + FToStr(GrFocalY));
2077 }
2078 double gradientSkew;
2079 if (item->GrStrokeSkew == 90)
2080 gradientSkew = 1;
2081 else if (item->GrStrokeSkew == 180)
2082 gradientSkew = 0;
2083 else if (item->GrStrokeSkew == 270)
2084 gradientSkew = -1;
2085 else if (item->GrStrokeSkew == 390)
2086 gradientSkew = 0;
2087 else
2088 gradientSkew = tan(M_PI / 180.0 * item->GrStrokeSkew);
2089 QTransform qmatrix;
2090 if (item->GrTypeStroke == Gradient_Linear)
2091 {
2092 qmatrix.translate(GrStartX, GrStartY);
2093 qmatrix.shear(-gradientSkew, 0);
2094 qmatrix.translate(-GrStartX, -GrStartY);
2095 }
2096 else
2097 {
2098 double rotEnd = xy2Deg(GrEndX - GrStartX, GrEndY - GrStartY);
2099 qmatrix.translate(GrStartX, GrStartY);
2100 qmatrix.rotate(rotEnd);
2101 qmatrix.shear(gradientSkew, 0);
2102 qmatrix.translate(0, GrStartY * (1.0 - item->GrStrokeScale));
2103 qmatrix.translate(-GrStartX, -GrStartY);
2104 qmatrix.scale(1, item->GrStrokeScale);
2105 }
2106 gr.setAttribute("Transform", MatrixToStr(qmatrix));
2107 if (item->lineTransparency() != 0)
2108 gr.setAttribute("Opacity", FToStr(1.0 - item->lineTransparency()));
2109 QDomElement grs;
2110 if (item->GrTypeStroke == Gradient_Linear)
2111 grs = p_docu.createElement("LinearGradientBrush.GradientStops");
2112 else
2113 grs = p_docu.createElement("RadialGradientBrush.GradientStops");
2114 bool isFirst = true;
2115 double actualStop = 0.0, lastStop = 0.0;
2116 QList<VColorStop*> cstops = item->stroke_gradient.colorStops();
2117 for (int cst = 0; cst < item->stroke_gradient.stops(); ++cst)
2118 {
2119 actualStop = cstops.at(cst)->rampPoint;
2120 if ((actualStop != lastStop) || (isFirst))
2121 {
2122 QDomElement itcl = p_docu.createElement("GradientStop");
2123 itcl.setAttribute("Offset", FToStr(cstops.at(cst)->rampPoint));
2124 itcl.setAttribute("Color", setColor(cstops.at(cst)->name, cstops.at(cst)->shade, 1.0 - cstops.at(cst)->opacity));
2125 grs.appendChild(itcl);
2126 lastStop = actualStop;
2127 isFirst = false;
2128 }
2129 }
2130 gr.appendChild(grs);
2131 ob.appendChild(gr);
2132 parentElem.appendChild(ob);
2133 }
2134 }
2135 }
2136
getFillStyle(PageItem * item,QDomElement & parentElem,QDomElement & rel_root,double xOffset,double yOffset,bool withTransparency)2137 void XPSExPlug::getFillStyle(PageItem *item, QDomElement &parentElem, QDomElement &rel_root, double xOffset, double yOffset, bool withTransparency)
2138 {
2139 if (item->GrType == 0)
2140 {
2141 if (item->fillColor() != CommonStrings::None)
2142 {
2143 if ((withTransparency) || (item->GrMask == 0))
2144 parentElem.setAttribute("Fill", setColor(item->fillColor(), item->fillShade(), item->fillTransparency()));
2145 else
2146 parentElem.setAttribute("Fill", setColor(item->fillColor(), item->fillShade(), 0));
2147 }
2148 return;
2149 }
2150
2151 if ((item->GrType == Gradient_Linear) || (item->GrType == Gradient_Radial))
2152 {
2153 QDomElement ob = p_docu.createElement("Path.Fill");
2154 QDomElement gr;
2155 double GrStartX = (item->GrStartX + xOffset) * conversionFactor;
2156 double GrStartY = (item->GrStartY + yOffset) * conversionFactor;
2157 double GrFocalX = (item->GrFocalX + xOffset) * conversionFactor;
2158 double GrFocalY = (item->GrFocalY + yOffset) * conversionFactor;
2159 double GrEndX = (item->GrEndX + xOffset) * conversionFactor;
2160 double GrEndY = (item->GrEndY + yOffset) * conversionFactor;
2161 if (item->GrType == Gradient_Linear)
2162 {
2163 gr = p_docu.createElement("LinearGradientBrush");
2164 gr.setAttribute("MappingMode", "Absolute");
2165 gr.setAttribute("StartPoint", FToStr(GrStartX) + ", " + FToStr(GrStartY));
2166 gr.setAttribute("EndPoint", FToStr(GrEndX) + ", " + FToStr(GrEndY));
2167 }
2168 else
2169 {
2170 gr = p_docu.createElement("RadialGradientBrush");
2171 double rad = sqrt(pow(GrEndX - GrStartX, 2) + pow(GrEndY - GrStartY,2));
2172 gr.setAttribute("MappingMode", "Absolute");
2173 gr.setAttribute("RadiusX", FToStr(rad));
2174 gr.setAttribute("RadiusY", FToStr(rad));
2175 gr.setAttribute("Center", FToStr(GrStartX) + ", " + FToStr(GrStartY));
2176 gr.setAttribute("GradientOrigin", FToStr(GrFocalX) + ", " + FToStr(GrFocalY));
2177 }
2178 double gradientSkew;
2179 if (item->GrSkew == 90)
2180 gradientSkew = 1;
2181 else if (item->GrSkew == 180)
2182 gradientSkew = 0;
2183 else if (item->GrSkew == 270)
2184 gradientSkew = -1;
2185 else if (item->GrSkew == 390)
2186 gradientSkew = 0;
2187 else
2188 gradientSkew = tan(M_PI / 180.0 * item->GrSkew);
2189 QTransform qmatrix;
2190 if (item->GrType == Gradient_Linear)
2191 {
2192 qmatrix.translate(GrStartX, GrStartY);
2193 qmatrix.shear(-gradientSkew, 0);
2194 qmatrix.translate(-GrStartX, -GrStartY);
2195 }
2196 else
2197 {
2198 double rotEnd = xy2Deg(GrEndX - GrStartX, GrEndY - GrStartY);
2199 qmatrix.translate(GrStartX, GrStartY);
2200 qmatrix.rotate(rotEnd);
2201 qmatrix.shear(gradientSkew, 0);
2202 qmatrix.translate(0, GrStartY * (1.0 - item->GrScale));
2203 qmatrix.translate(-GrStartX, -GrStartY);
2204 qmatrix.scale(1, item->GrScale);
2205 }
2206 gr.setAttribute("Transform", MatrixToStr(qmatrix));
2207 if ((item->fillTransparency() != 0) && ((withTransparency) || (item->GrMask == 0)))
2208 gr.setAttribute("Opacity", FToStr(1.0 - item->fillTransparency()));
2209 QDomElement grs;
2210 if (item->GrType == Gradient_Linear)
2211 grs = p_docu.createElement("LinearGradientBrush.GradientStops");
2212 else
2213 grs = p_docu.createElement("RadialGradientBrush.GradientStops");
2214 bool isFirst = true;
2215 double actualStop = 0.0, lastStop = 0.0;
2216 QList<VColorStop*> cstops = item->fill_gradient.colorStops();
2217 for (int cst = 0; cst < item->fill_gradient.stops(); ++cst)
2218 {
2219 actualStop = cstops.at(cst)->rampPoint;
2220 if ((actualStop != lastStop) || (isFirst))
2221 {
2222 QDomElement itcl = p_docu.createElement("GradientStop");
2223 itcl.setAttribute("Offset", FToStr(cstops.at(cst)->rampPoint));
2224 itcl.setAttribute("Color", setColor(cstops.at(cst)->name, cstops.at(cst)->shade, 1.0 - cstops.at(cst)->opacity));
2225 grs.appendChild(itcl);
2226 lastStop = actualStop;
2227 isFirst = false;
2228 }
2229 }
2230 gr.appendChild(grs);
2231 ob.appendChild(gr);
2232 parentElem.appendChild(ob);
2233 }
2234 else if (item->GrType == 8)
2235 {
2236 ScPattern pa = m_Doc->docPatterns[item->pattern()];
2237 QDomElement ob = p_docu.createElement("Path.Fill");
2238 QDomElement gr = p_docu.createElement("VisualBrush");
2239 gr.setAttribute("TileMode", "Tile");
2240 gr.setAttribute("ViewboxUnits", "Absolute");
2241 gr.setAttribute("ViewportUnits", "Absolute");
2242 gr.setAttribute("Viewbox", QString("0, 0, %1, %2").arg(pa.width * conversionFactor).arg(pa.height * conversionFactor));
2243 double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation, patternSkewX, patternSkewY;
2244 item->patternTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation, patternSkewX, patternSkewY);
2245 patternScaleX /= 100.0;
2246 patternScaleY /= 100.0;
2247 gr.setAttribute("Viewport", QString("%1, %2, %3, %4").arg((xOffset + patternOffsetX) * conversionFactor).arg((yOffset + patternOffsetY) * conversionFactor).arg((pa.width * patternScaleX) * conversionFactor).arg((pa.height * patternScaleY) * conversionFactor));
2248 bool mirrorX, mirrorY;
2249 item->patternFlip(mirrorX, mirrorY);
2250 if ((patternRotation != 0) || (patternSkewX != 0) || (patternSkewY != 0) || mirrorX || mirrorY)
2251 {
2252 QTransform mpa;
2253 mpa.rotate(patternRotation);
2254 mpa.shear(-patternSkewX, patternSkewY);
2255 mpa.scale(pa.scaleX, pa.scaleY);
2256 if (mirrorX)
2257 mpa.scale(-1, 1);
2258 if (mirrorY)
2259 mpa.scale(1, -1);
2260 gr.setAttribute("Transform", MatrixToStr(mpa));
2261 }
2262 if ((item->fillTransparency() != 0) && ((withTransparency) || (item->GrMask == 0)))
2263 gr.setAttribute("Opacity", FToStr(1.0 - item->fillTransparency()));
2264 QDomElement grp = p_docu.createElement("VisualBrush.Visual");
2265 for (int em = 0; em < pa.items.count(); ++em)
2266 {
2267 PageItem* embed = pa.items.at(em);
2268 writeItemOnPage(embed->gXpos, embed->gYpos, embed, grp, rel_root);
2269 }
2270 gr.appendChild(grp);
2271 ob.appendChild(gr);
2272 parentElem.appendChild(ob);
2273 }
2274
2275 }
2276
handleMask(int type,PageItem * item,QDomElement & parentElem,QDomElement & rel_root,double xOffset,double yOffset)2277 void XPSExPlug::handleMask(int type, PageItem *item, QDomElement &parentElem, QDomElement &rel_root, double xOffset, double yOffset)
2278 {
2279 QDomElement ob;
2280 if (type == 1)
2281 ob = p_docu.createElement("Canvas.OpacityMask");
2282 else if (type == 2)
2283 ob = p_docu.createElement("Glyph.OpacityMask");
2284 else
2285 ob = p_docu.createElement("Path.OpacityMask");
2286 if ((item->GrMask == GradMask_Linear) || (item->GrMask == GradMask_Radial))
2287 {
2288 QDomElement gr;
2289 double GrStartX = (item->GrMaskStartX + xOffset) * conversionFactor;
2290 double GrStartY = (item->GrMaskStartY + yOffset) * conversionFactor;
2291 double GrFocalX = (item->GrMaskFocalX + xOffset) * conversionFactor;
2292 double GrFocalY = (item->GrMaskFocalY + yOffset) * conversionFactor;
2293 double GrEndX = (item->GrMaskEndX + xOffset) * conversionFactor;
2294 double GrEndY = (item->GrMaskEndY + yOffset) * conversionFactor;
2295 if ((item->GrMask == GradMask_Linear) || (item->GrMask == GradMask_LinearLumAlpha))
2296 {
2297 gr = p_docu.createElement("LinearGradientBrush");
2298 gr.setAttribute("MappingMode", "Absolute");
2299 gr.setAttribute("StartPoint", FToStr(GrStartX) + ", " + FToStr(GrStartY));
2300 gr.setAttribute("EndPoint", FToStr(GrEndX) + ", " + FToStr(GrEndY));
2301 }
2302 else
2303 {
2304 gr = p_docu.createElement("RadialGradientBrush");
2305 double rad = sqrt(pow(GrEndX - GrStartX, 2) + pow(GrEndY - GrStartY,2));
2306 gr.setAttribute("MappingMode", "Absolute");
2307 gr.setAttribute("RadiusX", FToStr(rad));
2308 gr.setAttribute("RadiusY", FToStr(rad));
2309 gr.setAttribute("Center", FToStr(GrStartX) + ", " + FToStr(GrStartY));
2310 gr.setAttribute("GradientOrigin", FToStr(GrFocalX) + ", " + FToStr(GrFocalY));
2311 }
2312 double gradientSkew;
2313 if (item->GrMaskSkew == 90)
2314 gradientSkew = 1;
2315 else if (item->GrMaskSkew == 180)
2316 gradientSkew = 0;
2317 else if (item->GrMaskSkew == 270)
2318 gradientSkew = -1;
2319 else if (item->GrMaskSkew == 390)
2320 gradientSkew = 0;
2321 else
2322 gradientSkew = tan(M_PI / 180.0 * item->GrMaskSkew);
2323 QTransform qmatrix;
2324 if (item->GrMask == GradMask_Linear)
2325 {
2326 qmatrix.translate(GrStartX, GrStartY);
2327 qmatrix.shear(-gradientSkew, 0);
2328 qmatrix.translate(-GrStartX, -GrStartY);
2329 }
2330 else
2331 {
2332 double rotEnd = xy2Deg(GrEndX - GrStartX, GrEndY - GrStartY);
2333 qmatrix.translate(GrStartX, GrStartY);
2334 qmatrix.rotate(rotEnd);
2335 qmatrix.shear(gradientSkew, 0);
2336 qmatrix.translate(0, GrStartY * (1.0 - item->GrMaskScale));
2337 qmatrix.translate(-GrStartX, -GrStartY);
2338 qmatrix.scale(1, item->GrMaskScale);
2339 }
2340 gr.setAttribute("Transform", MatrixToStr(qmatrix));
2341 QDomElement grs;
2342 if (item->GrMask == GradMask_Linear)
2343 grs = p_docu.createElement("LinearGradientBrush.GradientStops");
2344 else
2345 grs = p_docu.createElement("RadialGradientBrush.GradientStops");
2346 bool isFirst = true;
2347 double actualStop = 0.0, lastStop = 0.0;
2348 QList<VColorStop*> cstops = item->mask_gradient.colorStops();
2349 for (int cst = 0; cst < item->mask_gradient.stops(); ++cst)
2350 {
2351 actualStop = cstops.at(cst)->rampPoint;
2352 if ((actualStop != lastStop) || (isFirst))
2353 {
2354 QDomElement itcl = p_docu.createElement("GradientStop");
2355 itcl.setAttribute("Offset", FToStr(cstops.at(cst)->rampPoint));
2356 itcl.setAttribute("Color", setColor(cstops.at(cst)->name, cstops.at(cst)->shade, 1.0 - cstops.at(cst)->opacity));
2357 grs.appendChild(itcl);
2358 lastStop = actualStop;
2359 isFirst = false;
2360 }
2361 }
2362 gr.appendChild(grs);
2363 ob.appendChild(gr);
2364 }
2365 else if (item->GrMask == GradMask_Pattern)
2366 {
2367 ScPattern pa = m_Doc->docPatterns[item->patternMask()];
2368 QDomElement gr = p_docu.createElement("VisualBrush");
2369 gr.setAttribute("TileMode", "Tile");
2370 gr.setAttribute("ViewboxUnits", "Absolute");
2371 gr.setAttribute("ViewportUnits", "Absolute");
2372 gr.setAttribute("Viewbox", QString("0, 0, %1, %2").arg(pa.width * conversionFactor).arg(pa.height * conversionFactor));
2373 double patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation, patternSkewX, patternSkewY;
2374 item->maskTransform(patternScaleX, patternScaleY, patternOffsetX, patternOffsetY, patternRotation, patternSkewX, patternSkewY);
2375 patternScaleX /= 100.0;
2376 patternScaleY /= 100.0;
2377 gr.setAttribute("Viewport", QString("%1, %2, %3, %4").arg((xOffset + patternOffsetX) * conversionFactor).arg((yOffset + patternOffsetY) * conversionFactor).arg((pa.width * patternScaleX) * conversionFactor).arg((pa.height * patternScaleY) * conversionFactor));
2378 bool mirrorX, mirrorY;
2379 item->maskFlip(mirrorX, mirrorY);
2380 if ((patternRotation != 0) || (patternSkewX != 0) || (patternSkewY != 0) || mirrorX || mirrorY)
2381 {
2382 QTransform mpa;
2383 mpa.rotate(patternRotation);
2384 mpa.shear(-patternSkewX, patternSkewY);
2385 mpa.scale(pa.scaleX, pa.scaleY);
2386 if (mirrorX)
2387 mpa.scale(-1, 1);
2388 if (mirrorY)
2389 mpa.scale(1, -1);
2390 gr.setAttribute("Transform", MatrixToStr(mpa));
2391 }
2392 QDomElement grp = p_docu.createElement("VisualBrush.Visual");
2393 for (int em = 0; em < pa.items.count(); ++em)
2394 {
2395 PageItem* embed = pa.items.at(em);
2396 writeItemOnPage(embed->gXpos, embed->gYpos, embed, grp, rel_root);
2397 }
2398 gr.appendChild(grp);
2399 ob.appendChild(gr);
2400 }
2401 parentElem.appendChild(ob);
2402 }
2403
setColor(const QString & farbe,int shad,double transparency)2404 QString XPSExPlug::setColor(const QString& farbe, int shad, double transparency)
2405 {
2406 if (farbe == CommonStrings::None)
2407 return "#00FFFFFF";
2408 const ScColor& col = m_Doc->PageColors[farbe];
2409 QString color = ScColorEngine::getShadeColorProof(col, m_Doc, shad).name().mid(1);
2410 color = color.toUpper();
2411 QString alpha = "";
2412 alpha.setNum(qRound((1.0 - transparency) * 255), 16);
2413 alpha = alpha.toUpper();
2414 if (alpha.length() == 1)
2415 alpha.prepend("0");
2416 return "#" + alpha + color;
2417 }
2418
setClipAttr(QDomElement & elem,FPointArray * ite,bool fillRule)2419 void XPSExPlug::setClipAttr(QDomElement &elem, FPointArray *ite, bool fillRule)
2420 {
2421 QString pathStr = setClipPath(ite, true);
2422 if (pathStr.length() > 0)
2423 {
2424 if (fillRule)
2425 pathStr.prepend("F 0 ");
2426 else
2427 pathStr.prepend("F 1 ");
2428 elem.setAttribute("Clip", pathStr);
2429 }
2430 }
2431
setClipPath(FPointArray * ite,bool closed)2432 QString XPSExPlug::setClipPath(FPointArray *ite, bool closed)
2433 {
2434 QString tmp;
2435 FPoint np, np1, np2, np3, np4, firstP;
2436 bool nPath = true;
2437 bool first = true;
2438 if (ite->size() <= 3)
2439 return tmp;
2440
2441 for (int poi=0; poi<ite->size()-3; poi += 4)
2442 {
2443 if (ite->isMarker(poi))
2444 {
2445 nPath = true;
2446 continue;
2447 }
2448 if (nPath)
2449 {
2450 np = ite->point(poi);
2451 if ((!first) && (closed) && (np4 == firstP))
2452 tmp += "Z ";
2453 tmp += QString("M%1,%2 ").arg(np.x()).arg(np.y());
2454 nPath = false;
2455 first = false;
2456 firstP = np;
2457 np4 = np;
2458 }
2459 np = ite->point(poi);
2460 np1 = ite->point(poi+1);
2461 np2 = ite->point(poi+3);
2462 np3 = ite->point(poi+2);
2463 if ((np == np1) && (np2 == np3))
2464 tmp += QString("L%1,%2 ").arg(np3.x()).arg(np3.y());
2465 else
2466 tmp += QString("C%1,%2 %3,%4 %5,%6 ").arg(np1.x()).arg(np1.y()).arg(np2.x()).arg(np2.y()).arg(np3.x()).arg(np3.y());
2467 np4 = np3;
2468 }
2469 if (closed)
2470 tmp += "Z";
2471 return tmp;
2472 }
2473
writeDocRels()2474 void XPSExPlug::writeDocRels()
2475 {
2476 // Create and write required "Documents/1/_rels/FixedDoc.fdoc.rels" file
2477 QDomDocument doc("rels");
2478 QString st = "<Relationships></Relationships>";
2479 doc.setContent(st);
2480 QDomElement root = doc.documentElement();
2481 root.setAttribute("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships");
2482 doc.appendChild(root);
2483 QFile ft(baseDir + "/Documents/1/_rels/FixedDoc.fdoc.rels");
2484 if (ft.open(QIODevice::WriteOnly))
2485 {
2486 QString vo = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
2487 QDataStream s(&ft);
2488 vo += doc.toString();
2489 QByteArray utf8wr = vo.toUtf8();
2490 s.writeRawData(utf8wr.data(), utf8wr.length());
2491 ft.close();
2492 }
2493 }
2494
writeCore()2495 void XPSExPlug::writeCore()
2496 {
2497 // Create and write required "docProps/core.xml" file
2498 QDomDocument doc("rels");
2499 QString st = "<cp:coreProperties></cp:coreProperties>";
2500 doc.setContent(st);
2501 QDomElement root = doc.documentElement();
2502 root.setAttribute("xmlns:cp", "http://schemas.openxmlformats.org/package/2006/metadata/core-properties");
2503 root.setAttribute("xmlns:dc", "http://purl.org/dc/elements/1.1/");
2504 root.setAttribute("xmlns:dcterms", "http://purl.org/dc/terms/");
2505 root.setAttribute("xmlns:dcmitype", "http://purl.org/dc/dcmitype/");
2506 root.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
2507 QDomElement rel1 = doc.createElement("dc:creator");
2508 rel1.setNodeValue("");
2509 root.appendChild(rel1);
2510 QDomElement rel2 = doc.createElement("dcterms:created");
2511 rel2.setAttribute("xsi:type", "dcterms:W3CDTF");
2512 rel2.setNodeValue("");
2513 root.appendChild(rel2);
2514 QDomElement rel3 = doc.createElement("dcterms:modified");
2515 rel3.setNodeValue("");
2516 rel3.setAttribute("xsi:type", "dcterms:W3CDTF");
2517 root.appendChild(rel3);
2518 doc.appendChild(root);
2519 QFile ft(baseDir + "/docProps/core.xml");
2520 if (ft.open(QIODevice::WriteOnly))
2521 {
2522 QString vo = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
2523 QDataStream s(&ft);
2524 vo += doc.toString();
2525 QByteArray utf8wr = vo.toUtf8();
2526 s.writeRawData(utf8wr.data(), utf8wr.length());
2527 ft.close();
2528 }
2529 }
2530
writeContentType()2531 void XPSExPlug::writeContentType()
2532 {
2533 // Create and write required "[Content_Type].xml" file
2534 QDomDocument doc("Content_Type");
2535 QString st = "<Types></Types>";
2536 doc.setContent(st);
2537 QDomElement root = doc.documentElement();
2538 root.setAttribute("xmlns", "http://schemas.openxmlformats.org/package/2006/content-types");
2539 QDomElement rel1 = doc.createElement("Default");
2540 rel1.setAttribute("Extension", "png");
2541 rel1.setAttribute("ContentType", "image/png");
2542 root.appendChild(rel1);
2543 QDomElement rel2 = doc.createElement("Default");
2544 rel2.setAttribute("Extension", "jpeg");
2545 rel2.setAttribute("ContentType", "image/jpeg");
2546 root.appendChild(rel2);
2547 QDomElement rel3 = doc.createElement("Default");
2548 rel3.setAttribute("Extension", "jpg");
2549 rel3.setAttribute("ContentType", "image/jpeg");
2550 root.appendChild(rel3);
2551 QDomElement rel4 = doc.createElement("Default");
2552 rel4.setAttribute("Extension", "rels");
2553 rel4.setAttribute("ContentType", "application/vnd.openxmlformats-package.relationships+xml");
2554 root.appendChild(rel4);
2555 QDomElement rel5 = doc.createElement("Default");
2556 rel5.setAttribute("Extension", "xml");
2557 rel5.setAttribute("ContentType", "application/xml");
2558 root.appendChild(rel5);
2559 QDomElement rel6 = doc.createElement("Default");
2560 rel6.setAttribute("Extension", "fdseq");
2561 rel6.setAttribute("ContentType", "application/vnd.ms-package.xps-fixeddocumentsequence+xml");
2562 root.appendChild(rel6);
2563 QDomElement rel7 = doc.createElement("Default");
2564 rel7.setAttribute("Extension", "fpage");
2565 rel7.setAttribute("ContentType", "application/vnd.ms-package.xps-fixedpage+xml");
2566 root.appendChild(rel7);
2567 QDomElement rel8 = doc.createElement("Default");
2568 rel8.setAttribute("Extension", "struct");
2569 rel8.setAttribute("ContentType", "application/vnd.ms-package.xps-documentstructure+xml");
2570 root.appendChild(rel8);
2571 QDomElement rel9 = doc.createElement("Default");
2572 rel9.setAttribute("Extension", "fdoc");
2573 rel9.setAttribute("ContentType", "application/vnd.ms-package.xps-fixeddocument+xml");
2574 root.appendChild(rel9);
2575 QDomElement rel10 = doc.createElement("Default");
2576 rel10.setAttribute("Extension", "odttf");
2577 rel10.setAttribute("ContentType", "application/vnd.ms-package.obfuscated-opentype");
2578 root.appendChild(rel10);
2579 QDomElement rel11 = doc.createElement("Default");
2580 rel11.setAttribute("Extension", "dict");
2581 rel11.setAttribute("ContentType", "application/vnd.ms-package.xps-resourcedictionary+xml");
2582 root.appendChild(rel11);
2583 QDomElement rel12 = doc.createElement("Override");
2584 rel12.setAttribute("PartName", "/docProps/core.xml");
2585 rel12.setAttribute("ContentType", "application/vnd.openxmlformats-package.core-properties+xml");
2586 root.appendChild(rel12);
2587 doc.appendChild(root);
2588 QFile ft(baseDir + "/[Content_Types].xml");
2589 if (ft.open(QIODevice::WriteOnly))
2590 {
2591 QString vo = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
2592 QDataStream s(&ft);
2593 vo += doc.toString();
2594 QByteArray utf8wr = vo.toUtf8();
2595 s.writeRawData(utf8wr.data(), utf8wr.length());
2596 ft.close();
2597 }
2598 }
2599
writeBaseRel()2600 void XPSExPlug::writeBaseRel()
2601 {
2602 // Create and write required "_rels/.rels" file
2603 QDomDocument doc("rels");
2604 QString st = "<Relationships></Relationships>";
2605 doc.setContent(st);
2606 QDomElement root = doc.documentElement();
2607 root.setAttribute("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships");
2608 QDomElement rel1 = doc.createElement("Relationship");
2609 rel1.setAttribute("Id", "rID1");
2610 rel1.setAttribute("Type", "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties");
2611 rel1.setAttribute("Target", "docProps/core.xml");
2612 root.appendChild(rel1);
2613 QDomElement rel2 = doc.createElement("Relationship");
2614 rel2.setAttribute("Id", "rID2");
2615 rel2.setAttribute("Type", "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail");
2616 rel2.setAttribute("Target", "docProps/thumbnail.jpeg");
2617 root.appendChild(rel2);
2618 QDomElement rel3 = doc.createElement("Relationship");
2619 rel3.setAttribute("Id", "rID3");
2620 rel3.setAttribute("Type", "http://schemas.microsoft.com/xps/2005/06/fixedrepresentation");
2621 rel3.setAttribute("Target", "FixedDocSeq.fdseq");
2622 root.appendChild(rel3);
2623 doc.appendChild(root);
2624 QFile ft(baseDir + "/_rels/.rels");
2625 if (ft.open(QIODevice::WriteOnly))
2626 {
2627 QString vo = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n";
2628 QDataStream s(&ft);
2629 vo += doc.toString();
2630 QByteArray utf8wr = vo.toUtf8();
2631 s.writeRawData(utf8wr.data(), utf8wr.length());
2632 ft.close();
2633 }
2634 }
2635
FToStr(double c)2636 QString XPSExPlug::FToStr(double c)
2637 {
2638 QString cc;
2639 return cc.setNum(c);
2640 }
2641
IToStr(int c)2642 QString XPSExPlug::IToStr(int c)
2643 {
2644 QString cc;
2645 return cc.setNum(c);
2646 }
2647
MatrixToStr(QTransform & mat,double factor)2648 QString XPSExPlug::MatrixToStr(QTransform &mat, double factor)
2649 {
2650 QString cc("%1, %2, %3, %4, %5, %6");
2651 return cc.arg(mat.m11()).arg(mat.m12()).arg(mat.m21()).arg(mat.m22()).arg(mat.dx() * factor).arg(mat.dy() * factor);
2652 }
2653
MatrixToStr(QTransform & mat)2654 QString XPSExPlug::MatrixToStr(QTransform &mat)
2655 {
2656 QString cc("%1, %2, %3, %4, %5, %6");
2657 return cc.arg(mat.m11()).arg(mat.m12()).arg(mat.m21()).arg(mat.m22()).arg(mat.dx()).arg(mat.dy());
2658 }
2659
hex2int(char hex)2660 int XPSExPlug::hex2int(char hex)
2661 {
2662 QChar hexchar = QLatin1Char(hex);
2663 int v;
2664 if (hexchar.isDigit())
2665 v = hexchar.digitValue();
2666 else if (hexchar >= QLatin1Char('A') && hexchar <= QLatin1Char('F'))
2667 v = hexchar.cell() - 'A' + 10;
2668 else if (hexchar >= QLatin1Char('a') && hexchar <= QLatin1Char('f'))
2669 v = hexchar.cell() - 'a' + 10;
2670 else
2671 v = -1;
2672 return v;
2673 }
2674
checkForFallback(PageItem * item)2675 bool XPSExPlug::checkForFallback(PageItem *item)
2676 {
2677 bool ret = false;
2678 int GrType = item->GrType;
2679 int GrMask = item->GrMask;
2680 if ((GrType == Gradient_4Colors) || (GrType == Gradient_Diamond) || (GrType == Gradient_Mesh) || (GrType == Gradient_PatchMesh) || (GrType == Gradient_Conical))
2681 ret = true;
2682 if ((GrMask == GradMask_LinearLumAlpha) || (GrMask == GradMask_RadialLumAlpha) || (GrMask == GradMask_PatternLumAlpha) || (GrMask == GradMask_PatternLumAlphaInverted) || (GrMask == GradMask_PatternInverted))
2683 ret = true;
2684 if (item->fillBlendmode() != 0)
2685 ret = true;
2686 if (item->lineBlendmode() != 0)
2687 ret = true;
2688 if (item->hasSoftShadow())
2689 ret = true;
2690 return ret;
2691 }
2692
~XPSExPlug()2693 XPSExPlug::~XPSExPlug()
2694 {
2695 }
2696