From 07e8f27776e44141c8d61d365b810cbdd9f54dd1 Mon Sep 17 00:00:00 2001 From: Le Tan Date: Fri, 8 Sep 2017 21:41:46 +0800 Subject: [PATCH] optimize VImagePreviewer by flags --- src/hgmarkdownhighlighter.cpp | 32 ++++++++++++++++++++--- src/hgmarkdownhighlighter.h | 17 ++++++++++-- src/vimagepreviewer.cpp | 49 +++++++++++++++++++++-------------- src/vimagepreviewer.h | 4 ++- src/vmdedit.cpp | 2 +- 5 files changed, 77 insertions(+), 27 deletions(-) diff --git a/src/hgmarkdownhighlighter.cpp b/src/hgmarkdownhighlighter.cpp index c07827d5..979410bb 100644 --- a/src/hgmarkdownhighlighter.cpp +++ b/src/hgmarkdownhighlighter.cpp @@ -80,7 +80,7 @@ HGMarkdownHighlighter::~HGMarkdownHighlighter() } } -void HGMarkdownHighlighter::updateBlockUserData(const QString &p_text) +void HGMarkdownHighlighter::updateBlockUserData(int p_blockNum, const QString &p_text) { VTextBlockData *blockData = dynamic_cast(currentBlockUserData()); if (!blockData) { @@ -88,7 +88,33 @@ void HGMarkdownHighlighter::updateBlockUserData(const QString &p_text) setCurrentBlockUserData(blockData); } - blockData->setContainsPreviewImage(p_text.contains(QChar::ObjectReplacementCharacter)); + bool contains = p_text.contains(QChar::ObjectReplacementCharacter); + blockData->setContainsPreviewImage(contains); + + auto curIt = m_potentialPreviewBlocks.find(p_blockNum); + if (curIt == m_potentialPreviewBlocks.end()) { + if (contains) { + m_potentialPreviewBlocks.insert(p_blockNum, true); + } + } else { + if (!contains) { + m_potentialPreviewBlocks.erase(curIt); + } + } + + // Delete elements beyond current block count. + int blocks = document->blockCount(); + if (!m_potentialPreviewBlocks.isEmpty()) { + auto it = m_potentialPreviewBlocks.end(); + do { + --it; + if (it.key() >= blocks) { + it = m_potentialPreviewBlocks.erase(it); + } else { + break; + } + } while (it != m_potentialPreviewBlocks.begin()); + } } void HGMarkdownHighlighter::highlightBlock(const QString &text) @@ -107,7 +133,7 @@ void HGMarkdownHighlighter::highlightBlock(const QString &text) // We can use other highlighting methods to complement it. // Set current block's user data. - updateBlockUserData(text); + updateBlockUserData(blockNum, text); // If it is a block inside HTML comment, just skip it. if (isBlockInsideCommentRegion(currentBlock())) { diff --git a/src/hgmarkdownhighlighter.h b/src/hgmarkdownhighlighter.h index 0d91faa7..48402b6d 100644 --- a/src/hgmarkdownhighlighter.h +++ b/src/hgmarkdownhighlighter.h @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -118,9 +118,12 @@ public: int waitInterval, QTextDocument *parent = 0); ~HGMarkdownHighlighter(); + // Request to update highlihgt (re-parse and re-highlight) void setCodeBlockHighlights(const QVector &p_units); + const QMap &getPotentialPreviewBlocks() const; + signals: void highlightCompleted(); @@ -160,6 +163,11 @@ private: int m_numOfCodeBlockHighlightsToRecv; + // If the ith block contains preview, then the set contains i. + // If the set contains i, the ith block may contain preview. + // We just use the key. + QMap m_potentialPreviewBlocks; + // All HTML comment regions. QVector m_commentRegions; @@ -210,7 +218,12 @@ private: void highlightChanged(); // Set the user data of currentBlock(). - void updateBlockUserData(const QString &p_text); + void updateBlockUserData(int p_blockNum, const QString &p_text); }; +inline const QMap &HGMarkdownHighlighter::getPotentialPreviewBlocks() const +{ + return m_potentialPreviewBlocks; +} + #endif diff --git a/src/vimagepreviewer.cpp b/src/vimagepreviewer.cpp index 8da0648f..b101d503 100644 --- a/src/vimagepreviewer.cpp +++ b/src/vimagepreviewer.cpp @@ -20,10 +20,10 @@ extern VConfigManager *g_config; const int VImagePreviewer::c_minImageWidth = 100; -VImagePreviewer::VImagePreviewer(VMdEdit *p_edit) +VImagePreviewer::VImagePreviewer(VMdEdit *p_edit, const HGMarkdownHighlighter *p_highlighter) : QObject(p_edit), m_edit(p_edit), m_document(p_edit->document()), - m_file(p_edit->getFile()), m_imageWidth(c_minImageWidth), - m_timeStamp(0), m_previewIndex(0), + m_file(p_edit->getFile()), m_highlighter(p_highlighter), + m_imageWidth(c_minImageWidth), m_timeStamp(0), m_previewIndex(0), m_previewEnabled(g_config->getEnablePreviewImages()), m_isPreviewing(false) { m_updateTimer = new QTimer(this); @@ -152,19 +152,28 @@ void VImagePreviewer::clearObsoletePreviewImages(QTextCursor &p_cursor) } } - bool hasObsolete = false; - QTextBlock block = m_document->begin(); // Clean block data and delete obsolete preview. - while (block.isValid()) { - if (!VTextBlockData::containsPreviewImage(block)) { - block = block.next(); - continue; - } else { - QTextBlock nextBlock = block.next(); - // Notice the short circuit. - hasObsolete = clearObsoletePreviewImagesOfBlock(block, p_cursor) || hasObsolete; - block = nextBlock; - } + bool hasObsolete = false; + int blockCount = m_document->blockCount(); + // Must copy it. + QMap potentialBlocks = m_highlighter->getPotentialPreviewBlocks(); + // From back to front. + if (!potentialBlocks.isEmpty()) { + auto it = potentialBlocks.end(); + do { + --it; + int blockNum = it.key(); + if (blockNum >= blockCount) { + continue; + } + + QTextBlock block = m_document->findBlockByNumber(blockNum); + if (block.isValid() + && VTextBlockData::containsPreviewImage(block)) { + // Notice the short circuit. + hasObsolete = clearObsoletePreviewImagesOfBlock(block, p_cursor) || hasObsolete; + } + } while (it != potentialBlocks.begin()); } if (hasObsolete) { @@ -246,11 +255,11 @@ bool VImagePreviewer::clearObsoletePreviewImagesOfBlock(QTextBlock &p_block, return hasObsolete; } -// Returns true if p_text[p_start, p_end) is all spaces. -static bool isAllSpaces(const QString &p_text, int p_start, int p_end) +// Returns true if p_text[p_start, p_end) is all spaces or QChar::ObjectReplacementCharacter. +static bool isAllSpacesOrObject(const QString &p_text, int p_start, int p_end) { for (int i = p_start; i < p_end && i < p_text.size(); ++i) { - if (!p_text[i].isSpace()) { + if (!p_text[i].isSpace() && p_text[i] != QChar::ObjectReplacementCharacter) { return false; } } @@ -281,9 +290,9 @@ void VImagePreviewer::fetchImageLinksFromRegions(QVector &p_image Q_ASSERT(reg.m_endPos <= blockEnd); ImageLinkInfo info(reg.m_startPos, reg.m_endPos); if ((reg.m_startPos == blockStart - || isAllSpaces(text, 0, reg.m_startPos - blockStart)) + || isAllSpacesOrObject(text, 0, reg.m_startPos - blockStart)) && (reg.m_endPos == blockEnd - || isAllSpaces(text, reg.m_endPos - blockStart, blockEnd - blockStart))) { + || isAllSpacesOrObject(text, reg.m_endPos - blockStart, blockEnd - blockStart))) { // Image block. info.m_isBlock = true; info.m_linkUrl = fetchImagePathToPreview(text); diff --git a/src/vimagepreviewer.h b/src/vimagepreviewer.h index b17c6b75..d99dce5d 100644 --- a/src/vimagepreviewer.h +++ b/src/vimagepreviewer.h @@ -17,7 +17,7 @@ class VImagePreviewer : public QObject { Q_OBJECT public: - explicit VImagePreviewer(VMdEdit *p_edit); + explicit VImagePreviewer(VMdEdit *p_edit, const HGMarkdownHighlighter *p_highlighter); // Whether @p_block is an image previewed block. // The image previewed block is a block containing only the special character @@ -202,6 +202,8 @@ private: QTextDocument *m_document; VFile *m_file; + const HGMarkdownHighlighter *m_highlighter; + // Map from image full path to QUrl identifier in the QTextDocument's cache. QHash m_imageCache; diff --git a/src/vmdedit.cpp b/src/vmdedit.cpp index 04ada89b..20c694ae 100644 --- a/src/vmdedit.cpp +++ b/src/vmdedit.cpp @@ -44,7 +44,7 @@ VMdEdit::VMdEdit(VFile *p_file, VDocument *p_vdoc, MarkdownConverterType p_type, m_cbHighlighter = new VCodeBlockHighlightHelper(m_mdHighlighter, p_vdoc, p_type); - m_imagePreviewer = new VImagePreviewer(this); + m_imagePreviewer = new VImagePreviewer(this, m_mdHighlighter); connect(m_mdHighlighter, &HGMarkdownHighlighter::imageLinksUpdated, m_imagePreviewer, &VImagePreviewer::imageLinksChanged); connect(m_imagePreviewer, &VImagePreviewer::requestUpdateImageLinks,