2 * Copyright (C) 2010 Apple 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
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
29 #include "DownloadManager.h"
30 #include "InjectedBundleNodeHandle.h"
31 #include "InjectedBundleRangeHandle.h"
32 #include "InjectedBundleScriptWorld.h"
33 #include "WKAPICast.h"
34 #include "WKBundleAPICast.h"
35 #include "WebChromeClient.h"
37 #include "WebPageProxyMessages.h"
38 #include "WebProcess.h"
39 #include <JavaScriptCore/APICast.h>
40 #include <JavaScriptCore/JSContextRef.h>
41 #include <JavaScriptCore/JSLock.h>
42 #include <JavaScriptCore/JSValueRef.h>
43 #include <WebCore/AnimationController.h>
44 #include <WebCore/ArchiveResource.h>
45 #include <WebCore/CSSComputedStyleDeclaration.h>
46 #include <WebCore/Chrome.h>
47 #include <WebCore/DocumentLoader.h>
48 #include <WebCore/Frame.h>
49 #include <WebCore/FrameView.h>
50 #include <WebCore/HTMLFrameOwnerElement.h>
51 #include <WebCore/HTMLNames.h>
52 #include <WebCore/JSCSSStyleDeclaration.h>
53 #include <WebCore/JSElement.h>
54 #include <WebCore/JSRange.h>
55 #include <WebCore/Page.h>
56 #include <WebCore/RenderTreeAsText.h>
57 #include <WebCore/SecurityOrigin.h>
58 #include <WebCore/TextIterator.h>
59 #include <WebCore/TextResourceDecoder.h>
60 #include <wtf/text/StringBuilder.h>
62 #if ENABLE(WEB_INTENTS)
63 #include "IntentData.h"
64 #include <WebCore/DOMWindowIntents.h>
65 #include <WebCore/DeliveredIntent.h>
68 #if PLATFORM(MAC) || PLATFORM(WIN)
69 #include <WebCore/LegacyWebArchive.h>
73 #include <wtf/RefCountedLeakCounter.h>
77 using namespace WebCore;
81 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webFrameCounter, ("WebFrame"));
83 static uint64_t generateFrameID()
85 static uint64_t uniqueFrameID = 1;
86 return uniqueFrameID++;
89 static uint64_t generateListenerID()
91 static uint64_t uniqueListenerID = 1;
92 return uniqueListenerID++;
95 PassRefPtr<WebFrame> WebFrame::createMainFrame(WebPage* page)
97 RefPtr<WebFrame> frame = create();
99 page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()));
101 frame->init(page, String(), 0);
103 return frame.release();
106 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
108 RefPtr<WebFrame> frame = create();
110 WebFrame* parentFrame = static_cast<WebFrameLoaderClient*>(ownerElement->document()->frame()->loader()->client())->webFrame();
111 page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID(), parentFrame->frameID()));
113 frame->init(page, frameName, ownerElement);
115 return frame.release();
118 PassRefPtr<WebFrame> WebFrame::create()
120 RefPtr<WebFrame> frame = adoptRef(new WebFrame);
122 // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
125 return frame.release();
130 , m_policyListenerID(0)
131 , m_policyFunction(0)
132 , m_policyDownloadID(0)
133 , m_frameLoaderClient(this)
135 , m_frameID(generateFrameID())
137 WebProcess::shared().addWebFrame(m_frameID, this);
140 webFrameCounter.increment();
144 WebFrame::~WebFrame()
146 ASSERT(!m_coreFrame);
149 webFrameCounter.decrement();
153 void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
155 RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient);
156 m_coreFrame = frame.get();
158 frame->tree()->setName(frameName);
161 ASSERT(ownerElement->document()->frame());
162 ownerElement->document()->frame()->tree()->appendChild(frame);
168 WebPage* WebFrame::page() const
173 if (WebCore::Page* page = m_coreFrame->page())
174 return static_cast<WebChromeClient*>(page->chrome()->client())->page();
179 void WebFrame::invalidate()
181 WebProcess::shared().removeWebFrame(m_frameID);
185 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
187 // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
189 invalidatePolicyListener();
191 m_policyListenerID = generateListenerID();
192 m_policyFunction = policyFunction;
193 return m_policyListenerID;
196 void WebFrame::invalidatePolicyListener()
198 if (!m_policyListenerID)
201 m_policyDownloadID = 0;
202 m_policyListenerID = 0;
203 m_policyFunction = 0;
206 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID)
211 if (!m_policyListenerID)
214 if (listenerID != m_policyListenerID)
217 ASSERT(m_policyFunction);
219 FramePolicyFunction function = m_policyFunction;
221 invalidatePolicyListener();
223 m_policyDownloadID = downloadID;
225 (m_coreFrame->loader()->policyChecker()->*function)(action);
228 #if ENABLE(TIZEN_DOWNLOAD_ATTRIBUTE)
229 void WebFrame::startDownload(const WebCore::ResourceRequest& request, const String& suggestedName)
231 #if ENABLE(DOWNLOAD_ATTRIBUTE)
232 if (!m_policyDownloadID) {
233 // If m_policyDownloadID doesn't exists, a new download session with a new downloadID (from UI Process) is needed.
234 page()->send(Messages::WebPageProxy::StartDownload(request, suggestedName));
238 UNUSED_PARAM(suggestedName);
240 ASSERT(m_policyDownloadID);
241 DownloadManager::shared().startDownload(m_policyDownloadID, page(), request);
242 m_policyDownloadID = 0;
245 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
247 ASSERT(m_policyDownloadID);
249 DownloadManager::shared().startDownload(m_policyDownloadID, page(), request);
251 m_policyDownloadID = 0;
255 void WebFrame::convertHandleToDownload(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& response)
257 ASSERT(m_policyDownloadID);
259 DownloadManager::shared().convertHandleToDownload(m_policyDownloadID, page(), handle, request, response);
260 m_policyDownloadID = 0;
263 #if ENABLE(WEB_INTENTS)
264 void WebFrame::deliverIntent(const IntentData& intentData)
266 OwnPtr<DeliveredIntentClient> dummyClient;
267 OwnPtr<MessagePortArray> dummyPorts;
268 Vector<uint8_t> dataCopy = intentData.data;
269 RefPtr<DeliveredIntent> deliveredIntent = DeliveredIntent::create(m_coreFrame, dummyClient.release(), intentData.action, intentData.type,
270 SerializedScriptValue::adopt(dataCopy), dummyPorts.release(),
272 WebCore::DOMWindowIntents::from(m_coreFrame->domWindow())->deliver(deliveredIntent.release());
276 String WebFrame::source() const
280 Document* document = m_coreFrame->document();
283 TextResourceDecoder* decoder = document->decoder();
286 DocumentLoader* documentLoader = m_coreFrame->loader()->activeDocumentLoader();
289 RefPtr<SharedBuffer> mainResourceData = documentLoader->mainResourceData();
290 if (!mainResourceData)
292 return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
295 String WebFrame::contentsAsString() const
301 StringBuilder builder;
302 for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
303 if (!builder.isEmpty())
305 builder.append(static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame()->contentsAsString());
307 // FIXME: It may make sense to use toStringPreserveCapacity() here.
308 return builder.toString();
311 Document* document = m_coreFrame->document();
315 RefPtr<Element> documentElement = document->documentElement();
316 if (!documentElement)
319 RefPtr<Range> range = document->createRange();
321 ExceptionCode ec = 0;
322 range->selectNode(documentElement.get(), ec);
326 return plainText(range.get());
329 String WebFrame::selectionAsString() const
334 return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor()->selectedText());
337 IntSize WebFrame::size() const
342 FrameView* frameView = m_coreFrame->view();
346 return frameView->contentsSize();
349 bool WebFrame::isFrameSet() const
354 Document* document = m_coreFrame->document();
357 return document->isFrameSet();
360 bool WebFrame::isMainFrame() const
362 if (WebPage* p = page())
363 return p->mainWebFrame() == this;
368 String WebFrame::name() const
373 return m_coreFrame->tree()->uniqueName();
376 String WebFrame::url() const
381 DocumentLoader* documentLoader = m_coreFrame->loader()->documentLoader();
385 return documentLoader->url().string();
388 String WebFrame::innerText() const
393 if (!m_coreFrame->document()->documentElement())
396 return m_coreFrame->document()->documentElement()->innerText();
399 WebFrame* WebFrame::parentFrame() const
401 if (!m_coreFrame || !m_coreFrame->ownerElement() || !m_coreFrame->ownerElement()->document())
404 return static_cast<WebFrameLoaderClient*>(m_coreFrame->ownerElement()->document()->frame()->loader()->client())->webFrame();
407 PassRefPtr<ImmutableArray> WebFrame::childFrames()
410 return ImmutableArray::create();
412 size_t size = m_coreFrame->tree()->childCount();
414 return ImmutableArray::create();
416 Vector<RefPtr<APIObject> > vector;
417 vector.reserveInitialCapacity(size);
419 for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
420 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame();
421 vector.uncheckedAppend(webFrame);
424 return ImmutableArray::adopt(vector);
427 unsigned WebFrame::numberOfActiveAnimations() const
432 AnimationController* controller = m_coreFrame->animation();
436 return controller->numberOfActiveAnimations(m_coreFrame->document());
439 bool WebFrame::pauseAnimationOnElementWithId(const String& animationName, const String& elementID, double time)
444 AnimationController* controller = m_coreFrame->animation();
448 if (!m_coreFrame->document())
451 Node* coreNode = m_coreFrame->document()->getElementById(elementID);
452 if (!coreNode || !coreNode->renderer())
455 return controller->pauseAnimationAtTime(coreNode->renderer(), animationName, time);
458 bool WebFrame::pauseTransitionOnElementWithId(const String& propertyName, const String& elementID, double time)
463 AnimationController* controller = m_coreFrame->animation();
467 if (!m_coreFrame->document())
470 Node* coreNode = m_coreFrame->document()->getElementById(elementID);
471 if (!coreNode || !coreNode->renderer())
474 return controller->pauseTransitionAtTime(coreNode->renderer(), propertyName, time);
477 void WebFrame::suspendAnimations()
482 AnimationController* controller = m_coreFrame->animation();
486 controller->suspendAnimations();
489 void WebFrame::resumeAnimations()
494 AnimationController* controller = m_coreFrame->animation();
498 controller->resumeAnimations();
501 String WebFrame::layerTreeAsText() const
506 return m_coreFrame->layerTreeAsText();
509 unsigned WebFrame::pendingUnloadCount() const
514 return m_coreFrame->domWindow()->pendingUnloadEventListeners();
517 bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const
522 return m_coreFrame->document()->securityOrigin()->canDisplay(url);
525 JSGlobalContextRef WebFrame::jsContext()
527 return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
530 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
532 return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec());
535 IntRect WebFrame::contentBounds() const
540 FrameView* view = m_coreFrame->view();
544 return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
547 IntRect WebFrame::visibleContentBounds() const
552 FrameView* view = m_coreFrame->view();
556 IntRect contentRect = view->visibleContentRect(true);
557 return IntRect(0, 0, contentRect.width(), contentRect.height());
560 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
565 FrameView* view = m_coreFrame->view();
569 IntRect contentRect = view->visibleContentRect(false);
570 return IntRect(0, 0, contentRect.width(), contentRect.height());
573 IntSize WebFrame::scrollOffset() const
578 FrameView* view = m_coreFrame->view();
582 return view->scrollOffset();
585 bool WebFrame::hasHorizontalScrollbar() const
590 FrameView* view = m_coreFrame->view();
594 return view->horizontalScrollbar();
597 bool WebFrame::hasVerticalScrollbar() const
602 FrameView* view = m_coreFrame->view();
606 return view->verticalScrollbar();
609 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
614 FrameView* view = m_coreFrame->view();
618 Color bgColor = view->documentBackgroundColor();
619 if (!bgColor.isValid())
622 bgColor.getRGBA(*red, *green, *blue, *alpha);
626 bool WebFrame::containsAnyFormElements() const
631 Document* document = m_coreFrame->document();
635 for (Node* node = document->documentElement(); node; node = node->traverseNextNode()) {
636 if (!node->isElementNode())
638 if (static_cast<Element*>(node)->hasTagName(HTMLNames::formTag))
644 WebFrame* WebFrame::frameForContext(JSContextRef context)
646 JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
647 JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
648 if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
651 Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
652 return static_cast<WebFrameLoaderClient*>(coreFrame->loader()->client())->webFrame();
655 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
660 JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
661 ExecState* exec = globalObject->globalExec();
663 JSLockHolder lock(exec);
664 return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
667 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
672 JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
673 ExecState* exec = globalObject->globalExec();
675 JSLockHolder lock(exec);
676 return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
679 JSValueRef WebFrame::computedStyleIncludingVisitedInfo(JSObjectRef element)
684 JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(mainThreadNormalWorld());
685 ExecState* exec = globalObject->globalExec();
687 if (!toJS(element)->inherits(&JSElement::s_info))
688 return JSValueMakeUndefined(toRef(exec));
690 RefPtr<CSSComputedStyleDeclaration> style = CSSComputedStyleDeclaration::create(static_cast<JSElement*>(toJS(element))->impl(), true);
692 JSLockHolder lock(exec);
693 return toRef(exec, toJS(exec, globalObject, style.get()));
696 String WebFrame::counterValue(JSObjectRef element)
698 if (!toJS(element)->inherits(&JSElement::s_info))
701 return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
704 String WebFrame::markerText(JSObjectRef element)
706 if (!toJS(element)->inherits(&JSElement::s_info))
709 return markerTextForListItem(static_cast<JSElement*>(toJS(element))->impl());
712 String WebFrame::provisionalURL() const
717 return m_coreFrame->loader()->provisionalDocumentLoader()->url().string();
720 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const
725 DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
729 // First, try the main resource.
730 if (loader->url() == url)
731 return loader->response().suggestedFilename();
733 // Next, try subresources.
734 RefPtr<ArchiveResource> resource = loader->subresource(url);
736 return resource->response().suggestedFilename();
738 return page()->cachedSuggestedFilenameForURL(url);
741 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const
746 DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
750 // First, try the main resource.
751 if (loader->url() == url)
752 return loader->response().mimeType();
754 // Next, try subresources.
755 RefPtr<ArchiveResource> resource = loader->subresource(url);
757 return resource->mimeType();
759 return page()->cachedResponseMIMETypeForURL(url);
762 void WebFrame::setTextDirection(const String& direction)
764 if (!m_coreFrame || !m_coreFrame->editor())
767 if (direction == "auto")
768 m_coreFrame->editor()->setBaseWritingDirection(NaturalWritingDirection);
769 else if (direction == "ltr")
770 m_coreFrame->editor()->setBaseWritingDirection(LeftToRightWritingDirection);
771 else if (direction == "rtl")
772 m_coreFrame->editor()->setBaseWritingDirection(RightToLeftWritingDirection);
775 #if PLATFORM(MAC) || PLATFORM(WIN)
777 class WebFrameFilter : public FrameFilter {
779 WebFrameFilter(WebFrame*, WebFrame::FrameFilterFunction, void* context);
782 virtual bool shouldIncludeSubframe(Frame*) const OVERRIDE;
784 WebFrame* m_topLevelWebFrame;
785 WebFrame::FrameFilterFunction m_callback;
789 WebFrameFilter::WebFrameFilter(WebFrame* topLevelWebFrame, WebFrame::FrameFilterFunction callback, void* context)
790 : m_topLevelWebFrame(topLevelWebFrame)
791 , m_callback(callback)
796 bool WebFrameFilter::shouldIncludeSubframe(Frame* frame) const
801 WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame();
802 return m_callback(toAPI(m_topLevelWebFrame), toAPI(webFrame), m_context);
805 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
807 WebFrameFilter filter(this, callback, context);
809 if (RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), &filter))
810 return archive->rawDataRepresentation();
816 } // namespace WebKit