diff options
Diffstat (limited to 'src/core/clipboard_qt.cpp')
-rw-r--r-- | src/core/clipboard_qt.cpp | 251 |
1 files changed, 121 insertions, 130 deletions
diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp index 6549a19da..3f49c6e3c 100644 --- a/src/core/clipboard_qt.cpp +++ b/src/core/clipboard_qt.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtWebEngine module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only // Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be @@ -48,17 +12,24 @@ #include "base/logging.h" #include "base/strings/utf_offset_string_conversions.h" #include "base/strings/utf_string_conversions.h" +#include "base/types/variant_util.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/base/clipboard/custom_data_helper.h" #include "ui/base/clipboard/clipboard.h" +#include "ui/base/clipboard/clipboard_monitor.h" #include "ui/base/clipboard/clipboard_constants.h" #include "ui/base/clipboard/clipboard_format_type.h" +#include "ui/base/data_transfer_policy/data_transfer_endpoint.h" #include "ui/base/ui_base_features.h" +#include <QBuffer> #include <QGuiApplication> #include <QImage> +#include <QImageWriter> #include <QMimeData> +#include <memory> + namespace QtWebEngineCore { static void registerMetaTypes() @@ -77,7 +48,13 @@ ClipboardChangeObserver::ClipboardChangeObserver() void ClipboardChangeObserver::trackChange(QClipboard::Mode mode) { - ++sequenceNumber[mode]; + if (mode == QClipboard::Clipboard) + m_primarySequenceNumber = ui::ClipboardSequenceNumberToken(); + else if (mode == QClipboard::Selection) + m_selectionSequenceNumber = ui::ClipboardSequenceNumberToken(); + else + return; + ui::ClipboardMonitor::GetInstance()->NotifyClipboardDataChanged(); } } // namespace QtWebEngineCore @@ -86,12 +63,12 @@ using namespace QtWebEngineCore; namespace { -QScopedPointer<QMimeData> uncommittedData; +std::unique_ptr<QMimeData> uncommittedData; QMimeData *getUncommittedData() { if (!uncommittedData) uncommittedData.reset(new QMimeData); - return uncommittedData.data(); + return uncommittedData.get(); } } // namespace @@ -114,50 +91,46 @@ extern void CFHtmlExtractMetadata(const std::string &cf_html, std::string *base_ 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) +void ClipboardQt::WritePortableAndPlatformRepresentations(ui::ClipboardBuffer type, + const ObjectMap &objects, + std::vector<ui::Clipboard::PlatformRepresentation> platform_representations, + std::unique_ptr<ui::DataTransferEndpoint> data_src) { DCHECK(CalledOnValidThread()); DCHECK(IsSupportedClipboardBuffer(type)); + if (!platform_representations.empty()) + DispatchPlatformRepresentations(std::move(platform_representations)); for (const auto &object : objects) - DispatchPortableRepresentation(object.first, object.second); + DispatchPortableRepresentation(object.second); // Commit the accumulated data. if (uncommittedData) - QGuiApplication::clipboard()->setMimeData(uncommittedData.take(), + QGuiApplication::clipboard()->setMimeData(uncommittedData.release(), type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection); if (type == ui::ClipboardBuffer::kCopyPaste && IsSupportedClipboardBuffer(ui::ClipboardBuffer::kSelection)) { - ObjectMap::const_iterator text_iter = objects.find(PortableFormat::kText); + auto text_iter = objects.find(base::VariantIndexOfType<Data, TextData>()); if (text_iter != objects.end()) { // Copy text and SourceTag to the selection clipboard. - WritePortableRepresentations(ui::ClipboardBuffer::kSelection, - ObjectMap(text_iter, text_iter + 1), - nullptr); + WritePortableAndPlatformRepresentations(ui::ClipboardBuffer::kSelection, + ObjectMap(text_iter, ++text_iter), + {}, + nullptr); } } m_dataSrc[type] = std::move(data_src); } -void ClipboardQt::WritePlatformRepresentations(ui::ClipboardBuffer buffer, - std::vector<ui::Clipboard::PlatformRepresentation> platform_representations, - std::unique_ptr<ui::DataTransferEndpoint> data_src) +void ClipboardQt::WriteText(base::StringPiece text) { - DCHECK(CalledOnValidThread()); - DCHECK(IsSupportedClipboardBuffer(buffer)); - DispatchPlatformRepresentations(std::move(platform_representations)); - m_dataSrc[buffer] = std::move(data_src); + getUncommittedData()->setText(toQString(text)); } -void ClipboardQt::WriteText(const char *text_data, size_t text_len) +void ClipboardQt::WriteHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url) { - getUncommittedData()->setText(QString::fromUtf8(text_data, text_len)); -} - -void ClipboardQt::WriteHTML(const char *markup_data, size_t markup_len, const char *url_data, size_t url_len) -{ - QString markup_string = QString::fromUtf8(markup_data, markup_len); + QString markup_string = toQString(markup); #if defined (Q_OS_MACOS) // We need to prepend the charset on macOS to prevent garbled Unicode characters // when pasting to certain applications (e.g. Notes, TextEdit) @@ -168,18 +141,27 @@ void ClipboardQt::WriteHTML(const char *markup_data, size_t markup_len, const ch #if !defined(Q_OS_WIN) getUncommittedData()->setHtml(markup_string); #else - std::string url; - if (url_len > 0) - url.assign(url_data, url_len); + QString url; + if (source_url) + url = toQString(*source_url); + + std::string cf_html = HtmlToCFHtml(markup_string.toStdString(), url.toStdString()); + size_t html_start = std::string::npos; + size_t fragment_start = std::string::npos; + size_t fragment_end = std::string::npos; + CFHtmlExtractMetadata(cf_html, nullptr, &html_start, &fragment_start, &fragment_end); + + DCHECK(fragment_start != std::string::npos && fragment_end != std::string::npos + && html_start != std::string::npos); + DCHECK(fragment_start >= html_start && fragment_end >= fragment_start); - std::string cf_html = HtmlToCFHtml(markup_string.toStdString(), url); - getUncommittedData()->setHtml(QString::fromStdString(cf_html)); + getUncommittedData()->setHtml(QString::fromStdString(cf_html.substr(html_start))); #endif // !defined(Q_OS_WIN) } -void ClipboardQt::WriteRTF(const char *rtf_data, size_t data_len) +void ClipboardQt::WriteRTF(base::StringPiece rtf) { - getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeRTF), QByteArray(rtf_data, data_len)); + getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeRTF), toQByteArray(rtf)); } void ClipboardQt::WriteWebSmartPaste() @@ -192,12 +174,12 @@ void ClipboardQt::WriteBitmap(const SkBitmap &bitmap) getUncommittedData()->setImageData(toQImage(bitmap).copy()); } -void ClipboardQt::WriteBookmark(const char *title_data, size_t title_len, const char *url_data, size_t url_len) +void ClipboardQt::WriteBookmark(base::StringPiece title_in, base::StringPiece url_in) { // FIXME: Untested, seems to be used only for drag-n-drop. // Write as a mozilla url (UTF16: URL, newline, title). - QString url = QString::fromUtf8(url_data, url_len); - QString title = QString::fromUtf8(title_data, title_len); + QString url = toQString(url_in); + QString title = toQString(title_in); QByteArray data; data.append(reinterpret_cast<const char *>(url.utf16()), url.size() * 2); @@ -206,9 +188,9 @@ void ClipboardQt::WriteBookmark(const char *title_data, size_t title_len, const getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeMozillaURL), data); } -void ClipboardQt::WriteData(const ui::ClipboardFormatType &format, const char *data_data, size_t data_len) +void ClipboardQt::WriteData(const ui::ClipboardFormatType &format, base::span<const uint8_t> data) { - getUncommittedData()->setData(QString::fromStdString(format.GetName()), QByteArray(data_data, data_len)); + getUncommittedData()->setData(QString::fromStdString(format.GetName()), QByteArray((const char *)data.data(), data.size())); } bool ClipboardQt::IsFormatAvailable(const ui::ClipboardFormatType &format, @@ -217,7 +199,12 @@ bool ClipboardQt::IsFormatAvailable(const ui::ClipboardFormatType &format, { const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection); - return mimeData && mimeData->hasFormat(QString::fromStdString(format.GetName())); + + if (!mimeData) + return false; + if (format == ui::ClipboardFormatType::PngType()) + return mimeData->hasImage(); + return mimeData->hasFormat(QString::fromStdString(format.GetName())); } void ClipboardQt::Clear(ui::ClipboardBuffer type) @@ -229,7 +216,7 @@ void ClipboardQt::Clear(ui::ClipboardBuffer type) void ClipboardQt::ReadAvailableTypes(ui::ClipboardBuffer type, const ui::DataTransferEndpoint *data_dst, - std::vector<base::string16> *types) const + std::vector<std::u16string> *types) const { if (!types) { NOTREACHED(); @@ -241,19 +228,19 @@ void ClipboardQt::ReadAvailableTypes(ui::ClipboardBuffer type, type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection); if (!mimeData) return; - if (mimeData->hasImage() && !mimeData->formats().contains(QStringLiteral("image/png"))) - types->push_back(toString16(QStringLiteral("image/png"))); - const QStringList formats = mimeData->formats(); - for (const QString &mimeType : formats) - types->push_back(toString16(mimeType)); - const QByteArray customData = mimeData->data(QString::fromLatin1(ui::kMimeTypeWebCustomData)); - ui::ReadCustomDataTypes(customData.constData(), customData.size(), types); + for (const auto& mime_type : GetStandardFormats(type, data_dst)) + types->push_back(mime_type); + + if (mimeData->hasFormat(QString::fromLatin1(ui::kMimeTypeWebCustomData))) { + const QByteArray customData = mimeData->data(QString::fromLatin1(ui::kMimeTypeWebCustomData)); + ui::ReadCustomDataTypes(customData.constData(), customData.size(), types); + } } void ClipboardQt::ReadText(ui::ClipboardBuffer type, const ui::DataTransferEndpoint *data_dst, - base::string16 *result) const + std::u16string *result) const { const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection); @@ -273,7 +260,7 @@ void ClipboardQt::ReadAsciiText(ui::ClipboardBuffer type, void ClipboardQt::ReadHTML(ui::ClipboardBuffer type, const ui::DataTransferEndpoint *data_dst, - base::string16 *markup, std::string *src_url, + std::u16string *markup, std::string *src_url, uint32_t *fragment_start, uint32_t *fragment_end) const { markup->clear(); @@ -329,37 +316,26 @@ void ClipboardQt::ReadRTF(ui::ClipboardBuffer type, *result = std::string(byteArray.constData(), byteArray.length()); } -void ClipboardQt::ReadImage(ui::ClipboardBuffer type, - const ui::DataTransferEndpoint *data_dst, - ReadImageCallback callback) const +void ClipboardQt::ReadPng(ui::ClipboardBuffer type, const ui::DataTransferEndpoint *, ui::Clipboard::ReadPngCallback callback) const { const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection); if (!mimeData) - return std::move(callback).Run(SkBitmap()); + return std::move(callback).Run({}); QImage image = qvariant_cast<QImage>(mimeData->imageData()); - image = image.convertToFormat(QImage::Format_ARGB32); - SkBitmap bitmap; - - bitmap.allocN32Pixels(image.width(), image.height(), true); - const size_t bytesPerRowDst = bitmap.rowBytes(); - const size_t bytesPerLineSrc = static_cast<size_t>(image.bytesPerLine()); - const size_t dataBytes = std::min(bytesPerRowDst, bytesPerLineSrc); - uchar *dst = static_cast<uchar *>(bitmap.getPixels()); - const uchar *src = image.constBits(); - for (int y = 0; y < image.height(); ++y) { - memcpy(dst, src, dataBytes); - dst += bytesPerRowDst; - src += bytesPerLineSrc; - } - - return std::move(callback).Run(bitmap); + QBuffer buffer; + QImageWriter writer(&buffer, "png"); + writer.write(image); + std::vector<uint8_t> pngData; + pngData.resize(buffer.size()); + memcpy(pngData.data(), buffer.data().data(), buffer.size()); + return std::move(callback).Run(std::move(pngData)); } -void ClipboardQt::ReadCustomData(ui::ClipboardBuffer clipboard_type, const base::string16 &type, +void ClipboardQt::ReadCustomData(ui::ClipboardBuffer clipboard_type, const std::u16string &type, const ui::DataTransferEndpoint *data_dst, - base::string16 *result) const + std::u16string *result) const { const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( clipboard_type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection); @@ -369,14 +345,14 @@ void ClipboardQt::ReadCustomData(ui::ClipboardBuffer clipboard_type, const base: ui::ReadCustomDataForType(customData.constData(), customData.size(), type, result); } -void ClipboardQt::ReadBookmark(const ui::DataTransferEndpoint *data_dst, base::string16 *title, std::string *url) const +void ClipboardQt::ReadBookmark(const ui::DataTransferEndpoint *data_dst, std::u16string *title, std::string *url) const { NOTIMPLEMENTED(); } void ClipboardQt::ReadSvg(ui::ClipboardBuffer clipboard_type, const ui::DataTransferEndpoint *, - base::string16 *result) const + std::u16string *result) const { const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( clipboard_type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection); @@ -387,10 +363,10 @@ void ClipboardQt::ReadSvg(ui::ClipboardBuffer clipboard_type, *result = toString16(QString::fromUtf8(svgData)); } -void ClipboardQt::WriteSvg(const char *svg_data, size_t data_len) +void ClipboardQt::WriteSvg(base::StringPiece markup) { getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeSvg), - QByteArray(svg_data, data_len)); + toQByteArray(markup)); } void ClipboardQt::ReadData(const ui::ClipboardFormatType &format, @@ -404,10 +380,11 @@ void ClipboardQt::ReadData(const ui::ClipboardFormatType &format, *result = std::string(byteArray.constData(), byteArray.length()); } -uint64_t ClipboardQt::GetSequenceNumber(ui::ClipboardBuffer type) const +const ui::ClipboardSequenceNumberToken &ClipboardQt::GetSequenceNumber(ui::ClipboardBuffer type) const { - return clipboardChangeObserver()->getSequenceNumber(type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard - : QClipboard::Selection); + return type == ui::ClipboardBuffer::kCopyPaste + ? clipboardChangeObserver()->getPrimarySequenceNumber() + : clipboardChangeObserver()->getSelectionSequenceNumber(); } const ui::DataTransferEndpoint *ClipboardQt::GetSource(ui::ClipboardBuffer buffer) const @@ -443,6 +420,11 @@ void ClipboardQt::WriteFilenames(std::vector<ui::FileInfo> filenames) getUncommittedData()->setUrls(urls); } +void ClipboardQt::WriteUnsanitizedHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url) +{ + WriteHTML(std::move(markup), std::move(source_url)); +} + #if defined(USE_OZONE) bool ClipboardQt::IsSelectionBufferAvailable() const { @@ -450,25 +432,34 @@ bool ClipboardQt::IsSelectionBufferAvailable() const } #endif -std::vector<base::string16> ClipboardQt::ReadAvailablePlatformSpecificFormatNames(ui::ClipboardBuffer buffer, const ui::DataTransferEndpoint *data_dst) const -{ - // based on ClipboardX11 - std::vector<base::string16> types; - if (IsFormatAvailable(ui::ClipboardFormatType::GetPlainTextType(), buffer, data_dst)) - types.push_back(base::UTF8ToUTF16(ui::ClipboardFormatType::GetPlainTextType().GetName())); - if (IsFormatAvailable(ui::ClipboardFormatType::GetHtmlType(), buffer, data_dst)) - types.push_back(base::UTF8ToUTF16(ui::ClipboardFormatType::GetHtmlType().GetName())); - if (IsFormatAvailable(ui::ClipboardFormatType::GetRtfType(), buffer, data_dst)) - types.push_back(base::UTF8ToUTF16(ui::ClipboardFormatType::GetRtfType().GetName())); - if (IsFormatAvailable(ui::ClipboardFormatType::GetBitmapType(), buffer, data_dst)) - types.push_back(base::UTF8ToUTF16(ui::kMimeTypePNG)); - if (IsFormatAvailable(ui::ClipboardFormatType::GetSvgType(), buffer, data_dst)) - types.push_back(base::UTF8ToUTF16(ui::kMimeTypeSvg)); +// This is the same as ReadAvailableTypes minus dealing with custom-data +std::vector<std::u16string> ClipboardQt::GetStandardFormats(ui::ClipboardBuffer buffer, const ui::DataTransferEndpoint *data_dst) const +{ + Q_UNUSED(data_dst); const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData( buffer == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection); - if (base::FeatureList::IsEnabled(features::kClipboardFilenames) && mimeData->hasUrls()) + if (!mimeData) + return {}; + + std::vector<std::u16string> types; + if (mimeData->hasImage()) + types.push_back(base::UTF8ToUTF16(ui::kMimeTypePNG)); + if (mimeData->hasHtml()) + types.push_back(base::UTF8ToUTF16(ui::kMimeTypeHTML)); + if (mimeData->hasText()) + types.push_back(base::UTF8ToUTF16(ui::kMimeTypeText)); + if (mimeData->hasUrls()) types.push_back(base::UTF8ToUTF16(ui::kMimeTypeURIList)); - // ### Should we add non-standard mime-types? + const QStringList formats = mimeData->formats(); + for (const QString &mimeType : formats) { + auto mime_type = mimeType.toStdString(); + // Only add white-listed formats here + if (mime_type == ui::ClipboardFormatType::SvgType().GetName() || + mime_type == ui::ClipboardFormatType::RtfType().GetName()) { + types.push_back(base::UTF8ToUTF16(mime_type)); + continue; + } + } return types; } |