summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Varga <pvarga@inf.u-szeged.hu>2021-11-11 14:24:48 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2021-11-19 09:00:15 +0000
commit5a2db0883cc6acadebf3fa0197c36d81af167492 (patch)
tree0d6823483133c95e7df11f2af7ca4840b7da8662
parent52cf91622a628ababfd39514c0e1b465d1a70b89 (diff)
Add CF_HTML clipboard format handling
Fixes: QTBUG-92539 Change-Id: Iece974e7b045bd793ceb8870f370803bf2524c33 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io> (cherry picked from commit 74021bfcb8f3937e960e76c39d06f5a2a6304673) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/core/CMakeLists.txt5
-rw-r--r--src/core/clipboard_qt.cpp44
-rw-r--r--src/core/clipboard_util_win.cpp140
3 files changed, 189 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 2143b8fad..f287ac3ba 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -256,6 +256,11 @@ foreach(arch ${archs})
renderer/extensions/resource_request_policy_qt.cpp renderer/extensions/resource_request_policy_qt.h
)
+ extend_gn_target(${buildGn} CONDITION WIN32
+ SOURCES
+ clipboard_util_win.cpp
+ )
+
##
# GN PARAMETERS SETUP
##
diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp
index 026653cbb..6549a19da 100644
--- a/src/core/clipboard_qt.cpp
+++ b/src/core/clipboard_qt.cpp
@@ -46,6 +46,7 @@
#include "type_conversion.h"
#include "base/logging.h"
+#include "base/strings/utf_offset_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/custom_data_helper.h"
@@ -107,6 +108,12 @@ Clipboard *Clipboard::Create()
namespace QtWebEngineCore {
+#if defined(Q_OS_WIN)
+extern std::string HtmlToCFHtml(const std::string &html, const std::string &base_url);
+extern void CFHtmlExtractMetadata(const std::string &cf_html, std::string *base_url,
+ size_t *html_start, size_t *fragment_start, size_t *fragment_end);
+#endif // defined(Q_OS_WIN)
+
void ClipboardQt::WritePortableRepresentations(ui::ClipboardBuffer type, const ObjectMap &objects, std::unique_ptr<ui::DataTransferEndpoint> data_src)
{
DCHECK(CalledOnValidThread());
@@ -157,7 +164,17 @@ void ClipboardQt::WriteHTML(const char *markup_data, size_t markup_len, const ch
// Mirrors the behavior in ui/base/clipboard/clipboard_mac.mm in Chromium.
markup_string.prepend(QLatin1String("<meta charset='utf-8'>"));
#endif
+
+#if !defined(Q_OS_WIN)
getUncommittedData()->setHtml(markup_string);
+#else
+ std::string url;
+ if (url_len > 0)
+ url.assign(url_data, url_len);
+
+ std::string cf_html = HtmlToCFHtml(markup_string.toStdString(), url);
+ getUncommittedData()->setHtml(QString::fromStdString(cf_html));
+#endif // !defined(Q_OS_WIN)
}
void ClipboardQt::WriteRTF(const char *rtf_data, size_t data_len)
@@ -269,8 +286,35 @@ void ClipboardQt::ReadHTML(ui::ClipboardBuffer type,
type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
if (!mimeData)
return;
+
+#if !defined(Q_OS_WIN)
*markup = toString16(mimeData->html());
*fragment_end = static_cast<uint32_t>(markup->length());
+#else
+ const std::string cf_html = mimeData->html().toStdString();
+ size_t html_start = std::string::npos;
+ size_t start_index = std::string::npos;
+ size_t end_index = std::string::npos;
+ CFHtmlExtractMetadata(cf_html, src_url, &html_start, &start_index, &end_index);
+
+ // This might happen if the contents of the clipboard changed and CF_HTML is
+ // no longer available.
+ if (start_index == std::string::npos || end_index == std::string::npos
+ || html_start == std::string::npos)
+ return;
+
+ if (start_index < html_start || end_index < start_index)
+ return;
+
+ std::vector<size_t> offsets;
+ offsets.push_back(start_index - html_start);
+ offsets.push_back(end_index - html_start);
+ markup->assign(base::UTF8ToUTF16AndAdjustOffsets(cf_html.data() + html_start, &offsets));
+ // Ensure the Fragment points within the string; see https://crbug.com/607181.
+ size_t end = std::min(offsets[1], markup->length());
+ *fragment_start = base::checked_cast<uint32_t>(std::min(offsets[0], end));
+ *fragment_end = base::checked_cast<uint32_t>(end);
+#endif // !defined(Q_OS_WIN)
}
void ClipboardQt::ReadRTF(ui::ClipboardBuffer type,
diff --git a/src/core/clipboard_util_win.cpp b/src/core/clipboard_util_win.cpp
new file mode 100644
index 000000000..ae615b3b6
--- /dev/null
+++ b/src/core/clipboard_util_win.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.Chromium file.
+
+#include <string>
+
+#include "base/strings/stringprintf.h"
+#include "base/strings/string_util.h"
+
+// These functions are copied from ui/base/clipboard/clipboard_util_win.cc
+
+namespace QtWebEngineCore {
+
+// Helper method for converting from text/html to MS CF_HTML.
+// Documentation for the CF_HTML format is available at
+// http://msdn.microsoft.com/en-us/library/aa767917(VS.85).aspx
+// HtmlToCFHtml is based on similar method in
+// WebCore/platform/win/ClipboardUtilitiesWin.cpp.
+std::string HtmlToCFHtml(const std::string &html, const std::string &base_url)
+{
+ if (html.empty())
+ return std::string();
+
+#define MAX_DIGITS 10
+#define MAKE_NUMBER_FORMAT_1(digits) MAKE_NUMBER_FORMAT_2(digits)
+#define MAKE_NUMBER_FORMAT_2(digits) "%0" #digits "u"
+#define NUMBER_FORMAT MAKE_NUMBER_FORMAT_1(MAX_DIGITS)
+
+ static const char *header = "Version:0.9\r\n"
+ "StartHTML:" NUMBER_FORMAT "\r\n"
+ "EndHTML:" NUMBER_FORMAT "\r\n"
+ "StartFragment:" NUMBER_FORMAT "\r\n"
+ "EndFragment:" NUMBER_FORMAT "\r\n";
+ static const char *source_url_prefix = "SourceURL:";
+
+ static const char *start_markup = "<html>\r\n<body>\r\n<!--StartFragment-->";
+ static const char *end_markup = "<!--EndFragment-->\r\n</body>\r\n</html>";
+
+ // Calculate offsets
+ size_t start_html_offset = strlen(header) - strlen(NUMBER_FORMAT) * 4 + MAX_DIGITS * 4;
+ if (!base_url.empty()) {
+ start_html_offset += strlen(source_url_prefix) + base_url.length() + 2; // Add 2 for \r\n.
+ }
+ size_t start_fragment_offset = start_html_offset + strlen(start_markup);
+ size_t end_fragment_offset = start_fragment_offset + html.length();
+ size_t end_html_offset = end_fragment_offset + strlen(end_markup);
+
+ std::string result = base::StringPrintf(header, start_html_offset, end_html_offset,
+ start_fragment_offset, end_fragment_offset);
+ if (!base_url.empty()) {
+ result += source_url_prefix;
+ result += base_url;
+ result += "\r\n";
+ }
+ result += start_markup;
+ result += html;
+ result += end_markup;
+
+#undef MAX_DIGITS
+#undef MAKE_NUMBER_FORMAT_1
+#undef MAKE_NUMBER_FORMAT_2
+#undef NUMBER_FORMAT
+
+ return result;
+}
+
+void CFHtmlExtractMetadata(const std::string &cf_html, std::string *base_url, size_t *html_start,
+ size_t *fragment_start, size_t *fragment_end)
+{
+ // Obtain base_url if present.
+ if (base_url) {
+ static constexpr char kSrcUrlStr[] = "SourceURL:";
+ size_t line_start = cf_html.find(kSrcUrlStr);
+ if (line_start != std::string::npos) {
+ size_t src_end = cf_html.find("\n", line_start);
+ size_t src_start = line_start + strlen(kSrcUrlStr);
+ if (src_end != std::string::npos && src_start != std::string::npos) {
+ *base_url = cf_html.substr(src_start, src_end - src_start);
+ base::TrimWhitespaceASCII(*base_url, base::TRIM_ALL, base_url);
+ }
+ }
+ }
+
+ // Find the markup between "<!--StartFragment-->" and "<!--EndFragment-->".
+ // If the comments cannot be found, like copying from OpenOffice Writer,
+ // we simply fall back to using StartFragment/EndFragment bytecount values
+ // to determine the fragment indexes.
+ std::string cf_html_lower = base::ToLowerASCII(cf_html);
+ size_t markup_start = cf_html_lower.find("<html", 0);
+ if (html_start) {
+ *html_start = markup_start;
+ }
+ size_t tag_start = cf_html.find("<!--StartFragment", markup_start);
+ if (tag_start == std::string::npos) {
+ static constexpr char kStartFragmentStr[] = "StartFragment:";
+ size_t start_fragment_start = cf_html.find(kStartFragmentStr);
+ if (start_fragment_start != std::string::npos) {
+ *fragment_start = static_cast<size_t>(
+ atoi(cf_html.c_str() + start_fragment_start + strlen(kStartFragmentStr)));
+ }
+
+ static constexpr char kEndFragmentStr[] = "EndFragment:";
+ size_t end_fragment_start = cf_html.find(kEndFragmentStr);
+ if (end_fragment_start != std::string::npos) {
+ *fragment_end = static_cast<size_t>(
+ atoi(cf_html.c_str() + end_fragment_start + strlen(kEndFragmentStr)));
+ }
+ } else {
+ *fragment_start = cf_html.find('>', tag_start) + 1;
+ size_t tag_end = cf_html.rfind("<!--EndFragment", std::string::npos);
+ *fragment_end = cf_html.rfind('<', tag_end);
+ }
+}
+
+} // namespace QtWebEngineCore