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