| OLD | NEW |
| (Empty) | |
| 1 /* |
| 2 * Copyright (C) 2014 Google 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 are |
| 6 * met: |
| 7 * |
| 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above |
| 11 * copyright notice, this list of conditions and the following disclaimer |
| 12 * in the documentation and/or other materials provided with the |
| 13 * distribution. |
| 14 * * Neither the name of Google Inc. nor the names of its |
| 15 * contributors may be used to endorse or promote products derived from |
| 16 * this software without specific prior written permission. |
| 17 * |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ |
| 30 |
| 31 #include "config.h" |
| 32 #include "web/WebFrameWidgetImpl.h" |
| 33 |
| 34 #include "core/editing/Editor.h" |
| 35 #include "core/editing/FrameSelection.h" |
| 36 #include "core/editing/InputMethodController.h" |
| 37 #include "core/editing/PlainTextRange.h" |
| 38 #include "core/frame/FrameView.h" |
| 39 #include "core/frame/RemoteFrame.h" |
| 40 #include "core/frame/Settings.h" |
| 41 #include "core/page/EventHandler.h" |
| 42 #include "core/page/FocusController.h" |
| 43 #include "core/page/Page.h" |
| 44 #include "core/rendering/RenderView.h" |
| 45 #include "core/rendering/compositing/RenderLayerCompositor.h" |
| 46 #include "platform/KeyboardCodes.h" |
| 47 #include "platform/NotImplemented.h" |
| 48 #include "public/web/WebBeginFrameArgs.h" |
| 49 #include "public/web/WebWidgetClient.h" |
| 50 #include "web/WebInputEventConversion.h" |
| 51 #include "web/WebLocalFrameImpl.h" |
| 52 #include "web/WebPluginContainerImpl.h" |
| 53 #include "web/WebRemoteFrameImpl.h" |
| 54 #include "web/WebViewImpl.h" |
| 55 |
| 56 namespace blink { |
| 57 |
| 58 // WebFrameWidget --------------------------------------------------------------
-- |
| 59 |
| 60 WebFrameWidget* WebFrameWidget::create(WebWidgetClient* client, WebLocalFrame* l
ocalRoot) |
| 61 { |
| 62 // Pass the WebFrameWidget's self-reference to the caller. |
| 63 return WebFrameWidgetImpl::create(client, localRoot); |
| 64 } |
| 65 |
| 66 WebFrameWidgetImpl* WebFrameWidgetImpl::create(WebWidgetClient* client, WebLocal
Frame* localRoot) |
| 67 { |
| 68 // Pass the WebFrameWidgetImpl's self-reference to the caller. |
| 69 return adoptRef(new WebFrameWidgetImpl(client, localRoot)).leakRef(); |
| 70 } |
| 71 |
| 72 WebFrameWidgetImpl::WebFrameWidgetImpl(WebWidgetClient* client, WebLocalFrame* l
ocalRoot) |
| 73 : m_client(client) |
| 74 , m_localRoot(toWebLocalFrameImpl(localRoot)) |
| 75 , m_layerTreeView(nullptr) |
| 76 , m_rootLayer(nullptr) |
| 77 , m_rootGraphicsLayer(nullptr) |
| 78 , m_isAcceleratedCompositingActive(false) |
| 79 , m_layerTreeViewClosed(false) |
| 80 , m_webView(m_localRoot->viewImpl()) |
| 81 , m_page(m_webView->page()) |
| 82 , m_suppressNextKeypressEvent(false) |
| 83 , m_ignoreInputEvents(false) |
| 84 { |
| 85 ASSERT(m_localRoot->frame()->isLocalRoot()); |
| 86 initializeLayerTreeView(); |
| 87 m_localRoot->setFrameWidget(this); |
| 88 } |
| 89 |
| 90 WebFrameWidgetImpl::~WebFrameWidgetImpl() |
| 91 { |
| 92 } |
| 93 |
| 94 // WebWidget ------------------------------------------------------------------ |
| 95 |
| 96 void WebFrameWidgetImpl::close() |
| 97 { |
| 98 // Reset the delegate to prevent notifications being sent as we're being |
| 99 // deleted. |
| 100 m_client = nullptr; |
| 101 |
| 102 deref(); // Balances ref() acquired in WebFrameWidget::create |
| 103 } |
| 104 |
| 105 WebSize WebFrameWidgetImpl::size() |
| 106 { |
| 107 return m_size; |
| 108 } |
| 109 |
| 110 void WebFrameWidgetImpl::willStartLiveResize() |
| 111 { |
| 112 if (m_localRoot->frameView()) |
| 113 m_localRoot->frameView()->willStartLiveResize(); |
| 114 |
| 115 LocalFrame* frame = m_localRoot->frame(); |
| 116 WebPluginContainerImpl* pluginContainer = WebLocalFrameImpl::pluginContainer
FromFrame(frame); |
| 117 if (pluginContainer) |
| 118 pluginContainer->willStartLiveResize(); |
| 119 } |
| 120 |
| 121 void WebFrameWidgetImpl::resize(const WebSize& newSize) |
| 122 { |
| 123 if (m_size == newSize) |
| 124 return; |
| 125 |
| 126 FrameView* view = m_localRoot->frameView(); |
| 127 if (!view) |
| 128 return; |
| 129 |
| 130 m_size = newSize; |
| 131 |
| 132 updateMainFrameLayoutSize(); |
| 133 |
| 134 view->resize(m_size); |
| 135 |
| 136 // FIXME: In WebViewImpl this layout was a precursor to setting the minimum
scale limit. |
| 137 // It is not clear if this is necessary for frame-level widget resize. |
| 138 if (view->needsLayout()) |
| 139 view->layout(); |
| 140 |
| 141 // FIXME: Investigate whether this is needed; comment from eseidel suggests
that this function |
| 142 // is flawed. |
| 143 sendResizeEventAndRepaint(); |
| 144 } |
| 145 |
| 146 void WebFrameWidgetImpl::sendResizeEventAndRepaint() |
| 147 { |
| 148 // FIXME: This is wrong. The FrameView is responsible sending a resizeEvent |
| 149 // as part of layout. Layout is also responsible for sending invalidations |
| 150 // to the embedder. This method and all callers may be wrong. -- eseidel. |
| 151 if (m_localRoot->frameView()) { |
| 152 // Enqueues the resize event. |
| 153 m_localRoot->frame()->document()->enqueueResizeEvent(); |
| 154 } |
| 155 |
| 156 if (m_client) { |
| 157 if (isAcceleratedCompositingActive()) { |
| 158 updateLayerTreeViewport(); |
| 159 } else { |
| 160 WebRect damagedRect(0, 0, m_size.width, m_size.height); |
| 161 m_client->didInvalidateRect(damagedRect); |
| 162 } |
| 163 } |
| 164 } |
| 165 |
| 166 void WebFrameWidgetImpl::resizePinchViewport(const WebSize& newSize) |
| 167 { |
| 168 // FIXME: Implement pinch viewport for out-of-process iframes. |
| 169 } |
| 170 |
| 171 void WebFrameWidgetImpl::updateMainFrameLayoutSize() |
| 172 { |
| 173 if (!m_localRoot) |
| 174 return; |
| 175 |
| 176 RefPtr<FrameView> view = m_localRoot->frameView(); |
| 177 if (!view) |
| 178 return; |
| 179 |
| 180 WebSize layoutSize = m_size; |
| 181 |
| 182 view->setLayoutSize(layoutSize); |
| 183 } |
| 184 |
| 185 void WebFrameWidgetImpl::willEndLiveResize() |
| 186 { |
| 187 if (m_localRoot->frameView()) |
| 188 m_localRoot->frameView()->willEndLiveResize(); |
| 189 |
| 190 LocalFrame* frame = m_localRoot->frame(); |
| 191 WebPluginContainerImpl* pluginContainer = WebLocalFrameImpl::pluginContainer
FromFrame(frame); |
| 192 if (pluginContainer) |
| 193 pluginContainer->willEndLiveResize(); |
| 194 } |
| 195 |
| 196 void WebFrameWidgetImpl::willEnterFullScreen() |
| 197 { |
| 198 // FIXME: Implement full screen for out-of-process iframes. |
| 199 } |
| 200 |
| 201 void WebFrameWidgetImpl::didEnterFullScreen() |
| 202 { |
| 203 // FIXME: Implement full screen for out-of-process iframes. |
| 204 } |
| 205 |
| 206 void WebFrameWidgetImpl::willExitFullScreen() |
| 207 { |
| 208 // FIXME: Implement full screen for out-of-process iframes. |
| 209 } |
| 210 |
| 211 void WebFrameWidgetImpl::didExitFullScreen() |
| 212 { |
| 213 // FIXME: Implement full screen for out-of-process iframes. |
| 214 } |
| 215 |
| 216 void WebFrameWidgetImpl::beginFrame(const WebBeginFrameArgs& frameTime) |
| 217 { |
| 218 TRACE_EVENT0("blink", "WebFrameWidgetImpl::beginFrame"); |
| 219 |
| 220 WebBeginFrameArgs validFrameTime(frameTime); |
| 221 if (!validFrameTime.lastFrameTimeMonotonic) |
| 222 validFrameTime.lastFrameTimeMonotonic = monotonicallyIncreasingTime(); |
| 223 |
| 224 PageWidgetDelegate::animate(*m_page, validFrameTime.lastFrameTimeMonotonic,
*m_localRoot->frame()); |
| 225 } |
| 226 |
| 227 void WebFrameWidgetImpl::layout() |
| 228 { |
| 229 TRACE_EVENT0("blink", "WebFrameWidgetImpl::layout"); |
| 230 if (!m_localRoot) |
| 231 return; |
| 232 |
| 233 PageWidgetDelegate::layout(*m_page, *m_localRoot->frame()); |
| 234 updateLayerTreeBackgroundColor(); |
| 235 } |
| 236 |
| 237 void WebFrameWidgetImpl::paint(WebCanvas* canvas, const WebRect& rect) |
| 238 { |
| 239 // Out-of-process iframes require compositing. |
| 240 ASSERT_NOT_REACHED(); |
| 241 } |
| 242 |
| 243 |
| 244 void WebFrameWidgetImpl::updateLayerTreeViewport() |
| 245 { |
| 246 if (!page() || !m_layerTreeView) |
| 247 return; |
| 248 |
| 249 // FIXME: We need access to page scale information from the WebView. |
| 250 m_layerTreeView->setPageScaleFactorAndLimits(1, 1, 1); |
| 251 } |
| 252 |
| 253 void WebFrameWidgetImpl::updateLayerTreeBackgroundColor() |
| 254 { |
| 255 if (!m_layerTreeView) |
| 256 return; |
| 257 |
| 258 m_layerTreeView->setBackgroundColor(alphaChannel(m_webView->backgroundColorO
verride()) ? m_webView->backgroundColorOverride() : m_webView->backgroundColor()
); |
| 259 } |
| 260 |
| 261 void WebFrameWidgetImpl::updateLayerTreeDeviceScaleFactor() |
| 262 { |
| 263 ASSERT(page()); |
| 264 ASSERT(m_layerTreeView); |
| 265 |
| 266 float deviceScaleFactor = page()->deviceScaleFactor(); |
| 267 m_layerTreeView->setDeviceScaleFactor(deviceScaleFactor); |
| 268 } |
| 269 |
| 270 bool WebFrameWidgetImpl::isTransparent() const |
| 271 { |
| 272 // FIXME: This might need to proxy to the WebView's isTransparent(). |
| 273 return false; |
| 274 } |
| 275 |
| 276 void WebFrameWidgetImpl::compositeAndReadbackAsync(WebCompositeAndReadbackAsyncC
allback* callback) |
| 277 { |
| 278 m_layerTreeView->compositeAndReadbackAsync(callback); |
| 279 } |
| 280 |
| 281 bool WebFrameWidgetImpl::isTrackingRepaints() const |
| 282 { |
| 283 return m_localRoot->frameView()->isTrackingPaintInvalidations(); |
| 284 } |
| 285 |
| 286 void WebFrameWidgetImpl::themeChanged() |
| 287 { |
| 288 FrameView* view = m_localRoot->frameView(); |
| 289 |
| 290 WebRect damagedRect(0, 0, m_size.width, m_size.height); |
| 291 view->invalidateRect(damagedRect); |
| 292 } |
| 293 |
| 294 const WebInputEvent* WebFrameWidgetImpl::m_currentInputEvent = nullptr; |
| 295 |
| 296 // FIXME: autogenerate this kind of code, and use it throughout Blink rather tha
n |
| 297 // the one-offs for subsets of these values. |
| 298 static String inputTypeToName(WebInputEvent::Type type) |
| 299 { |
| 300 switch (type) { |
| 301 case WebInputEvent::MouseDown: |
| 302 return EventTypeNames::mousedown; |
| 303 case WebInputEvent::MouseUp: |
| 304 return EventTypeNames::mouseup; |
| 305 case WebInputEvent::MouseMove: |
| 306 return EventTypeNames::mousemove; |
| 307 case WebInputEvent::MouseEnter: |
| 308 return EventTypeNames::mouseenter; |
| 309 case WebInputEvent::MouseLeave: |
| 310 return EventTypeNames::mouseleave; |
| 311 case WebInputEvent::ContextMenu: |
| 312 return EventTypeNames::contextmenu; |
| 313 case WebInputEvent::MouseWheel: |
| 314 return EventTypeNames::mousewheel; |
| 315 case WebInputEvent::KeyDown: |
| 316 return EventTypeNames::keydown; |
| 317 case WebInputEvent::KeyUp: |
| 318 return EventTypeNames::keyup; |
| 319 case WebInputEvent::GestureScrollBegin: |
| 320 return EventTypeNames::gesturescrollstart; |
| 321 case WebInputEvent::GestureScrollEnd: |
| 322 return EventTypeNames::gesturescrollend; |
| 323 case WebInputEvent::GestureScrollUpdate: |
| 324 return EventTypeNames::gesturescrollupdate; |
| 325 case WebInputEvent::GestureTapDown: |
| 326 return EventTypeNames::gesturetapdown; |
| 327 case WebInputEvent::GestureShowPress: |
| 328 return EventTypeNames::gestureshowpress; |
| 329 case WebInputEvent::GestureTap: |
| 330 return EventTypeNames::gesturetap; |
| 331 case WebInputEvent::GestureTapUnconfirmed: |
| 332 return EventTypeNames::gesturetapunconfirmed; |
| 333 case WebInputEvent::TouchStart: |
| 334 return EventTypeNames::touchstart; |
| 335 case WebInputEvent::TouchMove: |
| 336 return EventTypeNames::touchmove; |
| 337 case WebInputEvent::TouchEnd: |
| 338 return EventTypeNames::touchend; |
| 339 case WebInputEvent::TouchCancel: |
| 340 return EventTypeNames::touchcancel; |
| 341 default: |
| 342 return String("unknown"); |
| 343 } |
| 344 } |
| 345 |
| 346 bool WebFrameWidgetImpl::handleInputEvent(const WebInputEvent& inputEvent) |
| 347 { |
| 348 |
| 349 TRACE_EVENT1("input", "WebFrameWidgetImpl::handleInputEvent", "type", inputT
ypeToName(inputEvent.type).ascii()); |
| 350 |
| 351 // Report the event to be NOT processed by WebKit, so that the browser can h
andle it appropriately. |
| 352 if (m_ignoreInputEvents) |
| 353 return false; |
| 354 |
| 355 TemporaryChange<const WebInputEvent*> currentEventChange(m_currentInputEvent
, &inputEvent); |
| 356 |
| 357 if (m_mouseCaptureNode && WebInputEvent::isMouseEventType(inputEvent.type))
{ |
| 358 TRACE_EVENT1("input", "captured mouse event", "type", inputEvent.type); |
| 359 // Save m_mouseCaptureNode since mouseCaptureLost() will clear it. |
| 360 RefPtrWillBeRawPtr<Node> node = m_mouseCaptureNode; |
| 361 |
| 362 // Not all platforms call mouseCaptureLost() directly. |
| 363 if (inputEvent.type == WebInputEvent::MouseUp) |
| 364 mouseCaptureLost(); |
| 365 |
| 366 OwnPtr<UserGestureIndicator> gestureIndicator; |
| 367 |
| 368 AtomicString eventType; |
| 369 switch (inputEvent.type) { |
| 370 case WebInputEvent::MouseMove: |
| 371 eventType = EventTypeNames::mousemove; |
| 372 break; |
| 373 case WebInputEvent::MouseLeave: |
| 374 eventType = EventTypeNames::mouseout; |
| 375 break; |
| 376 case WebInputEvent::MouseDown: |
| 377 eventType = EventTypeNames::mousedown; |
| 378 gestureIndicator = adoptPtr(new UserGestureIndicator(DefinitelyProce
ssingNewUserGesture)); |
| 379 m_mouseCaptureGestureToken = gestureIndicator->currentToken(); |
| 380 break; |
| 381 case WebInputEvent::MouseUp: |
| 382 eventType = EventTypeNames::mouseup; |
| 383 gestureIndicator = adoptPtr(new UserGestureIndicator(m_mouseCaptureG
estureToken.release())); |
| 384 break; |
| 385 default: |
| 386 ASSERT_NOT_REACHED(); |
| 387 } |
| 388 |
| 389 node->dispatchMouseEvent( |
| 390 PlatformMouseEventBuilder(m_localRoot->frameView(), static_cast<cons
t WebMouseEvent&>(inputEvent)), |
| 391 eventType, static_cast<const WebMouseEvent&>(inputEvent).clickCount)
; |
| 392 return true; |
| 393 } |
| 394 |
| 395 return PageWidgetDelegate::handleInputEvent(*this, inputEvent, m_localRoot->
frame()); |
| 396 } |
| 397 |
| 398 void WebFrameWidgetImpl::setCursorVisibilityState(bool isVisible) |
| 399 { |
| 400 m_page->setIsCursorVisible(isVisible); |
| 401 } |
| 402 |
| 403 bool WebFrameWidgetImpl::hasTouchEventHandlersAt(const WebPoint& point) |
| 404 { |
| 405 // FIXME: Implement this. Note that the point must be divided by pageScaleFa
ctor. |
| 406 return true; |
| 407 } |
| 408 |
| 409 void WebFrameWidgetImpl::scheduleAnimation() |
| 410 { |
| 411 if (m_layerTreeView) { |
| 412 m_layerTreeView->setNeedsAnimate(); |
| 413 return; |
| 414 } |
| 415 if (m_client) |
| 416 m_client->scheduleAnimation(); |
| 417 } |
| 418 |
| 419 void WebFrameWidgetImpl::applyViewportDeltas( |
| 420 const WebSize& pinchViewportDelta, |
| 421 const WebSize& mainFrameDelta, |
| 422 const WebFloatSize& elasticOverscrollDelta, |
| 423 float pageScaleDelta, |
| 424 float topControlsDelta) |
| 425 { |
| 426 // FIXME: To be implemented. |
| 427 } |
| 428 |
| 429 void WebFrameWidgetImpl::applyViewportDeltas(const WebSize& scrollDelta, float p
ageScaleDelta, float topControlsDelta) |
| 430 { |
| 431 // FIXME: To be implemented. |
| 432 } |
| 433 |
| 434 void WebFrameWidgetImpl::mouseCaptureLost() |
| 435 { |
| 436 TRACE_EVENT_ASYNC_END0("input", "capturing mouse", this); |
| 437 m_mouseCaptureNode = nullptr; |
| 438 } |
| 439 |
| 440 void WebFrameWidgetImpl::setFocus(bool enable) |
| 441 { |
| 442 m_page->focusController().setFocused(enable); |
| 443 if (enable) { |
| 444 m_page->focusController().setActive(true); |
| 445 RefPtr<Frame> focusedFrame = m_page->focusController().focusedFrame(); |
| 446 if (focusedFrame && focusedFrame->isLocalFrame()) { |
| 447 LocalFrame* localFrame = toLocalFrame(focusedFrame.get()); |
| 448 Element* element = localFrame->document()->focusedElement(); |
| 449 if (element && localFrame->selection().selection().isNone()) { |
| 450 // If the selection was cleared while the WebView was not |
| 451 // focused, then the focus element shows with a focus ring but |
| 452 // no caret and does respond to keyboard inputs. |
| 453 if (element->isTextFormControl()) { |
| 454 element->updateFocusAppearance(true); |
| 455 } else if (element->isContentEditable()) { |
| 456 // updateFocusAppearance() selects all the text of |
| 457 // contentseditable DIVs. So we set the selection explicitly |
| 458 // instead. Note that this has the side effect of moving the |
| 459 // caret back to the beginning of the text. |
| 460 Position position(element, 0, Position::PositionIsOffsetInAn
chor); |
| 461 localFrame->selection().setSelection(VisibleSelection(positi
on, SEL_DEFAULT_AFFINITY)); |
| 462 } |
| 463 } |
| 464 } |
| 465 } |
| 466 } |
| 467 |
| 468 bool WebFrameWidgetImpl::setComposition( |
| 469 const WebString& text, |
| 470 const WebVector<WebCompositionUnderline>& underlines, |
| 471 int selectionStart, |
| 472 int selectionEnd) |
| 473 { |
| 474 // FIXME: To be implemented. |
| 475 return false; |
| 476 } |
| 477 |
| 478 bool WebFrameWidgetImpl::confirmComposition() |
| 479 { |
| 480 // FIXME: To be implemented. |
| 481 return false; |
| 482 } |
| 483 |
| 484 bool WebFrameWidgetImpl::confirmComposition(ConfirmCompositionBehavior selection
Behavior) |
| 485 { |
| 486 // FIXME: To be implemented. |
| 487 return false; |
| 488 } |
| 489 |
| 490 bool WebFrameWidgetImpl::confirmComposition(const WebString& text) |
| 491 { |
| 492 // FIXME: To be implemented. |
| 493 return false; |
| 494 } |
| 495 |
| 496 bool WebFrameWidgetImpl::compositionRange(size_t* location, size_t* length) |
| 497 { |
| 498 // FIXME: To be implemented. |
| 499 return false; |
| 500 } |
| 501 |
| 502 WebTextInputInfo WebFrameWidgetImpl::textInputInfo() |
| 503 { |
| 504 WebTextInputInfo info; |
| 505 // FIXME: To be implemented. |
| 506 return info; |
| 507 } |
| 508 |
| 509 WebColor WebFrameWidgetImpl::backgroundColor() const |
| 510 { |
| 511 if (isTransparent()) |
| 512 return Color::transparent; |
| 513 if (!m_localRoot->frameView()) |
| 514 return m_webView->backgroundColor(); |
| 515 FrameView* view = m_localRoot->frameView(); |
| 516 return view->documentBackgroundColor().rgb(); |
| 517 } |
| 518 |
| 519 bool WebFrameWidgetImpl::selectionBounds(WebRect& anchor, WebRect& focus) const |
| 520 { |
| 521 const Frame* frame = focusedCoreFrame(); |
| 522 if (!frame || !frame->isLocalFrame()) |
| 523 return false; |
| 524 |
| 525 const LocalFrame* localFrame = toLocalFrame(frame); |
| 526 if (!localFrame) |
| 527 return false; |
| 528 FrameSelection& selection = localFrame->selection(); |
| 529 |
| 530 if (selection.isCaret()) { |
| 531 anchor = focus = selection.absoluteCaretBounds(); |
| 532 } else { |
| 533 RefPtrWillBeRawPtr<Range> selectedRange = selection.toNormalizedRange(); |
| 534 if (!selectedRange) |
| 535 return false; |
| 536 |
| 537 RefPtrWillBeRawPtr<Range> range(Range::create(selectedRange->startContai
ner()->document(), |
| 538 selectedRange->startContainer(), |
| 539 selectedRange->startOffset(), |
| 540 selectedRange->startContainer(), |
| 541 selectedRange->startOffset())); |
| 542 anchor = localFrame->editor().firstRectForRange(range.get()); |
| 543 |
| 544 range = Range::create(selectedRange->endContainer()->document(), |
| 545 selectedRange->endContainer(), |
| 546 selectedRange->endOffset(), |
| 547 selectedRange->endContainer(), |
| 548 selectedRange->endOffset()); |
| 549 focus = localFrame->editor().firstRectForRange(range.get()); |
| 550 } |
| 551 |
| 552 IntRect scaledAnchor(localFrame->view()->contentsToWindow(anchor)); |
| 553 IntRect scaledFocus(localFrame->view()->contentsToWindow(focus)); |
| 554 |
| 555 anchor = scaledAnchor; |
| 556 focus = scaledFocus; |
| 557 |
| 558 if (!selection.selection().isBaseFirst()) |
| 559 std::swap(anchor, focus); |
| 560 return true; |
| 561 } |
| 562 |
| 563 bool WebFrameWidgetImpl::selectionTextDirection(WebTextDirection& start, WebText
Direction& end) const |
| 564 { |
| 565 if (!focusedCoreFrame()->isLocalFrame()) |
| 566 return false; |
| 567 const LocalFrame* frame = toLocalFrame(focusedCoreFrame()); |
| 568 if (!frame) |
| 569 return false; |
| 570 FrameSelection& selection = frame->selection(); |
| 571 if (!selection.toNormalizedRange()) |
| 572 return false; |
| 573 start = toWebTextDirection(selection.start().primaryDirection()); |
| 574 end = toWebTextDirection(selection.end().primaryDirection()); |
| 575 return true; |
| 576 } |
| 577 |
| 578 bool WebFrameWidgetImpl::isSelectionAnchorFirst() const |
| 579 { |
| 580 if (!focusedCoreFrame()->isLocalFrame()) |
| 581 return false; |
| 582 if (const LocalFrame* frame = toLocalFrame(focusedCoreFrame())) |
| 583 return frame->selection().selection().isBaseFirst(); |
| 584 return false; |
| 585 } |
| 586 |
| 587 bool WebFrameWidgetImpl::caretOrSelectionRange(size_t* location, size_t* length) |
| 588 { |
| 589 if (!focusedCoreFrame()->isLocalFrame()) |
| 590 return false; |
| 591 const LocalFrame* focused = toLocalFrame(focusedCoreFrame()); |
| 592 if (!focused) |
| 593 return false; |
| 594 |
| 595 PlainTextRange selectionOffsets = focused->inputMethodController().getSelect
ionOffsets(); |
| 596 if (selectionOffsets.isNull()) |
| 597 return false; |
| 598 |
| 599 *location = selectionOffsets.start(); |
| 600 *length = selectionOffsets.length(); |
| 601 return true; |
| 602 } |
| 603 |
| 604 void WebFrameWidgetImpl::setTextDirection(WebTextDirection direction) |
| 605 { |
| 606 // The Editor::setBaseWritingDirection() function checks if we can change |
| 607 // the text direction of the selected node and updates its DOM "dir" |
| 608 // attribute and its CSS "direction" property. |
| 609 // So, we just call the function as Safari does. |
| 610 if (!focusedCoreFrame()->isLocalFrame()) |
| 611 return; |
| 612 const LocalFrame* focused = toLocalFrame(focusedCoreFrame()); |
| 613 if (!focused) |
| 614 return; |
| 615 |
| 616 Editor& editor = focused->editor(); |
| 617 if (!editor.canEdit()) |
| 618 return; |
| 619 |
| 620 switch (direction) { |
| 621 case WebTextDirectionDefault: |
| 622 editor.setBaseWritingDirection(NaturalWritingDirection); |
| 623 break; |
| 624 |
| 625 case WebTextDirectionLeftToRight: |
| 626 editor.setBaseWritingDirection(LeftToRightWritingDirection); |
| 627 break; |
| 628 |
| 629 case WebTextDirectionRightToLeft: |
| 630 editor.setBaseWritingDirection(RightToLeftWritingDirection); |
| 631 break; |
| 632 |
| 633 default: |
| 634 notImplemented(); |
| 635 break; |
| 636 } |
| 637 } |
| 638 |
| 639 bool WebFrameWidgetImpl::isAcceleratedCompositingActive() const |
| 640 { |
| 641 return m_isAcceleratedCompositingActive; |
| 642 } |
| 643 |
| 644 void WebFrameWidgetImpl::willCloseLayerTreeView() |
| 645 { |
| 646 setIsAcceleratedCompositingActive(false); |
| 647 m_layerTreeView = nullptr; |
| 648 m_layerTreeViewClosed = true; |
| 649 } |
| 650 |
| 651 void WebFrameWidgetImpl::didChangeWindowResizerRect() |
| 652 { |
| 653 if (m_localRoot->frameView()) |
| 654 m_localRoot->frameView()->windowResizerRectChanged(); |
| 655 } |
| 656 |
| 657 void WebFrameWidgetImpl::handleMouseLeave(LocalFrame& mainFrame, const WebMouseE
vent& event) |
| 658 { |
| 659 // FIXME: WebWidget doesn't have the method below. |
| 660 // m_client->setMouseOverURL(WebURL()); |
| 661 PageWidgetEventHandler::handleMouseLeave(mainFrame, event); |
| 662 } |
| 663 |
| 664 void WebFrameWidgetImpl::handleMouseDown(LocalFrame& mainFrame, const WebMouseEv
ent& event) |
| 665 { |
| 666 // Take capture on a mouse down on a plugin so we can send it mouse events. |
| 667 // If the hit node is a plugin but a scrollbar is over it don't start mouse |
| 668 // capture because it will interfere with the scrollbar receiving events. |
| 669 IntPoint point(event.x, event.y); |
| 670 if (event.button == WebMouseEvent::ButtonLeft) { |
| 671 point = m_localRoot->frameView()->windowToContents(point); |
| 672 HitTestResult result(m_localRoot->frame()->eventHandler().hitTestResultA
tPoint(point)); |
| 673 result.setToShadowHostIfInUserAgentShadowRoot(); |
| 674 Node* hitNode = result.innerNonSharedNode(); |
| 675 |
| 676 if (!result.scrollbar() && hitNode && hitNode->renderer() && hitNode->re
nderer()->isEmbeddedObject()) { |
| 677 m_mouseCaptureNode = hitNode; |
| 678 TRACE_EVENT_ASYNC_BEGIN0("input", "capturing mouse", this); |
| 679 } |
| 680 } |
| 681 |
| 682 PageWidgetEventHandler::handleMouseDown(mainFrame, event); |
| 683 |
| 684 if (event.button == WebMouseEvent::ButtonLeft && m_mouseCaptureNode) |
| 685 m_mouseCaptureGestureToken = mainFrame.eventHandler().takeLastMouseDownG
estureToken(); |
| 686 |
| 687 // FIXME: Add context menu support. |
| 688 } |
| 689 |
| 690 void WebFrameWidgetImpl::handleMouseUp(LocalFrame& mainFrame, const WebMouseEven
t& event) |
| 691 { |
| 692 PageWidgetEventHandler::handleMouseUp(mainFrame, event); |
| 693 |
| 694 // FIXME: Add context menu support (Windows). |
| 695 } |
| 696 |
| 697 bool WebFrameWidgetImpl::handleMouseWheel(LocalFrame& mainFrame, const WebMouseW
heelEvent& event) |
| 698 { |
| 699 return PageWidgetEventHandler::handleMouseWheel(mainFrame, event); |
| 700 } |
| 701 |
| 702 bool WebFrameWidgetImpl::handleGestureEvent(const WebGestureEvent& event) |
| 703 { |
| 704 // FIXME: Add gesture support. |
| 705 return false; |
| 706 } |
| 707 |
| 708 bool WebFrameWidgetImpl::handleKeyEvent(const WebKeyboardEvent& event) |
| 709 { |
| 710 ASSERT((event.type == WebInputEvent::RawKeyDown) |
| 711 || (event.type == WebInputEvent::KeyDown) |
| 712 || (event.type == WebInputEvent::KeyUp)); |
| 713 |
| 714 // Please refer to the comments explaining the m_suppressNextKeypressEvent |
| 715 // member. |
| 716 // The m_suppressNextKeypressEvent is set if the KeyDown is handled by |
| 717 // Webkit. A keyDown event is typically associated with a keyPress(char) |
| 718 // event and a keyUp event. We reset this flag here as this is a new keyDown |
| 719 // event. |
| 720 m_suppressNextKeypressEvent = false; |
| 721 |
| 722 RefPtr<Frame> focusedFrame = focusedCoreFrame(); |
| 723 if (focusedFrame && focusedFrame->isRemoteFrame()) { |
| 724 WebRemoteFrameImpl* webFrame = WebRemoteFrameImpl::fromFrame(*toRemoteFr
ame(focusedFrame.get())); |
| 725 webFrame->client()->forwardInputEvent(&event); |
| 726 return true; |
| 727 } |
| 728 |
| 729 if (!focusedFrame || !focusedFrame->isLocalFrame()) |
| 730 return false; |
| 731 |
| 732 RefPtr<LocalFrame> frame = toLocalFrame(focusedFrame.get()); |
| 733 |
| 734 PlatformKeyboardEventBuilder evt(event); |
| 735 |
| 736 if (frame->eventHandler().keyEvent(evt)) { |
| 737 if (WebInputEvent::RawKeyDown == event.type) { |
| 738 // Suppress the next keypress event unless the focused node is a plu
g-in node. |
| 739 // (Flash needs these keypress events to handle non-US keyboards.) |
| 740 Element* element = focusedElement(); |
| 741 if (!element || !element->renderer() || !element->renderer()->isEmbe
ddedObject()) |
| 742 m_suppressNextKeypressEvent = true; |
| 743 } |
| 744 return true; |
| 745 } |
| 746 |
| 747 return keyEventDefault(event); |
| 748 } |
| 749 |
| 750 bool WebFrameWidgetImpl::handleCharEvent(const WebKeyboardEvent& event) |
| 751 { |
| 752 ASSERT(event.type == WebInputEvent::Char); |
| 753 |
| 754 // Please refer to the comments explaining the m_suppressNextKeypressEvent |
| 755 // member. The m_suppressNextKeypressEvent is set if the KeyDown is |
| 756 // handled by Webkit. A keyDown event is typically associated with a |
| 757 // keyPress(char) event and a keyUp event. We reset this flag here as it |
| 758 // only applies to the current keyPress event. |
| 759 bool suppress = m_suppressNextKeypressEvent; |
| 760 m_suppressNextKeypressEvent = false; |
| 761 |
| 762 LocalFrame* frame = toLocalFrame(focusedCoreFrame()); |
| 763 if (!frame) |
| 764 return suppress; |
| 765 |
| 766 EventHandler& handler = frame->eventHandler(); |
| 767 |
| 768 PlatformKeyboardEventBuilder evt(event); |
| 769 if (!evt.isCharacterKey()) |
| 770 return true; |
| 771 |
| 772 // Accesskeys are triggered by char events and can't be suppressed. |
| 773 if (handler.handleAccessKey(evt)) |
| 774 return true; |
| 775 |
| 776 // Safari 3.1 does not pass off windows system key messages (WM_SYSCHAR) to |
| 777 // the eventHandler::keyEvent. We mimic this behavior on all platforms since |
| 778 // for now we are converting other platform's key events to windows key |
| 779 // events. |
| 780 if (evt.isSystemKey()) |
| 781 return false; |
| 782 |
| 783 if (!suppress && !handler.keyEvent(evt)) |
| 784 return keyEventDefault(event); |
| 785 |
| 786 return true; |
| 787 } |
| 788 |
| 789 |
| 790 bool WebFrameWidgetImpl::keyEventDefault(const WebKeyboardEvent& event) |
| 791 { |
| 792 LocalFrame* frame = toLocalFrame(focusedCoreFrame()); |
| 793 if (!frame) |
| 794 return false; |
| 795 |
| 796 switch (event.type) { |
| 797 case WebInputEvent::Char: |
| 798 if (event.windowsKeyCode == VKEY_SPACE) { |
| 799 int keyCode = ((event.modifiers & WebInputEvent::ShiftKey) ? VKEY_PR
IOR : VKEY_NEXT); |
| 800 return scrollViewWithKeyboard(keyCode, event.modifiers); |
| 801 } |
| 802 break; |
| 803 case WebInputEvent::RawKeyDown: |
| 804 if (event.modifiers == WebInputEvent::ControlKey) { |
| 805 switch (event.windowsKeyCode) { |
| 806 #if !OS(MACOSX) |
| 807 case 'A': |
| 808 WebFrame::fromFrame(focusedCoreFrame())->executeCommand(WebStrin
g::fromUTF8("SelectAll")); |
| 809 return true; |
| 810 case VKEY_INSERT: |
| 811 case 'C': |
| 812 WebFrame::fromFrame(focusedCoreFrame())->executeCommand(WebStrin
g::fromUTF8("Copy")); |
| 813 return true; |
| 814 #endif |
| 815 // Match FF behavior in the sense that Ctrl+home/end are the only Ct
rl |
| 816 // key combinations which affect scrolling. Safari is buggy in the |
| 817 // sense that it scrolls the page for all Ctrl+scrolling key |
| 818 // combinations. For e.g. Ctrl+pgup/pgdn/up/down, etc. |
| 819 case VKEY_HOME: |
| 820 case VKEY_END: |
| 821 break; |
| 822 default: |
| 823 return false; |
| 824 } |
| 825 } |
| 826 if (!event.isSystemKey && !(event.modifiers & WebInputEvent::ShiftKey)) |
| 827 return scrollViewWithKeyboard(event.windowsKeyCode, event.modifiers)
; |
| 828 break; |
| 829 default: |
| 830 break; |
| 831 } |
| 832 return false; |
| 833 } |
| 834 |
| 835 bool WebFrameWidgetImpl::scrollViewWithKeyboard(int keyCode, int modifiers) |
| 836 { |
| 837 ScrollDirection scrollDirection; |
| 838 ScrollGranularity scrollGranularity; |
| 839 #if OS(MACOSX) |
| 840 // Control-Up/Down should be PageUp/Down on Mac. |
| 841 if (modifiers & WebMouseEvent::ControlKey) { |
| 842 if (keyCode == VKEY_UP) |
| 843 keyCode = VKEY_PRIOR; |
| 844 else if (keyCode == VKEY_DOWN) |
| 845 keyCode = VKEY_NEXT; |
| 846 } |
| 847 #endif |
| 848 if (!mapKeyCodeForScroll(keyCode, &scrollDirection, &scrollGranularity)) |
| 849 return false; |
| 850 |
| 851 if (LocalFrame* frame = toLocalFrame(focusedCoreFrame())) |
| 852 return frame->eventHandler().bubblingScroll(scrollDirection, scrollGranu
larity); |
| 853 return false; |
| 854 } |
| 855 |
| 856 bool WebFrameWidgetImpl::mapKeyCodeForScroll( |
| 857 int keyCode, |
| 858 ScrollDirection* scrollDirection, |
| 859 ScrollGranularity* scrollGranularity) |
| 860 { |
| 861 switch (keyCode) { |
| 862 case VKEY_LEFT: |
| 863 *scrollDirection = ScrollLeft; |
| 864 *scrollGranularity = ScrollByLine; |
| 865 break; |
| 866 case VKEY_RIGHT: |
| 867 *scrollDirection = ScrollRight; |
| 868 *scrollGranularity = ScrollByLine; |
| 869 break; |
| 870 case VKEY_UP: |
| 871 *scrollDirection = ScrollUp; |
| 872 *scrollGranularity = ScrollByLine; |
| 873 break; |
| 874 case VKEY_DOWN: |
| 875 *scrollDirection = ScrollDown; |
| 876 *scrollGranularity = ScrollByLine; |
| 877 break; |
| 878 case VKEY_HOME: |
| 879 *scrollDirection = ScrollUp; |
| 880 *scrollGranularity = ScrollByDocument; |
| 881 break; |
| 882 case VKEY_END: |
| 883 *scrollDirection = ScrollDown; |
| 884 *scrollGranularity = ScrollByDocument; |
| 885 break; |
| 886 case VKEY_PRIOR: // page up |
| 887 *scrollDirection = ScrollUp; |
| 888 *scrollGranularity = ScrollByPage; |
| 889 break; |
| 890 case VKEY_NEXT: // page down |
| 891 *scrollDirection = ScrollDown; |
| 892 *scrollGranularity = ScrollByPage; |
| 893 break; |
| 894 default: |
| 895 return false; |
| 896 } |
| 897 |
| 898 return true; |
| 899 } |
| 900 |
| 901 Frame* WebFrameWidgetImpl::focusedCoreFrame() const |
| 902 { |
| 903 return m_page ? m_page->focusController().focusedOrMainFrame() : nullptr; |
| 904 } |
| 905 |
| 906 Element* WebFrameWidgetImpl::focusedElement() const |
| 907 { |
| 908 Frame* frame = m_page->focusController().focusedFrame(); |
| 909 if (!frame || !frame->isLocalFrame()) |
| 910 return nullptr; |
| 911 |
| 912 Document* document = toLocalFrame(frame)->document(); |
| 913 if (!document) |
| 914 return nullptr; |
| 915 |
| 916 return document->focusedElement(); |
| 917 } |
| 918 |
| 919 void WebFrameWidgetImpl::initializeLayerTreeView() |
| 920 { |
| 921 if (m_client) { |
| 922 m_client->initializeLayerTreeView(); |
| 923 m_layerTreeView = m_client->layerTreeView(); |
| 924 } |
| 925 |
| 926 m_page->settings().setAcceleratedCompositingEnabled(m_layerTreeView); |
| 927 |
| 928 // FIXME: only unittests, click to play, Android priting, and printing (for
headers and footers) |
| 929 // make this assert necessary. We should make them not hit this code and the
n delete allowsBrokenNullLayerTreeView. |
| 930 ASSERT(m_layerTreeView || !m_client || m_client->allowsBrokenNullLayerTreeVi
ew()); |
| 931 } |
| 932 |
| 933 void WebFrameWidgetImpl::setIsAcceleratedCompositingActive(bool active) |
| 934 { |
| 935 // In the middle of shutting down; don't try to spin back up a compositor. |
| 936 // FIXME: compositing startup/shutdown should be refactored so that it |
| 937 // turns on explicitly rather than lazily, which causes this awkwardness. |
| 938 if (m_layerTreeViewClosed) |
| 939 return; |
| 940 |
| 941 ASSERT(!active || m_layerTreeView); |
| 942 |
| 943 if (m_isAcceleratedCompositingActive == active) |
| 944 return; |
| 945 |
| 946 if (!m_client) |
| 947 return; |
| 948 |
| 949 if (active) { |
| 950 TRACE_EVENT0("blink", "WebViewImpl::setIsAcceleratedCompositingActive(tr
ue)"); |
| 951 m_layerTreeView->setRootLayer(*m_rootLayer); |
| 952 |
| 953 bool visible = page()->visibilityState() == PageVisibilityStateVisible; |
| 954 m_layerTreeView->setVisible(visible); |
| 955 updateLayerTreeDeviceScaleFactor(); |
| 956 updateLayerTreeBackgroundColor(); |
| 957 m_layerTreeView->setHasTransparentBackground(isTransparent()); |
| 958 updateLayerTreeViewport(); |
| 959 m_isAcceleratedCompositingActive = true; |
| 960 } |
| 961 if (m_localRoot->frameView()) |
| 962 m_localRoot->frameView()->setClipsRepaints(!m_isAcceleratedCompositingAc
tive); |
| 963 } |
| 964 |
| 965 RenderLayerCompositor* WebFrameWidgetImpl::compositor() const |
| 966 { |
| 967 LocalFrame* frame = toLocalFrame(toCoreFrame(m_localRoot)); |
| 968 if (!frame || !frame->document() || !frame->document()->renderView()) |
| 969 return nullptr; |
| 970 |
| 971 return frame->document()->renderView()->compositor(); |
| 972 } |
| 973 |
| 974 void WebFrameWidgetImpl::suppressInvalidations(bool enable) |
| 975 { |
| 976 if (m_client) |
| 977 m_client->suppressCompositorScheduling(enable); |
| 978 } |
| 979 |
| 980 void WebFrameWidgetImpl::setRootGraphicsLayer(GraphicsLayer* layer) |
| 981 { |
| 982 suppressInvalidations(true); |
| 983 |
| 984 m_rootGraphicsLayer = layer; |
| 985 m_rootLayer = layer ? layer->platformLayer() : nullptr; |
| 986 |
| 987 setIsAcceleratedCompositingActive(layer); |
| 988 |
| 989 if (m_layerTreeView) { |
| 990 if (m_rootLayer) { |
| 991 m_layerTreeView->setRootLayer(*m_rootLayer); |
| 992 // We register viewport layers here since there may not be a layer |
| 993 // tree view prior to this point. |
| 994 GraphicsLayer* rootScrollLayer = compositor()->scrollLayer(); |
| 995 ASSERT(rootScrollLayer); |
| 996 WebLayer* pageScaleLayer = rootScrollLayer->parent() ? rootScrollLay
er->parent()->platformLayer() : nullptr; |
| 997 m_layerTreeView->registerViewportLayers(nullptr, pageScaleLayer, roo
tScrollLayer->platformLayer(), nullptr); |
| 998 } else { |
| 999 m_layerTreeView->clearRootLayer(); |
| 1000 m_layerTreeView->clearViewportLayers(); |
| 1001 } |
| 1002 } |
| 1003 |
| 1004 suppressInvalidations(false); |
| 1005 } |
| 1006 |
| 1007 } // namespace blink |
| OLD | NEW |