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