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)
......
......@@ -33,6 +33,7 @@
#import "FindIndicator.h"
#import "FindIndicatorWindow.h"
#import "LayerBackedDrawingAreaProxy.h"
#import "Logging.h"
#import "NativeWebKeyboardEvent.h"
#import "PDFViewController.h"
#import "PageClientImpl.h"
......@@ -46,6 +47,7 @@
#import "WebProcessProxy.h"
#import "WebSystemInterface.h"
#import <QuartzCore/QuartzCore.h>
#import <WebCore/ColorMac.h>
#import <WebCore/FloatRect.h>
#import <WebCore/IntRect.h>
#import <WebCore/KeyboardEvent.h>
......@@ -105,16 +107,26 @@ struct EditCommandState {
// that has been already sent to WebCore.
NSEvent *_keyDownEventBeingResent;
Vector<KeypressCommand> _commandsList;
BOOL _isSelectionNone;
BOOL _isSelectionEditable;
BOOL _isSelectionInPasswordField;
BOOL _hasMarkedText;
Vector<CompositionUnderline> _underlines;
unsigned _selectionStart;
unsigned _selectionEnd;
NSRange _selectedRange;
}
@end
@implementation WKViewData
@end
@interface NSObject (NSTextInputContextDetails)
- (BOOL)wantsToHandleMouseEvents;
- (BOOL)handleMouseEvent:(NSEvent *)event;
@end
@implementation WKView
- (id)initWithFrame:(NSRect)frame pageNamespaceRef:(WKPageNamespaceRef)pageNamespaceRef pageGroupRef:(WKPageGroupRef)pageGroupRef
......@@ -144,10 +156,12 @@ struct EditCommandState {
_data->_menuEntriesCount = 0;
_data->_isPerformingUpdate = false;
_data->_isSelectionNone = YES;
_data->_isSelectionEditable = NO;
_data->_isSelectionInPasswordField = NO;
_data->_hasMarkedText = NO;
_data->_selectedRange = NSMakeRange(NSNotFound, 0);
return self;
}
......@@ -344,12 +358,9 @@ WEBCORE_COMMAND(takeFindStringFromSelection)
_data->_page->handle##Type##Event(webEvent); \
}
EVENT_HANDLER(mouseDown, Mouse)
EVENT_HANDLER(mouseDragged, Mouse)
EVENT_HANDLER(mouseEntered, Mouse)
EVENT_HANDLER(mouseExited, Mouse)
EVENT_HANDLER(mouseMoved, Mouse)
EVENT_HANDLER(mouseUp, Mouse)
EVENT_HANDLER(otherMouseDown, Mouse)
EVENT_HANDLER(otherMouseDragged, Mouse)
EVENT_HANDLER(otherMouseMoved, Mouse)
......@@ -362,6 +373,22 @@ EVENT_HANDLER(scrollWheel, Wheel)
#undef EVENT_HANDLER
#define MOUSE_EVENT_HANDLER(Selector) \
- (void)Selector:(NSEvent *)theEvent \
{ \
NSInputManager *currentInputManager = [NSInputManager currentInputManager]; \
if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:theEvent]) \
return; \
WebMouseEvent webEvent = WebEventFactory::createWebMouseEvent(theEvent, self); \
_data->_page->handleMouseEvent(webEvent); \
}
MOUSE_EVENT_HANDLER(mouseDown)
MOUSE_EVENT_HANDLER(mouseDragged)
MOUSE_EVENT_HANDLER(mouseUp)
#undef MOUSE_EVENT_HANDLER
- (void)doCommandBySelector:(SEL)selector
{
if (selector != @selector(noop:))
......@@ -370,7 +397,33 @@ EVENT_HANDLER(scrollWheel, Wheel)
- (void)insertText:(id)string
{
_data->_commandsList.append(KeypressCommand("insertText", string));
BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string);
NSString *text;
bool isFromInputMethod = _data->_hasMarkedText;
if (isAttributedString) {
text = [string string];
// We deal with the NSTextInputReplacementRangeAttributeName attribute from NSAttributedString here
// simply because it is used by at least one Input Method -- it corresonds to the kEventParamTextInputSendReplaceRange
// event in TSM. This behaviour matches that of -[WebHTMLView setMarkedText:selectedRange:] when it receives an
// NSAttributedString
NSString *rangeString = [string attribute:NSTextInputReplacementRangeAttributeName atIndex:0 longestEffectiveRange:NULL inRange:NSMakeRange(0, [text length])];
LOG(TextInput, "ReplacementRange: %@", rangeString);
if (rangeString)
isFromInputMethod = YES;
} else
text = string;
String eventText = text;
if (!isFromInputMethod)
_data->_commandsList.append(KeypressCommand("insertText", text));
else {
eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
_data->_commandsList.append(KeypressCommand("insertText", eventText));
}
}
- (BOOL)_handleStyleKeyEquivalent:(NSEvent *)event
......@@ -432,24 +485,31 @@ EVENT_HANDLER(scrollWheel, Wheel)
_data->_keyDownEventBeingResent = [event retain];
}
- (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
{
_data->_isSelectionNone = isNone;
_data->_isSelectionEditable = isContentEditable;
_data->_isSelectionInPasswordField = isPasswordField;
_data->_hasMarkedText = hasComposition;
_data->_selectedRange = newrange;
}
- (Vector<KeypressCommand>&)_interceptKeyEvent:(NSEvent *)theEvent
- (Vector<KeypressCommand>&)_interceptKeyEvent:(NSEvent *)theEvent
{
_data->_commandsList.clear();
// interpretKeyEvents will trigger one or more calls to doCommandBySelector or setText
// that will populate the commandsList vector.
[self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
return _data->_commandsList;
}
- (void)_getTextInputState:(unsigned)start selectionEnd:(unsigned)end underlines:(Vector<WebCore::CompositionUnderline>&)lines
{
start = _data->_selectionStart;
end = _data->_selectionEnd;
lines = _data->_underlines;
}
- (void)keyUp:(NSEvent *)theEvent
{
_data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self));
......@@ -457,6 +517,9 @@ EVENT_HANDLER(scrollWheel, Wheel)
- (void)keyDown:(NSEvent *)theEvent
{
_data->_underlines.clear();
_data->_selectionStart = 0;
_data->_selectionEnd = 0;
// We could be receiving a key down from AppKit if we have re-sent an event
// that maps to an action that is currently unavailable (for example a copy when
// there is no range selection).
......@@ -472,17 +535,24 @@ EVENT_HANDLER(scrollWheel, Wheel)
- (NSRange)selectedRange
{
return NSMakeRange(NSNotFound, 0);
if (_data->_isSelectionNone || !_data->_isSelectionEditable)
return NSMakeRange(NSNotFound, 0);
LOG(TextInput, "selectedRange -> (%u, %u)", _data->_selectedRange.location, _data->_selectedRange.length);
return _data->_selectedRange;
}
- (BOOL)hasMarkedText
{
LOG(TextInput, "hasMarkedText -> %u", _data-> _hasMarkedText);
return _data->_hasMarkedText;
}
- (void)unmarkText
{
// Not implemented
LOG(TextInput, "unmarkText");
_data->_commandsList.append(KeypressCommand("unmarkText"));
}
- (NSArray *)validAttributesForMarkedText
......@@ -499,41 +569,95 @@ EVENT_HANDLER(scrollWheel, Wheel)
// NSBackgroundColorAttributeName, NSLanguageAttributeName.
CFRetain(validAttributes);
}
LOG(TextInput, "validAttributesForMarkedText -> (...)");
return validAttributes;
}
static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnderline>& result)
{
int length = [[string string] length];
int i = 0;
while (i < length) {
NSRange range;
NSDictionary *attrs = [string attributesAtIndex:i longestEffectiveRange:&range inRange:NSMakeRange(i, length - i)];
if (NSNumber *style = [attrs objectForKey:NSUnderlineStyleAttributeName]) {
Color color = Color::black;
if (NSColor *colorAttr = [attrs objectForKey:NSUnderlineColorAttributeName])
color = colorFromNSColor([colorAttr colorUsingColorSpaceName:NSDeviceRGBColorSpace]);
result.append(CompositionUnderline(range.location, NSMaxRange(range), color, [style intValue] > 1));
}
i = range.location + range.length;
}
}
- (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange
{
// Not implemented
BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
LOG(TextInput, "setMarkedText:\"%@\" selectedRange:(%u, %u)", isAttributedString ? [string string] : string, newSelRange.location, newSelRange.length);
NSString *text = string;
if (isAttributedString) {
text = [string string];
extractUnderlines(string, _data->_underlines);
}
_data->_commandsList.append(KeypressCommand("setMarkedText", text));
_data->_selectionStart = newSelRange.location;
_data->_selectionEnd = NSMaxRange(newSelRange);
}
- (NSRange)markedRange
{
// Not implemented
return NSMakeRange(0, 0);
uint64_t location;
uint64_t length;
_data->_page->getMarkedRange(location, length);
LOG(TextInput, "markedRange -> (%u, %u)", location, length);
return NSMakeRange(location, length);
}
- (NSAttributedString *)attributedSubstringFromRange:(NSRange)nsRange
{
// Not implemented
// This is not implemented for now. Need to figure out how to serialize the attributed string across processes.
LOG(TextInput, "attributedSubstringFromRange");
return nil;
}
- (NSInteger)conversationIdentifier
{
return (NSInteger)self;
}
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
{
// Not implemented
return NSNotFound;
NSWindow *window = [self window];
if (window)
thePoint = [window convertScreenToBase:thePoint];
thePoint = [self convertPoint:thePoint fromView:nil]; // the point is relative to the main frame
uint64_t result = _data->_page->characterIndexForPoint(IntPoint(thePoint));
LOG(TextInput, "characterIndexForPoint:(%f, %f) -> %u", thePoint.x, thePoint.y, result);
return result;
}
- (NSRect)firstRectForCharacterRange:(NSRange)theRange
{
// Not implemented
return NSMakeRect(0, 0, 0, 0);
// Just to match NSTextView's behavior. Regression tests cannot detect this;
// to reproduce, use a test application from http://bugs.webkit.org/show_bug.cgi?id=4682
// (type something; try ranges (1, -1) and (2, -1).
if ((theRange.location + theRange.length < theRange.location) && (theRange.location + theRange.length != 0))
theRange.length = 0;
NSRect resultRect = _data->_page->firstRectForCharacterRange(theRange.location, theRange.length);
resultRect = [self convertRect:resultRect toView:nil];
NSWindow *window = [self window];
if (window)
resultRect.origin = [window convertBaseToScreen:resultRect.origin];
LOG(TextInput, "firstRectForCharacterRange:(%u, %u) -> (%f, %f, %f, %f)", theRange.location, theRange.length, resultRect.origin.x, resultRect.origin.y, resultRect.size.width, resultRect.size.height);
return resultRect;
}
- (void)_updateActiveState
......@@ -729,6 +853,11 @@ static bool isViewVisible(NSView *view)
return hitView;
}
- (NSInteger)conversationIdentifier
{
return (NSInteger)self;
}
@end
@implementation WKView (Internal)
......
......@@ -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,