summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm')
-rw-r--r--Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm451
1 files changed, 296 insertions, 155 deletions
diff --git a/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm b/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm
index 8d81889..d7b352c 100644
--- a/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm
+++ b/Source/WebKit2/WebProcess/WebPage/mac/WebPageMac.mm
@@ -27,10 +27,13 @@
#import "WebPage.h"
#import "AccessibilityWebPageObject.h"
+#import "AttributedString.h"
#import "DataReference.h"
+#import "EditorState.h"
#import "PluginView.h"
#import "WebCoreArgumentCoders.h"
#import "WebEvent.h"
+#import "WebEventConversion.h"
#import "WebFrame.h"
#import "WebPageProxyMessages.h"
#import "WebProcess.h"
@@ -39,6 +42,7 @@
#import <WebCore/Frame.h>
#import <WebCore/FrameView.h>
#import <WebCore/HitTestResult.h>
+#import <WebCore/HTMLConverter.h>
#import <WebCore/KeyboardEvent.h>
#import <WebCore/Page.h>
#import <WebCore/PlatformKeyboardEvent.h>
@@ -53,6 +57,8 @@ using namespace WebCore;
namespace WebKit {
+static PassRefPtr<Range> convertToRange(Frame*, NSRange);
+
void WebPage::platformInitialize()
{
m_page->addSchedulePair(SchedulePair::create([NSRunLoop currentRunLoop], kCFRunLoopCommonModes));
@@ -77,68 +83,131 @@ void WebPage::platformPreferencesDidChange(const WebPreferencesStore&)
{
}
-bool WebPage::interceptEditingKeyboardEvent(KeyboardEvent* evt, bool shouldSaveCommand)
+typedef HashMap<String, String> SelectorNameMap;
+
+// Map selectors into Editor command names.
+// This is not needed for any selectors that have the same name as the Editor command.
+static const SelectorNameMap* createSelectorExceptionMap()
+{
+ SelectorNameMap* map = new HashMap<String, String>;
+
+ map->add("insertNewlineIgnoringFieldEditor:", "InsertNewline");
+ map->add("insertParagraphSeparator:", "InsertNewline");
+ map->add("insertTabIgnoringFieldEditor:", "InsertTab");
+ map->add("pageDown:", "MovePageDown");
+ map->add("pageDownAndModifySelection:", "MovePageDownAndModifySelection");
+ map->add("pageUp:", "MovePageUp");
+ map->add("pageUpAndModifySelection:", "MovePageUpAndModifySelection");
+
+ return map;
+}
+
+static String commandNameForSelectorName(const String& selectorName)
+{
+ // Check the exception map first.
+ static const SelectorNameMap* exceptionMap = createSelectorExceptionMap();
+ SelectorNameMap::const_iterator it = exceptionMap->find(selectorName);
+ if (it != exceptionMap->end())
+ return it->second;
+
+ // Remove the trailing colon.
+ // No need to capitalize the command name since Editor command names are not case sensitive.
+ size_t selectorNameLength = selectorName.length();
+ if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':')
+ return String();
+ return selectorName.left(selectorNameLength - 1);
+}
+
+static Frame* frameForEvent(KeyboardEvent* event)
{
- Node* node = evt->target()->toNode();
+ Node* node = event->target()->toNode();
ASSERT(node);
Frame* frame = node->document()->frame();
ASSERT(frame);
+ return frame;
+}
+
+bool WebPage::executeKeypressCommandsInternal(const Vector<WebCore::KeypressCommand>& commands, KeyboardEvent* event)
+{
+ Frame* frame = frameForEvent(event);
+ ASSERT(frame->page() == corePage());
+
+ bool eventWasHandled = false;
+ for (size_t i = 0; i < commands.size(); ++i) {
+ if (commands[i].commandName == "insertText:") {
+ ASSERT(!frame->editor()->hasComposition());
+
+ if (!frame->editor()->canEdit())
+ continue;
+
+ // An insertText: might be handled by other responders in the chain if we don't handle it.
+ // One example is space bar that results in scrolling down the page.
+ eventWasHandled |= frame->editor()->insertText(commands[i].text, event);
+ } else {
+ Editor::Command command = frame->editor()->command(commandNameForSelectorName(commands[i].commandName));
+ if (command.isSupported()) {
+ bool commandExecutedByEditor = command.execute(event);
+ eventWasHandled |= commandExecutedByEditor;
+ if (!commandExecutedByEditor) {
+ bool performedNonEditingBehavior = event->keyEvent()->type() == PlatformKeyboardEvent::RawKeyDown && performNonEditingBehaviorForSelector(commands[i].commandName);
+ eventWasHandled |= performedNonEditingBehavior;
+ }
+ } else {
+ bool commandWasHandledByUIProcess = false;
+ WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::ExecuteSavedCommandBySelector(commands[i].commandName),
+ Messages::WebPageProxy::ExecuteSavedCommandBySelector::Reply(commandWasHandledByUIProcess), m_pageID);
+ eventWasHandled |= commandWasHandledByUIProcess;
+ }
+ }
+ }
+ return eventWasHandled;
+}
+
+bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event, bool saveCommands)
+{
+ ASSERT(!saveCommands || event->keypressCommands().isEmpty()); // Save commands once for each event.
+
+ Frame* frame = frameForEvent(event);
- const PlatformKeyboardEvent* keyEvent = evt->keyEvent();
- if (!keyEvent)
+ const PlatformKeyboardEvent* platformEvent = event->keyEvent();
+ if (!platformEvent)
return false;
- const Vector<KeypressCommand>& commands = evt->keypressCommands();
- bool hasKeypressCommand = !commands.isEmpty();
-
+ Vector<KeypressCommand>& commands = event->keypressCommands();
+
+ if ([platformEvent->macEvent() type] == NSFlagsChanged)
+ return false;
+
bool eventWasHandled = false;
- if (shouldSaveCommand || !hasKeypressCommand) {
- Vector<KeypressCommand> commandsList;
- Vector<CompositionUnderline> underlines;
- unsigned start;
- unsigned end;
- if (!WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(keyEvent->type()),
- Messages::WebPageProxy::InterpretKeyEvent::Reply(commandsList, start, end, underlines),
- m_pageID, CoreIPC::Connection::NoTimeout))
+ if (saveCommands) {
+ KeyboardEvent* oldEvent = m_keyboardEventBeingInterpreted;
+ m_keyboardEventBeingInterpreted = event;
+ bool sendResult = WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretQueuedKeyEvent(editorState()),
+ Messages::WebPageProxy::InterpretQueuedKeyEvent::Reply(eventWasHandled, commands), m_pageID);
+ m_keyboardEventBeingInterpreted = oldEvent;
+ if (!sendResult)
+ return false;
+
+ // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline.
+ // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that
+ // should be handled like normal text input after DOM event dispatch.
+ if (!event->keypressCommands().isEmpty())
return false;
- if (commandsList.isEmpty())
- return eventWasHandled;
-
- if (commandsList[0].commandName == "setMarkedText") {
- frame->editor()->setComposition(commandsList[0].text, underlines, start, end);
- eventWasHandled = true;
- } else if (commandsList[0].commandName == "insertText" && frame->editor()->hasComposition()) {
- frame->editor()->confirmComposition(commandsList[0].text);
- eventWasHandled = true;
- } else if (commandsList[0].commandName == "unmarkText") {
- frame->editor()->confirmComposition();
- eventWasHandled = true;
- } else {
- for (size_t i = 0; i < commandsList.size(); i++)
- evt->keypressCommands().append(commandsList[i]);
- }
} else {
- size_t size = commands.size();
- // Are there commands that would just cause text insertion if executed via Editor?
+ // Are there commands that could just cause text insertion if executed via Editor?
// WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore
// to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated
// (e.g. Tab that inserts a Tab character, or Enter).
bool haveTextInsertionCommands = false;
- for (size_t i = 0; i < size; ++i) {
- if (frame->editor()->command(commands[i].commandName).isTextInsertion())
+ for (size_t i = 0; i < commands.size(); ++i) {
+ if (frame->editor()->command(commandNameForSelectorName(commands[i].commandName)).isTextInsertion())
haveTextInsertionCommands = true;
}
- if (!haveTextInsertionCommands || keyEvent->type() == PlatformKeyboardEvent::Char) {
- for (size_t i = 0; i < size; ++i) {
- if (commands[i].commandName == "insertText") {
- // Don't insert null or control characters as they can result in unexpected behaviour
- if (evt->charCode() < ' ')
- return false;
- eventWasHandled = frame->editor()->insertText(commands[i].text, evt);
- } else
- if (frame->editor()->command(commands[i].commandName).isSupported())
- eventWasHandled = frame->editor()->command(commands[i].commandName).execute(evt);
- }
+ // If there are no text insertion commands, default keydown handler is the right time to execute the commands.
+ // Keypress (Char event) handler is the latest opportunity to execute.
+ if (!haveTextInsertionCommands || platformEvent->type() == PlatformKeyboardEvent::Char) {
+ eventWasHandled = executeKeypressCommandsInternal(event->keypressCommands(), event);
+ event->keypressCommands().clear();
}
}
return eventWasHandled;
@@ -152,6 +221,54 @@ void WebPage::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdenti
}
}
+void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, EditorState& newState)
+{
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+
+ if (frame->selection()->isContentEditable()) {
+ RefPtr<Range> replacementRange;
+ if (replacementRangeStart != NSNotFound) {
+ replacementRange = convertToRange(frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart));
+ frame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
+ }
+
+ frame->editor()->setComposition(text, underlines, selectionStart, selectionEnd);
+ }
+
+ newState = editorState();
+}
+
+void WebPage::confirmComposition(EditorState& newState)
+{
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+
+ frame->editor()->confirmComposition();
+
+ newState = editorState();
+}
+
+void WebPage::insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, bool& handled, EditorState& newState)
+{
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+
+ RefPtr<Range> replacementRange;
+ if (replacementRangeStart != NSNotFound) {
+ replacementRange = convertToRange(frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart));
+ frame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY));
+ }
+
+ if (!frame->editor()->hasComposition()) {
+ // An insertText: might be handled by other responders in the chain if we don't handle it.
+ // One example is space bar that results in scrolling down the page.
+ handled = frame->editor()->insertText(text, m_keyboardEventBeingInterpreted);
+ } else {
+ handled = true;
+ frame->editor()->confirmComposition(text);
+ }
+
+ newState = editorState();
+}
+
void WebPage::getMarkedRange(uint64_t& location, uint64_t& length)
{
location = NSNotFound;
@@ -159,38 +276,59 @@ void WebPage::getMarkedRange(uint64_t& location, uint64_t& length)
Frame* frame = m_page->focusController()->focusedOrMainFrame();
if (!frame)
return;
-
- getLocationAndLengthFromRange(frame->editor()->compositionRange().get(), location, length);
-}
+ RefPtr<Range> range = frame->editor()->compositionRange();
+ size_t locationSize;
+ size_t lengthSize;
+ if (range && TextIterator::locationAndLengthFromRange(range.get(), locationSize, lengthSize)) {
+ location = static_cast<uint64_t>(locationSize);
+ length = static_cast<uint64_t>(lengthSize);
+ }
+}
-static PassRefPtr<Range> characterRangeAtPositionForPoint(Frame* frame, const VisiblePosition& position, const IntPoint& point)
+void WebPage::getSelectedRange(uint64_t& location, uint64_t& length)
{
- if (position.isNull())
- return 0;
+ location = NSNotFound;
+ length = 0;
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame)
+ return;
- VisiblePosition previous = position.previous();
- if (previous.isNotNull()) {
- RefPtr<Range> previousCharacterRange = makeRange(previous, position);
- IntRect rect = frame->editor()->firstRectForRange(previousCharacterRange.get());
- if (rect.contains(point))
- return previousCharacterRange.release();
- }
-
- VisiblePosition next = position.next();
- if (next.isNotNull()) {
- RefPtr<Range> nextCharacterRange = makeRange(position, next);
- IntRect rect = frame->editor()->firstRectForRange(nextCharacterRange.get());
- if (rect.contains(point))
- return nextCharacterRange.release();
+ size_t locationSize;
+ size_t lengthSize;
+ RefPtr<Range> range = frame->selection()->toNormalizedRange();
+ if (range && TextIterator::locationAndLengthFromRange(range.get(), locationSize, lengthSize)) {
+ location = static_cast<uint64_t>(locationSize);
+ length = static_cast<uint64_t>(lengthSize);
}
-
- return 0;
}
-static PassRefPtr<Range> characterRangeAtPoint(Frame* frame, const IntPoint& point)
+void WebPage::getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString& result)
{
- return characterRangeAtPositionForPoint(frame, frame->visiblePositionForPoint(point), point);
+ NSRange nsRange = NSMakeRange(location, length - location);
+
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame)
+ return;
+
+ if (frame->selection()->isNone() || !frame->selection()->isContentEditable() || frame->selection()->isInPasswordField())
+ return;
+
+ RefPtr<Range> range = convertToRange(frame, nsRange);
+ if (!range)
+ return;
+
+ result.string = [WebHTMLConverter editingAttributedStringFromRange:range.get()];
+ NSAttributedString* attributedString = result.string.get();
+
+ // [WebHTMLConverter editingAttributedStringFromRange:] insists on inserting a trailing
+ // whitespace at the end of the string which breaks the ATOK input method. <rdar://problem/5400551>
+ // To work around this we truncate the resultant string to the correct length.
+ if ([attributedString length] > nsRange.length) {
+ ASSERT([attributedString length] == nsRange.length + 1);
+ ASSERT([[attributedString string] characterAtIndex:nsRange.length] == '\n' || [[attributedString string] characterAtIndex:nsRange.length] == ' ');
+ result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, nsRange.length)];
+ }
}
void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index)
@@ -203,15 +341,17 @@ void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index)
HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(point, false);
frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame();
- RefPtr<Range> range = characterRangeAtPoint(frame, result.point());
+ RefPtr<Range> range = frame->rangeForPoint(result.point());
if (!range)
return;
- uint64_t length;
- getLocationAndLengthFromRange(range.get(), index, length);
+ size_t location;
+ size_t length;
+ if (TextIterator::locationAndLengthFromRange(range.get(), location, length))
+ index = static_cast<uint64_t>(location);
}
-static PassRefPtr<Range> convertToRange(Frame* frame, NSRange nsrange)
+PassRefPtr<Range> convertToRange(Frame* frame, NSRange nsrange)
{
if (nsrange.location > INT_MAX)
return 0;
@@ -246,6 +386,12 @@ void WebPage::firstRectForCharacterRange(uint64_t location, uint64_t length, Web
resultRect = frame->view()->contentsToWindow(rect);
}
+void WebPage::executeKeypressCommands(const Vector<WebCore::KeypressCommand>& commands, bool& handled, EditorState& newState)
+{
+ handled = executeKeypressCommandsInternal(commands, m_keyboardEventBeingInterpreted);
+ newState = editorState();
+}
+
static bool isPositionInRange(const VisiblePosition& position, Range* range)
{
RefPtr<Range> positionRange = makeRange(position, position);
@@ -284,12 +430,12 @@ void WebPage::performDictionaryLookupAtLocation(const FloatPoint& floatPoint)
frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame();
IntPoint translatedPoint = frame->view()->windowToContents(point);
- VisiblePosition position = frame->visiblePositionForPoint(translatedPoint);
// Don't do anything if there is no character at the point.
- if (!characterRangeAtPositionForPoint(frame, position, translatedPoint))
+ if (!frame->rangeForPoint(translatedPoint))
return;
+ VisiblePosition position = frame->visiblePositionForPoint(translatedPoint);
VisibleSelection selection = m_page->focusController()->focusedOrMainFrame()->selection()->selection();
if (shouldUseSelection(position, selection)) {
performDictionaryLookupForSelection(DictionaryPopupInfo::HotKey, frame, selection);
@@ -378,96 +524,54 @@ void WebPage::performDictionaryLookupForRange(DictionaryPopupInfo::Type type, Fr
dictionaryPopupInfo.type = type;
dictionaryPopupInfo.origin = FloatPoint(rangeRect.x(), rangeRect.y());
dictionaryPopupInfo.fontInfo.fontAttributeDictionary = fontDescriptorAttributes;
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
dictionaryPopupInfo.options = (CFDictionaryRef)options;
+#endif
send(Messages::WebPageProxy::DidPerformDictionaryLookup(rangeText, dictionaryPopupInfo));
}
-bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
+bool WebPage::performNonEditingBehaviorForSelector(const String& selector)
{
- if (keyboardEvent.type() != WebEvent::KeyDown)
- return false;
-
- // FIXME: This should be in WebCore.
-
- switch (keyboardEvent.windowsVirtualKeyCode()) {
- case VK_BACK:
- if (keyboardEvent.shiftKey())
- m_page->goForward();
- else
- m_page->goBack();
- break;
- case VK_SPACE:
- if (keyboardEvent.shiftKey())
- logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
- else
- logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
- break;
- case VK_PRIOR:
- logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
- break;
- case VK_NEXT:
- logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
- break;
- case VK_HOME:
- logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
- break;
- case VK_END:
- logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
- break;
- case VK_UP:
- if (keyboardEvent.shiftKey())
- return false;
- if (keyboardEvent.metaKey()) {
- scroll(m_page.get(), ScrollUp, ScrollByDocument);
- scroll(m_page.get(), ScrollLeft, ScrollByDocument);
- } else if (keyboardEvent.altKey() || keyboardEvent.controlKey())
- scroll(m_page.get(), ScrollUp, ScrollByPage);
- else
- scroll(m_page.get(), ScrollUp, ScrollByLine);
- break;
- case VK_DOWN:
- if (keyboardEvent.shiftKey())
- return false;
- if (keyboardEvent.metaKey()) {
- scroll(m_page.get(), ScrollDown, ScrollByDocument);
- scroll(m_page.get(), ScrollLeft, ScrollByDocument);
- } else if (keyboardEvent.altKey() || keyboardEvent.controlKey())
- scroll(m_page.get(), ScrollDown, ScrollByPage);
- else
- scroll(m_page.get(), ScrollDown, ScrollByLine);
- break;
- case VK_LEFT:
- if (keyboardEvent.shiftKey())
- return false;
- if (keyboardEvent.metaKey())
- m_page->goBack();
- else {
- if (keyboardEvent.altKey() || keyboardEvent.controlKey())
- scroll(m_page.get(), ScrollLeft, ScrollByPage);
- else
- scroll(m_page.get(), ScrollLeft, ScrollByLine);
- }
- break;
- case VK_RIGHT:
- if (keyboardEvent.shiftKey())
- return false;
- if (keyboardEvent.metaKey())
- m_page->goForward();
- else {
- if (keyboardEvent.altKey() || keyboardEvent.controlKey())
- scroll(m_page.get(), ScrollRight, ScrollByPage);
- else
- scroll(m_page.get(), ScrollRight, ScrollByLine);
- }
- break;
- default:
+ // FIXME: All these selectors have corresponding Editor commands, but the commands only work in editable content.
+ // Should such non-editing behaviors be implemented in Editor or EventHandler::defaultArrowEventHandler() perhaps?
+ if (selector == "moveUp:")
+ scroll(m_page.get(), ScrollUp, ScrollByLine);
+ else if (selector == "moveToBeginningOfParagraph:")
+ scroll(m_page.get(), ScrollUp, ScrollByPage);
+ else if (selector == "moveToBeginningOfDocument:") {
+ scroll(m_page.get(), ScrollUp, ScrollByDocument);
+ scroll(m_page.get(), ScrollLeft, ScrollByDocument);
+ } else if (selector == "moveDown:")
+ scroll(m_page.get(), ScrollDown, ScrollByLine);
+ else if (selector == "moveToEndOfParagraph:")
+ scroll(m_page.get(), ScrollDown, ScrollByPage);
+ else if (selector == "moveToEndOfDocument:") {
+ scroll(m_page.get(), ScrollDown, ScrollByDocument);
+ scroll(m_page.get(), ScrollLeft, ScrollByDocument);
+ } else if (selector == "moveLeft:")
+ scroll(m_page.get(), ScrollLeft, ScrollByLine);
+ else if (selector == "moveWordLeft:")
+ scroll(m_page.get(), ScrollLeft, ScrollByPage);
+ else if (selector == "moveToLeftEndOfLine:")
+ m_page->goBack();
+ else if (selector == "moveRight:")
+ scroll(m_page.get(), ScrollRight, ScrollByLine);
+ else if (selector == "moveWordRight:")
+ scroll(m_page.get(), ScrollRight, ScrollByPage);
+ else if (selector == "moveToRightEndOfLine:")
+ m_page->goForward();
+ else
return false;
- }
return true;
}
+bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&)
+{
+ return false;
+}
+
void WebPage::registerUIProcessAccessibilityTokens(const CoreIPC::DataReference& elementToken, const CoreIPC::DataReference& windowToken)
{
#if !defined(BUILDING_ON_SNOW_LEOPARD)
@@ -484,6 +588,10 @@ void WebPage::registerUIProcessAccessibilityTokens(const CoreIPC::DataReference&
void WebPage::writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes, bool& result)
{
Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame || frame->selection()->isNone()) {
+ result = false;
+ return;
+ }
frame->editor()->writeSelectionToPasteboard(pasteboardName, pasteboardTypes);
result = true;
}
@@ -491,6 +599,10 @@ void WebPage::writeSelectionToPasteboard(const String& pasteboardName, const Vec
void WebPage::readSelectionFromPasteboard(const String& pasteboardName, bool& result)
{
Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame || frame->selection()->isNone()) {
+ result = false;
+ return;
+ }
frame->editor()->readSelectionFromPasteboard(pasteboardName);
result = true;
}
@@ -548,10 +660,39 @@ void WebPage::setDragSource(NSObject *dragSource)
void WebPage::platformDragEnded()
{
+ // The draggedImage method releases its responder; we retain here to balance that.
+ [m_dragSource.get() retain];
// The drag source we care about here is NSFilePromiseDragSource, which doesn't look at
// the arguments. It's OK to just pass arbitrary constant values, so we just pass all zeroes.
[m_dragSource.get() draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationNone];
m_dragSource = nullptr;
}
+void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent& event, bool& result)
+{
+ result = false;
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame)
+ return;
+
+ HitTestResult hitResult = frame->eventHandler()->hitTestResultAtPoint(event.position(), true);
+ if (hitResult.isSelected())
+ result = frame->eventHandler()->eventMayStartDrag(platform(event));
+}
+
+void WebPage::acceptsFirstMouse(int eventNumber, const WebKit::WebMouseEvent& event, bool& result)
+{
+ result = false;
+ Frame* frame = m_page->focusController()->focusedOrMainFrame();
+ if (!frame)
+ return;
+
+ HitTestResult hitResult = frame->eventHandler()->hitTestResultAtPoint(event.position(), true);
+ frame->eventHandler()->setActivationEventNumber(eventNumber);
+ if (hitResult.isSelected())
+ result = frame->eventHandler()->eventMayStartDrag(platform(event));
+ else
+ result = !!hitResult.scrollbar();
+}
+
} // namespace WebKit