#import <AppKit/NSAttributedString.h>
#endif
-#import "APIHistoryClient.h"
+#import "APILegacyContextHistoryClient.h"
+#import "APIPageConfiguration.h"
#import "AttributedString.h"
#import "ColorSpaceData.h"
#import "DataReference.h"
#import "EditingRange.h"
#import "EditorState.h"
-#import "FindIndicator.h"
-#import "FindIndicatorWindow.h"
#import "LayerTreeContext.h"
#import "Logging.h"
+#import "NativeWebGestureEvent.h"
#import "NativeWebKeyboardEvent.h"
#import "NativeWebMouseEvent.h"
#import "NativeWebWheelEvent.h"
#import "PageClientImpl.h"
#import "PasteboardTypes.h"
#import "RemoteLayerTreeDrawingAreaProxy.h"
+#import "RemoteObjectRegistry.h"
+#import "RemoteObjectRegistryMessages.h"
#import "StringUtilities.h"
#import "TextChecker.h"
#import "TextCheckerState.h"
#import "ViewSnapshotStore.h"
#import "WKAPICast.h"
#import "WKFullScreenWindowController.h"
+#import "WKImmediateActionController.h"
+#import "WKLayoutMode.h"
#import "WKPrintingView.h"
#import "WKProcessPoolInternal.h"
#import "WKStringCF.h"
#import "WKTextInputWindowController.h"
#import "WKViewInternal.h"
+#import "WKViewLayoutStrategy.h"
#import "WKViewPrivate.h"
+#import "WKWebView.h"
#import "WebBackForwardList.h"
-#import "WebContext.h"
#import "WebEventFactory.h"
+#import "WebHitTestResultData.h"
+#import "WebInspectorProxy.h"
#import "WebKit2Initialize.h"
#import "WebPage.h"
#import "WebPageGroup.h"
#import "WebPageProxy.h"
#import "WebPreferences.h"
+#import "WebProcessPool.h"
#import "WebProcessProxy.h"
#import "WebSystemInterface.h"
+#import "_WKRemoteObjectRegistryInternal.h"
#import "_WKThumbnailViewInternal.h"
#import <QuartzCore/QuartzCore.h>
#import <WebCore/AXObjectCache.h>
#import <WebCore/ColorMac.h>
+#import <WebCore/DataDetectorsSPI.h>
+#import <WebCore/DictionaryLookup.h>
#import <WebCore/DragController.h>
#import <WebCore/DragData.h>
#import <WebCore/FloatRect.h>
#import <WebCore/FileSystem.h>
#import <WebCore/KeyboardEvent.h>
#import <WebCore/LocalizedStrings.h>
+#import <WebCore/LookupSPI.h>
+#import <WebCore/NSImmediateActionGestureRecognizerSPI.h>
+#import <WebCore/NSMenuSPI.h>
#import <WebCore/PlatformEventFactoryMac.h>
#import <WebCore/PlatformScreen.h>
#import <WebCore/Region.h>
+#import <WebCore/RuntimeApplicationChecks.h>
#import <WebCore/SharedBuffer.h>
+#import <WebCore/SoftLinking.h>
#import <WebCore/TextAlternativeWithRange.h>
+#import <WebCore/TextIndicator.h>
+#import <WebCore/TextIndicatorWindow.h>
+#import <WebCore/TextUndoInsertionMarkupMac.h>
#import <WebCore/WebActionDisablingCALayerDelegate.h>
#import <WebCore/WebCoreCALayerExtras.h>
#import <WebCore/WebCoreFullScreenPlaceholderView.h>
@end
@interface NSWindow (WKNSWindowDetails)
-- (NSRect)_intersectBottomCornersWithRect:(NSRect)viewRect;
-- (void)_maskRoundedBottomCorners:(NSRect)clipRect;
+- (id)_newFirstResponderAfterResigning;
@end
#if USE(ASYNC_NSTEXTINPUTCLIENT)
CGError CGSGetScreenRectForWindow(CGSConnectionID cid, CGSWindowID wid, CGRect *rect);
};
+SOFT_LINK_CONSTANT_MAY_FAIL(Lookup, LUNotificationPopoverWillClose, NSString *)
+
using namespace WebKit;
using namespace WebCore;
};
#endif
+@class WKWindowVisibilityObserver;
+
@interface WKViewData : NSObject {
@public
std::unique_ptr<PageClientImpl> _pageClient;
#if WK_API_ENABLED
RetainPtr<WKBrowsingContextController> _browsingContextController;
+ RetainPtr<NSView> _inspectorAttachmentView;
+
+ RetainPtr<_WKRemoteObjectRegistry> _remoteObjectRegistry;
#endif
+ RetainPtr<NSTrackingArea> _primaryTrackingArea;
+
// For ToolTips.
NSToolTipTag _lastToolTipTag;
id _trackingRectOwner;
RetainPtr<NSView> _layerHostingView;
RetainPtr<id> _remoteAccessibilityChild;
-
+
// For asynchronous validation.
ValidationMap _validationMap;
- std::unique_ptr<FindIndicatorWindow> _findIndicatorWindow;
+ std::unique_ptr<TextIndicatorWindow> _textIndicatorWindow;
// We keep here the event when resending it to
// the application to distinguish the case of a new event from one
bool _inBecomeFirstResponder;
bool _inResignFirstResponder;
+ BOOL _willBecomeFirstResponderAgain;
NSEvent *_mouseDownEvent;
+ NSEvent *_pressureEvent;
BOOL _ignoringMouseDraggedEvents;
id _flagsChangedEventMonitor;
BOOL _inSecureInputState;
- NSRect _windowBottomCornerIntersectionRect;
-
- unsigned _frameSizeUpdatesDisabledCount;
BOOL _shouldDeferViewInWindowChanges;
+ NSWindow *_targetWindowForMovePreparation;
BOOL _viewInWindowChangeWasDeferred;
BOOL _useContentPreparationRectForVisibleRect;
BOOL _windowOcclusionDetectionEnabled;
+ RetainPtr<WKWindowVisibilityObserver> _windowVisibilityObserver;
+
std::unique_ptr<ViewGestureController> _gestureController;
BOOL _allowsMagnification;
+ BOOL _ignoresNonWheelEvents;
+ BOOL _ignoresAllEvents;
BOOL _allowsBackForwardNavigationGestures;
+ BOOL _allowsLinkPreview;
+
+ RetainPtr<WKViewLayoutStrategy> _layoutStrategy;
+ WKLayoutMode _lastRequestedLayoutMode;
+ float _lastRequestedViewScale;
RetainPtr<CALayer> _rootLayer;
+ BOOL _didScheduleSetTopContentInset;
+ CGFloat _topContentInset;
+ CGFloat _totalHeightOfBanners;
+
+ CGFloat _overrideDeviceScaleFactor;
+
+ BOOL _didRegisterForLookupPopoverCloseNotifications;
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ BOOL _automaticallyAdjustsContentInsets;
+ RetainPtr<WKImmediateActionController> _immediateActionController;
+ RetainPtr<NSImmediateActionGestureRecognizer> _immediateActionGestureRecognizer;
+#endif
+
#if WK_API_ENABLED
_WKThumbnailView *_thumbnailView;
#endif
@implementation WKViewData
@end
+@interface WKWindowVisibilityObserver : NSObject {
+ WKView *_view;
+}
+
+- (instancetype)initWithView:(WKView *)view;
+- (void)startObserving:(NSWindow *)window;
+- (void)stopObserving:(NSWindow *)window;
+@end
+
+@implementation WKWindowVisibilityObserver
+
+- (instancetype)initWithView:(WKView *)view
+{
+ self = [super init];
+ if (!self)
+ return nil;
+
+ _view = view;
+ return self;
+}
+
+- (void)startObserving:(NSWindow *)window
+{
+ // An NSView derived object such as WKView cannot observe these notifications, because NSView itself observes them.
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOffScreen:)
+ name:@"NSWindowDidOrderOffScreenNotification" object:window];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidOrderOnScreen:)
+ name:@"_NSWindowDidBecomeVisible" object:window];
+}
+
+- (void)stopObserving:(NSWindow *)window
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowDidOrderOffScreenNotification" object:window];
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidBecomeVisible" object:window];
+}
+
+- (void)_windowDidOrderOnScreen:(NSNotification *)notification
+{
+ [_view _windowDidOrderOnScreen:notification];
+}
+
+- (void)_windowDidOrderOffScreen:(NSNotification *)notification
+{
+ [_view _windowDidOrderOffScreen:notification];
+}
+
+@end
+
@interface WKResponderChainSink : NSResponder {
NSResponder *_lastResponderInChain;
bool _didReceiveUnhandledCommand;
- (void)dealloc
{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ [_data->_immediateActionController willDestroyView:self];
+#endif
+ [_data->_layoutStrategy willDestroyView:self];
+
+#if WK_API_ENABLED
+ if (_data->_remoteObjectRegistry) {
+ _data->_page->process().processPool().removeMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), _data->_page->pageID());
+ [_data->_remoteObjectRegistry _invalidate];
+ }
+#endif
+
_data->_page->close();
#if WK_API_ENABLED
NSNotificationCenter* workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
[workspaceNotificationCenter removeObserver:self name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
- WebContext::statistics().wkViewCount--;
+ if (canLoadLUNotificationPopoverWillClose())
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:getLUNotificationPopoverWillClose() object:nil];
+
+ WebProcessPool::statistics().wkViewCount--;
[super dealloc];
}
- (WKBrowsingContextController *)browsingContextController
{
if (!_data->_browsingContextController)
- _data->_browsingContextController = [[WKBrowsingContextController alloc] _initWithPageRef:toAPI(_data->_page.get())];
+ _data->_browsingContextController = adoptNS([[WKBrowsingContextController alloc] _initWithPageRef:toAPI(_data->_page.get())]);
return _data->_browsingContextController.get();
}
- (BOOL)becomeFirstResponder
{
+ // If we just became first responder again, there is no need to do anything,
+ // since resignFirstResponder has correctly detected this situation.
+ if (_data->_willBecomeFirstResponderAgain) {
+ _data->_willBecomeFirstResponderAgain = NO;
+ return YES;
+ }
+
NSSelectionDirection direction = [[self window] keyViewSelectionDirection];
_data->_inBecomeFirstResponder = true;
[self _updateSecureInputState];
_data->_page->viewStateDidChange(ViewState::IsFocused);
+ // Restore the selection in the editable region if resigning first responder cleared selection.
+ _data->_page->restoreSelectionInFocusedEditableElement();
_data->_inBecomeFirstResponder = false;
NSEvent *keyboardEvent = nil;
if ([event type] == NSKeyDown || [event type] == NSKeyUp)
keyboardEvent = event;
- _data->_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, Vector<KeypressCommand>()));
+ _data->_page->setInitialFocus(direction == NSSelectingNext, keyboardEvent != nil, NativeWebKeyboardEvent(keyboardEvent, false, Vector<KeypressCommand>()), [](WebKit::CallbackBase::Error) { });
}
return YES;
}
- (BOOL)resignFirstResponder
{
+#if WK_API_ENABLED
+ // Predict the case where we are losing first responder status only to
+ // gain it back again. We want resignFirstResponder to do nothing in that case.
+ id nextResponder = [[self window] _newFirstResponderAfterResigning];
+ if ([nextResponder isKindOfClass:[WKWebView class]] && self.superview == nextResponder) {
+ _data->_willBecomeFirstResponderAgain = YES;
+ return YES;
+ }
+#endif
+
+ _data->_willBecomeFirstResponderAgain = NO;
_data->_inResignFirstResponder = true;
#if USE(ASYNC_NSTEXTINPUTCLIENT)
- (void)viewWillStartLiveResize
{
_data->_page->viewWillStartLiveResize();
+
+ [_data->_layoutStrategy willStartLiveResize];
}
- (void)viewDidEndLiveResize
{
_data->_page->viewWillEndLiveResize();
+
+ [_data->_layoutStrategy didEndLiveResize];
}
- (BOOL)isFlipped
{
[super setFrameSize:size];
- if (![self frameSizeUpdatesDisabled]) {
- if (_data->_clipsToVisibleRect)
- [self _updateViewExposedRect];
- [self _setDrawingAreaSize:size];
- }
+ [_data->_layoutStrategy didChangeFrameSize];
}
- (void)_updateWindowAndViewFrames
- (void)renewGState
{
- // Hide the find indicator.
- _data->_findIndicatorWindow = nullptr;
+ if (_data->_textIndicatorWindow)
+ [self _dismissContentRelativeChildWindowsWithAnimation:NO];
// Update the view frame.
if ([self window])
[self _updateWindowAndViewFrames];
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ [self _updateContentInsetsIfAutomatic];
+#endif
+
[super renewGState];
}
return _data->_page->readSelectionFromPasteboard([pasteboard name]);
}
+// Font panel support.
+
+- (void)updateFontPanelIfNeeded
+{
+ const EditorState& editorState = _data->_page->editorState();
+ if (editorState.selectionIsNone || !editorState.isContentEditable)
+ return;
+ if ([NSFontPanel sharedFontPanelExists] && [[NSFontPanel sharedFontPanel] isVisible]) {
+ _data->_page->fontAtSelection([](const String& fontName, double fontSize, bool selectionHasMultipleFonts, WebKit::CallbackBase::Error error) {
+ NSFont *font = [NSFont fontWithName:fontName size:fontSize];
+ if (font)
+ [[NSFontManager sharedFontManager] setSelectedFont:font isMultiple:selectionHasMultipleFonts];
+ });
+ }
+}
+
+- (void)_selectionChanged
+{
+ [self updateFontPanelIfNeeded];
+}
+
+- (void)changeFont:(id)sender
+{
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ NSFont *font = [fontManager convertFont:[fontManager selectedFont]];
+ if (!font)
+ return;
+ _data->_page->setFont([font familyName], [font pointSize], [[font fontDescriptor] symbolicTraits]);
+}
+
/*
When possible, editing-related methods should be implemented in WebCore with the
Editing-related methods still unimplemented that are implemented in WebKit1:
-- (void)capitalizeWord:(id)sender;
-- (void)changeFont:(id)sender;
- (void)complete:(id)sender;
- (void)copyFont:(id)sender;
-- (void)lowercaseWord:(id)sender;
- (void)makeBaseWritingDirectionLeftToRight:(id)sender;
- (void)makeBaseWritingDirectionNatural:(id)sender;
- (void)makeBaseWritingDirectionRightToLeft:(id)sender;
- (void)scrollLineDown:(id)sender;
- (void)scrollLineUp:(id)sender;
- (void)showGuessPanel:(id)sender;
-- (void)uppercaseWord:(id)sender;
Some other editing-related methods still unimplemented:
// If we are not already awaiting validation for this command, start the asynchronous validation process.
// FIXME: Theoretically, there is a race here; when we get the answer it might be old, from a previous time
// we asked for the same command; there is no guarantee the answer is still valid.
- _data->_page->validateCommand(commandName, [self](const String& commandName, bool isEnabled, int32_t state, CallbackBase::Error error) {
+ _data->_page->validateCommand(commandName, [self](const String& commandName, bool isEnabled, int32_t state, WebKit::CallbackBase::Error error) {
// If the process exits before the command can be validated, we'll be called back with an error.
- if (error != CallbackBase::Error::None)
+ if (error != WebKit::CallbackBase::Error::None)
return;
[self _setUserInterfaceItemState:commandName enabled:isEnabled state:state];
- (IBAction)startSpeaking:(id)sender
{
- _data->_page->getSelectionOrContentsAsString([self](const String& string, CallbackBase::Error error) {
- if (error != CallbackBase::Error::None)
+ _data->_page->getSelectionOrContentsAsString([self](const String& string, WebKit::CallbackBase::Error error) {
+ if (error != WebKit::CallbackBase::Error::None)
return;
if (!string)
return;
_data->_page->capitalizeWord();
}
-- (void)displayIfNeeded
-{
- // FIXME: We should remove this code when <rdar://problem/9362085> is resolved. In the meantime,
- // it is necessary to disable scren updates so we get a chance to redraw the corners before this
- // display is visible.
- NSWindow *window = [self window];
- BOOL shouldMaskWindow = window && !NSIsEmptyRect(_data->_windowBottomCornerIntersectionRect);
- if (shouldMaskWindow)
- NSDisableScreenUpdates();
-
- [super displayIfNeeded];
-
- if (shouldMaskWindow) {
- [window _maskRoundedBottomCorners:_data->_windowBottomCornerIntersectionRect];
- NSEnableScreenUpdates();
- _data->_windowBottomCornerIntersectionRect = NSZeroRect;
- }
-}
-
// Events
--(BOOL)shouldIgnoreMouseEvents
-{
- // FIXME: This check is surprisingly specific. Are there any other cases where we need to block mouse events?
- // Do we actually need to in thumbnail view? And if we do, what about non-mouse events?
-#if WK_API_ENABLED
- if (_data->_thumbnailView)
- return YES;
-#endif
- return NO;
-}
-
// Override this so that AppKit will send us arrow keys as key down events so we can
// support them via the key bindings mechanism.
- (BOOL)_wantsKeyDownForEvent:(NSEvent *)event
#define NATIVE_MOUSE_EVENT_HANDLER(Selector) \
- (void)Selector:(NSEvent *)theEvent \
{ \
- if ([self shouldIgnoreMouseEvents]) \
+ if (_data->_ignoresNonWheelEvents) \
+ return; \
+ if (NSTextInputContext *context = [self inputContext]) { \
+ [context handleEvent:theEvent completionHandler:^(BOOL handled) { \
+ if (handled) \
+ LOG(TextInput, "%s was handled by text input context", String(#Selector).substring(0, String(#Selector).find("Internal")).ascii().data()); \
+ else { \
+ NativeWebMouseEvent webEvent(theEvent, _data->_pressureEvent, self); \
+ _data->_page->handleMouseEvent(webEvent); \
+ } \
+ }]; \
+ return; \
+ } \
+ NativeWebMouseEvent webEvent(theEvent, _data->_pressureEvent, self); \
+ _data->_page->handleMouseEvent(webEvent); \
+ }
+#define NATIVE_MOUSE_EVENT_HANDLER_INTERNAL(Selector) \
+ - (void)Selector:(NSEvent *)theEvent \
+ { \
+ if (_data->_ignoresNonWheelEvents) \
return; \
if (NSTextInputContext *context = [self inputContext]) { \
[context handleEvent:theEvent completionHandler:^(BOOL handled) { \
if (handled) \
LOG(TextInput, "%s was handled by text input context", String(#Selector).substring(0, String(#Selector).find("Internal")).ascii().data()); \
else { \
- NativeWebMouseEvent webEvent(theEvent, self); \
+ NativeWebMouseEvent webEvent(theEvent, _data->_pressureEvent, self); \
_data->_page->handleMouseEvent(webEvent); \
} \
}]; \
return; \
} \
- NativeWebMouseEvent webEvent(theEvent, self); \
+ NativeWebMouseEvent webEvent(theEvent, _data->_pressureEvent, self); \
_data->_page->handleMouseEvent(webEvent); \
}
#else
#define NATIVE_MOUSE_EVENT_HANDLER(Selector) \
- (void)Selector:(NSEvent *)theEvent \
{ \
- if ([self shouldIgnoreMouseEvents]) \
+ if (_data->_ignoresNonWheelEvents) \
+ return; \
+ 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, _data->_pressureEvent, self); \
+ _data->_page->handleMouseEvent(webEvent); \
+ }
+#define NATIVE_MOUSE_EVENT_HANDLER_INTERNAL(Selector) \
+ - (void)Selector:(NSEvent *)theEvent \
+ { \
+ if (_data->_ignoresNonWheelEvents) \
return; \
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); \
+ NativeWebMouseEvent webEvent(theEvent, _data->_pressureEvent, self); \
_data->_page->handleMouseEvent(webEvent); \
}
#endif
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)
+NATIVE_MOUSE_EVENT_HANDLER_INTERNAL(mouseMovedInternal)
+NATIVE_MOUSE_EVENT_HANDLER_INTERNAL(mouseDownInternal)
+NATIVE_MOUSE_EVENT_HANDLER_INTERNAL(mouseUpInternal)
+NATIVE_MOUSE_EVENT_HANDLER_INTERNAL(mouseDraggedInternal)
+
#undef NATIVE_MOUSE_EVENT_HANDLER
- (void)_ensureGestureController
- (void)scrollWheel:(NSEvent *)event
{
- if ([self shouldIgnoreMouseEvents])
+ if (_data->_ignoresAllEvents)
return;
+ if (event.phase == NSEventPhaseBegan)
+ [self _dismissContentRelativeChildWindowsWithAnimation:NO];
+
if (_data->_allowsBackForwardNavigationGestures) {
[self _ensureGestureController];
if (_data->_gestureController->handleScrollWheelEvent(event))
- (void)swipeWithEvent:(NSEvent *)event
{
- if ([self shouldIgnoreMouseEvents])
+ if (_data->_ignoresNonWheelEvents)
return;
if (!_data->_allowsBackForwardNavigationGestures) {
- (void)mouseMoved:(NSEvent *)event
{
- if ([self shouldIgnoreMouseEvents])
+ if (_data->_ignoresNonWheelEvents)
return;
// When a view is first responder, it gets mouse moved events even when the mouse is outside its visible rect.
- (void)mouseDown:(NSEvent *)event
{
- if ([self shouldIgnoreMouseEvents])
+ if (_data->_ignoresNonWheelEvents)
return;
[self _setMouseDownEvent:event];
_data->_ignoringMouseDraggedEvents = NO;
+
[self mouseDownInternal:event];
}
- (void)mouseUp:(NSEvent *)event
{
- if ([self shouldIgnoreMouseEvents])
+ if (_data->_ignoresNonWheelEvents)
return;
[self _setMouseDownEvent:nil];
- (void)mouseDragged:(NSEvent *)event
{
- if ([self shouldIgnoreMouseEvents])
+ if (_data->_ignoresNonWheelEvents)
return;
if (_data->_ignoringMouseDraggedEvents)
[self mouseDraggedInternal:event];
}
+- (void)pressureChangeWithEvent:(NSEvent *)event
+{
+#if defined(__LP64__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 101003
+ if (event == _data->_pressureEvent)
+ return;
+
+ if (_data->_ignoresNonWheelEvents)
+ return;
+
+ if (event.phase != NSEventPhaseChanged && event.phase != NSEventPhaseBegan && event.phase != NSEventPhaseEnded)
+ return;
+
+ NativeWebMouseEvent webEvent(event, _data->_pressureEvent, self);
+ _data->_page->handleMouseEvent(webEvent);
+
+ [_data->_pressureEvent release];
+ _data->_pressureEvent = [event retain];
+#endif
+}
+
- (BOOL)acceptsFirstMouse:(NSEvent *)event
{
// There's a chance that responding to this event will run a nested event loop, and
return NO;
[self _setMouseDownEvent:event];
- bool result = _data->_page->acceptsFirstMouse([event eventNumber], WebEventFactory::createWebMouseEvent(event, self));
+ bool result = _data->_page->acceptsFirstMouse([event eventNumber], WebEventFactory::createWebMouseEvent(event, _data->_pressureEvent, self));
[self _setMouseDownEvent:nil];
return result;
}
return NO;
[self _setMouseDownEvent:event];
- bool result = _data->_page->shouldDelayWindowOrderingForEvent(WebEventFactory::createWebMouseEvent(event, self));
+ bool result = _data->_page->shouldDelayWindowOrderingForEvent(WebEventFactory::createWebMouseEvent(event, _data->_pressureEvent, self));
[self _setMouseDownEvent:nil];
return result;
}
NSString *text;
Vector<TextAlternativeWithRange> dictationAlternatives;
+ bool registerUndoGroup = false;
if (isAttributedString) {
#if USE(DICTATION_ALTERNATIVES)
collectDictationTextAlternatives(string, dictationAlternatives);
#endif
+#if USE(INSERTION_UNDO_GROUPING)
+ registerUndoGroup = shouldRegisterInsertionUndoGroup(string);
+#endif
// FIXME: We ignore most attributes from the string, so for example inserting from Character Palette loses font and glyph variation data.
text = [string string];
} else
// insertText can be called for several reasons:
// - If it's from normal key event processing (including key bindings), we save the action to perform it later.
- // - If it's from an input method, then we should go ahead and insert the text now.
+ // - If it's from an input method, then we should insert the text now.
// - 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.
Vector<KeypressCommand>* keypressCommands = _data->_collectedKeypressCommands;
String eventText = text;
eventText.replace(NSBackTabCharacter, NSTabCharacter); // same thing is done in KeyEventMac.mm in WebCore
if (!dictationAlternatives.isEmpty())
- _data->_page->insertDictatedTextAsync(eventText, replacementRange, dictationAlternatives);
+ _data->_page->insertDictatedTextAsync(eventText, replacementRange, dictationAlternatives, registerUndoGroup);
else
- _data->_page->insertTextAsync(eventText, replacementRange);
+ _data->_page->insertTextAsync(eventText, replacementRange, registerUndoGroup);
}
- (void)selectedRangeWithCompletionHandler:(void(^)(NSRange selectedRange))completionHandlerPtr
RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
LOG(TextInput, "selectedRange");
- _data->_page->getSelectedRangeAsync([completionHandler](const EditingRange& editingRangeResult, CallbackBase::Error error) {
+ _data->_page->getSelectedRangeAsync([completionHandler](const EditingRange& editingRangeResult, WebKit::CallbackBase::Error error) {
void (^completionHandlerBlock)(NSRange) = (void (^)(NSRange))completionHandler.get();
- if (error != CallbackBase::Error::None) {
+ if (error != WebKit::CallbackBase::Error::None) {
LOG(TextInput, " ...selectedRange failed.");
completionHandlerBlock(NSMakeRange(NSNotFound, 0));
return;
RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
LOG(TextInput, "markedRange");
- _data->_page->getMarkedRangeAsync([completionHandler](const EditingRange& editingRangeResult, CallbackBase::Error error) {
+ _data->_page->getMarkedRangeAsync([completionHandler](const EditingRange& editingRangeResult, WebKit::CallbackBase::Error error) {
void (^completionHandlerBlock)(NSRange) = (void (^)(NSRange))completionHandler.get();
- if (error != CallbackBase::Error::None) {
+ if (error != WebKit::CallbackBase::Error::None) {
LOG(TextInput, " ...markedRange failed.");
completionHandlerBlock(NSMakeRange(NSNotFound, 0));
return;
RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
LOG(TextInput, "hasMarkedText");
- _data->_page->getMarkedRangeAsync([completionHandler](const EditingRange& editingRangeResult, CallbackBase::Error error) {
+ _data->_page->getMarkedRangeAsync([completionHandler](const EditingRange& editingRangeResult, WebKit::CallbackBase::Error error) {
void (^completionHandlerBlock)(BOOL) = (void (^)(BOOL))completionHandler.get();
- if (error != CallbackBase::Error::None) {
+ if (error != WebKit::CallbackBase::Error::None) {
LOG(TextInput, " ...hasMarkedText failed.");
completionHandlerBlock(NO);
return;
RetainPtr<id> completionHandler = adoptNS([completionHandlerPtr copy]);
LOG(TextInput, "attributedSubstringFromRange:(%u, %u)", nsRange.location, nsRange.length);
- _data->_page->attributedSubstringForCharacterRangeAsync(nsRange, [completionHandler](const AttributedString& string, const EditingRange& actualRange, CallbackBase::Error error) {
+ _data->_page->attributedSubstringForCharacterRangeAsync(nsRange, [completionHandler](const AttributedString& string, const EditingRange& actualRange, WebKit::CallbackBase::Error error) {
void (^completionHandlerBlock)(NSAttributedString *, NSRange) = (void (^)(NSAttributedString *, NSRange))completionHandler.get();
- if (error != CallbackBase::Error::None) {
+ if (error != WebKit::CallbackBase::Error::None) {
LOG(TextInput, " ...attributedSubstringFromRange failed.");
completionHandlerBlock(0, NSMakeRange(NSNotFound, 0));
return;
return;
}
- _data->_page->firstRectForCharacterRangeAsync(theRange, [self, completionHandler](const IntRect& rect, const EditingRange& actualRange, CallbackBase::Error error) {
+ _data->_page->firstRectForCharacterRangeAsync(theRange, [self, completionHandler](const IntRect& rect, const EditingRange& actualRange, WebKit::CallbackBase::Error error) {
void (^completionHandlerBlock)(NSRect, NSRange) = (void (^)(NSRect, NSRange))completionHandler.get();
- if (error != CallbackBase::Error::None) {
+ if (error != WebKit::CallbackBase::Error::None) {
LOG(TextInput, " ...firstRectForCharacterRange failed.");
completionHandlerBlock(NSZeroRect, NSMakeRange(NSNotFound, 0));
return;
#pragma clang diagnostic pop
thePoint = [self convertPoint:thePoint fromView:nil]; // the point is relative to the main frame
- _data->_page->characterIndexForPointAsync(IntPoint(thePoint), [completionHandler](uint64_t result, CallbackBase::Error error) {
+ _data->_page->characterIndexForPointAsync(IntPoint(thePoint), [completionHandler](uint64_t result, WebKit::CallbackBase::Error error) {
void (^completionHandlerBlock)(NSUInteger) = (void (^)(NSUInteger))completionHandler.get();
- if (error != CallbackBase::Error::None) {
+ if (error != WebKit::CallbackBase::Error::None) {
LOG(TextInput, " ...characterIndexForPoint failed.");
completionHandlerBlock(0);
return;
- (BOOL)performKeyEquivalent:(NSEvent *)event
{
+ if (_data->_ignoresNonWheelEvents)
+ 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.
- (void)keyUp:(NSEvent *)theEvent
{
+ if (_data->_ignoresNonWheelEvents)
+ return;
+
LOG(TextInput, "keyUp:%p %@", theEvent, theEvent);
[self _interpretKeyEvent:theEvent completionHandler:^(BOOL handledByInputMethod, const Vector<KeypressCommand>& commands) {
- (void)keyDown:(NSEvent *)theEvent
{
+ if (_data->_ignoresNonWheelEvents)
+ return;
+
LOG(TextInput, "keyDown:%p %@%s", theEvent, theEvent, (theEvent == _data->_keyDownEventBeingResent) ? " (re-sent)" : "");
if ([self _tryHandlePluginComplexTextInputKeyDown:theEvent]) {
- (void)flagsChanged:(NSEvent *)theEvent
{
+ if (_data->_ignoresNonWheelEvents)
+ return;
+
LOG(TextInput, "flagsChanged:%p %@", theEvent, theEvent);
unsigned short keyCode = [theEvent keyCode];
// 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.
+ // - If it's from an input method, then we should 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.
- (BOOL)performKeyEquivalent:(NSEvent *)event
{
+ if (_data->_ignoresNonWheelEvents)
+ 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.
- (void)keyUp:(NSEvent *)theEvent
{
+ if (_data->_ignoresNonWheelEvents)
+ return;
+
LOG(TextInput, "keyUp:%p %@", theEvent, theEvent);
// We don't interpret the keyUp event, as this breaks key bindings (see <https://bugs.webkit.org/show_bug.cgi?id=130100>).
_data->_page->handleKeyboardEvent(NativeWebKeyboardEvent(theEvent, false, Vector<KeypressCommand>()));
- (void)keyDown:(NSEvent *)theEvent
{
+ if (_data->_ignoresNonWheelEvents)
+ return;
+
LOG(TextInput, "keyDown:%p %@%s", theEvent, theEvent, (theEvent == _data->_keyDownEventBeingResent) ? " (re-sent)" : "");
// There's a chance that responding to this event will run a nested event loop, and
- (void)flagsChanged:(NSEvent *)theEvent
{
+ if (_data->_ignoresNonWheelEvents)
+ return;
+
LOG(TextInput, "flagsChanged:%p %@", theEvent, theEvent);
// There's a chance that responding to this event will run a nested event loop, and
#if USE(DICTATION_ALTERNATIVES)
NSTextAlternativesAttributeName,
#endif
+#if USE(INSERTION_UNDO_GROUPING)
+ NSTextInsertionUndoableAttributeName,
+#endif
nil];
// NSText also supports the following attributes, but it's
// hard to tell which are really required for text input to
return NSMouseInRect(localPoint, visibleThumbRect, [self isFlipped]);
}
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+static void* keyValueObservingContext = &keyValueObservingContext;
+#endif
+
- (void)addWindowObserversForWindow:(NSWindow *)window
{
if (window) {
name:NSWindowDidMoveNotification object:window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidResize:)
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];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeBackingProperties:)
name:NSWindowDidChangeBackingPropertiesNotification object:window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeScreen:)
name:NSWindowDidChangeScreenNotification object:window];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeLayerHosting:)
name:@"_NSWindowDidChangeContentsHostedInLayerSurfaceNotification" object:window];
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_windowDidChangeOcclusionState:)
name:NSWindowDidChangeOcclusionStateNotification object:window];
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ [window addObserver:self forKeyPath:@"contentLayoutRect" options:NSKeyValueObservingOptionInitial context:keyValueObservingContext];
+ [window addObserver:self forKeyPath:@"titlebarAppearsTransparent" options:NSKeyValueObservingOptionInitial context:keyValueObservingContext];
#endif
+ [_data->_windowVisibilityObserver startObserving:window];
}
}
+- (void)_addFontPanelObserver
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ [[NSFontPanel sharedFontPanel] addObserver:self forKeyPath:@"visible" options:0 context:keyValueObservingContext];
+#endif
+}
+
- (void)removeWindowObservers
{
- NSWindow *window = [self window];
+ NSWindow *window = _data->_targetWindowForMovePreparation ? _data->_targetWindowForMovePreparation : [self window];
if (!window)
return;
[[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:@"NSWindowWillOrderOffScreenNotification" object:window];
- [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSWindowDidOrderOffScreenNotification" object:window];
- [[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidBecomeVisible" object:window];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidChangeBackingPropertiesNotification object:window];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidChangeScreenNotification object:window];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"_NSWindowDidChangeContentsHostedInLayerSurfaceNotification" object:window];
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSWindowDidChangeOcclusionStateNotification object:window];
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ if (_data->_page->isEditable())
+ [[NSFontPanel sharedFontPanel] removeObserver:self forKeyPath:@"visible" context:keyValueObservingContext];
+ [window removeObserver:self forKeyPath:@"contentLayoutRect" context:keyValueObservingContext];
+ [window removeObserver:self forKeyPath:@"titlebarAppearsTransparent" context:keyValueObservingContext];
#endif
+ [_data->_windowVisibilityObserver stopObserving:window];
}
- (void)viewWillMoveToWindow:(NSWindow *)window
{
+ // If we're in the middle of preparing to move to a window, we should only be moved to that window.
+ ASSERT(!_data->_targetWindowForMovePreparation || (_data->_targetWindowForMovePreparation == window));
+
NSWindow *currentWindow = [self window];
if (window == currentWindow)
return;
- (void)viewDidMoveToWindow
{
- if ([self window]) {
+ NSWindow *window = _data->_targetWindowForMovePreparation ? _data->_targetWindowForMovePreparation : self.window;
+
+ if (window) {
[self doWindowDidChangeScreen];
ViewState::Flags viewStateChanges = ViewState::WindowIsActive | ViewState::IsVisible;
[self _updateWindowAndViewFrames];
+ // FIXME(135509) This call becomes unnecessary once 135509 is fixed; remove.
+ _data->_page->layerHostingModeDidChange();
+
if (!_data->_flagsChangedEventMonitor) {
_data->_flagsChangedEventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:NSFlagsChangedMask handler:^(NSEvent *flagsChangedEvent) {
[self _postFakeMouseMovedEventForFlagsChangedEvent:flagsChangedEvent];
}
[self _accessibilityRegisterUIProcessTokens];
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ if (_data->_immediateActionGestureRecognizer && ![[self gestureRecognizers] containsObject:_data->_immediateActionGestureRecognizer.get()] && !_data->_ignoresNonWheelEvents && _data->_allowsLinkPreview)
+ [self addGestureRecognizer:_data->_immediateActionGestureRecognizer.get()];
+#endif
} else {
ViewState::Flags viewStateChanges = ViewState::WindowIsActive | ViewState::IsVisible;
if ([self isDeferringViewInWindowChanges])
[NSEvent removeMonitor:_data->_flagsChangedEventMonitor];
_data->_flagsChangedEventMonitor = nil;
- WKHideWordDefinitionWindow();
+ [self _dismissContentRelativeChildWindowsWithAnimation:NO];
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ if (_data->_immediateActionGestureRecognizer)
+ [self removeGestureRecognizer:_data->_immediateActionGestureRecognizer.get()];
+#endif
}
_data->_page->setIntrinsicDeviceScaleFactor([self _intrinsicDeviceScaleFactor]);
- (void)doWindowDidChangeScreen
{
- _data->_page->windowScreenDidChange((PlatformDisplayID)[[[[[self window] screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
+ NSWindow *window = _data->_targetWindowForMovePreparation ? _data->_targetWindowForMovePreparation : self.window;
+ _data->_page->windowScreenDidChange((PlatformDisplayID)[[[[window screen] deviceDescription] objectForKey:@"NSScreenNumber"] intValue]);
}
- (void)_windowDidBecomeKey:(NSNotification *)notification
_data->_page->setIntrinsicDeviceScaleFactor(newBackingScaleFactor);
}
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
- (void)_windowDidChangeOcclusionState:(NSNotification *)notification
{
_data->_page->viewStateDidChange(ViewState::IsVisible);
}
-#endif
- (void)drawRect:(NSRect)rect
{
- LOG(View, "drawRect: x:%g, y:%g, width:%g, height:%g", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+ LOG(Printing, "drawRect: x:%g, y:%g, width:%g, height:%g", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
_data->_page->endPrinting();
}
_data->_page->viewStateDidChange(ViewState::IsVisible);
}
-- (void)_applicationWillTerminate:(NSNotification *)notification
+- (void)_prepareForDictionaryLookup
{
- _data->_page->process().context().applicationWillTerminate();
+ if (_data->_didRegisterForLookupPopoverCloseNotifications)
+ return;
+
+ _data->_didRegisterForLookupPopoverCloseNotifications = YES;
+
+ if (canLoadLUNotificationPopoverWillClose())
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_dictionaryLookupPopoverWillClose:) name:getLUNotificationPopoverWillClose() object:nil];
+}
+
+- (void)_dictionaryLookupPopoverWillClose:(NSNotification *)notification
+{
+ [self _clearTextIndicatorWithAnimation:TextIndicatorWindowDismissalAnimation::None];
}
- (void)_accessibilityRegisterUIProcessTokens
NSEvent *fakeEvent = [NSEvent mouseEventWithType:NSMouseMoved location:[[flagsChangedEvent window] mouseLocationOutsideOfEventStream]
modifierFlags:[flagsChangedEvent modifierFlags] timestamp:[flagsChangedEvent timestamp] windowNumber:[flagsChangedEvent windowNumber]
context:[flagsChangedEvent context] eventNumber:0 clickCount:0 pressure:0];
- NativeWebMouseEvent webEvent(fakeEvent, self);
+ NativeWebMouseEvent webEvent(fakeEvent, _data->_pressureEvent, self);
_data->_page->handleMouseEvent(webEvent);
}
- (float)_intrinsicDeviceScaleFactor
{
- NSWindow *window = [self window];
- if (window)
+ if (_data->_overrideDeviceScaleFactor)
+ return _data->_overrideDeviceScaleFactor;
+ if (_data->_targetWindowForMovePreparation)
+ return [_data->_targetWindowForMovePreparation backingScaleFactor];
+ if (NSWindow *window = [self window])
return [window backingScaleFactor];
return [[NSScreen mainScreen] backingScaleFactor];
}
_data->_resizeScrollOffset = NSZeroSize;
}
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
- (void)quickLookWithEvent:(NSEvent *)event
{
+ if (_data->_ignoresNonWheelEvents)
+ return;
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ if (_data->_immediateActionGestureRecognizer) {
+ [super quickLookWithEvent:event];
+ return;
+ }
+#endif
+
NSPoint locationInViewCoordinates = [self convertPoint:[event locationInWindow] fromView:nil];
_data->_page->performDictionaryLookupAtLocation(FloatPoint(locationInViewCoordinates.x, locationInViewCoordinates.y));
}
-#endif
- (std::unique_ptr<WebKit::DrawingAreaProxy>)_createDrawingAreaProxy
{
if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"WebKit2UseRemoteLayerTreeDrawingArea"] boolValue])
- return std::make_unique<RemoteLayerTreeDrawingAreaProxy>(_data->_page.get());
+ return std::make_unique<RemoteLayerTreeDrawingAreaProxy>(*_data->_page);
- return std::make_unique<TiledCoreAnimationDrawingAreaProxy>(_data->_page.get());
+ return std::make_unique<TiledCoreAnimationDrawingAreaProxy>(*_data->_page);
}
- (BOOL)_isFocused
- (WebKit::ColorSpaceData)_colorSpace
{
if (!_data->_colorSpace) {
- if ([self window])
- _data->_colorSpace = [[self window] colorSpace];
+ if (_data->_targetWindowForMovePreparation)
+ _data->_colorSpace = [_data->_targetWindowForMovePreparation colorSpace];
+ else if (NSWindow *window = [self window])
+ _data->_colorSpace = [window colorSpace];
else
_data->_colorSpace = [[NSScreen mainScreen] colorSpace];
}
- (void)_processDidExit
{
+ [self _notifyInputContextAboutDiscardedComposition];
+
if (_data->_layerHostingView)
[self _setAcceleratedCompositingModeRootLayer:nil];
}
}
-- (void)_setFindIndicator:(PassRefPtr<FindIndicator>)findIndicator fadeOut:(BOOL)fadeOut animate:(BOOL)animate
+- (void)_setTextIndicator:(TextIndicator&)textIndicator
{
- if (!findIndicator) {
- _data->_findIndicatorWindow = nullptr;
- return;
- }
+ [self _setTextIndicator:textIndicator withLifetime:TextIndicatorWindowLifetime::Permanent];
+}
+
+- (void)_setTextIndicator:(TextIndicator&)textIndicator withLifetime:(TextIndicatorWindowLifetime)lifetime
+{
+ if (!_data->_textIndicatorWindow)
+ _data->_textIndicatorWindow = std::make_unique<TextIndicatorWindow>(self);
+
+ NSRect textBoundingRectInScreenCoordinates = [self.window convertRectToScreen:[self convertRect:textIndicator.textBoundingRectInRootViewCoordinates() toView:nil]];
+ _data->_textIndicatorWindow->setTextIndicator(textIndicator, NSRectToCGRect(textBoundingRectInScreenCoordinates), lifetime);
+}
- if (!_data->_findIndicatorWindow)
- _data->_findIndicatorWindow = std::make_unique<FindIndicatorWindow>(self);
+- (void)_clearTextIndicatorWithAnimation:(TextIndicatorWindowDismissalAnimation)animation
+{
+ if (_data->_textIndicatorWindow)
+ _data->_textIndicatorWindow->clearTextIndicator(animation);
+ _data->_textIndicatorWindow = nullptr;
+}
- _data->_findIndicatorWindow->setFindIndicator(findIndicator, fadeOut, animate);
+- (void)_setTextIndicatorAnimationProgress:(float)progress
+{
+ if (_data->_textIndicatorWindow)
+ _data->_textIndicatorWindow->setAnimationProgress(progress);
}
- (CALayer *)_rootLayer
return _data->_rootLayer.get();
}
-- (ViewSnapshot)_takeViewSnapshot
+static RetainPtr<CGImageRef> takeWindowSnapshot(CGSWindowID windowID, bool captureAtNominalResolution)
{
- NSWindow *window = self.window;
+ CGSWindowCaptureOptions options = kCGSCaptureIgnoreGlobalClipShape;
+ if (captureAtNominalResolution)
+ options |= kCGSWindowCaptureNominalResolution;
+ RetainPtr<CFArrayRef> windowSnapshotImages = adoptCF(CGSHWCaptureWindowList(CGSMainConnectionID(), &windowID, 1, options));
- ViewSnapshot snapshot;
+ if (windowSnapshotImages && CFArrayGetCount(windowSnapshotImages.get()))
+ return (CGImageRef)CFArrayGetValueAtIndex(windowSnapshotImages.get(), 0);
+
+ // Fall back to the non-hardware capture path if we didn't get a snapshot
+ // (which usually happens if the window is fully off-screen).
+ CGWindowImageOption imageOptions = kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque;
+ if (captureAtNominalResolution)
+ imageOptions |= kCGWindowImageNominalResolution;
+ return adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, imageOptions));
+}
+
+- (PassRefPtr<ViewSnapshot>)_takeViewSnapshot
+{
+ NSWindow *window = self.window;
CGSWindowID windowID = (CGSWindowID)[window windowNumber];
- if (!windowID)
- return snapshot;
+ if (!windowID || ![window isVisible])
+ return nullptr;
- RetainPtr<CGImageRef> windowSnapshotImage = adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque));
+ RetainPtr<CGImageRef> windowSnapshotImage = takeWindowSnapshot(windowID, false);
+ if (!windowSnapshotImage)
+ return nullptr;
// Work around <rdar://problem/17084993>; re-request the snapshot at kCGWindowImageNominalResolution if it was captured at the wrong scale.
CGFloat desiredSnapshotWidth = window.frame.size.width * window.screen.backingScaleFactor;
if (CGImageGetWidth(windowSnapshotImage.get()) != desiredSnapshotWidth)
- windowSnapshotImage = adoptCF(CGWindowListCreateImage(CGRectNull, kCGWindowListOptionIncludingWindow, windowID, kCGWindowImageBoundsIgnoreFraming | kCGWindowImageShouldBeOpaque | kCGWindowImageNominalResolution));
+ windowSnapshotImage = takeWindowSnapshot(windowID, true);
+
+ if (!windowSnapshotImage)
+ return nullptr;
[self _ensureGestureController];
auto croppedSnapshotImage = adoptCF(CGImageCreateWithImageInRect(windowSnapshotImage.get(), NSRectToCGRect([window convertRectToBacking:croppedImageRect])));
- snapshot.image = croppedSnapshotImage.get();
+ auto surface = IOSurface::createFromImage(croppedSnapshotImage.get());
+ if (!surface)
+ return nullptr;
+ surface->setIsVolatile(true);
- IntSize imageSize(CGImageGetWidth(croppedSnapshotImage.get()), CGImageGetHeight(croppedSnapshotImage.get()));
- snapshot.size = imageSize;
- snapshot.imageSizeInBytes = imageSize.width() * imageSize.height() * 4;
-
- return snapshot;
+ return ViewSnapshot::create(WTF::move(surface));
}
- (void)_wheelEventWasNotHandledByWebCore:(NSEvent *)event
}
if (inputSourceChanged) {
- // The input source changed, go ahead and discard any entered text.
+ // The input source changed; discard any entered text.
[[WKTextInputWindowController sharedTextInputWindowController] unmarkText];
}
[self _setPluginComplexTextInputState:pluginComplexTextInputState];
}
-- (void)_setDragImage:(NSImage *)image at:(NSPoint)clientPoint linkDrag:(BOOL)linkDrag
+- (void)_dragImageForView:(NSView *)view withImage:(NSImage *)image at:(NSPoint)clientPoint linkDrag:(BOOL)linkDrag
{
- IntSize size([image size]);
- size.scale(1.0 / _data->_page->deviceScaleFactor());
- [image setSize:size];
-
// The call below could release this WKView.
RetainPtr<WKView> protector(self);
-
+
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- [self dragImage:image
+ [view dragImage:image
at:clientPoint
offset:NSZeroSize
- event:(linkDrag) ? [NSApp currentEvent] :_data->_mouseDownEvent
+ event:(linkDrag) ? [NSApp currentEvent] : _data->_mouseDownEvent
pasteboard:[NSPasteboard pasteboardWithName:NSDragPboard]
source:self
slideBack:YES];
&& hasCaseInsensitiveSuffix(filename, @".jpg"));
}
-- (void)_setPromisedData:(WebCore::Image *)image withFileName:(NSString *)filename withExtension:(NSString *)extension withTitle:(NSString *)title withURL:(NSString *)url withVisibleURL:(NSString *)visibleUrl withArchive:(WebCore::SharedBuffer*) archiveBuffer forPasteboard:(NSString *)pasteboardName
-
+- (void)_setFileAndURLTypes:(NSString *)filename withExtension:(NSString *)extension withTitle:(NSString *)title withURL:(NSString *)url withVisibleURL:(NSString *)visibleUrl forPasteboard:(NSPasteboard *)pasteboard
{
- NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:pasteboardName];
- RetainPtr<NSMutableArray> types = adoptNS([[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil]);
-
- [types addObjectsFromArray:archiveBuffer ? PasteboardTypes::forImagesWithArchive() : PasteboardTypes::forImages()];
- [pasteboard declareTypes:types.get() owner:self];
if (!matchesExtensionOrEquivalent(filename, extension))
filename = [[filename stringByAppendingString:@"."] stringByAppendingString:extension];
-
+
[pasteboard setString:visibleUrl forType:NSStringPboardType];
[pasteboard setString:visibleUrl forType:PasteboardTypes::WebURLPboardType];
[pasteboard setString:title forType:PasteboardTypes::WebURLNamePboardType];
[pasteboard setPropertyList:[NSArray arrayWithObjects:[NSArray arrayWithObject:visibleUrl], [NSArray arrayWithObject:title], nil] forType:PasteboardTypes::WebURLsWithTitlesPboardType];
[pasteboard setPropertyList:[NSArray arrayWithObject:extension] forType:NSFilesPromisePboardType];
+ _data->_promisedFilename = filename;
+ _data->_promisedURL = url;
+}
+
+- (void)_setPromisedDataForImage:(WebCore::Image *)image withFileName:(NSString *)filename withExtension:(NSString *)extension withTitle:(NSString *)title withURL:(NSString *)url withVisibleURL:(NSString *)visibleUrl withArchive:(WebCore::SharedBuffer*) archiveBuffer forPasteboard:(NSString *)pasteboardName
+
+{
+ NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:pasteboardName];
+ RetainPtr<NSMutableArray> types = adoptNS([[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil]);
+
+ [types addObjectsFromArray:archiveBuffer ? PasteboardTypes::forImagesWithArchive() : PasteboardTypes::forImages()];
+ [pasteboard declareTypes:types.get() owner:self];
+ [self _setFileAndURLTypes:filename withExtension:extension withTitle:title withURL:url withVisibleURL:visibleUrl forPasteboard:pasteboard];
if (archiveBuffer)
[pasteboard setData:archiveBuffer->createNSData().get() forType:PasteboardTypes::WebArchivePboardType];
_data->_promisedImage = image;
- _data->_promisedFilename = filename;
- _data->_promisedURL = url;
}
+#if ENABLE(ATTACHMENT_ELEMENT)
+- (void)_setPromisedDataForAttachment:(NSString *)filename withExtension:(NSString *)extension withTitle:(NSString *)title withURL:(NSString *)url withVisibleURL:(NSString *)visibleUrl forPasteboard:(NSString *)pasteboardName
+
+{
+ NSPasteboard *pasteboard = [NSPasteboard pasteboardWithName:pasteboardName];
+ RetainPtr<NSMutableArray> types = adoptNS([[NSMutableArray alloc] initWithObjects:NSFilesPromisePboardType, nil]);
+ [types addObjectsFromArray:PasteboardTypes::forURL()];
+ [pasteboard declareTypes:types.get() owner:self];
+ [self _setFileAndURLTypes:filename withExtension:extension withTitle:title withURL:url withVisibleURL:visibleUrl forPasteboard:pasteboard];
+
+ RetainPtr<NSMutableArray> paths = adoptNS([[NSMutableArray alloc] init]);
+ [paths addObject:title];
+ [pasteboard setPropertyList:paths.get() forType:NSFilenamesPboardType];
+
+ _data->_promisedImage = nullptr;
+}
+#endif
+
- (void)pasteboardChangedOwner:(NSPasteboard *)pasteboard
{
- _data->_promisedImage = 0;
+ _data->_promisedImage = nullptr;
_data->_promisedFilename = "";
_data->_promisedURL = "";
}
if ([type isEqual:NSTIFFPboardType] && _data->_promisedImage) {
[pasteboard setData:(NSData *)_data->_promisedImage->getTIFFRepresentation() forType:NSTIFFPboardType];
- _data->_promisedImage = 0;
+ _data->_promisedImage = nullptr;
}
}
if (_data->_promisedImage) {
data = _data->_promisedImage->data()->createNSData();
wrapper = adoptNS([[NSFileWrapper alloc] initRegularFileWithContents:data.get()]);
- [wrapper setPreferredFilename:_data->_promisedFilename];
- }
+ } else
+ wrapper = adoptNS([[NSFileWrapper alloc] initWithURL:[NSURL URLWithString:_data->_promisedURL] options:NSFileWrapperReadingImmediate error:nil]);
- if (!wrapper) {
+ if (wrapper)
+ [wrapper setPreferredFilename:_data->_promisedFilename];
+ else {
LOG_ERROR("Failed to create image file.");
return nil;
}
[[super inputContext] discardMarkedText]; // Inform the input method that we won't have an inline input area despite having been asked to.
}
+- (NSWindow *)_targetWindowForMovePreparation
+{
+ return _data->_targetWindowForMovePreparation;
+}
+
#if ENABLE(FULLSCREEN_API)
- (BOOL)_hasFullScreenWindowController
{
[self invalidateIntrinsicContentSize];
}
-- (void)_cacheWindowBottomCornerRect
-{
- // FIXME: We should remove this code when <rdar://problem/9362085> is resolved.
- NSWindow *window = [self window];
- if (!window)
- return;
-
- _data->_windowBottomCornerIntersectionRect = [window _intersectBottomCornersWithRect:[self convertRect:[self visibleRect] toView:nil]];
- if (!NSIsEmptyRect(_data->_windowBottomCornerIntersectionRect))
- [self setNeedsDisplayInRect:[self convertRect:_data->_windowBottomCornerIntersectionRect fromView:nil]];
-}
-
- (NSInteger)spellCheckerDocumentTag
{
if (!_data->_hasSpellCheckerDocumentTag) {
return _data->_page->suppressVisibilityUpdates();
}
-- (instancetype)initWithFrame:(NSRect)frame context:(WebContext&)context configuration:(WebPageConfiguration)webPageConfiguration webView:(WKWebView *)webView
+- (NSTrackingArea *)_primaryTrackingArea
{
- self = [super initWithFrame:frame];
- if (!self)
- return nil;
+ return _data->_primaryTrackingArea.get();
+}
+
+- (void)_setPrimaryTrackingArea:(NSTrackingArea *)trackingArea
+{
+ [self removeTrackingArea:_data->_primaryTrackingArea.get()];
+ _data->_primaryTrackingArea = trackingArea;
+ [self addTrackingArea:trackingArea];
+}
+
+- (instancetype)initWithFrame:(NSRect)frame processPool:(WebProcessPool&)processPool configuration:(Ref<API::PageConfiguration>&&)configuration webView:(WKWebView *)webView
+{
+ self = [super initWithFrame:frame];
+ if (!self)
+ return nil;
[NSApp registerServicesMenuSendTypes:PasteboardTypes::forSelection() returnTypes:PasteboardTypes::forEditing()];
InitializeWebKit2();
// Legacy style scrollbars have design details that rely on tracking the mouse all the time.
- NSTrackingAreaOptions options = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingInVisibleRect;
+ NSTrackingAreaOptions options = NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingInVisibleRect | NSTrackingCursorUpdate;
if (WKRecommendedScrollerStyle() == NSScrollerStyleLegacy)
options |= NSTrackingActiveAlways;
else
options |= NSTrackingActiveInKeyWindow;
- NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:frame
- options:options
- owner:self
- userInfo:nil];
- [self addTrackingArea:trackingArea];
- [trackingArea release];
-
_data = [[WKViewData alloc] init];
+ _data->_primaryTrackingArea = adoptNS([[NSTrackingArea alloc] initWithRect:frame options:options owner:self userInfo:nil]);
+ [self addTrackingArea:_data->_primaryTrackingArea.get()];
+
_data->_pageClient = std::make_unique<PageClientImpl>(self, webView);
- _data->_page = context.createWebPage(*_data->_pageClient, std::move(webPageConfiguration));
- _data->_page->setAddsVisitedLinks(context.historyClient().addsVisitedLinks());
+ _data->_page = processPool.createWebPage(*_data->_pageClient, WTF::move(configuration));
+ _data->_page->setAddsVisitedLinks(processPool.historyClient().addsVisitedLinks());
_data->_page->setIntrinsicDeviceScaleFactor([self _intrinsicDeviceScaleFactor]);
_data->_page->initializeWebPage();
_data->_mouseDownEvent = nil;
+ _data->_pressureEvent = nil;
_data->_ignoringMouseDraggedEvents = NO;
_data->_clipsToVisibleRect = NO;
_data->_useContentPreparationRectForVisibleRect = NO;
_data->_windowOcclusionDetectionEnabled = YES;
+ _data->_lastRequestedLayoutMode = kWKLayoutModeViewSize;
+ _data->_lastRequestedViewScale = 1;
+
+ _data->_windowVisibilityObserver = adoptNS([[WKWindowVisibilityObserver alloc] initWithView:self]);
_data->_intrinsicContentSize = NSMakeSize(NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric);
_data->_needsViewFrameInWindowCoordinates = _data->_page->preferences().pluginsEnabled();
-
+
+ _data->_layoutStrategy = [WKViewLayoutStrategy layoutStrategyWithPage:*_data->_page view:self mode:kWKLayoutModeViewSize];
+
[self _registerDraggedTypes];
self.wantsLayer = YES;
// Explicitly set the layer contents placement so AppKit will make sure that our layer has masksToBounds set to YES.
self.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
- WebContext::statistics().wkViewCount++;
+ WebProcessPool::statistics().wkViewCount++;
NSNotificationCenter* workspaceNotificationCenter = [[NSWorkspace sharedWorkspace] notificationCenter];
[workspaceNotificationCenter addObserver:self selector:@selector(_activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:NSApp];
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ _data->_allowsLinkPreview = YES;
+
+ if (Class gestureClass = NSClassFromString(@"NSImmediateActionGestureRecognizer")) {
+ _data->_immediateActionGestureRecognizer = adoptNS([(NSImmediateActionGestureRecognizer *)[gestureClass alloc] init]);
+ _data->_immediateActionController = adoptNS([[WKImmediateActionController alloc] initWithPage:*_data->_page view:self recognizer:_data->_immediateActionGestureRecognizer.get()]);
+ [_data->_immediateActionGestureRecognizer setDelegate:_data->_immediateActionController.get()];
+ [_data->_immediateActionGestureRecognizer setDelaysPrimaryMouseButtonEvents:NO];
+ }
+#endif
return self;
}
[self _updateThumbnailViewLayer];
else
[self _setAcceleratedCompositingModeRootLayer:_data->_rootLayer.get()];
-
- if (!thumbnailView.usesSnapshot)
- _data->_page->viewStateDidChange(ViewState::WindowIsActive | ViewState::IsInWindow | ViewState::IsVisible);
}
- (_WKThumbnailView *)_thumbnailView
_WKThumbnailView *thumbnailView = _data->_thumbnailView;
ASSERT(thumbnailView);
- if (!thumbnailView.usesSnapshot || (thumbnailView._waitingForSnapshot && self.window))
+ if (thumbnailView._waitingForSnapshot && self.window)
[self _reparentLayerTreeInThumbnailView];
}
}
#endif // WK_API_ENABLED
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+
+- (void)_updateContentInsetsIfAutomatic
+{
+ if (!self._automaticallyAdjustsContentInsets)
+ return;
+
+ if ((self.window.styleMask & NSFullSizeContentViewWindowMask) && !self.window.titlebarAppearsTransparent && ![self enclosingScrollView]) {
+ NSRect contentLayoutRect = [self convertRect:self.window.contentLayoutRect fromView:nil];
+ CGFloat newTopContentInset = NSMaxY(contentLayoutRect) - NSHeight(contentLayoutRect);
+ if (self._topContentInset != newTopContentInset)
+ self._topContentInset = newTopContentInset;
+ } else
+ self._topContentInset = 0;
+}
+
+#endif
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ if (context != keyValueObservingContext) {
+ [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
+ return;
+ }
+
+ if ([keyPath isEqualToString:@"visible"] && [NSFontPanel sharedFontPanelExists] && object == [NSFontPanel sharedFontPanel]) {
+ [self updateFontPanelIfNeeded];
+ return;
+ }
+ if ([keyPath isEqualToString:@"contentLayoutRect"] || [keyPath isEqualToString:@"titlebarAppearsTransparent"])
+ [self _updateContentInsetsIfAutomatic];
+#endif
+}
+
+
+- (void)_didFirstVisuallyNonEmptyLayoutForMainFrame
+{
+ if (_data->_gestureController)
+ _data->_gestureController->didFirstVisuallyNonEmptyLayoutForMainFrame();
+}
+
+- (BOOL)_supportsArbitraryLayoutModes
+{
+ if ([_data->_fullScreenWindowController isFullScreen])
+ return NO;
+
+ WebPageProxy* page = _data->_page.get();
+ if (!page)
+ return YES;
+ WebFrameProxy* frame = page->mainFrame();
+ if (!frame)
+ return YES;
+
+ // If we have a plugin document in the main frame, avoid using custom WKLayoutModes
+ // and fall back to the defaults, because there's a good chance that it won't work (e.g. with PDFPlugin).
+ if (frame->containsPluginDocument())
+ return NO;
+
+ return YES;
+}
+
+- (void)_updateSupportsArbitraryLayoutModes
+{
+ if (![self _supportsArbitraryLayoutModes]) {
+ WKLayoutMode oldRequestedLayoutMode = _data->_lastRequestedLayoutMode;
+ float oldRequestedViewScale = _data->_lastRequestedViewScale;
+ [self _setViewScale:1];
+ [self _setLayoutMode:kWKLayoutModeViewSize];
+
+ // The 'last requested' parameters will have been overwritten by setting them above, but we don't
+ // want this to count as a request (only changes from the client count), so reset them.
+ _data->_lastRequestedLayoutMode = oldRequestedLayoutMode;
+ _data->_lastRequestedViewScale = oldRequestedViewScale;
+ } else if (_data->_lastRequestedLayoutMode != [_data->_layoutStrategy layoutMode]) {
+ [self _setViewScale:_data->_lastRequestedViewScale];
+ [self _setLayoutMode:_data->_lastRequestedLayoutMode];
+ }
+}
+
+#if WK_API_ENABLED
+- (_WKRemoteObjectRegistry *)_remoteObjectRegistry
+{
+ if (!_data->_remoteObjectRegistry) {
+ _data->_remoteObjectRegistry = adoptNS([[_WKRemoteObjectRegistry alloc] _initWithMessageSender:*_data->_page]);
+ _data->_page->process().processPool().addMessageReceiver(Messages::RemoteObjectRegistry::messageReceiverName(), _data->_page->pageID(), [_data->_remoteObjectRegistry remoteObjectRegistry]);
+ }
+
+ return _data->_remoteObjectRegistry.get();
+}
+
+#endif
+
+
+- (void)_didCommitLoadForMainFrame
+{
+ [self _updateSupportsArbitraryLayoutModes];
+}
+
+- (void)_didFinishLoadForMainFrame
+{
+ if (_data->_gestureController)
+ _data->_gestureController->didFinishLoadForMainFrame();
+}
+
+- (void)_didFailLoadForMainFrame
+{
+ if (_data->_gestureController)
+ _data->_gestureController->didFailLoadForMainFrame();
+}
+
+- (void)_didSameDocumentNavigationForMainFrame:(SameDocumentNavigationType)type
+{
+ if (_data->_gestureController)
+ _data->_gestureController->didSameDocumentNavigationForMainFrame(type);
+}
+
+- (void)_removeNavigationGestureSnapshot
+{
+ if (_data->_gestureController)
+ _data->_gestureController->removeSwipeSnapshot();
+}
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+
+- (void)_didPerformImmediateActionHitTest:(const WebHitTestResultData&)hitTestResult contentPreventsDefault:(BOOL)contentPreventsDefault userData:(API::Object*)userData
+{
+ [_data->_immediateActionController didPerformImmediateActionHitTest:hitTestResult contentPreventsDefault:contentPreventsDefault userData:userData];
+}
+
+#endif // __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
+- (void)_startWindowDrag
+{
+ [[self window] performWindowDragWithEvent:_data->_mouseDownEvent];
+}
+#endif
+
@end
@implementation WKView (Private)
_data->_page->recordNavigationSnapshot();
}
+- (void)saveBackForwardSnapshotForItem:(WKBackForwardListItemRef)item
+{
+ _data->_page->recordNavigationSnapshot(*toImpl(item));
+}
+
- (id)initWithFrame:(NSRect)frame contextRef:(WKContextRef)contextRef pageGroupRef:(WKPageGroupRef)pageGroupRef
{
return [self initWithFrame:frame contextRef:contextRef pageGroupRef:pageGroupRef relatedToPage:nil];
- (id)initWithFrame:(NSRect)frame contextRef:(WKContextRef)contextRef pageGroupRef:(WKPageGroupRef)pageGroupRef relatedToPage:(WKPageRef)relatedPage
{
- WebPageConfiguration webPageConfiguration;
- webPageConfiguration.pageGroup = toImpl(pageGroupRef);
- webPageConfiguration.relatedPage = toImpl(relatedPage);
+ auto configuration = API::PageConfiguration::create();
+ configuration->setProcessPool(toImpl(contextRef));
+ configuration->setPageGroup(toImpl(pageGroupRef));
+ configuration->setRelatedPage(toImpl(relatedPage));
- return [self initWithFrame:frame context:*toImpl(contextRef) configuration:webPageConfiguration webView:nil];
+ return [self initWithFrame:frame processPool:*toImpl(contextRef) configuration:WTF::move(configuration) webView:nil];
+}
+
+- (id)initWithFrame:(NSRect)frame configurationRef:(WKPageConfigurationRef)configurationRef
+{
+ Ref<API::PageConfiguration> configuration = toImpl(configurationRef)->copy();
+ auto& processPool = *configuration->processPool();
+
+ return [self initWithFrame:frame processPool:processPool configuration:WTF::move(configuration) webView:nil];
}
-#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080
- (BOOL)wantsUpdateLayer
{
return YES;
if (DrawingAreaProxy* drawingArea = _data->_page->drawingArea())
drawingArea->waitForPossibleGeometryUpdate();
}
-#endif
- (WKPageRef)pageRef
{
- (NSPrintOperation *)printOperationWithPrintInfo:(NSPrintInfo *)printInfo forFrame:(WKFrameRef)frameRef
{
- LOG(View, "Creating an NSPrintOperation for frame '%s'", toImpl(frameRef)->url().utf8().data());
+ LOG(Printing, "Creating an NSPrintOperation for frame '%s'", toImpl(frameRef)->url().utf8().data());
// FIXME: If the frame cannot be printed (e.g. if it contains an encrypted PDF that disallows
// printing), this function should return nil.
- (void)disableFrameSizeUpdates
{
- _data->_frameSizeUpdatesDisabledCount++;
+ [_data->_layoutStrategy disableFrameSizeUpdates];
}
- (void)enableFrameSizeUpdates
{
- if (!_data->_frameSizeUpdatesDisabledCount)
- return;
-
- if (!(--_data->_frameSizeUpdatesDisabledCount)) {
- if (_data->_clipsToVisibleRect)
- [self _updateViewExposedRect];
- [self _setDrawingAreaSize:[self frame].size];
- }
+ [_data->_layoutStrategy enableFrameSizeUpdates];
}
- (BOOL)frameSizeUpdatesDisabled
{
- return _data->_frameSizeUpdatesDisabledCount > 0;
+ return [_data->_layoutStrategy frameSizeUpdatesDisabled];
}
+ (void)hideWordDefinitionWindow
{
- WKHideWordDefinitionWindow();
-}
-
-- (CGFloat)minimumLayoutWidth
-{
- static BOOL loggedDeprecationWarning = NO;
-
- if (!loggedDeprecationWarning) {
- NSLog(@"Please use minimumSizeForAutoLayout instead of minimumLayoutWidth.");
- loggedDeprecationWarning = YES;
- }
-
- return self.minimumSizeForAutoLayout.width;
-}
-
-- (void)setMinimumLayoutWidth:(CGFloat)minimumLayoutWidth
-{
- static BOOL loggedDeprecationWarning = NO;
-
- if (!loggedDeprecationWarning) {
- NSLog(@"Please use setMinimumSizeForAutoLayout: instead of setMinimumLayoutWidth:.");
- loggedDeprecationWarning = YES;
- }
-
- [self setMinimumWidthForAutoLayout:minimumLayoutWidth];
-}
-
-- (CGFloat)minimumWidthForAutoLayout
-{
- return self.minimumSizeForAutoLayout.width;
-}
-
-- (void)setMinimumWidthForAutoLayout:(CGFloat)minimumLayoutWidth
-{
- self.minimumSizeForAutoLayout = NSMakeSize(minimumLayoutWidth, self.minimumSizeForAutoLayout.height);
+ DictionaryLookup::hidePopup();
}
- (NSSize)minimumSizeForAutoLayout
_data->_page->setUnderlayColor(colorFromNSColor(underlayColor));
}
+#if WK_API_ENABLED
+- (NSView *)_inspectorAttachmentView
+{
+ NSView *attachmentView = _data->_inspectorAttachmentView.get();
+ return attachmentView ? attachmentView : self;
+}
+
+- (void)_setInspectorAttachmentView:(NSView *)newView
+{
+ NSView *oldView = _data->_inspectorAttachmentView.get();
+ if (oldView == newView)
+ return;
+
+ _data->_inspectorAttachmentView = newView;
+ _data->_page->inspector()->attachmentViewDidChange(oldView ? oldView : self, newView ? newView : self);
+}
+#endif
+
- (NSView *)fullScreenPlaceholderView
{
#if ENABLE(FULLSCREEN_API)
- (NSWindow *)createFullScreenWindow
{
#if ENABLE(FULLSCREEN_API)
-#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
- NSRect contentRect = NSZeroRect;
-#else
- NSRect contentRect = [[NSScreen mainScreen] frame];
-#endif
- return [[[WebCoreFullScreenWindow alloc] initWithContentRect:contentRect styleMask:(NSBorderlessWindowMask | NSResizableWindowMask) backing:NSBackingStoreBuffered defer:NO] autorelease];
+ return [[[WebCoreFullScreenWindow alloc] initWithContentRect:[[NSScreen mainScreen] frame] styleMask:(NSBorderlessWindowMask | NSResizableWindowMask) backing:NSBackingStoreBuffered defer:NO] autorelease];
#else
return nil;
#endif
}
+// FIXME: All of these "DeferringViewInWindowChanges" methods should be able to be removed once clients are weaned off of them.
- (void)beginDeferringViewInWindowChanges
{
if (_data->_shouldDeferViewInWindowChanges) {
_data->_shouldDeferViewInWindowChanges = NO;
if (_data->_viewInWindowChangeWasDeferred) {
+ [self _dispatchSetTopContentInset];
_data->_page->viewStateDidChange(ViewState::IsInWindow);
_data->_viewInWindowChangeWasDeferred = NO;
}
return;
}
- PageClient* pageClient = _data->_pageClient.get();
- bool hasPendingViewInWindowChange = _data->_viewInWindowChangeWasDeferred && _data->_page->isInWindow() != pageClient->isViewInWindow();
-
_data->_shouldDeferViewInWindowChanges = NO;
if (_data->_viewInWindowChangeWasDeferred) {
- _data->_page->viewStateDidChange(ViewState::IsInWindow, hasPendingViewInWindowChange ? WebPageProxy::WantsReplyOrNot::DoesWantReply : WebPageProxy::WantsReplyOrNot::DoesNotWantReply);
+ [self _dispatchSetTopContentInset];
+ _data->_page->viewStateDidChange(ViewState::IsInWindow);
_data->_viewInWindowChangeWasDeferred = NO;
}
+}
+
+- (void)_prepareForMoveToWindow:(NSWindow *)targetWindow withCompletionHandler:(void(^)(void))completionHandler
+{
+ _data->_shouldDeferViewInWindowChanges = YES;
+ [self viewWillMoveToWindow:targetWindow];
+ _data->_targetWindowForMovePreparation = targetWindow;
+ [self viewDidMoveToWindow];
+
+ _data->_shouldDeferViewInWindowChanges = NO;
+
+ _data->_page->installViewStateChangeCompletionHandler(^() {
+ completionHandler();
+ ASSERT(self.window == _data->_targetWindowForMovePreparation);
+ _data->_targetWindowForMovePreparation = nil;
+ });
- if (hasPendingViewInWindowChange)
- _data->_page->waitForDidUpdateViewState();
+ [self _dispatchSetTopContentInset];
+ _data->_page->viewStateDidChange(ViewState::IsInWindow, false, WebPageProxy::ViewStateChangeDispatchMode::Immediate);
+ _data->_viewInWindowChangeWasDeferred = NO;
}
- (BOOL)isDeferringViewInWindowChanges
return _data->_allowsBackForwardNavigationGestures;
}
+- (BOOL)allowsLinkPreview
+{
+ return _data->_allowsLinkPreview;
+}
+
+- (void)setAllowsLinkPreview:(BOOL)allowsLinkPreview
+{
+ if (_data->_allowsLinkPreview == allowsLinkPreview)
+ return;
+
+ _data->_allowsLinkPreview = allowsLinkPreview;
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ if (!allowsLinkPreview)
+ [self removeGestureRecognizer:_data->_immediateActionGestureRecognizer.get()];
+ else if (NSGestureRecognizer *immediateActionRecognizer = _data->_immediateActionGestureRecognizer.get())
+ [self addGestureRecognizer:immediateActionRecognizer];
+#endif
+}
+
+- (void)_setIgnoresAllEvents:(BOOL)ignoresAllEvents
+{
+ _data->_ignoresAllEvents = ignoresAllEvents;
+ [self _setIgnoresNonWheelEvents:ignoresAllEvents];
+}
+
+// Forward _setIgnoresNonWheelMouseEvents to _setIgnoresNonWheelEvents to avoid breaking existing clients.
+- (void)_setIgnoresNonWheelMouseEvents:(BOOL)ignoresNonWheelMouseEvents
+{
+ [self _setIgnoresNonWheelEvents:ignoresNonWheelMouseEvents];
+}
+
+- (void)_setIgnoresNonWheelEvents:(BOOL)ignoresNonWheelEvents
+{
+ if (_data->_ignoresNonWheelEvents == ignoresNonWheelEvents)
+ return;
+
+ _data->_ignoresNonWheelEvents = ignoresNonWheelEvents;
+ _data->_page->setShouldDispatchFakeMouseMoveEvents(!ignoresNonWheelEvents);
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ if (ignoresNonWheelEvents)
+ [self removeGestureRecognizer:_data->_immediateActionGestureRecognizer.get()];
+ else if (NSGestureRecognizer *immediateActionRecognizer = _data->_immediateActionGestureRecognizer.get()) {
+ if (_data->_allowsLinkPreview)
+ [self addGestureRecognizer:immediateActionRecognizer];
+ }
+#endif
+}
+
+- (BOOL)_ignoresNonWheelEvents
+{
+ return _data->_ignoresNonWheelEvents;
+}
+
+- (BOOL)_ignoresAllEvents
+{
+ return _data->_ignoresAllEvents;
+}
+
+- (void)_setOverrideDeviceScaleFactor:(CGFloat)deviceScaleFactor
+{
+ _data->_overrideDeviceScaleFactor = deviceScaleFactor;
+ _data->_page->setIntrinsicDeviceScaleFactor([self _intrinsicDeviceScaleFactor]);
+}
+
+- (CGFloat)_overrideDeviceScaleFactor
+{
+ return _data->_overrideDeviceScaleFactor;
+}
+
+- (WKLayoutMode)_layoutMode
+{
+ return [_data->_layoutStrategy layoutMode];
+}
+
+- (void)_setLayoutMode:(WKLayoutMode)layoutMode
+{
+ _data->_lastRequestedLayoutMode = layoutMode;
+
+ if (![self _supportsArbitraryLayoutModes] && layoutMode != kWKLayoutModeViewSize)
+ return;
+
+ if (layoutMode == [_data->_layoutStrategy layoutMode])
+ return;
+
+ [_data->_layoutStrategy willChangeLayoutStrategy];
+ _data->_layoutStrategy = [WKViewLayoutStrategy layoutStrategyWithPage:*_data->_page view:self mode:layoutMode];
+}
+
+- (CGSize)_fixedLayoutSize
+{
+ return _data->_page->fixedLayoutSize();
+}
+
+- (void)_setFixedLayoutSize:(CGSize)fixedLayoutSize
+{
+ _data->_page->setFixedLayoutSize(expandedIntSize(FloatSize(fixedLayoutSize)));
+}
+
+- (CGFloat)_viewScale
+{
+ return _data->_page->viewScaleFactor();
+}
+
+- (void)_setViewScale:(CGFloat)viewScale
+{
+ _data->_lastRequestedViewScale = viewScale;
+
+ if (![self _supportsArbitraryLayoutModes] && viewScale != 1)
+ return;
+
+ if (viewScale <= 0 || isnan(viewScale) || isinf(viewScale))
+ [NSException raise:NSInvalidArgumentException format:@"View scale should be a positive number"];
+
+ _data->_page->scaleView(viewScale);
+ [_data->_layoutStrategy didChangeViewScale];
+}
+
+- (void)_dispatchSetTopContentInset
+{
+ if (!_data->_didScheduleSetTopContentInset)
+ return;
+
+ _data->_didScheduleSetTopContentInset = NO;
+ _data->_page->setTopContentInset(_data->_topContentInset);
+}
+
- (void)_setTopContentInset:(CGFloat)contentInset
{
- _data->_page->setTopContentInset(contentInset);
+ _data->_topContentInset = contentInset;
+
+ if (_data->_didScheduleSetTopContentInset)
+ return;
+
+ _data->_didScheduleSetTopContentInset = YES;
+
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self _dispatchSetTopContentInset];
+ });
}
- (CGFloat)_topContentInset
{
- return _data->_page->topContentInset();
+ return _data->_topContentInset;
+}
+
+- (void)_setTotalHeightOfBanners:(CGFloat)totalHeightOfBanners
+{
+ _data->_totalHeightOfBanners = totalHeightOfBanners;
+}
+
+- (CGFloat)_totalHeightOfBanners
+{
+ return _data->_totalHeightOfBanners;
+}
+
+- (void)_setOverlayScrollbarStyle:(_WKOverlayScrollbarStyle)scrollbarStyle
+{
+ WTF::Optional<WebCore::ScrollbarOverlayStyle> coreScrollbarStyle;
+
+ switch (scrollbarStyle) {
+ case _WKOverlayScrollbarStyleDark:
+ coreScrollbarStyle = ScrollbarOverlayStyleDark;
+ break;
+ case _WKOverlayScrollbarStyleLight:
+ coreScrollbarStyle = ScrollbarOverlayStyleLight;
+ break;
+ case _WKOverlayScrollbarStyleDefault:
+ coreScrollbarStyle = ScrollbarOverlayStyleDefault;
+ break;
+ case _WKOverlayScrollbarStyleAutomatic:
+ default:
+ break;
+ }
+
+ _data->_page->setOverlayScrollbarStyle(coreScrollbarStyle);
+}
+
+- (_WKOverlayScrollbarStyle)_overlayScrollbarStyle
+{
+ WTF::Optional<WebCore::ScrollbarOverlayStyle> coreScrollbarStyle = _data->_page->overlayScrollbarStyle();
+
+ if (!coreScrollbarStyle)
+ return _WKOverlayScrollbarStyleAutomatic;
+
+ switch (coreScrollbarStyle.value()) {
+ case ScrollbarOverlayStyleDark:
+ return _WKOverlayScrollbarStyleDark;
+ case ScrollbarOverlayStyleLight:
+ return _WKOverlayScrollbarStyleLight;
+ case ScrollbarOverlayStyleDefault:
+ return _WKOverlayScrollbarStyleDefault;
+ default:
+ return _WKOverlayScrollbarStyleAutomatic;
+ }
}
- (NSColor *)_pageExtendedBackgroundColor
return nsColor(color);
}
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-noreturn"
// This method forces a drawing area geometry update, even if frame size updates are disabled.
// The updated is performed asynchronously; we don't wait for the geometry update before returning.
// The area drawn need not match the current frame size - if it differs it will be anchored to the
// frame according to the current contentAnchor.
- (void)forceAsyncDrawingAreaSizeUpdate:(NSSize)size
{
+ // This SPI is only used on 10.9 and below, and is incompatible with the fence-based drawing area size synchronization in 10.10+.
+#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
if (_data->_clipsToVisibleRect)
[self _updateViewExposedRect];
[self _setDrawingAreaSize:size];
// the drawing area size such that the latest update is sent.
if (DrawingAreaProxy* drawingArea = _data->_page->drawingArea())
drawingArea->waitForPossibleGeometryUpdate(std::chrono::milliseconds::zero());
+#else
+ ASSERT_NOT_REACHED();
+#endif
}
- (void)waitForAsyncDrawingAreaSizeUpdate
{
+ // This SPI is only used on 10.9 and below, and is incompatible with the fence-based drawing area size synchronization in 10.10+.
+#if __MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
if (DrawingAreaProxy* drawingArea = _data->_page->drawingArea()) {
// If a geometry update is still pending then the action of receiving the
// first geometry update may result in another update being scheduled -
drawingArea->waitForPossibleGeometryUpdate(DrawingAreaProxy::didUpdateBackingStoreStateTimeout() / 2);
drawingArea->waitForPossibleGeometryUpdate(DrawingAreaProxy::didUpdateBackingStoreStateTimeout() / 2);
}
+#else
+ ASSERT_NOT_REACHED();
+#endif
}
+#pragma clang diagnostic pop
- (BOOL)isUsingUISideCompositing
{
- (void)magnifyWithEvent:(NSEvent *)event
{
if (!_data->_allowsMagnification) {
+#if ENABLE(MAC_GESTURE_EVENTS)
+ NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, self);
+ _data->_page->handleGestureEvent(webEvent);
+#endif
[super magnifyWithEvent:event];
return;
}
+ [self _dismissContentRelativeChildWindowsWithAnimation:NO];
+
[self _ensureGestureController];
- _data->_gestureController->handleMagnificationGesture(event.magnification, [self convertPoint:event.locationInWindow fromView:nil]);
+#if ENABLE(MAC_GESTURE_EVENTS)
+ if (_data->_gestureController->hasActiveMagnificationGesture()) {
+ _data->_gestureController->handleMagnificationGestureEvent(event, [self convertPoint:event.locationInWindow fromView:nil]);
+ return;
+ }
+
+ NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, self);
+ _data->_page->handleGestureEvent(webEvent);
+#else
+ _data->_gestureController->handleMagnificationGestureEvent(event, [self convertPoint:event.locationInWindow fromView:nil]);
+#endif
+}
+
+#if ENABLE(MAC_GESTURE_EVENTS)
+- (void)rotateWithEvent:(NSEvent *)event
+{
+ NativeWebGestureEvent webEvent = NativeWebGestureEvent(event, self);
+ _data->_page->handleGestureEvent(webEvent);
+}
+#endif
+
+- (void)_gestureEventWasNotHandledByWebCore:(NSEvent *)event
+{
+#if ENABLE(MAC_GESTURE_EVENTS)
+ if (_data->_gestureController)
+ _data->_gestureController->gestureEventWasNotHandledByWebCore(event, [self convertPoint:event.locationInWindow fromView:nil]);
+#endif
}
- (void)smartMagnifyWithEvent:(NSEvent *)event
return;
}
+ [self _dismissContentRelativeChildWindowsWithAnimation:NO];
+
[self _ensureGestureController];
_data->_gestureController->handleSmartMagnificationGesture([self convertPoint:event.locationInWindow fromView:nil]);
}
--(void)endGestureWithEvent:(NSEvent *)event
+- (void)setMagnification:(double)magnification centeredAtPoint:(NSPoint)point
{
- if (!_data->_gestureController) {
- [super endGestureWithEvent:event];
- return;
- }
+ if (magnification <= 0 || isnan(magnification) || isinf(magnification))
+ [NSException raise:NSInvalidArgumentException format:@"Magnification should be a positive number"];
- _data->_gestureController->endActiveGesture();
-}
+ [self _dismissContentRelativeChildWindowsWithAnimation:NO];
-- (void)setMagnification:(double)magnification centeredAtPoint:(NSPoint)point
-{
_data->_page->scalePageInViewCoordinates(magnification, roundedIntPoint(point));
}
- (void)setMagnification:(double)magnification
{
+ if (magnification <= 0 || isnan(magnification) || isinf(magnification))
+ [NSException raise:NSInvalidArgumentException format:@"Magnification should be a positive number"];
+
+ [self _dismissContentRelativeChildWindowsWithAnimation:NO];
+
FloatPoint viewCenter(NSMidX([self bounds]), NSMidY([self bounds]));
_data->_page->scalePageInViewCoordinates(magnification, roundedIntPoint(viewCenter));
}
return handledEvent;
}
+- (void)_setDidMoveSwipeSnapshotCallback:(void(^)(CGRect))callback
+{
+ if (!_data->_allowsBackForwardNavigationGestures)
+ return;
+
+ [self _ensureGestureController];
+ _data->_gestureController->setDidMoveSwipeSnapshotCallback(callback);
+}
+
+- (id)_immediateActionAnimationControllerForHitTestResult:(WKHitTestResultRef)hitTestResult withType:(uint32_t)type userData:(WKTypeRef)userData
+{
+ return nil;
+}
+
+- (void)_prepareForImmediateActionAnimation
+{
+}
+
+- (void)_cancelImmediateActionAnimation
+{
+}
+
+- (void)_completeImmediateActionAnimation
+{
+}
+
+- (void)_didChangeContentSize:(NSSize)newSize
+{
+}
+
+- (void)_dismissContentRelativeChildWindows
+{
+ // FIXME: We don't know which panel we are dismissing, it may not even be in the current page (see <rdar://problem/13875766>).
+ if ([[self window] isKeyWindow]
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ || [_data->_immediateActionController hasActiveImmediateAction]
+#endif
+ ) {
+ DictionaryLookup::hidePopup();
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ DDActionsManager *actionsManager = [getDDActionsManagerClass() sharedManager];
+ if ([actionsManager respondsToSelector:@selector(requestBubbleClosureUnanchorOnFailure:)])
+ [actionsManager requestBubbleClosureUnanchorOnFailure:YES];
+#endif
+ }
+
+ [self _clearTextIndicatorWithAnimation:TextIndicatorWindowDismissalAnimation::FadeOut];
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+ [_data->_immediateActionController dismissContentRelativeChildWindows];
+#endif
+
+ static_cast<PageClient&>(*_data->_pageClient).dismissCorrectionPanel(ReasonForDismissingAlternativeTextIgnored);
+}
+
+- (void)_dismissContentRelativeChildWindowsWithAnimation:(BOOL)withAnimation
+{
+ // Calling _clearTextIndicatorWithAnimation here will win out over the animated clear in _dismissContentRelativeChildWindows.
+ // We can't invert these because clients can override (and have overridden) _dismissContentRelativeChildWindows, so it needs to be called.
+ [self _clearTextIndicatorWithAnimation:withAnimation ? TextIndicatorWindowDismissalAnimation::FadeOut : TextIndicatorWindowDismissalAnimation::None];
+ [self _dismissContentRelativeChildWindows];
+}
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
+
+- (void)_setAutomaticallyAdjustsContentInsets:(BOOL)automaticallyAdjustsContentInsets
+{
+ _data->_automaticallyAdjustsContentInsets = automaticallyAdjustsContentInsets;
+ [self _updateContentInsetsIfAutomatic];
+}
+
+- (BOOL)_automaticallyAdjustsContentInsets
+{
+ return _data->_automaticallyAdjustsContentInsets;
+}
+
+#endif
+
@end
@implementation WKResponderChainSink