diff --git a/desktop-widgets/printer.cpp b/desktop-widgets/printer.cpp index 066e0b23be..716d05d242 100644 --- a/desktop-widgets/printer.cpp +++ b/desktop-widgets/printer.cpp @@ -8,6 +8,8 @@ #include "core/selection.h" #include "core/statistics.h" #include "core/qthelper.h" +#include "core/errorhelper.h" +#include "core/xmlparams.h" #include "profile-widget/profilescene.h" #include @@ -19,6 +21,9 @@ # include # include # include +# include +# include +# include #else #include #include @@ -294,6 +299,57 @@ void Printer::previewOnePage() #ifdef USE_QLITEHTML void Printer::Preview(QString content, QPrinter *printer) { + // Replace dive profile placeholders via XSLT so the transformation is resilient to HTML formatting changes. + auto applyProfileXslt = [](const QString &html, const QString &profileDir) -> QString { + const QByteArray htmlUtf8 = html.toUtf8(); + htmlDocPtr doc = htmlReadMemory(htmlUtf8.constData(), htmlUtf8.size(), "preview.html", nullptr, + HTML_PARSE_RECOVER | HTML_PARSE_NODEFDTD | HTML_PARSE_NOERROR | HTML_PARSE_NOWARNING | HTML_PARSE_NONET); + if (!doc) { + report_error("Failed to parse HTML for profile injection"); + return html; + } + + xsltStylesheetPtr xslt = get_stylesheet("inject-profiles.xslt"); + if (!xslt) { + report_error("Failed to load inject-profiles.xslt stylesheet"); + xmlFreeDoc(doc); + return html; + } + + struct xml_params *params = alloc_xml_params(); + // XSLT parameters need to be XPath expressions, so wrap string values in single quotes + QByteArray quotedDir = QString("'%1'").arg(profileDir).toUtf8(); + xml_params_add(params, "profile-dir", quotedDir.constData()); + xml_params_add(params, "img-height", "'30%'"); + xml_params_add(params, "img-width", "'30%'"); + + xmlDocPtr transformed = xsltApplyStylesheet(xslt, doc, xml_params_get(params)); + free_xml_params(params); + xmlFreeDoc(doc); + if (!transformed) { + report_error("Failed to apply profile injection transformation"); + xsltFreeStylesheet(xslt); + return html; + } + + xmlChar *out = nullptr; + int outLen = 0; + if (xsltSaveResultToString(&out, &outLen, transformed, xslt) != 0 || !out) { + report_error("Failed to serialize transformed HTML"); + xmlFreeDoc(transformed); + xsltFreeStylesheet(xslt); + return html; + } + + QString result = QString::fromUtf8(reinterpret_cast(out), outLen); + xmlFree(out); + xmlFreeDoc(transformed); + xsltFreeStylesheet(xslt); + return result; + }; + + content = applyProfileXslt(content, printDir.path()); + QDialog previewer; previewer.setWindowTitle(tr("Print Preview")); @@ -329,9 +385,6 @@ void Printer::Preview(QString content, QPrinter *printer) // QTextStream in(&file); // previewWidget.setHtml(in.readAll()); - QString repl = QString("").arg(printDir.path()); - content.replace(QRegularExpression("\\s*"), repl); - previewWidget.setUrl(QUrl("file:///", QUrl::TolerantMode)); previewWidget.setHtml(content); previewWidget.print(printer); diff --git a/scripts/build.sh b/scripts/build.sh index f62e4d4bf7..f76ffb2cce 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -488,7 +488,7 @@ for (( i=0 ; i < ${#BUILDS[@]} ; i++ )) ; do BUILDDIR=${BUILDDIRS[$i]} echo "build $SUBSURFACE_EXECUTABLE in $BUILDDIR" - if [ "$SUBSURFACE_EXECUTABLE" = "DesktopExecutable" ] && [ "$BUILD_WITH_WEBKIT" = "1" ]; then + if [ "$SUBSURFACE_EXECUTABLE" = "DesktopExecutable" ]; then EXTRA_OPTS="-DNO_PRINTING=OFF" else EXTRA_OPTS="-DNO_PRINTING=ON" diff --git a/subsurface.qrc b/subsurface.qrc index fb0f933a55..ad9af66a7b 100644 --- a/subsurface.qrc +++ b/subsurface.qrc @@ -47,6 +47,7 @@ xslt/shearwater.xslt xslt/DiveLog.xslt xslt/av1.xslt + xslt/inject-profiles.xslt icons/gas.png icons/mod.png icons/he.png diff --git a/xslt/inject-profiles.xslt b/xslt/inject-profiles.xslt new file mode 100644 index 0000000000..718b8e8dc7 --- /dev/null +++ b/xslt/inject-profiles.xslt @@ -0,0 +1,22 @@ + + + + 30% + 30% + + + + + + + + + + + + + + + + +