Make Frame's ScriptController an OwnPtr and remove the #include
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / WebFrame.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
24  */
25
26 #include "config.h"
27 #include "WebFrame.h"
28
29 #include "DownloadManager.h"
30 #include "InjectedBundleHitTestResult.h"
31 #include "InjectedBundleNodeHandle.h"
32 #include "InjectedBundleRangeHandle.h"
33 #include "InjectedBundleScriptWorld.h"
34 #include "PluginView.h"
35 #include "WKAPICast.h"
36 #include "WKBundleAPICast.h"
37 #include "WebChromeClient.h"
38 #include "WebPage.h"
39 #include "WebPageProxyMessages.h"
40 #include "WebProcess.h"
41 #include <JavaScriptCore/APICast.h>
42 #include <JavaScriptCore/JSContextRef.h>
43 #include <JavaScriptCore/JSLock.h>
44 #include <JavaScriptCore/JSValueRef.h>
45 #include <WebCore/ArchiveResource.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/NetworkingContext.h>
56 #include <WebCore/NodeTraversal.h>
57 #include <WebCore/Page.h>
58 #include <WebCore/PluginDocument.h>
59 #include <WebCore/RenderTreeAsText.h>
60 #include <WebCore/ResourceBuffer.h>
61 #include <WebCore/ResourceLoader.h>
62 #include <WebCore/ScriptController.h>
63 #include <WebCore/SecurityOrigin.h>
64 #include <WebCore/TextIterator.h>
65 #include <WebCore/TextResourceDecoder.h>
66 #include <wtf/text/StringBuilder.h>
67
68 #if PLATFORM(MAC)
69 #include <WebCore/LegacyWebArchive.h>
70 #endif
71
72 #if ENABLE(NETWORK_PROCESS)
73 #include "NetworkConnectionToWebProcessMessages.h"
74 #include "NetworkProcessConnection.h"
75 #include "WebCoreArgumentCoders.h"
76 #endif
77
78 #ifndef NDEBUG
79 #include <wtf/RefCountedLeakCounter.h>
80 #endif
81
82 using namespace JSC;
83 using namespace WebCore;
84
85 namespace WebKit {
86
87 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webFrameCounter, ("WebFrame"));
88
89 static uint64_t generateFrameID()
90 {
91     static uint64_t uniqueFrameID = 1;
92     return uniqueFrameID++;
93 }
94
95 static uint64_t generateListenerID()
96 {
97     static uint64_t uniqueListenerID = 1;
98     return uniqueListenerID++;
99 }
100
101 PassRefPtr<WebFrame> WebFrame::createMainFrame(WebPage* page)
102 {
103     RefPtr<WebFrame> frame = create();
104
105     page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()));
106
107     frame->init(page, String(), 0);
108
109     return frame.release();
110 }
111
112 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
113 {
114     RefPtr<WebFrame> frame = create();
115
116     page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID()));
117
118     frame->init(page, frameName, ownerElement);
119
120     return frame.release();
121 }
122
123 PassRefPtr<WebFrame> WebFrame::create()
124 {
125     RefPtr<WebFrame> frame = adoptRef(new WebFrame);
126
127     // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
128     frame->ref();
129
130     return frame.release();
131 }
132
133 WebFrame::WebFrame()
134     : m_coreFrame(0)
135     , m_policyListenerID(0)
136     , m_policyFunction(0)
137     , m_policyDownloadID(0)
138     , m_frameLoaderClient(this)
139     , m_loadListener(0)
140     , m_frameID(generateFrameID())
141 {
142     WebProcess::shared().addWebFrame(m_frameID, this);
143
144 #ifndef NDEBUG
145     webFrameCounter.increment();
146 #endif
147 }
148
149 WebFrame::~WebFrame()
150 {
151     ASSERT(!m_coreFrame);
152
153 #ifndef NDEBUG
154     webFrameCounter.decrement();
155 #endif
156 }
157
158 void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
159 {
160     RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient);
161     m_coreFrame = frame.get();
162
163     frame->tree()->setName(frameName);
164
165     if (ownerElement) {
166         ASSERT(ownerElement->document()->frame());
167         ownerElement->document()->frame()->tree()->appendChild(frame);
168     }
169
170     frame->init();
171 }
172
173 WebPage* WebFrame::page() const
174
175     if (!m_coreFrame)
176         return 0;
177     
178     if (Page* page = m_coreFrame->page())
179         return WebPage::fromCorePage(page);
180
181     return 0;
182 }
183
184 void WebFrame::invalidate()
185 {
186     WebProcess::shared().removeWebFrame(m_frameID);
187     m_coreFrame = 0;
188 }
189
190 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
191 {
192     // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
193
194     invalidatePolicyListener();
195
196     m_policyListenerID = generateListenerID();
197     m_policyFunction = policyFunction;
198     return m_policyListenerID;
199 }
200
201 void WebFrame::invalidatePolicyListener()
202 {
203     if (!m_policyListenerID)
204         return;
205
206     m_policyDownloadID = 0;
207     m_policyListenerID = 0;
208     m_policyFunction = 0;
209 }
210
211 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID)
212 {
213     if (!m_coreFrame)
214         return;
215
216     if (!m_policyListenerID)
217         return;
218
219     if (listenerID != m_policyListenerID)
220         return;
221
222     ASSERT(m_policyFunction);
223
224     FramePolicyFunction function = m_policyFunction;
225
226     invalidatePolicyListener();
227
228     m_policyDownloadID = downloadID;
229
230     (m_coreFrame->loader()->policyChecker()->*function)(action);
231 }
232
233 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
234 {
235     ASSERT(m_policyDownloadID);
236
237     uint64_t policyDownloadID = m_policyDownloadID;
238     m_policyDownloadID = 0;
239
240 #if ENABLE(NETWORK_PROCESS)
241     if (WebProcess::shared().usesNetworkProcess()) {
242         bool privateBrowsingEnabled = m_coreFrame->loader()->networkingContext()->storageSession().isPrivateBrowsingSession();
243         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::StartDownload(privateBrowsingEnabled, policyDownloadID, request), 0);
244         return;
245     }
246 #endif
247
248     WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
249 }
250
251 void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, const ResourceRequest& request, const ResourceResponse& response)
252 {
253     ASSERT(m_policyDownloadID);
254
255     uint64_t policyDownloadID = m_policyDownloadID;
256     m_policyDownloadID = 0;
257
258 #if ENABLE(NETWORK_PROCESS)
259     if (WebProcess::shared().usesNetworkProcess()) {
260         // FIXME: Handle this case.
261         return;
262     }
263 #endif
264
265     WebProcess::shared().downloadManager().convertHandleToDownload(policyDownloadID, documentLoader->mainResourceLoader()->handle(), request, response);
266 }
267
268 String WebFrame::source() const 
269 {
270     if (!m_coreFrame)
271         return String();
272     Document* document = m_coreFrame->document();
273     if (!document)
274         return String();
275     TextResourceDecoder* decoder = document->decoder();
276     if (!decoder)
277         return String();
278     DocumentLoader* documentLoader = m_coreFrame->loader()->activeDocumentLoader();
279     if (!documentLoader)
280         return String();
281     RefPtr<ResourceBuffer> mainResourceData = documentLoader->mainResourceData();
282     if (!mainResourceData)
283         return String();
284     return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
285 }
286
287 String WebFrame::contentsAsString() const 
288 {
289     if (!m_coreFrame)
290         return String();
291
292     if (isFrameSet()) {
293         StringBuilder builder;
294         for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
295             if (!builder.isEmpty())
296                 builder.append(' ');
297             builder.append(static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame()->contentsAsString());
298         }
299         // FIXME: It may make sense to use toStringPreserveCapacity() here.
300         return builder.toString();
301     }
302
303     Document* document = m_coreFrame->document();
304     if (!document)
305         return String();
306
307     RefPtr<Element> documentElement = document->documentElement();
308     if (!documentElement)
309         return String();
310
311     RefPtr<Range> range = document->createRange();
312
313     ExceptionCode ec = 0;
314     range->selectNode(documentElement.get(), ec);
315     if (ec)
316         return String();
317
318     return plainText(range.get());
319 }
320
321 String WebFrame::selectionAsString() const 
322 {
323     if (!m_coreFrame)
324         return String();
325
326     return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor()->selectedText());
327 }
328
329 IntSize WebFrame::size() const
330 {
331     if (!m_coreFrame)
332         return IntSize();
333
334     FrameView* frameView = m_coreFrame->view();
335     if (!frameView)
336         return IntSize();
337
338     return frameView->contentsSize();
339 }
340
341 bool WebFrame::isFrameSet() const
342 {
343     if (!m_coreFrame)
344         return false;
345
346     Document* document = m_coreFrame->document();
347     if (!document)
348         return false;
349     return document->isFrameSet();
350 }
351
352 bool WebFrame::isMainFrame() const
353 {
354     if (WebPage* p = page())
355         return p->mainWebFrame() == this;
356
357     return false;
358 }
359
360 String WebFrame::name() const
361 {
362     if (!m_coreFrame)
363         return String();
364
365     return m_coreFrame->tree()->uniqueName();
366 }
367
368 String WebFrame::url() const
369 {
370     if (!m_coreFrame)
371         return String();
372
373     DocumentLoader* documentLoader = m_coreFrame->loader()->documentLoader();
374     if (!documentLoader)
375         return String();
376
377     return documentLoader->url().string();
378 }
379
380 String WebFrame::innerText() const
381 {
382     if (!m_coreFrame)
383         return String();
384
385     if (!m_coreFrame->document()->documentElement())
386         return String();
387
388     return m_coreFrame->document()->documentElement()->innerText();
389 }
390
391 WebFrame* WebFrame::parentFrame() const
392 {
393     if (!m_coreFrame || !m_coreFrame->ownerElement() || !m_coreFrame->ownerElement()->document())
394         return 0;
395
396     return static_cast<WebFrameLoaderClient*>(m_coreFrame->ownerElement()->document()->frame()->loader()->client())->webFrame();
397 }
398
399 PassRefPtr<ImmutableArray> WebFrame::childFrames()
400 {
401     if (!m_coreFrame)
402         return ImmutableArray::create();
403
404     size_t size = m_coreFrame->tree()->childCount();
405     if (!size)
406         return ImmutableArray::create();
407
408     Vector<RefPtr<APIObject> > vector;
409     vector.reserveInitialCapacity(size);
410
411     for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
412         WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame();
413         vector.uncheckedAppend(webFrame);
414     }
415
416     return ImmutableArray::adopt(vector);
417 }
418
419 String WebFrame::layerTreeAsText() const
420 {
421     if (!m_coreFrame)
422         return "";
423
424     return m_coreFrame->layerTreeAsText(0);
425 }
426
427 unsigned WebFrame::pendingUnloadCount() const
428 {
429     if (!m_coreFrame)
430         return 0;
431
432     return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
433 }
434
435 bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const
436 {
437     if (!m_coreFrame)
438         return true;
439         
440     return m_coreFrame->document()->securityOrigin()->canDisplay(url);
441 }
442
443 JSGlobalContextRef WebFrame::jsContext()
444 {
445     return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
446 }
447
448 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
449 {
450     return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec());
451 }
452
453 bool WebFrame::handlesPageScaleGesture() const
454 {
455     if (!m_coreFrame->document()->isPluginDocument())
456         return 0;
457
458     PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
459     PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
460
461     return pluginView->handlesPageScaleFactor();
462 }
463
464 IntRect WebFrame::contentBounds() const
465 {    
466     if (!m_coreFrame)
467         return IntRect();
468     
469     FrameView* view = m_coreFrame->view();
470     if (!view)
471         return IntRect();
472     
473     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
474 }
475
476 IntRect WebFrame::visibleContentBounds() const
477 {
478     if (!m_coreFrame)
479         return IntRect();
480     
481     FrameView* view = m_coreFrame->view();
482     if (!view)
483         return IntRect();
484     
485     IntRect contentRect = view->visibleContentRect(ScrollableArea::IncludeScrollbars);
486     return IntRect(0, 0, contentRect.width(), contentRect.height());
487 }
488
489 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
490 {
491     if (!m_coreFrame)
492         return IntRect();
493     
494     FrameView* view = m_coreFrame->view();
495     if (!view)
496         return IntRect();
497     
498     IntRect contentRect = view->visibleContentRect();
499     return IntRect(0, 0, contentRect.width(), contentRect.height());
500 }
501
502 IntSize WebFrame::scrollOffset() const
503 {
504     if (!m_coreFrame)
505         return IntSize();
506     
507     FrameView* view = m_coreFrame->view();
508     if (!view)
509         return IntSize();
510
511     return view->scrollOffset();
512 }
513
514 bool WebFrame::hasHorizontalScrollbar() const
515 {
516     if (!m_coreFrame)
517         return false;
518
519     FrameView* view = m_coreFrame->view();
520     if (!view)
521         return false;
522
523     return view->horizontalScrollbar();
524 }
525
526 bool WebFrame::hasVerticalScrollbar() const
527 {
528     if (!m_coreFrame)
529         return false;
530
531     FrameView* view = m_coreFrame->view();
532     if (!view)
533         return false;
534
535     return view->verticalScrollbar();
536 }
537
538 PassRefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
539 {
540     if (!m_coreFrame)
541         return 0;
542
543     return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler()->hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent));
544 }
545
546 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
547 {
548     if (!m_coreFrame)
549         return false;
550
551     FrameView* view = m_coreFrame->view();
552     if (!view)
553         return false;
554
555     Color bgColor = view->documentBackgroundColor();
556     if (!bgColor.isValid())
557         return false;
558
559     bgColor.getRGBA(*red, *green, *blue, *alpha);
560     return true;
561 }
562
563 bool WebFrame::containsAnyFormElements() const
564 {
565     if (!m_coreFrame)
566         return false;
567     
568     Document* document = m_coreFrame->document();
569     if (!document)
570         return false;
571
572     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
573         if (!node->isElementNode())
574             continue;
575         if (toElement(node)->hasTagName(HTMLNames::formTag))
576             return true;
577     }
578     return false;
579 }
580
581 void WebFrame::stopLoading()
582 {
583     if (!m_coreFrame)
584         return;
585
586     m_coreFrame->loader()->stopForUserCancel();
587 }
588
589 WebFrame* WebFrame::frameForContext(JSContextRef context)
590 {
591     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
592     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
593     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
594         return 0;
595
596     Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
597     return static_cast<WebFrameLoaderClient*>(coreFrame->loader()->client())->webFrame();
598 }
599
600 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
601 {
602     if (!m_coreFrame)
603         return 0;
604
605     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
606     ExecState* exec = globalObject->globalExec();
607
608     JSLockHolder lock(exec);
609     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
610 }
611
612 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
613 {
614     if (!m_coreFrame)
615         return 0;
616
617     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
618     ExecState* exec = globalObject->globalExec();
619
620     JSLockHolder lock(exec);
621     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
622 }
623
624 String WebFrame::counterValue(JSObjectRef element)
625 {
626     if (!toJS(element)->inherits(&JSElement::s_info))
627         return String();
628
629     return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
630 }
631
632 String WebFrame::provisionalURL() const
633 {
634     if (!m_coreFrame)
635         return String();
636
637     return m_coreFrame->loader()->provisionalDocumentLoader()->url().string();
638 }
639
640 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const
641 {
642     if (!m_coreFrame)
643         return String();
644
645     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
646     if (!loader)
647         return String();
648
649     // First, try the main resource.
650     if (loader->url() == url)
651         return loader->response().suggestedFilename();
652
653     // Next, try subresources.
654     RefPtr<ArchiveResource> resource = loader->subresource(url);
655     if (resource)
656         return resource->response().suggestedFilename();
657
658     return page()->cachedSuggestedFilenameForURL(url);
659 }
660
661 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const
662 {
663     if (!m_coreFrame)
664         return String();
665
666     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
667     if (!loader)
668         return String();
669
670     // First, try the main resource.
671     if (loader->url() == url)
672         return loader->response().mimeType();
673
674     // Next, try subresources.
675     RefPtr<ArchiveResource> resource = loader->subresource(url);
676     if (resource)
677         return resource->mimeType();
678
679     return page()->cachedResponseMIMETypeForURL(url);
680 }
681
682 void WebFrame::setTextDirection(const String& direction)
683 {
684     if (!m_coreFrame || !m_coreFrame->editor())
685         return;
686
687     if (direction == "auto")
688         m_coreFrame->editor()->setBaseWritingDirection(NaturalWritingDirection);
689     else if (direction == "ltr")
690         m_coreFrame->editor()->setBaseWritingDirection(LeftToRightWritingDirection);
691     else if (direction == "rtl")
692         m_coreFrame->editor()->setBaseWritingDirection(RightToLeftWritingDirection);
693 }
694
695 #if PLATFORM(MAC)
696
697 class WebFrameFilter : public FrameFilter {
698 public:
699     WebFrameFilter(WebFrame*, WebFrame::FrameFilterFunction, void* context);
700         
701 private:
702     virtual bool shouldIncludeSubframe(Frame*) const OVERRIDE;
703
704     WebFrame* m_topLevelWebFrame;
705     WebFrame::FrameFilterFunction m_callback;
706     void* m_context;
707 };
708
709 WebFrameFilter::WebFrameFilter(WebFrame* topLevelWebFrame, WebFrame::FrameFilterFunction callback, void* context)
710     : m_topLevelWebFrame(topLevelWebFrame)
711     , m_callback(callback)
712     , m_context(context)
713 {
714 }
715
716 bool WebFrameFilter::shouldIncludeSubframe(Frame* frame) const
717 {
718     if (!m_callback)
719         return true;
720         
721     WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame();
722     return m_callback(toAPI(m_topLevelWebFrame), toAPI(webFrame), m_context);
723 }
724
725 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
726 {
727     WebFrameFilter filter(this, callback, context);
728
729     if (RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), &filter))
730         return archive->rawDataRepresentation();
731     
732     return 0;
733 }
734 #endif
735     
736 } // namespace WebKit