Patch by James Robinson <jamesr@chromium.org> on 2011-07-13
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / LayerChromium.cpp
1 /*
2  * Copyright (C) 2010 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #if USE(ACCELERATED_COMPOSITING)
34
35 #include "LayerChromium.h"
36
37 #include "cc/CCLayerImpl.h"
38 #include "GraphicsContext3D.h"
39 #include "LayerRendererChromium.h"
40 #if USE(SKIA)
41 #include "NativeImageSkia.h"
42 #include "PlatformContextSkia.h"
43 #endif
44 #include "RenderLayerBacking.h"
45 #include "TextStream.h"
46 #include "skia/ext/platform_canvas.h"
47
48 namespace WebCore {
49
50 using namespace std;
51
52 static int s_nextLayerId = 1;
53
54 PassRefPtr<LayerChromium> LayerChromium::create(GraphicsLayerChromium* owner)
55 {
56     return adoptRef(new LayerChromium(owner));
57 }
58
59 LayerChromium::LayerChromium(GraphicsLayerChromium* owner)
60     : m_owner(owner)
61     , m_contentsDirty(false)
62     , m_layerId(s_nextLayerId++)
63     , m_parent(0)
64     , m_ccLayerImpl(0)
65     , m_anchorPoint(0.5, 0.5)
66     , m_backgroundColor(0, 0, 0, 0)
67     , m_opacity(1.0)
68     , m_zPosition(0.0)
69     , m_anchorPointZ(0)
70     , m_clearsContext(false)
71     , m_hidden(false)
72     , m_masksToBounds(false)
73     , m_opaque(true)
74     , m_geometryFlipped(false)
75     , m_needsDisplayOnBoundsChange(false)
76     , m_doubleSided(true)
77     , m_replicaLayer(0)
78 {
79     ASSERT(!LayerRendererChromium::s_inPaintLayerContents);
80 }
81
82 LayerChromium::~LayerChromium()
83 {
84     ASSERT(!LayerRendererChromium::s_inPaintLayerContents);
85     // Our parent should be holding a reference to us so there should be no
86     // way for us to be destroyed while we still have a parent.
87     ASSERT(!parent());
88
89     if (m_ccLayerImpl)
90         m_ccLayerImpl->clearOwner();
91
92     // Remove the parent reference from all children.
93     removeAllChildren();
94 }
95
96 void LayerChromium::cleanupResources()
97 {
98 }
99
100 void LayerChromium::setLayerRenderer(LayerRendererChromium* renderer)
101 {
102     // If we're changing layer renderers then we need to free up any resources
103     // allocated by the old renderer.
104     if (layerRenderer() && layerRenderer() != renderer) {
105         cleanupResources();
106         setNeedsDisplay();
107     }
108     m_layerRenderer = renderer;
109 }
110
111 void LayerChromium::setNeedsCommit()
112 {
113     // Call notifySyncRequired(), which for non-root layers plumbs through to
114     // call setRootLayerNeedsDisplay() on the WebView, which will cause LayerRendererChromium
115     // to render a frame.
116     // This function has no effect on root layers.
117     if (m_owner)
118         m_owner->notifySyncRequired();
119 }
120
121 void LayerChromium::addChild(PassRefPtr<LayerChromium> child)
122 {
123     insertChild(child, numChildren());
124 }
125
126 void LayerChromium::insertChild(PassRefPtr<LayerChromium> child, size_t index)
127 {
128     index = min(index, m_children.size());
129     child->removeFromParent();
130     child->setParent(this);
131     m_children.insert(index, child);
132     setNeedsCommit();
133 }
134
135 void LayerChromium::removeFromParent()
136 {
137     if (m_parent)
138         m_parent->removeChild(this);
139 }
140
141 void LayerChromium::removeChild(LayerChromium* child)
142 {
143     int foundIndex = indexOfChild(child);
144     if (foundIndex == -1)
145         return;
146
147     child->setParent(0);
148     m_children.remove(foundIndex);
149     setNeedsCommit();
150 }
151
152 void LayerChromium::replaceChild(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer)
153 {
154     ASSERT_ARG(reference, reference);
155     ASSERT_ARG(reference, reference->parent() == this);
156
157     if (reference == newLayer)
158         return;
159
160     int referenceIndex = indexOfChild(reference);
161     if (referenceIndex == -1) {
162         ASSERT_NOT_REACHED();
163         return;
164     }
165
166     reference->removeFromParent();
167
168     if (newLayer) {
169         newLayer->removeFromParent();
170         insertChild(newLayer, referenceIndex);
171     }
172 }
173
174 int LayerChromium::indexOfChild(const LayerChromium* reference)
175 {
176     for (size_t i = 0; i < m_children.size(); i++) {
177         if (m_children[i] == reference)
178             return i;
179     }
180     return -1;
181 }
182
183 void LayerChromium::setBounds(const IntSize& size)
184 {
185     if (bounds() == size)
186         return;
187
188     bool firstResize = !bounds().width() && !bounds().height() && size.width() && size.height();
189
190     m_bounds = size;
191
192     if (firstResize)
193         setNeedsDisplay(FloatRect(0, 0, bounds().width(), bounds().height()));
194     else
195         setNeedsCommit();
196 }
197
198 void LayerChromium::setFrame(const FloatRect& rect)
199 {
200     if (rect == m_frame)
201       return;
202
203     m_frame = rect;
204     setNeedsDisplay(FloatRect(0, 0, bounds().width(), bounds().height()));
205 }
206
207 const LayerChromium* LayerChromium::rootLayer() const
208 {
209     const LayerChromium* layer = this;
210     for (LayerChromium* parent = layer->parent(); parent; layer = parent, parent = parent->parent()) { }
211     return layer;
212 }
213
214 void LayerChromium::removeAllChildren()
215 {
216     while (m_children.size()) {
217         LayerChromium* layer = m_children[0].get();
218         ASSERT(layer->parent());
219         layer->removeFromParent();
220     }
221 }
222
223 void LayerChromium::setChildren(const Vector<RefPtr<LayerChromium> >& children)
224 {
225     if (children == m_children)
226         return;
227
228     removeAllChildren();
229     size_t listSize = children.size();
230     for (size_t i = 0; i < listSize; i++)
231         addChild(children[i]);
232 }
233
234 LayerChromium* LayerChromium::parent() const
235 {
236     return m_parent;
237 }
238
239 void LayerChromium::setName(const String& name)
240 {
241     m_name = name;
242 }
243
244 void LayerChromium::setNeedsDisplay(const FloatRect& dirtyRect)
245 {
246     // Simply mark the contents as dirty. For non-root layers, the call to
247     // setNeedsCommit will schedule a fresh compositing pass.
248     // For the root layer, setNeedsCommit has no effect.
249     m_contentsDirty = true;
250
251     m_dirtyRect.unite(dirtyRect);
252     setNeedsCommit();
253 }
254
255 void LayerChromium::setNeedsDisplay()
256 {
257     m_dirtyRect.setLocation(FloatPoint());
258     m_dirtyRect.setSize(bounds());
259     m_contentsDirty = true;
260     setNeedsCommit();
261 }
262
263 void LayerChromium::resetNeedsDisplay()
264 {
265     m_dirtyRect = FloatRect();
266     m_contentsDirty = false;
267 }
268
269 void LayerChromium::toGLMatrix(float* flattened, const TransformationMatrix& m)
270 {
271     flattened[0] = m.m11();
272     flattened[1] = m.m12();
273     flattened[2] = m.m13();
274     flattened[3] = m.m14();
275     flattened[4] = m.m21();
276     flattened[5] = m.m22();
277     flattened[6] = m.m23();
278     flattened[7] = m.m24();
279     flattened[8] = m.m31();
280     flattened[9] = m.m32();
281     flattened[10] = m.m33();
282     flattened[11] = m.m34();
283     flattened[12] = m.m41();
284     flattened[13] = m.m42();
285     flattened[14] = m.m43();
286     flattened[15] = m.m44();
287 }
288
289 void LayerChromium::pushPropertiesTo(CCLayerImpl* layer)
290 {
291     layer->setAnchorPoint(m_anchorPoint);
292     layer->setAnchorPointZ(m_anchorPointZ);
293     layer->setBounds(m_bounds);
294     layer->setContentBounds(contentBounds());
295     layer->setDebugBorderColor(m_debugBorderColor);
296     layer->setDebugBorderWidth(m_debugBorderWidth);
297     layer->setDoubleSided(m_doubleSided);
298     layer->setDrawsContent(drawsContent());
299     layer->setLayerRenderer(m_layerRenderer.get());
300     layer->setMasksToBounds(m_masksToBounds);
301     layer->setName(m_name);
302     layer->setOpacity(m_opacity);
303     layer->setPosition(m_position);
304     layer->setPreserves3D(preserves3D());
305     layer->setSublayerTransform(m_sublayerTransform);
306     layer->setTransform(m_transform);
307     layer->setVisibleLayerRect(m_visibleLayerRect);
308
309     if (maskLayer())
310         maskLayer()->pushPropertiesTo(layer->maskLayer());
311     if (replicaLayer())
312         replicaLayer()->pushPropertiesTo(layer->replicaLayer());
313 }
314
315 GraphicsContext3D* LayerChromium::layerRendererContext() const
316 {
317     ASSERT(layerRenderer());
318     return layerRenderer()->context();
319 }
320
321 void LayerChromium::drawTexturedQuad(GraphicsContext3D* context, const TransformationMatrix& projectionMatrix, const TransformationMatrix& drawMatrix,
322                                      float width, float height, float opacity,
323                                      int matrixLocation, int alphaLocation)
324 {
325     static float glMatrix[16];
326
327     TransformationMatrix renderMatrix = drawMatrix;
328
329     // Apply a scaling factor to size the quad from 1x1 to its intended size.
330     renderMatrix.scale3d(width, height, 1);
331
332     // Apply the projection matrix before sending the transform over to the shader.
333     toGLMatrix(&glMatrix[0], projectionMatrix * renderMatrix);
334
335     GLC(context, context->uniformMatrix4fv(matrixLocation, false, &glMatrix[0], 1));
336
337     if (alphaLocation != -1)
338         GLC(context, context->uniform1f(alphaLocation, opacity));
339
340     GLC(context, context->drawElements(GraphicsContext3D::TRIANGLES, 6, GraphicsContext3D::UNSIGNED_SHORT, 0));
341 }
342
343 String LayerChromium::layerTreeAsText() const
344 {
345     TextStream ts;
346     dumpLayer(ts, 0);
347     return ts.release();
348 }
349
350 static void writeIndent(TextStream& ts, int indent)
351 {
352     for (int i = 0; i != indent; ++i)
353         ts << "  ";
354 }
355
356 void LayerChromium::dumpLayer(TextStream& ts, int indent) const
357 {
358     writeIndent(ts, indent);
359     ts << layerTypeAsString() << "(" << m_name << ")\n";
360     dumpLayerProperties(ts, indent+2);
361     if (m_replicaLayer) {
362         writeIndent(ts, indent+2);
363         ts << "Replica:\n";
364         m_replicaLayer->dumpLayer(ts, indent+3);
365     }
366     if (m_maskLayer) {
367         writeIndent(ts, indent+2);
368         ts << "Mask:\n";
369         m_maskLayer->dumpLayer(ts, indent+3);
370     }
371     for (size_t i = 0; i < m_children.size(); ++i)
372         m_children[i]->dumpLayer(ts, indent+1);
373 }
374
375 void LayerChromium::dumpLayerProperties(TextStream& ts, int indent) const
376 {
377     writeIndent(ts, indent);
378     ts << "id: " << id() << " drawsContent: " << drawsContent() << " bounds " << m_bounds.width() << "x" << m_bounds.height() << "\n";
379
380 }
381
382 PassRefPtr<CCLayerImpl> LayerChromium::createCCLayerImpl()
383 {
384     return CCLayerImpl::create(this, m_layerId);
385 }
386
387 CCLayerImpl* LayerChromium::ccLayerImpl() const
388 {
389     return m_ccLayerImpl;
390 }
391
392 void LayerChromium::setBorderColor(const Color& color)
393 {
394     m_debugBorderColor = color;
395     setNeedsCommit();
396 }
397
398 void LayerChromium::setBorderWidth(float width)
399 {
400     m_debugBorderWidth = width;
401     setNeedsCommit();
402 }
403
404 LayerRendererChromium* LayerChromium::layerRenderer() const
405 {
406     return m_layerRenderer.get();
407 }
408
409 }
410 #endif // USE(ACCELERATED_COMPOSITING)