mirror of
https://gitee.com/vnotex/vnote.git
synced 2025-07-05 22:09:52 +08:00
preview: add cache for code block in-place preview
This commit is contained in:
parent
f2afe4b4e2
commit
4284d20dea
@ -1,6 +1,5 @@
|
|||||||
#include "vlivepreviewhelper.h"
|
#include "vlivepreviewhelper.h"
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
|
|
||||||
#include "veditor.h"
|
#include "veditor.h"
|
||||||
@ -30,8 +29,6 @@ extern VMainWindow *g_mainWin;
|
|||||||
|
|
||||||
#define INDEX_MASK 0x00ffffffUL
|
#define INDEX_MASK 0x00ffffffUL
|
||||||
|
|
||||||
#define SCALE_FACTOR_THRESHOLD 1.1
|
|
||||||
|
|
||||||
CodeBlockPreviewInfo::CodeBlockPreviewInfo()
|
CodeBlockPreviewInfo::CodeBlockPreviewInfo()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -41,33 +38,12 @@ CodeBlockPreviewInfo::CodeBlockPreviewInfo(const VCodeBlock &p_cb)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeBlockPreviewInfo::updateNonContent(const QTextDocument *p_doc,
|
|
||||||
const VCodeBlock &p_cb)
|
|
||||||
{
|
|
||||||
m_codeBlock.updateNonContent(p_cb);
|
|
||||||
if (m_inplacePreview.isNull()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextBlock block = p_doc->findBlockByNumber(m_codeBlock.m_endBlock);
|
|
||||||
if (block.isValid()) {
|
|
||||||
m_inplacePreview->m_startPos = block.position();
|
|
||||||
m_inplacePreview->m_endPos = block.position() + block.length();
|
|
||||||
m_inplacePreview->m_blockPos = block.position();
|
|
||||||
m_inplacePreview->m_blockNumber = m_codeBlock.m_endBlock;
|
|
||||||
// Padding is not changed since content is not changed.
|
|
||||||
} else {
|
|
||||||
m_inplacePreview.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CodeBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor,
|
void CodeBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor,
|
||||||
const QTextDocument *p_doc,
|
const QTextDocument *p_doc,
|
||||||
qreal p_scaleFactor)
|
const QPixmap &p_image)
|
||||||
{
|
{
|
||||||
QTextBlock block = p_doc->findBlockByNumber(m_codeBlock.m_endBlock);
|
QTextBlock block = p_doc->findBlockByNumber(m_codeBlock.m_endBlock);
|
||||||
if (block.isValid()) {
|
if (block.isValid()) {
|
||||||
Qt::TransformationMode tMode = Qt::SmoothTransformation;
|
|
||||||
VImageToPreview *preview = new VImageToPreview();
|
VImageToPreview *preview = new VImageToPreview();
|
||||||
|
|
||||||
preview->m_startPos = block.position();
|
preview->m_startPos = block.position();
|
||||||
@ -79,29 +55,7 @@ void CodeBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor,
|
|||||||
preview->m_name = QString::number(getImageIndex());
|
preview->m_name = QString::number(getImageIndex());
|
||||||
preview->m_isBlock = true;
|
preview->m_isBlock = true;
|
||||||
|
|
||||||
if (hasImageData()) {
|
preview->m_image = p_image;
|
||||||
if (p_scaleFactor < SCALE_FACTOR_THRESHOLD) {
|
|
||||||
preview->m_image.loadFromData(m_imgData.toUtf8(),
|
|
||||||
m_imgFormat.toLocal8Bit().data());
|
|
||||||
} else {
|
|
||||||
QPixmap tmpImg;
|
|
||||||
tmpImg.loadFromData(m_imgData.toUtf8(),
|
|
||||||
m_imgFormat.toLocal8Bit().data());
|
|
||||||
preview->m_image = tmpImg.scaledToWidth(tmpImg.width() * p_scaleFactor, tMode);
|
|
||||||
}
|
|
||||||
} else if (hasImageDataBa()) {
|
|
||||||
if (p_scaleFactor < SCALE_FACTOR_THRESHOLD) {
|
|
||||||
preview->m_image.loadFromData(m_imgDataBa,
|
|
||||||
m_imgFormat.toLocal8Bit().data());
|
|
||||||
} else {
|
|
||||||
QPixmap tmpImg;
|
|
||||||
tmpImg.loadFromData(m_imgDataBa,
|
|
||||||
m_imgFormat.toLocal8Bit().data());
|
|
||||||
preview->m_image = tmpImg.scaledToWidth(tmpImg.width() * p_scaleFactor, tMode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
preview->m_image = QPixmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_inplacePreview.reset(preview);
|
m_inplacePreview.reset(preview);
|
||||||
} else {
|
} else {
|
||||||
@ -110,6 +64,9 @@ void CodeBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define CODE_BLOCK_IMAGE_CACHE_SIZE_DIFF 10
|
||||||
|
#define CODE_BLOCK_IMAGE_CACHE_TIME_DIFF 5
|
||||||
|
|
||||||
VLivePreviewHelper::VLivePreviewHelper(VEditor *p_editor,
|
VLivePreviewHelper::VLivePreviewHelper(VEditor *p_editor,
|
||||||
VDocument *p_document,
|
VDocument *p_document,
|
||||||
QObject *p_parent)
|
QObject *p_parent)
|
||||||
@ -144,13 +101,26 @@ VLivePreviewHelper::VLivePreviewHelper(VEditor *p_editor,
|
|||||||
this, &VLivePreviewHelper::mathjaxPreviewResultReady);
|
this, &VLivePreviewHelper::mathjaxPreviewResultReady);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VLivePreviewHelper::isPreviewLang(const QString &p_lang) const
|
void VLivePreviewHelper::checkLang(const QString &p_lang,
|
||||||
|
bool &p_livePreview,
|
||||||
|
bool &p_inplacePreview) const
|
||||||
{
|
{
|
||||||
return (m_flowchartEnabled && (p_lang == "flow" || p_lang == "flowchart"))
|
if (m_flowchartEnabled && (p_lang == "flow" || p_lang == "flowchart")) {
|
||||||
|| (m_mermaidEnabled && p_lang == "mermaid")
|
p_livePreview = p_inplacePreview = true;
|
||||||
|| (m_plantUMLMode != PlantUMLMode::DisablePlantUML && p_lang == "puml")
|
} else if (m_plantUMLMode != PlantUMLMode::DisablePlantUML && p_lang == "puml") {
|
||||||
|| (m_graphvizEnabled && p_lang == "dot")
|
p_livePreview = true;
|
||||||
|| (m_mathjaxEnabled && p_lang == "mathjax");
|
p_inplacePreview = m_plantUMLMode == PlantUMLMode::LocalPlantUML;
|
||||||
|
} else if (m_graphvizEnabled && p_lang == "dot") {
|
||||||
|
p_livePreview = p_inplacePreview = true;
|
||||||
|
} else if (m_mermaidEnabled && p_lang == "mermaid") {
|
||||||
|
p_livePreview = true;
|
||||||
|
p_inplacePreview = false;
|
||||||
|
} else if (m_mathjaxEnabled && p_lang == "mathjax") {
|
||||||
|
p_livePreview = false;
|
||||||
|
p_inplacePreview = true;
|
||||||
|
} else {
|
||||||
|
p_livePreview = p_inplacePreview = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlocks)
|
void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlocks)
|
||||||
@ -164,34 +134,42 @@ void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlock
|
|||||||
int lastIndex = m_cbIndex;
|
int lastIndex = m_cbIndex;
|
||||||
m_cbIndex = -1;
|
m_cbIndex = -1;
|
||||||
int cursorBlock = m_editor->textCursorW().block().blockNumber();
|
int cursorBlock = m_editor->textCursorW().block().blockNumber();
|
||||||
int idx = 0;
|
|
||||||
bool needUpdate = m_livePreviewEnabled;
|
bool needUpdate = m_livePreviewEnabled;
|
||||||
bool manualInplacePreview = m_inplacePreviewEnabled;
|
bool manualInplacePreview = m_inplacePreviewEnabled;
|
||||||
for (auto const & vcb : p_codeBlocks) {
|
m_codeBlocks.clear();
|
||||||
if (!isPreviewLang(vcb.m_lang)) {
|
|
||||||
|
for (int i = 0; i < p_codeBlocks.size(); ++i) {
|
||||||
|
const VCodeBlock &vcb = p_codeBlocks[i];
|
||||||
|
bool livePreview = false, inplacePreview = false;
|
||||||
|
checkLang(vcb.m_lang, livePreview, inplacePreview);
|
||||||
|
if (!livePreview && !inplacePreview) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QString &text = vcb.m_text;
|
||||||
bool cached = false;
|
bool cached = false;
|
||||||
if (idx < m_codeBlocks.size()) {
|
|
||||||
CodeBlockPreviewInfo &cb = m_codeBlocks[idx];
|
|
||||||
if (cb.codeBlock().equalContent(vcb)) {
|
|
||||||
cb.updateNonContent(m_doc, vcb);
|
|
||||||
cached = true;
|
|
||||||
} else {
|
|
||||||
cb.setCodeBlock(vcb);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_codeBlocks.append(CodeBlockPreviewInfo(vcb));
|
m_codeBlocks.append(CodeBlockPreviewInfo(vcb));
|
||||||
|
int idx = m_codeBlocks.size() - 1;
|
||||||
|
|
||||||
|
auto it = m_cache.find(text);
|
||||||
|
if (it != m_cache.end()) {
|
||||||
|
QSharedPointer<CodeBlockImageCacheEntry> &entry = it.value();
|
||||||
|
entry->m_ts = m_timeStamp;
|
||||||
|
cached = true;
|
||||||
|
m_codeBlocks[idx].setImageData(entry->m_imgFormat, entry->m_imgData);
|
||||||
|
m_codeBlocks[idx].updateInplacePreview(m_editor, m_doc, entry->m_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_inplacePreviewEnabled
|
if (m_inplacePreviewEnabled
|
||||||
|
&& inplacePreview
|
||||||
&& (!cached || !m_codeBlocks[idx].inplacePreviewReady())) {
|
&& (!cached || !m_codeBlocks[idx].inplacePreviewReady())) {
|
||||||
processForInplacePreview(idx);
|
|
||||||
manualInplacePreview = false;
|
manualInplacePreview = false;
|
||||||
|
processForInplacePreview(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_livePreviewEnabled
|
if (m_livePreviewEnabled
|
||||||
|
&& livePreview
|
||||||
&& vcb.m_startBlock <= cursorBlock
|
&& vcb.m_startBlock <= cursorBlock
|
||||||
&& vcb.m_endBlock >= cursorBlock) {
|
&& vcb.m_endBlock >= cursorBlock) {
|
||||||
if (lastIndex == idx && cached) {
|
if (lastIndex == idx && cached) {
|
||||||
@ -200,14 +178,6 @@ void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlock
|
|||||||
|
|
||||||
m_cbIndex = idx;
|
m_cbIndex = idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
++idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idx == m_codeBlocks.size()) {
|
|
||||||
manualInplacePreview = false;
|
|
||||||
} else {
|
|
||||||
m_codeBlocks.resize(idx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (manualInplacePreview) {
|
if (manualInplacePreview) {
|
||||||
@ -217,6 +187,8 @@ void VLivePreviewHelper::updateCodeBlocks(const QVector<VCodeBlock> &p_codeBlock
|
|||||||
if (needUpdate) {
|
if (needUpdate) {
|
||||||
updateLivePreview();
|
updateLivePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clearObsoleteCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VLivePreviewHelper::handleCursorPositionChanged()
|
void VLivePreviewHelper::handleCursorPositionChanged()
|
||||||
@ -319,6 +291,7 @@ void VLivePreviewHelper::setLivePreviewEnabled(bool p_enabled)
|
|||||||
|
|
||||||
if (!m_inplacePreviewEnabled) {
|
if (!m_inplacePreviewEnabled) {
|
||||||
m_codeBlocks.clear();
|
m_codeBlocks.clear();
|
||||||
|
m_cache.clear();
|
||||||
updateInplacePreview();
|
updateInplacePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,6 +306,7 @@ void VLivePreviewHelper::setInplacePreviewEnabled(bool p_enabled)
|
|||||||
m_inplacePreviewEnabled = p_enabled;
|
m_inplacePreviewEnabled = p_enabled;
|
||||||
if (!m_inplacePreviewEnabled && !m_livePreviewEnabled) {
|
if (!m_inplacePreviewEnabled && !m_livePreviewEnabled) {
|
||||||
m_codeBlocks.clear();
|
m_codeBlocks.clear();
|
||||||
|
m_cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateInplacePreview();
|
updateInplacePreview();
|
||||||
@ -371,7 +345,17 @@ void VLivePreviewHelper::localAsyncResultReady(int p_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CodeBlockPreviewInfo &cb = m_codeBlocks[idx];
|
CodeBlockPreviewInfo &cb = m_codeBlocks[idx];
|
||||||
|
const QString &text = cb.codeBlock().m_text;
|
||||||
|
|
||||||
|
QSharedPointer<CodeBlockImageCacheEntry> entry(new CodeBlockImageCacheEntry(p_timeStamp,
|
||||||
|
p_format,
|
||||||
|
p_result,
|
||||||
|
getScaleFactor(cb)));
|
||||||
|
m_cache.insert(text, entry);
|
||||||
|
|
||||||
cb.setImageData(p_format, p_result);
|
cb.setImageData(p_format, p_result);
|
||||||
|
cb.updateInplacePreview(m_editor, m_doc, entry->m_image);
|
||||||
|
|
||||||
if (livePreview) {
|
if (livePreview) {
|
||||||
if (idx != m_cbIndex) {
|
if (idx != m_cbIndex) {
|
||||||
return;
|
return;
|
||||||
@ -380,8 +364,6 @@ void VLivePreviewHelper::localAsyncResultReady(int p_id,
|
|||||||
m_document->setPreviewContent(lang, p_result);
|
m_document->setPreviewContent(lang, p_result);
|
||||||
} else {
|
} else {
|
||||||
// Inplace preview.
|
// Inplace preview.
|
||||||
cb.updateInplacePreview(m_editor, m_doc, getScaleFactor(cb));
|
|
||||||
|
|
||||||
updateInplacePreview();
|
updateInplacePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,7 +372,7 @@ void VLivePreviewHelper::processForInplacePreview(int p_idx)
|
|||||||
{
|
{
|
||||||
CodeBlockPreviewInfo &cb = m_codeBlocks[p_idx];
|
CodeBlockPreviewInfo &cb = m_codeBlocks[p_idx];
|
||||||
const VCodeBlock &vcb = cb.codeBlock();
|
const VCodeBlock &vcb = cb.codeBlock();
|
||||||
Q_ASSERT(!(cb.hasImageData() || cb.hasImageDataBa()));
|
Q_ASSERT(!cb.hasImageData());
|
||||||
if (vcb.m_lang == "dot") {
|
if (vcb.m_lang == "dot") {
|
||||||
if (!m_graphvizHelper) {
|
if (!m_graphvizHelper) {
|
||||||
m_graphvizHelper = new VGraphvizHelper(this);
|
m_graphvizHelper = new VGraphvizHelper(this);
|
||||||
@ -474,7 +456,31 @@ void VLivePreviewHelper::mathjaxPreviewResultReady(int p_identitifer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CodeBlockPreviewInfo &cb = m_codeBlocks[p_id];
|
CodeBlockPreviewInfo &cb = m_codeBlocks[p_id];
|
||||||
cb.setImageDataBa(p_format, p_data);
|
const QString &text = cb.codeBlock().m_text;
|
||||||
cb.updateInplacePreview(m_editor, m_doc, getScaleFactor(cb));
|
|
||||||
|
QSharedPointer<CodeBlockImageCacheEntry> entry(new CodeBlockImageCacheEntry(p_timeStamp,
|
||||||
|
p_format,
|
||||||
|
p_data,
|
||||||
|
getScaleFactor(cb)));
|
||||||
|
m_cache.insert(text, entry);
|
||||||
|
|
||||||
|
cb.updateInplacePreview(m_editor, m_doc, entry->m_image);
|
||||||
|
|
||||||
updateInplacePreview();
|
updateInplacePreview();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VLivePreviewHelper::clearObsoleteCache()
|
||||||
|
{
|
||||||
|
if (m_cache.size() - m_codeBlocks.size() <= CODE_BLOCK_IMAGE_CACHE_SIZE_DIFF) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto it = m_cache.begin(); it != m_cache.end();) {
|
||||||
|
if (m_timeStamp - it.value()->m_ts > CODE_BLOCK_IMAGE_CACHE_TIME_DIFF) {
|
||||||
|
it.value().clear();
|
||||||
|
it = m_cache.erase(it);
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,19 +21,9 @@ public:
|
|||||||
|
|
||||||
explicit CodeBlockPreviewInfo(const VCodeBlock &p_cb);
|
explicit CodeBlockPreviewInfo(const VCodeBlock &p_cb);
|
||||||
|
|
||||||
void clearImageData()
|
|
||||||
{
|
|
||||||
m_imgData.clear();
|
|
||||||
m_imgDataBa.clear();
|
|
||||||
m_inplacePreview.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateNonContent(const QTextDocument *p_doc,
|
|
||||||
const VCodeBlock &p_cb);
|
|
||||||
|
|
||||||
void updateInplacePreview(const VEditor *p_editor,
|
void updateInplacePreview(const VEditor *p_editor,
|
||||||
const QTextDocument *p_doc,
|
const QTextDocument *p_doc,
|
||||||
qreal p_scaleFactor);
|
const QPixmap &p_image);
|
||||||
|
|
||||||
VCodeBlock &codeBlock()
|
VCodeBlock &codeBlock()
|
||||||
{
|
{
|
||||||
@ -45,13 +35,6 @@ public:
|
|||||||
return m_codeBlock;
|
return m_codeBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCodeBlock(const VCodeBlock &p_cb)
|
|
||||||
{
|
|
||||||
m_codeBlock = p_cb;
|
|
||||||
|
|
||||||
clearImageData();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool inplacePreviewReady() const
|
bool inplacePreviewReady() const
|
||||||
{
|
{
|
||||||
return !m_inplacePreview.isNull();
|
return !m_inplacePreview.isNull();
|
||||||
@ -67,16 +50,6 @@ public:
|
|||||||
return m_imgData;
|
return m_imgData;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasImageDataBa() const
|
|
||||||
{
|
|
||||||
return !m_imgDataBa.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QByteArray &imageDataBa() const
|
|
||||||
{
|
|
||||||
return m_imgDataBa;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QString &imageFormat() const
|
const QString &imageFormat() const
|
||||||
{
|
{
|
||||||
return m_imgFormat;
|
return m_imgFormat;
|
||||||
@ -84,22 +57,10 @@ public:
|
|||||||
|
|
||||||
void setImageData(const QString &p_format, const QString &p_data)
|
void setImageData(const QString &p_format, const QString &p_data)
|
||||||
{
|
{
|
||||||
m_imgDataBa.clear();
|
|
||||||
m_inplacePreview.clear();
|
|
||||||
|
|
||||||
m_imgFormat = p_format;
|
m_imgFormat = p_format;
|
||||||
m_imgData = p_data;
|
m_imgData = p_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setImageDataBa(const QString &p_format, const QByteArray &p_data)
|
|
||||||
{
|
|
||||||
m_imgData.clear();
|
|
||||||
m_inplacePreview.clear();
|
|
||||||
|
|
||||||
m_imgFormat = p_format;
|
|
||||||
m_imgDataBa = p_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QSharedPointer<VImageToPreview> inplacePreview() const
|
const QSharedPointer<VImageToPreview> inplacePreview() const
|
||||||
{
|
{
|
||||||
return m_inplacePreview;
|
return m_inplacePreview;
|
||||||
@ -116,8 +77,6 @@ private:
|
|||||||
|
|
||||||
QString m_imgData;
|
QString m_imgData;
|
||||||
|
|
||||||
QByteArray m_imgDataBa;
|
|
||||||
|
|
||||||
QString m_imgFormat;
|
QString m_imgFormat;
|
||||||
|
|
||||||
QSharedPointer<VImageToPreview> m_inplacePreview;
|
QSharedPointer<VImageToPreview> m_inplacePreview;
|
||||||
@ -161,7 +120,79 @@ private slots:
|
|||||||
const QByteArray &p_data);
|
const QByteArray &p_data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isPreviewLang(const QString &p_lang) const;
|
struct CodeBlockImageCacheEntry
|
||||||
|
{
|
||||||
|
#define SCALE_FACTOR_THRESHOLD 1.1
|
||||||
|
|
||||||
|
CodeBlockImageCacheEntry()
|
||||||
|
: m_ts(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeBlockImageCacheEntry(TimeStamp p_ts,
|
||||||
|
const QString &p_format,
|
||||||
|
const QByteArray &p_data,
|
||||||
|
qreal p_scaleFactor)
|
||||||
|
: m_ts(p_ts)
|
||||||
|
{
|
||||||
|
if (!p_data.isEmpty()) {
|
||||||
|
if (p_scaleFactor < SCALE_FACTOR_THRESHOLD) {
|
||||||
|
m_image.loadFromData(p_data,
|
||||||
|
p_format.toLocal8Bit().data());
|
||||||
|
} else {
|
||||||
|
QPixmap tmpImg;
|
||||||
|
tmpImg.loadFromData(p_data,
|
||||||
|
p_format.toLocal8Bit().data());
|
||||||
|
m_image = tmpImg.scaledToWidth(tmpImg.width() * p_scaleFactor,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeBlockImageCacheEntry(TimeStamp p_ts,
|
||||||
|
const QString &p_format,
|
||||||
|
const QString &p_data,
|
||||||
|
qreal p_scaleFactor)
|
||||||
|
: m_ts(p_ts),
|
||||||
|
m_imgData(p_data),
|
||||||
|
m_imgFormat(p_format)
|
||||||
|
{
|
||||||
|
if (!p_data.isEmpty()) {
|
||||||
|
if (p_scaleFactor < SCALE_FACTOR_THRESHOLD) {
|
||||||
|
m_image.loadFromData(p_data.toUtf8(),
|
||||||
|
p_format.toLocal8Bit().data());
|
||||||
|
} else {
|
||||||
|
QPixmap tmpImg;
|
||||||
|
tmpImg.loadFromData(p_data.toUtf8(),
|
||||||
|
p_format.toLocal8Bit().data());
|
||||||
|
m_image = tmpImg.scaledToWidth(tmpImg.width() * p_scaleFactor,
|
||||||
|
Qt::SmoothTransformation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasImageData() const
|
||||||
|
{
|
||||||
|
return !m_imgData.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasImage() const
|
||||||
|
{
|
||||||
|
return !m_image.isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeStamp m_ts;
|
||||||
|
|
||||||
|
// For live preview.
|
||||||
|
QString m_imgData;
|
||||||
|
QString m_imgFormat;
|
||||||
|
|
||||||
|
// For in-place preview.
|
||||||
|
QPixmap m_image;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void checkLang(const QString &p_lang, bool &p_livePreview, bool &p_inplacePreview) const;
|
||||||
|
|
||||||
// Get image data for this code block for inplace preview.
|
// Get image data for this code block for inplace preview.
|
||||||
void processForInplacePreview(int p_idx);
|
void processForInplacePreview(int p_idx);
|
||||||
@ -171,6 +202,8 @@ private:
|
|||||||
|
|
||||||
qreal getScaleFactor(const CodeBlockPreviewInfo &p_cb);
|
qreal getScaleFactor(const CodeBlockPreviewInfo &p_cb);
|
||||||
|
|
||||||
|
void clearObsoleteCache();
|
||||||
|
|
||||||
// Sorted by m_startBlock in ascending order.
|
// Sorted by m_startBlock in ascending order.
|
||||||
QVector<CodeBlockPreviewInfo> m_codeBlocks;
|
QVector<CodeBlockPreviewInfo> m_codeBlocks;
|
||||||
|
|
||||||
@ -206,6 +239,9 @@ private:
|
|||||||
TimeStamp m_timeStamp;
|
TimeStamp m_timeStamp;
|
||||||
|
|
||||||
const qreal m_scaleFactor;
|
const qreal m_scaleFactor;
|
||||||
|
|
||||||
|
// Indexed by content.
|
||||||
|
QHash<QString, QSharedPointer<CodeBlockImageCacheEntry>> m_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline bool VLivePreviewHelper::isPreviewEnabled() const
|
inline bool VLivePreviewHelper::isPreviewEnabled() const
|
||||||
|
@ -19,32 +19,9 @@ MathjaxBlockPreviewInfo::MathjaxBlockPreviewInfo(const VMathjaxBlock &p_mb)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void MathjaxBlockPreviewInfo::updateNonContent(const QTextDocument *p_doc,
|
|
||||||
const VEditor *p_editor,
|
|
||||||
const VMathjaxBlock &p_mb)
|
|
||||||
{
|
|
||||||
m_mathjaxBlock.updateNonContent(p_mb);
|
|
||||||
if (m_inplacePreview.isNull()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QTextBlock block = p_doc->findBlockByNumber(m_mathjaxBlock.m_blockNumber);
|
|
||||||
if (block.isValid()) {
|
|
||||||
m_inplacePreview->m_startPos = block.position() + m_mathjaxBlock.m_index;
|
|
||||||
m_inplacePreview->m_endPos = m_inplacePreview->m_startPos + m_mathjaxBlock.m_length;
|
|
||||||
m_inplacePreview->m_blockPos = block.position();
|
|
||||||
m_inplacePreview->m_blockNumber = m_mathjaxBlock.m_blockNumber;
|
|
||||||
// Padding may changed.
|
|
||||||
m_inplacePreview->m_padding = VPreviewManager::calculateBlockMargin(block,
|
|
||||||
p_editor->tabStopWidthW());
|
|
||||||
m_inplacePreview->m_isBlock = m_mathjaxBlock.m_previewedAsBlock;
|
|
||||||
} else {
|
|
||||||
m_inplacePreview.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MathjaxBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor,
|
void MathjaxBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor,
|
||||||
const QTextDocument *p_doc)
|
const QTextDocument *p_doc,
|
||||||
|
const QPixmap &p_image)
|
||||||
{
|
{
|
||||||
QTextBlock block = p_doc->findBlockByNumber(m_mathjaxBlock.m_blockNumber);
|
QTextBlock block = p_doc->findBlockByNumber(m_mathjaxBlock.m_blockNumber);
|
||||||
if (block.isValid()) {
|
if (block.isValid()) {
|
||||||
@ -59,12 +36,7 @@ void MathjaxBlockPreviewInfo::updateInplacePreview(const VEditor *p_editor,
|
|||||||
preview->m_name = QString::number(getImageIndex());
|
preview->m_name = QString::number(getImageIndex());
|
||||||
preview->m_isBlock = m_mathjaxBlock.m_previewedAsBlock;
|
preview->m_isBlock = m_mathjaxBlock.m_previewedAsBlock;
|
||||||
|
|
||||||
if (hasImageDataBa()) {
|
preview->m_image = p_image;
|
||||||
preview->m_image.loadFromData(m_imgDataBa,
|
|
||||||
m_imgFormat.toLocal8Bit().data());
|
|
||||||
} else {
|
|
||||||
preview->m_image = QPixmap();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_inplacePreview.reset(preview);
|
m_inplacePreview.reset(preview);
|
||||||
} else {
|
} else {
|
||||||
@ -133,13 +105,12 @@ void VMathJaxInplacePreviewHelper::updateMathjaxBlocks(const QVector<VMathjaxBlo
|
|||||||
QSharedPointer<MathjaxImageCacheEntry> &entry = it.value();
|
QSharedPointer<MathjaxImageCacheEntry> &entry = it.value();
|
||||||
entry->m_ts = m_timeStamp;
|
entry->m_ts = m_timeStamp;
|
||||||
cached = true;
|
cached = true;
|
||||||
m_mathjaxBlocks[i].setImageDataBa(entry->m_imgFormat, entry->m_imgDataBa);
|
m_mathjaxBlocks.last().updateInplacePreview(m_editor, m_doc, entry->m_image);
|
||||||
m_mathjaxBlocks[i].updateInplacePreview(m_editor, m_doc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cached || !m_mathjaxBlocks[i].inplacePreviewReady()) {
|
if (!cached || !m_mathjaxBlocks.last().inplacePreviewReady()) {
|
||||||
manualUpdate = false;
|
manualUpdate = false;
|
||||||
processForInplacePreview(i);
|
processForInplacePreview(m_mathjaxBlocks.size() - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,14 +193,12 @@ void VMathJaxInplacePreviewHelper::mathjaxPreviewResultReady(int p_identitifer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
MathjaxBlockPreviewInfo &mb = m_mathjaxBlocks[p_id];
|
MathjaxBlockPreviewInfo &mb = m_mathjaxBlocks[p_id];
|
||||||
mb.setImageDataBa(p_format, p_data);
|
|
||||||
mb.updateInplacePreview(m_editor, m_doc);
|
|
||||||
|
|
||||||
// Update the cache.
|
// Update the cache.
|
||||||
QSharedPointer<MathjaxImageCacheEntry> entry(new MathjaxImageCacheEntry(p_timeStamp,
|
QSharedPointer<MathjaxImageCacheEntry> entry(new MathjaxImageCacheEntry(p_timeStamp,
|
||||||
p_data,
|
p_data,
|
||||||
p_format));
|
p_format));
|
||||||
m_cache.insert(mb.mathjaxBlock().m_text, entry);
|
m_cache.insert(mb.mathjaxBlock().m_text, entry);
|
||||||
|
mb.updateInplacePreview(m_editor, m_doc, entry->m_image);
|
||||||
|
|
||||||
updateInplacePreview();
|
updateInplacePreview();
|
||||||
}
|
}
|
||||||
|
@ -19,17 +19,9 @@ public:
|
|||||||
|
|
||||||
explicit MathjaxBlockPreviewInfo(const VMathjaxBlock &p_mb);
|
explicit MathjaxBlockPreviewInfo(const VMathjaxBlock &p_mb);
|
||||||
|
|
||||||
void clearImageData()
|
void updateInplacePreview(const VEditor *p_editor,
|
||||||
{
|
const QTextDocument *p_doc,
|
||||||
m_imgDataBa.clear();
|
const QPixmap &p_image);
|
||||||
m_inplacePreview.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateNonContent(const QTextDocument *p_doc,
|
|
||||||
const VEditor *p_editor,
|
|
||||||
const VMathjaxBlock &p_mb);
|
|
||||||
|
|
||||||
void updateInplacePreview(const VEditor *p_editor, const QTextDocument *p_doc);
|
|
||||||
|
|
||||||
VMathjaxBlock &mathjaxBlock()
|
VMathjaxBlock &mathjaxBlock()
|
||||||
{
|
{
|
||||||
@ -41,29 +33,11 @@ public:
|
|||||||
return m_mathjaxBlock;
|
return m_mathjaxBlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setMathjaxBlock(const VMathjaxBlock &p_mb)
|
|
||||||
{
|
|
||||||
m_mathjaxBlock = p_mb;
|
|
||||||
clearImageData();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool inplacePreviewReady() const
|
bool inplacePreviewReady() const
|
||||||
{
|
{
|
||||||
return !m_inplacePreview.isNull();
|
return !m_inplacePreview.isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setImageDataBa(const QString &p_format, const QByteArray &p_data)
|
|
||||||
{
|
|
||||||
m_imgFormat = p_format;
|
|
||||||
m_imgDataBa = p_data;
|
|
||||||
m_inplacePreview.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasImageDataBa() const
|
|
||||||
{
|
|
||||||
return !m_imgDataBa.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
const QSharedPointer<VImageToPreview> inplacePreview() const
|
const QSharedPointer<VImageToPreview> inplacePreview() const
|
||||||
{
|
{
|
||||||
return m_inplacePreview;
|
return m_inplacePreview;
|
||||||
@ -78,10 +52,6 @@ private:
|
|||||||
|
|
||||||
VMathjaxBlock m_mathjaxBlock;
|
VMathjaxBlock m_mathjaxBlock;
|
||||||
|
|
||||||
QByteArray m_imgDataBa;
|
|
||||||
|
|
||||||
QString m_imgFormat;
|
|
||||||
|
|
||||||
QSharedPointer<VImageToPreview> m_inplacePreview;
|
QSharedPointer<VImageToPreview> m_inplacePreview;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -124,15 +94,15 @@ private:
|
|||||||
MathjaxImageCacheEntry(TimeStamp p_ts,
|
MathjaxImageCacheEntry(TimeStamp p_ts,
|
||||||
const QByteArray &p_dataBa,
|
const QByteArray &p_dataBa,
|
||||||
const QString &p_format)
|
const QString &p_format)
|
||||||
: m_ts(p_ts),
|
: m_ts(p_ts)
|
||||||
m_imgDataBa(p_dataBa),
|
|
||||||
m_imgFormat(p_format)
|
|
||||||
{
|
{
|
||||||
|
if (!p_dataBa.isEmpty()) {
|
||||||
|
m_image.loadFromData(p_dataBa, p_format.toLocal8Bit().data());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeStamp m_ts;
|
TimeStamp m_ts;
|
||||||
QByteArray m_imgDataBa;
|
QPixmap m_image;
|
||||||
QString m_imgFormat;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user