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