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 "WebPage.h" 28 29 #import "AccessibilityWebPageObject.h" 30 #import "AttributedString.h" 31 #import "DataReference.h" 32 #import "EditorState.h" 33 #import "PluginView.h" 34 #import "WebCoreArgumentCoders.h" 35 #import "WebEvent.h" 36 #import "WebEventConversion.h" 37 #import "WebFrame.h" 38 #import "WebPageProxyMessages.h" 39 #import "WebProcess.h" 40 #import <WebCore/AXObjectCache.h> 41 #import <WebCore/FocusController.h> 42 #import <WebCore/Frame.h> 43 #import <WebCore/FrameView.h> 44 #import <WebCore/HitTestResult.h> 45 #import <WebCore/HTMLConverter.h> 46 #import <WebCore/KeyboardEvent.h> 47 #import <WebCore/Page.h> 48 #import <WebCore/PlatformKeyboardEvent.h> 49 #import <WebCore/ResourceHandle.h> 50 #import <WebCore/ScrollView.h> 51 #import <WebCore/TextIterator.h> 52 #import <WebCore/WindowsKeyboardCodes.h> 53 #import <WebCore/visible_units.h> 54 #import <WebKitSystemInterface.h> 55 56 using namespace WebCore; 57 58 namespace WebKit { 59 60 static PassRefPtr<Range> convertToRange(Frame*, NSRange); 61 62 void WebPage::platformInitialize() 63 { 64 m_page->addSchedulePair(SchedulePair::create([NSRunLoop currentRunLoop], kCFRunLoopCommonModes)); 65 66 #if !defined(BUILDING_ON_SNOW_LEOPARD) 67 AccessibilityWebPageObject* mockAccessibilityElement = [[[AccessibilityWebPageObject alloc] init] autorelease]; 68 69 // Get the pid for the starting process. 70 pid_t pid = WebProcess::shared().presenterApplicationPid(); 71 WKAXInitializeElementWithPresenterPid(mockAccessibilityElement, pid); 72 [mockAccessibilityElement setWebPage:this]; 73 74 // send data back over 75 NSData* remoteToken = (NSData *)WKAXRemoteTokenForElement(mockAccessibilityElement); 76 CoreIPC::DataReference dataToken = CoreIPC::DataReference(reinterpret_cast<const uint8_t*>([remoteToken bytes]), [remoteToken length]); 77 send(Messages::WebPageProxy::RegisterWebProcessAccessibilityToken(dataToken)); 78 m_mockAccessibilityElement = mockAccessibilityElement; 79 #endif 80 } 81 82 void WebPage::platformPreferencesDidChange(const WebPreferencesStore&) 83 { 84 } 85 86 typedef HashMap<String, String> SelectorNameMap; 87 88 // Map selectors into Editor command names. 89 // This is not needed for any selectors that have the same name as the Editor command. 90 static const SelectorNameMap* createSelectorExceptionMap() 91 { 92 SelectorNameMap* map = new HashMap<String, String>; 93 94 map->add("insertNewlineIgnoringFieldEditor:", "InsertNewline"); 95 map->add("insertParagraphSeparator:", "InsertNewline"); 96 map->add("insertTabIgnoringFieldEditor:", "InsertTab"); 97 map->add("pageDown:", "MovePageDown"); 98 map->add("pageDownAndModifySelection:", "MovePageDownAndModifySelection"); 99 map->add("pageUp:", "MovePageUp"); 100 map->add("pageUpAndModifySelection:", "MovePageUpAndModifySelection"); 101 102 return map; 103 } 104 105 static String commandNameForSelectorName(const String& selectorName) 106 { 107 // Check the exception map first. 108 static const SelectorNameMap* exceptionMap = createSelectorExceptionMap(); 109 SelectorNameMap::const_iterator it = exceptionMap->find(selectorName); 110 if (it != exceptionMap->end()) 111 return it->second; 112 113 // Remove the trailing colon. 114 // No need to capitalize the command name since Editor command names are not case sensitive. 115 size_t selectorNameLength = selectorName.length(); 116 if (selectorNameLength < 2 || selectorName[selectorNameLength - 1] != ':') 117 return String(); 118 return selectorName.left(selectorNameLength - 1); 119 } 120 121 static Frame* frameForEvent(KeyboardEvent* event) 122 { 123 Node* node = event->target()->toNode(); 124 ASSERT(node); 125 Frame* frame = node->document()->frame(); 126 ASSERT(frame); 127 return frame; 128 } 129 130 bool WebPage::executeKeypressCommandsInternal(const Vector<WebCore::KeypressCommand>& commands, KeyboardEvent* event) 131 { 132 Frame* frame = frameForEvent(event); 133 ASSERT(frame->page() == corePage()); 134 135 bool eventWasHandled = false; 136 for (size_t i = 0; i < commands.size(); ++i) { 137 if (commands[i].commandName == "insertText:") { 138 ASSERT(!frame->editor()->hasComposition()); 139 140 if (!frame->editor()->canEdit()) 141 continue; 142 143 // An insertText: might be handled by other responders in the chain if we don't handle it. 144 // One example is space bar that results in scrolling down the page. 145 eventWasHandled |= frame->editor()->insertText(commands[i].text, event); 146 } else { 147 Editor::Command command = frame->editor()->command(commandNameForSelectorName(commands[i].commandName)); 148 if (command.isSupported()) { 149 bool commandExecutedByEditor = command.execute(event); 150 eventWasHandled |= commandExecutedByEditor; 151 if (!commandExecutedByEditor) { 152 bool performedNonEditingBehavior = event->keyEvent()->type() == PlatformKeyboardEvent::RawKeyDown && performNonEditingBehaviorForSelector(commands[i].commandName); 153 eventWasHandled |= performedNonEditingBehavior; 154 } 155 } else { 156 bool commandWasHandledByUIProcess = false; 157 WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::ExecuteSavedCommandBySelector(commands[i].commandName), 158 Messages::WebPageProxy::ExecuteSavedCommandBySelector::Reply(commandWasHandledByUIProcess), m_pageID); 159 eventWasHandled |= commandWasHandledByUIProcess; 160 } 161 } 162 } 163 return eventWasHandled; 164 } 165 166 bool WebPage::handleEditingKeyboardEvent(KeyboardEvent* event, bool saveCommands) 167 { 168 ASSERT(!saveCommands || event->keypressCommands().isEmpty()); // Save commands once for each event. 169 170 Frame* frame = frameForEvent(event); 171 172 const PlatformKeyboardEvent* platformEvent = event->keyEvent(); 173 if (!platformEvent) 174 return false; 175 Vector<KeypressCommand>& commands = event->keypressCommands(); 176 177 if ([platformEvent->macEvent() type] == NSFlagsChanged) 178 return false; 179 180 bool eventWasHandled = false; 181 182 if (saveCommands) { 183 KeyboardEvent* oldEvent = m_keyboardEventBeingInterpreted; 184 m_keyboardEventBeingInterpreted = event; 185 bool sendResult = WebProcess::shared().connection()->sendSync(Messages::WebPageProxy::InterpretQueuedKeyEvent(editorState()), 186 Messages::WebPageProxy::InterpretQueuedKeyEvent::Reply(eventWasHandled, commands), m_pageID); 187 m_keyboardEventBeingInterpreted = oldEvent; 188 if (!sendResult) 189 return false; 190 191 // An input method may make several actions per keypress. For example, pressing Return with Korean IM both confirms it and sends a newline. 192 // IM-like actions are handled immediately (so the return value from UI process is true), but there are saved commands that 193 // should be handled like normal text input after DOM event dispatch. 194 if (!event->keypressCommands().isEmpty()) 195 return false; 196 } else { 197 // Are there commands that could just cause text insertion if executed via Editor? 198 // WebKit doesn't have enough information about mode to decide how they should be treated, so we leave it upon WebCore 199 // to either handle them immediately (e.g. Tab that changes focus) or let a keypress event be generated 200 // (e.g. Tab that inserts a Tab character, or Enter). 201 bool haveTextInsertionCommands = false; 202 for (size_t i = 0; i < commands.size(); ++i) { 203 if (frame->editor()->command(commandNameForSelectorName(commands[i].commandName)).isTextInsertion()) 204 haveTextInsertionCommands = true; 205 } 206 // If there are no text insertion commands, default keydown handler is the right time to execute the commands. 207 // Keypress (Char event) handler is the latest opportunity to execute. 208 if (!haveTextInsertionCommands || platformEvent->type() == PlatformKeyboardEvent::Char) { 209 eventWasHandled = executeKeypressCommandsInternal(event->keypressCommands(), event); 210 event->keypressCommands().clear(); 211 } 212 } 213 return eventWasHandled; 214 } 215 216 void WebPage::sendComplexTextInputToPlugin(uint64_t pluginComplexTextInputIdentifier, const String& textInput) 217 { 218 for (HashSet<PluginView*>::const_iterator it = m_pluginViews.begin(), end = m_pluginViews.end(); it != end; ++it) { 219 if ((*it)->sendComplexTextInput(pluginComplexTextInputIdentifier, textInput)) 220 break; 221 } 222 } 223 224 void WebPage::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, EditorState& newState) 225 { 226 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 227 228 if (frame->selection()->isContentEditable()) { 229 RefPtr<Range> replacementRange; 230 if (replacementRangeStart != NSNotFound) { 231 replacementRange = convertToRange(frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart)); 232 frame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY)); 233 } 234 235 frame->editor()->setComposition(text, underlines, selectionStart, selectionEnd); 236 } 237 238 newState = editorState(); 239 } 240 241 void WebPage::confirmComposition(EditorState& newState) 242 { 243 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 244 245 frame->editor()->confirmComposition(); 246 247 newState = editorState(); 248 } 249 250 void WebPage::insertText(const String& text, uint64_t replacementRangeStart, uint64_t replacementRangeEnd, bool& handled, EditorState& newState) 251 { 252 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 253 254 RefPtr<Range> replacementRange; 255 if (replacementRangeStart != NSNotFound) { 256 replacementRange = convertToRange(frame, NSMakeRange(replacementRangeStart, replacementRangeEnd - replacementRangeStart)); 257 frame->selection()->setSelection(VisibleSelection(replacementRange.get(), SEL_DEFAULT_AFFINITY)); 258 } 259 260 if (!frame->editor()->hasComposition()) { 261 // An insertText: might be handled by other responders in the chain if we don't handle it. 262 // One example is space bar that results in scrolling down the page. 263 handled = frame->editor()->insertText(text, m_keyboardEventBeingInterpreted); 264 } else { 265 handled = true; 266 frame->editor()->confirmComposition(text); 267 } 268 269 newState = editorState(); 270 } 271 272 void WebPage::getMarkedRange(uint64_t& location, uint64_t& length) 273 { 274 location = NSNotFound; 275 length = 0; 276 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 277 if (!frame) 278 return; 279 280 RefPtr<Range> range = frame->editor()->compositionRange(); 281 size_t locationSize; 282 size_t lengthSize; 283 if (range && TextIterator::locationAndLengthFromRange(range.get(), locationSize, lengthSize)) { 284 location = static_cast<uint64_t>(locationSize); 285 length = static_cast<uint64_t>(lengthSize); 286 } 287 } 288 289 void WebPage::getSelectedRange(uint64_t& location, uint64_t& length) 290 { 291 location = NSNotFound; 292 length = 0; 293 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 294 if (!frame) 295 return; 296 297 size_t locationSize; 298 size_t lengthSize; 299 RefPtr<Range> range = frame->selection()->toNormalizedRange(); 300 if (range && TextIterator::locationAndLengthFromRange(range.get(), locationSize, lengthSize)) { 301 location = static_cast<uint64_t>(locationSize); 302 length = static_cast<uint64_t>(lengthSize); 303 } 304 } 305 306 void WebPage::getAttributedSubstringFromRange(uint64_t location, uint64_t length, AttributedString& result) 307 { 308 NSRange nsRange = NSMakeRange(location, length - location); 309 310 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 311 if (!frame) 312 return; 313 314 if (frame->selection()->isNone() || !frame->selection()->isContentEditable() || frame->selection()->isInPasswordField()) 315 return; 316 317 RefPtr<Range> range = convertToRange(frame, nsRange); 318 if (!range) 319 return; 320 321 result.string = [WebHTMLConverter editingAttributedStringFromRange:range.get()]; 322 NSAttributedString* attributedString = result.string.get(); 323 324 // [WebHTMLConverter editingAttributedStringFromRange:] insists on inserting a trailing 325 // whitespace at the end of the string which breaks the ATOK input method. <rdar://problem/5400551> 326 // To work around this we truncate the resultant string to the correct length. 327 if ([attributedString length] > nsRange.length) { 328 ASSERT([attributedString length] == nsRange.length + 1); 329 ASSERT([[attributedString string] characterAtIndex:nsRange.length] == '\n' || [[attributedString string] characterAtIndex:nsRange.length] == ' '); 330 result.string = [attributedString attributedSubstringFromRange:NSMakeRange(0, nsRange.length)]; 331 } 332 } 333 334 void WebPage::characterIndexForPoint(IntPoint point, uint64_t& index) 335 { 336 index = NSNotFound; 337 Frame* frame = m_page->mainFrame(); 338 if (!frame) 339 return; 340 341 HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(point, false); 342 frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame(); 343 344 RefPtr<Range> range = frame->rangeForPoint(result.point()); 345 if (!range) 346 return; 347 348 size_t location; 349 size_t length; 350 if (TextIterator::locationAndLengthFromRange(range.get(), location, length)) 351 index = static_cast<uint64_t>(location); 352 } 353 354 PassRefPtr<Range> convertToRange(Frame* frame, NSRange nsrange) 355 { 356 if (nsrange.location > INT_MAX) 357 return 0; 358 if (nsrange.length > INT_MAX || nsrange.location + nsrange.length > INT_MAX) 359 nsrange.length = INT_MAX - nsrange.location; 360 361 // our critical assumption is that we are only called by input methods that 362 // concentrate on a given area containing the selection 363 // We have to do this because of text fields and textareas. The DOM for those is not 364 // directly in the document DOM, so serialization is problematic. Our solution is 365 // to use the root editable element of the selection start as the positional base. 366 // That fits with AppKit's idea of an input context. 367 Element* selectionRoot = frame->selection()->rootEditableElement(); 368 Element* scope = selectionRoot ? selectionRoot : frame->document()->documentElement(); 369 return TextIterator::rangeFromLocationAndLength(scope, nsrange.location, nsrange.length); 370 } 371 372 void WebPage::firstRectForCharacterRange(uint64_t location, uint64_t length, WebCore::IntRect& resultRect) 373 { 374 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 375 resultRect.setLocation(IntPoint(0, 0)); 376 resultRect.setSize(IntSize(0, 0)); 377 378 RefPtr<Range> range = convertToRange(frame, NSMakeRange(location, length)); 379 if (!range) 380 return; 381 382 ASSERT(range->startContainer()); 383 ASSERT(range->endContainer()); 384 385 IntRect rect = frame->editor()->firstRectForRange(range.get()); 386 resultRect = frame->view()->contentsToWindow(rect); 387 } 388 389 void WebPage::executeKeypressCommands(const Vector<WebCore::KeypressCommand>& commands, bool& handled, EditorState& newState) 390 { 391 handled = executeKeypressCommandsInternal(commands, m_keyboardEventBeingInterpreted); 392 newState = editorState(); 393 } 394 395 static bool isPositionInRange(const VisiblePosition& position, Range* range) 396 { 397 RefPtr<Range> positionRange = makeRange(position, position); 398 399 ExceptionCode ec = 0; 400 range->compareBoundaryPoints(Range::START_TO_START, positionRange.get(), ec); 401 if (ec) 402 return false; 403 404 if (!range->isPointInRange(positionRange->startContainer(), positionRange->startOffset(), ec)) 405 return false; 406 if (ec) 407 return false; 408 409 return true; 410 } 411 412 static bool shouldUseSelection(const VisiblePosition& position, const VisibleSelection& selection) 413 { 414 RefPtr<Range> selectedRange = selection.toNormalizedRange(); 415 if (!selectedRange) 416 return false; 417 418 return isPositionInRange(position, selectedRange.get()); 419 } 420 421 void WebPage::performDictionaryLookupAtLocation(const FloatPoint& floatPoint) 422 { 423 Frame* frame = m_page->mainFrame(); 424 if (!frame) 425 return; 426 427 // Find the frame the point is over. 428 IntPoint point = roundedIntPoint(floatPoint); 429 HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(point, false); 430 frame = result.innerNonSharedNode() ? result.innerNonSharedNode()->document()->frame() : m_page->focusController()->focusedOrMainFrame(); 431 432 IntPoint translatedPoint = frame->view()->windowToContents(point); 433 434 // Don't do anything if there is no character at the point. 435 if (!frame->rangeForPoint(translatedPoint)) 436 return; 437 438 VisiblePosition position = frame->visiblePositionForPoint(translatedPoint); 439 VisibleSelection selection = m_page->focusController()->focusedOrMainFrame()->selection()->selection(); 440 if (shouldUseSelection(position, selection)) { 441 performDictionaryLookupForSelection(DictionaryPopupInfo::HotKey, frame, selection); 442 return; 443 } 444 445 NSDictionary *options = nil; 446 447 #if !defined(BUILDING_ON_SNOW_LEOPARD) 448 // As context, we are going to use the surrounding paragraph of text. 449 VisiblePosition paragraphStart = startOfParagraph(position); 450 VisiblePosition paragraphEnd = endOfParagraph(position); 451 452 NSRange rangeToPass = NSMakeRange(TextIterator::rangeLength(makeRange(paragraphStart, position).get()), 0); 453 454 RefPtr<Range> fullCharacterRange = makeRange(paragraphStart, paragraphEnd); 455 String fullPlainTextString = plainText(fullCharacterRange.get()); 456 457 NSRange extractedRange = WKExtractWordDefinitionTokenRangeFromContextualString(fullPlainTextString, rangeToPass, &options); 458 459 RefPtr<Range> finalRange = TextIterator::subrange(fullCharacterRange.get(), extractedRange.location, extractedRange.length); 460 if (!finalRange) 461 return; 462 #else 463 RefPtr<Range> finalRange = makeRange(startOfWord(position), endOfWord(position)); 464 if (!finalRange) 465 return; 466 #endif 467 468 performDictionaryLookupForRange(DictionaryPopupInfo::HotKey, frame, finalRange.get(), options); 469 } 470 471 void WebPage::performDictionaryLookupForSelection(DictionaryPopupInfo::Type type, Frame* frame, const VisibleSelection& selection) 472 { 473 RefPtr<Range> selectedRange = selection.toNormalizedRange(); 474 if (!selectedRange) 475 return; 476 477 NSDictionary *options = nil; 478 479 #if !defined(BUILDING_ON_SNOW_LEOPARD) 480 VisiblePosition selectionStart = selection.visibleStart(); 481 VisiblePosition selectionEnd = selection.visibleEnd(); 482 483 // As context, we are going to use the surrounding paragraphs of text. 484 VisiblePosition paragraphStart = startOfParagraph(selectionStart); 485 VisiblePosition paragraphEnd = endOfParagraph(selectionEnd); 486 487 int lengthToSelectionStart = TextIterator::rangeLength(makeRange(paragraphStart, selectionStart).get()); 488 int lengthToSelectionEnd = TextIterator::rangeLength(makeRange(paragraphStart, selectionEnd).get()); 489 NSRange rangeToPass = NSMakeRange(lengthToSelectionStart, lengthToSelectionEnd - lengthToSelectionStart); 490 491 String fullPlainTextString = plainText(makeRange(paragraphStart, paragraphEnd).get()); 492 493 // Since we already have the range we want, we just need to grab the returned options. 494 WKExtractWordDefinitionTokenRangeFromContextualString(fullPlainTextString, rangeToPass, &options); 495 #endif 496 497 performDictionaryLookupForRange(type, frame, selectedRange.get(), options); 498 } 499 500 void WebPage::performDictionaryLookupForRange(DictionaryPopupInfo::Type type, Frame* frame, Range* range, NSDictionary *options) 501 { 502 String rangeText = range->text(); 503 if (rangeText.stripWhiteSpace().isEmpty()) 504 return; 505 506 RenderObject* renderer = range->startContainer()->renderer(); 507 RenderStyle* style = renderer->style(); 508 NSFont *font = style->font().primaryFont()->getNSFont(); 509 if (!font) 510 return; 511 512 CFDictionaryRef fontDescriptorAttributes = (CFDictionaryRef)[[font fontDescriptor] fontAttributes]; 513 if (!fontDescriptorAttributes) 514 return; 515 516 Vector<FloatQuad> quads; 517 range->textQuads(quads); 518 if (quads.isEmpty()) 519 return; 520 521 IntRect rangeRect = frame->view()->contentsToWindow(quads[0].enclosingBoundingBox()); 522 523 DictionaryPopupInfo dictionaryPopupInfo; 524 dictionaryPopupInfo.type = type; 525 dictionaryPopupInfo.origin = FloatPoint(rangeRect.x(), rangeRect.y()); 526 dictionaryPopupInfo.fontInfo.fontAttributeDictionary = fontDescriptorAttributes; 527 #if !defined(BUILDING_ON_SNOW_LEOPARD) 528 dictionaryPopupInfo.options = (CFDictionaryRef)options; 529 #endif 530 531 send(Messages::WebPageProxy::DidPerformDictionaryLookup(rangeText, dictionaryPopupInfo)); 532 } 533 534 bool WebPage::performNonEditingBehaviorForSelector(const String& selector) 535 { 536 // FIXME: All these selectors have corresponding Editor commands, but the commands only work in editable content. 537 // Should such non-editing behaviors be implemented in Editor or EventHandler::defaultArrowEventHandler() perhaps? 538 if (selector == "moveUp:") 539 scroll(m_page.get(), ScrollUp, ScrollByLine); 540 else if (selector == "moveToBeginningOfParagraph:") 541 scroll(m_page.get(), ScrollUp, ScrollByPage); 542 else if (selector == "moveToBeginningOfDocument:") { 543 scroll(m_page.get(), ScrollUp, ScrollByDocument); 544 scroll(m_page.get(), ScrollLeft, ScrollByDocument); 545 } else if (selector == "moveDown:") 546 scroll(m_page.get(), ScrollDown, ScrollByLine); 547 else if (selector == "moveToEndOfParagraph:") 548 scroll(m_page.get(), ScrollDown, ScrollByPage); 549 else if (selector == "moveToEndOfDocument:") { 550 scroll(m_page.get(), ScrollDown, ScrollByDocument); 551 scroll(m_page.get(), ScrollLeft, ScrollByDocument); 552 } else if (selector == "moveLeft:") 553 scroll(m_page.get(), ScrollLeft, ScrollByLine); 554 else if (selector == "moveWordLeft:") 555 scroll(m_page.get(), ScrollLeft, ScrollByPage); 556 else if (selector == "moveToLeftEndOfLine:") 557 m_page->goBack(); 558 else if (selector == "moveRight:") 559 scroll(m_page.get(), ScrollRight, ScrollByLine); 560 else if (selector == "moveWordRight:") 561 scroll(m_page.get(), ScrollRight, ScrollByPage); 562 else if (selector == "moveToRightEndOfLine:") 563 m_page->goForward(); 564 else 565 return false; 566 567 return true; 568 } 569 570 bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent&) 571 { 572 return false; 573 } 574 575 void WebPage::registerUIProcessAccessibilityTokens(const CoreIPC::DataReference& elementToken, const CoreIPC::DataReference& windowToken) 576 { 577 #if !defined(BUILDING_ON_SNOW_LEOPARD) 578 NSData* elementTokenData = [NSData dataWithBytes:elementToken.data() length:elementToken.size()]; 579 NSData* windowTokenData = [NSData dataWithBytes:windowToken.data() length:windowToken.size()]; 580 id remoteElement = WKAXRemoteElementForToken(elementTokenData); 581 id remoteWindow = WKAXRemoteElementForToken(windowTokenData); 582 WKAXSetWindowForRemoteElement(remoteWindow, remoteElement); 583 584 [accessibilityRemoteObject() setRemoteParent:remoteElement]; 585 #endif 586 } 587 588 void WebPage::writeSelectionToPasteboard(const String& pasteboardName, const Vector<String>& pasteboardTypes, bool& result) 589 { 590 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 591 if (!frame || frame->selection()->isNone()) { 592 result = false; 593 return; 594 } 595 frame->editor()->writeSelectionToPasteboard(pasteboardName, pasteboardTypes); 596 result = true; 597 } 598 599 void WebPage::readSelectionFromPasteboard(const String& pasteboardName, bool& result) 600 { 601 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 602 if (!frame || frame->selection()->isNone()) { 603 result = false; 604 return; 605 } 606 frame->editor()->readSelectionFromPasteboard(pasteboardName); 607 result = true; 608 } 609 610 AccessibilityWebPageObject* WebPage::accessibilityRemoteObject() 611 { 612 return m_mockAccessibilityElement.get(); 613 } 614 615 bool WebPage::platformHasLocalDataForURL(const WebCore::KURL& url) 616 { 617 NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url]; 618 [request setValue:(NSString*)userAgent() forHTTPHeaderField:@"User-Agent"]; 619 NSCachedURLResponse *cachedResponse; 620 #if USE(CFURLSTORAGESESSIONS) 621 if (CFURLStorageSessionRef storageSession = ResourceHandle::privateBrowsingStorageSession()) 622 cachedResponse = WKCachedResponseForRequest(storageSession, request); 623 else 624 #endif 625 cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; 626 [request release]; 627 628 return cachedResponse; 629 } 630 631 String WebPage::cachedResponseMIMETypeForURL(const WebCore::KURL& url) 632 { 633 NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url]; 634 [request setValue:(NSString*)userAgent() forHTTPHeaderField:@"User-Agent"]; 635 NSCachedURLResponse *cachedResponse; 636 #if USE(CFURLSTORAGESESSIONS) 637 if (CFURLStorageSessionRef storageSession = ResourceHandle::privateBrowsingStorageSession()) 638 cachedResponse = WKCachedResponseForRequest(storageSession, request); 639 else 640 #endif 641 cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request]; 642 [request release]; 643 644 return [[cachedResponse response] MIMEType]; 645 } 646 647 bool WebPage::platformCanHandleRequest(const WebCore::ResourceRequest& request) 648 { 649 if ([NSURLConnection canHandleRequest:request.nsURLRequest()]) 650 return true; 651 652 // FIXME: Return true if this scheme is any one WebKit2 knows how to handle. 653 return request.url().protocolIs("applewebdata"); 654 } 655 656 void WebPage::setDragSource(NSObject *dragSource) 657 { 658 m_dragSource = dragSource; 659 } 660 661 void WebPage::platformDragEnded() 662 { 663 // The draggedImage method releases its responder; we retain here to balance that. 664 [m_dragSource.get() retain]; 665 // The drag source we care about here is NSFilePromiseDragSource, which doesn't look at 666 // the arguments. It's OK to just pass arbitrary constant values, so we just pass all zeroes. 667 [m_dragSource.get() draggedImage:nil endedAt:NSZeroPoint operation:NSDragOperationNone]; 668 m_dragSource = nullptr; 669 } 670 671 void WebPage::shouldDelayWindowOrderingEvent(const WebKit::WebMouseEvent& event, bool& result) 672 { 673 result = false; 674 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 675 if (!frame) 676 return; 677 678 HitTestResult hitResult = frame->eventHandler()->hitTestResultAtPoint(event.position(), true); 679 if (hitResult.isSelected()) 680 result = frame->eventHandler()->eventMayStartDrag(platform(event)); 681 } 682 683 void WebPage::acceptsFirstMouse(int eventNumber, const WebKit::WebMouseEvent& event, bool& result) 684 { 685 result = false; 686 Frame* frame = m_page->focusController()->focusedOrMainFrame(); 687 if (!frame) 688 return; 689 690 HitTestResult hitResult = frame->eventHandler()->hitTestResultAtPoint(event.position(), true); 691 frame->eventHandler()->setActivationEventNumber(eventNumber); 692 if (hitResult.isSelected()) 693 result = frame->eventHandler()->eventMayStartDrag(platform(event)); 694 else 695 result = !!hitResult.scrollbar(); 696 } 697 698 } // namespace WebKit 699