| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2011, 2012 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 "sky/engine/web/WebViewImpl.h" | |
| 32 | |
| 33 #include "gen/sky/core/CSSValueKeywords.h" | |
| 34 #include "gen/sky/core/HTMLNames.h" | |
| 35 #include "gen/sky/platform/RuntimeEnabledFeatures.h" | |
| 36 #include "sky/engine/core/dom/Document.h" | |
| 37 #include "sky/engine/core/dom/DocumentMarkerController.h" | |
| 38 #include "sky/engine/core/dom/NodeRenderingTraversal.h" | |
| 39 #include "sky/engine/core/dom/Text.h" | |
| 40 #include "sky/engine/core/editing/Editor.h" | |
| 41 #include "sky/engine/core/editing/FrameSelection.h" | |
| 42 #include "sky/engine/core/editing/HTMLInterchange.h" | |
| 43 #include "sky/engine/core/editing/InputMethodController.h" | |
| 44 #include "sky/engine/core/editing/TextIterator.h" | |
| 45 #include "sky/engine/core/events/KeyboardEvent.h" | |
| 46 #include "sky/engine/core/frame/FrameHost.h" | |
| 47 #include "sky/engine/core/frame/FrameView.h" | |
| 48 #include "sky/engine/core/frame/LocalFrame.h" | |
| 49 #include "sky/engine/core/frame/NewEventHandler.h" | |
| 50 #include "sky/engine/core/frame/Settings.h" | |
| 51 #include "sky/engine/core/html/HTMLImportElement.h" | |
| 52 #include "sky/engine/core/loader/FrameLoader.h" | |
| 53 #include "sky/engine/core/loader/UniqueIdentifier.h" | |
| 54 #include "sky/engine/core/page/EventHandler.h" | |
| 55 #include "sky/engine/core/page/FocusController.h" | |
| 56 #include "sky/engine/core/page/Page.h" | |
| 57 #include "sky/engine/core/rendering/RenderView.h" | |
| 58 #include "sky/engine/platform/KeyboardCodes.h" | |
| 59 #include "sky/engine/platform/Logging.h" | |
| 60 #include "sky/engine/platform/NotImplemented.h" | |
| 61 #include "sky/engine/platform/TraceEvent.h" | |
| 62 #include "sky/engine/platform/fonts/FontCache.h" | |
| 63 #include "sky/engine/platform/graphics/Color.h" | |
| 64 #include "sky/engine/platform/graphics/GraphicsContext.h" | |
| 65 #include "sky/engine/platform/graphics/Image.h" | |
| 66 #include "sky/engine/platform/graphics/ImageBuffer.h" | |
| 67 #include "sky/engine/public/platform/Platform.h" | |
| 68 #include "sky/engine/public/platform/WebFloatPoint.h" | |
| 69 #include "sky/engine/public/platform/WebImage.h" | |
| 70 #include "sky/engine/public/platform/WebLayerTreeView.h" | |
| 71 #include "sky/engine/public/platform/WebURLRequest.h" | |
| 72 #include "sky/engine/public/platform/WebVector.h" | |
| 73 #include "sky/engine/public/web/WebBeginFrameArgs.h" | |
| 74 #include "sky/engine/public/web/WebFrameClient.h" | |
| 75 #include "sky/engine/public/web/WebNode.h" | |
| 76 #include "sky/engine/public/web/WebRange.h" | |
| 77 #include "sky/engine/public/web/WebTextInputInfo.h" | |
| 78 #include "sky/engine/public/web/WebViewClient.h" | |
| 79 #include "sky/engine/web/CompositionUnderlineVectorBuilder.h" | |
| 80 #include "sky/engine/web/WebLocalFrameImpl.h" | |
| 81 #include "sky/engine/web/WebSettingsImpl.h" | |
| 82 #include "sky/engine/wtf/CurrentTime.h" | |
| 83 #include "sky/engine/wtf/RefPtr.h" | |
| 84 #include "sky/engine/wtf/TemporaryChange.h" | |
| 85 #include "url/gurl.h" | |
| 86 | |
| 87 // Get rid of WTF's pow define so we can use std::pow. | |
| 88 #undef pow | |
| 89 #include <cmath> // for std::pow | |
| 90 | |
| 91 namespace blink { | |
| 92 | |
| 93 // WebView ---------------------------------------------------------------- | |
| 94 | |
| 95 WebView* WebView::create(WebViewClient* client) | |
| 96 { | |
| 97 CRASH(); // WebView is deprecated. Please use SkyView. | |
| 98 // Pass the WebViewImpl's self-reference to the caller. | |
| 99 return WebViewImpl::create(client); | |
| 100 } | |
| 101 | |
| 102 WebViewImpl* WebViewImpl::create(WebViewClient* client) | |
| 103 { | |
| 104 // Pass the WebViewImpl's self-reference to the caller. | |
| 105 return adoptRef(new WebViewImpl(client)).leakRef(); | |
| 106 } | |
| 107 | |
| 108 void WebViewImpl::setMainFrame(WebFrame* frame) | |
| 109 { | |
| 110 toWebLocalFrameImpl(frame)->initializeCoreFrame(&page()->frameHost()); | |
| 111 } | |
| 112 | |
| 113 void WebViewImpl::setSpellCheckClient(WebSpellCheckClient* spellCheckClient) | |
| 114 { | |
| 115 m_spellCheckClient = spellCheckClient; | |
| 116 } | |
| 117 | |
| 118 WebViewImpl::WebViewImpl(WebViewClient* client) | |
| 119 : m_client(client) | |
| 120 , m_spellCheckClient(0) | |
| 121 , m_chromeClientImpl(this) | |
| 122 , m_editorClientImpl(this) | |
| 123 , m_spellCheckerClientImpl(this) | |
| 124 , m_fixedLayoutSizeLock(false) | |
| 125 , m_rootLayerScale(1) | |
| 126 , m_suppressNextKeypressEvent(false) | |
| 127 , m_imeAcceptEvents(true) | |
| 128 , m_isTransparent(false) | |
| 129 , m_rootLayer(0) | |
| 130 , m_matchesHeuristicsForGpuRasterization(false) | |
| 131 , m_recreatingGraphicsContext(false) | |
| 132 , m_flingModifier(0) | |
| 133 , m_flingSourceDevice(false) | |
| 134 , m_showPaintRects(false) | |
| 135 , m_showDebugBorders(false) | |
| 136 , m_baseBackgroundColor(Color::white) | |
| 137 , m_backgroundColorOverride(Color::transparent) | |
| 138 { | |
| 139 Page::PageClients pageClients; | |
| 140 pageClients.chromeClient = &m_chromeClientImpl; | |
| 141 pageClients.editorClient = &m_editorClientImpl; | |
| 142 pageClients.spellCheckerClient = &m_spellCheckerClientImpl; | |
| 143 | |
| 144 m_page = adoptPtr(new Page(pageClients, m_client->services())); | |
| 145 | |
| 146 setDeviceScaleFactor(m_client->screenInfo().deviceScaleFactor); | |
| 147 setVisibilityState(m_client->visibilityState(), true); | |
| 148 | |
| 149 m_client->initializeLayerTreeView(); | |
| 150 } | |
| 151 | |
| 152 WebViewImpl::~WebViewImpl() | |
| 153 { | |
| 154 ASSERT(!m_page); | |
| 155 } | |
| 156 | |
| 157 WebLocalFrameImpl* WebViewImpl::mainFrameImpl() | |
| 158 { | |
| 159 return m_page ? WebLocalFrameImpl::fromFrame(m_page->mainFrame()) : 0; | |
| 160 } | |
| 161 | |
| 162 void WebViewImpl::setShowPaintRects(bool show) | |
| 163 { | |
| 164 m_showPaintRects = show; | |
| 165 } | |
| 166 | |
| 167 void WebViewImpl::setShowDebugBorders(bool show) | |
| 168 { | |
| 169 m_showDebugBorders = show; | |
| 170 } | |
| 171 | |
| 172 void WebViewImpl::acceptLanguagesChanged() | |
| 173 { | |
| 174 if (!page()) | |
| 175 return; | |
| 176 | |
| 177 page()->acceptLanguagesChanged(); | |
| 178 } | |
| 179 | |
| 180 LocalFrame* WebViewImpl::focusedCoreFrame() const | |
| 181 { | |
| 182 return m_page ? m_page->focusController().focusedOrMainFrame() : 0; | |
| 183 } | |
| 184 | |
| 185 WebViewImpl* WebViewImpl::fromPage(Page* page) | |
| 186 { | |
| 187 if (!page) | |
| 188 return 0; | |
| 189 return static_cast<WebViewImpl*>(page->webView()); | |
| 190 } | |
| 191 | |
| 192 // WebWidget ------------------------------------------------------------------ | |
| 193 | |
| 194 void WebViewImpl::close() | |
| 195 { | |
| 196 if (m_page) { | |
| 197 // Initiate shutdown for the entire frameset. This will cause a lot of | |
| 198 // notifications to be sent. | |
| 199 m_page->willBeDestroyed(); | |
| 200 m_page.clear(); | |
| 201 } | |
| 202 | |
| 203 // Reset the delegate to prevent notifications being sent as we're being | |
| 204 // deleted. | |
| 205 m_client = 0; | |
| 206 | |
| 207 deref(); // Balances ref() acquired in WebView::create | |
| 208 } | |
| 209 | |
| 210 WebSize WebViewImpl::size() | |
| 211 { | |
| 212 return m_size; | |
| 213 } | |
| 214 | |
| 215 void WebViewImpl::performResize() | |
| 216 { | |
| 217 updateMainFrameLayoutSize(); | |
| 218 | |
| 219 // If the virtual viewport pinch mode is enabled, the main frame will be res
ized | |
| 220 // after layout so it can be sized to the contentsSize. | |
| 221 if (FrameView* view = m_page->mainFrame()->view()) | |
| 222 view->resize(m_size); | |
| 223 } | |
| 224 | |
| 225 void WebViewImpl::resize(const WebSize& newSize) | |
| 226 { | |
| 227 if (m_size == newSize) | |
| 228 return; | |
| 229 | |
| 230 FrameView* view = m_page->mainFrame()->view(); | |
| 231 if (!view) | |
| 232 return; | |
| 233 | |
| 234 m_size = newSize; | |
| 235 performResize(); | |
| 236 sendResizeEventAndRepaint(); | |
| 237 } | |
| 238 | |
| 239 void WebViewImpl::beginFrame(const WebBeginFrameArgs& frameTime) | |
| 240 { | |
| 241 TRACE_EVENT0("blink", "WebViewImpl::beginFrame"); | |
| 242 | |
| 243 WebBeginFrameArgs validFrameTime(frameTime); | |
| 244 if (!validFrameTime.lastFrameTimeMonotonic) | |
| 245 validFrameTime.lastFrameTimeMonotonic = monotonicallyIncreasingTime(); | |
| 246 | |
| 247 WTF_LOG(ScriptedAnimationController, "WebViewImpl::beginFrame: page = %d", !
m_page ? 0 : 1); | |
| 248 if (!m_page) | |
| 249 return; | |
| 250 | |
| 251 RefPtr<FrameView> view = m_page->mainFrame()->view(); | |
| 252 if (!view) | |
| 253 return; | |
| 254 m_page->animator().serviceScriptedAnimations(validFrameTime.lastFrameTimeMon
otonic); | |
| 255 } | |
| 256 | |
| 257 void WebViewImpl::layout() | |
| 258 { | |
| 259 TRACE_EVENT0("blink", "WebViewImpl::layout"); | |
| 260 if (!m_page) | |
| 261 return; | |
| 262 m_page->animator().updateLayoutAndStyleForPainting(m_page->mainFrame()); | |
| 263 } | |
| 264 | |
| 265 void WebViewImpl::paint(WebCanvas* canvas, const WebRect& rect) | |
| 266 { | |
| 267 if (rect.isEmpty()) | |
| 268 return; | |
| 269 GraphicsContext gc(canvas); | |
| 270 gc.setCertainlyOpaque(!isTransparent()); | |
| 271 gc.applyDeviceScaleFactor(m_page->deviceScaleFactor()); | |
| 272 gc.setDeviceScaleFactor(m_page->deviceScaleFactor()); | |
| 273 IntRect dirtyRect(rect); | |
| 274 gc.save(); // Needed to save the canvas, not the GraphicsContext. | |
| 275 FrameView* view = m_page->mainFrame()->view(); | |
| 276 if (view) { | |
| 277 gc.clip(dirtyRect); | |
| 278 view->paint(&gc, dirtyRect); | |
| 279 } else { | |
| 280 gc.fillRect(dirtyRect, Color::white); | |
| 281 } | |
| 282 gc.restore(); | |
| 283 } | |
| 284 | |
| 285 // FIXME: autogenerate this kind of code, and use it throughout Blink rather tha
n | |
| 286 // the one-offs for subsets of these values. | |
| 287 static String inputTypeToName(WebInputEvent::Type type) | |
| 288 { | |
| 289 switch (type) { | |
| 290 case WebInputEvent::KeyDown: | |
| 291 return EventTypeNames::keydown; | |
| 292 case WebInputEvent::KeyUp: | |
| 293 return EventTypeNames::keyup; | |
| 294 case WebInputEvent::GestureScrollBegin: | |
| 295 return EventTypeNames::gesturescrollstart; | |
| 296 case WebInputEvent::GestureScrollEnd: | |
| 297 return EventTypeNames::gesturescrollend; | |
| 298 case WebInputEvent::GestureScrollUpdate: | |
| 299 return EventTypeNames::gesturescrollupdate; | |
| 300 case WebInputEvent::GestureTapDown: | |
| 301 return EventTypeNames::gesturetapdown; | |
| 302 case WebInputEvent::GestureShowPress: | |
| 303 return EventTypeNames::gestureshowpress; | |
| 304 case WebInputEvent::GestureTap: | |
| 305 return EventTypeNames::gesturetap; | |
| 306 case WebInputEvent::GestureTapUnconfirmed: | |
| 307 return EventTypeNames::gesturetapunconfirmed; | |
| 308 default: | |
| 309 return String("unknown"); | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 bool WebViewImpl::handleInputEvent(const WebInputEvent& inputEvent) | |
| 314 { | |
| 315 TRACE_EVENT1("input", "WebViewImpl::handleInputEvent", "type", | |
| 316 TRACE_STR_COPY(inputTypeToName(inputEvent.type).ascii().data())
); | |
| 317 | |
| 318 if (WebInputEvent::isPointerEventType(inputEvent.type)) { | |
| 319 const WebPointerEvent& event = static_cast<const WebPointerEvent&>(input
Event); | |
| 320 return m_page->mainFrame()->newEventHandler().handlePointerEvent(event); | |
| 321 } | |
| 322 | |
| 323 if (WebInputEvent::isGestureEventType(inputEvent.type)) { | |
| 324 const WebGestureEvent& event = static_cast<const WebGestureEvent&>(input
Event); | |
| 325 return m_page->mainFrame()->newEventHandler().handleGestureEvent(event); | |
| 326 } | |
| 327 | |
| 328 if (WebInputEvent::isKeyboardEventType(inputEvent.type)) { | |
| 329 const WebKeyboardEvent& event = static_cast<const WebKeyboardEvent&>(inp
utEvent); | |
| 330 return m_page->mainFrame()->newEventHandler().handleKeyboardEvent(event)
; | |
| 331 } | |
| 332 | |
| 333 if (WebInputEvent::isWheelEventType(inputEvent.type)) { | |
| 334 const WebWheelEvent& event = static_cast<const WebWheelEvent&>(inputEven
t); | |
| 335 return m_page->mainFrame()->newEventHandler().handleWheelEvent(event); | |
| 336 } | |
| 337 | |
| 338 return false; | |
| 339 } | |
| 340 | |
| 341 void WebViewImpl::setFocus(bool enable) | |
| 342 { | |
| 343 m_page->focusController().setFocused(enable); | |
| 344 if (enable) { | |
| 345 m_page->focusController().setActive(true); | |
| 346 RefPtr<LocalFrame> focusedFrame = m_page->focusController().focusedFrame
(); | |
| 347 if (focusedFrame) { | |
| 348 LocalFrame* localFrame = focusedFrame.get(); | |
| 349 Element* element = localFrame->document()->focusedElement(); | |
| 350 if (element && localFrame->selection().selection().isNone()) { | |
| 351 // If the selection was cleared while the WebView was not | |
| 352 // focused, then the focus element shows with a focus ring but | |
| 353 // no caret and does respond to keyboard inputs. | |
| 354 if (element->isContentEditable()) { | |
| 355 // updateFocusAppearance() selects all the text of | |
| 356 // contentseditable DIVs. So we set the selection explicitly | |
| 357 // instead. Note that this has the side effect of moving the | |
| 358 // caret back to the beginning of the text. | |
| 359 Position position(element, 0, Position::PositionIsOffsetInAn
chor); | |
| 360 localFrame->selection().setSelection(VisibleSelection(positi
on, SEL_DEFAULT_AFFINITY)); | |
| 361 } | |
| 362 } | |
| 363 } | |
| 364 m_imeAcceptEvents = true; | |
| 365 } else { | |
| 366 // Clear focus on the currently focused frame if any. | |
| 367 if (!m_page) | |
| 368 return; | |
| 369 | |
| 370 RefPtr<LocalFrame> focusedFrame = m_page->focusController().focusedFrame
(); | |
| 371 if (focusedFrame) { | |
| 372 // Finish an ongoing composition to delete the composition node. | |
| 373 if (focusedFrame->inputMethodController().hasComposition()) { | |
| 374 focusedFrame->inputMethodController().confirmComposition(); | |
| 375 } | |
| 376 m_imeAcceptEvents = false; | |
| 377 } | |
| 378 } | |
| 379 } | |
| 380 | |
| 381 bool WebViewImpl::setComposition( | |
| 382 const WebString& text, | |
| 383 const WebVector<WebCompositionUnderline>& underlines, | |
| 384 int selectionStart, | |
| 385 int selectionEnd) | |
| 386 { | |
| 387 LocalFrame* focused = focusedCoreFrame(); | |
| 388 if (!focused || !m_imeAcceptEvents) | |
| 389 return false; | |
| 390 | |
| 391 // The input focus has been moved to another WebWidget object. | |
| 392 // We should use this |editor| object only to complete the ongoing | |
| 393 // composition. | |
| 394 InputMethodController& inputMethodController = focused->inputMethodControlle
r(); | |
| 395 if (!focused->editor().canEdit() && !inputMethodController.hasComposition()) | |
| 396 return false; | |
| 397 | |
| 398 // We should verify the parent node of this IME composition node are | |
| 399 // editable because JavaScript may delete a parent node of the composition | |
| 400 // node. In this case, WebKit crashes while deleting texts from the parent | |
| 401 // node, which doesn't exist any longer. | |
| 402 RefPtr<Range> range = inputMethodController.compositionRange(); | |
| 403 if (range) { | |
| 404 Node* node = range->startContainer(); | |
| 405 if (!node || !node->isContentEditable()) | |
| 406 return false; | |
| 407 } | |
| 408 | |
| 409 // If we're not going to fire a keypress event, then the keydown event was | |
| 410 // canceled. In that case, cancel any existing composition. | |
| 411 if (text.isEmpty() || m_suppressNextKeypressEvent) { | |
| 412 // A browser process sent an IPC message which does not contain a valid | |
| 413 // string, which means an ongoing composition has been canceled. | |
| 414 // If the ongoing composition has been canceled, replace the ongoing | |
| 415 // composition string with an empty string and complete it. | |
| 416 String emptyString; | |
| 417 Vector<CompositionUnderline> emptyUnderlines; | |
| 418 inputMethodController.setComposition(emptyString, emptyUnderlines, 0, 0)
; | |
| 419 return text.isEmpty(); | |
| 420 } | |
| 421 | |
| 422 // When the range of composition underlines overlap with the range between | |
| 423 // selectionStart and selectionEnd, WebKit somehow won't paint the selection | |
| 424 // at all (see InlineTextBox::paint() function in InlineTextBox.cpp). | |
| 425 // But the selection range actually takes effect. | |
| 426 inputMethodController.setComposition(String(text), | |
| 427 CompositionUnderlineVectorBuilder(underlines), | |
| 428 selectionStart, selectionEnd); | |
| 429 | |
| 430 return inputMethodController.hasComposition(); | |
| 431 } | |
| 432 | |
| 433 bool WebViewImpl::confirmComposition() | |
| 434 { | |
| 435 return confirmComposition(DoNotKeepSelection); | |
| 436 } | |
| 437 | |
| 438 bool WebViewImpl::confirmComposition(ConfirmCompositionBehavior selectionBehavio
r) | |
| 439 { | |
| 440 return confirmComposition(WebString(), selectionBehavior); | |
| 441 } | |
| 442 | |
| 443 bool WebViewImpl::confirmComposition(const WebString& text) | |
| 444 { | |
| 445 return confirmComposition(text, DoNotKeepSelection); | |
| 446 } | |
| 447 | |
| 448 bool WebViewImpl::confirmComposition(const WebString& text, ConfirmCompositionBe
havior selectionBehavior) | |
| 449 { | |
| 450 LocalFrame* focused = focusedCoreFrame(); | |
| 451 if (!focused || !m_imeAcceptEvents) | |
| 452 return false; | |
| 453 | |
| 454 return focused->inputMethodController().confirmCompositionOrInsertText(text,
selectionBehavior == KeepSelection ? InputMethodController::KeepSelection : Inp
utMethodController::DoNotKeepSelection); | |
| 455 } | |
| 456 | |
| 457 WebTextInputInfo WebViewImpl::textInputInfo() | |
| 458 { | |
| 459 WebTextInputInfo info; | |
| 460 | |
| 461 LocalFrame* focused = focusedCoreFrame(); | |
| 462 if (!focused) | |
| 463 return info; | |
| 464 | |
| 465 FrameSelection& selection = focused->selection(); | |
| 466 Element* element = selection.selection().rootEditableElement(); | |
| 467 if (!element) | |
| 468 return info; | |
| 469 | |
| 470 info.inputMode = inputModeOfFocusedElement(); | |
| 471 | |
| 472 info.type = textInputType(); | |
| 473 info.flags = textInputFlags(); | |
| 474 if (info.type == WebTextInputTypeNone) | |
| 475 return info; | |
| 476 | |
| 477 if (!focused->editor().canEdit()) | |
| 478 return info; | |
| 479 | |
| 480 // Emits an object replacement character for each replaced element so that | |
| 481 // it is exposed to IME and thus could be deleted by IME on android. | |
| 482 info.value = plainText(rangeOfContents(element).get(), TextIteratorEmitsObje
ctReplacementCharacter); | |
| 483 | |
| 484 if (info.value.isEmpty()) | |
| 485 return info; | |
| 486 | |
| 487 if (RefPtr<Range> range = selection.selection().firstRange()) { | |
| 488 PlainTextRange plainTextRange(PlainTextRange::create(*element, *range.ge
t())); | |
| 489 if (plainTextRange.isNotNull()) { | |
| 490 info.selectionStart = plainTextRange.start(); | |
| 491 info.selectionEnd = plainTextRange.end(); | |
| 492 } | |
| 493 } | |
| 494 | |
| 495 if (RefPtr<Range> range = focused->inputMethodController().compositionRange(
)) { | |
| 496 PlainTextRange plainTextRange(PlainTextRange::create(*element, *range.ge
t())); | |
| 497 if (plainTextRange.isNotNull()) { | |
| 498 info.compositionStart = plainTextRange.start(); | |
| 499 info.compositionEnd = plainTextRange.end(); | |
| 500 } | |
| 501 } | |
| 502 | |
| 503 return info; | |
| 504 } | |
| 505 | |
| 506 WebTextInputType WebViewImpl::textInputType() | |
| 507 { | |
| 508 Element* element = focusedElement(); | |
| 509 if (!element) | |
| 510 return WebTextInputTypeNone; | |
| 511 | |
| 512 if (element->isContentEditable(Node::UserSelectAllIsAlwaysNonEditable)) | |
| 513 return WebTextInputTypeContentEditable; | |
| 514 | |
| 515 return WebTextInputTypeNone; | |
| 516 } | |
| 517 | |
| 518 int WebViewImpl::textInputFlags() | |
| 519 { | |
| 520 Element* element = focusedElement(); | |
| 521 if (!element) | |
| 522 return WebTextInputFlagNone; | |
| 523 | |
| 524 int flags = 0; | |
| 525 | |
| 526 const AtomicString& autocomplete = element->getAttribute("autocomplete"); | |
| 527 if (autocomplete == "on") | |
| 528 flags |= WebTextInputFlagAutocompleteOn; | |
| 529 else if (autocomplete == "off") | |
| 530 flags |= WebTextInputFlagAutocompleteOff; | |
| 531 | |
| 532 const AtomicString& autocorrect = element->getAttribute("autocorrect"); | |
| 533 if (autocorrect == "on") | |
| 534 flags |= WebTextInputFlagAutocorrectOn; | |
| 535 else if (autocorrect == "off") | |
| 536 flags |= WebTextInputFlagAutocorrectOff; | |
| 537 | |
| 538 const AtomicString& spellcheck = element->getAttribute("spellcheck"); | |
| 539 if (spellcheck == "on") | |
| 540 flags |= WebTextInputFlagSpellcheckOn; | |
| 541 else if (spellcheck == "off") | |
| 542 flags |= WebTextInputFlagSpellcheckOff; | |
| 543 | |
| 544 return flags; | |
| 545 } | |
| 546 | |
| 547 WebString WebViewImpl::inputModeOfFocusedElement() | |
| 548 { | |
| 549 return WebString(); | |
| 550 } | |
| 551 | |
| 552 WebVector<WebCompositionUnderline> WebViewImpl::compositionUnderlines() const | |
| 553 { | |
| 554 const LocalFrame* focused = focusedCoreFrame(); | |
| 555 if (!focused) | |
| 556 return WebVector<WebCompositionUnderline>(); | |
| 557 const Vector<CompositionUnderline>& underlines = focused->inputMethodControl
ler().customCompositionUnderlines(); | |
| 558 WebVector<WebCompositionUnderline> results(underlines.size()); | |
| 559 for (size_t index = 0; index < underlines.size(); ++index) { | |
| 560 CompositionUnderline underline = underlines[index]; | |
| 561 results[index] = WebCompositionUnderline(underline.startOffset, underlin
e.endOffset, static_cast<WebColor>(underline.color.rgb()), underline.thick, stat
ic_cast<WebColor>(underline.backgroundColor.rgb())); | |
| 562 } | |
| 563 return results; | |
| 564 } | |
| 565 | |
| 566 // WebView -------------------------------------------------------------------- | |
| 567 | |
| 568 WebSettingsImpl* WebViewImpl::settingsImpl() | |
| 569 { | |
| 570 if (!m_webSettings) | |
| 571 m_webSettings = adoptPtr(new WebSettingsImpl(&m_page->settings())); | |
| 572 ASSERT(m_webSettings); | |
| 573 return m_webSettings.get(); | |
| 574 } | |
| 575 | |
| 576 WebSettings* WebViewImpl::settings() | |
| 577 { | |
| 578 return settingsImpl(); | |
| 579 } | |
| 580 | |
| 581 WebFrame* WebViewImpl::mainFrame() | |
| 582 { | |
| 583 return WebFrame::fromFrame(m_page ? m_page->mainFrame() : 0); | |
| 584 } | |
| 585 | |
| 586 WebFrame* WebViewImpl::focusedFrame() | |
| 587 { | |
| 588 return WebFrame::fromFrame(focusedCoreFrame()); | |
| 589 } | |
| 590 | |
| 591 void WebViewImpl::injectModule(const WebString& path) | |
| 592 { | |
| 593 RefPtr<Document> document = m_page->mainFrame()->document(); | |
| 594 RefPtr<HTMLImportElement> import = HTMLImportElement::create(*document); | |
| 595 import->setAttribute(HTMLNames::srcAttr, path); | |
| 596 document->appendChild(import.release()); | |
| 597 } | |
| 598 | |
| 599 void WebViewImpl::setFocusedFrame(WebFrame* frame) | |
| 600 { | |
| 601 if (!frame) { | |
| 602 // Clears the focused frame if any. | |
| 603 LocalFrame* focusedFrame = focusedCoreFrame(); | |
| 604 if (focusedFrame) | |
| 605 focusedFrame->selection().setFocused(false); | |
| 606 return; | |
| 607 } | |
| 608 LocalFrame* coreFrame = toWebLocalFrameImpl(frame)->frame(); | |
| 609 coreFrame->page()->focusController().setFocusedFrame(coreFrame); | |
| 610 } | |
| 611 | |
| 612 void WebViewImpl::setInitialFocus(bool reverse) | |
| 613 { | |
| 614 if (!m_page) | |
| 615 return; | |
| 616 LocalFrame* frame = page()->focusController().focusedOrMainFrame(); | |
| 617 if (Document* document = frame->document()) | |
| 618 document->setFocusedElement(nullptr); | |
| 619 page()->focusController().setInitialFocus(reverse ? FocusTypeBackward : Focu
sTypeForward); | |
| 620 } | |
| 621 | |
| 622 void WebViewImpl::clearFocusedElement() | |
| 623 { | |
| 624 RefPtr<LocalFrame> localFrame = focusedCoreFrame(); | |
| 625 if (!localFrame) | |
| 626 return; | |
| 627 | |
| 628 RefPtr<Document> document = localFrame->document(); | |
| 629 if (!document) | |
| 630 return; | |
| 631 | |
| 632 RefPtr<Element> oldFocusedElement = document->focusedElement(); | |
| 633 | |
| 634 // Clear the focused node. | |
| 635 document->setFocusedElement(nullptr); | |
| 636 | |
| 637 if (!oldFocusedElement) | |
| 638 return; | |
| 639 | |
| 640 // If a text field has focus, we need to make sure the selection controller | |
| 641 // knows to remove selection from it. Otherwise, the text field is still | |
| 642 // processing keyboard events even though focus has been moved to the page a
nd | |
| 643 // keystrokes get eaten as a result. | |
| 644 if (oldFocusedElement->isContentEditable()) | |
| 645 localFrame->selection().clear(); | |
| 646 } | |
| 647 | |
| 648 void WebViewImpl::advanceFocus(bool reverse) | |
| 649 { | |
| 650 page()->focusController().advanceFocus(reverse ? FocusTypeBackward : FocusTy
peForward); | |
| 651 } | |
| 652 | |
| 653 IntPoint WebViewImpl::clampOffsetAtScale(const IntPoint& offset, float scale) | |
| 654 { | |
| 655 FrameView* view = mainFrameImpl()->frameView(); | |
| 656 if (!view) | |
| 657 return offset; | |
| 658 | |
| 659 return view->clampOffsetAtScale(offset, scale); | |
| 660 } | |
| 661 | |
| 662 float WebViewImpl::deviceScaleFactor() const | |
| 663 { | |
| 664 if (!page()) | |
| 665 return 1; | |
| 666 | |
| 667 return page()->deviceScaleFactor(); | |
| 668 } | |
| 669 | |
| 670 void WebViewImpl::setDeviceScaleFactor(float scaleFactor) | |
| 671 { | |
| 672 if (!page()) | |
| 673 return; | |
| 674 | |
| 675 page()->setDeviceScaleFactor(scaleFactor); | |
| 676 } | |
| 677 | |
| 678 void WebViewImpl::updateMainFrameLayoutSize() | |
| 679 { | |
| 680 if (m_fixedLayoutSizeLock || !mainFrameImpl()) | |
| 681 return; | |
| 682 | |
| 683 RefPtr<FrameView> view = mainFrameImpl()->frameView(); | |
| 684 if (!view) | |
| 685 return; | |
| 686 | |
| 687 WebSize layoutSize = m_size; | |
| 688 | |
| 689 if (page()->settings().forceZeroLayoutHeight()) | |
| 690 layoutSize.height = 0; | |
| 691 | |
| 692 view->setLayoutSize(layoutSize); | |
| 693 } | |
| 694 | |
| 695 IntSize WebViewImpl::contentsSize() const | |
| 696 { | |
| 697 RenderView* root = page()->mainFrame()->contentRenderer(); | |
| 698 if (!root) | |
| 699 return IntSize(); | |
| 700 return root->documentRect().size(); | |
| 701 } | |
| 702 | |
| 703 void WebViewImpl::spellingMarkers(WebVector<uint32_t>* markers) | |
| 704 { | |
| 705 Vector<uint32_t> result; | |
| 706 LocalFrame* frame = m_page->mainFrame(); | |
| 707 const DocumentMarkerVector& documentMarkers = frame->document()->markers().m
arkers(); | |
| 708 for (size_t i = 0; i < documentMarkers.size(); ++i) | |
| 709 result.append(documentMarkers[i]->hash()); | |
| 710 markers->assign(result); | |
| 711 } | |
| 712 | |
| 713 void WebViewImpl::removeSpellingMarkersUnderWords(const WebVector<WebString>& wo
rds) | |
| 714 { | |
| 715 Vector<String> convertedWords; | |
| 716 convertedWords.append(words.data(), words.size()); | |
| 717 | |
| 718 LocalFrame* frame = m_page->mainFrame(); | |
| 719 frame->removeSpellingMarkersUnderWords(convertedWords); | |
| 720 } | |
| 721 | |
| 722 void WebViewImpl::sendResizeEventAndRepaint() | |
| 723 { | |
| 724 // FIXME: This is wrong. The FrameView is responsible sending a resizeEvent | |
| 725 // as part of layout. Layout is also responsible for sending invalidations | |
| 726 // to the embedder. This method and all callers may be wrong. -- eseidel. | |
| 727 if (m_page->mainFrame()->view()) { | |
| 728 // Enqueues the resize event. | |
| 729 m_page->mainFrame()->document()->enqueueResizeEvent(); | |
| 730 } | |
| 731 } | |
| 732 | |
| 733 void WebViewImpl::setIsTransparent(bool isTransparent) | |
| 734 { | |
| 735 // Set any existing frames to be transparent. | |
| 736 m_page->mainFrame()->view()->setTransparent(isTransparent); | |
| 737 | |
| 738 // Future frames check this to know whether to be transparent. | |
| 739 m_isTransparent = isTransparent; | |
| 740 } | |
| 741 | |
| 742 bool WebViewImpl::isTransparent() const | |
| 743 { | |
| 744 return m_isTransparent; | |
| 745 } | |
| 746 | |
| 747 // FIXME(sky): This is an android webview feature. Remove it. | |
| 748 void WebViewImpl::setBaseBackgroundColor(WebColor color) | |
| 749 { | |
| 750 layout(); | |
| 751 | |
| 752 if (m_baseBackgroundColor == color) | |
| 753 return; | |
| 754 | |
| 755 m_baseBackgroundColor = color; | |
| 756 | |
| 757 if (m_page->mainFrame()) | |
| 758 m_page->mainFrame()->view()->setBaseBackgroundColor(color); | |
| 759 } | |
| 760 | |
| 761 void WebViewImpl::setIsActive(bool active) | |
| 762 { | |
| 763 if (page()) | |
| 764 page()->focusController().setActive(active); | |
| 765 } | |
| 766 | |
| 767 bool WebViewImpl::isActive() const | |
| 768 { | |
| 769 return page() ? page()->focusController().isActive() : false; | |
| 770 } | |
| 771 | |
| 772 void WebViewImpl::didCommitLoad(bool isNewNavigation, bool isNavigationWithinPag
e) | |
| 773 { | |
| 774 } | |
| 775 | |
| 776 void WebViewImpl::setBackgroundColorOverride(WebColor color) | |
| 777 { | |
| 778 m_backgroundColorOverride = color; | |
| 779 } | |
| 780 | |
| 781 Element* WebViewImpl::focusedElement() const | |
| 782 { | |
| 783 LocalFrame* frame = m_page->focusController().focusedFrame(); | |
| 784 if (!frame) | |
| 785 return 0; | |
| 786 | |
| 787 Document* document = frame->document(); | |
| 788 if (!document) | |
| 789 return 0; | |
| 790 | |
| 791 return document->focusedElement(); | |
| 792 } | |
| 793 | |
| 794 HitTestResult WebViewImpl::hitTestResultForWindowPos(const IntPoint& pos) | |
| 795 { | |
| 796 IntPoint docPoint(m_page->mainFrame()->view()->windowToContents(pos)); | |
| 797 HitTestResult result = m_page->mainFrame()->eventHandler().hitTestResultAtPo
int(docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active); | |
| 798 return result; | |
| 799 } | |
| 800 | |
| 801 void WebViewImpl::scheduleVisualUpdate() | |
| 802 { | |
| 803 m_client->scheduleVisualUpdate(); | |
| 804 } | |
| 805 | |
| 806 void WebViewImpl::setVisibilityState(WebPageVisibilityState visibilityState, | |
| 807 bool isInitialState) { | |
| 808 if (!page()) | |
| 809 return; | |
| 810 | |
| 811 ASSERT(visibilityState == WebPageVisibilityStateVisible || visibilityState =
= WebPageVisibilityStateHidden); | |
| 812 m_page->setVisibilityState(static_cast<PageVisibilityState>(static_cast<int>
(visibilityState)), isInitialState); | |
| 813 } | |
| 814 | |
| 815 } // namespace blink | |
| OLD | NEW |