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