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