Commit f6768536 authored by enrica@apple.com's avatar enrica@apple.com

WebCore: Implement IME support for Mac.

<rdar://problem/7660589> WebKit2: Implement IME support for Mac.
https://bugs.webkit.org/show_bug.cgi?id=50788

Reviewed by Alexey Proskuryakov.

* dom/KeyboardEvent.h:
(WebCore::KeypressCommand::KeypressCommand): Removed ASSERT in constructor,
since it is now used for more than one command.

WebKit2: Implement IME support for Mac.
<rdar://problem/7660589> WebKit2: Implement IME support for Mac.
https://bugs.webkit.org/show_bug.cgi?id=50788
            
Reviewed by Alexey Proskuryakov.

This patch addes support for input methods in WebKit2.
In order to support IME, it was necessary to add synchronous calls from the UIProcess
to the WebProcess. These calls all have a timeout of 1 second.
The current implementation still uses the NSTextInput protocol, but the plan is to move
to the NSTextInputClient protocol. This has not been done yet for ease of comparison with
WebKit. attributedSubstringFromRange is the only method that has not been implemented, because
I have not yet decided what is the best way to send an NSAttributedString across the process
boundary.

* Platform/CoreIPC/HandleMessage.h:
(CoreIPC::callMemberFunction): Added template for member function.
with four reply arguments.
* Scripts/webkit2/messages.py: Added CompositionUnderline and relevant header.
* Shared/WebCoreArgumentCoders.h:
(CoreIPC::): Added encoder/decoder for CompositionUnderline.
* UIProcess/API/mac/PageClientImpl.h: Added parameters to interceptKeyEvent and selectionChanged.
* UIProcess/API/mac/PageClientImpl.mm:
(WebKit::PageClientImpl::selectionChanged): Added parameters.
(WebKit::PageClientImpl::interceptKeyEvent): Added parameters.
* UIProcess/API/mac/WKView.mm:
(-[WKView initWithFrame:pageNamespaceRef:pageGroupRef:]): Added initialization of new private members.
(-[WKView insertText:]):
(-[WKView _selectionChanged:isEditable:isPassword:hasMarkedText:range:]): Added parameters.
(-[WKView _interceptKeyEvent:hasComposition:start:end:lines:WebCore::]): Added parameters.
(-[WKView keyDown:]): Modified to reset state on each keyDown.
(-[WKView selectedRange]): Added.
(-[WKView hasMarkedText]): Added.
(-[WKView unmarkText]): Added.
(-[WKView validAttributesForMarkedText]): Added.
(extractUnderlines): Added.
(-[WKView setMarkedText:selectedRange:]): Added.
(-[WKView markedRange]): Added.
(-[WKView attributedSubstringFromRange:]): Added.
(-[WKView characterIndexForPoint:]): Added.
(-[WKView firstRectForCharacterRange:]): Added.
(-[WKView conversationIdentifier]): Added.
* UIProcess/API/mac/WKViewInternal.h: Added parameters to _interceptKeyEvent and _selectionChanged.
* UIProcess/PageClient.h: Added parameters to interpretKeyEvent and selectionChanged.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::getMarkedRange): Added.
(WebKit::WebPageProxy::characterIndexForPoint): Added.
(WebKit::WebPageProxy::firstRectForCharacterRange): Added.
(WebKit::WebPageProxy::interpretKeyEvent): Additional parameters.
(WebKit::WebPageProxy::didSelectionChange): Additional parameters for Mac platform.
* UIProcess/WebPageProxy.h: Added new methods and parameters to didSelectionChange
and interpretKeyEvent.
* UIProcess/WebPageProxy.messages.in: Added parameters to interpretKeyEvent and selectionChanged messages.
* UIProcess/WebProcessProxy.h:
(WebKit::WebProcessProxy::sendSync): Added support for synchronous messages.
The default timeout is 1 second.
* WebProcess/WebCoreSupport/WebEditorClient.cpp: respondToChangedSelection is now
only for non Mac platform.
* WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm:
(WebKit::WebEditorClient::respondToChangedSelection): Added implementation for Mac platform.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::didReceiveSyncMessage): Added.
* WebProcess/WebPage/WebPage.h: Added new methods and support for synchronous messages.
* WebProcess/WebPage/WebPage.messages.in: Added new messages.
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::interceptEditingKeyboardEvent): Added parameters.
(WebKit::WebPage::convertRangeToPlatformRange): Added.
(WebKit::WebPage::getMarkedRange): Added.
(WebKit::characterRangeAtPoint): Added.
(WebKit::WebPage::characterIndexForPoint): Added.
(WebKit::convertToRange): Added.
(WebKit::WebPage::firstRectForCharacterRange): Added.
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::didReceiveSyncMessage): Added.
* WebProcess/WebProcess.h: Added didReceiveSyncMessage.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@73796 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 7bd7f39d
2010-12-09 Enrica Casucci <enrica@apple.com>
Reviewed by Alexey Proskuryakov.
Implement IME support for Mac.
<rdar://problem/7660589> WebKit2: Implement IME support for Mac.
https://bugs.webkit.org/show_bug.cgi?id=50788
* dom/KeyboardEvent.h:
(WebCore::KeypressCommand::KeypressCommand): Removed ASSERT in constructor,
since it is now used for more than one command.
2010-12-10 Jessie Berlin <jberlin@apple.com>
Windows build fix. Unreviewed.
......
......@@ -35,7 +35,7 @@ namespace WebCore {
struct KeypressCommand {
KeypressCommand() { }
KeypressCommand(const String& commandName) : commandName(commandName) { }
KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { ASSERT(commandName == "insertText:" || commandName == "insertText"); }
KeypressCommand(const String& commandName, const String& text) : commandName(commandName), text(text) { }
String commandName;
String text;
......
2010-12-09 Enrica Casucci <enrica@apple.com>
Reviewed by Alexey Proskuryakov.
Implement IME support for Mac.
<rdar://problem/7660589> WebKit2: Implement IME support for Mac.
https://bugs.webkit.org/show_bug.cgi?id=50788
This patch addes support for input methods in WebKit2.
In order to support IME, it was necessary to add synchronous calls from the UIProcess
to the WebProcess. These calls all have a timeout of 1 second.
The current implementation still uses the NSTextInput protocol, but the plan is to move
to the NSTextInputClient protocol. This has not been done yet for ease of comparison with
WebKit. attributedSubstringFromRange is the only method that has not been implemented, because
I have not yet decided what is the best way to send an NSAttributedString across the process
boundary.
* Platform/CoreIPC/HandleMessage.h:
(CoreIPC::callMemberFunction): Added template for member function.
with four reply arguments.
* Scripts/webkit2/messages.py: Added CompositionUnderline and relevant header.
* Shared/WebCoreArgumentCoders.h:
(CoreIPC::): Added encoder/decoder for CompositionUnderline.
* UIProcess/API/mac/PageClientImpl.h: Added parameters to interceptKeyEvent and selectionChanged.
* UIProcess/API/mac/PageClientImpl.mm:
(WebKit::PageClientImpl::selectionChanged): Added parameters.
(WebKit::PageClientImpl::interceptKeyEvent): Added parameters.
* UIProcess/API/mac/WKView.mm:
(-[WKView initWithFrame:pageNamespaceRef:pageGroupRef:]): Added initialization of new private members.
(-[WKView insertText:]):
(-[WKView _selectionChanged:isEditable:isPassword:hasMarkedText:range:]): Added parameters.
(-[WKView _interceptKeyEvent:hasComposition:start:end:lines:WebCore::]): Added parameters.
(-[WKView keyDown:]): Modified to reset state on each keyDown.
(-[WKView selectedRange]): Added.
(-[WKView hasMarkedText]): Added.
(-[WKView unmarkText]): Added.
(-[WKView validAttributesForMarkedText]): Added.
(extractUnderlines): Added.
(-[WKView setMarkedText:selectedRange:]): Added.
(-[WKView markedRange]): Added.
(-[WKView attributedSubstringFromRange:]): Added.
(-[WKView characterIndexForPoint:]): Added.
(-[WKView firstRectForCharacterRange:]): Added.
(-[WKView conversationIdentifier]): Added.
* UIProcess/API/mac/WKViewInternal.h: Added parameters to _interceptKeyEvent and _selectionChanged.
* UIProcess/PageClient.h: Added parameters to interpretKeyEvent and selectionChanged.
* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::getMarkedRange): Added.
(WebKit::WebPageProxy::characterIndexForPoint): Added.
(WebKit::WebPageProxy::firstRectForCharacterRange): Added.
(WebKit::WebPageProxy::interpretKeyEvent): Additional parameters.
(WebKit::WebPageProxy::didSelectionChange): Additional parameters for Mac platform.
* UIProcess/WebPageProxy.h: Added new methods and parameters to didSelectionChange
and interpretKeyEvent.
* UIProcess/WebPageProxy.messages.in: Added parameters to interpretKeyEvent and selectionChanged messages.
* UIProcess/WebProcessProxy.h:
(WebKit::WebProcessProxy::sendSync): Added support for synchronous messages.
The default timeout is 1 second.
* WebProcess/WebCoreSupport/WebEditorClient.cpp: respondToChangedSelection is now
only for non Mac platform.
* WebProcess/WebCoreSupport/mac/WebEditorClientMac.mm:
(WebKit::WebEditorClient::respondToChangedSelection): Added implementation for Mac platform.
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::didReceiveSyncMessage): Added.
* WebProcess/WebPage/WebPage.h: Added new methods and support for synchronous messages.
* WebProcess/WebPage/WebPage.messages.in: Added new messages.
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::interceptEditingKeyboardEvent): Added parameters.
(WebKit::WebPage::convertRangeToPlatformRange): Added.
(WebKit::WebPage::getMarkedRange): Added.
(WebKit::characterRangeAtPoint): Added.
(WebKit::WebPage::characterIndexForPoint): Added.
(WebKit::convertToRange): Added.
(WebKit::WebPage::firstRectForCharacterRange): Added.
* WebProcess/WebProcess.cpp:
(WebKit::WebProcess::didReceiveSyncMessage): Added.
* WebProcess/WebProcess.h: Added didReceiveSyncMessage.
2010-12-10 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
Reviewed by Kenneth Rohde Christiansen.
......@@ -103,6 +103,12 @@ void callMemberFunction(const Arguments2<P1, P2>& args, Arguments0&, C* object,
(object->*function)(args.argument1, args.argument2);
}
template<typename C, typename MF, typename P1, typename R1, typename R2, typename R3, typename R4>
void callMemberFunction(const Arguments1<P1>& args, Arguments4<R1, R2, R3, R4>& replyArgs, C* object, MF function)
{
(object->*function)(args.argument1, replyArgs.argument1, replyArgs.argument2, replyArgs.argument3, replyArgs.argument4);
}
template<typename C, typename MF, typename P1, typename P2, typename R1>
void callMemberFunction(const Arguments2<P1, P2>& args, Arguments1<R1>& replyArgs, C* object, MF function)
{
......
......@@ -29,6 +29,7 @@
WTFLogChannel LogSessionState = { 0x00000001, "WebKit2LogLevel", WTFLogChannelOn };
WTFLogChannel LogContextMenu = { 0x00000002, "WebKit2LogLevel", WTFLogChannelOn };
WTFLogChannel LogTextInput = { 0x00000003, "WebKit2LogLevel", WTFLogChannelOn };
static inline void initializeLogChannel(WTFLogChannel* channel)
{
......
......@@ -38,6 +38,7 @@ EXTERN_C_BEGIN
extern WTFLogChannel LogContextMenu;
extern WTFLogChannel LogSessionState;
extern WTFLogChannel LogTextInput;
void initializeLogChannelsIfNecessary(void);
......
......@@ -250,6 +250,7 @@ def message_to_struct_declaration(message):
def struct_or_class(namespace, type):
structs = frozenset([
'WebCore::KeypressCommand',
'WebCore::CompositionUnderline',
'WebCore::PluginInfo',
'WebCore::ViewportArguments',
'WebCore::WindowFeatures',
......@@ -412,6 +413,7 @@ def headers_for_type(type):
'WTF::String': '<wtf/text/WTFString.h>',
'WebCore::KeypressCommand': '<WebCore/KeyboardEvent.h>',
'WebCore::PluginInfo': '<WebCore/PluginData.h>',
'WebCore::CompositionUnderline': '<WebCore/Editor.h>',
'WebKit::WebKeyboardEvent': '"WebEvent.h"',
'WebKit::WebMouseEvent': '"WebEvent.h"',
'WebKit::WebWheelEvent': '"WebEvent.h"',
......
......@@ -33,6 +33,7 @@
#include <WebCore/AuthenticationChallenge.h>
#include <WebCore/Credential.h>
#include <WebCore/Cursor.h>
#include <WebCore/Editor.h>
#include <WebCore/FloatRect.h>
#include <WebCore/IntRect.h>
#include <WebCore/KeyboardEvent.h>
......@@ -327,6 +328,22 @@ template<> struct ArgumentCoder<WebCore::KeypressCommand> {
}
};
#endif
template<> struct ArgumentCoder<WebCore::CompositionUnderline> {
static void encode(ArgumentEncoder* encoder, const WebCore::CompositionUnderline& underline)
{
encoder->encode(CoreIPC::In(underline.startOffset, underline.endOffset, underline.thick, underline.color.rgb()));
}
static bool decode(ArgumentDecoder* decoder, WebCore::CompositionUnderline& underline)
{
uint32_t rgb;
if (!decoder->decode(CoreIPC::Out(underline.startOffset, underline.endOffset, underline.thick, rgb)))
return false;
underline.color = rgb;
return true;
}
};
} // namespace CoreIPC
......
......@@ -58,13 +58,13 @@ private:
virtual void registerEditCommand(PassRefPtr<WebEditCommandProxy>, WebPageProxy::UndoOrRedo);
virtual void clearAllEditCommands();
virtual void setEditCommandState(const String& commandName, bool isEnabled, int state);
virtual void interceptKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commandName);
virtual void interceptKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commandName, uint32_t selectionStart, uint32_t selectionEnd, Vector<WebCore::CompositionUnderline>& underlines);
virtual WebCore::FloatRect convertToDeviceSpace(const WebCore::FloatRect&);
virtual WebCore::FloatRect convertToUserSpace(const WebCore::FloatRect&);
virtual void didNotHandleKeyEvent(const NativeWebKeyboardEvent&);
virtual void selectionChanged(bool, bool, bool, bool);
virtual void selectionChanged(bool, bool, bool, bool, uint64_t, uint64_t);
virtual PassRefPtr<WebPopupMenuProxy> createPopupMenuProxy();
virtual PassRefPtr<WebContextMenuProxy> createContextMenuProxy(WebPageProxy*);
......
......@@ -147,9 +147,9 @@ void PageClientImpl::setViewportArguments(const WebCore::ViewportArguments&)
}
void PageClientImpl::selectionChanged(bool isNone, bool isContentEditable, bool isPasswordField, bool hasComposition)
void PageClientImpl::selectionChanged(bool isNone, bool isContentEditable, bool isPasswordField, bool hasComposition, uint64_t location, uint64_t length)
{
[m_wkView _selectionChanged:isNone isEditable:isContentEditable isPassword:isPasswordField hasMarkedText:hasComposition];
[m_wkView _selectionChanged:isNone isEditable:isContentEditable isPassword:isPasswordField hasMarkedText:hasComposition range:NSMakeRange(location, length)];
}
static NSString* nameForEditAction(EditAction editAction)
......@@ -222,9 +222,10 @@ void PageClientImpl::setEditCommandState(const String& commandName, bool isEnabl
[m_wkView _setUserInterfaceItemState:nsStringFromWebCoreString(commandName) enabled:isEnabled state:newState];
}
void PageClientImpl::interceptKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commandsList)
void PageClientImpl::interceptKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commandsList, uint32_t selectionStart, uint32_t selectionEnd, Vector<WebCore::CompositionUnderline>& underlines)
{
commandsList = [m_wkView _interceptKeyEvent:event.nativeEvent()];
[m_wkView _getTextInputState:selectionStart selectionEnd:selectionEnd underlines:underlines];
}
FloatRect PageClientImpl::convertToDeviceSpace(const FloatRect& rect)
......
This diff is collapsed.
......@@ -24,6 +24,7 @@
*/
#import "WKView.h"
#import <WebCore/Editor.h>
#import <WebCore/KeyboardEvent.h>
namespace WebKit {
......@@ -38,10 +39,11 @@ namespace WebKit {
- (void)_setCursor:(NSCursor *)cursor;
- (void)_setUserInterfaceItemState:(NSString *)commandName enabled:(BOOL)isEnabled state:(int)newState;
- (Vector<WebCore::KeypressCommand>&)_interceptKeyEvent:(NSEvent *)theEvent;
- (void)_getTextInputState:(unsigned)start selectionEnd:(unsigned)end underlines:(Vector<WebCore::CompositionUnderline>&)lines;
- (void)_setEventBeingResent:(NSEvent *)event;
- (NSRect)_convertToDeviceSpace:(NSRect)rect;
- (NSRect)_convertToUserSpace:(NSRect)rect;
- (void)_selectionChanged:(BOOL)isNone isEditable:(BOOL)isContentEditable isPassword:(BOOL)isPasswordField hasMarkedText:(BOOL)hasComposition;
- (void)_selectionChanged:(BOOL)isNone isEditable:(BOOL)isContentEditable isPassword:(BOOL)isPasswordField hasMarkedText:(BOOL)hasComposition range:(NSRange)newrange;
- (void)_setFindIndicator:(PassRefPtr<WebKit::FindIndicator>)findIndicator fadeOut:(BOOL)fadeOut;
......
......@@ -69,13 +69,15 @@ public:
virtual void clearAllEditCommands() = 0;
virtual void setEditCommandState(const String& commandName, bool isEnabled, int state) = 0;
#if PLATFORM(MAC)
virtual void interceptKeyEvent(const NativeWebKeyboardEvent&, Vector<WebCore::KeypressCommand>&) = 0;
virtual void interceptKeyEvent(const NativeWebKeyboardEvent&, Vector<WebCore::KeypressCommand>&, uint32_t, uint32_t, Vector<WebCore::CompositionUnderline>&) = 0;
virtual void selectionChanged(bool, bool, bool, bool, uint64_t, uint64_t) = 0;
#else
virtual void selectionChanged(bool, bool, bool, bool) = 0;
#endif
virtual WebCore::FloatRect convertToDeviceSpace(const WebCore::FloatRect&) = 0;
virtual WebCore::FloatRect convertToUserSpace(const WebCore::FloatRect&) = 0;
virtual void didNotHandleKeyEvent(const NativeWebKeyboardEvent&) = 0;
virtual void selectionChanged(bool, bool, bool, bool) = 0;
virtual PassRefPtr<WebPopupMenuProxy> createPopupMenuProxy() = 0;
virtual PassRefPtr<WebContextMenuProxy> createContextMenuProxy(WebPageProxy*) = 0;
......
......@@ -486,6 +486,25 @@ void WebPageProxy::windowAndViewFramesChanged(const IntRect& windowFrameInScreen
process()->send(Messages::WebPage::WindowAndViewFramesChanged(windowFrameInScreenCoordinates, viewFrameInWindowCoordinates), m_pageID);
}
void WebPageProxy::getMarkedRange(uint64_t& location, uint64_t& length)
{
process()->sendSync(Messages::WebPage::GetMarkedRange(), Messages::WebPage::GetMarkedRange::Reply(location, length), m_pageID);
}
uint64_t WebPageProxy::characterIndexForPoint(const IntPoint point)
{
uint64_t result;
process()->sendSync(Messages::WebPage::CharacterIndexForPoint(point), Messages::WebPage::CharacterIndexForPoint::Reply(result), m_pageID);
return result;
}
WebCore::IntRect WebPageProxy::firstRectForCharacterRange(uint64_t location, uint64_t length)
{
IntRect resultRect;
process()->sendSync(Messages::WebPage::FirstRectForCharacterRange(location, length), Messages::WebPage::FirstRectForCharacterRange::Reply(resultRect), m_pageID);
return resultRect;
}
#endif
#if ENABLE(TILED_BACKING_STORE)
......@@ -751,9 +770,9 @@ void WebPageProxy::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIP
}
#if PLATFORM(MAC)
void WebPageProxy::interpretKeyEvent(uint32_t type, Vector<KeypressCommand>& commandsList)
void WebPageProxy::interpretKeyEvent(uint32_t type, Vector<KeypressCommand>& commandsList, uint32_t selectionStart, uint32_t selectionEnd, Vector<CompositionUnderline>& underlines)
{
m_pageClient->interceptKeyEvent(m_keyEventQueue.first(), commandsList);
m_pageClient->interceptKeyEvent(m_keyEventQueue.first(), commandsList, selectionStart, selectionEnd, underlines);
}
#endif
......@@ -1258,10 +1277,17 @@ void WebPageProxy::backForwardForwardListCount(int32_t& count)
}
// Selection change support
#if PLATFORM(MAC)
void WebPageProxy::didSelectionChange(bool isNone, bool isContentEditable, bool isPasswordField, bool hasComposition, uint64_t location, uint64_t length)
{
m_pageClient->selectionChanged(isNone, isContentEditable, isPasswordField, hasComposition, location, length);
}
#else
void WebPageProxy::didSelectionChange(bool isNone, bool isContentEditable, bool isPasswordField, bool hasComposition)
{
m_pageClient->selectionChanged(isNone, isContentEditable, isPasswordField, hasComposition);
}
#endif
// Undo management
......
......@@ -44,6 +44,7 @@
#include "WebPolicyClient.h"
#include "WebUIClient.h"
#include <WebCore/EditAction.h>
#include <WebCore/Editor.h>
#include <WebCore/FrameLoaderTypes.h>
#include <WebCore/KeyboardEvent.h>
#include <wtf/HashMap.h>
......@@ -176,6 +177,12 @@ public:
#if PLATFORM(MAC)
void updateWindowIsVisible(bool windowIsVisible);
void windowAndViewFramesChanged(const WebCore::IntRect& windowFrameInScreenCoordinates, const WebCore::IntRect& viewFrameInWindowCoordinates);
void getMarkedRange(uint64_t& location, uint64_t& length);
uint64_t characterIndexForPoint(const WebCore::IntPoint);
WebCore::IntRect firstRectForCharacterRange(uint64_t, uint64_t);
void didSelectionChange(bool, bool, bool, bool, uint64_t, uint64_t);
#else
void didSelectionChange(bool, bool, bool, bool);
#endif
#if ENABLE(TILED_BACKING_STORE)
......@@ -242,7 +249,6 @@ public:
void addEditCommand(WebEditCommandProxy*);
void removeEditCommand(WebEditCommandProxy*);
void registerEditCommand(PassRefPtr<WebEditCommandProxy>, UndoOrRedo);
void didSelectionChange(bool, bool, bool, bool);
WebProcessProxy* process() const;
WebPageNamespace* pageNamespace() const { return m_pageNamespace.get(); }
......@@ -353,7 +359,7 @@ private:
#if PLATFORM(MAC)
// Keyboard handling
void interpretKeyEvent(uint32_t eventType, Vector<WebCore::KeypressCommand>&);
void interpretKeyEvent(uint32_t eventType, Vector<WebCore::KeypressCommand>&, uint32_t selectionStart, uint32_t selectionEnd, Vector<WebCore::CompositionUnderline>& underlines);
#endif
// Find.
......
......@@ -104,7 +104,7 @@ messages -> WebPageProxy {
#if PLATFORM(MAC)
# Keyboard support
InterpretKeyEvent(uint32_t type) -> (Vector<WebCore::KeypressCommand> commandName)
InterpretKeyEvent(uint32_t type) -> (Vector<WebCore::KeypressCommand> commandName, uint32_t selectionStart, uint32_t selectionEnd, Vector<WebCore::CompositionUnderline> underlines)
#endif
# BackForward messages.
......@@ -120,7 +120,12 @@ messages -> WebPageProxy {
ClearAllEditCommands()
# Selection messages.
#if PLATFORM(MAC)
DidSelectionChange(bool isNone, bool isContentEditable, bool isPasswordField, bool hasComposition, uint64_t location, uint64_t length)
#endif
#if !PLATFORM(MAC)
DidSelectionChange(bool isNone, bool isContentEditable, bool isPasswordField, bool hasComposition)
#endif
# Find.
DidCountStringMatches(WTF::String string, uint32_t matchCount)
......
......@@ -65,6 +65,7 @@ public:
template<typename E, typename T> bool send(E messageID, uint64_t destinationID, const T& arguments);
template<typename T> bool send(const T& message, uint64_t destinationID);
template<typename U> bool sendSync(const U& message, const typename U::Reply& reply, uint64_t destinationID, double timeout);
CoreIPC::Connection* connection() const
{
......@@ -170,6 +171,12 @@ bool WebProcessProxy::send(const T& message, uint64_t destinationID)
return sendMessage(CoreIPC::MessageID(T::messageID), argumentEncoder.release());
}
template<typename U>
bool WebProcessProxy::sendSync(const U& message, const typename U::Reply& reply, uint64_t destinationID, double timeout = 1)
{
return m_connection->sendSync(message, reply, destinationID, timeout);
}
} // namespace WebKit
#endif // WebProcessProxy_h
......@@ -178,6 +178,7 @@ void WebEditorClient::respondToChangedContents()
notImplemented();
}
#if !PLATFORM(MAC)
void WebEditorClient::respondToChangedSelection()
{
static const String WebViewDidChangeSelectionNotification = "WebViewDidChangeSelectionNotification";
......@@ -187,7 +188,8 @@ void WebEditorClient::respondToChangedSelection()
return;
m_page->send(Messages::WebPageProxy::DidSelectionChange(frame->selection()->isNone(), frame->selection()->isContentEditable(), frame->selection()->isInPasswordField(), frame->editor()->hasComposition()));
}
#endif
void WebEditorClient::didEndEditing()
{
static const String WebViewDidEndEditingNotification = "WebViewDidEndEditingNotification";
......
......@@ -40,8 +40,10 @@
#include <WebCore/DocumentFragment.h>
#include <WebCore/DOMDocumentFragmentInternal.h>
#include <WebCore/DOMDocumentInternal.h>
#include <WebCore/FocusController.h>
#include <WebCore/Frame.h>
#include <WebCore/KeyboardEvent.h>
#include <WebCore/Page.h>
#include <WebKit/WebResource.h>
#include <WebKit/WebNSURLExtras.h>
#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
......@@ -61,6 +63,19 @@ using namespace WTF;
namespace WebKit {
void WebEditorClient::respondToChangedSelection()
{
static const String WebViewDidChangeSelectionNotification = "WebViewDidChangeSelectionNotification";
m_page->injectedBundleEditorClient().didChangeSelection(m_page, WebViewDidChangeSelectionNotification.impl());
WebCore::Frame* frame = m_page->corePage()->focusController()->focusedFrame();
if (!frame)
return;
uint64_t location;
uint64_t length;
WebPage::convertRangeToPlatformRange(frame, frame->selection()->toNormalizedRange().get(), location, length);
m_page->send(Messages::WebPageProxy::DidSelectionChange(frame->selection()->isNone(), frame->selection()->isContentEditable(), frame->selection()->isInPasswordField(), frame->editor()->hasComposition(), location, length));
}
void WebEditorClient::handleKeyboardEvent(KeyboardEvent* event)
{
if (m_page->interceptEditingKeyboardEvent(event, false))
......
......@@ -1162,6 +1162,11 @@ void WebPage::didReceiveMessage(CoreIPC::Connection* connection, CoreIPC::Messag
didReceiveWebPageMessage(connection, messageID, arguments);
}
CoreIPC::SyncReplyMode WebPage::didReceiveSyncMessage(CoreIPC::Connection* connection, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments, CoreIPC::ArgumentEncoder* reply)
{
return didReceiveSyncWebPageMessage(connection, messageID, arguments, reply);
}
InjectedBundleBackForwardList* WebPage::backForwardList()
{
if (!m_backForwardList)
......
......@@ -139,6 +139,7 @@ public:
// -- Called from WebProcess.
void didReceiveMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*);
CoreIPC::SyncReplyMode didReceiveSyncMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*, CoreIPC::ArgumentEncoder*);
// -- InjectedBundle methods
void initializeInjectedBundleContextMenuClient(WKBundlePageContextMenuClient*);
......@@ -238,7 +239,13 @@ public:
};
SandboxExtensionTracker& sandboxExtensionTracker() { return m_sandboxExtensionTracker; }
#if PLATFORM(MAC)
void getMarkedRange(uint64_t& location, uint64_t& length);
void characterIndexForPoint(const WebCore::IntPoint point, uint64_t& result);
void firstRectForCharacterRange(uint64_t location, uint64_t length, WebCore::IntRect& resultRect);
static void convertRangeToPlatformRange(WebCore::Frame* frame, WebCore::Range *range, uint64_t& location, uint64_t& length);
#endif
private:
WebPage(uint64_t pageID, const WebPageCreationParameters&);
......@@ -247,6 +254,7 @@ private:
void platformInitialize();
void didReceiveWebPageMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*);
CoreIPC::SyncReplyMode didReceiveSyncWebPageMessage(CoreIPC::Connection*, CoreIPC::MessageID, CoreIPC::ArgumentDecoder*, CoreIPC::ArgumentEncoder*);
static const char* interpretKeyEvent(const WebCore::KeyboardEvent*);
bool performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&);
......
......@@ -96,6 +96,9 @@ messages -> WebPage {
#if PLATFORM(MAC)
SetWindowIsVisible(bool windowIsVisible)
WindowAndViewFramesChanged(WebCore::IntRect windowFrameInScreenCoordinates, WebCore::IntRect viewFrameInWindowCoordinates)
GetMarkedRange() -> (uint64_t location, uint64_t length)
CharacterIndexForPoint(WebCore::IntPoint point) -> (uint64_t result)
FirstRectForCharacterRange(uint64_t location, uint64_t length) -> (WebCore::IntRect resultRect)
#endif
#if PLATFORM(QT)
......
......@@ -33,9 +33,13 @@
#include <WebCore/DocumentLoader.h>
#include <WebCore/FocusController.h>
#include <WebCore/Frame.h>
#include <WebCore/FrameView.h>
#include <WebCore/HitTestResult.h>
#include <WebCore/KeyboardEvent.h>
#include <WebCore/Page.h>
#include <WebCore/PlatformKeyboardEvent.h>
#include <WebCore/ScrollView.h>
#include <WebCore/TextIterator.h>
#include <WebCore/WindowsKeyboardCodes.h>
using namespace WebCore;
......@@ -68,12 +72,31 @@ bool WebPage::interceptEditingKeyboardEvent(KeyboardEvent* evt, bool shouldSaveC
bool eventWasHandled = false;
if (shouldSaveCommand && !hasKeypressCommand) {
Vector<KeypressCommand> commandsList;
if (!WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretKeyEvent(keyEvent->type()), Messages::WebPageProxy::InterpretKeyEvent::Reply(commandsList), m_pageID))
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))
return false;
for (size_t i = 0; i < commandsList.size(); i++)
evt->keypressCommands().append(commandsList[i]);
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?
......@@ -101,6 +124,120 @@ bool WebPage::interceptEditingKeyboardEvent(KeyboardEvent* evt, bool shouldSaveC
return eventWasHandled;
}
void WebPage::convertRangeToPlatformRange(WebCore::Frame* frame, WebCore::Range *range, uint64_t& location, uint64_t& length)
{
location = NSNotFound;
length = 0;
if (!range || !range->startContainer())
return;
Element* selectionRoot = frame->selection()->rootEditableElement();
Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement();
// Mouse events may cause TSM to attempt to create an NSRange for a portion of the view
// that is not inside the current editable region. These checks ensure we don't produce
// potentially invalid data when responding to such requests.
if (range->startContainer() != scope && !range->startContainer()->isDescendantOf(scope))
return;
if (range->endContainer() != scope && !range->endContainer()->isDescendantOf(scope))
return;
RefPtr<Range> testRange = Range::create(scope->document(), scope, 0, range->startContainer(), range->startOffset());
ASSERT(testRange->startContainer() == scope);
location = TextIterator::rangeLength(testRange.get());
ExceptionCode ec;
testRange->setEnd(range->endContainer(), range->endOffset(), ec);
ASSERT(testRange->startContainer() == scope);
length = TextIterator::rangeLength(testRange.get()) - location;
}
void WebPage::getMarkedRange(uint64_t& location, uint64_t& length)
{
location = NSNotFound;
length = 0;
Frame* frame = m_page->focusController()->focusedOrMainFrame();
if (!frame)
return;
convertRangeToPlatformRange(frame, frame->editor()->compositionRange().get(), location, length);
}
static Range *characterRangeAtPoint(Frame* frame, const IntPoint point)
{
VisiblePosition position = frame->visiblePositionForPoint(point);
if (position.isNull())
return NULL;
VisiblePosition previous = position.previous();
if (previous.isNotNull()) {
Range *previousCharacterRange = makeRange(previous, position).get();
NSRect rect = frame->editor()->firstRectForRange(previousCharacterRange);
if (NSPointInRect(point, rect))