diff --git a/src/dialog/vcopytextashtmldialog.cpp b/src/dialog/vcopytextashtmldialog.cpp index d7a7287b..5ba12fec 100644 --- a/src/dialog/vcopytextashtmldialog.cpp +++ b/src/dialog/vcopytextashtmldialog.cpp @@ -65,6 +65,8 @@ void VCopyTextAsHtmlDialog::setConvertedHtml(const QUrl &p_baseUrl, m_htmlViewer->setHtml(html, p_baseUrl); setHtmlVisible(true); + VWebUtils::translateColors(html); + // Fix image source. if (g_config->getFixImageSrcInWebWhenCopied()) { VWebUtils::fixImageSrcInHtml(p_baseUrl, html); diff --git a/src/resources/themes/v_moonlight/v_moonlight.palette b/src/resources/themes/v_moonlight/v_moonlight.palette index bf517358..2b23fc15 100644 --- a/src/resources/themes/v_moonlight/v_moonlight.palette +++ b/src/resources/themes/v_moonlight/v_moonlight.palette @@ -7,6 +7,12 @@ mdhl_file=v_moonlight.mdhl css_file=v_moonlight.css codeblock_css_file=v_moonlight_codeblock.css +; This mapping will be used to translate colors when the content of HTML is copied +; without background. You could just specify the foreground colors mapping here. +; It is useful for dark mode theme. '#aabbcc' or 'red' formats are supported. +; col1:col1_new,col2:col2_new +css_color_mapping=#abb2bf:#363636,#282c34:#f5f5f5,#61afef:#0099ff,#98c379:#8e24aa,#2c313a:#e0e0e0,#5c6370:#666666,#373e47:#999999,#6c6c6c:#444444,#c678dd:#0000ee,#e06c75:#880000,#56b6c2:#af00d7,#e6c07b:#008700,#d19a66:#bc6060,#61aeee:#bc6060 + [phony] ; Abstract color attributes. master_fg=@edit_fg diff --git a/src/utils/vwebutils.cpp b/src/utils/vwebutils.cpp index 6e86cfc6..98d14c44 100644 --- a/src/utils/vwebutils.cpp +++ b/src/utils/vwebutils.cpp @@ -4,6 +4,10 @@ #include #include +#include "vpalette.h" + +extern VPalette *g_palette; + VWebUtils::VWebUtils() { } @@ -56,3 +60,67 @@ bool VWebUtils::fixImageSrcInHtml(const QUrl &p_baseUrl, QString &p_html) return changed; } + +bool VWebUtils::removeBackgroundColor(QString &p_html) +{ + QRegExp reg("(<[^>]+\\sstyle=[^>]*(\\s|\"))background(-color)?:[^;]+;([^>]*>)"); + int size = p_html.size(); + p_html.replace(reg, "\\1\\4"); + return p_html.size() != size; +} + +bool VWebUtils::translateColors(QString &p_html) +{ + bool changed = false; + + const QHash &mapping = g_palette->getColorMapping(); + if (mapping.isEmpty()) { + return changed; + } + + QRegExp tagReg("(<[^>]+\\sstyle=[^>]*>)"); + // Won't mixed up with background-color. + QRegExp colorReg("(\\s|\")color:([^;]+);"); + + int pos = 0; + while (pos < p_html.size()) { + int idx = p_html.indexOf(tagReg, pos); + if (idx == -1) { + break; + } + + QString styleStr = tagReg.cap(1); + QString alteredStyleStr = styleStr; + + int posb = 0; + while (posb < alteredStyleStr.size()) { + int idxb = alteredStyleStr.indexOf(colorReg, posb); + if (idxb == -1) { + break; + } + + QString col = colorReg.cap(2).trimmed().toLower(); + auto it = mapping.find(col); + if (it == mapping.end()) { + posb = idxb + colorReg.matchedLength(); + continue; + } + + // Replace the color. + QString newCol = it.value(); + // Add one extra space between color and :. + QString newStr = QString("%1color : %2;").arg(colorReg.cap(1)).arg(newCol); + alteredStyleStr.replace(idxb, colorReg.matchedLength(), newStr); + posb = idxb + newStr.size(); + changed = true; + } + + pos = idx + tagReg.matchedLength(); + if (changed) { + pos = pos + alteredStyleStr.size() - styleStr.size(); + p_html.replace(idx, tagReg.matchedLength(), alteredStyleStr); + } + } + + return changed; +} diff --git a/src/utils/vwebutils.h b/src/utils/vwebutils.h index e0c82330..289e7680 100644 --- a/src/utils/vwebutils.h +++ b/src/utils/vwebutils.h @@ -11,6 +11,12 @@ public: // Fix in @p_html. static bool fixImageSrcInHtml(const QUrl &p_baseUrl, QString &p_html); + // Remove background color style in @p_html. + static bool removeBackgroundColor(QString &p_html); + + // Translate color styles in @p_html using mappings from VPalette. + static bool translateColors(QString &p_html); + private: VWebUtils(); }; diff --git a/src/vpalette.cpp b/src/vpalette.cpp index b8ea0180..45aed935 100644 --- a/src/vpalette.cpp +++ b/src/vpalette.cpp @@ -180,6 +180,19 @@ QMap VPalette::codeBlockCssStylesFromThemes(const QList m_colorMapping; + QString toString() const { - return QString("palette metadata qss=%1 mdhl=%2 css=%3 codeBlockCss=%4") + return QString("palette metadata qss=%1 mdhl=%2 css=%3 codeBlockCss=%4 colorMappingSize=%5") .arg(m_qssFile) .arg(m_mdhlFile) .arg(m_cssFile) - .arg(m_codeBlockCssFile); + .arg(m_codeBlockCssFile) + .arg(m_colorMapping.size()); } }; @@ -39,6 +44,8 @@ public: // Fill "@xxx" in @p_text with corresponding style. void fillStyle(QString &p_text) const; + const QHash &getColorMapping() const; + // Read themes and return the mappings of editor styles. static QMap editorStylesFromThemes(const QList &p_themeFiles); @@ -77,4 +84,9 @@ private: VPaletteMetaData m_data; }; +inline const QHash &VPalette::getColorMapping() const +{ + return m_data.m_colorMapping; +} + #endif // VPALETTE_H diff --git a/src/vwebview.cpp b/src/vwebview.cpp index eeadd98b..f047be56 100644 --- a/src/vwebview.cpp +++ b/src/vwebview.cpp @@ -229,14 +229,6 @@ void VWebView::hideUnusedActions(QMenu *p_menu) } } -static bool removeBackgroundColor(QString &p_html) -{ - QRegExp reg("(<[^>]+\\sstyle=[^>]*(\\s|\"))background(-color)?:[^;]+;([^>]*>)"); - int size = p_html.size(); - p_html.replace(reg, "\\1\\4"); - return p_html.size() != size; -} - bool VWebView::removeStyles(QString &p_html) { bool changed = false; @@ -336,8 +328,14 @@ void VWebView::alterHtmlMimeData(QClipboard *p_clipboard, } // Remove background color. - if (p_removeBackground && removeBackgroundColor(html)) { - altered = true; + if (p_removeBackground) { + if (VWebUtils::removeBackgroundColor(html)) { + altered = true; + } + + if (VWebUtils::translateColors(html)) { + altered = true; + } } // Fix local relative images.