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