Commit a29e33af authored by Koji Ishii's avatar Koji Ishii Committed by Commit Bot

Paste non-file-based images in clipboard as img tag

This patch converts a non-file-based image in clipboard to
an <img> tag with data URL when pasting to an editing host.

The generated markup matches |URLToImageMarkup| and the one
Firefox generates for the same case.

In addition to the unittests, manually tested by taking
screenshots to clipboard by pressing Alt+PrtScrn key on
Windows and confirmed:
* Pastable to `contenteditable`.
* Pastable to `-webkit-user-modify: read-write`.
* Not pastable to `<input>`, `<textarea>`, nor to
  `-webkit-user-modify: read-write-plaintext-only`.

Bug: 1008927
Change-Id: I19c17591567ad150575ed15af7743e819eaeb67e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2086463
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
Reviewed-by: default avatarYoshifumi Inoue <yosin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#750463}
parent 3c846ec9
...@@ -31,10 +31,13 @@ ...@@ -31,10 +31,13 @@
#include "third_party/blink/renderer/core/clipboard/clipboard_utilities.h" #include "third_party/blink/renderer/core/clipboard/clipboard_utilities.h"
#include "net/base/escape.h" #include "net/base/escape.h"
#include "third_party/blink/renderer/platform/image-encoders/image_encoder.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/text/base64.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h" #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h" #include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/skia/include/encode/SkPngEncoder.h"
namespace blink { namespace blink {
...@@ -90,4 +93,28 @@ String URLToImageMarkup(const KURL& url, const String& title) { ...@@ -90,4 +93,28 @@ String URLToImageMarkup(const KURL& url, const String& title) {
return builder.ToString(); return builder.ToString();
} }
String BitmapToImageMarkup(const SkBitmap& bitmap) {
if (bitmap.isNull())
return String();
// Encode bitmap to Vector<uint8_t> on the main thread.
SkPixmap pixmap;
bitmap.peekPixels(&pixmap);
// Set encoding options to favor speed over size.
SkPngEncoder::Options options;
options.fZLibLevel = 1;
options.fFilterFlags = SkPngEncoder::FilterFlag::kNone;
Vector<uint8_t> png_data;
if (!ImageEncoder::Encode(&png_data, pixmap, options))
return String();
StringBuilder markup;
markup.Append("<img src=\"data:image/png;base64,");
markup.Append(Base64Encode(png_data));
markup.Append("\" alt=\"\"/>");
return markup.ToString();
}
} // namespace blink } // namespace blink
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/forward.h" #include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace blink { namespace blink {
...@@ -44,6 +45,7 @@ CORE_EXPORT void ReplaceNewlinesWithWindowsStyleNewlines(String&); ...@@ -44,6 +45,7 @@ CORE_EXPORT void ReplaceNewlinesWithWindowsStyleNewlines(String&);
CORE_EXPORT void ReplaceNBSPWithSpace(String&); CORE_EXPORT void ReplaceNBSPWithSpace(String&);
CORE_EXPORT String ConvertURIListToURL(const String& uri_list); CORE_EXPORT String ConvertURIListToURL(const String& uri_list);
CORE_EXPORT String URLToImageMarkup(const KURL&, const String& title); CORE_EXPORT String URLToImageMarkup(const KURL&, const String& title);
CORE_EXPORT String BitmapToImageMarkup(const SkBitmap& bitmap);
} // namespace blink } // namespace blink
......
...@@ -43,4 +43,17 @@ TEST(ClipboardUtilitiesTest, URLToImageMarkupEmbeddedNull) { ...@@ -43,4 +43,17 @@ TEST(ClipboardUtilitiesTest, URLToImageMarkupEmbeddedNull) {
String(kTitleWithNull, sizeof(kTitleWithNull) - 1))); String(kTitleWithNull, sizeof(kTitleWithNull) - 1)));
} }
TEST(ClipboardUtilitiesTest, BitmapToImageMarkupEmpty) {
SkBitmap bitmap;
EXPECT_TRUE(BitmapToImageMarkup(bitmap).IsNull());
}
TEST(ClipboardUtilitiesTest, BitmapToImageMarkup) {
SkBitmap bitmap;
bitmap.allocPixels(SkImageInfo::MakeN32Premul(10, 5));
EXPECT_EQ(
R"HTML(<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAFCAYAAAB8ZH1oAAAADElEQVQYGWNgGEYAAADNAAGVVebMAAAAAElFTkSuQmCC" alt=""/>)HTML",
BitmapToImageMarkup(bitmap));
}
} // namespace blink } // namespace blink
...@@ -152,6 +152,12 @@ SkBitmap SystemClipboard::ReadImage(mojom::ClipboardBuffer buffer) { ...@@ -152,6 +152,12 @@ SkBitmap SystemClipboard::ReadImage(mojom::ClipboardBuffer buffer) {
return image; return image;
} }
String SystemClipboard::ReadImageAsImageMarkup(
mojom::blink::ClipboardBuffer buffer) {
SkBitmap bitmap = ReadImage(buffer);
return BitmapToImageMarkup(bitmap);
}
void SystemClipboard::WriteImageWithTag(Image* image, void SystemClipboard::WriteImageWithTag(Image* image,
const KURL& url, const KURL& url,
const String& title) { const String& title) {
......
...@@ -58,6 +58,7 @@ class CORE_EXPORT SystemClipboard final ...@@ -58,6 +58,7 @@ class CORE_EXPORT SystemClipboard final
String ReadRTF(); String ReadRTF();
SkBitmap ReadImage(mojom::ClipboardBuffer); SkBitmap ReadImage(mojom::ClipboardBuffer);
String ReadImageAsImageMarkup(mojom::blink::ClipboardBuffer);
// Write the image and its associated tag (bookmark/HTML types). // Write the image and its associated tag (bookmark/HTML types).
void WriteImageWithTag(Image*, const KURL&, const String& title); void WriteImageWithTag(Image*, const KURL&, const String& title);
......
...@@ -373,6 +373,15 @@ ClipboardCommands::GetFragmentFromClipboard(LocalFrame& frame) { ...@@ -373,6 +373,15 @@ ClipboardCommands::GetFragmentFromClipboard(LocalFrame& frame) {
if (fragment) if (fragment)
return std::make_pair(fragment, false); return std::make_pair(fragment, false);
if (const String markup = frame.GetSystemClipboard()->ReadImageAsImageMarkup(
mojom::blink::ClipboardBuffer::kStandard)) {
fragment = CreateFragmentFromMarkup(*frame.GetDocument(), markup,
/* base_url */ "",
kDisallowScriptingAndPluginContent);
DCHECK(fragment);
return std::make_pair(fragment, false);
}
const String text = frame.GetSystemClipboard()->ReadPlainText(); const String text = frame.GetSystemClipboard()->ReadPlainText();
if (text.IsEmpty()) if (text.IsEmpty())
return std::make_pair(fragment, false); return std::make_pair(fragment, false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment