Enable pasting HTML content from the Android clipboard

BUG=316717

Review URL: https://codereview.chromium.org/59023007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238530 0039d316-1c4b-4281-b951-d872f2087c98
parent a188c82e
......@@ -41,6 +41,13 @@ public class ApiCompatibilityUtils {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
}
/**
* @return True if the running version of the Android supports HTML clipboard.
*/
public static boolean isHTMLClipboardSupported() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN;
}
/**
* @see android.view.View#setLayoutDirection(int)
*/
......
......@@ -4,6 +4,7 @@
package org.chromium.ui.base;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
......@@ -76,6 +77,23 @@ public class Clipboard {
return null;
}
/**
* Gets the HTML text of top item on the primary clip on the Android clipboard.
*
* @return a Java string with the html text if any, or null if there is no html
* text or no entries on the primary clip.
*/
@CalledByNative
private String getHTMLText() {
if (isHTMLClipboardSupported()) {
final ClipData clip = mClipboardManager.getPrimaryClip();
if (clip != null && clip.getItemCount() > 0) {
return clip.getItemAt(0).getHtmlText();
}
}
return null;
}
/**
* Emulates the behavior of the now-deprecated
* {@link android.text.ClipboardManager#setText(CharSequence)}, setting the
......@@ -100,29 +118,14 @@ public class Clipboard {
*/
@CalledByNative
private void setHTMLText(final String html, final String text) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
if (isHTMLClipboardSupported()) {
mClipboardManager.setPrimaryClip(
ClipData.newHtmlText(null, text, html));
}
}
/**
* Approximates the behavior of the now-deprecated
* {@link android.text.ClipboardManager#hasText()}, returning true if and
* only if the clipboard has a primary clip and that clip contains a plain
* non-empty text entry (without attempting coercion - URLs and intents
* will cause this method to return false).
*
* @return as described above
*/
@SuppressWarnings("javadoc")
@CalledByNative
private boolean hasPlainText() {
final ClipData clip = mClipboardManager.getPrimaryClip();
if (clip != null && clip.getItemCount() > 0) {
final CharSequence text = clip.getItemAt(0).getText();
return !TextUtils.isEmpty(text);
}
return false;
private static boolean isHTMLClipboardSupported() {
return ApiCompatibilityUtils.isHTMLClipboardSupported();
}
}
......@@ -129,39 +129,50 @@ void ClipboardMap::Clear() {
// If the internal map contains a plain-text entry and it does not match that
// in the Android clipboard, clear the map and insert the Android text into it.
// If there is an HTML entry in the Android clipboard it gets inserted in the
// map.
void ClipboardMap::SyncWithAndroidClipboard() {
lock_.AssertAcquired();
JNIEnv* env = AttachCurrentThread();
// Update the plain text clipboard entry
std::map<std::string, std::string>::const_iterator it =
map_.find(kPlainTextFormat);
if (!Java_Clipboard_hasPlainText(env, clipboard_manager_.obj())) {
if (it != map_.end())
ScopedJavaLocalRef<jstring> java_string_text =
Java_Clipboard_getCoercedText(env, clipboard_manager_.obj());
if (java_string_text.obj()) {
std::string android_string = ConvertJavaStringToUTF8(java_string_text);
if (!android_string.empty() &&
(it == map_.end() || it->second != android_string)) {
// There is a different string in the Android clipboard than we have.
// Clear the map on our side.
map_.clear();
map_[kPlainTextFormat] = android_string;
}
} else {
if (it != map_.end()) {
// We have plain text on this side, but Android doesn't. Nuke ours.
map_.clear();
return;
}
}
ScopedJavaLocalRef<jstring> java_string =
Java_Clipboard_getCoercedText(env, clipboard_manager_.obj());
if (!java_string.obj()) {
// Tolerate a null value from the Java side, even though that should not
// happen since hasPlainText has already returned true.
// Should only happen if someone is using the clipboard on multiple
// threads and clears it out after hasPlainText but before we get here...
if (it != map_.end())
// We have plain text on this side, but Android doesn't. Nuke ours.
map_.clear();
if (!Java_Clipboard_isHTMLClipboardSupported(env)) {
return;
}
// If Android text differs from ours (or we have none), then copy Android's.
std::string android_string = ConvertJavaStringToUTF8(java_string);
if (it == map_.end() || it->second != android_string) {
map_.clear();
map_[kPlainTextFormat] = android_string;
// Update the html clipboard entry
ScopedJavaLocalRef<jstring> java_string_html =
Java_Clipboard_getHTMLText(env, clipboard_manager_.obj());
if (java_string_html.obj()) {
std::string android_string = ConvertJavaStringToUTF8(java_string_html);
if (!android_string.empty()) {
map_[kHTMLFormat] = android_string;
return;
}
}
it = map_.find(kHTMLFormat);
if (it != map_.end()) {
map_.erase(kHTMLFormat);
}
}
......
......@@ -89,11 +89,13 @@ TEST_F(ClipboardTest, TextTest) {
TEST_F(ClipboardTest, HTMLTest) {
string16 markup(ASCIIToUTF16("<string>Hi!</string>")), markup_result;
string16 plain(ASCIIToUTF16("Hi!")), plain_result;
std::string url("http://www.example.com/"), url_result;
{
ScopedClipboardWriter clipboard_writer(&clipboard(),
CLIPBOARD_TYPE_COPY_PASTE);
clipboard_writer.WriteText(plain);
clipboard_writer.WriteHTML(markup, url);
}
......@@ -175,10 +177,12 @@ TEST_F(ClipboardTest, TrickyHTMLTest) {
string16 markup(ASCIIToUTF16("<em>Bye!<!--EndFragment --></em>")),
markup_result;
std::string url, url_result;
string16 plain(ASCIIToUTF16("Bye!")), plain_result;
{
ScopedClipboardWriter clipboard_writer(&clipboard(),
CLIPBOARD_TYPE_COPY_PASTE);
clipboard_writer.WriteText(plain);
clipboard_writer.WriteHTML(markup, url);
}
......
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