Home | History | Annotate | Download | only in mac
      1 /*
      2  * Copyright (C) 2010, 2011 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #import "config.h"
     27 #import "PageClientImpl.h"
     28 
     29 #import "DataReference.h"
     30 #import "DictionaryPopupInfo.h"
     31 #import "FindIndicator.h"
     32 #import "NativeWebKeyboardEvent.h"
     33 #import "WKAPICast.h"
     34 #import "WKStringCF.h"
     35 #import "WKViewInternal.h"
     36 #import "WebContextMenuProxyMac.h"
     37 #import "WebEditCommandProxy.h"
     38 #import "WebPopupMenuProxyMac.h"
     39 #import <WebCore/Cursor.h>
     40 #import <WebCore/FloatRect.h>
     41 #import <WebCore/FoundationExtras.h>
     42 #import <WebCore/GraphicsContext.h>
     43 #import <WebCore/KeyboardEvent.h>
     44 #import <WebCore/NotImplemented.h>
     45 #import <wtf/PassOwnPtr.h>
     46 #import <wtf/text/CString.h>
     47 #import <wtf/text/WTFString.h>
     48 #import <WebKitSystemInterface.h>
     49 
     50 @interface NSApplication (WebNSApplicationDetails)
     51 - (NSCursor *)_cursorRectCursor;
     52 @end
     53 
     54 using namespace WebCore;
     55 using namespace WebKit;
     56 
     57 @interface WKEditCommandObjC : NSObject
     58 {
     59     RefPtr<WebEditCommandProxy> m_command;
     60 }
     61 - (id)initWithWebEditCommandProxy:(PassRefPtr<WebEditCommandProxy>)command;
     62 - (WebEditCommandProxy*)command;
     63 @end
     64 
     65 @interface WKEditorUndoTargetObjC : NSObject
     66 - (void)undoEditing:(id)sender;
     67 - (void)redoEditing:(id)sender;
     68 @end
     69 
     70 @implementation WKEditCommandObjC
     71 
     72 - (id)initWithWebEditCommandProxy:(PassRefPtr<WebEditCommandProxy>)command
     73 {
     74     self = [super init];
     75     if (!self)
     76         return nil;
     77 
     78     m_command = command;
     79     return self;
     80 }
     81 
     82 - (WebEditCommandProxy*)command
     83 {
     84     return m_command.get();
     85 }
     86 
     87 @end
     88 
     89 @implementation WKEditorUndoTargetObjC
     90 
     91 - (void)undoEditing:(id)sender
     92 {
     93     ASSERT([sender isKindOfClass:[WKEditCommandObjC class]]);
     94     [sender command]->unapply();
     95 }
     96 
     97 - (void)redoEditing:(id)sender
     98 {
     99     ASSERT([sender isKindOfClass:[WKEditCommandObjC class]]);
    100     [sender command]->reapply();
    101 }
    102 
    103 @end
    104 
    105 namespace WebKit {
    106 
    107 NSString* nsStringFromWebCoreString(const String& string)
    108 {
    109     return string.impl() ? HardAutorelease(WKStringCopyCFString(0, toAPI(string.impl()))) : @"";
    110 }
    111 
    112 PassOwnPtr<PageClientImpl> PageClientImpl::create(WKView* wkView)
    113 {
    114     return adoptPtr(new PageClientImpl(wkView));
    115 }
    116 
    117 PageClientImpl::PageClientImpl(WKView* wkView)
    118     : m_wkView(wkView)
    119     , m_undoTarget(AdoptNS, [[WKEditorUndoTargetObjC alloc] init])
    120 {
    121 }
    122 
    123 PageClientImpl::~PageClientImpl()
    124 {
    125 }
    126 
    127 PassOwnPtr<DrawingAreaProxy> PageClientImpl::createDrawingAreaProxy()
    128 {
    129     return [m_wkView _createDrawingAreaProxy];
    130 }
    131 
    132 void PageClientImpl::setViewNeedsDisplay(const WebCore::IntRect& rect)
    133 {
    134     [m_wkView setNeedsDisplayInRect:rect];
    135 }
    136 
    137 void PageClientImpl::displayView()
    138 {
    139     [m_wkView displayIfNeeded];
    140 }
    141 
    142 void PageClientImpl::scrollView(const IntRect& scrollRect, const IntSize& scrollOffset)
    143 {
    144     NSRect clippedScrollRect = NSIntersectionRect(scrollRect, NSOffsetRect(scrollRect, -scrollOffset.width(), -scrollOffset.height()));
    145 
    146     [m_wkView translateRectsNeedingDisplayInRect:clippedScrollRect by:scrollOffset];
    147     [m_wkView scrollRect:clippedScrollRect by:scrollOffset];
    148 }
    149 
    150 IntSize PageClientImpl::viewSize()
    151 {
    152     return IntSize([m_wkView bounds].size);
    153 }
    154 
    155 bool PageClientImpl::isViewWindowActive()
    156 {
    157     return [[m_wkView window] isKeyWindow] || [NSApp keyWindow] == [m_wkView window];
    158 }
    159 
    160 bool PageClientImpl::isViewFocused()
    161 {
    162     return [m_wkView _isFocused];
    163 }
    164 
    165 bool PageClientImpl::isViewVisible()
    166 {
    167     if (![m_wkView window])
    168         return false;
    169 
    170     if (![[m_wkView window] isVisible])
    171         return false;
    172 
    173     if ([m_wkView isHiddenOrHasHiddenAncestor])
    174         return false;
    175 
    176     return true;
    177 }
    178 
    179 bool PageClientImpl::isViewInWindow()
    180 {
    181     return [m_wkView window];
    182 }
    183 
    184 void PageClientImpl::processDidCrash()
    185 {
    186     [m_wkView _processDidCrash];
    187 }
    188 
    189 void PageClientImpl::pageClosed()
    190 {
    191     [m_wkView _pageClosed];
    192 }
    193 
    194 void PageClientImpl::didRelaunchProcess()
    195 {
    196     [m_wkView _didRelaunchProcess];
    197 }
    198 
    199 void PageClientImpl::toolTipChanged(const String& oldToolTip, const String& newToolTip)
    200 {
    201     [m_wkView _toolTipChangedFrom:nsStringFromWebCoreString(oldToolTip) to:nsStringFromWebCoreString(newToolTip)];
    202 }
    203 
    204 void PageClientImpl::setCursor(const WebCore::Cursor& cursor)
    205 {
    206     if (![NSApp _cursorRectCursor])
    207         [m_wkView _setCursor:cursor.platformCursor()];
    208 }
    209 
    210 void PageClientImpl::setViewportArguments(const WebCore::ViewportArguments&)
    211 {
    212 }
    213 
    214 void PageClientImpl::registerEditCommand(PassRefPtr<WebEditCommandProxy> prpCommand, WebPageProxy::UndoOrRedo undoOrRedo)
    215 {
    216     RefPtr<WebEditCommandProxy> command = prpCommand;
    217 
    218     RetainPtr<WKEditCommandObjC> commandObjC(AdoptNS, [[WKEditCommandObjC alloc] initWithWebEditCommandProxy:command]);
    219     String actionName = WebEditCommandProxy::nameForEditAction(command->editAction());
    220 
    221     NSUndoManager *undoManager = [m_wkView undoManager];
    222     [undoManager registerUndoWithTarget:m_undoTarget.get() selector:((undoOrRedo == WebPageProxy::Undo) ? @selector(undoEditing:) : @selector(redoEditing:)) object:commandObjC.get()];
    223     if (!actionName.isEmpty())
    224         [undoManager setActionName:(NSString *)actionName];
    225 }
    226 
    227 void PageClientImpl::clearAllEditCommands()
    228 {
    229     [[m_wkView undoManager] removeAllActionsWithTarget:m_undoTarget.get()];
    230 }
    231 
    232 bool PageClientImpl::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
    233 {
    234     return (undoOrRedo == WebPageProxy::Undo) ? [[m_wkView undoManager] canUndo] : [[m_wkView undoManager] canRedo];
    235 }
    236 
    237 void PageClientImpl::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo)
    238 {
    239     return (undoOrRedo == WebPageProxy::Undo) ? [[m_wkView undoManager] undo] : [[m_wkView undoManager] redo];
    240 }
    241 
    242 bool PageClientImpl::interpretKeyEvent(const NativeWebKeyboardEvent& event, Vector<WebCore::KeypressCommand>& commands)
    243 {
    244     return [m_wkView _interpretKeyEvent:event.nativeEvent() savingCommandsTo:commands];
    245 }
    246 
    247 void PageClientImpl::setDragImage(const IntPoint& clientPosition, PassRefPtr<ShareableBitmap> dragImage, bool isLinkDrag)
    248 {
    249     RetainPtr<CGImageRef> dragCGImage = dragImage->makeCGImage();
    250     RetainPtr<NSImage> dragNSImage(AdoptNS, [[NSImage alloc] initWithCGImage:dragCGImage.get() size:dragImage->size()]);
    251 
    252     [m_wkView _setDragImage:dragNSImage.get() at:clientPosition linkDrag:isLinkDrag];
    253 }
    254 
    255 void PageClientImpl::updateSecureInputState()
    256 {
    257     [m_wkView _updateSecureInputState];
    258 }
    259 
    260 FloatRect PageClientImpl::convertToDeviceSpace(const FloatRect& rect)
    261 {
    262     return [m_wkView _convertToDeviceSpace:rect];
    263 }
    264 
    265 FloatRect PageClientImpl::convertToUserSpace(const FloatRect& rect)
    266 {
    267     return [m_wkView _convertToUserSpace:rect];
    268 }
    269 
    270 IntRect PageClientImpl::windowToScreen(const IntRect& rect)
    271 {
    272     NSRect tempRect = rect;
    273     tempRect = [m_wkView convertRect:tempRect toView:nil];
    274     tempRect.origin = [[m_wkView window] convertBaseToScreen:tempRect.origin];
    275     return enclosingIntRect(tempRect);
    276 }
    277 
    278 void PageClientImpl::doneWithKeyEvent(const NativeWebKeyboardEvent& event, bool wasEventHandled)
    279 {
    280     NSEvent* nativeEvent = event.nativeEvent();
    281     if ([nativeEvent type] != NSKeyDown)
    282         return;
    283     if (wasEventHandled)
    284         [NSCursor setHiddenUntilMouseMoves:YES];
    285     else
    286         [m_wkView _resendKeyDownEvent:nativeEvent];
    287 }
    288 
    289 PassRefPtr<WebPopupMenuProxy> PageClientImpl::createPopupMenuProxy(WebPageProxy* page)
    290 {
    291     return WebPopupMenuProxyMac::create(m_wkView, page);
    292 }
    293 
    294 PassRefPtr<WebContextMenuProxy> PageClientImpl::createContextMenuProxy(WebPageProxy* page)
    295 {
    296     return WebContextMenuProxyMac::create(m_wkView, page);
    297 }
    298 
    299 void PageClientImpl::setFindIndicator(PassRefPtr<FindIndicator> findIndicator, bool fadeOut)
    300 {
    301     [m_wkView _setFindIndicator:findIndicator fadeOut:fadeOut];
    302 }
    303 
    304 void PageClientImpl::accessibilityWebProcessTokenReceived(const CoreIPC::DataReference& data)
    305 {
    306     NSData* remoteToken = [NSData dataWithBytes:data.data() length:data.size()];
    307     [m_wkView _setAccessibilityWebProcessToken:remoteToken];
    308 }
    309 
    310 #if USE(ACCELERATED_COMPOSITING)
    311 void PageClientImpl::enterAcceleratedCompositingMode(const LayerTreeContext& layerTreeContext)
    312 {
    313     [m_wkView _enterAcceleratedCompositingMode:layerTreeContext];
    314 }
    315 
    316 void PageClientImpl::exitAcceleratedCompositingMode()
    317 {
    318     [m_wkView _exitAcceleratedCompositingMode];
    319 }
    320 #endif // USE(ACCELERATED_COMPOSITING)
    321 
    322 void PageClientImpl::setComplexTextInputEnabled(uint64_t pluginComplexTextInputIdentifier, bool complexTextInputEnabled)
    323 {
    324     [m_wkView _setComplexTextInputEnabled:complexTextInputEnabled pluginComplexTextInputIdentifier:pluginComplexTextInputIdentifier];
    325 }
    326 
    327 CGContextRef PageClientImpl::containingWindowGraphicsContext()
    328 {
    329     NSWindow *window = [m_wkView window];
    330 
    331     // Don't try to get the graphics context if the NSWindow doesn't have a window device.
    332     if ([window windowNumber] <= 0)
    333         return 0;
    334 
    335     return static_cast<CGContextRef>([[window graphicsContext] graphicsPort]);
    336 }
    337 
    338 void PageClientImpl::didChangeScrollbarsForMainFrame() const
    339 {
    340     [m_wkView _didChangeScrollbarsForMainFrame];
    341 }
    342 
    343 void PageClientImpl::didCommitLoadForMainFrame(bool useCustomRepresentation)
    344 {
    345     [m_wkView _setPageHasCustomRepresentation:useCustomRepresentation];
    346 }
    347 
    348 void PageClientImpl::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference& dataReference)
    349 {
    350     [m_wkView _didFinishLoadingDataForCustomRepresentationWithSuggestedFilename:suggestedFilename dataReference:dataReference];
    351 }
    352 
    353 double PageClientImpl::customRepresentationZoomFactor()
    354 {
    355     return [m_wkView _customRepresentationZoomFactor];
    356 }
    357 
    358 void PageClientImpl::setCustomRepresentationZoomFactor(double zoomFactor)
    359 {
    360     [m_wkView _setCustomRepresentationZoomFactor:zoomFactor];
    361 }
    362 
    363 void PageClientImpl::findStringInCustomRepresentation(const String& string, FindOptions options, unsigned maxMatchCount)
    364 {
    365     [m_wkView _findStringInCustomRepresentation:string withFindOptions:options maxMatchCount:maxMatchCount];
    366 }
    367 
    368 void PageClientImpl::countStringMatchesInCustomRepresentation(const String& string, FindOptions options, unsigned maxMatchCount)
    369 {
    370     [m_wkView _countStringMatchesInCustomRepresentation:string withFindOptions:options maxMatchCount:maxMatchCount];
    371 }
    372 
    373 void PageClientImpl::flashBackingStoreUpdates(const Vector<IntRect>&)
    374 {
    375     notImplemented();
    376 }
    377 
    378 void PageClientImpl::didPerformDictionaryLookup(const String& text, double scaleFactor, const DictionaryPopupInfo& dictionaryPopupInfo)
    379 {
    380     NSFontDescriptor *fontDescriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:(NSDictionary *)dictionaryPopupInfo.fontInfo.fontAttributeDictionary.get()];
    381     NSFont *font = [NSFont fontWithDescriptor:fontDescriptor size:((scaleFactor != 1) ? [fontDescriptor pointSize] * scaleFactor : 0)];
    382 
    383     RetainPtr<NSMutableAttributedString> attributedString(AdoptNS, [[NSMutableAttributedString alloc] initWithString:nsStringFromWebCoreString(text)]);
    384     [attributedString.get() addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [attributedString.get() length])];
    385 
    386     NSPoint textBaselineOrigin = dictionaryPopupInfo.origin;
    387     textBaselineOrigin.y += [font ascender];
    388 
    389 #if !defined(BUILDING_ON_SNOW_LEOPARD)
    390     // Convert to screen coordinates.
    391     textBaselineOrigin = [m_wkView convertPoint:textBaselineOrigin toView:nil];
    392     textBaselineOrigin = [m_wkView.window convertRectToScreen:NSMakeRect(textBaselineOrigin.x, textBaselineOrigin.y, 0, 0)].origin;
    393 
    394     WKShowWordDefinitionWindow(attributedString.get(), textBaselineOrigin, (NSDictionary *)dictionaryPopupInfo.options.get());
    395 #else
    396     // If the dictionary lookup is being triggered by a hot key, force the overlay style.
    397     NSDictionary *options = (dictionaryPopupInfo.type == DictionaryPopupInfo::HotKey) ? [NSDictionary dictionaryWithObject:NSDefinitionPresentationTypeOverlay forKey:NSDefinitionPresentationTypeKey] : 0;
    398     [m_wkView showDefinitionForAttributedString:attributedString.get() range:NSMakeRange(0, [attributedString.get() length]) options:options baselineOriginProvider:^(NSRange adjustedRange) { return (NSPoint)textBaselineOrigin; }];
    399 #endif
    400 }
    401 
    402 void PageClientImpl::dismissDictionaryLookupPanel()
    403 {
    404 #if !defined(BUILDING_ON_SNOW_LEOPARD)
    405     WKHideWordDefinitionWindow();
    406 #endif
    407 }
    408 
    409 void PageClientImpl::showCorrectionPanel(CorrectionPanelInfo::PanelType type, const FloatRect& boundingBoxOfReplacedString, const String& replacedString, const String& replacementString, const Vector<String>& alternativeReplacementStrings)
    410 {
    411 #if !defined(BUILDING_ON_SNOW_LEOPARD)
    412     if (!isViewVisible() || !isViewInWindow())
    413         return;
    414     m_correctionPanel.show(m_wkView, type, boundingBoxOfReplacedString, replacedString, replacementString, alternativeReplacementStrings);
    415 #endif
    416 }
    417 
    418 void PageClientImpl::dismissCorrectionPanel(ReasonForDismissingCorrectionPanel reason)
    419 {
    420 #if !defined(BUILDING_ON_SNOW_LEOPARD)
    421     m_correctionPanel.dismiss(reason);
    422 #endif
    423 }
    424 
    425 String PageClientImpl::dismissCorrectionPanelSoon(WebCore::ReasonForDismissingCorrectionPanel reason)
    426 {
    427 #if !defined(BUILDING_ON_SNOW_LEOPARD)
    428     return m_correctionPanel.dismissSoon(reason);
    429 #else
    430     return String();
    431 #endif
    432 }
    433 
    434 void PageClientImpl::recordAutocorrectionResponse(EditorClient::AutocorrectionResponseType responseType, const String& replacedString, const String& replacementString)
    435 {
    436 #if !defined(BUILDING_ON_SNOW_LEOPARD)
    437     NSCorrectionResponse response = responseType == EditorClient::AutocorrectionReverted ? NSCorrectionResponseReverted : NSCorrectionResponseEdited;
    438     CorrectionPanel::recordAutocorrectionResponse(m_wkView, response, replacedString, replacementString);
    439 #endif
    440 }
    441 
    442 float PageClientImpl::userSpaceScaleFactor() const
    443 {
    444     NSWindow *window = [m_wkView window];
    445 #if !defined(BUILDING_ON_SNOW_LEOPARD)
    446     if (window)
    447         return [window backingScaleFactor];
    448     return [[NSScreen mainScreen] backingScaleFactor];
    449 #else
    450     if (window)
    451         return [window userSpaceScaleFactor];
    452     return [[NSScreen mainScreen] userSpaceScaleFactor];
    453 #endif
    454 }
    455 
    456 bool PageClientImpl::executeSavedCommandBySelector(const String& selectorString)
    457 {
    458     return [m_wkView _executeSavedCommandBySelector:NSSelectorFromString(selectorString)];
    459 }
    460 
    461 } // namespace WebKit
    462