[chromium] Compute occlusion during paint loop
[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 #include "LayerChromium.h"
35
36 #include "cc/CCLayerImpl.h"
37 #include "cc/CCLayerTreeHost.h"
38 #if USE(SKIA)
39 #include "NativeImageSkia.h"
40 #include "PlatformContextSkia.h"
41 #endif
42 #include "Region.h"
43 #include "RenderLayerBacking.h"
44 #include "TextStream.h"
45 #include "skia/ext/platform_canvas.h"
46
47 namespace WebCore {
48
49 using namespace std;
50
51 static int s_nextLayerId = 1;
52
53 PassRefPtr<LayerChromium> LayerChromium::create()
54 {
55     return adoptRef(new LayerChromium());
56 }
57
58 LayerChromium::LayerChromium()
59     : m_needsDisplay(false)
60     , m_layerId(s_nextLayerId++)
61     , m_parent(0)
62     , m_scrollable(false)
63     , m_anchorPoint(0.5, 0.5)
64     , m_backgroundColor(0, 0, 0, 0)
65     , m_backgroundCoversViewport(false)
66     , m_debugBorderWidth(0)
67     , m_opacity(1.0)
68     , m_anchorPointZ(0)
69     , m_isDrawable(false)
70     , m_masksToBounds(false)
71     , m_opaque(false)
72     , m_doubleSided(true)
73     , m_usesLayerClipping(false)
74     , m_isNonCompositedContent(false)
75     , m_preserves3D(false)
76     , m_alwaysReserveTextures(false)
77     , m_replicaLayer(0)
78     , m_drawOpacity(0)
79     , m_targetRenderSurface(0)
80     , m_contentsScale(1.0)
81     , m_pageScaleDirty(false)
82 {
83 }
84
85 LayerChromium::~LayerChromium()
86 {
87     // Our parent should be holding a reference to us so there should be no
88     // way for us to be destroyed while we still have a parent.
89     ASSERT(!parent());
90
91     // Remove the parent reference from all children.
92     removeAllChildren();
93 }
94
95 void LayerChromium::cleanupResources()
96 {
97 }
98
99 void LayerChromium::setIsNonCompositedContent(bool isNonCompositedContent)
100 {
101     m_isNonCompositedContent = isNonCompositedContent;
102 }
103
104 void LayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
105 {
106     if (m_layerTreeHost == host)
107         return;
108
109     // If we're changing hosts then we need to free up any resources
110     // allocated by the old host.
111     if (m_layerTreeHost)
112         cleanupResources();
113
114     m_layerTreeHost = host;
115
116     for (size_t i = 0; i < m_children.size(); ++i)
117         m_children[i]->setLayerTreeHost(host);
118
119     if (m_maskLayer)
120         m_maskLayer->setLayerTreeHost(host);
121     if (m_replicaLayer)
122         m_replicaLayer->setLayerTreeHost(host);
123 }
124
125 void LayerChromium::setNeedsCommit()
126 {
127     if (m_layerTreeHost)
128         m_layerTreeHost->setNeedsCommit();
129 }
130
131 void LayerChromium::setParent(LayerChromium* layer)
132 {
133     ASSERT(!layer || !layer->hasAncestor(this));
134     m_parent = layer;
135     setLayerTreeHost(m_parent ? m_parent->layerTreeHost() : 0);
136 }
137
138 bool LayerChromium::hasAncestor(LayerChromium* ancestor) const
139 {
140     for (LayerChromium* layer = parent(); layer; layer = layer->parent()) {
141         if (layer == ancestor)
142             return true;
143     }
144     return false;
145 }
146
147 void LayerChromium::addChild(PassRefPtr<LayerChromium> child)
148 {
149     insertChild(child, numChildren());
150 }
151
152 void LayerChromium::insertChild(PassRefPtr<LayerChromium> child, size_t index)
153 {
154     index = min(index, m_children.size());
155     child->removeFromParent();
156     child->setParent(this);
157     m_children.insert(index, child);
158     setNeedsCommit();
159 }
160
161 void LayerChromium::removeFromParent()
162 {
163     if (m_parent)
164         m_parent->removeChild(this);
165 }
166
167 void LayerChromium::removeChild(LayerChromium* child)
168 {
169     int foundIndex = indexOfChild(child);
170     if (foundIndex == -1)
171         return;
172
173     child->setParent(0);
174     m_children.remove(foundIndex);
175     setNeedsCommit();
176 }
177
178 void LayerChromium::replaceChild(LayerChromium* reference, PassRefPtr<LayerChromium> newLayer)
179 {
180     ASSERT_ARG(reference, reference);
181     ASSERT_ARG(reference, reference->parent() == this);
182
183     if (reference == newLayer)
184         return;
185
186     int referenceIndex = indexOfChild(reference);
187     if (referenceIndex == -1) {
188         ASSERT_NOT_REACHED();
189         return;
190     }
191
192     reference->removeFromParent();
193
194     if (newLayer) {
195         newLayer->removeFromParent();
196         insertChild(newLayer, referenceIndex);
197     }
198 }
199
200 int LayerChromium::indexOfChild(const LayerChromium* reference)
201 {
202     for (size_t i = 0; i < m_children.size(); i++) {
203         if (m_children[i] == reference)
204             return i;
205     }
206     return -1;
207 }
208
209 void LayerChromium::setBounds(const IntSize& size)
210 {
211     if (bounds() == size)
212         return;
213
214     bool firstResize = !bounds().width() && !bounds().height() && size.width() && size.height();
215
216     m_bounds = size;
217
218     if (firstResize || m_pageScaleDirty)
219         setNeedsDisplay();
220     else
221         setNeedsCommit();
222
223     m_pageScaleDirty = false;
224 }
225
226 const LayerChromium* LayerChromium::rootLayer() const
227 {
228     const LayerChromium* layer = this;
229     for (LayerChromium* parent = layer->parent(); parent; layer = parent, parent = parent->parent()) { }
230     return layer;
231 }
232
233 void LayerChromium::removeAllChildren()
234 {
235     while (m_children.size()) {
236         LayerChromium* layer = m_children[0].get();
237         ASSERT(layer->parent());
238         layer->removeFromParent();
239     }
240 }
241
242 void LayerChromium::setChildren(const Vector<RefPtr<LayerChromium> >& children)
243 {
244     if (children == m_children)
245         return;
246
247     removeAllChildren();
248     size_t listSize = children.size();
249     for (size_t i = 0; i < listSize; i++)
250         addChild(children[i]);
251 }
252
253 void LayerChromium::setAnchorPoint(const FloatPoint& anchorPoint)
254 {
255     if (m_anchorPoint == anchorPoint)
256         return;
257     m_anchorPoint = anchorPoint;
258     setNeedsCommit();
259 }
260
261 void LayerChromium::setAnchorPointZ(float anchorPointZ)
262 {
263     if (m_anchorPointZ == anchorPointZ)
264         return;
265     m_anchorPointZ = anchorPointZ;
266     setNeedsCommit();
267 }
268
269 void LayerChromium::setBackgroundColor(const Color& backgroundColor)
270 {
271     if (m_backgroundColor == backgroundColor)
272         return;
273     m_backgroundColor = backgroundColor;
274     setNeedsCommit();
275 }
276
277 void LayerChromium::setBackgroundCoversViewport(bool backgroundCoversViewport)
278 {
279     if (m_backgroundCoversViewport == backgroundCoversViewport)
280         return;
281     m_backgroundCoversViewport = backgroundCoversViewport;
282     setNeedsCommit();
283 }
284
285 void LayerChromium::setMasksToBounds(bool masksToBounds)
286 {
287     if (m_masksToBounds == masksToBounds)
288         return;
289     m_masksToBounds = masksToBounds;
290     setNeedsCommit();
291 }
292
293 void LayerChromium::setMaskLayer(LayerChromium* maskLayer)
294 {
295     if (m_maskLayer == maskLayer)
296         return;
297     if (m_maskLayer)
298         m_maskLayer->setLayerTreeHost(0);
299     m_maskLayer = maskLayer;
300     if (m_maskLayer)
301         m_maskLayer->setLayerTreeHost(m_layerTreeHost.get());
302     setNeedsCommit();
303 }
304
305 void LayerChromium::setReplicaLayer(LayerChromium* layer)
306 {
307     if (m_replicaLayer == layer)
308         return;
309     if (m_replicaLayer)
310         m_replicaLayer->setLayerTreeHost(0);
311     m_replicaLayer = layer;
312     if (m_replicaLayer)
313         m_replicaLayer->setLayerTreeHost(m_layerTreeHost.get());
314     setNeedsCommit();
315 }
316
317 void LayerChromium::setOpacity(float opacity)
318 {
319     if (m_opacity == opacity)
320         return;
321     m_opacity = opacity;
322     setNeedsCommit();
323 }
324
325 void LayerChromium::setOpaque(bool opaque)
326 {
327     if (m_opaque == opaque)
328         return;
329     m_opaque = opaque;
330     setNeedsDisplay();
331 }
332
333 void LayerChromium::setPosition(const FloatPoint& position)
334 {
335     if (m_position == position)
336         return;
337     m_position = position;
338     setNeedsCommit();
339 }
340
341 void LayerChromium::setSublayerTransform(const TransformationMatrix& sublayerTransform)
342 {
343     if (m_sublayerTransform == sublayerTransform)
344         return;
345     m_sublayerTransform = sublayerTransform;
346     setNeedsCommit();
347 }
348
349 void LayerChromium::setTransform(const TransformationMatrix& transform)
350 {
351     if (m_transform == transform)
352         return;
353     m_transform = transform;
354     setNeedsCommit();
355 }
356
357 void LayerChromium::setScrollPosition(const IntPoint& scrollPosition)
358 {
359     if (m_scrollPosition == scrollPosition)
360         return;
361     m_scrollPosition = scrollPosition;
362     setNeedsCommit();
363 }
364
365 void LayerChromium::setScrollable(bool scrollable)
366 {
367     if (m_scrollable == scrollable)
368         return;
369     m_scrollable = scrollable;
370     setNeedsCommit();
371 }
372
373 void LayerChromium::setDoubleSided(bool doubleSided)
374 {
375     if (m_doubleSided == doubleSided)
376         return;
377     m_doubleSided = doubleSided;
378     setNeedsCommit();
379 }
380
381 void LayerChromium::setIsDrawable(bool isDrawable)
382 {
383     if (m_isDrawable == isDrawable)
384         return;
385
386     m_isDrawable = isDrawable;
387     setNeedsCommit();
388 }
389
390 LayerChromium* LayerChromium::parent() const
391 {
392     return m_parent;
393 }
394
395 void LayerChromium::setName(const String& name)
396 {
397     m_name = name;
398 }
399
400 void LayerChromium::setNeedsDisplayRect(const FloatRect& dirtyRect)
401 {
402     // Simply mark the contents as dirty. For non-root layers, the call to
403     // setNeedsCommit will schedule a fresh compositing pass.
404     // For the root layer, setNeedsCommit has no effect.
405     if (!dirtyRect.isEmpty())
406         m_needsDisplay = true;
407
408     setNeedsCommit();
409 }
410
411 void LayerChromium::pushPropertiesTo(CCLayerImpl* layer)
412 {
413     layer->setAnchorPoint(m_anchorPoint);
414     layer->setAnchorPointZ(m_anchorPointZ);
415     layer->setBackgroundColor(m_backgroundColor);
416     layer->setBackgroundCoversViewport(m_backgroundCoversViewport);
417     layer->setBounds(m_bounds);
418     layer->setContentBounds(contentBounds());
419     layer->setDebugBorderColor(m_debugBorderColor);
420     layer->setDebugBorderWidth(m_debugBorderWidth);
421     layer->setDoubleSided(m_doubleSided);
422     layer->setDrawsContent(drawsContent());
423     layer->setIsNonCompositedContent(m_isNonCompositedContent);
424     layer->setMasksToBounds(m_masksToBounds);
425     layer->setScrollable(m_scrollable);
426     layer->setName(m_name);
427     layer->setOpaque(m_opaque);
428     layer->setOpacity(m_opacity);
429     layer->setPosition(m_position);
430     layer->setPreserves3D(preserves3D());
431     layer->setScrollPosition(m_scrollPosition);
432     layer->setSublayerTransform(m_sublayerTransform);
433     layer->setTransform(m_transform);
434     layer->setUpdateRect(m_updateRect);
435
436     layer->setScrollDelta(layer->scrollDelta() - layer->sentScrollDelta());
437     layer->setSentScrollDelta(IntSize());
438
439     if (maskLayer())
440         maskLayer()->pushPropertiesTo(layer->maskLayer());
441     if (replicaLayer())
442         replicaLayer()->pushPropertiesTo(layer->replicaLayer());
443
444     // Reset any state that should be cleared for the next update.
445     m_updateRect = FloatRect();
446 }
447
448 PassRefPtr<CCLayerImpl> LayerChromium::createCCLayerImpl()
449 {
450     return CCLayerImpl::create(m_layerId);
451 }
452
453 void LayerChromium::setDebugBorderColor(const Color& color)
454 {
455     m_debugBorderColor = color;
456     setNeedsCommit();
457 }
458
459 void LayerChromium::setDebugBorderWidth(float width)
460 {
461     m_debugBorderWidth = width;
462     setNeedsCommit();
463 }
464
465 void LayerChromium::setContentsScale(float contentsScale)
466 {
467     if (!needsContentsScale() || m_contentsScale == contentsScale)
468         return;
469     m_contentsScale = contentsScale;
470     setNeedsDisplay();
471 }
472
473 TransformationMatrix LayerChromium::contentToScreenSpaceTransform() const
474 {
475     IntSize boundsInLayerSpace = bounds();
476     IntSize boundsInContentSpace = contentBounds();
477
478     TransformationMatrix transform = screenSpaceTransform();
479
480     // Scale from content space to layer space
481     transform.scaleNonUniform(boundsInLayerSpace.width() / static_cast<double>(boundsInContentSpace.width()),
482                               boundsInLayerSpace.height() / static_cast<double>(boundsInContentSpace.height()));
483
484     return transform;
485 }
486
487 void LayerChromium::addSelfToOccludedScreenSpace(Region& occludedScreenSpace)
488 {
489     if (!opaque() || drawOpacity() != 1 || !isPaintedAxisAlignedInScreen())
490         return;
491
492     FloatRect targetRect = contentToScreenSpaceTransform().mapRect(FloatRect(visibleLayerRect()));
493     occludedScreenSpace.unite(enclosedIntRect(targetRect));
494 }
495
496 bool LayerChromium::isPaintedAxisAlignedInScreen() const
497 {
498     FloatQuad quad = contentToScreenSpaceTransform().mapQuad(FloatQuad(visibleLayerRect()));
499     return quad.isRectilinear();
500 }
501
502 void LayerChromium::createRenderSurface()
503 {
504     ASSERT(!m_renderSurface);
505     m_renderSurface = adoptPtr(new RenderSurfaceChromium(this));
506 }
507
508 bool LayerChromium::descendantDrawsContent()
509 {
510     for (size_t i = 0; i < m_children.size(); ++i) {
511         if (m_children[i]->drawsContent() || m_children[i]->descendantDrawsContent())
512             return true;
513     }
514     return false;
515 }
516
517 void sortLayers(Vector<RefPtr<LayerChromium> >::iterator, Vector<RefPtr<LayerChromium> >::iterator, void*)
518 {
519     // Currently we don't use z-order to decide what to paint, so there's no need to actually sort LayerChromiums.
520 }
521
522 }
523 #endif // USE(ACCELERATED_COMPOSITING)