ClipboardChromium.cpp [plain text]
#include "config.h"
#include "ClipboardChromium.h"
#include "CachedImage.h"
#include "ChromiumBridge.h"
#include "ChromiumDataObject.h"
#include "ClipboardUtilitiesChromium.h"
#include "Document.h"
#include "Element.h"
#include "FileList.h"
#include "Frame.h"
#include "HTMLNames.h"
#include "Image.h"
#include "MIMETypeRegistry.h"
#include "NamedNodeMap.h"
#include "Pasteboard.h"
#include "PlatformString.h"
#include "Range.h"
#include "RenderImage.h"
#include "StringBuilder.h"
#include "markup.h"
namespace WebCore {
using namespace HTMLNames;
enum ClipboardDataType {
ClipboardDataTypeNone,
ClipboardDataTypeURL,
ClipboardDataTypeURIList,
ClipboardDataTypeDownloadURL,
ClipboardDataTypePlainText,
ClipboardDataTypeHTML,
ClipboardDataTypeOther,
};
static char const* const textMIMETypeLineSeparator = "\r\n";
static ClipboardDataType clipboardTypeFromMIMEType(const String& type)
{
String cleanType = type.stripWhiteSpace().lower();
if (cleanType.isEmpty())
return ClipboardDataTypeNone;
if (cleanType == "text" || cleanType == "text/plain" || cleanType.startsWith("text/plain;"))
return ClipboardDataTypePlainText;
if (cleanType == "url")
return ClipboardDataTypeURL;
if (cleanType == "text/uri-list")
return ClipboardDataTypeURIList;
if (cleanType == "downloadurl")
return ClipboardDataTypeDownloadURL;
if (cleanType == "text/html")
return ClipboardDataTypeHTML;
return ClipboardDataTypeOther;
}
ClipboardChromium::ClipboardChromium(bool isForDragging,
PassRefPtr<ChromiumDataObject> dataObject,
ClipboardAccessPolicy policy)
: Clipboard(policy, isForDragging)
, m_dataObject(dataObject)
{
}
PassRefPtr<ClipboardChromium> ClipboardChromium::create(bool isForDragging,
PassRefPtr<ChromiumDataObject> dataObject, ClipboardAccessPolicy policy)
{
return adoptRef(new ClipboardChromium(isForDragging, dataObject, policy));
}
void ClipboardChromium::clearData(const String& type)
{
if (policy() != ClipboardWritable || !m_dataObject)
return;
ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
switch (dataType) {
case ClipboardDataTypeNone:
m_dataObject->clearAllExceptFiles();
return;
case ClipboardDataTypeURL:
case ClipboardDataTypeURIList:
m_dataObject->clearURL();
return;
case ClipboardDataTypeDownloadURL:
m_dataObject->downloadMetadata = "";
return;
case ClipboardDataTypePlainText:
m_dataObject->plainText = "";
return;
case ClipboardDataTypeHTML:
m_dataObject->textHtml = "";
m_dataObject->htmlBaseUrl = KURL();
return;
case ClipboardDataTypeOther:
return;
}
ASSERT_NOT_REACHED();
}
void ClipboardChromium::clearAllData()
{
if (policy() != ClipboardWritable)
return;
m_dataObject->clear();
}
String ClipboardChromium::getData(const String& type, bool& success) const
{
success = false;
if (policy() != ClipboardReadable || !m_dataObject)
return String();
ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
switch (dataType) {
case ClipboardDataTypeNone:
return String();
case ClipboardDataTypeURIList:
{
String text;
for (size_t i = 0; i < m_dataObject->uriList.size(); ++i) {
const String& uri = m_dataObject->uriList[i];
if (protocolIs(uri, "file"))
continue;
ASSERT(!uri.isEmpty());
if (!text.isEmpty())
text.append(textMIMETypeLineSeparator);
text.append(uri);
}
success = !text.isEmpty();
return text;
}
case ClipboardDataTypeURL:
if (!m_dataObject->url.isEmpty() && !m_dataObject->url.isLocalFile()) {
success = true;
return m_dataObject->url.string();
}
return String();
case ClipboardDataTypeDownloadURL:
success = !m_dataObject->downloadMetadata.isEmpty();
return m_dataObject->downloadMetadata;
case ClipboardDataTypePlainText:
if (!isForDragging()) {
PasteboardPrivate::ClipboardBuffer buffer =
Pasteboard::generalPasteboard()->isSelectionMode() ?
PasteboardPrivate::SelectionBuffer :
PasteboardPrivate::StandardBuffer;
String text = ChromiumBridge::clipboardReadPlainText(buffer);
success = !text.isEmpty();
return text;
}
success = !m_dataObject->plainText.isEmpty();
return m_dataObject->plainText;
case ClipboardDataTypeHTML:
if (!isForDragging()) {
PasteboardPrivate::ClipboardBuffer buffer =
Pasteboard::generalPasteboard()->isSelectionMode() ?
PasteboardPrivate::SelectionBuffer :
PasteboardPrivate::StandardBuffer;
String htmlText;
KURL sourceURL;
ChromiumBridge::clipboardReadHTML(buffer, &htmlText, &sourceURL);
success = !htmlText.isEmpty();
return htmlText;
}
success = !m_dataObject->textHtml.isEmpty();
return m_dataObject->textHtml;
case ClipboardDataTypeOther:
return String();
}
ASSERT_NOT_REACHED();
return String();
}
bool ClipboardChromium::setData(const String& type, const String& data)
{
if (policy() != ClipboardWritable)
return false;
ClipboardDataType dataType = clipboardTypeFromMIMEType(type);
switch (dataType) {
case ClipboardDataTypeNone:
return false;
case ClipboardDataTypeURL:
case ClipboardDataTypeURIList:
m_dataObject->url = KURL();
data.split('\n', m_dataObject->uriList);
for (size_t i = 0; i < m_dataObject->uriList.size(); ) {
String& line = m_dataObject->uriList[i];
line = line.stripWhiteSpace();
if (line.isEmpty()) {
m_dataObject->uriList.remove(i);
continue;
}
++i;
if (m_dataObject->url.isValid())
continue;
if (line[0] == '#')
continue;
KURL url = KURL(ParsedURLString, line);
if (url.isValid())
m_dataObject->url = url;
}
if (m_dataObject->uriList.isEmpty()) {
ASSERT(m_dataObject->url.isEmpty());
return data.isEmpty();
}
return true;
case ClipboardDataTypeDownloadURL:
m_dataObject->downloadMetadata = data;
return true;
case ClipboardDataTypePlainText:
m_dataObject->plainText = data;
return true;
case ClipboardDataTypeHTML:
m_dataObject->textHtml = data;
return true;
case ClipboardDataTypeOther:
return false;
}
ASSERT_NOT_REACHED();
return false;
}
HashSet<String> ClipboardChromium::types() const
{
HashSet<String> results;
if (policy() != ClipboardReadable && policy() != ClipboardTypesReadable)
return results;
if (!m_dataObject)
return results;
if (!m_dataObject->filenames.isEmpty())
results.add("Files");
if (m_dataObject->url.isValid() && !m_dataObject->url.isLocalFile()) {
ASSERT(!m_dataObject->uriList.isEmpty());
results.add("URL");
}
if (!m_dataObject->uriList.isEmpty()) {
for (Vector<String>::const_iterator it = m_dataObject->uriList.begin();
it != m_dataObject->uriList.end(); ++it) {
if (!protocolIs(*it, "file")) {
results.add("text/uri-list");
break;
}
}
}
if (!m_dataObject->plainText.isEmpty()) {
results.add("Text");
results.add("text/plain");
}
return results;
}
PassRefPtr<FileList> ClipboardChromium::files() const
{
if (policy() != ClipboardReadable)
return FileList::create();
if (!m_dataObject || m_dataObject->filenames.isEmpty())
return FileList::create();
RefPtr<FileList> fileList = FileList::create();
for (size_t i = 0; i < m_dataObject->filenames.size(); ++i)
fileList->append(File::create(m_dataObject->filenames.at(i)));
return fileList.release();
}
void ClipboardChromium::setDragImage(CachedImage* image, Node* node, const IntPoint& loc)
{
if (policy() != ClipboardImageWritable && policy() != ClipboardWritable)
return;
if (m_dragImage)
m_dragImage->removeClient(this);
m_dragImage = image;
if (m_dragImage)
m_dragImage->addClient(this);
m_dragLoc = loc;
m_dragImageElement = node;
}
void ClipboardChromium::setDragImage(CachedImage* img, const IntPoint& loc)
{
setDragImage(img, 0, loc);
}
void ClipboardChromium::setDragImageElement(Node* node, const IntPoint& loc)
{
setDragImage(0, node, loc);
}
DragImageRef ClipboardChromium::createDragImage(IntPoint& loc) const
{
DragImageRef result = 0;
if (m_dragImage) {
result = createDragImageFromImage(m_dragImage->image());
loc = m_dragLoc;
}
return result;
}
static String imageToMarkup(const String& url, Element* element)
{
StringBuilder markup;
markup.append("<img src=\"");
markup.append(url);
markup.append("\"");
NamedNodeMap* attrs = element->attributes();
unsigned length = attrs->length();
for (unsigned i = 0; i < length; ++i) {
Attribute* attr = attrs->attributeItem(i);
if (attr->localName() == "src")
continue;
markup.append(" ");
markup.append(attr->localName());
markup.append("=\"");
String escapedAttr = attr->value();
escapedAttr.replace("\"", """);
markup.append(escapedAttr);
markup.append("\"");
}
markup.append("/>");
return markup.toString();
}
static CachedImage* getCachedImage(Element* element)
{
ASSERT(element);
RenderObject* renderer = element->renderer();
if (!renderer || !renderer->isImage())
return 0;
RenderImage* image = toRenderImage(renderer);
if (image->cachedImage() && !image->cachedImage()->errorOccurred())
return image->cachedImage();
return 0;
}
static void writeImageToDataObject(ChromiumDataObject* dataObject, Element* element,
const KURL& url)
{
CachedImage* cachedImage = getCachedImage(element);
if (!cachedImage || !cachedImage->image() || !cachedImage->isLoaded())
return;
SharedBuffer* imageBuffer = cachedImage->image()->data();
if (!imageBuffer || !imageBuffer->size())
return;
dataObject->fileContent = imageBuffer;
String extension = MIMETypeRegistry::getPreferredExtensionForMIMEType(
cachedImage->response().mimeType());
dataObject->fileExtension = extension.isEmpty() ? "" : "." + extension;
String title = element->getAttribute(altAttr);
if (title.isEmpty())
title = cachedImage->response().suggestedFilename();
title = ClipboardChromium::validateFileName(title, dataObject);
dataObject->fileContentFilename = title + dataObject->fileExtension;
}
void ClipboardChromium::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
{
if (!m_dataObject)
return;
m_dataObject->url = url;
m_dataObject->urlTitle = title;
writeImageToDataObject(m_dataObject.get(), element, url);
AtomicString imageURL = element->getAttribute(srcAttr);
if (imageURL.isEmpty())
return;
String fullURL = frame->document()->completeURL(deprecatedParseURL(imageURL));
if (fullURL.isEmpty())
return;
m_dataObject->textHtml = imageToMarkup(fullURL, element);
}
void ClipboardChromium::writeURL(const KURL& url, const String& title, Frame*)
{
if (!m_dataObject)
return;
m_dataObject->url = url;
m_dataObject->urlTitle = title;
m_dataObject->plainText = url.string();
m_dataObject->textHtml = urlToMarkup(url, title);
m_dataObject->htmlBaseUrl = url;
}
void ClipboardChromium::writeRange(Range* selectedRange, Frame* frame)
{
ASSERT(selectedRange);
if (!m_dataObject)
return;
m_dataObject->textHtml = createMarkup(selectedRange, 0,
AnnotateForInterchange);
m_dataObject->htmlBaseUrl = frame->document()->url();
String str = frame->selectedText();
#if OS(WINDOWS)
replaceNewlinesWithWindowsStyleNewlines(str);
#endif
replaceNBSPWithSpace(str);
m_dataObject->plainText = str;
}
void ClipboardChromium::writePlainText(const String& text)
{
if (!m_dataObject)
return;
String str = text;
#if OS(WINDOWS)
replaceNewlinesWithWindowsStyleNewlines(str);
#endif
replaceNBSPWithSpace(str);
m_dataObject->plainText = str;
}
bool ClipboardChromium::hasData()
{
if (!m_dataObject)
return false;
return m_dataObject->hasData();
}
}