16c7087fc5a82776ff1e7d7302286b9e3ee8322a
[WebKit-https.git] / WebCore / history / CachedFrame.cpp
1 /*
2  * Copyright (C) 2009 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 COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25  
26 #include "config.h"
27 #include "CachedPage.h"
28
29 #include "CachedFramePlatformData.h"
30 #include "CString.h"
31 #include "DocumentLoader.h"
32 #include "ExceptionCode.h"
33 #include "EventNames.h"
34 #include "Frame.h"
35 #include "FrameLoaderClient.h"
36 #include "FrameView.h"
37 #include "Logging.h"
38 #include "PageTransitionEvent.h"
39 #include <wtf/RefCountedLeakCounter.h>
40
41 #if ENABLE(SVG)
42 #include "SVGDocumentExtensions.h"
43 #endif
44
45 namespace WebCore {
46
47 #ifndef NDEBUG
48 static WTF::RefCountedLeakCounter& cachedFrameCounter()
49 {
50     DEFINE_STATIC_LOCAL(WTF::RefCountedLeakCounter, counter, ("CachedFrame"));
51     return counter;
52 }
53 #endif
54
55 CachedFrameBase::CachedFrameBase(Frame* frame)
56     : m_document(frame->document())
57     , m_documentLoader(frame->loader()->documentLoader())
58     , m_view(frame->view())
59     , m_mousePressNode(frame->eventHandler()->mousePressNode())
60     , m_url(frame->loader()->url())
61     , m_isMainFrame(!frame->tree()->parent())
62 {
63 }
64
65 CachedFrameBase::~CachedFrameBase()
66 {
67 #ifndef NDEBUG
68     cachedFrameCounter().decrement();
69 #endif
70     // CachedFrames should always have had destroy() called by their parent CachedPage
71     ASSERT(!m_document);
72 }
73
74 void CachedFrameBase::restore()
75 {
76     ASSERT(m_document->view() == m_view);
77     
78     Frame* frame = m_view->frame();
79     m_cachedFrameScriptData->restore(frame);
80
81 #if ENABLE(SVG)
82     if (m_document->svgExtensions())
83         m_document->accessSVGExtensions()->unpauseAnimations();
84 #endif
85
86     frame->animation()->resumeAnimations(m_document.get());
87     frame->eventHandler()->setMousePressNode(m_mousePressNode.get());
88     m_document->resumeActiveDOMObjects();
89
90     // It is necessary to update any platform script objects after restoring the
91     // cached page.
92     frame->script()->updatePlatformScriptObjects();
93
94     // Reconstruct the FrameTree
95     for (unsigned i = 0; i < m_childFrames.size(); ++i)
96         frame->tree()->appendChild(m_childFrames[i]->view()->frame());
97
98     // Open the child CachedFrames in their respective FrameLoaders.
99     for (unsigned i = 0; i < m_childFrames.size(); ++i)
100         m_childFrames[i]->open();
101
102     m_document->dispatchWindowEvent(PageTransitionEvent::create(EventNames().pageshowEvent, true), m_document);
103 }
104
105 CachedFrame::CachedFrame(Frame* frame)
106     : CachedFrameBase(frame)
107 {
108 #ifndef NDEBUG
109     cachedFrameCounter().increment();
110 #endif
111     ASSERT(m_document);
112     ASSERT(m_documentLoader);
113     ASSERT(m_view);
114
115     // Active DOM objects must be suspended before we cached the frame script data
116     m_document->suspendActiveDOMObjects();
117     m_cachedFrameScriptData.set(new ScriptCachedFrameData(frame));
118     
119     // Custom scrollbar renderers will get reattached when the document comes out of the page cache
120     m_view->detachCustomScrollbars();
121
122     m_document->documentWillBecomeInactive(); 
123     frame->clearTimers();
124     m_document->setInPageCache(true);
125     
126     frame->loader()->client()->savePlatformDataToCachedFrame(this);
127
128     // Create the CachedFrames for all Frames in the FrameTree.
129     for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
130         m_childFrames.append(CachedFrame::create(child));
131
132     // Deconstruct the FrameTree, to restore it later.
133     // We do this for two reasons:
134     // 1 - We reuse the main frame, so when it navigates to a new page load it needs to start with a blank FrameTree.
135     // 2 - It's much easier to destroy a CachedFrame while it resides in the PageCache if it is disconnected from its parent.
136     for (unsigned i = 0; i < m_childFrames.size(); ++i)
137         frame->tree()->removeChild(m_childFrames[i]->view()->frame());
138
139 #ifndef NDEBUG
140     if (m_isMainFrame)
141         LOG(PageCache, "Finished creating CachedFrame for main frame url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
142     else
143         LOG(PageCache, "Finished creating CachedFrame for child frame with url '%s' and DocumentLoader %p\n", m_url.string().utf8().data(), m_documentLoader.get());
144 #endif
145 }
146
147 void CachedFrame::open()
148 {
149     ASSERT(m_view);
150     m_view->frame()->loader()->open(*this);
151 }
152
153 void CachedFrame::clear()
154 {
155     if (!m_document)
156         return;
157
158     // clear() should only be called for Frames representing documents that are no longer in the page cache.
159     // This means the CachedFrame has been:
160     // 1 - Successfully restore()'d by going back/forward.
161     // 2 - destroy()'ed because the PageCache is pruning or the WebView was closed.
162     ASSERT(!m_document->inPageCache());
163     ASSERT(m_view);
164     ASSERT(m_document->frame() == m_view->frame());
165
166     for (int i = m_childFrames.size() - 1; i >= 0; --i)
167         m_childFrames[i]->clear();
168
169     m_document = 0;
170     m_view = 0;
171     m_mousePressNode = 0;
172     m_url = KURL();
173
174     m_cachedFramePlatformData.clear();
175     m_cachedFrameScriptData.clear();
176 }
177
178 void CachedFrame::destroy()
179 {
180     if (!m_document)
181         return;
182     
183     // Only CachedFrames that are still in the PageCache should be destroyed in this manner
184     ASSERT(m_document->inPageCache());
185     ASSERT(m_view);
186     ASSERT(m_document->frame() == m_view->frame());
187
188     if (!m_isMainFrame) {
189         m_view->frame()->detachFromPage();
190         m_view->frame()->loader()->detachViewsAndDocumentLoader();
191     }
192     
193     for (int i = m_childFrames.size() - 1; i >= 0; --i)
194         m_childFrames[i]->destroy();
195
196     if (m_cachedFramePlatformData)
197         m_cachedFramePlatformData->clear();
198
199     Frame::clearTimers(m_view.get(), m_document.get());
200
201     // FIXME: Why do we need to call removeAllEventListeners here? When the document is in page cache, this method won't work
202     // fully anyway, because the document won't be able to access its DOMWindow object (due to being frameless).
203     m_document->removeAllEventListeners();
204
205     m_document->setInPageCache(false);
206     // FIXME: We don't call willRemove here. Why is that OK?
207     m_document->detach();
208     m_view->clearFrame();
209
210     clear();
211 }
212
213 void CachedFrame::setCachedFramePlatformData(CachedFramePlatformData* data)
214 {
215     m_cachedFramePlatformData.set(data);
216 }
217
218 CachedFramePlatformData* CachedFrame::cachedFramePlatformData()
219 {
220     return m_cachedFramePlatformData.get();
221 }
222
223 int CachedFrame::descendantFrameCount() const
224 {
225     int count = m_childFrames.size();
226     for (size_t i = 0; i < m_childFrames.size(); ++i)
227         count += m_childFrames[i]->descendantFrameCount();
228     
229     return count;
230 }
231
232 } // namespace WebCore