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 "WebFrameProxy.h"
28
29#include "WebCertificateInfo.h"
30#include "WebContext.h"
31#include "WebFormSubmissionListenerProxy.h"
32#include "WebFramePolicyListenerProxy.h"
33#include "WebPageMessages.h"
34#include "WebPageProxy.h"
35#include <WebCore/DOMImplementation.h>
36#include <WebCore/Image.h>
37#include <wtf/text/WTFString.h>
38
39using namespace WebCore;
40using namespace std;
41
42namespace WebKit {
43
44WebFrameProxy::WebFrameProxy(WebPageProxy* page, uint64_t frameID)
45    : m_page(page)
46    , m_parentFrame(0)
47    , m_nextSibling(0)
48    , m_previousSibling(0)
49    , m_firstChild(0)
50    , m_lastChild(0)
51    , m_loadState(LoadStateFinished)
52    , m_isFrameSet(false)
53    , m_frameID(frameID)
54{
55    WebContext::statistics().wkFrameCount++;
56}
57
58WebFrameProxy::~WebFrameProxy()
59{
60    WebContext::statistics().wkFrameCount--;
61}
62
63void WebFrameProxy::disconnect()
64{
65    m_page = 0;
66    m_parentFrame = 0;
67    m_nextSibling = 0;
68    m_previousSibling = 0;
69    m_firstChild = 0;
70    m_lastChild = 0;
71
72    if (m_activeListener) {
73        m_activeListener->invalidate();
74        m_activeListener = 0;
75    }
76}
77
78bool WebFrameProxy::isMainFrame() const
79{
80    if (!m_page)
81        return false;
82
83    return this == m_page->mainFrame();
84}
85
86void WebFrameProxy::stopLoading() const
87{
88    if (!m_page)
89        return;
90
91    if (!m_page->isValid())
92        return;
93
94    m_page->process()->send(Messages::WebPage::StopLoadingFrame(m_frameID), m_page->pageID());
95}
96
97bool WebFrameProxy::canProvideSource() const
98{
99    return isDisplayingMarkupDocument();
100}
101
102bool WebFrameProxy::canShowMIMEType(const String& mimeType) const
103{
104    if (!m_page)
105        return false;
106
107    if (m_page->canShowMIMEType(mimeType))
108        return true;
109
110#if PLATFORM(MAC)
111    // On Mac, we can show PDFs in the main frame.
112    if (isMainFrame() && !mimeType.isEmpty())
113        return WebContext::pdfAndPostScriptMIMETypes().contains(mimeType);
114#endif
115
116    return false;
117}
118
119bool WebFrameProxy::isDisplayingStandaloneImageDocument() const
120{
121    return Image::supportsType(m_MIMEType);
122}
123
124bool WebFrameProxy::isDisplayingMarkupDocument() const
125{
126    // FIXME: This check should be moved to somewhere in WebCore.
127    // FIXME: This returns false when displaying a web archive.
128    return m_MIMEType == "text/html" || m_MIMEType == "image/svg+xml" || DOMImplementation::isXMLMIMEType(m_MIMEType);
129}
130
131void WebFrameProxy::didStartProvisionalLoad(const String& url)
132{
133    ASSERT(m_loadState == LoadStateFinished);
134    ASSERT(m_provisionalURL.isEmpty());
135    m_loadState = LoadStateProvisional;
136    m_provisionalURL = url;
137}
138
139void WebFrameProxy::didReceiveServerRedirectForProvisionalLoad(const String& url)
140{
141    ASSERT(m_loadState == LoadStateProvisional);
142    m_provisionalURL = url;
143}
144
145void WebFrameProxy::didFailProvisionalLoad()
146{
147    ASSERT(m_loadState == LoadStateProvisional);
148    m_loadState = LoadStateFinished;
149    m_provisionalURL = String();
150}
151
152void WebFrameProxy::didCommitLoad(const String& contentType, const PlatformCertificateInfo& certificateInfo)
153{
154    ASSERT(m_loadState == LoadStateProvisional);
155    m_loadState = LoadStateCommitted;
156    m_url = m_provisionalURL;
157    m_provisionalURL = String();
158    m_title = String();
159    m_MIMEType = contentType;
160    m_isFrameSet = false;
161    m_certificateInfo = WebCertificateInfo::create(certificateInfo);
162}
163
164void WebFrameProxy::didFinishLoad()
165{
166    ASSERT(m_loadState == LoadStateCommitted);
167    ASSERT(m_provisionalURL.isEmpty());
168    m_loadState = LoadStateFinished;
169}
170
171void WebFrameProxy::didFailLoad()
172{
173    ASSERT(m_loadState == LoadStateCommitted);
174    ASSERT(m_provisionalURL.isEmpty());
175    m_loadState = LoadStateFinished;
176    m_title = String();
177}
178
179void WebFrameProxy::didSameDocumentNavigation(const String& url)
180{
181    m_url = url;
182}
183
184void WebFrameProxy::didChangeTitle(const String& title)
185{
186    m_title = title;
187}
188
189void WebFrameProxy::appendChild(WebFrameProxy* child)
190{
191    ASSERT(child->page() == page());
192    ASSERT(!child->m_parentFrame);
193    ASSERT(!child->m_nextSibling);
194    ASSERT(!child->m_previousSibling);
195
196    child->m_parentFrame = this;
197
198    WebFrameProxy* oldLast = m_lastChild;
199    m_lastChild = child;
200
201    if (oldLast) {
202        ASSERT(!oldLast->m_nextSibling);
203        child->m_previousSibling = oldLast;
204        oldLast->m_nextSibling = child;
205    } else
206        m_firstChild = child;
207}
208
209void WebFrameProxy::removeChild(WebFrameProxy* child)
210{
211    child->m_parentFrame = 0;
212
213    WebFrameProxy*& newLocationForNext = m_firstChild == child ? m_firstChild : child->m_previousSibling->m_nextSibling;
214    WebFrameProxy*& newLocationForPrevious = m_lastChild == child ? m_lastChild : child->m_nextSibling->m_previousSibling;
215    swap(newLocationForNext, child->m_nextSibling);
216    swap(newLocationForPrevious, child->m_previousSibling);
217    child->m_previousSibling = 0;
218    child->m_nextSibling = 0;
219}
220
221bool WebFrameProxy::isDescendantOf(const WebFrameProxy* ancestor) const
222{
223    if (!ancestor)
224        return false;
225
226    if (m_page != ancestor->m_page)
227        return false;
228
229    for (const WebFrameProxy* frame = this; frame; frame = frame->m_parentFrame) {
230        if (frame == ancestor)
231            return true;
232    }
233
234    return false;
235}
236
237void WebFrameProxy::dumpFrameTreeToSTDOUT(unsigned indent)
238{
239    if (!indent && m_parentFrame)
240        printf("NOTE: Printing subtree.\n");
241
242    for (unsigned i = 0; i < indent; ++i)
243        printf(" ");
244    printf("| FRAME %d %s\n", (int)m_frameID, m_url.utf8().data());
245
246    for (WebFrameProxy* child = m_firstChild; child; child = child->m_nextSibling)
247        child->dumpFrameTreeToSTDOUT(indent + 4);
248}
249
250void WebFrameProxy::didRemoveFromHierarchy()
251{
252    if (m_parentFrame)
253        m_parentFrame->removeChild(this);
254}
255
256PassRefPtr<ImmutableArray> WebFrameProxy::childFrames()
257{
258    if (!m_firstChild)
259        return ImmutableArray::create();
260
261    Vector<RefPtr<APIObject> > vector;
262    for (WebFrameProxy* child = m_firstChild; child; child = child->m_nextSibling)
263        vector.append(child);
264
265    return ImmutableArray::adopt(vector);
266}
267
268void WebFrameProxy::receivedPolicyDecision(WebCore::PolicyAction action, uint64_t listenerID)
269{
270    if (!m_page)
271        return;
272
273    ASSERT(m_activeListener);
274    ASSERT(m_activeListener->listenerID() == listenerID);
275    m_page->receivedPolicyDecision(action, this, listenerID);
276}
277
278WebFramePolicyListenerProxy* WebFrameProxy::setUpPolicyListenerProxy(uint64_t listenerID)
279{
280    if (m_activeListener)
281        m_activeListener->invalidate();
282    m_activeListener = WebFramePolicyListenerProxy::create(this, listenerID);
283    return static_cast<WebFramePolicyListenerProxy*>(m_activeListener.get());
284}
285
286WebFormSubmissionListenerProxy* WebFrameProxy::setUpFormSubmissionListenerProxy(uint64_t listenerID)
287{
288    if (m_activeListener)
289        m_activeListener->invalidate();
290    m_activeListener = WebFormSubmissionListenerProxy::create(this, listenerID);
291    return static_cast<WebFormSubmissionListenerProxy*>(m_activeListener.get());
292}
293
294void WebFrameProxy::getWebArchive(PassRefPtr<DataCallback> callback)
295{
296    if (!m_page) {
297        callback->invalidate();
298        return;
299    }
300
301    m_page->getWebArchiveOfFrame(this, callback);
302}
303
304void WebFrameProxy::getMainResourceData(PassRefPtr<DataCallback> callback)
305{
306    if (!m_page) {
307        callback->invalidate();
308        return;
309    }
310
311    m_page->getMainResourceDataOfFrame(this, callback);
312}
313
314void WebFrameProxy::getResourceData(WebURL* resourceURL, PassRefPtr<DataCallback> callback)
315{
316    if (!m_page) {
317        callback->invalidate();
318        return;
319    }
320
321    m_page->getResourceDataFromFrame(this, resourceURL, callback);
322}
323
324} // namespace WebKit
325