forked from WHC/Hermit
pdf: text that names no colour comes out black, not the palette
A QTextDocument takes its default text colour from the application palette, and markdown names no colour at all: in a window running a dark palette -- which is what a phone in dark mode hands Qt -- every plain paragraph was laid out #eeeeee on a white page. Printed, that is a blank document; on screen it reads as "the font is oddly faint". The first PDFs off the phone were exactly that. - PdfTools: paperDocument() sets the default stylesheet (body colour #000000) before setHtml, and writePdf() lays that out. A colour the document does name still wins, so an .html handed to the tool keeps its own -- checked with a #cc0000 document under both palettes. - --uitest: draws that document on a white image under a dark palette and looks for ink (238 before the fix, 0 after). Verified on the NX789J: md_to_pdf on the device now writes CID TrueType NotoSansCJKHK-Regular/-Bold text whose page renders at min=0.
This commit is contained in:
@@ -35,6 +35,7 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "core/AgentCore.h"
|
||||
#include "core/ToolProvider.h"
|
||||
@@ -168,10 +169,9 @@ bool sourceHtml(const cst_tool_ctx_t *ctx, const ctl_tool_call_t *c,
|
||||
* strip. */
|
||||
bool writePdf(const QString &html, const QString &path, const QString &title,
|
||||
QString *err) {
|
||||
QTextDocument doc;
|
||||
doc.setHtml(html);
|
||||
std::unique_ptr<QTextDocument> doc(paperDocument(html));
|
||||
if (!title.isEmpty())
|
||||
doc.setMetaInformation(QTextDocument::DocumentTitle, title);
|
||||
doc->setMetaInformation(QTextDocument::DocumentTitle, title);
|
||||
|
||||
QPdfWriter writer(path);
|
||||
writer.setPageSize(QPageSize(QPageSize::A4));
|
||||
@@ -186,17 +186,17 @@ bool writePdf(const QString &html, const QString &path, const QString &title,
|
||||
return false;
|
||||
}
|
||||
const QRectF page = writer.pageLayout().paintRectPixels(writer.resolution());
|
||||
doc.setPageSize(page.size());
|
||||
const int pages = qMax(1, doc.pageCount());
|
||||
doc->setPageSize(page.size());
|
||||
const int pages = qMax(1, doc->pageCount());
|
||||
for (int i = 0; i < pages; i++) {
|
||||
if (i)
|
||||
writer.newPage();
|
||||
painter.save();
|
||||
painter.translate(page.topLeft());
|
||||
painter.translate(0, -i * page.height());
|
||||
doc.drawContents(&painter,
|
||||
QRectF(0, 0, page.width(), page.height())
|
||||
.translated(0, i * page.height()));
|
||||
doc->drawContents(&painter,
|
||||
QRectF(0, 0, page.width(), page.height())
|
||||
.translated(0, i * page.height()));
|
||||
painter.restore();
|
||||
}
|
||||
painter.end();
|
||||
@@ -285,6 +285,24 @@ int mdToPdfRun(const cst_tool_ctx_t *ctx, const ctl_tool_call_t *c,
|
||||
|
||||
} // namespace
|
||||
|
||||
/* The document writePdf lays out, with a colour filled in for text that names
|
||||
* none of its own.
|
||||
*
|
||||
* Paper is white and has no theme, but a QTextDocument takes its default text
|
||||
* colour from the application palette: in a window running a dark palette --
|
||||
* which is what a phone in dark mode hands Qt -- every plain markdown
|
||||
* paragraph came out #eeeeee on a white page, i.e. a PDF that looks blank
|
||||
* when printed, and reads as "the font is oddly faint" on screen. Naming the
|
||||
* colour makes the page depend on the paper rather than on the window. A
|
||||
* colour the document does name still wins (an .html file somebody handed us
|
||||
* keeps its own), so this only fills the holes. */
|
||||
QTextDocument *paperDocument(const QString &html) {
|
||||
auto *doc = new QTextDocument;
|
||||
doc->setDefaultStyleSheet(QStringLiteral("body { color: #000000; }"));
|
||||
doc->setHtml(html);
|
||||
return doc;
|
||||
}
|
||||
|
||||
int registerQtTools(AgentCore *core) {
|
||||
if (!core)
|
||||
return 0;
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
/* The engine wrapper of the front end (core/AgentCore.h). Only a pointer
|
||||
* travels through this header, so the class stays incomplete here. */
|
||||
class AgentCore;
|
||||
/* Same for the document md_to_pdf lays out (PdfTools.cpp): the caller owns
|
||||
* it, and the test in ui/UiTest.cpp inspects how it draws. */
|
||||
class QTextDocument;
|
||||
|
||||
namespace app {
|
||||
|
||||
@@ -48,6 +51,10 @@ int registerPlatformTools(AgentCore *core);
|
||||
* (they are Qt, not a platform API): today md_to_pdf, owned by "app:qt".
|
||||
* Called next to registerPlatformTools(). */
|
||||
int registerQtTools(AgentCore *core);
|
||||
/* The document md_to_pdf lays out from `html`: the page's own defaults
|
||||
* applied (text with no colour of its own is black, not the window's palette
|
||||
* colour). The caller owns the result. */
|
||||
QTextDocument *paperDocument(const QString &html);
|
||||
/* Drop them again (they belong to the owners "app:*"). */
|
||||
void unregisterPlatformTools(AgentCore *core);
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <QBuffer>
|
||||
#include <QFile>
|
||||
#include <QImage>
|
||||
#include <QPalette>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QPainter>
|
||||
@@ -22,14 +23,17 @@
|
||||
#include <QQmlContext>
|
||||
#include <QQuickWindow>
|
||||
#include <QTest>
|
||||
#include <QTextDocument>
|
||||
|
||||
#include <QVariantMap>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "cst_agent.h"
|
||||
#include "cst_attach.h"
|
||||
#include "core/ToolProvider.h"
|
||||
#include "ui/SessionImages.h"
|
||||
#include "ui/ThemeIcons.h"
|
||||
|
||||
@@ -482,6 +486,36 @@ int runUiTest(AgentCore &core, const QString &size) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Paper is white whatever the window's palette says: markdown carries no
|
||||
* colour, so a dark window turned every plain paragraph #eeeeee -- a PDF
|
||||
* that looked blank. Draw it on a white image and look for ink. */
|
||||
{
|
||||
const QPalette was = QGuiApplication::palette();
|
||||
QPalette darkPalette = was;
|
||||
darkPalette.setColor(QPalette::Text, QColor(0xee, 0xee, 0xee));
|
||||
darkPalette.setColor(QPalette::WindowText, QColor(0xee, 0xee, 0xee));
|
||||
QGuiApplication::setPalette(darkPalette);
|
||||
std::unique_ptr<QTextDocument> page(app::paperDocument(
|
||||
QStringLiteral("<html><body>text that names no colour of its own"
|
||||
"</body></html>")));
|
||||
QImage paper(320, 60, QImage::Format_RGB32);
|
||||
paper.fill(0xffffffffu);
|
||||
QPainter ink(&paper);
|
||||
page->drawContents(&ink);
|
||||
ink.end();
|
||||
int darkest = 255;
|
||||
for (int y = 0; y < paper.height(); y++) {
|
||||
const QRgb *row = reinterpret_cast<const QRgb *>(paper.constScanLine(y));
|
||||
for (int x = 0; x < paper.width(); x++)
|
||||
darkest = qMin(darkest, qGray(row[x]));
|
||||
}
|
||||
check(darkest < 64,
|
||||
QStringLiteral("a dark window still lays out black ink on paper "
|
||||
"(darkest pixel %1)")
|
||||
.arg(darkest));
|
||||
QGuiApplication::setPalette(was);
|
||||
}
|
||||
|
||||
/* new sessions: the engine moves, the view empties, the store grows */
|
||||
const int before = core.sessions().size();
|
||||
clickMouse(win, QStringLiteral("newSessionButton"));
|
||||
|
||||
Reference in New Issue
Block a user