1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 //
4 // Copyright 2010-2020 wkhtmltopdf authors
5 //
6 // This file is part of wkhtmltopdf.
7 //
8 // wkhtmltopdf is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Lesser General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
12 //
13 // wkhtmltopdf is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public License
19 // along with wkhtmltopdf.  If not, see <http://www.gnu.org/licenses/>.
20 
21 
22 #ifdef _MSC_VER
23 #define strcasecmp _stricmp
24 #endif
25 
26 #include "pdfsettings.hh"
27 #include "reflect.hh"
28 #include <QMap>
29 #include <stdexcept>
30 
31 #include "dllbegin.inc"
32 namespace wkhtmltopdf {
33 namespace settings {
34 
35 template<>
36 struct DLL_LOCAL ReflectImpl<UnitReal>: public ReflectSimple {
37 	UnitReal & ur;
ReflectImplwkhtmltopdf::settings::ReflectImpl38 	ReflectImpl(UnitReal & _): ur(_) {}
getwkhtmltopdf::settings::ReflectImpl39 	QString get() {bool d; return unitRealToStr(ur, &d);}
setwkhtmltopdf::settings::ReflectImpl40 	void set(const QString & value, bool * ok) {ur = strToUnitReal(value.toUtf8().constData(), ok);}
41 };
42 
43 template<>
44 struct DLL_LOCAL ReflectImpl<QPrinter::PageSize>: public ReflectSimple {
45 	QPrinter::PageSize & ps;
ReflectImplwkhtmltopdf::settings::ReflectImpl46 	ReflectImpl(QPrinter::PageSize & _): ps(_) {}
getwkhtmltopdf::settings::ReflectImpl47 	QString get() {return pageSizeToStr(ps);}
setwkhtmltopdf::settings::ReflectImpl48 	void set(const QString & value, bool * ok) {ps = strToPageSize(value.toUtf8().constData(), ok);}
49 };
50 
51 template<>
52 struct DLL_LOCAL ReflectImpl<QPrinter::Orientation>: public ReflectSimple {
53 	QPrinter::Orientation & o;
ReflectImplwkhtmltopdf::settings::ReflectImpl54 	ReflectImpl(QPrinter::Orientation & _): o(_) {}
getwkhtmltopdf::settings::ReflectImpl55 	QString get() {return orientationToStr(o);}
setwkhtmltopdf::settings::ReflectImpl56 	void set(const QString & value, bool * ok) {o = strToOrientation(value.toUtf8().constData(), ok);}
57 };
58 
59 template<>
60 struct DLL_LOCAL ReflectImpl<QPrinter::PrinterMode>: public ReflectSimple {
61 	QPrinter::PrinterMode & m;
ReflectImplwkhtmltopdf::settings::ReflectImpl62 	ReflectImpl(QPrinter::PrinterMode & _): m(_) {}
getwkhtmltopdf::settings::ReflectImpl63 	QString get() {return printerModeToStr(m);}
setwkhtmltopdf::settings::ReflectImpl64 	void set(const QString & value, bool * ok) {m = strToPrinterMode(value.toUtf8().constData(), ok);}
65 };
66 
67 template<>
68 struct DLL_LOCAL ReflectImpl<QPrinter::ColorMode>: public ReflectSimple {
69 	QPrinter::ColorMode & m;
ReflectImplwkhtmltopdf::settings::ReflectImpl70 	ReflectImpl(QPrinter::ColorMode & _): m(_) {}
getwkhtmltopdf::settings::ReflectImpl71 	QString get() {return colorModeToStr(m);}
setwkhtmltopdf::settings::ReflectImpl72 	void set(const QString & value, bool * ok) {m = strToColorMode(value.toUtf8().constData(), ok);}
73 };
74 
75 template<>
76 struct DLL_LOCAL ReflectImpl<Margin>: public ReflectClass {
ReflectImplwkhtmltopdf::settings::ReflectImpl77 	ReflectImpl(Margin & c) {
78 		WKHTMLTOPDF_REFLECT(top);
79 		WKHTMLTOPDF_REFLECT(right);
80 		WKHTMLTOPDF_REFLECT(bottom);
81 		WKHTMLTOPDF_REFLECT(left);
82 	}
83 };
84 
85 template<>
86 struct DLL_LOCAL ReflectImpl<Size>: public ReflectClass {
ReflectImplwkhtmltopdf::settings::ReflectImpl87 	ReflectImpl(Size & c) {
88 		WKHTMLTOPDF_REFLECT(pageSize);
89 		WKHTMLTOPDF_REFLECT(height);
90 		WKHTMLTOPDF_REFLECT(width);
91 	}
92 };
93 
94 template<>
95 struct DLL_LOCAL ReflectImpl<TableOfContent>: public ReflectClass {
ReflectImplwkhtmltopdf::settings::ReflectImpl96 	ReflectImpl(TableOfContent & c) {
97 		WKHTMLTOPDF_REFLECT(useDottedLines);
98 		WKHTMLTOPDF_REFLECT(captionText);
99 		WKHTMLTOPDF_REFLECT(forwardLinks);
100 		WKHTMLTOPDF_REFLECT(backLinks);
101 		WKHTMLTOPDF_REFLECT(indentation);
102 		WKHTMLTOPDF_REFLECT(fontScale);
103 	}
104 };
105 
106 template<>
107 struct DLL_LOCAL ReflectImpl<PdfGlobal>: public ReflectClass {
ReflectImplwkhtmltopdf::settings::ReflectImpl108 	ReflectImpl(PdfGlobal & c) {
109 		WKHTMLTOPDF_REFLECT(size);
110 		ReflectClass::add("quiet", new QuietArgBackwardsCompatReflect(c.logLevel));	// Fake the "quiet" argument
111 		WKHTMLTOPDF_REFLECT(logLevel);
112 		WKHTMLTOPDF_REFLECT(useGraphics);
113 		WKHTMLTOPDF_REFLECT(resolveRelativeLinks);
114 		WKHTMLTOPDF_REFLECT(orientation);
115 		WKHTMLTOPDF_REFLECT(colorMode);
116 		WKHTMLTOPDF_REFLECT(resolution);
117 		WKHTMLTOPDF_REFLECT(dpi);
118 		WKHTMLTOPDF_REFLECT(pageOffset);
119 		WKHTMLTOPDF_REFLECT(copies);
120 		WKHTMLTOPDF_REFLECT(collate);
121 		WKHTMLTOPDF_REFLECT(outline);
122 		WKHTMLTOPDF_REFLECT(outlineDepth);
123 		WKHTMLTOPDF_REFLECT(dumpOutline);
124 		WKHTMLTOPDF_REFLECT(out);
125 		WKHTMLTOPDF_REFLECT(documentTitle);
126 		WKHTMLTOPDF_REFLECT(useCompression);
127 		WKHTMLTOPDF_REFLECT(margin);
128 		WKHTMLTOPDF_REFLECT(imageDPI);
129 		WKHTMLTOPDF_REFLECT(imageQuality);
130 		WKHTMLTOPDF_REFLECT(load);
131 		WKHTMLTOPDF_REFLECT(viewportSize);
132 	}
133 };
134 
135 template<>
136 struct DLL_LOCAL ReflectImpl<HeaderFooter>: public ReflectClass {
ReflectImplwkhtmltopdf::settings::ReflectImpl137 	ReflectImpl(HeaderFooter & c) {
138 		WKHTMLTOPDF_REFLECT(fontSize);
139 		WKHTMLTOPDF_REFLECT(fontName);
140 		WKHTMLTOPDF_REFLECT(left);
141 		WKHTMLTOPDF_REFLECT(right);
142 		WKHTMLTOPDF_REFLECT(center);
143 		WKHTMLTOPDF_REFLECT(line);
144 		WKHTMLTOPDF_REFLECT(htmlUrl);
145 		WKHTMLTOPDF_REFLECT(spacing);
146 	}
147 };
148 
149 template<>
150 struct DLL_LOCAL ReflectImpl<PdfObject>: public ReflectClass {
ReflectImplwkhtmltopdf::settings::ReflectImpl151 	ReflectImpl(PdfObject & c) {
152 		WKHTMLTOPDF_REFLECT(toc);
153 		WKHTMLTOPDF_REFLECT(page);
154 		WKHTMLTOPDF_REFLECT(header);
155 		WKHTMLTOPDF_REFLECT(footer);
156 		WKHTMLTOPDF_REFLECT(useExternalLinks);
157 		WKHTMLTOPDF_REFLECT(useLocalLinks);
158 		WKHTMLTOPDF_REFLECT(replacements);
159 		WKHTMLTOPDF_REFLECT(produceForms);
160 		WKHTMLTOPDF_REFLECT(load);
161 		WKHTMLTOPDF_REFLECT(web);
162 		WKHTMLTOPDF_REFLECT(includeInOutline);
163 		WKHTMLTOPDF_REFLECT(pagesCount);
164 		WKHTMLTOPDF_REFLECT(isTableOfContent);
165 		WKHTMLTOPDF_REFLECT(tocXsl);
166 	}
167 };
168 
169 
170 
171 /*!
172   \file settings.hh
173   \brief Defines the Settings class
174 */
pageSizeMap()175 DLL_LOCAL QMap<QString, QPrinter::PageSize> pageSizeMap() {
176 	QMap<QString, QPrinter::PageSize> res;
177 	res["A0"] = QPrinter::A0;
178 	res["A1"] = QPrinter::A1;
179 	res["A2"] = QPrinter::A2;
180 	res["A3"] = QPrinter::A3;
181 	res["A4"] = QPrinter::A4;
182 	res["A5"] = QPrinter::A5;
183 	res["A6"] = QPrinter::A6;
184 	res["A7"] = QPrinter::A7;
185 	res["A8"] = QPrinter::A8;
186 	res["A9"] = QPrinter::A9;
187 	res["B0"] = QPrinter::B0;
188 	res["B1"] = QPrinter::B1;
189 	res["B10"] = QPrinter::B10;
190 	res["B2"] = QPrinter::B2;
191 	res["B3"] = QPrinter::B3;
192 	res["B4"] = QPrinter::B4;
193 	res["B5"] = QPrinter::B5;
194 	res["B6"] = QPrinter::B6;
195 	res["B7"] = QPrinter::B7;
196 	res["B8"] = QPrinter::B8;
197 	res["B9"] = QPrinter::B9;
198 	res["C5E"] = QPrinter::C5E;
199 	res["Comm10E"] = QPrinter::Comm10E;
200 	res["DLE"] = QPrinter::DLE;
201 	res["Executive"] = QPrinter::Executive;
202 	res["Folio"] = QPrinter::Folio;
203 	res["Ledger"] = QPrinter::Ledger;
204 	res["Legal"] = QPrinter::Legal;
205 	res["Letter"] = QPrinter::Letter;
206 	res["Tabloid"] = QPrinter::Tabloid;
207 	return res;
208 }
209 
210 /*!
211   Convert a string to a paper size, basically all thinkable values are allowed.
212   if a unknown value is given A4 is returned
213   \param s The string to convert
214   \param ok If supplied indicates if the conversion was successful
215 */
strToPageSize(const char * s,bool * ok)216 QPrinter::PageSize strToPageSize(const char * s, bool * ok) {
217 	QMap<QString,QPrinter::PageSize> map = pageSizeMap();
218 	for (QMap<QString,QPrinter::PageSize>::const_iterator i=map.begin(); i != map.end(); ++i) {
219 		if (i.key().compare(s, Qt::CaseInsensitive) != 0) continue;
220 		if (ok) *ok=true;
221 		return i.value();
222 	}
223 	if (ok) *ok = false;
224 	return QPrinter::A4;
225 }
226 
pageSizeToStr(QPrinter::PageSize ps)227 QString pageSizeToStr(QPrinter::PageSize ps) {
228 	QMap<QString,QPrinter::PageSize> map = pageSizeMap();
229 	for (QMap<QString,QPrinter::PageSize>::const_iterator i=map.begin(); i != map.end(); ++i) {
230 		if (i.value() == ps) return i.key();
231 	}
232 	return "";
233 }
234 
235 
236 /*!
237   Read orientation from a string, possible values are landscape and portrait (case insensitive)
238   \param s The string containing the orientation
239   \param ok If supplied indicates whether the s was valid
240 */
strToOrientation(const char * s,bool * ok)241 QPrinter::Orientation strToOrientation(const char * s, bool * ok) {
242 	if (ok) *ok = true;
243  	if (!strcasecmp(s,"Landscape")) return QPrinter::Landscape;
244  	if (!strcasecmp(s,"Portrait")) return QPrinter::Portrait;
245 	if (ok) *ok = false;
246 	return QPrinter::Portrait;
247 }
248 
orientationToStr(QPrinter::Orientation o)249 QString orientationToStr(QPrinter::Orientation o) {
250 	return (o == QPrinter::Landscape)?"Landscape":"Portrait";
251 }
252 
253 
254 /*!
255   Parse a string describing a distance, into a real number and a unit.
256   \param o Tho string describing the distance
257   \param ok If supplied indicates whether the s was valid
258 */
strToUnitReal(const char * o,bool * ok)259 UnitReal strToUnitReal(const char * o, bool * ok) {
260 	qreal s=1.0; //Since not all units are provided by qt, we use this variable to scale
261 	//Them into units that are.
262 	QPrinter::Unit u=QPrinter::Millimeter;
263 	//Skip the real number part
264 	int i=0;
265 	while ('0' <= o[i]  && o[i] <= '9') ++i;
266 	if (o[i] == '.' || o[i] == '.') ++i;
267 	while ('0' <= o[i]  && o[i] <= '9') ++i;
268 	//Try to match the unit used
269 	if (!strcasecmp(o+i,"") || !strcasecmp(o+i,"mm") || !strcasecmp(o+i,"millimeter")) {
270 		u=QPrinter::Millimeter;
271 	} else if (!strcasecmp(o+i,"cm") || !strcasecmp(o+i,"centimeter")) {
272 		u=QPrinter::Millimeter;
273 		s=10.0; //1cm=10mm
274 	} else if (!strcasecmp(o+i,"m") || !strcasecmp(o+i,"meter")) {
275 		u=QPrinter::Millimeter;
276 		s=1000.0; //1m=1000m
277 	} else if (!strcasecmp(o+i,"didot"))
278 		u=QPrinter::Didot; //Todo is there a short for didot??
279 	else if (!strcasecmp(o+i,"inch") || !strcasecmp(o+i,"in"))
280 		u=QPrinter::Inch;
281 	else if (!strcasecmp(o+i,"pica") || !strcasecmp(o+i,"pc"))
282 		u=QPrinter::Pica;
283 	else if (!strcasecmp(o+i,"cicero"))
284 		u=QPrinter::Cicero;
285 	else if (!strcasecmp(o+i,"pixel") || !strcasecmp(o+i,"px"))
286 		u=QPrinter::DevicePixel;
287 	else if (!strcasecmp(o+i,"point") || !strcasecmp(o+i,"pt"))
288 		u=QPrinter::Point;
289 	else {
290 		if (ok) *ok=false;
291 		return UnitReal(QString(o).left(i).toDouble()*s, u);
292 	}
293 	return UnitReal(QString(o).left(i).toDouble(ok)*s, u);
294 }
295 
unitRealToStr(const UnitReal & ur,bool * ok)296 QString unitRealToStr(const UnitReal & ur, bool * ok) {
297 	QString c;
298 	if (ur.first == -1) {
299 		if (ok) *ok=false;
300 		return "";
301 	}
302 	if (ok) *ok=true;
303 	switch (ur.second) {
304 	case QPrinter::Didot: c = "didot"; break;
305 	case QPrinter::Inch: c = "in"; break;
306 	case QPrinter::Pica: c = "pica"; break;
307 	case QPrinter::DevicePixel: c = "px"; break;
308 	case QPrinter::Point: c = "pt"; break;
309 	case QPrinter::Millimeter: c = "mm"; break;
310 	default:
311 		if (ok) *ok=false;
312 		return "";
313 	}
314 	return QString("%1%2").arg(ur.first).arg(c);
315 }
316 
strToPrinterMode(const char * s,bool * ok)317 QPrinter::PrinterMode strToPrinterMode(const char * s, bool * ok) {
318 	if (ok) *ok=true;
319 	if (!strcasecmp(s,"screen")) return QPrinter::ScreenResolution;
320 	if (!strcasecmp(s,"printer")) return QPrinter::PrinterResolution;
321 	if (!strcasecmp(s,"high")) return QPrinter::HighResolution;
322 	*ok=false;
323 	return QPrinter::HighResolution;
324 }
325 
printerModeToStr(QPrinter::PrinterMode o)326 QString printerModeToStr(QPrinter::PrinterMode o) {
327 	switch (o) {
328 	case QPrinter::ScreenResolution: return "screen";
329 	case QPrinter::PrinterResolution: return "printer";
330 	case QPrinter::HighResolution: return "high";
331 	}
332 	return QString();
333 }
334 
strToColorMode(const char * s,bool * ok)335 QPrinter::ColorMode strToColorMode(const char * s, bool * ok) {
336 	if (ok) *ok=true;
337 	if (!strcasecmp(s,"color"))	return QPrinter::Color;
338 	if (!strcasecmp(s,"grayscale")) return QPrinter::GrayScale;
339 	*ok=false;
340 	return QPrinter::Color;
341 }
342 
colorModeToStr(QPrinter::ColorMode o)343 QString colorModeToStr(QPrinter::ColorMode o) {
344 	switch (o) {
345 	case QPrinter::Color: return "color";
346 	case QPrinter::GrayScale: return "grayscale";
347 	}
348 	return QString();
349 }
350 
Size()351 Size::Size():
352 	pageSize(QPrinter::A4),
353 	height(UnitReal(-1,QPrinter::Millimeter)),
354 	width(UnitReal(-1,QPrinter::Millimeter)) {}
355 
HeaderFooter()356 HeaderFooter::HeaderFooter():
357 	fontSize(12),
358 	fontName("Arial"),
359 	left(""),
360 	right(""),
361 	center(""),
362 	line(false),
363 	htmlUrl(""),
364 	spacing(0.0) {}
365 
Margin()366 Margin::Margin():
367     top(UnitReal(-1,QPrinter::Millimeter)),
368 	right(UnitReal(10,QPrinter::Millimeter)),
369     bottom(UnitReal(-1,QPrinter::Millimeter)),
370 	left(UnitReal(10,QPrinter::Millimeter)) {}
371 
PdfGlobal()372 PdfGlobal::PdfGlobal():
373 	logLevel(Info),
374 	useGraphics(false),
375 	resolveRelativeLinks(true),
376 	orientation(QPrinter::Portrait),
377 	colorMode(QPrinter::Color),
378 	resolution(QPrinter::HighResolution),
379 	dpi(96),
380 	pageOffset(0),
381 	copies(1),
382 	collate(true),
383 	outline(true),
384 	outlineDepth(4),
385 	dumpOutline(""),
386 	out(""),
387 	documentTitle(""),
388 	useCompression(true),
389 	viewportSize(""),
390 	imageDPI(600),
391 	imageQuality(94){};
392 
TableOfContent()393 TableOfContent::TableOfContent():
394 	useDottedLines(true),
395 	captionText("Table of Contents"),
396 	forwardLinks(true),
397 	backLinks(false),
398 	indentation("1em"),
399 	fontScale(0.8f) {}
400 
PdfObject()401 PdfObject::PdfObject():
402 	useExternalLinks(true),
403 	useLocalLinks(true),
404 	produceForms(false),
405 	includeInOutline(true),
406 	pagesCount(true),
407 	isTableOfContent(false),
408 	tocXsl("") {};
409 
get(const char * name)410 QString PdfGlobal::get(const char * name) {
411 	ReflectImpl<PdfGlobal> impl(*this);
412 	return impl.get(name);
413 }
414 
set(const char * name,const QString & value)415 bool PdfGlobal::set(const char * name, const QString & value) {
416 	ReflectImpl<PdfGlobal> impl(*this);
417 	return impl.set(name, value);
418 }
419 
get(const char * name)420 QString PdfObject::get(const char * name) {
421 	ReflectImpl<PdfObject> impl(*this);
422 	return impl.get(name);
423 }
424 
set(const char * name,const QString & value)425 bool PdfObject::set(const char * name, const QString & value) {
426 	ReflectImpl<PdfObject> impl(*this);
427 	return impl.set(name, value);
428 }
429 
430 }
431 }
432