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