1 /* 2 * Copyright (C) 2009 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 // How ownership works 32 // ------------------- 33 // 34 // Big oh represents a refcounted relationship: owner O--- ownee 35 // 36 // WebView (for the toplevel frame only) 37 // O 38 // | 39 // Page O------- Frame (m_mainFrame) O-------O FrameView 40 // || 41 // || 42 // FrameLoader O-------- WebFrame (via FrameLoaderClient) 43 // 44 // FrameLoader and Frame are formerly one object that was split apart because 45 // it got too big. They basically have the same lifetime, hence the double line. 46 // 47 // WebFrame is refcounted and has one ref on behalf of the FrameLoader/Frame. 48 // This is not a normal reference counted pointer because that would require 49 // changing WebKit code that we don't control. Instead, it is created with this 50 // ref initially and it is removed when the FrameLoader is getting destroyed. 51 // 52 // WebFrames are created in two places, first in WebViewImpl when the root 53 // frame is created, and second in WebFrame::createChildFrame when sub-frames 54 // are created. WebKit will hook up this object to the FrameLoader/Frame 55 // and the refcount will be correct. 56 // 57 // How frames are destroyed 58 // ------------------------ 59 // 60 // The main frame is never destroyed and is re-used. The FrameLoader is re-used 61 // and a reference to the main frame is kept by the Page. 62 // 63 // When frame content is replaced, all subframes are destroyed. This happens 64 // in FrameLoader::detachFromParent for each subframe. 65 // 66 // Frame going away causes the FrameLoader to get deleted. In FrameLoader's 67 // destructor, it notifies its client with frameLoaderDestroyed. This derefs 68 // the WebFrame and will cause it to be deleted (unless an external someone 69 // is also holding a reference). 70 // 71 // Thie client is expected to be set whenever the WebFrameImpl is attached to 72 // the DOM. 73 74 #include "config.h" 75 #include "WebFrameImpl.h" 76 77 #include <algorithm> 78 #include "AssociatedURLLoader.h" 79 #include "DOMUtilitiesPrivate.h" 80 #include "EventListenerWrapper.h" 81 #include "FindInPageCoordinates.h" 82 #include "HTMLNames.h" 83 #include "PageOverlay.h" 84 #include "V8DOMFileSystem.h" 85 #include "V8DirectoryEntry.h" 86 #include "V8FileEntry.h" 87 #include "WebConsoleMessage.h" 88 #include "WebDOMEvent.h" 89 #include "WebDOMEventListener.h" 90 #include "WebDataSourceImpl.h" 91 #include "WebDevToolsAgentPrivate.h" 92 #include "WebDocument.h" 93 #include "WebFindOptions.h" 94 #include "WebFormElement.h" 95 #include "WebFrameClient.h" 96 #include "WebHistoryItem.h" 97 #include "WebIconURL.h" 98 #include "WebInputElement.h" 99 #include "WebNode.h" 100 #include "WebPerformance.h" 101 #include "WebPlugin.h" 102 #include "WebPluginContainerImpl.h" 103 #include "WebPrintParams.h" 104 #include "WebRange.h" 105 #include "WebScriptSource.h" 106 #include "WebSecurityOrigin.h" 107 #include "WebSerializedScriptValue.h" 108 #include "WebViewImpl.h" 109 #include "bindings/v8/DOMWrapperWorld.h" 110 #include "bindings/v8/ExceptionState.h" 111 #include "bindings/v8/ExceptionStatePlaceholder.h" 112 #include "bindings/v8/ScriptController.h" 113 #include "bindings/v8/ScriptSourceCode.h" 114 #include "bindings/v8/ScriptValue.h" 115 #include "bindings/v8/V8GCController.h" 116 #include "core/dom/Document.h" 117 #include "core/dom/DocumentMarker.h" 118 #include "core/dom/DocumentMarkerController.h" 119 #include "core/dom/IconURL.h" 120 #include "core/dom/MessagePort.h" 121 #include "core/dom/Node.h" 122 #include "core/dom/NodeTraversal.h" 123 #include "core/dom/shadow/ShadowRoot.h" 124 #include "core/editing/Editor.h" 125 #include "core/editing/FrameSelection.h" 126 #include "core/editing/InputMethodController.h" 127 #include "core/editing/PlainTextRange.h" 128 #include "core/editing/SpellChecker.h" 129 #include "core/editing/TextAffinity.h" 130 #include "core/editing/TextIterator.h" 131 #include "core/editing/htmlediting.h" 132 #include "core/editing/markup.h" 133 #include "core/frame/Console.h" 134 #include "core/frame/DOMWindow.h" 135 #include "core/frame/FrameView.h" 136 #include "core/history/HistoryItem.h" 137 #include "core/html/HTMLCollection.h" 138 #include "core/html/HTMLFormElement.h" 139 #include "core/html/HTMLFrameOwnerElement.h" 140 #include "core/html/HTMLHeadElement.h" 141 #include "core/html/HTMLInputElement.h" 142 #include "core/html/HTMLLinkElement.h" 143 #include "core/html/HTMLTextAreaElement.h" 144 #include "core/html/PluginDocument.h" 145 #include "core/inspector/InspectorController.h" 146 #include "core/inspector/ScriptCallStack.h" 147 #include "core/loader/DocumentLoader.h" 148 #include "core/loader/FormState.h" 149 #include "core/loader/FrameLoadRequest.h" 150 #include "core/loader/FrameLoader.h" 151 #include "core/loader/SubstituteData.h" 152 #include "core/page/Chrome.h" 153 #include "core/page/EventHandler.h" 154 #include "core/page/FocusController.h" 155 #include "core/page/FrameTree.h" 156 #include "core/page/Page.h" 157 #include "core/page/PrintContext.h" 158 #include "core/frame/Settings.h" 159 #include "core/rendering/HitTestResult.h" 160 #include "core/rendering/RenderBox.h" 161 #include "core/rendering/RenderFrame.h" 162 #include "core/rendering/RenderLayer.h" 163 #include "core/rendering/RenderObject.h" 164 #include "core/rendering/RenderTreeAsText.h" 165 #include "core/rendering/RenderView.h" 166 #include "core/rendering/style/StyleInheritedData.h" 167 #include "core/timing/Performance.h" 168 #include "core/xml/DocumentXPathEvaluator.h" 169 #include "core/xml/XPathResult.h" 170 #include "modules/filesystem/DOMFileSystem.h" 171 #include "modules/filesystem/DirectoryEntry.h" 172 #include "modules/filesystem/FileEntry.h" 173 #include "platform/FileSystemType.h" 174 #include "platform/TraceEvent.h" 175 #include "platform/UserGestureIndicator.h" 176 #include "platform/clipboard/ClipboardUtilities.h" 177 #include "platform/fonts/FontCache.h" 178 #include "platform/graphics/GraphicsContext.h" 179 #include "platform/graphics/GraphicsLayerClient.h" 180 #include "platform/graphics/skia/SkiaUtils.h" 181 #include "platform/network/ResourceRequest.h" 182 #include "platform/scroll/ScrollbarTheme.h" 183 #include "platform/scroll/ScrollTypes.h" 184 #include "platform/weborigin/KURL.h" 185 #include "platform/weborigin/SchemeRegistry.h" 186 #include "platform/weborigin/SecurityPolicy.h" 187 #include "public/platform/Platform.h" 188 #include "public/platform/WebFileSystem.h" 189 #include "public/platform/WebFloatPoint.h" 190 #include "public/platform/WebFloatRect.h" 191 #include "public/platform/WebLayer.h" 192 #include "public/platform/WebPoint.h" 193 #include "public/platform/WebRect.h" 194 #include "public/platform/WebSize.h" 195 #include "public/platform/WebURLError.h" 196 #include "public/platform/WebVector.h" 197 #include "wtf/CurrentTime.h" 198 #include "wtf/HashMap.h" 199 200 using namespace WebCore; 201 202 namespace blink { 203 204 static int frameCount = 0; 205 206 // Key for a StatsCounter tracking how many WebFrames are active. 207 static const char webFrameActiveCount[] = "WebFrameActiveCount"; 208 209 static void frameContentAsPlainText(size_t maxChars, Frame* frame, StringBuilder& output) 210 { 211 Document* document = frame->document(); 212 if (!document) 213 return; 214 215 if (!frame->view()) 216 return; 217 218 // TextIterator iterates over the visual representation of the DOM. As such, 219 // it requires you to do a layout before using it (otherwise it'll crash). 220 document->updateLayout(); 221 222 // Select the document body. 223 RefPtr<Range> range(document->createRange()); 224 TrackExceptionState exceptionState; 225 range->selectNodeContents(document->body(), exceptionState); 226 227 if (!exceptionState.hadException()) { 228 // The text iterator will walk nodes giving us text. This is similar to 229 // the plainText() function in core/editing/TextIterator.h, but we implement the maximum 230 // size and also copy the results directly into a wstring, avoiding the 231 // string conversion. 232 for (TextIterator it(range.get()); !it.atEnd(); it.advance()) { 233 it.appendTextToStringBuilder(output, 0, maxChars - output.length()); 234 if (output.length() >= maxChars) 235 return; // Filled up the buffer. 236 } 237 } 238 239 // The separator between frames when the frames are converted to plain text. 240 const LChar frameSeparator[] = { '\n', '\n' }; 241 const size_t frameSeparatorLength = WTF_ARRAY_LENGTH(frameSeparator); 242 243 // Recursively walk the children. 244 const FrameTree& frameTree = frame->tree(); 245 for (Frame* curChild = frameTree.firstChild(); curChild; curChild = curChild->tree().nextSibling()) { 246 // Ignore the text of non-visible frames. 247 RenderView* contentRenderer = curChild->contentRenderer(); 248 RenderPart* ownerRenderer = curChild->ownerRenderer(); 249 if (!contentRenderer || !contentRenderer->width() || !contentRenderer->height() 250 || (contentRenderer->x() + contentRenderer->width() <= 0) || (contentRenderer->y() + contentRenderer->height() <= 0) 251 || (ownerRenderer && ownerRenderer->style() && ownerRenderer->style()->visibility() != VISIBLE)) { 252 continue; 253 } 254 255 // Make sure the frame separator won't fill up the buffer, and give up if 256 // it will. The danger is if the separator will make the buffer longer than 257 // maxChars. This will cause the computation above: 258 // maxChars - output->size() 259 // to be a negative number which will crash when the subframe is added. 260 if (output.length() >= maxChars - frameSeparatorLength) 261 return; 262 263 output.append(frameSeparator, frameSeparatorLength); 264 frameContentAsPlainText(maxChars, curChild, output); 265 if (output.length() >= maxChars) 266 return; // Filled up the buffer. 267 } 268 } 269 270 WebPluginContainerImpl* WebFrameImpl::pluginContainerFromFrame(Frame* frame) 271 { 272 if (!frame) 273 return 0; 274 if (!frame->document() || !frame->document()->isPluginDocument()) 275 return 0; 276 PluginDocument* pluginDocument = toPluginDocument(frame->document()); 277 return toPluginContainerImpl(pluginDocument->pluginWidget()); 278 } 279 280 WebPluginContainerImpl* WebFrameImpl::pluginContainerFromNode(WebCore::Frame* frame, const WebNode& node) 281 { 282 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame); 283 if (pluginContainer) 284 return pluginContainer; 285 return toPluginContainerImpl(node.pluginContainer()); 286 } 287 288 // Simple class to override some of PrintContext behavior. Some of the methods 289 // made virtual so that they can be overridden by ChromePluginPrintContext. 290 class ChromePrintContext : public PrintContext { 291 WTF_MAKE_NONCOPYABLE(ChromePrintContext); 292 public: 293 ChromePrintContext(Frame* frame) 294 : PrintContext(frame) 295 , m_printedPageWidth(0) 296 { 297 } 298 299 virtual ~ChromePrintContext() { } 300 301 virtual void begin(float width, float height) 302 { 303 ASSERT(!m_printedPageWidth); 304 m_printedPageWidth = width; 305 PrintContext::begin(m_printedPageWidth, height); 306 } 307 308 virtual void end() 309 { 310 PrintContext::end(); 311 } 312 313 virtual float getPageShrink(int pageNumber) const 314 { 315 IntRect pageRect = m_pageRects[pageNumber]; 316 return m_printedPageWidth / pageRect.width(); 317 } 318 319 // Spools the printed page, a subrect of frame(). Skip the scale step. 320 // NativeTheme doesn't play well with scaling. Scaling is done browser side 321 // instead. Returns the scale to be applied. 322 // On Linux, we don't have the problem with NativeTheme, hence we let WebKit 323 // do the scaling and ignore the return value. 324 virtual float spoolPage(GraphicsContext& context, int pageNumber) 325 { 326 IntRect pageRect = m_pageRects[pageNumber]; 327 float scale = m_printedPageWidth / pageRect.width(); 328 329 context.save(); 330 #if OS(POSIX) && !OS(MACOSX) 331 context.scale(WebCore::FloatSize(scale, scale)); 332 #endif 333 context.translate(static_cast<float>(-pageRect.x()), static_cast<float>(-pageRect.y())); 334 context.clip(pageRect); 335 frame()->view()->paintContents(&context, pageRect); 336 if (context.supportsURLFragments()) 337 outputLinkedDestinations(context, frame()->document(), pageRect); 338 context.restore(); 339 return scale; 340 } 341 342 void spoolAllPagesWithBoundaries(GraphicsContext& graphicsContext, const FloatSize& pageSizeInPixels) 343 { 344 if (!frame()->document() || !frame()->view() || !frame()->document()->renderer()) 345 return; 346 347 frame()->document()->updateLayout(); 348 349 float pageHeight; 350 computePageRects(FloatRect(FloatPoint(0, 0), pageSizeInPixels), 0, 0, 1, pageHeight); 351 352 const float pageWidth = pageSizeInPixels.width(); 353 size_t numPages = pageRects().size(); 354 int totalHeight = numPages * (pageSizeInPixels.height() + 1) - 1; 355 356 // Fill the whole background by white. 357 graphicsContext.setFillColor(Color::white); 358 graphicsContext.fillRect(FloatRect(0, 0, pageWidth, totalHeight)); 359 360 graphicsContext.save(); 361 362 int currentHeight = 0; 363 for (size_t pageIndex = 0; pageIndex < numPages; pageIndex++) { 364 // Draw a line for a page boundary if this isn't the first page. 365 if (pageIndex > 0) { 366 graphicsContext.save(); 367 graphicsContext.setStrokeColor(Color(0, 0, 255)); 368 graphicsContext.setFillColor(Color(0, 0, 255)); 369 graphicsContext.drawLine(IntPoint(0, currentHeight), IntPoint(pageWidth, currentHeight)); 370 graphicsContext.restore(); 371 } 372 373 graphicsContext.save(); 374 375 graphicsContext.translate(0, currentHeight); 376 #if OS(WIN) || OS(MACOSX) 377 // Account for the disabling of scaling in spoolPage. In the context 378 // of spoolAllPagesWithBoundaries the scale HAS NOT been pre-applied. 379 float scale = getPageShrink(pageIndex); 380 graphicsContext.scale(WebCore::FloatSize(scale, scale)); 381 #endif 382 spoolPage(graphicsContext, pageIndex); 383 graphicsContext.restore(); 384 385 currentHeight += pageSizeInPixels.height() + 1; 386 } 387 388 graphicsContext.restore(); 389 } 390 391 virtual void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight) 392 { 393 PrintContext::computePageRects(printRect, headerHeight, footerHeight, userScaleFactor, outPageHeight); 394 } 395 396 virtual int pageCount() const 397 { 398 return PrintContext::pageCount(); 399 } 400 401 private: 402 // Set when printing. 403 float m_printedPageWidth; 404 }; 405 406 // Simple class to override some of PrintContext behavior. This is used when 407 // the frame hosts a plugin that supports custom printing. In this case, we 408 // want to delegate all printing related calls to the plugin. 409 class ChromePluginPrintContext : public ChromePrintContext { 410 public: 411 ChromePluginPrintContext(Frame* frame, WebPluginContainerImpl* plugin, const WebPrintParams& printParams) 412 : ChromePrintContext(frame), m_plugin(plugin), m_pageCount(0), m_printParams(printParams) 413 { 414 } 415 416 virtual ~ChromePluginPrintContext() { } 417 418 virtual void begin(float width, float height) 419 { 420 } 421 422 virtual void end() 423 { 424 m_plugin->printEnd(); 425 } 426 427 virtual float getPageShrink(int pageNumber) const 428 { 429 // We don't shrink the page (maybe we should ask the widget ??) 430 return 1.0; 431 } 432 433 virtual void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight) 434 { 435 m_printParams.printContentArea = IntRect(printRect); 436 m_pageCount = m_plugin->printBegin(m_printParams); 437 } 438 439 virtual int pageCount() const 440 { 441 return m_pageCount; 442 } 443 444 // Spools the printed page, a subrect of frame(). Skip the scale step. 445 // NativeTheme doesn't play well with scaling. Scaling is done browser side 446 // instead. Returns the scale to be applied. 447 virtual float spoolPage(GraphicsContext& context, int pageNumber) 448 { 449 m_plugin->printPage(pageNumber, &context); 450 return 1.0; 451 } 452 453 private: 454 // Set when printing. 455 WebPluginContainerImpl* m_plugin; 456 int m_pageCount; 457 WebPrintParams m_printParams; 458 459 }; 460 461 static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) 462 { 463 return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : 0; 464 } 465 466 WebFrameImpl::FindMatch::FindMatch(PassRefPtr<Range> range, int ordinal) 467 : m_range(range) 468 , m_ordinal(ordinal) 469 { 470 } 471 472 class WebFrameImpl::DeferredScopeStringMatches { 473 public: 474 DeferredScopeStringMatches(WebFrameImpl* webFrame, int identifier, const WebString& searchText, const WebFindOptions& options, bool reset) 475 : m_timer(this, &DeferredScopeStringMatches::doTimeout) 476 , m_webFrame(webFrame) 477 , m_identifier(identifier) 478 , m_searchText(searchText) 479 , m_options(options) 480 , m_reset(reset) 481 { 482 m_timer.startOneShot(0.0); 483 } 484 485 private: 486 void doTimeout(Timer<DeferredScopeStringMatches>*) 487 { 488 m_webFrame->callScopeStringMatches(this, m_identifier, m_searchText, m_options, m_reset); 489 } 490 491 Timer<DeferredScopeStringMatches> m_timer; 492 RefPtr<WebFrameImpl> m_webFrame; 493 int m_identifier; 494 WebString m_searchText; 495 WebFindOptions m_options; 496 bool m_reset; 497 }; 498 499 // WebFrame ------------------------------------------------------------------- 500 501 int WebFrame::instanceCount() 502 { 503 return frameCount; 504 } 505 506 WebFrame* WebFrame::frameForCurrentContext() 507 { 508 v8::Handle<v8::Context> context = v8::Isolate::GetCurrent()->GetCurrentContext(); 509 if (context.IsEmpty()) 510 return 0; 511 return frameForContext(context); 512 } 513 514 WebFrame* WebFrame::frameForContext(v8::Handle<v8::Context> context) 515 { 516 return WebFrameImpl::fromFrame(toFrameIfNotDetached(context)); 517 } 518 519 WebFrame* WebFrame::fromFrameOwnerElement(const WebElement& element) 520 { 521 return WebFrameImpl::fromFrameOwnerElement(PassRefPtr<Element>(element).get()); 522 } 523 524 void WebFrameImpl::close() 525 { 526 m_client = 0; 527 deref(); // Balances ref() acquired in WebFrame::create 528 } 529 530 WebString WebFrameImpl::uniqueName() const 531 { 532 return frame()->tree().uniqueName(); 533 } 534 535 WebString WebFrameImpl::assignedName() const 536 { 537 return frame()->tree().name(); 538 } 539 540 void WebFrameImpl::setName(const WebString& name) 541 { 542 frame()->tree().setName(name); 543 } 544 545 long long WebFrameImpl::embedderIdentifier() const 546 { 547 return m_frameInit->frameID(); 548 } 549 550 WebVector<WebIconURL> WebFrameImpl::iconURLs(int iconTypesMask) const 551 { 552 // The URL to the icon may be in the header. As such, only 553 // ask the loader for the icon if it's finished loading. 554 if (frame()->loader().state() == FrameStateComplete) 555 return frame()->document()->iconURLs(iconTypesMask); 556 return WebVector<WebIconURL>(); 557 } 558 559 void WebFrameImpl::setRemoteWebLayer(WebLayer* webLayer) 560 { 561 if (!frame()) 562 return; 563 564 if (frame()->remotePlatformLayer()) 565 GraphicsLayer::unregisterContentsLayer(frame()->remotePlatformLayer()); 566 if (webLayer) 567 GraphicsLayer::registerContentsLayer(webLayer); 568 frame()->setRemotePlatformLayer(webLayer); 569 frame()->ownerElement()->setNeedsStyleRecalc(WebCore::SubtreeStyleChange, WebCore::StyleChangeFromRenderer); 570 } 571 572 void WebFrameImpl::setPermissionClient(WebPermissionClient* permissionClient) 573 { 574 m_permissionClient = permissionClient; 575 } 576 577 WebSize WebFrameImpl::scrollOffset() const 578 { 579 FrameView* view = frameView(); 580 if (!view) 581 return WebSize(); 582 return view->scrollOffset(); 583 } 584 585 WebSize WebFrameImpl::minimumScrollOffset() const 586 { 587 FrameView* view = frameView(); 588 if (!view) 589 return WebSize(); 590 return toIntSize(view->minimumScrollPosition()); 591 } 592 593 WebSize WebFrameImpl::maximumScrollOffset() const 594 { 595 FrameView* view = frameView(); 596 if (!view) 597 return WebSize(); 598 return toIntSize(view->maximumScrollPosition()); 599 } 600 601 void WebFrameImpl::setScrollOffset(const WebSize& offset) 602 { 603 if (FrameView* view = frameView()) 604 view->setScrollOffset(IntPoint(offset.width, offset.height)); 605 } 606 607 WebSize WebFrameImpl::contentsSize() const 608 { 609 return frame()->view()->contentsSize(); 610 } 611 612 bool WebFrameImpl::hasVisibleContent() const 613 { 614 return frame()->view()->visibleWidth() > 0 && frame()->view()->visibleHeight() > 0; 615 } 616 617 WebRect WebFrameImpl::visibleContentRect() const 618 { 619 return frame()->view()->visibleContentRect(); 620 } 621 622 bool WebFrameImpl::hasHorizontalScrollbar() const 623 { 624 return frame() && frame()->view() && frame()->view()->horizontalScrollbar(); 625 } 626 627 bool WebFrameImpl::hasVerticalScrollbar() const 628 { 629 return frame() && frame()->view() && frame()->view()->verticalScrollbar(); 630 } 631 632 WebView* WebFrameImpl::view() const 633 { 634 return viewImpl(); 635 } 636 637 WebFrame* WebFrameImpl::opener() const 638 { 639 if (!frame()) 640 return 0; 641 return fromFrame(frame()->loader().opener()); 642 } 643 644 void WebFrameImpl::setOpener(const WebFrame* webFrame) 645 { 646 frame()->loader().setOpener(webFrame ? toWebFrameImpl(webFrame)->frame() : 0); 647 } 648 649 WebFrame* WebFrameImpl::parent() const 650 { 651 if (!frame()) 652 return 0; 653 return fromFrame(frame()->tree().parent()); 654 } 655 656 WebFrame* WebFrameImpl::top() const 657 { 658 if (!frame()) 659 return 0; 660 return fromFrame(frame()->tree().top()); 661 } 662 663 WebFrame* WebFrameImpl::firstChild() const 664 { 665 if (!frame()) 666 return 0; 667 return fromFrame(frame()->tree().firstChild()); 668 } 669 670 WebFrame* WebFrameImpl::lastChild() const 671 { 672 if (!frame()) 673 return 0; 674 return fromFrame(frame()->tree().lastChild()); 675 } 676 677 WebFrame* WebFrameImpl::nextSibling() const 678 { 679 if (!frame()) 680 return 0; 681 return fromFrame(frame()->tree().nextSibling()); 682 } 683 684 WebFrame* WebFrameImpl::previousSibling() const 685 { 686 if (!frame()) 687 return 0; 688 return fromFrame(frame()->tree().previousSibling()); 689 } 690 691 WebFrame* WebFrameImpl::traverseNext(bool wrap) const 692 { 693 if (!frame()) 694 return 0; 695 return fromFrame(frame()->tree().traverseNextWithWrap(wrap)); 696 } 697 698 WebFrame* WebFrameImpl::traversePrevious(bool wrap) const 699 { 700 if (!frame()) 701 return 0; 702 return fromFrame(frame()->tree().traversePreviousWithWrap(wrap)); 703 } 704 705 WebFrame* WebFrameImpl::findChildByName(const WebString& name) const 706 { 707 if (!frame()) 708 return 0; 709 return fromFrame(frame()->tree().child(name)); 710 } 711 712 WebFrame* WebFrameImpl::findChildByExpression(const WebString& xpath) const 713 { 714 if (xpath.isEmpty()) 715 return 0; 716 717 Document* document = frame()->document(); 718 719 RefPtr<XPathResult> xpathResult = DocumentXPathEvaluator::evaluate(document, xpath, document, 0, XPathResult::ORDERED_NODE_ITERATOR_TYPE, 0, IGNORE_EXCEPTION); 720 if (!xpathResult) 721 return 0; 722 723 Node* node = xpathResult->iterateNext(IGNORE_EXCEPTION); 724 if (!node || !node->isFrameOwnerElement()) 725 return 0; 726 return fromFrame(toHTMLFrameOwnerElement(node)->contentFrame()); 727 } 728 729 WebDocument WebFrameImpl::document() const 730 { 731 if (!frame() || !frame()->document()) 732 return WebDocument(); 733 return WebDocument(frame()->document()); 734 } 735 736 WebPerformance WebFrameImpl::performance() const 737 { 738 if (!frame()) 739 return WebPerformance(); 740 return WebPerformance(frame()->domWindow()->performance()); 741 } 742 743 NPObject* WebFrameImpl::windowObject() const 744 { 745 if (!frame()) 746 return 0; 747 return frame()->script().windowScriptNPObject(); 748 } 749 750 void WebFrameImpl::bindToWindowObject(const WebString& name, NPObject* object) 751 { 752 bindToWindowObject(name, object, 0); 753 } 754 755 void WebFrameImpl::bindToWindowObject(const WebString& name, NPObject* object, void*) 756 { 757 if (!frame() || !frame()->script().canExecuteScripts(NotAboutToExecuteScript)) 758 return; 759 frame()->script().bindToWindowObject(frame(), String(name), object); 760 } 761 762 void WebFrameImpl::executeScript(const WebScriptSource& source) 763 { 764 ASSERT(frame()); 765 TextPosition position(OrdinalNumber::fromOneBasedInt(source.startLine), OrdinalNumber::first()); 766 frame()->script().executeScriptInMainWorld(ScriptSourceCode(source.code, source.url, position)); 767 } 768 769 void WebFrameImpl::executeScriptInIsolatedWorld(int worldID, const WebScriptSource* sourcesIn, unsigned numSources, int extensionGroup) 770 { 771 ASSERT(frame()); 772 RELEASE_ASSERT(worldID > 0); 773 RELEASE_ASSERT(worldID < EmbedderWorldIdLimit); 774 775 Vector<ScriptSourceCode> sources; 776 for (unsigned i = 0; i < numSources; ++i) { 777 TextPosition position(OrdinalNumber::fromOneBasedInt(sourcesIn[i].startLine), OrdinalNumber::first()); 778 sources.append(ScriptSourceCode(sourcesIn[i].code, sourcesIn[i].url, position)); 779 } 780 781 frame()->script().executeScriptInIsolatedWorld(worldID, sources, extensionGroup, 0); 782 } 783 784 void WebFrameImpl::setIsolatedWorldSecurityOrigin(int worldID, const WebSecurityOrigin& securityOrigin) 785 { 786 ASSERT(frame()); 787 DOMWrapperWorld::setIsolatedWorldSecurityOrigin(worldID, securityOrigin.get()); 788 } 789 790 void WebFrameImpl::setIsolatedWorldContentSecurityPolicy(int worldID, const WebString& policy) 791 { 792 ASSERT(frame()); 793 DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy(worldID, policy); 794 } 795 796 void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) 797 { 798 ASSERT(frame()); 799 800 MessageLevel webCoreMessageLevel; 801 switch (message.level) { 802 case WebConsoleMessage::LevelDebug: 803 webCoreMessageLevel = DebugMessageLevel; 804 break; 805 case WebConsoleMessage::LevelLog: 806 webCoreMessageLevel = LogMessageLevel; 807 break; 808 case WebConsoleMessage::LevelWarning: 809 webCoreMessageLevel = WarningMessageLevel; 810 break; 811 case WebConsoleMessage::LevelError: 812 webCoreMessageLevel = ErrorMessageLevel; 813 break; 814 default: 815 ASSERT_NOT_REACHED(); 816 return; 817 } 818 819 frame()->document()->addConsoleMessage(OtherMessageSource, webCoreMessageLevel, message.text); 820 } 821 822 void WebFrameImpl::collectGarbage() 823 { 824 if (!frame()) 825 return; 826 if (!frame()->settings()->isScriptEnabled()) 827 return; 828 V8GCController::collectGarbage(v8::Isolate::GetCurrent()); 829 } 830 831 bool WebFrameImpl::checkIfRunInsecureContent(const WebURL& url) const 832 { 833 ASSERT(frame()); 834 return frame()->loader().mixedContentChecker()->canRunInsecureContent(frame()->document()->securityOrigin(), url); 835 } 836 837 v8::Handle<v8::Value> WebFrameImpl::executeScriptAndReturnValue(const WebScriptSource& source) 838 { 839 ASSERT(frame()); 840 841 // FIXME: This fake user gesture is required to make a bunch of pyauto 842 // tests pass. If this isn't needed in non-test situations, we should 843 // consider removing this code and changing the tests. 844 // http://code.google.com/p/chromium/issues/detail?id=86397 845 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 846 847 TextPosition position(OrdinalNumber::fromOneBasedInt(source.startLine), OrdinalNumber::first()); 848 return frame()->script().executeScriptInMainWorldAndReturnValue(ScriptSourceCode(source.code, source.url, position)).v8Value(); 849 } 850 851 void WebFrameImpl::executeScriptInIsolatedWorld(int worldID, const WebScriptSource* sourcesIn, unsigned numSources, int extensionGroup, WebVector<v8::Local<v8::Value> >* results) 852 { 853 ASSERT(frame()); 854 RELEASE_ASSERT(worldID > 0); 855 RELEASE_ASSERT(worldID < EmbedderWorldIdLimit); 856 857 Vector<ScriptSourceCode> sources; 858 859 for (unsigned i = 0; i < numSources; ++i) { 860 TextPosition position(OrdinalNumber::fromOneBasedInt(sourcesIn[i].startLine), OrdinalNumber::first()); 861 sources.append(ScriptSourceCode(sourcesIn[i].code, sourcesIn[i].url, position)); 862 } 863 864 if (results) { 865 Vector<ScriptValue> scriptResults; 866 frame()->script().executeScriptInIsolatedWorld(worldID, sources, extensionGroup, &scriptResults); 867 WebVector<v8::Local<v8::Value> > v8Results(scriptResults.size()); 868 for (unsigned i = 0; i < scriptResults.size(); i++) 869 v8Results[i] = v8::Local<v8::Value>::New(toIsolate(frame()), scriptResults[i].v8Value()); 870 results->swap(v8Results); 871 } else { 872 frame()->script().executeScriptInIsolatedWorld(worldID, sources, extensionGroup, 0); 873 } 874 } 875 876 v8::Handle<v8::Value> WebFrameImpl::callFunctionEvenIfScriptDisabled(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> argv[]) 877 { 878 ASSERT(frame()); 879 return frame()->script().callFunction(function, receiver, argc, argv); 880 } 881 882 v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const 883 { 884 if (!frame()) 885 return v8::Local<v8::Context>(); 886 return ScriptController::mainWorldContext(frame()); 887 } 888 889 v8::Handle<v8::Value> WebFrameImpl::createFileSystem(WebFileSystemType type, const WebString& name, const WebString& path) 890 { 891 ASSERT(frame()); 892 return toV8(DOMFileSystem::create(frame()->document(), name, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, path.utf8().data())), v8::Handle<v8::Object>(), toIsolate(frame())); 893 } 894 895 v8::Handle<v8::Value> WebFrameImpl::createSerializableFileSystem(WebFileSystemType type, const WebString& name, const WebString& path) 896 { 897 ASSERT(frame()); 898 RefPtr<DOMFileSystem> fileSystem = DOMFileSystem::create(frame()->document(), name, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, path.utf8().data())); 899 fileSystem->makeClonable(); 900 return toV8(fileSystem.release(), v8::Handle<v8::Object>(), toIsolate(frame())); 901 } 902 903 v8::Handle<v8::Value> WebFrameImpl::createFileEntry(WebFileSystemType type, const WebString& fileSystemName, const WebString& fileSystemPath, const WebString& filePath, bool isDirectory) 904 { 905 ASSERT(frame()); 906 907 RefPtr<DOMFileSystemBase> fileSystem = DOMFileSystem::create(frame()->document(), fileSystemName, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, fileSystemPath.utf8().data())); 908 if (isDirectory) 909 return toV8(DirectoryEntry::create(fileSystem, filePath), v8::Handle<v8::Object>(), toIsolate(frame())); 910 return toV8(FileEntry::create(fileSystem, filePath), v8::Handle<v8::Object>(), toIsolate(frame())); 911 } 912 913 void WebFrameImpl::reload(bool ignoreCache) 914 { 915 ASSERT(frame()); 916 frame()->loader().reload(ignoreCache ? EndToEndReload : NormalReload); 917 } 918 919 void WebFrameImpl::reloadWithOverrideURL(const WebURL& overrideUrl, bool ignoreCache) 920 { 921 ASSERT(frame()); 922 frame()->loader().reload(ignoreCache ? EndToEndReload : NormalReload, overrideUrl); 923 } 924 925 void WebFrameImpl::loadRequest(const WebURLRequest& request) 926 { 927 ASSERT(frame()); 928 ASSERT(!request.isNull()); 929 const ResourceRequest& resourceRequest = request.toResourceRequest(); 930 931 if (resourceRequest.url().protocolIs("javascript")) { 932 loadJavaScriptURL(resourceRequest.url()); 933 return; 934 } 935 936 frame()->loader().load(FrameLoadRequest(0, resourceRequest)); 937 } 938 939 void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item) 940 { 941 ASSERT(frame()); 942 RefPtr<HistoryItem> historyItem = PassRefPtr<HistoryItem>(item); 943 ASSERT(historyItem); 944 frame()->page()->historyController().goToItem(historyItem.get()); 945 } 946 947 void WebFrameImpl::loadData(const WebData& data, const WebString& mimeType, const WebString& textEncoding, const WebURL& baseURL, const WebURL& unreachableURL, bool replace) 948 { 949 ASSERT(frame()); 950 951 // If we are loading substitute data to replace an existing load, then 952 // inherit all of the properties of that original request. This way, 953 // reload will re-attempt the original request. It is essential that 954 // we only do this when there is an unreachableURL since a non-empty 955 // unreachableURL informs FrameLoader::reload to load unreachableURL 956 // instead of the currently loaded URL. 957 ResourceRequest request; 958 if (replace && !unreachableURL.isEmpty()) 959 request = frame()->loader().originalRequest(); 960 request.setURL(baseURL); 961 962 FrameLoadRequest frameRequest(0, request, SubstituteData(data, mimeType, textEncoding, unreachableURL)); 963 ASSERT(frameRequest.substituteData().isValid()); 964 frameRequest.setLockBackForwardList(replace); 965 frame()->loader().load(frameRequest); 966 } 967 968 void WebFrameImpl::loadHTMLString(const WebData& data, const WebURL& baseURL, const WebURL& unreachableURL, bool replace) 969 { 970 ASSERT(frame()); 971 loadData(data, WebString::fromUTF8("text/html"), WebString::fromUTF8("UTF-8"), baseURL, unreachableURL, replace); 972 } 973 974 bool WebFrameImpl::isLoading() const 975 { 976 if (!frame()) 977 return false; 978 return frame()->loader().isLoading(); 979 } 980 981 void WebFrameImpl::stopLoading() 982 { 983 if (!frame()) 984 return; 985 // FIXME: Figure out what we should really do here. It seems like a bug 986 // that FrameLoader::stopLoading doesn't call stopAllLoaders. 987 frame()->loader().stopAllLoaders(); 988 } 989 990 WebDataSource* WebFrameImpl::provisionalDataSource() const 991 { 992 ASSERT(frame()); 993 994 // We regard the policy document loader as still provisional. 995 DocumentLoader* documentLoader = frame()->loader().provisionalDocumentLoader(); 996 if (!documentLoader) 997 documentLoader = frame()->loader().policyDocumentLoader(); 998 999 return DataSourceForDocLoader(documentLoader); 1000 } 1001 1002 WebDataSource* WebFrameImpl::dataSource() const 1003 { 1004 ASSERT(frame()); 1005 return DataSourceForDocLoader(frame()->loader().documentLoader()); 1006 } 1007 1008 WebHistoryItem WebFrameImpl::previousHistoryItem() const 1009 { 1010 ASSERT(frame()); 1011 // We use the previous item here because documentState (filled-out forms) 1012 // only get saved to history when it becomes the previous item. The caller 1013 // is expected to query the history item after a navigation occurs, after 1014 // the desired history item has become the previous entry. 1015 return WebHistoryItem(frame()->page()->historyController().previousItemForExport()); 1016 } 1017 1018 WebHistoryItem WebFrameImpl::currentHistoryItem() const 1019 { 1020 ASSERT(frame()); 1021 1022 // We're shutting down. 1023 if (!frame()->loader().activeDocumentLoader()) 1024 return WebHistoryItem(); 1025 1026 // If we are still loading, then we don't want to clobber the current 1027 // history item as this could cause us to lose the scroll position and 1028 // document state. However, it is OK for new navigations. 1029 // FIXME: Can we make this a plain old getter, instead of worrying about 1030 // clobbering here? 1031 if (!frame()->page()->historyController().inSameDocumentLoad() && (frame()->loader().loadType() == FrameLoadTypeStandard 1032 || !frame()->loader().activeDocumentLoader()->isLoadingInAPISense())) 1033 frame()->loader().saveDocumentAndScrollState(); 1034 1035 if (RefPtr<HistoryItem> item = frame()->page()->historyController().provisionalItemForExport()) 1036 return WebHistoryItem(item); 1037 return WebHistoryItem(frame()->page()->historyController().currentItemForExport()); 1038 } 1039 1040 void WebFrameImpl::enableViewSourceMode(bool enable) 1041 { 1042 if (frame()) 1043 frame()->setInViewSourceMode(enable); 1044 } 1045 1046 bool WebFrameImpl::isViewSourceModeEnabled() const 1047 { 1048 if (!frame()) 1049 return false; 1050 return frame()->inViewSourceMode(); 1051 } 1052 1053 void WebFrameImpl::setReferrerForRequest(WebURLRequest& request, const WebURL& referrerURL) 1054 { 1055 String referrer = referrerURL.isEmpty() ? frame()->document()->outgoingReferrer() : String(referrerURL.spec().utf16()); 1056 referrer = SecurityPolicy::generateReferrerHeader(frame()->document()->referrerPolicy(), request.url(), referrer); 1057 if (referrer.isEmpty()) 1058 return; 1059 request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer); 1060 } 1061 1062 void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request) 1063 { 1064 ResourceResponse response; 1065 frame()->loader().client()->dispatchWillSendRequest(0, 0, request.toMutableResourceRequest(), response); 1066 } 1067 1068 WebURLLoader* WebFrameImpl::createAssociatedURLLoader(const WebURLLoaderOptions& options) 1069 { 1070 return new AssociatedURLLoader(this, options); 1071 } 1072 1073 unsigned WebFrameImpl::unloadListenerCount() const 1074 { 1075 return frame()->domWindow()->pendingUnloadEventListeners(); 1076 } 1077 1078 void WebFrameImpl::replaceSelection(const WebString& text) 1079 { 1080 bool selectReplacement = false; 1081 bool smartReplace = true; 1082 frame()->editor().replaceSelectionWithText(text, selectReplacement, smartReplace); 1083 } 1084 1085 void WebFrameImpl::insertText(const WebString& text) 1086 { 1087 if (frame()->inputMethodController().hasComposition()) 1088 frame()->inputMethodController().confirmComposition(text); 1089 else 1090 frame()->editor().insertText(text, 0); 1091 } 1092 1093 void WebFrameImpl::setMarkedText(const WebString& text, unsigned location, unsigned length) 1094 { 1095 Vector<CompositionUnderline> decorations; 1096 frame()->inputMethodController().setComposition(text, decorations, location, length); 1097 } 1098 1099 void WebFrameImpl::unmarkText() 1100 { 1101 frame()->inputMethodController().cancelComposition(); 1102 } 1103 1104 bool WebFrameImpl::hasMarkedText() const 1105 { 1106 return frame()->inputMethodController().hasComposition(); 1107 } 1108 1109 WebRange WebFrameImpl::markedRange() const 1110 { 1111 return frame()->inputMethodController().compositionRange(); 1112 } 1113 1114 bool WebFrameImpl::firstRectForCharacterRange(unsigned location, unsigned length, WebRect& rect) const 1115 { 1116 if ((location + length < location) && (location + length)) 1117 length = 0; 1118 1119 Element* editable = frame()->selection().rootEditableElementOrDocumentElement(); 1120 ASSERT(editable); 1121 RefPtr<Range> range = PlainTextRange(location, location + length).createRange(*editable); 1122 if (!range) 1123 return false; 1124 IntRect intRect = frame()->editor().firstRectForRange(range.get()); 1125 rect = WebRect(intRect); 1126 rect = frame()->view()->contentsToWindow(rect); 1127 return true; 1128 } 1129 1130 size_t WebFrameImpl::characterIndexForPoint(const WebPoint& webPoint) const 1131 { 1132 if (!frame()) 1133 return kNotFound; 1134 1135 IntPoint point = frame()->view()->windowToContents(webPoint); 1136 HitTestResult result = frame()->eventHandler().hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent); 1137 RefPtr<Range> range = frame()->rangeForPoint(result.roundedPointInInnerNodeFrame()); 1138 if (!range) 1139 return kNotFound; 1140 Element* editable = frame()->selection().rootEditableElementOrDocumentElement(); 1141 ASSERT(editable); 1142 return PlainTextRange::create(*editable, *range.get()).start(); 1143 } 1144 1145 bool WebFrameImpl::executeCommand(const WebString& name, const WebNode& node) 1146 { 1147 ASSERT(frame()); 1148 1149 if (name.length() <= 2) 1150 return false; 1151 1152 // Since we don't have NSControl, we will convert the format of command 1153 // string and call the function on Editor directly. 1154 String command = name; 1155 1156 // Make sure the first letter is upper case. 1157 command.replace(0, 1, command.substring(0, 1).upper()); 1158 1159 // Remove the trailing ':' if existing. 1160 if (command[command.length() - 1] == UChar(':')) 1161 command = command.substring(0, command.length() - 1); 1162 1163 WebPluginContainerImpl* pluginContainer = pluginContainerFromNode(frame(), node); 1164 if (pluginContainer && pluginContainer->executeEditCommand(name)) 1165 return true; 1166 1167 bool result = true; 1168 1169 // Specially handling commands that Editor::execCommand does not directly 1170 // support. 1171 if (command == "DeleteToEndOfParagraph") { 1172 if (!frame()->editor().deleteWithDirection(DirectionForward, ParagraphBoundary, true, false)) 1173 frame()->editor().deleteWithDirection(DirectionForward, CharacterGranularity, true, false); 1174 } else if (command == "Indent") { 1175 frame()->editor().indent(); 1176 } else if (command == "Outdent") { 1177 frame()->editor().outdent(); 1178 } else if (command == "DeleteBackward") { 1179 result = frame()->editor().command(AtomicString("BackwardDelete")).execute(); 1180 } else if (command == "DeleteForward") { 1181 result = frame()->editor().command(AtomicString("ForwardDelete")).execute(); 1182 } else if (command == "AdvanceToNextMisspelling") { 1183 // Wee need to pass false here or else the currently selected word will never be skipped. 1184 frame()->spellChecker().advanceToNextMisspelling(false); 1185 } else if (command == "ToggleSpellPanel") { 1186 frame()->spellChecker().showSpellingGuessPanel(); 1187 } else { 1188 result = frame()->editor().command(command).execute(); 1189 } 1190 return result; 1191 } 1192 1193 bool WebFrameImpl::executeCommand(const WebString& name, const WebString& value, const WebNode& node) 1194 { 1195 ASSERT(frame()); 1196 String webName = name; 1197 1198 WebPluginContainerImpl* pluginContainer = pluginContainerFromNode(frame(), node); 1199 if (pluginContainer && pluginContainer->executeEditCommand(name, value)) 1200 return true; 1201 1202 // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit for editable nodes. 1203 if (!frame()->editor().canEdit() && webName == "moveToBeginningOfDocument") 1204 return viewImpl()->propagateScroll(ScrollUp, ScrollByDocument); 1205 1206 if (!frame()->editor().canEdit() && webName == "moveToEndOfDocument") 1207 return viewImpl()->propagateScroll(ScrollDown, ScrollByDocument); 1208 1209 if (webName == "showGuessPanel") { 1210 frame()->spellChecker().showSpellingGuessPanel(); 1211 return true; 1212 } 1213 1214 return frame()->editor().command(webName).execute(value); 1215 } 1216 1217 bool WebFrameImpl::isCommandEnabled(const WebString& name) const 1218 { 1219 ASSERT(frame()); 1220 return frame()->editor().command(name).isEnabled(); 1221 } 1222 1223 void WebFrameImpl::enableContinuousSpellChecking(bool enable) 1224 { 1225 if (enable == isContinuousSpellCheckingEnabled()) 1226 return; 1227 frame()->spellChecker().toggleContinuousSpellChecking(); 1228 } 1229 1230 bool WebFrameImpl::isContinuousSpellCheckingEnabled() const 1231 { 1232 return frame()->spellChecker().isContinuousSpellCheckingEnabled(); 1233 } 1234 1235 void WebFrameImpl::requestTextChecking(const WebElement& webElement) 1236 { 1237 if (webElement.isNull()) 1238 return; 1239 frame()->spellChecker().requestTextChecking(*webElement.constUnwrap<Element>()); 1240 } 1241 1242 void WebFrameImpl::replaceMisspelledRange(const WebString& text) 1243 { 1244 // If this caret selection has two or more markers, this function replace the range covered by the first marker with the specified word as Microsoft Word does. 1245 if (pluginContainerFromFrame(frame())) 1246 return; 1247 RefPtr<Range> caretRange = frame()->selection().toNormalizedRange(); 1248 if (!caretRange) 1249 return; 1250 Vector<DocumentMarker*> markers = frame()->document()->markers()->markersInRange(caretRange.get(), DocumentMarker::MisspellingMarkers()); 1251 if (markers.size() < 1 || markers[0]->startOffset() >= markers[0]->endOffset()) 1252 return; 1253 RefPtr<Range> markerRange = Range::create(caretRange->ownerDocument(), caretRange->startContainer(), markers[0]->startOffset(), caretRange->endContainer(), markers[0]->endOffset()); 1254 if (!markerRange) 1255 return; 1256 frame()->selection().setSelection(markerRange.get(), CharacterGranularity); 1257 frame()->editor().replaceSelectionWithText(text, false, false); 1258 } 1259 1260 void WebFrameImpl::removeSpellingMarkers() 1261 { 1262 frame()->document()->markers()->removeMarkers(DocumentMarker::MisspellingMarkers()); 1263 } 1264 1265 bool WebFrameImpl::hasSelection() const 1266 { 1267 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame()); 1268 if (pluginContainer) 1269 return pluginContainer->plugin()->hasSelection(); 1270 1271 // frame()->selection()->isNone() never returns true. 1272 return frame()->selection().start() != frame()->selection().end(); 1273 } 1274 1275 WebRange WebFrameImpl::selectionRange() const 1276 { 1277 return frame()->selection().toNormalizedRange(); 1278 } 1279 1280 WebString WebFrameImpl::selectionAsText() const 1281 { 1282 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame()); 1283 if (pluginContainer) 1284 return pluginContainer->plugin()->selectionAsText(); 1285 1286 RefPtr<Range> range = frame()->selection().toNormalizedRange(); 1287 if (!range) 1288 return WebString(); 1289 1290 String text = range->text(); 1291 #if OS(WIN) 1292 replaceNewlinesWithWindowsStyleNewlines(text); 1293 #endif 1294 replaceNBSPWithSpace(text); 1295 return text; 1296 } 1297 1298 WebString WebFrameImpl::selectionAsMarkup() const 1299 { 1300 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame()); 1301 if (pluginContainer) 1302 return pluginContainer->plugin()->selectionAsMarkup(); 1303 1304 RefPtr<Range> range = frame()->selection().toNormalizedRange(); 1305 if (!range) 1306 return WebString(); 1307 1308 return createMarkup(range.get(), 0, AnnotateForInterchange, false, ResolveNonLocalURLs); 1309 } 1310 1311 void WebFrameImpl::selectWordAroundPosition(Frame* frame, VisiblePosition position) 1312 { 1313 VisibleSelection selection(position); 1314 selection.expandUsingGranularity(WordGranularity); 1315 1316 TextGranularity granularity = selection.isRange() ? WordGranularity : CharacterGranularity; 1317 frame->selection().setSelection(selection, granularity); 1318 } 1319 1320 bool WebFrameImpl::selectWordAroundCaret() 1321 { 1322 FrameSelection& selection = frame()->selection(); 1323 ASSERT(!selection.isNone()); 1324 if (selection.isNone() || selection.isRange()) 1325 return false; 1326 selectWordAroundPosition(frame(), selection.selection().visibleStart()); 1327 return true; 1328 } 1329 1330 void WebFrameImpl::selectRange(const WebPoint& base, const WebPoint& extent) 1331 { 1332 moveRangeSelection(base, extent); 1333 } 1334 1335 void WebFrameImpl::selectRange(const WebRange& webRange) 1336 { 1337 if (RefPtr<Range> range = static_cast<PassRefPtr<Range> >(webRange)) 1338 frame()->selection().setSelectedRange(range.get(), WebCore::VP_DEFAULT_AFFINITY, false); 1339 } 1340 1341 void WebFrameImpl::moveRangeSelection(const WebPoint& base, const WebPoint& extent) 1342 { 1343 VisiblePosition basePosition = visiblePositionForWindowPoint(base); 1344 VisiblePosition extentPosition = visiblePositionForWindowPoint(extent); 1345 VisibleSelection newSelection = VisibleSelection(basePosition, extentPosition); 1346 frame()->selection().setSelection(newSelection, CharacterGranularity); 1347 } 1348 1349 void WebFrameImpl::moveCaretSelection(const WebPoint& point) 1350 { 1351 Element* editable = frame()->selection().rootEditableElement(); 1352 if (!editable) 1353 return; 1354 1355 VisiblePosition position = visiblePositionForWindowPoint(point); 1356 frame()->selection().moveTo(position, UserTriggered); 1357 } 1358 1359 void WebFrameImpl::setCaretVisible(bool visible) 1360 { 1361 frame()->selection().setCaretVisible(visible); 1362 } 1363 1364 VisiblePosition WebFrameImpl::visiblePositionForWindowPoint(const WebPoint& point) 1365 { 1366 FloatPoint unscaledPoint(point); 1367 unscaledPoint.scale(1 / view()->pageScaleFactor(), 1 / view()->pageScaleFactor()); 1368 1369 HitTestRequest request = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::ConfusingAndOftenMisusedDisallowShadowContent; 1370 HitTestResult result(frame()->view()->windowToContents(roundedIntPoint(unscaledPoint))); 1371 frame()->document()->renderView()->layer()->hitTest(request, result); 1372 1373 if (Node* node = result.targetNode()) 1374 return frame()->selection().selection().visiblePositionRespectingEditingBoundary(result.localPoint(), node); 1375 return VisiblePosition(); 1376 } 1377 1378 int WebFrameImpl::printBegin(const WebPrintParams& printParams, const WebNode& constrainToNode) 1379 { 1380 ASSERT(!frame()->document()->isFrameSet()); 1381 WebPluginContainerImpl* pluginContainer = 0; 1382 if (constrainToNode.isNull()) { 1383 // If this is a plugin document, check if the plugin supports its own 1384 // printing. If it does, we will delegate all printing to that. 1385 pluginContainer = pluginContainerFromFrame(frame()); 1386 } else { 1387 // We only support printing plugin nodes for now. 1388 pluginContainer = toPluginContainerImpl(constrainToNode.pluginContainer()); 1389 } 1390 1391 if (pluginContainer && pluginContainer->supportsPaginatedPrint()) 1392 m_printContext = adoptPtr(new ChromePluginPrintContext(frame(), pluginContainer, printParams)); 1393 else 1394 m_printContext = adoptPtr(new ChromePrintContext(frame())); 1395 1396 FloatRect rect(0, 0, static_cast<float>(printParams.printContentArea.width), static_cast<float>(printParams.printContentArea.height)); 1397 m_printContext->begin(rect.width(), rect.height()); 1398 float pageHeight; 1399 // We ignore the overlays calculation for now since they are generated in the 1400 // browser. pageHeight is actually an output parameter. 1401 m_printContext->computePageRects(rect, 0, 0, 1.0, pageHeight); 1402 1403 return m_printContext->pageCount(); 1404 } 1405 1406 float WebFrameImpl::getPrintPageShrink(int page) 1407 { 1408 ASSERT(m_printContext && page >= 0); 1409 return m_printContext->getPageShrink(page); 1410 } 1411 1412 float WebFrameImpl::printPage(int page, WebCanvas* canvas) 1413 { 1414 #if ENABLE(PRINTING) 1415 ASSERT(m_printContext && page >= 0 && frame() && frame()->document()); 1416 1417 GraphicsContext graphicsContext(canvas); 1418 graphicsContext.setPrinting(true); 1419 return m_printContext->spoolPage(graphicsContext, page); 1420 #else 1421 return 0; 1422 #endif 1423 } 1424 1425 void WebFrameImpl::printEnd() 1426 { 1427 ASSERT(m_printContext); 1428 m_printContext->end(); 1429 m_printContext.clear(); 1430 } 1431 1432 bool WebFrameImpl::isPrintScalingDisabledForPlugin(const WebNode& node) 1433 { 1434 WebPluginContainerImpl* pluginContainer = node.isNull() ? pluginContainerFromFrame(frame()) : toPluginContainerImpl(node.pluginContainer()); 1435 1436 if (!pluginContainer || !pluginContainer->supportsPaginatedPrint()) 1437 return false; 1438 1439 return pluginContainer->isPrintScalingDisabled(); 1440 } 1441 1442 bool WebFrameImpl::hasCustomPageSizeStyle(int pageIndex) 1443 { 1444 return frame()->document()->styleForPage(pageIndex)->pageSizeType() != PAGE_SIZE_AUTO; 1445 } 1446 1447 bool WebFrameImpl::isPageBoxVisible(int pageIndex) 1448 { 1449 return frame()->document()->isPageBoxVisible(pageIndex); 1450 } 1451 1452 void WebFrameImpl::pageSizeAndMarginsInPixels(int pageIndex, WebSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft) 1453 { 1454 IntSize size = pageSize; 1455 frame()->document()->pageSizeAndMarginsInPixels(pageIndex, size, marginTop, marginRight, marginBottom, marginLeft); 1456 pageSize = size; 1457 } 1458 1459 WebString WebFrameImpl::pageProperty(const WebString& propertyName, int pageIndex) 1460 { 1461 ASSERT(m_printContext); 1462 return m_printContext->pageProperty(frame(), propertyName.utf8().data(), pageIndex); 1463 } 1464 1465 bool WebFrameImpl::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, WebRect* selectionRect) 1466 { 1467 if (!frame() || !frame()->page()) 1468 return false; 1469 1470 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 1471 1472 if (!options.findNext) 1473 frame()->page()->unmarkAllTextMatches(); 1474 else 1475 setMarkerActive(m_activeMatch.get(), false); 1476 1477 if (m_activeMatch && &m_activeMatch->ownerDocument() != frame()->document()) 1478 m_activeMatch = 0; 1479 1480 // If the user has selected something since the last Find operation we want 1481 // to start from there. Otherwise, we start searching from where the last Find 1482 // operation left off (either a Find or a FindNext operation). 1483 VisibleSelection selection(frame()->selection().selection()); 1484 bool activeSelection = !selection.isNone(); 1485 if (activeSelection) { 1486 m_activeMatch = selection.firstRange().get(); 1487 frame()->selection().clear(); 1488 } 1489 1490 ASSERT(frame() && frame()->view()); 1491 const FindOptions findOptions = (options.forward ? 0 : Backwards) 1492 | (options.matchCase ? 0 : CaseInsensitive) 1493 | (wrapWithinFrame ? WrapAround : 0) 1494 | (options.wordStart ? AtWordStarts : 0) 1495 | (options.medialCapitalAsWordStart ? TreatMedialCapitalAsWordStart : 0) 1496 | (options.findNext ? 0 : StartInSelection); 1497 m_activeMatch = frame()->editor().findStringAndScrollToVisible(searchText, m_activeMatch.get(), findOptions); 1498 1499 if (!m_activeMatch) { 1500 // If we're finding next the next active match might not be in the current frame. 1501 // In this case we don't want to clear the matches cache. 1502 if (!options.findNext) 1503 clearFindMatchesCache(); 1504 invalidateArea(InvalidateAll); 1505 return false; 1506 } 1507 1508 #if OS(ANDROID) 1509 viewImpl()->zoomToFindInPageRect(frameView()->contentsToWindow(enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get())))); 1510 #endif 1511 1512 setMarkerActive(m_activeMatch.get(), true); 1513 WebFrameImpl* oldActiveFrame = mainFrameImpl->m_currentActiveMatchFrame; 1514 mainFrameImpl->m_currentActiveMatchFrame = this; 1515 1516 // Make sure no node is focused. See http://crbug.com/38700. 1517 frame()->document()->setFocusedElement(0); 1518 1519 if (!options.findNext || activeSelection) { 1520 // This is either a Find operation or a Find-next from a new start point 1521 // due to a selection, so we set the flag to ask the scoping effort 1522 // to find the active rect for us and report it back to the UI. 1523 m_locatingActiveRect = true; 1524 } else { 1525 if (oldActiveFrame != this) { 1526 if (options.forward) 1527 m_activeMatchIndexInCurrentFrame = 0; 1528 else 1529 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1; 1530 } else { 1531 if (options.forward) 1532 ++m_activeMatchIndexInCurrentFrame; 1533 else 1534 --m_activeMatchIndexInCurrentFrame; 1535 1536 if (m_activeMatchIndexInCurrentFrame + 1 > m_lastMatchCount) 1537 m_activeMatchIndexInCurrentFrame = 0; 1538 if (m_activeMatchIndexInCurrentFrame == -1) 1539 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1; 1540 } 1541 if (selectionRect) { 1542 *selectionRect = frameView()->contentsToWindow(m_activeMatch->boundingBox()); 1543 reportFindInPageSelection(*selectionRect, m_activeMatchIndexInCurrentFrame + 1, identifier); 1544 } 1545 } 1546 1547 return true; 1548 } 1549 1550 void WebFrameImpl::stopFinding(bool clearSelection) 1551 { 1552 if (!clearSelection) 1553 setFindEndstateFocusAndSelection(); 1554 cancelPendingScopingEffort(); 1555 1556 // Remove all markers for matches found and turn off the highlighting. 1557 frame()->document()->markers()->removeMarkers(DocumentMarker::TextMatch); 1558 frame()->editor().setMarkedTextMatchesAreHighlighted(false); 1559 clearFindMatchesCache(); 1560 1561 // Let the frame know that we don't want tickmarks or highlighting anymore. 1562 invalidateArea(InvalidateAll); 1563 } 1564 1565 void WebFrameImpl::scopeStringMatches(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset) 1566 { 1567 if (reset) { 1568 // This is a brand new search, so we need to reset everything. 1569 // Scoping is just about to begin. 1570 m_scopingInProgress = true; 1571 1572 // Need to keep the current identifier locally in order to finish the 1573 // request in case the frame is detached during the process. 1574 m_findRequestIdentifier = identifier; 1575 1576 // Clear highlighting for this frame. 1577 if (frame() && frame()->page() && frame()->editor().markedTextMatchesAreHighlighted()) 1578 frame()->page()->unmarkAllTextMatches(); 1579 1580 // Clear the tickmarks and results cache. 1581 clearFindMatchesCache(); 1582 1583 // Clear the counters from last operation. 1584 m_lastMatchCount = 0; 1585 m_nextInvalidateAfter = 0; 1586 1587 m_resumeScopingFromRange = 0; 1588 1589 // The view might be null on detached frames. 1590 if (frame() && frame()->page()) 1591 viewImpl()->mainFrameImpl()->m_framesScopingCount++; 1592 1593 // Now, defer scoping until later to allow find operation to finish quickly. 1594 scopeStringMatchesSoon(identifier, searchText, options, false); // false means just reset, so don't do it again. 1595 return; 1596 } 1597 1598 if (!shouldScopeMatches(searchText)) { 1599 // Note that we want to defer the final update when resetting even if shouldScopeMatches returns false. 1600 // This is done in order to prevent sending a final message based only on the results of the first frame 1601 // since m_framesScopingCount would be 0 as other frames have yet to reset. 1602 finishCurrentScopingEffort(identifier); 1603 return; 1604 } 1605 1606 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 1607 RefPtr<Range> searchRange(rangeOfContents(frame()->document())); 1608 1609 Node* originalEndContainer = searchRange->endContainer(); 1610 int originalEndOffset = searchRange->endOffset(); 1611 1612 TrackExceptionState exceptionState, exceptionState2; 1613 if (m_resumeScopingFromRange) { 1614 // This is a continuation of a scoping operation that timed out and didn't 1615 // complete last time around, so we should start from where we left off. 1616 searchRange->setStart(m_resumeScopingFromRange->startContainer(), m_resumeScopingFromRange->startOffset(exceptionState2) + 1, exceptionState); 1617 if (exceptionState.hadException() || exceptionState2.hadException()) { 1618 if (exceptionState2.hadException()) // A non-zero |exceptionState| happens when navigating during search. 1619 ASSERT_NOT_REACHED(); 1620 return; 1621 } 1622 } 1623 1624 // This timeout controls how long we scope before releasing control. This 1625 // value does not prevent us from running for longer than this, but it is 1626 // periodically checked to see if we have exceeded our allocated time. 1627 const double maxScopingDuration = 0.1; // seconds 1628 1629 int matchCount = 0; 1630 bool timedOut = false; 1631 double startTime = currentTime(); 1632 do { 1633 // Find next occurrence of the search string. 1634 // FIXME: (http://b/1088245) This WebKit operation may run for longer 1635 // than the timeout value, and is not interruptible as it is currently 1636 // written. We may need to rewrite it with interruptibility in mind, or 1637 // find an alternative. 1638 RefPtr<Range> resultRange(findPlainText(searchRange.get(), 1639 searchText, 1640 options.matchCase ? 0 : CaseInsensitive)); 1641 if (resultRange->collapsed(exceptionState)) { 1642 if (!resultRange->startContainer()->isInShadowTree()) 1643 break; 1644 1645 searchRange->setStartAfter( 1646 resultRange->startContainer()->deprecatedShadowAncestorNode(), exceptionState); 1647 searchRange->setEnd(originalEndContainer, originalEndOffset, exceptionState); 1648 continue; 1649 } 1650 1651 ++matchCount; 1652 1653 // Catch a special case where Find found something but doesn't know what 1654 // the bounding box for it is. In this case we set the first match we find 1655 // as the active rect. 1656 IntRect resultBounds = resultRange->boundingBox(); 1657 IntRect activeSelectionRect; 1658 if (m_locatingActiveRect) { 1659 activeSelectionRect = m_activeMatch.get() ? 1660 m_activeMatch->boundingBox() : resultBounds; 1661 } 1662 1663 // If the Find function found a match it will have stored where the 1664 // match was found in m_activeSelectionRect on the current frame. If we 1665 // find this rect during scoping it means we have found the active 1666 // tickmark. 1667 bool foundActiveMatch = false; 1668 if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) { 1669 // We have found the active tickmark frame. 1670 mainFrameImpl->m_currentActiveMatchFrame = this; 1671 foundActiveMatch = true; 1672 // We also know which tickmark is active now. 1673 m_activeMatchIndexInCurrentFrame = matchCount - 1; 1674 // To stop looking for the active tickmark, we set this flag. 1675 m_locatingActiveRect = false; 1676 1677 // Notify browser of new location for the selected rectangle. 1678 reportFindInPageSelection( 1679 frameView()->contentsToWindow(resultBounds), 1680 m_activeMatchIndexInCurrentFrame + 1, 1681 identifier); 1682 } 1683 1684 addMarker(resultRange.get(), foundActiveMatch); 1685 1686 m_findMatchesCache.append(FindMatch(resultRange.get(), m_lastMatchCount + matchCount)); 1687 1688 // Set the new start for the search range to be the end of the previous 1689 // result range. There is no need to use a VisiblePosition here, 1690 // since findPlainText will use a TextIterator to go over the visible 1691 // text nodes. 1692 searchRange->setStart(resultRange->endContainer(exceptionState), resultRange->endOffset(exceptionState), exceptionState); 1693 1694 Node* shadowTreeRoot = searchRange->shadowRoot(); 1695 if (searchRange->collapsed(exceptionState) && shadowTreeRoot) 1696 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), exceptionState); 1697 1698 m_resumeScopingFromRange = resultRange; 1699 timedOut = (currentTime() - startTime) >= maxScopingDuration; 1700 } while (!timedOut); 1701 1702 // Remember what we search for last time, so we can skip searching if more 1703 // letters are added to the search string (and last outcome was 0). 1704 m_lastSearchString = searchText; 1705 1706 if (matchCount > 0) { 1707 frame()->editor().setMarkedTextMatchesAreHighlighted(true); 1708 1709 m_lastMatchCount += matchCount; 1710 1711 // Let the mainframe know how much we found during this pass. 1712 mainFrameImpl->increaseMatchCount(matchCount, identifier); 1713 } 1714 1715 if (timedOut) { 1716 // If we found anything during this pass, we should redraw. However, we 1717 // don't want to spam too much if the page is extremely long, so if we 1718 // reach a certain point we start throttling the redraw requests. 1719 if (matchCount > 0) 1720 invalidateIfNecessary(); 1721 1722 // Scoping effort ran out of time, lets ask for another time-slice. 1723 scopeStringMatchesSoon( 1724 identifier, 1725 searchText, 1726 options, 1727 false); // don't reset. 1728 return; // Done for now, resume work later. 1729 } 1730 1731 finishCurrentScopingEffort(identifier); 1732 } 1733 1734 void WebFrameImpl::flushCurrentScopingEffort(int identifier) 1735 { 1736 if (!frame() || !frame()->page()) 1737 return; 1738 1739 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 1740 1741 // This frame has no further scoping left, so it is done. Other frames might, 1742 // of course, continue to scope matches. 1743 mainFrameImpl->m_framesScopingCount--; 1744 1745 // If this is the last frame to finish scoping we need to trigger the final 1746 // update to be sent. 1747 if (!mainFrameImpl->m_framesScopingCount) 1748 mainFrameImpl->increaseMatchCount(0, identifier); 1749 } 1750 1751 void WebFrameImpl::finishCurrentScopingEffort(int identifier) 1752 { 1753 flushCurrentScopingEffort(identifier); 1754 1755 m_scopingInProgress = false; 1756 m_lastFindRequestCompletedWithNoMatches = !m_lastMatchCount; 1757 1758 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet. 1759 invalidateArea(InvalidateScrollbar); 1760 } 1761 1762 void WebFrameImpl::cancelPendingScopingEffort() 1763 { 1764 deleteAllValues(m_deferredScopingWork); 1765 m_deferredScopingWork.clear(); 1766 1767 m_activeMatchIndexInCurrentFrame = -1; 1768 1769 // Last request didn't complete. 1770 if (m_scopingInProgress) 1771 m_lastFindRequestCompletedWithNoMatches = false; 1772 1773 m_scopingInProgress = false; 1774 } 1775 1776 void WebFrameImpl::increaseMatchCount(int count, int identifier) 1777 { 1778 // This function should only be called on the mainframe. 1779 ASSERT(!parent()); 1780 1781 if (count) 1782 ++m_findMatchMarkersVersion; 1783 1784 m_totalMatchCount += count; 1785 1786 // Update the UI with the latest findings. 1787 if (client()) 1788 client()->reportFindInPageMatchCount(identifier, m_totalMatchCount, !m_framesScopingCount); 1789 } 1790 1791 void WebFrameImpl::reportFindInPageSelection(const WebRect& selectionRect, int activeMatchOrdinal, int identifier) 1792 { 1793 // Update the UI with the latest selection rect. 1794 if (client()) 1795 client()->reportFindInPageSelection(identifier, ordinalOfFirstMatchForFrame(this) + activeMatchOrdinal, selectionRect); 1796 } 1797 1798 void WebFrameImpl::resetMatchCount() 1799 { 1800 if (m_totalMatchCount > 0) 1801 ++m_findMatchMarkersVersion; 1802 1803 m_totalMatchCount = 0; 1804 m_framesScopingCount = 0; 1805 } 1806 1807 void WebFrameImpl::sendOrientationChangeEvent(int orientation) 1808 { 1809 #if ENABLE(ORIENTATION_EVENTS) 1810 if (frame()) 1811 frame()->sendOrientationChangeEvent(orientation); 1812 #endif 1813 } 1814 1815 void WebFrameImpl::dispatchMessageEventWithOriginCheck(const WebSecurityOrigin& intendedTargetOrigin, const WebDOMEvent& event) 1816 { 1817 ASSERT(!event.isNull()); 1818 frame()->domWindow()->dispatchMessageEventWithOriginCheck(intendedTargetOrigin.get(), event, 0); 1819 } 1820 1821 int WebFrameImpl::findMatchMarkersVersion() const 1822 { 1823 ASSERT(!parent()); 1824 return m_findMatchMarkersVersion; 1825 } 1826 1827 void WebFrameImpl::clearFindMatchesCache() 1828 { 1829 if (!m_findMatchesCache.isEmpty()) 1830 viewImpl()->mainFrameImpl()->m_findMatchMarkersVersion++; 1831 1832 m_findMatchesCache.clear(); 1833 m_findMatchRectsAreValid = false; 1834 } 1835 1836 bool WebFrameImpl::isActiveMatchFrameValid() const 1837 { 1838 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 1839 WebFrameImpl* activeMatchFrame = mainFrameImpl->activeMatchFrame(); 1840 return activeMatchFrame && activeMatchFrame->m_activeMatch && activeMatchFrame->frame()->tree().isDescendantOf(mainFrameImpl->frame()); 1841 } 1842 1843 void WebFrameImpl::updateFindMatchRects() 1844 { 1845 IntSize currentContentsSize = contentsSize(); 1846 if (m_contentsSizeForCurrentFindMatchRects != currentContentsSize) { 1847 m_contentsSizeForCurrentFindMatchRects = currentContentsSize; 1848 m_findMatchRectsAreValid = false; 1849 } 1850 1851 size_t deadMatches = 0; 1852 for (Vector<FindMatch>::iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) { 1853 if (!it->m_range->boundaryPointsValid() || !it->m_range->startContainer()->inDocument()) 1854 it->m_rect = FloatRect(); 1855 else if (!m_findMatchRectsAreValid) 1856 it->m_rect = findInPageRectFromRange(it->m_range.get()); 1857 1858 if (it->m_rect.isEmpty()) 1859 ++deadMatches; 1860 } 1861 1862 // Remove any invalid matches from the cache. 1863 if (deadMatches) { 1864 Vector<FindMatch> filteredMatches; 1865 filteredMatches.reserveCapacity(m_findMatchesCache.size() - deadMatches); 1866 1867 for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) 1868 if (!it->m_rect.isEmpty()) 1869 filteredMatches.append(*it); 1870 1871 m_findMatchesCache.swap(filteredMatches); 1872 } 1873 1874 // Invalidate the rects in child frames. Will be updated later during traversal. 1875 if (!m_findMatchRectsAreValid) 1876 for (WebFrame* child = firstChild(); child; child = child->nextSibling()) 1877 toWebFrameImpl(child)->m_findMatchRectsAreValid = false; 1878 1879 m_findMatchRectsAreValid = true; 1880 } 1881 1882 WebFloatRect WebFrameImpl::activeFindMatchRect() 1883 { 1884 ASSERT(!parent()); 1885 1886 if (!isActiveMatchFrameValid()) 1887 return WebFloatRect(); 1888 1889 return WebFloatRect(findInPageRectFromRange(m_currentActiveMatchFrame->m_activeMatch.get())); 1890 } 1891 1892 void WebFrameImpl::findMatchRects(WebVector<WebFloatRect>& outputRects) 1893 { 1894 ASSERT(!parent()); 1895 1896 Vector<WebFloatRect> matchRects; 1897 for (WebFrameImpl* frame = this; frame; frame = toWebFrameImpl(frame->traverseNext(false))) 1898 frame->appendFindMatchRects(matchRects); 1899 1900 outputRects = matchRects; 1901 } 1902 1903 void WebFrameImpl::appendFindMatchRects(Vector<WebFloatRect>& frameRects) 1904 { 1905 updateFindMatchRects(); 1906 frameRects.reserveCapacity(frameRects.size() + m_findMatchesCache.size()); 1907 for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) { 1908 ASSERT(!it->m_rect.isEmpty()); 1909 frameRects.append(it->m_rect); 1910 } 1911 } 1912 1913 int WebFrameImpl::selectNearestFindMatch(const WebFloatPoint& point, WebRect* selectionRect) 1914 { 1915 ASSERT(!parent()); 1916 1917 WebFrameImpl* bestFrame = 0; 1918 int indexInBestFrame = -1; 1919 float distanceInBestFrame = FLT_MAX; 1920 1921 for (WebFrameImpl* frame = this; frame; frame = toWebFrameImpl(frame->traverseNext(false))) { 1922 float distanceInFrame; 1923 int indexInFrame = frame->nearestFindMatch(point, distanceInFrame); 1924 if (distanceInFrame < distanceInBestFrame) { 1925 bestFrame = frame; 1926 indexInBestFrame = indexInFrame; 1927 distanceInBestFrame = distanceInFrame; 1928 } 1929 } 1930 1931 if (indexInBestFrame != -1) 1932 return bestFrame->selectFindMatch(static_cast<unsigned>(indexInBestFrame), selectionRect); 1933 1934 return -1; 1935 } 1936 1937 int WebFrameImpl::nearestFindMatch(const FloatPoint& point, float& distanceSquared) 1938 { 1939 updateFindMatchRects(); 1940 1941 int nearest = -1; 1942 distanceSquared = FLT_MAX; 1943 for (size_t i = 0; i < m_findMatchesCache.size(); ++i) { 1944 ASSERT(!m_findMatchesCache[i].m_rect.isEmpty()); 1945 FloatSize offset = point - m_findMatchesCache[i].m_rect.center(); 1946 float width = offset.width(); 1947 float height = offset.height(); 1948 float currentDistanceSquared = width * width + height * height; 1949 if (currentDistanceSquared < distanceSquared) { 1950 nearest = i; 1951 distanceSquared = currentDistanceSquared; 1952 } 1953 } 1954 return nearest; 1955 } 1956 1957 int WebFrameImpl::selectFindMatch(unsigned index, WebRect* selectionRect) 1958 { 1959 ASSERT_WITH_SECURITY_IMPLICATION(index < m_findMatchesCache.size()); 1960 1961 RefPtr<Range> range = m_findMatchesCache[index].m_range; 1962 if (!range->boundaryPointsValid() || !range->startContainer()->inDocument()) 1963 return -1; 1964 1965 // Check if the match is already selected. 1966 WebFrameImpl* activeMatchFrame = viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame; 1967 if (this != activeMatchFrame || !m_activeMatch || !areRangesEqual(m_activeMatch.get(), range.get())) { 1968 if (isActiveMatchFrameValid()) 1969 activeMatchFrame->setMarkerActive(activeMatchFrame->m_activeMatch.get(), false); 1970 1971 m_activeMatchIndexInCurrentFrame = m_findMatchesCache[index].m_ordinal - 1; 1972 1973 // Set this frame as the active frame (the one with the active highlight). 1974 viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame = this; 1975 viewImpl()->setFocusedFrame(this); 1976 1977 m_activeMatch = range.release(); 1978 setMarkerActive(m_activeMatch.get(), true); 1979 1980 // Clear any user selection, to make sure Find Next continues on from the match we just activated. 1981 frame()->selection().clear(); 1982 1983 // Make sure no node is focused. See http://crbug.com/38700. 1984 frame()->document()->setFocusedElement(0); 1985 } 1986 1987 IntRect activeMatchRect; 1988 IntRect activeMatchBoundingBox = enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get())); 1989 1990 if (!activeMatchBoundingBox.isEmpty()) { 1991 if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->renderer()) 1992 m_activeMatch->firstNode()->renderer()->scrollRectToVisible(activeMatchBoundingBox, 1993 ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded); 1994 1995 // Zoom to the active match. 1996 activeMatchRect = frameView()->contentsToWindow(activeMatchBoundingBox); 1997 viewImpl()->zoomToFindInPageRect(activeMatchRect); 1998 } 1999 2000 if (selectionRect) 2001 *selectionRect = activeMatchRect; 2002 2003 return ordinalOfFirstMatchForFrame(this) + m_activeMatchIndexInCurrentFrame + 1; 2004 } 2005 2006 WebString WebFrameImpl::contentAsText(size_t maxChars) const 2007 { 2008 if (!frame()) 2009 return WebString(); 2010 StringBuilder text; 2011 frameContentAsPlainText(maxChars, frame(), text); 2012 return text.toString(); 2013 } 2014 2015 WebString WebFrameImpl::contentAsMarkup() const 2016 { 2017 if (!frame()) 2018 return WebString(); 2019 return createFullMarkup(frame()->document()); 2020 } 2021 2022 WebString WebFrameImpl::renderTreeAsText(RenderAsTextControls toShow) const 2023 { 2024 RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal; 2025 2026 if (toShow & RenderAsTextDebug) 2027 behavior |= RenderAsTextShowCompositedLayers | RenderAsTextShowAddresses | RenderAsTextShowIDAndClass | RenderAsTextShowLayerNesting; 2028 2029 if (toShow & RenderAsTextPrinting) 2030 behavior |= RenderAsTextPrintingMode; 2031 2032 return externalRepresentation(frame(), behavior); 2033 } 2034 2035 WebString WebFrameImpl::markerTextForListItem(const WebElement& webElement) const 2036 { 2037 return WebCore::markerTextForListItem(const_cast<Element*>(webElement.constUnwrap<Element>())); 2038 } 2039 2040 void WebFrameImpl::printPagesWithBoundaries(WebCanvas* canvas, const WebSize& pageSizeInPixels) 2041 { 2042 ASSERT(m_printContext); 2043 2044 GraphicsContext graphicsContext(canvas); 2045 graphicsContext.setPrinting(true); 2046 2047 m_printContext->spoolAllPagesWithBoundaries(graphicsContext, FloatSize(pageSizeInPixels.width, pageSizeInPixels.height)); 2048 } 2049 2050 WebRect WebFrameImpl::selectionBoundsRect() const 2051 { 2052 return hasSelection() ? WebRect(IntRect(frame()->selection().bounds(false))) : WebRect(); 2053 } 2054 2055 bool WebFrameImpl::selectionStartHasSpellingMarkerFor(int from, int length) const 2056 { 2057 if (!frame()) 2058 return false; 2059 return frame()->spellChecker().selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length); 2060 } 2061 2062 WebString WebFrameImpl::layerTreeAsText(bool showDebugInfo) const 2063 { 2064 if (!frame()) 2065 return WebString(); 2066 2067 return WebString(frame()->layerTreeAsText(showDebugInfo ? LayerTreeIncludesDebugInfo : LayerTreeNormal)); 2068 } 2069 2070 // WebFrameImpl public --------------------------------------------------------- 2071 2072 WebFrame* WebFrame::create(WebFrameClient* client) 2073 { 2074 return WebFrameImpl::create(client); 2075 } 2076 2077 WebFrame* WebFrame::create(WebFrameClient* client, long long embedderIdentifier) 2078 { 2079 return WebFrameImpl::create(client, embedderIdentifier); 2080 } 2081 2082 long long WebFrame::generateEmbedderIdentifier() 2083 { 2084 static long long next = 0; 2085 // Assume that 64-bit will not wrap to -1. 2086 return ++next; 2087 } 2088 2089 WebFrameImpl* WebFrameImpl::create(WebFrameClient* client) 2090 { 2091 return WebFrameImpl::create(client, generateEmbedderIdentifier()); 2092 } 2093 2094 WebFrameImpl* WebFrameImpl::create(WebFrameClient* client, long long embedderIdentifier) 2095 { 2096 return adoptRef(new WebFrameImpl(client, embedderIdentifier)).leakRef(); 2097 } 2098 2099 WebFrameImpl::WebFrameImpl(WebFrameClient* client, long long embedderIdentifier) 2100 : FrameDestructionObserver(0) 2101 , m_frameInit(WebFrameInit::create(this, embedderIdentifier)) 2102 , m_client(client) 2103 , m_permissionClient(0) 2104 , m_currentActiveMatchFrame(0) 2105 , m_activeMatchIndexInCurrentFrame(-1) 2106 , m_locatingActiveRect(false) 2107 , m_resumeScopingFromRange(0) 2108 , m_lastMatchCount(-1) 2109 , m_totalMatchCount(-1) 2110 , m_framesScopingCount(-1) 2111 , m_findRequestIdentifier(-1) 2112 , m_scopingInProgress(false) 2113 , m_lastFindRequestCompletedWithNoMatches(false) 2114 , m_nextInvalidateAfter(0) 2115 , m_findMatchMarkersVersion(0) 2116 , m_findMatchRectsAreValid(false) 2117 , m_inputEventsScaleFactorForEmulation(1) 2118 { 2119 blink::Platform::current()->incrementStatsCounter(webFrameActiveCount); 2120 frameCount++; 2121 } 2122 2123 WebFrameImpl::~WebFrameImpl() 2124 { 2125 blink::Platform::current()->decrementStatsCounter(webFrameActiveCount); 2126 frameCount--; 2127 2128 cancelPendingScopingEffort(); 2129 } 2130 2131 void WebFrameImpl::setWebCoreFrame(WebCore::Frame* frame) 2132 { 2133 ASSERT(frame); 2134 observeFrame(frame); 2135 } 2136 2137 void WebFrameImpl::initializeAsMainFrame(WebCore::Page* page) 2138 { 2139 m_frameInit->setPage(page); 2140 RefPtr<Frame> mainFrame = Frame::create(m_frameInit); 2141 setWebCoreFrame(mainFrame.get()); 2142 2143 // Add reference on behalf of FrameLoader. See comments in 2144 // WebFrameLoaderClient::frameLoaderDestroyed for more info. 2145 ref(); 2146 2147 // We must call init() after m_frame is assigned because it is referenced 2148 // during init(). 2149 frame()->init(); 2150 } 2151 2152 PassRefPtr<Frame> WebFrameImpl::createChildFrame(const FrameLoadRequest& request, HTMLFrameOwnerElement* ownerElement) 2153 { 2154 ASSERT(m_client); 2155 WebFrameImpl* webframe = toWebFrameImpl(m_client->createChildFrame(this, request.frameName())); 2156 2157 // If the embedder is returning 0 from createChildFrame(), it has not been 2158 // updated to the new ownership semantics where the embedder creates the 2159 // WebFrame. In that case, fall back to the old logic where the 2160 // WebFrameImpl is created here and published back to the embedder. To 2161 // bridge between the two ownership semantics, webframeLifetimeHack is 2162 // needeed to balance out the refcounting. 2163 // 2164 // FIXME: Remove once all embedders return non-null from createChildFrame(). 2165 RefPtr<WebFrameImpl> webframeLifetimeHack; 2166 bool mustCallDidCreateFrame = false; 2167 if (!webframe) { 2168 mustCallDidCreateFrame = true; 2169 webframeLifetimeHack = adoptRef(WebFrameImpl::create(m_client)); 2170 webframe = webframeLifetimeHack.get(); 2171 } 2172 2173 // Add an extra ref on behalf of the page/FrameLoader, which references the 2174 // WebFrame via the FrameLoaderClient interface. See the comment at the top 2175 // of this file for more info. 2176 webframe->ref(); 2177 2178 webframe->m_frameInit->setPage(frame()->page()); 2179 webframe->m_frameInit->setOwnerElement(ownerElement); 2180 RefPtr<Frame> childFrame = Frame::create(webframe->m_frameInit); 2181 webframe->setWebCoreFrame(childFrame.get()); 2182 2183 childFrame->tree().setName(request.frameName()); 2184 2185 frame()->tree().appendChild(childFrame); 2186 2187 // FIXME: Remove once all embedders return non-null from createChildFrame(). 2188 if (mustCallDidCreateFrame) 2189 m_client->didCreateFrame(this, webframe); 2190 2191 // Frame::init() can trigger onload event in the parent frame, 2192 // which may detach this frame and trigger a null-pointer access 2193 // in FrameTree::removeChild. Move init() after appendChild call 2194 // so that webframe->mFrame is in the tree before triggering 2195 // onload event handler. 2196 // Because the event handler may set webframe->mFrame to null, 2197 // it is necessary to check the value after calling init() and 2198 // return without loading URL. 2199 // NOTE: m_client will be null if this frame has been detached. 2200 // (b:791612) 2201 childFrame->init(); // create an empty document 2202 if (!childFrame->tree().parent()) 2203 return 0; 2204 2205 // If we're moving in the back/forward list, we might want to replace the content 2206 // of this child frame with whatever was there at that point. 2207 HistoryItem* childItem = 0; 2208 if (isBackForwardLoadType(frame()->loader().loadType()) && !frame()->document()->loadEventFinished()) 2209 childItem = frame()->page()->historyController().itemForNewChildFrame(childFrame.get()); 2210 2211 if (childItem) 2212 childFrame->loader().loadHistoryItem(childItem); 2213 else 2214 childFrame->loader().load(FrameLoadRequest(0, request.resourceRequest(), "_self")); 2215 2216 // A synchronous navigation (about:blank) would have already processed 2217 // onload, so it is possible for the frame to have already been destroyed by 2218 // script in the page. 2219 // NOTE: m_client will be null if this frame has been detached. 2220 if (!childFrame->tree().parent()) 2221 return 0; 2222 2223 return childFrame.release(); 2224 } 2225 2226 void WebFrameImpl::didChangeContentsSize(const IntSize& size) 2227 { 2228 // This is only possible on the main frame. 2229 if (m_totalMatchCount > 0) { 2230 ASSERT(!parent()); 2231 ++m_findMatchMarkersVersion; 2232 } 2233 } 2234 2235 void WebFrameImpl::createFrameView() 2236 { 2237 TRACE_EVENT0("webkit", "WebFrameImpl::createFrameView"); 2238 2239 ASSERT(frame()); // If frame() doesn't exist, we probably didn't init properly. 2240 2241 WebViewImpl* webView = viewImpl(); 2242 bool isMainFrame = webView->mainFrameImpl()->frame() == frame(); 2243 if (isMainFrame) 2244 webView->suppressInvalidations(true); 2245 2246 frame()->createView(webView->size(), webView->baseBackgroundColor(), webView->isTransparent()); 2247 if (webView->shouldAutoResize() && isMainFrame) 2248 frame()->view()->enableAutoSizeMode(true, webView->minAutoSize(), webView->maxAutoSize()); 2249 2250 frame()->view()->setInputEventsTransformForEmulation(m_inputEventsOffsetForEmulation, m_inputEventsScaleFactorForEmulation); 2251 2252 if (isMainFrame) 2253 webView->suppressInvalidations(false); 2254 } 2255 2256 WebFrameImpl* WebFrameImpl::fromFrame(Frame* frame) 2257 { 2258 if (!frame) 2259 return 0; 2260 return toFrameLoaderClientImpl(frame->loader().client())->webFrame(); 2261 } 2262 2263 WebFrameImpl* WebFrameImpl::fromFrameOwnerElement(Element* element) 2264 { 2265 // FIXME: Why do we check specifically for <iframe> and <frame> here? Why can't we get the WebFrameImpl from an <object> element, for example. 2266 if (!element || !element->isFrameOwnerElement() || (!element->hasTagName(HTMLNames::iframeTag) && !element->hasTagName(HTMLNames::frameTag))) 2267 return 0; 2268 return fromFrame(toHTMLFrameOwnerElement(element)->contentFrame()); 2269 } 2270 2271 WebViewImpl* WebFrameImpl::viewImpl() const 2272 { 2273 if (!frame()) 2274 return 0; 2275 return WebViewImpl::fromPage(frame()->page()); 2276 } 2277 2278 WebDataSourceImpl* WebFrameImpl::dataSourceImpl() const 2279 { 2280 return static_cast<WebDataSourceImpl*>(dataSource()); 2281 } 2282 2283 WebDataSourceImpl* WebFrameImpl::provisionalDataSourceImpl() const 2284 { 2285 return static_cast<WebDataSourceImpl*>(provisionalDataSource()); 2286 } 2287 2288 void WebFrameImpl::setFindEndstateFocusAndSelection() 2289 { 2290 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 2291 2292 if (this == mainFrameImpl->activeMatchFrame() && m_activeMatch.get()) { 2293 // If the user has set the selection since the match was found, we 2294 // don't focus anything. 2295 VisibleSelection selection(frame()->selection().selection()); 2296 if (!selection.isNone()) 2297 return; 2298 2299 // Try to find the first focusable node up the chain, which will, for 2300 // example, focus links if we have found text within the link. 2301 Node* node = m_activeMatch->firstNode(); 2302 if (node && node->isInShadowTree()) { 2303 Node* host = node->deprecatedShadowAncestorNode(); 2304 if (host->hasTagName(HTMLNames::inputTag) || isHTMLTextAreaElement(host)) 2305 node = host; 2306 } 2307 for (; node; node = node->parentNode()) { 2308 if (!node->isElementNode()) 2309 continue; 2310 Element* element = toElement(node); 2311 if (element->isFocusable()) { 2312 // Found a focusable parent node. Set the active match as the 2313 // selection and focus to the focusable node. 2314 frame()->selection().setSelection(m_activeMatch.get()); 2315 frame()->document()->setFocusedElement(element); 2316 return; 2317 } 2318 } 2319 2320 // Iterate over all the nodes in the range until we find a focusable node. 2321 // This, for example, sets focus to the first link if you search for 2322 // text and text that is within one or more links. 2323 node = m_activeMatch->firstNode(); 2324 for (; node && node != m_activeMatch->pastLastNode(); node = NodeTraversal::next(*node)) { 2325 if (!node->isElementNode()) 2326 continue; 2327 Element* element = toElement(node); 2328 if (element->isFocusable()) { 2329 frame()->document()->setFocusedElement(element); 2330 return; 2331 } 2332 } 2333 2334 // No node related to the active match was focusable, so set the 2335 // active match as the selection (so that when you end the Find session, 2336 // you'll have the last thing you found highlighted) and make sure that 2337 // we have nothing focused (otherwise you might have text selected but 2338 // a link focused, which is weird). 2339 frame()->selection().setSelection(m_activeMatch.get()); 2340 frame()->document()->setFocusedElement(0); 2341 2342 // Finally clear the active match, for two reasons: 2343 // We just finished the find 'session' and we don't want future (potentially 2344 // unrelated) find 'sessions' operations to start at the same place. 2345 // The WebFrameImpl could get reused and the m_activeMatch could end up pointing 2346 // to a document that is no longer valid. Keeping an invalid reference around 2347 // is just asking for trouble. 2348 m_activeMatch = 0; 2349 } 2350 } 2351 2352 void WebFrameImpl::didFail(const ResourceError& error, bool wasProvisional) 2353 { 2354 if (!client()) 2355 return; 2356 WebURLError webError = error; 2357 if (wasProvisional) 2358 client()->didFailProvisionalLoad(this, webError); 2359 else 2360 client()->didFailLoad(this, webError); 2361 } 2362 2363 void WebFrameImpl::setCanHaveScrollbars(bool canHaveScrollbars) 2364 { 2365 frame()->view()->setCanHaveScrollbars(canHaveScrollbars); 2366 } 2367 2368 void WebFrameImpl::setInputEventsTransformForEmulation(const IntSize& offset, float contentScaleFactor) 2369 { 2370 m_inputEventsOffsetForEmulation = offset; 2371 m_inputEventsScaleFactorForEmulation = contentScaleFactor; 2372 if (frame()->view()) 2373 frame()->view()->setInputEventsTransformForEmulation(m_inputEventsOffsetForEmulation, m_inputEventsScaleFactorForEmulation); 2374 } 2375 2376 void WebFrameImpl::invalidateArea(AreaToInvalidate area) 2377 { 2378 ASSERT(frame() && frame()->view()); 2379 FrameView* view = frame()->view(); 2380 2381 if ((area & InvalidateAll) == InvalidateAll) 2382 view->invalidateRect(view->frameRect()); 2383 else { 2384 if ((area & InvalidateContentArea) == InvalidateContentArea) { 2385 IntRect contentArea( 2386 view->x(), view->y(), view->visibleWidth(), view->visibleHeight()); 2387 IntRect frameRect = view->frameRect(); 2388 contentArea.move(-frameRect.x(), -frameRect.y()); 2389 view->invalidateRect(contentArea); 2390 } 2391 } 2392 2393 if ((area & InvalidateScrollbar) == InvalidateScrollbar) { 2394 // Invalidate the vertical scroll bar region for the view. 2395 Scrollbar* scrollbar = view->verticalScrollbar(); 2396 if (scrollbar) 2397 scrollbar->invalidate(); 2398 } 2399 } 2400 2401 void WebFrameImpl::addMarker(Range* range, bool activeMatch) 2402 { 2403 frame()->document()->markers()->addTextMatchMarker(range, activeMatch); 2404 } 2405 2406 void WebFrameImpl::setMarkerActive(Range* range, bool active) 2407 { 2408 if (!range || range->collapsed(IGNORE_EXCEPTION)) 2409 return; 2410 frame()->document()->markers()->setMarkersActive(range, active); 2411 } 2412 2413 int WebFrameImpl::ordinalOfFirstMatchForFrame(WebFrameImpl* frame) const 2414 { 2415 int ordinal = 0; 2416 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 2417 // Iterate from the main frame up to (but not including) |frame| and 2418 // add up the number of matches found so far. 2419 for (WebFrameImpl* it = mainFrameImpl; it != frame; it = toWebFrameImpl(it->traverseNext(true))) { 2420 if (it->m_lastMatchCount > 0) 2421 ordinal += it->m_lastMatchCount; 2422 } 2423 return ordinal; 2424 } 2425 2426 bool WebFrameImpl::shouldScopeMatches(const String& searchText) 2427 { 2428 // Don't scope if we can't find a frame or a view. 2429 // The user may have closed the tab/application, so abort. 2430 // Also ignore detached frames, as many find operations report to the main frame. 2431 if (!frame() || !frame()->view() || !frame()->page() || !hasVisibleContent()) 2432 return false; 2433 2434 ASSERT(frame()->document() && frame()->view()); 2435 2436 // If the frame completed the scoping operation and found 0 matches the last 2437 // time it was searched, then we don't have to search it again if the user is 2438 // just adding to the search string or sending the same search string again. 2439 if (m_lastFindRequestCompletedWithNoMatches && !m_lastSearchString.isEmpty()) { 2440 // Check to see if the search string prefixes match. 2441 String previousSearchPrefix = 2442 searchText.substring(0, m_lastSearchString.length()); 2443 2444 if (previousSearchPrefix == m_lastSearchString) 2445 return false; // Don't search this frame, it will be fruitless. 2446 } 2447 2448 return true; 2449 } 2450 2451 void WebFrameImpl::scopeStringMatchesSoon(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset) 2452 { 2453 m_deferredScopingWork.append(new DeferredScopeStringMatches(this, identifier, searchText, options, reset)); 2454 } 2455 2456 void WebFrameImpl::callScopeStringMatches(DeferredScopeStringMatches* caller, int identifier, const WebString& searchText, const WebFindOptions& options, bool reset) 2457 { 2458 m_deferredScopingWork.remove(m_deferredScopingWork.find(caller)); 2459 scopeStringMatches(identifier, searchText, options, reset); 2460 2461 // This needs to happen last since searchText is passed by reference. 2462 delete caller; 2463 } 2464 2465 void WebFrameImpl::invalidateIfNecessary() 2466 { 2467 if (m_lastMatchCount <= m_nextInvalidateAfter) 2468 return; 2469 2470 // FIXME: (http://b/1088165) Optimize the drawing of the tickmarks and 2471 // remove this. This calculation sets a milestone for when next to 2472 // invalidate the scrollbar and the content area. We do this so that we 2473 // don't spend too much time drawing the scrollbar over and over again. 2474 // Basically, up until the first 500 matches there is no throttle. 2475 // After the first 500 matches, we set set the milestone further and 2476 // further out (750, 1125, 1688, 2K, 3K). 2477 static const int startSlowingDownAfter = 500; 2478 static const int slowdown = 750; 2479 2480 int i = m_lastMatchCount / startSlowingDownAfter; 2481 m_nextInvalidateAfter += i * slowdown; 2482 invalidateArea(InvalidateScrollbar); 2483 } 2484 2485 void WebFrameImpl::loadJavaScriptURL(const KURL& url) 2486 { 2487 // This is copied from ScriptController::executeScriptIfJavaScriptURL. 2488 // Unfortunately, we cannot just use that method since it is private, and 2489 // it also doesn't quite behave as we require it to for bookmarklets. The 2490 // key difference is that we need to suppress loading the string result 2491 // from evaluating the JS URL if executing the JS URL resulted in a 2492 // location change. We also allow a JS URL to be loaded even if scripts on 2493 // the page are otherwise disabled. 2494 2495 if (!frame()->document() || !frame()->page()) 2496 return; 2497 2498 RefPtr<Document> ownerDocument(frame()->document()); 2499 2500 // Protect privileged pages against bookmarklets and other javascript manipulations. 2501 if (SchemeRegistry::shouldTreatURLSchemeAsNotAllowingJavascriptURLs(frame()->document()->url().protocol())) 2502 return; 2503 2504 String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:"))); 2505 UserGestureIndicator gestureIndicator(DefinitelyProcessingNewUserGesture); 2506 ScriptValue result = frame()->script().executeScriptInMainWorldAndReturnValue(ScriptSourceCode(script)); 2507 2508 String scriptResult; 2509 if (!result.getString(scriptResult)) 2510 return; 2511 2512 if (!frame()->navigationScheduler().locationChangePending()) 2513 frame()->document()->loader()->replaceDocument(scriptResult, ownerDocument.get()); 2514 } 2515 2516 void WebFrameImpl::willDetachPage() 2517 { 2518 if (!frame() || !frame()->page()) 2519 return; 2520 2521 // Do not expect string scoping results from any frames that got detached 2522 // in the middle of the operation. 2523 if (m_scopingInProgress) { 2524 2525 // There is a possibility that the frame being detached was the only 2526 // pending one. We need to make sure final replies can be sent. 2527 flushCurrentScopingEffort(m_findRequestIdentifier); 2528 2529 cancelPendingScopingEffort(); 2530 } 2531 } 2532 2533 } // namespace blink 2534