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