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