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 calls 68 // WebFrame::Closing and then derefs the WebFrame and will cause it to be 69 // deleted (unless an external someone is also holding a reference). 70 71 #include "config.h" 72 #include "WebFrameImpl.h" 73 74 #include "AssociatedURLLoader.h" 75 #include "BackForwardController.h" 76 #include "Chrome.h" 77 #include "ClipboardUtilitiesChromium.h" 78 #include "Console.h" 79 #include "DOMUtilitiesPrivate.h" 80 #include "DOMWindow.h" 81 #include "Document.h" 82 #include "DocumentFragment.h" // Only needed for ReplaceSelectionCommand.h :( 83 #include "DocumentLoader.h" 84 #include "DocumentMarker.h" 85 #include "DocumentMarkerController.h" 86 #include "Editor.h" 87 #include "EventHandler.h" 88 #include "FormState.h" 89 #include "FrameLoadRequest.h" 90 #include "FrameLoader.h" 91 #include "FrameTree.h" 92 #include "FrameView.h" 93 #include "HitTestResult.h" 94 #include "HTMLCollection.h" 95 #include "HTMLFormElement.h" 96 #include "HTMLFrameOwnerElement.h" 97 #include "HTMLHeadElement.h" 98 #include "HTMLInputElement.h" 99 #include "HTMLLinkElement.h" 100 #include "HTMLNames.h" 101 #include "HistoryItem.h" 102 #include "InspectorController.h" 103 #include "Page.h" 104 #include "painting/GraphicsContextBuilder.h" 105 #include "Performance.h" 106 #include "PlatformBridge.h" 107 #include "PluginDocument.h" 108 #include "PrintContext.h" 109 #include "RenderFrame.h" 110 #include "RenderLayer.h" 111 #include "RenderObject.h" 112 #include "RenderTreeAsText.h" 113 #include "RenderView.h" 114 #include "RenderWidget.h" 115 #include "ReplaceSelectionCommand.h" 116 #include "ResourceHandle.h" 117 #include "ResourceRequest.h" 118 #include "SVGDocumentExtensions.h" 119 #include "SVGSMILElement.h" 120 #include "ScriptController.h" 121 #include "ScriptSourceCode.h" 122 #include "ScriptValue.h" 123 #include "ScrollTypes.h" 124 #include "ScrollbarTheme.h" 125 #include "SelectionController.h" 126 #include "Settings.h" 127 #include "SkiaUtils.h" 128 #include "SubstituteData.h" 129 #include "TextAffinity.h" 130 #include "TextIterator.h" 131 #include "WebAnimationControllerImpl.h" 132 #include "WebConsoleMessage.h" 133 #include "WebDataSourceImpl.h" 134 #include "WebDocument.h" 135 #include "WebFindOptions.h" 136 #include "WebFormElement.h" 137 #include "WebFrameClient.h" 138 #include "WebHistoryItem.h" 139 #include "WebInputElement.h" 140 #include "WebNode.h" 141 #include "WebPasswordAutocompleteListener.h" 142 #include "WebPerformance.h" 143 #include "WebPlugin.h" 144 #include "WebPluginContainerImpl.h" 145 #include "WebPoint.h" 146 #include "WebRange.h" 147 #include "WebRect.h" 148 #include "WebScriptSource.h" 149 #include "WebSecurityOrigin.h" 150 #include "WebSize.h" 151 #include "WebURLError.h" 152 #include "WebVector.h" 153 #include "WebViewImpl.h" 154 #include "XPathResult.h" 155 #include "markup.h" 156 157 #include <algorithm> 158 #include <wtf/CurrentTime.h> 159 160 #if OS(LINUX) || OS(FREEBSD) 161 #include <gdk/gdk.h> 162 #endif 163 164 #if USE(V8) 165 #include "AsyncFileSystem.h" 166 #include "AsyncFileSystemChromium.h" 167 #include "DirectoryEntry.h" 168 #include "DOMFileSystem.h" 169 #include "FileEntry.h" 170 #include "V8DirectoryEntry.h" 171 #include "V8DOMFileSystem.h" 172 #include "V8FileEntry.h" 173 #include "WebFileSystem.h" 174 #endif 175 176 using namespace WebCore; 177 178 namespace WebKit { 179 180 static int frameCount = 0; 181 182 // Key for a StatsCounter tracking how many WebFrames are active. 183 static const char* const webFrameActiveCount = "WebFrameActiveCount"; 184 185 static const char* const osdType = "application/opensearchdescription+xml"; 186 static const char* const osdRel = "search"; 187 188 // Backend for contentAsPlainText, this is a recursive function that gets 189 // the text for the current frame and all of its subframes. It will append 190 // the text of each frame in turn to the |output| up to |maxChars| length. 191 // 192 // The |frame| must be non-null. 193 static void frameContentAsPlainText(size_t maxChars, Frame* frame, 194 Vector<UChar>* output) 195 { 196 Document* doc = frame->document(); 197 if (!doc) 198 return; 199 200 if (!frame->view()) 201 return; 202 203 // TextIterator iterates over the visual representation of the DOM. As such, 204 // it requires you to do a layout before using it (otherwise it'll crash). 205 if (frame->view()->needsLayout()) 206 frame->view()->layout(); 207 208 // Select the document body. 209 RefPtr<Range> range(doc->createRange()); 210 ExceptionCode exception = 0; 211 range->selectNodeContents(doc->body(), exception); 212 213 if (!exception) { 214 // The text iterator will walk nodes giving us text. This is similar to 215 // the plainText() function in TextIterator.h, but we implement the maximum 216 // size and also copy the results directly into a wstring, avoiding the 217 // string conversion. 218 for (TextIterator it(range.get()); !it.atEnd(); it.advance()) { 219 const UChar* chars = it.characters(); 220 if (!chars) { 221 if (it.length()) { 222 // It appears from crash reports that an iterator can get into a state 223 // where the character count is nonempty but the character pointer is 224 // null. advance()ing it will then just add that many to the null 225 // pointer which won't be caught in a null check but will crash. 226 // 227 // A null pointer and 0 length is common for some nodes. 228 // 229 // IF YOU CATCH THIS IN A DEBUGGER please let brettw know. We don't 230 // currently understand the conditions for this to occur. Ideally, the 231 // iterators would never get into the condition so we should fix them 232 // if we can. 233 ASSERT_NOT_REACHED(); 234 break; 235 } 236 237 // Just got a null node, we can forge ahead! 238 continue; 239 } 240 size_t toAppend = 241 std::min(static_cast<size_t>(it.length()), maxChars - output->size()); 242 output->append(chars, toAppend); 243 if (output->size() >= maxChars) 244 return; // Filled up the buffer. 245 } 246 } 247 248 // The separator between frames when the frames are converted to plain text. 249 const UChar frameSeparator[] = { '\n', '\n' }; 250 const size_t frameSeparatorLen = 2; 251 252 // Recursively walk the children. 253 FrameTree* frameTree = frame->tree(); 254 for (Frame* curChild = frameTree->firstChild(); curChild; curChild = curChild->tree()->nextSibling()) { 255 // Ignore the text of non-visible frames. 256 RenderView* contentRenderer = curChild->contentRenderer(); 257 RenderPart* ownerRenderer = curChild->ownerRenderer(); 258 if (!contentRenderer || !contentRenderer->width() || !contentRenderer->height() 259 || (contentRenderer->x() + contentRenderer->width() <= 0) || (contentRenderer->y() + contentRenderer->height() <= 0) 260 || (ownerRenderer && ownerRenderer->style() && ownerRenderer->style()->visibility() != VISIBLE)) { 261 continue; 262 } 263 264 // Make sure the frame separator won't fill up the buffer, and give up if 265 // it will. The danger is if the separator will make the buffer longer than 266 // maxChars. This will cause the computation above: 267 // maxChars - output->size() 268 // to be a negative number which will crash when the subframe is added. 269 if (output->size() >= maxChars - frameSeparatorLen) 270 return; 271 272 output->append(frameSeparator, frameSeparatorLen); 273 frameContentAsPlainText(maxChars, curChild, output); 274 if (output->size() >= maxChars) 275 return; // Filled up the buffer. 276 } 277 } 278 279 static long long generateFrameIdentifier() 280 { 281 static long long next = 0; 282 return ++next; 283 } 284 285 WebPluginContainerImpl* WebFrameImpl::pluginContainerFromFrame(Frame* frame) 286 { 287 if (!frame) 288 return 0; 289 if (!frame->document() || !frame->document()->isPluginDocument()) 290 return 0; 291 PluginDocument* pluginDocument = static_cast<PluginDocument*>(frame->document()); 292 return static_cast<WebPluginContainerImpl *>(pluginDocument->pluginWidget()); 293 } 294 295 // Simple class to override some of PrintContext behavior. Some of the methods 296 // made virtual so that they can be overriden by ChromePluginPrintContext. 297 class ChromePrintContext : public PrintContext { 298 WTF_MAKE_NONCOPYABLE(ChromePrintContext); 299 public: 300 ChromePrintContext(Frame* frame) 301 : PrintContext(frame) 302 , m_printedPageWidth(0) 303 { 304 } 305 306 virtual void begin(float width, float height) 307 { 308 ASSERT(!m_printedPageWidth); 309 m_printedPageWidth = width; 310 PrintContext::begin(m_printedPageWidth, height); 311 } 312 313 virtual void end() 314 { 315 PrintContext::end(); 316 } 317 318 virtual float getPageShrink(int pageNumber) const 319 { 320 IntRect pageRect = m_pageRects[pageNumber]; 321 return m_printedPageWidth / pageRect.width(); 322 } 323 324 // Spools the printed page, a subrect of m_frame. Skip the scale step. 325 // NativeTheme doesn't play well with scaling. Scaling is done browser side 326 // instead. Returns the scale to be applied. 327 // On Linux, we don't have the problem with NativeTheme, hence we let WebKit 328 // do the scaling and ignore the return value. 329 virtual float spoolPage(GraphicsContext& ctx, int pageNumber) 330 { 331 IntRect pageRect = m_pageRects[pageNumber]; 332 float scale = m_printedPageWidth / pageRect.width(); 333 334 ctx.save(); 335 #if OS(LINUX) || OS(FREEBSD) 336 ctx.scale(WebCore::FloatSize(scale, scale)); 337 #endif 338 ctx.translate(static_cast<float>(-pageRect.x()), 339 static_cast<float>(-pageRect.y())); 340 ctx.clip(pageRect); 341 m_frame->view()->paintContents(&ctx, pageRect); 342 ctx.restore(); 343 return scale; 344 } 345 346 virtual void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight) 347 { 348 return PrintContext::computePageRects(printRect, headerHeight, footerHeight, userScaleFactor, outPageHeight); 349 } 350 351 virtual int pageCount() const 352 { 353 return PrintContext::pageCount(); 354 } 355 356 virtual bool shouldUseBrowserOverlays() const 357 { 358 return true; 359 } 360 361 private: 362 // Set when printing. 363 float m_printedPageWidth; 364 }; 365 366 // Simple class to override some of PrintContext behavior. This is used when 367 // the frame hosts a plugin that supports custom printing. In this case, we 368 // want to delegate all printing related calls to the plugin. 369 class ChromePluginPrintContext : public ChromePrintContext { 370 public: 371 ChromePluginPrintContext(Frame* frame, WebPluginContainerImpl* plugin, int printerDPI) 372 : ChromePrintContext(frame), m_plugin(plugin), m_pageCount(0), m_printerDPI(printerDPI) 373 { 374 } 375 376 virtual void begin(float width, float height) 377 { 378 } 379 380 virtual void end() 381 { 382 m_plugin->printEnd(); 383 } 384 385 virtual float getPageShrink(int pageNumber) const 386 { 387 // We don't shrink the page (maybe we should ask the widget ??) 388 return 1.0; 389 } 390 391 virtual void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight) 392 { 393 m_pageCount = m_plugin->printBegin(IntRect(printRect), m_printerDPI); 394 } 395 396 virtual int pageCount() const 397 { 398 return m_pageCount; 399 } 400 401 // Spools the printed page, a subrect of m_frame. Skip the scale step. 402 // NativeTheme doesn't play well with scaling. Scaling is done browser side 403 // instead. Returns the scale to be applied. 404 virtual float spoolPage(GraphicsContext& ctx, int pageNumber) 405 { 406 m_plugin->printPage(pageNumber, &ctx); 407 return 1.0; 408 } 409 410 virtual bool shouldUseBrowserOverlays() const 411 { 412 return false; 413 } 414 415 private: 416 // Set when printing. 417 WebPluginContainerImpl* m_plugin; 418 int m_pageCount; 419 int m_printerDPI; 420 }; 421 422 static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) 423 { 424 return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : 0; 425 } 426 427 428 // WebFrame ------------------------------------------------------------------- 429 430 class WebFrameImpl::DeferredScopeStringMatches { 431 public: 432 DeferredScopeStringMatches(WebFrameImpl* webFrame, 433 int identifier, 434 const WebString& searchText, 435 const WebFindOptions& options, 436 bool reset) 437 : m_timer(this, &DeferredScopeStringMatches::doTimeout) 438 , m_webFrame(webFrame) 439 , m_identifier(identifier) 440 , m_searchText(searchText) 441 , m_options(options) 442 , m_reset(reset) 443 { 444 m_timer.startOneShot(0.0); 445 } 446 447 private: 448 void doTimeout(Timer<DeferredScopeStringMatches>*) 449 { 450 m_webFrame->callScopeStringMatches( 451 this, m_identifier, m_searchText, m_options, m_reset); 452 } 453 454 Timer<DeferredScopeStringMatches> m_timer; 455 RefPtr<WebFrameImpl> m_webFrame; 456 int m_identifier; 457 WebString m_searchText; 458 WebFindOptions m_options; 459 bool m_reset; 460 }; 461 462 463 // WebFrame ------------------------------------------------------------------- 464 465 int WebFrame::instanceCount() 466 { 467 return frameCount; 468 } 469 470 WebFrame* WebFrame::frameForEnteredContext() 471 { 472 Frame* frame = 473 ScriptController::retrieveFrameForEnteredContext(); 474 return WebFrameImpl::fromFrame(frame); 475 } 476 477 WebFrame* WebFrame::frameForCurrentContext() 478 { 479 Frame* frame = 480 ScriptController::retrieveFrameForCurrentContext(); 481 return WebFrameImpl::fromFrame(frame); 482 } 483 484 #if WEBKIT_USING_V8 485 WebFrame* WebFrame::frameForContext(v8::Handle<v8::Context> context) 486 { 487 return WebFrameImpl::fromFrame(V8Proxy::retrieveFrame(context)); 488 } 489 #endif 490 491 WebFrame* WebFrame::fromFrameOwnerElement(const WebElement& element) 492 { 493 return WebFrameImpl::fromFrameOwnerElement( 494 PassRefPtr<Element>(element).get()); 495 } 496 497 WebString WebFrameImpl::name() const 498 { 499 return m_frame->tree()->uniqueName(); 500 } 501 502 void WebFrameImpl::setName(const WebString& name) 503 { 504 m_frame->tree()->setName(name); 505 } 506 507 long long WebFrameImpl::identifier() const 508 { 509 return m_identifier; 510 } 511 512 WebURL WebFrameImpl::url() const 513 { 514 const WebDataSource* ds = dataSource(); 515 if (!ds) 516 return WebURL(); 517 return ds->request().url(); 518 } 519 520 WebURL WebFrameImpl::favIconURL() const 521 { 522 FrameLoader* frameLoader = m_frame->loader(); 523 // The URL to the favicon may be in the header. As such, only 524 // ask the loader for the favicon if it's finished loading. 525 if (frameLoader->state() == FrameStateComplete) { 526 const KURL& url = frameLoader->iconURL(); 527 if (!url.isEmpty()) 528 return url; 529 } 530 return WebURL(); 531 } 532 533 WebURL WebFrameImpl::openSearchDescriptionURL() const 534 { 535 FrameLoader* frameLoader = m_frame->loader(); 536 if (frameLoader->state() == FrameStateComplete 537 && m_frame->document() && m_frame->document()->head() 538 && !m_frame->tree()->parent()) { 539 HTMLHeadElement* head = m_frame->document()->head(); 540 if (head) { 541 RefPtr<HTMLCollection> children = head->children(); 542 for (Node* child = children->firstItem(); child; child = children->nextItem()) { 543 HTMLLinkElement* linkElement = toHTMLLinkElement(child); 544 if (linkElement 545 && linkElement->type() == osdType 546 && linkElement->rel() == osdRel 547 && !linkElement->href().isEmpty()) 548 return linkElement->href(); 549 } 550 } 551 } 552 return WebURL(); 553 } 554 555 WebString WebFrameImpl::encoding() const 556 { 557 return frame()->document()->loader()->writer()->encoding(); 558 } 559 560 WebSize WebFrameImpl::scrollOffset() const 561 { 562 FrameView* view = frameView(); 563 if (view) 564 return view->scrollOffset(); 565 566 return WebSize(); 567 } 568 569 void WebFrameImpl::setScrollOffset(const WebSize& offset) 570 { 571 if (FrameView* view = frameView()) 572 view->setScrollOffset(IntPoint(offset.width, offset.height)); 573 } 574 575 WebSize WebFrameImpl::contentsSize() const 576 { 577 return frame()->view()->contentsSize(); 578 } 579 580 int WebFrameImpl::contentsPreferredWidth() const 581 { 582 if (m_frame->document() && m_frame->document()->renderView()) 583 return m_frame->document()->renderView()->minPreferredLogicalWidth(); 584 return 0; 585 } 586 587 int WebFrameImpl::documentElementScrollHeight() const 588 { 589 if (m_frame->document() && m_frame->document()->documentElement()) 590 return m_frame->document()->documentElement()->scrollHeight(); 591 return 0; 592 } 593 594 bool WebFrameImpl::hasVisibleContent() const 595 { 596 return frame()->view()->visibleWidth() > 0 && frame()->view()->visibleHeight() > 0; 597 } 598 599 WebView* WebFrameImpl::view() const 600 { 601 return viewImpl(); 602 } 603 604 void WebFrameImpl::clearOpener() 605 { 606 m_frame->loader()->setOpener(0); 607 } 608 609 WebFrame* WebFrameImpl::opener() const 610 { 611 Frame* opener = 0; 612 if (m_frame) 613 opener = m_frame->loader()->opener(); 614 return fromFrame(opener); 615 } 616 617 WebFrame* WebFrameImpl::parent() const 618 { 619 Frame* parent = 0; 620 if (m_frame) 621 parent = m_frame->tree()->parent(); 622 return fromFrame(parent); 623 } 624 625 WebFrame* WebFrameImpl::top() const 626 { 627 if (m_frame) 628 return fromFrame(m_frame->tree()->top()); 629 630 return 0; 631 } 632 633 WebFrame* WebFrameImpl::firstChild() const 634 { 635 return fromFrame(frame()->tree()->firstChild()); 636 } 637 638 WebFrame* WebFrameImpl::lastChild() const 639 { 640 return fromFrame(frame()->tree()->lastChild()); 641 } 642 643 WebFrame* WebFrameImpl::nextSibling() const 644 { 645 return fromFrame(frame()->tree()->nextSibling()); 646 } 647 648 WebFrame* WebFrameImpl::previousSibling() const 649 { 650 return fromFrame(frame()->tree()->previousSibling()); 651 } 652 653 WebFrame* WebFrameImpl::traverseNext(bool wrap) const 654 { 655 return fromFrame(frame()->tree()->traverseNextWithWrap(wrap)); 656 } 657 658 WebFrame* WebFrameImpl::traversePrevious(bool wrap) const 659 { 660 return fromFrame(frame()->tree()->traversePreviousWithWrap(wrap)); 661 } 662 663 WebFrame* WebFrameImpl::findChildByName(const WebString& name) const 664 { 665 return fromFrame(frame()->tree()->child(name)); 666 } 667 668 WebFrame* WebFrameImpl::findChildByExpression(const WebString& xpath) const 669 { 670 if (xpath.isEmpty()) 671 return 0; 672 673 Document* document = m_frame->document(); 674 675 ExceptionCode ec = 0; 676 PassRefPtr<XPathResult> xpathResult = 677 document->evaluate(xpath, 678 document, 679 0, // namespace 680 XPathResult::ORDERED_NODE_ITERATOR_TYPE, 681 0, // XPathResult object 682 ec); 683 if (!xpathResult.get()) 684 return 0; 685 686 Node* node = xpathResult->iterateNext(ec); 687 688 if (!node || !node->isFrameOwnerElement()) 689 return 0; 690 HTMLFrameOwnerElement* frameElement = 691 static_cast<HTMLFrameOwnerElement*>(node); 692 return fromFrame(frameElement->contentFrame()); 693 } 694 695 WebDocument WebFrameImpl::document() const 696 { 697 if (!m_frame || !m_frame->document()) 698 return WebDocument(); 699 return WebDocument(m_frame->document()); 700 } 701 702 void WebFrameImpl::forms(WebVector<WebFormElement>& results) const 703 { 704 if (!m_frame) 705 return; 706 707 RefPtr<HTMLCollection> forms = m_frame->document()->forms(); 708 size_t sourceLength = forms->length(); 709 Vector<WebFormElement> temp; 710 temp.reserveCapacity(sourceLength); 711 for (size_t i = 0; i < sourceLength; ++i) { 712 Node* node = forms->item(i); 713 // Strange but true, sometimes node can be 0. 714 if (node && node->isHTMLElement()) 715 temp.append(WebFormElement(static_cast<HTMLFormElement*>(node))); 716 } 717 results.assign(temp); 718 } 719 720 WebAnimationController* WebFrameImpl::animationController() 721 { 722 return &m_animationController; 723 } 724 725 WebPerformance WebFrameImpl::performance() const 726 { 727 if (!m_frame || !m_frame->domWindow()) 728 return WebPerformance(); 729 730 return WebPerformance(m_frame->domWindow()->performance()); 731 } 732 733 WebSecurityOrigin WebFrameImpl::securityOrigin() const 734 { 735 if (!m_frame || !m_frame->document()) 736 return WebSecurityOrigin(); 737 738 return WebSecurityOrigin(m_frame->document()->securityOrigin()); 739 } 740 741 void WebFrameImpl::grantUniversalAccess() 742 { 743 ASSERT(m_frame && m_frame->document()); 744 if (m_frame && m_frame->document()) 745 m_frame->document()->securityOrigin()->grantUniversalAccess(); 746 } 747 748 NPObject* WebFrameImpl::windowObject() const 749 { 750 if (!m_frame) 751 return 0; 752 753 return m_frame->script()->windowScriptNPObject(); 754 } 755 756 void WebFrameImpl::bindToWindowObject(const WebString& name, NPObject* object) 757 { 758 ASSERT(m_frame); 759 if (!m_frame || !m_frame->script()->canExecuteScripts(NotAboutToExecuteScript)) 760 return; 761 762 String key = name; 763 #if USE(V8) 764 m_frame->script()->bindToWindowObject(m_frame, key, object); 765 #else 766 notImplemented(); 767 #endif 768 } 769 770 void WebFrameImpl::executeScript(const WebScriptSource& source) 771 { 772 TextPosition1 position(WTF::OneBasedNumber::fromOneBasedInt(source.startLine), WTF::OneBasedNumber::base()); 773 m_frame->script()->executeScript( 774 ScriptSourceCode(source.code, source.url, position)); 775 } 776 777 void WebFrameImpl::executeScriptInIsolatedWorld( 778 int worldId, const WebScriptSource* sourcesIn, unsigned numSources, 779 int extensionGroup) 780 { 781 Vector<ScriptSourceCode> sources; 782 783 for (unsigned i = 0; i < numSources; ++i) { 784 TextPosition1 position(WTF::OneBasedNumber::fromOneBasedInt(sourcesIn[i].startLine), WTF::OneBasedNumber::base()); 785 sources.append(ScriptSourceCode( 786 sourcesIn[i].code, sourcesIn[i].url, position)); 787 } 788 789 m_frame->script()->evaluateInIsolatedWorld(worldId, sources, extensionGroup); 790 } 791 792 void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message) 793 { 794 ASSERT(frame()); 795 796 MessageLevel webCoreMessageLevel; 797 switch (message.level) { 798 case WebConsoleMessage::LevelTip: 799 webCoreMessageLevel = TipMessageLevel; 800 break; 801 case WebConsoleMessage::LevelLog: 802 webCoreMessageLevel = LogMessageLevel; 803 break; 804 case WebConsoleMessage::LevelWarning: 805 webCoreMessageLevel = WarningMessageLevel; 806 break; 807 case WebConsoleMessage::LevelError: 808 webCoreMessageLevel = ErrorMessageLevel; 809 break; 810 default: 811 ASSERT_NOT_REACHED(); 812 return; 813 } 814 815 frame()->domWindow()->console()->addMessage( 816 OtherMessageSource, LogMessageType, webCoreMessageLevel, message.text, 817 1, String()); 818 } 819 820 void WebFrameImpl::collectGarbage() 821 { 822 if (!m_frame) 823 return; 824 if (!m_frame->settings()->isJavaScriptEnabled()) 825 return; 826 // FIXME: Move this to the ScriptController and make it JS neutral. 827 #if USE(V8) 828 m_frame->script()->collectGarbage(); 829 #else 830 notImplemented(); 831 #endif 832 } 833 834 #if USE(V8) 835 v8::Handle<v8::Value> WebFrameImpl::executeScriptAndReturnValue( 836 const WebScriptSource& source) 837 { 838 TextPosition1 position(WTF::OneBasedNumber::fromOneBasedInt(source.startLine), WTF::OneBasedNumber::base()); 839 return m_frame->script()->executeScript( 840 ScriptSourceCode(source.code, source.url, position)).v8Value(); 841 } 842 843 // Returns the V8 context for this frame, or an empty handle if there is none. 844 v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const 845 { 846 if (!m_frame) 847 return v8::Local<v8::Context>(); 848 849 return V8Proxy::mainWorldContext(m_frame); 850 } 851 852 v8::Handle<v8::Value> WebFrameImpl::createFileSystem(WebFileSystem::Type type, 853 const WebString& name, 854 const WebString& path) 855 { 856 return toV8(DOMFileSystem::create(frame()->document(), name, AsyncFileSystemChromium::create(static_cast<AsyncFileSystem::Type>(type), path))); 857 } 858 859 v8::Handle<v8::Value> WebFrameImpl::createFileEntry(WebFileSystem::Type type, 860 const WebString& fileSystemName, 861 const WebString& fileSystemPath, 862 const WebString& filePath, 863 bool isDirectory) 864 { 865 RefPtr<DOMFileSystemBase> fileSystem = DOMFileSystem::create(frame()->document(), fileSystemName, AsyncFileSystemChromium::create(static_cast<AsyncFileSystem::Type>(type), fileSystemPath)); 866 if (isDirectory) 867 return toV8(DirectoryEntry::create(fileSystem, filePath)); 868 return toV8(FileEntry::create(fileSystem, filePath)); 869 } 870 #endif 871 872 bool WebFrameImpl::insertStyleText( 873 const WebString& css, const WebString& id) { 874 Document* document = frame()->document(); 875 if (!document) 876 return false; 877 Element* documentElement = document->documentElement(); 878 if (!documentElement) 879 return false; 880 881 ExceptionCode err = 0; 882 883 if (!id.isEmpty()) { 884 Element* oldElement = document->getElementById(id); 885 if (oldElement) { 886 Node* parent = oldElement->parentNode(); 887 if (!parent) 888 return false; 889 parent->removeChild(oldElement, err); 890 } 891 } 892 893 RefPtr<Element> stylesheet = document->createElement( 894 HTMLNames::styleTag, false); 895 if (!id.isEmpty()) 896 stylesheet->setAttribute(HTMLNames::idAttr, id); 897 stylesheet->setTextContent(css, err); 898 ASSERT(!err); 899 Node* first = documentElement->firstChild(); 900 bool success = documentElement->insertBefore(stylesheet, first, err); 901 ASSERT(success); 902 return success; 903 } 904 905 void WebFrameImpl::reload(bool ignoreCache) 906 { 907 m_frame->loader()->history()->saveDocumentAndScrollState(); 908 m_frame->loader()->reload(ignoreCache); 909 } 910 911 void WebFrameImpl::loadRequest(const WebURLRequest& request) 912 { 913 ASSERT(!request.isNull()); 914 const ResourceRequest& resourceRequest = request.toResourceRequest(); 915 916 if (resourceRequest.url().protocolIs("javascript")) { 917 loadJavaScriptURL(resourceRequest.url()); 918 return; 919 } 920 921 m_frame->loader()->load(resourceRequest, false); 922 } 923 924 void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item) 925 { 926 RefPtr<HistoryItem> historyItem = PassRefPtr<HistoryItem>(item); 927 ASSERT(historyItem.get()); 928 929 // If there is no currentItem, which happens when we are navigating in 930 // session history after a crash, we need to manufacture one otherwise WebKit 931 // hoarks. This is probably the wrong thing to do, but it seems to work. 932 RefPtr<HistoryItem> currentItem = m_frame->loader()->history()->currentItem(); 933 if (!currentItem) { 934 currentItem = HistoryItem::create(); 935 currentItem->setLastVisitWasFailure(true); 936 m_frame->loader()->history()->setCurrentItem(currentItem.get()); 937 m_frame->page()->backForward()->setCurrentItem(currentItem.get()); 938 } 939 940 m_inSameDocumentHistoryLoad = currentItem->shouldDoSameDocumentNavigationTo(historyItem.get()); 941 m_frame->page()->goToItem(historyItem.get(), 942 FrameLoadTypeIndexedBackForward); 943 m_inSameDocumentHistoryLoad = false; 944 } 945 946 void WebFrameImpl::loadData(const WebData& data, 947 const WebString& mimeType, 948 const WebString& textEncoding, 949 const WebURL& baseURL, 950 const WebURL& unreachableURL, 951 bool replace) 952 { 953 SubstituteData substData(data, mimeType, textEncoding, unreachableURL); 954 ASSERT(substData.isValid()); 955 956 // If we are loading substitute data to replace an existing load, then 957 // inherit all of the properties of that original request. This way, 958 // reload will re-attempt the original request. It is essential that 959 // we only do this when there is an unreachableURL since a non-empty 960 // unreachableURL informs FrameLoader::reload to load unreachableURL 961 // instead of the currently loaded URL. 962 ResourceRequest request; 963 if (replace && !unreachableURL.isEmpty()) 964 request = m_frame->loader()->originalRequest(); 965 request.setURL(baseURL); 966 967 m_frame->loader()->load(request, substData, false); 968 if (replace) { 969 // Do this to force WebKit to treat the load as replacing the currently 970 // loaded page. 971 m_frame->loader()->setReplacing(); 972 } 973 } 974 975 void WebFrameImpl::loadHTMLString(const WebData& data, 976 const WebURL& baseURL, 977 const WebURL& unreachableURL, 978 bool replace) 979 { 980 loadData(data, 981 WebString::fromUTF8("text/html"), 982 WebString::fromUTF8("UTF-8"), 983 baseURL, 984 unreachableURL, 985 replace); 986 } 987 988 bool WebFrameImpl::isLoading() const 989 { 990 if (!m_frame) 991 return false; 992 return m_frame->loader()->isLoading(); 993 } 994 995 void WebFrameImpl::stopLoading() 996 { 997 if (!m_frame) 998 return; 999 1000 // FIXME: Figure out what we should really do here. It seems like a bug 1001 // that FrameLoader::stopLoading doesn't call stopAllLoaders. 1002 m_frame->loader()->stopAllLoaders(); 1003 m_frame->loader()->stopLoading(UnloadEventPolicyNone); 1004 } 1005 1006 WebDataSource* WebFrameImpl::provisionalDataSource() const 1007 { 1008 FrameLoader* frameLoader = m_frame->loader(); 1009 1010 // We regard the policy document loader as still provisional. 1011 DocumentLoader* docLoader = frameLoader->provisionalDocumentLoader(); 1012 if (!docLoader) 1013 docLoader = frameLoader->policyDocumentLoader(); 1014 1015 return DataSourceForDocLoader(docLoader); 1016 } 1017 1018 WebDataSource* WebFrameImpl::dataSource() const 1019 { 1020 return DataSourceForDocLoader(m_frame->loader()->documentLoader()); 1021 } 1022 1023 WebHistoryItem WebFrameImpl::previousHistoryItem() const 1024 { 1025 // We use the previous item here because documentState (filled-out forms) 1026 // only get saved to history when it becomes the previous item. The caller 1027 // is expected to query the history item after a navigation occurs, after 1028 // the desired history item has become the previous entry. 1029 return WebHistoryItem(m_frame->loader()->history()->previousItem()); 1030 } 1031 1032 WebHistoryItem WebFrameImpl::currentHistoryItem() const 1033 { 1034 // If we are still loading, then we don't want to clobber the current 1035 // history item as this could cause us to lose the scroll position and 1036 // document state. However, it is OK for new navigations. 1037 // FIXME: Can we make this a plain old getter, instead of worrying about 1038 // clobbering here? 1039 if (!m_inSameDocumentHistoryLoad && (m_frame->loader()->loadType() == FrameLoadTypeStandard 1040 || !m_frame->loader()->activeDocumentLoader()->isLoadingInAPISense())) 1041 m_frame->loader()->history()->saveDocumentAndScrollState(); 1042 1043 return WebHistoryItem(m_frame->page()->backForward()->currentItem()); 1044 } 1045 1046 void WebFrameImpl::enableViewSourceMode(bool enable) 1047 { 1048 if (m_frame) 1049 m_frame->setInViewSourceMode(enable); 1050 } 1051 1052 bool WebFrameImpl::isViewSourceModeEnabled() const 1053 { 1054 if (m_frame) 1055 return m_frame->inViewSourceMode(); 1056 1057 return false; 1058 } 1059 1060 void WebFrameImpl::setReferrerForRequest( 1061 WebURLRequest& request, const WebURL& referrerURL) { 1062 String referrer; 1063 if (referrerURL.isEmpty()) 1064 referrer = m_frame->loader()->outgoingReferrer(); 1065 else 1066 referrer = referrerURL.spec().utf16(); 1067 if (SecurityOrigin::shouldHideReferrer(request.url(), referrer)) 1068 return; 1069 request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer); 1070 } 1071 1072 void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request) 1073 { 1074 ResourceResponse response; 1075 m_frame->loader()->client()->dispatchWillSendRequest( 1076 0, 0, request.toMutableResourceRequest(), response); 1077 } 1078 1079 // FIXME: Remove this overload when clients have been changed to pass options. 1080 WebURLLoader* WebFrameImpl::createAssociatedURLLoader() 1081 { 1082 return new AssociatedURLLoader(this); 1083 } 1084 1085 WebURLLoader* WebFrameImpl::createAssociatedURLLoader(const WebURLLoaderOptions& options) 1086 { 1087 return new AssociatedURLLoader(this, options); 1088 } 1089 1090 void WebFrameImpl::commitDocumentData(const char* data, size_t length) 1091 { 1092 m_frame->loader()->documentLoader()->commitData(data, length); 1093 } 1094 1095 unsigned WebFrameImpl::unloadListenerCount() const 1096 { 1097 return frame()->domWindow()->pendingUnloadEventListeners(); 1098 } 1099 1100 bool WebFrameImpl::isProcessingUserGesture() const 1101 { 1102 return frame()->loader()->isProcessingUserGesture(); 1103 } 1104 1105 bool WebFrameImpl::willSuppressOpenerInNewFrame() const 1106 { 1107 return frame()->loader()->suppressOpenerInNewFrame(); 1108 } 1109 1110 void WebFrameImpl::replaceSelection(const WebString& text) 1111 { 1112 RefPtr<DocumentFragment> fragment = createFragmentFromText( 1113 frame()->selection()->toNormalizedRange().get(), text); 1114 applyCommand(ReplaceSelectionCommand::create( 1115 frame()->document(), fragment.get(), ReplaceSelectionCommand::SmartReplace | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting)); 1116 } 1117 1118 void WebFrameImpl::insertText(const WebString& text) 1119 { 1120 Editor* editor = frame()->editor(); 1121 1122 if (editor->hasComposition()) 1123 editor->confirmComposition(text); 1124 else 1125 editor->insertText(text, 0); 1126 } 1127 1128 void WebFrameImpl::setMarkedText( 1129 const WebString& text, unsigned location, unsigned length) 1130 { 1131 Editor* editor = frame()->editor(); 1132 1133 Vector<CompositionUnderline> decorations; 1134 editor->setComposition(text, decorations, location, length); 1135 } 1136 1137 void WebFrameImpl::unmarkText() 1138 { 1139 frame()->editor()->confirmCompositionWithoutDisturbingSelection(); 1140 } 1141 1142 bool WebFrameImpl::hasMarkedText() const 1143 { 1144 return frame()->editor()->hasComposition(); 1145 } 1146 1147 WebRange WebFrameImpl::markedRange() const 1148 { 1149 return frame()->editor()->compositionRange(); 1150 } 1151 1152 bool WebFrameImpl::firstRectForCharacterRange(unsigned location, unsigned length, WebRect& rect) const 1153 { 1154 if ((location + length < location) && (location + length)) 1155 length = 0; 1156 1157 Element* selectionRoot = frame()->selection()->rootEditableElement(); 1158 Element* scope = selectionRoot ? selectionRoot : frame()->document()->documentElement(); 1159 RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(scope, location, length); 1160 if (!range) 1161 return false; 1162 IntRect intRect = frame()->editor()->firstRectForRange(range.get()); 1163 rect = WebRect(intRect.x(), intRect.y(), intRect.width(), intRect.height()); 1164 1165 return true; 1166 } 1167 1168 bool WebFrameImpl::executeCommand(const WebString& name) 1169 { 1170 ASSERT(frame()); 1171 1172 if (name.length() <= 2) 1173 return false; 1174 1175 // Since we don't have NSControl, we will convert the format of command 1176 // string and call the function on Editor directly. 1177 String command = name; 1178 1179 // Make sure the first letter is upper case. 1180 command.replace(0, 1, command.substring(0, 1).upper()); 1181 1182 // Remove the trailing ':' if existing. 1183 if (command[command.length() - 1] == UChar(':')) 1184 command = command.substring(0, command.length() - 1); 1185 1186 if (command == "Copy") { 1187 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame()); 1188 if (pluginContainer) { 1189 pluginContainer->copy(); 1190 return true; 1191 } 1192 } 1193 1194 bool rv = true; 1195 1196 // Specially handling commands that Editor::execCommand does not directly 1197 // support. 1198 if (command == "DeleteToEndOfParagraph") { 1199 Editor* editor = frame()->editor(); 1200 if (!editor->deleteWithDirection(DirectionForward, 1201 ParagraphBoundary, 1202 true, 1203 false)) { 1204 editor->deleteWithDirection(DirectionForward, 1205 CharacterGranularity, 1206 true, 1207 false); 1208 } 1209 } else if (command == "Indent") 1210 frame()->editor()->indent(); 1211 else if (command == "Outdent") 1212 frame()->editor()->outdent(); 1213 else if (command == "DeleteBackward") 1214 rv = frame()->editor()->command(AtomicString("BackwardDelete")).execute(); 1215 else if (command == "DeleteForward") 1216 rv = frame()->editor()->command(AtomicString("ForwardDelete")).execute(); 1217 else if (command == "AdvanceToNextMisspelling") { 1218 // False must be passed here, or the currently selected word will never be 1219 // skipped. 1220 frame()->editor()->advanceToNextMisspelling(false); 1221 } else if (command == "ToggleSpellPanel") 1222 frame()->editor()->showSpellingGuessPanel(); 1223 else 1224 rv = frame()->editor()->command(command).execute(); 1225 return rv; 1226 } 1227 1228 bool WebFrameImpl::executeCommand(const WebString& name, const WebString& value) 1229 { 1230 ASSERT(frame()); 1231 String webName = name; 1232 1233 // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit 1234 // for editable nodes. 1235 if (!frame()->editor()->canEdit() && webName == "moveToBeginningOfDocument") 1236 return viewImpl()->propagateScroll(ScrollUp, ScrollByDocument); 1237 1238 if (!frame()->editor()->canEdit() && webName == "moveToEndOfDocument") 1239 return viewImpl()->propagateScroll(ScrollDown, ScrollByDocument); 1240 1241 return frame()->editor()->command(webName).execute(value); 1242 } 1243 1244 bool WebFrameImpl::isCommandEnabled(const WebString& name) const 1245 { 1246 ASSERT(frame()); 1247 return frame()->editor()->command(name).isEnabled(); 1248 } 1249 1250 void WebFrameImpl::enableContinuousSpellChecking(bool enable) 1251 { 1252 if (enable == isContinuousSpellCheckingEnabled()) 1253 return; 1254 // Note, the editor will will notify the client that the continuous spell 1255 // checking state has changed by calling 1256 // WebFrameClient::didToggleContinuousSpellChecking(). 1257 frame()->editor()->toggleContinuousSpellChecking(); 1258 } 1259 1260 bool WebFrameImpl::isContinuousSpellCheckingEnabled() const 1261 { 1262 return frame()->editor()->isContinuousSpellCheckingEnabled(); 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.get()) 1288 return WebString(); 1289 1290 String text = range->text(); 1291 #if OS(WINDOWS) 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.get()) 1306 return WebString(); 1307 1308 return createMarkup(range.get(), 0); 1309 } 1310 1311 void WebFrameImpl::selectWordAroundPosition(Frame* frame, VisiblePosition pos) 1312 { 1313 VisibleSelection selection(pos); 1314 selection.expandUsingGranularity(WordGranularity); 1315 1316 if (frame->selection()->shouldChangeSelection(selection)) { 1317 TextGranularity granularity = selection.isRange() ? WordGranularity : CharacterGranularity; 1318 frame->selection()->setSelection(selection, granularity); 1319 } 1320 } 1321 1322 bool WebFrameImpl::selectWordAroundCaret() 1323 { 1324 SelectionController* controller = frame()->selection(); 1325 ASSERT(!controller->isNone()); 1326 if (controller->isNone() || controller->isRange()) 1327 return false; 1328 selectWordAroundPosition(frame(), controller->selection().visibleStart()); 1329 return true; 1330 } 1331 1332 void WebFrameImpl::selectRange(const WebPoint& start, const WebPoint& end) 1333 { 1334 VisibleSelection selection(visiblePositionForWindowPoint(start), 1335 visiblePositionForWindowPoint(end)); 1336 1337 if (frame()->selection()->shouldChangeSelection(selection)) 1338 frame()->selection()->setSelection(selection, CharacterGranularity, 1339 MakeNonDirectionalSelection); 1340 } 1341 1342 VisiblePosition WebFrameImpl::visiblePositionForWindowPoint(const WebPoint& point) 1343 { 1344 HitTestRequest::HitTestRequestType hitType = HitTestRequest::MouseMove; 1345 hitType |= HitTestRequest::ReadOnly; 1346 hitType |= HitTestRequest::Active; 1347 HitTestRequest request(hitType); 1348 FrameView* view = frame()->view(); 1349 HitTestResult result(view->windowToContents( 1350 view->convertFromContainingWindow(IntPoint(point.x, point.y)))); 1351 1352 frame()->document()->renderView()->layer()->hitTest(request, result); 1353 1354 // Matching the logic in MouseEventWithHitTestResults::targetNode() 1355 Node* node = result.innerNode(); 1356 if (!node) 1357 return VisiblePosition(); 1358 Element* element = node->parentElement(); 1359 if (!node->inDocument() && element && element->inDocument()) 1360 node = element; 1361 1362 return node->renderer()->positionForPoint(result.localPoint()); 1363 } 1364 1365 int WebFrameImpl::printBegin(const WebSize& pageSize, 1366 const WebNode& constrainToNode, 1367 int printerDPI, 1368 bool* useBrowserOverlays) 1369 { 1370 ASSERT(!frame()->document()->isFrameSet()); 1371 WebPluginContainerImpl* pluginContainer = 0; 1372 if (constrainToNode.isNull()) { 1373 // If this is a plugin document, check if the plugin supports its own 1374 // printing. If it does, we will delegate all printing to that. 1375 pluginContainer = pluginContainerFromFrame(frame()); 1376 } else { 1377 // We only support printing plugin nodes for now. 1378 const Node* coreNode = constrainToNode.constUnwrap<Node>(); 1379 if (coreNode->hasTagName(HTMLNames::objectTag) || coreNode->hasTagName(HTMLNames::embedTag)) { 1380 RenderObject* object = coreNode->renderer(); 1381 if (object && object->isWidget()) { 1382 Widget* widget = toRenderWidget(object)->widget(); 1383 if (widget && widget->isPluginContainer()) 1384 pluginContainer = static_cast<WebPluginContainerImpl*>(widget); 1385 } 1386 } 1387 } 1388 1389 if (pluginContainer && pluginContainer->supportsPaginatedPrint()) 1390 m_printContext.set(new ChromePluginPrintContext(frame(), pluginContainer, printerDPI)); 1391 else 1392 m_printContext.set(new ChromePrintContext(frame())); 1393 1394 FloatRect rect(0, 0, static_cast<float>(pageSize.width), 1395 static_cast<float>(pageSize.height)); 1396 m_printContext->begin(rect.width(), rect.height()); 1397 float pageHeight; 1398 // We ignore the overlays calculation for now since they are generated in the 1399 // browser. pageHeight is actually an output parameter. 1400 m_printContext->computePageRects(rect, 0, 0, 1.0, pageHeight); 1401 if (useBrowserOverlays) 1402 *useBrowserOverlays = m_printContext->shouldUseBrowserOverlays(); 1403 1404 return m_printContext->pageCount(); 1405 } 1406 1407 float WebFrameImpl::getPrintPageShrink(int page) 1408 { 1409 // Ensure correct state. 1410 if (!m_printContext.get() || page < 0) { 1411 ASSERT_NOT_REACHED(); 1412 return 0; 1413 } 1414 1415 return m_printContext->getPageShrink(page); 1416 } 1417 1418 float WebFrameImpl::printPage(int page, WebCanvas* canvas) 1419 { 1420 // Ensure correct state. 1421 if (!m_printContext.get() || page < 0 || !frame() || !frame()->document()) { 1422 ASSERT_NOT_REACHED(); 1423 return 0; 1424 } 1425 1426 GraphicsContextBuilder builder(canvas); 1427 GraphicsContext& gc = builder.context(); 1428 #if WEBKIT_USING_SKIA 1429 gc.platformContext()->setPrinting(true); 1430 #endif 1431 1432 return m_printContext->spoolPage(gc, page); 1433 } 1434 1435 void WebFrameImpl::printEnd() 1436 { 1437 ASSERT(m_printContext.get()); 1438 if (m_printContext.get()) 1439 m_printContext->end(); 1440 m_printContext.clear(); 1441 } 1442 1443 bool WebFrameImpl::isPageBoxVisible(int pageIndex) 1444 { 1445 return frame()->document()->isPageBoxVisible(pageIndex); 1446 } 1447 1448 void WebFrameImpl::pageSizeAndMarginsInPixels(int pageIndex, 1449 WebSize& pageSize, 1450 int& marginTop, 1451 int& marginRight, 1452 int& marginBottom, 1453 int& marginLeft) 1454 { 1455 IntSize size(pageSize.width, pageSize.height); 1456 frame()->document()->pageSizeAndMarginsInPixels(pageIndex, 1457 size, 1458 marginTop, 1459 marginRight, 1460 marginBottom, 1461 marginLeft); 1462 pageSize = size; 1463 } 1464 1465 bool WebFrameImpl::find(int identifier, 1466 const WebString& searchText, 1467 const WebFindOptions& options, 1468 bool wrapWithinFrame, 1469 WebRect* selectionRect) 1470 { 1471 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 1472 1473 if (!options.findNext) 1474 frame()->page()->unmarkAllTextMatches(); 1475 else 1476 setMarkerActive(m_activeMatch.get(), false); // Active match is changing. 1477 1478 // Starts the search from the current selection. 1479 bool startInSelection = true; 1480 1481 // If the user has selected something since the last Find operation we want 1482 // to start from there. Otherwise, we start searching from where the last Find 1483 // operation left off (either a Find or a FindNext operation). 1484 VisibleSelection selection(frame()->selection()->selection()); 1485 bool activeSelection = !selection.isNone(); 1486 if (!activeSelection && m_activeMatch) { 1487 selection = VisibleSelection(m_activeMatch.get()); 1488 frame()->selection()->setSelection(selection); 1489 } 1490 1491 ASSERT(frame() && frame()->view()); 1492 bool found = frame()->editor()->findString( 1493 searchText, options.forward, options.matchCase, wrapWithinFrame, 1494 startInSelection); 1495 if (found) { 1496 // Store which frame was active. This will come in handy later when we 1497 // change the active match ordinal below. 1498 WebFrameImpl* oldActiveFrame = mainFrameImpl->m_activeMatchFrame; 1499 // Set this frame as the active frame (the one with the active highlight). 1500 mainFrameImpl->m_activeMatchFrame = this; 1501 1502 // We found something, so we can now query the selection for its position. 1503 VisibleSelection newSelection(frame()->selection()->selection()); 1504 IntRect currSelectionRect; 1505 1506 // If we thought we found something, but it couldn't be selected (perhaps 1507 // because it was marked -webkit-user-select: none), we can't set it to 1508 // be active but we still continue searching. This matches Safari's 1509 // behavior, including some oddities when selectable and un-selectable text 1510 // are mixed on a page: see https://bugs.webkit.org/show_bug.cgi?id=19127. 1511 if (newSelection.isNone() || (newSelection.start() == newSelection.end())) 1512 m_activeMatch = 0; 1513 else { 1514 m_activeMatch = newSelection.toNormalizedRange(); 1515 currSelectionRect = m_activeMatch->boundingBox(); 1516 setMarkerActive(m_activeMatch.get(), true); // Active. 1517 // WebKit draws the highlighting for all matches. 1518 executeCommand(WebString::fromUTF8("Unselect")); 1519 } 1520 1521 // Make sure no node is focused. See http://crbug.com/38700. 1522 frame()->document()->setFocusedNode(0); 1523 1524 if (!options.findNext || activeSelection) { 1525 // This is either a Find operation or a Find-next from a new start point 1526 // due to a selection, so we set the flag to ask the scoping effort 1527 // to find the active rect for us so we can update the ordinal (n of m). 1528 m_locatingActiveRect = true; 1529 } else { 1530 if (oldActiveFrame != this) { 1531 // If the active frame has changed it means that we have a multi-frame 1532 // page and we just switch to searching in a new frame. Then we just 1533 // want to reset the index. 1534 if (options.forward) 1535 m_activeMatchIndex = 0; 1536 else 1537 m_activeMatchIndex = m_lastMatchCount - 1; 1538 } else { 1539 // We are still the active frame, so increment (or decrement) the 1540 // |m_activeMatchIndex|, wrapping if needed (on single frame pages). 1541 options.forward ? ++m_activeMatchIndex : --m_activeMatchIndex; 1542 if (m_activeMatchIndex + 1 > m_lastMatchCount) 1543 m_activeMatchIndex = 0; 1544 if (m_activeMatchIndex == -1) 1545 m_activeMatchIndex = m_lastMatchCount - 1; 1546 } 1547 if (selectionRect) { 1548 *selectionRect = frameView()->contentsToWindow(currSelectionRect); 1549 reportFindInPageSelection(*selectionRect, m_activeMatchIndex + 1, identifier); 1550 } 1551 } 1552 } else { 1553 // Nothing was found in this frame. 1554 m_activeMatch = 0; 1555 1556 // Erase all previous tickmarks and highlighting. 1557 invalidateArea(InvalidateAll); 1558 } 1559 1560 return found; 1561 } 1562 1563 void WebFrameImpl::stopFinding(bool clearSelection) 1564 { 1565 if (!clearSelection) 1566 setFindEndstateFocusAndSelection(); 1567 cancelPendingScopingEffort(); 1568 1569 // Remove all markers for matches found and turn off the highlighting. 1570 frame()->document()->markers()->removeMarkers(DocumentMarker::TextMatch); 1571 frame()->editor()->setMarkedTextMatchesAreHighlighted(false); 1572 1573 // Let the frame know that we don't want tickmarks or highlighting anymore. 1574 invalidateArea(InvalidateAll); 1575 } 1576 1577 void WebFrameImpl::scopeStringMatches(int identifier, 1578 const WebString& searchText, 1579 const WebFindOptions& options, 1580 bool reset) 1581 { 1582 if (!shouldScopeMatches(searchText)) 1583 return; 1584 1585 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 1586 1587 if (reset) { 1588 // This is a brand new search, so we need to reset everything. 1589 // Scoping is just about to begin. 1590 m_scopingComplete = false; 1591 // Clear highlighting for this frame. 1592 if (frame()->editor()->markedTextMatchesAreHighlighted()) 1593 frame()->page()->unmarkAllTextMatches(); 1594 // Clear the counters from last operation. 1595 m_lastMatchCount = 0; 1596 m_nextInvalidateAfter = 0; 1597 1598 m_resumeScopingFromRange = 0; 1599 1600 mainFrameImpl->m_framesScopingCount++; 1601 1602 // Now, defer scoping until later to allow find operation to finish quickly. 1603 scopeStringMatchesSoon( 1604 identifier, 1605 searchText, 1606 options, 1607 false); // false=we just reset, so don't do it again. 1608 return; 1609 } 1610 1611 RefPtr<Range> searchRange(rangeOfContents(frame()->document())); 1612 1613 Node* originalEndContainer = searchRange->endContainer(); 1614 int originalEndOffset = searchRange->endOffset(); 1615 1616 ExceptionCode ec = 0, ec2 = 0; 1617 if (m_resumeScopingFromRange.get()) { 1618 // This is a continuation of a scoping operation that timed out and didn't 1619 // complete last time around, so we should start from where we left off. 1620 searchRange->setStart(m_resumeScopingFromRange->startContainer(), 1621 m_resumeScopingFromRange->startOffset(ec2) + 1, 1622 ec); 1623 if (ec || ec2) { 1624 if (ec2) // A non-zero |ec| happens when navigating during search. 1625 ASSERT_NOT_REACHED(); 1626 return; 1627 } 1628 } 1629 1630 // This timeout controls how long we scope before releasing control. This 1631 // value does not prevent us from running for longer than this, but it is 1632 // periodically checked to see if we have exceeded our allocated time. 1633 const double maxScopingDuration = 0.1; // seconds 1634 1635 int matchCount = 0; 1636 bool timedOut = false; 1637 double startTime = currentTime(); 1638 do { 1639 // Find next occurrence of the search string. 1640 // FIXME: (http://b/1088245) This WebKit operation may run for longer 1641 // than the timeout value, and is not interruptible as it is currently 1642 // written. We may need to rewrite it with interruptibility in mind, or 1643 // find an alternative. 1644 RefPtr<Range> resultRange(findPlainText(searchRange.get(), 1645 searchText, 1646 options.matchCase ? 0 : CaseInsensitive)); 1647 if (resultRange->collapsed(ec)) { 1648 if (!resultRange->startContainer()->isInShadowTree()) 1649 break; 1650 1651 searchRange->setStartAfter( 1652 resultRange->startContainer()->shadowAncestorNode(), ec); 1653 searchRange->setEnd(originalEndContainer, originalEndOffset, ec); 1654 continue; 1655 } 1656 1657 // Only treat the result as a match if it is visible 1658 if (frame()->editor()->insideVisibleArea(resultRange.get())) { 1659 ++matchCount; 1660 1661 // Catch a special case where Find found something but doesn't know what 1662 // the bounding box for it is. In this case we set the first match we find 1663 // as the active rect. 1664 IntRect resultBounds = resultRange->boundingBox(); 1665 IntRect activeSelectionRect; 1666 if (m_locatingActiveRect) { 1667 activeSelectionRect = m_activeMatch.get() ? 1668 m_activeMatch->boundingBox() : resultBounds; 1669 } 1670 1671 // If the Find function found a match it will have stored where the 1672 // match was found in m_activeSelectionRect on the current frame. If we 1673 // find this rect during scoping it means we have found the active 1674 // tickmark. 1675 bool foundActiveMatch = false; 1676 if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) { 1677 // We have found the active tickmark frame. 1678 mainFrameImpl->m_activeMatchFrame = this; 1679 foundActiveMatch = true; 1680 // We also know which tickmark is active now. 1681 m_activeMatchIndex = matchCount - 1; 1682 // To stop looking for the active tickmark, we set this flag. 1683 m_locatingActiveRect = false; 1684 1685 // Notify browser of new location for the selected rectangle. 1686 reportFindInPageSelection( 1687 frameView()->contentsToWindow(resultBounds), 1688 m_activeMatchIndex + 1, 1689 identifier); 1690 } 1691 1692 addMarker(resultRange.get(), foundActiveMatch); 1693 } 1694 1695 // Set the new start for the search range to be the end of the previous 1696 // result range. There is no need to use a VisiblePosition here, 1697 // since findPlainText will use a TextIterator to go over the visible 1698 // text nodes. 1699 searchRange->setStart(resultRange->endContainer(ec), resultRange->endOffset(ec), ec); 1700 1701 Node* shadowTreeRoot = searchRange->shadowTreeRootNode(); 1702 if (searchRange->collapsed(ec) && shadowTreeRoot) 1703 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec); 1704 1705 m_resumeScopingFromRange = resultRange; 1706 timedOut = (currentTime() - startTime) >= maxScopingDuration; 1707 } while (!timedOut); 1708 1709 // Remember what we search for last time, so we can skip searching if more 1710 // letters are added to the search string (and last outcome was 0). 1711 m_lastSearchString = searchText; 1712 1713 if (matchCount > 0) { 1714 frame()->editor()->setMarkedTextMatchesAreHighlighted(true); 1715 1716 m_lastMatchCount += matchCount; 1717 1718 // Let the mainframe know how much we found during this pass. 1719 mainFrameImpl->increaseMatchCount(matchCount, identifier); 1720 } 1721 1722 if (timedOut) { 1723 // If we found anything during this pass, we should redraw. However, we 1724 // don't want to spam too much if the page is extremely long, so if we 1725 // reach a certain point we start throttling the redraw requests. 1726 if (matchCount > 0) 1727 invalidateIfNecessary(); 1728 1729 // Scoping effort ran out of time, lets ask for another time-slice. 1730 scopeStringMatchesSoon( 1731 identifier, 1732 searchText, 1733 options, 1734 false); // don't reset. 1735 return; // Done for now, resume work later. 1736 } 1737 1738 // This frame has no further scoping left, so it is done. Other frames might, 1739 // of course, continue to scope matches. 1740 m_scopingComplete = true; 1741 mainFrameImpl->m_framesScopingCount--; 1742 1743 // If this is the last frame to finish scoping we need to trigger the final 1744 // update to be sent. 1745 if (!mainFrameImpl->m_framesScopingCount) 1746 mainFrameImpl->increaseMatchCount(0, identifier); 1747 1748 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet. 1749 invalidateArea(InvalidateScrollbar); 1750 } 1751 1752 void WebFrameImpl::cancelPendingScopingEffort() 1753 { 1754 deleteAllValues(m_deferredScopingWork); 1755 m_deferredScopingWork.clear(); 1756 1757 m_activeMatchIndex = -1; 1758 } 1759 1760 void WebFrameImpl::increaseMatchCount(int count, int identifier) 1761 { 1762 // This function should only be called on the mainframe. 1763 ASSERT(!parent()); 1764 1765 m_totalMatchCount += count; 1766 1767 // Update the UI with the latest findings. 1768 if (client()) 1769 client()->reportFindInPageMatchCount(identifier, m_totalMatchCount, !m_framesScopingCount); 1770 } 1771 1772 void WebFrameImpl::reportFindInPageSelection(const WebRect& selectionRect, 1773 int activeMatchOrdinal, 1774 int identifier) 1775 { 1776 // Update the UI with the latest selection rect. 1777 if (client()) 1778 client()->reportFindInPageSelection(identifier, ordinalOfFirstMatchForFrame(this) + activeMatchOrdinal, selectionRect); 1779 } 1780 1781 void WebFrameImpl::resetMatchCount() 1782 { 1783 m_totalMatchCount = 0; 1784 m_framesScopingCount = 0; 1785 } 1786 1787 WebString WebFrameImpl::contentAsText(size_t maxChars) const 1788 { 1789 if (!m_frame) 1790 return WebString(); 1791 1792 Vector<UChar> text; 1793 frameContentAsPlainText(maxChars, m_frame, &text); 1794 return String::adopt(text); 1795 } 1796 1797 WebString WebFrameImpl::contentAsMarkup() const 1798 { 1799 return createFullMarkup(m_frame->document()); 1800 } 1801 1802 WebString WebFrameImpl::renderTreeAsText(bool showDebugInfo) const 1803 { 1804 RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal; 1805 1806 if (showDebugInfo) { 1807 behavior |= RenderAsTextShowCompositedLayers 1808 | RenderAsTextShowAddresses 1809 | RenderAsTextShowIDAndClass 1810 | RenderAsTextShowLayerNesting; 1811 } 1812 1813 return externalRepresentation(m_frame, behavior); 1814 } 1815 1816 WebString WebFrameImpl::counterValueForElementById(const WebString& id) const 1817 { 1818 if (!m_frame) 1819 return WebString(); 1820 1821 Element* element = m_frame->document()->getElementById(id); 1822 if (!element) 1823 return WebString(); 1824 1825 return counterValueForElement(element); 1826 } 1827 1828 WebString WebFrameImpl::markerTextForListItem(const WebElement& webElement) const 1829 { 1830 return WebCore::markerTextForListItem(const_cast<Element*>(webElement.constUnwrap<Element>())); 1831 } 1832 1833 int WebFrameImpl::pageNumberForElementById(const WebString& id, 1834 float pageWidthInPixels, 1835 float pageHeightInPixels) const 1836 { 1837 if (!m_frame) 1838 return -1; 1839 1840 Element* element = m_frame->document()->getElementById(id); 1841 if (!element) 1842 return -1; 1843 1844 FloatSize pageSize(pageWidthInPixels, pageHeightInPixels); 1845 return PrintContext::pageNumberForElement(element, pageSize); 1846 } 1847 1848 WebRect WebFrameImpl::selectionBoundsRect() const 1849 { 1850 if (hasSelection()) 1851 return IntRect(frame()->selection()->bounds(false)); 1852 1853 return WebRect(); 1854 } 1855 1856 bool WebFrameImpl::selectionStartHasSpellingMarkerFor(int from, int length) const 1857 { 1858 if (!m_frame) 1859 return false; 1860 return m_frame->editor()->selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length); 1861 } 1862 1863 bool WebFrameImpl::pauseSVGAnimation(const WebString& animationId, double time, const WebString& elementId) 1864 { 1865 #if !ENABLE(SVG) 1866 return false; 1867 #else 1868 if (!m_frame) 1869 return false; 1870 1871 Document* document = m_frame->document(); 1872 if (!document || !document->svgExtensions()) 1873 return false; 1874 1875 Node* coreNode = document->getElementById(animationId); 1876 if (!coreNode || !SVGSMILElement::isSMILElement(coreNode)) 1877 return false; 1878 1879 return document->accessSVGExtensions()->sampleAnimationAtTime(elementId, static_cast<SVGSMILElement*>(coreNode), time); 1880 #endif 1881 } 1882 1883 WebString WebFrameImpl::layerTreeAsText(bool showDebugInfo) const 1884 { 1885 if (!m_frame) 1886 return WebString(); 1887 return WebString(m_frame->layerTreeAsText(showDebugInfo)); 1888 } 1889 1890 // WebFrameImpl public --------------------------------------------------------- 1891 1892 PassRefPtr<WebFrameImpl> WebFrameImpl::create(WebFrameClient* client) 1893 { 1894 return adoptRef(new WebFrameImpl(client)); 1895 } 1896 1897 WebFrameImpl::WebFrameImpl(WebFrameClient* client) 1898 : m_frameLoaderClient(this) 1899 , m_client(client) 1900 , m_activeMatchFrame(0) 1901 , m_activeMatchIndex(-1) 1902 , m_locatingActiveRect(false) 1903 , m_resumeScopingFromRange(0) 1904 , m_lastMatchCount(-1) 1905 , m_totalMatchCount(-1) 1906 , m_framesScopingCount(-1) 1907 , m_scopingComplete(false) 1908 , m_nextInvalidateAfter(0) 1909 , m_animationController(this) 1910 , m_identifier(generateFrameIdentifier()) 1911 , m_inSameDocumentHistoryLoad(false) 1912 { 1913 PlatformBridge::incrementStatsCounter(webFrameActiveCount); 1914 frameCount++; 1915 } 1916 1917 WebFrameImpl::~WebFrameImpl() 1918 { 1919 PlatformBridge::decrementStatsCounter(webFrameActiveCount); 1920 frameCount--; 1921 1922 cancelPendingScopingEffort(); 1923 clearPasswordListeners(); 1924 } 1925 1926 void WebFrameImpl::initializeAsMainFrame(WebViewImpl* webViewImpl) 1927 { 1928 RefPtr<Frame> frame = Frame::create(webViewImpl->page(), 0, &m_frameLoaderClient); 1929 m_frame = frame.get(); 1930 1931 // Add reference on behalf of FrameLoader. See comments in 1932 // WebFrameLoaderClient::frameLoaderDestroyed for more info. 1933 ref(); 1934 1935 // We must call init() after m_frame is assigned because it is referenced 1936 // during init(). 1937 m_frame->init(); 1938 } 1939 1940 PassRefPtr<Frame> WebFrameImpl::createChildFrame( 1941 const FrameLoadRequest& request, HTMLFrameOwnerElement* ownerElement) 1942 { 1943 RefPtr<WebFrameImpl> webframe(adoptRef(new WebFrameImpl(m_client))); 1944 1945 // Add an extra ref on behalf of the Frame/FrameLoader, which references the 1946 // WebFrame via the FrameLoaderClient interface. See the comment at the top 1947 // of this file for more info. 1948 webframe->ref(); 1949 1950 RefPtr<Frame> childFrame = Frame::create( 1951 m_frame->page(), ownerElement, &webframe->m_frameLoaderClient); 1952 webframe->m_frame = childFrame.get(); 1953 1954 childFrame->tree()->setName(request.frameName()); 1955 1956 m_frame->tree()->appendChild(childFrame); 1957 1958 // Frame::init() can trigger onload event in the parent frame, 1959 // which may detach this frame and trigger a null-pointer access 1960 // in FrameTree::removeChild. Move init() after appendChild call 1961 // so that webframe->mFrame is in the tree before triggering 1962 // onload event handler. 1963 // Because the event handler may set webframe->mFrame to null, 1964 // it is necessary to check the value after calling init() and 1965 // return without loading URL. 1966 // (b:791612) 1967 childFrame->init(); // create an empty document 1968 if (!childFrame->tree()->parent()) 1969 return 0; 1970 1971 m_frame->loader()->loadURLIntoChildFrame( 1972 request.resourceRequest().url(), 1973 request.resourceRequest().httpReferrer(), 1974 childFrame.get()); 1975 1976 // A synchronous navigation (about:blank) would have already processed 1977 // onload, so it is possible for the frame to have already been destroyed by 1978 // script in the page. 1979 if (!childFrame->tree()->parent()) 1980 return 0; 1981 1982 return childFrame.release(); 1983 } 1984 1985 void WebFrameImpl::layout() 1986 { 1987 // layout this frame 1988 FrameView* view = m_frame->view(); 1989 if (view) 1990 view->updateLayoutAndStyleIfNeededRecursive(); 1991 } 1992 1993 void WebFrameImpl::paintWithContext(GraphicsContext& gc, const WebRect& rect) 1994 { 1995 IntRect dirtyRect(rect); 1996 gc.save(); 1997 if (m_frame->document() && frameView()) { 1998 gc.clip(dirtyRect); 1999 frameView()->paint(&gc, dirtyRect); 2000 m_frame->page()->inspectorController()->drawNodeHighlight(gc); 2001 } else 2002 gc.fillRect(dirtyRect, Color::white, ColorSpaceDeviceRGB); 2003 gc.restore(); 2004 } 2005 2006 void WebFrameImpl::paint(WebCanvas* canvas, const WebRect& rect) 2007 { 2008 if (rect.isEmpty()) 2009 return; 2010 paintWithContext(GraphicsContextBuilder(canvas).context(), rect); 2011 } 2012 2013 void WebFrameImpl::createFrameView() 2014 { 2015 ASSERT(m_frame); // If m_frame doesn't exist, we probably didn't init properly. 2016 2017 Page* page = m_frame->page(); 2018 ASSERT(page); 2019 ASSERT(page->mainFrame()); 2020 2021 bool isMainFrame = m_frame == page->mainFrame(); 2022 if (isMainFrame && m_frame->view()) 2023 m_frame->view()->setParentVisible(false); 2024 2025 m_frame->setView(0); 2026 2027 WebViewImpl* webView = viewImpl(); 2028 2029 RefPtr<FrameView> view; 2030 if (isMainFrame) 2031 view = FrameView::create(m_frame, webView->size()); 2032 else 2033 view = FrameView::create(m_frame); 2034 2035 m_frame->setView(view); 2036 2037 if (webView->isTransparent()) 2038 view->setTransparent(true); 2039 2040 // FIXME: The Mac code has a comment about this possibly being unnecessary. 2041 // See installInFrame in WebCoreFrameBridge.mm 2042 if (m_frame->ownerRenderer()) 2043 m_frame->ownerRenderer()->setWidget(view.get()); 2044 2045 if (HTMLFrameOwnerElement* owner = m_frame->ownerElement()) 2046 view->setCanHaveScrollbars(owner->scrollingMode() != ScrollbarAlwaysOff); 2047 2048 if (isMainFrame) 2049 view->setParentVisible(true); 2050 } 2051 2052 WebFrameImpl* WebFrameImpl::fromFrame(Frame* frame) 2053 { 2054 if (!frame) 2055 return 0; 2056 2057 return static_cast<FrameLoaderClientImpl*>(frame->loader()->client())->webFrame(); 2058 } 2059 2060 WebFrameImpl* WebFrameImpl::fromFrameOwnerElement(Element* element) 2061 { 2062 if (!element 2063 || !element->isFrameOwnerElement() 2064 || (!element->hasTagName(HTMLNames::iframeTag) 2065 && !element->hasTagName(HTMLNames::frameTag))) 2066 return 0; 2067 2068 HTMLFrameOwnerElement* frameElement = 2069 static_cast<HTMLFrameOwnerElement*>(element); 2070 return fromFrame(frameElement->contentFrame()); 2071 } 2072 2073 WebViewImpl* WebFrameImpl::viewImpl() const 2074 { 2075 if (!m_frame) 2076 return 0; 2077 2078 return WebViewImpl::fromPage(m_frame->page()); 2079 } 2080 2081 WebDataSourceImpl* WebFrameImpl::dataSourceImpl() const 2082 { 2083 return static_cast<WebDataSourceImpl*>(dataSource()); 2084 } 2085 2086 WebDataSourceImpl* WebFrameImpl::provisionalDataSourceImpl() const 2087 { 2088 return static_cast<WebDataSourceImpl*>(provisionalDataSource()); 2089 } 2090 2091 void WebFrameImpl::setFindEndstateFocusAndSelection() 2092 { 2093 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 2094 2095 if (this == mainFrameImpl->activeMatchFrame() && m_activeMatch.get()) { 2096 // If the user has set the selection since the match was found, we 2097 // don't focus anything. 2098 VisibleSelection selection(frame()->selection()->selection()); 2099 if (!selection.isNone()) 2100 return; 2101 2102 // Try to find the first focusable node up the chain, which will, for 2103 // example, focus links if we have found text within the link. 2104 Node* node = m_activeMatch->firstNode(); 2105 while (node && !node->isFocusable() && node != frame()->document()) 2106 node = node->parentNode(); 2107 2108 if (node && node != frame()->document()) { 2109 // Found a focusable parent node. Set focus to it. 2110 frame()->document()->setFocusedNode(node); 2111 return; 2112 } 2113 2114 // Iterate over all the nodes in the range until we find a focusable node. 2115 // This, for example, sets focus to the first link if you search for 2116 // text and text that is within one or more links. 2117 node = m_activeMatch->firstNode(); 2118 while (node && node != m_activeMatch->pastLastNode()) { 2119 if (node->isFocusable()) { 2120 frame()->document()->setFocusedNode(node); 2121 return; 2122 } 2123 node = node->traverseNextNode(); 2124 } 2125 2126 // No node related to the active match was focusable, so set the 2127 // active match as the selection (so that when you end the Find session, 2128 // you'll have the last thing you found highlighted) and make sure that 2129 // we have nothing focused (otherwise you might have text selected but 2130 // a link focused, which is weird). 2131 frame()->selection()->setSelection(m_activeMatch.get()); 2132 frame()->document()->setFocusedNode(0); 2133 } 2134 } 2135 2136 void WebFrameImpl::didFail(const ResourceError& error, bool wasProvisional) 2137 { 2138 if (!client()) 2139 return; 2140 WebURLError webError = error; 2141 if (wasProvisional) 2142 client()->didFailProvisionalLoad(this, webError); 2143 else 2144 client()->didFailLoad(this, webError); 2145 } 2146 2147 void WebFrameImpl::setCanHaveScrollbars(bool canHaveScrollbars) 2148 { 2149 m_frame->view()->setCanHaveScrollbars(canHaveScrollbars); 2150 } 2151 2152 bool WebFrameImpl::registerPasswordListener( 2153 WebInputElement inputElement, 2154 WebPasswordAutocompleteListener* listener) 2155 { 2156 RefPtr<HTMLInputElement> element(inputElement.unwrap<HTMLInputElement>()); 2157 if (!m_passwordListeners.add(element, listener).second) { 2158 delete listener; 2159 return false; 2160 } 2161 return true; 2162 } 2163 2164 void WebFrameImpl::notifiyPasswordListenerOfAutocomplete( 2165 const WebInputElement& inputElement) 2166 { 2167 const HTMLInputElement* element = inputElement.constUnwrap<HTMLInputElement>(); 2168 WebPasswordAutocompleteListener* listener = getPasswordListener(element); 2169 // Password listeners need to autocomplete other fields that depend on the 2170 // input element with autofill suggestions. 2171 if (listener) 2172 listener->performInlineAutocomplete(element->value(), false, false); 2173 } 2174 2175 WebPasswordAutocompleteListener* WebFrameImpl::getPasswordListener( 2176 const HTMLInputElement* inputElement) 2177 { 2178 return m_passwordListeners.get(RefPtr<HTMLInputElement>(const_cast<HTMLInputElement*>(inputElement))); 2179 } 2180 2181 // WebFrameImpl private -------------------------------------------------------- 2182 2183 void WebFrameImpl::closing() 2184 { 2185 m_frame = 0; 2186 } 2187 2188 void WebFrameImpl::invalidateArea(AreaToInvalidate area) 2189 { 2190 ASSERT(frame() && frame()->view()); 2191 FrameView* view = frame()->view(); 2192 2193 if ((area & InvalidateAll) == InvalidateAll) 2194 view->invalidateRect(view->frameRect()); 2195 else { 2196 if ((area & InvalidateContentArea) == InvalidateContentArea) { 2197 IntRect contentArea( 2198 view->x(), view->y(), view->visibleWidth(), view->visibleHeight()); 2199 IntRect frameRect = view->frameRect(); 2200 contentArea.move(-frameRect.x(), -frameRect.y()); 2201 view->invalidateRect(contentArea); 2202 } 2203 2204 if ((area & InvalidateScrollbar) == InvalidateScrollbar) { 2205 // Invalidate the vertical scroll bar region for the view. 2206 IntRect scrollBarVert( 2207 view->x() + view->visibleWidth(), view->y(), 2208 ScrollbarTheme::nativeTheme()->scrollbarThickness(), 2209 view->visibleHeight()); 2210 IntRect frameRect = view->frameRect(); 2211 scrollBarVert.move(-frameRect.x(), -frameRect.y()); 2212 view->invalidateRect(scrollBarVert); 2213 } 2214 } 2215 } 2216 2217 void WebFrameImpl::addMarker(Range* range, bool activeMatch) 2218 { 2219 // Use a TextIterator to visit the potentially multiple nodes the range 2220 // covers. 2221 TextIterator markedText(range); 2222 for (; !markedText.atEnd(); markedText.advance()) { 2223 RefPtr<Range> textPiece = markedText.range(); 2224 int exception = 0; 2225 2226 DocumentMarker marker = { 2227 DocumentMarker::TextMatch, 2228 textPiece->startOffset(exception), 2229 textPiece->endOffset(exception), 2230 "", 2231 activeMatch 2232 }; 2233 2234 if (marker.endOffset > marker.startOffset) { 2235 // Find the node to add a marker to and add it. 2236 Node* node = textPiece->startContainer(exception); 2237 frame()->document()->markers()->addMarker(node, marker); 2238 2239 // Rendered rects for markers in WebKit are not populated until each time 2240 // the markers are painted. However, we need it to happen sooner, because 2241 // the whole purpose of tickmarks on the scrollbar is to show where 2242 // matches off-screen are (that haven't been painted yet). 2243 Vector<DocumentMarker> markers = frame()->document()->markers()->markersForNode(node); 2244 frame()->document()->markers()->setRenderedRectForMarker( 2245 textPiece->startContainer(exception), 2246 markers[markers.size() - 1], 2247 range->boundingBox()); 2248 } 2249 } 2250 } 2251 2252 void WebFrameImpl::setMarkerActive(Range* range, bool active) 2253 { 2254 WebCore::ExceptionCode ec; 2255 if (!range || range->collapsed(ec)) 2256 return; 2257 2258 frame()->document()->markers()->setMarkersActive(range, active); 2259 } 2260 2261 int WebFrameImpl::ordinalOfFirstMatchForFrame(WebFrameImpl* frame) const 2262 { 2263 int ordinal = 0; 2264 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl(); 2265 // Iterate from the main frame up to (but not including) |frame| and 2266 // add up the number of matches found so far. 2267 for (WebFrameImpl* it = mainFrameImpl; 2268 it != frame; 2269 it = static_cast<WebFrameImpl*>(it->traverseNext(true))) { 2270 if (it->m_lastMatchCount > 0) 2271 ordinal += it->m_lastMatchCount; 2272 } 2273 return ordinal; 2274 } 2275 2276 bool WebFrameImpl::shouldScopeMatches(const String& searchText) 2277 { 2278 // Don't scope if we can't find a frame or a view or if the frame is not visible. 2279 // The user may have closed the tab/application, so abort. 2280 if (!frame() || !frame()->view() || !hasVisibleContent()) 2281 return false; 2282 2283 ASSERT(frame()->document() && frame()->view()); 2284 2285 // If the frame completed the scoping operation and found 0 matches the last 2286 // time it was searched, then we don't have to search it again if the user is 2287 // just adding to the search string or sending the same search string again. 2288 if (m_scopingComplete && !m_lastSearchString.isEmpty() && !m_lastMatchCount) { 2289 // Check to see if the search string prefixes match. 2290 String previousSearchPrefix = 2291 searchText.substring(0, m_lastSearchString.length()); 2292 2293 if (previousSearchPrefix == m_lastSearchString) 2294 return false; // Don't search this frame, it will be fruitless. 2295 } 2296 2297 return true; 2298 } 2299 2300 void WebFrameImpl::scopeStringMatchesSoon(int identifier, const WebString& searchText, 2301 const WebFindOptions& options, bool reset) 2302 { 2303 m_deferredScopingWork.append(new DeferredScopeStringMatches( 2304 this, identifier, searchText, options, reset)); 2305 } 2306 2307 void WebFrameImpl::callScopeStringMatches(DeferredScopeStringMatches* caller, 2308 int identifier, const WebString& searchText, 2309 const WebFindOptions& options, bool reset) 2310 { 2311 m_deferredScopingWork.remove(m_deferredScopingWork.find(caller)); 2312 2313 scopeStringMatches(identifier, searchText, options, reset); 2314 2315 // This needs to happen last since searchText is passed by reference. 2316 delete caller; 2317 } 2318 2319 void WebFrameImpl::invalidateIfNecessary() 2320 { 2321 if (m_lastMatchCount > m_nextInvalidateAfter) { 2322 // FIXME: (http://b/1088165) Optimize the drawing of the tickmarks and 2323 // remove this. This calculation sets a milestone for when next to 2324 // invalidate the scrollbar and the content area. We do this so that we 2325 // don't spend too much time drawing the scrollbar over and over again. 2326 // Basically, up until the first 500 matches there is no throttle. 2327 // After the first 500 matches, we set set the milestone further and 2328 // further out (750, 1125, 1688, 2K, 3K). 2329 static const int startSlowingDownAfter = 500; 2330 static const int slowdown = 750; 2331 int i = (m_lastMatchCount / startSlowingDownAfter); 2332 m_nextInvalidateAfter += i * slowdown; 2333 2334 invalidateArea(InvalidateScrollbar); 2335 } 2336 } 2337 2338 void WebFrameImpl::clearPasswordListeners() 2339 { 2340 deleteAllValues(m_passwordListeners); 2341 m_passwordListeners.clear(); 2342 } 2343 2344 void WebFrameImpl::loadJavaScriptURL(const KURL& url) 2345 { 2346 // This is copied from ScriptController::executeIfJavaScriptURL. 2347 // Unfortunately, we cannot just use that method since it is private, and 2348 // it also doesn't quite behave as we require it to for bookmarklets. The 2349 // key difference is that we need to suppress loading the string result 2350 // from evaluating the JS URL if executing the JS URL resulted in a 2351 // location change. We also allow a JS URL to be loaded even if scripts on 2352 // the page are otherwise disabled. 2353 2354 if (!m_frame->document() || !m_frame->page()) 2355 return; 2356 2357 String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:"))); 2358 ScriptValue result = m_frame->script()->executeScript(script, true); 2359 2360 String scriptResult; 2361 if (!result.getString(scriptResult)) 2362 return; 2363 2364 if (!m_frame->navigationScheduler()->locationChangePending()) 2365 m_frame->document()->loader()->writer()->replaceDocument(scriptResult); 2366 } 2367 2368 } // namespace WebKit 2369