summaryrefslogtreecommitdiffstats
path: root/Source/WebKit2/UIProcess/API/mac
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebKit2/UIProcess/API/mac')
-rw-r--r--Source/WebKit2/UIProcess/API/mac/PDFViewController.h5
-rw-r--r--Source/WebKit2/UIProcess/API/mac/PDFViewController.mm221
-rw-r--r--Source/WebKit2/UIProcess/API/mac/PageClientImpl.h17
-rw-r--r--Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm156
-rw-r--r--Source/WebKit2/UIProcess/API/mac/WKTextInputWindowController.mm9
-rw-r--r--Source/WebKit2/UIProcess/API/mac/WKView.h2
-rw-r--r--Source/WebKit2/UIProcess/API/mac/WKView.mm660
-rw-r--r--Source/WebKit2/UIProcess/API/mac/WKViewInternal.h19
8 files changed, 827 insertions, 262 deletions
diff --git a/Source/WebKit2/UIProcess/API/mac/PDFViewController.h b/Source/WebKit2/UIProcess/API/mac/PDFViewController.h
index dc30f56..041aa7b 100644
--- a/Source/WebKit2/UIProcess/API/mac/PDFViewController.h
+++ b/Source/WebKit2/UIProcess/API/mac/PDFViewController.h
@@ -26,6 +26,7 @@
#ifndef PDFViewController_h
#define PDFViewController_h
+#include "WebFindOptions.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/PassOwnPtr.h>
@@ -64,6 +65,10 @@ public:
NSPrintOperation *makePrintOperation(NSPrintInfo *);
void openPDFInFinder();
void savePDFToDownloadsFolder();
+ void linkClicked(const String& url);
+
+ void findString(const String&, FindOptions, unsigned maxMatchCount);
+ void countStringMatches(const String&, FindOptions, unsigned maxMatchCount);
private:
explicit PDFViewController(WKView *wkView);
diff --git a/Source/WebKit2/UIProcess/API/mac/PDFViewController.mm b/Source/WebKit2/UIProcess/API/mac/PDFViewController.mm
index 5c64000..436a08a 100644
--- a/Source/WebKit2/UIProcess/API/mac/PDFViewController.mm
+++ b/Source/WebKit2/UIProcess/API/mac/PDFViewController.mm
@@ -30,10 +30,12 @@
#import "WKAPICast.h"
#import "WKView.h"
#import "WebData.h"
+#import "WebEventFactory.h"
#import "WebPageGroup.h"
#import "WebPageProxy.h"
#import "WebPreferences.h"
#import <PDFKit/PDFKit.h>
+#import <WebCore/LocalizedStrings.h>
#import <wtf/text/WTFString.h>
// Redeclarations of PDFKit notifications. We can't use the API since we use a weak link to the framework.
@@ -51,7 +53,51 @@ using namespace WebKit;
@end
extern "C" NSString *_NSPathForSystemFramework(NSString *framework);
+
+// MARK: C UTILITY FUNCTIONS
+
+static void _applicationInfoForMIMEType(NSString *type, NSString **name, NSImage **image)
+{
+ ASSERT(name);
+ ASSERT(image);
+ CFURLRef appURL = 0;
+
+ OSStatus error = LSCopyApplicationForMIMEType((CFStringRef)type, kLSRolesAll, &appURL);
+ if (error != noErr)
+ return;
+
+ NSString *appPath = [(NSURL *)appURL path];
+ if (appURL)
+ CFRelease(appURL);
+
+ *image = [[NSWorkspace sharedWorkspace] iconForFile:appPath];
+ [*image setSize:NSMakeSize(16, 16)];
+
+ *name = [[NSFileManager defaultManager] displayNameAtPath:appPath];
+}
+
+// FIXME 4182876: We can eliminate this function in favor if -isEqual: if [PDFSelection isEqual:] is overridden
+// to compare contents.
+static BOOL _PDFSelectionsAreEqual(PDFSelection *selectionA, PDFSelection *selectionB)
+{
+ NSArray *aPages = [selectionA pages];
+ NSArray *bPages = [selectionB pages];
+
+ if (![aPages isEqual:bPages])
+ return NO;
+
+ NSUInteger count = [aPages count];
+ for (NSUInteger i = 0; i < count; ++i) {
+ NSRect aBounds = [selectionA boundsForPage:[aPages objectAtIndex:i]];
+ NSRect bBounds = [selectionB boundsForPage:[bPages objectAtIndex:i]];
+ if (!NSEqualRects(aBounds, bBounds))
+ return NO;
+ }
+
+ return YES;
+}
+
@interface WKPDFView : NSView
{
PDFViewController* _pdfViewController;
@@ -68,7 +114,7 @@ extern "C" NSString *_NSPathForSystemFramework(NSString *framework);
- (void)setDocument:(PDFDocument *)pdfDocument;
- (void)_applyPDFPreferences;
-
+- (PDFSelection *)_nextMatchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag fromSelection:(PDFSelection *)initialSelection startInSelection:(BOOL)startInSelection;
@end
@implementation WKPDFView
@@ -159,6 +205,64 @@ extern "C" NSString *_NSPathForSystemFramework(NSString *framework);
[self _updatePreferencesSoon];
}
+- (void)_openWithFinder:(id)sender
+{
+ _pdfViewController->openPDFInFinder();
+}
+
+- (PDFSelection *)_nextMatchFor:(NSString *)string direction:(BOOL)forward caseSensitive:(BOOL)caseFlag wrap:(BOOL)wrapFlag fromSelection:(PDFSelection *)initialSelection startInSelection:(BOOL)startInSelection
+{
+ if (![string length])
+ return nil;
+
+ int options = 0;
+ if (!forward)
+ options |= NSBackwardsSearch;
+
+ if (!caseFlag)
+ options |= NSCaseInsensitiveSearch;
+
+ PDFDocument *document = [_pdfView document];
+
+ PDFSelection *selectionForInitialSearch = [initialSelection copy];
+ if (startInSelection) {
+ // Initially we want to include the selected text in the search. So we must modify the starting search
+ // selection to fit PDFDocument's search requirements: selection must have a length >= 1, begin before
+ // the current selection (if searching forwards) or after (if searching backwards).
+ int initialSelectionLength = [[initialSelection string] length];
+ if (forward) {
+ [selectionForInitialSearch extendSelectionAtStart:1];
+ [selectionForInitialSearch extendSelectionAtEnd:-initialSelectionLength];
+ } else {
+ [selectionForInitialSearch extendSelectionAtEnd:1];
+ [selectionForInitialSearch extendSelectionAtStart:-initialSelectionLength];
+ }
+ }
+ PDFSelection *foundSelection = [document findString:string fromSelection:selectionForInitialSearch withOptions:options];
+ [selectionForInitialSearch release];
+
+ // If we first searched in the selection, and we found the selection, search again from just past the selection
+ if (startInSelection && _PDFSelectionsAreEqual(foundSelection, initialSelection))
+ foundSelection = [document findString:string fromSelection:initialSelection withOptions:options];
+
+ if (!foundSelection && wrapFlag)
+ foundSelection = [document findString:string fromSelection:nil withOptions:options];
+
+ return foundSelection;
+}
+
+- (NSUInteger)_countMatches:(NSString *)string caseSensitive:(BOOL)caseFlag
+{
+ if (![string length])
+ return 0;
+
+ int options = caseFlag ? 0 : NSCaseInsensitiveSearch;
+
+ return [[[_pdfView document] findString:string withOptions:options] count];
+}
+
+// MARK: NSView overrides
+
- (void)viewDidMoveToWindow
{
if (![self window])
@@ -181,7 +285,69 @@ extern "C" NSString *_NSPathForSystemFramework(NSString *framework);
[notificationCenter removeObserver:self name:_webkit_PDFViewPageChangedNotification object:_pdfView];
}
-// PDFView delegate methods
+- (NSView *)hitTest:(NSPoint)point
+{
+ // Override hitTest so we can override menuForEvent.
+ NSEvent *event = [NSApp currentEvent];
+ NSEventType type = [event type];
+ if (type == NSRightMouseDown || (type == NSLeftMouseDown && ([event modifierFlags] & NSControlKeyMask)))
+ return self;
+
+ return [super hitTest:point];
+}
+
+- (NSMenu *)menuForEvent:(NSEvent *)theEvent
+{
+ NSMenu *menu = [[NSMenu alloc] initWithTitle:@""];
+
+ NSEnumerator *menuItemEnumerator = [[[_pdfView menuForEvent:theEvent] itemArray] objectEnumerator];
+ while (NSMenuItem *item = [menuItemEnumerator nextObject]) {
+ NSMenuItem *itemCopy = [item copy];
+ [menu addItem:itemCopy];
+ [itemCopy release];
+
+ if ([item action] != @selector(copy:))
+ continue;
+
+ // Add in an "Open with <default PDF viewer>" item
+ NSString *appName = nil;
+ NSImage *appIcon = nil;
+
+ _applicationInfoForMIMEType(@"application/pdf", &appName, &appIcon);
+ if (!appName)
+ appName = WEB_UI_STRING("Finder", "Default application name for Open With context menu");
+
+ // To match the PDFKit style, we'll add Open with Preview even when there's no document yet to view, and
+ // disable it using validateUserInterfaceItem.
+ NSString *title = [NSString stringWithFormat:WEB_UI_STRING("Open with %@", "context menu item for PDF"), appName];
+
+ item = [[NSMenuItem alloc] initWithTitle:title action:@selector(_openWithFinder:) keyEquivalent:@""];
+ if (appIcon)
+ [item setImage:appIcon];
+ [menu addItem:[NSMenuItem separatorItem]];
+ [menu addItem:item];
+ [item release];
+ }
+
+ return [menu autorelease];
+}
+
+// MARK: NSUserInterfaceValidations PROTOCOL IMPLEMENTATION
+
+- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
+{
+ SEL action = [item action];
+ if (action == @selector(_openWithFinder:))
+ return [_pdfView document] != nil;
+ return YES;
+}
+
+// MARK: PDFView delegate methods
+
+- (void)PDFViewWillClickOnLink:(PDFView *)sender withURL:(NSURL *)URL
+{
+ _pdfViewController->linkClicked([URL absoluteString]);
+}
- (void)PDFViewOpenPDFInNativeApplication:(PDFView *)sender
{
@@ -416,4 +582,55 @@ NSString *PDFViewController::pathToPDFOnDisk()
return path;
}
+void PDFViewController::linkClicked(const String& url)
+{
+ NSEvent* nsEvent = [NSApp currentEvent];
+ WebMouseEvent event;
+ switch ([nsEvent type]) {
+ case NSLeftMouseUp:
+ case NSRightMouseUp:
+ case NSOtherMouseUp:
+ event = WebEventFactory::createWebMouseEvent(nsEvent, m_pdfView);
+ default:
+ // For non mouse-clicks or for keyboard events, pass an empty WebMouseEvent
+ // through. The event is only used by the WebFrameLoaderClient to determine
+ // the modifier keys and which mouse button is down. These queries will be
+ // valid with an empty event.
+ break;
+ }
+
+ page()->linkClicked(url, event);
+}
+
+void PDFViewController::findString(const String& string, FindOptions options, unsigned maxMatchCount)
+{
+ BOOL forward = !(options & FindOptionsBackwards);
+ BOOL caseFlag = !(options & FindOptionsCaseInsensitive);
+ BOOL wrapFlag = options & FindOptionsWrapAround;
+
+ PDFSelection *selection = [m_wkPDFView.get() _nextMatchFor:string direction:forward caseSensitive:caseFlag wrap:wrapFlag fromSelection:[m_pdfView currentSelection] startInSelection:NO];
+ NSUInteger matchCount = [m_wkPDFView.get() _countMatches:string caseSensitive:caseFlag];
+ if (matchCount > maxMatchCount)
+ matchCount = maxMatchCount;
+
+ if (!selection) {
+ page()->didFailToFindString(string);
+ return;
+ }
+
+ [m_pdfView setCurrentSelection:selection];
+ [m_pdfView scrollSelectionToVisible:nil];
+ page()->didFindString(string, matchCount);
+}
+
+void PDFViewController::countStringMatches(const String& string, FindOptions options, unsigned maxMatchCount)
+{
+ BOOL caseFlag = !(options & FindOptionsCaseInsensitive);
+
+ NSUInteger matchCount = [m_wkPDFView.get() _countMatches:string caseSensitive:caseFlag];
+ if (matchCount > maxMatchCount)
+ matchCount = maxMatchCount;
+ page()->didCountStringMatches(string, matchCount);
+}
+
} // namespace WebKit
diff --git a/Source/WebKit2/UIProcess/API/mac/PageClientImpl.h b/Source/WebKit2/UIProcess/API/mac/PageClientImpl.h
index e217fc5..9e08a28 100644
--- a/Source/WebKit2/UIProcess/API/mac/PageClientImpl.h
+++ b/Source/WebKit2/UIProcess/API/mac/PageClientImpl.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,8 +30,8 @@
#include "PageClient.h"
#include <wtf/RetainPtr.h>
+@class WKEditorUndoTargetObjC;
@class WKView;
-@class WebEditorUndoTargetObjC;
namespace WebKit {
@@ -63,16 +63,18 @@ private:
virtual void processDidCrash();
virtual void pageClosed();
virtual void didRelaunchProcess();
- virtual void setFocus(bool focused);
- virtual void takeFocus(bool direction);
virtual void toolTipChanged(const String& oldToolTip, const String& newToolTip);
virtual void setCursor(const WebCore::Cursor&);
virtual void setViewportArguments(const WebCore::ViewportArguments&);
virtual void registerEditCommand(PassRefPtr<WebEditCommandProxy>, WebPageProxy::UndoOrRedo);
virtual void clearAllEditCommands();
- virtual void interceptKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commandName, uint32_t selectionStart, uint32_t selectionEnd, Vector<WebCore::CompositionUnderline>& underlines);
+ virtual bool canUndoRedo(WebPageProxy::UndoOrRedo);
+ virtual void executeUndoRedo(WebPageProxy::UndoOrRedo);
+ virtual bool interpretKeyEvent(const NativeWebKeyboardEvent&, Vector<WebCore::KeypressCommand>&);
+ virtual bool executeSavedCommandBySelector(const String& selector);
virtual void setDragImage(const WebCore::IntPoint& clientPosition, PassRefPtr<ShareableBitmap> dragImage, bool isLinkDrag);
+ virtual void updateSecureInputState();
virtual WebCore::FloatRect convertToDeviceSpace(const WebCore::FloatRect&);
virtual WebCore::FloatRect convertToUserSpace(const WebCore::FloatRect&);
@@ -100,10 +102,13 @@ private:
virtual double customRepresentationZoomFactor();
virtual void setCustomRepresentationZoomFactor(double);
+ virtual void findStringInCustomRepresentation(const String&, FindOptions, unsigned maxMatchCount);
+ virtual void countStringMatchesInCustomRepresentation(const String&, FindOptions, unsigned maxMatchCount);
virtual void flashBackingStoreUpdates(const Vector<WebCore::IntRect>& updateRects);
virtual void didPerformDictionaryLookup(const String&, double scaleFactor, const DictionaryPopupInfo&);
+ virtual void dismissDictionaryLookupPanel();
virtual void showCorrectionPanel(WebCore::CorrectionPanelInfo::PanelType, const WebCore::FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings);
virtual void dismissCorrectionPanel(WebCore::ReasonForDismissingCorrectionPanel);
@@ -113,7 +118,7 @@ private:
virtual float userSpaceScaleFactor() const;
WKView* m_wkView;
- RetainPtr<WebEditorUndoTargetObjC> m_undoTarget;
+ RetainPtr<WKEditorUndoTargetObjC> m_undoTarget;
#if !defined(BUILDING_ON_SNOW_LEOPARD)
CorrectionPanel m_correctionPanel;
#endif
diff --git a/Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm b/Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm
index 7a0d62d..e1888de 100644
--- a/Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm
+++ b/Source/WebKit2/UIProcess/API/mac/PageClientImpl.mm
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -52,20 +52,24 @@
@end
using namespace WebCore;
+using namespace WebKit;
-@interface WebEditCommandObjC : NSObject
+@interface WKEditCommandObjC : NSObject
{
- RefPtr<WebKit::WebEditCommandProxy> m_command;
+ RefPtr<WebEditCommandProxy> m_command;
}
+- (id)initWithWebEditCommandProxy:(PassRefPtr<WebEditCommandProxy>)command;
+- (WebEditCommandProxy*)command;
+@end
-- (id)initWithWebEditCommandProxy:(PassRefPtr<WebKit::WebEditCommandProxy>)command;
-- (WebKit::WebEditCommandProxy*)command;
-
+@interface WKEditorUndoTargetObjC : NSObject
+- (void)undoEditing:(id)sender;
+- (void)redoEditing:(id)sender;
@end
-@implementation WebEditCommandObjC
+@implementation WKEditCommandObjC
-- (id)initWithWebEditCommandProxy:(PassRefPtr<WebKit::WebEditCommandProxy>)command
+- (id)initWithWebEditCommandProxy:(PassRefPtr<WebEditCommandProxy>)command
{
self = [super init];
if (!self)
@@ -75,31 +79,24 @@ using namespace WebCore;
return self;
}
-- (WebKit::WebEditCommandProxy*)command
+- (WebEditCommandProxy*)command
{
return m_command.get();
}
@end
-@interface WebEditorUndoTargetObjC : NSObject
-
-- (void)undoEditing:(id)sender;
-- (void)redoEditing:(id)sender;
-
-@end
-
-@implementation WebEditorUndoTargetObjC
+@implementation WKEditorUndoTargetObjC
- (void)undoEditing:(id)sender
{
- ASSERT([sender isKindOfClass:[WebEditCommandObjC class]]);
+ ASSERT([sender isKindOfClass:[WKEditCommandObjC class]]);
[sender command]->unapply();
}
- (void)redoEditing:(id)sender
{
- ASSERT([sender isKindOfClass:[WebEditCommandObjC class]]);
+ ASSERT([sender isKindOfClass:[WKEditCommandObjC class]]);
[sender command]->reapply();
}
@@ -119,7 +116,7 @@ PassOwnPtr<PageClientImpl> PageClientImpl::create(WKView* wkView)
PageClientImpl::PageClientImpl(WKView* wkView)
: m_wkView(wkView)
- , m_undoTarget(AdoptNS, [[WebEditorUndoTargetObjC alloc] init])
+ , m_undoTarget(AdoptNS, [[WKEditorUndoTargetObjC alloc] init])
{
}
@@ -157,7 +154,7 @@ IntSize PageClientImpl::viewSize()
bool PageClientImpl::isViewWindowActive()
{
- return [[m_wkView window] isKeyWindow];
+ return [[m_wkView window] isKeyWindow] || [NSApp keyWindow] == [m_wkView window];
}
bool PageClientImpl::isViewFocused()
@@ -170,6 +167,9 @@ bool PageClientImpl::isViewVisible()
if (![m_wkView window])
return false;
+ if (![[m_wkView window] isVisible])
+ return false;
+
if ([m_wkView isHiddenOrHasHiddenAncestor])
return false;
@@ -196,20 +196,6 @@ void PageClientImpl::didRelaunchProcess()
[m_wkView _didRelaunchProcess];
}
-void PageClientImpl::setFocus(bool focused)
-{
- if (focused)
- [[m_wkView window] makeFirstResponder:m_wkView];
- else
- // takeFocus in this context means take focus away from the WKView.
- takeFocus(true);
-}
-
-void PageClientImpl::takeFocus(bool direction)
-{
- [m_wkView _takeFocus:direction];
-}
-
void PageClientImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip)
{
[m_wkView _toolTipChangedFrom:nsStringFromWebCoreString(oldToolTip) to:nsStringFromWebCoreString(newToolTip)];
@@ -223,67 +209,19 @@ void PageClientImpl::setCursor(const WebCore::Cursor& cursor)
void PageClientImpl::setViewportArguments(const WebCore::ViewportArguments&)
{
-
-}
-
-static NSString* nameForEditAction(EditAction editAction)
-{
- // FIXME: Use localized strings.
- // FIXME: Move this to a platform independent location.
-
- switch (editAction) {
- case EditActionUnspecified: return nil;
- case EditActionSetColor: return @"Set Color";
- case EditActionSetBackgroundColor: return @"Set Background Color";
- case EditActionTurnOffKerning: return @"Turn Off Kerning";
- case EditActionTightenKerning: return @"Tighten Kerning";
- case EditActionLoosenKerning: return @"Loosen Kerning";
- case EditActionUseStandardKerning: return @"Use Standard Kerning";
- case EditActionTurnOffLigatures: return @"Turn Off Ligatures";
- case EditActionUseStandardLigatures: return @"Use Standard Ligatures";
- case EditActionUseAllLigatures: return @"Use All Ligatures";
- case EditActionRaiseBaseline: return @"Raise Baseline";
- case EditActionLowerBaseline: return @"Lower Baseline";
- case EditActionSetTraditionalCharacterShape: return @"Set Traditional Character Shape";
- case EditActionSetFont: return @"Set Font";
- case EditActionChangeAttributes: return @"Change Attributes";
- case EditActionAlignLeft: return @"Align Left";
- case EditActionAlignRight: return @"Align Right";
- case EditActionCenter: return @"Center";
- case EditActionJustify: return @"Justify";
- case EditActionSetWritingDirection: return @"Set Writing Direction";
- case EditActionSubscript: return @"Subscript";
- case EditActionSuperscript: return @"Superscript";
- case EditActionUnderline: return @"Underline";
- case EditActionOutline: return @"Outline";
- case EditActionUnscript: return @"Unscript";
- case EditActionDrag: return @"Drag";
- case EditActionCut: return @"Cut";
- case EditActionPaste: return @"Paste";
- case EditActionPasteFont: return @"Paste Font";
- case EditActionPasteRuler: return @"Paste Ruler";
- case EditActionTyping: return @"Typing";
- case EditActionCreateLink: return @"Create Link";
- case EditActionUnlink: return @"Unlink";
- case EditActionInsertList: return @"Insert List";
- case EditActionFormatBlock: return @"Formatting";
- case EditActionIndent: return @"Indent";
- case EditActionOutdent: return @"Outdent";
- }
- return nil;
}
void PageClientImpl::registerEditCommand(PassRefPtr<WebEditCommandProxy> prpCommand, WebPageProxy::UndoOrRedo undoOrRedo)
{
RefPtr<WebEditCommandProxy> command = prpCommand;
- RetainPtr<WebEditCommandObjC> commandObjC(AdoptNS, [[WebEditCommandObjC alloc] initWithWebEditCommandProxy:command]);
- NSString *actionName = nameForEditAction(command->editAction());
+ RetainPtr<WKEditCommandObjC> commandObjC(AdoptNS, [[WKEditCommandObjC alloc] initWithWebEditCommandProxy:command]);
+ String actionName = WebEditCommandProxy::nameForEditAction(command->editAction());
NSUndoManager *undoManager = [m_wkView undoManager];
[undoManager registerUndoWithTarget:m_undoTarget.get() selector:((undoOrRedo == WebPageProxy::Undo) ? @selector(undoEditing:) : @selector(redoEditing:)) object:commandObjC.get()];
- if (actionName)
- [undoManager setActionName:actionName];
+ if (!actionName.isEmpty())
+ [undoManager setActionName:(NSString *)actionName];
}
void PageClientImpl::clearAllEditCommands()
@@ -291,10 +229,19 @@ void PageClientImpl::clearAllEditCommands()
[[m_wkView undoManager] removeAllActionsWithTarget:m_undoTarget.get()];
}
-void PageClientImpl::interceptKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commandsList, uint32_t selectionStart, uint32_t selectionEnd, Vector<WebCore::CompositionUnderline>& underlines)
+bool PageClientImpl::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
{
- commandsList = [m_wkView _interceptKeyEvent:event.nativeEvent()];
- [m_wkView _getTextInputState:selectionStart selectionEnd:selectionEnd underlines:underlines];
+ return (undoOrRedo == WebPageProxy::Undo) ? [[m_wkView undoManager] canUndo] : [[m_wkView undoManager] canRedo];
+}
+
+void PageClientImpl::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
+{
+ return (undoOrRedo == WebPageProxy::Undo) ? [[m_wkView undoManager] undo] : [[m_wkView undoManager] redo];
+}
+
+bool PageClientImpl::interpretKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commands)
+{
+ return [m_wkView _interpretKeyEvent:event.nativeEvent() savingCommandsTo:commands];
}
void PageClientImpl::setDragImage(const IntPoint& clientPosition, PassRefPtr<ShareableBitmap> dragImage, bool isLinkDrag)
@@ -304,7 +251,12 @@ void PageClientImpl::setDragImage(const IntPoint& clientPosition, PassRefPtr<Sha
[m_wkView _setDragImage:dragNSImage.get() at:clientPosition linkDrag:isLinkDrag];
}
-
+
+void PageClientImpl::updateSecureInputState()
+{
+ [m_wkView _updateSecureInputState];
+}
+
FloatRect PageClientImpl::convertToDeviceSpace(const FloatRect& rect)
{
return [m_wkView _convertToDeviceSpace:rect];
@@ -408,6 +360,16 @@ void PageClientImpl::setCustomRepresentationZoomFactor(double zoomFactor)
[m_wkView _setCustomRepresentationZoomFactor:zoomFactor];
}
+void PageClientImpl::findStringInCustomRepresentation(const String& string, FindOptions options, unsigned maxMatchCount)
+{
+ [m_wkView _findStringInCustomRepresentation:string withFindOptions:options maxMatchCount:maxMatchCount];
+}
+
+void PageClientImpl::countStringMatchesInCustomRepresentation(const String& string, FindOptions options, unsigned maxMatchCount)
+{
+ [m_wkView _countStringMatchesInCustomRepresentation:string withFindOptions:options maxMatchCount:maxMatchCount];
+}
+
void PageClientImpl::flashBackingStoreUpdates(const Vector<IntRect>&)
{
notImplemented();
@@ -437,6 +399,13 @@ void PageClientImpl::didPerformDictionaryLookup(const String& text, double scale
#endif
}
+void PageClientImpl::dismissDictionaryLookupPanel()
+{
+#if !defined(BUILDING_ON_SNOW_LEOPARD)
+ WKHideWordDefinitionWindow();
+#endif
+}
+
void PageClientImpl::showCorrectionPanel(CorrectionPanelInfo::PanelType type, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings)
{
#if !defined(BUILDING_ON_SNOW_LEOPARD)
@@ -484,4 +453,9 @@ float PageClientImpl::userSpaceScaleFactor() const
#endif
}
+bool PageClientImpl::executeSavedCommandBySelector(const String& selectorString)
+{
+ return [m_wkView _executeSavedCommandBySelector:NSSelectorFromString(selectorString)];
+}
+
} // namespace WebKit
diff --git a/Source/WebKit2/UIProcess/API/mac/WKTextInputWindowController.mm b/Source/WebKit2/UIProcess/API/mac/WKTextInputWindowController.mm
index 3b69a1d..2c9ceaa 100644
--- a/Source/WebKit2/UIProcess/API/mac/WKTextInputWindowController.mm
+++ b/Source/WebKit2/UIProcess/API/mac/WKTextInputWindowController.mm
@@ -86,7 +86,14 @@
BOOL hadMarkedText = [_inputTextView hasMarkedText];
*string = nil;
-
+
+ // Let TSM know that a bottom input window would be created for marked text.
+ EventRef carbonEvent = static_cast<EventRef>(const_cast<void*>([event eventRef]));
+ if (carbonEvent) {
+ Boolean ignorePAH = true;
+ SetEventParameter(carbonEvent, 'iPAH', typeBoolean, sizeof(ignorePAH), &ignorePAH);
+ }
+
if (![[_inputTextView inputContext] handleEvent:event])
return NO;
diff --git a/Source/WebKit2/UIProcess/API/mac/WKView.h b/Source/WebKit2/UIProcess/API/mac/WKView.h
index 8c1826c..098b3ca 100644
--- a/Source/WebKit2/UIProcess/API/mac/WKView.h
+++ b/Source/WebKit2/UIProcess/API/mac/WKView.h
@@ -29,7 +29,7 @@
@class WKViewData;
WK_EXPORT
-@interface WKView : NSView <NSTextInput> {
+@interface WKView : NSView <NSTextInputClient> {
WKViewData *_data;
unsigned _frameSizeUpdatesDisabledCount;
}
diff --git a/Source/WebKit2/UIProcess/API/mac/WKView.mm b/Source/WebKit2/UIProcess/API/mac/WKView.mm
index 05693ef..80345f7 100644
--- a/Source/WebKit2/UIProcess/API/mac/WKView.mm
+++ b/Source/WebKit2/UIProcess/API/mac/WKView.mm
@@ -26,14 +26,17 @@
#import "config.h"
#import "WKView.h"
+#import "AttributedString.h"
#import "ChunkedUpdateDrawingAreaProxy.h"
#import "DataReference.h"
#import "DrawingAreaProxyImpl.h"
+#import "EditorState.h"
#import "FindIndicator.h"
#import "FindIndicatorWindow.h"
#import "LayerTreeContext.h"
#import "Logging.h"
#import "NativeWebKeyboardEvent.h"
+#import "NativeWebMouseEvent.h"
#import "PDFViewController.h"
#import "PageClientImpl.h"
#import "PasteboardTypes.h"
@@ -69,24 +72,23 @@
#import <wtf/RefPtr.h>
#import <wtf/RetainPtr.h>
-@interface NSApplication (WebNSApplicationDetails)
+@interface NSApplication (WKNSApplicationDetails)
- (void)speakString:(NSString *)string;
- (void)_setCurrentEvent:(NSEvent *)event;
@end
-@interface NSWindow (WebNSWindowDetails)
+@interface NSObject (WKNSTextInputContextDetails)
+- (BOOL)wantsToHandleMouseEvents;
+- (BOOL)handleMouseEvent:(NSEvent *)event;
+@end
+
+@interface NSWindow (WKNSWindowDetails)
- (NSRect)_growBoxRect;
- (id)_growBoxOwner;
- (void)_setShowOpaqueGrowBoxForOwner:(id)owner;
- (BOOL)_updateGrowBoxForWindowFrameChange;
@end
-extern "C" {
- // Need to declare this attribute name because AppKit exports it but does not make it available in API or SPI headers.
- // <rdar://problem/8631468> tracks the request to make it available. This code should be removed when the bug is closed.
- extern NSString *NSTextInputReplacementRangeAttributeName;
-}
-
using namespace WebKit;
using namespace WebCore;
@@ -98,6 +100,13 @@ typedef HashMap<String, ValidationVector> ValidationMap;
}
+struct WKViewInterpretKeyEventsParameters {
+ bool eventInterpretationHadSideEffects;
+ bool consumedByIM;
+ bool executingSavedKeypressCommands;
+ Vector<KeypressCommand>* commands;
+};
+
@interface WKViewData : NSObject {
@public
OwnPtr<PageClientImpl> _pageClient;
@@ -122,18 +131,13 @@ typedef HashMap<String, ValidationVector> ValidationMap;
// the application to distinguish the case of a new event from one
// that has been already sent to WebCore.
RetainPtr<NSEvent> _keyDownEventBeingResent;
- bool _isInInterpretKeyEvents;
- Vector<KeypressCommand> _commandsList;
+ WKViewInterpretKeyEventsParameters* _interpretKeyEventsParameters;
NSSize _resizeScrollOffset;
// The identifier of the plug-in we want to send complex text input to, or 0 if there is none.
uint64_t _pluginComplexTextInputIdentifier;
- Vector<CompositionUnderline> _underlines;
- unsigned _selectionStart;
- unsigned _selectionEnd;
-
bool _inBecomeFirstResponder;
bool _inResignFirstResponder;
NSEvent *_mouseDownEvent;
@@ -150,15 +154,21 @@ typedef HashMap<String, ValidationVector> ValidationMap;
BOOL _hasSpellCheckerDocumentTag;
NSInteger _spellCheckerDocumentTag;
+
+ BOOL _inSecureInputState;
}
@end
-@implementation WKViewData
+@interface WKResponderChainSink : NSResponder {
+ NSResponder *_lastResponderInChain;
+ bool _didReceiveUnhandledCommand;
+}
+- (id)initWithResponderChain:(NSResponder *)chain;
+- (void)detach;
+- (bool)didReceiveUnhandledCommand;
@end
-@interface NSObject (NSTextInputContextDetails)
-- (BOOL)wantsToHandleMouseEvents;
-- (BOOL)handleMouseEvent:(NSEvent *)event;
+@implementation WKViewData
@end
@implementation WKView
@@ -239,6 +249,8 @@ typedef HashMap<String, ValidationVector> ValidationMap;
{
_data->_page->close();
+ ASSERT(!_data->_inSecureInputState);
+
[_data release];
_data = nil;
@@ -282,7 +294,10 @@ typedef HashMap<String, ValidationVector> ValidationMap;
NSSelectionDirection direction = [[self window] keyViewSelectionDirection];
_data->_inBecomeFirstResponder = true;
+
+ [self _updateSecureInputState];
_data->_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
+
_data->_inBecomeFirstResponder = false;
if (direction != NSDirectSelection)
@@ -294,7 +309,13 @@ typedef HashMap<String, ValidationVector> ValidationMap;
- (BOOL)resignFirstResponder
{
_data->_inResignFirstResponder = true;
+
+ if (_data->_inSecureInputState) {
+ DisableSecureEventInput();
+ _data->_inSecureInputState = NO;
+ }
_data->_page->viewStateDidChange(WebPageProxy::ViewIsFocused);
+
_data->_inResignFirstResponder = false;
return YES;
@@ -514,13 +535,13 @@ WEBCORE_COMMAND(yankAndSelect)
- (id)validRequestorForSendType:(NSString *)sendType returnType:(NSString *)returnType
{
- BOOL isValidSendType = !sendType || ([PasteboardTypes::forSelection() containsObject:sendType] && !_data->_page->selectionState().isNone);
+ BOOL isValidSendType = !sendType || ([PasteboardTypes::forSelection() containsObject:sendType] && !_data->_page->editorState().selectionIsNone);
BOOL isValidReturnType = NO;
if (!returnType)
isValidReturnType = YES;
- else if ([PasteboardTypes::forEditing() containsObject:returnType] && _data->_page->selectionState().isContentEditable) {
+ else if ([PasteboardTypes::forEditing() containsObject:returnType] && _data->_page->editorState().isContentEditable) {
// We can insert strings in any editable context. We can insert other types, like images, only in rich edit contexts.
- isValidReturnType = _data->_page->selectionState().isContentRichlyEditable || [returnType isEqualToString:NSStringPboardType];
+ isValidReturnType = _data->_page->editorState().isContentRichlyEditable || [returnType isEqualToString:NSStringPboardType];
}
if (isValidSendType && isValidReturnType)
return self;
@@ -604,12 +625,12 @@ static void validateCommandCallback(WKStringRef commandName, bool isEnabled, int
if (action == @selector(showGuessPanel:)) {
if (NSMenuItem *menuItem = ::menuItem(item))
- [menuItem setTitle:contextMenuItemTagShowSpellingPanel([[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible])];
- return _data->_page->selectionState().isContentEditable;
+ [menuItem setTitle:contextMenuItemTagShowSpellingPanel(![[[NSSpellChecker sharedSpellChecker] spellingPanel] isVisible])];
+ return _data->_page->editorState().isContentEditable;
}
if (action == @selector(checkSpelling:) || action == @selector(changeSpelling:))
- return _data->_page->selectionState().isContentEditable;
+ return _data->_page->editorState().isContentEditable;
if (action == @selector(toggleContinuousSpellChecking:)) {
bool enabled = TextChecker::isContinuousSpellCheckingAllowed();
@@ -627,47 +648,47 @@ static void validateCommandCallback(WKStringRef commandName, bool isEnabled, int
if (action == @selector(toggleAutomaticSpellingCorrection:)) {
bool checked = TextChecker::state().isAutomaticSpellingCorrectionEnabled;
[menuItem(item) setState:checked ? NSOnState : NSOffState];
- return _data->_page->selectionState().isContentEditable;
+ return _data->_page->editorState().isContentEditable;
}
if (action == @selector(orderFrontSubstitutionsPanel:)) {
if (NSMenuItem *menuItem = ::menuItem(item))
- [menuItem setTitle:contextMenuItemTagShowSubstitutions([[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible])];
- return _data->_page->selectionState().isContentEditable;
+ [menuItem setTitle:contextMenuItemTagShowSubstitutions(![[[NSSpellChecker sharedSpellChecker] substitutionsPanel] isVisible])];
+ return _data->_page->editorState().isContentEditable;
}
if (action == @selector(toggleSmartInsertDelete:)) {
bool checked = _data->_page->isSmartInsertDeleteEnabled();
[menuItem(item) setState:checked ? NSOnState : NSOffState];
- return _data->_page->selectionState().isContentEditable;
+ return _data->_page->editorState().isContentEditable;
}
if (action == @selector(toggleAutomaticQuoteSubstitution:)) {
bool checked = TextChecker::state().isAutomaticQuoteSubstitutionEnabled;
[menuItem(item) setState:checked ? NSOnState : NSOffState];
- return _data->_page->selectionState().isContentEditable;
+ return _data->_page->editorState().isContentEditable;
}
if (action == @selector(toggleAutomaticDashSubstitution:)) {
bool checked = TextChecker::state().isAutomaticDashSubstitutionEnabled;
[menuItem(item) setState:checked ? NSOnState : NSOffState];
- return _data->_page->selectionState().isContentEditable;
+ return _data->_page->editorState().isContentEditable;
}
if (action == @selector(toggleAutomaticLinkDetection:)) {
bool checked = TextChecker::state().isAutomaticLinkDetectionEnabled;
[menuItem(item) setState:checked ? NSOnState : NSOffState];
- return _data->_page->selectionState().isContentEditable;
+ return _data->_page->editorState().isContentEditable;
}
if (action == @selector(toggleAutomaticTextReplacement:)) {
bool checked = TextChecker::state().isAutomaticTextReplacementEnabled;
[menuItem(item) setState:checked ? NSOnState : NSOffState];
- return _data->_page->selectionState().isContentEditable;
+ return _data->_page->editorState().isContentEditable;
}
if (action == @selector(uppercaseWord:) || action == @selector(lowercaseWord:) || action == @selector(capitalizeWord:))
- return _data->_page->selectionState().selectedRangeLength && _data->_page->selectionState().isContentEditable;
+ return _data->_page->editorState().selectionIsRange && _data->_page->editorState().isContentEditable;
if (action == @selector(stopSpeaking:))
return [NSApp isSpeaking];
@@ -751,9 +772,6 @@ static void speakString(WKStringRef string, WKErrorRef error, void*)
TextChecker::setContinuousSpellCheckingEnabled(spellCheckingEnabled);
_data->_page->process()->updateTextCheckerState();
-
- if (!spellCheckingEnabled)
- _data->_page->unmarkAllMisspellings();
}
- (BOOL)isGrammarCheckingEnabled
@@ -768,9 +786,6 @@ static void speakString(WKStringRef string, WKErrorRef error, void*)
TextChecker::setGrammarCheckingEnabled(flag);
_data->_page->process()->updateTextCheckerState();
-
- if (!flag)
- _data->_page->unmarkAllBadGrammar();
}
- (IBAction)toggleGrammarChecking:(id)sender
@@ -779,9 +794,6 @@ static void speakString(WKStringRef string, WKErrorRef error, void*)
TextChecker::setGrammarCheckingEnabled(grammarCheckingEnabled);
_data->_page->process()->updateTextCheckerState();
-
- if (!grammarCheckingEnabled)
- _data->_page->unmarkAllBadGrammar();
}
- (IBAction)toggleAutomaticSpellingCorrection:(id)sender
@@ -927,6 +939,33 @@ static void speakString(WKStringRef string, WKErrorRef error, void*)
_data->_mouseDownEvent = [event retain];
}
+#define NATIVE_MOUSE_EVENT_HANDLER(Selector) \
+ - (void)Selector:(NSEvent *)theEvent \
+ { \
+ if ([[self inputContext] handleEvent:theEvent]) { \
+ LOG(TextInput, "%s was handled by text input context", String(#Selector).substring(0, String(#Selector).find("Internal")).ascii().data()); \
+ return; \
+ } \
+ NativeWebMouseEvent webEvent(theEvent, self); \
+ _data->_page->handleMouseEvent(webEvent); \
+ }
+
+NATIVE_MOUSE_EVENT_HANDLER(mouseEntered)
+NATIVE_MOUSE_EVENT_HANDLER(mouseExited)
+NATIVE_MOUSE_EVENT_HANDLER(mouseMovedInternal)
+NATIVE_MOUSE_EVENT_HANDLER(mouseDownInternal)
+NATIVE_MOUSE_EVENT_HANDLER(mouseUpInternal)
+NATIVE_MOUSE_EVENT_HANDLER(mouseDraggedInternal)
+NATIVE_MOUSE_EVENT_HANDLER(otherMouseDown)
+NATIVE_MOUSE_EVENT_HANDLER(otherMouseDragged)
+NATIVE_MOUSE_EVENT_HANDLER(otherMouseMoved)
+NATIVE_MOUSE_EVENT_HANDLER(otherMouseUp)
+NATIVE_MOUSE_EVENT_HANDLER(rightMouseDown)
+NATIVE_MOUSE_EVENT_HANDLER(rightMouseDragged)
+NATIVE_MOUSE_EVENT_HANDLER(rightMouseUp)
+
+#undef NATIVE_MOUSE_EVENT_HANDLER
+
#define EVENT_HANDLER(Selector, Type) \
- (void)Selector:(NSEvent *)theEvent \
{ \
@@ -934,28 +973,17 @@ static void speakString(WKStringRef string, WKErrorRef error, void*)
_data->_page->handle##Type##Event(webEvent); \
}
-EVENT_HANDLER(mouseEntered, Mouse)
-EVENT_HANDLER(mouseExited, Mouse)
-EVENT_HANDLER(mouseMoved, Mouse)
-EVENT_HANDLER(otherMouseDown, Mouse)
-EVENT_HANDLER(otherMouseDragged, Mouse)
-EVENT_HANDLER(otherMouseMoved, Mouse)
-EVENT_HANDLER(otherMouseUp, Mouse)
-EVENT_HANDLER(rightMouseDown, Mouse)
-EVENT_HANDLER(rightMouseDragged, Mouse)
-EVENT_HANDLER(rightMouseMoved, Mouse)
-EVENT_HANDLER(rightMouseUp, Mouse)
EVENT_HANDLER(scrollWheel, Wheel)
#undef EVENT_HANDLER
-- (void)_mouseHandler:(NSEvent *)event
+- (void)mouseMoved:(NSEvent *)event
{
- NSInputManager *currentInputManager = [NSInputManager currentInputManager];
- if ([currentInputManager wantsToHandleMouseEvents] && [currentInputManager handleMouseEvent:event])
+ // When a view is first responder, it gets mouse moved events even when the mouse is outside its visible rect.
+ if (self == [[self window] firstResponder] && !NSPointInRect([self convertPoint:[event locationInWindow] fromView:nil], [self visibleRect]))
return;
- WebMouseEvent webEvent = WebEventFactory::createWebMouseEvent(event, self);
- _data->_page->handleMouseEvent(webEvent);
+
+ [self mouseMovedInternal:event];
}
- (void)mouseDown:(NSEvent *)event
@@ -963,20 +991,57 @@ EVENT_HANDLER(scrollWheel, Wheel)
[self _setMouseDownEvent:event];
_data->_ignoringMouseDraggedEvents = NO;
_data->_dragHasStarted = NO;
- [self _mouseHandler:event];
+ [self mouseDownInternal:event];
}
- (void)mouseUp:(NSEvent *)event
{
[self _setMouseDownEvent:nil];
- [self _mouseHandler:event];
+ [self mouseUpInternal:event];
}
- (void)mouseDragged:(NSEvent *)event
{
if (_data->_ignoringMouseDraggedEvents)
return;
- [self _mouseHandler:event];
+ [self mouseDraggedInternal:event];
+}
+
+- (BOOL)acceptsFirstMouse:(NSEvent *)event
+{
+ // There's a chance that responding to this event will run a nested event loop, and
+ // fetching a new event might release the old one. Retaining and then autoreleasing
+ // the current event prevents that from causing a problem inside WebKit or AppKit code.
+ [[event retain] autorelease];
+
+ if (![self hitTest:[event locationInWindow]])
+ return NO;
+
+ [self _setMouseDownEvent:event];
+ bool result = _data->_page->acceptsFirstMouse([event eventNumber], WebEventFactory::createWebMouseEvent(event, self));
+ [self _setMouseDownEvent:nil];
+ return result;
+}
+
+- (BOOL)shouldDelayWindowOrderingForEvent:(NSEvent *)event
+{
+ // If this is the active window or we don't have a range selection, there is no need to perform additional checks
+ // and we can avoid making a synchronous call to the WebProcess.
+ if ([[self window] isKeyWindow] || _data->_page->editorState().selectionIsNone || !_data->_page->editorState().selectionIsRange)
+ return NO;
+
+ // There's a chance that responding to this event will run a nested event loop, and
+ // fetching a new event might release the old one. Retaining and then autoreleasing
+ // the current event prevents that from causing a problem inside WebKit or AppKit code.
+ [[event retain] autorelease];
+
+ if (![self hitTest:[event locationInWindow]])
+ return NO;
+
+ [self _setMouseDownEvent:event];
+ bool result = _data->_page->shouldDelayWindowOrderingForEvent(WebEventFactory::createWebMouseEvent(event, self));
+ [self _setMouseDownEvent:nil];
+ return result;
}
#if ENABLE(GESTURE_EVENTS)
@@ -1018,52 +1083,75 @@ static const short kIOHIDEventTypeScroll = 6;
{
LOG(TextInput, "doCommandBySelector:\"%s\"", sel_getName(selector));
- if (!_data->_isInInterpretKeyEvents) {
+ WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
+ if (parameters)
+ parameters->consumedByIM = false;
+
+ // As in insertText:replacementRange:, we assume that the call comes from an input method if there is marked text.
+ bool isFromInputMethod = _data->_page->editorState().hasComposition;
+
+ if (parameters && !isFromInputMethod)
+ parameters->commands->append(KeypressCommand(NSStringFromSelector(selector)));
+ else {
+ // FIXME: Send the command to Editor synchronously and only send it along the
+ // responder chain if it's a selector that does not correspond to an editing command.
[super doCommandBySelector:selector];
- return;
}
- if (selector != @selector(noop:))
- _data->_commandsList.append(KeypressCommand(commandNameForSelector(selector)));
}
- (void)insertText:(id)string
{
- BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
-
- LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string);
+ // Unlike and NSTextInputClient variant with replacementRange, this NSResponder method is called when there is no input context,
+ // so text input processing isn't performed. We are not going to actually insert any text in that case, but saving an insertText
+ // command ensures that a keypress event is dispatched as appropriate.
+ [self insertText:string replacementRange:NSMakeRange(NSNotFound, 0)];
+}
+
+- (void)insertText:(id)string replacementRange:(NSRange)replacementRange
+{
+ BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
+ ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
+
+ if (replacementRange.location != NSNotFound)
+ LOG(TextInput, "insertText:\"%@\" replacementRange:(%u, %u)", isAttributedString ? [string string] : string, replacementRange.location, replacementRange.length);
+ else
+ LOG(TextInput, "insertText:\"%@\"", isAttributedString ? [string string] : string);
+ WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
+ if (parameters)
+ parameters->consumedByIM = false;
+
NSString *text;
- bool isFromInputMethod = _data->_page->selectionState().hasComposition;
+ bool isFromInputMethod = _data->_page->editorState().hasComposition;
if (isAttributedString) {
+ // FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data.
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;
+ // insertText can be called for several reasons:
+ // - If it's from normal key event processing (including key bindings), we may need to save the action to perform it later.
+ // - If it's from an input method, then we should go ahead and insert the text now. We assume it's from the input method if we have marked text.
+ // FIXME: In theory, this could be wrong for some input methods, so we should try to find another way to determine if the call is from the input method.
+ // - If it's sent outside of keyboard event processing (e.g. from Character Viewer, or when confirming an inline input area with a mouse),
+ // then we also execute it immediately, as there will be no other chance.
+ if (parameters && !isFromInputMethod) {
+ ASSERT(replacementRange.location == NSNotFound);
+ parameters->commands->append(KeypressCommand("insertText:", text));
+ return;
+ }
+
String eventText = text;
-
- // We'd need a different code path here if we wanted to be able to handle this
- // outside of interpretKeyEvents.
- ASSERT(_data->_isInInterpretKeyEvents);
+ eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
+ bool eventHandled = _data->_page->insertText(eventText, replacementRange.location, NSMaxRange(replacementRange));
- 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));
- }
+ if (parameters)
+ parameters->eventInterpretationHadSideEffects |= eventHandled;
}
- (BOOL)_handleStyleKeyEquivalent:(NSEvent *)event
{
- if (!_data->_page->selectionState().isContentEditable)
+ if (!_data->_page->editorState().isContentEditable)
return NO;
if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) != NSCommandKeyMask)
@@ -1130,9 +1218,6 @@ static const short kIOHIDEventTypeScroll = 6;
}
}
- _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).
@@ -1144,37 +1229,108 @@ static const short kIOHIDEventTypeScroll = 6;
_data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self));
}
-- (NSTextInputContext *)inputContext {
- if (_data->_pluginComplexTextInputIdentifier && !_data->_isInInterpretKeyEvents)
+- (void)flagsChanged:(NSEvent *)theEvent
+{
+ // There's a chance that responding to this event will run a nested event loop, and
+ // fetching a new event might release the old one. Retaining and then autoreleasing
+ // the current event prevents that from causing a problem inside WebKit or AppKit code.
+ [[theEvent retain] autorelease];
+
+ unsigned short keyCode = [theEvent keyCode];
+
+ // Don't make an event from the num lock and function keys
+ if (!keyCode || keyCode == 10 || keyCode == 63)
+ return;
+
+ _data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, self));
+}
+
+- (void)_executeSavedKeypressCommands
+{
+ WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
+ if (!parameters || parameters->commands->isEmpty())
+ return;
+
+ // We could be called again if the execution of one command triggers a call to selectedRange.
+ // In this case, the state is up to date, and we don't need to execute any more saved commands to return a result.
+ if (parameters->executingSavedKeypressCommands)
+ return;
+
+ parameters->executingSavedKeypressCommands = true;
+ parameters->eventInterpretationHadSideEffects |= _data->_page->executeKeypressCommands(*parameters->commands);
+ parameters->commands->clear();
+ parameters->executingSavedKeypressCommands = false;
+}
+
+- (NSTextInputContext *)inputContext
+{
+ WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
+
+ if (_data->_pluginComplexTextInputIdentifier && !parameters)
return [[WKTextInputWindowController sharedTextInputWindowController] inputContext];
+ // Disable text input machinery when in non-editable content. An invisible inline input area affects performance, and can prevent Expose from working.
+ if (!_data->_page->editorState().isContentEditable)
+ return nil;
+
return [super inputContext];
}
- (NSRange)selectedRange
{
- if (_data->_page->selectionState().isNone || !_data->_page->selectionState().isContentEditable)
- return NSMakeRange(NSNotFound, 0);
-
- LOG(TextInput, "selectedRange -> (%u, %u)", _data->_page->selectionState().selectedRangeStart, _data->_page->selectionState().selectedRangeLength);
- return NSMakeRange(_data->_page->selectionState().selectedRangeStart, _data->_page->selectionState().selectedRangeLength);
+ [self _executeSavedKeypressCommands];
+
+ uint64_t selectionStart;
+ uint64_t selectionLength;
+ _data->_page->getSelectedRange(selectionStart, selectionLength);
+
+ NSRange result = NSMakeRange(selectionStart, selectionLength);
+ if (result.location == NSNotFound)
+ LOG(TextInput, "selectedRange -> (NSNotFound, %u)", result.length);
+ else
+ LOG(TextInput, "selectedRange -> (%u, %u)", result.location, result.length);
+
+ return result;
}
- (BOOL)hasMarkedText
{
- LOG(TextInput, "hasMarkedText -> %u", _data->_page->selectionState().hasComposition);
- return _data->_page->selectionState().hasComposition;
+ WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
+
+ BOOL result;
+ if (parameters) {
+ result = _data->_page->editorState().hasComposition;
+ if (result) {
+ // A saved command can confirm a composition, but it cannot start a new one.
+ [self _executeSavedKeypressCommands];
+ result = _data->_page->editorState().hasComposition;
+ }
+ } else {
+ uint64_t location;
+ uint64_t length;
+ _data->_page->getMarkedRange(location, length);
+ result = location != NSNotFound;
+ }
+
+ LOG(TextInput, "hasMarkedText -> %u", result);
+ return result;
}
- (void)unmarkText
{
+ [self _executeSavedKeypressCommands];
+
LOG(TextInput, "unmarkText");
- // We'd need a different code path here if we wanted to be able to handle this
- // outside of interpretKeyEvents.
- ASSERT(_data->_isInInterpretKeyEvents);
+ // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
+ WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
+
+ if (parameters) {
+ parameters->eventInterpretationHadSideEffects = true;
+ parameters->consumedByIM = false;
+ }
- _data->_commandsList.append(KeypressCommand("unmarkText"));
+ _data->_page->confirmComposition();
}
- (NSArray *)validAttributesForMarkedText
@@ -1183,7 +1339,7 @@ static const short kIOHIDEventTypeScroll = 6;
if (!validAttributes) {
validAttributes = [[NSArray alloc] initWithObjects:
NSUnderlineStyleAttributeName, NSUnderlineColorAttributeName,
- NSMarkedClauseSegmentAttributeName, NSTextInputReplacementRangeAttributeName, nil];
+ NSMarkedClauseSegmentAttributeName, nil];
// NSText also supports the following attributes, but it's
// hard to tell which are really required for text input to
// work well; I have not seen any input method make use of them yet.
@@ -1215,47 +1371,86 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
}
}
-- (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange
+- (void)setMarkedText:(id)string selectedRange:(NSRange)newSelRange replacementRange:(NSRange)replacementRange
{
- BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]]; // Otherwise, NSString
-
+ [self _executeSavedKeypressCommands];
+
+ BOOL isAttributedString = [string isKindOfClass:[NSAttributedString class]];
+ ASSERT(isAttributedString || [string isKindOfClass:[NSString class]]);
+
LOG(TextInput, "setMarkedText:\"%@\" selectedRange:(%u, %u)", isAttributedString ? [string string] : string, newSelRange.location, newSelRange.length);
+
+ // Use pointer to get parameters passed to us by the caller of interpretKeyEvents.
+ WKViewInterpretKeyEventsParameters* parameters = _data->_interpretKeyEventsParameters;
+
+ if (parameters) {
+ parameters->eventInterpretationHadSideEffects = true;
+ parameters->consumedByIM = false;
+ }
- NSString *text = string;
-
+ Vector<CompositionUnderline> underlines;
+ NSString *text;
+
if (isAttributedString) {
+ // FIXME: We ignore most attributes from the string, so an input method cannot specify e.g. a font or a glyph variation.
text = [string string];
- extractUnderlines(string, _data->_underlines);
+ extractUnderlines(string, underlines);
+ } else
+ text = string;
+
+ if (_data->_page->editorState().isInPasswordField) {
+ // In password fields, we only allow ASCII dead keys, and don't allow inline input, matching NSSecureTextInputField.
+ // Allowing ASCII dead keys is necessary to enable full Roman input when using a Vietnamese keyboard.
+ ASSERT(!_data->_page->editorState().hasComposition);
+ [[super inputContext] discardMarkedText]; // Inform the input method that we won't have an inline input area despite having been asked to.
+ if ([text length] == 1 && [[text decomposedStringWithCanonicalMapping] characterAtIndex:0] < 0x80) {
+ _data->_page->insertText(text, replacementRange.location, NSMaxRange(replacementRange));
+ } else
+ NSBeep();
+ return;
}
-
- // We'd need a different code path here if we wanted to be able to handle this
- // outside of interpretKeyEvents.
- ASSERT(_data->_isInInterpretKeyEvents);
- _data->_commandsList.append(KeypressCommand("setMarkedText", text));
- _data->_selectionStart = newSelRange.location;
- _data->_selectionEnd = NSMaxRange(newSelRange);
+ _data->_page->setComposition(text, underlines, newSelRange.location, NSMaxRange(newSelRange), replacementRange.location, NSMaxRange(replacementRange));
}
- (NSRange)markedRange
{
+ [self _executeSavedKeypressCommands];
+
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
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)nsRange actualRange:(NSRangePointer)actualRange
{
- // This is not implemented for now. Need to figure out how to serialize the attributed string across processes.
- LOG(TextInput, "attributedSubstringFromRange");
- return nil;
+ [self _executeSavedKeypressCommands];
+
+ if (!_data->_page->editorState().isContentEditable) {
+ LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> nil", nsRange.location, nsRange.length);
+ return nil;
+ }
+
+ if (_data->_page->editorState().isInPasswordField)
+ return nil;
+
+ AttributedString result;
+ _data->_page->getAttributedSubstringFromRange(nsRange.location, NSMaxRange(nsRange), result);
+
+ if (actualRange)
+ *actualRange = nsRange;
+
+ LOG(TextInput, "attributedSubstringFromRange:(%u, %u) -> \"%@\"", nsRange.location, nsRange.length, [result.string.get() string]);
+ return [[result.string.get() retain] autorelease];
}
- (NSUInteger)characterIndexForPoint:(NSPoint)thePoint
{
+ [self _executeSavedKeypressCommands];
+
NSWindow *window = [self window];
if (window)
@@ -1267,8 +1462,10 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
return result;
}
-- (NSRect)firstRectForCharacterRange:(NSRange)theRange
+- (NSRect)firstRectForCharacterRange:(NSRange)theRange actualRange:(NSRangePointer)actualRange
{
+ [self _executeSavedKeypressCommands];
+
// 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).
@@ -1281,7 +1478,10 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
NSWindow *window = [self window];
if (window)
resultRect.origin = [window convertBaseToScreen:resultRect.origin];
-
+
+ if (actualRange)
+ *actualRange = theRange;
+
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;
}
@@ -1318,7 +1518,7 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
_data->_page->resetDragOperation();
- _data->_page->performDragControllerAction(DragControllerActionEntered, &dragData, [[draggingInfo draggingPasteboard] name]);
+ _data->_page->dragEntered(&dragData, [[draggingInfo draggingPasteboard] name]);
return NSDragOperationCopy;
}
@@ -1327,7 +1527,7 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]);
IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
- _data->_page->performDragControllerAction(DragControllerActionUpdated, &dragData, [[draggingInfo draggingPasteboard] name]);
+ _data->_page->dragUpdated(&dragData, [[draggingInfo draggingPasteboard] name]);
return _data->_page->dragOperation();
}
@@ -1336,7 +1536,7 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]);
IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
- _data->_page->performDragControllerAction(DragControllerActionExited, &dragData, [[draggingInfo draggingPasteboard] name]);
+ _data->_page->dragExited(&dragData, [[draggingInfo draggingPasteboard] name]);
_data->_page->resetDragOperation();
}
@@ -1345,15 +1545,53 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
return YES;
}
+// FIXME: This code is more or less copied from Pasteboard::getBestURL.
+// It would be nice to be able to share the code somehow.
+static void maybeCreateSandboxExtensionFromPasteboard(NSPasteboard *pasteboard, SandboxExtension::Handle& sandboxExtensionHandle)
+{
+ NSArray *types = [pasteboard types];
+ if (![types containsObject:NSFilenamesPboardType])
+ return;
+
+ NSArray *files = [pasteboard propertyListForType:NSFilenamesPboardType];
+ if ([files count] != 1)
+ return;
+
+ NSString *file = [files objectAtIndex:0];
+ BOOL isDirectory;
+ if (![[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory])
+ return;
+
+ if (isDirectory)
+ return;
+
+ SandboxExtension::createHandle("/", SandboxExtension::ReadOnly, sandboxExtensionHandle);
+}
+
- (BOOL)performDragOperation:(id <NSDraggingInfo>)draggingInfo
{
IntPoint client([self convertPoint:[draggingInfo draggingLocation] fromView:nil]);
IntPoint global(globalPoint([draggingInfo draggingLocation], [self window]));
DragData dragData(draggingInfo, client, global, static_cast<DragOperation>([draggingInfo draggingSourceOperationMask]), [self applicationFlags:draggingInfo]);
- _data->_page->performDragControllerAction(DragControllerActionPerformDrag, &dragData, [[draggingInfo draggingPasteboard] name]);
+
+ SandboxExtension::Handle sandboxExtensionHandle;
+ maybeCreateSandboxExtensionFromPasteboard([draggingInfo draggingPasteboard], sandboxExtensionHandle);
+
+ _data->_page->performDrag(&dragData, [[draggingInfo draggingPasteboard] name], sandboxExtensionHandle);
+
return YES;
}
+// This code is needed to support drag and drop when the drag types cannot be matched.
+// This is the case for elements that do not place content
+// in the drag pasteboard automatically when the drag start (i.e. dragging a DIV element).
+- (NSView *)_hitTest:(NSPoint *)point dragTypes:(NSSet *)types
+{
+ if ([[self superview] mouse:*point inRect:[self frame]])
+ return self;
+ return nil;
+}
+
- (void)_updateWindowVisibility
{
_data->_page->updateWindowIsVisible(![[self window] isMiniaturized]);
@@ -1423,6 +1661,10 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
name:NSWindowDidMoveNotification object:window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowFrameDidChange:)
name:NSWindowDidResizeNotification object:window];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOffScreen:)
+ name:@"NSWindowDidOrderOffScreenNotification" object:window];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOnScreen:)
+ name:@"_NSWindowDidBecomeVisible" object:window];
}
}
@@ -1438,6 +1680,8 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidDeminiaturizeNotification object:window];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidMoveNotification object:window];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidResizeNotification object:window];
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowDidOrderOffScreenNotification" object:window];
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidBecomeVisible" object:window];
}
- (void)viewWillMoveToWindow:(NSWindow *)window
@@ -1492,15 +1736,19 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
- (void)_windowDidBecomeKey:(NSNotification *)notification
{
NSWindow *keyWindow = [notification object];
- if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet])
+ if (keyWindow == [self window] || keyWindow == [[self window] attachedSheet]) {
+ [self _updateSecureInputState];
_data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
+ }
}
- (void)_windowDidResignKey:(NSNotification *)notification
{
NSWindow *formerKeyWindow = [notification object];
- if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet])
+ if (formerKeyWindow == [self window] || formerKeyWindow == [[self window] attachedSheet]) {
+ [self _updateSecureInputState];
_data->_page->viewStateDidChange(WebPageProxy::ViewWindowIsActive);
+ }
}
- (void)_windowDidMiniaturize:(NSNotification *)notification
@@ -1518,6 +1766,16 @@ static void extractUnderlines(NSAttributedString *string, Vector<CompositionUnde
[self _updateWindowAndViewFrames];
}
+- (void)_windowDidOrderOffScreen:(NSNotification *)notification
+{
+ _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible);
+}
+
+- (void)_windowDidOrderOnScreen:(NSNotification *)notification
+{
+ _data->_page->viewStateDidChange(WebPageProxy::ViewIsVisible);
+}
+
static void drawPageBackground(CGContextRef context, WebPageProxy* page, const IntRect& rect)
{
if (!page->drawsBackground())
@@ -1667,6 +1925,7 @@ static void drawPageBackground(CGContextRef context, WebPageProxy* page, const I
// NSPrintOperation takes ownership of the view.
NSPrintOperation *printOperation = [NSPrintOperation printOperationWithView:printingView.get()];
[printOperation setCanSpawnSeparateThread:YES];
+ [printOperation setJobTitle:toImpl(frameRef)->title()];
printingView->_printOperation = printOperation;
return printOperation;
}
@@ -1706,14 +1965,6 @@ static void drawPageBackground(CGContextRef context, WebPageProxy* page, const I
[self setNeedsDisplay:YES];
}
-- (void)_takeFocus:(BOOL)forward
-{
- if (forward)
- [[self window] selectKeyViewFollowingView:self];
- else
- [[self window] selectKeyViewPrecedingView:self];
-}
-
- (void)_setCursor:(NSCursor *)cursor
{
if ([NSCursor currentCursor] == cursor)
@@ -1744,27 +1995,34 @@ static void drawPageBackground(CGContextRef context, WebPageProxy* page, const I
_data->_keyDownEventBeingResent = nullptr;
}
-- (Vector<KeypressCommand>&)_interceptKeyEvent:(NSEvent *)theEvent
+- (BOOL)_interpretKeyEvent:(NSEvent *)event savingCommandsTo:(Vector<WebCore::KeypressCommand>&)commands
{
- ASSERT(!_data->_isInInterpretKeyEvents);
+ ASSERT(!_data->_interpretKeyEventsParameters);
+ ASSERT(commands.isEmpty());
- _data->_isInInterpretKeyEvents = true;
- _data->_commandsList.clear();
+ if ([event type] == NSFlagsChanged)
+ return NO;
- // Calling interpretKeyEvents will trigger one or more calls to doCommandBySelector and insertText
- // that will populate the commandsList vector.
- [self interpretKeyEvents:[NSArray arrayWithObject:theEvent]];
+ WKViewInterpretKeyEventsParameters parameters;
+ parameters.eventInterpretationHadSideEffects = false;
+ parameters.executingSavedKeypressCommands = false;
+ // We assume that an input method has consumed the event, and only change this assumption if one of the NSTextInput methods is called.
+ // We assume the IM will *not* consume hotkey sequences.
+ parameters.consumedByIM = !([event modifierFlags] & NSCommandKeyMask);
+ parameters.commands = &commands;
+ _data->_interpretKeyEventsParameters = &parameters;
- _data->_isInInterpretKeyEvents = false;
+ [self interpretKeyEvents:[NSArray arrayWithObject:event]];
- return _data->_commandsList;
-}
+ _data->_interpretKeyEventsParameters = 0;
-- (void)_getTextInputState:(unsigned)start selectionEnd:(unsigned)end underlines:(Vector<CompositionUnderline>&)lines
-{
- start = _data->_selectionStart;
- end = _data->_selectionEnd;
- lines = _data->_underlines;
+ // An input method may consume an event and not tell us (e.g. when displaying a candidate window),
+ // in which case we should not bubble the event up the DOM.
+ if (parameters.consumedByIM)
+ return YES;
+
+ // If we have already executed all or some of the commands, the event is "handled". Note that there are additional checks on web process side.
+ return parameters.eventInterpretationHadSideEffects;
}
- (NSRect)_convertToDeviceSpace:(NSRect)rect
@@ -2010,6 +2268,22 @@ static void drawPageBackground(CGContextRef context, WebPageProxy* page, const I
_data->_pdfViewController->setZoomFactor(zoomFactor);
}
+- (void)_findStringInCustomRepresentation:(NSString *)string withFindOptions:(WebKit::FindOptions)options maxMatchCount:(NSUInteger)count
+{
+ if (!_data->_pdfViewController)
+ return;
+
+ _data->_pdfViewController->findString(string, options, count);
+}
+
+- (void)_countStringMatchesInCustomRepresentation:(NSString *)string withFindOptions:(WebKit::FindOptions)options maxMatchCount:(NSUInteger)count
+{
+ if (!_data->_pdfViewController)
+ return;
+
+ _data->_pdfViewController->countStringMatches(string, options, count);
+}
+
- (void)_setDragImage:(NSImage *)image at:(NSPoint)clientPoint linkDrag:(BOOL)linkDrag
{
// We need to prevent re-entering this call to avoid crashing in AppKit.
@@ -2028,6 +2302,32 @@ static void drawPageBackground(CGContextRef context, WebPageProxy* page, const I
_data->_dragHasStarted = NO;
}
+- (void)_updateSecureInputState
+{
+ if (![[self window] isKeyWindow] || ([[self window] firstResponder] != self && !_data->_inBecomeFirstResponder)) {
+ if (_data->_inSecureInputState) {
+ DisableSecureEventInput();
+ _data->_inSecureInputState = NO;
+ }
+ return;
+ }
+ // WKView has a single input context for all editable areas (except for plug-ins).
+ NSTextInputContext *context = [super inputContext];
+ bool isInPasswordField = _data->_page->editorState().isInPasswordField;
+
+ if (isInPasswordField) {
+ if (!_data->_inSecureInputState)
+ EnableSecureEventInput();
+ static NSArray *romanInputSources = [[NSArray alloc] initWithObjects:&NSAllRomanInputSourcesLocaleIdentifier count:1];
+ [context setAllowedInputSourceLocales:romanInputSources];
+ } else {
+ if (_data->_inSecureInputState)
+ DisableSecureEventInput();
+ [context setAllowedInputSourceLocales:nil];
+ }
+ _data->_inSecureInputState = isInPasswordField;
+}
+
- (void)_setDrawingAreaSize:(NSSize)size
{
if (!_data->_page->drawingArea())
@@ -2053,6 +2353,16 @@ static void drawPageBackground(CGContextRef context, WebPageProxy* page, const I
}
#endif
+- (bool)_executeSavedCommandBySelector:(SEL)selector
+{
+ // The sink does two things: 1) Tells us if the responder went unhandled, and
+ // 2) prevents any NSBeep; we don't ever want to beep here.
+ RetainPtr<WKResponderChainSink> sink(AdoptNS, [[WKResponderChainSink alloc] initWithResponderChain:self]);
+ [super doCommandBySelector:selector];
+ [sink.get() detach];
+ return ![sink.get() didReceiveUnhandledCommand];
+}
+
@end
@implementation WKView (Private)
@@ -2101,3 +2411,45 @@ static void drawPageBackground(CGContextRef context, WebPageProxy* page, const I
@end
+@implementation WKResponderChainSink
+
+- (id)initWithResponderChain:(NSResponder *)chain
+{
+ self = [super init];
+ if (!self)
+ return nil;
+ _lastResponderInChain = chain;
+ while (NSResponder *next = [_lastResponderInChain nextResponder])
+ _lastResponderInChain = next;
+ [_lastResponderInChain setNextResponder:self];
+ return self;
+}
+
+- (void)detach
+{
+ [_lastResponderInChain setNextResponder:nil];
+ _lastResponderInChain = nil;
+}
+
+- (bool)didReceiveUnhandledCommand
+{
+ return _didReceiveUnhandledCommand;
+}
+
+- (void)noResponderFor:(SEL)selector
+{
+ _didReceiveUnhandledCommand = true;
+}
+
+- (void)doCommandBySelector:(SEL)selector
+{
+ _didReceiveUnhandledCommand = true;
+}
+
+- (BOOL)tryToPerform:(SEL)action with:(id)object
+{
+ _didReceiveUnhandledCommand = true;
+ return YES;
+}
+
+@end
diff --git a/Source/WebKit2/UIProcess/API/mac/WKViewInternal.h b/Source/WebKit2/UIProcess/API/mac/WKViewInternal.h
index e4a40f7..82acdcf 100644
--- a/Source/WebKit2/UIProcess/API/mac/WKViewInternal.h
+++ b/Source/WebKit2/UIProcess/API/mac/WKViewInternal.h
@@ -24,22 +24,25 @@
*/
#import "WKView.h"
-#import <WebCore/Editor.h>
-#import <WebCore/KeyboardEvent.h>
+#import "WebFindOptions.h"
+#import <wtf/Forward.h>
+#import <wtf/Vector.h>
namespace CoreIPC {
class DataReference;
}
+namespace WebCore {
+ struct KeypressCommand;
+}
+
namespace WebKit {
class DrawingAreaProxy;
class FindIndicator;
class LayerTreeContext;
}
-#if ENABLE(FULLSCREEN_API)
@class WKFullScreenWindowController;
-#endif
@interface WKView (Internal)
- (PassOwnPtr<WebKit::DrawingAreaProxy>)_createDrawingAreaProxy;
@@ -47,13 +50,12 @@ namespace WebKit {
- (void)_processDidCrash;
- (void)_pageClosed;
- (void)_didRelaunchProcess;
-- (void)_takeFocus:(BOOL)direction;
- (void)_toolTipChangedFrom:(NSString *)oldToolTip to:(NSString *)newToolTip;
- (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;
+- (BOOL)_interpretKeyEvent:(NSEvent *)theEvent savingCommandsTo:(Vector<WebCore::KeypressCommand>&)commands;
- (void)_resendKeyDownEvent:(NSEvent *)event;
+- (bool)_executeSavedCommandBySelector:(SEL)selector;
- (NSRect)_convertToDeviceSpace:(NSRect)rect;
- (NSRect)_convertToUserSpace:(NSRect)rect;
- (void)_setFindIndicator:(PassRefPtr<WebKit::FindIndicator>)findIndicator fadeOut:(BOOL)fadeOut;
@@ -68,7 +70,10 @@ namespace WebKit {
- (void)_didFinishLoadingDataForCustomRepresentationWithSuggestedFilename:(const String&)suggestedFilename dataReference:(const CoreIPC::DataReference&)dataReference;
- (double)_customRepresentationZoomFactor;
- (void)_setCustomRepresentationZoomFactor:(double)zoomFactor;
+- (void)_findStringInCustomRepresentation:(NSString *)string withFindOptions:(WebKit::FindOptions)options maxMatchCount:(NSUInteger)count;
+- (void)_countStringMatchesInCustomRepresentation:(NSString *)string withFindOptions:(WebKit::FindOptions)options maxMatchCount:(NSUInteger)count;
- (void)_setDragImage:(NSImage *)image at:(NSPoint)clientPoint linkDrag:(BOOL)linkDrag;
+- (void)_updateSecureInputState;
- (void)_setDrawingAreaSize:(NSSize)size;