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 = TextIterator::rangeFromLocationAndLength(frame()->selection()->rootEditableElementOrDocumentElement(), markers[0]->startOffset(), markers[0]->endOffset() - markers[0]->startOffset());
1314 if (!markerRange.get() || !frame()->selection()->shouldChangeSelection(markerRange.get()))
1316 frame()->selection()->setSelection(markerRange.get(), CharacterGranularity);
1317 frame()->editor()->replaceSelectionWithText(text, false, true);
1320 bool WebFrameImpl::hasSelection() const
1322 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1323 if (pluginContainer)
1324 return pluginContainer->plugin()->hasSelection();
1326 // frame()->selection()->isNone() never returns true.
1327 return (frame()->selection()->start() != frame()->selection()->end());
1330 WebRange WebFrameImpl::selectionRange() const
1332 return frame()->selection()->toNormalizedRange();
1335 WebString WebFrameImpl::selectionAsText() const
1337 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1338 if (pluginContainer)
1339 return pluginContainer->plugin()->selectionAsText();
1341 RefPtr<Range> range = frame()->selection()->toNormalizedRange();
1345 String text = range->text();
1347 replaceNewlinesWithWindowsStyleNewlines(text);
1349 replaceNBSPWithSpace(text);
1353 WebString WebFrameImpl::selectionAsMarkup() const
1355 WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
1356 if (pluginContainer)
1357 return pluginContainer->plugin()->selectionAsMarkup();
1359 RefPtr<Range> range = frame()->selection()->toNormalizedRange();
1363 return createMarkup(range.get(), 0, AnnotateForInterchange, false, ResolveNonLocalURLs);
1366 void WebFrameImpl::selectWordAroundPosition(Frame* frame, VisiblePosition position)
1368 VisibleSelection selection(position);
1369 selection.expandUsingGranularity(WordGranularity);
1371 if (frame->selection()->shouldChangeSelection(selection)) {
1372 TextGranularity granularity = selection.isRange() ? WordGranularity : CharacterGranularity;
1373 frame->selection()->setSelection(selection, granularity);
1377 bool WebFrameImpl::selectWordAroundCaret()
1379 FrameSelection* selection = frame()->selection();
1380 ASSERT(!selection->isNone());
1381 if (selection->isNone() || selection->isRange())
1383 selectWordAroundPosition(frame(), selection->selection().visibleStart());
1387 void WebFrameImpl::selectRange(const WebPoint& base, const WebPoint& extent)
1389 IntPoint unscaledBase = base;
1390 IntPoint unscaledExtent = extent;
1391 if (frame()->page()->settings()->applyPageScaleFactorInCompositor()) {
1392 unscaledExtent.scale(1 / view()->pageScaleFactor(), 1 / view()->pageScaleFactor());
1393 unscaledBase.scale(1 / view()->pageScaleFactor(), 1 / view()->pageScaleFactor());
1395 VisiblePosition basePosition = visiblePositionForWindowPoint(unscaledBase);
1396 VisiblePosition extentPosition = visiblePositionForWindowPoint(unscaledExtent);
1397 VisibleSelection newSelection = VisibleSelection(basePosition, extentPosition);
1398 if (frame()->selection()->shouldChangeSelection(newSelection))
1399 frame()->selection()->setSelection(newSelection, CharacterGranularity);
1402 void WebFrameImpl::selectRange(const WebRange& webRange)
1404 if (RefPtr<Range> range = static_cast<PassRefPtr<Range> >(webRange))
1405 frame()->selection()->setSelectedRange(range.get(), WebCore::VP_DEFAULT_AFFINITY, false);
1408 void WebFrameImpl::moveCaretSelectionTowardsWindowPoint(const WebPoint& point)
1410 IntPoint unscaledPoint(point);
1411 if (frame()->page()->settings()->applyPageScaleFactorInCompositor())
1412 unscaledPoint.scale(1 / view()->pageScaleFactor(), 1 / view()->pageScaleFactor());
1414 Element* editable = frame()->selection()->rootEditableElement();
1418 IntPoint contentsPoint = frame()->view()->windowToContents(unscaledPoint);
1419 LayoutPoint localPoint(editable->convertFromPage(contentsPoint));
1420 VisiblePosition position = editable->renderer()->positionForPoint(localPoint);
1421 if (frame()->selection()->shouldChangeSelection(position))
1422 frame()->selection()->moveTo(position, UserTriggered);
1425 VisiblePosition WebFrameImpl::visiblePositionForWindowPoint(const WebPoint& point)
1427 HitTestRequest request = HitTestRequest::Move | HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping;
1428 HitTestResult result(frame()->view()->windowToContents(IntPoint(point)));
1430 frame()->document()->renderView()->layer()->hitTest(request, result);
1432 Node* node = result.targetNode();
1434 return VisiblePosition();
1435 return node->renderer()->positionForPoint(result.localPoint());
1438 int WebFrameImpl::printBegin(const WebPrintParams& printParams, const WebNode& constrainToNode, bool* useBrowserOverlays)
1440 ASSERT(!frame()->document()->isFrameSet());
1441 WebPluginContainerImpl* pluginContainer = 0;
1442 if (constrainToNode.isNull()) {
1443 // If this is a plugin document, check if the plugin supports its own
1444 // printing. If it does, we will delegate all printing to that.
1445 pluginContainer = pluginContainerFromFrame(frame());
1447 // We only support printing plugin nodes for now.
1448 pluginContainer = static_cast<WebPluginContainerImpl*>(constrainToNode.pluginContainer());
1451 if (pluginContainer && pluginContainer->supportsPaginatedPrint())
1452 m_printContext = adoptPtr(new ChromePluginPrintContext(frame(), pluginContainer, printParams));
1454 m_printContext = adoptPtr(new ChromePrintContext(frame()));
1456 FloatRect rect(0, 0, static_cast<float>(printParams.printContentArea.width), static_cast<float>(printParams.printContentArea.height));
1457 m_printContext->begin(rect.width(), rect.height());
1459 // We ignore the overlays calculation for now since they are generated in the
1460 // browser. pageHeight is actually an output parameter.
1461 m_printContext->computePageRects(rect, 0, 0, 1.0, pageHeight);
1462 if (useBrowserOverlays)
1463 *useBrowserOverlays = m_printContext->shouldUseBrowserOverlays();
1465 return m_printContext->pageCount();
1468 float WebFrameImpl::getPrintPageShrink(int page)
1470 ASSERT(m_printContext && page >= 0);
1471 return m_printContext->getPageShrink(page);
1474 float WebFrameImpl::printPage(int page, WebCanvas* canvas)
1476 #if ENABLE(PRINTING)
1477 ASSERT(m_printContext && page >= 0 && frame() && frame()->document());
1479 GraphicsContextBuilder builder(canvas);
1480 GraphicsContext& graphicsContext = builder.context();
1481 graphicsContext.platformContext()->setPrinting(true);
1482 return m_printContext->spoolPage(graphicsContext, page);
1488 void WebFrameImpl::printEnd()
1490 ASSERT(m_printContext);
1491 m_printContext->end();
1492 m_printContext.clear();
1495 bool WebFrameImpl::isPrintScalingDisabledForPlugin(const WebNode& node)
1497 WebPluginContainerImpl* pluginContainer = node.isNull() ? pluginContainerFromFrame(frame()) : static_cast<WebPluginContainerImpl*>(node.pluginContainer());
1499 if (!pluginContainer || !pluginContainer->supportsPaginatedPrint())
1502 return pluginContainer->isPrintScalingDisabled();
1505 bool WebFrameImpl::hasCustomPageSizeStyle(int pageIndex)
1507 return frame()->document()->styleForPage(pageIndex)->pageSizeType() != PAGE_SIZE_AUTO;
1510 bool WebFrameImpl::isPageBoxVisible(int pageIndex)
1512 return frame()->document()->isPageBoxVisible(pageIndex);
1515 void WebFrameImpl::pageSizeAndMarginsInPixels(int pageIndex, WebSize& pageSize, int& marginTop, int& marginRight, int& marginBottom, int& marginLeft)
1517 IntSize size = pageSize;
1518 frame()->document()->pageSizeAndMarginsInPixels(pageIndex, size, marginTop, marginRight, marginBottom, marginLeft);
1522 WebString WebFrameImpl::pageProperty(const WebString& propertyName, int pageIndex)
1524 ASSERT(m_printContext);
1525 return m_printContext->pageProperty(frame(), propertyName.utf8().data(), pageIndex);
1528 bool WebFrameImpl::find(int identifier, const WebString& searchText, const WebFindOptions& options, bool wrapWithinFrame, WebRect* selectionRect)
1530 if (!frame() || !frame()->page())
1533 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1535 if (!options.findNext)
1536 frame()->page()->unmarkAllTextMatches();
1538 setMarkerActive(m_activeMatch.get(), false);
1540 if (m_activeMatch && m_activeMatch->ownerDocument() != frame()->document())
1543 // If the user has selected something since the last Find operation we want
1544 // to start from there. Otherwise, we start searching from where the last Find
1545 // operation left off (either a Find or a FindNext operation).
1546 VisibleSelection selection(frame()->selection()->selection());
1547 bool activeSelection = !selection.isNone();
1548 if (activeSelection) {
1549 m_activeMatch = selection.firstRange().get();
1550 frame()->selection()->clear();
1553 ASSERT(frame() && frame()->view());
1554 const FindOptions findOptions = (options.forward ? 0 : Backwards)
1555 | (options.matchCase ? 0 : CaseInsensitive)
1556 | (wrapWithinFrame ? WrapAround : 0)
1557 | (!options.findNext ? StartInSelection : 0);
1558 m_activeMatch = frame()->editor()->findStringAndScrollToVisible(searchText, m_activeMatch.get(), findOptions);
1560 if (!m_activeMatch) {
1561 // If we're finding next the next active match might not be in the current frame.
1562 // In this case we don't want to clear the matches cache.
1563 if (!options.findNext)
1564 clearFindMatchesCache();
1565 invalidateArea(InvalidateAll);
1570 viewImpl()->zoomToFindInPageRect(frameView()->contentsToWindow(enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get()))));
1573 setMarkerActive(m_activeMatch.get(), true);
1574 WebFrameImpl* oldActiveFrame = mainFrameImpl->m_currentActiveMatchFrame;
1575 mainFrameImpl->m_currentActiveMatchFrame = this;
1577 // Make sure no node is focused. See http://crbug.com/38700.
1578 frame()->document()->setFocusedNode(0);
1580 if (!options.findNext || activeSelection) {
1581 // This is either a Find operation or a Find-next from a new start point
1582 // due to a selection, so we set the flag to ask the scoping effort
1583 // to find the active rect for us and report it back to the UI.
1584 m_locatingActiveRect = true;
1586 if (oldActiveFrame != this) {
1587 if (options.forward)
1588 m_activeMatchIndexInCurrentFrame = 0;
1590 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1;
1592 if (options.forward)
1593 ++m_activeMatchIndexInCurrentFrame;
1595 --m_activeMatchIndexInCurrentFrame;
1597 if (m_activeMatchIndexInCurrentFrame + 1 > m_lastMatchCount)
1598 m_activeMatchIndexInCurrentFrame = 0;
1599 if (m_activeMatchIndexInCurrentFrame == -1)
1600 m_activeMatchIndexInCurrentFrame = m_lastMatchCount - 1;
1602 if (selectionRect) {
1603 *selectionRect = frameView()->contentsToWindow(m_activeMatch->boundingBox());
1604 reportFindInPageSelection(*selectionRect, m_activeMatchIndexInCurrentFrame + 1, identifier);
1611 void WebFrameImpl::stopFinding(bool clearSelection)
1613 if (!clearSelection)
1614 setFindEndstateFocusAndSelection();
1615 cancelPendingScopingEffort();
1617 // Remove all markers for matches found and turn off the highlighting.
1618 frame()->document()->markers()->removeMarkers(DocumentMarker::TextMatch);
1619 frame()->editor()->setMarkedTextMatchesAreHighlighted(false);
1620 clearFindMatchesCache();
1622 // Let the frame know that we don't want tickmarks or highlighting anymore.
1623 invalidateArea(InvalidateAll);
1626 void WebFrameImpl::scopeStringMatches(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset)
1629 // This is a brand new search, so we need to reset everything.
1630 // Scoping is just about to begin.
1631 m_scopingInProgress = true;
1633 // Need to keep the current identifier locally in order to finish the
1634 // request in case the frame is detached during the process.
1635 m_findRequestIdentifier = identifier;
1637 // Clear highlighting for this frame.
1638 if (frame() && frame()->page() && frame()->editor()->markedTextMatchesAreHighlighted())
1639 frame()->page()->unmarkAllTextMatches();
1641 // Clear the tickmarks and results cache.
1642 clearFindMatchesCache();
1644 // Clear the counters from last operation.
1645 m_lastMatchCount = 0;
1646 m_nextInvalidateAfter = 0;
1648 m_resumeScopingFromRange = 0;
1650 // The view might be null on detached frames.
1651 if (frame() && frame()->page())
1652 viewImpl()->mainFrameImpl()->m_framesScopingCount++;
1654 // Now, defer scoping until later to allow find operation to finish quickly.
1655 scopeStringMatchesSoon(identifier, searchText, options, false); // false means just reset, so don't do it again.
1659 if (!shouldScopeMatches(searchText)) {
1660 // Note that we want to defer the final update when resetting even if shouldScopeMatches returns false.
1661 // This is done in order to prevent sending a final message based only on the results of the first frame
1662 // since m_framesScopingCount would be 0 as other frames have yet to reset.
1663 finishCurrentScopingEffort(identifier);
1667 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1668 RefPtr<Range> searchRange(rangeOfContents(frame()->document()));
1670 Node* originalEndContainer = searchRange->endContainer();
1671 int originalEndOffset = searchRange->endOffset();
1673 ExceptionCode ec = 0, ec2 = 0;
1674 if (m_resumeScopingFromRange) {
1675 // This is a continuation of a scoping operation that timed out and didn't
1676 // complete last time around, so we should start from where we left off.
1677 searchRange->setStart(m_resumeScopingFromRange->startContainer(),
1678 m_resumeScopingFromRange->startOffset(ec2) + 1,
1681 if (ec2) // A non-zero |ec| happens when navigating during search.
1682 ASSERT_NOT_REACHED();
1687 // This timeout controls how long we scope before releasing control. This
1688 // value does not prevent us from running for longer than this, but it is
1689 // periodically checked to see if we have exceeded our allocated time.
1690 const double maxScopingDuration = 0.1; // seconds
1693 bool timedOut = false;
1694 double startTime = currentTime();
1696 // Find next occurrence of the search string.
1697 // FIXME: (http://b/1088245) This WebKit operation may run for longer
1698 // than the timeout value, and is not interruptible as it is currently
1699 // written. We may need to rewrite it with interruptibility in mind, or
1700 // find an alternative.
1701 RefPtr<Range> resultRange(findPlainText(searchRange.get(),
1703 options.matchCase ? 0 : CaseInsensitive));
1704 if (resultRange->collapsed(ec)) {
1705 if (!resultRange->startContainer()->isInShadowTree())
1708 searchRange->setStartAfter(
1709 resultRange->startContainer()->deprecatedShadowAncestorNode(), ec);
1710 searchRange->setEnd(originalEndContainer, originalEndOffset, ec);
1716 // Catch a special case where Find found something but doesn't know what
1717 // the bounding box for it is. In this case we set the first match we find
1718 // as the active rect.
1719 IntRect resultBounds = resultRange->boundingBox();
1720 IntRect activeSelectionRect;
1721 if (m_locatingActiveRect) {
1722 activeSelectionRect = m_activeMatch.get() ?
1723 m_activeMatch->boundingBox() : resultBounds;
1726 // If the Find function found a match it will have stored where the
1727 // match was found in m_activeSelectionRect on the current frame. If we
1728 // find this rect during scoping it means we have found the active
1730 bool foundActiveMatch = false;
1731 if (m_locatingActiveRect && (activeSelectionRect == resultBounds)) {
1732 // We have found the active tickmark frame.
1733 mainFrameImpl->m_currentActiveMatchFrame = this;
1734 foundActiveMatch = true;
1735 // We also know which tickmark is active now.
1736 m_activeMatchIndexInCurrentFrame = matchCount - 1;
1737 // To stop looking for the active tickmark, we set this flag.
1738 m_locatingActiveRect = false;
1740 // Notify browser of new location for the selected rectangle.
1741 reportFindInPageSelection(
1742 frameView()->contentsToWindow(resultBounds),
1743 m_activeMatchIndexInCurrentFrame + 1,
1747 addMarker(resultRange.get(), foundActiveMatch);
1749 m_findMatchesCache.append(FindMatch(resultRange.get(), m_lastMatchCount + matchCount));
1751 // Set the new start for the search range to be the end of the previous
1752 // result range. There is no need to use a VisiblePosition here,
1753 // since findPlainText will use a TextIterator to go over the visible
1755 searchRange->setStart(resultRange->endContainer(ec), resultRange->endOffset(ec), ec);
1757 Node* shadowTreeRoot = searchRange->shadowRoot();
1758 if (searchRange->collapsed(ec) && shadowTreeRoot)
1759 searchRange->setEnd(shadowTreeRoot, shadowTreeRoot->childNodeCount(), ec);
1761 m_resumeScopingFromRange = resultRange;
1762 timedOut = (currentTime() - startTime) >= maxScopingDuration;
1763 } while (!timedOut);
1765 // Remember what we search for last time, so we can skip searching if more
1766 // letters are added to the search string (and last outcome was 0).
1767 m_lastSearchString = searchText;
1769 if (matchCount > 0) {
1770 frame()->editor()->setMarkedTextMatchesAreHighlighted(true);
1772 m_lastMatchCount += matchCount;
1774 // Let the mainframe know how much we found during this pass.
1775 mainFrameImpl->increaseMatchCount(matchCount, identifier);
1779 // If we found anything during this pass, we should redraw. However, we
1780 // don't want to spam too much if the page is extremely long, so if we
1781 // reach a certain point we start throttling the redraw requests.
1783 invalidateIfNecessary();
1785 // Scoping effort ran out of time, lets ask for another time-slice.
1786 scopeStringMatchesSoon(
1790 false); // don't reset.
1791 return; // Done for now, resume work later.
1794 finishCurrentScopingEffort(identifier);
1797 void WebFrameImpl::flushCurrentScopingEffort(int identifier)
1799 if (!frame() || !frame()->page())
1802 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1804 // This frame has no further scoping left, so it is done. Other frames might,
1805 // of course, continue to scope matches.
1806 mainFrameImpl->m_framesScopingCount--;
1808 // If this is the last frame to finish scoping we need to trigger the final
1809 // update to be sent.
1810 if (!mainFrameImpl->m_framesScopingCount)
1811 mainFrameImpl->increaseMatchCount(0, identifier);
1814 void WebFrameImpl::finishCurrentScopingEffort(int identifier)
1816 flushCurrentScopingEffort(identifier);
1818 m_scopingInProgress = false;
1819 m_lastFindRequestCompletedWithNoMatches = !m_lastMatchCount;
1821 // This frame is done, so show any scrollbar tickmarks we haven't drawn yet.
1822 invalidateArea(InvalidateScrollbar);
1825 void WebFrameImpl::cancelPendingScopingEffort()
1827 deleteAllValues(m_deferredScopingWork);
1828 m_deferredScopingWork.clear();
1830 m_activeMatchIndexInCurrentFrame = -1;
1832 // Last request didn't complete.
1833 if (m_scopingInProgress)
1834 m_lastFindRequestCompletedWithNoMatches = false;
1836 m_scopingInProgress = false;
1839 void WebFrameImpl::increaseMatchCount(int count, int identifier)
1841 // This function should only be called on the mainframe.
1845 ++m_findMatchMarkersVersion;
1847 m_totalMatchCount += count;
1849 // Update the UI with the latest findings.
1851 client()->reportFindInPageMatchCount(identifier, m_totalMatchCount, !m_framesScopingCount);
1854 void WebFrameImpl::reportFindInPageSelection(const WebRect& selectionRect, int activeMatchOrdinal, int identifier)
1856 // Update the UI with the latest selection rect.
1858 client()->reportFindInPageSelection(identifier, ordinalOfFirstMatchForFrame(this) + activeMatchOrdinal, selectionRect);
1861 void WebFrameImpl::resetMatchCount()
1863 if (m_totalMatchCount > 0)
1864 ++m_findMatchMarkersVersion;
1866 m_totalMatchCount = 0;
1867 m_framesScopingCount = 0;
1870 void WebFrameImpl::sendOrientationChangeEvent(int orientation)
1872 #if ENABLE(ORIENTATION_EVENTS)
1874 frame()->sendOrientationChangeEvent(orientation);
1878 void WebFrameImpl::addEventListener(const WebString& eventType, WebDOMEventListener* listener, bool useCapture)
1880 DOMWindow* window = frame()->document()->domWindow();
1881 EventListenerWrapper* listenerWrapper = listener->createEventListenerWrapper(eventType, useCapture, window);
1882 window->addEventListener(eventType, adoptRef(listenerWrapper), useCapture);
1885 void WebFrameImpl::removeEventListener(const WebString& eventType, WebDOMEventListener* listener, bool useCapture)
1887 DOMWindow* window = frame()->document()->domWindow();
1888 EventListenerWrapper* listenerWrapper = listener->getEventListenerWrapper(eventType, useCapture, window);
1889 window->removeEventListener(eventType, listenerWrapper, useCapture);
1892 bool WebFrameImpl::dispatchEvent(const WebDOMEvent& event)
1894 ASSERT(!event.isNull());
1895 return frame()->document()->domWindow()->dispatchEvent(event);
1898 void WebFrameImpl::dispatchMessageEventWithOriginCheck(const WebSecurityOrigin& intendedTargetOrigin, const WebDOMEvent& event)
1900 ASSERT(!event.isNull());
1901 frame()->document()->domWindow()->dispatchMessageEventWithOriginCheck(intendedTargetOrigin.get(), event, 0);
1904 int WebFrameImpl::findMatchMarkersVersion() const
1907 return m_findMatchMarkersVersion;
1910 void WebFrameImpl::clearFindMatchesCache()
1912 if (!m_findMatchesCache.isEmpty())
1913 viewImpl()->mainFrameImpl()->m_findMatchMarkersVersion++;
1915 m_findMatchesCache.clear();
1916 m_findMatchRectsAreValid = false;
1919 bool WebFrameImpl::isActiveMatchFrameValid() const
1921 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
1922 WebFrameImpl* activeMatchFrame = mainFrameImpl->activeMatchFrame();
1923 return activeMatchFrame && activeMatchFrame->m_activeMatch && activeMatchFrame->frame()->tree()->isDescendantOf(mainFrameImpl->frame());
1926 void WebFrameImpl::updateFindMatchRects()
1928 IntSize currentContentsSize = contentsSize();
1929 if (m_contentsSizeForCurrentFindMatchRects != currentContentsSize) {
1930 m_contentsSizeForCurrentFindMatchRects = currentContentsSize;
1931 m_findMatchRectsAreValid = false;
1934 size_t deadMatches = 0;
1935 for (Vector<FindMatch>::iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) {
1936 if (!it->m_range->boundaryPointsValid() || !it->m_range->startContainer()->inDocument())
1937 it->m_rect = FloatRect();
1938 else if (!m_findMatchRectsAreValid)
1939 it->m_rect = findInPageRectFromRange(it->m_range.get());
1941 if (it->m_rect.isEmpty())
1945 // Remove any invalid matches from the cache.
1947 Vector<FindMatch> filteredMatches;
1948 filteredMatches.reserveCapacity(m_findMatchesCache.size() - deadMatches);
1950 for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it)
1951 if (!it->m_rect.isEmpty())
1952 filteredMatches.append(*it);
1954 m_findMatchesCache.swap(filteredMatches);
1957 // Invalidate the rects in child frames. Will be updated later during traversal.
1958 if (!m_findMatchRectsAreValid)
1959 for (WebFrame* child = firstChild(); child; child = child->nextSibling())
1960 static_cast<WebFrameImpl*>(child)->m_findMatchRectsAreValid = false;
1962 m_findMatchRectsAreValid = true;
1965 WebFloatRect WebFrameImpl::activeFindMatchRect()
1969 if (!isActiveMatchFrameValid())
1970 return WebFloatRect();
1972 return WebFloatRect(findInPageRectFromRange(m_currentActiveMatchFrame->m_activeMatch.get()));
1975 void WebFrameImpl::findMatchRects(WebVector<WebFloatRect>& outputRects)
1979 Vector<WebFloatRect> matchRects;
1980 for (WebFrameImpl* frame = this; frame; frame = static_cast<WebFrameImpl*>(frame->traverseNext(false)))
1981 frame->appendFindMatchRects(matchRects);
1983 outputRects = matchRects;
1986 void WebFrameImpl::appendFindMatchRects(Vector<WebFloatRect>& frameRects)
1988 updateFindMatchRects();
1989 frameRects.reserveCapacity(frameRects.size() + m_findMatchesCache.size());
1990 for (Vector<FindMatch>::const_iterator it = m_findMatchesCache.begin(); it != m_findMatchesCache.end(); ++it) {
1991 ASSERT(!it->m_rect.isEmpty());
1992 frameRects.append(it->m_rect);
1996 int WebFrameImpl::selectNearestFindMatch(const WebFloatPoint& point, WebRect* selectionRect)
2000 WebFrameImpl* bestFrame = 0;
2001 int indexInBestFrame = -1;
2002 float distanceInBestFrame = FLT_MAX;
2004 for (WebFrameImpl* frame = this; frame; frame = static_cast<WebFrameImpl*>(frame->traverseNext(false))) {
2005 float distanceInFrame;
2006 int indexInFrame = frame->nearestFindMatch(point, distanceInFrame);
2007 if (distanceInFrame < distanceInBestFrame) {
2009 indexInBestFrame = indexInFrame;
2010 distanceInBestFrame = distanceInFrame;
2014 if (indexInBestFrame != -1)
2015 return bestFrame->selectFindMatch(static_cast<unsigned>(indexInBestFrame), selectionRect);
2020 int WebFrameImpl::nearestFindMatch(const FloatPoint& point, float& distanceSquared)
2022 updateFindMatchRects();
2025 distanceSquared = FLT_MAX;
2026 for (size_t i = 0; i < m_findMatchesCache.size(); ++i) {
2027 ASSERT(!m_findMatchesCache[i].m_rect.isEmpty());
2028 FloatSize offset = point - m_findMatchesCache[i].m_rect.center();
2029 float width = offset.width();
2030 float height = offset.height();
2031 float currentDistanceSquared = width * width + height * height;
2032 if (currentDistanceSquared < distanceSquared) {
2034 distanceSquared = currentDistanceSquared;
2040 int WebFrameImpl::selectFindMatch(unsigned index, WebRect* selectionRect)
2042 ASSERT_WITH_SECURITY_IMPLICATION(index < m_findMatchesCache.size());
2044 RefPtr<Range> range = m_findMatchesCache[index].m_range;
2045 if (!range->boundaryPointsValid() || !range->startContainer()->inDocument())
2048 // Check if the match is already selected.
2049 WebFrameImpl* activeMatchFrame = viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame;
2050 if (this != activeMatchFrame || !m_activeMatch || !areRangesEqual(m_activeMatch.get(), range.get())) {
2051 if (isActiveMatchFrameValid())
2052 activeMatchFrame->setMarkerActive(activeMatchFrame->m_activeMatch.get(), false);
2054 m_activeMatchIndexInCurrentFrame = m_findMatchesCache[index].m_ordinal - 1;
2056 // Set this frame as the active frame (the one with the active highlight).
2057 viewImpl()->mainFrameImpl()->m_currentActiveMatchFrame = this;
2058 viewImpl()->setFocusedFrame(this);
2060 m_activeMatch = range.release();
2061 setMarkerActive(m_activeMatch.get(), true);
2063 // Clear any user selection, to make sure Find Next continues on from the match we just activated.
2064 frame()->selection()->clear();
2066 // Make sure no node is focused. See http://crbug.com/38700.
2067 frame()->document()->setFocusedNode(0);
2070 IntRect activeMatchRect;
2071 IntRect activeMatchBoundingBox = enclosingIntRect(RenderObject::absoluteBoundingBoxRectForRange(m_activeMatch.get()));
2073 if (!activeMatchBoundingBox.isEmpty()) {
2074 if (m_activeMatch->firstNode() && m_activeMatch->firstNode()->renderer())
2075 m_activeMatch->firstNode()->renderer()->scrollRectToVisible(activeMatchBoundingBox,
2076 ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
2078 // Zoom to the active match.
2079 activeMatchRect = frameView()->contentsToWindow(activeMatchBoundingBox);
2080 viewImpl()->zoomToFindInPageRect(activeMatchRect);
2084 *selectionRect = activeMatchRect;
2086 return ordinalOfFirstMatchForFrame(this) + m_activeMatchIndexInCurrentFrame + 1;
2089 void WebFrameImpl::deliverIntent(const WebIntent& intent, WebMessagePortChannelArray* ports, WebDeliveredIntentClient* intentClient)
2091 #if ENABLE(WEB_INTENTS)
2092 OwnPtr<WebCore::DeliveredIntentClient> client(adoptPtr(new DeliveredIntentClientImpl(intentClient)));
2094 WebSerializedScriptValue intentData = WebSerializedScriptValue::fromString(intent.data());
2095 const WebCore::Intent* webcoreIntent = intent;
2097 // See PlatformMessagePortChannel.cpp
2098 OwnPtr<MessagePortChannelArray> channels;
2099 if (ports && ports->size()) {
2100 channels = adoptPtr(new MessagePortChannelArray(ports->size()));
2101 for (size_t i = 0; i < ports->size(); ++i) {
2102 RefPtr<PlatformMessagePortChannel> platformChannel = PlatformMessagePortChannel::create((*ports)[i]);
2103 (*ports)[i]->setClient(platformChannel.get());
2104 (*channels)[i] = MessagePortChannel::create(platformChannel);
2107 OwnPtr<MessagePortArray> portArray = WebCore::MessagePort::entanglePorts(*(frame()->document()), channels.release());
2109 RefPtr<DeliveredIntent> deliveredIntent = DeliveredIntent::create(frame(), client.release(), intent.action(), intent.type(), intentData, portArray.release(), webcoreIntent->extras());
2111 DOMWindowIntents::from(frame()->document()->domWindow())->deliver(deliveredIntent.release());
2115 WebString WebFrameImpl::contentAsText(size_t maxChars) const
2120 frameContentAsPlainText(maxChars, frame(), &text);
2121 return String::adopt(text);
2124 WebString WebFrameImpl::contentAsMarkup() const
2128 return createFullMarkup(frame()->document());
2131 WebString WebFrameImpl::renderTreeAsText(RenderAsTextControls toShow) const
2133 RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal;
2135 if (toShow & RenderAsTextDebug)
2136 behavior |= RenderAsTextShowCompositedLayers | RenderAsTextShowAddresses | RenderAsTextShowIDAndClass | RenderAsTextShowLayerNesting;
2138 if (toShow & RenderAsTextPrinting)
2139 behavior |= RenderAsTextPrintingMode;
2141 return externalRepresentation(frame(), behavior);
2144 WebString WebFrameImpl::markerTextForListItem(const WebElement& webElement) const
2146 return WebCore::markerTextForListItem(const_cast<Element*>(webElement.constUnwrap<Element>()));
2149 void WebFrameImpl::printPagesWithBoundaries(WebCanvas* canvas, const WebSize& pageSizeInPixels)
2151 ASSERT(m_printContext);
2153 GraphicsContextBuilder builder(canvas);
2154 GraphicsContext& graphicsContext = builder.context();
2155 graphicsContext.platformContext()->setPrinting(true);
2157 m_printContext->spoolAllPagesWithBoundaries(graphicsContext, FloatSize(pageSizeInPixels.width, pageSizeInPixels.height));
2160 WebRect WebFrameImpl::selectionBoundsRect() const
2162 return hasSelection() ? WebRect(IntRect(frame()->selection()->bounds(false))) : WebRect();
2165 bool WebFrameImpl::selectionStartHasSpellingMarkerFor(int from, int length) const
2169 return frame()->editor()->selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
2172 WebString WebFrameImpl::layerTreeAsText(bool showDebugInfo) const
2177 LayerTreeFlags flags = showDebugInfo ? LayerTreeFlagsIncludeDebugInfo : 0;
2178 return WebString(frame()->layerTreeAsText(flags));
2181 // WebFrameImpl public ---------------------------------------------------------
2183 PassRefPtr<WebFrameImpl> WebFrameImpl::create(WebFrameClient* client)
2185 return adoptRef(new WebFrameImpl(client));
2188 WebFrameImpl::WebFrameImpl(WebFrameClient* client)
2189 : FrameDestructionObserver(0)
2190 , m_frameLoaderClient(this)
2192 , m_currentActiveMatchFrame(0)
2193 , m_activeMatchIndexInCurrentFrame(-1)
2194 , m_locatingActiveRect(false)
2195 , m_resumeScopingFromRange(0)
2196 , m_lastMatchCount(-1)
2197 , m_totalMatchCount(-1)
2198 , m_framesScopingCount(-1)
2199 , m_findRequestIdentifier(-1)
2200 , m_scopingInProgress(false)
2201 , m_lastFindRequestCompletedWithNoMatches(false)
2202 , m_nextInvalidateAfter(0)
2203 , m_findMatchMarkersVersion(0)
2204 , m_findMatchRectsAreValid(false)
2205 , m_animationController(this)
2206 , m_identifier(generateFrameIdentifier())
2207 , m_inSameDocumentHistoryLoad(false)
2209 WebKit::Platform::current()->incrementStatsCounter(webFrameActiveCount);
2213 WebFrameImpl::~WebFrameImpl()
2215 WebKit::Platform::current()->decrementStatsCounter(webFrameActiveCount);
2218 cancelPendingScopingEffort();
2221 void WebFrameImpl::setWebCoreFrame(WebCore::Frame* frame)
2224 observeFrame(frame);
2227 void WebFrameImpl::initializeAsMainFrame(WebCore::Page* page)
2229 RefPtr<Frame> mainFrame = Frame::create(page, 0, &m_frameLoaderClient);
2230 setWebCoreFrame(mainFrame.get());
2232 // Add reference on behalf of FrameLoader. See comments in
2233 // WebFrameLoaderClient::frameLoaderDestroyed for more info.
2236 // We must call init() after m_frame is assigned because it is referenced
2241 PassRefPtr<Frame> WebFrameImpl::createChildFrame(const FrameLoadRequest& request, HTMLFrameOwnerElement* ownerElement)
2243 RefPtr<WebFrameImpl> webframe(adoptRef(new WebFrameImpl(m_client)));
2245 // Add an extra ref on behalf of the Frame/FrameLoader, which references the
2246 // WebFrame via the FrameLoaderClient interface. See the comment at the top
2247 // of this file for more info.
2250 RefPtr<Frame> childFrame = Frame::create(frame()->page(), ownerElement, &webframe->m_frameLoaderClient);
2251 webframe->setWebCoreFrame(childFrame.get());
2253 childFrame->tree()->setName(request.frameName());
2255 frame()->tree()->appendChild(childFrame);
2257 // Frame::init() can trigger onload event in the parent frame,
2258 // which may detach this frame and trigger a null-pointer access
2259 // in FrameTree::removeChild. Move init() after appendChild call
2260 // so that webframe->mFrame is in the tree before triggering
2261 // onload event handler.
2262 // Because the event handler may set webframe->mFrame to null,
2263 // it is necessary to check the value after calling init() and
2264 // return without loading URL.
2266 childFrame->init(); // create an empty document
2267 if (!childFrame->tree()->parent())
2270 frame()->loader()->loadURLIntoChildFrame(request.resourceRequest().url(), request.resourceRequest().httpReferrer(), childFrame.get());
2272 // A synchronous navigation (about:blank) would have already processed
2273 // onload, so it is possible for the frame to have already been destroyed by
2274 // script in the page.
2275 if (!childFrame->tree()->parent())
2279 m_client->didCreateFrame(this, webframe.get());
2281 return childFrame.release();
2284 void WebFrameImpl::didChangeContentsSize(const IntSize& size)
2286 // This is only possible on the main frame.
2287 if (m_totalMatchCount > 0) {
2289 ++m_findMatchMarkersVersion;
2293 void WebFrameImpl::createFrameView()
2295 TRACE_EVENT0("webkit", "WebFrameImpl::createFrameView");
2297 ASSERT(frame()); // If frame() doesn't exist, we probably didn't init properly.
2299 WebViewImpl* webView = viewImpl();
2300 bool isMainFrame = webView->mainFrameImpl()->frame() == frame();
2302 webView->suppressInvalidations(true);
2304 frame()->createView(webView->size(), Color::white, webView->isTransparent(), webView->fixedLayoutSize(), IntRect(), isMainFrame ? webView->isFixedLayoutModeEnabled() : 0);
2305 if (webView->shouldAutoResize() && isMainFrame)
2306 frame()->view()->enableAutoSizeMode(true, webView->minAutoSize(), webView->maxAutoSize());
2309 webView->suppressInvalidations(false);
2311 if (isMainFrame && webView->devToolsAgentPrivate())
2312 webView->devToolsAgentPrivate()->mainFrameViewCreated(this);
2315 WebFrameImpl* WebFrameImpl::fromFrame(Frame* frame)
2319 return static_cast<FrameLoaderClientImpl*>(frame->loader()->client())->webFrame();
2322 WebFrameImpl* WebFrameImpl::fromFrameOwnerElement(Element* element)
2324 // FIXME: Why do we check specifically for <iframe> and <frame> here? Why can't we get the WebFrameImpl from an <object> element, for example.
2325 if (!element || !element->isFrameOwnerElement() || (!element->hasTagName(HTMLNames::iframeTag) && !element->hasTagName(HTMLNames::frameTag)))
2327 HTMLFrameOwnerElement* frameElement = static_cast<HTMLFrameOwnerElement*>(element);
2328 return fromFrame(frameElement->contentFrame());
2331 WebViewImpl* WebFrameImpl::viewImpl() const
2335 return WebViewImpl::fromPage(frame()->page());
2338 WebDataSourceImpl* WebFrameImpl::dataSourceImpl() const
2340 return static_cast<WebDataSourceImpl*>(dataSource());
2343 WebDataSourceImpl* WebFrameImpl::provisionalDataSourceImpl() const
2345 return static_cast<WebDataSourceImpl*>(provisionalDataSource());
2348 void WebFrameImpl::setFindEndstateFocusAndSelection()
2350 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
2352 if (this == mainFrameImpl->activeMatchFrame() && m_activeMatch.get()) {
2353 // If the user has set the selection since the match was found, we
2354 // don't focus anything.
2355 VisibleSelection selection(frame()->selection()->selection());
2356 if (!selection.isNone())
2359 // Try to find the first focusable node up the chain, which will, for
2360 // example, focus links if we have found text within the link.
2361 Node* node = m_activeMatch->firstNode();
2362 if (node && node->isInShadowTree()) {
2363 Node* host = node->deprecatedShadowAncestorNode();
2364 if (host->hasTagName(HTMLNames::inputTag) || host->hasTagName(HTMLNames::textareaTag))
2367 while (node && !node->isFocusable() && node != frame()->document())
2368 node = node->parentNode();
2370 if (node && node != frame()->document()) {
2371 // Found a focusable parent node. Set the active match as the
2372 // selection and focus to the focusable node.
2373 frame()->selection()->setSelection(m_activeMatch.get());
2374 frame()->document()->setFocusedNode(node);
2378 // Iterate over all the nodes in the range until we find a focusable node.
2379 // This, for example, sets focus to the first link if you search for
2380 // text and text that is within one or more links.
2381 node = m_activeMatch->firstNode();
2382 while (node && node != m_activeMatch->pastLastNode()) {
2383 if (node->isFocusable()) {
2384 frame()->document()->setFocusedNode(node);
2387 node = NodeTraversal::next(node);
2390 // No node related to the active match was focusable, so set the
2391 // active match as the selection (so that when you end the Find session,
2392 // you'll have the last thing you found highlighted) and make sure that
2393 // we have nothing focused (otherwise you might have text selected but
2394 // a link focused, which is weird).
2395 frame()->selection()->setSelection(m_activeMatch.get());
2396 frame()->document()->setFocusedNode(0);
2398 // Finally clear the active match, for two reasons:
2399 // We just finished the find 'session' and we don't want future (potentially
2400 // unrelated) find 'sessions' operations to start at the same place.
2401 // The WebFrameImpl could get reused and the m_activeMatch could end up pointing
2402 // to a document that is no longer valid. Keeping an invalid reference around
2403 // is just asking for trouble.
2408 void WebFrameImpl::didFail(const ResourceError& error, bool wasProvisional)
2412 WebURLError webError = error;
2414 client()->didFailProvisionalLoad(this, webError);
2416 client()->didFailLoad(this, webError);
2419 void WebFrameImpl::setCanHaveScrollbars(bool canHaveScrollbars)
2421 frame()->view()->setCanHaveScrollbars(canHaveScrollbars);
2424 void WebFrameImpl::invalidateArea(AreaToInvalidate area)
2426 ASSERT(frame() && frame()->view());
2427 FrameView* view = frame()->view();
2429 if ((area & InvalidateAll) == InvalidateAll)
2430 view->invalidateRect(view->frameRect());
2432 if ((area & InvalidateContentArea) == InvalidateContentArea) {
2433 IntRect contentArea(
2434 view->x(), view->y(), view->visibleWidth(), view->visibleHeight());
2435 IntRect frameRect = view->frameRect();
2436 contentArea.move(-frameRect.x(), -frameRect.y());
2437 view->invalidateRect(contentArea);
2441 if ((area & InvalidateScrollbar) == InvalidateScrollbar) {
2442 // Invalidate the vertical scroll bar region for the view.
2443 Scrollbar* scrollbar = view->verticalScrollbar();
2445 scrollbar->invalidate();
2449 void WebFrameImpl::addMarker(Range* range, bool activeMatch)
2451 frame()->document()->markers()->addTextMatchMarker(range, activeMatch);
2454 void WebFrameImpl::setMarkerActive(Range* range, bool active)
2456 WebCore::ExceptionCode ec;
2457 if (!range || range->collapsed(ec))
2459 frame()->document()->markers()->setMarkersActive(range, active);
2462 int WebFrameImpl::ordinalOfFirstMatchForFrame(WebFrameImpl* frame) const
2465 WebFrameImpl* mainFrameImpl = viewImpl()->mainFrameImpl();
2466 // Iterate from the main frame up to (but not including) |frame| and
2467 // add up the number of matches found so far.
2468 for (WebFrameImpl* it = mainFrameImpl; it != frame; it = static_cast<WebFrameImpl*>(it->traverseNext(true))) {
2469 if (it->m_lastMatchCount > 0)
2470 ordinal += it->m_lastMatchCount;
2475 bool WebFrameImpl::shouldScopeMatches(const String& searchText)
2477 // Don't scope if we can't find a frame or a view.
2478 // The user may have closed the tab/application, so abort.
2479 // Also ignore detached frames, as many find operations report to the main frame.
2480 if (!frame() || !frame()->view() || !frame()->page() || !hasVisibleContent())
2483 ASSERT(frame()->document() && frame()->view());
2485 // If the frame completed the scoping operation and found 0 matches the last
2486 // time it was searched, then we don't have to search it again if the user is
2487 // just adding to the search string or sending the same search string again.
2488 if (m_lastFindRequestCompletedWithNoMatches && !m_lastSearchString.isEmpty()) {
2489 // Check to see if the search string prefixes match.
2490 String previousSearchPrefix =
2491 searchText.substring(0, m_lastSearchString.length());
2493 if (previousSearchPrefix == m_lastSearchString)
2494 return false; // Don't search this frame, it will be fruitless.
2500 void WebFrameImpl::scopeStringMatchesSoon(int identifier, const WebString& searchText, const WebFindOptions& options, bool reset)
2502 m_deferredScopingWork.append(new DeferredScopeStringMatches(this, identifier, searchText, options, reset));
2505 void WebFrameImpl::callScopeStringMatches(DeferredScopeStringMatches* caller, int identifier, const WebString& searchText, const WebFindOptions& options, bool reset)
2507 m_deferredScopingWork.remove(m_deferredScopingWork.find(caller));
2508 scopeStringMatches(identifier, searchText, options, reset);
2510 // This needs to happen last since searchText is passed by reference.
2514 void WebFrameImpl::invalidateIfNecessary()
2516 if (m_lastMatchCount <= m_nextInvalidateAfter)
2519 // FIXME: (http://b/1088165) Optimize the drawing of the tickmarks and
2520 // remove this. This calculation sets a milestone for when next to
2521 // invalidate the scrollbar and the content area. We do this so that we
2522 // don't spend too much time drawing the scrollbar over and over again.
2523 // Basically, up until the first 500 matches there is no throttle.
2524 // After the first 500 matches, we set set the milestone further and
2525 // further out (750, 1125, 1688, 2K, 3K).
2526 static const int startSlowingDownAfter = 500;
2527 static const int slowdown = 750;
2529 int i = m_lastMatchCount / startSlowingDownAfter;
2530 m_nextInvalidateAfter += i * slowdown;
2531 invalidateArea(InvalidateScrollbar);
2534 void WebFrameImpl::loadJavaScriptURL(const KURL& url)
2536 // This is copied from ScriptController::executeIfJavaScriptURL.
2537 // Unfortunately, we cannot just use that method since it is private, and
2538 // it also doesn't quite behave as we require it to for bookmarklets. The
2539 // key difference is that we need to suppress loading the string result
2540 // from evaluating the JS URL if executing the JS URL resulted in a
2541 // location change. We also allow a JS URL to be loaded even if scripts on
2542 // the page are otherwise disabled.
2544 if (!frame()->document() || !frame()->page())
2547 RefPtr<Document> ownerDocument(frame()->document());
2549 // Protect privileged pages against bookmarklets and other javascript manipulations.
2550 if (SchemeRegistry::shouldTreatURLSchemeAsNotAllowingJavascriptURLs(frame()->document()->url().protocol()))
2553 String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:")));
2554 ScriptValue result = frame()->script()->executeScript(script, true);
2556 String scriptResult;
2557 if (!result.getString(scriptResult))
2560 if (!frame()->navigationScheduler()->locationChangePending())
2561 frame()->document()->loader()->writer()->replaceDocument(scriptResult, ownerDocument.get());
2564 void WebFrameImpl::willDetachPage()
2566 if (!frame() || !frame()->page())
2569 // Do not expect string scoping results from any frames that got detached
2570 // in the middle of the operation.
2571 if (m_scopingInProgress) {
2573 // There is a possibility that the frame being detached was the only
2574 // pending one. We need to make sure final replies can be sent.
2575 flushCurrentScopingEffort(m_findRequestIdentifier);
2577 cancelPendingScopingEffort();
2581 } // namespace WebKit