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