• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
generateFrameID()71 static uint64_t generateFrameID()
72 {
73     static uint64_t uniqueFrameID = 1;
74     return uniqueFrameID++;
75 }
76 
generateListenerID()77 static uint64_t generateListenerID()
78 {
79     static uint64_t uniqueListenerID = 1;
80     return uniqueListenerID++;
81 }
82 
createMainFrame(WebPage * page)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 
createSubframe(WebPage * page,const String & frameName,HTMLFrameOwnerElement * ownerElement)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 
create()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 
WebFrame()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 
~WebFrame()132 WebFrame::~WebFrame()
133 {
134     ASSERT(!m_coreFrame);
135 
136 #ifndef NDEBUG
137     webFrameCounter.decrement();
138 #endif
139 }
140 
init(WebPage * page,const String & frameName,HTMLFrameOwnerElement * ownerElement)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 
page() const156 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 
invalidate()167 void WebFrame::invalidate()
168 {
169     WebProcess::shared().removeWebFrame(m_frameID);
170     m_coreFrame = 0;
171 }
172 
setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)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 
invalidatePolicyListener()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 
didReceivePolicyDecision(uint64_t listenerID,PolicyAction action,uint64_t downloadID)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 
startDownload(const WebCore::ResourceRequest & request)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 
convertHandleToDownload(ResourceHandle * handle,const ResourceRequest & request,const ResourceRequest & initialRequest,const ResourceResponse & response)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 
source() const233 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 
contentsAsString() const252 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 
selectionAsString() const286 String WebFrame::selectionAsString() const
287 {
288     if (!m_coreFrame)
289         return String();
290 
291     return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor()->selectedText());
292 }
293 
size() const294 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 
isFrameSet() const306 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 
isMainFrame() const317 bool WebFrame::isMainFrame() const
318 {
319     if (WebPage* p = page())
320         return p->mainFrame() == this;
321 
322     return false;
323 }
324 
name() const325 String WebFrame::name() const
326 {
327     if (!m_coreFrame)
328         return String();
329 
330     return m_coreFrame->tree()->uniqueName();
331 }
332 
url() const333 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 
innerText() const345 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 
childFrames()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 
numberOfActiveAnimations() const376 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 
pauseAnimationOnElementWithId(const String & animationName,const String & elementID,double time)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 
suspendAnimations()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 
resumeAnimations()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 
layerTreeAsText() const431 String WebFrame::layerTreeAsText() const
432 {
433     if (!m_coreFrame)
434         return "";
435 
436     return m_coreFrame->layerTreeAsText();
437 }
438 
pendingUnloadCount() const439 unsigned WebFrame::pendingUnloadCount() const
440 {
441     if (!m_coreFrame)
442         return 0;
443 
444     return m_coreFrame->domWindow()->pendingUnloadEventListeners();
445 }
446 
allowsFollowingLink(const WebCore::KURL & url) const447 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 
jsContext()455 JSGlobalContextRef WebFrame::jsContext()
456 {
457     return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
458 }
459 
jsContextForWorld(InjectedBundleScriptWorld * world)460 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
461 {
462     return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec());
463 }
464 
contentBounds() const465 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 
visibleContentBounds() const477 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 
visibleContentBoundsExcludingScrollbars() const490 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 
scrollOffset() const503 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 
hasHorizontalScrollbar() const515 bool WebFrame::hasHorizontalScrollbar() const
516 {
517     if (!m_coreFrame)
518         return false;
519 
520     FrameView* view = m_coreFrame->view();
521     if (!view)
522         return false;
523 
524     return view->horizontalScrollbar();
525 }
526 
hasVerticalScrollbar() const527 bool WebFrame::hasVerticalScrollbar() const
528 {
529     if (!m_coreFrame)
530         return false;
531 
532     FrameView* view = m_coreFrame->view();
533     if (!view)
534         return false;
535 
536     return view->verticalScrollbar();
537 }
538 
getDocumentBackgroundColor(double * red,double * green,double * blue,double * alpha)539 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
540 {
541     if (!m_coreFrame)
542         return false;
543     Document* document = m_coreFrame->document();
544     if (!document)
545         return false;
546 
547     Element* rootElementToUse = document->body();
548     if (!rootElementToUse)
549         rootElementToUse = document->documentElement();
550     if (!rootElementToUse)
551         return false;
552 
553     RenderObject* renderer = rootElementToUse->renderer();
554     if (!renderer)
555         return false;
556     Color color = renderer->style()->visitedDependentColor(CSSPropertyBackgroundColor);
557     if (!color.isValid())
558         return false;
559 
560     color.getRGBA(*red, *green, *blue, *alpha);
561     return true;
562 }
563 
frameForContext(JSContextRef context)564 WebFrame* WebFrame::frameForContext(JSContextRef context)
565 {
566     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
567     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
568     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
569         return 0;
570 
571     Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
572     return static_cast<WebFrameLoaderClient*>(coreFrame->loader()->client())->webFrame();
573 }
574 
jsWrapperForWorld(InjectedBundleNodeHandle * nodeHandle,InjectedBundleScriptWorld * world)575 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, 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, nodeHandle->coreNode()));
585 }
586 
jsWrapperForWorld(InjectedBundleRangeHandle * rangeHandle,InjectedBundleScriptWorld * world)587 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
588 {
589     if (!m_coreFrame)
590         return 0;
591 
592     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
593     ExecState* exec = globalObject->globalExec();
594 
595     JSLock lock(SilenceAssertionsOnly);
596     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
597 }
598 
computedStyleIncludingVisitedInfo(JSObjectRef element)599 JSValueRef WebFrame::computedStyleIncludingVisitedInfo(JSObjectRef element)
600 {
601     if (!m_coreFrame)
602         return 0;
603 
604     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(mainThreadNormalWorld());
605     ExecState* exec = globalObject->globalExec();
606 
607     if (!toJS(element)->inherits(&JSElement::s_info))
608         return JSValueMakeUndefined(toRef(exec));
609 
610     RefPtr<CSSComputedStyleDeclaration> style = computedStyle(static_cast<JSElement*>(toJS(element))->impl(), true);
611 
612     JSLock lock(SilenceAssertionsOnly);
613     return toRef(exec, toJS(exec, globalObject, style.get()));
614 }
615 
counterValue(JSObjectRef element)616 String WebFrame::counterValue(JSObjectRef element)
617 {
618     if (!toJS(element)->inherits(&JSElement::s_info))
619         return String();
620 
621     return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
622 }
623 
markerText(JSObjectRef element)624 String WebFrame::markerText(JSObjectRef element)
625 {
626     if (!toJS(element)->inherits(&JSElement::s_info))
627         return String();
628 
629     return markerTextForListItem(static_cast<JSElement*>(toJS(element))->impl());
630 }
631 
provisionalURL() const632 String WebFrame::provisionalURL() const
633 {
634     if (!m_coreFrame)
635         return String();
636 
637     return m_coreFrame->loader()->provisionalDocumentLoader()->url().string();
638 }
639 
suggestedFilenameForResourceWithURL(const KURL & url) const640 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const
641 {
642     if (!m_coreFrame)
643         return String();
644 
645     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
646     if (!loader)
647         return String();
648 
649     // First, try the main resource.
650     if (loader->url() == url)
651         return loader->response().suggestedFilename();
652 
653     // Next, try subresources.
654     RefPtr<ArchiveResource> resource = loader->subresource(url);
655     if (!resource)
656         return String();
657 
658     return resource->response().suggestedFilename();
659 }
660 
mimeTypeForResourceWithURL(const KURL & url) const661 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const
662 {
663     if (!m_coreFrame)
664         return String();
665 
666     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
667     if (!loader)
668         return String();
669 
670     // First, try the main resource.
671     if (loader->url() == url)
672         return loader->response().mimeType();
673 
674     // Next, try subresources.
675     RefPtr<ArchiveResource> resource = loader->subresource(url);
676     if (resource)
677         return resource->mimeType();
678 
679     return page()->cachedResponseMIMETypeForURL(url);
680 }
681 
682 } // namespace WebKit
683