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