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