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