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