2 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
31 // How ownership works
32 // -------------------
34 // Big oh represents a refcounted relationship: owner O--- ownee
36 // WebView (for the toplevel frame only)
39 // Page O------- Frame (m_mainFrame) O-------O FrameView
42 // FrameLoader O-------- WebFrame (via FrameLoaderClient)
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.
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.
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.
57 // How frames are destroyed
58 // ------------------------
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.
63 // When frame content is replaced, all subframes are destroyed. This happens
64 // in FrameLoader::detachFromParent for each subframe.
66 // Frame going away causes the FrameLoader to get deleted. In FrameLoader's
67 // destructor, it notifies its client with frameLoaderDestroyed. This calls
68 // WebFrame::Closing and then derefs the WebFrame and will cause it to be
69 // deleted (unless an external someone is also holding a reference).
72 #include "WebFrameImpl.h"
74 #include "AssociatedURLLoader.h"
75 #include "AsyncFileSystem.h"
76 #include "AsyncFileSystemChromium.h"
77 #include "BackForwardController.h"
79 #include "ClipboardUtilitiesChromium.h"
81 #include "DOMFileSystem.h"
82 #include "DOMUtilitiesPrivate.h"
83 #include "DOMWindow.h"
84 #include "DOMWindowIntents.h"
85 #include "DOMWrapperWorld.h"
86 #include "DirectoryEntry.h"
88 #include "DocumentLoader.h"
89 #include "DocumentMarker.h"
90 #include "DocumentMarkerController.h"
92 #include "EventHandler.h"
93 #include "EventListenerWrapper.h"
94 #include "FileEntry.h"
95 #include "FileSystemType.h"
96 #include "FindInPageCoordinates.h"
97 #include "FocusController.h"
98 #include "FontCache.h"
99 #include "FormState.h"
100 #include "FrameLoadRequest.h"
101 #include "FrameLoader.h"
102 #include "FrameSelection.h"
103 #include "FrameTree.h"
104 #include "FrameView.h"
105 #include "HTMLCollection.h"
106 #include "HTMLFormElement.h"
107 #include "HTMLFrameOwnerElement.h"
108 #include "HTMLHeadElement.h"
109 #include "HTMLInputElement.h"
110 #include "HTMLLinkElement.h"
111 #include "HTMLNames.h"
112 #include "HistoryItem.h"
113 #include "HitTestResult.h"
115 #include "InspectorController.h"
117 #include "MessagePort.h"
119 #include "NodeTraversal.h"
121 #include "PageOverlay.h"
122 #include "Performance.h"
123 #include "PlatformMessagePortChannel.h"
124 #include "PluginDocument.h"
125 #include "PrintContext.h"
126 #include "RenderBox.h"
127 #include "RenderFrame.h"
128 #include "RenderLayer.h"
129 #include "RenderObject.h"
130 #include "RenderTreeAsText.h"
131 #include "RenderView.h"
132 #include "ResourceHandle.h"
133 #include "ResourceRequest.h"
134 #include "SchemeRegistry.h"
135 #include "ScriptCallStack.h"
136 #include "ScriptController.h"
137 #include "ScriptSourceCode.h"
138 #include "ScriptValue.h"
139 #include "ScrollTypes.h"
140 #include "ScrollbarTheme.h"
141 #include "SecurityPolicy.h"
142 #include "Settings.h"
143 #include "ShadowRoot.h"
144 #include "SkiaUtils.h"
145 #include "SpellChecker.h"
146 #include "StyleInheritedData.h"
147 #include "SubstituteData.h"
148 #include "TextAffinity.h"
149 #include "TextIterator.h"
150 #include "TraceEvent.h"
151 #include "UserGestureIndicator.h"
152 #include "V8DOMFileSystem.h"
153 #include "V8DirectoryEntry.h"
154 #include "V8FileEntry.h"
155 #include "V8GCController.h"
156 #include "WebAnimationControllerImpl.h"
157 #include "WebConsoleMessage.h"
158 #include "WebDOMEvent.h"
159 #include "WebDOMEventListener.h"
160 #include "WebDataSourceImpl.h"
161 #include "WebDeliveredIntentClient.h"
162 #include "WebDevToolsAgentPrivate.h"
163 #include "WebDocument.h"
164 #include "WebFindOptions.h"
165 #include "WebFormElement.h"
166 #include "WebFrameClient.h"
167 #include "WebHistoryItem.h"
168 #include "WebIconURL.h"
169 #include "WebInputElement.h"
170 #include "WebIntent.h"
172 #include "WebPerformance.h"
173 #include "WebPlugin.h"
174 #include "WebPluginContainerImpl.h"
175 #include "WebPrintParams.h"
176 #include "WebRange.h"
177 #include "WebScriptSource.h"
178 #include "WebSecurityOrigin.h"
179 #include "WebSerializedScriptValue.h"
180 #include "WebViewImpl.h"
181 #include "XPathResult.h"
182 #include "htmlediting.h"
184 #include "painting/GraphicsContextBuilder.h"
186 #include <public/Platform.h>
187 #include <public/WebFileSystem.h>
188 #include <public/WebFloatPoint.h>
189 #include <public/WebFloatRect.h>
190 #include <public/WebPoint.h>
191 #include <public/WebRect.h>
192 #include <public/WebSize.h>
193 #include <public/WebURLError.h>
194 #include <public/WebVector.h>
195 #include <wtf/CurrentTime.h>
196 #include <wtf/HashMap.h>
198 #if ENABLE(WEB_INTENTS)
199 #include "DeliveredIntent.h"
200 #include "DeliveredIntentClientImpl.h"
203 using namespace WebCore;
207 static int frameCount = 0;
209 // Key for a StatsCounter tracking how many WebFrames are active.
210 static const char* const webFrameActiveCount = "WebFrameActiveCount";
212 // Backend for contentAsPlainText, this is a recursive function that gets
213 // the text for the current frame and all of its subframes. It will append
214 // the text of each frame in turn to the |output| up to |maxChars| length.
216 // The |frame| must be non-null.
218 // FIXME: We should use StringBuilder rather than Vector<UChar>.
219 static void frameContentAsPlainText(size_t maxChars, Frame* frame, Vector<UChar>* output)
221 Document* document = frame->document();
228 // TextIterator iterates over the visual representation of the DOM. As such,
229 // it requires you to do a layout before using it (otherwise it'll crash).
230 if (frame->view()->needsLayout())
231 frame->view()->layout();
233 // Select the document body.
234 RefPtr<Range> range(document->createRange());
235 ExceptionCode exception = 0;
236 range->selectNodeContents(document->body(), exception);
239 // The text iterator will walk nodes giving us text. This is similar to
240 // the plainText() function in TextIterator.h, but we implement the maximum
241 // size and also copy the results directly into a wstring, avoiding the
242 // string conversion.
243 for (TextIterator it(range.get()); !it.atEnd(); it.advance()) {
244 const UChar* chars = it.characters();
247 // It appears from crash reports that an iterator can get into a state
248 // where the character count is nonempty but the character pointer is
249 // null. advance()ing it will then just add that many to the null
250 // pointer which won't be caught in a null check but will crash.
252 // A null pointer and 0 length is common for some nodes.
254 // IF YOU CATCH THIS IN A DEBUGGER please let brettw know. We don't
255 // currently understand the conditions for this to occur. Ideally, the
256 // iterators would never get into the condition so we should fix them
258 ASSERT_NOT_REACHED();
262 // Just got a null node, we can forge ahead!
266 std::min(static_cast<size_t>(it.length()), maxChars - output->size());
267 output->append(chars, toAppend);
268 if (output->size() >= maxChars)
269 return; // Filled up the buffer.
273 // The separator between frames when the frames are converted to plain text.
274 const UChar frameSeparator[] = { '\n', '\n' };
275 const size_t frameSeparatorLen = 2;
277 // Recursively walk the children.
278 FrameTree* frameTree = frame->tree();
279 for (Frame* curChild = frameTree->firstChild(); curChild; curChild = curChild->tree()->nextSibling()) {
280 // Ignore the text of non-visible frames.
281 RenderView* contentRenderer = curChild->contentRenderer();
282 RenderPart* ownerRenderer = curChild->ownerRenderer();
283 if (!contentRenderer || !contentRenderer->width() || !contentRenderer->height()
284 || (contentRenderer->x() + contentRenderer->width() <= 0) || (contentRenderer->y() + contentRenderer->height() <= 0)
285 || (ownerRenderer && ownerRenderer->style() && ownerRenderer->style()->visibility() != VISIBLE)) {
289 // Make sure the frame separator won't fill up the buffer, and give up if
290 // it will. The danger is if the separator will make the buffer longer than
291 // maxChars. This will cause the computation above:
292 // maxChars - output->size()
293 // to be a negative number which will crash when the subframe is added.
294 if (output->size() >= maxChars - frameSeparatorLen)
297 output->append(frameSeparator, frameSeparatorLen);
298 frameContentAsPlainText(maxChars, curChild, output);
299 if (output->size() >= maxChars)
300 return; // Filled up the buffer.
304 static long long generateFrameIdentifier()
306 static long long next = 0;
310 WebPluginContainerImpl* WebFrameImpl::pluginContainerFromFrame(Frame* frame)
314 if (!frame->document() || !frame->document()->isPluginDocument())
316 PluginDocument* pluginDocument = static_cast<PluginDocument*>(frame->document());
317 return static_cast<WebPluginContainerImpl *>(pluginDocument->pluginWidget());
320 // Simple class to override some of PrintContext behavior. Some of the methods
321 // made virtual so that they can be overridden by ChromePluginPrintContext.
322 class ChromePrintContext : public PrintContext {
323 WTF_MAKE_NONCOPYABLE(ChromePrintContext);
325 ChromePrintContext(Frame* frame)
326 : PrintContext(frame)
327 , m_printedPageWidth(0)
331 virtual ~ChromePrintContext() { }
333 virtual void begin(float width, float height)
335 ASSERT(!m_printedPageWidth);
336 m_printedPageWidth = width;
337 PrintContext::begin(m_printedPageWidth, height);
345 virtual float getPageShrink(int pageNumber) const
347 IntRect pageRect = m_pageRects[pageNumber];
348 return m_printedPageWidth / pageRect.width();
351 // Spools the printed page, a subrect of frame(). Skip the scale step.
352 // NativeTheme doesn't play well with scaling. Scaling is done browser side
353 // instead. Returns the scale to be applied.
354 // On Linux, we don't have the problem with NativeTheme, hence we let WebKit
355 // do the scaling and ignore the return value.
356 virtual float spoolPage(GraphicsContext& context, int pageNumber)
358 IntRect pageRect = m_pageRects[pageNumber];
359 float scale = m_printedPageWidth / pageRect.width();
362 #if OS(UNIX) && !OS(DARWIN)
363 context.scale(WebCore::FloatSize(scale, scale));
365 context.translate(static_cast<float>(-pageRect.x()), static_cast<float>(-pageRect.y()));
366 context.clip(pageRect);
367 frame()->view()->paintContents(&context, pageRect);
372 void spoolAllPagesWithBoundaries(GraphicsContext& graphicsContext, const FloatSize& pageSizeInPixels)
374 if (!frame()->document() || !frame()->view() || !frame()->document()->renderer())
377 frame()->document()->updateLayout();
380 computePageRects(FloatRect(FloatPoint(0, 0), pageSizeInPixels), 0, 0, 1, pageHeight);
382 const float pageWidth = pageSizeInPixels.width();
383 size_t numPages = pageRects().size();
384 int totalHeight = numPages * (pageSizeInPixels.height() + 1) - 1;
386 // Fill the whole background by white.
387 graphicsContext.setFillColor(Color(255, 255, 255), ColorSpaceDeviceRGB);
388 graphicsContext.fillRect(FloatRect(0, 0, pageWidth, totalHeight));
390 graphicsContext.save();
392 int currentHeight = 0;
393 for (size_t pageIndex = 0; pageIndex < numPages; pageIndex++) {
394 // Draw a line for a page boundary if this isn't the first page.
396 graphicsContext.save();
397 graphicsContext.setStrokeColor(Color(0, 0, 255), ColorSpaceDeviceRGB);
398 graphicsContext.setFillColor(Color(0, 0, 255), ColorSpaceDeviceRGB);
399 graphicsContext.drawLine(IntPoint(0, currentHeight), IntPoint(pageWidth, currentHeight));
400 graphicsContext.restore();
403 graphicsContext.save();
405 graphicsContext.translate(0, currentHeight);
406 #if !OS(UNIX) || OS(DARWIN)
407 // Account for the disabling of scaling in spoolPage. In the context
408 // of spoolAllPagesWithBoundaries the scale HAS NOT been pre-applied.
409 float scale = getPageShrink(pageIndex);
410 graphicsContext.scale(WebCore::FloatSize(scale, scale));
412 spoolPage(graphicsContext, pageIndex);
413 graphicsContext.restore();
415 currentHeight += pageSizeInPixels.height() + 1;
418 graphicsContext.restore();
421 virtual void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight)
423 PrintContext::computePageRects(printRect, headerHeight, footerHeight, userScaleFactor, outPageHeight);
426 virtual int pageCount() const
428 return PrintContext::pageCount();
431 virtual bool shouldUseBrowserOverlays() const
437 // Set when printing.
438 float m_printedPageWidth;
441 // Simple class to override some of PrintContext behavior. This is used when
442 // the frame hosts a plugin that supports custom printing. In this case, we
443 // want to delegate all printing related calls to the plugin.
444 class ChromePluginPrintContext : public ChromePrintContext {
446 ChromePluginPrintContext(Frame* frame, WebPluginContainerImpl* plugin, const WebPrintParams& printParams)
447 : ChromePrintContext(frame), m_plugin(plugin), m_pageCount(0), m_printParams(printParams)
451 virtual ~ChromePluginPrintContext() { }
453 virtual void begin(float width, float height)
459 m_plugin->printEnd();
462 virtual float getPageShrink(int pageNumber) const
464 // We don't shrink the page (maybe we should ask the widget ??)
468 virtual void computePageRects(const FloatRect& printRect, float headerHeight, float footerHeight, float userScaleFactor, float& outPageHeight)
470 m_printParams.printContentArea = IntRect(printRect);
471 m_pageCount = m_plugin->printBegin(m_printParams);
474 virtual int pageCount() const
479 // Spools the printed page, a subrect of frame(). Skip the scale step.
480 // NativeTheme doesn't play well with scaling. Scaling is done browser side
481 // instead. Returns the scale to be applied.
482 virtual float spoolPage(GraphicsContext& context, int pageNumber)
484 m_plugin->printPage(pageNumber, &context);
488 virtual bool shouldUseBrowserOverlays() const
494 // Set when printing.
495 WebPluginContainerImpl* m_plugin;
497 WebPrintParams m_printParams;
501 static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader)
503 return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : 0;
506 WebFrameImpl::FindMatch::FindMatch(PassRefPtr<Range> range, int ordinal)
512 class WebFrameImpl::DeferredScopeStringMatches {
514 DeferredScopeStringMatches(WebFrameImpl* webFrame, int identifier, const WebString& searchText, const WebFindOptions& options, bool reset)
515 : m_timer(this, &DeferredScopeStringMatches::doTimeout)
516 , m_webFrame(webFrame)
517 , m_identifier(identifier)
518 , m_searchText(searchText)
522 m_timer.startOneShot(0.0);
526 void doTimeout(Timer<DeferredScopeStringMatches>*)
528 m_webFrame->callScopeStringMatches(this, m_identifier, m_searchText, m_options, m_reset);
531 Timer<DeferredScopeStringMatches> m_timer;
532 RefPtr<WebFrameImpl> m_webFrame;
534 WebString m_searchText;
535 WebFindOptions m_options;
539 // WebFrame -------------------------------------------------------------------
541 int WebFrame::instanceCount()
546 WebFrame* WebFrame::frameForCurrentContext()
548 v8::Handle<v8::Context> context = v8::Context::GetCurrent();
549 if (context.IsEmpty())
551 return frameForContext(context);
555 WebFrame* WebFrame::frameForContext(v8::Handle<v8::Context> context)
557 return WebFrameImpl::fromFrame(toFrameIfNotDetached(context));
561 WebFrame* WebFrame::fromFrameOwnerElement(const WebElement& element)
563 return WebFrameImpl::fromFrameOwnerElement(PassRefPtr<Element>(element).get());
566 WebString WebFrameImpl::uniqueName() const
568 return frame()->tree()->uniqueName();
571 WebString WebFrameImpl::assignedName() const
573 return frame()->tree()->name();
576 void WebFrameImpl::setName(const WebString& name)
578 frame()->tree()->setName(name);
581 long long WebFrameImpl::identifier() const
586 WebVector<WebIconURL> WebFrameImpl::iconURLs(int iconTypes) const
588 // The URL to the icon may be in the header. As such, only
589 // ask the loader for the icon if it's finished loading.
590 if (frame()->loader()->state() == FrameStateComplete)
591 return frame()->loader()->icon()->urlsForTypes(iconTypes);
592 return WebVector<WebIconURL>();
595 WebSize WebFrameImpl::scrollOffset() const
597 FrameView* view = frameView();
600 return view->scrollOffset();
603 WebSize WebFrameImpl::minimumScrollOffset() const
605 FrameView* view = frameView();
608 return toIntSize(view->minimumScrollPosition());
611 WebSize WebFrameImpl::maximumScrollOffset() const
613 FrameView* view = frameView();
616 return toIntSize(view->maximumScrollPosition());
619 void WebFrameImpl::setScrollOffset(const WebSize& offset)
621 if (FrameView* view = frameView())
622 view->setScrollOffset(IntPoint(offset.width, offset.height));
625 WebSize WebFrameImpl::contentsSize() const
627 return frame()->view()->contentsSize();
630 int WebFrameImpl::contentsPreferredWidth() const
632 if (frame()->document() && frame()->document()->renderView()) {
633 FontCachePurgePreventer fontCachePurgePreventer;
634 return frame()->document()->renderView()->minPreferredLogicalWidth();
639 int WebFrameImpl::documentElementScrollHeight() const
641 if (frame()->document() && frame()->document()->documentElement())
642 return frame()->document()->documentElement()->scrollHeight();
646 bool WebFrameImpl::hasVisibleContent() const
648 return frame()->view()->visibleWidth() > 0 && frame()->view()->visibleHeight() > 0;
651 WebRect WebFrameImpl::visibleContentRect() const
653 return frame()->view()->visibleContentRect();
656 bool WebFrameImpl::hasHorizontalScrollbar() const
658 return frame() && frame()->view() && frame()->view()->horizontalScrollbar();
661 bool WebFrameImpl::hasVerticalScrollbar() const
663 return frame() && frame()->view() && frame()->view()->verticalScrollbar();
666 WebView* WebFrameImpl::view() const
671 WebFrame* WebFrameImpl::opener() const
675 return fromFrame(frame()->loader()->opener());
678 void WebFrameImpl::setOpener(const WebFrame* webFrame)
680 frame()->loader()->setOpener(webFrame ? static_cast<const WebFrameImpl*>(webFrame)->frame() : 0);
683 WebFrame* WebFrameImpl::parent() const
687 return fromFrame(frame()->tree()->parent());
690 WebFrame* WebFrameImpl::top() const
694 return fromFrame(frame()->tree()->top());
697 WebFrame* WebFrameImpl::firstChild() const
701 return fromFrame(frame()->tree()->firstChild());
704 WebFrame* WebFrameImpl::lastChild() const
708 return fromFrame(frame()->tree()->lastChild());
711 WebFrame* WebFrameImpl::nextSibling() const
715 return fromFrame(frame()->tree()->nextSibling());
718 WebFrame* WebFrameImpl::previousSibling() const
722 return fromFrame(frame()->tree()->previousSibling());
725 WebFrame* WebFrameImpl::traverseNext(bool wrap) const
729 return fromFrame(frame()->tree()->traverseNextWithWrap(wrap));
732 WebFrame* WebFrameImpl::traversePrevious(bool wrap) const
736 return fromFrame(frame()->tree()->traversePreviousWithWrap(wrap));
739 WebFrame* WebFrameImpl::findChildByName(const WebString& name) const
743 return fromFrame(frame()->tree()->child(name));
746 WebFrame* WebFrameImpl::findChildByExpression(const WebString& xpath) const
751 Document* document = frame()->document();
753 ExceptionCode ec = 0;
754 RefPtr<XPathResult> xpathResult = document->evaluate(xpath, document, 0, XPathResult::ORDERED_NODE_ITERATOR_TYPE, 0, ec);
758 Node* node = xpathResult->iterateNext(ec);
759 if (!node || !node->isFrameOwnerElement())
761 HTMLFrameOwnerElement* frameElement = static_cast<HTMLFrameOwnerElement*>(node);
762 return fromFrame(frameElement->contentFrame());
765 WebDocument WebFrameImpl::document() const
767 if (!frame() || !frame()->document())
768 return WebDocument();
769 return WebDocument(frame()->document());
772 WebAnimationController* WebFrameImpl::animationController()
774 return &m_animationController;
777 WebPerformance WebFrameImpl::performance() const
780 return WebPerformance();
781 return WebPerformance(frame()->document()->domWindow()->performance());
784 NPObject* WebFrameImpl::windowObject() const
788 return frame()->script()->windowScriptNPObject();
791 void WebFrameImpl::bindToWindowObject(const WebString& name, NPObject* object)
793 if (!frame() || !frame()->script()->canExecuteScripts(NotAboutToExecuteScript))
795 frame()->script()->bindToWindowObject(frame(), String(name), object);
798 void WebFrameImpl::executeScript(const WebScriptSource& source)
801 TextPosition position(OrdinalNumber::fromOneBasedInt(source.startLine), OrdinalNumber::first());
802 frame()->script()->executeScript(ScriptSourceCode(source.code, source.url, position));
805 void WebFrameImpl::executeScriptInIsolatedWorld(int worldID, const WebScriptSource* sourcesIn, unsigned numSources, int extensionGroup)
809 Vector<ScriptSourceCode> sources;
810 for (unsigned i = 0; i < numSources; ++i) {
811 TextPosition position(OrdinalNumber::fromOneBasedInt(sourcesIn[i].startLine), OrdinalNumber::first());
812 sources.append(ScriptSourceCode(sourcesIn[i].code, sourcesIn[i].url, position));
815 frame()->script()->evaluateInIsolatedWorld(worldID, sources, extensionGroup, 0);
818 void WebFrameImpl::setIsolatedWorldSecurityOrigin(int worldID, const WebSecurityOrigin& securityOrigin)
821 DOMWrapperWorld::setIsolatedWorldSecurityOrigin(worldID, securityOrigin.get());
824 void WebFrameImpl::setIsolatedWorldContentSecurityPolicy(int worldID, const WebString& policy)
827 DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy(worldID, policy);
830 void WebFrameImpl::addMessageToConsole(const WebConsoleMessage& message)
834 MessageLevel webCoreMessageLevel;
835 switch (message.level) {
836 case WebConsoleMessage::LevelTip:
837 webCoreMessageLevel = TipMessageLevel;
839 case WebConsoleMessage::LevelLog:
840 webCoreMessageLevel = LogMessageLevel;
842 case WebConsoleMessage::LevelWarning:
843 webCoreMessageLevel = WarningMessageLevel;
845 case WebConsoleMessage::LevelError:
846 webCoreMessageLevel = ErrorMessageLevel;
848 case WebConsoleMessage::LevelDebug:
849 webCoreMessageLevel = DebugMessageLevel;
852 ASSERT_NOT_REACHED();
856 frame()->document()->addConsoleMessage(OtherMessageSource, webCoreMessageLevel, message.text);
859 void WebFrameImpl::collectGarbage()
863 if (!frame()->settings()->isScriptEnabled())
865 V8GCController::collectGarbage();
868 bool WebFrameImpl::checkIfRunInsecureContent(const WebURL& url) const
871 return frame()->loader()->mixedContentChecker()->canRunInsecureContent(frame()->document()->securityOrigin(), url);
874 v8::Handle<v8::Value> WebFrameImpl::executeScriptAndReturnValue(const WebScriptSource& source)
878 // FIXME: This fake user gesture is required to make a bunch of pyauto
879 // tests pass. If this isn't needed in non-test situations, we should
880 // consider removing this code and changing the tests.
881 // http://code.google.com/p/chromium/issues/detail?id=86397
882 UserGestureIndicator gestureIndicator(DefinitelyProcessingUserGesture);
884 TextPosition position(OrdinalNumber::fromOneBasedInt(source.startLine), OrdinalNumber::first());
885 return frame()->script()->executeScript(ScriptSourceCode(source.code, source.url, position)).v8Value();
888 void WebFrameImpl::executeScriptInIsolatedWorld(int worldID, const WebScriptSource* sourcesIn, unsigned numSources, int extensionGroup, WebVector<v8::Local<v8::Value> >* results)
892 Vector<ScriptSourceCode> sources;
894 for (unsigned i = 0; i < numSources; ++i) {
895 TextPosition position(OrdinalNumber::fromOneBasedInt(sourcesIn[i].startLine), OrdinalNumber::first());
896 sources.append(ScriptSourceCode(sourcesIn[i].code, sourcesIn[i].url, position));
900 Vector<ScriptValue> scriptResults;
901 frame()->script()->evaluateInIsolatedWorld(worldID, sources, extensionGroup, &scriptResults);
902 WebVector<v8::Local<v8::Value> > v8Results(scriptResults.size());
903 for (unsigned i = 0; i < scriptResults.size(); i++)
904 v8Results[i] = v8::Local<v8::Value>::New(scriptResults[i].v8Value());
905 results->swap(v8Results);
907 frame()->script()->evaluateInIsolatedWorld(worldID, sources, extensionGroup, 0);
910 v8::Handle<v8::Value> WebFrameImpl::callFunctionEvenIfScriptDisabled(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> argv[])
913 return frame()->script()->callFunctionEvenIfScriptDisabled(function, receiver, argc, argv).v8Value();
916 v8::Local<v8::Context> WebFrameImpl::mainWorldScriptContext() const
919 return v8::Local<v8::Context>();
920 return ScriptController::mainWorldContext(frame());
923 v8::Handle<v8::Value> WebFrameImpl::createFileSystem(WebFileSystem::Type type, const WebString& name, const WebString& path)
926 return toV8(DOMFileSystem::create(frame()->document(), name, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, path.utf8().data()), AsyncFileSystemChromium::create()), v8::Handle<v8::Object>(), frame()->script()->currentWorldContext()->GetIsolate());
929 v8::Handle<v8::Value> WebFrameImpl::createSerializableFileSystem(WebFileSystem::Type type, const WebString& name, const WebString& path)
932 RefPtr<DOMFileSystem> fileSystem = DOMFileSystem::create(frame()->document(), name, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, path.utf8().data()), AsyncFileSystemChromium::create());
933 fileSystem->makeClonable();
934 return toV8(fileSystem.release(), v8::Handle<v8::Object>(), frame()->script()->currentWorldContext()->GetIsolate());
937 v8::Handle<v8::Value> WebFrameImpl::createFileEntry(WebFileSystem::Type type, const WebString& fileSystemName, const WebString& fileSystemPath, const WebString& filePath, bool isDirectory)
941 RefPtr<DOMFileSystemBase> fileSystem = DOMFileSystem::create(frame()->document(), fileSystemName, static_cast<WebCore::FileSystemType>(type), KURL(ParsedURLString, fileSystemPath.utf8().data()), AsyncFileSystemChromium::create());
943 return toV8(DirectoryEntry::create(fileSystem, filePath), v8::Handle<v8::Object>(), frame()->script()->currentWorldContext()->GetIsolate());
944 return toV8(FileEntry::create(fileSystem, filePath), v8::Handle<v8::Object>(), frame()->script()->currentWorldContext()->GetIsolate());
947 void WebFrameImpl::reload(bool ignoreCache)
950 frame()->loader()->history()->saveDocumentAndScrollState();
951 frame()->loader()->reload(ignoreCache);
954 void WebFrameImpl::reloadWithOverrideURL(const WebURL& overrideUrl, bool ignoreCache)
957 frame()->loader()->history()->saveDocumentAndScrollState();
958 frame()->loader()->reloadWithOverrideURL(overrideUrl, ignoreCache);
961 void WebFrameImpl::loadRequest(const WebURLRequest& request)
964 ASSERT(!request.isNull());
965 const ResourceRequest& resourceRequest = request.toResourceRequest();
967 if (resourceRequest.url().protocolIs("javascript")) {
968 loadJavaScriptURL(resourceRequest.url());
972 frame()->loader()->load(FrameLoadRequest(frame(), resourceRequest));
975 void WebFrameImpl::loadHistoryItem(const WebHistoryItem& item)
978 RefPtr<HistoryItem> historyItem = PassRefPtr<HistoryItem>(item);
981 frame()->loader()->prepareForHistoryNavigation();
982 RefPtr<HistoryItem> currentItem = frame()->loader()->history()->currentItem();
983 m_inSameDocumentHistoryLoad = currentItem && currentItem->shouldDoSameDocumentNavigationTo(historyItem.get());
984 frame()->page()->goToItem(historyItem.get(), FrameLoadTypeIndexedBackForward);
985 m_inSameDocumentHistoryLoad = false;
988 void WebFrameImpl::loadData(const WebData& data, const WebString& mimeType, const WebString& textEncoding, const WebURL& baseURL, const WebURL& unreachableURL, bool replace)
992 // If we are loading substitute data to replace an existing load, then
993 // inherit all of the properties of that original request. This way,
994 // reload will re-attempt the original request. It is essential that
995 // we only do this when there is an unreachableURL since a non-empty
996 // unreachableURL informs FrameLoader::reload to load unreachableURL
997 // instead of the currently loaded URL.
998 ResourceRequest request;
999 if (replace && !unreachableURL.isEmpty())
1000 request = frame()->loader()->originalRequest();
1001 request.setURL(baseURL);
1003 FrameLoadRequest frameRequest(frame(), request, SubstituteData(data, mimeType, textEncoding, unreachableURL));
1004 ASSERT(frameRequest.substituteData().isValid());
1005 frame()->loader()->load(frameRequest);
1007 // Do this to force WebKit to treat the load as replacing the currently
1009 frame()->loader()->setReplacing();
1013 void WebFrameImpl::loadHTMLString(const WebData& data, const WebURL& baseURL, const WebURL& unreachableURL, bool replace)
1016 loadData(data, WebString::fromUTF8("text/html"), WebString::fromUTF8("UTF-8"), baseURL, unreachableURL, replace);
1019 bool WebFrameImpl::isLoading() const
1023 return frame()->loader()->isLoading();
1026 void WebFrameImpl::stopLoading()
1030 // FIXME: Figure out what we should really do here. It seems like a bug
1031 // that FrameLoader::stopLoading doesn't call stopAllLoaders.
1032 frame()->loader()->stopAllLoaders();
1033 frame()->loader()->stopLoading(UnloadEventPolicyNone);
1036 WebDataSource* WebFrameImpl::provisionalDataSource() const
1040 // We regard the policy document loader as still provisional.
1041 DocumentLoader* documentLoader = frame()->loader()->provisionalDocumentLoader();
1042 if (!documentLoader)
1043 documentLoader = frame()->loader()->policyDocumentLoader();
1045 return DataSourceForDocLoader(documentLoader);
1048 WebDataSource* WebFrameImpl::dataSource() const
1051 return DataSourceForDocLoader(frame()->loader()->documentLoader());
1054 WebHistoryItem WebFrameImpl::previousHistoryItem() const
1057 // We use the previous item here because documentState (filled-out forms)
1058 // only get saved to history when it becomes the previous item. The caller
1059 // is expected to query the history item after a navigation occurs, after
1060 // the desired history item has become the previous entry.
1061 return WebHistoryItem(frame()->loader()->history()->previousItem());
1064 WebHistoryItem WebFrameImpl::currentHistoryItem() const
1068 // We're shutting down.
1069 if (!frame()->loader()->activeDocumentLoader())
1070 return WebHistoryItem();
1072 // If we are still loading, then we don't want to clobber the current
1073 // history item as this could cause us to lose the scroll position and
1074 // document state. However, it is OK for new navigations.
1075 // FIXME: Can we make this a plain old getter, instead of worrying about
1077 if (!m_inSameDocumentHistoryLoad && (frame()->loader()->loadType() == FrameLoadTypeStandard
1078 || !frame()->loader()->activeDocumentLoader()->isLoadingInAPISense()))
1079 frame()->loader()->history()->saveDocumentAndScrollState();
1081 return WebHistoryItem(frame()->page()->backForward()->currentItem());
1084 void WebFrameImpl::enableViewSourceMode(bool enable)
1087 frame()->setInViewSourceMode(enable);
1090 bool WebFrameImpl::isViewSourceModeEnabled() const
1094 return frame()->inViewSourceMode();
1097 void WebFrameImpl::setReferrerForRequest(WebURLRequest& request, const WebURL& referrerURL)
1099 String referrer = referrerURL.isEmpty() ? frame()->loader()->outgoingReferrer() : String(referrerURL.spec().utf16());
1100 referrer = SecurityPolicy::generateReferrerHeader(frame()->document()->referrerPolicy(), request.url(), referrer);
1101 if (referrer.isEmpty())
1103 request.setHTTPHeaderField(WebString::fromUTF8("Referer"), referrer);
1106 void WebFrameImpl::dispatchWillSendRequest(WebURLRequest& request)
1108 ResourceResponse response;
1109 frame()->loader()->client()->dispatchWillSendRequest(0, 0, request.toMutableResourceRequest(), response);
1112 WebURLLoader* WebFrameImpl::createAssociatedURLLoader(const WebURLLoaderOptions& options)
1114 return new AssociatedURLLoader(this, options);
1117 void WebFrameImpl::commitDocumentData(const char* data, size_t length)
1119 frame()->loader()->documentLoader()->commitData(data, length);
1122 unsigned WebFrameImpl::unloadListenerCount() const
1124 return frame()->document()->domWindow()->pendingUnloadEventListeners();
1127 bool WebFrameImpl::isProcessingUserGesture() const
1129 return ScriptController::processingUserGesture();
1132 bool WebFrameImpl::consumeUserGesture() const
1134 return UserGestureIndicator::consumeUserGesture();
1137 bool WebFrameImpl::willSuppressOpenerInNewFrame() const
1139 return frame()->loader()->suppressOpenerInNewFrame();
1142 void WebFrameImpl::replaceSelection(const WebString& text)
1144 bool selectReplacement = false;
1145 bool smartReplace = true;
1146 frame()->editor()->replaceSelectionWithText(text, selectReplacement, smartReplace);
1149 void WebFrameImpl::insertText(const WebString& text)
1151 if (frame()->editor()->hasComposition())
1152 frame()->editor()->confirmComposition(text);
1154 frame()->editor()->insertText(text, 0);
1157 void WebFrameImpl::setMarkedText(const WebString& text, unsigned location, unsigned length)
1159 Vector<CompositionUnderline> decorations;
1160 frame()->editor()->setComposition(text, decorations, location, length);
1163 void WebFrameImpl::unmarkText()
1165 frame()->editor()->cancelComposition();
1168 bool WebFrameImpl::hasMarkedText() const
1170 return frame()->editor()->hasComposition();
1173 WebRange WebFrameImpl::markedRange() const
1175 return frame()->editor()->compositionRange();
1178 bool WebFrameImpl::firstRectForCharacterRange(unsigned location, unsigned length, WebRect& rect) const
1180 if ((location + length < location) && (location + length))
1183 RefPtr<Range> range = TextIterator::rangeFromLocationAndLength(frame()->selection()->rootEditableElementOrDocumentElement(), location, length);
1186 IntRect intRect = frame()->editor()->firstRectForRange(range.get());
1187 rect = WebRect(intRect);
1188 rect = frame()->view()->contentsToWindow(rect);
1192 size_t WebFrameImpl::characterIndexForPoint(const WebPoint& webPoint) const
1197 IntPoint point = frame()->view()->windowToContents(webPoint);
1198 HitTestResult result = frame()->eventHandler()->hitTestResultAtPoint(point, false);
1199 RefPtr<Range> range = frame()->rangeForPoint(result.roundedPointInInnerNodeFrame());
1203 size_t location, length;
1204 TextIterator::getLocationAndLengthFromRange(frame()->selection()->rootEditableElementOrDocumentElement(), range.get(), location, length);
1208 bool WebFrameImpl::executeCommand(const WebString& name, const WebNode& node)
1212 if (name.length() <= 2)
1215 // Since we don't have NSControl, we will convert the format of command
1216 // string and call the function on Editor directly.
1217 String command = name;
1219 // Make sure the first letter is upper case.
1220 command.replace(0, 1, command.substring(0, 1).upper());
1222 // Remove the trailing ':' if existing.
1223 if (command[command.length() - 1] == UChar(':'))
1224 command = command.substring(0, command.length() - 1);
1226 if (command == "Copy") {
1227 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1228 if (!pluginContainer)
1229 pluginContainer = static_cast<WebPluginContainerImpl*>(node.pluginContainer());
1230 if (pluginContainer) {
1231 pluginContainer->copy();
1238 // Specially handling commands that Editor::execCommand does not directly
1240 if (command == "DeleteToEndOfParagraph") {
1241 if (!frame()->editor()->deleteWithDirection(DirectionForward, ParagraphBoundary, true, false))
1242 frame()->editor()->deleteWithDirection(DirectionForward, CharacterGranularity, true, false);
1243 } else if (command == "Indent")
1244 frame()->editor()->indent();
1245 else if (command == "Outdent")
1246 frame()->editor()->outdent();
1247 else if (command == "DeleteBackward")
1248 result = frame()->editor()->command(AtomicString("BackwardDelete")).execute();
1249 else if (command == "DeleteForward")
1250 result = frame()->editor()->command(AtomicString("ForwardDelete")).execute();
1251 else if (command == "AdvanceToNextMisspelling") {
1252 // Wee need to pass false here or else the currently selected word will never be skipped.
1253 frame()->editor()->advanceToNextMisspelling(false);
1254 } else if (command == "ToggleSpellPanel")
1255 frame()->editor()->showSpellingGuessPanel();
1257 result = frame()->editor()->command(command).execute();
1261 bool WebFrameImpl::executeCommand(const WebString& name, const WebString& value)
1264 String webName = name;
1266 // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit for editable nodes.
1267 if (!frame()->editor()->canEdit() && webName == "moveToBeginningOfDocument")
1268 return viewImpl()->propagateScroll(ScrollUp, ScrollByDocument);
1270 if (!frame()->editor()->canEdit() && webName == "moveToEndOfDocument")
1271 return viewImpl()->propagateScroll(ScrollDown, ScrollByDocument);
1273 return frame()->editor()->command(webName).execute(value);
1276 bool WebFrameImpl::isCommandEnabled(const WebString& name) const
1279 return frame()->editor()->command(name).isEnabled();
1282 void WebFrameImpl::enableContinuousSpellChecking(bool enable)
1284 if (enable == isContinuousSpellCheckingEnabled())
1286 frame()->editor()->toggleContinuousSpellChecking();
1289 bool WebFrameImpl::isContinuousSpellCheckingEnabled() const
1291 return frame()->editor()->isContinuousSpellCheckingEnabled();
1294 void WebFrameImpl::requestTextChecking(const WebElement& webElement)
1296 if (webElement.isNull())
1298 RefPtr<Range> rangeToCheck = rangeOfContents(const_cast<Element*>(webElement.constUnwrap<Element>()));
1299 frame()->editor()->spellChecker()->requestCheckingFor(SpellCheckRequest::create(TextCheckingTypeSpelling | TextCheckingTypeGrammar, TextCheckingProcessBatch, rangeToCheck, rangeToCheck));
1302 void WebFrameImpl::replaceMisspelledRange(const WebString& text)
1304 // 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.
1305 if (pluginContainerFromFrame(frame()))
1307 RefPtr<Range> caretRange = frame()->selection()->toNormalizedRange();
1310 Vector<DocumentMarker*> markers = frame()->document()->markers()->markersInRange(caretRange.get(), DocumentMarker::Spelling | DocumentMarker::Grammar);
1311 if (markers.size() < 1 || markers[0]->startOffset() >= markers[0]->endOffset())
1313 RefPtr<Range> markerRange = Range::create(caretRange->ownerDocument(), caretRange->startContainer(), markers[0]->startOffset(), caretRange->endContainer(), markers[0]->endOffset());
1316 if (!frame()->selection()->shouldChangeSelection(markerRange.get()))
1318 frame()->selection()->setSelection(markerRange.get(), CharacterGranularity);
1319 frame()->editor()->replaceSelectionWithText(text, false, false);
1322 bool WebFrameImpl::hasSelection() const
1324 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1325 if (pluginContainer)
1326 return pluginContainer->plugin()->hasSelection();
1328 // frame()->selection()->isNone() never returns true.
1329 return (frame()->selection()->start() != frame()->selection()->end());
1332 WebRange WebFrameImpl::selectionRange() const
1334 return frame()->selection()->toNormalizedRange();
1337 WebString WebFrameImpl::selectionAsText() const
1339 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1340 if (pluginContainer)
1341 return pluginContainer->plugin()->selectionAsText();
1343 RefPtr<Range> range = frame()->selection()->toNormalizedRange();
1347 String text = range->text();
1349 replaceNewlinesWithWindowsStyleNewlines(text);
1351 replaceNBSPWithSpace(text);
1355 WebString WebFrameImpl::selectionAsMarkup() const
1357 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1358 if (pluginContainer)
1359 return pluginContainer->plugin()->selectionAsMarkup();
1361 RefPtr<Range> range = frame()->selection()->toNormalizedRange();
1365 return createMarkup(range.get(), 0, AnnotateForInterchange, false, ResolveNonLocalURLs);
1368 void WebFrameImpl::selectWordAroundPosition(Frame* frame, VisiblePosition position)
1370 VisibleSelection selection(position);
1371 selection.expandUsingGranularity(WordGranularity);
1373 if (frame->selection()->shouldChangeSelection(selection)) {
1374 TextGranularity granularity = selection.isRange() ? WordGranularity : CharacterGranularity;
1375 frame->selection()->setSelection(selection, granularity);
1379 bool WebFrameImpl::selectWordAroundCaret()
1381 FrameSelection* selection = frame()->selection();
1382 ASSERT(!selection->isNone());
1383 if (selection->isNone() || selection->isRange())
1385 selectWordAroundPosition(frame(), selection->selection().visibleStart());
1389 void WebFrameImpl::selectRange(const WebPoint& base, const WebPoint& extent)
1391 IntPoint unscaledBase = base;
1392 IntPoint unscaledExtent = extent;
1393 if (frame()->page()->settings()->applyPageScaleFactorInCompositor()) {
1394 unscaledExtent.scale(1 / view()->pageScaleFactor(), 1 / view()->pageScaleFactor());
1395 unscaledBase.scale(1 / view()->pageScaleFactor(), 1 / view()->pageScaleFactor());
1397 VisiblePosition basePosition = visiblePositionForWindowPoint(unscaledBase);
1398 VisiblePosition extentPosition = visiblePositionForWindowPoint(unscaledExtent);
1399 VisibleSelection newSelection = VisibleSelection(basePosition, extentPosition);
1400 if (frame()->selection()->shouldChangeSelection(newSelection))
1401 frame()->selection()->setSelection(newSelection, CharacterGranularity);
1404 void WebFrameImpl::selectRange(const WebRange& webRange)
1406 if (RefPtr<Range> range = static_cast<PassRefPtr<Range> >(webRange))
1407 frame()->selection()->setSelectedRange(range.get(), WebCore::VP_DEFAULT_AFFINITY, false);
1410 void WebFrameImpl::moveCaretSelectionTowardsWindowPoint(const WebPoint& point)
1412 IntPoint unscaledPoint(point);
1413 if (frame()->page()->settings()->applyPageScaleFactorInCompositor())
1414 unscaledPoint.scale(1 / view()->pageScaleFactor(), 1 / view()->pageScaleFactor());
1416 Element* editable = frame()->selection()->rootEditableElement();
1420 IntPoint contentsPoint = frame()->view()->windowToContents(unscaledPoint);
1421 LayoutPoint localPoint(editable->convertFromPage(contentsPoint));
1422 VisiblePosition position = editable->renderer()->positionForPoint(localPoint);
1423 if (frame()->selection()->shouldChangeSelection(position))
1424 frame()->selection()->moveTo(position, UserTriggered);
1427 VisiblePosition WebFrameImpl::visiblePositionForWindowPoint(const WebPoint& point)
1429 HitTestRequest request = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping;
1430 HitTestResult result(frame()->view()->windowToContents(IntPoint(point)));
1432 frame()->document()->renderView()->layer()->hitTest(request, result);
1434 Node* node = result.targetNode();
1436 return VisiblePosition();
1437 return node->renderer()->positionForPoint(result.localPoint());
1440 int WebFrameImpl::printBegin(const WebPrintParams& printParams, const WebNode& constrainToNode, bool* useBrowserOverlays)
1442 ASSERT(!frame()->document()->isFrameSet());
1443 WebPluginContainerImpl* pluginContainer = 0;
1444 if (constrainToNode.isNull()) {
1445 // If this is a plugin document, check if the plugin supports its own
1446 // printing. If it does, we will delegate all printing to that.
1447 pluginContainer = pluginContainerFromFrame(frame());
1449 // We only support printing plugin nodes for now.
1450 pluginContainer = static_cast<WebPluginContainerImpl*>(constrainToNode.pluginContainer());
1453 if (pluginContainer && pluginContainer->supportsPaginatedPrint())
1454 m_printContext = adoptPtr(new ChromePluginPrintContext(frame(), pluginContainer, printParams));
1456 m_printContext = adoptPtr(new ChromePrintContext(frame()));
1458 FloatRect rect(0, 0, static_cast<float>(printParams.printContentArea.width), static_cast<float>(printParams.printContentArea.height));
1459 m_printContext->begin(rect.width(), rect.height());
1461 // We ignore the overlays calculation for now since they are generated in the
1462 // browser. pageHeight is actually an output parameter.
1463 m_printContext->computePageRects(rect, 0, 0, 1.0, pageHeight);
1464 if (useBrowserOverlays)
1465 *useBrowserOverlays = m_printContext->shouldUseBrowserOverlays();
1467 return m_printContext->pageCount();
1470 float WebFrameImpl::getPrintPageShrink(int page)
1472 ASSERT(m_printContext && page >= 0);
1473 return m_printContext->getPageShrink(page);
1476 float WebFrameImpl::printPage(int page, WebCanvas* canvas)
1478 #if ENABLE(PRINTING)
1479 ASSERT(m_printContext && page >= 0 && frame() && frame()->document());
1481 GraphicsContextBuilder builder(canvas);
1482 GraphicsContext& graphicsContext = builder.context();
1483 graphicsContext.platformContext()->setPrinting(true);
1484 return m_printContext->spoolPage(graphicsContext, page);
1490 void WebFrameImpl::printEnd()
1492 ASSERT(m_printContext);
1493 m_printContext->end();
1494 m_printContext.clear();
1497 bool WebFrameImpl::isPrintScalingDisabledForPlugin(const WebNode& node)
1499 WebPluginContainerImpl* pluginContainer = node.isNull() ? pluginContainerFromFrame(frame()) : static_cast<WebPluginContainerImpl*>(node.pluginContainer());
1501 if (!pluginContainer || !pluginContainer->supportsPaginatedPrint())
1504 return pluginContainer->isPrintScalingDisabled();
1507 bool WebFrameImpl::hasCustomPageSizeStyle(int pageIndex)
1509 return frame()->document()->styleForPage(pageIndex)->pageSizeType() != PAGE_SIZE_AUTO;
1512 bool WebFrameImpl::isPageBoxVisible(int pageIndex)
1514 return frame()->document()->isPageBoxVisible(pageIndex);
1517 void WebFrameImpl::pageSizeAndMarginsInPixels(int pageIndex, WebSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
1519 IntSize size = pageSize;
1520 frame()->document()->pageSizeAndMarginsInPixels(pageIndex, size, marginTop, marginRight, marginBottom, marginLeft);
1524 WebString WebFrameImpl::pageProperty(const WebString& propertyName, int pageIndex)
1526 ASSERT(m_printContext);
1527 return m_printContext->pageProperty(frame(), propertyName.utf8().data(), pageIndex);
1530 bool WebFrameImpl::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, WebRect* selectionRect)
1532 if (!frame() || !frame()->page())
1535 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1537 if (!options.findNext)
1538 frame()->page()->unmarkAllTextMatches();
1540 setMarkerActive(m_activeMatch.get(), false);
1542 if (m_activeMatch && m_activeMatch->ownerDocument() != frame()->document())
1545 // If the user has selected something since the last Find operation we want
1546 // to start from there. Otherwise, we start searching from where the last Find
1547 // operation left off (either a Find or a FindNext operation).
1548 VisibleSelection selection(frame()->selection()->selection());
1549 bool activeSelection = !selection.isNone();
1550 if (activeSelection) {
1551 m_activeMatch = selection.firstRange().get();
1552 frame()->selection()->clear();
1555 ASSERT(frame() && frame()->view());
1556 const FindOptions findOptions = (options.forward ? 0 : Backwards)
1557 | (options.matchCase ? 0 : CaseInsensitive)
1558 | (wrapWithinFrame ? WrapAround : 0)
1559 | (!options.findNext ? StartInSelection : 0);
1560 m_activeMatch = frame()->editor()->findStringAndScrollToVisible(searchText, m_activeMatch.get(), findOptions);
1562 if (!m_activeMatch) {
1563 // If we're finding next the next active match might not be in the current frame.
1564 // In this case we don't want to clear the matches cache.
1565 if (!options.findNext)
1566 clearFindMatchesCache();
1567 invalidateArea(InvalidateAll);
1572 viewImpl()->zoomToFindInPageRect(frameView()->contentsToWindow(enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get()))));
1575 setMarkerActive(m_activeMatch.get(), true);
1576 WebFrameImpl* oldActiveFrame = mainFrameImpl->m_currentActiveMatchFrame;
1577 mainFrameImpl->m_currentActiveMatchFrame = this;
1579 // Make sure no node is focused. See http://crbug.com/38700.
1580 frame()->document()->setFocusedNode(0);
1582 if (!options.findNext || activeSelection) {
1583 // This is either a Find operation or a Find-next from a new start point
1584 // due to a selection, so we set the flag to ask the scoping effort
1585 // to find the active rect for us and report it back to the UI.
1586 m_locatingActiveRect = true;
1588 if (oldActiveFrame != this) {
1589 if (options.forward)
1590 m_activeMatchIndexInCurrentFrame = 0;
1592 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1;
1594 if (options.forward)
1595 ++m_activeMatchIndexInCurrentFrame;
1597 --m_activeMatchIndexInCurrentFrame;
1599 if (m_activeMatchIndexInCurrentFrame + 1 > m_lastMatchCount)
1600 m_activeMatchIndexInCurrentFrame = 0;
1601 if (m_activeMatchIndexInCurrentFrame == -1)
1602 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1;
1604 if (selectionRect) {
1605 *selectionRect = frameView()->contentsToWindow(m_activeMatch->boundingBox());
1606 reportFindInPageSelection(*selectionRect, m_activeMatchIndexInCurrentFrame + 1, identifier);
1613 void WebFrameImpl::stopFinding(bool clearSelection)
1615 if (!clearSelection)
1616 setFindEndstateFocusAndSelection();
1617 cancelPendingScopingEffort();
1619 // Remove all markers for matches found and turn off the highlighting.
1620 frame()->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
1621 frame()->editor()->setMarkedTextMatchesAreHighlighted(false);
1622 clearFindMatchesCache();
1624 // Let the frame know that we don't want tickmarks or highlighting anymore.
1625 invalidateArea(InvalidateAll);
1628 void WebFrameImpl::scopeStringMatches(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset)
1631 // This is a brand new search, so we need to reset everything.
1632 // Scoping is just about to begin.
1633 m_scopingInProgress = true;
1635 // Need to keep the current identifier locally in order to finish the
1636 // request in case the frame is detached during the process.
1637 m_findRequestIdentifier = identifier;
1639 // Clear highlighting for this frame.
1640 if (frame() && frame()->page() && frame()->editor()->markedTextMatchesAreHighlighted())
1641 frame()->page()->unmarkAllTextMatches();
1643 // Clear the tickmarks and results cache.
1644 clearFindMatchesCache();
1646 // Clear the counters from last operation.
1647 m_lastMatchCount = 0;
1648 m_nextInvalidateAfter = 0;
1650 m_resumeScopingFromRange = 0;
1652 // The view might be null on detached frames.
1653 if (frame() && frame()->page())
1654 viewImpl()->mainFrameImpl()->m_framesScopingCount++;
1656 // Now, defer scoping until later to allow find operation to finish quickly.
1657 scopeStringMatchesSoon(identifier, searchText, options, false); // false means just reset, so don't do it again.
1661 if (!shouldScopeMatches(searchText)) {
1662 // Note that we want to defer the final update when resetting even if shouldScopeMatches returns false.
1663 // This is done in order to prevent sending a final message based only on the results of the first frame
1664 // since m_framesScopingCount would be 0 as other frames have yet to reset.
1665 finishCurrentScopingEffort(identifier);
1669 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1670 RefPtr<Range> searchRange(rangeOfContents(frame()->document()));
1672 Node* originalEndContainer = searchRange->endContainer();
1673 int originalEndOffset = searchRange->endOffset();
1675 ExceptionCode ec = 0, ec2 = 0;
1676 if (m_resumeScopingFromRange) {
1677 // This is a continuation of a scoping operation that timed out and didn't
1678 // complete last time around, so we should start from where we left off.
1679 searchRange->setStart(m_resumeScopingFromRange->startContainer(),
1680 m_resumeScopingFromRange->startOffset(ec2) + 1,
1683 if (ec2) // A non-zero |ec| happens when navigating during search.
1684 ASSERT_NOT_REACHED();
1689 // This timeout controls how long we scope before releasing control. This
1690 // value does not prevent us from running for longer than this, but it is
1691 // periodically checked to see if we have exceeded our allocated time.
1692 const double maxScopingDuration = 0.1; // seconds
1695 bool timedOut = false;
1696 double startTime = currentTime();
1698 // Find next occurrence of the search string.
1699 // FIXME: (http://b/1088245) This WebKit operation may run for longer
1700 // than the timeout value, and is not interruptible as it is currently
1701 // written. We may need to rewrite it with interruptibility in mind, or
1702 // find an alternative.
1703 RefPtr<Range> resultRange(findPlainText(searchRange.get(),
1705 options.matchCase ? 0 : CaseInsensitive));
1706 if (resultRange->collapsed(ec)) {
1707 if (!resultRange->startContainer()->isInShadowTree())
1710 searchRange->setStartAfter(
1711 resultRange->startContainer()->deprecatedShadowAncestorNode(), ec);
1712 searchRange->setEnd(originalEndContainer, originalEndOffset, ec);
1718 // Catch a special case where Find found something but doesn't know what
1719 // the bounding box for it is. In this case we set the first match we find
1720 // as the active rect.
1721 IntRect resultBounds = resultRange->boundingBox();
1722 IntRect activeSelectionRect;
1723 if (m_locatingActiveRect) {
1724 activeSelectionRect = m_activeMatch.get() ?
1725 m_activeMatch->boundingBox() : resultBounds;
1728 // If the Find function found a match it will have stored where the
1729 // match was found in m_activeSelectionRect on the current frame. If we
1730 // find this rect during scoping it means we have found the active
1732 bool foundActiveMatch = false;
1733 if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) {
1734 // We have found the active tickmark frame.
1735 mainFrameImpl->m_currentActiveMatchFrame = this;
1736 foundActiveMatch = true;
1737 // We also know which tickmark is active now.
1738 m_activeMatchIndexInCurrentFrame = matchCount - 1;
1739 // To stop looking for the active tickmark, we set this flag.
1740 m_locatingActiveRect = false;
1742 // Notify browser of new location for the selected rectangle.
1743 reportFindInPageSelection(
1744 frameView()->contentsToWindow(resultBounds),
1745 m_activeMatchIndexInCurrentFrame + 1,
1749 addMarker(resultRange.get(), foundActiveMatch);
1751 m_findMatchesCache.append(FindMatch(resultRange.get(), m_lastMatchCount + matchCount));
1753 // Set the new start for the search range to be the end of the previous
1754 // result range. There is no need to use a VisiblePosition here,
1755 // since findPlainText will use a TextIterator to go over the visible
1757 searchRange->setStart(resultRange->endContainer(ec), resultRange->endOffset(ec), ec);
1759 Node* shadowTreeRoot = searchRange->shadowRoot();
1760 if (searchRange->collapsed(ec) && shadowTreeRoot)
1761 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
1763 m_resumeScopingFromRange = resultRange;
1764 timedOut = (currentTime() - startTime) >= maxScopingDuration;
1765 } while (!timedOut);
1767 // Remember what we search for last time, so we can skip searching if more
1768 // letters are added to the search string (and last outcome was 0).
1769 m_lastSearchString = searchText;
1771 if (matchCount > 0) {
1772 frame()->editor()->setMarkedTextMatchesAreHighlighted(true);
1774 m_lastMatchCount += matchCount;
1776 // Let the mainframe know how much we found during this pass.
1777 mainFrameImpl->increaseMatchCount(matchCount, identifier);
1781 // If we found anything during this pass, we should redraw. However, we
1782 // don't want to spam too much if the page is extremely long, so if we
1783 // reach a certain point we start throttling the redraw requests.
1785 invalidateIfNecessary();
1787 // Scoping effort ran out of time, lets ask for another time-slice.
1788 scopeStringMatchesSoon(
1792 false); // don't reset.
1793 return; // Done for now, resume work later.
1796 finishCurrentScopingEffort(identifier);
1799 void WebFrameImpl::flushCurrentScopingEffort(int identifier)
1801 if (!frame() || !frame()->page())
1804 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1806 // This frame has no further scoping left, so it is done. Other frames might,
1807 // of course, continue to scope matches.
1808 mainFrameImpl->m_framesScopingCount--;
1810 // If this is the last frame to finish scoping we need to trigger the final
1811 // update to be sent.
1812 if (!mainFrameImpl->m_framesScopingCount)
1813 mainFrameImpl->increaseMatchCount(0, identifier);
1816 void WebFrameImpl::finishCurrentScopingEffort(int identifier)
1818 flushCurrentScopingEffort(identifier);
1820 m_scopingInProgress = false;
1821 m_lastFindRequestCompletedWithNoMatches = !m_lastMatchCount;
1823 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet.
1824 invalidateArea(InvalidateScrollbar);
1827 void WebFrameImpl::cancelPendingScopingEffort()
1829 deleteAllValues(m_deferredScopingWork);
1830 m_deferredScopingWork.clear();
1832 m_activeMatchIndexInCurrentFrame = -1;
1834 // Last request didn't complete.
1835 if (m_scopingInProgress)
1836 m_lastFindRequestCompletedWithNoMatches = false;
1838 m_scopingInProgress = false;
1841 void WebFrameImpl::increaseMatchCount(int count, int identifier)
1843 // This function should only be called on the mainframe.
1847 ++m_findMatchMarkersVersion;
1849 m_totalMatchCount += count;
1851 // Update the UI with the latest findings.
1853 client()->reportFindInPageMatchCount(identifier, m_totalMatchCount, !m_framesScopingCount);
1856 void WebFrameImpl::reportFindInPageSelection(const WebRect& selectionRect, int activeMatchOrdinal, int identifier)
1858 // Update the UI with the latest selection rect.
1860 client()->reportFindInPageSelection(identifier, ordinalOfFirstMatchForFrame(this) + activeMatchOrdinal, selectionRect);
1863 void WebFrameImpl::resetMatchCount()
1865 if (m_totalMatchCount > 0)
1866 ++m_findMatchMarkersVersion;
1868 m_totalMatchCount = 0;
1869 m_framesScopingCount = 0;
1872 void WebFrameImpl::sendOrientationChangeEvent(int orientation)
1874 #if ENABLE(ORIENTATION_EVENTS)
1876 frame()->sendOrientationChangeEvent(orientation);
1880 void WebFrameImpl::addEventListener(const WebString& eventType, WebDOMEventListener* listener, bool useCapture)
1882 DOMWindow* window = frame()->document()->domWindow();
1883 EventListenerWrapper* listenerWrapper = listener->createEventListenerWrapper(eventType, useCapture, window);
1884 window->addEventListener(eventType, adoptRef(listenerWrapper), useCapture);
1887 void WebFrameImpl::removeEventListener(const WebString& eventType, WebDOMEventListener* listener, bool useCapture)
1889 DOMWindow* window = frame()->document()->domWindow();
1890 EventListenerWrapper* listenerWrapper = listener->getEventListenerWrapper(eventType, useCapture, window);
1891 window->removeEventListener(eventType, listenerWrapper, useCapture);
1894 bool WebFrameImpl::dispatchEvent(const WebDOMEvent& event)
1896 ASSERT(!event.isNull());
1897 return frame()->document()->domWindow()->dispatchEvent(event);
1900 void WebFrameImpl::dispatchMessageEventWithOriginCheck(const WebSecurityOrigin& intendedTargetOrigin, const WebDOMEvent& event)
1902 ASSERT(!event.isNull());
1903 frame()->document()->domWindow()->dispatchMessageEventWithOriginCheck(intendedTargetOrigin.get(), event, 0);
1906 int WebFrameImpl::findMatchMarkersVersion() const
1909 return m_findMatchMarkersVersion;
1912 void WebFrameImpl::clearFindMatchesCache()
1914 if (!m_findMatchesCache.isEmpty())
1915 viewImpl()->mainFrameImpl()->m_findMatchMarkersVersion++;
1917 m_findMatchesCache.clear();
1918 m_findMatchRectsAreValid = false;
1921 bool WebFrameImpl::isActiveMatchFrameValid() const
1923 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1924 WebFrameImpl* activeMatchFrame = mainFrameImpl->activeMatchFrame();
1925 return activeMatchFrame && activeMatchFrame->m_activeMatch && activeMatchFrame->frame()->tree()->isDescendantOf(mainFrameImpl->frame());
1928 void WebFrameImpl::updateFindMatchRects()
1930 IntSize currentContentsSize = contentsSize();
1931 if (m_contentsSizeForCurrentFindMatchRects != currentContentsSize) {
1932 m_contentsSizeForCurrentFindMatchRects = currentContentsSize;
1933 m_findMatchRectsAreValid = false;
1936 size_t deadMatches = 0;
1937 for (Vector<FindMatch>::iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) {
1938 if (!it->m_range->boundaryPointsValid() || !it->m_range->startContainer()->inDocument())
1939 it->m_rect = FloatRect();
1940 else if (!m_findMatchRectsAreValid)
1941 it->m_rect = findInPageRectFromRange(it->m_range.get());
1943 if (it->m_rect.isEmpty())
1947 // Remove any invalid matches from the cache.
1949 Vector<FindMatch> filteredMatches;
1950 filteredMatches.reserveCapacity(m_findMatchesCache.size() - deadMatches);
1952 for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it)
1953 if (!it->m_rect.isEmpty())
1954 filteredMatches.append(*it);
1956 m_findMatchesCache.swap(filteredMatches);
1959 // Invalidate the rects in child frames. Will be updated later during traversal.
1960 if (!m_findMatchRectsAreValid)
1961 for (WebFrame* child = firstChild(); child; child = child->nextSibling())
1962 static_cast<WebFrameImpl*>(child)->m_findMatchRectsAreValid = false;
1964 m_findMatchRectsAreValid = true;
1967 WebFloatRect WebFrameImpl::activeFindMatchRect()
1971 if (!isActiveMatchFrameValid())
1972 return WebFloatRect();
1974 return WebFloatRect(findInPageRectFromRange(m_currentActiveMatchFrame->m_activeMatch.get()));
1977 void WebFrameImpl::findMatchRects(WebVector<WebFloatRect>& outputRects)
1981 Vector<WebFloatRect> matchRects;
1982 for (WebFrameImpl* frame = this; frame; frame = static_cast<WebFrameImpl*>(frame->traverseNext(false)))
1983 frame->appendFindMatchRects(matchRects);
1985 outputRects = matchRects;
1988 void WebFrameImpl::appendFindMatchRects(Vector<WebFloatRect>& frameRects)
1990 updateFindMatchRects();
1991 frameRects.reserveCapacity(frameRects.size() + m_findMatchesCache.size());
1992 for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) {
1993 ASSERT(!it->m_rect.isEmpty());
1994 frameRects.append(it->m_rect);
1998 int WebFrameImpl::selectNearestFindMatch(const WebFloatPoint& point, WebRect* selectionRect)
2002 WebFrameImpl* bestFrame = 0;
2003 int indexInBestFrame = -1;
2004 float distanceInBestFrame = FLT_MAX;
2006 for (WebFrameImpl* frame = this; frame; frame = static_cast<WebFrameImpl*>(frame->traverseNext(false))) {
2007 float distanceInFrame;
2008 int indexInFrame = frame->nearestFindMatch(point, distanceInFrame);
2009 if (distanceInFrame < distanceInBestFrame) {
2011 indexInBestFrame = indexInFrame;
2012 distanceInBestFrame = distanceInFrame;
2016 if (indexInBestFrame != -1)
2017 return bestFrame->selectFindMatch(static_cast<unsigned>(indexInBestFrame), selectionRect);
2022 int WebFrameImpl::nearestFindMatch(const FloatPoint& point, float& distanceSquared)
2024 updateFindMatchRects();
2027 distanceSquared = FLT_MAX;
2028 for (size_t i = 0; i < m_findMatchesCache.size(); ++i) {
2029 ASSERT(!m_findMatchesCache[i].m_rect.isEmpty());
2030 FloatSize offset = point - m_findMatchesCache[i].m_rect.center();
2031 float width = offset.width();
2032 float height = offset.height();
2033 float currentDistanceSquared = width * width + height * height;
2034 if (currentDistanceSquared < distanceSquared) {
2036 distanceSquared = currentDistanceSquared;
2042 int WebFrameImpl::selectFindMatch(unsigned index, WebRect* selectionRect)
2044 ASSERT_WITH_SECURITY_IMPLICATION(index < m_findMatchesCache.size());
2046 RefPtr<Range> range = m_findMatchesCache[index].m_range;
2047 if (!range->boundaryPointsValid() || !range->startContainer()->inDocument())
2050 // Check if the match is already selected.
2051 WebFrameImpl* activeMatchFrame = viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame;
2052 if (this != activeMatchFrame || !m_activeMatch || !areRangesEqual(m_activeMatch.get(), range.get())) {
2053 if (isActiveMatchFrameValid())
2054 activeMatchFrame->setMarkerActive(activeMatchFrame->m_activeMatch.get(), false);
2056 m_activeMatchIndexInCurrentFrame = m_findMatchesCache[index].m_ordinal - 1;
2058 // Set this frame as the active frame (the one with the active highlight).
2059 viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame = this;
2060 viewImpl()->setFocusedFrame(this);
2062 m_activeMatch = range.release();
2063 setMarkerActive(m_activeMatch.get(), true);
2065 // Clear any user selection, to make sure Find Next continues on from the match we just activated.
2066 frame()->selection()->clear();
2068 // Make sure no node is focused. See http://crbug.com/38700.
2069 frame()->document()->setFocusedNode(0);
2072 IntRect activeMatchRect;
2073 IntRect activeMatchBoundingBox = enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get()));
2075 if (!activeMatchBoundingBox.isEmpty()) {
2076 if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->renderer())
2077 m_activeMatch->firstNode()->renderer()->scrollRectToVisible(activeMatchBoundingBox,
2078 ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
2080 // Zoom to the active match.
2081 activeMatchRect = frameView()->contentsToWindow(activeMatchBoundingBox);
2082 viewImpl()->zoomToFindInPageRect(activeMatchRect);
2086 *selectionRect = activeMatchRect;
2088 return ordinalOfFirstMatchForFrame(this) + m_activeMatchIndexInCurrentFrame + 1;
2091 void WebFrameImpl::deliverIntent(const WebIntent& intent, WebMessagePortChannelArray* ports, WebDeliveredIntentClient* intentClient)
2093 #if ENABLE(WEB_INTENTS)
2094 OwnPtr<WebCore::DeliveredIntentClient> client(adoptPtr(new DeliveredIntentClientImpl(intentClient)));
2096 WebSerializedScriptValue intentData = WebSerializedScriptValue::fromString(intent.data());
2097 const WebCore::Intent* webcoreIntent = intent;
2099 // See PlatformMessagePortChannel.cpp
2100 OwnPtr<MessagePortChannelArray> channels;
2101 if (ports && ports->size()) {
2102 channels = adoptPtr(new MessagePortChannelArray(ports->size()));
2103 for (size_t i = 0; i < ports->size(); ++i) {
2104 RefPtr<PlatformMessagePortChannel> platformChannel = PlatformMessagePortChannel::create((*ports)[i]);
2105 (*ports)[i]->setClient(platformChannel.get());
2106 (*channels)[i] = MessagePortChannel::create(platformChannel);
2109 OwnPtr<MessagePortArray> portArray = WebCore::MessagePort::entanglePorts(*(frame()->document()), channels.release());
2111 RefPtr<DeliveredIntent> deliveredIntent = DeliveredIntent::create(frame(), client.release(), intent.action(), intent.type(), intentData, portArray.release(), webcoreIntent->extras());
2113 DOMWindowIntents::from(frame()->document()->domWindow())->deliver(deliveredIntent.release());
2117 WebString WebFrameImpl::contentAsText(size_t maxChars) const
2122 frameContentAsPlainText(maxChars, frame(), &text);
2123 return String::adopt(text);
2126 WebString WebFrameImpl::contentAsMarkup() const
2130 return createFullMarkup(frame()->document());
2133 WebString WebFrameImpl::renderTreeAsText(RenderAsTextControls toShow) const
2135 RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal;
2137 if (toShow & RenderAsTextDebug)
2138 behavior |= RenderAsTextShowCompositedLayers | RenderAsTextShowAddresses | RenderAsTextShowIDAndClass | RenderAsTextShowLayerNesting;
2140 if (toShow & RenderAsTextPrinting)
2141 behavior |= RenderAsTextPrintingMode;
2143 return externalRepresentation(frame(), behavior);
2146 WebString WebFrameImpl::markerTextForListItem(const WebElement& webElement) const
2148 return WebCore::markerTextForListItem(const_cast<Element*>(webElement.constUnwrap<Element>()));
2151 void WebFrameImpl::printPagesWithBoundaries(WebCanvas* canvas, const WebSize& pageSizeInPixels)
2153 ASSERT(m_printContext);
2155 GraphicsContextBuilder builder(canvas);
2156 GraphicsContext& graphicsContext = builder.context();
2157 graphicsContext.platformContext()->setPrinting(true);
2159 m_printContext->spoolAllPagesWithBoundaries(graphicsContext, FloatSize(pageSizeInPixels.width, pageSizeInPixels.height));
2162 WebRect WebFrameImpl::selectionBoundsRect() const
2164 return hasSelection() ? WebRect(IntRect(frame()->selection()->bounds(false))) : WebRect();
2167 bool WebFrameImpl::selectionStartHasSpellingMarkerFor(int from, int length) const
2171 return frame()->editor()->selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
2174 WebString WebFrameImpl::layerTreeAsText(bool showDebugInfo) const
2179 LayerTreeFlags flags = showDebugInfo ? LayerTreeFlagsIncludeDebugInfo : 0;
2180 return WebString(frame()->layerTreeAsText(flags));
2183 // WebFrameImpl public ---------------------------------------------------------
2185 PassRefPtr<WebFrameImpl> WebFrameImpl::create(WebFrameClient* client)
2187 return adoptRef(new WebFrameImpl(client));
2190 WebFrameImpl::WebFrameImpl(WebFrameClient* client)
2191 : FrameDestructionObserver(0)
2192 , m_frameLoaderClient(this)
2194 , m_currentActiveMatchFrame(0)
2195 , m_activeMatchIndexInCurrentFrame(-1)
2196 , m_locatingActiveRect(false)
2197 , m_resumeScopingFromRange(0)
2198 , m_lastMatchCount(-1)
2199 , m_totalMatchCount(-1)
2200 , m_framesScopingCount(-1)
2201 , m_findRequestIdentifier(-1)
2202 , m_scopingInProgress(false)
2203 , m_lastFindRequestCompletedWithNoMatches(false)
2204 , m_nextInvalidateAfter(0)
2205 , m_findMatchMarkersVersion(0)
2206 , m_findMatchRectsAreValid(false)
2207 , m_animationController(this)
2208 , m_identifier(generateFrameIdentifier())
2209 , m_inSameDocumentHistoryLoad(false)
2211 WebKit::Platform::current()->incrementStatsCounter(webFrameActiveCount);
2215 WebFrameImpl::~WebFrameImpl()
2217 WebKit::Platform::current()->decrementStatsCounter(webFrameActiveCount);
2220 cancelPendingScopingEffort();
2223 void WebFrameImpl::setWebCoreFrame(WebCore::Frame* frame)
2226 observeFrame(frame);
2229 void WebFrameImpl::initializeAsMainFrame(WebCore::Page* page)
2231 RefPtr<Frame> mainFrame = Frame::create(page, 0, &m_frameLoaderClient);
2232 setWebCoreFrame(mainFrame.get());
2234 // Add reference on behalf of FrameLoader. See comments in
2235 // WebFrameLoaderClient::frameLoaderDestroyed for more info.
2238 // We must call init() after m_frame is assigned because it is referenced
2243 PassRefPtr<Frame> WebFrameImpl::createChildFrame(const FrameLoadRequest& request, HTMLFrameOwnerElement* ownerElement)
2245 RefPtr<WebFrameImpl> webframe(adoptRef(new WebFrameImpl(m_client)));
2247 // Add an extra ref on behalf of the Frame/FrameLoader, which references the
2248 // WebFrame via the FrameLoaderClient interface. See the comment at the top
2249 // of this file for more info.
2252 RefPtr<Frame> childFrame = Frame::create(frame()->page(), ownerElement, &webframe->m_frameLoaderClient);
2253 webframe->setWebCoreFrame(childFrame.get());
2255 childFrame->tree()->setName(request.frameName());
2257 frame()->tree()->appendChild(childFrame);
2259 // Frame::init() can trigger onload event in the parent frame,
2260 // which may detach this frame and trigger a null-pointer access
2261 // in FrameTree::removeChild. Move init() after appendChild call
2262 // so that webframe->mFrame is in the tree before triggering
2263 // onload event handler.
2264 // Because the event handler may set webframe->mFrame to null,
2265 // it is necessary to check the value after calling init() and
2266 // return without loading URL.
2268 childFrame->init(); // create an empty document
2269 if (!childFrame->tree()->parent())
2272 frame()->loader()->loadURLIntoChildFrame(request.resourceRequest().url(), request.resourceRequest().httpReferrer(), childFrame.get());
2274 // A synchronous navigation (about:blank) would have already processed
2275 // onload, so it is possible for the frame to have already been destroyed by
2276 // script in the page.
2277 if (!childFrame->tree()->parent())
2281 m_client->didCreateFrame(this, webframe.get());
2283 return childFrame.release();
2286 void WebFrameImpl::didChangeContentsSize(const IntSize& size)
2288 // This is only possible on the main frame.
2289 if (m_totalMatchCount > 0) {
2291 ++m_findMatchMarkersVersion;
2295 void WebFrameImpl::createFrameView()
2297 TRACE_EVENT0("webkit", "WebFrameImpl::createFrameView");
2299 ASSERT(frame()); // If frame() doesn't exist, we probably didn't init properly.
2301 WebViewImpl* webView = viewImpl();
2302 bool isMainFrame = webView->mainFrameImpl()->frame() == frame();
2304 webView->suppressInvalidations(true);
2306 frame()->createView(webView->size(), Color::white, webView->isTransparent(), webView->fixedLayoutSize(), IntRect(), isMainFrame ? webView->isFixedLayoutModeEnabled() : 0);
2307 if (webView->shouldAutoResize() && isMainFrame)
2308 frame()->view()->enableAutoSizeMode(true, webView->minAutoSize(), webView->maxAutoSize());
2311 webView->suppressInvalidations(false);
2313 if (isMainFrame && webView->devToolsAgentPrivate())
2314 webView->devToolsAgentPrivate()->mainFrameViewCreated(this);
2317 WebFrameImpl* WebFrameImpl::fromFrame(Frame* frame)
2321 return static_cast<FrameLoaderClientImpl*>(frame->loader()->client())->webFrame();
2324 WebFrameImpl* WebFrameImpl::fromFrameOwnerElement(Element* element)
2326 // FIXME: Why do we check specifically for <iframe> and <frame> here? Why can't we get the WebFrameImpl from an <object> element, for example.
2327 if (!element || !element->isFrameOwnerElement() || (!element->hasTagName(HTMLNames::iframeTag) && !element->hasTagName(HTMLNames::frameTag)))
2329 HTMLFrameOwnerElement* frameElement = static_cast<HTMLFrameOwnerElement*>(element);
2330 return fromFrame(frameElement->contentFrame());
2333 WebViewImpl* WebFrameImpl::viewImpl() const
2337 return WebViewImpl::fromPage(frame()->page());
2340 WebDataSourceImpl* WebFrameImpl::dataSourceImpl() const
2342 return static_cast<WebDataSourceImpl*>(dataSource());
2345 WebDataSourceImpl* WebFrameImpl::provisionalDataSourceImpl() const
2347 return static_cast<WebDataSourceImpl*>(provisionalDataSource());
2350 void WebFrameImpl::setFindEndstateFocusAndSelection()
2352 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
2354 if (this == mainFrameImpl->activeMatchFrame() && m_activeMatch.get()) {
2355 // If the user has set the selection since the match was found, we
2356 // don't focus anything.
2357 VisibleSelection selection(frame()->selection()->selection());
2358 if (!selection.isNone())
2361 // Try to find the first focusable node up the chain, which will, for
2362 // example, focus links if we have found text within the link.
2363 Node* node = m_activeMatch->firstNode();
2364 if (node && node->isInShadowTree()) {
2365 Node* host = node->deprecatedShadowAncestorNode();
2366 if (host->hasTagName(HTMLNames::inputTag) || host->hasTagName(HTMLNames::textareaTag))
2369 while (node && !node->isFocusable() && node != frame()->document())
2370 node = node->parentNode();
2372 if (node && node != frame()->document()) {
2373 // Found a focusable parent node. Set the active match as the
2374 // selection and focus to the focusable node.
2375 frame()->selection()->setSelection(m_activeMatch.get());
2376 frame()->document()->setFocusedNode(node);
2380 // Iterate over all the nodes in the range until we find a focusable node.
2381 // This, for example, sets focus to the first link if you search for
2382 // text and text that is within one or more links.
2383 node = m_activeMatch->firstNode();
2384 while (node && node != m_activeMatch->pastLastNode()) {
2385 if (node->isFocusable()) {
2386 frame()->document()->setFocusedNode(node);
2389 node = NodeTraversal::next(node);
2392 // No node related to the active match was focusable, so set the
2393 // active match as the selection (so that when you end the Find session,
2394 // you'll have the last thing you found highlighted) and make sure that
2395 // we have nothing focused (otherwise you might have text selected but
2396 // a link focused, which is weird).
2397 frame()->selection()->setSelection(m_activeMatch.get());
2398 frame()->document()->setFocusedNode(0);
2400 // Finally clear the active match, for two reasons:
2401 // We just finished the find 'session' and we don't want future (potentially
2402 // unrelated) find 'sessions' operations to start at the same place.
2403 // The WebFrameImpl could get reused and the m_activeMatch could end up pointing
2404 // to a document that is no longer valid. Keeping an invalid reference around
2405 // is just asking for trouble.
2410 void WebFrameImpl::didFail(const ResourceError& error, bool wasProvisional)
2414 WebURLError webError = error;
2416 client()->didFailProvisionalLoad(this, webError);
2418 client()->didFailLoad(this, webError);
2421 void WebFrameImpl::setCanHaveScrollbars(bool canHaveScrollbars)
2423 frame()->view()->setCanHaveScrollbars(canHaveScrollbars);
2426 void WebFrameImpl::invalidateArea(AreaToInvalidate area)
2428 ASSERT(frame() && frame()->view());
2429 FrameView* view = frame()->view();
2431 if ((area & InvalidateAll) == InvalidateAll)
2432 view->invalidateRect(view->frameRect());
2434 if ((area & InvalidateContentArea) == InvalidateContentArea) {
2435 IntRect contentArea(
2436 view->x(), view->y(), view->visibleWidth(), view->visibleHeight());
2437 IntRect frameRect = view->frameRect();
2438 contentArea.move(-frameRect.x(), -frameRect.y());
2439 view->invalidateRect(contentArea);
2443 if ((area & InvalidateScrollbar) == InvalidateScrollbar) {
2444 // Invalidate the vertical scroll bar region for the view.
2445 Scrollbar* scrollbar = view->verticalScrollbar();
2447 scrollbar->invalidate();
2451 void WebFrameImpl::addMarker(Range* range, bool activeMatch)
2453 frame()->document()->markers()->addTextMatchMarker(range, activeMatch);
2456 void WebFrameImpl::setMarkerActive(Range* range, bool active)
2458 WebCore::ExceptionCode ec;
2459 if (!range || range->collapsed(ec))
2461 frame()->document()->markers()->setMarkersActive(range, active);
2464 int WebFrameImpl::ordinalOfFirstMatchForFrame(WebFrameImpl* frame) const
2467 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
2468 // Iterate from the main frame up to (but not including) |frame| and
2469 // add up the number of matches found so far.
2470 for (WebFrameImpl* it = mainFrameImpl; it != frame; it = static_cast<WebFrameImpl*>(it->traverseNext(true))) {
2471 if (it->m_lastMatchCount > 0)
2472 ordinal += it->m_lastMatchCount;
2477 bool WebFrameImpl::shouldScopeMatches(const String& searchText)
2479 // Don't scope if we can't find a frame or a view.
2480 // The user may have closed the tab/application, so abort.
2481 // Also ignore detached frames, as many find operations report to the main frame.
2482 if (!frame() || !frame()->view() || !frame()->page() || !hasVisibleContent())
2485 ASSERT(frame()->document() && frame()->view());
2487 // If the frame completed the scoping operation and found 0 matches the last
2488 // time it was searched, then we don't have to search it again if the user is
2489 // just adding to the search string or sending the same search string again.
2490 if (m_lastFindRequestCompletedWithNoMatches && !m_lastSearchString.isEmpty()) {
2491 // Check to see if the search string prefixes match.
2492 String previousSearchPrefix =
2493 searchText.substring(0, m_lastSearchString.length());
2495 if (previousSearchPrefix == m_lastSearchString)
2496 return false; // Don't search this frame, it will be fruitless.
2502 void WebFrameImpl::scopeStringMatchesSoon(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset)
2504 m_deferredScopingWork.append(new DeferredScopeStringMatches(this, identifier, searchText, options, reset));
2507 void WebFrameImpl::callScopeStringMatches(DeferredScopeStringMatches* caller, int identifier, const WebString& searchText, const WebFindOptions& options, bool reset)
2509 m_deferredScopingWork.remove(m_deferredScopingWork.find(caller));
2510 scopeStringMatches(identifier, searchText, options, reset);
2512 // This needs to happen last since searchText is passed by reference.
2516 void WebFrameImpl::invalidateIfNecessary()
2518 if (m_lastMatchCount <= m_nextInvalidateAfter)
2521 // FIXME: (http://b/1088165) Optimize the drawing of the tickmarks and
2522 // remove this. This calculation sets a milestone for when next to
2523 // invalidate the scrollbar and the content area. We do this so that we
2524 // don't spend too much time drawing the scrollbar over and over again.
2525 // Basically, up until the first 500 matches there is no throttle.
2526 // After the first 500 matches, we set set the milestone further and
2527 // further out (750, 1125, 1688, 2K, 3K).
2528 static const int startSlowingDownAfter = 500;
2529 static const int slowdown = 750;
2531 int i = m_lastMatchCount / startSlowingDownAfter;
2532 m_nextInvalidateAfter += i * slowdown;
2533 invalidateArea(InvalidateScrollbar);
2536 void WebFrameImpl::loadJavaScriptURL(const KURL& url)
2538 // This is copied from ScriptController::executeIfJavaScriptURL.
2539 // Unfortunately, we cannot just use that method since it is private, and
2540 // it also doesn't quite behave as we require it to for bookmarklets. The
2541 // key difference is that we need to suppress loading the string result
2542 // from evaluating the JS URL if executing the JS URL resulted in a
2543 // location change. We also allow a JS URL to be loaded even if scripts on
2544 // the page are otherwise disabled.
2546 if (!frame()->document() || !frame()->page())
2549 RefPtr<Document> ownerDocument(frame()->document());
2551 // Protect privileged pages against bookmarklets and other javascript manipulations.
2552 if (SchemeRegistry::shouldTreatURLSchemeAsNotAllowingJavascriptURLs(frame()->document()->url().protocol()))
2555 String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
2556 ScriptValue result = frame()->script()->executeScript(script, true);
2558 String scriptResult;
2559 if (!result.getString(scriptResult))
2562 if (!frame()->navigationScheduler()->locationChangePending())
2563 frame()->document()->loader()->writer()->replaceDocument(scriptResult, ownerDocument.get());
2566 void WebFrameImpl::willDetachPage()
2568 if (!frame() || !frame()->page())
2571 // Do not expect string scoping results from any frames that got detached
2572 // in the middle of the operation.
2573 if (m_scopingInProgress) {
2575 // There is a possibility that the frame being detached was the only
2576 // pending one. We need to make sure final replies can be sent.
2577 flushCurrentScopingEffort(m_findRequestIdentifier);
2579 cancelPendingScopingEffort();
2583 } // namespace WebKit