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                  	scribusXml.cpp the document xml library for scribus
9                              -------------------
10     begin                : Sam Jul 14 10:00:00 CEST 2001
11     copyright            : (C) 2001 by Christian T�p
12     email                : christian.toepp@mr-ct@gmx.de
13  ***************************************************************************/
14 
15 #include "scribusXml.h"
16 
17 #include <QApplication>
18 #include <QByteArray>
19 #include <QBuffer>
20 #include <QCursor>
21 #include <QDir>
22 #include <QFile>
23 #include <QRegExp>
24 #include <QTextCodec>
25 #include <QTextStream>
26 #include <QXmlStreamReader>
27 #include <QDebug>
28 
29 #include <cstdlib>
30 
31 #include "commonstrings.h"
32 #include "pageitem.h"
33 #include "pageitem_latexframe.h"
34 #ifdef HAVE_OSG
35 	#include "pageitem_osgframe.h"
36 #endif
37 #include "prefsmanager.h"
38 #include "scclocale.h"
39 #include "scmimedata.h"
40 #include "scpage.h"
41 #include "scpaths.h"
42 #include "scribusdoc.h"
43 #include "selection.h"
44 #include "units.h"
45 
46 #include <iostream>
47 
48 #include "scconfig.h"
49 
50 #include "util.h"
51 #include "util_text.h"
52 #include "util_math.h"
53 #include "util_color.h"
54 #include "sclimits.h"
55 #include "scpattern.h"
56 #include "sctextstream.h"
57 #include "scxmlstreamwriter.h"
58 #include "scpainter.h"
59 #include "fileloader.h"
60 #include "loadsaveplugin.h"
61 #include "plugins/formatidlist.h"
62 
63 using namespace std;
64 
ScriXmlDoc()65 ScriXmlDoc::ScriXmlDoc()
66 {
67 }
68 
readElemHeader(const QString & file,bool isFile,double * x,double * y,double * w,double * h)69 bool ScriXmlDoc::readElemHeader(const QString& file, bool isFile, double *x, double *y, double *w, double *h)
70 {
71 	QString ff = "";
72 	if (isFile)
73 	{
74 		QByteArray f;
75 		if (!loadRawText(file, f))
76 			return false;
77 		if (f.left(16) == "<SCRIBUSELEMUTF8")
78 			ff = QString::fromUtf8(f.data());
79 		else
80 			ff = f;
81 	}
82 	else
83 		ff  = file;
84 
85 	bool succeed = false;
86 	QStringRef tName;
87 	QXmlStreamReader sReader(ff);
88 	QXmlStreamReader::TokenType tType;
89 	while (!sReader.atEnd() && !sReader.hasError())
90 	{
91 		tType = sReader.readNext();
92 		if (tType == QXmlStreamReader::StartElement)
93 		{
94 			tName = sReader.name();
95 			if ((tName == "SCRIBUSELEM") || (tName == "SCRIBUSELEMUTF8"))
96 			{
97 				QXmlStreamAttributes attrs = sReader.attributes();;
98 				QString attx = attrs.value("XP").toString();
99 				QString atty = attrs.value("YP").toString();
100 				QString attw = attrs.value("W").toString();
101 				QString atth = attrs.value("H").toString();
102 				*x = (attx.isEmpty()) ? 0.0 : ScCLocale::toDoubleC(attx);
103 				*y = (atty.isEmpty()) ? 0.0 : ScCLocale::toDoubleC(atty);
104 				*w = (attw.isEmpty()) ? 0.0 : ScCLocale::toDoubleC(attw);
105 				*h = (atth.isEmpty()) ? 0.0 : ScCLocale::toDoubleC(atth);
106 				succeed = true;
107 			}
108 		}
109 	}
110 	return (succeed && !sReader.hasError());
111 }
112 
readElem(const QString & fileNameOrData,ScribusDoc * doc,double xPos,double yPos,bool isDataFromFile,bool loc)113 bool ScriXmlDoc::readElem(const QString& fileNameOrData, ScribusDoc *doc, double xPos, double yPos, bool isDataFromFile, bool loc)
114 {
115 	// Do not suppose the existence of layer with id = 0
116 	// return readElemToLayer(fileName, avail, doc, Xp, Yp, Fi, loc, FontSub, view, 0);
117 	return readElemToLayer(fileNameOrData, doc, xPos, yPos, isDataFromFile, loc, doc->activeLayer());
118 }
119 
readElemToLayer(const QString & fileNameOrData,ScribusDoc * doc,double xPos,double yPos,bool isDataFromFile,bool loc,int toLayer)120 bool ScriXmlDoc::readElemToLayer(const QString& fileNameOrData, ScribusDoc *doc, double xPos, double yPos, bool isDataFromFile, bool loc, int toLayer)
121 {
122 	QString elementData;
123 	QString fileDir = ScPaths::applicationDataDir();
124 	if (isDataFromFile)
125 	{
126 		QByteArray f;
127 		if (!loadRawText(fileNameOrData, f))
128 			return false;
129 		if (f.left(16) == "<SCRIBUSELEMUTF8")
130 			elementData = QString::fromUtf8(f.data());
131 		else
132 			elementData = f;
133 		fileDir = QFileInfo(fileNameOrData).absolutePath();
134 	}
135 	else
136 	{
137 		elementData = fileNameOrData;
138 	}
139 	// In case elementData contains some old broken scribus xml
140 	elementData.replace(QChar(5), SpecialChars::PARSEP);
141 	elementData.replace(QChar(4), SpecialChars::TAB);
142 	elementData.replace(QChar(0), QChar(32));
143 	elementData.replace("&#x5;", SpecialChars::PARSEP);
144 	elementData.replace("&#x4;", SpecialChars::TAB);
145 	const FileFormat *fmt = LoadSavePlugin::getFormatById(FORMATID_SLA150IMPORT);
146 	if (fmt)
147 	{
148 		fmt->setupTargets(doc, nullptr, doc->scMW(), nullptr, &(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts));
149 		fmt->loadElements(elementData, fileDir, toLayer, xPos, yPos, loc);
150 		return true;
151 	}
152 	return false;
153 }
154 
writeElem(ScribusDoc * doc,Selection * selection)155 QString ScriXmlDoc::writeElem(ScribusDoc *doc, Selection* selection)
156 {
157 	if (selection->count()==0)
158 		return "";
159 	double xp, yp, wp, hp;
160 	PageItem *item;
161 	QString documentStr = "";
162 	item = selection->itemAt(0);
163 
164 	auto items = getItemsFromSelection(doc, selection);
165 
166 	double selectionWidth = 0;
167 	double selectionHeight = 0;
168 	if (selection->isMultipleSelection())
169 	{
170 		double gx, gy, gw, gh;
171 		selection->getGroupRect(&gx, &gy, &gw, &gh);
172 		xp = gx;
173 		yp = gy;
174 		wp = gw;
175 		hp = gh;
176 		selection->getVisualGroupRect(&gx, &gy, &selectionWidth, &selectionHeight);
177 	}
178 	else
179 	{
180 		double minx =  std::numeric_limits<double>::max();
181 		double miny =  std::numeric_limits<double>::max();
182 		double maxx = -std::numeric_limits<double>::max();
183 		double maxy = -std::numeric_limits<double>::max();
184 		double x1, x2, y1, y2;
185 		item->getVisualBoundingRect(&x1, &y1, &x2, &y2);
186 		xp = qMin(minx, x1);
187 		yp = qMin(miny, y1);
188 		selectionWidth  = wp = qMax(maxx, x2) - xp;
189 		selectionHeight = hp = qMax(maxy, y2) - yp;
190 	}
191 	double scaleI = 50.0 / qMax(selectionWidth, selectionHeight);
192 	QImage retImg = QImage(50, 50, QImage::Format_ARGB32_Premultiplied);
193 	retImg.fill( qRgba(0, 0, 0, 0) );
194 	ScPainter *painter = new ScPainter(&retImg, retImg.width(), retImg.height(), 1, 0);
195 	painter->setZoomFactor(scaleI);
196 	for (int em = 0; em < items.count(); ++em)
197 	{
198 		PageItem* embedded = items.at(em);
199 		painter->save();
200 		painter->translate(-xp, -yp);
201 		embedded->invalid = true;
202 		embedded->DrawObj(painter, QRectF());
203 		painter->restore();
204 	}
205 	int pg = doc->OnPage(xp + wp / 2.0, yp + hp / 2.0);
206 	if (pg > -1)
207 	{
208 		xp = xp - doc->getXOffsetForPage(pg);
209 		yp = yp - doc->getYOffsetForPage(pg);
210 	}
211 	delete painter;
212 	QBuffer buffer;
213 	buffer.open(QIODevice::WriteOnly);
214 	retImg.save(&buffer, "PNG");
215 	QByteArray ba = buffer.buffer().toBase64();
216 	buffer.close();
217 	const FileFormat *fmt = LoadSavePlugin::getFormatById(FORMATID_SLA150EXPORT);
218 	if (fmt)
219 	{
220 		fmt->setupTargets(doc, nullptr, doc->scMW(), nullptr, &(PrefsManager::instance().appPrefs.fontPrefs.AvailFonts));
221 		documentStr = fmt->saveElements(xp, yp, wp, hp, selection, ba);
222 	}
223 	return documentStr;
224 }
225 
writeToMimeData(ScribusDoc * doc,Selection * selection)226 ScElemMimeData* ScriXmlDoc::writeToMimeData(ScribusDoc *doc, Selection *selection)
227 {
228 	ScElemMimeData* md = new ScElemMimeData();
229 	md->setScribusElem(writeElem(doc, selection));
230 	return md;
231 }
232 
getItemsFromSelection(ScribusDoc * doc,Selection * selection)233 QList<PageItem*> ScriXmlDoc::getItemsFromSelection(ScribusDoc *doc, Selection* selection)
234 {
235 	QMap<int, PageItem*> items;
236 
237 	const QList<PageItem*> selectedItems = selection->items();
238 	for (auto item : selectedItems)
239 		items.insert(doc->Items->indexOf(item), item);
240 	return items.values();
241 }