88eb3cd1fd97f0fcfc11175daf867a5258b918d3
[WebKit-https.git] / Source / WebCore / platform / graphics / texmap / TextureMapperLayer.cpp
1 /*
2  Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  Library General Public License for more details.
13
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB.  If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "TextureMapperLayer.h"
22
23 #if USE(ACCELERATED_COMPOSITING)
24
25 namespace WebCore {
26
27 class TextureMapperPaintOptions {
28 public:
29     RefPtr<BitmapTexture> surface;
30     RefPtr<BitmapTexture> mask;
31     float opacity;
32     TransformationMatrix transform;
33     IntSize offset;
34     TextureMapper* textureMapper;
35     TextureMapperPaintOptions()
36         : opacity(1)
37         , textureMapper(0)
38     { }
39 };
40
41 const TextureMapperLayer* TextureMapperLayer::rootLayer() const
42 {
43     if (m_effectTarget)
44         return m_effectTarget->rootLayer();
45     if (m_parent)
46         return m_parent->rootLayer();
47     return this;
48 }
49
50 void TextureMapperLayer::computeTransformsRecursive()
51 {
52     if (m_state.size.isEmpty() && m_state.masksToBounds)
53         return;
54
55     // Compute transforms recursively on the way down to leafs.
56     TransformationMatrix parentTransform;
57     if (m_parent)
58         parentTransform = m_parent->m_currentTransform.combinedForChildren();
59     else if (m_effectTarget)
60         parentTransform = m_effectTarget->m_currentTransform.combined();
61     m_currentTransform.combineTransforms(parentTransform);
62
63     m_state.visible = m_state.backfaceVisibility || !m_currentTransform.combined().isBackFaceVisible();
64
65     if (m_parent && m_parent->m_state.preserves3D)
66         m_centerZ = m_currentTransform.combined().mapPoint(FloatPoint3D(m_state.size.width() / 2, m_state.size.height() / 2, 0)).z();
67
68     if (m_state.maskLayer)
69         m_state.maskLayer->computeTransformsRecursive();
70     if (m_state.replicaLayer)
71         m_state.replicaLayer->computeTransformsRecursive();
72     for (size_t i = 0; i < m_children.size(); ++i)
73         m_children[i]->computeTransformsRecursive();
74
75     // Reorder children if needed on the way back up.
76     if (m_state.preserves3D)
77         sortByZOrder(m_children, 0, m_children.size());
78 }
79
80 void TextureMapperLayer::paint()
81 {
82     computeTransformsRecursive();
83
84     TextureMapperPaintOptions options;
85     options.textureMapper = m_textureMapper;
86     options.textureMapper->bindSurface(0);
87     paintRecursive(options);
88 }
89
90 static Color blendWithOpacity(const Color& color, float opacity)
91 {
92     RGBA32 rgba = color.rgb();
93     // See Color::getRGBA() to know how to extract alpha from color.
94     float alpha = alphaChannel(rgba) / 255.;
95     float effectiveAlpha = alpha * opacity;
96     return Color(colorWithOverrideAlpha(rgba, effectiveAlpha));
97 }
98
99 void TextureMapperLayer::paintSelf(const TextureMapperPaintOptions& options)
100 {
101     if (!m_state.visible || !m_state.contentsVisible)
102         return;
103
104     // We apply the following transform to compensate for painting into a surface, and then apply the offset so that the painting fits in the target rect.
105     TransformationMatrix transform;
106     transform.translate(options.offset.width(), options.offset.height());
107     transform.multiply(options.transform);
108     transform.multiply(m_currentTransform.combined());
109
110     float opacity = options.opacity;
111     RefPtr<BitmapTexture> mask = options.mask;
112
113     if (m_state.solidColor.isValid() && !m_state.contentsRect.isEmpty()) {
114         options.textureMapper->drawSolidColor(m_state.contentsRect, transform, blendWithOpacity(m_state.solidColor, opacity));
115         if (m_state.showDebugBorders)
116             options.textureMapper->drawBorder(m_state.debugBorderColor, m_state.debugBorderWidth, layerRect(), transform);
117         return;
118     }
119
120     if (m_backingStore) {
121         ASSERT(m_state.drawsContent && m_state.contentsVisible && !m_state.size.isEmpty());
122         ASSERT(!layerRect().isEmpty());
123         m_backingStore->paintToTextureMapper(options.textureMapper, layerRect(), transform, opacity, mask.get());
124         if (m_state.showDebugBorders)
125             m_backingStore->drawBorder(options.textureMapper, m_state.debugBorderColor, m_state.debugBorderWidth, layerRect(), transform);
126         // Only draw repaint count for the main backing store.
127         if (m_state.showRepaintCounter)
128             m_backingStore->drawRepaintCounter(options.textureMapper, m_state.repaintCount, m_state.debugBorderColor, layerRect(), transform);
129     }
130
131     if (m_contentsLayer) {
132         ASSERT(!layerRect().isEmpty());
133         m_contentsLayer->paintToTextureMapper(options.textureMapper, m_state.contentsRect, transform, opacity, mask.get());
134         if (m_state.showDebugBorders)
135             m_contentsLayer->drawBorder(options.textureMapper, m_state.debugBorderColor, m_state.debugBorderWidth, m_state.contentsRect, transform);
136     }
137 }
138
139 int TextureMapperLayer::compareGraphicsLayersZValue(const void* a, const void* b)
140 {
141     TextureMapperLayer* const* layerA = static_cast<TextureMapperLayer* const*>(a);
142     TextureMapperLayer* const* layerB = static_cast<TextureMapperLayer* const*>(b);
143     return int(((*layerA)->m_centerZ - (*layerB)->m_centerZ) * 1000);
144 }
145
146 void TextureMapperLayer::sortByZOrder(Vector<TextureMapperLayer* >& array, int /* first */, int /* last */)
147 {
148     qsort(array.data(), array.size(), sizeof(TextureMapperLayer*), compareGraphicsLayersZValue);
149 }
150
151 void TextureMapperLayer::paintSelfAndChildren(const TextureMapperPaintOptions& options)
152 {
153     paintSelf(options);
154
155     if (m_children.isEmpty())
156         return;
157
158     bool shouldClip = m_state.masksToBounds && !m_state.preserves3D;
159     if (shouldClip)
160         options.textureMapper->beginClip(TransformationMatrix(options.transform).multiply(m_currentTransform.combined()), layerRect());
161
162     for (size_t i = 0; i < m_children.size(); ++i)
163         m_children[i]->paintRecursive(options);
164
165     if (shouldClip)
166         options.textureMapper->endClip();
167 }
168
169 IntRect TextureMapperLayer::intermediateSurfaceRect()
170 {
171     // FIXME: Add an inverse transform to LayerTransform.
172     return intermediateSurfaceRect(m_currentTransform.combined().inverse());
173 }
174
175 IntRect TextureMapperLayer::intermediateSurfaceRect(const TransformationMatrix& matrix)
176 {
177     IntRect rect;
178     TransformationMatrix localTransform = TransformationMatrix(matrix).multiply(m_currentTransform.combined());
179     rect = enclosingIntRect(localTransform.mapRect(layerRect()));
180     if (!m_state.masksToBounds && !m_state.maskLayer) {
181         for (size_t i = 0; i < m_children.size(); ++i)
182             rect.unite(m_children[i]->intermediateSurfaceRect(matrix));
183     }
184
185 #if ENABLE(CSS_FILTERS)
186     if (m_currentFilters.hasOutsets()) {
187         FilterOutsets outsets = m_currentFilters.outsets();
188         IntRect unfilteredTargetRect(rect);
189         rect.move(std::max(0, -outsets.left()), std::max(0, -outsets.top()));
190         rect.expand(outsets.left() + outsets.right(), outsets.top() + outsets.bottom());
191         rect.unite(unfilteredTargetRect);
192     }
193 #endif
194
195     if (m_state.replicaLayer)
196         rect.unite(m_state.replicaLayer->intermediateSurfaceRect(matrix));
197
198     return rect;
199 }
200
201 TextureMapperLayer::ContentsLayerCount TextureMapperLayer::countPotentialLayersWithContents() const
202 {
203     int selfLayersWithContents = (m_state.drawsContent ? 1 : 0) + (m_contentsLayer ? 1 : 0);
204     int potentialLayersWithContents = selfLayersWithContents + m_children.size();
205
206     if (!potentialLayersWithContents)
207         return NoLayersWithContent;
208
209     if (potentialLayersWithContents > 1)
210         return MultipleLayersWithContents;
211
212     if (m_children.isEmpty())
213         return SingleLayerWithContents;
214
215     return m_children.first()->countPotentialLayersWithContents();
216 }
217
218 bool TextureMapperLayer::shouldPaintToIntermediateSurface() const
219 {
220 #if ENABLE(CSS_FILTERS)
221     if (m_currentFilters.size())
222         return true;
223 #endif
224     bool hasOpacity = m_currentOpacity < 0.99;
225     bool canHaveMultipleLayersWithContent = countPotentialLayersWithContents() == MultipleLayersWithContents;
226     bool hasReplica = !!m_state.replicaLayer;
227     bool hasMask = !!m_state.maskLayer;
228
229     // We don't use two-pass blending for preserves-3d, that's in sync with Safari.
230     if (m_state.preserves3D)
231         return false;
232
233     // We should use an intermediate surface when blending several items with an ancestor opacity.
234     // Tested by compositing/reflections/reflection-opacity.html
235     if (hasOpacity && (canHaveMultipleLayersWithContent || hasReplica))
236         return true;
237
238     // We should use an intermediate surface with a masked ancestor.
239     // In the case of replicas the mask is applied before replicating.
240     // Tested by compositing/masks/masked-ancestor.html
241     if (hasMask && canHaveMultipleLayersWithContent && !hasReplica)
242         return true;
243
244     return false;
245 }
246
247 bool TextureMapperLayer::isVisible() const
248 {
249     if (m_state.size.isEmpty() && (m_state.masksToBounds || m_state.maskLayer || m_children.isEmpty()))
250         return false;
251     if (!m_state.visible && m_children.isEmpty())
252         return false;
253     if (!m_state.contentsVisible && m_children.isEmpty())
254         return false;
255     if (m_currentOpacity < 0.01)
256         return false;
257     return true;
258 }
259
260 void TextureMapperLayer::paintSelfAndChildrenWithReplica(const TextureMapperPaintOptions& options)
261 {
262     if (m_state.replicaLayer) {
263         TextureMapperPaintOptions replicaOptions(options);
264         // We choose either the content's mask or the replica's mask.
265         // FIXME: blend the two if both exist.
266         if (m_state.replicaLayer->m_state.maskLayer)
267             replicaOptions.mask = m_state.replicaLayer->m_state.maskLayer->texture();
268
269         replicaOptions.transform
270             .multiply(m_state.replicaLayer->m_currentTransform.combined())
271             .multiply(m_currentTransform.combined().inverse());
272         paintSelfAndChildren(replicaOptions);
273     }
274
275     paintSelfAndChildren(options);
276 }
277
278 void TextureMapperLayer::setAnimatedTransform(const TransformationMatrix& matrix)
279 {
280     m_shouldUpdateCurrentTransformFromGraphicsLayer = false;
281     m_currentTransform.setLocalTransform(matrix);
282 }
283
284 void TextureMapperLayer::setAnimatedOpacity(float opacity)
285 {
286     m_shouldUpdateCurrentOpacityFromGraphicsLayer = false;
287     m_currentOpacity = opacity;
288 }
289
290 #if ENABLE(CSS_FILTERS)
291 void TextureMapperLayer::setAnimatedFilters(const FilterOperations& filters)
292 {
293     m_shouldUpdateCurrentFiltersFromGraphicsLayer = false;
294     m_currentFilters = filters;
295 }
296
297 static bool shouldKeepContentTexture(const FilterOperations& filters)
298 {
299     for (size_t i = 0; i < filters.size(); ++i) {
300         switch (filters.operations().at(i)->getOperationType()) {
301         // The drop-shadow filter requires the content texture, because it needs to composite it
302         // on top of the blurred shadow color.
303         case FilterOperation::DROP_SHADOW:
304             return true;
305         default:
306             break;
307         }
308     }
309
310     return false;
311 }
312
313 static PassRefPtr<BitmapTexture> applyFilters(const FilterOperations& filters, TextureMapper* textureMapper, BitmapTexture* source, IntRect& targetRect)
314 {
315     if (!filters.size())
316         return source;
317
318     RefPtr<BitmapTexture> filterSurface = shouldKeepContentTexture(filters) ? textureMapper->acquireTextureFromPool(source->size()) : source;
319     return filterSurface->applyFilters(textureMapper, *source, filters);
320 }
321 #endif
322
323 void TextureMapperLayer::paintRecursive(const TextureMapperPaintOptions& options)
324 {
325     if (!isVisible())
326         return;
327
328     float opacity = options.opacity * m_currentOpacity;
329     RefPtr<BitmapTexture> maskTexture = m_state.maskLayer ? m_state.maskLayer->texture() : 0;
330
331     TextureMapperPaintOptions paintOptions(options);
332     paintOptions.mask = maskTexture.get();
333
334     if (!shouldPaintToIntermediateSurface()) {
335         paintOptions.opacity = opacity;
336         paintSelfAndChildrenWithReplica(paintOptions);
337         return;
338     }
339
340     // Prepare a surface to paint into.
341     // We paint into the surface ignoring the opacity/transform of the current layer.
342     IntRect surfaceRect = intermediateSurfaceRect();
343     RefPtr<BitmapTexture> surface = options.textureMapper->acquireTextureFromPool(surfaceRect.size());
344     paintOptions.surface = surface;
345     options.textureMapper->bindSurface(surface.get());
346     paintOptions.opacity = 1;
347
348     paintOptions.transform = m_currentTransform.combined().inverse();
349     paintOptions.offset = -IntSize(surfaceRect.x(), surfaceRect.y());
350
351     paintSelfAndChildrenWithReplica(paintOptions);
352
353     // If we painted the replica, the mask is already applied so we don't need to paint it again.
354     if (m_state.replicaLayer)
355         maskTexture = 0;
356
357 #if ENABLE(CSS_FILTERS)
358     surface = applyFilters(m_currentFilters, options.textureMapper, surface.get(), surfaceRect);
359 #endif
360
361     options.textureMapper->bindSurface(options.surface.get());
362     TransformationMatrix targetTransform;
363     targetTransform.translate(options.offset.width(), options.offset.height());
364     targetTransform.multiply(options.transform);
365     targetTransform.multiply(m_currentTransform.combined());
366
367     options.textureMapper->drawTexture(*surface.get(), surfaceRect, targetTransform, opacity, maskTexture.get());
368 }
369
370 TextureMapperLayer::~TextureMapperLayer()
371 {
372     for (int i = m_children.size() - 1; i >= 0; --i)
373         m_children[i]->m_parent = 0;
374
375     if (m_parent)
376         m_parent->m_children.remove(m_parent->m_children.find(this));
377 }
378
379 TextureMapper* TextureMapperLayer::textureMapper() const
380 {
381     return rootLayer()->m_textureMapper;
382 }
383
384 void TextureMapperLayer::setChildren(const Vector<TextureMapperLayer*>& newChildren)
385 {
386     removeAllChildren();
387     for (size_t i = 0; i < newChildren.size(); ++i)
388         addChild(newChildren[i]);
389 }
390
391 void TextureMapperLayer::addChild(TextureMapperLayer* childLayer)
392 {
393     ASSERT(childLayer != this);
394
395     if (childLayer->m_parent)
396         childLayer->removeFromParent();
397
398     childLayer->m_parent = this;
399     m_children.append(childLayer);
400 }
401
402 void TextureMapperLayer::removeFromParent()
403 {
404     if (m_parent) {
405         unsigned i;
406         for (i = 0; i < m_parent->m_children.size(); i++) {
407             if (this == m_parent->m_children[i]) {
408                 m_parent->m_children.remove(i);
409                 break;
410             }
411         }
412
413         m_parent = 0;
414     }
415 }
416
417 void TextureMapperLayer::removeAllChildren()
418 {
419     while (m_children.size()) {
420         TextureMapperLayer* curLayer = m_children[0];
421         ASSERT(curLayer->m_parent);
422         curLayer->removeFromParent();
423     }
424 }
425
426 void TextureMapperLayer::setMaskLayer(TextureMapperLayer* maskLayer)
427 {
428     if (maskLayer)
429         maskLayer->m_effectTarget = this;
430     m_state.maskLayer = maskLayer;
431 }
432
433 void TextureMapperLayer::setReplicaLayer(TextureMapperLayer* replicaLayer)
434 {
435     if (replicaLayer)
436         replicaLayer->m_effectTarget = this;
437     m_state.replicaLayer = replicaLayer;
438 }
439
440 void TextureMapperLayer::setPosition(const FloatPoint& position)
441 {
442     m_state.pos = position;
443     m_currentTransform.setPosition(adjustedPosition());
444 }
445
446 void TextureMapperLayer::setSize(const FloatSize& size)
447 {
448     m_state.size = size;
449     m_currentTransform.setSize(size);
450 }
451
452 void TextureMapperLayer::setAnchorPoint(const FloatPoint3D& anchorPoint)
453 {
454     m_state.anchorPoint = anchorPoint;
455     m_currentTransform.setAnchorPoint(anchorPoint);
456 }
457
458 void TextureMapperLayer::setPreserves3D(bool preserves3D)
459 {
460     m_state.preserves3D = preserves3D;
461     m_currentTransform.setFlattening(!preserves3D);
462 }
463
464 void TextureMapperLayer::setTransform(const TransformationMatrix& transform)
465 {
466     m_state.transform = transform;
467     m_currentTransform.setLocalTransform(transform);
468 }
469
470 void TextureMapperLayer::setChildrenTransform(const TransformationMatrix& childrenTransform)
471 {
472     m_state.childrenTransform = childrenTransform;
473     m_currentTransform.setChildrenTransform(childrenTransform);
474 }
475
476 void TextureMapperLayer::setContentsRect(const IntRect& contentsRect)
477 {
478     m_state.contentsRect = contentsRect;
479 }
480
481 void TextureMapperLayer::setMasksToBounds(bool masksToBounds)
482 {
483     m_state.masksToBounds = masksToBounds;
484 }
485
486 void TextureMapperLayer::setDrawsContent(bool drawsContent)
487 {
488     m_state.drawsContent = drawsContent;
489 }
490
491 void TextureMapperLayer::setContentsVisible(bool contentsVisible)
492 {
493     m_state.contentsVisible = contentsVisible;
494 }
495
496 void TextureMapperLayer::setContentsOpaque(bool contentsOpaque)
497 {
498     m_state.contentsOpaque = contentsOpaque;
499 }
500
501 void TextureMapperLayer::setBackfaceVisibility(bool backfaceVisibility)
502 {
503     m_state.backfaceVisibility = backfaceVisibility;
504 }
505
506 void TextureMapperLayer::setOpacity(float opacity)
507 {
508     m_state.opacity = opacity;
509 }
510
511 void TextureMapperLayer::setSolidColor(const Color& color)
512 {
513     m_state.solidColor = color;
514 }
515
516 #if ENABLE(CSS_FILTERS)
517 void TextureMapperLayer::setFilters(const FilterOperations& filters)
518 {
519     m_state.filters = filters;
520 }
521 #endif
522
523 void TextureMapperLayer::setDebugVisuals(bool showDebugBorders, const Color& debugBorderColor, float debugBorderWidth, bool showRepaintCounter)
524 {
525     m_state.showDebugBorders = showDebugBorders;
526     m_state.debugBorderColor = debugBorderColor;
527     m_state.debugBorderWidth = debugBorderWidth;
528     m_state.showRepaintCounter = showRepaintCounter;
529 }
530
531 void TextureMapperLayer::setRepaintCount(int repaintCount)
532 {
533     m_state.repaintCount = repaintCount;
534 }
535
536 void TextureMapperLayer::setContentsLayer(TextureMapperPlatformLayer* platformLayer)
537 {
538     m_contentsLayer = platformLayer;
539 }
540
541 void TextureMapperLayer::setAnimations(const GraphicsLayerAnimations& animations)
542 {
543     m_animations = animations;
544 }
545
546 void TextureMapperLayer::setFixedToViewport(bool fixedToViewport)
547 {
548     m_fixedToViewport = fixedToViewport;
549 }
550
551 void TextureMapperLayer::setBackingStore(PassRefPtr<TextureMapperBackingStore> backingStore)
552 {
553     m_backingStore = backingStore;
554 }
555
556 bool TextureMapperLayer::descendantsOrSelfHaveRunningAnimations() const
557 {
558     if (m_animations.hasRunningAnimations())
559         return true;
560
561     for (size_t i = 0; i < m_children.size(); ++i) {
562         if (m_children[i]->descendantsOrSelfHaveRunningAnimations())
563             return true;
564     }
565
566     return false;
567 }
568
569 void TextureMapperLayer::applyAnimationsRecursively()
570 {
571     syncAnimations();
572     for (size_t i = 0; i < m_children.size(); ++i)
573         m_children[i]->applyAnimationsRecursively();
574 }
575
576 void TextureMapperLayer::syncAnimations()
577 {
578     m_animations.apply(this);
579     if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitTransform) && m_shouldUpdateCurrentTransformFromGraphicsLayer)
580         m_currentTransform.setLocalTransform(m_state.transform);
581     if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyOpacity) && m_shouldUpdateCurrentOpacityFromGraphicsLayer)
582         m_currentOpacity = m_state.opacity;
583
584 #if ENABLE(CSS_FILTERS)
585     if (!m_animations.hasActiveAnimationsOfType(AnimatedPropertyWebkitFilter) && m_shouldUpdateCurrentFiltersFromGraphicsLayer)
586         m_currentFilters = m_state.filters;
587 #endif
588 }
589
590 bool TextureMapperLayer::isAncestorFixedToViewport() const
591 {
592     for (TextureMapperLayer* parent = m_parent; parent; parent = parent->m_parent) {
593         if (parent->m_fixedToViewport)
594             return true;
595     }
596
597     return false;
598 }
599
600 void TextureMapperLayer::setScrollPositionDeltaIfNeeded(const FloatSize& delta)
601 {
602     // delta is the difference between the scroll offset in the ui process and the scroll offset
603     // in the web process. We add this delta to the position of fixed layers, to make
604     // sure that they do not move while scrolling. We need to reset this delta to fixed layers
605     // that have an ancestor which is also a fixed layer, because the delta will be added to the ancestor.
606     if (isAncestorFixedToViewport())
607         m_scrollPositionDelta = FloatSize();
608     else
609         m_scrollPositionDelta = delta;
610     m_currentTransform.setPosition(adjustedPosition());
611 }
612
613 }
614 #endif