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