RESOLVED FIXED 40515
Atomically update the system clipboard for copy/cut events
https://bugs.webkit.org/show_bug.cgi?id=40515
Summary Atomically update the system clipboard for copy/cut events
Daniel Cheng
Reported 2010-06-11 20:50:51 PDT
Right now, the various Clipboard implementations contain a lot of platform-specific details. We should create a new platform object (like DragData) to abstract away the interactions with platform data.
Attachments
Patch (15.78 KB, patch)
2010-06-11 22:29 PDT, Daniel Cheng
no flags
Patch (16.12 KB, patch)
2010-06-12 04:23 PDT, Daniel Cheng
no flags
Patch (15.64 KB, patch)
2010-06-12 04:28 PDT, Daniel Cheng
no flags
Patch (15.64 KB, patch)
2010-06-12 04:55 PDT, Daniel Cheng
no flags
Patch (12.90 KB, patch)
2011-11-02 14:27 PDT, Daniel Cheng
no flags
Patch (14.50 KB, patch)
2011-11-09 16:28 PST, Daniel Cheng
no flags
Patch (14.43 KB, patch)
2011-11-10 16:03 PST, Daniel Cheng
no flags
Patch (14.49 KB, patch)
2011-11-10 17:11 PST, Daniel Cheng
levin: review+
Daniel Cheng
Comment 1 2010-06-11 22:29:39 PDT
WebKit Review Bot
Comment 2 2010-06-11 22:38:26 PDT
Attachment 58540 [details] did not pass style-queue: Failed to run "['WebKitTools/Scripts/check-webkit-style', '--no-squash']" exit_code: 1 Webcore/platform/ClipboardData.h:1: One or more unexpected \r (^M) found; better to use only a \n [whitespace/carriage_return] [1] Suppressing further [whitespace/carriage_return] reports for this file. Webcore/platform/ClipboardData.cpp:1: One or more unexpected \r (^M) found; better to use only a \n [whitespace/carriage_return] [1] Suppressing further [whitespace/carriage_return] reports for this file. Total errors found: 145 in 11 files If any of these errors are false positives, please file a bug against check-webkit-style.
Early Warning System Bot
Comment 3 2010-06-11 22:43:32 PDT
WebKit Review Bot
Comment 4 2010-06-11 22:53:49 PDT
Daniel Cheng
Comment 5 2010-06-12 04:23:23 PDT
Daniel Cheng
Comment 6 2010-06-12 04:28:43 PDT
Created attachment 58548 [details] Patch Fix bad merge.
Early Warning System Bot
Comment 7 2010-06-12 04:35:56 PDT
Early Warning System Bot
Comment 8 2010-06-12 04:40:47 PDT
Daniel Cheng
Comment 9 2010-06-12 04:55:24 PDT
Created attachment 58549 [details] Patch Fix build break (paths had incorrect case)
WebKit Review Bot
Comment 10 2010-06-12 05:05:36 PDT
Daniel Cheng
Comment 11 2010-06-16 18:04:13 PDT
Darin, do you mind reviewing this patch? https://bugs.webkit.org/show_bug.cgi?id=40455 isn't complete, but it shows how this proposed patch would be used.
Darin Adler
Comment 12 2010-06-29 15:05:07 PDT
Comment on attachment 58549 [details] Patch > +class ClipboardData : public RefCounted<ClipboardData> { This seems fine, but I'm not sure why it's an abstract base class. Generally speaking the platform directory does not use runtime factories that vend objects of abstract base classes. I have seen other libraries that use this approach, but it has runtime costs that we prefer not to pay in WebKit. The interface here looks generally OK in terms of what the functions are and the argument types, but the basic approach does not seem right. An example of how we do this without virtual functions is in the FileChooser.h source file. Not sure that needs to be a reference-counted object, but otherwise it's a reasonable example. DragData.h is another example, although a particularly messy one.
Daniel Cheng
Comment 13 2010-06-30 17:08:31 PDT
(In reply to comment #12) > (From update of attachment 58549 [details]) > > +class ClipboardData : public RefCounted<ClipboardData> { > > This seems fine, but I'm not sure why it's an abstract base class. Generally speaking the platform directory does not use runtime factories that vend objects of abstract base classes. I have seen other libraries that use this approach, but it has runtime costs that we prefer not to pay in WebKit. > > The interface here looks generally OK in terms of what the functions are and the argument types, but the basic approach does not seem right. > > An example of how we do this without virtual functions is in the FileChooser.h source file. Not sure that needs to be a reference-counted object, but otherwise it's a reasonable example. DragData.h is another example, although a particularly messy one. The interface is virtual because there are two implementations for a given platform: 1. One implementation that lives under platform. This provides a read-only implementation of ClipboardData which wraps accessing native copy/paste and drag/drop data. 2. Another common implementation that lives in a location TBD. It is primarily intended for writing (in the cut/copy/dragstart events), though you can read from it as well. The reason for creating two separate implementations like this is because I found the way the current Clipboard worked to be a little wonky: - When starting drags, platform implementations of Clipboard simply allow data members to be set. At some point, DragClient::startDrag is called and the implementation atomically creates a data object and sets all data that will be in that drag. - For copy/cut operations, Clipboard immediately writes back to the clipboard, so Clipboard contents won't be set atomically. Thus, we end up with Clipboard implementations that look like: if (m_isForDragging) { m_foo = bar; } else { // FIXME: Add Pasteboard support. } This is true for Windows WebKit, Chromium WebKit, and probably a number of other platforms as well. - If writing drag data and copy data are abstracted by one generic object, then Clipboard becomes much simpler. Persisting data to the clipboard might look like this instead: if (clipboard.isDirty()) { Pasteboard::clear(); Pasteboard::writeData(clipboard); } This also has the bonus side effect that preventing a copy or cut no longer clears the Pasteboard contents, which follows IE behavior.
Daniel Cheng
Comment 14 2011-11-02 14:27:01 PDT
Daniel Cheng
Comment 15 2011-11-03 12:02:18 PDT
Darin, do you mind taking another look at this? We'll need this change to fix https://bugs.webkit.org/show_bug.cgi?id=34288, so that simply preventing the default action without setting any data doesn't cause the clipboard to get cleared on copy/cut.
Daniel Cheng
Comment 16 2011-11-07 12:06:07 PST
I've completely rewritten this patch, and I think it should address previous review concerns to this patch. There is no more ClipboardData interface, so if you could take another look, that'd be great.
Darin Adler
Comment 17 2011-11-07 12:30:02 PST
Comment on attachment 113377 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=113377&action=review > Source/WebCore/editing/Editor.cpp:743 > + if (noDefaultProcessing && policy == ClipboardWritable) { > + Pasteboard* pasteboard = Pasteboard::generalPasteboard(); > + pasteboard->clear(); > + pasteboard->writeClipboard(clipboard.get()); > + } If the actual pasteboard processing is done in this function, then the name dispatchCPPEvent is inappropriate. Is that something new to this patch, or has it always been true.
Daniel Cheng
Comment 18 2011-11-07 12:50:32 PST
(In reply to comment #17) > (From update of attachment 113377 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=113377&action=review > > > Source/WebCore/editing/Editor.cpp:743 > > + if (noDefaultProcessing && policy == ClipboardWritable) { > > + Pasteboard* pasteboard = Pasteboard::generalPasteboard(); > > + pasteboard->clear(); > > + pasteboard->writeClipboard(clipboard.get()); > > + } > > If the actual pasteboard processing is done in this function, then the name dispatchCPPEvent is inappropriate. Is that something new to this patch, or has it always been true. This has always been true, but the pasteboard mutation wasn't as obvious before--it was happening inside Clipboard::setData().
Daniel Cheng
Comment 19 2011-11-07 14:01:24 PST
(In reply to comment #17) > (From update of attachment 113377 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=113377&action=review > > > Source/WebCore/editing/Editor.cpp:743 > > + if (noDefaultProcessing && policy == ClipboardWritable) { > > + Pasteboard* pasteboard = Pasteboard::generalPasteboard(); > > + pasteboard->clear(); > > + pasteboard->writeClipboard(clipboard.get()); > > + } > > If the actual pasteboard processing is done in this function, then the name dispatchCPPEvent is inappropriate. Is that something new to this patch, or has it always been true. I thought about ways to split up dispatchCPPEvent to move the pasteboard processing out of dispatchCPPEvent, but I can't think of any good way without duplicating some of the boilerplate to set up the clipboard event and fire it. What makes dispatchCPPEvent an inappropriate name, and do you have suggestions on how this can be addressed?
David Levin
Comment 20 2011-11-08 13:49:49 PST
Comment on attachment 113377 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=113377&action=review > Source/WebCore/ChangeLog:8 > + Add a Pasteboard::writeClipboard() method which is roughly analogous to Part of this should be the comment for dispatchCPPEvent. > Source/WebCore/ChangeLog:12 > + Covered by existing tests. It is only covered by existing tests if 1. It is only a refactoring (but that is not the case here as I see new function calls). 2. An existing test is broken and this fixes it, but I don't see a new baseline for a test. So what is testing these new api calls?/Why are they needed? > Source/WebCore/ChangeLog:15 > + (WebCore::Editor::tryDHTMLCopy): Ideally your changelog would have an explanation of what was done in each function. For example, it would say "Move clear call to dispatchCPPEvent" here. Think of this like a breadcrumb trail for the reviewer so they don't need to piece as much together. > Source/WebCore/ChangeLog:16 > + (WebCore::Editor::tryDHTMLCut): Here "Ditto" >>>> Source/WebCore/editing/Editor.cpp:743 >>>> + } >>> >>> If the actual pasteboard processing is done in this function, then the name dispatchCPPEvent is inappropriate. Is that something new to this patch, or has it always been true. >> >> This has always been true, but the pasteboard mutation wasn't as obvious before--it was happening inside Clipboard::setData(). > > I thought about ways to split up dispatchCPPEvent to move the pasteboard processing out of dispatchCPPEvent, but I can't think of any good way without duplicating some of the boilerplate to set up the clipboard event and fire it. What makes dispatchCPPEvent an inappropriate name, and do you have suggestions on how this can be addressed? It dispatches the event on line 737 but then this stuff is extra. Please describe what this function does and then we can find a name. > Source/WebCore/editing/mac/EditorMac.mm:52 > + policy == ClipboardWritable ? [NSPasteboard pasteboardWithUniqueName] : [NSPasteboard generalPasteboard], policy, frame); The changelog should tell me why this change is being done. > Source/WebCore/platform/mac/PasteboardMac.mm:333 > + } Why is this code needed now? (Hint: The ChangeLog should tell me.) > Source/WebCore/platform/qt/PasteboardQt.cpp:179 > + static_cast<ClipboardQt*>(clipboard)->clipboardData()); No need for a carriage return here. What does this fix? (Hint: I should know due to the ChangeLog.) > Source/WebCore/platform/wince/PasteboardWinCE.cpp:39 > +#include "NotImplemented.h" Why include this header and not use notImplemented?
Daniel Cheng
Comment 21 2011-11-09 16:28:40 PST
Daniel Cheng
Comment 22 2011-11-10 16:03:24 PST
Daniel Cheng
Comment 23 2011-11-10 16:05:30 PST
Comment on attachment 113377 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=113377&action=review >> Source/WebCore/ChangeLog:8 >> + Add a Pasteboard::writeClipboard() method which is roughly analogous to > > Part of this should be the comment for dispatchCPPEvent. Done. >> Source/WebCore/ChangeLog:12 >> + Covered by existing tests. > > It is only covered by existing tests if > 1. It is only a refactoring (but that is not the case here as I see new function calls). > 2. An existing test is broken and this fixes it, but I don't see a new baseline for a test. > > So what is testing these new api calls?/Why are they needed? Done. >> Source/WebCore/ChangeLog:15 >> + (WebCore::Editor::tryDHTMLCopy): > > Ideally your changelog would have an explanation of what was done in each function. > > For example, it would say "Move clear call to dispatchCPPEvent" here. Think of this like a breadcrumb trail for the reviewer so they don't need to piece as much together. Done. >> Source/WebCore/ChangeLog:16 >> + (WebCore::Editor::tryDHTMLCut): > > Here "Ditto" Done. >>>>> Source/WebCore/editing/Editor.cpp:743 >>>> >>>> If the actual pasteboard processing is done in this function, then the name dispatchCPPEvent is inappropriate. Is that something new to this patch, or has it always been true. >>> >>> This has always been true, but the pasteboard mutation wasn't as obvious before--it was happening inside Clipboard::setData(). >> >> I thought about ways to split up dispatchCPPEvent to move the pasteboard processing out of dispatchCPPEvent, but I can't think of any good way without duplicating some of the boilerplate to set up the clipboard event and fire it. What makes dispatchCPPEvent an inappropriate name, and do you have suggestions on how this can be addressed? > > It dispatches the event on line 737 but then this stuff is extra. Please describe what this function does and then we can find a name. Done... I think. >> Source/WebCore/editing/mac/EditorMac.mm:52 >> + policy == ClipboardWritable ? [NSPasteboard pasteboardWithUniqueName] : [NSPasteboard generalPasteboard], policy, frame); > > The changelog should tell me why this change is being done. Done. >> Source/WebCore/platform/mac/PasteboardMac.mm:333 >> + } > > Why is this code needed now? (Hint: The ChangeLog should tell me.) Done. >> Source/WebCore/platform/qt/PasteboardQt.cpp:179 >> + static_cast<ClipboardQt*>(clipboard)->clipboardData()); > > No need for a carriage return here. > > What does this fix? (Hint: I should know due to the ChangeLog.) Done. >> Source/WebCore/platform/wince/PasteboardWinCE.cpp:39 >> +#include "NotImplemented.h" > > Why include this header and not use notImplemented? Done.
David Levin
Comment 24 2011-11-10 16:51:51 PST
Comment on attachment 114592 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=114592&action=review Just one question before I r+. > Source/WebCore/platform/gtk/PasteboardGtk.cpp:138 > + static_cast<ClipboardGtk*>(clipboard)->clipboard()); Why did it check m_clipboard before but now it doesn't?
Daniel Cheng
Comment 25 2011-11-10 16:58:11 PST
Comment on attachment 114592 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=114592&action=review >> Source/WebCore/platform/gtk/PasteboardGtk.cpp:138 >> + static_cast<ClipboardGtk*>(clipboard)->clipboard()); > > Why did it check m_clipboard before but now it doesn't? Because m_clipboard was only accessible to ClipboardGtk. I added an accessor for it so we can use it in PasteboardGtk as well.
David Levin
Comment 26 2011-11-10 17:01:02 PST
(In reply to comment #25) > (From update of attachment 114592 [details]) > View in context: https://bugs.webkit.org/attachment.cgi?id=114592&action=review > > >> Source/WebCore/platform/gtk/PasteboardGtk.cpp:138 > >> + static_cast<ClipboardGtk*>(clipboard)->clipboard()); > > > > Why did it check m_clipboard before but now it doesn't? > > Because m_clipboard was only accessible to ClipboardGtk. I added an accessor for it so we can use it in PasteboardGtk as well. I'll be more verbose. Prior code: if (success && m_clipboard) PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents(m_clipboard); Why was the prior code checking that m_clipboard wasn't NULL but the current code uses the equivalent "static_cast<ClipboardGtk*>(clipboard)->clipboard()" without doing a NULL check: PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents( static_cast<ClipboardGtk*>(clipboard)->clipboard()); If you answered this just now, I didn't understand the answer.
Daniel Cheng
Comment 27 2011-11-10 17:11:39 PST
Daniel Cheng
Comment 28 2011-11-10 17:12:08 PST
Comment on attachment 114592 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=114592&action=review >>>> Source/WebCore/platform/gtk/PasteboardGtk.cpp:138 >>>> + static_cast<ClipboardGtk*>(clipboard)->clipboard()); >>> >>> Why did it check m_clipboard before but now it doesn't? >> >> Because m_clipboard was only accessible to ClipboardGtk. I added an accessor for it so we can use it in PasteboardGtk as well. > > I'll be more verbose. > > Prior code: > if (success && m_clipboard) > PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents(m_clipboard); > > Why was the prior code checking that m_clipboard wasn't NULL but the current code uses the equivalent "static_cast<ClipboardGtk*>(clipboard)->clipboard()" without doing a NULL check: > > PasteboardHelper::defaultPasteboardHelper()->writeClipboardContents( > static_cast<ClipboardGtk*>(clipboard)->clipboard()); > > If you answered this just now, I didn't understand the answer. Good point. Fixed.
Daniel Cheng
Comment 29 2011-11-10 20:12:25 PST
Ryosuke Niwa
Comment 30 2011-11-23 10:57:40 PST
Why did this test land without any tests? This patch changes the timing at which copy/cut/paste events are dispatched and therefore need to be tested.
Ryosuke Niwa
Comment 31 2011-11-23 11:03:51 PST
(In reply to comment #30) > Why did this patch land without any tests? This patch changes the timing at which copy/cut/paste events are dispatched and therefore need to be tested. On second thought, this might be okay since this change only affects copy and cut both of which can't read clipboard data
Daniel Cheng
Comment 32 2011-11-23 11:05:45 PST
(In reply to comment #31) > (In reply to comment #30) > > Why did this patch land without any tests? This patch changes the timing at which copy/cut/paste events are dispatched and therefore need to be tested. > > On second thought, this might be okay since this change only affects copy and cut both of which can't read clipboard data This was a mistake on my part. I thought that pasteboard tests that interacted with the system clipboard would be inherently flaky due to the global nature of the clipboard, but it appears we correctly handle that case today. I am working on followup tests and will be landing them in a separate patch.
Note You need to log in before you can comment on or make changes to this bug.