#ifndef VTEXTBLOCKDATA_H #define VTEXTBLOCKDATA_H #include #include #include #include "vconstants.h" #include "markdownhighlighterdata.h" #include "vtextdocumentlayoutdata.h" // Sources of the preview. enum class PreviewSource { ImageLink = 0, CodeBlock, MathjaxBlock, MaxNumberOfSources }; // Info about a previewed image. struct VPreviewedImageInfo { VPreviewedImageInfo() : m_startPos(-1), m_endPos(-1), m_padding(0), m_inline(false) { } VPreviewedImageInfo(int p_startPos, int p_endPos, int p_padding, bool p_inline, const QString &p_imageName, const QSize &p_imageSize, const QString &p_background) : m_startPos(p_startPos), m_endPos(p_endPos), m_padding(p_padding), m_inline(p_inline), m_imageName(p_imageName), m_imageSize(p_imageSize), m_background(p_background) { } bool operator<(const VPreviewedImageInfo &a) const { return m_endPos <= a.m_startPos; } bool operator==(const VPreviewedImageInfo &a) const { return m_startPos == a.m_startPos && m_endPos == a.m_endPos && m_padding == a.m_padding && m_inline == a.m_inline && m_imageName == a.m_imageName && m_imageSize == a.m_imageSize && m_background == a.m_background; } bool intersect(const VPreviewedImageInfo &a) const { return !(m_endPos <= a.m_startPos || m_startPos >= a.m_endPos); } bool contains(int p_positionInBlock) const { return p_positionInBlock >= m_startPos && p_positionInBlock < m_endPos; } QString toString() const { return QString("previewed image (%1): [%2, %3] padding %4 inline %5 (%6,%7) bg(%8)") .arg(m_imageName) .arg(m_startPos) .arg(m_endPos) .arg(m_padding) .arg(m_inline) .arg(m_imageSize.width()) .arg(m_imageSize.height()) .arg(m_background); } // Start position of text corresponding to the image within block. int m_startPos; // End position of text corresponding to the image within block. int m_endPos; // Padding of the image. Only valid for block image. int m_padding; // Whether it is inline image or block image. bool m_inline; // Image name in the resource manager. QString m_imageName; // Image size of the image. Cache for performance. QSize m_imageSize; // Forced background before drawing this image. QString m_background; }; struct VPreviewInfo { VPreviewInfo() : m_source(PreviewSource::ImageLink), m_timeStamp(0) { } VPreviewInfo(PreviewSource p_source, long long p_timeStamp, int p_startPos, int p_endPos, int p_padding, bool p_inline, const QString &p_imageName, const QSize &p_imageSize, const QString &p_background) : m_source(p_source), m_timeStamp(p_timeStamp), m_imageInfo(p_startPos, p_endPos, p_padding, p_inline, p_imageName, p_imageSize, p_background) { } // Source of this preview. PreviewSource m_source; // Timestamp for this preview. long long m_timeStamp; // Image info of this preview. VPreviewedImageInfo m_imageInfo; }; // User data for each block. class VTextBlockData : public QTextBlockUserData { public: VTextBlockData(); ~VTextBlockData(); // Insert @p_info into m_previews, preserving the order. // Returns true if only timestamp is updated. bool insertPreviewInfo(VPreviewInfo *p_info); // For degub only. QString toString() const; const QVector &getPreviews() const; // Return true if there have obsolete preview being deleted. bool clearObsoletePreview(long long p_timeStamp, PreviewSource p_source); int getCodeBlockIndentation() const; void setCodeBlockIndentation(int p_indent); TimeStamp getTimeStamp() const; void setTimeStamp(TimeStamp p_ts); TimeStamp getCodeBlockTimeStamp() const; void setCodeBlockTimeStamp(TimeStamp p_ts); bool isBlockHighlightCacheMatched(const QVector &p_highlight) const; QVector &getBlockHighlightCache(); void setBlockHighlightCache(const QVector &p_highlight); bool isCodeBlockHighlightCacheMatched(const QVector &p_highlight) const; QVector &getCodeBlockHighlightCache(); void setCodeBlockHighlightCache(const QVector &p_highlight); bool isCacheValid() const; void setCacheValid(bool p_valid); static VTextBlockData *blockData(const QTextBlock &p_block); static BlockLayoutInfo *layoutInfo(const QTextBlock &p_block); private: // Check the order of elements. bool checkOrder() const; // TimeStamp of the highlight result which has been applied to this block. TimeStamp m_timeStamp; // TimeStamp of the code block highlight result which has been applied to this block. TimeStamp m_codeBlockTimeStamp; // Block highlight cache. QVector m_blockHighlightCache; // Code block highlight cache. // This cache is always valid. QVector m_codeBlockHighlightCache; // Whether the highlight cache is valid. bool m_cacheValid; // Sorted by m_imageInfo.m_startPos, with no two element's position intersected. QVector m_previews; // Indentation of the this code block if this block is a fenced code block. int m_codeBlockIndentation; BlockLayoutInfo m_layoutInfo; }; inline const QVector &VTextBlockData::getPreviews() const { return m_previews; } inline int VTextBlockData::getCodeBlockIndentation() const { return m_codeBlockIndentation; } inline void VTextBlockData::setCodeBlockIndentation(int p_indent) { m_codeBlockIndentation = p_indent; } inline TimeStamp VTextBlockData::getTimeStamp() const { return m_timeStamp; } inline void VTextBlockData::setTimeStamp(TimeStamp p_ts) { m_timeStamp = p_ts; } inline TimeStamp VTextBlockData::getCodeBlockTimeStamp() const { return m_codeBlockTimeStamp; } inline void VTextBlockData::setCodeBlockTimeStamp(TimeStamp p_ts) { m_codeBlockTimeStamp = p_ts; } inline bool VTextBlockData::isBlockHighlightCacheMatched(const QVector &p_highlight) const { if (!m_cacheValid || p_highlight.size() != m_blockHighlightCache.size()) { return false; } int sz = p_highlight.size(); for (int i = 0; i < sz; ++i) { if (!(p_highlight[i] == m_blockHighlightCache[i])) { return false; } } return true; } inline QVector &VTextBlockData::getBlockHighlightCache() { return m_blockHighlightCache; } inline void VTextBlockData::setBlockHighlightCache(const QVector &p_highlight) { m_blockHighlightCache = p_highlight; } inline bool VTextBlockData::isCodeBlockHighlightCacheMatched(const QVector &p_highlight) const { if (p_highlight.size() != m_codeBlockHighlightCache.size()) { return false; } int sz = p_highlight.size(); for (int i = 0; i < sz; ++i) { if (!(p_highlight[i] == m_codeBlockHighlightCache[i])) { return false; } } return true; } inline QVector &VTextBlockData::getCodeBlockHighlightCache() { return m_codeBlockHighlightCache; } inline void VTextBlockData::setCodeBlockHighlightCache(const QVector &p_highlight) { m_codeBlockHighlightCache = p_highlight; } inline bool VTextBlockData::isCacheValid() const { return m_cacheValid; } inline void VTextBlockData::setCacheValid(bool p_valid) { m_cacheValid = p_valid; } inline VTextBlockData *VTextBlockData::blockData(const QTextBlock &p_block) { if (!p_block.isValid()) { return NULL; } VTextBlockData *data = static_cast(p_block.userData()); if (!data) { data = new VTextBlockData(); const_cast(p_block).setUserData(data); } return data; } inline BlockLayoutInfo *VTextBlockData::layoutInfo(const QTextBlock &p_block) { VTextBlockData *data = blockData(p_block); if (data) { return &data->m_layoutInfo; } else { return NULL; } } #endif // VTEXTBLOCKDATA_H