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