Reflow deterministico: stile iniettato nell'HTML del capitolo (chapterHtml+loadHtml), niente JS post-load; runJavaScript solo per lo scroll
This commit is contained in:
+28
-26
@@ -53,10 +53,15 @@ Page {
|
|||||||
if (!loaded)
|
if (!loaded)
|
||||||
return
|
return
|
||||||
loadWatchdog.stop()
|
loadWatchdog.stop()
|
||||||
if (page.restoring)
|
|
||||||
page.restoring = false
|
|
||||||
page.ready = true
|
page.ready = true
|
||||||
applyFontScale()
|
// ripristina la posizione in frazione sull'altezza ricalcolata
|
||||||
|
if (page.chapterFraction > 0.01) {
|
||||||
|
web.runJavaScript(
|
||||||
|
"window.scrollTo(0," + page.chapterFraction
|
||||||
|
+ "*Math.max(1,document.documentElement.scrollHeight-window.innerHeight));true",
|
||||||
|
function() { })
|
||||||
|
}
|
||||||
|
page.restoring = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,33 +229,32 @@ Page {
|
|||||||
page.chapterFraction = 0
|
page.chapterFraction = 0
|
||||||
}
|
}
|
||||||
page.currentChapter = index
|
page.currentChapter = index
|
||||||
page.restoring = true
|
loadChapter()
|
||||||
page.ready = false
|
|
||||||
web.url = "file://" + book.chapterFilePath(index)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeFontScale(delta) {
|
function changeFontScale(delta) {
|
||||||
page.fontScale = Math.max(0.7, Math.min(2.5, page.fontScale + delta))
|
page.fontScale = Math.max(0.7, Math.min(2.5, page.fontScale + delta))
|
||||||
applyFontScale()
|
// ricarica il capitolo con la nuova dimensione: il reflow avviene al load
|
||||||
|
loadChapter()
|
||||||
}
|
}
|
||||||
|
|
||||||
// reflow: imposta il font-size del documento (il testo si ri-avvolge)
|
function fontPx() {
|
||||||
// e ripristina la posizione in frazione sull'altezza ricalcolata.
|
return Math.round(16 * page.fontScale * 100) / 100
|
||||||
// Serve uno <style> con !important: molti EPUB impostano px su body/p
|
}
|
||||||
// che vincerebbero sul semplice font-size dell'html
|
|
||||||
function applyFontScale() {
|
// carica il capitolo corrente via loadHtml: lo stile di reflow (font-size)
|
||||||
if (!web.loaded)
|
// è iniettato nell'HTML dal parser, quindi niente JS post-load
|
||||||
|
function loadChapter() {
|
||||||
|
var html = book.chapterHtml(page.currentChapter, page.fontPx())
|
||||||
|
if (html.length === 0) {
|
||||||
|
page.errorMessage = "Capitolo non leggibile"
|
||||||
|
page.ready = true
|
||||||
return
|
return
|
||||||
var px = Math.round(16 * page.fontScale * 100) / 100
|
}
|
||||||
var script = "(function(){"
|
page.ready = false
|
||||||
+ "var s=document.getElementById('cw-font');"
|
page.restoring = true
|
||||||
+ "if(!s){s=document.createElement('style');s.id='cw-font';document.head.appendChild(s);}"
|
loadWatchdog.restart()
|
||||||
+ "s.textContent='html,body{font-size:" + px + "px!important}"
|
web.loadHtml(html, book.chapterBaseUrl(page.currentChapter))
|
||||||
+ "p,div,li,td,blockquote,section{font-size:1em!important}';"
|
|
||||||
+ "window.scrollTo(0," + page.chapterFraction
|
|
||||||
+ "*Math.max(1,document.documentElement.scrollHeight-window.innerHeight));"
|
|
||||||
+ "true})()"
|
|
||||||
web.runJavaScript(script, function() { })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showChapterList() {
|
function showChapterList() {
|
||||||
@@ -280,9 +284,7 @@ Page {
|
|||||||
page.currentChapter = Math.max(0, Math.min(ch, book.chapterCount - 1))
|
page.currentChapter = Math.max(0, Math.min(ch, book.chapterCount - 1))
|
||||||
page.chapterFraction = fr
|
page.chapterFraction = fr
|
||||||
}
|
}
|
||||||
page.ready = false
|
loadChapter()
|
||||||
loadWatchdog.restart()
|
|
||||||
web.url = "file://" + book.chapterFilePath(page.currentChapter)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QFileInfo>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QUrl>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@@ -404,6 +406,37 @@ QVariantList EpubBook::chapterList() const
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString EpubBook::chapterHtml(int index, int fontSizePx) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= m_chapters.size())
|
||||||
|
return QString();
|
||||||
|
QFile f(m_chapters.at(index).path);
|
||||||
|
if (!f.open(QIODevice::ReadOnly))
|
||||||
|
return QString();
|
||||||
|
QString html = QString::fromUtf8(f.readAll());
|
||||||
|
|
||||||
|
// stile di reflow iniettato nel documento: !important vince sui CSS del libro
|
||||||
|
const QString style = QStringLiteral(
|
||||||
|
"<style id=\"cw-font\">html,body{font-size:%1px!important}"
|
||||||
|
"p,div,li,td,blockquote,section{font-size:1em!important}</style>")
|
||||||
|
.arg(fontSizePx);
|
||||||
|
const int headEnd = html.indexOf(QStringLiteral("</head>"), 0, Qt::CaseInsensitive);
|
||||||
|
if (headEnd >= 0)
|
||||||
|
html.insert(headEnd, style);
|
||||||
|
else
|
||||||
|
html.prepend(style);
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString EpubBook::chapterBaseUrl(int index) const
|
||||||
|
{
|
||||||
|
if (index < 0 || index >= m_chapters.size())
|
||||||
|
return QString();
|
||||||
|
return QUrl::fromLocalFile(
|
||||||
|
QFileInfo(m_chapters.at(index).path).absolutePath() + QStringLiteral("/"))
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
QString EpubBook::makeBookmarkKey(int chapterIndex, double fraction) const
|
QString EpubBook::makeBookmarkKey(int chapterIndex, double fraction) const
|
||||||
{
|
{
|
||||||
return QStringLiteral("cw:v1:%1:%2").arg(chapterIndex).arg(fraction, 0, 'f', 4);
|
return QStringLiteral("cw:v1:%1:%2").arg(chapterIndex).arg(fraction, 0, 'f', 4);
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ public:
|
|||||||
Q_INVOKABLE QString chapterTitle(int index) const;
|
Q_INVOKABLE QString chapterTitle(int index) const;
|
||||||
// elenco [{index, title}] per la lista capitoli
|
// elenco [{index, title}] per la lista capitoli
|
||||||
Q_INVOKABLE QVariantList chapterList() const;
|
Q_INVOKABLE QVariantList chapterList() const;
|
||||||
|
// HTML del capitolo con lo stile di reflow iniettato (font-size in px)
|
||||||
|
Q_INVOKABLE QString chapterHtml(int index, int fontSizePx) const;
|
||||||
|
// base URL (file://) per risolvere immagini/CSS relativi del capitolo
|
||||||
|
Q_INVOKABLE QString chapterBaseUrl(int index) const;
|
||||||
|
|
||||||
// chiave segno locale, es. "cw:v1:3:0.42" (capitolo 3, 42% del capitolo)
|
// chiave segno locale, es. "cw:v1:3:0.42" (capitolo 3, 42% del capitolo)
|
||||||
Q_INVOKABLE QString makeBookmarkKey(int chapterIndex, double fraction) const;
|
Q_INVOKABLE QString makeBookmarkKey(int chapterIndex, double fraction) const;
|
||||||
|
|||||||
Reference in New Issue
Block a user