Browse Source

optimize VImagePreviewer by flags

Le Tan 8 years ago
parent
commit
07e8f27776
5 changed files with 77 additions and 27 deletions
  1. 29 3
      src/hgmarkdownhighlighter.cpp
  2. 15 2
      src/hgmarkdownhighlighter.h
  3. 29 20
      src/vimagepreviewer.cpp
  4. 3 1
      src/vimagepreviewer.h
  5. 1 1
      src/vmdedit.cpp

+ 29 - 3
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<VTextBlockData *>(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())) {

+ 15 - 2
src/hgmarkdownhighlighter.h

@@ -4,7 +4,7 @@
 #include <QTextCharFormat>
 #include <QSyntaxHighlighter>
 #include <QAtomicInt>
-#include <QSet>
+#include <QMap>
 #include <QString>
 #include <QHash>
 
@@ -118,9 +118,12 @@ public:
                           int waitInterval,
                           QTextDocument *parent = 0);
     ~HGMarkdownHighlighter();
+
     // Request to update highlihgt (re-parse and re-highlight)
     void setCodeBlockHighlights(const QVector<HLUnitPos> &p_units);
 
+    const QMap<int, bool> &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<int, bool> m_potentialPreviewBlocks;
+
     // All HTML comment regions.
     QVector<VElementRegion> 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<int, bool> &HGMarkdownHighlighter::getPotentialPreviewBlocks() const
+{
+    return m_potentialPreviewBlocks;
+}
+
 #endif

+ 29 - 20
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<int, bool> 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<ImageLinkInfo> &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);

+ 3 - 1
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<QString, ImageInfo> m_imageCache;
 

+ 1 - 1
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,