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 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
28 #if USE(ACCELERATED_COMPOSITING)
29
30 #include "AnimationController.h"
31 #include "CSSPropertyNames.h"
32 #include "CSSStyleSelector.h"
33 #include "FrameView.h"
34 #include "GraphicsContext.h"
35 #include "GraphicsLayer.h"
36 #include "HTMLElement.h"
37 #include "HTMLNames.h"
38 #include "RenderBox.h"
39 #include "RenderImage.h"
40 #include "RenderLayerCompositor.h"
41 #include "RenderVideo.h"
42 #include "RenderView.h"
43
44 #include "RenderLayerBacking.h"
45
46 using namespace std;
47
48 namespace WebCore {
49
50 static bool hasBorderOutlineOrShadow(const RenderStyle*);
51 static bool hasBoxDecorations(const RenderStyle*);
52 static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle*);
53
RenderLayerBacking(RenderLayer * layer)54 RenderLayerBacking::RenderLayerBacking(RenderLayer* layer)
55 : m_owningLayer(layer)
56 , m_ancestorClippingLayer(0)
57 , m_graphicsLayer(0)
58 , m_foregroundLayer(0)
59 , m_clippingLayer(0)
60 , m_hasDirectlyCompositedContent(false)
61 {
62 createGraphicsLayer();
63 }
64
~RenderLayerBacking()65 RenderLayerBacking::~RenderLayerBacking()
66 {
67 updateClippingLayers(false, false);
68 updateForegroundLayer(false);
69 destroyGraphicsLayer();
70 }
71
createGraphicsLayer()72 void RenderLayerBacking::createGraphicsLayer()
73 {
74 m_graphicsLayer = GraphicsLayer::createGraphicsLayer(this);
75
76 #ifndef NDEBUG
77 if (renderer()->node()) {
78 if (renderer()->node()->isDocumentNode())
79 m_graphicsLayer->setName("Document Node");
80 else {
81 if (renderer()->node()->isHTMLElement() && renderer()->node()->hasID())
82 m_graphicsLayer->setName(renderer()->renderName() + String(" ") + static_cast<HTMLElement*>(renderer()->node())->id());
83 else
84 m_graphicsLayer->setName(renderer()->renderName());
85 }
86 } else
87 m_graphicsLayer->setName("Anonymous Node");
88 #endif // NDEBUG
89
90 updateLayerOpacity();
91 updateLayerTransform();
92 }
93
destroyGraphicsLayer()94 void RenderLayerBacking::destroyGraphicsLayer()
95 {
96 if (m_graphicsLayer)
97 m_graphicsLayer->removeFromParent();
98
99 delete m_graphicsLayer;
100 m_graphicsLayer = 0;
101
102 delete m_foregroundLayer;
103 m_foregroundLayer = 0;
104
105 delete m_clippingLayer;
106 m_clippingLayer = 0;
107 }
108
updateLayerOpacity()109 void RenderLayerBacking::updateLayerOpacity()
110 {
111 m_graphicsLayer->setOpacity(compositingOpacity(renderer()->opacity()));
112 }
113
updateLayerTransform()114 void RenderLayerBacking::updateLayerTransform()
115 {
116 RenderStyle* style = renderer()->style();
117
118 // FIXME: This could use m_owningLayer->transform(), but that currently has transform-origin
119 // baked into it, and we don't want that.
120 TransformationMatrix t;
121 if (m_owningLayer->hasTransform()) {
122 style->applyTransform(t, toRenderBox(renderer())->borderBoxRect().size(), RenderStyle::ExcludeTransformOrigin);
123 makeMatrixRenderable(t, compositor()->hasAcceleratedCompositing());
124 }
125
126 m_graphicsLayer->setTransform(t);
127 }
128
updateAfterLayout(UpdateDepth updateDepth)129 void RenderLayerBacking::updateAfterLayout(UpdateDepth updateDepth)
130 {
131 RenderLayerCompositor* layerCompositor = compositor();
132 if (!layerCompositor->compositingLayersNeedRebuild()) {
133 // Calling updateGraphicsLayerGeometry() here gives incorrect results, because the
134 // position of this layer's GraphicsLayer depends on the position of our compositing
135 // ancestor's GraphicsLayer. That cannot be determined until all the descendant
136 // RenderLayers of that ancestor have been processed via updateLayerPositions().
137 //
138 // The solution is to update compositing children of this layer here,
139 // via updateCompositingChildrenGeometry().
140 setCompositedBounds(layerCompositor->calculateCompositedBounds(m_owningLayer, m_owningLayer));
141 layerCompositor->updateCompositingDescendantGeometry(m_owningLayer, m_owningLayer, updateDepth);
142
143 if (!m_owningLayer->parent()) {
144 updateGraphicsLayerGeometry();
145 layerCompositor->updateRootLayerPosition();
146 }
147 }
148 }
149
updateGraphicsLayerConfiguration()150 bool RenderLayerBacking::updateGraphicsLayerConfiguration()
151 {
152 RenderLayerCompositor* compositor = this->compositor();
153
154 bool layerConfigChanged = false;
155 if (updateForegroundLayer(compositor->needsContentsCompositingLayer(m_owningLayer)))
156 layerConfigChanged = true;
157
158 if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), compositor->clipsCompositingDescendants(m_owningLayer)))
159 layerConfigChanged = true;
160
161 m_hasDirectlyCompositedContent = false;
162 if (canUseDirectCompositing()) {
163 if (renderer()->isImage()) {
164 updateImageContents();
165 m_hasDirectlyCompositedContent = true;
166 m_graphicsLayer->setDrawsContent(false);
167 }
168
169 if (rendererHasBackground())
170 m_graphicsLayer->setBackgroundColor(rendererBackgroundColor());
171 else
172 m_graphicsLayer->clearBackgroundColor();
173 }
174
175 return layerConfigChanged;
176 }
177
updateGraphicsLayerGeometry()178 void RenderLayerBacking::updateGraphicsLayerGeometry()
179 {
180 // If we haven't built z-order lists yet, wait until later.
181 if (m_owningLayer->isStackingContext() && m_owningLayer->m_zOrderListsDirty)
182 return;
183
184 // Set transform property, if it is not animating. We have to do this here because the transform
185 // is affected by the layer dimensions.
186 if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyWebkitTransform))
187 updateLayerTransform();
188
189 // Set opacity, if it is not animating.
190 if (!renderer()->animation()->isAnimatingPropertyOnRenderer(renderer(), CSSPropertyOpacity))
191 updateLayerOpacity();
192
193 RenderStyle* style = renderer()->style();
194 m_graphicsLayer->setPreserves3D(style->transformStyle3D() == TransformStyle3DPreserve3D);
195 m_graphicsLayer->setBackfaceVisibility(style->backfaceVisibility() == BackfaceVisibilityVisible);
196
197 RenderLayer* compAncestor = m_owningLayer->ancestorCompositingLayer();
198
199 // We compute everything relative to the enclosing compositing layer.
200 IntRect ancestorCompositingBounds;
201 if (compAncestor) {
202 ASSERT(compAncestor->backing());
203 ancestorCompositingBounds = compAncestor->backing()->compositedBounds();
204 }
205
206 IntRect localCompositingBounds = compositedBounds();
207
208 IntRect relativeCompositingBounds(localCompositingBounds);
209 int deltaX = 0, deltaY = 0;
210 m_owningLayer->convertToLayerCoords(compAncestor, deltaX, deltaY);
211 relativeCompositingBounds.move(deltaX, deltaY);
212
213 IntPoint graphicsLayerParentLocation;
214 if (compAncestor && compAncestor->backing()->hasClippingLayer()) {
215 // If the compositing ancestor has a layer to clip children, we parent in that, and therefore
216 // position relative to it.
217 graphicsLayerParentLocation = toRenderBox(compAncestor->renderer())->overflowClipRect(0, 0).location();
218 } else
219 graphicsLayerParentLocation = ancestorCompositingBounds.location();
220
221 if (compAncestor && m_ancestorClippingLayer) {
222 // Call calculateRects to get the backgroundRect which is what is used to clip the contents of this
223 // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects
224 // for a compositing layer, rootLayer is the layer itself.
225 ClipRects parentRects;
226 m_owningLayer->parentClipRects(compAncestor, parentRects, true);
227 IntRect parentClipRect = parentRects.overflowClipRect();
228
229 m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation));
230 m_ancestorClippingLayer->setSize(parentClipRect.size());
231
232 // backgroundRect is relative to compAncestor, so subtract deltaX/deltaY to get back to local coords.
233 IntSize rendererOffset(parentClipRect.location().x() - deltaX, parentClipRect.location().y() - deltaY);
234 m_ancestorClippingLayer->setOffsetFromRenderer(rendererOffset);
235
236 // The primary layer is then parented in, and positioned relative to this clipping layer.
237 graphicsLayerParentLocation = parentClipRect.location();
238 }
239
240 m_graphicsLayer->setPosition(FloatPoint() + (relativeCompositingBounds.location() - graphicsLayerParentLocation));
241 m_graphicsLayer->setOffsetFromRenderer(localCompositingBounds.location() - IntPoint());
242
243 FloatSize oldSize = m_graphicsLayer->size();
244 FloatSize newSize = relativeCompositingBounds.size();
245 if (oldSize != newSize) {
246 m_graphicsLayer->setSize(newSize);
247 // A bounds change will almost always require redisplay. Usually that redisplay
248 // will happen because of a repaint elsewhere, but not always:
249 // e.g. see RenderView::setMaximalOutlineSize()
250 m_graphicsLayer->setNeedsDisplay();
251 }
252
253 // If we have a layer that clips children, position it.
254 if (m_clippingLayer) {
255 IntRect clippingBox = toRenderBox(renderer())->overflowClipRect(0, 0);
256 m_clippingLayer->setPosition(FloatPoint() + (clippingBox.location() - localCompositingBounds.location()));
257 m_clippingLayer->setSize(clippingBox.size());
258 m_clippingLayer->setOffsetFromRenderer(clippingBox.location() - IntPoint());
259 }
260
261 if (m_owningLayer->hasTransform()) {
262 const IntRect borderBox = toRenderBox(renderer())->borderBoxRect();
263
264 // Get layout bounds in the coords of compAncestor to match relativeCompositingBounds.
265 IntRect layerBounds = IntRect(deltaX, deltaY, borderBox.width(), borderBox.height());
266
267 // Update properties that depend on layer dimensions
268 FloatPoint3D transformOrigin = computeTransformOrigin(borderBox);
269 // Compute the anchor point, which is in the center of the renderer box unless transform-origin is set.
270 FloatPoint3D anchor(relativeCompositingBounds.width() != 0.0f ? ((layerBounds.x() - relativeCompositingBounds.x()) + transformOrigin.x()) / relativeCompositingBounds.width() : 0.5f,
271 relativeCompositingBounds.height() != 0.0f ? ((layerBounds.y() - relativeCompositingBounds.y()) + transformOrigin.y()) / relativeCompositingBounds.height() : 0.5f,
272 transformOrigin.z());
273 m_graphicsLayer->setAnchorPoint(anchor);
274
275 RenderStyle* style = renderer()->style();
276 if (style->hasPerspective()) {
277 TransformationMatrix t = owningLayer()->perspectiveTransform();
278
279 if (m_clippingLayer) {
280 m_clippingLayer->setChildrenTransform(t);
281 m_graphicsLayer->setChildrenTransform(TransformationMatrix());
282 }
283 else
284 m_graphicsLayer->setChildrenTransform(t);
285 } else {
286 if (m_clippingLayer)
287 m_clippingLayer->setChildrenTransform(TransformationMatrix());
288 else
289 m_graphicsLayer->setChildrenTransform(TransformationMatrix());
290 }
291 } else {
292 m_graphicsLayer->setAnchorPoint(FloatPoint3D(0.5f, 0.5f, 0));
293 }
294
295 if (m_foregroundLayer) {
296 // The contents layer is always coincidental with the graphicsLayer for now.
297 m_foregroundLayer->setPosition(IntPoint(0, 0));
298 m_foregroundLayer->setSize(newSize);
299 m_foregroundLayer->setOffsetFromRenderer(m_graphicsLayer->offsetFromRenderer());
300 }
301
302 m_graphicsLayer->setContentsRect(contentsBox());
303 if (!m_hasDirectlyCompositedContent)
304 m_graphicsLayer->setDrawsContent(!isSimpleContainerCompositingLayer() && !paintingGoesToWindow());
305 }
306
updateInternalHierarchy()307 void RenderLayerBacking::updateInternalHierarchy()
308 {
309 // m_foregroundLayer has to be inserted in the correct order with child layers,
310 // so it's not inserted here.
311 if (m_ancestorClippingLayer) {
312 m_ancestorClippingLayer->removeAllChildren();
313 m_graphicsLayer->removeFromParent();
314 m_ancestorClippingLayer->addChild(m_graphicsLayer);
315 }
316
317 if (m_clippingLayer) {
318 m_clippingLayer->removeFromParent();
319 m_graphicsLayer->addChild(m_clippingLayer);
320 }
321 }
322
323 // Return true if the layers changed.
updateClippingLayers(bool needsAncestorClip,bool needsDescendantClip)324 bool RenderLayerBacking::updateClippingLayers(bool needsAncestorClip, bool needsDescendantClip)
325 {
326 bool layersChanged = false;
327
328 if (needsAncestorClip) {
329 if (!m_ancestorClippingLayer) {
330 m_ancestorClippingLayer = GraphicsLayer::createGraphicsLayer(this);
331 #ifndef NDEBUG
332 m_ancestorClippingLayer->setName("Ancestor clipping Layer");
333 #endif
334 m_ancestorClippingLayer->setMasksToBounds(true);
335 layersChanged = true;
336 }
337 } else if (m_ancestorClippingLayer) {
338 m_ancestorClippingLayer->removeFromParent();
339 delete m_ancestorClippingLayer;
340 m_ancestorClippingLayer = 0;
341 layersChanged = true;
342 }
343
344 if (needsDescendantClip) {
345 if (!m_clippingLayer) {
346 m_clippingLayer = GraphicsLayer::createGraphicsLayer(0);
347 #ifndef NDEBUG
348 m_clippingLayer->setName("Child clipping Layer");
349 #endif
350 m_clippingLayer->setMasksToBounds(true);
351 layersChanged = true;
352 }
353 } else if (m_clippingLayer) {
354 m_clippingLayer->removeFromParent();
355 delete m_clippingLayer;
356 m_clippingLayer = 0;
357 layersChanged = true;
358 }
359
360 if (layersChanged)
361 updateInternalHierarchy();
362
363 return layersChanged;
364 }
365
updateForegroundLayer(bool needsForegroundLayer)366 bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer)
367 {
368 bool layerChanged = false;
369 if (needsForegroundLayer) {
370 if (!m_foregroundLayer) {
371 m_foregroundLayer = GraphicsLayer::createGraphicsLayer(this);
372 #ifndef NDEBUG
373 m_foregroundLayer->setName("Contents");
374 #endif
375 m_foregroundLayer->setDrawsContent(true);
376 m_foregroundLayer->setDrawingPhase(GraphicsLayerPaintForegroundMask);
377 m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintBackgroundMask);
378 layerChanged = true;
379 }
380 } else if (m_foregroundLayer) {
381 m_foregroundLayer->removeFromParent();
382 delete m_foregroundLayer;
383 m_foregroundLayer = 0;
384 m_graphicsLayer->setDrawingPhase(GraphicsLayerPaintAllMask);
385 layerChanged = true;
386 }
387 return layerChanged;
388 }
389
compositingOpacity(float rendererOpacity) const390 float RenderLayerBacking::compositingOpacity(float rendererOpacity) const
391 {
392 float finalOpacity = rendererOpacity;
393
394 for (RenderLayer* curr = m_owningLayer->parent(); curr; curr = curr->parent()) {
395 // We only care about parents that are stacking contexts.
396 // Recall that opacity creates stacking context.
397 if (!curr->isStackingContext())
398 continue;
399
400 // If we found a compositing layer, we want to compute opacity
401 // relative to it. So we can break here.
402 if (curr->isComposited())
403 break;
404
405 finalOpacity *= curr->renderer()->opacity();
406 }
407
408 return finalOpacity;
409 }
410
hasBorderOutlineOrShadow(const RenderStyle * style)411 static bool hasBorderOutlineOrShadow(const RenderStyle* style)
412 {
413 return style->hasBorder() || style->hasBorderRadius() || style->hasOutline() || style->hasAppearance() || style->boxShadow();
414 }
415
hasBoxDecorations(const RenderStyle * style)416 static bool hasBoxDecorations(const RenderStyle* style)
417 {
418 return hasBorderOutlineOrShadow(style) || style->hasBackground();
419 }
420
hasBoxDecorationsWithBackgroundImage(const RenderStyle * style)421 static bool hasBoxDecorationsWithBackgroundImage(const RenderStyle* style)
422 {
423 return hasBorderOutlineOrShadow(style) || style->hasBackgroundImage();
424 }
425
rendererHasBackground() const426 bool RenderLayerBacking::rendererHasBackground() const
427 {
428 // FIXME: share more code here
429 if (renderer()->node() && renderer()->node()->isDocumentNode()) {
430 RenderObject* htmlObject = renderer()->firstChild();
431 if (!htmlObject)
432 return false;
433
434 RenderStyle* style = htmlObject->style();
435 if (style->hasBackground())
436 return true;
437
438 RenderObject* bodyObject = htmlObject->firstChild();
439 if (!bodyObject)
440 return false;
441
442 style = bodyObject->style();
443 return style->hasBackground();
444 }
445
446 return renderer()->style()->hasBackground();
447 }
448
rendererBackgroundColor() const449 const Color& RenderLayerBacking::rendererBackgroundColor() const
450 {
451 // FIXME: share more code here
452 if (renderer()->node() && renderer()->node()->isDocumentNode()) {
453 RenderObject* htmlObject = renderer()->firstChild();
454 RenderStyle* style = htmlObject->style();
455 if (style->hasBackground())
456 return style->backgroundColor();
457
458 RenderObject* bodyObject = htmlObject->firstChild();
459 style = bodyObject->style();
460 return style->backgroundColor();
461 }
462
463 return renderer()->style()->backgroundColor();
464 }
465
466 // A "simple container layer" is a RenderLayer which has no visible content to render.
467 // It may have no children, or all its children may be themselves composited.
468 // This is a useful optimization, because it allows us to avoid allocating backing store.
isSimpleContainerCompositingLayer() const469 bool RenderLayerBacking::isSimpleContainerCompositingLayer() const
470 {
471 RenderObject* renderObject = renderer();
472 if (renderObject->isReplaced() || // replaced objects are not containers
473 renderObject->hasMask()) // masks require special treatment
474 return false;
475
476 RenderStyle* style = renderObject->style();
477
478 // Reject anything that has a border, a border-radius or outline,
479 // or any background (color or image).
480 // FIXME: we could optimize layers for simple backgrounds.
481 if (hasBoxDecorations(style))
482 return false;
483
484 // If we have got this far and the renderer has no children, then we're ok.
485 if (!renderObject->firstChild())
486 return true;
487
488 if (renderObject->node() && renderObject->node()->isDocumentNode()) {
489 // Look to see if the root object has a non-simple backgound
490 RenderObject* rootObject = renderObject->document()->documentElement()->renderer();
491 if (!rootObject)
492 return false;
493
494 style = rootObject->style();
495
496 // Reject anything that has a border, a border-radius or outline,
497 // or is not a simple background (no background, or solid color).
498 if (hasBoxDecorationsWithBackgroundImage(style))
499 return false;
500
501 // Now look at the body's renderer.
502 HTMLElement* body = renderObject->document()->body();
503 RenderObject* bodyObject = (body && body->hasLocalName(HTMLNames::bodyTag)) ? body->renderer() : 0;
504 if (!bodyObject)
505 return false;
506
507 style = bodyObject->style();
508
509 if (hasBoxDecorationsWithBackgroundImage(style))
510 return false;
511
512 // Ceck to see if all the body's children are compositing layers.
513 if (hasNonCompositingContent())
514 return false;
515
516 return true;
517 }
518
519 // Check to see if all the renderer's children are compositing layers.
520 if (hasNonCompositingContent())
521 return false;
522
523 return true;
524 }
525
hasNonCompositingContent() const526 bool RenderLayerBacking::hasNonCompositingContent() const
527 {
528 // Conservative test for having no rendered children.
529
530 // Some HTML can cause whitespace text nodes to have renderers, like:
531 // <div>
532 // <img src=...>
533 // </div>
534 // so test for 0x0 RenderTexts here
535 for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
536 if (!child->hasLayer()) {
537 if (child->isRenderInline() || !child->isBox())
538 return true;
539
540 if (toRenderBox(child)->width() > 0 || toRenderBox(child)->height() > 0)
541 return true;
542 }
543 }
544
545 // FIXME: test for overflow controls.
546 if (m_owningLayer->isStackingContext()) {
547 // Use the m_hasCompositingDescendant bit to optimize?
548 if (Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList()) {
549 size_t listSize = negZOrderList->size();
550 for (size_t i = 0; i < listSize; ++i) {
551 RenderLayer* curLayer = negZOrderList->at(i);
552 if (!curLayer->isComposited())
553 return true;
554 }
555 }
556
557 if (Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList()) {
558 size_t listSize = posZOrderList->size();
559 for (size_t i = 0; i < listSize; ++i) {
560 RenderLayer* curLayer = posZOrderList->at(i);
561 if (!curLayer->isComposited())
562 return true;
563 }
564 }
565 }
566
567 if (Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList()) {
568 size_t listSize = normalFlowList->size();
569 for (size_t i = 0; i < listSize; ++i) {
570 RenderLayer* curLayer = normalFlowList->at(i);
571 if (!curLayer->isComposited())
572 return true;
573 }
574 }
575
576 return false;
577 }
578
579 // A layer can use direct compositing if the render layer's object is a replaced object and has no children.
580 // This allows the GraphicsLayer to display the RenderLayer contents directly; it's used for images.
canUseDirectCompositing() const581 bool RenderLayerBacking::canUseDirectCompositing() const
582 {
583 RenderObject* renderObject = renderer();
584
585 // Reject anything that isn't an image
586 if (!renderObject->isImage() && !renderObject->isVideo())
587 return false;
588
589 if (renderObject->hasMask() || renderObject->hasReflection())
590 return false;
591
592 // Video can use an inner layer even if it has box decorations; we draw those into another layer.
593 if (renderObject->isVideo())
594 return true;
595
596 // Reject anything that would require the image to be drawn via the GraphicsContext,
597 // like border, shadows etc. Solid background color is OK.
598 return !hasBoxDecorationsWithBackgroundImage(renderObject->style());
599 }
600
rendererContentChanged()601 void RenderLayerBacking::rendererContentChanged()
602 {
603 if (canUseDirectCompositing() && renderer()->isImage())
604 updateImageContents();
605 }
606
updateImageContents()607 void RenderLayerBacking::updateImageContents()
608 {
609 ASSERT(renderer()->isImage());
610 RenderImage* imageRenderer = toRenderImage(renderer());
611
612 CachedImage* cachedImage = imageRenderer->cachedImage();
613 if (!cachedImage)
614 return;
615
616 Image* image = cachedImage->image();
617 if (!image)
618 return;
619
620 // We have to wait until the image is fully loaded before setting it on the layer.
621 if (!cachedImage->isLoaded())
622 return;
623
624 // This is a no-op if the layer doesn't have an inner layer for the image.
625 m_graphicsLayer->setContentsToImage(image);
626
627 // Image animation is "lazy", in that it automatically stops unless someone is drawing
628 // the image. So we have to kick the animation each time; this has the downside that the
629 // image will keep animating, even if its layer is not visible.
630 image->startAnimation();
631 }
632
computeTransformOrigin(const IntRect & borderBox) const633 FloatPoint3D RenderLayerBacking::computeTransformOrigin(const IntRect& borderBox) const
634 {
635 RenderStyle* style = renderer()->style();
636
637 FloatPoint3D origin;
638 origin.setX(style->transformOriginX().calcFloatValue(borderBox.width()));
639 origin.setY(style->transformOriginY().calcFloatValue(borderBox.height()));
640 origin.setZ(style->transformOriginZ());
641
642 return origin;
643 }
644
computePerspectiveOrigin(const IntRect & borderBox) const645 FloatPoint RenderLayerBacking::computePerspectiveOrigin(const IntRect& borderBox) const
646 {
647 RenderStyle* style = renderer()->style();
648
649 float boxWidth = borderBox.width();
650 float boxHeight = borderBox.height();
651
652 FloatPoint origin;
653 origin.setX(style->perspectiveOriginX().calcFloatValue(boxWidth));
654 origin.setY(style->perspectiveOriginY().calcFloatValue(boxHeight));
655
656 return origin;
657 }
658
659 // Return the offset from the top-left of this compositing layer at which the renderer's contents are painted.
contentOffsetInCompostingLayer() const660 IntSize RenderLayerBacking::contentOffsetInCompostingLayer() const
661 {
662 return IntSize(-m_compositedBounds.x(), -m_compositedBounds.y());
663 }
664
contentsBox() const665 IntRect RenderLayerBacking::contentsBox() const
666 {
667 if (!renderer()->isBox())
668 return IntRect();
669
670 IntRect contentsRect;
671 #if ENABLE(VIDEO)
672 if (renderer()->isVideo()) {
673 RenderVideo* videoRenderer = toRenderVideo(renderer());
674 contentsRect = videoRenderer->videoBox();
675 } else
676 #endif
677 contentsRect = toRenderBox(renderer())->contentBoxRect();
678
679 IntSize contentOffset = contentOffsetInCompostingLayer();
680 contentsRect.move(contentOffset);
681 return contentsRect;
682 }
683
684 // Map the given point from coordinates in the GraphicsLayer to RenderLayer coordinates.
graphicsLayerToContentsCoordinates(const GraphicsLayer * graphicsLayer,const FloatPoint & point)685 FloatPoint RenderLayerBacking::graphicsLayerToContentsCoordinates(const GraphicsLayer* graphicsLayer, const FloatPoint& point)
686 {
687 return point + FloatSize(graphicsLayer->offsetFromRenderer());
688 }
689
690 // Map the given point from coordinates in the RenderLayer to GraphicsLayer coordinates.
contentsToGraphicsLayerCoordinates(const GraphicsLayer * graphicsLayer,const FloatPoint & point)691 FloatPoint RenderLayerBacking::contentsToGraphicsLayerCoordinates(const GraphicsLayer* graphicsLayer, const FloatPoint& point)
692 {
693 return point - FloatSize(graphicsLayer->offsetFromRenderer());
694 }
695
paintingGoesToWindow() const696 bool RenderLayerBacking::paintingGoesToWindow() const
697 {
698 return m_owningLayer->isRootLayer();
699 }
700
setContentsNeedDisplay()701 void RenderLayerBacking::setContentsNeedDisplay()
702 {
703 if (m_graphicsLayer && m_graphicsLayer->drawsContent())
704 m_graphicsLayer->setNeedsDisplay();
705
706 if (m_foregroundLayer && m_foregroundLayer->drawsContent())
707 m_foregroundLayer->setNeedsDisplay();
708 }
709
710 // r is in the coordinate space of the layer's render object
setContentsNeedDisplayInRect(const IntRect & r)711 void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r)
712 {
713 if (m_graphicsLayer && m_graphicsLayer->drawsContent()) {
714 FloatPoint dirtyOrigin = contentsToGraphicsLayerCoordinates(m_graphicsLayer, FloatPoint(r.x(), r.y()));
715 FloatRect dirtyRect(dirtyOrigin, r.size());
716 FloatRect bounds(FloatPoint(), m_graphicsLayer->size());
717 if (bounds.intersects(dirtyRect))
718 m_graphicsLayer->setNeedsDisplayInRect(dirtyRect);
719 }
720
721 if (m_foregroundLayer && m_foregroundLayer->drawsContent()) {
722 // FIXME: do incremental repaint
723 m_foregroundLayer->setNeedsDisplay();
724 }
725 }
726
setClip(GraphicsContext * p,const IntRect & paintDirtyRect,const IntRect & clipRect)727 static void setClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
728 {
729 if (paintDirtyRect == clipRect)
730 return;
731 p->save();
732 p->clip(clipRect);
733 }
734
restoreClip(GraphicsContext * p,const IntRect & paintDirtyRect,const IntRect & clipRect)735 static void restoreClip(GraphicsContext* p, const IntRect& paintDirtyRect, const IntRect& clipRect)
736 {
737 if (paintDirtyRect == clipRect)
738 return;
739 p->restore();
740 }
741
742 // Share this with RenderLayer::paintLayer, which would have to be educated about GraphicsLayerPaintingPhase?
paintIntoLayer(RenderLayer * rootLayer,GraphicsContext * context,const IntRect & paintDirtyRect,PaintRestriction paintRestriction,GraphicsLayerPaintingPhase paintingPhase,RenderObject * paintingRoot)743 void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context,
744 const IntRect& paintDirtyRect, // in the coords of rootLayer
745 PaintRestriction paintRestriction, GraphicsLayerPaintingPhase paintingPhase,
746 RenderObject* paintingRoot)
747 {
748 if (paintingGoesToWindow()) {
749 ASSERT_NOT_REACHED();
750 return;
751 }
752
753 m_owningLayer->updateLayerListsIfNeeded();
754
755 // Paint the reflection first if we have one.
756 if (m_owningLayer->hasReflection()) {
757 // Mark that we are now inside replica painting.
758 m_owningLayer->setPaintingInsideReflection(true);
759 m_owningLayer->reflectionLayer()->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot, 0, RenderLayer::PaintLayerPaintingReflection);
760 m_owningLayer->setPaintingInsideReflection(false);
761 }
762
763 // Calculate the clip rects we should use.
764 IntRect layerBounds, damageRect, clipRectToApply, outlineRect;
765 m_owningLayer->calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect);
766
767 int x = layerBounds.x(); // layerBounds is computed relative to rootLayer
768 int y = layerBounds.y();
769 int tx = x - m_owningLayer->renderBoxX();
770 int ty = y - m_owningLayer->renderBoxY();
771
772 // If this layer's renderer is a child of the paintingRoot, we render unconditionally, which
773 // is done by passing a nil paintingRoot down to our renderer (as if no paintingRoot was ever set).
774 // Else, our renderer tree may or may not contain the painting root, so we pass that root along
775 // so it will be tested against as we decend through the renderers.
776 RenderObject *paintingRootForRenderer = 0;
777 if (paintingRoot && !renderer()->isDescendantOf(paintingRoot))
778 paintingRootForRenderer = paintingRoot;
779
780 bool shouldPaint = m_owningLayer->hasVisibleContent() && m_owningLayer->isSelfPaintingLayer();
781
782 if (shouldPaint && (paintingPhase & GraphicsLayerPaintBackgroundMask)) {
783 // If this is the root then we need to send in a bigger bounding box
784 // because we'll be painting the background as well (see RenderBox::paintRootBoxDecorations()).
785 IntRect paintBox = clipRectToApply;
786
787 // FIXME: do we need this code?
788 if (renderer()->node() && renderer()->node()->isDocumentNode() && renderer()->document()->isHTMLDocument()) {
789 RenderBox* box = toRenderBox(renderer());
790 int w = box->width();
791 int h = box->height();
792
793 int rw;
794 int rh;
795 if (box->view()->frameView()) {
796 rw = box->view()->frameView()->contentsWidth();
797 rh = box->view()->frameView()->contentsHeight();
798 } else {
799 rw = box->view()->width();
800 rh = box->view()->height();
801 }
802
803 int bx = tx - box->marginLeft();
804 int by = ty - box->marginTop();
805 int bw = max(w + box->marginLeft() + box->marginRight() + box->borderLeft() + box->borderRight(), rw);
806 int bh = max(h + box->marginTop() + box->marginBottom() + box->borderTop() + box->borderBottom(), rh);
807 paintBox = IntRect(bx, by, bw, bh);
808 }
809
810 // Paint our background first, before painting any child layers.
811 // Establish the clip used to paint our background.
812 setClip(context, paintDirtyRect, damageRect);
813
814 RenderObject::PaintInfo info(context, paintBox, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0);
815 renderer()->paint(info, tx, ty);
816
817 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
818 // z-index. We paint after we painted the background/border, so that the scrollbars will
819 // sit above the background/border.
820 m_owningLayer->paintOverflowControls(context, x, y, damageRect);
821
822 // Restore the clip.
823 restoreClip(context, paintDirtyRect, damageRect);
824 }
825
826 if (shouldPaint && (paintingPhase & GraphicsLayerPaintForegroundMask)) {
827 // Now walk the sorted list of children with negative z-indices. Only RenderLayers without compositing layers will paint.
828 // FIXME: should these be painted as background?
829 Vector<RenderLayer*>* negZOrderList = m_owningLayer->negZOrderList();
830 if (negZOrderList) {
831 for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it)
832 it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot);
833 }
834
835 bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText;
836 bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText;
837
838 // Set up the clip used when painting our children.
839 setClip(context, paintDirtyRect, clipRectToApply);
840 RenderObject::PaintInfo paintInfo(context, clipRectToApply,
841 selectionOnly ? PaintPhaseSelection : PaintPhaseChildBlockBackgrounds,
842 forceBlackText, paintingRootForRenderer, 0);
843 renderer()->paint(paintInfo, tx, ty);
844
845 if (!selectionOnly) {
846 paintInfo.phase = PaintPhaseFloat;
847 renderer()->paint(paintInfo, tx, ty);
848
849 paintInfo.phase = PaintPhaseForeground;
850 renderer()->paint(paintInfo, tx, ty);
851
852 paintInfo.phase = PaintPhaseChildOutlines;
853 renderer()->paint(paintInfo, tx, ty);
854 }
855
856 // Now restore our clip.
857 restoreClip(context, paintDirtyRect, clipRectToApply);
858
859 if (!outlineRect.isEmpty()) {
860 // Paint our own outline
861 RenderObject::PaintInfo paintInfo(context, outlineRect, PaintPhaseSelfOutline, false, paintingRootForRenderer, 0);
862 setClip(context, paintDirtyRect, outlineRect);
863 renderer()->paint(paintInfo, tx, ty);
864 restoreClip(context, paintDirtyRect, outlineRect);
865 }
866
867 // Paint any child layers that have overflow.
868 Vector<RenderLayer*>* normalFlowList = m_owningLayer->normalFlowList();
869 if (normalFlowList) {
870 for (Vector<RenderLayer*>::iterator it = normalFlowList->begin(); it != normalFlowList->end(); ++it)
871 it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot);
872 }
873
874 // Now walk the sorted list of children with positive z-indices.
875 Vector<RenderLayer*>* posZOrderList = m_owningLayer->posZOrderList();
876 if (posZOrderList) {
877 for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it)
878 it[0]->paintLayer(rootLayer, context, paintDirtyRect, paintRestriction, paintingRoot);
879 }
880
881 if (renderer()->hasMask() && !selectionOnly && !damageRect.isEmpty()) {
882 setClip(context, paintDirtyRect, damageRect);
883
884 // Paint the mask.
885 RenderObject::PaintInfo paintInfo(context, damageRect, PaintPhaseMask, false, paintingRootForRenderer, 0);
886 renderer()->paint(paintInfo, tx, ty);
887
888 // Restore the clip.
889 restoreClip(context, paintDirtyRect, damageRect);
890 }
891 }
892
893 ASSERT(!m_owningLayer->m_usedTransparency);
894 }
895
896 // Up-call from compositing layer drawing callback.
paintContents(const GraphicsLayer *,GraphicsContext & context,GraphicsLayerPaintingPhase drawingPhase,const IntRect & clip)897 void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& context, GraphicsLayerPaintingPhase drawingPhase, const IntRect& clip)
898 {
899 // We have to use the same root as for hit testing, because both methods
900 // can compute and cache clipRects.
901 IntRect enclosingBBox = compositedBounds();
902
903 IntRect clipRect(clip);
904
905 // Set up the coordinate space to be in the layer's rendering coordinates.
906 context.translate(-enclosingBBox.x(), -enclosingBBox.y());
907
908 // Offset the clip.
909 clipRect.move(enclosingBBox.x(), enclosingBBox.y());
910
911 // The dirtyRect is in the coords of the painting root.
912 IntRect dirtyRect = enclosingBBox;
913 dirtyRect.intersect(clipRect);
914
915 paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintRestrictionNone, drawingPhase, renderer());
916 }
917
startAnimation(double beginTime,const Animation * anim,const KeyframeList & keyframes)918 bool RenderLayerBacking::startAnimation(double beginTime, const Animation* anim, const KeyframeList& keyframes)
919 {
920 bool hasOpacity = keyframes.containsProperty(CSSPropertyOpacity);
921 bool hasTransform = keyframes.containsProperty(CSSPropertyWebkitTransform);
922
923 if (!hasOpacity && !hasTransform)
924 return false;
925
926 KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
927 KeyframeValueList opacityVector(AnimatedPropertyOpacity);
928
929 for (Vector<KeyframeValue>::const_iterator it = keyframes.beginKeyframes(); it != keyframes.endKeyframes(); ++it) {
930 const RenderStyle* keyframeStyle = it->style();
931 float key = it->key();
932
933 if (!keyframeStyle)
934 continue;
935
936 // get timing function
937 const TimingFunction* tf = keyframeStyle->hasAnimations() ? &((*keyframeStyle->animations()).animation(0)->timingFunction()) : 0;
938
939 if (hasTransform)
940 transformVector.insert(new TransformAnimationValue(key, &(keyframeStyle->transform()), tf));
941
942 if (hasOpacity)
943 opacityVector.insert(new FloatAnimationValue(key, keyframeStyle->opacity(), tf));
944 }
945
946 bool didAnimateTransform = !hasTransform;
947 bool didAnimateOpacity = !hasOpacity;
948
949 if (hasTransform && m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), anim, keyframes.animationName(), beginTime))
950 didAnimateTransform = true;
951
952 if (hasOpacity && m_graphicsLayer->addAnimation(opacityVector, IntSize(), anim, keyframes.animationName(), beginTime))
953 didAnimateOpacity = true;
954
955 bool runningAcceleratedAnimation = didAnimateTransform && didAnimateOpacity;
956 if (runningAcceleratedAnimation)
957 compositor()->didStartAcceleratedAnimation();
958
959 return runningAcceleratedAnimation;
960 }
961
startTransition(double beginTime,int property,const RenderStyle * fromStyle,const RenderStyle * toStyle)962 bool RenderLayerBacking::startTransition(double beginTime, int property, const RenderStyle* fromStyle, const RenderStyle* toStyle)
963 {
964 bool didAnimate = false;
965 ASSERT(property != cAnimateAll);
966
967 if (property == (int)CSSPropertyOpacity) {
968 const Animation* opacityAnim = toStyle->transitionForProperty(CSSPropertyOpacity);
969 if (opacityAnim && !opacityAnim->isEmptyOrZeroDuration()) {
970 KeyframeValueList opacityVector(AnimatedPropertyOpacity);
971 opacityVector.insert(new FloatAnimationValue(0, compositingOpacity(fromStyle->opacity())));
972 opacityVector.insert(new FloatAnimationValue(1, compositingOpacity(toStyle->opacity())));
973 if (m_graphicsLayer->addAnimation(opacityVector, toRenderBox(renderer())->borderBoxRect().size(), opacityAnim, String(), beginTime))
974 didAnimate = true;
975 }
976 }
977
978 if (property == (int)CSSPropertyWebkitTransform && m_owningLayer->hasTransform()) {
979 const Animation* transformAnim = toStyle->transitionForProperty(CSSPropertyWebkitTransform);
980 if (transformAnim && !transformAnim->isEmptyOrZeroDuration()) {
981 KeyframeValueList transformVector(AnimatedPropertyWebkitTransform);
982 transformVector.insert(new TransformAnimationValue(0, &fromStyle->transform()));
983 transformVector.insert(new TransformAnimationValue(1, &toStyle->transform()));
984 if (m_graphicsLayer->addAnimation(transformVector, toRenderBox(renderer())->borderBoxRect().size(), transformAnim, String(), beginTime))
985 didAnimate = true;
986 }
987 }
988
989 if (didAnimate)
990 compositor()->didStartAcceleratedAnimation();
991
992 return didAnimate;
993 }
994
notifyAnimationStarted(const GraphicsLayer *,double time)995 void RenderLayerBacking::notifyAnimationStarted(const GraphicsLayer*, double time)
996 {
997 renderer()->animation()->notifyAnimationStarted(renderer(), time);
998 }
999
notifySyncRequired(const GraphicsLayer *)1000 void RenderLayerBacking::notifySyncRequired(const GraphicsLayer*)
1001 {
1002 if (!renderer()->documentBeingDestroyed())
1003 compositor()->scheduleSync();
1004 }
1005
animationFinished(const String & animationName)1006 void RenderLayerBacking::animationFinished(const String& animationName)
1007 {
1008 m_graphicsLayer->removeAnimationsForKeyframes(animationName);
1009 }
1010
animationPaused(const String & animationName)1011 void RenderLayerBacking::animationPaused(const String& animationName)
1012 {
1013 m_graphicsLayer->pauseAnimation(animationName);
1014 }
1015
transitionFinished(int property)1016 void RenderLayerBacking::transitionFinished(int property)
1017 {
1018 AnimatedPropertyID animatedProperty = cssToGraphicsLayerProperty(property);
1019 if (animatedProperty != AnimatedPropertyInvalid)
1020 m_graphicsLayer->removeAnimationsForProperty(animatedProperty);
1021 }
1022
suspendAnimations(double time)1023 void RenderLayerBacking::suspendAnimations(double time)
1024 {
1025 m_graphicsLayer->suspendAnimations(time);
1026 }
1027
resumeAnimations()1028 void RenderLayerBacking::resumeAnimations()
1029 {
1030 m_graphicsLayer->resumeAnimations();
1031 }
1032
compositedBounds() const1033 IntRect RenderLayerBacking::compositedBounds() const
1034 {
1035 return m_compositedBounds;
1036 }
1037
setCompositedBounds(const IntRect & bounds)1038 void RenderLayerBacking::setCompositedBounds(const IntRect& bounds)
1039 {
1040 m_compositedBounds = bounds;
1041
1042 }
graphicsLayerToCSSProperty(AnimatedPropertyID property)1043 int RenderLayerBacking::graphicsLayerToCSSProperty(AnimatedPropertyID property)
1044 {
1045 int cssProperty = CSSPropertyInvalid;
1046 switch (property) {
1047 case AnimatedPropertyWebkitTransform:
1048 cssProperty = CSSPropertyWebkitTransform;
1049 break;
1050 case AnimatedPropertyOpacity:
1051 cssProperty = CSSPropertyOpacity;
1052 break;
1053 case AnimatedPropertyBackgroundColor:
1054 cssProperty = CSSPropertyBackgroundColor;
1055 break;
1056 case AnimatedPropertyInvalid:
1057 ASSERT_NOT_REACHED();
1058 }
1059 return cssProperty;
1060 }
1061
cssToGraphicsLayerProperty(int cssProperty)1062 AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(int cssProperty)
1063 {
1064 switch (cssProperty) {
1065 case CSSPropertyWebkitTransform:
1066 return AnimatedPropertyWebkitTransform;
1067 case CSSPropertyOpacity:
1068 return AnimatedPropertyOpacity;
1069 case CSSPropertyBackgroundColor:
1070 return AnimatedPropertyBackgroundColor;
1071 // It's fine if we see other css properties here; they are just not accelerated.
1072 }
1073 return AnimatedPropertyInvalid;
1074 }
1075
1076 } // namespace WebCore
1077
1078 #endif // USE(ACCELERATED_COMPOSITING)
1079