Atomically update the system clipboard for copy/cut events
authordcheng@chromium.org <dcheng@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Nov 2011 04:12:14 +0000 (04:12 +0000)
committerdcheng@chromium.org <dcheng@chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 11 Nov 2011 04:12:14 +0000 (04:12 +0000)
https://bugs.webkit.org/show_bug.cgi?id=40515

Reviewed by David Levin.

This change consolidates the system pasteboard mutation logic into dispatchCPPEvent() rather
than having it scattered throughout tryDHTMLCopy/tryDHTMLCut and the various Clipboard*
classes. This allows us to ensure that the system pasteboard remains in a consistent state
even if there's an exception thrown during event handling, and it also lays the ground work
for allowing pages to prevent copy/cut without causing the system pasteboard to be cleared.

No new tests, since any layout test would be flaky since it would depend on and affect
global system state.

* editing/Editor.cpp:
(WebCore::Editor::tryDHTMLCopy): Move Pasteboard::clear() call to dispatchCPPEvent().
(WebCore::Editor::tryDHTMLCut): Ditto.
(WebCore::Editor::dispatchCPPEvent):
Only persist Clipboard mutations to the system pasteboard if the event was dispatched
successfully and default processing was prevented.
* editing/mac/EditorMac.mm:
(WebCore::Editor::newGeneralClipboard):
When creating a Clipboard for copy/cut, back it with a unique instance of NSPasteboard to
buffer pasteboard mutations.
* platform/Pasteboard.h:
* platform/chromium/PasteboardChromium.cpp:
(WebCore::Pasteboard::writeClipboard):
* platform/efl/PasteboardEfl.cpp:
(WebCore::Pasteboard::writeClipboard):
* platform/gtk/ClipboardGtk.cpp: Moved pasteboard writeback to PasteboardGtk.
(WebCore::ClipboardGtk::setData):
* platform/gtk/ClipboardGtk.h:
(WebCore::ClipboardGtk::clipboard):
* platform/gtk/PasteboardGtk.cpp:
(WebCore::Pasteboard::writeClipboard):
* platform/mac/PasteboardMac.mm:
(WebCore::Pasteboard::writeClipboard):
Implement logic to flush data from temporary NSPasteboard to system pasteboard.
* platform/gtk/ClipboardGtk.cpp: Moved pasteboard writeback to PasteboardQt.
(WebCore::ClipboardGtk::setData):
* platform/qt/PasteboardQt.cpp:
(WebCore::Pasteboard::writeClipboard):
* platform/win/PasteboardWin.cpp:
(WebCore::Pasteboard::writeClipboard):
* platform/wince/PasteboardWinCE.cpp:
(WebCore::Pasteboard::writeClipboard):
* platform/wx/PasteboardWx.cpp:
(WebCore::Pasteboard::writeClipboard):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@99924 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
Source/WebCore/ChangeLog
Source/WebCore/editing/Editor.cpp
Source/WebCore/editing/mac/EditorMac.mm
Source/WebCore/platform/Pasteboard.h
Source/WebCore/platform/chromium/PasteboardChromium.cpp
Source/WebCore/platform/efl/PasteboardEfl.cpp
Source/WebCore/platform/gtk/ClipboardGtk.cpp
Source/WebCore/platform/gtk/ClipboardGtk.h
Source/WebCore/platform/gtk/PasteboardGtk.cpp
Source/WebCore/platform/mac/PasteboardMac.mm
Source/WebCore/platform/qt/ClipboardQt.cpp
Source/WebCore/platform/qt/PasteboardQt.cpp
Source/WebCore/platform/win/PasteboardWin.cpp
Source/WebCore/platform/wince/PasteboardWinCE.cpp
Source/WebCore/platform/wx/PasteboardWx.cpp

index 61bc2ec..d5f6a48 100644 (file)
@@ -1,3 +1,54 @@
+2011-11-10  Daniel Cheng  <dcheng@chromium.org>
+
+        Atomically update the system clipboard for copy/cut events
+        https://bugs.webkit.org/show_bug.cgi?id=40515
+
+        Reviewed by David Levin.
+
+        This change consolidates the system pasteboard mutation logic into dispatchCPPEvent() rather
+        than having it scattered throughout tryDHTMLCopy/tryDHTMLCut and the various Clipboard*
+        classes. This allows us to ensure that the system pasteboard remains in a consistent state
+        even if there's an exception thrown during event handling, and it also lays the ground work
+        for allowing pages to prevent copy/cut without causing the system pasteboard to be cleared.
+
+        No new tests, since any layout test would be flaky since it would depend on and affect
+        global system state.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::tryDHTMLCopy): Move Pasteboard::clear() call to dispatchCPPEvent().
+        (WebCore::Editor::tryDHTMLCut): Ditto.
+        (WebCore::Editor::dispatchCPPEvent):
+        Only persist Clipboard mutations to the system pasteboard if the event was dispatched
+        successfully and default processing was prevented.
+        * editing/mac/EditorMac.mm:
+        (WebCore::Editor::newGeneralClipboard):
+        When creating a Clipboard for copy/cut, back it with a unique instance of NSPasteboard to
+        buffer pasteboard mutations.
+        * platform/Pasteboard.h:
+        * platform/chromium/PasteboardChromium.cpp:
+        (WebCore::Pasteboard::writeClipboard):
+        * platform/efl/PasteboardEfl.cpp:
+        (WebCore::Pasteboard::writeClipboard):
+        * platform/gtk/ClipboardGtk.cpp: Moved pasteboard writeback to PasteboardGtk.
+        (WebCore::ClipboardGtk::setData):
+        * platform/gtk/ClipboardGtk.h:
+        (WebCore::ClipboardGtk::clipboard):
+        * platform/gtk/PasteboardGtk.cpp:
+        (WebCore::Pasteboard::writeClipboard):
+        * platform/mac/PasteboardMac.mm:
+        (WebCore::Pasteboard::writeClipboard):
+        Implement logic to flush data from temporary NSPasteboard to system pasteboard.
+        * platform/gtk/ClipboardGtk.cpp: Moved pasteboard writeback to PasteboardQt.
+        (WebCore::ClipboardGtk::setData):
+        * platform/qt/PasteboardQt.cpp:
+        (WebCore::Pasteboard::writeClipboard):
+        * platform/win/PasteboardWin.cpp:
+        (WebCore::Pasteboard::writeClipboard):
+        * platform/wince/PasteboardWinCE.cpp:
+        (WebCore::Pasteboard::writeClipboard):
+        * platform/wx/PasteboardWx.cpp:
+        (WebCore::Pasteboard::writeClipboard):
+
 2011-11-10  Julien Chaffraix  <jchaffraix@webkit.org>
 
         RenderTableSection's recalcCell logic is doing too much work
index 092c804..011bafe 100644 (file)
@@ -446,11 +446,6 @@ bool Editor::tryDHTMLCopy()
     if (m_frame->selection()->isInPasswordField())
         return false;
 
-    if (canCopy())
-        // Must be done before oncopy adds types and data to the pboard,
-        // also done for security, as it erases data from the last copy/paste.
-        Pasteboard::generalPasteboard()->clear();
-
     return !dispatchCPPEvent(eventNames().copyEvent, ClipboardWritable);
 }
 
@@ -459,11 +454,6 @@ bool Editor::tryDHTMLCut()
     if (m_frame->selection()->isInPasswordField())
         return false;
     
-    if (canCut())
-        // Must be done before oncut adds types and data to the pboard,
-        // also done for security, as it erases data from the last copy/paste.
-        Pasteboard::generalPasteboard()->clear();
-
     return !dispatchCPPEvent(eventNames().cutEvent, ClipboardWritable);
 }
 
@@ -746,6 +736,11 @@ bool Editor::dispatchCPPEvent(const AtomicString &eventType, ClipboardAccessPoli
     RefPtr<Event> evt = ClipboardEvent::create(eventType, true, true, clipboard);
     target->dispatchEvent(evt, ec);
     bool noDefaultProcessing = evt->defaultPrevented();
+    if (noDefaultProcessing && policy == ClipboardWritable) {
+        Pasteboard* pasteboard = Pasteboard::generalPasteboard();
+        pasteboard->clear();
+        pasteboard->writeClipboard(clipboard.get());
+    }
 
     // invalidate clipboard here for security
     clipboard->setAccessPolicy(ClipboardNumb);
index 5cff696..27b2141 100644 (file)
@@ -48,7 +48,8 @@ using namespace HTMLNames;
 
 PassRefPtr<Clipboard> Editor::newGeneralClipboard(ClipboardAccessPolicy policy, Frame* frame)
 {
-    return ClipboardMac::create(Clipboard::CopyAndPaste, [NSPasteboard generalPasteboard], policy, frame);
+    return ClipboardMac::create(Clipboard::CopyAndPaste,
+        policy == ClipboardWritable ? [NSPasteboard pasteboardWithUniqueName] : [NSPasteboard generalPasteboard], policy, frame);
 }
 
 void Editor::showFontPanel()
index 4b83ab3..866e7e5 100644 (file)
@@ -73,6 +73,7 @@ extern NSString *WebURLPboardType;
 extern NSString *WebURLsWithTitlesPboardType;
 #endif
 
+class Clipboard;
 class DocumentFragment;
 class Frame;
 class HitTestResult;
@@ -102,6 +103,7 @@ public:
     void writeFileWrapperAsRTFDAttachment(NSFileWrapper*);
     String asURL(Frame*);
 #endif
+    void writeClipboard(Clipboard*);
     void clear();
     bool canSmartReplace();
     PassRefPtr<DocumentFragment> documentFragment(Frame*, PassRefPtr<Range>, bool allowPlainText, bool& chosePlainText);
index f41c100..d09e197 100644 (file)
@@ -155,6 +155,10 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String& title)
     PlatformSupport::clipboardWriteImage(bitmap, url, title);
 }
 
+void Pasteboard::writeClipboard(Clipboard*)
+{
+}
+
 bool Pasteboard::canSmartReplace()
 {
     return PlatformSupport::clipboardIsFormatAvailable(PasteboardPrivate::WebSmartPasteFormat, m_selectionMode ? PasteboardPrivate::SelectionBuffer : PasteboardPrivate::StandardBuffer);
index 77c1d90..08004a5 100644 (file)
@@ -66,6 +66,11 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&)
     notImplemented();
 }
 
+void Pasteboard::writeClipboard(Clipboard*)
+{
+    notImplemented();
+}
+
 void Pasteboard::clear()
 {
     notImplemented();
index 5b33335..b554d20 100644 (file)
@@ -181,9 +181,6 @@ bool ClipboardGtk::setData(const String& typeString, const String& data)
         success = true;
     }
 
-    if (success && m_clipboard)
-        PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents(m_clipboard);
-
     return success;
 }
 
index 551f8fd..d8b7518 100644 (file)
@@ -73,6 +73,7 @@ namespace WebCore {
         virtual bool hasData();
 
         PassRefPtr<DataObjectGtk> dataObject() { return m_dataObject; }
+        GtkClipboard* clipboard() { return m_clipboard; }
 
     private:
         ClipboardGtk(ClipboardAccessPolicy, GtkClipboard*, Frame*);
index bfbfd67..49afbc7 100644 (file)
@@ -20,6 +20,7 @@
 #include "config.h"
 #include "Pasteboard.h"
 
+#include "ClipboardGtk.h"
 #include "DataObjectGtk.h"
 #include "DocumentFragment.h"
 #include "Frame.h"
@@ -131,6 +132,13 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String& title)
     PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents(clipboard);
 }
 
+void Pasteboard::writeClipboard(Clipboard* clipboard)
+{
+    GtkClipboard* gtkClipboard = static_cast<ClipboardGtk*>(clipboard)->clipboard();
+    if (gtkClipboard)
+        PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents(gtkClipboard);
+}
+
 void Pasteboard::clear()
 {
     gtk_clipboard_clear(gtk_clipboard_get_for_display(gdk_display_get_default(), GDK_SELECTION_CLIPBOARD));
index d1e90a9..852e17a 100644 (file)
@@ -27,6 +27,7 @@
 #import "Pasteboard.h"
 
 #import "CachedResource.h"
+#import "ClipboardMac.h"
 #import "DOMRangeInternal.h"
 #import "Document.h"
 #import "DocumentFragment.h"
@@ -320,6 +321,18 @@ void Pasteboard::writeImage(Node* node, const KURL& url, const String& title)
     writeFileWrapperAsRTFDAttachment(fileWrapperForImage(cachedImage, cocoaURL));
 }
 
+void Pasteboard::writeClipboard(Clipboard* clipboard)
+{
+    NSPasteboard* pasteboard = static_cast<ClipboardMac*>(clipboard)->pasteboard();
+    NSArray* types = [pasteboard types];
+
+    [m_pasteboard.get() addTypes:types owner:nil];
+    for (NSUInteger i = 0; i < [types count]; i++) {
+        NSString* type = [types objectAtIndex:i];
+        [m_pasteboard.get() setData:[pasteboard dataForType:type] forType:type];
+    }
+}
+
 bool Pasteboard::canSmartReplace()
 {
     return [[m_pasteboard.get() types] containsObject:WebSmartPastePboardType];
index b30f63d..2734952 100644 (file)
@@ -185,10 +185,6 @@ bool ClipboardQt::setData(const String& type, const String& data)
         m_writableData->setData(QString(type), array);
     }
 
-#ifndef QT_NO_CLIPBOARD
-    if (isForCopyAndPaste())
-        QGuiApplication::clipboard()->setMimeData(m_writableData);
-#endif
     return true;
 }
 
index 050fe13..dc7fb8f 100644 (file)
@@ -28,6 +28,7 @@
 #include "config.h"
 #include "Pasteboard.h"
 
+#include "ClipboardQt.h"
 #include "DocumentFragment.h"
 #include "Editor.h"
 #include "Frame.h"
@@ -172,6 +173,13 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&)
 #endif
 }
 
+void Pasteboard::writeClipboard(Clipboard* clipboard)
+{
+#ifndef QT_NO_CLIPBOARD
+    QGuiApplication::clipboard()->setMimeData(static_cast<ClipboardQt*>(clipboard)->clipboardData());
+#endif
+}
+
 /* This function is called from Editor::tryDHTMLCopy before actually set the clipboard
  * It introduce a race condition with klipper, which will try to grab the clipboard 
  * It's not required to clear it anyway, since QClipboard take care about replacing the clipboard
index e0cc86a..d768a3d 100644 (file)
@@ -35,6 +35,7 @@
 #include "HitTestResult.h"
 #include "Image.h"
 #include "KURL.h"
+#include "NotImplemented.h"
 #include "Page.h"
 #include "Range.h"
 #include "RenderImage.h"
@@ -250,6 +251,11 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&)
     }
 }
 
+void Pasteboard::writeClipboard(Clipboard*)
+{
+    notImplemented();
+}
+
 bool Pasteboard::canSmartReplace()
 { 
     return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
index 53dbfa8..13bbe48 100644 (file)
@@ -36,6 +36,7 @@
 #include "HitTestResult.h"
 #include "Image.h"
 #include "KURL.h"
+#include "NotImplemented.h"
 #include "Page.h"
 #include "Range.h"
 #include "RenderImage.h"
@@ -231,6 +232,11 @@ void Pasteboard::writeImage(Node* node, const KURL&, const String&)
         DeleteObject(resultBitmap);
 }
 
+void Pasteboard::writeClipboard(Clipboard*)
+{
+    notImplemented();
+}
+
 bool Pasteboard::canSmartReplace()
 {
     return ::IsClipboardFormatAvailable(WebSmartPasteFormat);
index 4677d14..4993664 100644 (file)
@@ -105,6 +105,11 @@ void Pasteboard::writeURL(const KURL& url, const String&, Frame*)
     }
 }
 
+void Pasteboard::writeClipboard(Clipboard*)
+{
+    notImplemented();
+}
+
 void Pasteboard::clear()
 {
     wxTheClipboard->Clear();