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