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