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