2011-01-07 James Robinson <jamesr@chromium.org>
[WebKit-https.git] / WebKit2 / WebProcess / WebPage / ChunkedUpdateDrawingArea.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 "ChunkedUpdateDrawingArea.h"
27
28 #include "DrawingAreaMessageKinds.h"
29 #include "DrawingAreaProxyMessageKinds.h"
30 #include "MessageID.h"
31 #include "UpdateChunk.h"
32 #include "WebCoreArgumentCoders.h"
33 #include "WebPage.h"
34 #include "WebProcess.h"
35
36 using namespace WebCore;
37
38 namespace WebKit {
39
40 ChunkedUpdateDrawingArea::ChunkedUpdateDrawingArea(DrawingAreaInfo::Identifier identifier, WebPage* webPage)
41     : DrawingArea(DrawingAreaInfo::ChunkedUpdate, identifier, webPage)
42     , m_isWaitingForUpdate(false)
43     , m_paintingIsSuspended(false)
44     , m_displayTimer(WebProcess::shared().runLoop(), this, &ChunkedUpdateDrawingArea::display)
45 {
46 }
47
48 ChunkedUpdateDrawingArea::~ChunkedUpdateDrawingArea()
49 {
50 }
51
52 void ChunkedUpdateDrawingArea::scroll(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect)
53 {
54     // FIXME: Do something much smarter.
55     setNeedsDisplay(rectToScroll);
56 }
57
58 void ChunkedUpdateDrawingArea::setNeedsDisplay(const IntRect& rect)
59 {
60     // FIXME: Collect a set of rects/region instead of just the union
61     // of all rects.
62     m_dirtyRect.unite(rect);
63     scheduleDisplay();
64 }
65
66 void ChunkedUpdateDrawingArea::display()
67 {
68     ASSERT(!m_isWaitingForUpdate);
69  
70     if (m_paintingIsSuspended)
71         return;
72
73     if (m_dirtyRect.isEmpty())
74         return;
75
76     // Laying out the page can cause the drawing area to change so we keep an extra reference.
77     RefPtr<ChunkedUpdateDrawingArea> protect(this);
78
79     // Layout if necessary.
80     m_webPage->layoutIfNeeded();
81  
82     if (m_webPage->drawingArea() != this)
83         return;
84     
85     IntRect dirtyRect = m_dirtyRect;
86     m_dirtyRect = IntRect();
87
88     // Create a new UpdateChunk and paint into it.
89     UpdateChunk updateChunk(dirtyRect);
90     paintIntoUpdateChunk(&updateChunk);
91
92     WebProcess::shared().connection()->send(DrawingAreaProxyLegacyMessage::Update, m_webPage->pageID(), CoreIPC::In(updateChunk));
93
94     m_isWaitingForUpdate = true;
95     m_displayTimer.stop();
96 }
97
98 void ChunkedUpdateDrawingArea::scheduleDisplay()
99 {
100     if (m_paintingIsSuspended)
101         return;
102
103     if (m_isWaitingForUpdate)
104         return;
105     
106     if (m_dirtyRect.isEmpty())
107         return;
108
109     if (m_displayTimer.isActive())
110         return;
111
112     m_displayTimer.startOneShot(0);
113 }
114
115 void ChunkedUpdateDrawingArea::setSize(const IntSize& viewSize)
116 {
117     ASSERT_ARG(viewSize, !viewSize.isEmpty());
118
119     // We don't want to wait for an update until we display.
120     m_isWaitingForUpdate = false;
121     
122     // Laying out the page can cause the drawing area to change so we keep an extra reference.
123     RefPtr<ChunkedUpdateDrawingArea> protect(this);
124
125     m_webPage->setSize(viewSize);
126     m_webPage->layoutIfNeeded();
127
128     if (m_webPage->drawingArea() != this)
129         return;
130
131     if (m_paintingIsSuspended) {
132         ASSERT(!m_displayTimer.isActive());
133
134         // Painting is suspended, just send back an empty update chunk.
135         WebProcess::shared().connection()->send(DrawingAreaProxyLegacyMessage::DidSetSize, m_webPage->pageID(), CoreIPC::In(UpdateChunk()));
136         return;
137     }
138
139     // Create a new UpdateChunk and paint into it.
140     UpdateChunk updateChunk(IntRect(0, 0, viewSize.width(), viewSize.height()));
141     paintIntoUpdateChunk(&updateChunk);
142
143     m_displayTimer.stop();
144
145     WebProcess::shared().connection()->send(DrawingAreaProxyLegacyMessage::DidSetSize, m_webPage->pageID(), CoreIPC::In(updateChunk));
146 }
147
148 void ChunkedUpdateDrawingArea::suspendPainting()
149 {
150     ASSERT(!m_paintingIsSuspended);
151     
152     m_paintingIsSuspended = true;
153     m_displayTimer.stop();
154 }
155
156 void ChunkedUpdateDrawingArea::resumePainting(bool forceRepaint)
157 {
158     ASSERT(m_paintingIsSuspended);
159     
160     m_paintingIsSuspended = false;
161
162     if (forceRepaint) {
163         // Just set the dirty rect to the entire page size.
164         m_dirtyRect = IntRect(IntPoint(0, 0), m_webPage->size());
165     }
166
167     // Schedule a display.
168     scheduleDisplay();
169 }
170
171 void ChunkedUpdateDrawingArea::didUpdate()
172 {
173     m_isWaitingForUpdate = false;
174
175     // Display if needed.
176     display();
177 }
178
179 void ChunkedUpdateDrawingArea::didReceiveMessage(CoreIPC::Connection*, CoreIPC::MessageID messageID, CoreIPC::ArgumentDecoder* arguments)
180 {
181     DrawingAreaInfo::Identifier targetIdentifier;
182     if (!arguments->decode(CoreIPC::Out(targetIdentifier)))
183         return;
184
185     // We can switch drawing areas on the fly, so if this message was targetted at an obsolete drawing area, ignore it.
186     if (targetIdentifier != info().identifier)
187         return;
188
189     switch (messageID.get<DrawingAreaLegacyMessage::Kind>()) {
190         case DrawingAreaLegacyMessage::SetSize: {
191             IntSize size;
192             if (!arguments->decode(CoreIPC::Out(size)))
193                 return;
194
195             setSize(size);
196             break;
197         }
198         
199         case DrawingAreaLegacyMessage::SuspendPainting:
200             suspendPainting();
201             break;
202
203         case DrawingAreaLegacyMessage::ResumePainting: {
204             bool forceRepaint;
205             if (!arguments->decode(CoreIPC::Out(forceRepaint)))
206                 return;
207             
208             resumePainting(forceRepaint);
209             break;
210         }
211         case DrawingAreaLegacyMessage::DidUpdate:
212             didUpdate();
213             break;
214
215         default:
216             ASSERT_NOT_REACHED();
217             break;
218     }
219 }
220
221 } // namespace WebKit