Roll out r81593 Need WebKit2 API for creating a page with a specific main frame name
[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     DocumentLoader* documentLoader = m_coreFrame->loader()->documentLoader();
339     if (!documentLoader)
340         return String();
341
342     return documentLoader->url().string();
343 }
344
345 String WebFrame::innerText() const
346 {
347     if (!m_coreFrame)
348         return String();
349
350     if (!m_coreFrame->document()->documentElement())
351         return String();
352
353     return m_coreFrame->document()->documentElement()->innerText();
354 }
355
356 PassRefPtr<ImmutableArray> WebFrame::childFrames()
357 {
358     if (!m_coreFrame)
359         return ImmutableArray::create();
360
361     size_t size = m_coreFrame->tree()->childCount();
362     if (!size)
363         return ImmutableArray::create();
364
365     Vector<RefPtr<APIObject> > vector;
366     vector.reserveInitialCapacity(size);
367
368     for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
369         WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame();
370         vector.uncheckedAppend(webFrame);
371     }
372
373     return ImmutableArray::adopt(vector);
374 }
375
376 unsigned WebFrame::numberOfActiveAnimations() const
377 {
378     if (!m_coreFrame)
379         return 0;
380
381     AnimationController* controller = m_coreFrame->animation();
382     if (!controller)
383         return 0;
384
385     return controller->numberOfActiveAnimations();
386 }
387
388 bool WebFrame::pauseAnimationOnElementWithId(const String& animationName, const String& elementID, double time)
389 {
390     if (!m_coreFrame)
391         return false;
392
393     AnimationController* controller = m_coreFrame->animation();
394     if (!controller)
395         return false;
396
397     if (!m_coreFrame->document())
398         return false;
399
400     Node* coreNode = m_coreFrame->document()->getElementById(elementID);
401     if (!coreNode || !coreNode->renderer())
402         return false;
403
404     return controller->pauseAnimationAtTime(coreNode->renderer(), animationName, time);
405 }
406
407 void WebFrame::suspendAnimations()
408 {
409     if (!m_coreFrame)
410         return;
411
412     AnimationController* controller = m_coreFrame->animation();
413     if (!controller)
414         return;
415
416     controller->suspendAnimations();
417 }
418
419 void WebFrame::resumeAnimations()
420 {
421     if (!m_coreFrame)
422         return;
423
424     AnimationController* controller = m_coreFrame->animation();
425     if (!controller)
426         return;
427
428     controller->resumeAnimations();
429 }
430
431 String WebFrame::layerTreeAsText() const
432 {
433     if (!m_coreFrame)
434         return "";
435
436     return m_coreFrame->layerTreeAsText();
437 }
438
439 unsigned WebFrame::pendingUnloadCount() const
440 {
441     if (!m_coreFrame)
442         return 0;
443
444     return m_coreFrame->domWindow()->pendingUnloadEventListeners();
445 }
446
447 bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const
448 {
449     if (!m_coreFrame)
450         return true;
451         
452     return m_coreFrame->document()->securityOrigin()->canDisplay(url);
453 }
454
455 JSGlobalContextRef WebFrame::jsContext()
456 {
457     return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
458 }
459
460 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
461 {
462     return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec());
463 }
464
465 IntRect WebFrame::contentBounds() const
466 {    
467     if (!m_coreFrame)
468         return IntRect();
469     
470     FrameView* view = m_coreFrame->view();
471     if (!view)
472         return IntRect();
473     
474     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
475 }
476
477 IntRect WebFrame::visibleContentBounds() const
478 {
479     if (!m_coreFrame)
480         return IntRect();
481     
482     FrameView* view = m_coreFrame->view();
483     if (!view)
484         return IntRect();
485     
486     IntRect contentRect = view->visibleContentRect(true);
487     return IntRect(0, 0, contentRect.width(), contentRect.height());
488 }
489
490 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
491 {
492     if (!m_coreFrame)
493         return IntRect();
494     
495     FrameView* view = m_coreFrame->view();
496     if (!view)
497         return IntRect();
498     
499     IntRect contentRect = view->visibleContentRect(false);
500     return IntRect(0, 0, contentRect.width(), contentRect.height());
501 }
502
503 IntSize WebFrame::scrollOffset() const
504 {
505     if (!m_coreFrame)
506         return IntSize();
507     
508     FrameView* view = m_coreFrame->view();
509     if (!view)
510         return IntSize();
511
512     return view->scrollOffset();
513 }
514
515 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
516 {
517     if (!m_coreFrame)
518         return false;
519     Document* document = m_coreFrame->document();
520     if (!document)
521         return false;
522
523     Element* rootElementToUse = document->body();
524     if (!rootElementToUse)
525         rootElementToUse = document->documentElement();
526     if (!rootElementToUse)
527         return false;
528
529     RenderObject* renderer = rootElementToUse->renderer();
530     if (!renderer)
531         return false;
532     Color color = renderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
533     if (!color.isValid())
534         return false;
535
536     color.getRGBA(*red, *green, *blue, *alpha);
537     return true;
538 }
539
540 WebFrame* WebFrame::frameForContext(JSContextRef context)
541 {
542     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
543     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
544     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
545         return 0;
546
547     Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
548     return static_cast<WebFrameLoaderClient*>(coreFrame->loader()->client())->webFrame();
549 }
550
551 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
552 {
553     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
554     ExecState* exec = globalObject->globalExec();
555
556     JSLock lock(SilenceAssertionsOnly);
557     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
558 }
559
560 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
561 {
562     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
563     ExecState* exec = globalObject->globalExec();
564
565     JSLock lock(SilenceAssertionsOnly);
566     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
567 }
568
569 JSValueRef WebFrame::computedStyleIncludingVisitedInfo(JSObjectRef element)
570 {
571     if (!m_coreFrame)
572         return 0;
573
574     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(mainThreadNormalWorld());
575     ExecState* exec = globalObject->globalExec();
576
577     if (!toJS(element)->inherits(&JSElement::s_info))
578         return JSValueMakeUndefined(toRef(exec));
579
580     RefPtr<CSSComputedStyleDeclaration> style = computedStyle(static_cast<JSElement*>(toJS(element))->impl(), true);
581
582     JSLock lock(SilenceAssertionsOnly);
583     return toRef(exec, toJS(exec, globalObject, style.get()));
584 }
585
586 String WebFrame::counterValue(JSObjectRef element)
587 {
588     if (!toJS(element)->inherits(&JSElement::s_info))
589         return String();
590
591     return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
592 }
593
594 String WebFrame::markerText(JSObjectRef element)
595 {
596     if (!toJS(element)->inherits(&JSElement::s_info))
597         return String();
598
599     return markerTextForListItem(static_cast<JSElement*>(toJS(element))->impl());
600 }
601
602 String WebFrame::provisionalURL() const
603 {
604     if (!m_coreFrame)
605         return String();
606
607     return m_coreFrame->loader()->provisionalDocumentLoader()->url().string();
608 }
609
610 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const
611 {
612     if (!m_coreFrame)
613         return String();
614
615     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
616     if (!loader)
617         return String();
618
619     // First, try the main resource.
620     if (loader->url() == url)
621         return loader->response().suggestedFilename();
622
623     // Next, try subresources.
624     RefPtr<ArchiveResource> resource = loader->subresource(url);
625     if (!resource)
626         return String();
627     
628     return resource->response().suggestedFilename();
629 }
630
631 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const
632 {
633     if (!m_coreFrame)
634         return String();
635
636     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
637     if (!loader)
638         return String();
639
640     // First, try the main resource.
641     if (loader->url() == url)
642         return loader->response().mimeType();
643
644     // Next, try subresources.
645     RefPtr<ArchiveResource> resource = loader->subresource(url);
646     if (resource)
647         return resource->mimeType();
648
649     return page()->cachedResponseMIMETypeForURL(url);
650 }
651
652 } // namespace WebKit