1/* 2 * Copyright (c) 2008, 2009, Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "core/platform/Pasteboard.h" 33 34#include "HTMLNames.h" 35#include "SVGNames.h" 36#include "XLinkNames.h" 37#include "core/dom/Document.h" 38#include "core/dom/DocumentFragment.h" 39#include "core/dom/Element.h" 40#include "core/dom/Range.h" 41#include "core/editing/markup.h" 42#include "core/html/parser/HTMLParserIdioms.h" 43#include "core/loader/cache/ImageResource.h" 44#include "core/page/Frame.h" 45#include "core/platform/chromium/ClipboardChromium.h" 46#include "core/platform/chromium/ClipboardUtilitiesChromium.h" 47#include "core/platform/graphics/Image.h" 48#include "core/platform/graphics/skia/NativeImageSkia.h" 49#include "core/rendering/RenderImage.h" 50#include "public/platform/Platform.h" 51#include "public/platform/WebClipboard.h" 52#include "public/platform/WebDragData.h" 53#include "weborigin/KURL.h" 54 55namespace WebCore { 56 57Pasteboard* Pasteboard::generalPasteboard() 58{ 59 static Pasteboard* pasteboard = new Pasteboard; 60 return pasteboard; 61} 62 63Pasteboard::Pasteboard() 64 : m_selectionMode(false) 65{ 66} 67 68void Pasteboard::clear() 69{ 70 // The ScopedClipboardWriter class takes care of clearing the clipboard's 71 // previous contents. 72} 73 74bool Pasteboard::isSelectionMode() const 75{ 76 return m_selectionMode; 77} 78 79void Pasteboard::setSelectionMode(bool selectionMode) 80{ 81 m_selectionMode = selectionMode; 82} 83 84void Pasteboard::writeSelection(Range* selectedRange, bool canSmartCopyOrDelete, Frame* frame, ShouldSerializeSelectedTextForClipboard shouldSerializeSelectedTextForClipboard) 85{ 86 String html = createMarkup(selectedRange, 0, AnnotateForInterchange, false, ResolveNonLocalURLs); 87 KURL url = selectedRange->startContainer()->document()->url(); 88 String plainText = shouldSerializeSelectedTextForClipboard == IncludeImageAltTextForClipboard ? frame->selectedTextForClipboard() : frame->selectedText(); 89#if OS(WINDOWS) 90 replaceNewlinesWithWindowsStyleNewlines(plainText); 91#endif 92 replaceNBSPWithSpace(plainText); 93 94 WebKit::Platform::current()->clipboard()->writeHTML(html, url, plainText, canSmartCopyOrDelete); 95} 96 97void Pasteboard::writePlainText(const String& text, SmartReplaceOption) 98{ 99 // FIXME: add support for smart replace 100#if OS(WINDOWS) 101 String plainText(text); 102 replaceNewlinesWithWindowsStyleNewlines(plainText); 103 WebKit::Platform::current()->clipboard()->writePlainText(plainText); 104#else 105 WebKit::Platform::current()->clipboard()->writePlainText(text); 106#endif 107} 108 109void Pasteboard::writeURL(const KURL& url, const String& titleStr, Frame* frame) 110{ 111 ASSERT(!url.isEmpty()); 112 113 String title(titleStr); 114 if (title.isEmpty()) { 115 title = url.lastPathComponent(); 116 if (title.isEmpty()) 117 title = url.host(); 118 } 119 120 WebKit::Platform::current()->clipboard()->writeURL(url, title); 121} 122 123void Pasteboard::writeImage(Node* node, const KURL&, const String& title) 124{ 125 ASSERT(node); 126 127 if (!(node->renderer() && node->renderer()->isImage())) 128 return; 129 130 RenderImage* renderer = toRenderImage(node->renderer()); 131 ImageResource* cachedImage = renderer->cachedImage(); 132 if (!cachedImage || cachedImage->errorOccurred()) 133 return; 134 Image* image = cachedImage->imageForRenderer(renderer); 135 ASSERT(image); 136 137 RefPtr<NativeImageSkia> bitmap = image->nativeImageForCurrentFrame(); 138 if (!bitmap) 139 return; 140 141 // If the image is wrapped in a link, |url| points to the target of the 142 // link. This isn't useful to us, so get the actual image URL. 143 AtomicString urlString; 144 if (node->hasTagName(HTMLNames::imgTag) || node->hasTagName(HTMLNames::inputTag)) 145 urlString = toElement(node)->getAttribute(HTMLNames::srcAttr); 146 else if (node->hasTagName(SVGNames::imageTag)) 147 urlString = toElement(node)->getAttribute(XLinkNames::hrefAttr); 148 else if (node->hasTagName(HTMLNames::embedTag) || node->hasTagName(HTMLNames::objectTag)) { 149 Element* element = toElement(node); 150 urlString = element->imageSourceURL(); 151 } 152 KURL url = urlString.isEmpty() ? KURL() : node->document()->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString)); 153 WebKit::WebImage webImage = bitmap->bitmap(); 154 WebKit::Platform::current()->clipboard()->writeImage(webImage, WebKit::WebURL(url), WebKit::WebString(title)); 155} 156 157void Pasteboard::writeClipboard(Clipboard* clipboard) 158{ 159 WebKit::WebDragData dragData = static_cast<ClipboardChromium*>(clipboard)->dataObject(); 160 WebKit::Platform::current()->clipboard()->writeDataObject(dragData); 161} 162 163bool Pasteboard::canSmartReplace() 164{ 165 return WebKit::Platform::current()->clipboard()->isFormatAvailable(WebKit::WebClipboard::FormatSmartPaste, m_selectionMode ? WebKit::WebClipboard::BufferSelection : WebKit::WebClipboard::BufferStandard); 166} 167 168String Pasteboard::plainText(Frame* frame) 169{ 170 return WebKit::Platform::current()->clipboard()->readPlainText(m_selectionMode ? WebKit::WebClipboard::BufferSelection : WebKit::WebClipboard::BufferStandard); 171} 172 173PassRefPtr<DocumentFragment> Pasteboard::documentFragment(Frame* frame, PassRefPtr<Range> context, bool allowPlainText, bool& chosePlainText) 174{ 175 chosePlainText = false; 176 WebKit::WebClipboard::Buffer buffer = m_selectionMode ? WebKit::WebClipboard::BufferSelection : WebKit::WebClipboard::BufferStandard; 177 178 if (WebKit::Platform::current()->clipboard()->isFormatAvailable(WebKit::WebClipboard::FormatHTML, buffer)) { 179 unsigned fragmentStart = 0; 180 unsigned fragmentEnd = 0; 181 WebKit::WebURL url; 182 WebKit::WebString markup = WebKit::Platform::current()->clipboard()->readHTML(buffer, &url, &fragmentStart, &fragmentEnd); 183 if (!markup.isEmpty()) { 184 if (RefPtr<DocumentFragment> fragment = createFragmentFromMarkupWithContext(frame->document(), markup, fragmentStart, fragmentEnd, KURL(url), DisallowScriptingAndPluginContent)) 185 return fragment.release(); 186 } 187 } 188 189 if (allowPlainText) { 190 String markup = WebKit::Platform::current()->clipboard()->readPlainText(buffer); 191 if (!markup.isEmpty()) { 192 chosePlainText = true; 193 if (RefPtr<DocumentFragment> fragment = createFragmentFromText(context.get(), markup)) 194 return fragment.release(); 195 } 196 } 197 198 return 0; 199} 200 201} // namespace WebCore 202